]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Mar 2011 04:02:22 +0000 (21:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Mar 2011 04:02:22 +0000 (21:02 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (56 commits)
  route: Take the right src and dst addresses in ip_route_newports
  ipv4: Fix nexthop caching wrt. scoping.
  ipv4: Invalidate nexthop cache nh_saddr more correctly.
  net: fix pch_gbe section mismatch warning
  ipv4: fix fib metrics
  mlx4_en: Removing HW info from ethtool -i report.
  net_sched: fix THROTTLED/RUNNING race
  drivers/net/a2065.c: Convert release_resource to release_region/release_mem_region
  drivers/net/ariadne.c: Convert release_resource to release_region/release_mem_region
  bonding: fix rx_handler locking
  myri10ge: fix rmmod crash
  mlx4_en: updated driver version to 1.5.4.1
  mlx4_en: Using blue flame support
  mlx4_core: reserve UARs for userspace consumers
  mlx4_core: maintain available field in bitmap allocator
  mlx4: Add blue flame support for kernel consumers
  mlx4_en: Enabling new steering
  mlx4: Add support for promiscuous mode in the new steering model.
  mlx4: generalization of multicast steering.
  mlx4_en: Reporting HW revision in ethtool -i
  ...

2611 files changed:
.mailmap
Documentation/ABI/stable/sysfs-class-backlight
Documentation/ABI/testing/configfs-spear-pcie-gadget [new file with mode: 0644]
Documentation/ABI/testing/pstore
Documentation/ABI/testing/sysfs-bus-media [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-rbd
Documentation/ABI/testing/sysfs-devices-mmc [new file with mode: 0644]
Documentation/ABI/testing/sysfs-fs-ext4
Documentation/ABI/testing/sysfs-fs-pstore [deleted file]
Documentation/Changes
Documentation/CodingStyle
Documentation/DocBook/Makefile
Documentation/DocBook/media-entities.tmpl
Documentation/DocBook/media.tmpl
Documentation/DocBook/v4l/bayer.pdf [new file with mode: 0644]
Documentation/DocBook/v4l/bayer.png [new file with mode: 0644]
Documentation/DocBook/v4l/common.xml
Documentation/DocBook/v4l/compat.xml
Documentation/DocBook/v4l/dev-capture.xml
Documentation/DocBook/v4l/dev-output.xml
Documentation/DocBook/v4l/dev-subdev.xml [new file with mode: 0644]
Documentation/DocBook/v4l/func-mmap.xml
Documentation/DocBook/v4l/func-munmap.xml
Documentation/DocBook/v4l/io.xml
Documentation/DocBook/v4l/lirc_device_interface.xml
Documentation/DocBook/v4l/media-controller.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-func-close.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-func-ioctl.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-func-open.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-ioc-device-info.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-ioc-enum-entities.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-ioc-enum-links.xml [new file with mode: 0644]
Documentation/DocBook/v4l/media-ioc-setup-link.xml [new file with mode: 0644]
Documentation/DocBook/v4l/nv12mt.gif [new file with mode: 0644]
Documentation/DocBook/v4l/nv12mt_example.gif [new file with mode: 0644]
Documentation/DocBook/v4l/pipeline.pdf [new file with mode: 0644]
Documentation/DocBook/v4l/pipeline.png [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-nv12m.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-nv12mt.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-srggb12.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt-yuv420m.xml [new file with mode: 0644]
Documentation/DocBook/v4l/pixfmt.xml
Documentation/DocBook/v4l/planar-apis.xml [new file with mode: 0644]
Documentation/DocBook/v4l/subdev-formats.xml [new file with mode: 0644]
Documentation/DocBook/v4l/v4l2.xml
Documentation/DocBook/v4l/videodev2.h.xml
Documentation/DocBook/v4l/vidioc-enum-fmt.xml
Documentation/DocBook/v4l/vidioc-g-fmt.xml
Documentation/DocBook/v4l/vidioc-qbuf.xml
Documentation/DocBook/v4l/vidioc-querybuf.xml
Documentation/DocBook/v4l/vidioc-querycap.xml
Documentation/DocBook/v4l/vidioc-streamon.xml
Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml [new file with mode: 0644]
Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml [new file with mode: 0644]
Documentation/acpi/apei/output_format.txt
Documentation/block/biodoc.txt
Documentation/cgroups/blkio-controller.txt
Documentation/device-mapper/dm-flakey.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fb/sm501fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ads1015.txt [new file with mode: 0644]
Documentation/devicetree/bindings/open-pic.txt [new file with mode: 0644]
Documentation/dvb/get_dvb_firmware
Documentation/dvb/lmedm04.txt
Documentation/fb/sm501.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/adfs.txt
Documentation/filesystems/exofs.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/porting
Documentation/filesystems/squashfs.txt
Documentation/filesystems/vfs.txt
Documentation/filesystems/xfs-delayed-logging-design.txt
Documentation/hwmon/ads1015 [new file with mode: 0644]
Documentation/hwmon/hpfall.c [deleted file]
Documentation/hwmon/lis3lv02d [deleted file]
Documentation/hwmon/lm75
Documentation/hwmon/sch5627 [new file with mode: 0644]
Documentation/hwmon/twl4030-madc-hwmon [new file with mode: 0644]
Documentation/hwmon/w83795 [new file with mode: 0644]
Documentation/i2c/busses/i2c-diolan-u2c [new file with mode: 0644]
Documentation/i2c/busses/i2c-i801
Documentation/i2c/instantiating-devices
Documentation/i2c/upgrading-clients
Documentation/ioctl/ioctl-number.txt
Documentation/iostats.txt
Documentation/kbuild/kbuild.txt
Documentation/kernel-parameters.txt
Documentation/laptops/hpfall.c [new file with mode: 0644]
Documentation/media-framework.txt [new file with mode: 0644]
Documentation/misc-devices/lis3lv02d [new file with mode: 0644]
Documentation/misc-devices/spear-pcie-gadget.txt [new file with mode: 0644]
Documentation/rapidio/rapidio.txt [new file with mode: 0644]
Documentation/rapidio/sysfs.txt [new file with mode: 0644]
Documentation/scheduler/sched-design-CFS.txt
Documentation/video4linux/README.ivtv
Documentation/video4linux/Zoran
Documentation/video4linux/gspca.txt
Documentation/video4linux/omap3isp.txt [new file with mode: 0644]
Documentation/video4linux/v4l2-framework.txt
Documentation/vm/page-types.c
Documentation/x86/x86_64/boot-options.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/bitops.h
arch/alpha/include/asm/types.h
arch/arm/Kconfig
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/mmcif-sh7372.c
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/include/asm/bitops.h
arch/arm/include/asm/localtimer.h
arch/arm/include/asm/outercache.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/setup.h
arch/arm/include/asm/types.h
arch/arm/kernel/crash_dump.c
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/traps.c
arch/arm/lib/uaccess_with_memcpy.c
arch/arm/mach-ep93xx/gpio.c
arch/arm/mach-exynos4/localtimer.c
arch/arm/mach-imx/mach-mx27_3ds.c
arch/arm/mach-imx/mach-pcm038.c
arch/arm/mach-integrator/Kconfig
arch/arm/mach-integrator/common.h
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/impd1.c
arch/arm/mach-integrator/include/mach/cm.h
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-mmp/include/mach/mmp2.h
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-msm/timer.c
arch/arm/mach-mx3/mach-mx31_3ds.c
arch/arm/mach-mx3/mach-mx31moboard.c
arch/arm/mach-mxs/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-mxs/include/mach/mmc.h [new file with mode: 0644]
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/devices.h [new file with mode: 0644]
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/timer-mpu.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-evalboard.c
arch/arm/mach-pxa/colibri-pxa270-income.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/csb726.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/mxm8x10.c
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/pxa95x.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-pxa/saar.c
arch/arm/mach-pxa/saarb.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tavorevb3.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-pxa/vpac270.c
arch/arm/mach-pxa/xcep.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-pxa/zylonite_pxa300.c
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/headsmp.S [deleted file]
arch/arm/mach-realview/localtimer.c [deleted file]
arch/arm/mach-realview/platsmp.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-s3c2410/h1940-bluetooth.c
arch/arm/mach-s3c2410/include/mach/h1940.h
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2440/mach-rx1950.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/include/mach/mmc-ap4eb.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/mmc-mackerel.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/mmc.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h [deleted file]
arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h [deleted file]
arch/arm/mach-shmobile/include/mach/mmcif.h [deleted file]
arch/arm/mach-shmobile/localtimer.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/board-harmony-pcie.c
arch/arm/mach-tegra/board-harmony-pinmux.c
arch/arm/mach-tegra/board-harmony-power.c [new file with mode: 0644]
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-harmony.h
arch/arm/mach-tegra/board-paz00-pinmux.c [new file with mode: 0644]
arch/arm/mach-tegra/board-paz00.c [new file with mode: 0644]
arch/arm/mach-tegra/board-paz00.h [new file with mode: 0644]
arch/arm/mach-tegra/board-seaboard-pinmux.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/board-seaboard.h
arch/arm/mach-tegra/board-trimslice-pinmux.c
arch/arm/mach-tegra/board-trimslice.c
arch/arm/mach-tegra/board-trimslice.h
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/devices.h
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/localtimer.c
arch/arm/mach-ux500/localtimer.c
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/core.h
arch/arm/mach-versatile/include/mach/hardware.h
arch/arm/mach-versatile/versatile_ab.c
arch/arm/mach-versatile/versatile_pb.c
arch/arm/mach-vexpress/Kconfig
arch/arm/mach-vexpress/Makefile
arch/arm/mach-vexpress/core.h
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/headsmp.S [deleted file]
arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
arch/arm/mach-vexpress/include/mach/motherboard.h
arch/arm/mach-vexpress/localtimer.c [deleted file]
arch/arm/mach-vexpress/platsmp.c
arch/arm/mach-vexpress/v2m.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault-armv.c
arch/arm/mm/fault.c
arch/arm/mm/idmap.c
arch/arm/mm/init.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/pgd.c
arch/arm/plat-mxc/include/mach/esdhc.h
arch/arm/plat-nomadik/gpio.c
arch/arm/plat-nomadik/include/plat/ste_dma40.h
arch/arm/plat-omap/include/plat/display.h
arch/arm/plat-omap/include/plat/omap34xx.h
arch/arm/plat-pxa/include/plat/i2c.h [deleted file]
arch/arm/plat-versatile/Kconfig [new file with mode: 0644]
arch/arm/plat-versatile/Makefile
arch/arm/plat-versatile/clcd.c [new file with mode: 0644]
arch/arm/plat-versatile/fpga-irq.c [new file with mode: 0644]
arch/arm/plat-versatile/headsmp.S [new file with mode: 0644]
arch/arm/plat-versatile/include/plat/clcd.h [new file with mode: 0644]
arch/arm/plat-versatile/include/plat/fpga-irq.h [new file with mode: 0644]
arch/arm/plat-versatile/localtimer.c [new file with mode: 0644]
arch/arm/plat-versatile/platsmp.c [new file with mode: 0644]
arch/arm/tools/mach-types
arch/arm/vfp/Makefile
arch/avr32/Kconfig
arch/avr32/boards/atngw100/mrmt.c
arch/avr32/boards/atngw100/setup.c
arch/avr32/include/asm/bitops.h
arch/avr32/include/asm/types.h
arch/avr32/kernel/avr32_ksyms.c
arch/avr32/kernel/irq.c
arch/avr32/lib/findbit.S
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/extint.c
arch/avr32/mach-at32ap/intc.c
arch/avr32/mach-at32ap/pio.c
arch/blackfin/Kconfig
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/include/asm/atomic.h
arch/blackfin/include/asm/bitops.h
arch/blackfin/include/asm/def_LPBlackfin.h
arch/blackfin/include/asm/dpmc.h
arch/blackfin/include/asm/ipipe.h
arch/blackfin/include/asm/ipipe_base.h
arch/blackfin/include/asm/irqflags.h
arch/blackfin/include/asm/smp.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/irqchip.c
arch/blackfin/kernel/kgdb.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/mach-bf518/include/mach/defBF512.h
arch/blackfin/mach-bf527/include/mach/defBF522.h
arch/blackfin/mach-bf533/boards/ip0x.c
arch/blackfin/mach-bf537/boards/cm_bf537e.c
arch/blackfin/mach-bf537/boards/cm_bf537u.c
arch/blackfin/mach-bf537/boards/dnp5370.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf537/include/mach/defBF534.h
arch/blackfin/mach-bf548/Kconfig
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/defBF544.h
arch/blackfin/mach-bf548/include/mach/defBF547.h
arch/blackfin/mach-bf548/include/mach/dma.h
arch/blackfin/mach-bf548/include/mach/irq.h
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/hotplug.c
arch/blackfin/mach-bf561/secondary.S
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/arch_checks.c
arch/blackfin/mach-common/cache.S
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/dpmc.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/head.S
arch/blackfin/mach-common/interrupt.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/smp.c
arch/cris/include/asm/bitops.h
arch/cris/include/asm/thread_info.h
arch/cris/include/asm/types.h
arch/frv/Kconfig
arch/frv/include/asm/bitops.h
arch/frv/include/asm/processor.h
arch/frv/include/asm/thread_info.h
arch/frv/include/asm/types.h
arch/frv/kernel/process.c
arch/h8300/Kconfig
arch/h8300/boot/compressed/Makefile
arch/h8300/include/asm/bitops.h
arch/h8300/include/asm/types.h
arch/h8300/kernel/irq.c
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/bitops.h
arch/ia64/include/asm/thread_info.h
arch/ia64/include/asm/types.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/crash_dump.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/setup.c
arch/ia64/kvm/Makefile
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/sn/kernel/Makefile
arch/ia64/sn/kernel/sn2/Makefile
arch/ia64/sn/pci/Makefile
arch/ia64/sn/pci/pcibr/Makefile
arch/ia64/uv/kernel/Makefile
arch/m32r/Kconfig
arch/m32r/include/asm/bitops.h
arch/m32r/include/asm/thread_info.h
arch/m32r/include/asm/types.h
arch/m32r/kernel/irq.c
arch/m32r/platforms/m32104ut/setup.c
arch/m32r/platforms/m32700ut/setup.c
arch/m32r/platforms/mappi/setup.c
arch/m32r/platforms/mappi2/setup.c
arch/m32r/platforms/mappi3/setup.c
arch/m32r/platforms/oaks32r/setup.c
arch/m32r/platforms/opsput/setup.c
arch/m32r/platforms/usrv/setup.c
arch/m68k/Kconfig
arch/m68k/Kconfig.debug
arch/m68k/Kconfig.mmu [new file with mode: 0644]
arch/m68k/Kconfig.nommu [new file with mode: 0644]
arch/m68k/Makefile
arch/m68k/Makefile_mm [new file with mode: 0644]
arch/m68k/Makefile_no [new file with mode: 0644]
arch/m68k/configs/m5208evb_defconfig [new file with mode: 0644]
arch/m68k/configs/m5249evb_defconfig [new file with mode: 0644]
arch/m68k/configs/m5272c3_defconfig [new file with mode: 0644]
arch/m68k/configs/m5275evb_defconfig [new file with mode: 0644]
arch/m68k/configs/m5307c3_defconfig [new file with mode: 0644]
arch/m68k/configs/m5407c3_defconfig [new file with mode: 0644]
arch/m68k/include/asm/bitops_mm.h
arch/m68k/include/asm/bitops_no.h
arch/m68k/include/asm/types.h
arch/m68k/kernel/Makefile
arch/m68k/kernel/Makefile_mm [new file with mode: 0644]
arch/m68k/kernel/Makefile_no [new file with mode: 0644]
arch/m68k/kernel/asm-offsets.c
arch/m68k/kernel/asm-offsets_mm.c [new file with mode: 0644]
arch/m68k/kernel/asm-offsets_no.c [new file with mode: 0644]
arch/m68k/kernel/dma.c
arch/m68k/kernel/dma_mm.c [new file with mode: 0644]
arch/m68k/kernel/dma_no.c [new file with mode: 0644]
arch/m68k/kernel/entry.S
arch/m68k/kernel/entry_mm.S [new file with mode: 0644]
arch/m68k/kernel/entry_no.S [new file with mode: 0644]
arch/m68k/kernel/init_task.c [new file with mode: 0644]
arch/m68k/kernel/irq.c [new file with mode: 0644]
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/m68k_ksyms_mm.c [new file with mode: 0644]
arch/m68k/kernel/m68k_ksyms_no.c [new file with mode: 0644]
arch/m68k/kernel/module.c
arch/m68k/kernel/module_mm.c [new file with mode: 0644]
arch/m68k/kernel/module_no.c [new file with mode: 0644]
arch/m68k/kernel/process.c
arch/m68k/kernel/process_mm.c [new file with mode: 0644]
arch/m68k/kernel/process_no.c [new file with mode: 0644]
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/ptrace_mm.c [new file with mode: 0644]
arch/m68k/kernel/ptrace_no.c [new file with mode: 0644]
arch/m68k/kernel/setup.c
arch/m68k/kernel/setup_mm.c [new file with mode: 0644]
arch/m68k/kernel/setup_no.c [new file with mode: 0644]
arch/m68k/kernel/signal.c
arch/m68k/kernel/signal_mm.c [new file with mode: 0644]
arch/m68k/kernel/signal_no.c [new file with mode: 0644]
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/sys_m68k_mm.c [new file with mode: 0644]
arch/m68k/kernel/sys_m68k_no.c [new file with mode: 0644]
arch/m68k/kernel/syscalltable.S [new file with mode: 0644]
arch/m68k/kernel/time.c
arch/m68k/kernel/time_mm.c [new file with mode: 0644]
arch/m68k/kernel/time_no.c [new file with mode: 0644]
arch/m68k/kernel/traps.c
arch/m68k/kernel/traps_mm.c [new file with mode: 0644]
arch/m68k/kernel/traps_no.c [new file with mode: 0644]
arch/m68k/kernel/vmlinux.lds.S
arch/m68k/kernel/vmlinux.lds_mm.S [new file with mode: 0644]
arch/m68k/kernel/vmlinux.lds_no.S [new file with mode: 0644]
arch/m68k/lib/Makefile
arch/m68k/lib/Makefile_mm [new file with mode: 0644]
arch/m68k/lib/Makefile_no [new file with mode: 0644]
arch/m68k/lib/checksum.c
arch/m68k/lib/checksum_mm.c [new file with mode: 0644]
arch/m68k/lib/checksum_no.c [new file with mode: 0644]
arch/m68k/lib/delay.c [new file with mode: 0644]
arch/m68k/lib/divsi3.S [new file with mode: 0644]
arch/m68k/lib/memcpy.c [new file with mode: 0644]
arch/m68k/lib/memmove.c [new file with mode: 0644]
arch/m68k/lib/memset.c [new file with mode: 0644]
arch/m68k/lib/modsi3.S [new file with mode: 0644]
arch/m68k/lib/muldi3.c
arch/m68k/lib/muldi3_mm.c [new file with mode: 0644]
arch/m68k/lib/muldi3_no.c [new file with mode: 0644]
arch/m68k/lib/mulsi3.S [new file with mode: 0644]
arch/m68k/lib/udivsi3.S [new file with mode: 0644]
arch/m68k/lib/umodsi3.S [new file with mode: 0644]
arch/m68k/mm/Makefile
arch/m68k/mm/Makefile_mm [new file with mode: 0644]
arch/m68k/mm/Makefile_no [new file with mode: 0644]
arch/m68k/mm/init.c
arch/m68k/mm/init_mm.c [new file with mode: 0644]
arch/m68k/mm/init_no.c [new file with mode: 0644]
arch/m68k/mm/kmap.c
arch/m68k/mm/kmap_mm.c [new file with mode: 0644]
arch/m68k/mm/kmap_no.c [new file with mode: 0644]
arch/m68k/platform/5206/Makefile [new file with mode: 0644]
arch/m68k/platform/5206/config.c [new file with mode: 0644]
arch/m68k/platform/5206/gpio.c [new file with mode: 0644]
arch/m68k/platform/5206e/Makefile [new file with mode: 0644]
arch/m68k/platform/5206e/config.c [new file with mode: 0644]
arch/m68k/platform/5206e/gpio.c [new file with mode: 0644]
arch/m68k/platform/520x/Makefile [new file with mode: 0644]
arch/m68k/platform/520x/config.c [new file with mode: 0644]
arch/m68k/platform/520x/gpio.c [new file with mode: 0644]
arch/m68k/platform/523x/Makefile [new file with mode: 0644]
arch/m68k/platform/523x/config.c [new file with mode: 0644]
arch/m68k/platform/523x/gpio.c [new file with mode: 0644]
arch/m68k/platform/5249/Makefile [new file with mode: 0644]
arch/m68k/platform/5249/config.c [new file with mode: 0644]
arch/m68k/platform/5249/gpio.c [new file with mode: 0644]
arch/m68k/platform/5249/intc2.c [new file with mode: 0644]
arch/m68k/platform/5272/Makefile [new file with mode: 0644]
arch/m68k/platform/5272/config.c [new file with mode: 0644]
arch/m68k/platform/5272/gpio.c [new file with mode: 0644]
arch/m68k/platform/5272/intc.c [new file with mode: 0644]
arch/m68k/platform/527x/Makefile [new file with mode: 0644]
arch/m68k/platform/527x/config.c [new file with mode: 0644]
arch/m68k/platform/527x/gpio.c [new file with mode: 0644]
arch/m68k/platform/528x/Makefile [new file with mode: 0644]
arch/m68k/platform/528x/config.c [new file with mode: 0644]
arch/m68k/platform/528x/gpio.c [new file with mode: 0644]
arch/m68k/platform/5307/Makefile [new file with mode: 0644]
arch/m68k/platform/5307/config.c [new file with mode: 0644]
arch/m68k/platform/5307/gpio.c [new file with mode: 0644]
arch/m68k/platform/5307/nettel.c [new file with mode: 0644]
arch/m68k/platform/532x/Makefile [new file with mode: 0644]
arch/m68k/platform/532x/config.c [new file with mode: 0644]
arch/m68k/platform/532x/gpio.c [new file with mode: 0644]
arch/m68k/platform/5407/Makefile [new file with mode: 0644]
arch/m68k/platform/5407/config.c [new file with mode: 0644]
arch/m68k/platform/5407/gpio.c [new file with mode: 0644]
arch/m68k/platform/54xx/Makefile [new file with mode: 0644]
arch/m68k/platform/54xx/config.c [new file with mode: 0644]
arch/m68k/platform/54xx/firebee.c [new file with mode: 0644]
arch/m68k/platform/68328/Makefile [new file with mode: 0644]
arch/m68k/platform/68328/bootlogo.h [new file with mode: 0644]
arch/m68k/platform/68328/bootlogo.pl [new file with mode: 0644]
arch/m68k/platform/68328/config.c [new file with mode: 0644]
arch/m68k/platform/68328/entry.S [new file with mode: 0644]
arch/m68k/platform/68328/head-de2.S [new file with mode: 0644]
arch/m68k/platform/68328/head-pilot.S [new file with mode: 0644]
arch/m68k/platform/68328/head-ram.S [new file with mode: 0644]
arch/m68k/platform/68328/head-rom.S [new file with mode: 0644]
arch/m68k/platform/68328/ints.c [new file with mode: 0644]
arch/m68k/platform/68328/romvec.S [new file with mode: 0644]
arch/m68k/platform/68328/timers.c [new file with mode: 0644]
arch/m68k/platform/68360/Makefile [new file with mode: 0644]
arch/m68k/platform/68360/commproc.c [new file with mode: 0644]
arch/m68k/platform/68360/config.c [new file with mode: 0644]
arch/m68k/platform/68360/entry.S [new file with mode: 0644]
arch/m68k/platform/68360/head-ram.S [new file with mode: 0644]
arch/m68k/platform/68360/head-rom.S [new file with mode: 0644]
arch/m68k/platform/68360/ints.c [new file with mode: 0644]
arch/m68k/platform/68EZ328/Makefile [new file with mode: 0644]
arch/m68k/platform/68EZ328/bootlogo.h [new file with mode: 0644]
arch/m68k/platform/68EZ328/config.c [new file with mode: 0644]
arch/m68k/platform/68VZ328/Makefile [new file with mode: 0644]
arch/m68k/platform/68VZ328/config.c [new file with mode: 0644]
arch/m68k/platform/Makefile [new file with mode: 0644]
arch/m68k/platform/coldfire/Makefile [new file with mode: 0644]
arch/m68k/platform/coldfire/cache.c [new file with mode: 0644]
arch/m68k/platform/coldfire/clk.c [new file with mode: 0644]
arch/m68k/platform/coldfire/dma.c [new file with mode: 0644]
arch/m68k/platform/coldfire/dma_timer.c [new file with mode: 0644]
arch/m68k/platform/coldfire/entry.S [new file with mode: 0644]
arch/m68k/platform/coldfire/gpio.c [new file with mode: 0644]
arch/m68k/platform/coldfire/head.S [new file with mode: 0644]
arch/m68k/platform/coldfire/intc-2.c [new file with mode: 0644]
arch/m68k/platform/coldfire/intc-simr.c [new file with mode: 0644]
arch/m68k/platform/coldfire/intc.c [new file with mode: 0644]
arch/m68k/platform/coldfire/pinmux.c [new file with mode: 0644]
arch/m68k/platform/coldfire/pit.c [new file with mode: 0644]
arch/m68k/platform/coldfire/sltimers.c [new file with mode: 0644]
arch/m68k/platform/coldfire/timers.c [new file with mode: 0644]
arch/m68k/platform/coldfire/vectors.c [new file with mode: 0644]
arch/m68knommu/Kconfig [deleted file]
arch/m68knommu/Kconfig.debug [deleted file]
arch/m68knommu/Makefile [deleted file]
arch/m68knommu/configs/m5208evb_defconfig [deleted file]
arch/m68knommu/configs/m5249evb_defconfig [deleted file]
arch/m68knommu/configs/m5272c3_defconfig [deleted file]
arch/m68knommu/configs/m5275evb_defconfig [deleted file]
arch/m68knommu/configs/m5307c3_defconfig [deleted file]
arch/m68knommu/configs/m5407c3_defconfig [deleted file]
arch/m68knommu/defconfig [deleted file]
arch/m68knommu/kernel/.gitignore [deleted file]
arch/m68knommu/kernel/Makefile [deleted file]
arch/m68knommu/kernel/asm-offsets.c [deleted file]
arch/m68knommu/kernel/dma.c [deleted file]
arch/m68knommu/kernel/entry.S [deleted file]
arch/m68knommu/kernel/init_task.c [deleted file]
arch/m68knommu/kernel/irq.c [deleted file]
arch/m68knommu/kernel/m68k_ksyms.c [deleted file]
arch/m68knommu/kernel/module.c [deleted file]
arch/m68knommu/kernel/process.c [deleted file]
arch/m68knommu/kernel/ptrace.c [deleted file]
arch/m68knommu/kernel/setup.c [deleted file]
arch/m68knommu/kernel/signal.c [deleted file]
arch/m68knommu/kernel/sys_m68k.c [deleted file]
arch/m68knommu/kernel/syscalltable.S [deleted file]
arch/m68knommu/kernel/time.c [deleted file]
arch/m68knommu/kernel/traps.c [deleted file]
arch/m68knommu/kernel/vmlinux.lds.S [deleted file]
arch/m68knommu/lib/Makefile [deleted file]
arch/m68knommu/lib/ashldi3.c [deleted file]
arch/m68knommu/lib/ashrdi3.c [deleted file]
arch/m68knommu/lib/checksum.c [deleted file]
arch/m68knommu/lib/delay.c [deleted file]
arch/m68knommu/lib/divsi3.S [deleted file]
arch/m68knommu/lib/lshrdi3.c [deleted file]
arch/m68knommu/lib/memcpy.c [deleted file]
arch/m68knommu/lib/memmove.c [deleted file]
arch/m68knommu/lib/memset.c [deleted file]
arch/m68knommu/lib/modsi3.S [deleted file]
arch/m68knommu/lib/muldi3.c [deleted file]
arch/m68knommu/lib/mulsi3.S [deleted file]
arch/m68knommu/lib/udivsi3.S [deleted file]
arch/m68knommu/lib/umodsi3.S [deleted file]
arch/m68knommu/mm/Makefile [deleted file]
arch/m68knommu/mm/init.c [deleted file]
arch/m68knommu/mm/kmap.c [deleted file]
arch/m68knommu/platform/5206/Makefile [deleted file]
arch/m68knommu/platform/5206/config.c [deleted file]
arch/m68knommu/platform/5206/gpio.c [deleted file]
arch/m68knommu/platform/5206e/Makefile [deleted file]
arch/m68knommu/platform/5206e/config.c [deleted file]
arch/m68knommu/platform/5206e/gpio.c [deleted file]
arch/m68knommu/platform/520x/Makefile [deleted file]
arch/m68knommu/platform/520x/config.c [deleted file]
arch/m68knommu/platform/520x/gpio.c [deleted file]
arch/m68knommu/platform/523x/Makefile [deleted file]
arch/m68knommu/platform/523x/config.c [deleted file]
arch/m68knommu/platform/523x/gpio.c [deleted file]
arch/m68knommu/platform/5249/Makefile [deleted file]
arch/m68knommu/platform/5249/config.c [deleted file]
arch/m68knommu/platform/5249/gpio.c [deleted file]
arch/m68knommu/platform/5249/intc2.c [deleted file]
arch/m68knommu/platform/5272/Makefile [deleted file]
arch/m68knommu/platform/5272/config.c [deleted file]
arch/m68knommu/platform/5272/gpio.c [deleted file]
arch/m68knommu/platform/5272/intc.c [deleted file]
arch/m68knommu/platform/527x/Makefile [deleted file]
arch/m68knommu/platform/527x/config.c [deleted file]
arch/m68knommu/platform/527x/gpio.c [deleted file]
arch/m68knommu/platform/528x/Makefile [deleted file]
arch/m68knommu/platform/528x/config.c [deleted file]
arch/m68knommu/platform/528x/gpio.c [deleted file]
arch/m68knommu/platform/5307/Makefile [deleted file]
arch/m68knommu/platform/5307/config.c [deleted file]
arch/m68knommu/platform/5307/gpio.c [deleted file]
arch/m68knommu/platform/5307/nettel.c [deleted file]
arch/m68knommu/platform/532x/Makefile [deleted file]
arch/m68knommu/platform/532x/config.c [deleted file]
arch/m68knommu/platform/532x/gpio.c [deleted file]
arch/m68knommu/platform/5407/Makefile [deleted file]
arch/m68knommu/platform/5407/config.c [deleted file]
arch/m68knommu/platform/5407/gpio.c [deleted file]
arch/m68knommu/platform/54xx/Makefile [deleted file]
arch/m68knommu/platform/54xx/config.c [deleted file]
arch/m68knommu/platform/54xx/firebee.c [deleted file]
arch/m68knommu/platform/68328/Makefile [deleted file]
arch/m68knommu/platform/68328/bootlogo.h [deleted file]
arch/m68knommu/platform/68328/bootlogo.pl [deleted file]
arch/m68knommu/platform/68328/config.c [deleted file]
arch/m68knommu/platform/68328/entry.S [deleted file]
arch/m68knommu/platform/68328/head-de2.S [deleted file]
arch/m68knommu/platform/68328/head-pilot.S [deleted file]
arch/m68knommu/platform/68328/head-ram.S [deleted file]
arch/m68knommu/platform/68328/head-rom.S [deleted file]
arch/m68knommu/platform/68328/ints.c [deleted file]
arch/m68knommu/platform/68328/romvec.S [deleted file]
arch/m68knommu/platform/68328/timers.c [deleted file]
arch/m68knommu/platform/68360/Makefile [deleted file]
arch/m68knommu/platform/68360/commproc.c [deleted file]
arch/m68knommu/platform/68360/config.c [deleted file]
arch/m68knommu/platform/68360/entry.S [deleted file]
arch/m68knommu/platform/68360/head-ram.S [deleted file]
arch/m68knommu/platform/68360/head-rom.S [deleted file]
arch/m68knommu/platform/68360/ints.c [deleted file]
arch/m68knommu/platform/68EZ328/Makefile [deleted file]
arch/m68knommu/platform/68EZ328/bootlogo.h [deleted file]
arch/m68knommu/platform/68EZ328/config.c [deleted file]
arch/m68knommu/platform/68VZ328/Makefile [deleted file]
arch/m68knommu/platform/68VZ328/config.c [deleted file]
arch/m68knommu/platform/Makefile [deleted file]
arch/m68knommu/platform/coldfire/Makefile [deleted file]
arch/m68knommu/platform/coldfire/cache.c [deleted file]
arch/m68knommu/platform/coldfire/clk.c [deleted file]
arch/m68knommu/platform/coldfire/dma.c [deleted file]
arch/m68knommu/platform/coldfire/dma_timer.c [deleted file]
arch/m68knommu/platform/coldfire/entry.S [deleted file]
arch/m68knommu/platform/coldfire/gpio.c [deleted file]
arch/m68knommu/platform/coldfire/head.S [deleted file]
arch/m68knommu/platform/coldfire/intc-2.c [deleted file]
arch/m68knommu/platform/coldfire/intc-simr.c [deleted file]
arch/m68knommu/platform/coldfire/intc.c [deleted file]
arch/m68knommu/platform/coldfire/pinmux.c [deleted file]
arch/m68knommu/platform/coldfire/pit.c [deleted file]
arch/m68knommu/platform/coldfire/sltimers.c [deleted file]
arch/m68knommu/platform/coldfire/timers.c [deleted file]
arch/m68knommu/platform/coldfire/vectors.c [deleted file]
arch/microblaze/Kconfig
arch/microblaze/kernel/cpu/Makefile
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/common/irq.c
arch/mips/alchemy/devboards/bcsr.c
arch/mips/ar7/irq.c
arch/mips/ath79/irq.c
arch/mips/bcm63xx/boards/Makefile
arch/mips/bcm63xx/irq.c
arch/mips/dec/ioasic-irq.c
arch/mips/dec/kn02-irq.c
arch/mips/emma/markeins/irq.c
arch/mips/fw/arc/Makefile
arch/mips/include/asm/bitops.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h [new file with mode: 0644]
arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h [new file with mode: 0644]
arch/mips/include/asm/spinlock.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/types.h
arch/mips/include/asm/unistd.h
arch/mips/jazz/irq.c
arch/mips/jz4740/Makefile
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/gpio.c
arch/mips/jz4740/irq.c
arch/mips/kernel/i8259.c
arch/mips/kernel/irq-gic.c
arch/mips/kernel/irq-gt641xx.c
arch/mips/kernel/irq-msc01.c
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/irq_txx9.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smtc.c
arch/mips/lasat/interrupt.c
arch/mips/loongson/common/bonito-irq.c
arch/mips/mipssim/sim_smtc.c
arch/mips/mti-malta/malta-smtc.c
arch/mips/oprofile/Makefile
arch/mips/pmc-sierra/Kconfig
arch/mips/pmc-sierra/msp71xx/Makefile
arch/mips/pmc-sierra/msp71xx/msp_eth.c [new file with mode: 0644]
arch/mips/pmc-sierra/msp71xx/msp_irq.c
arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
arch/mips/pmc-sierra/msp71xx/msp_irq_per.c [new file with mode: 0644]
arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c
arch/mips/pmc-sierra/msp71xx/msp_setup.c
arch/mips/pmc-sierra/msp71xx/msp_smp.c [new file with mode: 0644]
arch/mips/pmc-sierra/msp71xx/msp_smtc.c [new file with mode: 0644]
arch/mips/pmc-sierra/msp71xx/msp_time.c
arch/mips/pmc-sierra/msp71xx/msp_usb.c
arch/mips/pmc-sierra/yosemite/Makefile
arch/mips/pnx833x/common/interrupts.c
arch/mips/pnx8550/common/int.c
arch/mips/powertv/Makefile
arch/mips/powertv/asic/Makefile
arch/mips/powertv/asic/irq_asic.c
arch/mips/powertv/pci/Makefile
arch/mips/rb532/irq.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sni/a20r.c
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/txx9/generic/irq_tx4939.c
arch/mips/txx9/jmr3927/irq.c
arch/mips/txx9/rbtx4927/irq.c
arch/mips/txx9/rbtx4938/irq.c
arch/mips/txx9/rbtx4939/irq.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/irq.c
arch/mn10300/Kconfig
arch/mn10300/Kconfig.debug
arch/mn10300/include/asm/bitops.h
arch/mn10300/include/asm/debugger.h [new file with mode: 0644]
arch/mn10300/include/asm/div64.h
arch/mn10300/include/asm/fpu.h
arch/mn10300/include/asm/intctl-regs.h
arch/mn10300/include/asm/irqflags.h
arch/mn10300/include/asm/kgdb.h [new file with mode: 0644]
arch/mn10300/include/asm/smp.h
arch/mn10300/include/asm/thread_info.h
arch/mn10300/include/asm/types.h
arch/mn10300/kernel/Makefile
arch/mn10300/kernel/cevt-mn10300.c
arch/mn10300/kernel/csrc-mn10300.c
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/fpu.c
arch/mn10300/kernel/gdb-cache.S [deleted file]
arch/mn10300/kernel/gdb-io-ttysm.c
arch/mn10300/kernel/gdb-stub.c
arch/mn10300/kernel/internal.h
arch/mn10300/kernel/irq.c
arch/mn10300/kernel/kgdb.c [new file with mode: 0644]
arch/mn10300/kernel/mn10300-serial.c
arch/mn10300/kernel/process.c
arch/mn10300/kernel/smp.c
arch/mn10300/kernel/switch_to.S
arch/mn10300/kernel/time.c
arch/mn10300/kernel/traps.c
arch/mn10300/mm/Kconfig.cache
arch/mn10300/mm/Makefile
arch/mn10300/mm/cache-dbg-flush-by-reg.S [new file with mode: 0644]
arch/mn10300/mm/cache-dbg-flush-by-tag.S [new file with mode: 0644]
arch/mn10300/mm/cache-dbg-inv-by-reg.S [new file with mode: 0644]
arch/mn10300/mm/cache-dbg-inv-by-tag.S [new file with mode: 0644]
arch/mn10300/mm/cache-dbg-inv.S [new file with mode: 0644]
arch/mn10300/mm/cache-flush-by-tag.S
arch/mn10300/mm/cache-inv-by-reg.S
arch/mn10300/mm/cache-inv-by-tag.S
arch/mn10300/mm/cache.inc [new file with mode: 0644]
arch/mn10300/mm/fault.c
arch/mn10300/proc-mn103e010/include/proc/cache.h
arch/mn10300/proc-mn2ws0050/include/proc/cache.h
arch/mn10300/unit-asb2364/include/unit/fpga-regs.h
arch/mn10300/unit-asb2364/include/unit/serial.h
arch/mn10300/unit-asb2364/irq-fpga.c
arch/mn10300/unit-asb2364/unit-init.c
arch/parisc/Kconfig
arch/parisc/include/asm/bitops.h
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/irq.h
arch/parisc/include/asm/pgtable.h
arch/parisc/include/asm/types.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/irq.c
arch/parisc/kernel/pacache.S
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/types.h
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/pci_dn.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/vdso.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/xmon/xmon.c
arch/s390/boot/Makefile
arch/s390/include/asm/bitops.h
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/ccwgroup.h
arch/s390/include/asm/cmpxchg.h [new file with mode: 0644]
arch/s390/include/asm/system.h
arch/s390/include/asm/types.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/early.c
arch/s390/kernel/setup.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/vdso.c
arch/s390/kvm/Makefile
arch/s390/math-emu/Makefile
arch/s390/oprofile/Makefile
arch/s390/oprofile/init.c
arch/score/include/asm/thread_info.h
arch/sh/Kconfig
arch/sh/boards/board-edosk7760.c
arch/sh/boot/romimage/mmcif-sh7724.c
arch/sh/include/asm/bitops.h
arch/sh/include/asm/sizes.h
arch/sh/include/asm/thread_info.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/kernel/crash_dump.c
arch/sh/kernel/process.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/ptrace_64.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/vsyscall/vsyscall.c
arch/sh/mm/pmb.c
arch/sparc/Kconfig
arch/sparc/include/asm/bitops_32.h
arch/sparc/include/asm/bitops_64.h
arch/sparc/include/asm/irq_32.h
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/thread_info_32.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/types.h
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/of_device_common.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/time_32.c
arch/sparc/mm/init_32.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/tile/include/asm/bitops.h
arch/tile/include/asm/thread_info.h
arch/tile/kernel/process.c
arch/tile/lib/atomic_32.c
arch/tile/mm/pgtable.c
arch/um/Kconfig.common
arch/um/drivers/line.c
arch/um/include/asm/processor-generic.h
arch/um/include/shared/line.h
arch/um/kernel/irq.c
arch/um/sys-i386/asm/elf.h
arch/um/sys-ppc/Makefile
arch/um/sys-x86_64/asm/elf.h
arch/unicore32/mm/init.c
arch/x86/Kconfig
arch/x86/ia32/ia32_aout.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/acpi.h
arch/x86/include/asm/bitops.h
arch/x86/include/asm/dma.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/types.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.h
arch/x86/kernel/cpu/mcheck/mce-apei.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/crash_dump_32.c
arch/x86/kernel/crash_dump_64.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/e820.c
arch/x86/kernel/head64.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/process_64.c
arch/x86/kernel/setup.c
arch/x86/kernel/syscall_table_32.S
arch/x86/mm/init_64.c
arch/x86/platform/olpc/olpc-xo1.c
arch/x86/vdso/vdso32-setup.c
arch/x86/xen/mmu.c
arch/xtensa/Kconfig
arch/xtensa/boot/Makefile
arch/xtensa/boot/lib/Makefile
arch/xtensa/include/asm/bitops.h
arch/xtensa/include/asm/types.h
arch/xtensa/kernel/irq.c
arch/xtensa/platforms/s6105/device.c
arch/xtensa/variants/s6000/gpio.c
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-lib.c
block/blk-merge.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-throttle.c
block/blk.h
block/cfq-iosched.c
block/cfq.h
block/deadline-iosched.c
block/elevator.c
block/genhd.c
block/noop-iosched.c
crypto/deflate.c
crypto/zlib.c
drivers/acpi/acpi_pad.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/dsargs.c [new file with mode: 0644]
drivers/acpi/acpica/dscontrol.c [new file with mode: 0644]
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c [new file with mode: 0644]
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/utdecode.c [new file with mode: 0644]
drivers/acpi/acpica/utglobal.c
drivers/acpi/apei/Kconfig
drivers/acpi/apei/cper.c
drivers/acpi/apei/erst-dbg.c
drivers/acpi/apei/erst.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/ec_sys.c
drivers/acpi/internal.h
drivers/acpi/nvs.c
drivers/acpi/osl.c
drivers/acpi/pci_link.c
drivers/acpi/pci_root.c
drivers/acpi/processor_core.c
drivers/acpi/processor_driver.c
drivers/acpi/reboot.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/video.c
drivers/block/DAC960.c
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_worker.c
drivers/block/drbd/drbd_wrappers.h
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/paride/pf.c
drivers/block/pktcdvd.c
drivers/block/rbd.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/ub.c
drivers/block/umem.c
drivers/block/xsysace.c
drivers/cdrom/gdrom.c
drivers/cdrom/viocd.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mem.c
drivers/char/msm_smd_pkt.c [new file with mode: 0644]
drivers/char/mwave/Makefile
drivers/char/mwave/README
drivers/dca/dca-core.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/dmatest.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/fsldma.c
drivers/dma/fsldma.h
drivers/dma/mxs-dma.c [new file with mode: 0644]
drivers/dma/pch_dma.c
drivers/dma/ste_dma40.c
drivers/dma/ste_dma40_ll.c
drivers/dma/ste_dma40_ll.h
drivers/dma/timb_dma.c
drivers/firewire/Kconfig
drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/core-device.c
drivers/firewire/core-iso.c
drivers/firewire/core-topology.c
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/sigma.c [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/adp5588-gpio.c
drivers/gpio/gpiolib.c
drivers/gpio/janz-ttl.c
drivers/gpio/max732x.c
drivers/gpio/pca953x.c
drivers/gpio/pl061.c
drivers/gpio/rdc321x-gpio.c
drivers/gpio/sch_gpio.c
drivers/gpio/stmpe-gpio.c
drivers/gpio/sx150x.c
drivers/gpio/tc3589x-gpio.c
drivers/gpio/timbgpio.c
drivers/gpio/vr41xx_giu.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/nouveau/nouveau_backlight.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/radeon/Kconfig
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-picolcd.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/ads1015.c [new file with mode: 0644]
drivers/hwmon/hp_accel.c [deleted file]
drivers/hwmon/jz4740-hwmon.c
drivers/hwmon/lis3lv02d.c [deleted file]
drivers/hwmon/lis3lv02d.h [deleted file]
drivers/hwmon/lis3lv02d_i2c.c [deleted file]
drivers/hwmon/lis3lv02d_spi.c [deleted file]
drivers/hwmon/lm75.c
drivers/hwmon/sch5627.c [new file with mode: 0644]
drivers/hwmon/sht15.c
drivers/hwmon/twl4030-madc-hwmon.c [new file with mode: 0644]
drivers/i2c/Makefile
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-diolan-u2c.c [new file with mode: 0644]
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-pxa-pci.c [new file with mode: 0644]
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/i2c-boardinfo.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/ide/Makefile
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-cd_ioctl.c
drivers/ide/ide-gd.c
drivers/ide/ide-io.c
drivers/ide/ide-park.c
drivers/idle/intel_idle.c
drivers/ieee802154/Makefile
drivers/infiniband/core/addr.c
drivers/infiniband/core/agent.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/evdev.c
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/qt1070.c [new file with mode: 0644]
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/misc/88pm860x_onkey.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/adxl34x-spi.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/twl4030-vibra.c
drivers/input/misc/uinput.c
drivers/input/misc/xen-kbdfront.c [new file with mode: 0644]
drivers/input/mouse/bcm5974.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/sparse-keymap.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ad7879-spi.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_mxt_ts.c [new file with mode: 0644]
drivers/input/touchscreen/qt602240_ts.c [deleted file]
drivers/input/touchscreen/tsc2005.c [new file with mode: 0644]
drivers/input/touchscreen/wm831x-ts.c [new file with mode: 0644]
drivers/input/xen-kbdfront.c [deleted file]
drivers/isdn/hisax/Makefile
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-triggers.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-lm3530.c [new file with mode: 0644]
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-net5501.c
drivers/macintosh/via-pmu-backlight.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/bitmap.c
drivers/md/dm-crypt.c
drivers/md/dm-flakey.c [new file with mode: 0644]
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/Kconfig
drivers/media/Makefile
drivers/media/common/tuners/tda9887.c
drivers/media/common/tuners/tea5761.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/dvb/Kconfig
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/dib0700.h
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/technisat-usb2.c [new file with mode: 0644]
drivers/media/dvb/firewire/Kconfig
drivers/media/dvb/firewire/Makefile
drivers/media/dvb/firewire/firedtv-1394.c [deleted file]
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/firewire/firedtv-dvb.c
drivers/media/dvb/firewire/firedtv-fe.c
drivers/media/dvb/firewire/firedtv-fw.c
drivers/media/dvb/firewire/firedtv.h
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/dib0090.c
drivers/media/dvb/frontends/dib0090.h
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/dib8000.c
drivers/media/dvb/frontends/dib8000.h
drivers/media/dvb/frontends/dib9000.c [new file with mode: 0644]
drivers/media/dvb/frontends/dib9000.h [new file with mode: 0644]
drivers/media/dvb/frontends/dibx000_common.c
drivers/media/dvb/frontends/dibx000_common.h
drivers/media/dvb/frontends/ds3000.c
drivers/media/dvb/frontends/ds3000.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/stv0367.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv0367.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0367_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0367_regs.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv0900.h
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv090x.c
drivers/media/dvb/frontends/stv090x.h
drivers/media/dvb/frontends/stv090x_reg.h
drivers/media/dvb/frontends/zl10036.c
drivers/media/dvb/ngene/Makefile
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/ngene/ngene-core.c
drivers/media/dvb/ngene/ngene-dvb.c
drivers/media/dvb/ngene/ngene.h
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/media-device.c [new file with mode: 0644]
drivers/media/media-devnode.c [new file with mode: 0644]
drivers/media/media-entity.c [new file with mode: 0644]
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-si4713.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/wl128x/Kconfig [new file with mode: 0644]
drivers/media/radio/wl128x/Makefile [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv.h [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_common.c [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_common.h [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_rx.c [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_rx.h [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_tx.c [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_tx.h [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_v4l2.c [new file with mode: 0644]
drivers/media/radio/wl128x/fmdrv_v4l2.h [new file with mode: 0644]
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/imon.c
drivers/media/rc/ir-nec-decoder.c
drivers/media/rc/ite-cir.c [new file with mode: 0644]
drivers/media/rc/ite-cir.h [new file with mode: 0644]
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
drivers/media/rc/keymaps/rc-avermedia-dvbt.c
drivers/media/rc/keymaps/rc-avermedia-m135a.c
drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
drivers/media/rc/keymaps/rc-behold-columbus.c
drivers/media/rc/keymaps/rc-behold.c
drivers/media/rc/keymaps/rc-budget-ci-old.c
drivers/media/rc/keymaps/rc-cinergy.c
drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
drivers/media/rc/keymaps/rc-encore-enltv.c
drivers/media/rc/keymaps/rc-encore-enltv2.c
drivers/media/rc/keymaps/rc-flydvb.c
drivers/media/rc/keymaps/rc-hauppauge-new.c [deleted file]
drivers/media/rc/keymaps/rc-hauppauge.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-imon-mce.c
drivers/media/rc/keymaps/rc-imon-pad.c
drivers/media/rc/keymaps/rc-kworld-315u.c
drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
drivers/media/rc/keymaps/rc-lme2510.c
drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
drivers/media/rc/keymaps/rc-nebula.c
drivers/media/rc/keymaps/rc-norwood.c
drivers/media/rc/keymaps/rc-pctv-sedna.c
drivers/media/rc/keymaps/rc-pixelview-mk12.c
drivers/media/rc/keymaps/rc-pixelview-new.c
drivers/media/rc/keymaps/rc-pixelview.c
drivers/media/rc/keymaps/rc-pv951.c
drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c [deleted file]
drivers/media/rc/keymaps/rc-rc5-tv.c [deleted file]
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
drivers/media/rc/keymaps/rc-technisat-usb2.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-terratec-slim-2.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-winfast.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7343.c
drivers/media/video/adv7343_regs.h
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt819.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cs5345.c
drivers/media/video/cx18/cx18-av-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-controls.h
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-mailbox.h
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx231xx/cx231xx-417.c
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-i2c.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/Kconfig
drivers/media/video/cx23885/Makefile
drivers/media/video/cx23885/altera-ci.c [new file with mode: 0644]
drivers/media/video/cx23885/altera-ci.h [new file with mode: 0644]
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx23885/cx23885-reg.h
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/vpfe_capture.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/autogain_functions.h [new file with mode: 0644]
drivers/media/video/gspca/cpia1.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/jeilinj.c
drivers/media/video/gspca/nw80x.c [new file with mode: 0644]
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/vicam.c [new file with mode: 0644]
drivers/media/video/gspca/zc3xx-reg.h
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-i2c.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-udma.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtv-yuv.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/meye.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9v022.c
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/noon010pc30.c [new file with mode: 0644]
drivers/media/video/omap1_camera.c
drivers/media/video/omap24xxcam.c
drivers/media/video/omap3isp/Makefile [new file with mode: 0644]
drivers/media/video/omap3isp/cfa_coef_table.h [new file with mode: 0644]
drivers/media/video/omap3isp/gamma_table.h [new file with mode: 0644]
drivers/media/video/omap3isp/isp.c [new file with mode: 0644]
drivers/media/video/omap3isp/isp.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispccdc.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispccdc.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispccp2.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispccp2.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispcsi2.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispcsi2.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispcsiphy.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispcsiphy.h [new file with mode: 0644]
drivers/media/video/omap3isp/isph3a.h [new file with mode: 0644]
drivers/media/video/omap3isp/isph3a_aewb.c [new file with mode: 0644]
drivers/media/video/omap3isp/isph3a_af.c [new file with mode: 0644]
drivers/media/video/omap3isp/isphist.c [new file with mode: 0644]
drivers/media/video/omap3isp/isphist.h [new file with mode: 0644]
drivers/media/video/omap3isp/isppreview.c [new file with mode: 0644]
drivers/media/video/omap3isp/isppreview.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispqueue.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispqueue.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispreg.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispresizer.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispresizer.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispstat.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispstat.h [new file with mode: 0644]
drivers/media/video/omap3isp/ispvideo.c [new file with mode: 0644]
drivers/media/video/omap3isp/ispvideo.h [new file with mode: 0644]
drivers/media/video/omap3isp/luma_enhance_table.h [new file with mode: 0644]
drivers/media/video/omap3isp/noise_filter_table.h [new file with mode: 0644]
drivers/media/video/ov6650.c
drivers/media/video/ov9740.c [new file with mode: 0644]
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-reg.c
drivers/media/video/s5p-fimc/regs-fimc.h
drivers/media/video/saa7110.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/saa7164-api.c
drivers/media/video/saa7164/saa7164-buffer.c
drivers/media/video/saa7164/saa7164-bus.c
drivers/media/video/saa7164/saa7164-cmd.c
drivers/media/video/saa7164/saa7164-core.c
drivers/media/video/saa7164/saa7164-dvb.c
drivers/media/video/saa7164/saa7164-encoder.c
drivers/media/video/saa7164/saa7164-fw.c
drivers/media/video/saa7164/saa7164-vbi.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_mediabus.c
drivers/media/video/timblogiw.c
drivers/media/video/tlg2300/pd-video.c
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp7002.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-fh.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-mem2mem.c
drivers/media/video/v4l2-subdev.c [new file with mode: 0644]
drivers/media/video/via-camera.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf2-core.c [new file with mode: 0644]
drivers/media/video/videobuf2-dma-contig.c [new file with mode: 0644]
drivers/media/video/videobuf2-dma-sg.c [new file with mode: 0644]
drivers/media/video/videobuf2-memops.c [new file with mode: 0644]
drivers/media/video/videobuf2-vmalloc.c [new file with mode: 0644]
drivers/media/video/vivi.c
drivers/media/video/vpx3220.c
drivers/media/video/wm8775.c
drivers/memstick/Makefile
drivers/memstick/core/Makefile
drivers/memstick/host/Kconfig
drivers/memstick/host/Makefile
drivers/memstick/host/r592.c [new file with mode: 0644]
drivers/memstick/host/r592.h [new file with mode: 0644]
drivers/message/fusion/Makefile
drivers/message/i2o/i2o_block.c
drivers/mfd/88pm860x-core.c
drivers/mfd/88pm860x-i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab3100-core.c
drivers/mfd/ab3550-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c [new file with mode: 0644]
drivers/mfd/ab8500-sysctrl.c [new file with mode: 0644]
drivers/mfd/adp5520.c
drivers/mfd/asic3.c
drivers/mfd/cs5535-mfd.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/htc-pasic3.c
drivers/mfd/janz-cmodio.c
drivers/mfd/jz4740-adc.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8997.c [new file with mode: 0644]
drivers/mfd/max8998.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mfd-core.c
drivers/mfd/pcf50633-core.c
drivers/mfd/rdc321x-southbridge.c
drivers/mfd/sh_mobile_sdhi.c
drivers/mfd/sm501.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/timberdale.c
drivers/mfd/tps6105x.c [new file with mode: 0644]
drivers/mfd/tps6586x.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-codec.c
drivers/mfd/twl4030-madc.c [new file with mode: 0644]
drivers/mfd/ucb1x00-ts.c
drivers/mfd/vx855.c
drivers/mfd/wl1273-core.c
drivers/mfd/wm831x-i2c.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8400-core.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/apds9802als.c
drivers/misc/atmel_tclib.c
drivers/misc/bh1780gli.c
drivers/misc/bmp085.c
drivers/misc/cb710/Makefile
drivers/misc/ep93xx_pwm.c
drivers/misc/hmc6352.c
drivers/misc/lis3lv02d/Kconfig [new file with mode: 0644]
drivers/misc/lis3lv02d/Makefile [new file with mode: 0644]
drivers/misc/lis3lv02d/lis3lv02d.c [new file with mode: 0644]
drivers/misc/lis3lv02d/lis3lv02d.h [new file with mode: 0644]
drivers/misc/lis3lv02d/lis3lv02d_i2c.c [new file with mode: 0644]
drivers/misc/lis3lv02d/lis3lv02d_spi.c [new file with mode: 0644]
drivers/misc/pch_phub.c
drivers/misc/sgi-gru/Makefile
drivers/misc/spear13xx_pcie_gadget.c [new file with mode: 0644]
drivers/mmc/card/Kconfig
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/Makefile
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/quirks.c [new file with mode: 0644]
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c [new file with mode: 0644]
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/via-sdmmc.c
drivers/mtd/nand/tmio_nand.c
drivers/mtd/ubi/io.c
drivers/net/caif/Makefile
drivers/net/can/janz-ican3.c
drivers/net/ks8842.c
drivers/net/mlx4/main.c
drivers/net/ppp_deflate.c
drivers/net/rionet.c
drivers/net/skfp/Makefile
drivers/net/wan/lmc/Makefile
drivers/net/wireless/hostap/hostap_config.h
drivers/net/wireless/zd1211rw/Makefile
drivers/of/base.c
drivers/of/fdt.c
drivers/of/platform.c
drivers/parisc/dino.c
drivers/parisc/eisa.c
drivers/parisc/gsc.c
drivers/parisc/iosapic.c
drivers/parisc/superio.c
drivers/pci/pci-acpi.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_errprint.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv_core.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/hp_accel.c [new file with mode: 0644]
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/pnp/base.h
drivers/pnp/manager.c
drivers/pnp/resource.c
drivers/power/Kconfig
drivers/power/bq20z75.c
drivers/power/bq27x00_battery.c
drivers/power/ds2782_battery.c
drivers/power/jz4740-battery.c
drivers/power/power_supply_core.c
drivers/power/power_supply_leds.c
drivers/power/power_supply_sysfs.c
drivers/power/s3c_adc_battery.c
drivers/power/twl4030_charger.c
drivers/power/z2_battery.c
drivers/pps/clients/Makefile
drivers/pps/generators/pps_gen_parport.c
drivers/rapidio/Makefile
drivers/rapidio/rio-scan.c
drivers/rapidio/rio-sysfs.c
drivers/rapidio/rio.c
drivers/rapidio/switches/Makefile
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/ab3100.c
drivers/regulator/max8997.c [new file with mode: 0644]
drivers/regulator/mc13783-regulator.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/tps6105x-regulator.c [new file with mode: 0644]
drivers/regulator/twl-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-isl1208.c
drivers/rtc/rtc-tegra.c [new file with mode: 0644]
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/char/con3215.c
drivers/s390/char/raw3270.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_block.c
drivers/s390/char/vmur.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/qdio_main.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_ccw.c
drivers/scsi/aacraid/Makefile
drivers/scsi/aic94xx/Makefile
drivers/scsi/libsas/Makefile
drivers/scsi/lpfc/Makefile
drivers/scsi/mvsas/Makefile
drivers/scsi/pcmcia/Makefile
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/sd.c
drivers/sh/clk/core.c
drivers/sh/intc/core.c
drivers/sh/intc/internals.h
drivers/spi/amba-pl022.c
drivers/spi/omap2_mcspi.c
drivers/spi/xilinx_spi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/altera-stapl/Kconfig [new file with mode: 0644]
drivers/staging/altera-stapl/Makefile [new file with mode: 0644]
drivers/staging/altera-stapl/altera-comp.c [new file with mode: 0644]
drivers/staging/altera-stapl/altera-exprt.h [new file with mode: 0644]
drivers/staging/altera-stapl/altera-jtag.c [new file with mode: 0644]
drivers/staging/altera-stapl/altera-jtag.h [new file with mode: 0644]
drivers/staging/altera-stapl/altera-lpt.c [new file with mode: 0644]
drivers/staging/altera-stapl/altera.c [new file with mode: 0644]
drivers/staging/cx25821/Kconfig
drivers/staging/cx25821/cx25821-alsa.c
drivers/staging/cx25821/cx25821-core.c
drivers/staging/cx25821/cx25821-video.c
drivers/staging/cx25821/cx25821.h
drivers/staging/cxd2099/Kconfig [new file with mode: 0644]
drivers/staging/cxd2099/Makefile [new file with mode: 0644]
drivers/staging/cxd2099/TODO [new file with mode: 0644]
drivers/staging/cxd2099/cxd2099.c [new file with mode: 0644]
drivers/staging/cxd2099/cxd2099.h [new file with mode: 0644]
drivers/staging/dabusb/Kconfig [deleted file]
drivers/staging/dabusb/Makefile [deleted file]
drivers/staging/dabusb/TODO [deleted file]
drivers/staging/dabusb/dabusb.c [deleted file]
drivers/staging/dabusb/dabusb.h [deleted file]
drivers/staging/easycap/easycap_ioctl.c
drivers/staging/hv/blkvsc_drv.c
drivers/staging/lirc/Kconfig
drivers/staging/lirc/Makefile
drivers/staging/lirc/TODO.lirc_zilog
drivers/staging/lirc/lirc_imon.c
drivers/staging/lirc/lirc_it87.c [deleted file]
drivers/staging/lirc/lirc_it87.h [deleted file]
drivers/staging/lirc/lirc_ite8709.c [deleted file]
drivers/staging/lirc/lirc_sasem.c
drivers/staging/lirc/lirc_zilog.c
drivers/staging/olpc_dcon/olpc_dcon.c
drivers/staging/samsung-laptop/samsung-laptop.c
drivers/staging/se401/Kconfig [deleted file]
drivers/staging/se401/Makefile [deleted file]
drivers/staging/se401/TODO [deleted file]
drivers/staging/se401/se401.c [deleted file]
drivers/staging/se401/se401.h [deleted file]
drivers/staging/se401/videodev.h [deleted file]
drivers/staging/tm6000/tm6000-alsa.c
drivers/staging/tm6000/tm6000-cards.c
drivers/staging/tm6000/tm6000-core.c
drivers/staging/tm6000/tm6000-regs.h
drivers/staging/tm6000/tm6000-stds.c
drivers/staging/tm6000/tm6000-video.c
drivers/staging/tm6000/tm6000.h
drivers/staging/tty/specialix.c
drivers/staging/usbvideo/Kconfig [deleted file]
drivers/staging/usbvideo/Makefile [deleted file]
drivers/staging/usbvideo/TODO [deleted file]
drivers/staging/usbvideo/usbvideo.c [deleted file]
drivers/staging/usbvideo/usbvideo.h [deleted file]
drivers/staging/usbvideo/vicam.c [deleted file]
drivers/staging/usbvideo/videodev.h [deleted file]
drivers/staging/westbridge/astoria/block/cyasblkdev_block.c
drivers/target/target_core_iblock.c
drivers/thermal/thermal_sys.c
drivers/tty/bfin_jtag_comm.c
drivers/tty/sysrq.c
drivers/tty/tty_buffer.c
drivers/tty/tty_ldisc.c
drivers/tty/vt/keyboard.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/host/ehci-q.c
drivers/usb/host/ohci-tmio.c
drivers/usb/misc/appledisplay.c
drivers/usb/misc/uss720.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/musb_gadget.c
drivers/usb/serial/usb_wwan.c
drivers/video/amba-clcd.c
drivers/video/arkfb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_backlight.c
drivers/video/aty/radeon_base.c
drivers/video/aty/radeon_i2c.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adx_bl.c
drivers/video/backlight/apple_bl.c [new file with mode: 0644]
drivers/video/backlight/atmel-pwm-bl.c
drivers/video/backlight/backlight.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/ep93xx_bl.c
drivers/video/backlight/generic_bl.c
drivers/video/backlight/hp680_bl.c
drivers/video/backlight/jornada720_bl.c
drivers/video/backlight/jornada720_lcd.c
drivers/video/backlight/kb3886_bl.c
drivers/video/backlight/ld9040.c [new file with mode: 0644]
drivers/video/backlight/ld9040_gamma.h [new file with mode: 0644]
drivers/video/backlight/locomolcd.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/mbp_nvidia_bl.c [deleted file]
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/pcf50633-backlight.c
drivers/video/backlight/progear_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/wm831x_bl.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/cg14.c
drivers/video/cg6.c
drivers/video/console/fbcon.c
drivers/video/console/tileblit.c
drivers/video/edid.h
drivers/video/ffb.c
drivers/video/hecubafb.c
drivers/video/hpfb.c
drivers/video/imxfb.c
drivers/video/intelfb/Makefile
drivers/video/matrox/matroxfb_base.c
drivers/video/metronomefb.c
drivers/video/nvidia/nv_backlight.c
drivers/video/omap/Kconfig
drivers/video/omap/blizzard.c
drivers/video/omap/hwa742.c
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/Makefile
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-lgphilips-lb035q02.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/Makefile
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c [new file with mode: 0644]
drivers/video/omap2/dss/hdmi.h [new file with mode: 0644]
drivers/video/omap2/dss/hdmi_omap4_panel.c [new file with mode: 0644]
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/Kconfig
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/riva/fbdev.c
drivers/video/s3c-fb.c
drivers/video/s3fb.c
drivers/video/sh7760fb.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sis/sis.h
drivers/video/sis/sis_main.c
drivers/video/sis/vgatypes.h
drivers/video/sm501fb.c
drivers/video/svgalib.c
drivers/video/tcx.c
drivers/video/tmiofb.c
drivers/video/uvesafb.c
drivers/video/vermilion/vermilion.c
drivers/video/vesafb.c
drivers/video/via/viafbdev.h
drivers/video/vt8623fb.c
drivers/w1/masters/ds1wm.c
drivers/watchdog/rdc321x_wdt.c
fs/9p/acl.c
fs/9p/fid.c
fs/9p/v9fs.h
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/vfs_super.c
fs/adfs/adfs.h
fs/adfs/dir_f.c
fs/adfs/dir_fplus.c
fs/adfs/inode.c
fs/adfs/super.c
fs/affs/Makefile
fs/affs/file.c
fs/aio.c
fs/attr.c
fs/autofs4/autofs_i.h
fs/autofs4/dev-ioctl.c
fs/autofs4/expire.c
fs/autofs4/root.c
fs/autofs4/waitq.c
fs/befs/linuxvfs.c
fs/bfs/dir.c
fs/bfs/file.c
fs/binfmt_elf.c
fs/bio-integrity.c
fs/bio.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/volumes.c
fs/btrfs/zlib.c
fs/buffer.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/file.c
fs/coda/Makefile
fs/coda/sysctl.c
fs/compat.c
fs/devpts/inode.c
fs/direct-io.c
fs/drop_caches.c
fs/efs/inode.c
fs/eventpoll.c
fs/exec.c
fs/exofs/common.h
fs/exofs/dir.c
fs/exofs/exofs.h
fs/exofs/file.c
fs/exofs/inode.c
fs/exofs/super.c
fs/ext2/acl.c
fs/ext2/ext2.h
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/ext3/acl.c
fs/ext3/inode.c
fs/ext3/ioctl.c
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fsync.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/fat/inode.c
fs/fcntl.c
fs/fifo.c
fs/freevxfs/vxfs_subr.c
fs/fs-writeback.c
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/generic_acl.c
fs/gfs2/Makefile
fs/gfs2/aops.c
fs/gfs2/file.c
fs/gfs2/log.c
fs/gfs2/lops.c
fs/gfs2/meta_io.c
fs/hfs/inode.c
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hpfs/file.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/isofs/inode.c
fs/jbd/commit.c
fs/jbd2/commit.c
fs/jffs2/acl.c
fs/jffs2/compr_zlib.c
fs/jfs/Makefile
fs/jfs/inode.c
fs/jfs/ioctl.c
fs/jfs/jfs_metapage.c
fs/jfs/xattr.c
fs/locks.c
fs/logfs/compr.c
fs/logfs/dev_bdev.c
fs/logfs/file.c
fs/logfs/inode.c
fs/minix/Kconfig
fs/minix/inode.c
fs/minix/minix.h
fs/mpage.c
fs/namei.c
fs/namespace.c
fs/ncpfs/Makefile
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/getroot.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/namespace.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/proc.c
fs/nfs/write.c
fs/nfs_common/nfsacl.c
fs/nfsd/export.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/alloc.c
fs/nilfs2/alloc.h
fs/nilfs2/bmap.c
fs/nilfs2/bmap.h
fs/nilfs2/btnode.c
fs/nilfs2/btree.c
fs/nilfs2/dir.c
fs/nilfs2/direct.c
fs/nilfs2/file.c
fs/nilfs2/gcinode.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/mdt.c
fs/nilfs2/mdt.h
fs/nilfs2/namei.c
fs/nilfs2/nilfs.h
fs/nilfs2/page.c
fs/nilfs2/page.h
fs/nilfs2/recovery.c
fs/nilfs2/sb.h [deleted file]
fs/nilfs2/segbuf.c
fs/nilfs2/segment.c
fs/nilfs2/segment.h
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
fs/notify/inode_mark.c
fs/notify/mark.c
fs/notify/vfsmount_mark.c
fs/ntfs/Makefile
fs/ntfs/aops.c
fs/ntfs/compress.c
fs/ntfs/inode.c
fs/ocfs2/Makefile
fs/ocfs2/acl.c
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/dlm/Makefile
fs/ocfs2/dlmfs/Makefile
fs/ocfs2/ioctl.c
fs/ocfs2/ocfs2.h
fs/omfs/file.c
fs/open.c
fs/partitions/check.c
fs/proc/array.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/root.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/pstore/inode.c
fs/pstore/internal.h
fs/pstore/platform.c
fs/qnx4/inode.c
fs/quota/dquot.c
fs/reiserfs/Makefile
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/xattr_acl.c
fs/select.c
fs/squashfs/Kconfig
fs/squashfs/decompressor.c
fs/squashfs/decompressor.h
fs/squashfs/dir.c
fs/squashfs/lzo_wrapper.c
fs/squashfs/namei.c
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs.h
fs/squashfs/super.c
fs/squashfs/xz_wrapper.c
fs/squashfs/zlib_wrapper.c
fs/super.c
fs/sync.c
fs/sysv/itree.c
fs/ubifs/Kconfig
fs/ubifs/debug.c
fs/ubifs/file.c
fs/ubifs/ioctl.c
fs/ubifs/lprops.c
fs/ubifs/lpt_commit.c
fs/ubifs/orphan.c
fs/ubifs/super.c
fs/udf/balloc.c
fs/udf/file.c
fs/udf/inode.c
fs/ufs/inode.c
fs/ufs/truncate.c
fs/ufs/util.h
fs/utimes.c
fs/xattr.c
fs/xfs/Makefile
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/linux-2.6/xfs_message.c [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_message.h [new file with mode: 0644]
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/linux-2.6/xfs_sysctl.c
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_dquot_item.c
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm_bhv.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/quota/xfs_trans_dquot.c
fs/xfs/support/debug.c [deleted file]
fs/xfs/support/debug.h [deleted file]
fs/xfs/xfs_alloc.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_error.c
fs/xfs/xfs_error.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_rw.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_vnodeops.c
include/acpi/acoutput.h
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/actbl.h
include/acpi/actbl2.h
include/acpi/apei.h
include/asm-generic/bitops.h
include/asm-generic/bitops/ext2-atomic.h
include/asm-generic/bitops/ext2-non-atomic.h [deleted file]
include/asm-generic/bitops/le.h
include/asm-generic/bitops/minix-le.h [deleted file]
include/asm-generic/bitops/minix.h [deleted file]
include/asm-generic/bug.h
include/asm-generic/types.h
include/asm-generic/unistd.h
include/drm/drm.h
include/linux/Kbuild
include/linux/acpi_io.h
include/linux/aer.h
include/linux/amba/clcd.h
include/linux/backing-dev.h
include/linux/backlight.h
include/linux/bio.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/buffer_head.h
include/linux/capability.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/libceph.h
include/linux/ceph/osd_client.h
include/linux/ceph/rados.h
include/linux/compaction.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/cper.h
include/linux/crc32.h
include/linux/cred.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/dm-ioctl.h
include/linux/dw_dmac.h
include/linux/elevator.h
include/linux/err.h
include/linux/ext3_fs.h
include/linux/firewire.h
include/linux/fs.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/i2c-id.h [deleted file]
include/linux/i2c.h
include/linux/i2c/ads1015.h [new file with mode: 0644]
include/linux/i2c/atmel_mxt_ts.h [new file with mode: 0644]
include/linux/i2c/mcs.h
include/linux/i2c/pxa-i2c.h [new file with mode: 0644]
include/linux/i2c/qt602240_ts.h [deleted file]
include/linux/i2c/twl.h
include/linux/i2c/twl4030-madc.h [new file with mode: 0644]
include/linux/input-polldev.h
include/linux/input.h
include/linux/ipc_namespace.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/jbd2.h
include/linux/journal-head.h
include/linux/kallsyms.h
include/linux/kbd_kern.h
include/linux/kernel.h
include/linux/kgdb.h
include/linux/kthread.h
include/linux/led-lm3530.h [new file with mode: 0644]
include/linux/leds.h
include/linux/magic.h
include/linux/media.h [new file with mode: 0644]
include/linux/memcontrol.h
include/linux/mfd/88pm860x.h
include/linux/mfd/ab8500.h
include/linux/mfd/ab8500/gpadc.h [new file with mode: 0644]
include/linux/mfd/ab8500/sysctrl.h [new file with mode: 0644]
include/linux/mfd/abx500.h
include/linux/mfd/core.h
include/linux/mfd/max8997-private.h [new file with mode: 0644]
include/linux/mfd/max8997.h [new file with mode: 0644]
include/linux/mfd/mc13xxx.h
include/linux/mfd/tps6105x.h [new file with mode: 0644]
include/linux/mfd/wl1273-core.h
include/linux/mfd/wm831x/pdata.h
include/linux/mfd/wm8994/core.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/boot.h [new file with mode: 0644]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/mmc.h
include/linux/mmc/sh_mmcif.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nilfs2_fs.h
include/linux/of_platform.h
include/linux/omap3isp.h [new file with mode: 0644]
include/linux/page-flags.h
include/linux/page_cgroup.h
include/linux/pagemap.h
include/linux/pci-aspm.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/pid.h
include/linux/power/bq20z75.h [new file with mode: 0644]
include/linux/power/bq27x00_battery.h [new file with mode: 0644]
include/linux/power_supply.h
include/linux/proc_fs.h
include/linux/pwm_backlight.h
include/linux/quotaops.h
include/linux/reiserfs_fs.h
include/linux/res_counter.h
include/linux/rio.h
include/linux/rio_drv.h
include/linux/rmap.h
include/linux/sched.h
include/linux/security.h
include/linux/sigma.h [new file with mode: 0644]
include/linux/slab.h
include/linux/slub_def.h
include/linux/sm501.h
include/linux/smp.h
include/linux/spi/tsc2005.h [new file with mode: 0644]
include/linux/sunrpc/gss_api.h
include/linux/svga.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/tty.h
include/linux/types.h
include/linux/utsname.h
include/linux/v4l2-mediabus.h [new file with mode: 0644]
include/linux/v4l2-subdev.h [new file with mode: 0644]
include/linux/videodev2.h
include/linux/vmstat.h
include/linux/writeback.h
include/linux/zlib.h
include/media/media-device.h [new file with mode: 0644]
include/media/media-devnode.h [new file with mode: 0644]
include/media/media-entity.h [new file with mode: 0644]
include/media/noon010pc30.h [new file with mode: 0644]
include/media/rc-map.h
include/media/s3c_fimc.h [deleted file]
include/media/s5p_fimc.h [new file with mode: 0644]
include/media/soc_camera.h
include/media/soc_mediabus.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-device.h
include/media/v4l2-fh.h
include/media/v4l2-ioctl.h
include/media/v4l2-mediabus.h
include/media/v4l2-mem2mem.h
include/media/v4l2-subdev.h
include/media/videobuf2-core.h [new file with mode: 0644]
include/media/videobuf2-dma-contig.h [new file with mode: 0644]
include/media/videobuf2-dma-sg.h [new file with mode: 0644]
include/media/videobuf2-memops.h [new file with mode: 0644]
include/media/videobuf2-vmalloc.h [new file with mode: 0644]
include/media/wm8775.h
include/staging/altera.h [new file with mode: 0644]
include/trace/events/ext4.h
include/trace/events/jbd2.h
include/video/atmel_lcdc.h
init/calibrate.c
init/do_mounts.c
init/do_mounts_rd.c
init/main.c
init/version.c
ipc/msg.c
ipc/msgutil.c
ipc/namespace.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/bounds.c
kernel/capability.c
kernel/cgroup.c
kernel/cpu.c
kernel/cpuset.c
kernel/crash_dump.c [new file with mode: 0644]
kernel/cred.c
kernel/debug/gdbstub.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/gcov/Makefile
kernel/groups.c
kernel/irq/Kconfig
kernel/irq/irqdesc.c
kernel/irq/proc.c
kernel/kallsyms.c
kernel/kthread.c
kernel/lockdep_proc.c
kernel/module.c
kernel/nsproxy.c
kernel/panic.c
kernel/perf_event.c
kernel/pid_namespace.c
kernel/power/Makefile
kernel/power/block_io.c
kernel/printk.c
kernel/ptrace.c
kernel/res_counter.c
kernel/sched.c
kernel/sched_idletask.c
kernel/sched_stoptask.c
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/stop_machine.c
kernel/sys.c
kernel/sysctl.c
kernel/sysctl_check.c
kernel/taskstats.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/uid16.c
kernel/user.c
kernel/utsname.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/find_next_bit.c
lib/kstrtox.c [new file with mode: 0644]
lib/show_mem.c
lib/test-kstrtox.c [new file with mode: 0644]
lib/vsprintf.c
lib/zlib_deflate/deflate.c
lib/zlib_deflate/defutil.h
mm/Kconfig.debug
mm/backing-dev.c
mm/bootmem.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/ksm.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/nobootmem.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_cgroup.c
mm/page_io.c
mm/pagewalk.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/truncate.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/9p/client.c
net/9p/protocol.c
net/9p/trans_common.c
net/9p/trans_fd.c
net/9p/trans_rdma.c
net/9p/trans_virtio.c
net/9p/util.c
net/ceph/armor.c
net/ceph/ceph_common.c
net/ceph/osd_client.c
net/core/pktgen.c
net/rds/cong.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/svcauth_unix.c
net/sunrpc/xprtsock.c
scripts/Makefile
scripts/Makefile.build
scripts/bloat-o-meter
scripts/checkpatch.pl
scripts/extract-ikconfig
scripts/genksyms/Makefile
scripts/genksyms/genksyms.c
scripts/genksyms/genksyms.h
scripts/genksyms/lex.c_shipped
scripts/genksyms/lex.l
scripts/genksyms/parse.c_shipped
scripts/genksyms/parse.h_shipped
scripts/genksyms/parse.y
scripts/get_maintainer.pl
scripts/mod/modpost.c
scripts/package/Makefile
scripts/package/buildtar
scripts/setlocalversion
scripts/tags.sh
scripts/unifdef.c
security/apparmor/lsm.c
security/commoncap.c
security/security.c
security/selinux/hooks.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_via.c
sound/soc/codecs/Kconfig
sound/soc/codecs/cq93vc.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm8400.c
sound/soc/davinci/davinci-vcif.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/soc-core.c
sound/sound_firmware.c
sound/usb/card.c
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-lock.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/util/build-id.c
tools/perf/util/header.c
tools/perf/util/hist.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/symbol.c
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
virt/kvm/kvm_main.c

index 1eba28acab64c83c3e6fd1c39cebfbc6ad6d29ac..5a6dd592eedc888090d43bb8299b1ddc2143ce08 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -20,6 +20,7 @@ Andreas Herrmann <aherrman@de.ibm.com>
 Andrew Morton <akpm@osdl.org>
 Andrew Vasquez <andrew.vasquez@qlogic.com>
 Andy Adamson <andros@citi.umich.edu>
+Archit Taneja <archit@ti.com>
 Arnaud Patard <arnaud.patard@rtp-net.org>
 Arnd Bergmann <arnd@arndb.de>
 Axel Dyks <xl@xlsigned.net>
@@ -70,6 +71,7 @@ Leonid I Ananiev <leonid.i.ananiev@intel.com>
 Linas Vepstas <linas@austin.ibm.com>
 Mark Brown <broonie@sirena.org.uk>
 Matthieu CASTET <castet.matthieu@free.fr>
+Mayuresh Janorkar <mayur@ti.com>
 Michael Buesch <mb@bu3sch.de>
 Michael Buesch <mbuesch@freenet.de>
 Michel DƤnzer <michel@tungstengraphics.com>
@@ -78,6 +80,7 @@ Morten Welinder <terra@gnome.org>
 Morten Welinder <welinder@anemone.rentec.com>
 Morten Welinder <welinder@darter.rentec.com>
 Morten Welinder <welinder@troll.com>
+Mythri P K <mythripk@ti.com>
 Nguyen Anh Quynh <aquynh@gmail.com>
 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
 Patrick Mochel <mochel@digitalimplant.org>
@@ -98,6 +101,7 @@ S.Ƈağlar Onur <caglar@pardus.org.tr>
 Simon Kelley <simon@thekelleys.org.uk>
 StĆ©phane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
 Stephen Hemminger <shemminger@osdl.org>
+Sumit Semwal <sumit.semwal@ti.com>
 Tejun Heo <htejun@gmail.com>
 Thomas Graf <tgraf@suug.ch>
 Tony Luck <tony.luck@intel.com>
index 4d637e1c4ff7723fd2e7e247b9cd6b7feb80eec0..70302f370e7ec1c1d46e4d278f41319e1ce536c1 100644 (file)
@@ -34,3 +34,23 @@ Contact:     Richard Purdie <rpurdie@rpsys.net>
 Description:
                Maximum brightness for <backlight>.
 Users:         HAL
+
+What:          /sys/class/backlight/<backlight>/type
+Date:          September 2010
+KernelVersion: 2.6.37
+Contact:       Matthew Garrett <mjg@redhat.com>
+Description:
+               The type of interface controlled by <backlight>.
+               "firmware": The driver uses a standard firmware interface
+               "platform": The driver uses a platform-specific interface
+               "raw": The driver controls hardware registers directly
+
+               In the general case, when multiple backlight
+               interfaces are available for a single device, firmware
+               control should be preferred to platform control should
+               be preferred to raw control. Using a firmware
+               interface reduces the probability of confusion with
+               the hardware and the OS independently updating the
+               backlight state. Platform interfaces are mostly a
+               holdover from pre-standardisation of firmware
+               interfaces.
diff --git a/Documentation/ABI/testing/configfs-spear-pcie-gadget b/Documentation/ABI/testing/configfs-spear-pcie-gadget
new file mode 100644 (file)
index 0000000..8759881
--- /dev/null
@@ -0,0 +1,31 @@
+What:          /config/pcie-gadget
+Date:          Feb 2011
+KernelVersion: 2.6.37
+Contact:       Pratyush Anand <pratyush.anand@st.com>
+Description:
+
+       Interface is used to configure selected dual mode PCIe controller
+       as device and then program its various registers to configure it
+       as a particular device type.
+       This interfaces can be used to show spear's PCIe device capability.
+
+       Nodes are only visible when configfs is mounted. To mount configfs
+       in /config directory use:
+       # mount -t configfs none /config/
+
+       For nth PCIe Device Controller
+       /config/pcie-gadget.n/
+               link ... used to enable ltssm and read its status.
+               int_type ...used to configure and read type of supported
+                       interrupt
+               no_of_msi ... used to configure number of MSI vector needed and
+                       to read no of MSI granted.
+               inta ... write 1 to assert INTA and 0 to de-assert.
+               send_msi ... write MSI vector to be sent.
+               vendor_id ... used to write and read vendor id (hex)
+               device_id ... used to write and read device id (hex)
+               bar0_size ... used to write and read bar0_size
+               bar0_address ... used to write and read bar0 mapped area in hex.
+               bar0_rw_offset ... used to write and read offset of bar0 where
+                       bar0_data will be written or read.
+               bar0_data ... used to write and read data at bar0_rw_offset.
index f1fb2a004264bc6989a20d92ca333b436c7154d4..ddf451ee2a08812eb16a28f3264618ca2e1e749b 100644 (file)
@@ -1,6 +1,6 @@
 Where:         /dev/pstore/...
-Date:          January 2011
-Kernel Version: 2.6.38
+Date:          March 2011
+Kernel Version: 2.6.39
 Contact:       tony.luck@intel.com
 Description:   Generic interface to platform dependent persistent storage.
 
@@ -11,7 +11,7 @@ Description:  Generic interface to platform dependent persistent storage.
                of the console log is captured, but other interesting
                data can also be saved.
 
-               # mount -t pstore - /dev/pstore
+               # mount -t pstore -o kmsg_bytes=8000 - /dev/pstore
 
                $ ls -l /dev/pstore
                total 0
@@ -33,3 +33,9 @@ Description:  Generic interface to platform dependent persistent storage.
                will be saved elsewhere and erased from persistent store
                soon after boot to free up space ready for the next
                catastrophe.
+
+               The 'kmsg_bytes' mount option changes the target amount of
+               data saved on each oops/panic. Pstore saves (possibly
+               multiple) files based on the record size of the underlying
+               persistent storage until at least this amount is reached.
+               Default is 10 Kbytes.
diff --git a/Documentation/ABI/testing/sysfs-bus-media b/Documentation/ABI/testing/sysfs-bus-media
new file mode 100644 (file)
index 0000000..7057e57
--- /dev/null
@@ -0,0 +1,6 @@
+What:          /sys/bus/media/devices/.../model
+Date:          January 2011
+Contact:       Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+               linux-media@vger.kernel.org
+Description:   Contains the device model name in UTF-8. The device version is
+               is not be appended to the model name.
index 90a87e2a572ba47b8549c182facfc3407f2793bd..fa72ccb2282e77c879c0a7a135f6d86828a143cc 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/bus/rbd/
 Date:          November 2010
-Contact:       Yehuda Sadeh <yehuda@hq.newdream.net>,
+Contact:       Yehuda Sadeh <yehuda@newdream.net>,
                Sage Weil <sage@newdream.net>
 Description:
 
diff --git a/Documentation/ABI/testing/sysfs-devices-mmc b/Documentation/ABI/testing/sysfs-devices-mmc
new file mode 100644 (file)
index 0000000..5a50ab6
--- /dev/null
@@ -0,0 +1,21 @@
+What:          /sys/devices/.../mmc_host/mmcX/mmcX:XXXX/enhanced_area_offset
+Date:          January 2011
+Contact:       Chuanxiao Dong <chuanxiao.dong@intel.com>
+Description:
+               Enhanced area is a new feature defined in eMMC4.4 standard.
+               eMMC4.4 or later card can support such feature. This kind of
+               area can help to improve the card performance. If the feature
+               is enabled, this attribute will indicate the start address of
+               enhanced data area. If not, this attribute will be -EINVAL.
+               Unit Byte. Format decimal.
+
+What:          /sys/devices/.../mmc_host/mmcX/mmcX:XXXX/enhanced_area_size
+Date:          January 2011
+Contact:       Chuanxiao Dong <chuanxiao.dong@intel.com>
+Description:
+               Enhanced area is a new feature defined in eMMC4.4 standard.
+               eMMC4.4 or later card can support such feature. This kind of
+               area can help to improve the card performance. If the feature
+               is enabled, this attribute will indicate the size of enhanced
+               data area. If not, this attribute will be -EINVAL.
+               Unit KByte. Format decimal.
index 5fb709997d9635ac4f5ee1d8bed00f207b9c3feb..f22ac0872ae8de41a44406edfab71384d54b830a 100644 (file)
@@ -48,7 +48,7 @@ Description:
                 will have its blocks allocated out of its own unique
                 preallocation pool.
 
-What:          /sys/fs/ext4/<disk>/inode_readahead
+What:          /sys/fs/ext4/<disk>/inode_readahead_blks
 Date:          March 2008
 Contact:       "Theodore Ts'o" <tytso@mit.edu>
 Description:
@@ -85,7 +85,14 @@ Date:                June 2008
 Contact:       "Theodore Ts'o" <tytso@mit.edu>
 Description:
                Tuning parameter which (if non-zero) controls the goal
-               inode used by the inode allocator in p0reference to
-               all other allocation hueristics.  This is intended for
+               inode used by the inode allocator in preference to
+               all other allocation heuristics.  This is intended for
                debugging use only, and should be 0 on production
                systems.
+
+What:          /sys/fs/ext4/<disk>/max_writeback_mb_bump
+Date:          September 2009
+Contact:       "Theodore Ts'o" <tytso@mit.edu>
+Description:
+               The maximum number of megabytes the writeback code will
+               try to write out before move on to another inode.
diff --git a/Documentation/ABI/testing/sysfs-fs-pstore b/Documentation/ABI/testing/sysfs-fs-pstore
deleted file mode 100644 (file)
index 8e659d8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-What:          /sys/fs/pstore/kmsg_bytes
-Date:          January 2011
-Kernel Version: 2.6.38
-Contact:       "Tony Luck" <tony.luck@intel.com>
-Description:
-               Controls amount of console log that will be saved
-               to persistent store on oops/panic.
index 4fb88f15f2efc250c220dbc5385d07ad9b4b3c6b..5f4828a034e3235f21d3e6050f4a4092dc4bd23e 100644 (file)
@@ -35,7 +35,7 @@ o  util-linux             2.10o                   # fdformat --version
 o  module-init-tools      0.9.10                  # depmod -V
 o  e2fsprogs              1.41.4                  # e2fsck -V
 o  jfsutils               1.1.3                   # fsck.jfs -V
-o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.6.3                   # reiserfsck -V
 o  xfsprogs               2.6.0                   # xfs_db -V
 o  squashfs-tools         4.0                     # mksquashfs -version
 o  btrfs-progs            0.18                    # btrfsck
@@ -46,9 +46,9 @@ o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
 o  nfs-utils              1.0.5                   # showmount --version
 o  procps                 3.2.0                   # ps --version
 o  oprofile               0.9                     # oprofiled --version
-o  udev                   081                     # udevinfo -V
-o  grub                   0.93                    # grub --version
-o  mcelog                0.6
+o  udev                   081                     # udevd --version
+o  grub                   0.93                    # grub --version || grub-install --version
+o  mcelog                 0.6                     # mcelog --version
 o  iptables               1.4.2                   # iptables -V
 
 
index 1cd3478e5834e0a7a8e1110ebd1a736989794148..58b0bf9178349c435fd53674d96c29d7ecea0414 100644 (file)
@@ -168,6 +168,13 @@ Do not unnecessarily use braces where a single statement will do.
 if (condition)
        action();
 
+and
+
+if (condition)
+       do_this();
+else
+       do_that();
+
 This does not apply if one branch of a conditional statement is a single
 statement. Use braces in both branches.
 
index 8b6e00a71034cbd7151ace7adbe3558f3cbb99bd..2deb069aedf1e9a99e8264f545a56f9f3b9b112f 100644 (file)
@@ -53,7 +53,10 @@ MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
 
 build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
-              cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/
+              cp $(srctree)/Documentation/DocBook/dvb/*.png \
+                 $(srctree)/Documentation/DocBook/v4l/*.gif \
+                 $(srctree)/Documentation/DocBook/v4l/*.png \
+                 $(objtree)/Documentation/DocBook/media/
 
 xmldoclinks:
 ifneq ($(objtree),$(srctree))
index be34dcbe0d90662b19eaab4bd670bfdc1ed1e546..5d259c632cdfdb8af5627b990271d79201bb0c92 100644 (file)
 <!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
 <!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">
 
+<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
+<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
+<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
+
 <!-- Ioctls -->
 <!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
 <!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
 <!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
 <!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
 <!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_G_CROP</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_S_CROP</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
+<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
 <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
 <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
 <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
 <!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
 
+<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
+<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
+<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
+
 <!-- Types -->
 <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
 
 <!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
 <!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
 <!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
+<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
 <!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
 <!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
 <!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
 <!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
 <!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
 <!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
+<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
 <!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
 <!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">
 
 <!ENTITY v4l2-audioout "struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link>">
 <!ENTITY v4l2-bt-timings "struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link>">
 <!ENTITY v4l2-buffer "struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link>">
+<!ENTITY v4l2-plane "struct&nbsp;<link linkend='v4l2-plane'>v4l2_plane</link>">
 <!ENTITY v4l2-capability "struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link>">
 <!ENTITY v4l2-captureparm "struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link>">
 <!ENTITY v4l2-clip "struct&nbsp;<link linkend='v4l2-clip'>v4l2_clip</link>">
 <!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
 <!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
 <!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
+<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
 <!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
 <!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
 <!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
 <!ENTITY v4l2-outputparm "struct&nbsp;<link linkend='v4l2-outputparm'>v4l2_outputparm</link>">
 <!ENTITY v4l2-pix-format "struct&nbsp;<link linkend='v4l2-pix-format'>v4l2_pix_format</link>">
+<!ENTITY v4l2-pix-format-mplane "struct&nbsp;<link linkend='v4l2-pix-format-mplane'>v4l2_pix_format_mplane</link>">
+<!ENTITY v4l2-plane-pix-format "struct&nbsp;<link linkend='v4l2-plane-pix-format'>v4l2_plane_pix_format</link>">
 <!ENTITY v4l2-queryctrl "struct&nbsp;<link linkend='v4l2-queryctrl'>v4l2_queryctrl</link>">
 <!ENTITY v4l2-querymenu "struct&nbsp;<link linkend='v4l2-querymenu'>v4l2_querymenu</link>">
 <!ENTITY v4l2-rect "struct&nbsp;<link linkend='v4l2-rect'>v4l2_rect</link>">
 <!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
 <!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
 <!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
+<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
+<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
+<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
+<!ENTITY v4l2-subdev-crop "struct&nbsp;<link linkend='v4l2-subdev-crop'>v4l2_subdev_crop</link>">
+<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
+<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
 <!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
 <!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
 <!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
 <!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
 <!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
 
+<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
+<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
+<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
+<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
+<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">
+
 <!-- Error Codes -->
 <!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
 <!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
 <!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
 <!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
 <!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
+<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
 <!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">
 
 <!-- Subsections -->
 <!ENTITY sub-biblio SYSTEM "v4l/biblio.xml">
 <!ENTITY sub-common SYSTEM "v4l/common.xml">
+<!ENTITY sub-planar-apis SYSTEM "v4l/planar-apis.xml">
 <!ENTITY sub-compat SYSTEM "v4l/compat.xml">
 <!ENTITY sub-controls SYSTEM "v4l/controls.xml">
 <!ENTITY sub-dev-capture SYSTEM "v4l/dev-capture.xml">
 <!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
 <!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
 <!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
+<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
 <!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
 <!ENTITY sub-driver SYSTEM "v4l/driver.xml">
 <!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
 <!ENTITY sub-io SYSTEM "v4l/io.xml">
 <!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
 <!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
+<!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
+<!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
 <!ENTITY sub-nv16 SYSTEM "v4l/pixfmt-nv16.xml">
 <!ENTITY sub-packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
 <!ENTITY sub-packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
 <!ENTITY sub-yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
 <!ENTITY sub-yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
 <!ENTITY sub-yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
+<!ENTITY sub-yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
 <!ENTITY sub-yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
 <!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
 <!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
 <!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
+<!ENTITY sub-subdev-enum-frame-interval SYSTEM "v4l/vidioc-subdev-enum-frame-interval.xml">
+<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
+<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
+<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
+<!ENTITY sub-subdev-g-crop SYSTEM "v4l/vidioc-subdev-g-crop.xml">
+<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
+<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
 <!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
 <!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
 <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
 <!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
 <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
 
+<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
+<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
+<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
+<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
+<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
+<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
+
 <!-- Function Reference -->
 <!ENTITY close SYSTEM "v4l/func-close.xml">
 <!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
 <!ENTITY write SYSTEM "v4l/func-write.xml">
 <!ENTITY grey SYSTEM "v4l/pixfmt-grey.xml">
 <!ENTITY nv12 SYSTEM "v4l/pixfmt-nv12.xml">
+<!ENTITY nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
 <!ENTITY nv16 SYSTEM "v4l/pixfmt-nv16.xml">
 <!ENTITY packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
 <!ENTITY packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
 <!ENTITY yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
 <!ENTITY yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
 <!ENTITY yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
+<!ENTITY yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
 <!ENTITY yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
index a99088aae1aa80e5a0fe872422009d663af65f60..88f2cc680cc2abd4ef168e3ba32c4948fe85f030 100644 (file)
@@ -106,6 +106,9 @@ Foundation. A copy of the license is included in the chapter entitled
 &sub-remote_controllers;
 </chapter>
 </part>
+<part id="media_common">
+&sub-media-controller;
+</part>
 
 &sub-fdl-appendix;
 
diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf
new file mode 100644 (file)
index 0000000..905e60e
Binary files /dev/null and b/Documentation/DocBook/v4l/bayer.pdf differ
diff --git a/Documentation/DocBook/v4l/bayer.png b/Documentation/DocBook/v4l/bayer.png
new file mode 100644 (file)
index 0000000..9b15fb2
Binary files /dev/null and b/Documentation/DocBook/v4l/bayer.png differ
index cea23e1c4fc6f7f517434b861de46fef08a6fd25..dbab79c215c1fd55f29a6f94ce92a3953391a3e7 100644 (file)
@@ -846,6 +846,8 @@ conversion routine or library for integration into applications.</para>
     </section>
   </section>
 
+  &sub-planar-apis;
+
   <section id="crop">
     <title>Image Cropping, Insertion and Scaling</title>
 
index c9ce61d981f56d4e8cef67e5a1d84b8f456faa74..9f7cd4f2579220f08082bd91d79dc04bd65fcd5a 100644 (file)
@@ -1711,8 +1711,8 @@ ioctl would enumerate the available audio inputs. An ioctl to
 determine the current audio input, if more than one combines with the
 current video input, did not exist. So
 <constant>VIDIOC_G_AUDIO</constant> was renamed to
-<constant>VIDIOC_G_AUDIO_OLD</constant>, this ioctl will be removed in
-the future. The &VIDIOC-ENUMAUDIO; ioctl was added to enumerate
+<constant>VIDIOC_G_AUDIO_OLD</constant>, this ioctl was removed on
+Kernel 2.6.39. The &VIDIOC-ENUMAUDIO; ioctl was added to enumerate
 audio inputs, while &VIDIOC-G-AUDIO; now reports the current audio
 input.</para>
          <para>The same changes were made to &VIDIOC-G-AUDOUT; and
@@ -1726,7 +1726,7 @@ must be updated to successfully compile again.</para>
          <para>The &VIDIOC-OVERLAY; ioctl was incorrectly defined with
 write-read parameter. It was changed to write-only, while the write-read
 version was renamed to <constant>VIDIOC_OVERLAY_OLD</constant>. The old
-ioctl will be removed in the future. Until further the "videodev"
+ioctl was removed on Kernel 2.6.39. Until further the "videodev"
 kernel module will automatically translate to the new version, so drivers
 must be recompiled, but not applications.</para>
        </listitem>
@@ -1744,7 +1744,7 @@ surface can be seen.</para>
 defined with write-only parameter, inconsistent with other ioctls
 modifying their argument. They were changed to write-read, while a
 <constant>_OLD</constant> suffix was added to the write-only versions.
-The old ioctls will be removed in the future. Drivers and
+The old ioctls were removed on Kernel 2.6.39. Drivers and
 applications assuming a constant parameter need an update.</para>
        </listitem>
       </orderedlist>
@@ -1815,8 +1815,8 @@ yet to be addressed, for details see <xref
          <para>The &VIDIOC-CROPCAP; ioctl was incorrectly defined
 with read-only parameter. It is now defined as write-read ioctl, while
 the read-only version was renamed to
-<constant>VIDIOC_CROPCAP_OLD</constant>. The old ioctl will be removed
-in the future.</para>
+<constant>VIDIOC_CROPCAP_OLD</constant>. The old ioctl was removed
+on Kernel 2.6.39.</para>
        </listitem>
       </orderedlist>
     </section>
@@ -2353,6 +2353,20 @@ that used it. It was originally scheduled for removal in 2.6.35.
        </listitem>
       </orderedlist>
     </section>
+    <section>
+      <title>V4L2 in Linux 2.6.39</title>
+      <orderedlist>
+        <listitem>
+          <para>The old VIDIOC_*_OLD symbols and V4L1 support were removed.</para>
+        </listitem>
+        <listitem>
+          <para>Multi-planar API added. Does not affect the compatibility of
+          current drivers and applications. See
+          <link linkend="planar-apis">multi-planar API</link>
+          for details.</para>
+        </listitem>
+      </orderedlist>
+    </section>
 
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
index 32807e43f170f6e0bf09d6edd362698969044903..2237c661f26aceb3a65ec5992bc0dc8e542c7752 100644 (file)
@@ -18,7 +18,8 @@ files are used for video output devices.</para>
     <title>Querying Capabilities</title>
 
     <para>Devices supporting the video capture interface set the
-<constant>V4L2_CAP_VIDEO_CAPTURE</constant> flag in the
+<constant>V4L2_CAP_VIDEO_CAPTURE</constant> or
+<constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant> flag in the
 <structfield>capabilities</structfield> field of &v4l2-capability;
 returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
 they may also support the <link linkend="overlay">video overlay</link>
@@ -64,9 +65,11 @@ linkend="crop" />.</para>
 
     <para>To query the current image format applications set the
 <structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> and call the
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and call the
 &VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> member of the
+the &v4l2-pix-format; <structfield>pix</structfield> or the
+&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
 <structfield>fmt</structfield> union.</para>
 
     <para>To request different parameters applications set the
@@ -84,8 +87,8 @@ adjust the parameters and finally return the actual parameters as
 without disabling I/O or possibly time consuming hardware
 preparations.</para>
 
-    <para>The contents of &v4l2-pix-format; are discussed in <xref
-linkend="pixfmt" />. See also the specification of the
+    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
+are discussed in <xref linkend="pixfmt" />. See also the specification of the
 <constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
 and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
 capture devices must implement both the
index 63c3c20e5a72921c5a431e34a72bab71f1a736b4..919e22c538542c001747b69a9c9639c511044f60 100644 (file)
@@ -17,7 +17,8 @@ files are used for video capture devices.</para>
     <title>Querying Capabilities</title>
 
     <para>Devices supporting the video output interface set the
-<constant>V4L2_CAP_VIDEO_OUTPUT</constant> flag in the
+<constant>V4L2_CAP_VIDEO_OUTPUT</constant> or
+<constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant> flag in the
 <structfield>capabilities</structfield> field of &v4l2-capability;
 returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
 they may also support the <link linkend="raw-vbi">raw VBI
@@ -60,9 +61,11 @@ linkend="crop" />.</para>
 
     <para>To query the current image format applications set the
 <structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> and call the
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and call the
 &VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> member of the
+the &v4l2-pix-format; <structfield>pix</structfield> or the
+&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
 <structfield>fmt</structfield> union.</para>
 
     <para>To request different parameters applications set the
@@ -80,8 +83,8 @@ adjust the parameters and finally return the actual parameters as
 without disabling I/O or possibly time consuming hardware
 preparations.</para>
 
-    <para>The contents of &v4l2-pix-format; are discussed in <xref
-linkend="pixfmt" />. See also the specification of the
+    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
+are discussed in <xref linkend="pixfmt" />. See also the specification of the
 <constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
 and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
 output devices must implement both the
diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
new file mode 100644 (file)
index 0000000..21caff6
--- /dev/null
@@ -0,0 +1,313 @@
+  <title>Sub-device Interface</title>
+
+  <note>
+    <title>Experimental</title>
+    <para>This is an <link linkend="experimental">experimental</link>
+    interface and may change in the future.</para>
+  </note>
+
+  <para>The complex nature of V4L2 devices, where hardware is often made of
+  several integrated circuits that need to interact with each other in a
+  controlled way, leads to complex V4L2 drivers. The drivers usually reflect
+  the hardware model in software, and model the different hardware components
+  as software blocks called sub-devices.</para>
+
+  <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
+  implements the media device API, they will automatically inherit from media
+  entities. Applications will be able to enumerate the sub-devices and discover
+  the hardware topology using the media entities, pads and links enumeration
+  API.</para>
+
+  <para>In addition to make sub-devices discoverable, drivers can also choose
+  to make them directly configurable by applications. When both the sub-device
+  driver and the V4L2 device driver support this, sub-devices will feature a
+  character device node on which ioctls can be called to
+  <itemizedlist>
+    <listitem><para>query, read and write sub-devices controls</para></listitem>
+    <listitem><para>subscribe and unsubscribe to events and retrieve them</para></listitem>
+    <listitem><para>negotiate image formats on individual pads</para></listitem>
+  </itemizedlist>
+  </para>
+
+  <para>Sub-device character device nodes, conventionally named
+  <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
+
+  <section>
+    <title>Controls</title>
+    <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
+    usually merge all controls and expose them through video device nodes.
+    Applications can control all sub-devices through a single interface.</para>
+
+    <para>Complex devices sometimes implement the same control in different
+    pieces of hardware. This situation is common in embedded platforms, where
+    both sensors and image processing hardware implement identical functions,
+    such as contrast adjustment, white balance or faulty pixels correction. As
+    the V4L2 controls API doesn't support several identical controls in a single
+    device, all but one of the identical controls are hidden.</para>
+
+    <para>Applications can access those hidden controls through the sub-device
+    node with the V4L2 control API described in <xref linkend="control" />. The
+    ioctls behave identically as when issued on V4L2 device nodes, with the
+    exception that they deal only with controls implemented in the sub-device.
+    </para>
+
+    <para>Depending on the driver, those controls might also be exposed through
+    one (or several) V4L2 device nodes.</para>
+  </section>
+
+  <section>
+    <title>Events</title>
+    <para>V4L2 sub-devices can notify applications of events as described in
+    <xref linkend="event" />. The API behaves identically as when used on V4L2
+    device nodes, with the exception that it only deals with events generated by
+    the sub-device. Depending on the driver, those events might also be reported
+    on one (or several) V4L2 device nodes.</para>
+  </section>
+
+  <section id="pad-level-formats">
+    <title>Pad-level Formats</title>
+
+    <warning><para>Pad-level formats are only applicable to very complex device that
+    need to expose low-level format configuration to user space. Generic V4L2
+    applications do <emphasis>not</emphasis> need to use the API described in
+    this section.</para></warning>
+
+    <note><para>For the purpose of this section, the term
+    <wordasword>format</wordasword> means the combination of media bus data
+    format, frame width and frame height.</para></note>
+
+    <para>Image formats are typically negotiated on video capture and output
+    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
+    The driver is responsible for configuring every block in the video pipeline
+    according to the requested format at the pipeline input and/or
+    output.</para>
+
+    <para>For complex devices, such as often found in embedded systems,
+    identical image sizes at the output of a pipeline can be achieved using
+    different hardware configurations. One such example is shown on
+    <xref linkend="pipeline-scaling" />, where
+    image scaling can be performed on both the video sensor and the host image
+    processing hardware.</para>
+
+    <figure id="pipeline-scaling">
+      <title>Image Format Negotation on Pipelines</title>
+      <mediaobject>
+       <imageobject>
+         <imagedata fileref="pipeline.pdf" format="PS" />
+       </imageobject>
+       <imageobject>
+         <imagedata fileref="pipeline.png" format="PNG" />
+       </imageobject>
+       <textobject>
+         <phrase>High quality and high speed pipeline configuration</phrase>
+       </textobject>
+      </mediaobject>
+    </figure>
+
+    <para>The sensor scaler is usually of less quality than the host scaler, but
+    scaling on the sensor is required to achieve higher frame rates. Depending
+    on the use case (quality vs. speed), the pipeline must be configured
+    differently. Applications need to configure the formats at every point in
+    the pipeline explicitly.</para>
+
+    <para>Drivers that implement the <link linkend="media-controller-intro">media
+    API</link> can expose pad-level image format configuration to applications.
+    When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
+    &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
+
+    <para>Applications are responsible for configuring coherent parameters on
+    the whole pipeline and making sure that connected pads have compatible
+    formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
+    time, and an &EPIPE; is then returned if the configuration is
+    invalid.</para>
+
+    <para>Pad-level image format configuration support can be tested by calling
+    the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
+    pad-level format configuration is not supported by the sub-device.</para>
+
+    <section>
+      <title>Format Negotiation</title>
+
+      <para>Acceptable formats on pads can (and usually do) depend on a number
+      of external parameters, such as formats on other pads, active links, or
+      even controls. Finding a combination of formats on all pads in a video
+      pipeline, acceptable to both application and driver, can't rely on formats
+      enumeration only. A format negotiation mechanism is required.</para>
+
+      <para>Central to the format negotiation mechanism are the get/set format
+      operations. When called with the <structfield>which</structfield> argument
+      set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
+      &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
+      formats parameters that are not connected to the hardware configuration.
+      Modifying those 'try' formats leaves the device state untouched (this
+      applies to both the software state stored in the driver and the hardware
+      state stored in the device itself).</para>
+
+      <para>While not kept as part of the device state, try formats are stored
+      in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
+      the last try format set <emphasis>on the same sub-device file
+      handle</emphasis>. Several applications querying the same sub-device at
+      the same time will thus not interact with each other.</para>
+
+      <para>To find out whether a particular format is supported by the device,
+      applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
+      needed, change the requested <structfield>format</structfield> based on
+      device requirements and return the possibly modified value. Applications
+      can then choose to try a different format or accept the returned value and
+      continue.</para>
+
+      <para>Formats returned by the driver during a negotiation iteration are
+      guaranteed to be supported by the device. In particular, drivers guarantee
+      that a returned format will not be further changed if passed to an
+      &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
+      formats on other pads or links' configuration are not changed).</para>
+
+      <para>Drivers automatically propagate formats inside sub-devices. When a
+      try or active format is set on a pad, corresponding formats on other pads
+      of the same sub-device can be modified by the driver. Drivers are free to
+      modify formats as required by the device. However, they should comply with
+      the following rules when possible:
+      <itemizedlist>
+        <listitem><para>Formats should be propagated from sink pads to source pads.
+       Modifying a format on a source pad should not modify the format on any
+       sink pad.</para></listitem>
+        <listitem><para>Sub-devices that scale frames using variable scaling factors
+       should reset the scale factors to default values when sink pads formats
+       are modified. If the 1:1 scaling ratio is supported, this means that
+       source pads formats should be reset to the sink pads formats.</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>Formats are not propagated across links, as that would involve
+      propagating them from one sub-device file handle to another. Applications
+      must then take care to configure both ends of every link explicitly with
+      compatible formats. Identical formats on the two ends of a link are
+      guaranteed to be compatible. Drivers are free to accept different formats
+      matching device requirements as being compatible.</para>
+
+      <para><xref linkend="sample-pipeline-config" />
+      shows a sample configuration sequence for the pipeline described in
+      <xref linkend="pipeline-scaling" /> (table
+      columns list entity names and pad numbers).</para>
+
+      <table pgwide="0" frame="none" id="sample-pipeline-config">
+       <title>Sample Pipeline Configuration</title>
+       <tgroup cols="3">
+         <colspec colname="what"/>
+         <colspec colname="sensor-0" />
+         <colspec colname="frontend-0" />
+         <colspec colname="frontend-1" />
+         <colspec colname="scaler-0" />
+         <colspec colname="scaler-1" />
+         <thead>
+           <row>
+             <entry></entry>
+             <entry>Sensor/0</entry>
+             <entry>Frontend/0</entry>
+             <entry>Frontend/1</entry>
+             <entry>Scaler/0</entry>
+             <entry>Scaler/1</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row>
+             <entry>Initial state</entry>
+             <entry>2048x1536</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+           </row>
+           <row>
+             <entry>Configure frontend input</entry>
+             <entry>2048x1536</entry>
+             <entry><emphasis>2048x1536</emphasis></entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+           </row>
+           <row>
+             <entry>Configure scaler input</entry>
+             <entry>2048x1536</entry>
+             <entry>2048x1536</entry>
+             <entry>2046x1534</entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+           </row>
+           <row>
+             <entry>Configure scaler output</entry>
+             <entry>2048x1536</entry>
+             <entry>2048x1536</entry>
+             <entry>2046x1534</entry>
+             <entry>2046x1534</entry>
+             <entry><emphasis>1280x960</emphasis></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <para>
+      <orderedlist>
+       <listitem><para>Initial state. The sensor output is set to its native 3MP
+       resolution. Resolutions on the host frontend and scaler input and output
+       pads are undefined.</para></listitem>
+       <listitem><para>The application configures the frontend input pad resolution to
+       2048x1536. The driver propagates the format to the frontend output pad.
+       Note that the propagated output format can be different, as in this case,
+       than the input format, as the hardware might need to crop pixels (for
+       instance when converting a Bayer filter pattern to RGB or YUV).</para></listitem>
+       <listitem><para>The application configures the scaler input pad resolution to
+       2046x1534 to match the frontend output resolution. The driver propagates
+       the format to the scaler output pad.</para></listitem>
+       <listitem><para>The application configures the scaler output pad resolution to
+       1280x960.</para></listitem>
+      </orderedlist>
+      </para>
+
+      <para>When satisfied with the try results, applications can set the active
+      formats by setting the <structfield>which</structfield> argument to
+      <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
+      exactly as try formats by drivers. To avoid modifying the hardware state
+      during format negotiation, applications should negotiate try formats first
+      and then modify the active settings using the try formats returned during
+      the last negotiation iteration. This guarantees that the active format
+      will be applied as-is by the driver without being modified.
+      </para>
+    </section>
+
+    <section>
+      <title>Cropping and scaling</title>
+
+      <para>Many sub-devices support cropping frames on their input or output
+      pads (or possible even on both). Cropping is used to select the area of
+      interest in an image, typically on a video sensor or video decoder. It can
+      also be used as part of digital zoom implementations to select the area of
+      the image that will be scaled up.</para>
+
+      <para>Crop settings are defined by a crop rectangle and represented in a
+      &v4l2-rect; by the coordinates of the top left corner and the rectangle
+      size. Both the coordinates and sizes are expressed in pixels.</para>
+
+      <para>The crop rectangle is retrieved and set using the
+      &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
+      formats, drivers store try and active crop rectangles. The format
+      negotiation mechanism applies to crop settings as well.</para>
+
+      <para>On input pads, cropping is applied relatively to the current pad
+      format. The pad format represents the image size as received by the
+      sub-device from the previous block in the pipeline, and the crop rectangle
+      represents the sub-image that will be transmitted further inside the
+      sub-device for processing. The crop rectangle be entirely containted
+      inside the input image size.</para>
+
+      <para>Input crop rectangle are reset to their default value when the input
+      image format is modified. Drivers should use the input image size as the
+      crop rectangle default value, but hardware requirements may prevent this.
+      </para>
+
+      <para>Cropping behaviour on output pads is not defined.</para>
+
+    </section>
+  </section>
+
+  &sub-subdev-formats;
index 2e2fc3933aea73685ee473b9da2f154943850e4c..786732b64bbde3b2aef4e087aae0ab01933b3bc1 100644 (file)
@@ -45,7 +45,10 @@ just specify a <constant>NULL</constant> pointer here.</para>
        <listitem>
          <para>Length of the memory area to map. This must be the
 same value as returned by the driver in the &v4l2-buffer;
-<structfield>length</structfield> field.</para>
+<structfield>length</structfield> field for the
+single-planar API, and the same value as returned by the driver
+in the &v4l2-plane; <structfield>length</structfield> field for the
+multi-planar API.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
@@ -106,7 +109,10 @@ flag.</para>
        <listitem>
          <para>Offset of the buffer in device memory. This must be the
 same value as returned by the driver in the &v4l2-buffer;
-<structfield>m</structfield> union <structfield>offset</structfield> field.</para>
+<structfield>m</structfield> union <structfield>offset</structfield> field for
+the single-planar API, and the same value as returned by the driver
+in the &v4l2-plane; <structfield>m</structfield> union
+<structfield>mem_offset</structfield> field for the multi-planar API.</para>
        </listitem>
       </varlistentry>
     </variablelist>
index 502ed49323b00542efdf7348a0b4c836b03c2aa2..e2c4190f9bb609a623a7f11994c138b66aee3ffc 100644 (file)
@@ -37,7 +37,8 @@
          <para>Length of the mapped buffer. This must be the same
 value as given to <function>mmap()</function> and returned by the
 driver in the &v4l2-buffer; <structfield>length</structfield>
-field.</para>
+field for the single-planar API and in the &v4l2-plane;
+<structfield>length</structfield> field for the multi-planar API.</para>
        </listitem>
       </varlistentry>
     </variablelist>
index d424886beda051a7f9bbe6db441c1d76bdb62250..227e7ac45a06c4dbf3ac91973e492c3301df983f 100644 (file)
@@ -121,18 +121,22 @@ mapped.</para>
     <para>Before applications can access the buffers they must map
 them into their address space with the &func-mmap; function. The
 location of the buffers in device memory can be determined with the
-&VIDIOC-QUERYBUF; ioctl. The <structfield>m.offset</structfield> and
-<structfield>length</structfield> returned in a &v4l2-buffer; are
-passed as sixth and second parameter to the
-<function>mmap()</function> function. The offset and length values
-must not be modified. Remember the buffers are allocated in physical
-memory, as opposed to virtual memory which can be swapped out to disk.
-Applications should free the buffers as soon as possible with the
-&func-munmap; function.</para>
+&VIDIOC-QUERYBUF; ioctl. In the single-planar API case, the
+<structfield>m.offset</structfield> and <structfield>length</structfield>
+returned in a &v4l2-buffer; are passed as sixth and second parameter to the
+<function>mmap()</function> function. When using the multi-planar API,
+struct &v4l2-buffer; contains an array of &v4l2-plane; structures, each
+containing its own <structfield>m.offset</structfield> and
+<structfield>length</structfield>. When using the multi-planar API, every
+plane of every buffer has to be mapped separately, so the number of
+calls to &func-mmap; should be equal to number of buffers times number of
+planes in each buffer. The offset and length values must not be modified.
+Remember, the buffers are allocated in physical memory, as opposed to virtual
+memory, which can be swapped out to disk. Applications should free the buffers
+as soon as possible with the &func-munmap; function.</para>
 
     <example>
-      <title>Mapping buffers</title>
-
+      <title>Mapping buffers in the single-planar API</title>
       <programlisting>
 &v4l2-requestbuffers; reqbuf;
 struct {
@@ -141,63 +145,145 @@ struct {
 } *buffers;
 unsigned int i;
 
-memset (&amp;reqbuf, 0, sizeof (reqbuf));
+memset(&amp;reqbuf, 0, sizeof(reqbuf));
 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 reqbuf.memory = V4L2_MEMORY_MMAP;
 reqbuf.count = 20;
 
 if (-1 == ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf)) {
        if (errno == EINVAL)
-               printf ("Video capturing or mmap-streaming is not supported\n");
+               printf("Video capturing or mmap-streaming is not supported\n");
        else
-               perror ("VIDIOC_REQBUFS");
+               perror("VIDIOC_REQBUFS");
 
-       exit (EXIT_FAILURE);
+       exit(EXIT_FAILURE);
 }
 
 /* We want at least five buffers. */
 
 if (reqbuf.count &lt; 5) {
        /* You may need to free the buffers here. */
-       printf ("Not enough buffer memory\n");
-       exit (EXIT_FAILURE);
+       printf("Not enough buffer memory\n");
+       exit(EXIT_FAILURE);
 }
 
-buffers = calloc (reqbuf.count, sizeof (*buffers));
-assert (buffers != NULL);
+buffers = calloc(reqbuf.count, sizeof(*buffers));
+assert(buffers != NULL);
 
 for (i = 0; i &lt; reqbuf.count; i++) {
        &v4l2-buffer; buffer;
 
-       memset (&amp;buffer, 0, sizeof (buffer));
+       memset(&amp;buffer, 0, sizeof(buffer));
        buffer.type = reqbuf.type;
        buffer.memory = V4L2_MEMORY_MMAP;
        buffer.index = i;
 
        if (-1 == ioctl (fd, &VIDIOC-QUERYBUF;, &amp;buffer)) {
-               perror ("VIDIOC_QUERYBUF");
-               exit (EXIT_FAILURE);
+               perror("VIDIOC_QUERYBUF");
+               exit(EXIT_FAILURE);
        }
 
        buffers[i].length = buffer.length; /* remember for munmap() */
 
-       buffers[i].start = mmap (NULL, buffer.length,
-                                PROT_READ | PROT_WRITE, /* recommended */
-                                MAP_SHARED,             /* recommended */
-                                fd, buffer.m.offset);
+       buffers[i].start = mmap(NULL, buffer.length,
+                               PROT_READ | PROT_WRITE, /* recommended */
+                               MAP_SHARED,             /* recommended */
+                               fd, buffer.m.offset);
 
        if (MAP_FAILED == buffers[i].start) {
                /* If you do not exit here you should unmap() and free()
                   the buffers mapped so far. */
-               perror ("mmap");
-               exit (EXIT_FAILURE);
+               perror("mmap");
+               exit(EXIT_FAILURE);
+       }
+}
+
+/* Cleanup. */
+
+for (i = 0; i &lt; reqbuf.count; i++)
+       munmap(buffers[i].start, buffers[i].length);
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Mapping buffers in the multi-planar API</title>
+      <programlisting>
+&v4l2-requestbuffers; reqbuf;
+/* Our current format uses 3 planes per buffer */
+#define FMT_NUM_PLANES = 3;
+
+struct {
+       void *start[FMT_NUM_PLANES];
+       size_t length[FMT_NUM_PLANES];
+} *buffers;
+unsigned int i, j;
+
+memset(&amp;reqbuf, 0, sizeof(reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+reqbuf.memory = V4L2_MEMORY_MMAP;
+reqbuf.count = 20;
+
+if (ioctl(fd, &VIDIOC-REQBUFS;, &amp;reqbuf) &lt; 0) {
+       if (errno == EINVAL)
+               printf("Video capturing or mmap-streaming is not supported\n");
+       else
+               perror("VIDIOC_REQBUFS");
+
+       exit(EXIT_FAILURE);
+}
+
+/* We want at least five buffers. */
+
+if (reqbuf.count &lt; 5) {
+       /* You may need to free the buffers here. */
+       printf("Not enough buffer memory\n");
+       exit(EXIT_FAILURE);
+}
+
+buffers = calloc(reqbuf.count, sizeof(*buffers));
+assert(buffers != NULL);
+
+for (i = 0; i &lt; reqbuf.count; i++) {
+       &v4l2-buffer; buffer;
+       &v4l2-plane; planes[FMT_NUM_PLANES];
+
+       memset(&amp;buffer, 0, sizeof(buffer));
+       buffer.type = reqbuf.type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+       buffer.index = i;
+       /* length in struct v4l2_buffer in multi-planar API stores the size
+        * of planes array. */
+       buffer.length = FMT_NUM_PLANES;
+       buffer.m.planes = planes;
+
+       if (ioctl(fd, &VIDIOC-QUERYBUF;, &amp;buffer) &lt; 0) {
+               perror("VIDIOC_QUERYBUF");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Every plane has to be mapped separately */
+       for (j = 0; j &lt; FMT_NUM_PLANES; j++) {
+               buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
+
+               buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
+                                PROT_READ | PROT_WRITE, /* recommended */
+                                MAP_SHARED,             /* recommended */
+                                fd, buffer.m.planes[j].m.offset);
+
+               if (MAP_FAILED == buffers[i].start[j]) {
+                       /* If you do not exit here you should unmap() and free()
+                          the buffers and planes mapped so far. */
+                       perror("mmap");
+                       exit(EXIT_FAILURE);
+               }
        }
 }
 
 /* Cleanup. */
 
 for (i = 0; i &lt; reqbuf.count; i++)
-       munmap (buffers[i].start, buffers[i].length);
+       for (j = 0; j &lt; FMT_NUM_PLANES; j++)
+               munmap(buffers[i].start[j], buffers[i].length[j]);
       </programlisting>
     </example>
 
@@ -286,13 +372,13 @@ pointer method (not only memory mapping) is supported must be
 determined by calling the &VIDIOC-REQBUFS; ioctl.</para>
 
     <para>This I/O method combines advantages of the read/write and
-memory mapping methods. Buffers are allocated by the application
+memory mapping methods. Buffers (planes) are allocated by the application
 itself, and can reside for example in virtual or shared memory. Only
 pointers to data are exchanged, these pointers and meta-information
-are passed in &v4l2-buffer;. The driver must be switched
-into user pointer I/O mode by calling the &VIDIOC-REQBUFS; with the
-desired buffer type. No buffers are allocated beforehands,
-consequently they are not indexed and cannot be queried like mapped
+are passed in &v4l2-buffer; (or in &v4l2-plane; in the multi-planar API case).
+The driver must be switched into user pointer I/O mode by calling the
+&VIDIOC-REQBUFS; with the desired buffer type. No buffers (planes) are allocated
+beforehand, consequently they are not indexed and cannot be queried like mapped
 buffers with the <constant>VIDIOC_QUERYBUF</constant> ioctl.</para>
 
     <example>
@@ -316,7 +402,7 @@ if (ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf) == -1) {
       </programlisting>
     </example>
 
-    <para>Buffer addresses and sizes are passed on the fly with the
+    <para>Buffer (plane) addresses and sizes are passed on the fly with the
 &VIDIOC-QBUF; ioctl. Although buffers are commonly cycled,
 applications can pass different addresses and sizes at each
 <constant>VIDIOC_QBUF</constant> call. If required by the hardware the
@@ -396,11 +482,18 @@ rest should be evident.</para>
     <title>Buffers</title>
 
     <para>A buffer contains data exchanged by application and
-driver using one of the Streaming I/O methods. Only pointers to
-buffers are exchanged, the data itself is not copied. These pointers,
-together with meta-information like timestamps or field parity, are
-stored in a struct <structname>v4l2_buffer</structname>, argument to
-the &VIDIOC-QUERYBUF;, &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl.</para>
+driver using one of the Streaming I/O methods. In the multi-planar API, the
+data is held in planes, while the buffer structure acts as a container
+for the planes. Only pointers to buffers (planes) are exchanged, the data
+itself is not copied. These pointers, together with meta-information like
+timestamps or field parity, are stored in a struct
+<structname>v4l2_buffer</structname>, argument to
+the &VIDIOC-QUERYBUF;, &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl.
+In the multi-planar API, some plane-specific members of struct
+<structname>v4l2_buffer</structname>, such as pointers and sizes for each
+plane, are stored in struct <structname>v4l2_plane</structname> instead.
+In that case, struct <structname>v4l2_buffer</structname> contains an array of
+plane structures.</para>
 
       <para>Nominally timestamps refer to the first data byte transmitted.
 In practice however the wide range of hardware covered by the V4L2 API
@@ -551,26 +644,40 @@ in accordance with the selected I/O method.</entry>
            <entry></entry>
            <entry>__u32</entry>
            <entry><structfield>offset</structfield></entry>
-           <entry>When <structfield>memory</structfield> is
-<constant>V4L2_MEMORY_MMAP</constant> this is the offset of the buffer
-from the start of the device memory. The value is returned by the
-driver and apart of serving as parameter to the &func-mmap; function
-not useful for applications. See <xref linkend="mmap" /> for details.</entry>
+           <entry>For the single-planar API and when
+<structfield>memory</structfield> is <constant>V4L2_MEMORY_MMAP</constant> this
+is the offset of the buffer from the start of the device memory. The value is
+returned by the driver and apart of serving as parameter to the &func-mmap;
+function not useful for applications. See <xref linkend="mmap" /> for details
+         </entry>
          </row>
          <row>
            <entry></entry>
            <entry>unsigned long</entry>
            <entry><structfield>userptr</structfield></entry>
-           <entry>When <structfield>memory</structfield> is
-<constant>V4L2_MEMORY_USERPTR</constant> this is a pointer to the
-buffer (casted to unsigned long type) in virtual memory, set by the
-application. See <xref linkend="userp" /> for details.</entry>
+           <entry>For the single-planar API and when
+<structfield>memory</structfield> is <constant>V4L2_MEMORY_USERPTR</constant>
+this is a pointer to the buffer (casted to unsigned long type) in virtual
+memory, set by the application. See <xref linkend="userp" /> for details.
+           </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct v4l2_plane</entry>
+           <entry><structfield>*planes</structfield></entry>
+           <entry>When using the multi-planar API, contains a userspace pointer
+           to an array of &v4l2-plane;. The size of the array should be put
+           in the <structfield>length</structfield> field of this
+           <structname>v4l2_buffer</structname> structure.</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>length</structfield></entry>
            <entry></entry>
-           <entry>Size of the buffer (not the payload) in bytes.</entry>
+           <entry>Size of the buffer (not the payload) in bytes for the
+           single-planar API. For the multi-planar API should contain the
+           number of elements in the <structfield>planes</structfield> array.
+           </entry>
          </row>
          <row>
            <entry>__u32</entry>
@@ -596,6 +703,66 @@ should set this to 0.</entry>
       </tgroup>
     </table>
 
+    <table frame="none" pgwide="1" id="v4l2-plane">
+      <title>struct <structname>v4l2_plane</structname></title>
+      <tgroup cols="4">
+        &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>bytesused</structfield></entry>
+           <entry></entry>
+           <entry>The number of bytes occupied by data in the plane
+           (its payload).</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>length</structfield></entry>
+           <entry></entry>
+           <entry>Size in bytes of the plane (not its payload).</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>m</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>mem_offset</structfield></entry>
+           <entry>When the memory type in the containing &v4l2-buffer; is
+             <constant>V4L2_MEMORY_MMAP</constant>, this is the value that
+             should be passed to &func-mmap;, similar to the
+             <structfield>offset</structfield> field in &v4l2-buffer;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__unsigned long</entry>
+           <entry><structfield>userptr</structfield></entry>
+           <entry>When the memory type in the containing &v4l2-buffer; is
+             <constant>V4L2_MEMORY_USERPTR</constant>, this is a userspace
+             pointer to the memory allocated for this plane by an application.
+             </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>data_offset</structfield></entry>
+           <entry></entry>
+           <entry>Offset in bytes to video data in the plane, if applicable.
+           </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[11]</structfield></entry>
+           <entry></entry>
+           <entry>Reserved for future use. Should be zeroed by an
+           application.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
     <table frame="none" pgwide="1" id="v4l2-buf-type">
       <title>enum v4l2_buf_type</title>
       <tgroup cols="3">
@@ -604,13 +771,27 @@ should set this to 0.</entry>
          <row>
            <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
            <entry>1</entry>
-           <entry>Buffer of a video capture stream, see <xref
+           <entry>Buffer of a single-planar video capture stream, see <xref
+               linkend="capture" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
+           </entry>
+           <entry>9</entry>
+           <entry>Buffer of a multi-planar video capture stream, see <xref
                linkend="capture" />.</entry>
          </row>
          <row>
            <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
            <entry>2</entry>
-           <entry>Buffer of a video output stream, see <xref
+           <entry>Buffer of a single-planar video output stream, see <xref
+               linkend="output" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>
+           </entry>
+           <entry>10</entry>
+           <entry>Buffer of a multi-planar video output stream, see <xref
                linkend="output" />.</entry>
          </row>
          <row>
index 68134c0ab4d1b19aaf66c920bcc4e61662fcd68a..0e0453f39e73d931166da65ed23ec613d54155b0 100644 (file)
@@ -45,7 +45,7 @@ describing an IR signal are read from the chardev.</para>
 <para>The data written to the chardev is a pulse/space sequence of integer
 values. Pulses and spaces are only marked implicitly by their position. The
 data must start and end with a pulse, therefore, the data must always include
-an unevent number of samples. The write function must block until the data has
+an uneven number of samples. The write function must block until the data has
 been transmitted by the hardware.</para>
 </section>
 
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
new file mode 100644 (file)
index 0000000..2dc25e1
--- /dev/null
@@ -0,0 +1,89 @@
+<partinfo>
+  <authorgroup>
+    <author>
+      <firstname>Laurent</firstname>
+      <surname>Pinchart</surname>
+      <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
+      <contrib>Initial version.</contrib>
+    </author>
+  </authorgroup>
+  <copyright>
+    <year>2010</year>
+    <holder>Laurent Pinchart</holder>
+  </copyright>
+
+  <revhistory>
+    <!-- Put document revisions here, newest first. -->
+    <revision>
+      <revnumber>1.0.0</revnumber>
+      <date>2010-11-10</date>
+      <authorinitials>lp</authorinitials>
+      <revremark>Initial revision</revremark>
+    </revision>
+  </revhistory>
+</partinfo>
+
+<title>Media Controller API</title>
+
+<chapter id="media_controller">
+  <title>Media Controller</title>
+
+  <section id="media-controller-intro">
+    <title>Introduction</title>
+    <para>Media devices increasingly handle multiple related functions. Many USB
+    cameras include microphones, video capture hardware can also output video,
+    or SoC camera interfaces also perform memory-to-memory operations similar to
+    video codecs.</para>
+    <para>Independent functions, even when implemented in the same hardware, can
+    be modelled as separate devices. A USB camera with a microphone will be
+    presented to userspace applications as V4L2 and ALSA capture devices. The
+    devices' relationships (when using a webcam, end-users shouldn't have to
+    manually select the associated USB microphone), while not made available
+    directly to applications by the drivers, can usually be retrieved from
+    sysfs.</para>
+    <para>With more and more advanced SoC devices being introduced, the current
+    approach will not scale. Device topologies are getting increasingly complex
+    and can't always be represented by a tree structure. Hardware blocks are
+    shared between different functions, creating dependencies between seemingly
+    unrelated devices.</para>
+    <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
+    applications to access hardware parameters. As newer hardware expose an
+    increasingly high number of those parameters, drivers need to guess what
+    applications really require based on limited information, thereby
+    implementing policies that belong to userspace.</para>
+    <para>The media controller API aims at solving those problems.</para>
+  </section>
+
+  <section id="media-controller-model">
+    <title>Media device model</title>
+    <para>Discovering a device internal topology, and configuring it at runtime,
+    is one of the goals of the media controller API. To achieve this, hardware
+    devices are modelled as an oriented graph of building blocks called entities
+    connected through pads.</para>
+    <para>An entity is a basic media hardware or software building block. It can
+    correspond to a large variety of logical blocks such as physical hardware
+    devices (CMOS sensor for instance), logical hardware devices (a building
+    block in a System-on-Chip image processing pipeline), DMA channels or
+    physical connectors.</para>
+    <para>A pad is a connection endpoint through which an entity can interact
+    with other entities. Data (not restricted to video) produced by an entity
+    flows from the entity's output to one or more entity inputs. Pads should not
+    be confused with physical pins at chip boundaries.</para>
+    <para>A link is a point-to-point oriented connection between two pads,
+    either on the same entity or on different entities. Data flows from a source
+    pad to a sink pad.</para>
+  </section>
+</chapter>
+
+<appendix id="media-user-func">
+  <title>Function Reference</title>
+  <!-- Keep this alphabetically sorted. -->
+  &sub-media-open;
+  &sub-media-close;
+  &sub-media-ioctl;
+  <!-- All ioctls go here. -->
+  &sub-media-ioc-device-info;
+  &sub-media-ioc-enum-entities;
+  &sub-media-ioc-enum-links;
+  &sub-media-ioc-setup-link;
+</appendix>
diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/v4l/media-func-close.xml
new file mode 100644 (file)
index 0000000..be149c8
--- /dev/null
@@ -0,0 +1,59 @@
+<refentry id="media-func-close">
+  <refmeta>
+    <refentrytitle>media close()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-close</refname>
+    <refpurpose>Close a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>close</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Closes the media device. Resources associated with the file descriptor
+    are freed. The device configuration remain unchanged.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>close</function> returns 0 on success. On error, -1 is
+    returned, and <varname>errno</varname> is set appropriately. Possible error
+    codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid open file descriptor.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/v4l/media-func-ioctl.xml
new file mode 100644 (file)
index 0000000..bda8604
--- /dev/null
@@ -0,0 +1,116 @@
+<refentry id="media-func-ioctl">
+  <refmeta>
+    <refentrytitle>media ioctl()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-ioctl</refname>
+    <refpurpose>Control a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>void *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>Media ioctl request code as defined in the media.h header file,
+         for example MEDIA_IOC_SETUP_LINK.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a request-specific structure.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>The <function>ioctl()</function> function manipulates media device
+    parameters. The argument <parameter>fd</parameter> must be an open file
+    descriptor.</para>
+    <para>The ioctl <parameter>request</parameter> code specifies the media
+    function to be called. It has encoded in it whether the argument is an
+    input, output or read/write parameter, and the size of the argument
+    <parameter>argp</parameter> in bytes.</para>
+    <para>Macros and structures definitions specifying media ioctl requests and
+    their parameters are located in the media.h header file. All media ioctl
+    requests, their respective function and parameters are specified in
+    <xref linkend="media-user-func" />.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
+    success. On failure, <returnvalue>-1</returnvalue> is returned, and the
+    <varname>errno</varname> variable is set appropriately. Generic error codes
+    are listed below, and request-specific error codes are listed in the
+    individual requests descriptions.</para>
+    <para>When an ioctl that takes an output or read/write parameter fails,
+    the parameter remains unmodified.</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid open file descriptor.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EFAULT</errorcode></term>
+       <listitem>
+         <para><parameter>argp</parameter> references an inaccessible memory
+         area.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <parameter>request</parameter> or the data pointed to by
+         <parameter>argp</parameter> is not valid. This is a very common error
+         code, see the individual ioctl requests listed in
+         <xref linkend="media-user-func" /> for actual causes.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOMEM</errorcode></term>
+       <listitem>
+         <para>Insufficient kernel memory was available to complete the
+         request.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOTTY</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is  not  associated  with  a character
+         special device.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/v4l/media-func-open.xml
new file mode 100644 (file)
index 0000000..f7df034
--- /dev/null
@@ -0,0 +1,94 @@
+<refentry id="media-func-open">
+  <refmeta>
+    <refentrytitle>media open()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-open</refname>
+    <refpurpose>Open a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>open</function></funcdef>
+       <paramdef>const char *<parameter>device_name</parameter></paramdef>
+       <paramdef>int <parameter>flags</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>device_name</parameter></term>
+       <listitem>
+         <para>Device to be opened.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>flags</parameter></term>
+       <listitem>
+         <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
+         or <constant>O_RDWR</constant>. Other flags have no effect.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>Description</title>
+    <para>To open a media device applications call <function>open()</function>
+    with the desired device name. The function has no side effects; the device
+    configuration remain unchanged.</para>
+    <para>When the device is opened in read-only mode, attemps to modify its
+    configuration will result in an error, and <varname>errno</varname> will be
+    set to <errorcode>EBADF</errorcode>.</para>
+  </refsect1>
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>open</function> returns the new file descriptor on success.
+    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
+    Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>The requested access to the file is not allowed.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EMFILE</errorcode></term>
+       <listitem>
+         <para>The  process  already  has  the  maximum number of files open.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENFILE</errorcode></term>
+       <listitem>
+         <para>The system limit on the total number of open files has been
+         reached.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOMEM</errorcode></term>
+       <listitem>
+         <para>Insufficient kernel memory was available.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENXIO</errorcode></term>
+       <listitem>
+         <para>No device corresponding to this device special file exists.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
new file mode 100644 (file)
index 0000000..1f32373
--- /dev/null
@@ -0,0 +1,133 @@
+<refentry id="media-ioc-device-info">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_DEVICE_INFO</refname>
+    <refpurpose>Query device information</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_DEVICE_INFO</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
+    ioctl. To query device information, applications call the ioctl with a
+    pointer to a &media-device-info;. The driver fills the structure and returns
+    the information to the application.
+    The ioctl never fails.</para>
+
+    <table pgwide="1" frame="none" id="media-device-info">
+      <title>struct <structname>media_device_info</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>char</entry>
+           <entry><structfield>driver</structfield>[16]</entry>
+           <entry><para>Name of the driver implementing the media API as a
+           NUL-terminated ASCII string. The driver version is stored in the
+           <structfield>driver_version</structfield> field.</para>
+           <para>Driver specific applications can use this information to
+           verify the driver identity. It is also useful to work around
+           known bugs, or to identify drivers in error reports.</para></entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>model</structfield>[32]</entry>
+           <entry>Device model name as a NUL-terminated UTF-8 string. The
+           device version is stored in the <structfield>device_version</structfield>
+           field and is not be appended to the model name.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>serial</structfield>[40]</entry>
+           <entry>Serial number as a NUL-terminated ASCII string.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>bus_info</structfield>[32]</entry>
+           <entry>Location of the device in the system as a NUL-terminated
+           ASCII string. This includes the bus type name (PCI, USB, ...) and a
+           bus-specific identifier.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>media_version</structfield></entry>
+           <entry>Media API version, formatted with the
+           <constant>KERNEL_VERSION()</constant> macro.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>hw_revision</structfield></entry>
+           <entry>Hardware device revision in a driver-specific format.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>media_version</structfield></entry>
+           <entry>Media device driver version, formatted with the
+           <constant>KERNEL_VERSION()</constant> macro. Together with the
+           <structfield>driver</structfield> field this identifies a particular
+           driver.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[31]</entry>
+           <entry>Reserved for future extensions. Drivers and applications must
+           set this array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+    <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
+    fields can be used to distinguish between multiple instances of otherwise
+    identical hardware. The serial number takes precedence when provided and can
+    be assumed to be unique. If the serial number is an empty string, the
+    <structfield>bus_info</structfield> field can be used instead. The
+    <structfield>bus_info</structfield> field is guaranteed to be unique, but
+    can vary across reboots or device unplug/replug.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return value</title>
+    <para>This function doesn't return specific error codes.</para>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
new file mode 100644 (file)
index 0000000..576b68b
--- /dev/null
@@ -0,0 +1,308 @@
+<refentry id="media-ioc-enum-entities">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
+    <refpurpose>Enumerate entities and their properties</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_ENUM_ENTITIES</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To query the attributes of an entity, applications set the id field
+    of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
+    ioctl with a pointer to this structure. The driver fills the rest of the
+    structure or returns an &EINVAL; when the id is invalid.</para>
+    <para>Entities can be enumerated by or'ing the id with the
+    <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
+    information about the entity with the smallest id strictly larger than the
+    requested one ('next entity'), or the &EINVAL; if there is none.</para>
+    <para>Entity IDs can be non-contiguous. Applications must
+    <emphasis>not</emphasis> try to enumerate entities by calling
+    MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
+    <para>Two or more entities that share a common non-zero
+    <structfield>group_id</structfield> value are considered as logically
+    grouped. Groups are used to report
+    <itemizedlist>
+      <listitem><para>ALSA, VBI and video nodes that carry the same media
+      stream</para></listitem>
+      <listitem><para>lens and flash controllers associated with a sensor</para></listitem>
+    </itemizedlist>
+    </para>
+
+    <table pgwide="1" frame="none" id="media-entity-desc">
+      <title>struct <structname>media_entity_desc</structname></title>
+      <tgroup cols="5">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <colspec colname="c5" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity id, set by the application. When the id is or'ed with
+           <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
+           flag and returns the first entity with a larger id.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>revision</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity revision in a driver/hardware specific format.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>group_id</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity group ID</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>pads</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Number of pads</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>links</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Total number of outbound links. Inbound links are not counted
+           in this field.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>v4l</structfield></entry>
+           <entry></entry>
+           <entry>Valid for V4L sub-devices and nodes only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>major</structfield></entry>
+           <entry>V4L device node major number. For V4L sub-devices with no
+           device node, set by the driver to 0.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>minor</structfield></entry>
+           <entry>V4L device node minor number. For V4L sub-devices with no
+           device node, set by the driver to 0.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>fb</structfield></entry>
+           <entry></entry>
+           <entry>Valid for frame buffer nodes only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>major</structfield></entry>
+           <entry>Frame buffer device node major number.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>minor</structfield></entry>
+           <entry>Frame buffer device node minor number.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>alsa</structfield></entry>
+           <entry></entry>
+           <entry>Valid for ALSA devices only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>card</structfield></entry>
+           <entry>ALSA card number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>device</structfield></entry>
+           <entry>ALSA device number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>subdevice</structfield></entry>
+           <entry>ALSA sub-device number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>int</entry>
+           <entry><structfield>dvb</structfield></entry>
+           <entry></entry>
+           <entry>DVB card number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+           <entry><structfield>raw</structfield>[180]</entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-entity-type">
+      <title>Media entity types</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
+           <entry>Unknown device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
+           <entry>V4L video, radio or vbi device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
+           <entry>Frame buffer device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
+           <entry>ALSA card</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
+           <entry>DVB card</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
+           <entry>Unknown V4L sub-device</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
+           <entry>Video sensor</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
+           <entry>Flash controller</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
+           <entry>Lens controller</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-entity-flag">
+      <title>Media entity flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
+           <entry>Default entity for its type. Used to discover the default
+           audio, VBI and video devices, the default camera sensor, ...</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-entity-desc; <structfield>id</structfield> references
+         a non-existing entity.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
new file mode 100644 (file)
index 0000000..d2fc73e
--- /dev/null
@@ -0,0 +1,207 @@
+<refentry id="media-ioc-enum-links">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_ENUM_LINKS</refname>
+    <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_ENUM_LINKS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To enumerate pads and/or links for a given entity, applications set
+    the entity field of a &media-links-enum; structure and initialize the
+    &media-pad-desc; and &media-link-desc; structure arrays pointed by the
+    <structfield>pads</structfield> and <structfield>links</structfield> fields.
+    They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
+    structure.</para>
+    <para>If the <structfield>pads</structfield> field is not NULL, the driver
+    fills the <structfield>pads</structfield> array with information about the
+    entity's pads. The array must have enough room to store all the entity's
+    pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
+    ioctl.</para>
+    <para>If the <structfield>links</structfield> field is not NULL, the driver
+    fills the <structfield>links</structfield> array with information about the
+    entity's outbound links. The array must have enough room to store all the
+    entity's outbound links. The number of outbound links can be retrieved with
+    the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
+    <para>Only forward links that originate at one of the entity's source pads
+    are returned during the enumeration process.</para>
+
+    <table pgwide="1" frame="none" id="media-links-enum">
+      <title>struct <structname>media_links_enum</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entity</structfield></entry>
+           <entry>Entity id, set by the application.</entry>
+         </row>
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry>*<structfield>pads</structfield></entry>
+           <entry>Pointer to a pads array allocated by the application. Ignored
+           if NULL.</entry>
+         </row>
+         <row>
+           <entry>struct &media-link-desc;</entry>
+           <entry>*<structfield>links</structfield></entry>
+           <entry>Pointer to a links array allocated by the application. Ignored
+           if NULL.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="media-pad-desc">
+      <title>struct <structname>media_pad_desc</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entity</structfield></entry>
+           <entry>ID of the entity this pad belongs to.</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>0-based pad index.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-pad-flag">
+      <title>Media pad flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
+           <entry>Input pad, relative to the entity. Input pads sink data and
+           are targets of links.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
+           <entry>Output pad, relative to the entity. Output pads source data
+           and are origins of links.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="media-link-desc">
+      <title>struct <structname>media_links_desc</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry><structfield>source</structfield></entry>
+           <entry>Pad at the origin of this link.</entry>
+         </row>
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry><structfield>sink</structfield></entry>
+           <entry>Pad at the target of this link.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-link-flag">
+      <title>Media link flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
+           <entry>The link is enabled and can be used to transfer media data.
+           When two or more links target a sink pad, only one of them can be
+           enabled at a time.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
+           <entry>The link enabled state can't be modified at runtime. An
+           immutable link is always enabled.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
+           <entry>The link enabled state can be modified during streaming. This
+           flag is set by drivers and is read-only for applications.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+    <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
+    <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-links-enum; <structfield>id</structfield> references
+         a non-existing entity.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
new file mode 100644 (file)
index 0000000..2331e76
--- /dev/null
@@ -0,0 +1,93 @@
+<refentry id="media-ioc-setup-link">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_SETUP_LINK</refname>
+    <refpurpose>Modify the properties of a link</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_ENUM_LINKS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To change link properties applications fill a &media-link-desc; with
+    link identification information (source and sink pad) and the new requested
+    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
+    that structure.</para>
+    <para>The only configurable property is the <constant>ENABLED</constant>
+    link flag to enable/disable a link. Links marked with the
+    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
+    </para>
+    <para>Link configuration has no side effect on other links. If an enabled
+    link at the sink pad prevents the link from being enabled, the driver
+    returns with an &EBUSY;.</para>
+    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
+    be enabled/disabled while streaming media data. Attempting to enable or
+    disable a streaming non-dynamic link will return an &EBUSY;.</para>
+    <para>If the specified link can't be found the driver returns with an
+    &EINVAL;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The link properties can't be changed because the link is
+         currently busy. This can be caused, for instance, by an active media
+         stream (audio or video) on the link. The ioctl shouldn't be retried if
+         no other action is performed before to fix the problem.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-link-desc; references a non-existing link, or the
+         link is immutable and an attempt to modify its configuration was made.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/nv12mt.gif b/Documentation/DocBook/v4l/nv12mt.gif
new file mode 100644 (file)
index 0000000..ef2d4cf
Binary files /dev/null and b/Documentation/DocBook/v4l/nv12mt.gif differ
diff --git a/Documentation/DocBook/v4l/nv12mt_example.gif b/Documentation/DocBook/v4l/nv12mt_example.gif
new file mode 100644 (file)
index 0000000..df81d68
Binary files /dev/null and b/Documentation/DocBook/v4l/nv12mt_example.gif differ
diff --git a/Documentation/DocBook/v4l/pipeline.pdf b/Documentation/DocBook/v4l/pipeline.pdf
new file mode 100644 (file)
index 0000000..ee3e37f
Binary files /dev/null and b/Documentation/DocBook/v4l/pipeline.pdf differ
diff --git a/Documentation/DocBook/v4l/pipeline.png b/Documentation/DocBook/v4l/pipeline.png
new file mode 100644 (file)
index 0000000..f19b86c
Binary files /dev/null and b/Documentation/DocBook/v4l/pipeline.png differ
diff --git a/Documentation/DocBook/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/v4l/pixfmt-nv12m.xml
new file mode 100644 (file)
index 0000000..c9e166d
--- /dev/null
@@ -0,0 +1,154 @@
+    <refentry id="V4L2-PIX-FMT-NV12M">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV12M ('NV12M')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname> <constant>V4L2_PIX_FMT_NV12M</constant></refname>
+       <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> with planes
+         non contiguous in memory. </refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is a multi-planar, two-plane version of the YUV 4:2:0 format.
+The three components are separated into two sub-images or planes.
+<constant>V4L2_PIX_FMT_NV12M</constant> differs from <constant>V4L2_PIX_FMT_NV12
+</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
+plane do not necessarily immediately follows the luma plane.
+The luminance data occupies the first plane. The Y plane has one byte per pixel.
+In the second plane there is a chrominance data with alternating chroma samples.
+The CbCr plane is the same width, in bytes, as the Y plane (and of the image),
+but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. </para>
+
+       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
+used only in drivers and applications that support the multi-planar API,
+described in <xref linkend="planar-apis"/>. </para>
+
+       <para>If the Y plane has pad bytes after each row, then the
+CbCr plane has as many pad bytes after its rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_NV12M</constant> 4 &times; 4 pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;4:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/v4l/pixfmt-nv12mt.xml
new file mode 100644 (file)
index 0000000..7a2855a
--- /dev/null
@@ -0,0 +1,74 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV12MT ('TM12')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-NV12MT"><constant>V4L2_PIX_FMT_NV12MT
+</constant></refname>
+       <refpurpose>Formats with &frac12; horizontal and vertical
+chroma resolution. This format has two planes - one for luminance and one for
+chrominance. Chroma samples are interleaved. The difference to
+<constant>V4L2_PIX_FMT_NV12</constant> is the memory layout. Pixels are
+grouped in macroblocks of 64x32 size. The order of macroblocks in memory is
+also not standard.
+       </refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is the two-plane versions of the YUV 4:2:0 format where data
+is grouped into 64x32 macroblocks. The three components are separated into two
+sub-images or planes. The Y plane has one byte per pixel and pixels are grouped
+into 64x32 macroblocks. The CbCr plane has the same width, in bytes, as the Y
+plane (and the image), but is half as tall in pixels. The chroma plane is also
+grouped into 64x32 macroblocks.</para>
+       <para>Width of the buffer has to be aligned to the multiple of 128, and
+height alignment is 32. Every four adjactent buffers - two horizontally and two
+vertically are grouped together and are located in memory in Z or flipped Z
+order. </para>
+       <para>Layout of macroblocks in memory is presented in the following
+figure.</para>
+       <para><figure id="nv12mt">
+           <title><constant>V4L2_PIX_FMT_NV12MT</constant> macroblock Z shape
+memory layout</title>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="nv12mt.gif" format="GIF" />
+             </imageobject>
+           </mediaobject>
+       </figure>
+       The requirement that width is multiple of 128 is implemented because,
+the Z shape cannot be cut in half horizontally. In case the vertical resolution
+of macroblocks is odd then the last row of macroblocks is arranged in a linear
+order.  </para>
+       <para>In case of chroma the layout is identical. Cb and Cr samples are
+interleaved. Height of the buffer is aligned to 32.
+       </para>
+       <example>
+         <title>Memory layout of macroblocks in <constant>V4L2_PIX_FMT_NV12
+</constant> format pixel image - extreme case</title>
+       <para>
+       <figure id="nv12mt_ex">
+           <title>Example <constant>V4L2_PIX_FMT_NV12MT</constant> memory
+layout of macroblocks</title>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="nv12mt_example.gif" format="GIF" />
+             </imageobject>
+           </mediaobject>
+       </figure>
+       Memory layout of macroblocks of <constant>V4L2_PIX_FMT_NV12MT
+</constant> format in most extreme case.
+       </para>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/v4l/pixfmt-srggb12.xml
new file mode 100644 (file)
index 0000000..9ba4fb6
--- /dev/null
@@ -0,0 +1,90 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB12 ('RG12'),
+        V4L2_PIX_FMT_SGRBG12 ('BA12'),
+        V4L2_PIX_FMT_SGBRG12 ('GB12'),
+        V4L2_PIX_FMT_SBGGR12 ('BG12'),
+        </refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-SRGGB12"><constant>V4L2_PIX_FMT_SRGGB12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGRBG12"><constant>V4L2_PIX_FMT_SGRBG12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGBRG12"><constant>V4L2_PIX_FMT_SGBRG12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SBGGR12"><constant>V4L2_PIX_FMT_SBGGR12</constant></refname>
+       <refpurpose>12-bit Bayer formats expanded to 16 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>The following four pixel formats are raw sRGB / Bayer formats with
+12 bits per colour. Each colour component is stored in a 16-bit word, with 6
+unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes are
+stored in memory in little endian order. They are conventionally described
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR12</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte, high 6 bits in high bytes are 0.
+         <informaltable frame="none">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00low</subscript></entry>
+                 <entry>B<subscript>00high</subscript></entry>
+                 <entry>G<subscript>01low</subscript></entry>
+                 <entry>G<subscript>01high</subscript></entry>
+                 <entry>B<subscript>02low</subscript></entry>
+                 <entry>B<subscript>02high</subscript></entry>
+                 <entry>G<subscript>03low</subscript></entry>
+                 <entry>G<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>G<subscript>10low</subscript></entry>
+                 <entry>G<subscript>10high</subscript></entry>
+                 <entry>R<subscript>11low</subscript></entry>
+                 <entry>R<subscript>11high</subscript></entry>
+                 <entry>G<subscript>12low</subscript></entry>
+                 <entry>G<subscript>12high</subscript></entry>
+                 <entry>R<subscript>13low</subscript></entry>
+                 <entry>R<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>B<subscript>20low</subscript></entry>
+                 <entry>B<subscript>20high</subscript></entry>
+                 <entry>G<subscript>21low</subscript></entry>
+                 <entry>G<subscript>21high</subscript></entry>
+                 <entry>B<subscript>22low</subscript></entry>
+                 <entry>B<subscript>22high</subscript></entry>
+                 <entry>G<subscript>23low</subscript></entry>
+                 <entry>G<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>G<subscript>30low</subscript></entry>
+                 <entry>G<subscript>30high</subscript></entry>
+                 <entry>R<subscript>31low</subscript></entry>
+                 <entry>R<subscript>31high</subscript></entry>
+                 <entry>G<subscript>32low</subscript></entry>
+                 <entry>G<subscript>32high</subscript></entry>
+                 <entry>R<subscript>33low</subscript></entry>
+                 <entry>R<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/v4l/pixfmt-yuv420m.xml
new file mode 100644 (file)
index 0000000..f5d8f57
--- /dev/null
@@ -0,0 +1,162 @@
+    <refentry id="V4L2-PIX-FMT-YUV420M">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YUV420M ('YU12M')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname> <constant>V4L2_PIX_FMT_YUV420M</constant></refname>
+       <refpurpose>Variation of <constant>V4L2_PIX_FMT_YUV420</constant>
+         with planes non contiguous in memory. </refpurpose>
+      </refnamediv>
+
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is a multi-planar format, as opposed to a packed format.
+The three components are separated into three sub- images or planes.
+
+The Y plane is first. The Y plane has one byte per pixel. The Cb data
+constitutes the second plane which is half the width and half
+the height of the Y plane (and of the image). Each Cb belongs to four
+pixels, a two-by-two square of the image. For example,
+Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
+Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
+Y'<subscript>11</subscript>. The Cr data, just like the Cb plane, is
+in the third plane. </para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cb
+and Cr planes have half as many pad bytes after their rows. In other
+words, two Cx rows (including padding) is exactly as long as one Y row
+(including padding).</para>
+
+       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
+used only in drivers and applications that support the multi-planar API,
+described in <xref linkend="planar-apis"/>. </para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YVU420M</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row><entry></entry></row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;2:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                   </row>
+                   <row><entry></entry></row>
+                   <row>
+                     <entry>start2&nbsp;+&nbsp;0:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start2&nbsp;+&nbsp;2:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
index cfffc88d7383f4dc14b409f03e13964859af4c61..c6fdcbbd1b41dc7adbffc0011ac34a291b503509 100644 (file)
@@ -2,12 +2,16 @@
 
   <para>The V4L2 API was primarily designed for devices exchanging
 image data with applications. The
-<structname>v4l2_pix_format</structname> structure defines the format
-and layout of an image in memory. Image formats are negotiated with
-the &VIDIOC-S-FMT; ioctl. (The explanations here focus on video
+<structname>v4l2_pix_format</structname> and <structname>v4l2_pix_format_mplane
+</structname> structures define the format and layout of an image in memory.
+The former is used with the single-planar API, while the latter is used with the
+multi-planar version (see <xref linkend="planar-apis"/>). Image formats are
+negotiated with the &VIDIOC-S-FMT; ioctl. (The explanations here focus on video
 capturing and output, for overlay frame buffer formats see also
 &VIDIOC-G-FBUF;.)</para>
 
+<section>
+  <title>Single-planar format structure</title>
   <table pgwide="1" frame="none" id="v4l2-pix-format">
     <title>struct <structname>v4l2_pix_format</structname></title>
     <tgroup cols="3">
@@ -106,6 +110,98 @@ set this field to zero.</entry>
       </tbody>
     </tgroup>
   </table>
+</section>
+
+<section>
+  <title>Multi-planar format structures</title>
+  <para>The <structname>v4l2_plane_pix_format</structname> structures define
+    size and layout for each of the planes in a multi-planar format.
+    The <structname>v4l2_pix_format_mplane</structname> structure contains
+    information common to all planes (such as image width and height) and
+    an array of <structname>v4l2_plane_pix_format</structname> structures,
+    describing all planes of that format.</para>
+  <table pgwide="1" frame="none" id="v4l2-plane-pix-format">
+    <title>struct <structname>vl42_plane_pix_format</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>sizeimage</structfield></entry>
+          <entry>Maximum size in bytes required for image data in this plane.
+          </entry>
+        </row>
+        <row>
+          <entry>__u16</entry>
+          <entry><structfield>bytesperline</structfield></entry>
+          <entry>Distance in bytes between the leftmost pixels in two adjacent
+            lines.</entry>
+        </row>
+        <row>
+          <entry>__u16</entry>
+          <entry><structfield>reserved[7]</structfield></entry>
+          <entry>Reserved for future extensions. Should be zeroed by the
+           application.</entry>
+        </row>
+      </tbody>
+    </tgroup>
+  </table>
+  <table pgwide="1" frame="none" id="v4l2-pix-format-mplane">
+    <title>struct <structname>v4l2_pix_format_mplane</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>width</structfield></entry>
+          <entry>Image width in pixels.</entry>
+        </row>
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>height</structfield></entry>
+          <entry>Image height in pixels.</entry>
+        </row>
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>pixelformat</structfield></entry>
+          <entry>The pixel format. Both single- and multi-planar four character
+codes can be used.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-field;</entry>
+          <entry><structfield>field</structfield></entry>
+          <entry>See &v4l2-pix-format;.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-colorspace;</entry>
+          <entry><structfield>colorspace</structfield></entry>
+          <entry>See &v4l2-pix-format;.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-plane-pix-format;</entry>
+          <entry><structfield>plane_fmt[VIDEO_MAX_PLANES]</structfield></entry>
+          <entry>An array of structures describing format of each plane this
+          pixel format consists of. The number of valid entries in this array
+          has to be put in the <structfield>num_planes</structfield>
+          field.</entry>
+        </row>
+        <row>
+          <entry>__u8</entry>
+          <entry><structfield>num_planes</structfield></entry>
+          <entry>Number of planes (i.e. separate memory buffers) for this format
+          and the number of valid entries in the
+          <structfield>plane_fmt</structfield> array.</entry>
+        </row>
+        <row>
+          <entry>__u8</entry>
+          <entry><structfield>reserved[11]</structfield></entry>
+          <entry>Reserved for future extensions. Should be zeroed by the
+           application.</entry>
+        </row>
+      </tbody>
+    </tgroup>
+  </table>
+</section>
 
   <section>
     <title>Standard Image Formats</title>
@@ -142,11 +238,19 @@ leftmost pixel of the second row from the top, and so on. The last row
 has just as many pad bytes after it as the other rows.</para>
 
     <para>In V4L2 each format has an identifier which looks like
-<constant>PIX_FMT_XXX</constant>, defined in the <filename>videodev2.h</filename>
-header file. These identifiers
-represent <link linkend="v4l2-fourcc">four character codes</link>
+<constant>PIX_FMT_XXX</constant>, defined in the <link
+linkend="videodev">videodev.h</link> header file. These identifiers
+represent <link linkend="v4l2-fourcc">four character (FourCC) codes</link>
 which are also listed below, however they are not the same as those
 used in the Windows world.</para>
+
+    <para>For some formats, data is stored in separate, discontiguous
+memory buffers. Those formats are identified by a separate set of FourCC codes
+and are referred to as "multi-planar formats". For example, a YUV422 frame is
+normally stored in one memory buffer, but it can also be placed in two or three
+separate buffers, with Y component in one buffer and CbCr components in another
+in the 2-planar version or with each component in its own buffer in the
+3-planar case. Those sub-buffers are referred to as "planes".</para>
   </section>
 
   <section id="colorspaces">
@@ -599,10 +703,13 @@ information.</para>
     &sub-vyuy;
     &sub-y41p;
     &sub-yuv420;
+    &sub-yuv420m;
     &sub-yuv410;
     &sub-yuv422p;
     &sub-yuv411p;
     &sub-nv12;
+    &sub-nv12m;
+    &sub-nv12mt;
     &sub-nv16;
   </section>
 
diff --git a/Documentation/DocBook/v4l/planar-apis.xml b/Documentation/DocBook/v4l/planar-apis.xml
new file mode 100644 (file)
index 0000000..878ce20
--- /dev/null
@@ -0,0 +1,62 @@
+<section id="planar-apis">
+  <title>Single- and multi-planar APIs</title>
+
+  <para>Some devices require data for each input or output video frame
+  to be placed in discontiguous memory buffers. In such cases, one
+  video frame has to be addressed using more than one memory address, i.e. one
+  pointer per "plane". A plane is a sub-buffer of the current frame. For
+  examples of such formats see <xref linkend="pixfmt" />.</para>
+
+  <para>Initially, V4L2 API did not support multi-planar buffers and a set of
+  extensions has been introduced to handle them. Those extensions constitute
+  what is being referred to as the "multi-planar API".</para>
+
+  <para>Some of the V4L2 API calls and structures are interpreted differently,
+  depending on whether single- or multi-planar API is being used. An application
+  can choose whether to use one or the other by passing a corresponding buffer
+  type to its ioctl calls. Multi-planar versions of buffer types are suffixed
+  with an `_MPLANE' string. For a list of available multi-planar buffer types
+  see &v4l2-buf-type;.
+  </para>
+
+  <section>
+    <title>Multi-planar formats</title>
+    <para>Multi-planar API introduces new multi-planar formats. Those formats
+    use a separate set of FourCC codes. It is important to distinguish between
+    the multi-planar API and a multi-planar format. Multi-planar API calls can
+    handle all single-planar formats as well (as long as they are passed in
+    multi-planar API structures), while the single-planar API cannot
+    handle multi-planar formats.</para>
+  </section>
+
+  <section>
+    <title>Calls that distinguish between single and multi-planar APIs</title>
+    <variablelist>
+      <varlistentry>
+        <term>&VIDIOC-QUERYCAP;</term>
+        <listitem><para>Two additional multi-planar capabilities are added. They can
+        be set together with non-multi-planar ones for devices that handle
+        both single- and multi-planar formats.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-G-FMT;, &VIDIOC-S-FMT;, &VIDIOC-TRY-FMT;</term>
+        <listitem><para>New structures for describing multi-planar formats are added:
+        &v4l2-pix-format-mplane; and &v4l2-plane-pix-format;. Drivers may
+        define new multi-planar formats, which have distinct FourCC codes from
+        the existing single-planar ones.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-QBUF;, &VIDIOC-DQBUF;, &VIDIOC-QUERYBUF;</term>
+        <listitem><para>A new &v4l2-plane; structure for describing planes is added.
+        Arrays of this structure are passed in the new
+        <structfield>m.planes</structfield> field of &v4l2-buffer;.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-REQBUFS;</term>
+        <listitem><para>Will allocate multi-planar buffers as requested.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </section>
+</section>
diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
new file mode 100644 (file)
index 0000000..7041127
--- /dev/null
@@ -0,0 +1,2467 @@
+<section id="v4l2-mbus-format">
+  <title>Media Bus Formats</title>
+
+  <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
+    <title>struct <structname>v4l2_mbus_framefmt</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>width</structfield></entry>
+         <entry>Image width, in pixels.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>height</structfield></entry>
+         <entry>Image height, in pixels.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>code</structfield></entry>
+         <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>field</structfield></entry>
+         <entry>Field order, from &v4l2-field;. See
+         <xref linkend="field-order" /> for details.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>colorspace</structfield></entry>
+         <entry>Image colorspace, from &v4l2-colorspace;. See
+         <xref linkend="colorspaces" /> for details.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>reserved</structfield>[7]</entry>
+         <entry>Reserved for future extensions. Applications and drivers must
+         set the array to zero.</entry>
+       </row>
+      </tbody>
+    </tgroup>
+  </table>
+
+  <section id="v4l2-mbus-pixelcode">
+    <title>Media Bus Pixel Codes</title>
+
+    <para>The media bus pixel codes describe image formats as flowing over
+    physical busses (both between separate physical components and inside SoC
+    devices). This should not be confused with the V4L2 pixel formats that
+    describe, using four character codes, image formats as stored in memory.
+    </para>
+
+    <para>While there is a relationship between image formats on busses and
+    image formats in memory (a raw Bayer image won't be magically converted to
+    JPEG just by storing it to memory), there is no one-to-one correspondance
+    between them.</para>
+
+    <section>
+      <title>Packed RGB Formats</title>
+
+      <para>Those formats transfer pixel data as red, green and blue components.
+      The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The red, green and blue components order code, as encoded in a
+       pixel sample. Possible values are RGB and BGR.</para></listitem>
+       <listitem><para>The number of bits per component, for each component. The values
+       can be different for all components. Common values are 555 and 565.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1 and 2.</para></listitem>
+       <listitem><para>The bus width.</para></listitem>
+       <listitem><para>For formats where the total number of bits per pixel is smaller
+       than the number of bus samples per pixel times the bus width, a padding
+       value stating if the bytes are padded in their most high order bits
+       (PADHI) or low order bits (PADLO).</para></listitem>
+       <listitem><para>For formats where the number of bus samples per pixel is larger
+       than 1, an endianness value stating if the pixel is transferred MSB first
+       (BE) or LSB first (LE).</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
+      green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
+      samples per pixel with the most significant bits (padding, red and half of
+      the green value) transferred first will be named
+      <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
+      </para>
+
+      <para>The following tables list existing packet RGB formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
+       <title>RGB formats</title>
+       <tgroup cols="11">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b07" align="center" />
+         <colspec colnum="5" colname="b06" align="center" />
+         <colspec colnum="6" colname="b05" align="center" />
+         <colspec colnum="7" colname="b04" align="center" />
+         <colspec colnum="8" colname="b03" align="center" />
+         <colspec colnum="9" colname="b02" align="center" />
+         <colspec colnum="10" colname="b01" align="center" />
+         <colspec colnum="11" colname="b00" align="center" />
+         <spanspec namest="b07" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
+             <entry>0x1001</entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
+             <entry>0x1002</entry>
+             <entry></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
+             <entry>0x1003</entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
+             <entry>0x1004</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
+             <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
+             <entry>0x1005</entry>
+             <entry></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
+             <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
+             <entry>0x1006</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
+             <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
+             <entry>0x1007</entry>
+             <entry></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
+             <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
+             <entry>0x1008</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
+    <section>
+      <title>Bayer Formats</title>
+
+      <para>Those formats transfer pixel data as red, green and blue components.
+      The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The red, green and blue components order code, as encoded in a
+       pixel sample. The possible values are shown in <xref
+       linkend="bayer-patterns" />.</para></listitem>
+       <listitem><para>The number of bits per pixel component. All components are
+       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
+       </listitem>
+       <listitem><para>If the pixel components are DPCM-compressed, a mention of the
+       DPCM compression and the number of bits per compressed pixel component.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1 and 2.</para></listitem>
+       <listitem><para>The bus width.</para></listitem>
+       <listitem><para>For formats where the total number of bits per pixel is smaller
+       than the number of bus samples per pixel times the bus width, a padding
+       value stating if the bytes are padded in their most high order bits
+       (PADHI) or low order bits (PADLO).</para></listitem>
+       <listitem><para>For formats where the number of bus samples per pixel is larger
+       than 1, an endianness value stating if the pixel is transferred MSB first
+       (BE) or LSB first (LE).</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format with uncompressed 10-bit Bayer components
+      arranged in a red, green, green, blue pattern transferred as 2 8-bit
+      samples per pixel with the least significant bits transferred first will
+      be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
+      </para>
+
+      <figure id="bayer-patterns">
+       <title>Bayer Patterns</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="bayer.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="bayer.png" format="PNG" />
+         </imageobject>
+         <textobject>
+           <phrase>Bayer filter color patterns</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+
+      <para>The following table lists existing packet Bayer formats. The data
+      organization is given as an example for the first pixel only.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
+       <title>Bayer Formats</title>
+       <tgroup cols="15">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b11" align="center" />
+         <colspec colnum="5" colname="b10" align="center" />
+         <colspec colnum="6" colname="b09" align="center" />
+         <colspec colnum="7" colname="b08" align="center" />
+         <colspec colnum="8" colname="b07" align="center" />
+         <colspec colnum="9" colname="b06" align="center" />
+         <colspec colnum="10" colname="b05" align="center" />
+         <colspec colnum="11" colname="b04" align="center" />
+         <colspec colnum="12" colname="b03" align="center" />
+         <colspec colnum="13" colname="b02" align="center" />
+         <colspec colnum="14" colname="b01" align="center" />
+         <colspec colnum="15" colname="b00" align="center" />
+         <spanspec namest="b11" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>11</entry>
+             <entry>10</entry>
+             <entry>9</entry>
+             <entry>8</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
+             <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
+             <entry>0x3001</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
+             <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
+             <entry>0x3002</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
+             <entry>0x300b</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
+             <entry>0x300c</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
+             <entry>0x3009</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
+             <entry>0x300d</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
+             <entry>0x3003</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
+             <entry>0x3004</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
+             <entry>0x3005</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
+             <entry>0x3006</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
+             <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
+             <entry>0x3007</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
+             <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
+             <entry>0x300e</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
+             <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
+             <entry>0x300a</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
+             <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
+             <entry>0x300f</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>9</subscript></entry>
+             <entry>r<subscript>8</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
+             <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
+             <entry>0x3008</entry>
+             <entry></entry>
+             <entry>b<subscript>11</subscript></entry>
+             <entry>b<subscript>10</subscript></entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG12-1X12">
+             <entry>V4L2_MBUS_FMT_SGBRG12_1X12</entry>
+             <entry>0x3010</entry>
+             <entry></entry>
+             <entry>g<subscript>11</subscript></entry>
+             <entry>g<subscript>10</subscript></entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG12-1X12">
+             <entry>V4L2_MBUS_FMT_SGRBG12_1X12</entry>
+             <entry>0x3011</entry>
+             <entry></entry>
+             <entry>g<subscript>11</subscript></entry>
+             <entry>g<subscript>10</subscript></entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB12-1X12">
+             <entry>V4L2_MBUS_FMT_SRGGB12_1X12</entry>
+             <entry>0x3012</entry>
+             <entry></entry>
+             <entry>r<subscript>11</subscript></entry>
+             <entry>r<subscript>10</subscript></entry>
+             <entry>r<subscript>9</subscript></entry>
+             <entry>r<subscript>8</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
+    <section>
+      <title>Packed YUV Formats</title>
+
+      <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
+      and V components. The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The Y, U and V components order code, as transferred on the
+       bus. Possible values are YUYV, UYVY, YVYU and VYUY.</para></listitem>
+       <listitem><para>The number of bits per pixel component. All components are
+       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1, 1.5 (encoded as 1_5) and 2.</para></listitem>
+       <listitem><para>The bus width. When the bus width is larger than the number of
+       bits per pixel component, several components are packed in a single bus
+       sample. The components are ordered as specified by the order code, with
+       components on the left of the code transferred in the high order bits.
+       Common values are 8 and 16.</para>
+       </listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format where pixels are encoded as 8-bit YUV values
+      downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
+      U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
+      </para>
+
+      <para>The following table lisst existing packet YUV formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
+       <title>YUV Formats</title>
+       <tgroup cols="23">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b19" align="center" />
+         <colspec colnum="5" colname="b18" align="center" />
+         <colspec colnum="6" colname="b17" align="center" />
+         <colspec colnum="7" colname="b16" align="center" />
+         <colspec colnum="8" colname="b15" align="center" />
+         <colspec colnum="9" colname="b14" align="center" />
+         <colspec colnum="10" colname="b13" align="center" />
+         <colspec colnum="11" colname="b12" align="center" />
+         <colspec colnum="12" colname="b11" align="center" />
+         <colspec colnum="13" colname="b10" align="center" />
+         <colspec colnum="14" colname="b09" align="center" />
+         <colspec colnum="15" colname="b08" align="center" />
+         <colspec colnum="16" colname="b07" align="center" />
+         <colspec colnum="17" colname="b06" align="center" />
+         <colspec colnum="18" colname="b05" align="center" />
+         <colspec colnum="19" colname="b04" align="center" />
+         <colspec colnum="20" colname="b03" align="center" />
+         <colspec colnum="21" colname="b02" align="center" />
+         <colspec colnum="22" colname="b01" align="center" />
+         <colspec colnum="23" colname="b00" align="center" />
+         <spanspec namest="b19" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>19</entry>
+             <entry>18</entry>
+             <entry>17</entry>
+             <entry>16</entry>
+             <entry>15</entry>
+             <entry>14</entry>
+             <entry>13</entry>
+             <entry>12</entry>
+             <entry>11</entry>
+             <entry>10</entry>
+             <entry>9</entry>
+             <entry>8</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-Y8-1X8">
+             <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
+             <entry>0x2001</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
+             <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
+             <entry>0x2002</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
+             <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
+             <entry>0x2003</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
+             <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
+             <entry>0x2004</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
+             <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
+             <entry>0x2005</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-2X8">
+             <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
+             <entry>0x2006</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-2X8">
+             <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
+             <entry>0x2007</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-2X8">
+             <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
+             <entry>0x2008</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-2X8">
+             <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
+             <entry>0x2009</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-Y10-1X10">
+             <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
+             <entry>0x200a</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV10-2X10">
+             <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
+             <entry>0x200b</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU10-2X10">
+             <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
+             <entry>0x200c</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-1X16">
+             <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
+             <entry>0x200f</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-1X16">
+             <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
+             <entry>0x2010</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-1X16">
+             <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
+             <entry>0x2011</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-1X16">
+             <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
+             <entry>0x2012</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV10-1X20">
+             <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
+             <entry>0x200d</entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU10-1X20">
+             <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
+             <entry>0x200e</entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+  </section>
+</section>
index 9288af96de347f6afbb82002869ce4ce0a837f76..a7fd76d0dac1f6e04e8961e94fb29cc430bf2053 100644 (file)
@@ -85,6 +85,17 @@ Remote Controller chapter.</contrib>
          </address>
        </affiliation>
       </author>
+
+      <author>
+       <firstname>Pawel</firstname>
+       <surname>Osciak</surname>
+       <contrib>Designed and documented the multi-planar API.</contrib>
+       <affiliation>
+         <address>
+           <email>pawel AT osciak.com</email>
+         </address>
+       </affiliation>
+      </author>
     </authorgroup>
 
     <copyright>
@@ -102,7 +113,8 @@ Remote Controller chapter.</contrib>
       <year>2010</year>
       <year>2011</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
-Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
+Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
+       Pawel Osciak</holder>
     </copyright>
     <legalnotice>
     <para>Except when explicitly stated as GPL, programming examples within
@@ -115,6 +127,13 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>2.6.39</revnumber>
+       <date>2011-03-01</date>
+       <authorinitials>mcc, po</authorinitials>
+       <revremark>Removed VIDIOC_*_OLD from videodev2.h header and update it to reflect latest changes. Added the <link linkend="planar-apis">multi-planar API</link>.</revremark>
+      </revision>
+
       <revision>
        <revnumber>2.6.37</revnumber>
        <date>2010-08-06</date>
@@ -382,7 +401,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.38</subtitle>
+ <subtitle>Revision 2.6.39</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -411,6 +430,7 @@ and discussions on the V4L mailing list.</revremark>
     <section id="radio"> &sub-dev-radio; </section>
     <section id="rds"> &sub-dev-rds; </section>
     <section id="event"> &sub-dev-event; </section>
+    <section id="subdev"> &sub-dev-subdev; </section>
   </chapter>
 
   <chapter id="driver">
@@ -478,6 +498,12 @@ and discussions on the V4L mailing list.</revremark>
     &sub-reqbufs;
     &sub-s-hw-freq-seek;
     &sub-streamon;
+    &sub-subdev-enum-frame-interval;
+    &sub-subdev-enum-frame-size;
+    &sub-subdev-enum-mbus-code;
+    &sub-subdev-g-crop;
+    &sub-subdev-g-fmt;
+    &sub-subdev-g-frame-interval;
     &sub-subscribe-event;
     <!-- End of ioctls. -->
     &sub-mmap;
index 325b23b6964c28e2f0a9b9f4832449ea38849b46..2b796a2ee98a06fd8c7c853a63f52600be3ab9d8 100644 (file)
@@ -71,6 +71,7 @@
  * Moved from videodev.h
  */
 #define VIDEO_MAX_FRAME               32
+#define VIDEO_MAX_PLANES               8
 
 #ifndef __KERNEL__
 
@@ -158,9 +159,23 @@ enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> {
         /* Experimental */
         V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
 #endif
+        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
+        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
         V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
+#define V4L2_TYPE_IS_MULTIPLANAR(type)                  \
+        ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE   \
+         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+
+#define V4L2_TYPE_IS_OUTPUT(type)                               \
+        ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT                   \
+         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE         \
+         || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY               \
+         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY        \
+         || (type) == V4L2_BUF_TYPE_VBI_OUTPUT                  \
+         || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+
 enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link> {
         V4L2_TUNER_RADIO             = 1,
         V4L2_TUNER_ANALOG_TV         = 2,
@@ -246,6 +261,11 @@ struct <link linkend="v4l2-capability">v4l2_capability</link> {
 #define V4L2_CAP_HW_FREQ_SEEK           0x00000400  /* Can do hardware frequency seek  */
 #define V4L2_CAP_RDS_OUTPUT             0x00000800  /* Is an RDS encoder */
 
+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE   0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE    0x00002000
+
 #define V4L2_CAP_TUNER                  0x00010000  /* has a tuner */
 #define V4L2_CAP_AUDIO                  0x00020000  /* has audio support */
 #define V4L2_CAP_RADIO                  0x00040000  /* is a radio device */
@@ -320,6 +340,13 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
 #define <link linkend="V4L2-PIX-FMT-NV16">V4L2_PIX_FMT_NV16</link>    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
 #define <link linkend="V4L2-PIX-FMT-NV61">V4L2_PIX_FMT_NV61</link>    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
 
+/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
+#define <link linkend="V4L2-PIX-FMT-NV12M">V4L2_PIX_FMT_NV12M</link>   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define <link linkend="V4L2-PIX-FMT-NV12MT">V4L2_PIX_FMT_NV12MT</link>  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
+
+/* three non contiguous planes - Y, Cb, Cr */
+#define <link linkend="V4L2-PIX-FMT-YUV420M">V4L2_PIX_FMT_YUV420M</link> v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
+
 /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define <link linkend="V4L2-PIX-FMT-SBGGR8">V4L2_PIX_FMT_SBGGR8</link>  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define <link linkend="V4L2-PIX-FMT-SGBRG8">V4L2_PIX_FMT_SGBRG8</link>  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
@@ -518,6 +545,62 @@ struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> {
         __u32                   reserved[2];
 };
 
+/**
+ * struct <link linkend="v4l2-plane">v4l2_plane</link> - plane info for multi-planar buffers
+ * @bytesused:          number of bytes occupied by data in the plane (payload)
+ * @length:             size of this plane (NOT the payload) in bytes
+ * @mem_offset:         when memory in the associated struct <link linkend="v4l2-buffer">v4l2_buffer</link> is
+ *                      V4L2_MEMORY_MMAP, equals the offset from the start of
+ *                      the device memory for this plane (or is a "cookie" that
+ *                      should be passed to mmap() called on the video node)
+ * @userptr:            when memory is V4L2_MEMORY_USERPTR, a userspace pointer
+ *                      pointing to this plane
+ * @data_offset:        offset in the plane to the start of data; usually 0,
+ *                      unless there is a header in front of the data
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ */
+struct <link linkend="v4l2-plane">v4l2_plane</link> {
+        __u32                   bytesused;
+        __u32                   length;
+        union {
+                __u32           mem_offset;
+                unsigned long   userptr;
+        } m;
+        __u32                   data_offset;
+        __u32                   reserved[11];
+};
+
+/**
+ * struct <link linkend="v4l2-buffer">v4l2_buffer</link> - video buffer info
+ * @index:      id number of the buffer
+ * @type:       buffer type (type == *_MPLANE for multiplanar buffers)
+ * @bytesused:  number of bytes occupied by data in the buffer (payload);
+ *              unused (set to 0) for multiplanar buffers
+ * @flags:      buffer informational flags
+ * @field:      field order of the image in the buffer
+ * @timestamp:  frame timestamp
+ * @timecode:   frame timecode
+ * @sequence:   sequence count of this frame
+ * @memory:     the method, in which the actual video data is passed
+ * @offset:     for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ *              offset from the start of the device memory for this plane,
+ *              (or a "cookie" that should be passed to mmap() as offset)
+ * @userptr:    for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
+ *              a userspace pointer pointing to this buffer
+ * @planes:     for multiplanar buffers; userspace pointer to the array of plane
+ *              info structs for this buffer
+ * @length:     size in bytes of the buffer (NOT its payload) for single-plane
+ *              buffers (when type != *_MPLANE); number of elements in the
+ *              planes array for multi-plane buffers
+ * @input:      input number from which the video data has has been captured
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
 struct <link linkend="v4l2-buffer">v4l2_buffer</link> {
         __u32                   index;
         enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
@@ -533,6 +616,7 @@ struct <link linkend="v4l2-buffer">v4l2_buffer</link> {
         union {
                 __u32           offset;
                 unsigned long   userptr;
+                struct <link linkend="v4l2-plane">v4l2_plane</link> *planes;
         } m;
         __u32                   length;
         __u32                   input;
@@ -1623,12 +1707,56 @@ struct <link linkend="v4l2-mpeg-vbi-fmt-ivtv">v4l2_mpeg_vbi_fmt_ivtv</link> {
  *      A G G R E G A T E   S T R U C T U R E S
  */
 
-/*      Stream data format
+/**
+ * struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> - additional, per-plane format definition
+ * @sizeimage:          maximum size in bytes required for data, for which
+ *                      this plane will be used
+ * @bytesperline:       distance in bytes between the leftmost pixels in two
+ *                      adjacent lines
+ */
+struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> {
+        __u32           sizeimage;
+        __u16           bytesperline;
+        __u16           reserved[7];
+} __attribute__ ((packed));
+
+/**
+ * struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> - multiplanar format definition
+ * @width:              image width in pixels
+ * @height:             image height in pixels
+ * @pixelformat:        little endian four character code (fourcc)
+ * @field:              field order (for interlaced video)
+ * @colorspace:         supplemental to pixelformat
+ * @plane_fmt:          per-plane information
+ * @num_planes:         number of planes for this format
+ */
+struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> {
+        __u32                           width;
+        __u32                           height;
+        __u32                           pixelformat;
+        enum <link linkend="v4l2-field">v4l2_field</link>                 field;
+        enum <link linkend="v4l2-colorspace">v4l2_colorspace</link>            colorspace;
+
+        struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link>    plane_fmt[VIDEO_MAX_PLANES];
+        __u8                            num_planes;
+        __u8                            reserved[11];
+} __attribute__ ((packed));
+
+/**
+ * struct <link linkend="v4l2-format">v4l2_format</link> - stream data format
+ * @type:       type of the data stream
+ * @pix:        definition of an image format
+ * @pix_mp:     definition of a multiplanar image format
+ * @win:        definition of an overlaid image
+ * @vbi:        raw VBI capture or output parameters
+ * @sliced:     sliced VBI capture or output parameters
+ * @raw_data:   placeholder for future extensions and custom formats
  */
 struct <link linkend="v4l2-format">v4l2_format</link> {
         enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
         union {
                 struct <link linkend="v4l2-pix-format">v4l2_pix_format</link>          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+                struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link>   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
                 struct <link linkend="v4l2-window">v4l2_window</link>              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                 struct <link linkend="v4l2-vbi-format">v4l2_vbi_format</link>          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
                 struct <link linkend="v4l2-sliced-vbi-format">v4l2_sliced_vbi_format</link>   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
@@ -1636,7 +1764,6 @@ struct <link linkend="v4l2-format">v4l2_format</link> {
         } fmt;
 };
 
-
 /*      Stream type-dependent parameters
  */
 struct <link linkend="v4l2-streamparm">v4l2_streamparm</link> {
@@ -1809,16 +1936,6 @@ struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
-#ifdef __OLD_VIDIOC_
-/* for compatibility, will go away some day */
-#define VIDIOC_OVERLAY_OLD      _IOWR('V', 14, int)
-#define VIDIOC_S_PARM_OLD        _IOW('V', 22, struct <link linkend="v4l2-streamparm">v4l2_streamparm</link>)
-#define VIDIOC_S_CTRL_OLD        _IOW('V', 28, struct <link linkend="v4l2-control">v4l2_control</link>)
-#define VIDIOC_G_AUDIO_OLD      _IOWR('V', 33, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_G_AUDOUT_OLD     _IOWR('V', 49, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_CROPCAP_OLD       _IOR('V', 58, struct <link linkend="v4l2-cropcap">v4l2_cropcap</link>)
-#endif
-
 #define BASE_VIDIOC_PRIVATE     192             /* 192-255 are private */
 
 #endif /* __LINUX_VIDEODEV2_H */
index 960d44615ca6b472974da0a1fefa78616c247187..71d373b6d36a31ac50bed40aaebf0c67a51eff23 100644 (file)
@@ -76,7 +76,9 @@ pixelformat</structfield> field.</entry>
            <entry>Type of the data stream, set by the application.
 Only these types are valid here:
 <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>,
 <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
 defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
 and higher.</entry>
index 7c7d1b72c40df2dd9f9ba2f467e00c5208ef5af0..a4ae59b664ebaa12c9b8ae6999cce8525f9a8788 100644 (file)
@@ -60,11 +60,13 @@ application.</para>
 <structfield>type</structfield> field of a struct
 <structname>v4l2_format</structname> to the respective buffer (stream)
 type. For example video capture devices use
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>. When the application
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>. When the application
 calls the <constant>VIDIOC_G_FMT</constant> ioctl with a pointer to
 this structure the driver fills the respective member of the
 <structfield>fmt</structfield> union. In case of video capture devices
-that is the &v4l2-pix-format; <structfield>pix</structfield> member.
+that is either the &v4l2-pix-format; <structfield>pix</structfield> or
+the &v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member.
 When the requested buffer type is not supported drivers return an
 &EINVAL;.</para>
 
@@ -131,6 +133,15 @@ this ioctl.</para>
            <entry>Definition of an image format, see <xref
                linkend="pixfmt" />, used by video capture and output
 devices.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-pix-format-mplane;</entry>
+           <entry><structfield>pix_mp</structfield></entry>
+           <entry>Definition of an image format, see <xref
+               linkend="pixfmt" />, used by video capture and output
+devices that support the <link linkend="planar-apis">multi-planar
+version of the API</link>.</entry>
          </row>
          <row>
            <entry></entry>
index ab691ebf3b9373969b95a2af7cac8d84663fc35a..f2b11f8a40310eebbe48d0839f7f0125c92bb201 100644 (file)
@@ -64,7 +64,8 @@ zero to the number of buffers allocated with &VIDIOC-REQBUFS;
 contents of the struct <structname>v4l2_buffer</structname> returned
 by a &VIDIOC-QUERYBUF; ioctl will do as well. When the buffer is
 intended for output (<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>, or
 <constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>) applications must also
 initialize the <structfield>bytesused</structfield>,
 <structfield>field</structfield> and
@@ -75,7 +76,11 @@ supports capturing from specific video inputs and you want to specify a video
 input, then <structfield>flags</structfield> should be set to
 <constant>V4L2_BUF_FLAG_INPUT</constant> and the field
 <structfield>input</structfield> must be initialized to the desired input.
-The <structfield>reserved</structfield> field must be set to 0.
+The <structfield>reserved</structfield> field must be set to 0. When using
+the <link linkend="planar-apis">multi-planar API</link>, the
+<structfield>m.planes</structfield> field must contain a userspace pointer
+to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
+field must be set to the number of elements in that array.
 </para>
 
     <para>To enqueue a <link linkend="mmap">memory mapped</link>
@@ -93,10 +98,13 @@ structure the driver sets the
 buffer applications set the <structfield>memory</structfield>
 field to <constant>V4L2_MEMORY_USERPTR</constant>, the
 <structfield>m.userptr</structfield> field to the address of the
-buffer and <structfield>length</structfield> to its size.
-When <constant>VIDIOC_QBUF</constant> is called with a pointer to this
-structure the driver sets the <constant>V4L2_BUF_FLAG_QUEUED</constant>
-flag and clears the <constant>V4L2_BUF_FLAG_MAPPED</constant> and
+buffer and <structfield>length</structfield> to its size. When the multi-planar
+API is used, <structfield>m.userptr</structfield> and
+<structfield>length</structfield> members of the passed array of &v4l2-plane;
+have to be used instead. When <constant>VIDIOC_QBUF</constant> is called with
+a pointer to this structure the driver sets the
+<constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the
+<constant>V4L2_BUF_FLAG_MAPPED</constant> and
 <constant>V4L2_BUF_FLAG_DONE</constant> flags in the
 <structfield>flags</structfield> field, or it returns an error code.
 This ioctl locks the memory pages of the buffer in physical memory,
@@ -115,7 +123,9 @@ remaining fields or returns an error code. The driver may also set
 <constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
 field. It indicates a non-critical (recoverable) streaming error. In such case
 the application may continue as normal, but should be aware that data in the
-dequeued buffer might be corrupted.</para>
+dequeued buffer might be corrupted. When using the multi-planar API, the
+planes array does not have to be passed; the <structfield>m.planes</structfield>
+member must be set to NULL in that case.</para>
 
     <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
 buffer is in the outgoing queue. When the
index e649805a4908838d2f4028099a8aa24a234c6db7..5c104d42d31cd9b3dd2860c1bf3db221ed911f2c 100644 (file)
@@ -61,6 +61,10 @@ buffer at any time after buffers have been allocated with the
 to the number of buffers allocated with &VIDIOC-REQBUFS;
     (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
 The <structfield>reserved</structfield> field should to set to 0.
+When using the <link linkend="planar-apis">multi-planar API</link>, the
+<structfield>m.planes</structfield> field must contain a userspace pointer to an
+array of &v4l2-plane; and the <structfield>length</structfield> field has
+to be set to the number of elements in that array.
 After calling <constant>VIDIOC_QUERYBUF</constant> with a pointer to
     this structure drivers return an error code or fill the rest of
 the structure.</para>
@@ -70,11 +74,13 @@ the structure.</para>
 <constant>V4L2_BUF_FLAG_QUEUED</constant> and
 <constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The
 <structfield>memory</structfield> field will be set to the current
-I/O method, the <structfield>m.offset</structfield>
+I/O method. For the single-planar API, the <structfield>m.offset</structfield>
 contains the offset of the buffer from the start of the device memory,
-the <structfield>length</structfield> field its size. The driver may
-or may not set the remaining fields and flags, they are meaningless in
-this context.</para>
+the <structfield>length</structfield> field its size. For the multi-planar API,
+fields <structfield>m.mem_offset</structfield> and
+<structfield>length</structfield> in the <structfield>m.planes</structfield>
+array elements will be used instead. The driver may or may not set the remaining
+fields and flags, they are meaningless in this context.</para>
 
     <para>The <structname>v4l2_buffer</structname> structure is
     specified in <xref linkend="buffer" />.</para>
index d499da93a4506917619e57847ca9bdf82330198d..f29f1b86213c68b55744420f8cb65eeaff708806 100644 (file)
@@ -142,15 +142,29 @@ this array to zero.</entry>
          <row>
            <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
            <entry>0x00000001</entry>
-           <entry>The device supports the <link
+           <entry>The device supports the single-planar API through the <link
 linkend="capture">Video Capture</link> interface.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant></entry>
+           <entry>0x00001000</entry>
+           <entry>The device supports the
+           <link linkend="planar-apis">multi-planar API</link> through the
+           <link linkend="capture">Video Capture</link> interface.</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CAP_VIDEO_OUTPUT</constant></entry>
            <entry>0x00000002</entry>
-           <entry>The device supports the <link
+           <entry>The device supports the single-planar API through the <link
 linkend="output">Video Output</link> interface.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant></entry>
+           <entry>0x00002000</entry>
+           <entry>The device supports the
+           <link linkend="planar-apis">multi-planar API</link> through the
+           <link linkend="output">Video Output</link> interface.</entry>
+         </row>
          <row>
            <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
            <entry>0x00000004</entry>
index e42bff1f2c0a3d132458fcf50e29c3989ee808a2..75ed39bf4d2bb4b8c64909b52d7348f2930cef3e 100644 (file)
@@ -93,6 +93,15 @@ synchronize with other events.</para>
 been allocated (memory mapping) or enqueued (output) yet.</para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><errorcode>EPIPE</errorcode></term>
+       <listitem>
+         <para>The driver implements <link
+         linkend="pad-level-formats">pad-level format configuration</link> and
+         the pipeline configuration is invalid.
+         </para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 </refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
new file mode 100644 (file)
index 0000000..2f8f4f0
--- /dev/null
@@ -0,0 +1,152 @@
+<refentry id="vidioc-subdev-enum-frame-interval">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
+    <refpurpose>Enumerate frame intervals</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_interval_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>This ioctl lets applications enumerate available frame intervals on a
+    given sub-device pad. Frame intervals only makes sense for sub-devices that
+    can control the frame period on their own. This includes, for instance,
+    image sensors and TV tuners.</para>
+
+    <para>For the common use case of image sensors, the frame intervals
+    available on the sub-device output pad depend on the frame format and size
+    on the same pad. Applications must thus specify the desired format and size
+    when enumerating frame intervals.</para>
+
+    <para>To enumerate frame intervals applications initialize the
+    <structfield>index</structfield>, <structfield>pad</structfield>,
+    <structfield>code</structfield>, <structfield>width</structfield> and
+    <structfield>height</structfield> fields of
+    &v4l2-subdev-frame-interval-enum; and call the
+    <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
+    to this structure. Drivers fill the rest of the structure or return
+    an &EINVAL; if one of the input fields is invalid. All frame intervals are
+    enumerable by beginning at index zero and incrementing by one until
+    <errorcode>EINVAL</errorcode> is returned.</para>
+
+    <para>Available frame intervals may depend on the current 'try' formats
+    at other pads of the sub-device, as well as on the current active links. See
+    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+    <para>Sub-devices that support the frame interval enumeration ioctl should
+    implemented it on a single pad only. Its behaviour when supported on
+    multiple pads of the same sub-device is not defined.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
+      <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>interval</structfield></entry>
+           <entry>Period, in seconds, between consecutive video frames.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-interval-enum;
+         <structfield>pad</structfield> references a non-existing pad, one of
+         the <structfield>code</structfield>, <structfield>width</structfield>
+         or <structfield>height</structfield> fields are invalid for the given
+         pad or the <structfield>index</structfield> field is out of bounds.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
new file mode 100644 (file)
index 0000000..79ce42b
--- /dev/null
@@ -0,0 +1,154 @@
+<refentry id="vidioc-subdev-enum-frame-size">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
+    <refpurpose>Enumerate media bus frame sizes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_size_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>This ioctl allows applications to enumerate all frame sizes
+    supported by a sub-device on the given pad for the given media bus format.
+    Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
+    ioctl.</para>
+
+    <para>To enumerate frame sizes applications initialize the
+    <structfield>pad</structfield>, <structfield>code</structfield> and
+    <structfield>index</structfield> fields of the
+    &v4l2-subdev-mbus-code-enum; and call the
+    <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
+    the structure. Drivers fill the minimum and maximum frame sizes or return
+    an &EINVAL; if one of the input parameters is invalid.</para>
+
+    <para>Sub-devices that only support discrete frame sizes (such as most
+    sensors) will return one or more frame sizes with identical minimum and
+    maximum values.</para>
+
+    <para>Not all possible sizes in given [minimum, maximum] ranges need to be
+    supported. For instance, a scaler that uses a fixed-point scaling ratio
+    might not be able to produce every frame size between the minimum and
+    maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
+    try the sub-device for an exact supported frame size.</para>
+
+    <para>Available frame sizes may depend on the current 'try' formats at other
+    pads of the sub-device, as well as on the current active links and the
+    current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
+    information about try formats.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
+      <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_width</structfield></entry>
+           <entry>Minimum frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_width</structfield></entry>
+           <entry>Maximum frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_height</structfield></entry>
+           <entry>Minimum frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_height</structfield></entry>
+           <entry>Maximum frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
+         references a non-existing pad, the <structfield>code</structfield> is
+         invalid for the given pad or the <structfield>index</structfield>
+         field is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
new file mode 100644 (file)
index 0000000..a6b3432
--- /dev/null
@@ -0,0 +1,119 @@
+<refentry id="vidioc-subdev-enum-mbus-code">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
+    <refpurpose>Enumerate media bus formats</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_mbus_code_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_MBUS_CODE</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>To enumerate media bus formats available at a given sub-device pad
+    applications initialize the <structfield>pad</structfield> and
+    <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
+    call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
+    pointer to this structure. Drivers fill the rest of the structure or return
+    an &EINVAL; if either the <structfield>pad</structfield> or
+    <structfield>index</structfield> are invalid. All media bus formats are
+    enumerable by beginning at index zero and incrementing by one until
+    <errorcode>EINVAL</errorcode> is returned.</para>
+
+    <para>Available media bus formats may depend on the current 'try' formats
+    at other pads of the sub-device, as well as on the current active links. See
+    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
+      <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
+         references a non-existing pad, or the <structfield>index</structfield>
+         field is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
new file mode 100644 (file)
index 0000000..0619732
--- /dev/null
@@ -0,0 +1,155 @@
+<refentry id="vidioc-subdev-g-crop">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_CROP</refname>
+    <refname>VIDIOC_SUBDEV_S_CROP</refname>
+    <refpurpose>Get or set the crop rectangle on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>To retrieve the current crop rectangle applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
+    desired pad number as reported by the media API and the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
+    <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
+    structure. The driver fills the members of the <structfield>rect</structfield>
+    field or returns &EINVAL; if the input arguments are invalid, or if cropping
+    is not supported on the given pad.</para>
+
+    <para>To change the current crop rectangle applications set both the
+    <structfield>pad</structfield> and <structfield>which</structfield> fields
+    and all members of the <structfield>rect</structfield> field. They then call
+    the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
+    structure. The driver verifies the requested crop rectangle, adjusts it
+    based on the hardware capabilities and configures the device. Upon return
+    the &v4l2-subdev-crop; contains the current format as would be returned
+    by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
+    rectangles are not applied to the device by the driver, but are mangled
+    exactly as active crop rectangles and stored in the sub-device file handle.
+    Two applications querying the same sub-device would thus not interact with
+    each other.</para>
+
+    <para>Drivers must not return an error solely because the requested crop
+    rectangle doesn't match the device capabilities. They must instead modify
+    the rectangle to match what the hardware can provide. The modified format
+    should be as close as possible to the original request.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-crop">
+      <title>struct <structname>v4l2_subdev_crop</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media framework.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>which</structfield></entry>
+           <entry>Crop rectangle to get or set, from
+           &v4l2-subdev-format-whence;.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>rect</structfield></entry>
+           <entry>Crop rectangle boundaries, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The crop rectangle can't be changed because the pad is currently
+         busy. This can be caused, for instance, by an active video stream on
+         the pad. The ioctl must not be retried without performing another
+         action to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
+         references a non-existing pad, the <structfield>which</structfield>
+         field references a non-existing format, or cropping is not supported
+         on the given subdev pad.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
new file mode 100644 (file)
index 0000000..f367c57
--- /dev/null
@@ -0,0 +1,180 @@
+<refentry id="vidioc-subdev-g-fmt">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_FMT</refname>
+    <refname>VIDIOC_SUBDEV_S_FMT</refname>
+    <refpurpose>Get or set the data format on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_format *<parameter>argp</parameter>
+       </paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls are used to negotiate the frame format at specific
+    subdev pads in the image pipeline.</para>
+
+    <para>To retrieve the current format applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
+    desired pad number as reported by the media API and the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
+    structure the driver fills the members of the <structfield>format</structfield>
+    field.</para>
+
+    <para>To change the current format applications set both the
+    <structfield>pad</structfield> and <structfield>which</structfield> fields
+    and all members of the <structfield>format</structfield> field. When they
+    call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
+    structure the driver verifies the requested format, adjusts it based on the
+    hardware capabilities and configures the device. Upon return the
+    &v4l2-subdev-format; contains the current format as would be returned by a
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
+    applied to the device by the driver, but are changed exactly as active
+    formats and stored in the sub-device file handle. Two applications querying
+    the same sub-device would thus not interact with each other.</para>
+
+    <para>For instance, to try a format at the output pad of a sub-device,
+    applications would first set the try format at the sub-device input with the
+    <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
+    retrieve the default format at the output pad with the
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
+    pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
+    the returned value.</para>
+
+    <para>Try formats do not depend on active formats, but can depend on the
+    current links configuration or sub-device controls value. For instance, a
+    low-pass noise filter might crop pixels at the frame boundaries, modifying
+    its output frame size.</para>
+
+    <para>Drivers must not return an error solely because the requested format
+    doesn't match the device capabilities. They must instead modify the format
+    to match what the hardware can provide. The modified format should be as
+    close as possible to the original request.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-format">
+      <title>struct <structname>v4l2_subdev_format</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>which</structfield></entry>
+           <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-mbus-framefmt;</entry>
+           <entry><structfield>format</structfield></entry>
+           <entry>Definition of an image format, see <xref
+           linkend="v4l2-mbus-framefmt" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
+      <title>enum <structname>v4l2_subdev_format_whence</structname></title>
+      <tgroup cols="3">
+        &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
+           <entry>0</entry>
+           <entry>Try formats, used for querying device capabilities.</entry>
+         </row>
+         <row>
+           <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
+           <entry>1</entry>
+           <entry>Active formats, applied to the hardware.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The format can't be changed because the pad is currently busy.
+         This can be caused, for instance, by an active video stream on the
+         pad. The ioctl must not be retried without performing another action
+         to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-format; <structfield>pad</structfield>
+         references a non-existing pad, or the <structfield>which</structfield>
+         field references a non-existing format.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
new file mode 100644 (file)
index 0000000..0bc3ea2
--- /dev/null
@@ -0,0 +1,141 @@
+<refentry id="vidioc-subdev-g-frame-interval">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
+    <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
+    <refpurpose>Get or set the frame interval on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_interval *<parameter>argp</parameter>
+       </paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls are used to get and set the frame interval at specific
+    subdev pads in the image pipeline. The frame interval only makes sense for
+    sub-devices that can control the frame period on their own. This includes,
+    for instance, image sensors and TV tuners. Sub-devices that don't support
+    frame intervals must not implement these ioctls.</para>
+
+    <para>To retrieve the current frame interval applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
+    the desired pad number as reported by the media controller API. When they
+    call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
+    pointer to this structure the driver fills the members of the
+    <structfield>interval</structfield> field.</para>
+
+    <para>To change the current frame interval applications set both the
+    <structfield>pad</structfield> field and all members of the
+    <structfield>interval</structfield> field. When they call the
+    <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
+    this structure the driver verifies the requested interval, adjusts it based
+    on the hardware capabilities and configures the device. Upon return the
+    &v4l2-subdev-frame-interval; contains the current frame interval as would be
+    returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
+    </para>
+
+    <para>Drivers must not return an error solely because the requested interval
+    doesn't match the device capabilities. They must instead modify the interval
+    to match what the hardware can provide. The modified interval should be as
+    close as possible to the original request.</para>
+
+    <para>Sub-devices that support the frame interval ioctls should implement
+    them on a single pad only. Their behaviour when supported on multiple pads
+    of the same sub-device is not defined.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
+      <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>interval</structfield></entry>
+           <entry>Period, in seconds, between consecutive video frames.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The frame interval can't be changed because the pad is currently
+         busy. This can be caused, for instance, by an active video stream on
+         the pad. The ioctl must not be retried without performing another
+         action to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
+         references a non-existing pad, or the pad doesn't support frame
+         intervals.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
index 9146952c612a3bb18269601c9cd2d5c6106b0bb2..0c49c197c47a4c744e76e121b80893ca2711e92d 100644 (file)
@@ -92,6 +92,11 @@ vendor_id: <integer>, device_id: <integer>
 class_code: <integer>]
 [serial number: <integer>, <integer>]
 [bridge: secondary_status: <integer>, control: <integer>]
+[aer_status: <integer>, aer_mask: <integer>
+<aer status string>
+[aer_uncor_severity: <integer>]
+aer_layer=<aer layer string>, aer_agent=<aer agent string>
+aer_tlp_header: <integer> <integer> <integer> <integer>]
 
 <pcie port type string>* := PCIe end point | legacy PCI end point | \
 unknown | unknown | root port | upstream switch port | \
@@ -99,6 +104,26 @@ downstream switch port | PCIe to PCI/PCI-X bridge | \
 PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \
 root complex event collector
 
+if section severity is fatal or recoverable
+<aer status string># :=
+unknown | unknown | unknown | unknown | Data Link Protocol | \
+unknown | unknown | unknown | unknown | unknown | unknown | unknown | \
+Poisoned TLP | Flow Control Protocol | Completion Timeout | \
+Completer Abort | Unexpected Completion | Receiver Overflow | \
+Malformed TLP | ECRC | Unsupported Request
+else
+<aer status string># :=
+Receiver Error | unknown | unknown | unknown | unknown | unknown | \
+Bad TLP | Bad DLLP | RELAY_NUM Rollover | unknown | unknown | unknown | \
+Replay Timer Timeout | Advisory Non-Fatal
+fi
+
+<aer layer string> :=
+Physical Layer | Data Link Layer | Transaction Layer
+
+<aer agent string> :=
+Receiver ID | Requester ID | Completer ID | Transmitter ID
+
 Where, [] designate corresponding content is optional
 
 All <field string> description with * has the following format:
index b9a83dd24732486965f41225d8184405e4766c4a..2a7b38c832c72e705bd9136ace4d9ece77c16628 100644 (file)
@@ -963,11 +963,6 @@ elevator_dispatch_fn*              fills the dispatch queue with ready requests.
 
 elevator_add_req_fn*           called to add a new request into the scheduler
 
-elevator_queue_empty_fn                returns true if the merge queue is empty.
-                               Drivers shouldn't use this, but rather check
-                               if elv_next_request is NULL (without losing the
-                               request if one exists!)
-
 elevator_former_req_fn
 elevator_latter_req_fn         These return the request before or after the
                                one specified in disk sort order. Used by the
index 4ed7b5ceeed212c1b7a734451456896f4759ee9d..465351d4cf853e8a308c9c84abef789b3dcfa42c 100644 (file)
@@ -140,7 +140,7 @@ Proportional weight policy files
        - Specifies per cgroup weight. This is default weight of the group
          on all the devices until and unless overridden by per device rule.
          (See blkio.weight_device).
-         Currently allowed range of weights is from 100 to 1000.
+         Currently allowed range of weights is from 10 to 1000.
 
 - blkio.weight_device
        - One can specify per cgroup per device rules using this interface.
@@ -343,34 +343,6 @@ Common files among various policies
 
 CFQ sysfs tunable
 =================
-/sys/block/<disk>/queue/iosched/group_isolation
------------------------------------------------
-
-If group_isolation=1, it provides stronger isolation between groups at the
-expense of throughput. By default group_isolation is 0. In general that
-means that if group_isolation=0, expect fairness for sequential workload
-only. Set group_isolation=1 to see fairness for random IO workload also.
-
-Generally CFQ will put random seeky workload in sync-noidle category. CFQ
-will disable idling on these queues and it does a collective idling on group
-of such queues. Generally these are slow moving queues and if there is a
-sync-noidle service tree in each group, that group gets exclusive access to
-disk for certain period. That means it will bring the throughput down if
-group does not have enough IO to drive deeper queue depths and utilize disk
-capacity to the fullest in the slice allocated to it. But the flip side is
-that even a random reader should get better latencies and overall throughput
-if there are lots of sequential readers/sync-idle workload running in the
-system.
-
-If group_isolation=0, then CFQ automatically moves all the random seeky queues
-in the root group. That means there will be no service differentiation for
-that kind of workload. This leads to better throughput as we do collective
-idling on root sync-noidle tree.
-
-By default one should run with group_isolation=0. If that is not sufficient
-and one wants stronger isolation between groups, then set group_isolation=1
-but this will come at cost of reduced throughput.
-
 /sys/block/<disk>/queue/iosched/slice_idle
 ------------------------------------------
 On a faster hardware CFQ can be slow, especially with sequential workload.
diff --git a/Documentation/device-mapper/dm-flakey.txt b/Documentation/device-mapper/dm-flakey.txt
new file mode 100644 (file)
index 0000000..c8efdfd
--- /dev/null
@@ -0,0 +1,17 @@
+dm-flakey
+=========
+
+This target is the same as the linear target except that it returns I/O
+errors periodically.  It's been found useful in simulating failing
+devices for testing purposes.
+
+Starting from the time the table is loaded, the device is available for
+<up interval> seconds, then returns errors for <down interval> seconds,
+and then this cycle repeats.
+
+Parameters: <dev path> <offset> <up interval> <down interval>
+    <dev path>: Full pathname to the underlying block-device, or a
+                "major:minor" device-number.
+    <offset>: Starting sector within the device.
+    <up interval>: Number of seconds device is available.
+    <down interval>: Number of seconds device returns errors.
diff --git a/Documentation/devicetree/bindings/fb/sm501fb.txt b/Documentation/devicetree/bindings/fb/sm501fb.txt
new file mode 100644 (file)
index 0000000..7d319fb
--- /dev/null
@@ -0,0 +1,34 @@
+* SM SM501
+
+The SM SM501 is a LCD controller, with proper hardware, it can also
+drive DVI monitors.
+
+Required properties:
+- compatible : should be "smi,sm501".
+- reg : contain two entries:
+    - First entry: System Configuration register
+    - Second entry: IO space (Display Controller register)
+- interrupts : SMI interrupt to the cpu should be described here.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- mode : select a video mode:
+    <xres>x<yres>[-<bpp>][@<refresh>]
+- edid : verbatim EDID data block describing attached display.
+  Data from the detailed timing descriptor will be used to
+  program the display controller.
+- little-endian: availiable on big endian systems, to
+  set different foreign endian.
+- big-endian: availiable on little endian systems, to
+  set different foreign endian.
+
+Example for MPC5200:
+       display@1,0 {
+               compatible = "smi,sm501";
+               reg = <1 0x00000000 0x00800000
+                      1 0x03e00000 0x00200000>;
+               interrupts = <1 1 3>;
+               mode = "640x480-32@60";
+               edid = [edid-data];
+       };
diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
new file mode 100644 (file)
index 0000000..918a507
--- /dev/null
@@ -0,0 +1,73 @@
+ADS1015 (I2C)
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+For configuration all possible combinations are mapped to 8 channels:
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured individually:
+ - pga is the programmable gain amplifier (values are full scale)
+    0: +/- 6.144 V
+    1: +/- 4.096 V
+    2: +/- 2.048 V (default)
+    3: +/- 1.024 V
+    4: +/- 0.512 V
+    5: +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600 (default)
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C bus address of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+           compatible = "ti,ads1015";
+           reg = <0x49>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+
+           [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter data rate
+
+  Example ADS1015 channel node:
+
+    channel@4 {
+           reg = <4>;
+           ti,gain = <3>;
+           ti,datarate = <5>;
+    };
diff --git a/Documentation/devicetree/bindings/open-pic.txt b/Documentation/devicetree/bindings/open-pic.txt
new file mode 100644 (file)
index 0000000..909a902
--- /dev/null
@@ -0,0 +1,98 @@
+* Open PIC Binding
+
+This binding specifies what properties must be available in the device tree
+representation of an Open PIC compliant interrupt controller.  This binding is
+based on the binding defined for Open PIC in [1] and is a superset of that
+binding.
+
+Required properties:
+
+  NOTE: Many of these descriptions were paraphrased here from [1] to aid
+        readability.
+
+    - compatible: Specifies the compatibility list for the PIC.  The type
+      shall be <string> and the value shall include "open-pic".
+
+    - reg: Specifies the base physical address(s) and size(s) of this
+      PIC's addressable register space.  The type shall be <prop-encoded-array>.
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an Open PIC.  No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source.  The type shall be a <u32> and the value shall be 2.
+
+    - #address-cells: Specifies the number of cells needed to encode an
+      address.  The type shall be <u32> and the value shall be 0.  As such,
+      'interrupt-map' nodes do not have to specify a parent unit address.
+
+Optional properties:
+
+    - pic-no-reset: The presence of this property indicates that the PIC
+      shall not be reset during runtime initialization.  No property value shall
+      be defined.  The presence of this property also mandates that any
+      initialization related to interrupt sources shall be limited to sources
+      explicitly referenced in the device tree.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as
+  follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+
+    - <2nd-cell>: The level-sense information, encoded as follows:
+                    0 = low-to-high edge triggered
+                    1 = active low level-sensitive
+                    2 = active high level-sensitive
+                    3 = high-to-low edge triggered
+
+* Examples
+
+Example 1:
+
+       /*
+        * An Open PIC interrupt controller
+        */
+       mpic: pic@40000 {
+               // This is an interrupt controller node.
+               interrupt-controller;
+
+               // No address cells so that 'interrupt-map' nodes which reference
+               // this Open PIC node do not need a parent address specifier.
+               #address-cells = <0>;
+
+               // Two cells to encode interrupt sources.
+               #interrupt-cells = <2>;
+
+               // Offset address of 0x40000 and size of 0x40000.
+               reg = <0x40000 0x40000>;
+
+               // Compatible with Open PIC.
+               compatible = "open-pic";
+
+               // The PIC shall not be reset.
+               pic-no-reset;
+       };
+
+Example 2:
+
+       /*
+        * An interrupt generating device that is wired to an Open PIC.
+        */
+       serial0: serial@4500 {
+               // Interrupt source '42' that is active high level-sensitive.
+               // Note that there are only two cells as specified in the interrupt
+               // parent's '#interrupt-cells' property.
+               interrupts = <42 2>;
+
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&mpic>;
+       };
+
+* References
+
+[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform
+    Requirements (ePAPR), Version 1.0, July 2008.
+    (http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf)
+
index 59690de8ebfe1312ddef53131e025beaf0d69a94..3348d313fbe08ca68049dc3e3e3e0580b654a5c1 100644 (file)
@@ -556,6 +556,9 @@ sub ngene {
     my $hash1 = "d798d5a757121174f0dbc5f2833c0c85";
     my $file2 = "ngene_17.fw";
     my $hash2 = "26b687136e127b8ac24b81e0eeafc20b";
+    my $url2 = "http://l4m-daten.de/downloads/firmware/dvb-s2/linux/all/";
+    my $file3 = "ngene_18.fw";
+    my $hash3 = "ebce3ea769a53e3e0b0197c3b3f127e3";
 
     checkstandard();
 
@@ -565,7 +568,10 @@ sub ngene {
     wgetfile($file2, $url . $file2);
     verify($file2, $hash2);
 
-    "$file1, $file2";
+    wgetfile($file3, $url2 . $file3);
+    verify($file3, $hash3);
+
+    "$file1, $file2, $file3";
 }
 
 sub az6027{
index 6418865042017220c3e2f4f242bc30b21db20505..10b5f0411386a16a85085ab717d5b98c81c44b18 100644 (file)
@@ -4,7 +4,7 @@ following file(s) to this directory.
 for DM04+/QQBOX LME2510C (Sharp 7395 Tuner)
 -------------------------------------------
 
-The Sharp 7395 driver can be found in windows/system32/driver
+The Sharp 7395 driver can be found in windows/system32/drivers
 
 US2A0D.sys (dated 17 Mar 2009)
 
@@ -44,7 +44,7 @@ and run
 
 
 Other LG firmware can be extracted manually from US280D.sys
-only found in windows/system32/driver.
+only found in windows/system32/drivers
 
 dd if=US280D.sys ibs=1 skip=42360 count=3924 of=dvb-usb-lme2510-lg.fw
 
@@ -55,4 +55,16 @@ dd if=US280D.sys ibs=1 skip=35200 count=3850 of=dvb-usb-lme2510c-lg.fw
 
 ---------------------------------------------------------------------
 
+The Sharp 0194 tuner driver can be found in windows/system32/drivers
+
+US290D.sys (dated 09 Apr 2009)
+
+For LME2510
+dd if=US290D.sys ibs=1 skip=36856 count=3976 of=dvb-usb-lme2510-s0194.fw
+
+
+For LME2510C
+dd if=US290D.sys ibs=1 skip=33152 count=3697 of=dvb-usb-lme2510c-s0194.fw
+
+
 Copy the firmware file(s) to /lib/firmware
diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt
new file mode 100644 (file)
index 0000000..8d17aeb
--- /dev/null
@@ -0,0 +1,10 @@
+Configuration:
+
+You can pass the following kernel command line options to sm501 videoframebuffer:
+
+       sm501fb.bpp=    SM501 Display driver:
+                       Specifiy bits-per-pixel if not specified by 'mode'
+
+       sm501fb.mode=   SM501 Display driver:
+                       Specify resolution as
+                       "<xres>x<yres>[-<bpp>][@<refresh>]"
index f487c6918d7870c57bec4202cf22482af21b3d6f..274b32d12532a2e0e3814e70940b39721dde864a 100644 (file)
@@ -108,42 +108,6 @@ Who:       Pavel Machek <pavel@ucw.cz>
 
 ---------------------------
 
-What:  Video4Linux obsolete drivers using V4L1 API
-When:  kernel 2.6.39
-Files: drivers/staging/se401/* drivers/staging/usbvideo/*
-Check: drivers/staging/se401/se401.c drivers/staging/usbvideo/usbvideo.c
-Why:   There are some drivers still using V4L1 API, despite all efforts we've done
-       to migrate. Those drivers are for obsolete hardware that the old maintainer
-       didn't care (or not have the hardware anymore), and that no other developer
-       could find any hardware to buy. They probably have no practical usage today,
-       and people with such old hardware could probably keep using an older version
-       of the kernel. Those drivers will be moved to staging on 2.6.38 and, if nobody
-       cares enough to port and test them with V4L2 API, they'll be removed on 2.6.39.
-Who:   Mauro Carvalho Chehab <mchehab@infradead.org>
-
----------------------------
-
-What:  Video4Linux: Remove obsolete ioctl's
-When:  kernel 2.6.39
-Files: include/media/videodev2.h
-Why:   Some ioctl's were defined wrong on 2.6.2 and 2.6.6, using the wrong
-       type of R/W arguments. They were fixed, but the old ioctl names are
-       still there, maintained to avoid breaking binary compatibility:
-         #define VIDIOC_OVERLAY_OLD    _IOWR('V', 14, int)
-         #define VIDIOC_S_PARM_OLD     _IOW('V', 22, struct v4l2_streamparm)
-         #define VIDIOC_S_CTRL_OLD     _IOW('V', 28, struct v4l2_control)
-         #define VIDIOC_G_AUDIO_OLD    _IOWR('V', 33, struct v4l2_audio)
-         #define VIDIOC_G_AUDOUT_OLD   _IOWR('V', 49, struct v4l2_audioout)
-         #define VIDIOC_CROPCAP_OLD    _IOR('V', 58, struct v4l2_cropcap)
-       There's no sense on preserving those forever, as it is very doubtful
-       that someone would try to use a such old binary with a modern kernel.
-       Removing them will allow us to remove some magic done at the V4L ioctl
-       handler.
-
-Who:   Mauro Carvalho Chehab <mchehab@infradead.org>
-
----------------------------
-
 What:  sys_sysctl
 When:  September 2010
 Option: CONFIG_SYSCTL_SYSCALL
@@ -270,14 +234,6 @@ Who:       Zhang Rui <rui.zhang@intel.com>
 
 ---------------------------
 
-What:  /proc/acpi/button
-When:  August 2007
-Why:   /proc/acpi/button has been replaced by events to the input layer
-       since 2.6.20.
-Who:   Len Brown <len.brown@intel.com>
-
----------------------------
-
 What:  /proc/acpi/event
 When:  February 2008
 Why:   /proc/acpi/event has been replaced by events via the input layer
@@ -585,16 +541,6 @@ Who:    NeilBrown <neilb@suse.de>
 
 ----------------------------
 
-What:  i2c_adapter.id
-When:  June 2011
-Why:   This field is deprecated. I2C device drivers shouldn't change their
-       behavior based on the underlying I2C adapter. Instead, the I2C
-       adapter driver should instantiate the I2C devices and provide the
-       needed platform-specific information.
-Who:   Jean Delvare <khali@linux-fr.org>
-
-----------------------------
-
 What:  cancel_rearming_delayed_work[queue]()
 When:  2.6.39
 
@@ -645,3 +591,12 @@ Who:       Florian Westphal <fw@strlen.de>
 Files: include/linux/netfilter_ipv4/ipt_addrtype.h
 
 ----------------------------
+
+What:  i2c_driver.attach_adapter
+       i2c_driver.detach_adapter
+When:  September 2011
+Why:   These legacy callbacks should no longer be used as i2c-core offers
+       a variety of preferable alternative ways to instantiate I2C devices.
+Who:   Jean Delvare <khali@linux-fr.org>
+
+----------------------------
index 2e994efe12cbf25905921d5b1d2fbb7f8e3c177a..61b31acb9176b35bc77c914b2b3913abbcc9e78a 100644 (file)
@@ -128,7 +128,7 @@ alloc_inode:
 destroy_inode:
 dirty_inode:                           (must not sleep)
 write_inode:
-drop_inode:                            !!!inode_lock!!!
+drop_inode:                            !!!inode->i_lock!!!
 evict_inode:
 put_super:             write
 write_super:           read
index 9e8811f92b84160451947366508957d26b750597..5949766353f73308a40a91b0d7d9e70a3b8f89c1 100644 (file)
@@ -9,6 +9,9 @@ Mount options for ADFS
                will be nnn.  Default 0700.
   othmask=nnn  The permission mask for ADFS 'other' permissions
                will be nnn.  Default 0077.
+  ftsuffix=n   When ftsuffix=0, no file type suffix will be applied.
+               When ftsuffix=1, a hexadecimal suffix corresponding to
+               the RISC OS file type will be added.  Default 0.
 
 Mapping of ADFS permissions to Linux permissions
 ------------------------------------------------
@@ -55,3 +58,18 @@ Mapping of ADFS permissions to Linux permissions
 
   You can therefore tailor the permission translation to whatever you
   desire the permissions should be under Linux.
+
+RISC OS file type suffix
+------------------------
+
+  RISC OS file types are stored in bits 19..8 of the file load address.
+
+  To enable non-RISC OS systems to be used to store files without losing
+  file type information, a file naming convention was devised (initially
+  for use with NFS) such that a hexadecimal suffix of the form ,xyz
+  denoted the file type: e.g. BasicFile,ffb is a BASIC (0xffb) file.  This
+  naming convention is now also used by RISC OS emulators such as RPCEmu.
+
+  Mounting an ADFS disc with option ftsuffix=1 will cause appropriate file
+  type suffixes to be appended to file names read from a directory.  If the
+  ftsuffix option is zero or omitted, no file type suffixes will be added.
index abd2a9b5b787c324034f24d3a84523f99c657de1..23583a136975cce78a3f4606663b2d456ec7bb89 100644 (file)
@@ -104,7 +104,15 @@ Where:
     exofs specific options: Options are separated by commas (,)
                pid=<integer> - The partition number to mount/create as
                                 container of the filesystem.
-                                This option is mandatory.
+                                This option is mandatory. integer can be
+                                Hex by pre-pending an 0x to the number.
+               osdname=<id>  - Mount by a device's osdname.
+                                osdname is usually a 36 character uuid of the
+                                form "d2683732-c906-4ee1-9dbd-c10c27bb40df".
+                                It is one of the device's uuid specified in the
+                                mkfs.exofs format command.
+                                If this option is specified then the /dev/osdX
+                                above can be empty and is ignored.
                 to=<integer>  - Timeout in ticks for a single command.
                                 default is (60 * HZ) [for debugging only]
 
index 6ab9442d7eeb666e496e79acba6471b813207434..6b050464a90de62d1bd4b5c3d372baa044f36d16 100644 (file)
@@ -367,12 +367,47 @@ init_itable=n             The lazy itable init code will wait n times the
                        minimizes the impact on the systme performance
                        while file system's inode table is being initialized.
 
-discard                Controls whether ext4 should issue discard/TRIM
+discard                        Controls whether ext4 should issue discard/TRIM
 nodiscard(*)           commands to the underlying block device when
                        blocks are freed.  This is useful for SSD devices
                        and sparse/thinly-provisioned LUNs, but it is off
                        by default until sufficient testing has been done.
 
+nouid32                        Disables 32-bit UIDs and GIDs.  This is for
+                       interoperability  with  older kernels which only
+                       store and expect 16-bit values.
+
+resize                 Allows to resize filesystem to the end of the last
+                       existing block group, further resize has to be done
+                       with resize2fs either online, or offline. It can be
+                       used only with conjunction with remount.
+
+block_validity         This options allows to enables/disables the in-kernel
+noblock_validity       facility for tracking filesystem metadata blocks
+                       within internal data structures. This allows multi-
+                       block allocator and other routines to quickly locate
+                       extents which might overlap with filesystem metadata
+                       blocks. This option is intended for debugging
+                       purposes and since it negatively affects the
+                       performance, it is off by default.
+
+dioread_lock           Controls whether or not ext4 should use the DIO read
+dioread_nolock         locking. If the dioread_nolock option is specified
+                       ext4 will allocate uninitialized extent before buffer
+                       write and convert the extent to initialized after IO
+                       completes. This approach allows ext4 code to avoid
+                       using inode mutex, which improves scalability on high
+                       speed storages. However this does not work with nobh
+                       option and the mount will fail. Nor does it work with
+                       data journaling and dioread_nolock option will be
+                       ignored with kernel warning. Note that dioread_nolock
+                       code path is only used for extent-based files.
+                       Because of the restrictions this options comprises
+                       it is off by default (e.g. dioread_lock).
+
+i_version              Enable 64-bit inode version support. This option is
+                       off by default.
+
 Data Mode
 =========
 There are 3 different data modes:
@@ -400,6 +435,176 @@ needs to be read from and written to disk at the same time where it
 outperforms all others modes.  Currently ext4 does not have delayed
 allocation support if this data journalling mode is selected.
 
+/proc entries
+=============
+
+Information about mounted ext4 file systems can be found in
+/proc/fs/ext4.  Each mounted filesystem will have a directory in
+/proc/fs/ext4 based on its device name (i.e., /proc/fs/ext4/hdc or
+/proc/fs/ext4/dm-0).   The files in each per-device directory are shown
+in table below.
+
+Files in /proc/fs/ext4/<devname>
+..............................................................................
+ File            Content
+ mb_groups       details of multiblock allocator buddy cache of free blocks
+..............................................................................
+
+/sys entries
+============
+
+Information about mounted ext4 file systems can be found in
+/sys/fs/ext4.  Each mounted filesystem will have a directory in
+/sys/fs/ext4 based on its device name (i.e., /sys/fs/ext4/hdc or
+/sys/fs/ext4/dm-0).   The files in each per-device directory are shown
+in table below.
+
+Files in /sys/fs/ext4/<devname>
+(see also Documentation/ABI/testing/sysfs-fs-ext4)
+..............................................................................
+ File                         Content
+
+ delayed_allocation_blocks    This file is read-only and shows the number of
+                              blocks that are dirty in the page cache, but
+                              which do not have their location in the
+                              filesystem allocated yet.
+
+ inode_goal                   Tuning parameter which (if non-zero) controls
+                              the goal inode used by the inode allocator in
+                              preference to all other allocation heuristics.
+                              This is intended for debugging use only, and
+                              should be 0 on production systems.
+
+ inode_readahead_blks         Tuning parameter which controls the maximum
+                              number of inode table blocks that ext4's inode
+                              table readahead algorithm will pre-read into
+                              the buffer cache
+
+ lifetime_write_kbytes        This file is read-only and shows the number of
+                              kilobytes of data that have been written to this
+                              filesystem since it was created.
+
+ max_writeback_mb_bump        The maximum number of megabytes the writeback
+                              code will try to write out before move on to
+                              another inode.
+
+ mb_group_prealloc            The multiblock allocator will round up allocation
+                              requests to a multiple of this tuning parameter if
+                              the stripe size is not set in the ext4 superblock
+
+ mb_max_to_scan               The maximum number of extents the multiblock
+                              allocator will search to find the best extent
+
+ mb_min_to_scan               The minimum number of extents the multiblock
+                              allocator will search to find the best extent
+
+ mb_order2_req                Tuning parameter which controls the minimum size
+                              for requests (as a power of 2) where the buddy
+                              cache is used
+
+ mb_stats                     Controls whether the multiblock allocator should
+                              collect statistics, which are shown during the
+                              unmount. 1 means to collect statistics, 0 means
+                              not to collect statistics
+
+ mb_stream_req                Files which have fewer blocks than this tunable
+                              parameter will have their blocks allocated out
+                              of a block group specific preallocation pool, so
+                              that small files are packed closely together.
+                              Each large file will have its blocks allocated
+                              out of its own unique preallocation pool.
+
+ session_write_kbytes         This file is read-only and shows the number of
+                              kilobytes of data that have been written to this
+                              filesystem since it was mounted.
+..............................................................................
+
+Ioctls
+======
+
+There is some Ext4 specific functionality which can be accessed by applications
+through the system call interfaces. The list of all Ext4 specific ioctls are
+shown in the table below.
+
+Table of Ext4 specific ioctls
+..............................................................................
+ Ioctl                       Description
+ EXT4_IOC_GETFLAGS           Get additional attributes associated with inode.
+                             The ioctl argument is an integer bitfield, with
+                             bit values described in ext4.h. This ioctl is an
+                             alias for FS_IOC_GETFLAGS.
+
+ EXT4_IOC_SETFLAGS           Set additional attributes associated with inode.
+                             The ioctl argument is an integer bitfield, with
+                             bit values described in ext4.h. This ioctl is an
+                             alias for FS_IOC_SETFLAGS.
+
+ EXT4_IOC_GETVERSION
+ EXT4_IOC_GETVERSION_OLD
+                             Get the inode i_generation number stored for
+                             each inode. The i_generation number is normally
+                             changed only when new inode is created and it is
+                             particularly useful for network filesystems. The
+                             '_OLD' version of this ioctl is an alias for
+                             FS_IOC_GETVERSION.
+
+ EXT4_IOC_SETVERSION
+ EXT4_IOC_SETVERSION_OLD
+                             Set the inode i_generation number stored for
+                             each inode. The '_OLD' version of this ioctl
+                             is an alias for FS_IOC_SETVERSION.
+
+ EXT4_IOC_GROUP_EXTEND       This ioctl has the same purpose as the resize
+                             mount option. It allows to resize filesystem
+                             to the end of the last existing block group,
+                             further resize has to be done with resize2fs,
+                             either online, or offline. The argument points
+                             to the unsigned logn number representing the
+                             filesystem new block count.
+
+ EXT4_IOC_MOVE_EXT           Move the block extents from orig_fd (the one
+                             this ioctl is pointing to) to the donor_fd (the
+                             one specified in move_extent structure passed
+                             as an argument to this ioctl). Then, exchange
+                             inode metadata between orig_fd and donor_fd.
+                             This is especially useful for online
+                             defragmentation, because the allocator has the
+                             opportunity to allocate moved blocks better,
+                             ideally into one contiguous extent.
+
+ EXT4_IOC_GROUP_ADD          Add a new group descriptor to an existing or
+                             new group descriptor block. The new group
+                             descriptor is described by ext4_new_group_input
+                             structure, which is passed as an argument to
+                             this ioctl. This is especially useful in
+                             conjunction with EXT4_IOC_GROUP_EXTEND,
+                             which allows online resize of the filesystem
+                             to the end of the last existing block group.
+                             Those two ioctls combined is used in userspace
+                             online resize tool (e.g. resize2fs).
+
+ EXT4_IOC_MIGRATE            This ioctl operates on the filesystem itself.
+                             It converts (migrates) ext3 indirect block mapped
+                             inode to ext4 extent mapped inode by walking
+                             through indirect block mapping of the original
+                             inode and converting contiguous block ranges
+                             into ext4 extents of the temporary inode. Then,
+                             inodes are swapped. This ioctl might help, when
+                             migrating from ext3 to ext4 filesystem, however
+                             suggestion is to create fresh ext4 filesystem
+                             and copy data from the backup. Note, that
+                             filesystem has to support extents for this ioctl
+                             to work.
+
+ EXT4_IOC_ALLOC_DA_BLKS              Force all of the delay allocated blocks to be
+                             allocated to preserve application-expected ext3
+                             behaviour. Note that this will also start
+                             triggering a write of the data blocks, but this
+                             behaviour may change in the future as it is
+                             not necessary and has been done this way only
+                             for sake of simplicity.
+..............................................................................
+
 References
 ==========
 
index 0c986c9e8519ad32d455b1818436c61aab8434c6..6e29954851a243427d20fe07dd83970569180338 100644 (file)
@@ -298,11 +298,14 @@ be used instead.  It gets called whenever the inode is evicted, whether it has
 remaining links or not.  Caller does *not* evict the pagecache or inode-associated
 metadata buffers; getting rid of those is responsibility of method, as it had
 been for ->delete_inode().
-       ->drop_inode() returns int now; it's called on final iput() with inode_lock
-held and it returns true if filesystems wants the inode to be dropped.  As before,
-generic_drop_inode() is still the default and it's been updated appropriately.
-generic_delete_inode() is also alive and it consists simply of return 1.  Note that
-all actual eviction work is done by caller after ->drop_inode() returns.
+
+       ->drop_inode() returns int now; it's called on final iput() with
+inode->i_lock held and it returns true if filesystems wants the inode to be
+dropped.  As before, generic_drop_inode() is still the default and it's been
+updated appropriately.  generic_delete_inode() is also alive and it consists
+simply of return 1.  Note that all actual eviction work is done by caller after
+->drop_inode() returns.
+
        clear_inode() is gone; use end_writeback() instead.  As before, it must
 be called exactly once on each call of ->evict_inode() (as it used to be for
 each call of ->delete_inode()).  Unlike before, if you are using inode-associated
@@ -395,6 +398,9 @@ Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set,
 so the i_size should not change when hole punching, even when puching the end of
 a file off.
 
+--
+[mandatory]
+
 --
 [mandatory]
        ->get_sb() is gone.  Switch to use of ->mount().  Typically it's just
index 66699afd66cad8bd1941a2a5b2de8cee360767b5..2d78f191184498459b951e3292a1e81770ddefb5 100644 (file)
@@ -59,12 +59,15 @@ obtained from this site also.
 3. SQUASHFS FILESYSTEM DESIGN
 -----------------------------
 
-A squashfs filesystem consists of a maximum of eight parts, packed together on a byte
-alignment:
+A squashfs filesystem consists of a maximum of nine parts, packed together on a
+byte alignment:
 
         ---------------
        |  superblock   |
        |---------------|
+       |  compression  |
+       |    options    |
+       |---------------|
        |  datablocks   |
        |  & fragments  |
        |---------------|
@@ -91,7 +94,14 @@ the source directory, and checked for duplicates.  Once all file data has been
 written the completed inode, directory, fragment, export and uid/gid lookup
 tables are written.
 
-3.1 Inodes
+3.1 Compression options
+-----------------------
+
+Compressors can optionally support compression specific options (e.g.
+dictionary size).  If non-default compression options have been used, then
+these are stored here.
+
+3.2 Inodes
 ----------
 
 Metadata (inodes and directories) are compressed in 8Kbyte blocks.  Each
@@ -114,7 +124,7 @@ directory inode are defined: inodes optimised for frequently occurring
 regular files and directories, and extended types where extra
 information has to be stored.
 
-3.2 Directories
+3.3 Directories
 ---------------
 
 Like inodes, directories are packed into compressed metadata blocks, stored
@@ -144,7 +154,7 @@ decompressed to do a lookup irrespective of the length of the directory.
 This scheme has the advantage that it doesn't require extra memory overhead
 and doesn't require much extra storage on disk.
 
-3.3 File data
+3.4 File data
 -------------
 
 Regular files consist of a sequence of contiguous compressed blocks, and/or a
@@ -163,7 +173,7 @@ Larger files use multiple slots, with 1.75 TiB files using all 8 slots.
 The index cache is designed to be memory efficient, and by default uses
 16 KiB.
 
-3.4 Fragment lookup table
+3.5 Fragment lookup table
 -------------------------
 
 Regular files can contain a fragment index which is mapped to a fragment
@@ -173,7 +183,7 @@ A second index table is used to locate these.  This second index table for
 speed of access (and because it is small) is read at mount time and cached
 in memory.
 
-3.5 Uid/gid lookup table
+3.6 Uid/gid lookup table
 ------------------------
 
 For space efficiency regular files store uid and gid indexes, which are
@@ -182,7 +192,7 @@ stored compressed into metadata blocks.  A second index table is used to
 locate these.  This second index table for speed of access (and because it
 is small) is read at mount time and cached in memory.
 
-3.6 Export table
+3.7 Export table
 ----------------
 
 To enable Squashfs filesystems to be exportable (via NFS etc.) filesystems
@@ -196,7 +206,7 @@ This table is stored compressed into metadata blocks.  A second index table is
 used to locate these.  This second index table for speed of access (and because
 it is small) is read at mount time and cached in memory.
 
-3.7 Xattr table
+3.8 Xattr table
 ---------------
 
 The xattr table contains extended attributes for each inode.  The xattrs
index 306f0ae8df094c14cd6825aaf27e5448efa04b24..80815ed654cb499a1b5fc7683c016438bf8886f5 100644 (file)
@@ -254,7 +254,7 @@ or bottom half).
        should be synchronous or not, not all filesystems check this flag.
 
   drop_inode: called when the last access to the inode is dropped,
-       with the inode_lock spinlock held.
+       with the inode->i_lock spinlock held.
 
        This method should be either NULL (normal UNIX filesystem
        semantics) or "generic_delete_inode" (for filesystems that do not
index 7445bf335dae7eeba4bd6640a82fa3987f48d2cc..5282e3e5141310ac1b73c3dd28d192d020932d97 100644 (file)
@@ -791,10 +791,3 @@ mount option. Fundamentally, there is no reason why the log manager would not
 be able to swap methods automatically and transparently depending on load
 characteristics, but this should not be necessary if delayed logging works as
 designed.
-
-Roadmap:
-
-2.6.39 Switch default mount option to use delayed logging
-       => should be roughly 12 months after initial merge
-       => enough time to shake out remaining problems before next round of
-          enterprise distro kernel rebases
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
new file mode 100644 (file)
index 0000000..f6fe9c2
--- /dev/null
@@ -0,0 +1,72 @@
+Kernel driver ads1015
+=====================
+
+Supported chips:
+  * Texas Instruments ADS1015
+    Prefix: 'ads1015'
+    Datasheet: Publicly available at the Texas Instruments website :
+               http://focus.ti.com/lit/ds/symlink/ads1015.pdf
+
+Authors:
+        Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
+
+Description
+-----------
+
+This driver implements support for the Texas Instruments ADS1015.
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+The inputs can be made available by 8 sysfs input files in0_input - in7_input:
+in0: Voltage over AIN0 and AIN1.
+in1: Voltage over AIN0 and AIN3.
+in2: Voltage over AIN1 and AIN3.
+in3: Voltage over AIN2 and AIN3.
+in4: Voltage over AIN0 and GND.
+in5: Voltage over AIN1 and GND.
+in6: Voltage over AIN2 and GND.
+in7: Voltage over AIN3 and GND.
+
+Which inputs are available can be configured using platform data or devicetree.
+
+By default all inputs are exported.
+
+Platform Data
+-------------
+
+In linux/i2c/ads1015.h platform data is defined, channel_data contains
+configuration data for the used input combinations:
+- pga is the programmable gain amplifier (values are full scale)
+  0: +/- 6.144 V
+  1: +/- 4.096 V
+  2: +/- 2.048 V
+  3: +/- 1.024 V
+  4: +/- 0.512 V
+  5: +/- 0.256 V
+- data_rate in samples per second
+  0: 128
+  1: 250
+  2: 490
+  3: 920
+  4: 1600
+  5: 2400
+  6: 3300
+
+Example:
+struct ads1015_platform_data data = {
+       .channel_data = {
+               [2] = { .enabled = true, .pga = 1, .data_rate = 0 },
+               [4] = { .enabled = true, .pga = 4, .data_rate = 5 },
+       }
+};
+
+In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
+(FS +/- 0.512 V, 2400 SPS) would be created.
+
+Devicetree
+----------
+
+Configuration is also possible via devicetree:
+Documentation/devicetree/bindings/hwmon/ads1015.txt
diff --git a/Documentation/hwmon/hpfall.c b/Documentation/hwmon/hpfall.c
deleted file mode 100644 (file)
index a4a8fc5..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Disk protection for HP machines.
- *
- * Copyright 2008 Eric Piel
- * Copyright 2009 Pavel Machek <pavel@ucw.cz>
- *
- * GPLv2.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sched.h>
-
-char unload_heads_path[64];
-
-int set_unload_heads_path(char *device)
-{
-       char devname[64];
-
-       if (strlen(device) <= 5 || strncmp(device, "/dev/", 5) != 0)
-               return -EINVAL;
-       strncpy(devname, device + 5, sizeof(devname));
-
-       snprintf(unload_heads_path, sizeof(unload_heads_path),
-                               "/sys/block/%s/device/unload_heads", devname);
-       return 0;
-}
-int valid_disk(void)
-{
-       int fd = open(unload_heads_path, O_RDONLY);
-       if (fd < 0) {
-               perror(unload_heads_path);
-               return 0;
-       }
-
-       close(fd);
-       return 1;
-}
-
-void write_int(char *path, int i)
-{
-       char buf[1024];
-       int fd = open(path, O_RDWR);
-       if (fd < 0) {
-               perror("open");
-               exit(1);
-       }
-       sprintf(buf, "%d", i);
-       if (write(fd, buf, strlen(buf)) != strlen(buf)) {
-               perror("write");
-               exit(1);
-       }
-       close(fd);
-}
-
-void set_led(int on)
-{
-       write_int("/sys/class/leds/hp::hddprotect/brightness", on);
-}
-
-void protect(int seconds)
-{
-       write_int(unload_heads_path, seconds*1000);
-}
-
-int on_ac(void)
-{
-//     /sys/class/power_supply/AC0/online
-}
-
-int lid_open(void)
-{
-//     /proc/acpi/button/lid/LID/state
-}
-
-void ignore_me(void)
-{
-       protect(0);
-       set_led(0);
-}
-
-int main(int argc, char **argv)
-{
-       int fd, ret;
-       struct sched_param param;
-
-       if (argc == 1)
-               ret = set_unload_heads_path("/dev/sda");
-       else if (argc == 2)
-               ret = set_unload_heads_path(argv[1]);
-       else
-               ret = -EINVAL;
-
-       if (ret || !valid_disk()) {
-               fprintf(stderr, "usage: %s <device> (default: /dev/sda)\n",
-                               argv[0]);
-               exit(1);
-       }
-
-       fd = open("/dev/freefall", O_RDONLY);
-       if (fd < 0) {
-               perror("/dev/freefall");
-               return EXIT_FAILURE;
-       }
-
-       daemon(0, 0);
-       param.sched_priority = sched_get_priority_max(SCHED_FIFO);
-       sched_setscheduler(0, SCHED_FIFO, &param);
-       mlockall(MCL_CURRENT|MCL_FUTURE);
-
-       signal(SIGALRM, ignore_me);
-
-       for (;;) {
-               unsigned char count;
-
-               ret = read(fd, &count, sizeof(count));
-               alarm(0);
-               if ((ret == -1) && (errno == EINTR)) {
-                       /* Alarm expired, time to unpark the heads */
-                       continue;
-               }
-
-               if (ret != sizeof(count)) {
-                       perror("read");
-                       break;
-               }
-
-               protect(21);
-               set_led(1);
-               if (1 || on_ac() || lid_open())
-                       alarm(2);
-               else
-                       alarm(20);
-       }
-
-       close(fd);
-       return EXIT_SUCCESS;
-}
diff --git a/Documentation/hwmon/lis3lv02d b/Documentation/hwmon/lis3lv02d
deleted file mode 100644 (file)
index 06534f2..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-Kernel driver lis3lv02d
-=======================
-
-Supported chips:
-
-  * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
-  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits)
-
-Authors:
-        Yan Burman <burman.yan@gmail.com>
-       Eric Piel <eric.piel@tremplin-utc.net>
-
-
-Description
------------
-
-This driver provides support for the accelerometer found in various HP laptops
-sporting the feature officially called "HP Mobile Data Protection System 3D" or
-"HP 3D DriveGuard". It detects automatically laptops with this sensor. Known
-models (full list can be found in drivers/hwmon/hp_accel.c) will have their
-axis automatically oriented on standard way (eg: you can directly play
-neverball). The accelerometer data is readable via
-/sys/devices/platform/lis3lv02d. Reported values are scaled
-to mg values (1/1000th of earth gravity).
-
-Sysfs attributes under /sys/devices/platform/lis3lv02d/:
-position - 3D position that the accelerometer reports. Format: "(x,y,z)"
-rate - read reports the sampling rate of the accelerometer device in HZ.
-       write changes sampling rate of the accelerometer device.
-       Only values which are supported by HW are accepted.
-selftest - performs selftest for the chip as specified by chip manufacturer.
-
-This driver also provides an absolute input class device, allowing
-the laptop to act as a pinball machine-esque joystick. Joystick device can be
-calibrated. Joystick device can be in two different modes.
-By default output values are scaled between -32768 .. 32767. In joystick raw
-mode, joystick and sysfs position entry have the same scale. There can be
-small difference due to input system fuzziness feature.
-Events are also available as input event device.
-
-Selftest is meant only for hardware diagnostic purposes. It is not meant to be
-used during normal operations. Position data is not corrupted during selftest
-but interrupt behaviour is not guaranteed to work reliably. In test mode, the
-sensing element is internally moved little bit. Selftest measures difference
-between normal mode and test mode. Chip specifications tell the acceptance
-limit for each type of the chip. Limits are provided via platform data
-to allow adjustment of the limits without a change to the actual driver.
-Seltest returns either "OK x y z" or "FAIL x y z" where x, y and z are
-measured difference between modes. Axes are not remapped in selftest mode.
-Measurement values are provided to help HW diagnostic applications to make
-final decision.
-
-On HP laptops, if the led infrastructure is activated, support for a led
-indicating disk protection will be provided as /sys/class/leds/hp::hddprotect.
-
-Another feature of the driver is misc device called "freefall" that
-acts similar to /dev/rtc and reacts on free-fall interrupts received
-from the device. It supports blocking operations, poll/select and
-fasync operation modes. You must read 1 bytes from the device.  The
-result is number of free-fall interrupts since the last successful
-read (or 255 if number of interrupts would not fit). See the hpfall.c
-file for an example on using the device.
-
-
-Axes orientation
-----------------
-
-For better compatibility between the various laptops. The values reported by
-the accelerometer are converted into a "standard" organisation of the axes
-(aka "can play neverball out of the box"):
- * When the laptop is horizontal the position reported is about 0 for X and Y
-       and a positive value for Z
- * If the left side is elevated, X increases (becomes positive)
- * If the front side (where the touchpad is) is elevated, Y decreases
-       (becomes negative)
- * If the laptop is put upside-down, Z becomes negative
-
-If your laptop model is not recognized (cf "dmesg"), you can send an
-email to the maintainer to add it to the database.  When reporting a new
-laptop, please include the output of "dmidecode" plus the value of
-/sys/devices/platform/lis3lv02d/position in these four cases.
-
-Q&A
----
-
-Q: How do I safely simulate freefall? I have an HP "portable
-workstation" which has about 3.5kg and a plastic case, so letting it
-fall to the ground is out of question...
-
-A: The sensor is pretty sensitive, so your hands can do it. Lift it
-into free space, follow the fall with your hands for like 10
-centimeters. That should be enough to trigger the detection.
index 8e6356fe05d78bbea5cdaf41e2def9b2f5aaf5a4..a1790401fddee6bed131867878257b2004a91989 100644 (file)
@@ -7,6 +7,11 @@ Supported chips:
     Addresses scanned: I2C 0x48 - 0x4f
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/
+  * National Semiconductor LM75A
+    Prefix: 'lm75a'
+    Addresses scanned: I2C 0x48 - 0x4f
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/
   * Dallas Semiconductor DS75
     Prefix: 'lm75'
     Addresses scanned: I2C 0x48 - 0x4f
diff --git a/Documentation/hwmon/sch5627 b/Documentation/hwmon/sch5627
new file mode 100644 (file)
index 0000000..446a054
--- /dev/null
@@ -0,0 +1,22 @@
+Kernel driver sch5627
+=====================
+
+Supported chips:
+  * SMSC SCH5627
+    Prefix: 'sch5627'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Application Note available upon request
+
+Author: Hans de Goede <hdegoede@redhat.com>
+
+
+Description
+-----------
+
+SMSC SCH5627 Super I/O chips include complete hardware monitoring
+capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
+
+The hardware monitoring part of the SMSC SCH5627 is accessed by talking
+through an embedded microcontroller. An application note describing the
+protocol for communicating with the microcontroller is available upon
+request. Please mail me if you want a copy.
diff --git a/Documentation/hwmon/twl4030-madc-hwmon b/Documentation/hwmon/twl4030-madc-hwmon
new file mode 100644 (file)
index 0000000..ef79843
--- /dev/null
@@ -0,0 +1,45 @@
+Kernel driver twl4030-madc
+=========================
+
+Supported chips:
+       * Texas Instruments TWL4030
+       Prefix: 'twl4030-madc'
+
+
+Authors:
+       J Keerthy <j-keerthy@ti.com>
+
+Description
+-----------
+
+The Texas Instruments TWL4030 is a Power Management and Audio Circuit. Among
+other things it contains a 10-bit A/D converter MADC. The converter has 16
+channels which can be used in different modes.
+
+
+See this table for the meaning of the different channels
+
+Channel Signal
+------------------------------------------
+0      Battery type(BTYPE)
+1      BCI: Battery temperature (BTEMP)
+2      GP analog input
+3      GP analog input
+4      GP analog input
+5      GP analog input
+6      GP analog input
+7      GP analog input
+8      BCI: VBUS voltage(VBUS)
+9      Backup Battery voltage (VBKP)
+10     BCI: Battery charger current (ICHG)
+11     BCI: Battery charger voltage (VCHG)
+12     BCI: Main battery voltage (VBAT)
+13     Reserved
+14     Reserved
+15     VRUSB Supply/Speaker left/Speaker right polarization level
+
+
+The Sysfs nodes will represent the voltage in the units of mV,
+the temperature channel shows the converted temperature in
+degree celcius. The Battery charging current channel represents
+battery charging current in mA.
diff --git a/Documentation/hwmon/w83795 b/Documentation/hwmon/w83795
new file mode 100644 (file)
index 0000000..9f16037
--- /dev/null
@@ -0,0 +1,127 @@
+Kernel driver w83795
+====================
+
+Supported chips:
+  * Winbond/Nuvoton W83795G
+    Prefix: 'w83795g'
+    Addresses scanned: I2C 0x2c - 0x2f
+    Datasheet: Available for download on nuvoton.com
+  * Winbond/Nuvoton W83795ADG
+    Prefix: 'w83795adg'
+    Addresses scanned: I2C 0x2c - 0x2f
+    Datasheet: Available for download on nuvoton.com
+
+Authors:
+    Wei Song (Nuvoton)
+    Jean Delvare <khali@linux-fr.org>
+
+
+Pin mapping
+-----------
+
+Here is a summary of the pin mapping for the W83795G and W83795ADG.
+This can be useful to convert data provided by board manufacturers
+into working libsensors configuration statements.
+
+    W83795G                    |
+  Pin  | Name                  | Register      | Sysfs attribute
+------------------------------------------------------------------
+   13  | VSEN1 (VCORE1)        | 10h           | in0
+   14  | VSEN2 (VCORE2)        | 11h           | in1
+   15  | VSEN3 (VCORE3)        | 12h           | in2
+   16  | VSEN4                 | 13h           | in3
+   17  | VSEN5                 | 14h           | in4
+   18  | VSEN6                 | 15h           | in5
+   19  | VSEN7                 | 16h           | in6
+   20  | VSEN8                 | 17h           | in7
+   21  | VSEN9                 | 18h           | in8
+   22  | VSEN10                | 19h           | in9
+   23  | VSEN11                | 1Ah           | in10
+   28  | VTT                   | 1Bh           | in11
+   24  | 3VDD                  | 1Ch           | in12
+   25  | 3VSB                  | 1Dh           | in13
+   26  | VBAT                  | 1Eh           | in14
+    3  | VSEN12/TR5            | 1Fh           | in15/temp5
+    4  | VSEN13/TR5            | 20h           | in16/temp6
+  5/  6        | VDSEN14/TR1/TD1       | 21h           | in17/temp1
+  7/  8        | VDSEN15/TR2/TD2       | 22h           | in18/temp2
+  9/ 10        | VDSEN16/TR3/TD3       | 23h           | in19/temp3
+ 11/ 12        | VDSEN17/TR4/TD4       | 24h           | in20/temp4
+   40  | FANIN1                | 2Eh           | fan1
+   42  | FANIN2                | 2Fh           | fan2
+   44  | FANIN3                | 30h           | fan3
+   46  | FANIN4                | 31h           | fan4
+   48  | FANIN5                | 32h           | fan5
+   50  | FANIN6                | 33h           | fan6
+   52  | FANIN7                | 34h           | fan7
+   54  | FANIN8                | 35h           | fan8
+   57  | FANIN9                | 36h           | fan9
+   58  | FANIN10               | 37h           | fan10
+   59  | FANIN11               | 38h           | fan11
+   60  | FANIN12               | 39h           | fan12
+   31  | FANIN13               | 3Ah           | fan13
+   35  | FANIN14               | 3Bh           | fan14
+   41  | FANCTL1               | 10h (bank 2)  | pwm1
+   43  | FANCTL2               | 11h (bank 2)  | pwm2
+   45  | FANCTL3               | 12h (bank 2)  | pwm3
+   47  | FANCTL4               | 13h (bank 2)  | pwm4
+   49  | FANCTL5               | 14h (bank 2)  | pwm5
+   51  | FANCTL6               | 15h (bank 2)  | pwm6
+   53  | FANCTL7               | 16h (bank 2)  | pwm7
+   55  | FANCTL8               | 17h (bank 2)  | pwm8
+ 29/ 30        | PECI/TSI (DTS1)       | 26h           | temp7
+ 29/ 30        | PECI/TSI (DTS2)       | 27h           | temp8
+ 29/ 30        | PECI/TSI (DTS3)       | 28h           | temp9
+ 29/ 30        | PECI/TSI (DTS4)       | 29h           | temp10
+ 29/ 30        | PECI/TSI (DTS5)       | 2Ah           | temp11
+ 29/ 30        | PECI/TSI (DTS6)       | 2Bh           | temp12
+ 29/ 30        | PECI/TSI (DTS7)       | 2Ch           | temp13
+ 29/ 30        | PECI/TSI (DTS8)       | 2Dh           | temp14
+   27  | CASEOPEN#             | 46h           | intrusion0
+
+    W83795ADG                  |
+  Pin  | Name                  | Register      | Sysfs attribute
+------------------------------------------------------------------
+   10  | VSEN1 (VCORE1)        | 10h           | in0
+   11  | VSEN2 (VCORE2)        | 11h           | in1
+   12  | VSEN3 (VCORE3)        | 12h           | in2
+   13  | VSEN4                 | 13h           | in3
+   14  | VSEN5                 | 14h           | in4
+   15  | VSEN6                 | 15h           | in5
+   16  | VSEN7                 | 16h           | in6
+   17  | VSEN8                 | 17h           | in7
+   22  | VTT                   | 1Bh           | in11
+   18  | 3VDD                  | 1Ch           | in12
+   19  | 3VSB                  | 1Dh           | in13
+   20  | VBAT                  | 1Eh           | in14
+   48  | VSEN12/TR5            | 1Fh           | in15/temp5
+    1  | VSEN13/TR5            | 20h           | in16/temp6
+  2/  3        | VDSEN14/TR1/TD1       | 21h           | in17/temp1
+  4/  5        | VDSEN15/TR2/TD2       | 22h           | in18/temp2
+  6/  7        | VDSEN16/TR3/TD3       | 23h           | in19/temp3
+  8/  9        | VDSEN17/TR4/TD4       | 24h           | in20/temp4
+   32  | FANIN1                | 2Eh           | fan1
+   34  | FANIN2                | 2Fh           | fan2
+   36  | FANIN3                | 30h           | fan3
+   37  | FANIN4                | 31h           | fan4
+   38  | FANIN5                | 32h           | fan5
+   39  | FANIN6                | 33h           | fan6
+   40  | FANIN7                | 34h           | fan7
+   41  | FANIN8                | 35h           | fan8
+   43  | FANIN9                | 36h           | fan9
+   44  | FANIN10               | 37h           | fan10
+   45  | FANIN11               | 38h           | fan11
+   46  | FANIN12               | 39h           | fan12
+   24  | FANIN13               | 3Ah           | fan13
+   28  | FANIN14               | 3Bh           | fan14
+   33  | FANCTL1               | 10h (bank 2)  | pwm1
+   35  | FANCTL2               | 11h (bank 2)  | pwm2
+   23  | PECI (DTS1)           | 26h           | temp7
+   23  | PECI (DTS2)           | 27h           | temp8
+   23  | PECI (DTS3)           | 28h           | temp9
+   23  | PECI (DTS4)           | 29h           | temp10
+   23  | PECI (DTS5)           | 2Ah           | temp11
+   23  | PECI (DTS6)           | 2Bh           | temp12
+   23  | PECI (DTS7)           | 2Ch           | temp13
+   23  | PECI (DTS8)           | 2Dh           | temp14
+   21  | CASEOPEN#             | 46h           | intrusion0
diff --git a/Documentation/i2c/busses/i2c-diolan-u2c b/Documentation/i2c/busses/i2c-diolan-u2c
new file mode 100644 (file)
index 0000000..30fe4bb
--- /dev/null
@@ -0,0 +1,26 @@
+Kernel driver i2c-diolan-u2c
+
+Supported adapters:
+  * Diolan U2C-12 I2C-USB adapter
+    Documentation:
+       http://www.diolan.com/i2c/u2c12.html
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+Description
+-----------
+
+This is the driver for the Diolan U2C-12 USB-I2C adapter.
+
+The Diolan U2C-12 I2C-USB Adapter provides a low cost solution to connect
+a computer to I2C slave devices using a USB interface. It also supports
+connectivity to SPI devices.
+
+This driver only supports the I2C interface of U2C-12. The driver does not use
+interrupts.
+
+
+Module parameters
+-----------------
+
+* frequency: I2C bus frequency
index 93fe76e56522a199a0ab5044544673418be64ec0..6df69765ccb75045615dec13c3b564c550d18021 100644 (file)
@@ -16,8 +16,9 @@ Supported adapters:
   * Intel EP80579 (Tolapai)
   * Intel 82801JI (ICH10)
   * Intel 5/3400 Series (PCH)
-  * Intel Cougar Point (PCH)
+  * Intel 6 Series (PCH)
   * Intel Patsburg (PCH)
+  * Intel DH89xxCC (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index 87da405a85979d9cf925fc711590f5d0deef9b7c..9edb75d8c9b94cdc5d7d50241499892bca42243b 100644 (file)
@@ -100,7 +100,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
        (...)
        i2c_adap = i2c_get_adapter(2);
        memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-       strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
+       strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
        isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
                                                   normal_i2c, NULL);
        i2c_put_adapter(i2c_adap);
index 9a45f9bb6a255d421bd2903e69120c0a8e281017..d6991625c407d41102f25a008c4f4801396ec1b7 100644 (file)
@@ -61,7 +61,7 @@ static int example_attach(struct i2c_adapter *adap, int addr, int kind)
        return 0;
 }
 
-static int __devexit example_detach(struct i2c_client *client)
+static int example_detach(struct i2c_client *client)
 {
        struct example_state *state = i2c_get_clientdata(client);
 
@@ -81,7 +81,7 @@ static struct i2c_driver example_driver = {
                .name           = "example",
        },
        .attach_adapter = example_attach_adapter,
-       .detach_client  = __devexit_p(example_detach),
+       .detach_client  = example_detach,
        .suspend        = example_suspend,
        .resume         = example_resume,
 };
@@ -93,7 +93,7 @@ Updating the client
 The new style binding model will check against a list of supported
 devices and their associated address supplied by the code registering
 the busses. This means that the driver .attach_adapter and
-.detach_adapter methods can be removed, along with the addr_data,
+.detach_client methods can be removed, along with the addr_data,
 as follows:
 
 - static struct i2c_driver example_driver;
@@ -110,14 +110,14 @@ as follows:
 
  static struct i2c_driver example_driver = {
 -      .attach_adapter = example_attach_adapter,
--      .detach_client  = __devexit_p(example_detach),
+-      .detach_client  = example_detach,
  }
 
 Add the probe and remove methods to the i2c_driver, as so:
 
  static struct i2c_driver example_driver = {
 +      .probe          = example_probe,
-+      .remove         = __devexit_p(example_remove),
++      .remove         = example_remove,
  }
 
 Change the example_attach method to accept the new parameters
@@ -199,8 +199,8 @@ to delete the i2c_detach_client call. It is possible that you
 can also remove the ret variable as it is not not needed for
 any of the core functions.
 
-- static int __devexit example_detach(struct i2c_client *client)
-+ static int __devexit example_remove(struct i2c_client *client)
+- static int example_detach(struct i2c_client *client)
++ static int example_remove(struct i2c_client *client)
 {
        struct example_state *state = i2c_get_clientdata(client);
 
@@ -253,7 +253,7 @@ static int example_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit example_remove(struct i2c_client *client)
+static int example_remove(struct i2c_client *client)
 {
        struct example_state *state = i2c_get_clientdata(client);
 
@@ -275,7 +275,7 @@ static struct i2c_driver example_driver = {
        },
        .id_table       = example_idtable,
        .probe          = example_probe,
-       .remove         = __devexit_p(example_remove),
+       .remove         = example_remove,
        .suspend        = example_suspend,
        .resume         = example_resume,
 };
index e68543f767d50d33bd0f11740e929bb28651262b..a0a5d82b6b0b86c94415284ea7d29387bbaaf7c7 100644 (file)
@@ -273,6 +273,7 @@ Code  Seq#(hex)     Include File            Comments
 'z'    40-7F                           CAN bus card    conflict!
                                        <mailto:oe@port.de>
 'z'    10-4F   drivers/s390/crypto/zcrypt_api.h        conflict!
+'|'    00-7F   linux/media.h
 0x80   00-1F   linux/fb.h
 0x89   00-06   arch/x86/include/asm/sockios.h
 0x89   0B-DF   linux/sockios.h
index f6dece5b701436a9581a1d55d30b169a23d9f8a3..c76c21d87e8582a2bd624ac126ba45290e851d70 100644 (file)
@@ -1,8 +1,6 @@
 I/O statistics fields
 ---------------
 
-Last modified Sep 30, 2003
-
 Since 2.4.20 (and some versions before, with patches), and 2.5.45,
 more extensive disk statistics have been introduced to help measure disk
 activity. Tools such as sar and iostat typically interpret these and do
@@ -46,11 +44,12 @@ the above example, the first field of statistics would be 446216.
 By contrast, in 2.6 if you look at /sys/block/hda/stat, you'll
 find just the eleven fields, beginning with 446216.  If you look at
 /proc/diskstats, the eleven fields will be preceded by the major and
-minor device numbers, and device name.  Each of these formats provide
+minor device numbers, and device name.  Each of these formats provides
 eleven fields of statistics, each meaning exactly the same things.
 All fields except field 9 are cumulative since boot.  Field 9 should
-go to zero as I/Os complete; all others only increase.  Yes, these are
-32 bit unsigned numbers, and on a very busy or long-lived system they
+go to zero as I/Os complete; all others only increase (unless they
+overflow and wrap).  Yes, these are (32-bit or 64-bit) unsigned long
+(native word size) numbers, and on a very busy or long-lived system they
 may wrap. Applications should be prepared to deal with that; unless
 your observations are measured in large numbers of minutes or hours,
 they should not wrap twice before you notice them.
@@ -96,11 +95,11 @@ introduced when changes collide, so (for instance) adding up all the
 read I/Os issued per partition should equal those made to the disks ...
 but due to the lack of locking it may only be very close.
 
-In 2.6, there are counters for each cpu, which made the lack of locking
-almost a non-issue.  When the statistics are read, the per-cpu counters
-are summed (possibly overflowing the unsigned 32-bit variable they are
+In 2.6, there are counters for each CPU, which make the lack of locking
+almost a non-issue.  When the statistics are read, the per-CPU counters
+are summed (possibly overflowing the unsigned long variable they are
 summed to) and the result given to the user.  There is no convenient
-user interface for accessing the per-cpu counters themselves.
+user interface for accessing the per-CPU counters themselves.
 
 Disks vs Partitions
 -------------------
index 8f63b224ab0969a758e5347d055777f1601d0b4c..f1431d099fce31371aa74f63efed4f7ce5f9b64b 100644 (file)
@@ -196,3 +196,8 @@ to be included in the databases, separated by blank space. E.g.:
 To get all available archs you can also specify all. E.g.:
 
     $ make ALLSOURCE_ARCHS=all tags
+
+KBUILD_ENABLE_EXTRA_GCC_CHECKS
+--------------------------------------------------
+If enabled over the make command line with "W=1", it turns on additional
+gcc -W... options for more extensive build-time checking.
index d18a9e12152a701bb2729afdb65288ad6da2fccf..c357a31411cdb98978153eb5de0ecb2db025648f 100644 (file)
@@ -872,6 +872,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                               If specified, z/VM IUCV HVC accepts connections
                               from listed z/VM user IDs only.
 
+       keep_bootcon    [KNL]
+                       Do not unregister boot console at start. This is only
+                       useful for debugging when something happens in the window
+                       between unregistering the boot console and initializing
+                       the real console.
+
        i2c_bus=        [HW] Override the default board specific I2C bus speed
                             or register an additional I2C bus that is not
                             registered from board initialization code.
@@ -1597,11 +1603,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: [state][,regs][,debounce][,die]
 
        nmi_watchdog=   [KNL,BUGS=X86] Debugging features for SMP kernels
-                       Format: [panic,][num]
+                       Format: [panic,][nopanic,][num]
                        Valid num: 0
                        0 - turn nmi_watchdog off
                        When panic is specified, panic when an NMI watchdog
-                       timeout occurs.
+                       timeout occurs (or 'nopanic' to override the opposite
+                       default).
                        This is useful when you use a panic=... timeout and
                        need the box quickly up again.
 
@@ -1825,6 +1832,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                perfmon on Intel CPUs instead of the
                                CPU specific event set.
 
+       oops=panic      Always panic on oopses. Default is to just kill the process,
+                       but there is a small probability of deadlocking the machine.
+                       This will also cause panics on machine check exceptions.
+                       Useful together with panic=30 to trigger a reboot.
+
        OSS             [HW,OSS]
                        See Documentation/sound/oss/oss-parameters.txt
 
diff --git a/Documentation/laptops/hpfall.c b/Documentation/laptops/hpfall.c
new file mode 100644 (file)
index 0000000..a4a8fc5
--- /dev/null
@@ -0,0 +1,146 @@
+/* Disk protection for HP machines.
+ *
+ * Copyright 2008 Eric Piel
+ * Copyright 2009 Pavel Machek <pavel@ucw.cz>
+ *
+ * GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sched.h>
+
+char unload_heads_path[64];
+
+int set_unload_heads_path(char *device)
+{
+       char devname[64];
+
+       if (strlen(device) <= 5 || strncmp(device, "/dev/", 5) != 0)
+               return -EINVAL;
+       strncpy(devname, device + 5, sizeof(devname));
+
+       snprintf(unload_heads_path, sizeof(unload_heads_path),
+                               "/sys/block/%s/device/unload_heads", devname);
+       return 0;
+}
+int valid_disk(void)
+{
+       int fd = open(unload_heads_path, O_RDONLY);
+       if (fd < 0) {
+               perror(unload_heads_path);
+               return 0;
+       }
+
+       close(fd);
+       return 1;
+}
+
+void write_int(char *path, int i)
+{
+       char buf[1024];
+       int fd = open(path, O_RDWR);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+       sprintf(buf, "%d", i);
+       if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+               perror("write");
+               exit(1);
+       }
+       close(fd);
+}
+
+void set_led(int on)
+{
+       write_int("/sys/class/leds/hp::hddprotect/brightness", on);
+}
+
+void protect(int seconds)
+{
+       write_int(unload_heads_path, seconds*1000);
+}
+
+int on_ac(void)
+{
+//     /sys/class/power_supply/AC0/online
+}
+
+int lid_open(void)
+{
+//     /proc/acpi/button/lid/LID/state
+}
+
+void ignore_me(void)
+{
+       protect(0);
+       set_led(0);
+}
+
+int main(int argc, char **argv)
+{
+       int fd, ret;
+       struct sched_param param;
+
+       if (argc == 1)
+               ret = set_unload_heads_path("/dev/sda");
+       else if (argc == 2)
+               ret = set_unload_heads_path(argv[1]);
+       else
+               ret = -EINVAL;
+
+       if (ret || !valid_disk()) {
+               fprintf(stderr, "usage: %s <device> (default: /dev/sda)\n",
+                               argv[0]);
+               exit(1);
+       }
+
+       fd = open("/dev/freefall", O_RDONLY);
+       if (fd < 0) {
+               perror("/dev/freefall");
+               return EXIT_FAILURE;
+       }
+
+       daemon(0, 0);
+       param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+       sched_setscheduler(0, SCHED_FIFO, &param);
+       mlockall(MCL_CURRENT|MCL_FUTURE);
+
+       signal(SIGALRM, ignore_me);
+
+       for (;;) {
+               unsigned char count;
+
+               ret = read(fd, &count, sizeof(count));
+               alarm(0);
+               if ((ret == -1) && (errno == EINTR)) {
+                       /* Alarm expired, time to unpark the heads */
+                       continue;
+               }
+
+               if (ret != sizeof(count)) {
+                       perror("read");
+                       break;
+               }
+
+               protect(21);
+               set_led(1);
+               if (1 || on_ac() || lid_open())
+                       alarm(2);
+               else
+                       alarm(20);
+       }
+
+       close(fd);
+       return EXIT_SUCCESS;
+}
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
new file mode 100644 (file)
index 0000000..fd48add
--- /dev/null
@@ -0,0 +1,353 @@
+Linux kernel media framework
+============================
+
+This document describes the Linux kernel media framework, its data structures,
+functions and their usage.
+
+
+Introduction
+------------
+
+The media controller API is documented in DocBook format in
+Documentation/DocBook/v4l/media-controller.xml. This document will focus on
+the kernel-side implementation of the media framework.
+
+
+Abstract media device model
+---------------------------
+
+Discovering a device internal topology, and configuring it at runtime, is one
+of the goals of the media framework. To achieve this, hardware devices are
+modeled as an oriented graph of building blocks called entities connected
+through pads.
+
+An entity is a basic media hardware building block. It can correspond to
+a large variety of logical blocks such as physical hardware devices
+(CMOS sensor for instance), logical hardware devices (a building block
+in a System-on-Chip image processing pipeline), DMA channels or physical
+connectors.
+
+A pad is a connection endpoint through which an entity can interact with
+other entities. Data (not restricted to video) produced by an entity
+flows from the entity's output to one or more entity inputs. Pads should
+not be confused with physical pins at chip boundaries.
+
+A link is a point-to-point oriented connection between two pads, either
+on the same entity or on different entities. Data flows from a source
+pad to a sink pad.
+
+
+Media device
+------------
+
+A media device is represented by a struct media_device instance, defined in
+include/media/media-device.h. Allocation of the structure is handled by the
+media device driver, usually by embedding the media_device instance in a
+larger driver-specific structure.
+
+Drivers register media device instances by calling
+
+       media_device_register(struct media_device *mdev);
+
+The caller is responsible for initializing the media_device structure before
+registration. The following fields must be set:
+
+ - dev must point to the parent device (usually a pci_dev, usb_interface or
+   platform_device instance).
+
+ - model must be filled with the device model name as a NUL-terminated UTF-8
+   string. The device/model revision must not be stored in this field.
+
+The following fields are optional:
+
+ - serial is a unique serial number stored as a NUL-terminated ASCII string.
+   The field is big enough to store a GUID in text form. If the hardware
+   doesn't provide a unique serial number this field must be left empty.
+
+ - bus_info represents the location of the device in the system as a
+   NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
+   "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
+   the usb_make_path() function must be used. This field is used by
+   applications to distinguish between otherwise identical devices that don't
+   provide a serial number.
+
+ - hw_revision is the hardware device revision in a driver-specific format.
+   When possible the revision should be formatted with the KERNEL_VERSION
+   macro.
+
+ - driver_version is formatted with the KERNEL_VERSION macro. The version
+   minor must be incremented when new features are added to the userspace API
+   without breaking binary compatibility. The version major must be
+   incremented when binary compatibility is broken.
+
+Upon successful registration a character device named media[0-9]+ is created.
+The device major and minor numbers are dynamic. The model name is exported as
+a sysfs attribute.
+
+Drivers unregister media device instances by calling
+
+       media_device_unregister(struct media_device *mdev);
+
+Unregistering a media device that hasn't been registered is *NOT* safe.
+
+
+Entities, pads and links
+------------------------
+
+- Entities
+
+Entities are represented by a struct media_entity instance, defined in
+include/media/media-entity.h. The structure is usually embedded into a
+higher-level structure, such as a v4l2_subdev or video_device instance,
+although drivers can allocate entities directly.
+
+Drivers initialize entities by calling
+
+       media_entity_init(struct media_entity *entity, u16 num_pads,
+                         struct media_pad *pads, u16 extra_links);
+
+The media_entity name, type, flags, revision and group_id fields can be
+initialized before or after calling media_entity_init. Entities embedded in
+higher-level standard structures can have some of those fields set by the
+higher-level framework.
+
+As the number of pads is known in advance, the pads array is not allocated
+dynamically but is managed by the entity driver. Most drivers will embed the
+pads array in a driver-specific structure, avoiding dynamic allocation.
+
+Drivers must set the direction of every pad in the pads array before calling
+media_entity_init. The function will initialize the other pads fields.
+
+Unlike the number of pads, the total number of links isn't always known in
+advance by the entity driver. As an initial estimate, media_entity_init
+pre-allocates a number of links equal to the number of pads plus an optional
+number of extra links. The links array will be reallocated if it grows beyond
+the initial estimate.
+
+Drivers register entities with a media device by calling
+
+       media_device_register_entity(struct media_device *mdev,
+                                    struct media_entity *entity);
+
+Entities are identified by a unique positive integer ID. Drivers can provide an
+ID by filling the media_entity id field prior to registration, or request the
+media controller framework to assign an ID automatically. Drivers that provide
+IDs manually must ensure that all IDs are unique. IDs are not guaranteed to be
+contiguous even when they are all assigned automatically by the framework.
+
+Drivers unregister entities by calling
+
+       media_device_unregister_entity(struct media_entity *entity);
+
+Unregistering an entity will not change the IDs of the other entities, and the
+ID will never be reused for a newly registered entity.
+
+When a media device is unregistered, all its entities are unregistered
+automatically. No manual entities unregistration is then required.
+
+Drivers free resources associated with an entity by calling
+
+       media_entity_cleanup(struct media_entity *entity);
+
+This function must be called during the cleanup phase after unregistering the
+entity. Note that the media_entity instance itself must be freed explicitly by
+the driver if required.
+
+Entities have flags that describe the entity capabilities and state.
+
+       MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
+       This can be used to report the default audio and video devices or the
+       default camera sensor.
+
+Logical entity groups can be defined by setting the group ID of all member
+entities to the same non-zero value. An entity group serves no purpose in the
+kernel, but is reported to userspace during entities enumeration. The group_id
+field belongs to the media device driver and must not by touched by entity
+drivers.
+
+Media device drivers should define groups if several entities are logically
+bound together. Example usages include reporting
+
+       - ALSA, VBI and video nodes that carry the same media stream
+       - lens and flash controllers associated with a sensor
+
+- Pads
+
+Pads are represented by a struct media_pad instance, defined in
+include/media/media-entity.h. Each entity stores its pads in a pads array
+managed by the entity driver. Drivers usually embed the array in a
+driver-specific structure.
+
+Pads are identified by their entity and their 0-based index in the pads array.
+Both information are stored in the media_pad structure, making the media_pad
+pointer the canonical way to store and pass link references.
+
+Pads have flags that describe the pad capabilities and state.
+
+       MEDIA_PAD_FL_SINK indicates that the pad supports sinking data.
+       MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
+
+One and only one of MEDIA_PAD_FL_SINK and MEDIA_PAD_FL_SOURCE must be set for
+each pad.
+
+- Links
+
+Links are represented by a struct media_link instance, defined in
+include/media/media-entity.h. Each entity stores all links originating at or
+targetting any of its pads in a links array. A given link is thus stored
+twice, once in the source entity and once in the target entity. The array is
+pre-allocated and grows dynamically as needed.
+
+Drivers create links by calling
+
+       media_entity_create_link(struct media_entity *source, u16 source_pad,
+                                struct media_entity *sink,   u16 sink_pad,
+                                u32 flags);
+
+An entry in the link array of each entity is allocated and stores pointers
+to source and sink pads.
+
+Links have flags that describe the link capabilities and state.
+
+       MEDIA_LNK_FL_ENABLED indicates that the link is enabled and can be used
+       to transfer media data. When two or more links target a sink pad, only
+       one of them can be enabled at a time.
+       MEDIA_LNK_FL_IMMUTABLE indicates that the link enabled state can't be
+       modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
+       MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
+       enabled.
+
+
+Graph traversal
+---------------
+
+The media framework provides APIs to iterate over entities in a graph.
+
+To iterate over all entities belonging to a media device, drivers can use the
+media_device_for_each_entity macro, defined in include/media/media-device.h.
+
+       struct media_entity *entity;
+
+       media_device_for_each_entity(entity, mdev) {
+               /* entity will point to each entity in turn */
+               ...
+       }
+
+Drivers might also need to iterate over all entities in a graph that can be
+reached only through enabled links starting at a given entity. The media
+framework provides a depth-first graph traversal API for that purpose.
+
+Note that graphs with cycles (whether directed or undirected) are *NOT*
+supported by the graph traversal API. To prevent infinite loops, the graph
+traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
+currently defined as 16.
+
+Drivers initiate a graph traversal by calling
+
+       media_entity_graph_walk_start(struct media_entity_graph *graph,
+                                     struct media_entity *entity);
+
+The graph structure, provided by the caller, is initialized to start graph
+traversal at the given entity.
+
+Drivers can then retrieve the next entity by calling
+
+       media_entity_graph_walk_next(struct media_entity_graph *graph);
+
+When the graph traversal is complete the function will return NULL.
+
+Graph traversal can be interrupted at any moment. No cleanup function call is
+required and the graph structure can be freed normally.
+
+Helper functions can be used to find a link between two given pads, or a pad
+connected to another pad through an enabled link
+
+       media_entity_find_link(struct media_pad *source,
+                              struct media_pad *sink);
+
+       media_entity_remote_source(struct media_pad *pad);
+
+Refer to the kerneldoc documentation for more information.
+
+
+Use count and power handling
+----------------------------
+
+Due to the wide differences between drivers regarding power management needs,
+the media controller does not implement power management. However, the
+media_entity structure includes a use_count field that media drivers can use to
+track the number of users of every entity for power management needs.
+
+The use_count field is owned by media drivers and must not be touched by entity
+drivers. Access to the field must be protected by the media device graph_mutex
+lock.
+
+
+Links setup
+-----------
+
+Link properties can be modified at runtime by calling
+
+       media_entity_setup_link(struct media_link *link, u32 flags);
+
+The flags argument contains the requested new link flags.
+
+The only configurable property is the ENABLED link flag to enable/disable a
+link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
+
+When a link is enabled or disabled, the media framework calls the
+link_setup operation for the two entities at the source and sink of the link,
+in that order. If the second link_setup call fails, another link_setup call is
+made on the first entity to restore the original link flags.
+
+Media device drivers can be notified of link setup operations by setting the
+media_device::link_notify pointer to a callback function. If provided, the
+notification callback will be called before enabling and after disabling
+links.
+
+Entity drivers must implement the link_setup operation if any of their links
+is non-immutable. The operation must either configure the hardware or store
+the configuration information to be applied later.
+
+Link configuration must not have any side effect on other links. If an enabled
+link at a sink pad prevents another link at the same pad from being disabled,
+the link_setup operation must return -EBUSY and can't implicitly disable the
+first enabled link.
+
+
+Pipelines and media streams
+---------------------------
+
+When starting streaming, drivers must notify all entities in the pipeline to
+prevent link states from being modified during streaming by calling
+
+       media_entity_pipeline_start(struct media_entity *entity,
+                                   struct media_pipeline *pipe);
+
+The function will mark all entities connected to the given entity through
+enabled links, either directly or indirectly, as streaming.
+
+The media_pipeline instance pointed to by the pipe argument will be stored in
+every entity in the pipeline. Drivers should embed the media_pipeline structure
+in higher-level pipeline structures and can then access the pipeline through
+the media_entity pipe field.
+
+Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
+be identical for all nested calls to the function.
+
+When stopping the stream, drivers must notify the entities with
+
+       media_entity_pipeline_stop(struct media_entity *entity);
+
+If multiple calls to media_entity_pipeline_start() have been made the same
+number of media_entity_pipeline_stop() calls are required to stop streaming. The
+media_entity pipe field is reset to NULL on the last nested stop call.
+
+Link configuration will fail with -EBUSY by default if either end of the link is
+a streaming entity. Links that can be modified while streaming must be marked
+with the MEDIA_LNK_FL_DYNAMIC flag.
+
+If other operations need to be disallowed on streaming entities (such as
+changing entities configuration parameters) drivers can explictly check the
+media_entity stream_count field to find out if an entity is streaming. This
+operation must be done with the media_device graph_mutex held.
diff --git a/Documentation/misc-devices/lis3lv02d b/Documentation/misc-devices/lis3lv02d
new file mode 100644 (file)
index 0000000..f1a4ec8
--- /dev/null
@@ -0,0 +1,92 @@
+Kernel driver lis3lv02d
+=======================
+
+Supported chips:
+
+  * STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
+  * STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits)
+
+Authors:
+        Yan Burman <burman.yan@gmail.com>
+       Eric Piel <eric.piel@tremplin-utc.net>
+
+
+Description
+-----------
+
+This driver provides support for the accelerometer found in various HP laptops
+sporting the feature officially called "HP Mobile Data Protection System 3D" or
+"HP 3D DriveGuard". It detects automatically laptops with this sensor. Known
+models (full list can be found in drivers/platform/x86/hp_accel.c) will have
+their axis automatically oriented on standard way (eg: you can directly play
+neverball). The accelerometer data is readable via
+/sys/devices/platform/lis3lv02d. Reported values are scaled
+to mg values (1/1000th of earth gravity).
+
+Sysfs attributes under /sys/devices/platform/lis3lv02d/:
+position - 3D position that the accelerometer reports. Format: "(x,y,z)"
+rate - read reports the sampling rate of the accelerometer device in HZ.
+       write changes sampling rate of the accelerometer device.
+       Only values which are supported by HW are accepted.
+selftest - performs selftest for the chip as specified by chip manufacturer.
+
+This driver also provides an absolute input class device, allowing
+the laptop to act as a pinball machine-esque joystick. Joystick device can be
+calibrated. Joystick device can be in two different modes.
+By default output values are scaled between -32768 .. 32767. In joystick raw
+mode, joystick and sysfs position entry have the same scale. There can be
+small difference due to input system fuzziness feature.
+Events are also available as input event device.
+
+Selftest is meant only for hardware diagnostic purposes. It is not meant to be
+used during normal operations. Position data is not corrupted during selftest
+but interrupt behaviour is not guaranteed to work reliably. In test mode, the
+sensing element is internally moved little bit. Selftest measures difference
+between normal mode and test mode. Chip specifications tell the acceptance
+limit for each type of the chip. Limits are provided via platform data
+to allow adjustment of the limits without a change to the actual driver.
+Seltest returns either "OK x y z" or "FAIL x y z" where x, y and z are
+measured difference between modes. Axes are not remapped in selftest mode.
+Measurement values are provided to help HW diagnostic applications to make
+final decision.
+
+On HP laptops, if the led infrastructure is activated, support for a led
+indicating disk protection will be provided as /sys/class/leds/hp::hddprotect.
+
+Another feature of the driver is misc device called "freefall" that
+acts similar to /dev/rtc and reacts on free-fall interrupts received
+from the device. It supports blocking operations, poll/select and
+fasync operation modes. You must read 1 bytes from the device.  The
+result is number of free-fall interrupts since the last successful
+read (or 255 if number of interrupts would not fit). See the hpfall.c
+file for an example on using the device.
+
+
+Axes orientation
+----------------
+
+For better compatibility between the various laptops. The values reported by
+the accelerometer are converted into a "standard" organisation of the axes
+(aka "can play neverball out of the box"):
+ * When the laptop is horizontal the position reported is about 0 for X and Y
+       and a positive value for Z
+ * If the left side is elevated, X increases (becomes positive)
+ * If the front side (where the touchpad is) is elevated, Y decreases
+       (becomes negative)
+ * If the laptop is put upside-down, Z becomes negative
+
+If your laptop model is not recognized (cf "dmesg"), you can send an
+email to the maintainer to add it to the database.  When reporting a new
+laptop, please include the output of "dmidecode" plus the value of
+/sys/devices/platform/lis3lv02d/position in these four cases.
+
+Q&A
+---
+
+Q: How do I safely simulate freefall? I have an HP "portable
+workstation" which has about 3.5kg and a plastic case, so letting it
+fall to the ground is out of question...
+
+A: The sensor is pretty sensitive, so your hands can do it. Lift it
+into free space, follow the fall with your hands for like 10
+centimeters. That should be enough to trigger the detection.
diff --git a/Documentation/misc-devices/spear-pcie-gadget.txt b/Documentation/misc-devices/spear-pcie-gadget.txt
new file mode 100644 (file)
index 0000000..02c13ef
--- /dev/null
@@ -0,0 +1,130 @@
+Spear PCIe Gadget Driver:
+
+Author
+=============
+Pratyush Anand (pratyush.anand@st.com)
+
+Location
+============
+driver/misc/spear13xx_pcie_gadget.c
+
+Supported Chip:
+===================
+SPEAr1300
+SPEAr1310
+
+Menuconfig option:
+==========================
+Device Drivers
+       Misc devices
+               PCIe gadget support for SPEAr13XX platform
+purpose
+===========
+This driver has several nodes which can be read/written by configfs interface.
+Its main purpose is to configure selected dual mode PCIe controller as device
+and then program its various registers to configure it as a particular device
+type. This driver can be used to show spear's PCIe device capability.
+
+Description of different nodes:
+=================================
+
+read behavior of nodes:
+------------------------------
+link           :gives ltssm status.
+int_type       :type of supported interrupt
+no_of_msi      :zero if MSI is not enabled by host. A positive value is the
+               number of MSI vector granted.
+vendor_id      :returns programmed vendor id (hex)
+device_id      :returns programmed device id(hex)
+bar0_size:     :returns size of bar0 in hex.
+bar0_address   :returns address of bar0 mapped area in hex.
+bar0_rw_offset :returns offset of bar0 for which bar0_data will return value.
+bar0_data      :returns data at bar0_rw_offset.
+
+write behavior of nodes:
+------------------------------
+link           :write UP to enable ltsmm DOWN to disable
+int_type       :write interrupt type to be configured and (int_type could be
+               INTA, MSI or NO_INT). Select MSI only when you have programmed
+               no_of_msi node.
+no_of_msi      :number of MSI vector needed.
+inta           :write 1 to assert INTA and 0 to de-assert.
+send_msi       :write MSI vector to be sent.
+vendor_id      :write vendor id(hex) to be programmed.
+device_id      :write device id(hex) to be programmed.
+bar0_size      :write size of bar0 in hex. default bar0 size is 1000 (hex)
+               bytes.
+bar0_address   :write  address of bar0 mapped area in hex. (default mapping of
+               bar0 is SYSRAM1(E0800000). Always program bar size before bar
+               address. Kernel might modify bar size and address for alignment, so
+               read back bar size and address after writing to cross check.
+bar0_rw_offset :write offset of bar0 for which bar0_data will write value.
+bar0_data      :write data to be written at bar0_rw_offset.
+
+Node programming example
+===========================
+Program all PCIe registers in such a way that when this device is connected
+to the PCIe host, then host sees this device as 1MB RAM.
+#mount -t configfs none /Config
+For nth PCIe Device Controller
+# cd /config/pcie_gadget.n/
+Now you have all the nodes in this directory.
+program vendor id as 0x104a
+# echo 104A >> vendor_id
+
+program device id as 0xCD80
+# echo CD80 >> device_id
+
+program BAR0 size as 1MB
+# echo 100000 >> bar0_size
+
+check for programmed bar0 size
+# cat bar0_size
+
+Program BAR0 Address as DDR (0x2100000). This is the physical address of
+memory, which is to be made visible to PCIe host. Similarly any other peripheral
+can also be made visible to PCIe host. E.g., if you program base address of UART
+as BAR0 address then when this device will be connected to a host, it will be
+visible as UART.
+# echo 2100000 >> bar0_address
+
+program interrupt type : INTA
+# echo INTA >> int_type
+
+go for link up now.
+# echo UP >> link
+
+It will have to be insured that, once link up is done on gadget, then only host
+is initialized and start to search PCIe devices on its port.
+
+/*wait till link is up*/
+# cat link
+wait till it returns UP.
+
+To assert INTA
+# echo 1 >> inta
+
+To de-assert INTA
+# echo 0 >> inta
+
+if MSI is to be used as interrupt, program no of msi vector needed (say4)
+# echo 4 >> no_of_msi
+
+select MSI as interrupt type
+# echo MSI >> int_type
+
+go for link up now
+# echo UP >> link
+
+wait till link is up
+# cat link
+An application can repetitively read this node till link is found UP. It can
+sleep between two read.
+
+wait till msi is enabled
+# cat no_of_msi
+Should return 4 (number of requested MSI vector)
+
+to send msi vector 2
+# echo 2 >> send_msi
+#cd -
diff --git a/Documentation/rapidio/rapidio.txt b/Documentation/rapidio/rapidio.txt
new file mode 100644 (file)
index 0000000..be70ee1
--- /dev/null
@@ -0,0 +1,173 @@
+                          The Linux RapidIO Subsystem
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The RapidIO standard is a packet-based fabric interconnect standard designed for
+use in embedded systems. Development of the RapidIO standard is directed by the
+RapidIO Trade Association (RTA). The current version of the RapidIO specification
+is publicly available for download from the RTA web-site [1].
+
+This document describes the basics of the Linux RapidIO subsystem and provides
+information on its major components.
+
+1 Overview
+----------
+
+Because the RapidIO subsystem follows the Linux device model it is integrated
+into the kernel similarly to other buses by defining RapidIO-specific device and
+bus types and registering them within the device model.
+
+The Linux RapidIO subsystem is architecture independent and therefore defines
+architecture-specific interfaces that provide support for common RapidIO
+subsystem operations.
+
+2. Core Components
+------------------
+
+A typical RapidIO network is a combination of endpoints and switches.
+Each of these components is represented in the subsystem by an associated data
+structure. The core logical components of the RapidIO subsystem are defined
+in include/linux/rio.h file.
+
+2.1 Master Port
+
+A master port (or mport) is a RapidIO interface controller that is local to the
+processor executing the Linux code. A master port generates and receives RapidIO
+packets (transactions). In the RapidIO subsystem each master port is represented
+by a rio_mport data structure. This structure contains master port specific
+resources such as mailboxes and doorbells. The rio_mport also includes a unique
+host device ID that is valid when a master port is configured as an enumerating
+host.
+
+RapidIO master ports are serviced by subsystem specific mport device drivers
+that provide functionality defined for this subsystem. To provide a hardware
+independent interface for RapidIO subsystem operations, rio_mport structure
+includes rio_ops data structure which contains pointers to hardware specific
+implementations of RapidIO functions.
+
+2.2 Device
+
+A RapidIO device is any endpoint (other than mport) or switch in the network.
+All devices are presented in the RapidIO subsystem by corresponding rio_dev data
+structure. Devices form one global device list and per-network device lists
+(depending on number of available mports and networks).
+
+2.3 Switch
+
+A RapidIO switch is a special class of device that routes packets between its
+ports towards their final destination. The packet destination port within a
+switch is defined by an internal routing table. A switch is presented in the
+RapidIO subsystem by rio_dev data structure expanded by additional rio_switch
+data structure, which contains switch specific information such as copy of the
+routing table and pointers to switch specific functions.
+
+The RapidIO subsystem defines the format and initialization method for subsystem
+specific switch drivers that are designed to provide hardware-specific
+implementation of common switch management routines.
+
+2.4 Network
+
+A RapidIO network is a combination of interconnected endpoint and switch devices.
+Each RapidIO network known to the system is represented by corresponding rio_net
+data structure. This structure includes lists of all devices and local master
+ports that form the same network. It also contains a pointer to the default
+master port that is used to communicate with devices within the network.
+
+3. Subsystem Initialization
+---------------------------
+
+In order to initialize the RapidIO subsystem, a platform must initialize and
+register at least one master port within the RapidIO network. To register mport
+within the subsystem controller driver initialization code calls function
+rio_register_mport() for each available master port. After all active master
+ports are registered with a RapidIO subsystem, the rio_init_mports() routine
+is called to perform enumeration and discovery.
+
+In the current PowerPC-based implementation a subsys_initcall() is specified to
+perform controller initialization and mport registration. At the end it directly
+calls rio_init_mports() to execute RapidIO enumeration and discovery.
+
+4. Enumeration and Discovery
+----------------------------
+
+When rio_init_mports() is called it scans a list of registered master ports and
+calls an enumeration or discovery routine depending on the configured role of a
+master port: host or agent.
+
+Enumeration is performed by a master port if it is configured as a host port by
+assigning a host device ID greater than or equal to zero. A host device ID is
+assigned to a master port through the kernel command line parameter "riohdid=",
+or can be configured in a platform-specific manner. If the host device ID for
+a specific master port is set to -1, the discovery process will be performed
+for it.
+
+The enumeration and discovery routines use RapidIO maintenance transactions
+to access the configuration space of devices.
+
+The enumeration process is implemented according to the enumeration algorithm
+outlined in the RapidIO Interconnect Specification: Annex I [1].
+
+The enumeration process traverses the network using a recursive depth-first
+algorithm. When a new device is found, the enumerator takes ownership of that
+device by writing into the Host Device ID Lock CSR. It does this to ensure that
+the enumerator has exclusive right to enumerate the device. If device ownership
+is successfully acquired, the enumerator allocates a new rio_dev structure and
+initializes it according to device capabilities.
+
+If the device is an endpoint, a unique device ID is assigned to it and its value
+is written into the device's Base Device ID CSR.
+
+If the device is a switch, the enumerator allocates an additional rio_switch
+structure to store switch specific information. Then the switch's vendor ID and
+device ID are queried against a table of known RapidIO switches. Each switch
+table entry contains a pointer to a switch-specific initialization routine that
+initializes pointers to the rest of switch specific operations, and performs
+hardware initialization if necessary. A RapidIO switch does not have a unique
+device ID; it relies on hopcount and routing for device ID of an attached
+endpoint if access to its configuration registers is required. If a switch (or
+chain of switches) does not have any endpoint (except enumerator) attached to
+it, a fake device ID will be assigned to configure a route to that switch.
+In the case of a chain of switches without endpoint, one fake device ID is used
+to configure a route through the entire chain and switches are differentiated by
+their hopcount value.
+
+For both endpoints and switches the enumerator writes a unique component tag
+into device's Component Tag CSR. That unique value is used by the error
+management notification mechanism to identify a device that is reporting an
+error management event.
+
+Enumeration beyond a switch is completed by iterating over each active egress
+port of that switch. For each active link, a route to a default device ID
+(0xFF for 8-bit systems and 0xFFFF for 16-bit systems) is temporarily written
+into the routing table. The algorithm recurs by calling itself with hopcount + 1
+and the default device ID in order to access the device on the active port.
+
+After the host has completed enumeration of the entire network it releases
+devices by clearing device ID locks (calls rio_clear_locks()). For each endpoint
+in the system, it sets the Master Enable bit in the Port General Control CSR
+to indicate that enumeration is completed and agents are allowed to execute
+passive discovery of the network.
+
+The discovery process is performed by agents and is similar to the enumeration
+process that is described above. However, the discovery process is performed
+without changes to the existing routing because agents only gather information
+about RapidIO network structure and are building an internal map of discovered
+devices. This way each Linux-based component of the RapidIO subsystem has
+a complete view of the network. The discovery process can be performed
+simultaneously by several agents. After initializing its RapidIO master port
+each agent waits for enumeration completion by the host for the configured wait
+time period. If this wait time period expires before enumeration is completed,
+an agent skips RapidIO discovery and continues with remaining kernel
+initialization.
+
+5. References
+-------------
+
+[1] RapidIO Trade Association. RapidIO Interconnect Specifications.
+    http://www.rapidio.org.
+[2] Rapidio TA. Technology Comparisons.
+    http://www.rapidio.org/education/technology_comparisons/
+[3] RapidIO support for Linux.
+    http://lwn.net/Articles/139118/
+[4] Matt Porter. RapidIO for Linux. Ottawa Linux Symposium, 2005
+    http://www.kernel.org/doc/ols/2005/ols2005v2-pages-43-56.pdf
diff --git a/Documentation/rapidio/sysfs.txt b/Documentation/rapidio/sysfs.txt
new file mode 100644 (file)
index 0000000..97f71ce
--- /dev/null
@@ -0,0 +1,90 @@
+                         RapidIO sysfs Files
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Device Subdirectories
+------------------------
+
+For each RapidIO device, the RapidIO subsystem creates files in an individual
+subdirectory with the following name, /sys/bus/rapidio/devices/<device_name>.
+
+The format of device_name is "nn:d:iiii", where:
+
+nn - two-digit hexadecimal ID of RapidIO network where the device resides
+d  - device typr: 'e' - for endpoint or 's' - for switch
+iiii - four-digit device destID for endpoints, or switchID for switches
+
+For example, below is a list of device directories that represents a typical
+RapidIO network with one switch, one host, and two agent endpoints, as it is
+seen by the enumerating host (destID = 1):
+
+/sys/bus/rapidio/devices/00:e:0000
+/sys/bus/rapidio/devices/00:e:0002
+/sys/bus/rapidio/devices/00:s:0001
+
+NOTE: An enumerating or discovering endpoint does not create a sysfs entry for
+itself, this is why an endpoint with destID=1 is not shown in the list.
+
+2. Attributes Common for All Devices
+------------------------------------
+
+Each device subdirectory contains the following informational read-only files:
+
+       did - returns the device identifier
+       vid - returns the device vendor identifier
+device_rev - returns the device revision level
+   asm_did - returns identifier for the assembly containing the device
+   asm_rev - returns revision level of the assembly containing the device
+   asm_vid - returns vendor identifier of the assembly containing the device
+   destid  - returns device destination ID assigned by the enumeration routine
+             (see 4.1 for switch specific details)
+   lprev   - returns name of previous device (switch) on the path to the device
+             that that owns this attribute
+
+In addition to the files listed above, each device has a binary attribute file
+that allows read/write access to the device configuration registers using
+the RapidIO maintenance transactions:
+
+ config - reads from and writes to the device configuration registers.
+
+This attribute is similar in behavior to the "config" attribute of PCI devices
+and provides an access to the RapidIO device registers using standard file read
+and write operations.
+
+3. Endpoint Device Attributes
+-----------------------------
+
+Currently Linux RapidIO subsystem does not create any endpoint specific sysfs
+attributes. It is possible that RapidIO master port drivers and endpoint device
+drivers will add their device-specific sysfs attributes but such attributes are
+outside the scope of this document.
+
+4. Switch Device Attributes
+---------------------------
+
+RapidIO switches have additional attributes in sysfs. RapidIO subsystem supports
+common and device-specific sysfs attributes for switches. Because switches are
+integrated into the RapidIO subsystem, it offers a method to create
+device-specific sysfs attributes by specifying a callback function that may be
+set by the switch initialization routine during enumeration or discovery process.
+
+4.1 Common Switch Attributes
+
+   routes - reports switch routing information in "destID port" format. This
+            attribute reports only valid routing table entries, one line for
+            each entry.
+   destid - device destination ID that defines a route to the switch
+ hopcount - number of hops on the path to the switch
+    lnext - returns names of devices linked to the switch except one of a device
+            linked to the ingress port (reported as "lprev"). This is an array
+            names with number of lines equal to number of ports in switch. If
+            a switch port has no attached device, returns "null" instead of
+            a device name.
+
+4.2 Device-specific Switch Attributes
+
+Device-specific switch attributes are listed for each RapidIO switch driver
+that exports additional attributes.
+
+IDT_GEN2:
+ errlog - reads contents of device error log until it is empty.
index 8239ebbcddce1d9b84689b8e1be530243bee5f83..99961993257a9f9cf358ca9641577e4b5b1699ff 100644 (file)
@@ -164,7 +164,7 @@ This is the (partial) list of the hooks:
    It puts the scheduling entity (task) into the red-black tree and
    increments the nr_running variable.
 
- - dequeue_tree(...)
+ - dequeue_task(...)
 
    When a task is no longer runnable, this function is called to keep the
    corresponding scheduling entity out of the red-black tree.  It decrements
@@ -195,11 +195,6 @@ This is the (partial) list of the hooks:
    This function is mostly called from time tick functions; it might lead to
    process switch.  This drives the running preemption.
 
- - task_new(...)
-
-   The core scheduler gives the scheduling module an opportunity to manage new
-   task startup.  The CFS scheduling module uses it for group scheduling, while
-   the scheduling module for a real-time task does not use it.
 
 
 
index 42b06686eb78760e7367eb410ce19b4ca2dfe452..2579b5b709ed6723aa75c7ad1a61a13dcc5aa05c 100644 (file)
@@ -36,8 +36,7 @@ Additional features for the PVR-350 (CX23415 based):
  * Provides comprehensive OSD (On Screen Display: ie. graphics overlaying the
    video signal)
  * Provides a framebuffer (allowing X applications to appear on the video
-   device) (this framebuffer is not yet part of the kernel. In the meantime it
-   is available from www.ivtvdriver.org).
+   device)
  * Supports raw YUV output.
 
 IMPORTANT: In case of problems first read this page:
index 699b60e070d216b1860e39aaa58c3f1967cc7866..c40e3bab08fa3cffc72c162931b8694d57fd2a03 100644 (file)
@@ -130,7 +130,7 @@ Card number: 4
 
 Note: No module for the mse3000 is available yet
 Note: No module for the vpx3224 is available yet
-Note: use encoder=X or decoder=X for non-default i2c chips (see i2c-id.h)
+Note: use encoder=X or decoder=X for non-default i2c chips
 
 ===========================
 
index 261776e0c5e1ea01b3da920fdabb7f6f6e57fffd..5c542e60f51db3dba6c037e633830a727284a9de 100644 (file)
@@ -103,6 +103,7 @@ spca561             046d:092d       Logitech QC Elch2
 spca561                046d:092e       Logitech QC Elch2
 spca561                046d:092f       Logitech QuickCam Express Plus
 sunplus                046d:0960       Logitech ClickSmart 420
+nw80x          046d:d001       Logitech QuickCam Pro (dark focus ring)
 sunplus                0471:0322       Philips DMVC1300K
 zc3xx          0471:0325       Philips SPC 200 NC
 zc3xx          0471:0326       Philips SPC 300 NC
@@ -150,10 +151,12 @@ sunplus           04fc:5330       Digitrex 2110
 sunplus                04fc:5360       Sunplus Generic
 spca500                04fc:7333       PalmPixDC85
 sunplus                04fc:ffff       Pure DigitalDakota
+nw80x          0502:d001       DVC V6
 spca501                0506:00df       3Com HomeConnect Lite
 sunplus                052b:1507       Megapixel 5 Pretec DC-1007
 sunplus                052b:1513       Megapix V4
 sunplus                052b:1803       MegaImage VI
+nw80x          052b:d001       EZCam Pro p35u
 tv8532         0545:808b       Veo Stingray
 tv8532         0545:8333       Veo Stingray
 sunplus                0546:3155       Polaroid PDC3070
@@ -177,6 +180,7 @@ sunplus             055f:c530       Mustek Gsmart LCD 3
 sunplus                055f:c540       Gsmart D30
 sunplus                055f:c630       Mustek MDC4000
 sunplus                055f:c650       Mustek MDC5500Z
+nw80x          055f:d001       Mustek Wcam 300 mini
 zc3xx          055f:d003       Mustek WCam300A
 zc3xx          055f:d004       Mustek WCam300 AN
 conex          0572:0041       Creative Notebook cx11646
@@ -195,14 +199,20 @@ gl860             05e3:0503       Genesys Logic PC Camera
 gl860          05e3:f191       Genesys Logic PC Camera
 spca561                060b:a001       Maxell Compact Pc PM3
 zc3xx          0698:2003       CTX M730V built in
+nw80x          06a5:0000       Typhoon Webcam 100 USB
+nw80x          06a5:d001       Divio based webcams
+nw80x          06a5:d800       Divio Chicony TwinkleCam, Trust SpaceCam
 spca500                06bd:0404       Agfa CL20
 spca500                06be:0800       Optimedia
+nw80x          06be:d001       EZCam Pro p35u
 sunplus                06d6:0031       Trust 610 LCD PowerC@m Zoom
 spca506                06e1:a190       ADS Instant VCD
+ov534          06f8:3002       Hercules Blog Webcam
 ov534_9                06f8:3003       Hercules Dualpix HD Weblog
 sonixj         06f8:3004       Hercules Classic Silver
 sonixj         06f8:3008       Hercules Deluxe Optical Glass
 pac7302                06f8:3009       Hercules Classic Link
+nw80x          0728:d001       AVerMedia Camguard
 spca508                0733:0110       ViewQuest VQ110
 spca501                0733:0401       Intel Create and Share
 spca501                0733:0402       ViewQuest M318B
diff --git a/Documentation/video4linux/omap3isp.txt b/Documentation/video4linux/omap3isp.txt
new file mode 100644 (file)
index 0000000..69be2c7
--- /dev/null
@@ -0,0 +1,278 @@
+OMAP 3 Image Signal Processor (ISP) driver
+
+Copyright (C) 2010 Nokia Corporation
+Copyright (C) 2009 Texas Instruments, Inc.
+
+Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+         Sakari Ailus <sakari.ailus@iki.fi>
+         David Cohen <dacohen@gmail.com>
+
+
+Introduction
+============
+
+This file documents the Texas Instruments OMAP 3 Image Signal Processor (ISP)
+driver located under drivers/media/video/omap3isp. The original driver was
+written by Texas Instruments but since that it has been rewritten (twice) at
+Nokia.
+
+The driver has been successfully used on the following versions of OMAP 3:
+
+       3430
+       3530
+       3630
+
+The driver implements V4L2, Media controller and v4l2_subdev interfaces.
+Sensor, lens and flash drivers using the v4l2_subdev interface in the kernel
+are supported.
+
+
+Split to subdevs
+================
+
+The OMAP 3 ISP is split into V4L2 subdevs, each of the blocks inside the ISP
+having one subdev to represent it. Each of the subdevs provide a V4L2 subdev
+interface to userspace.
+
+       OMAP3 ISP CCP2
+       OMAP3 ISP CSI2a
+       OMAP3 ISP CCDC
+       OMAP3 ISP preview
+       OMAP3 ISP resizer
+       OMAP3 ISP AEWB
+       OMAP3 ISP AF
+       OMAP3 ISP histogram
+
+Each possible link in the ISP is modelled by a link in the Media controller
+interface. For an example program see [2].
+
+
+Controlling the OMAP 3 ISP
+==========================
+
+In general, the settings given to the OMAP 3 ISP take effect at the beginning
+of the following frame. This is done when the module becomes idle during the
+vertical blanking period on the sensor. In memory-to-memory operation the pipe
+is run one frame at a time. Applying the settings is done between the frames.
+
+All the blocks in the ISP, excluding the CSI-2 and possibly the CCP2 receiver,
+insist on receiving complete frames. Sensors must thus never send the ISP
+partial frames.
+
+Autoidle does have issues with some ISP blocks on the 3430, at least.
+Autoidle is only enabled on 3630 when the omap3isp module parameter autoidle
+is non-zero.
+
+
+Events
+======
+
+The OMAP 3 ISP driver does support the V4L2 event interface on CCDC and
+statistics (AEWB, AF and histogram) subdevs.
+
+The CCDC subdev produces V4L2_EVENT_OMAP3ISP_HS_VS type event on HS_VS
+interrupt which is used to signal frame start. The event is triggered exactly
+when the reception of the first line of the frame starts in the CCDC module.
+The event can be subscribed on the CCDC subdev.
+
+(When using parallel interface one must pay account to correct configuration
+of the VS signal polarity. This is automatically correct when using the serial
+receivers.)
+
+Each of the statistics subdevs is able to produce events. An event is
+generated whenever a statistics buffer can be dequeued by a user space
+application using the VIDIOC_OMAP3ISP_STAT_REQ IOCTL. The events available
+are:
+
+       V4L2_EVENT_OMAP3ISP_AEWB
+       V4L2_EVENT_OMAP3ISP_AF
+       V4L2_EVENT_OMAP3ISP_HIST
+
+The type of the event data is struct omap3isp_stat_event_status for these
+ioctls. If there is an error calculating the statistics, there will be an
+event as usual, but no related statistics buffer. In this case
+omap3isp_stat_event_status.buf_err is set to non-zero.
+
+
+Private IOCTLs
+==============
+
+The OMAP 3 ISP driver supports standard V4L2 IOCTLs and controls where
+possible and practical. Much of the functions provided by the ISP, however,
+does not fall under the standard IOCTLs --- gamma tables and configuration of
+statistics collection are examples of such.
+
+In general, there is a private ioctl for configuring each of the blocks
+containing hardware-dependent functions.
+
+The following private IOCTLs are supported:
+
+       VIDIOC_OMAP3ISP_CCDC_CFG
+       VIDIOC_OMAP3ISP_PRV_CFG
+       VIDIOC_OMAP3ISP_AEWB_CFG
+       VIDIOC_OMAP3ISP_HIST_CFG
+       VIDIOC_OMAP3ISP_AF_CFG
+       VIDIOC_OMAP3ISP_STAT_REQ
+       VIDIOC_OMAP3ISP_STAT_EN
+
+The parameter structures used by these ioctls are described in
+include/linux/omap3isp.h. The detailed functions of the ISP itself related to
+a given ISP block is described in the Technical Reference Manuals (TRMs) ---
+see the end of the document for those.
+
+While it is possible to use the ISP driver without any use of these private
+IOCTLs it is not possible to obtain optimal image quality this way. The AEWB,
+AF and histogram modules cannot be used without configuring them using the
+appropriate private IOCTLs.
+
+
+CCDC and preview block IOCTLs
+=============================
+
+The VIDIOC_OMAP3ISP_CCDC_CFG and VIDIOC_OMAP3ISP_PRV_CFG IOCTLs are used to
+configure, enable and disable functions in the CCDC and preview blocks,
+respectively. Both IOCTLs control several functions in the blocks they
+control. VIDIOC_OMAP3ISP_CCDC_CFG IOCTL accepts a pointer to struct
+omap3isp_ccdc_update_config as its argument. Similarly VIDIOC_OMAP3ISP_PRV_CFG
+accepts a pointer to struct omap3isp_prev_update_config. The definition of
+both structures is available in [1].
+
+The update field in the structures tells whether to update the configuration
+for the specific function and the flag tells whether to enable or disable the
+function.
+
+The update and flag bit masks accept the following values. Each separate
+functions in the CCDC and preview blocks is associated with a flag (either
+disable or enable; part of the flag field in the structure) and a pointer to
+configuration data for the function.
+
+Valid values for the update and flag fields are listed here for
+VIDIOC_OMAP3ISP_CCDC_CFG. Values may be or'ed to configure more than one
+function in the same IOCTL call.
+
+        OMAP3ISP_CCDC_ALAW
+        OMAP3ISP_CCDC_LPF
+        OMAP3ISP_CCDC_BLCLAMP
+        OMAP3ISP_CCDC_BCOMP
+        OMAP3ISP_CCDC_FPC
+        OMAP3ISP_CCDC_CULL
+        OMAP3ISP_CCDC_CONFIG_LSC
+        OMAP3ISP_CCDC_TBL_LSC
+
+The corresponding values for the VIDIOC_OMAP3ISP_PRV_CFG are here:
+
+        OMAP3ISP_PREV_LUMAENH
+        OMAP3ISP_PREV_INVALAW
+        OMAP3ISP_PREV_HRZ_MED
+        OMAP3ISP_PREV_CFA
+        OMAP3ISP_PREV_CHROMA_SUPP
+        OMAP3ISP_PREV_WB
+        OMAP3ISP_PREV_BLKADJ
+        OMAP3ISP_PREV_RGB2RGB
+        OMAP3ISP_PREV_COLOR_CONV
+        OMAP3ISP_PREV_YC_LIMIT
+        OMAP3ISP_PREV_DEFECT_COR
+        OMAP3ISP_PREV_GAMMABYPASS
+        OMAP3ISP_PREV_DRK_FRM_CAPTURE
+        OMAP3ISP_PREV_DRK_FRM_SUBTRACT
+        OMAP3ISP_PREV_LENS_SHADING
+        OMAP3ISP_PREV_NF
+        OMAP3ISP_PREV_GAMMA
+
+The associated configuration pointer for the function may not be NULL when
+enabling the function. When disabling a function the configuration pointer is
+ignored.
+
+
+Statistic blocks IOCTLs
+=======================
+
+The statistics subdevs do offer more dynamic configuration options than the
+other subdevs. They can be enabled, disable and reconfigured when the pipeline
+is in streaming state.
+
+The statistics blocks always get the input image data from the CCDC (as the
+histogram memory read isn't implemented). The statistics are dequeueable by
+the user from the statistics subdev nodes using private IOCTLs.
+
+The private IOCTLs offered by the AEWB, AF and histogram subdevs are heavily
+reflected by the register level interface offered by the ISP hardware. There
+are aspects that are purely related to the driver implementation and these are
+discussed next.
+
+VIDIOC_OMAP3ISP_STAT_EN
+-----------------------
+
+This private IOCTL enables/disables a statistic module. If this request is
+done before streaming, it will take effect as soon as the pipeline starts to
+stream.  If the pipeline is already streaming, it will take effect as soon as
+the CCDC becomes idle.
+
+VIDIOC_OMAP3ISP_AEWB_CFG, VIDIOC_OMAP3ISP_HIST_CFG and VIDIOC_OMAP3ISP_AF_CFG
+-----------------------------------------------------------------------------
+
+Those IOCTLs are used to configure the modules. They require user applications
+to have an in-depth knowledge of the hardware. Most of the fields explanation
+can be found on OMAP's TRMs. The two following fields common to all the above
+configure private IOCTLs require explanation for better understanding as they
+are not part of the TRM.
+
+omap3isp_[h3a_af/h3a_aewb/hist]_config.buf_size:
+
+The modules handle their buffers internally. The necessary buffer size for the
+module's data output depends on the requested configuration. Although the
+driver supports reconfiguration while streaming, it does not support a
+reconfiguration which requires bigger buffer size than what is already
+internally allocated if the module is enabled. It will return -EBUSY on this
+case. In order to avoid such condition, either disable/reconfigure/enable the
+module or request the necessary buffer size during the first configuration
+while the module is disabled.
+
+The internal buffer size allocation considers the requested configuration's
+minimum buffer size and the value set on buf_size field. If buf_size field is
+out of [minimum, maximum] buffer size range, it's clamped to fit in there.
+The driver then selects the biggest value. The corrected buf_size value is
+written back to user application.
+
+omap3isp_[h3a_af/h3a_aewb/hist]_config.config_counter:
+
+As the configuration doesn't take effect synchronously to the request, the
+driver must provide a way to track this information to provide more accurate
+data. After a configuration is requested, the config_counter returned to user
+space application will be an unique value associated to that request. When
+user application receives an event for buffer availability or when a new
+buffer is requested, this config_counter is used to match a buffer data and a
+configuration.
+
+VIDIOC_OMAP3ISP_STAT_REQ
+------------------------
+
+Send to user space the oldest data available in the internal buffer queue and
+discards such buffer afterwards. The field omap3isp_stat_data.frame_number
+matches with the video buffer's field_count.
+
+
+Technical reference manuals (TRMs) and other documentation
+==========================================================
+
+OMAP 3430 TRM:
+<URL:http://focus.ti.com/pdfs/wtbu/OMAP34xx_ES3.1.x_PUBLIC_TRM_vZM.zip>
+Referenced 2011-03-05.
+
+OMAP 35xx TRM:
+<URL:http://www.ti.com/litv/pdf/spruf98o> Referenced 2011-03-05.
+
+OMAP 3630 TRM:
+<URL:http://focus.ti.com/pdfs/wtbu/OMAP36xx_ES1.x_PUBLIC_TRM_vQ.zip>
+Referenced 2011-03-05.
+
+DM 3730 TRM:
+<URL:http://www.ti.com/litv/pdf/sprugn4h> Referenced 2011-03-06.
+
+
+References
+==========
+
+[1] include/linux/omap3isp.h
+
+[2] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
index f22f35c271f38d34fda0c19d8942b536e2fc95d9..3b15608ee0700029a2b816bb5a971059af603386 100644 (file)
@@ -71,6 +71,10 @@ sub-device instances, the video_device struct stores V4L2 device node data
 and in the future a v4l2_fh struct will keep track of filehandle instances
 (this is not yet implemented).
 
+The V4L2 framework also optionally integrates with the media framework. If a
+driver sets the struct v4l2_device mdev field, sub-devices and video nodes
+will automatically appear in the media framework as entities.
+
 
 struct v4l2_device
 ------------------
@@ -83,11 +87,20 @@ You must register the device instance:
 
        v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
 
-Registration will initialize the v4l2_device struct and link dev->driver_data
-to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
-from dev (driver name followed by the bus_id, to be precise). If you set it
-up before calling v4l2_device_register then it will be untouched. If dev is
-NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
+Registration will initialize the v4l2_device struct. If the dev->driver_data
+field is NULL, it will be linked to v4l2_dev.
+
+Drivers that want integration with the media device framework need to set
+dev->driver_data manually to point to the driver-specific device structure
+that embed the struct v4l2_device instance. This is achieved by a
+dev_set_drvdata() call before registering the V4L2 device instance. They must
+also set the struct v4l2_device mdev field to point to a properly initialized
+and registered media_device instance.
+
+If v4l2_dev->name is empty then it will be set to a value derived from dev
+(driver name followed by the bus_id, to be precise). If you set it up before
+calling v4l2_device_register then it will be untouched. If dev is NULL, then
+you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
 You can use v4l2_device_set_name() to set the name based on a driver name and
 a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
@@ -108,6 +121,7 @@ You unregister with:
 
        v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 
+If the dev->driver_data field points to v4l2_dev, it will be reset to NULL.
 Unregistering will also automatically unregister all subdevs from the device.
 
 If you have a hotpluggable device (e.g. a USB device), then when a disconnect
@@ -167,6 +181,21 @@ static int __devinit drv_probe(struct pci_dev *pdev,
        state->instance = atomic_inc_return(&drv_instance) - 1;
 }
 
+If you have multiple device nodes then it can be difficult to know when it is
+safe to unregister v4l2_device. For this purpose v4l2_device has refcounting
+support. The refcount is increased whenever video_register_device is called and
+it is decreased whenever that device node is released. When the refcount reaches
+zero, then the v4l2_device release() callback is called. You can do your final
+cleanup there.
+
+If other device nodes (e.g. ALSA) are created, then you can increase and
+decrease the refcount manually as well by calling:
+
+void v4l2_device_get(struct v4l2_device *v4l2_dev);
+
+or:
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev);
 
 struct v4l2_subdev
 ------------------
@@ -254,6 +283,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
 Afterwards you need to initialize subdev->name with a unique name and set the
 module owner. This is done for you if you use the i2c helper functions.
 
+If integration with the media framework is needed, you must initialize the
+media_entity struct embedded in the v4l2_subdev struct (entity field) by
+calling media_entity_init():
+
+       struct media_pad *pads = &my_sd->pads;
+       int err;
+
+       err = media_entity_init(&sd->entity, npads, pads, 0);
+
+The pads array must have been previously initialized. There is no need to
+manually set the struct media_entity type and name fields, but the revision
+field must be initialized if needed.
+
+A reference to the entity will be automatically acquired/released when the
+subdev device node (if any) is opened/closed.
+
+Don't forget to cleanup the media entity before the sub-device is destroyed:
+
+       media_entity_cleanup(&sd->entity);
+
 A device (bridge) driver needs to register the v4l2_subdev with the
 v4l2_device:
 
@@ -263,6 +312,9 @@ This can fail if the subdev module disappeared before it could be registered.
 After this function was called successfully the subdev->dev field points to
 the v4l2_device.
 
+If the v4l2_device parent device has a non-NULL mdev field, the sub-device
+entity will be automatically registered with the media device.
+
 You can unregister a sub-device using:
 
        v4l2_device_unregister_subdev(sd);
@@ -319,6 +371,61 @@ controlled through GPIO pins. This distinction is only relevant when setting
 up the device, but once the subdev is registered it is completely transparent.
 
 
+V4L2 sub-device userspace API
+-----------------------------
+
+Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
+sub-devices can also be controlled directly by userspace applications.
+
+Device nodes named v4l-subdevX can be created in /dev to access sub-devices
+directly. If a sub-device supports direct userspace configuration it must set
+the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.
+
+After registering sub-devices, the v4l2_device driver can create device nodes
+for all registered sub-devices marked with V4L2_SUBDEV_FL_HAS_DEVNODE by calling
+v4l2_device_register_subdev_nodes(). Those device nodes will be automatically
+removed when sub-devices are unregistered.
+
+The device node handles a subset of the V4L2 API.
+
+VIDIOC_QUERYCTRL
+VIDIOC_QUERYMENU
+VIDIOC_G_CTRL
+VIDIOC_S_CTRL
+VIDIOC_G_EXT_CTRLS
+VIDIOC_S_EXT_CTRLS
+VIDIOC_TRY_EXT_CTRLS
+
+       The controls ioctls are identical to the ones defined in V4L2. They
+       behave identically, with the only exception that they deal only with
+       controls implemented in the sub-device. Depending on the driver, those
+       controls can be also be accessed through one (or several) V4L2 device
+       nodes.
+
+VIDIOC_DQEVENT
+VIDIOC_SUBSCRIBE_EVENT
+VIDIOC_UNSUBSCRIBE_EVENT
+
+       The events ioctls are identical to the ones defined in V4L2. They
+       behave identically, with the only exception that they deal only with
+       events generated by the sub-device. Depending on the driver, those
+       events can also be reported by one (or several) V4L2 device nodes.
+
+       Sub-device drivers that want to use events need to set the
+       V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize
+       v4l2_subdev::nevents to events queue depth before registering the
+       sub-device. After registration events can be queued as usual on the
+       v4l2_subdev::devnode device node.
+
+       To properly support events, the poll() file operation is also
+       implemented.
+
+Private ioctls
+
+       All ioctls not in the above list are passed directly to the sub-device
+       driver through the core::ioctl operation.
+
+
 I2C sub-device drivers
 ----------------------
 
@@ -457,6 +564,10 @@ You should also set these fields:
   Otherwise you give it a pointer to a struct mutex_lock and before any
   of the v4l2_file_operations is called this lock will be taken by the
   core and released afterwards.
+- prio: keeps track of the priorities. Used to implement VIDIOC_G/S_PRIORITY.
+  If left to NULL, then it will use the struct v4l2_prio_state in v4l2_device.
+  If you want to have a separate priority state per (group of) device node(s),
+  then you can point it to your own struct v4l2_prio_state.
 - parent: you only set this if v4l2_device was registered with NULL as
   the parent device struct. This only happens in cases where one hardware
   device has multiple PCI devices that all share the same v4l2_device core.
@@ -466,13 +577,34 @@ You should also set these fields:
   (cx8802). Since the v4l2_device cannot be associated with a particular
   PCI device it is setup without a parent device. But when the struct
   video_device is setup you do know which parent PCI device to use.
+- flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
+  handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
+  v4l2_fh. Eventually this flag will disappear once all drivers use the core
+  priority handling. But for now it has to be set explicitly.
 
-If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
-.ioctl to video_ioctl2 in your v4l2_file_operations struct.
+If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to video_ioctl2
+in your v4l2_file_operations struct.
+
+Do not use .ioctl! This is deprecated and will go away in the future.
 
 The v4l2_file_operations struct is a subset of file_operations. The main
 difference is that the inode argument is omitted since it is never used.
 
+If integration with the media framework is needed, you must initialize the
+media_entity struct embedded in the video_device struct (entity field) by
+calling media_entity_init():
+
+       struct media_pad *pad = &my_vdev->pad;
+       int err;
+
+       err = media_entity_init(&vdev->entity, 1, pad, 0);
+
+The pads array must have been previously initialized. There is no need to
+manually set the struct media_entity type and name fields.
+
+A reference to the entity will be automatically acquired/released when the
+video device is opened/closed.
+
 v4l2_file_operations and locking
 --------------------------------
 
@@ -502,6 +634,9 @@ for you.
                return err;
        }
 
+If the v4l2_device parent device has a non-NULL mdev field, the video device
+entity will be automatically registered with the media device.
+
 Which device is registered depends on the type argument. The following
 types exist:
 
@@ -577,6 +712,13 @@ release, of course) will return an error as well.
 When the last user of the video device node exits, then the vdev->release()
 callback is called and you can do the final cleanup there.
 
+Don't forget to cleanup the media entity associated with the video device if
+it has been initialized:
+
+       media_entity_cleanup(&vdev->entity);
+
+This can be done from the release callback.
+
 
 video_device helper functions
 -----------------------------
@@ -636,39 +778,25 @@ struct v4l2_fh
 --------------
 
 struct v4l2_fh provides a way to easily keep file handle specific data
-that is used by the V4L2 framework. Using v4l2_fh is optional for
-drivers.
+that is used by the V4L2 framework. New drivers must use struct v4l2_fh
+since it is also used to implement priority handling (VIDIOC_G/S_PRIORITY)
+if the video_device flag V4L2_FL_USE_FH_PRIO is also set.
 
 The users of v4l2_fh (in the V4L2 framework, not the driver) know
 whether a driver uses v4l2_fh as its file->private_data pointer by
-testing the V4L2_FL_USES_V4L2_FH bit in video_device->flags.
-
-Useful functions:
-
-- v4l2_fh_init()
-
-  Initialise the file handle. This *MUST* be performed in the driver's
-  v4l2_file_operations->open() handler.
-
-- v4l2_fh_add()
+testing the V4L2_FL_USES_V4L2_FH bit in video_device->flags. This bit is
+set whenever v4l2_fh_init() is called.
 
-  Add a v4l2_fh to video_device file handle list. May be called after
-  initialising the file handle.
-
-- v4l2_fh_del()
-
-  Unassociate the file handle from video_device(). The file handle
-  exit function may now be called.
+struct v4l2_fh is allocated as a part of the driver's own file handle
+structure and file->private_data is set to it in the driver's open
+function by the driver.
 
-- v4l2_fh_exit()
+In many cases the struct v4l2_fh will be embedded in a larger structure.
+In that case you should call v4l2_fh_init+v4l2_fh_add in open() and
+v4l2_fh_del+v4l2_fh_exit in release().
 
-  Uninitialise the file handle. After uninitialisation the v4l2_fh
-  memory can be freed.
-
-struct v4l2_fh is allocated as a part of the driver's own file handle
-structure and is set to file->private_data in the driver's open
-function by the driver. Drivers can extract their own file handle
-structure by using the container_of macro. Example:
+Drivers can extract their own file handle structure by using the container_of
+macro. Example:
 
 struct my_fh {
        int blah;
@@ -685,15 +813,21 @@ int my_open(struct file *file)
 
        ...
 
+       my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL);
+
+       ...
+
        ret = v4l2_fh_init(&my_fh->fh, vfd);
-       if (ret)
+       if (ret) {
+               kfree(my_fh);
                return ret;
+       }
 
-       v4l2_fh_add(&my_fh->fh);
+       ...
 
        file->private_data = &my_fh->fh;
-
-       ...
+       v4l2_fh_add(&my_fh->fh);
+       return 0;
 }
 
 int my_release(struct file *file)
@@ -702,8 +836,65 @@ int my_release(struct file *file)
        struct my_fh *my_fh = container_of(fh, struct my_fh, fh);
 
        ...
+       v4l2_fh_del(&my_fh->fh);
+       v4l2_fh_exit(&my_fh->fh);
+       kfree(my_fh);
+       return 0;
 }
 
+Below is a short description of the v4l2_fh functions used:
+
+int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+
+  Initialise the file handle. This *MUST* be performed in the driver's
+  v4l2_file_operations->open() handler.
+
+void v4l2_fh_add(struct v4l2_fh *fh)
+
+  Add a v4l2_fh to video_device file handle list. Must be called once the
+  file handle is completely initialized.
+
+void v4l2_fh_del(struct v4l2_fh *fh)
+
+  Unassociate the file handle from video_device(). The file handle
+  exit function may now be called.
+
+void v4l2_fh_exit(struct v4l2_fh *fh)
+
+  Uninitialise the file handle. After uninitialisation the v4l2_fh
+  memory can be freed.
+
+
+If struct v4l2_fh is not embedded, then you can use these helper functions:
+
+int v4l2_fh_open(struct file *filp)
+
+  This allocates a struct v4l2_fh, initializes it and adds it to the struct
+  video_device associated with the file struct.
+
+int v4l2_fh_release(struct file *filp)
+
+  This deletes it from the struct video_device associated with the file
+  struct, uninitialised the v4l2_fh and frees it.
+
+These two functions can be plugged into the v4l2_file_operation's open() and
+release() ops.
+
+
+Several drivers need to do something when the first file handle is opened and
+when the last file handle closes. Two helper functions were added to check
+whether the v4l2_fh struct is the only open filehandle of the associated
+device node:
+
+int v4l2_fh_is_singular(struct v4l2_fh *fh)
+
+  Returns 1 if the file handle is the only open file handle, else 0.
+
+int v4l2_fh_is_singular_file(struct file *filp)
+
+  Same, but it calls v4l2_fh_is_singular with filp->private_data.
+
+
 V4L2 events
 -----------
 
index cc96ee2666f2e5f10f13b83b1fab72bcf8e18924..7445caa26d05f59d9440d9556314be77ae090053 100644 (file)
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/statfs.h>
+#include "../../include/linux/magic.h"
 
 
+#ifndef MAX_PATH
+# define MAX_PATH 256
+#endif
+
+#ifndef STR
+# define _STR(x) #x
+# define STR(x) _STR(x)
+#endif
+
 /*
  * pagemap kernel ABI bits
  */
@@ -152,6 +164,12 @@ static const char *page_flag_names[] = {
 };
 
 
+static const char *debugfs_known_mountpoints[] = {
+       "/sys/kernel/debug",
+       "/debug",
+       0,
+};
+
 /*
  * data structures
  */
@@ -184,7 +202,7 @@ static int          kpageflags_fd;
 static int             opt_hwpoison;
 static int             opt_unpoison;
 
-static const char      hwpoison_debug_fs[] = "/debug/hwpoison";
+static char            hwpoison_debug_fs[MAX_PATH+1];
 static int             hwpoison_inject_fd;
 static int             hwpoison_forget_fd;
 
@@ -464,21 +482,100 @@ static uint64_t kpageflags_flags(uint64_t flags)
        return flags;
 }
 
+/* verify that a mountpoint is actually a debugfs instance */
+static int debugfs_valid_mountpoint(const char *debugfs)
+{
+       struct statfs st_fs;
+
+       if (statfs(debugfs, &st_fs) < 0)
+               return -ENOENT;
+       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+               return -ENOENT;
+
+       return 0;
+}
+
+/* find the path to the mounted debugfs */
+static const char *debugfs_find_mountpoint(void)
+{
+       const char **ptr;
+       char type[100];
+       FILE *fp;
+
+       ptr = debugfs_known_mountpoints;
+       while (*ptr) {
+               if (debugfs_valid_mountpoint(*ptr) == 0) {
+                       strcpy(hwpoison_debug_fs, *ptr);
+                       return hwpoison_debug_fs;
+               }
+               ptr++;
+       }
+
+       /* give up and parse /proc/mounts */
+       fp = fopen("/proc/mounts", "r");
+       if (fp == NULL)
+               perror("Can't open /proc/mounts for read");
+
+       while (fscanf(fp, "%*s %"
+                     STR(MAX_PATH)
+                     "s %99s %*s %*d %*d\n",
+                     hwpoison_debug_fs, type) == 2) {
+               if (strcmp(type, "debugfs") == 0)
+                       break;
+       }
+       fclose(fp);
+
+       if (strcmp(type, "debugfs") != 0)
+               return NULL;
+
+       return hwpoison_debug_fs;
+}
+
+/* mount the debugfs somewhere if it's not mounted */
+
+static void debugfs_mount(void)
+{
+       const char **ptr;
+
+       /* see if it's already mounted */
+       if (debugfs_find_mountpoint())
+               return;
+
+       ptr = debugfs_known_mountpoints;
+       while (*ptr) {
+               if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
+                       /* save the mountpoint */
+                       strcpy(hwpoison_debug_fs, *ptr);
+                       break;
+               }
+               ptr++;
+       }
+
+       if (*ptr == NULL) {
+               perror("mount debugfs");
+               exit(EXIT_FAILURE);
+       }
+}
+
 /*
  * page actions
  */
 
 static void prepare_hwpoison_fd(void)
 {
-       char buf[100];
+       char buf[MAX_PATH + 1];
+
+       debugfs_mount();
 
        if (opt_hwpoison && !hwpoison_inject_fd) {
-               sprintf(buf, "%s/corrupt-pfn", hwpoison_debug_fs);
+               snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
+                       hwpoison_debug_fs);
                hwpoison_inject_fd = checked_open(buf, O_WRONLY);
        }
 
        if (opt_unpoison && !hwpoison_forget_fd) {
-               sprintf(buf, "%s/unpoison-pfn", hwpoison_debug_fs);
+               snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
+                       hwpoison_debug_fs);
                hwpoison_forget_fd = checked_open(buf, O_WRONLY);
        }
 }
index 48c13b8ab90c498dcef836aa293c80e5ec153b4b..092e596a1301f184bce14acd04a15f8e97904c48 100644 (file)
@@ -293,11 +293,6 @@ IOMMU (input/output memory management unit)
 
 Debugging
 
-  oops=panic   Always panic on oopses. Default is to just kill the process,
-               but there is a small probability of deadlocking the machine.
-               This will also cause panics on machine check exceptions.
-               Useful together with panic=30 to trigger a reboot.
-
   kstack=N     Print N words from the kernel stack in oops dumps.
 
   pagefaulttrace  Dump all page faults. Only useful for extreme debugging
index c7a41b1fe453b267e02e5eef5ba649634dbc8060..4fb9017b441330a997f5a0d9499a3f1d245f3524 100644 (file)
@@ -72,7 +72,7 @@ Descriptions of section entries:
        L: Mailing list that is relevant to this area
        W: Web-page with status/info
        Q: Patchwork web based patch tracking system site
-       T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
+       T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit, topgit.
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -198,7 +198,7 @@ F:  Documentation/scsi/aacraid.txt
 F:     drivers/scsi/aacraid/
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
-M:     Hans de Goede <j.w.r.degoede@hhs.nl>
+M:     Hans de Goede <hdegoede@redhat.com>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     drivers/hwmon/abituguru.c
@@ -288,35 +288,35 @@ F:        sound/pci/ad1889.*
 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/AD5254
+W:     http://wiki.analog.com/AD5254
 S:     Supported
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/AD5398
+W:     http://wiki.analog.com/AD5398
 S:     Supported
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/AD7142
+W:     http://wiki.analog.com/AD7142
 S:     Supported
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/AD7877
+W:     http://wiki.analog.com/AD7877
 S:     Supported
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/AD7879
+W:     http://wiki.analog.com/AD7879
 S:     Supported
 F:     drivers/input/touchscreen/ad7879.c
 
@@ -342,18 +342,18 @@ F:        drivers/net/wireless/adm8211.*
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/ADP5520
+W:     http://wiki.analog.com/ADP5520
 S:     Supported
 F:     drivers/mfd/adp5520.c
 F:     drivers/video/backlight/adp5520_bl.c
-F:     drivers/led/leds-adp5520.c
+F:     drivers/leds/leds-adp5520.c
 F:     drivers/gpio/adp5520-gpio.c
 F:     drivers/input/keyboard/adp5520-keys.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/ADP5588
+W:     http://wiki.analog.com/ADP5588
 S:     Supported
 F:     drivers/input/keyboard/adp5588-keys.c
 F:     drivers/gpio/adp5588-gpio.c
@@ -361,10 +361,18 @@ F:        drivers/gpio/adp5588-gpio.c
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/ADP8860
+W:     http://wiki.analog.com/ADP8860
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
 
+ADS1015 HARDWARE MONITOR DRIVER
+M:     Dirk Eibach <eibach@gdsys.de>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/ads1015
+F:     drivers/hwmon/ads1015.c
+F:     include/linux/i2c/ads1015.h
+
 ADT746X FAN DRIVER
 M:     Colin Leroy <colin@colino.net>
 S:     Maintained
@@ -380,7 +388,7 @@ F:  drivers/hwmon/adt7475.c
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <michael.hennerich@analog.com>
 L:     device-driver-devel@blackfin.uclinux.org
-W:     http://wiki-analog.com/ADXL345
+W:     http://wiki.analog.com/ADXL345
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
 
@@ -520,11 +528,9 @@ F: drivers/infiniband/hw/amso1100/
 ANALOG DEVICES INC ASOC CODEC DRIVERS
 L:     device-driver-devel@blackfin.uclinux.org
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-W:     http://wiki-analog.com/
+W:     http://wiki.analog.com/
 S:     Supported
 F:     sound/soc/codecs/ad1*
-F:     sound/soc/codecs/adau*
-F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/ssm*
 
 ANALOG DEVICES INC ASOC DRIVERS
@@ -689,8 +695,8 @@ S:  Maintained
 ARM/CLKDEV SUPPORT
 M:     Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-F:     arch/arm/common/clkdev.c
 F:     arch/arm/include/asm/clkdev.h
+F:     drivers/clk/clkdev.c
 
 ARM/COMPULAB CM-X270/EM-X270 and CM-X300 MACHINE SUPPORT
 M:     Mike Rapoport <mike@compulab.co.il>
@@ -911,6 +917,7 @@ F:  drivers/mmc/host/msm_sdcc.c
 F:     drivers/mmc/host/msm_sdcc.h
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
+F:     drivers/platform/msm/
 T:     git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
 S:     Maintained
 
@@ -1070,7 +1077,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/TETON BGA MACHINE SUPPORT
-M:     Mark F. Brown <mark.brown314@gmail.com>
+M:     "Mark F. Brown" <mark.brown314@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -1474,7 +1481,7 @@ F:        drivers/mtd/devices/block2mtd.c
 
 BLUETOOTH DRIVERS
 M:     Marcel Holtmann <marcel@holtmann.org>
-M:     Gustavo F. Padovan <padovan@profusion.mobi>
+M:     "Gustavo F. Padovan" <padovan@profusion.mobi>
 L:     linux-bluetooth@vger.kernel.org
 W:     http://www.bluez.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
@@ -1483,7 +1490,7 @@ F:        drivers/bluetooth/
 
 BLUETOOTH SUBSYSTEM
 M:     Marcel Holtmann <marcel@holtmann.org>
-M:     Gustavo F. Padovan <padovan@profusion.mobi>
+M:     "Gustavo F. Padovan" <padovan@profusion.mobi>
 L:     linux-bluetooth@vger.kernel.org
 W:     http://www.bluez.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
@@ -2130,6 +2137,12 @@ F:       Documentation/serial/digiepca.txt
 F:     drivers/char/epca*
 F:     drivers/char/digi*
 
+DIOLAN U2C-12 I2C DRIVER
+M:     Guenter Roeck <guenter.roeck@ericsson.com>
+L:     linux-i2c@vger.kernel.org
+S:     Maintained
+F:     drivers/i2c/busses/i2c-diolan-u2c.c
+
 DIRECTORY NOTIFICATION (DNOTIFY)
 M:     Eric Paris <eparis@parisplace.org>
 S:     Maintained
@@ -2467,8 +2480,7 @@ F:        include/linux/cb710.h
 ENE KB2426 (ENE0100/ENE020XX) INFRARED RECEIVER
 M:     Maxim Levitsky <maximlevitsky@gmail.com>
 S:     Maintained
-F:     drivers/media/IR/ene_ir.c
-F:     drivers/media/IR/ene_ir.h
+F:     drivers/media/rc/ene_ir.*
 
 EPSON 1355 FRAMEBUFFER DRIVER
 M:     Christopher Hoover <ch@murgatroid.com>
@@ -2619,12 +2631,14 @@ F:      drivers/net/wan/dlci.c
 F:     drivers/net/wan/sdla.c
 
 FRAMEBUFFER LAYER
+M:     Paul Mundt <lethal@linux-sh.org>
 L:     linux-fbdev@vger.kernel.org
 W:     http://linux-fbdev.sourceforge.net/
 Q:     http://patchwork.kernel.org/project/linux-fbdev/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git
-S:     Orphan
+S:     Maintained
 F:     Documentation/fb/
+F:     Documentation/devicetree/bindings/fb/
 F:     drivers/video/
 F:     include/video/
 F:     include/linux/fb.h
@@ -2812,7 +2826,6 @@ F:        include/linux/gigaset_dev.h
 
 GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 F:     Documentation/gpio/gpio.txt
@@ -2835,7 +2848,6 @@ F:        drivers/platform/x86/hdaps.c
 HWPOISON MEMORY FAILURE HANDLING
 M:     Andi Kleen <andi@firstfloor.org>
 L:     linux-mm@kvack.org
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison
 S:     Maintained
 F:     mm/memory-failure.c
@@ -2936,7 +2948,7 @@ F:        Documentation/blockdev/cpqarray.txt
 F:     drivers/block/cpqarray.*
 
 HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
-M:     Stephen M. Cameron <scameron@beardog.cce.hp.com>
+M:     "Stephen M. Cameron" <scameron@beardog.cce.hp.com>
 L:     iss_storagedev@hp.com
 S:     Supported
 F:     Documentation/scsi/hpsa.txt
@@ -2993,7 +3005,7 @@ F:        kernel/hrtimer.c
 F:     kernel/time/clockevents.c
 F:     kernel/time/tick*.*
 F:     kernel/time/timer_*.c
-F      include/linux/clockevents.h
+F:     include/linux/clockevents.h
 F:     include/linux/hrtimer.h
 
 HIGH-SPEED SCC DRIVER FOR AX.25
@@ -3166,15 +3178,6 @@ L:       linux-pm@lists.linux-foundation.org
 S:     Supported
 F:     drivers/idle/i7300_idle.c
 
-IEEE 1394 SUBSYSTEM
-M:     Stefan Richter <stefanr@s5r6.in-berlin.de>
-L:     linux1394-devel@lists.sourceforge.net
-W:     http://ieee1394.wiki.kernel.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
-S:     Obsolete
-F:     Documentation/debugging-via-ohci1394.txt
-F:     drivers/ieee1394/
-
 IEEE 802.15.4 SUBSYSTEM
 M:     Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 M:     Sergey Lapin <slapin@ossfans.org>
@@ -3913,8 +3916,8 @@ S:        Supported
 LIS3LV02D ACCELEROMETER DRIVER
 M:     Eric Piel <eric.piel@tremplin-utc.net>
 S:     Maintained
-F:     Documentation/hwmon/lis3lv02d
-F:     drivers/hwmon/lis3lv02d.*
+F:     Documentation/misc-devices/lis3lv02d
+F:     drivers/misc/lis3lv02d/
 
 LLC (802.2)
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
@@ -4218,7 +4221,7 @@ F:        Documentation/serial/moxa-smartio
 F:     drivers/char/mxser.*
 
 MSI LAPTOP SUPPORT
-M:     Lee, Chun-Yi <jlee@novell.com>
+M:     "Lee, Chun-Yi" <jlee@novell.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/msi-laptop.c
@@ -4534,14 +4537,14 @@ S:      Maintained
 F:     sound/soc/omap/
 
 OMAP FRAMEBUFFER SUPPORT
-M:     Tomi Valkeinen <tomi.valkeinen@nokia.com>
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     linux-fbdev@vger.kernel.org
 L:     linux-omap@vger.kernel.org
 S:     Maintained
 F:     drivers/video/omap/
 
 OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
-M:     Tomi Valkeinen <tomi.valkeinen@nokia.com>
+M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     linux-omap@vger.kernel.org
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
@@ -4579,6 +4582,12 @@ L:       linux-omap@vger.kernel.org
 S:     Maintained
 F:     arch/arm/mach-omap2/omap_hwmod_44xx_data.c
 
+OMAP IMAGE SIGNAL PROCESSOR (ISP)
+M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/video/omap3isp/*
+
 OMAP USB SUPPORT
 M:     Felipe Balbi <balbi@ti.com>
 M:     David Brownell <dbrownell@users.sourceforge.net>
@@ -4713,7 +4722,6 @@ F:        drivers/i2c/busses/i2c-pasemi.c
 
 PADATA PARALLEL EXECUTION MECHANISM
 M:     Steffen Klassert <steffen.klassert@secunet.com>
-L:     linux-kernel@vger.kernel.org
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
 F:     kernel/padata.c
@@ -4863,7 +4871,6 @@ F:        include/crypto/pcrypt.h
 PER-CPU MEMORY ALLOCATOR
 M:     Tejun Heo <tj@kernel.org>
 M:     Christoph Lameter <cl@linux-foundation.org>
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git
 S:     Maintained
 F:     include/linux/percpu*.h
@@ -5284,6 +5291,11 @@ S:       Maintained
 F:     drivers/mtd/nand/r852.c
 F:     drivers/mtd/nand/r852.h
 
+RICOH R5C592 MEMORYSTICK DRIVER
+M:     Maxim Levitsky <maximlevitsky@gmail.com>
+S:     Maintained
+F:     drivers/memstick/host/r592.*
+
 RISCOM8 DRIVER
 S:     Orphan
 F:     Documentation/serial/riscom8.txt
@@ -5422,7 +5434,6 @@ S:        Supported
 F:     include/linux/clocksource.h
 F:     include/linux/time.h
 F:     include/linux/timex.h
-F:     include/linux/timekeeping.h
 F:     kernel/time/clocksource.c
 F:     kernel/time/time*.c
 F:     kernel/time/ntp.c
@@ -5510,7 +5521,7 @@ SCx200 CPU SUPPORT
 M:     Jim Cromie <jim.cromie@gmail.com>
 S:     Odd Fixes
 F:     Documentation/i2c/busses/scx200_acb
-F:     arch/x86/kernel/scx200_32.c
+F:     arch/x86/platform/scx200/
 F:     drivers/watchdog/scx200_wdt.c
 F:     drivers/i2c/busses/scx200*
 F:     drivers/mtd/maps/scx200_docflash.c
@@ -5654,24 +5665,13 @@ M:      Robin Holt <holt@sgi.com>
 S:     Maintained
 F:     drivers/misc/sgi-xp/
 
-SHARP LH SUPPORT (LH7952X & LH7A40X)
-M:     Marc Singer <elf@buici.com>
-W:     http://projects.buici.com/arm
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     Documentation/arm/Sharp-LH/ADC-LH7-Touchscreen
-F:     arch/arm/mach-lh7a40x/
-F:     drivers/tty/serial/serial_lh7a40x.c
-F:     drivers/usb/gadget/lh7a40*
-F:     drivers/usb/host/ohci-lh7a40*
-
 SIMPLE FIRMWARE INTERFACE (SFI)
 M:     Len Brown <lenb@kernel.org>
 L:     sfi-devel@simplefirmware.org
 W:     http://simplefirmware.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-sfi-2.6.git
 S:     Supported
-F:     arch/x86/kernel/*sfi*
+F:     arch/x86/platform/sfi/
 F:     drivers/sfi/
 F:     include/linux/sfi*.h
 
@@ -5769,6 +5769,13 @@ S:       Supported
 F:     Documentation/hwmon/emc2103
 F:     drivers/hwmon/emc2103.c
 
+SMSC SCH5627 HARDWARE MONITOR DRIVER
+M:     Hans de Goede <hdegoede@redhat.com>
+L:     lm-sensors@lm-sensors.org
+S:     Supported
+F:     Documentation/hwmon/sch5627
+F:     drivers/hwmon/sch5627.c
+
 SMSC47B397 HARDWARE MONITOR DRIVER
 M:     "Mark M. Hoffman" <mhoffman@lightlink.com>
 L:     lm-sensors@lm-sensors.org
@@ -6472,12 +6479,11 @@ S:      Maintained
 F:     drivers/net/usb/rtl8150.c
 
 USB SE401 DRIVER
-M:     Jeroen Vreeken <pe1rxq@amsat.org>
 L:     linux-usb@vger.kernel.org
 W:     http://www.chello.nl/~j.vreeken/se401/
-S:     Maintained
+S:     Orphan
 F:     Documentation/video4linux/se401.txt
-F:     drivers/media/video/se401.*
+F:     drivers/staging/se401/
 
 USB SERIAL BELKIN F5U103 DRIVER
 M:     William Greathouse <wgreathouse@smva.com>
@@ -6827,7 +6833,7 @@ F:        drivers/scsi/wd7000.c
 WINBOND CIR DRIVER
 M:     David HƤrdeman <david@hardeman.nu>
 S:     Maintained
-F:     drivers/input/misc/winbond-cir.c
+F:     drivers/media/rc/winbond-cir.c
 
 WIMAX STACK
 M:     Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
@@ -6904,7 +6910,6 @@ F:        sound/soc/codecs/wm*
 
 WORKQUEUE
 M:     Tejun Heo <tj@kernel.org>
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git
 S:     Maintained
 F:     include/linux/workqueue.h
index 92b8bed3059e5c9fc4e9938a905e00c66ee12f75..7d4e9c8da7295e628d8a7849b72e1d8651d8772c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,10 @@ ifeq ("$(origin O)", "command line")
   KBUILD_OUTPUT := $(O)
 endif
 
+ifeq ("$(origin W)", "command line")
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+endif
+
 # That's our default target when none is given on the command line
 PHONY := _all
 _all:
@@ -421,7 +425,7 @@ endif
 # of make so .config is not included in this case either (for *config).
 
 no-dot-config-targets := clean mrproper distclean \
-                        cscope TAGS tags help %docs check% coccicheck \
+                        cscope gtags TAGS tags help %docs check% coccicheck \
                         include/linux/version.h headers_% \
                         kernelversion %src-pkg
 
@@ -1018,7 +1022,7 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
 PHONY += __headers
 __headers: include/linux/version.h scripts_basic FORCE
-       $(Q)$(MAKE) $(build)=scripts scripts/unifdef
+       $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
 headers_install_all:
@@ -1135,7 +1139,7 @@ CLEAN_FILES +=    vmlinux System.map \
 MRPROPER_DIRS  += include/config usr/include include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
-                 Module.symvers tags TAGS cscope*
+                 Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
 
 # clean - Delete most, but leave enough to build external modules
 #
@@ -1222,6 +1226,7 @@ help:
        @echo  '  modules_prepare - Set up for building external modules'
        @echo  '  tags/TAGS       - Generate tags file for editors'
        @echo  '  cscope          - Generate cscope index'
+       @echo  '  gtags           - Generate GNU GLOBAL index'
        @echo  '  kernelrelease   - Output the release version string'
        @echo  '  kernelversion   - Output the version stored in Makefile'
        @echo  '  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
@@ -1262,6 +1267,7 @@ help:
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
        @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
+       @echo  '  make W=1   [targets] Enable extra gcc checks'
        @echo  ''
        @echo  'Execute "make" or "make all" to build all targets marked with [*] '
        @echo  'For further info see the ./README file'
@@ -1380,7 +1386,7 @@ clean: $(clean-dirs)
 quiet_cmd_tags = GEN     $@
       cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@
 
-tags TAGS cscope: FORCE
+tags TAGS cscope gtags: FORCE
        $(call cmd,tags)
 
 # Scripts to check various things for consistency
index adfab8a21dfe95714700580a58795da1f6f5d634..85b815215776d5abce038aa70257351e88be363d 100644 (file)
@@ -454,13 +454,11 @@ sched_find_first_bit(const unsigned long b[2])
        return __ffs(tmp) + ofs;
 }
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(l,n,a)   test_and_set_bit(n,a)
 #define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
 
-#include <asm-generic/bitops/minix.h>
-
 #endif /* __KERNEL__ */
 
 #endif /* _ALPHA_BITOPS_H */
index bd621ecd1eb33a21516af7ac6c3629b0f098e65b..881544339c218aed68c00f031ba06669c0a1d2fa 100644 (file)
 typedef unsigned int umode_t;
 
 #endif /* __ASSEMBLY__ */
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
-typedef u64 dma_addr_t;
-typedef u64 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
 #endif /* _ALPHA_TYPES_H */
index 599e1634840dae7cc5d20a7a3f53ef028c58104a..93d595a7477a174c41f5822372fef2700044261c 100644 (file)
@@ -235,6 +235,7 @@ config ARCH_INTEGRATOR
        select ICST
        select GENERIC_CLOCKEVENTS
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_FPGA_IRQ
        help
          Support for ARM's Integrator platform.
 
@@ -242,11 +243,11 @@ config ARCH_REALVIEW
        bool "ARM Ltd. RealView family"
        select ARM_AMBA
        select CLKDEV_LOOKUP
-       select HAVE_SCHED_CLOCK
        select ICST
        select GENERIC_CLOCKEVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLCD
        select ARM_TIMER_SP804
        select GPIO_PL061 if GPIOLIB
        help
@@ -257,11 +258,12 @@ config ARCH_VERSATILE
        select ARM_AMBA
        select ARM_VIC
        select CLKDEV_LOOKUP
-       select HAVE_SCHED_CLOCK
        select ICST
        select GENERIC_CLOCKEVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLCD
+       select PLAT_VERSATILE_FPGA_IRQ
        select ARM_TIMER_SP804
        help
          This enables support for ARM Ltd Versatile board.
@@ -274,9 +276,10 @@ config ARCH_VEXPRESS
        select CLKDEV_LOOKUP
        select GENERIC_CLOCKEVENTS
        select HAVE_CLK
-       select HAVE_SCHED_CLOCK
+       select HAVE_PATA_PLATFORM
        select ICST
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLCD
        help
          This enables support for the ARM Ltd Versatile Express boards.
 
@@ -1011,6 +1014,7 @@ source "arch/arm/mach-ux500/Kconfig"
 source "arch/arm/mach-versatile/Kconfig"
 
 source "arch/arm/mach-vexpress/Kconfig"
+source "arch/arm/plat-versatile/Kconfig"
 
 source "arch/arm/mach-vt8500/Kconfig"
 
index f9f77c65dff32d8708ec98b799630076185bafc3..8ebbb511c7836383aac94622d0ed00aed5c5f29a 100644 (file)
@@ -95,8 +95,8 @@ ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
 endif
 
-EXTRA_CFLAGS  := -fpic -fno-builtin
-EXTRA_AFLAGS  := -Wa,-march=all
+ccflags-y := -fpic -fno-builtin
+asflags-y := -Wa,-march=all
 
 # Provide size of uncompressed kernel to the decompressor via a linker symbol.
 LDFLAGS_vmlinux = --defsym _image_size=$(shell stat -c "%s" $(obj)/../Image)
index e6180af241f647458caea31c37eb5c559b53e623..7453c8337b83a278f84b83892f48e4e979804b70 100644 (file)
@@ -10,7 +10,8 @@
  */
 
 #include <linux/mmc/sh_mmcif.h>
-#include <mach/mmcif.h>
+#include <linux/mmc/boot.h>
+#include <mach/mmc.h>
 
 #define MMCIF_BASE      (void __iomem *)0xe6bd0000
 
@@ -41,8 +42,8 @@
  */
 asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len)
 {
-       mmcif_init_progress();
-       mmcif_update_progress(MMCIF_PROGRESS_ENTER);
+       mmc_init_progress();
+       mmc_update_progress(MMC_PROGRESS_ENTER);
 
        /* Initialise MMC
         * registers: PORT84CR-PORT92CR
@@ -68,12 +69,12 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len)
        /* Enable clock to MMC hardware block */
        __raw_writel(__raw_readl(SMSTPCR3) & ~(1 << 12), SMSTPCR3);
 
-       mmcif_update_progress(MMCIF_PROGRESS_INIT);
+       mmc_update_progress(MMC_PROGRESS_INIT);
 
        /* setup MMCIF hardware */
        sh_mmcif_boot_init(MMCIF_BASE);
 
-       mmcif_update_progress(MMCIF_PROGRESS_LOAD);
+       mmc_update_progress(MMC_PROGRESS_LOAD);
 
        /* load kernel via MMCIF interface */
        sh_mmcif_boot_do_read(MMCIF_BASE, 2, /* Kernel is at block 2 */
@@ -83,5 +84,5 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long len)
        /* Disable clock to MMC hardware block */
        __raw_writel(__raw_readl(SMSTPCR3) & (1 << 12), SMSTPCR3);
 
-       mmcif_update_progress(MMCIF_PROGRESS_DONE);
+       mmc_update_progress(MMC_PROGRESS_DONE);
 }
index 019fb7c67dc3615a6f96bfff64dd37014af2a90b..076db52ff6723deacf4ec0c9485909b886be1484 100644 (file)
@@ -193,6 +193,17 @@ CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 CONFIG_FB_OMAP_LCD_VGA=y
+CONFIG_OMAP2_DSS=m
+CONFIG_OMAP2_DSS_RFBI=y
+CONFIG_OMAP2_DSS_SDI=y
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_FB_OMAP2=m
+CONFIG_PANEL_GENERIC_DPI=m
+CONFIG_PANEL_SHARP_LS037V7DW01=m
+CONFIG_PANEL_NEC_NL8048HL11_01B=m
+CONFIG_PANEL_TAAL=m
+CONFIG_PANEL_TPO_TD043MTEA1=m
+CONFIG_PANEL_ACX565AKM=m
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
index 7a9267e5da5539a3ed70b458b499a572a45fd76b..8845f1c9925d9809749c3740cff3a6c1c02f9180 100644 (file)
@@ -21,6 +21,10 @@ CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_TEGRA=y
 CONFIG_MACH_HARMONY=y
+CONFIG_MACH_KAEN=y
+CONFIG_MACH_PAZ00=y
+CONFIG_MACH_TRIMSLICE=y
+CONFIG_MACH_WARIO=y
 CONFIG_TEGRA_DEBUG_UARTD=y
 CONFIG_ARM_ERRATA_742230=y
 CONFIG_NO_HZ=y
@@ -40,6 +44,10 @@ CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
 CONFIG_INET_ESP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
@@ -66,7 +74,7 @@ CONFIG_APDS9802ALS=y
 CONFIG_ISL29003=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
-# CONFIG_NETDEV_1000 is not set
+CONFIG_R8169=y
 # CONFIG_NETDEV_10000 is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
@@ -78,12 +86,23 @@ CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
-# CONFIG_HWMON is not set
-# CONFIG_MFD_SUPPORT is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_TEGRA=y
+CONFIG_SENSORS_LM90=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_TPS6586X=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_IIO=y
+CONFIG_SENSORS_ISL29018=y
+CONFIG_SENSORS_AK8975=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
@@ -95,6 +114,10 @@ CONFIG_EXT3_FS_SECURITY=y
 # CONFIG_DNOTIFY is not set
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
index af54ed102f5ff3e82a544dd3730c9bd6a5246505..6b7403fd8f54f939e8827b29cc59d6c53a1f9f42 100644 (file)
@@ -287,41 +287,63 @@ static inline int fls(int x)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-/*
- * Ext2 is defined to use little-endian byte ordering.
- * These do not need to be atomic.
- */
-#define ext2_set_bit(nr,p)                     \
-               __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define ext2_set_bit_atomic(lock,nr,p)          \
-                test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define ext2_clear_bit(nr,p)                   \
-               __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define ext2_clear_bit_atomic(lock,nr,p)        \
-                test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define ext2_test_bit(nr,p)                    \
-               test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define ext2_find_first_zero_bit(p,sz)         \
-               _find_first_zero_bit_le(p,sz)
-#define ext2_find_next_zero_bit(p,sz,off)      \
-               _find_next_zero_bit_le(p,sz,off)
-#define ext2_find_next_bit(p, sz, off) \
-               _find_next_bit_le(p, sz, off)
+static inline void __set_bit_le(int nr, void *addr)
+{
+       __set_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline void __clear_bit_le(int nr, void *addr)
+{
+       __clear_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int __test_and_set_bit_le(int nr, void *addr)
+{
+       return __test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int test_and_set_bit_le(int nr, void *addr)
+{
+       return test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int __test_and_clear_bit_le(int nr, void *addr)
+{
+       return __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int test_and_clear_bit_le(int nr, void *addr)
+{
+       return test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int test_bit_le(int nr, const void *addr)
+{
+       return test_bit(WORD_BITOFF_TO_LE(nr), addr);
+}
+
+static inline int find_first_zero_bit_le(const void *p, unsigned size)
+{
+       return _find_first_zero_bit_le(p, size);
+}
+
+static inline int find_next_zero_bit_le(const void *p, int size, int offset)
+{
+       return _find_next_zero_bit_le(p, size, offset);
+}
+
+static inline int find_next_bit_le(const void *p, int size, int offset)
+{
+       return _find_next_bit_le(p, size, offset);
+}
 
 /*
- * Minix is defined to use little-endian byte ordering.
- * These do not need to be atomic.
+ * Ext2 is defined to use little-endian byte ordering.
  */
-#define minix_set_bit(nr,p)                    \
-               __set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define minix_test_bit(nr,p)                   \
-               test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define minix_test_and_set_bit(nr,p)           \
-               __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define minix_test_and_clear_bit(nr,p)         \
-               __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p))
-#define minix_find_first_zero_bit(p,sz)                \
-               _find_first_zero_bit_le(p,sz)
+#define ext2_set_bit_atomic(lock, nr, p)       \
+               test_and_set_bit_le(nr, p)
+#define ext2_clear_bit_atomic(lock, nr, p)     \
+               test_and_clear_bit_le(nr, p)
 
 #endif /* __KERNEL__ */
 
index 6bc63ab498ce45d3c343a4b51f4b26790c8640ee..080d74f8128d4a4a5feb10b579aa42f5d757439f 100644 (file)
@@ -44,8 +44,14 @@ int local_timer_ack(void);
 /*
  * Setup a local timer interrupt for a CPU.
  */
-void local_timer_setup(struct clock_event_device *);
+int local_timer_setup(struct clock_event_device *);
 
+#else
+
+static inline int local_timer_setup(struct clock_event_device *evt)
+{
+       return -ENXIO;
+}
 #endif
 
 #endif
index 348d513afa92383fdd9239a736d788f06a51ca22..d8387437ec5aa8c49258d9ab9f3bbeca2b6bd189 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef __ASM_OUTERCACHE_H
 #define __ASM_OUTERCACHE_H
 
+#include <linux/types.h>
+
 struct outer_cache_fns {
        void (*inv_range)(unsigned long, unsigned long);
        void (*clean_range)(unsigned long, unsigned long);
@@ -38,17 +40,17 @@ struct outer_cache_fns {
 
 extern struct outer_cache_fns outer_cache;
 
-static inline void outer_inv_range(unsigned long start, unsigned long end)
+static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 {
        if (outer_cache.inv_range)
                outer_cache.inv_range(start, end);
 }
-static inline void outer_clean_range(unsigned long start, unsigned long end)
+static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
 {
        if (outer_cache.clean_range)
                outer_cache.clean_range(start, end);
 }
-static inline void outer_flush_range(unsigned long start, unsigned long end)
+static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
 {
        if (outer_cache.flush_range)
                outer_cache.flush_range(start, end);
@@ -74,11 +76,11 @@ static inline void outer_disable(void)
 
 #else
 
-static inline void outer_inv_range(unsigned long start, unsigned long end)
+static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 { }
-static inline void outer_clean_range(unsigned long start, unsigned long end)
+static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
 { }
-static inline void outer_flush_range(unsigned long start, unsigned long end)
+static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
 { }
 static inline void outer_flush_all(void) { }
 static inline void outer_inv_all(void) { }
index ebcb6432f45f829daaa0c33818b7347fe8df26c1..5750704e02718b9247704021a0832f161bcbaf3b 100644 (file)
@@ -301,6 +301,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 #define pgd_present(pgd)       (1)
 #define pgd_clear(pgdp)                do { } while (0)
 #define set_pgd(pgd,pgdp)      do { } while (0)
+#define set_pud(pud,pudp)      do { } while (0)
 
 
 /* Find an entry in the second-level page table.. */
@@ -351,7 +352,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 #define pte_unmap(pte)                 __pte_unmap(pte)
 
 #define pte_pfn(pte)           (pte_val(pte) >> PAGE_SHIFT)
-#define pfn_pte(pfn,prot)      __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pte(pfn,prot)      __pte(__pfn_to_phys(pfn) | pgprot_val(prot))
 
 #define pte_page(pte)          pfn_to_page(pte_pfn(pte))
 #define mk_pte(page,prot)      pfn_pte(page_to_pfn(page), prot)
index da8b52ec49cf43c433712ecff099cf0d7a9d8cfd..95176af3df8cdd1a5df238b0d738da47db316bf6 100644 (file)
@@ -195,7 +195,7 @@ static struct tagtable __tagtable_##fn __tag = { tag, fn }
 #define NR_BANKS 8
 
 struct membank {
-       unsigned long start;
+       phys_addr_t start;
        unsigned long size;
        unsigned int highmem;
 };
index 345df01534a4c9b1fbabab2c84c426c8f3945c6d..48192ac3a23a18fdb1629352f00a062837001ccc 100644 (file)
@@ -16,15 +16,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-typedef u32 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif
index cd3b853a8a6dd9347ac02818164b81e3436a4040..90c50d4b43f74089b8a7eae08753c41ec00b4461 100644 (file)
@@ -18,9 +18,6 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-/* stores the physical address of elf header of crash image */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
 /**
  * copy_oldmem_page() - copy one page from old kernel memory
  * @pfn: page frame number to be copied
index 44b84fe6e1b0fdc544c6f306ed33384a33734fab..8dbc126f7152d992472898a639801239d49a40ac 100644 (file)
@@ -238,8 +238,8 @@ static int enable_monitor_mode(void)
        ARM_DBG_READ(c1, 0, dscr);
 
        /* Ensure that halting mode is disabled. */
-       if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled."
-                               "Unable to access hardware resources.")) {
+       if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
+                       "halting debug mode enabled. Unable to access hardware resources.\n")) {
                ret = -EPERM;
                goto out;
        }
@@ -377,7 +377,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
                }
        }
 
-       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) {
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) {
                ret = -EBUSY;
                goto out;
        }
@@ -423,7 +423,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
                }
        }
 
-       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
                return;
 
        /* Reset the control register. */
@@ -635,7 +635,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
        if (WARN_ONCE(!bp->overflow_handler &&
                (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps()
                 || !bp->hw.bp_target),
-                       "overflow handler required but none found")) {
+                       "overflow handler required but none found\n")) {
                ret = -EINVAL;
        }
 out:
@@ -936,8 +936,8 @@ static int __init arch_hw_breakpoint_init(void)
        ARM_DBG_READ(c1, 0, dscr);
        if (dscr & ARM_DSCR_HDBGEN) {
                max_watchpoint_len = 4;
-               pr_warning("halting debug mode enabled. Assuming maximum "
-                          "watchpoint size of %u bytes.", max_watchpoint_len);
+               pr_warning("halting debug mode enabled. Assuming maximum watchpoint size of %u bytes.\n",
+                          max_watchpoint_len);
        } else {
                /* Work out the maximum supported watchpoint length. */
                max_watchpoint_len = get_max_wp_len();
index d1da92174277b1fefe4f4a15529d5694b82216c3..006c1e884eafedbbfab80caf6a53f3c24fc47a10 100644 (file)
@@ -466,13 +466,13 @@ static struct machine_desc * __init setup_machine(unsigned int nr)
                /* can't use cpu_relax() here as it may require MMU setup */;
 }
 
-static int __init arm_add_memory(unsigned long start, unsigned long size)
+static int __init arm_add_memory(phys_addr_t start, unsigned long size)
 {
        struct membank *bank = &meminfo.bank[meminfo.nr_banks];
 
        if (meminfo.nr_banks >= NR_BANKS) {
                printk(KERN_CRIT "NR_BANKS too low, "
-                       "ignoring memory at %#lx\n", start);
+                       "ignoring memory at 0x%08llx\n", (long long)start);
                return -EINVAL;
        }
 
@@ -502,7 +502,8 @@ static int __init arm_add_memory(unsigned long start, unsigned long size)
 static int __init early_mem(char *p)
 {
        static int usermem __initdata = 0;
-       unsigned long size, start;
+       unsigned long size;
+       phys_addr_t start;
        char *endp;
 
        /*
@@ -788,30 +789,6 @@ static void __init reserve_crashkernel(void)
 static inline void reserve_crashkernel(void) {}
 #endif /* CONFIG_KEXEC */
 
-/*
- * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
- * is_kdump_kernel() to determine if we are booting after a panic. Hence
- * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
- */
-
-#ifdef CONFIG_CRASH_DUMP
-/*
- * elfcorehdr= specifies the location of elf core header stored by the crashed
- * kernel. This option will be passed by kexec loader to the capture kernel.
- */
-static int __init setup_elfcorehdr(char *arg)
-{
-       char *end;
-
-       if (!arg)
-               return -EINVAL;
-
-       elfcorehdr_addr = memparse(arg, &end);
-       return end > arg ? 0 : -EINVAL;
-}
-early_param("elfcorehdr", setup_elfcorehdr);
-#endif /* CONFIG_CRASH_DUMP */
-
 static void __init squash_mem_tags(struct tag *tag)
 {
        for (; tag->hdr.size; tag = tag_next(tag))
index 4539ebcb089fad0c9471310aed633da450cf963f..8fe05ad932e4bd0b113c11c19f7e816650ace696 100644 (file)
@@ -474,13 +474,12 @@ static void smp_timer_broadcast(const struct cpumask *mask)
 #define smp_timer_broadcast    NULL
 #endif
 
-#ifndef CONFIG_LOCAL_TIMERS
 static void broadcast_timer_set_mode(enum clock_event_mode mode,
        struct clock_event_device *evt)
 {
 }
 
-static void local_timer_setup(struct clock_event_device *evt)
+static void broadcast_timer_setup(struct clock_event_device *evt)
 {
        evt->name       = "dummy_timer";
        evt->features   = CLOCK_EVT_FEAT_ONESHOT |
@@ -492,7 +491,6 @@ static void local_timer_setup(struct clock_event_device *evt)
 
        clockevents_register_device(evt);
 }
-#endif
 
 void __cpuinit percpu_timer_setup(void)
 {
@@ -502,7 +500,8 @@ void __cpuinit percpu_timer_setup(void)
        evt->cpumask = cpumask_of(cpu);
        evt->broadcast = smp_timer_broadcast;
 
-       local_timer_setup(evt);
+       if (local_timer_setup(evt))
+               broadcast_timer_setup(evt);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 21ac43f1c2d0e06c3d650f1cafee1c3d989874b8..f0000e188c8c8c5a14be6f21c37b961739ecfad6 100644 (file)
@@ -712,17 +712,17 @@ EXPORT_SYMBOL(__readwrite_bug);
 
 void __pte_error(const char *file, int line, pte_t pte)
 {
-       printk("%s:%d: bad pte %08lx.\n", file, line, pte_val(pte));
+       printk("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
 }
 
 void __pmd_error(const char *file, int line, pmd_t pmd)
 {
-       printk("%s:%d: bad pmd %08lx.\n", file, line, pmd_val(pmd));
+       printk("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
 }
 
 void __pgd_error(const char *file, int line, pgd_t pgd)
 {
-       printk("%s:%d: bad pgd %08lx.\n", file, line, pgd_val(pgd));
+       printk("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
 }
 
 asmlinkage void __div0(void)
index e2d2f2cd0c4f3b5c9b9c958aa65d073bcbbe722f..8b9b13649f8170304245466a9409ce5e5ae2018b 100644 (file)
@@ -27,13 +27,18 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
        pgd_t *pgd;
        pmd_t *pmd;
        pte_t *pte;
+       pud_t *pud;
        spinlock_t *ptl;
 
        pgd = pgd_offset(current->mm, addr);
        if (unlikely(pgd_none(*pgd) || pgd_bad(*pgd)))
                return 0;
 
-       pmd = pmd_offset(pgd, addr);
+       pud = pud_offset(pgd, addr);
+       if (unlikely(pud_none(*pud) || pud_bad(*pud)))
+               return 0;
+
+       pmd = pmd_offset(pud, addr);
        if (unlikely(pmd_none(*pmd) || pmd_bad(*pmd)))
                return 0;
 
index a889fa7c3ba19952b80f189727779c1aa35a4acf..34e071d79761131a3897a94436c6d00432470ffe 100644 (file)
@@ -360,52 +360,14 @@ static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
        gpio = ep93xx_chip->chip.base;
        for (i = 0; i < chip->ngpio; i++, gpio++) {
                int is_out = data_dir_reg & (1 << i);
+               int irq = gpio_to_irq(gpio);
 
-               seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s",
+               seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s %s\n",
                                chip->label, i, gpio,
                                gpiochip_is_requested(chip, i) ? : "",
                                is_out ? "out" : "in ",
-                               (data_reg & (1 << i)) ? "hi" : "lo");
-
-               if (!is_out) {
-                       int irq = gpio_to_irq(gpio);
-                       struct irq_desc *desc = irq_desc + irq;
-
-                       if (irq >= 0 && desc->action) {
-                               char *trigger;
-
-                               switch (desc->status & IRQ_TYPE_SENSE_MASK) {
-                               case IRQ_TYPE_NONE:
-                                       trigger = "(default)";
-                                       break;
-                               case IRQ_TYPE_EDGE_FALLING:
-                                       trigger = "edge-falling";
-                                       break;
-                               case IRQ_TYPE_EDGE_RISING:
-                                       trigger = "edge-rising";
-                                       break;
-                               case IRQ_TYPE_EDGE_BOTH:
-                                       trigger = "edge-both";
-                                       break;
-                               case IRQ_TYPE_LEVEL_HIGH:
-                                       trigger = "level-high";
-                                       break;
-                               case IRQ_TYPE_LEVEL_LOW:
-                                       trigger = "level-low";
-                                       break;
-                               default:
-                                       trigger = "?trigger?";
-                                       break;
-                               }
-
-                               seq_printf(s, " irq-%d %s%s",
-                                               irq, trigger,
-                                               (desc->status & IRQ_WAKEUP)
-                                                       ? " wakeup" : "");
-                       }
-               }
-
-               seq_printf(s, "\n");
+                               (data_reg & (1<<  i)) ? "hi" : "lo",
+                               (!is_out && irq>= 0) ? "(interrupt)" : "");
        }
 }
 
index 2a2993ae8d86b01540040da27454642b2dc898d0..6bf3d0ab96278b1c31571f9263e31ef0691265cf 100644 (file)
@@ -18,8 +18,9 @@
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
        evt->irq = IRQ_LOCALTIMER;
        twd_timer_setup(evt);
+       return 0;
 }
index 614b3c00c4a015fba85b34803b9006e91195cf4f..6e1accf93f811d57b7ab97c463b562a39bd43b82 100644 (file)
@@ -232,10 +232,13 @@ static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
 };
 
 /* MC13783 */
-static struct mc13xxx_platform_data mc13783_pdata __initdata = {
-       .regulators = mx27_3ds_regulators,
-       .num_regulators = ARRAY_SIZE(mx27_3ds_regulators),
-       .flags  = MC13XXX_USE_REGULATOR,
+static struct mc13xxx_platform_data mc13783_pdata = {
+       .regulators = {
+               .regulators = mx27_3ds_regulators,
+               .num_regulators = ARRAY_SIZE(mx27_3ds_regulators),
+
+       },
+       .flags  = MC13783_USE_REGULATOR,
 };
 
 /* SPI */
index 38c77084b615222d4064fae7d8f7b1c5adaa4426..4cbce6d0fef1652ff9358a496ef907d5b239e129 100644 (file)
@@ -263,10 +263,12 @@ static struct mc13xxx_regulator_init_data pcm038_regulators[] = {
 };
 
 static struct mc13xxx_platform_data pcm038_pmic = {
-       .regulators = pcm038_regulators,
-       .num_regulators = ARRAY_SIZE(pcm038_regulators),
-       .flags = MC13XXX_USE_ADC | MC13XXX_USE_REGULATOR |
-                MC13XXX_USE_TOUCHSCREEN,
+       .regulators = {
+               .regulators = pcm038_regulators,
+               .num_regulators = ARRAY_SIZE(pcm038_regulators),
+       },
+       .flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
+                MC13783_USE_TOUCHSCREEN,
 };
 
 static struct spi_board_info pcm038_spi_board_info[] __initdata = {
index 769b0f10c83496a48565ba50b236f9a10aaf9df9..d701d32a07f1b104273238f9580605bdeabcde55 100644 (file)
@@ -13,6 +13,7 @@ config ARCH_INTEGRATOR_CP
        bool "Support Integrator/CP platform"
        select ARCH_CINTEGRATOR
        select ARM_TIMER_SP804
+       select PLAT_VERSATILE_CLCD
        help
          Include support for the ARM(R) Integrator CP platform.
 
index 5f96e1518aa9408398fdbaa97ee7e639ffa50184..a08f9b0299dfa43090b564ca39f20cfdf4325a9c 100644 (file)
@@ -1 +1,2 @@
+void integrator_init_early(void);
 void integrator_reserve(void);
index b8e884b450da7454e77b9fe3d030f2729aacd8aa..77315b995681c01170ad13344d4b3be79a3f1e3b 100644 (file)
@@ -144,12 +144,15 @@ static struct clk_lookup lookups[] = {
        }
 };
 
+void __init integrator_init_early(void)
+{
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+}
+
 static int __init integrator_init(void)
 {
        int i;
 
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
index 5db574f8ae3fd218d393898512930adf53fe2bf3..8cbb75a96bd4b3140c3007f0393e06fe6194d807 100644 (file)
@@ -121,6 +121,7 @@ static struct clcd_panel vga = {
        .height         = -1,
        .tim2           = TIM2_BCD | TIM2_IPC,
        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
        .connector      = IMPD1_CTRL_DISP_VGA,
        .bpp            = 16,
        .grayscale      = 0,
@@ -149,6 +150,7 @@ static struct clcd_panel svga = {
        .tim2           = TIM2_BCD,
        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
        .connector      = IMPD1_CTRL_DISP_VGA,
+       .caps           = CLCD_CAP_5551,
        .bpp            = 16,
        .grayscale      = 0,
 };
@@ -175,6 +177,7 @@ static struct clcd_panel prospector = {
        .height         = -1,
        .tim2           = TIM2_BCD,
        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
        .fixedtimings   = 1,
        .connector      = IMPD1_CTRL_DISP_LCD,
        .bpp            = 16,
@@ -206,6 +209,7 @@ static struct clcd_panel ltm10c209 = {
        .height         = -1,
        .tim2           = TIM2_BCD,
        .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
        .fixedtimings   = 1,
        .connector      = IMPD1_CTRL_DISP_LCD,
        .bpp            = 16,
@@ -279,6 +283,7 @@ static void impd1fb_clcd_remove(struct clcd_fb *fb)
 
 static struct clcd_board impd1_clcd_data = {
        .name           = "IM-PD/1",
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_888,
        .check          = clcdfb_check,
        .decode         = clcdfb_decode,
        .disable        = impd1fb_clcd_disable,
index 1ab353e235955eee63e43a3a030d0b8b4b719a2b..445d57adb043afa2a23c681f9cdfda610b6bb7cd 100644 (file)
@@ -24,9 +24,9 @@ void cm_control(u32, u32);
 #define CM_CTRL_LCDBIASDN              (1 << 10)
 #define CM_CTRL_LCDMUXSEL_MASK         (7 << 11)
 #define CM_CTRL_LCDMUXSEL_GENLCD       (1 << 11)
-#define CM_CTRL_LCDMUXSEL_VGA_16BPP    (2 << 11)
+#define CM_CTRL_LCDMUXSEL_VGA565_TFT555        (2 << 11)
 #define CM_CTRL_LCDMUXSEL_SHARPLCD     (3 << 11)
-#define CM_CTRL_LCDMUXSEL_VGA_8421BPP  (4 << 11)
+#define CM_CTRL_LCDMUXSEL_VGA555_TFT555        (4 << 11)
 #define CM_CTRL_LCDEN0                 (1 << 14)
 #define CM_CTRL_LCDEN1                 (1 << 15)
 #define CM_CTRL_STATIC1                        (1 << 16)
index b666443b5cbbab0e80b88b2592152a8d34a86eb7..980803ff348ce938bcd72d9abdb7ed45b0af2803 100644 (file)
@@ -48,6 +48,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
+#include <plat/fpga-irq.h>
+
 #include "common.h"
 
 /* 
  * Setup a VA for the Integrator interrupt controller (for header #0,
  * just for now).
  */
-#define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE) 
-#define VA_SC_BASE     IO_ADDRESS(INTEGRATOR_SC_BASE)
-#define VA_EBI_BASE    IO_ADDRESS(INTEGRATOR_EBI_BASE)
-#define VA_CMIC_BASE   IO_ADDRESS(INTEGRATOR_HDR_IC)
+#define VA_IC_BASE     __io_address(INTEGRATOR_IC_BASE)
+#define VA_SC_BASE     __io_address(INTEGRATOR_SC_BASE)
+#define VA_EBI_BASE    __io_address(INTEGRATOR_EBI_BASE)
+#define VA_CMIC_BASE   __io_address(INTEGRATOR_HDR_IC)
 
 /*
  * Logical      Physical
@@ -156,27 +158,14 @@ static void __init ap_map_io(void)
 
 #define INTEGRATOR_SC_VALID_INT        0x003fffff
 
-static void sc_mask_irq(struct irq_data *d)
-{
-       writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
-}
-
-static void sc_unmask_irq(struct irq_data *d)
-{
-       writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_SET);
-}
-
-static struct irq_chip sc_chip = {
-       .name           = "SC",
-       .irq_ack        = sc_mask_irq,
-       .irq_mask       = sc_mask_irq,
-       .irq_unmask     = sc_unmask_irq,
+static struct fpga_irq_data sc_irq_data = {
+       .base           = VA_IC_BASE,
+       .irq_start      = 0,
+       .chip.name      = "SC",
 };
 
 static void __init ap_init_irq(void)
 {
-       unsigned int i;
-
        /* Disable all interrupts initially. */
        /* Do the core module ones */
        writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
@@ -185,13 +174,7 @@ static void __init ap_init_irq(void)
        writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
        writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
 
-       for (i = 0; i < NR_IRQS; i++) {
-               if (((1 << i) & INTEGRATOR_SC_VALID_INT) != 0) {
-                       set_irq_chip(i, &sc_chip);
-                       set_irq_handler(i, handle_level_irq);
-                       set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-               }
-       }
+       fpga_irq_init(-1, INTEGRATOR_SC_VALID_INT, &sc_irq_data);
 }
 
 #ifdef CONFIG_PM
@@ -282,7 +265,7 @@ static void ap_flash_exit(void)
 
 static void ap_flash_set_vpp(int on)
 {
-       unsigned long reg = on ? SC_CTRLS : SC_CTRLC;
+       void __iomem *reg = on ? SC_CTRLS : SC_CTRLC;
 
        writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
 }
@@ -499,8 +482,9 @@ static struct sys_timer ap_timer = {
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .boot_params    = 0x00000100,
-       .map_io         = ap_map_io,
        .reserve        = integrator_reserve,
+       .map_io         = ap_map_io,
+       .init_early     = integrator_init_early,
        .init_irq       = ap_init_irq,
        .timer          = &ap_timer,
        .init_machine   = ap_init,
index e9327da1382e7a5d5f56c55b09f6bc829e02f290..9e3ce26023e87fc70fbdb947e677cee2e6a7006b 100644 (file)
 
 #include <asm/hardware/timer-sp.h>
 
+#include <plat/clcd.h>
+#include <plat/fpga-irq.h>
+#include <plat/sched_clock.h>
+
 #include "common.h"
 
 #define INTCP_PA_FLASH_BASE            0x24000000
@@ -49,9 +53,9 @@
 
 #define INTCP_PA_CLCD_BASE             0xc0000000
 
-#define INTCP_VA_CIC_BASE              IO_ADDRESS(INTEGRATOR_HDR_BASE + 0x40)
-#define INTCP_VA_PIC_BASE              IO_ADDRESS(INTEGRATOR_IC_BASE)
-#define INTCP_VA_SIC_BASE              IO_ADDRESS(INTEGRATOR_CP_SIC_BASE)
+#define INTCP_VA_CIC_BASE              __io_address(INTEGRATOR_HDR_BASE + 0x40)
+#define INTCP_VA_PIC_BASE              __io_address(INTEGRATOR_IC_BASE)
+#define INTCP_VA_SIC_BASE              __io_address(INTEGRATOR_CP_SIC_BASE)
 
 #define INTCP_ETH_SIZE                 0x10
 
@@ -139,129 +143,48 @@ static void __init intcp_map_io(void)
        iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc));
 }
 
-#define cic_writel     __raw_writel
-#define cic_readl      __raw_readl
-#define pic_writel     __raw_writel
-#define pic_readl      __raw_readl
-#define sic_writel     __raw_writel
-#define sic_readl      __raw_readl
-
-static void cic_mask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_CIC_START;
-       cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
-}
-
-static void cic_unmask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_CIC_START;
-       cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET);
-}
-
-static struct irq_chip cic_chip = {
-       .name           = "CIC",
-       .irq_ack        = cic_mask_irq,
-       .irq_mask       = cic_mask_irq,
-       .irq_unmask     = cic_unmask_irq,
+static struct fpga_irq_data cic_irq_data = {
+       .base           = INTCP_VA_CIC_BASE,
+       .irq_start      = IRQ_CIC_START,
+       .chip.name      = "CIC",
 };
 
-static void pic_mask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_PIC_START;
-       pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
-}
-
-static void pic_unmask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_PIC_START;
-       pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET);
-}
-
-static struct irq_chip pic_chip = {
-       .name           = "PIC",
-       .irq_ack        = pic_mask_irq,
-       .irq_mask       = pic_mask_irq,
-       .irq_unmask     = pic_unmask_irq,
+static struct fpga_irq_data pic_irq_data = {
+       .base           = INTCP_VA_PIC_BASE,
+       .irq_start      = IRQ_PIC_START,
+       .chip.name      = "PIC",
 };
 
-static void sic_mask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_SIC_START;
-       sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
-}
-
-static void sic_unmask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_SIC_START;
-       sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET);
-}
-
-static struct irq_chip sic_chip = {
-       .name           = "SIC",
-       .irq_ack        = sic_mask_irq,
-       .irq_mask       = sic_mask_irq,
-       .irq_unmask     = sic_unmask_irq,
+static struct fpga_irq_data sic_irq_data = {
+       .base           = INTCP_VA_SIC_BASE,
+       .irq_start      = IRQ_SIC_START,
+       .chip.name      = "SIC",
 };
 
-static void
-sic_handle_irq(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
-
-       if (status == 0) {
-               do_bad_IRQ(irq, desc);
-               return;
-       }
-
-       do {
-               irq = ffs(status) - 1;
-               status &= ~(1 << irq);
-
-               irq += IRQ_SIC_START;
-
-               generic_handle_irq(irq);
-       } while (status);
-}
-
 static void __init intcp_init_irq(void)
 {
-       unsigned int i;
+       u32 pic_mask, sic_mask;
+
+       pic_mask = ~((~0u) << (11 - IRQ_PIC_START));
+       pic_mask |= (~((~0u) << (29 - 22))) << 22;
+       sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START));
 
        /*
         * Disable all interrupt sources
         */
-       pic_writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
-       pic_writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR);
-
-       for (i = IRQ_PIC_START; i <= IRQ_PIC_END; i++) {
-               if (i == 11)
-                       i = 22;
-               if (i == 29)
-                       break;
-               set_irq_chip(i, &pic_chip);
-               set_irq_handler(i, handle_level_irq);
-               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-       }
+       writel(0xffffffff, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
+       writel(0xffffffff, INTCP_VA_PIC_BASE + FIQ_ENABLE_CLEAR);
+       writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
+       writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR);
+       writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
+       writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR);
 
-       cic_writel(0xffffffff, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
-       cic_writel(0xffffffff, INTCP_VA_CIC_BASE + FIQ_ENABLE_CLEAR);
+       fpga_irq_init(-1, pic_mask, &pic_irq_data);
 
-       for (i = IRQ_CIC_START; i <= IRQ_CIC_END; i++) {
-               set_irq_chip(i, &cic_chip);
-               set_irq_handler(i, handle_level_irq);
-               set_irq_flags(i, IRQF_VALID);
-       }
-
-       sic_writel(0x00000fff, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
-       sic_writel(0x00000fff, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR);
-
-       for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
-               set_irq_chip(i, &sic_chip);
-               set_irq_handler(i, handle_level_irq);
-               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-       }
+       fpga_irq_init(-1, ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START)),
+               &cic_irq_data);
 
-       set_irq_chained_handler(IRQ_CP_CPPLDINT, sic_handle_irq);
+       fpga_irq_init(IRQ_CP_CPPLDINT, sic_mask, &sic_irq_data);
 }
 
 /*
@@ -449,43 +372,21 @@ static struct amba_device aaci_device = {
 /*
  * CLCD support
  */
-static struct clcd_panel vga = {
-       .mode           = {
-               .name           = "VGA",
-               .refresh        = 60,
-               .xres           = 640,
-               .yres           = 480,
-               .pixclock       = 39721,
-               .left_margin    = 40,
-               .right_margin   = 24,
-               .upper_margin   = 32,
-               .lower_margin   = 11,
-               .hsync_len      = 96,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-       .grayscale      = 0,
-};
-
 /*
  * Ensure VGA is selected.
  */
 static void cp_clcd_enable(struct clcd_fb *fb)
 {
-       u32 val;
+       struct fb_var_screeninfo *var = &fb->fb.var;
+       u32 val = CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
 
-       if (fb->fb.var.bits_per_pixel <= 8)
-               val = CM_CTRL_LCDMUXSEL_VGA_8421BPP;
+       if (var->bits_per_pixel <= 8 ||
+           (var->bits_per_pixel == 16 && var->green.length == 5))
+               /* Pseudocolor, RGB555, BGR555 */
+               val |= CM_CTRL_LCDMUXSEL_VGA555_TFT555;
        else if (fb->fb.var.bits_per_pixel <= 16)
-               val = CM_CTRL_LCDMUXSEL_VGA_16BPP
-                       | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1
-                       | CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
+               /* truecolor RGB565 */
+               val |= CM_CTRL_LCDMUXSEL_VGA565_TFT555;
        else
                val = 0; /* no idea for this, don't trust the docs */
 
@@ -498,49 +399,24 @@ static void cp_clcd_enable(struct clcd_fb *fb)
                   CM_CTRL_n24BITEN, val);
 }
 
-static unsigned long framesize = SZ_1M;
-
 static int cp_clcd_setup(struct clcd_fb *fb)
 {
-       dma_addr_t dma;
-
-       fb->panel = &vga;
-
-       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
-                                                   &dma, GFP_KERNEL);
-       if (!fb->fb.screen_base) {
-               printk(KERN_ERR "CLCD: unable to map framebuffer\n");
-               return -ENOMEM;
-       }
-
-       fb->fb.fix.smem_start   = dma;
-       fb->fb.fix.smem_len     = framesize;
-
-       return 0;
-}
-
-static int cp_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
-       return dma_mmap_writecombine(&fb->dev->dev, vma,
-                                    fb->fb.screen_base,
-                                    fb->fb.fix.smem_start,
-                                    fb->fb.fix.smem_len);
-}
+       fb->panel = versatile_clcd_get_panel("VGA");
+       if (!fb->panel)
+               return -EINVAL;
 
-static void cp_clcd_remove(struct clcd_fb *fb)
-{
-       dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
-                             fb->fb.screen_base, fb->fb.fix.smem_start);
+       return versatile_clcd_setup_dma(fb, SZ_1M);
 }
 
 static struct clcd_board clcd_data = {
        .name           = "Integrator/CP",
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_RGB565 | CLCD_CAP_888,
        .check          = clcdfb_check,
        .decode         = clcdfb_decode,
        .enable         = cp_clcd_enable,
        .setup          = cp_clcd_setup,
-       .mmap           = cp_clcd_mmap,
-       .remove         = cp_clcd_remove,
+       .mmap           = versatile_clcd_mmap_dma,
+       .remove         = versatile_clcd_remove_dma,
 };
 
 static struct amba_device clcd_device = {
@@ -565,11 +441,23 @@ static struct amba_device *amba_devs[] __initdata = {
        &clcd_device,
 };
 
+#define REFCOUNTER (__io_address(INTEGRATOR_HDR_BASE) + 0x28)
+
+static void __init intcp_init_early(void)
+{
+       clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups));
+
+       integrator_init_early();
+
+#ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK
+       versatile_sched_clock_init(REFCOUNTER, 24000000);
+#endif
+}
+
 static void __init intcp_init(void)
 {
        int i;
 
-       clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups));
        platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
@@ -599,8 +487,9 @@ static struct sys_timer cp_timer = {
 MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .boot_params    = 0x00000100,
-       .map_io         = intcp_map_io,
        .reserve        = integrator_reserve,
+       .map_io         = intcp_map_io,
+       .init_early     = intcp_init_early,
        .init_irq       = intcp_init_irq,
        .timer          = &cp_timer,
        .init_machine   = intcp_init,
index 4aec493640b41c1656bbdded16c1b55e0c2f4f60..2cbf6df09b82851ae7117c69279994723c41ec9f 100644 (file)
@@ -11,8 +11,8 @@ extern void __init mmp2_init_irq(void);
 extern void mmp2_clear_pmic_int(void);
 
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <mach/devices.h>
-#include <plat/i2c.h>
 
 extern struct pxa_device_desc mmp2_device_uart1;
 extern struct pxa_device_desc mmp2_device_uart2;
index 1801e420623259a6a4004dd0f8f9ba280997fc0a..a52b3d2f325ce7a3e6654b3fde2d87ad1af4dce4 100644 (file)
@@ -8,8 +8,8 @@ extern void __init pxa168_init_irq(void);
 extern void pxa168_clear_keypad_wakeup(void);
 
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <mach/devices.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 #include <video/pxa168fb.h>
 #include <plat/pxa27x_keypad.h>
index f13c49d6f8dc052988e6f5f407f333c2be183a2e..91be75591398baf9427a892864316101284dc7cf 100644 (file)
@@ -7,8 +7,8 @@ extern struct sys_timer pxa910_timer;
 extern void __init pxa910_init_irq(void);
 
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <mach/devices.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
 extern struct pxa_device_desc pxa910_device_uart1;
index e7f8e5a4d48f26331921089f819a9992864378e1..56f920c55b6aaaaa45737aeeddffadfa1b1a12d2 100644 (file)
@@ -263,7 +263,7 @@ static void __init msm_timer_init(void)
 }
 
 #ifdef CONFIG_SMP
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
        struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
 
@@ -295,6 +295,7 @@ void __cpuinit local_timer_setup(struct clock_event_device *evt)
        gic_enable_ppi(clock->irq.irq);
 
        clockevents_register_device(evt);
+       return 0;
 }
 
 inline int local_timer_ack(void)
index 544d3e414f5846f08ba96ef71c3fa41b29422cd2..034be624d35cb31f14c0e380e8e9eee3bf0b5339 100644 (file)
@@ -488,10 +488,12 @@ static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = {
 };
 
 /* MC13783 */
-static struct mc13xxx_platform_data mc13783_pdata __initdata = {
-       .regulators = mx31_3ds_regulators,
-       .num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
-       .flags  = MC13XXX_USE_REGULATOR | MC13XXX_USE_TOUCHSCREEN
+static struct mc13xxx_platform_data mc13783_pdata = {
+       .regulators = {
+               .regulators = mx31_3ds_regulators,
+               .num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
+       },
+       .flags  = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN,
 };
 
 /* SPI */
index 6f3692bccb8ad3201418015a4f28bc23dedf96af..3a021b01161db3ad122f531d9fe366bb1961b146 100644 (file)
@@ -268,8 +268,10 @@ static struct mc13783_leds_platform_data moboard_leds = {
 };
 
 static struct mc13xxx_platform_data moboard_pmic = {
-       .regulators = moboard_regulators,
-       .num_regulators = ARRAY_SIZE(moboard_regulators),
+       .regulators = {
+               .regulators = moboard_regulators,
+               .num_regulators = ARRAY_SIZE(moboard_regulators),
+       },
        .leds = &moboard_leds,
        .flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_RTC |
                MC13XXX_USE_ADC | MC13XXX_USE_LED,
diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h
new file mode 100644 (file)
index 0000000..7f4aeea
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MACH_MXS_DMA_H__
+#define __MACH_MXS_DMA_H__
+
+struct mxs_dma_data {
+       int chan_irq;
+};
+
+static inline int mxs_dma_is_apbh(struct dma_chan *chan)
+{
+       return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbh");
+}
+
+static inline int mxs_dma_is_apbx(struct dma_chan *chan)
+{
+       return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbx");
+}
+
+#endif /* __MACH_MXS_DMA_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/mmc.h b/arch/arm/mach-mxs/include/mach/mmc.h
new file mode 100644 (file)
index 0000000..211547a
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MACH_MXS_MMC_H__
+#define __MACH_MXS_MMC_H__
+
+struct mxs_mmc_platform_data {
+       int wp_gpio;    /* write protect pin */
+       unsigned int flags;
+#define SLOTF_4_BIT_CAPABLE    (1 << 0)
+#define SLOTF_8_BIT_CAPABLE    (1 << 1)
+};
+#endif /* __MACH_MXS_MMC_H__ */
index eeab35dea07e343f17e4c741b2a6ee1259feee52..b997a35830fce5e36f1624773916a90159a02865 100644 (file)
@@ -44,6 +44,7 @@ config ARCH_OMAP4
        depends on ARCH_OMAP2PLUS
        select CPU_V7
        select ARM_GIC
+       select LOCAL_TIMERS if SMP
        select PL310_ERRATA_588369
        select PL310_ERRATA_727915
        select ARM_ERRATA_720789
index c06eb423c4e4456bed2d8e09c4f515201101dffa..9afd087cc29c9b1346cde3b161236e6d01b37524 100644 (file)
@@ -307,9 +307,6 @@ static struct omap_dss_board_info sdp3430_dss_data = {
        .default_device = &sdp3430_lcd_device,
 };
 
-static struct regulator_consumer_supply sdp3430_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
-
 static struct omap_board_config_kernel sdp3430_config[] __initdata = {
 };
 
@@ -398,12 +395,13 @@ static struct regulator_consumer_supply sdp3430_vaux3_supplies[] = {
 };
 
 static struct regulator_consumer_supply sdp3430_vdda_dac_supplies[] = {
-       REGULATOR_SUPPLY("vdda_dac", "omapdss"),
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc"),
 };
 
 /* VPLL2 for digital video outputs */
 static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
        REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
 };
 
 static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = {
index 333ceb2c8fb02a465c8533712e0cc3f387b95eb5..56702c5e577fe3365cab09b56c32d5b4913020a0 100644 (file)
@@ -36,6 +36,7 @@
 #include <plat/usb.h>
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
+#include <plat/display.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -47,6 +48,8 @@
 #define ETH_KS8851_QUART               138
 #define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO       184
 #define OMAP4_SFH7741_ENABLE_GPIO              188
+#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
 
 static const int sdp4430_keymap[] = {
        KEY(0, 0, KEY_E),
@@ -547,6 +550,12 @@ static struct regulator_init_data sdp4430_vusb = {
        },
 };
 
+static struct regulator_init_data sdp4430_clk32kg = {
+       .constraints = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+       },
+};
+
 static struct twl4030_platform_data sdp4430_twldata = {
        .irq_base       = TWL6030_IRQ_BASE,
        .irq_end        = TWL6030_IRQ_END,
@@ -562,6 +571,7 @@ static struct twl4030_platform_data sdp4430_twldata = {
        .vaux1          = &sdp4430_vaux1,
        .vaux2          = &sdp4430_vaux2,
        .vaux3          = &sdp4430_vaux3,
+       .clk32kg        = &sdp4430_clk32kg,
        .usb            = &omap4_usbphy_data
 };
 
@@ -621,6 +631,76 @@ static void __init omap_sfh7741prox_init(void)
        }
 }
 
+static void sdp4430_hdmi_mux_init(void)
+{
+       /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+       omap_mux_init_signal("hdmi_hpd",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_cec",
+                       OMAP_PIN_INPUT_PULLUP);
+       /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+       omap_mux_init_signal("hdmi_ddc_scl",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_ddc_sda",
+                       OMAP_PIN_INPUT_PULLUP);
+}
+
+static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+       int status;
+
+       status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
+                                                       "hdmi_gpio_hpd");
+       if (status) {
+               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
+               return status;
+       }
+       status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
+                                                       "hdmi_gpio_ls_oe");
+       if (status) {
+               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
+               goto error1;
+       }
+
+       return 0;
+
+error1:
+       gpio_free(HDMI_GPIO_HPD);
+
+       return status;
+}
+
+static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+       gpio_free(HDMI_GPIO_LS_OE);
+       gpio_free(HDMI_GPIO_HPD);
+}
+
+static struct omap_dss_device sdp4430_hdmi_device = {
+       .name = "hdmi",
+       .driver_name = "hdmi_panel",
+       .type = OMAP_DISPLAY_TYPE_HDMI,
+       .platform_enable = sdp4430_panel_enable_hdmi,
+       .platform_disable = sdp4430_panel_disable_hdmi,
+       .channel = OMAP_DSS_CHANNEL_DIGIT,
+};
+
+static struct omap_dss_device *sdp4430_dss_devices[] = {
+       &sdp4430_hdmi_device,
+};
+
+static struct omap_dss_board_info sdp4430_dss_data = {
+       .num_devices    = ARRAY_SIZE(sdp4430_dss_devices),
+       .devices        = sdp4430_dss_devices,
+       .default_device = &sdp4430_hdmi_device,
+};
+
+void omap_4430sdp_display_init(void)
+{
+       sdp4430_hdmi_mux_init();
+       omap_display_init(&sdp4430_dss_data);
+}
+
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
        OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
@@ -729,6 +809,8 @@ static void __init omap_4430sdp_init(void)
        status = omap4_keyboard_init(&sdp4430_keypad_data);
        if (status)
                pr_err("Keypad initialization failed: %d\n", status);
+
+       omap_4430sdp_display_init();
 }
 
 static void __init omap_4430sdp_map_io(void)
index 7b5647954c13d3d59b128e53fcc4a49da6836b81..02a12b41c0ff0b178e3493706e24c54d68a2bf70 100644 (file)
@@ -488,7 +488,7 @@ static struct regulator_consumer_supply cm_t35_vsim_supply = {
 };
 
 static struct regulator_consumer_supply cm_t35_vdac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_consumer_supply cm_t35_vdvi_supply =
        REGULATOR_SUPPLY("vdvi", "omapdss");
index aa27483c493ef8054f4ceafa8255a1f141b64933..65f9fde2c567253a5f2e5cf8f73f32c624dc721d 100644 (file)
@@ -196,7 +196,7 @@ static struct omap_dss_board_info devkit8000_dss_data = {
 };
 
 static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static uint32_t board_keymap[] = {
        KEY(0, 0, KEY_1),
@@ -277,8 +277,10 @@ static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
        .setup          = devkit8000_twl_gpio_setup,
 };
 
-static struct regulator_consumer_supply devkit8000_vpll1_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply devkit8000_vpll1_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
 static struct regulator_init_data devkit8000_vmmc1 = {
@@ -319,8 +321,8 @@ static struct regulator_init_data devkit8000_vpll1 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &devkit8000_vpll1_supply,
+       .num_consumer_supplies  = ARRAY_SIZE(devkit8000_vpll1_supplies),
+       .consumer_supplies      = devkit8000_vpll1_supplies,
 };
 
 /* VAUX4 for ads7846 and nubs */
index d3199b4ecdb6df67f986d4b5506f13829502eb6b..5f8a2fd0633720f67b535b362d9c673ce2bedbe6 100644 (file)
@@ -485,8 +485,10 @@ static struct omap_dss_board_info igep2_dss_data = {
        .default_device = &igep2_dvi_device,
 };
 
-static struct regulator_consumer_supply igep2_vpll2_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply igep2_vpll2_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data igep2_vpll2 = {
        .constraints = {
@@ -499,8 +501,8 @@ static struct regulator_init_data igep2_vpll2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &igep2_vpll2_supply,
+       .num_consumer_supplies  = ARRAY_SIZE(igep2_vpll2_supplies),
+       .consumer_supplies      = igep2_vpll2_supplies,
 };
 
 static void __init igep2_display_init(void)
index 7640c054f43b6be37c8f92a9dd72d070c6cffbe4..33007fd4a0835fd298129c9fda30b844707cc08b 100644 (file)
@@ -232,10 +232,12 @@ static struct omap_dss_board_info beagle_dss_data = {
 };
 
 static struct regulator_consumer_supply beagle_vdac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
-static struct regulator_consumer_supply beagle_vdvi_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply beagle_vdvi_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static void __init beagle_display_init(void)
 {
@@ -422,8 +424,8 @@ static struct regulator_init_data beagle_vpll2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &beagle_vdvi_supply,
+       .num_consumer_supplies  = ARRAY_SIZE(beagle_vdvi_supplies),
+       .consumer_supplies      = beagle_vdvi_supplies,
 };
 
 static struct twl4030_usb_data beagle_usb_data = {
index 0fa2c7b208b1fe281ed7fadbdfe924ffdcc437ca..5a1a916e5cc8a1989959d807731d94719eb39513 100644 (file)
@@ -542,7 +542,7 @@ static struct twl4030_codec_data omap3evm_codec_data = {
 };
 
 static struct regulator_consumer_supply omap3_evm_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 /* VDAC for DSS driving S-Video */
 static struct regulator_init_data omap3_evm_vdac = {
@@ -560,8 +560,10 @@ static struct regulator_init_data omap3_evm_vdac = {
 };
 
 /* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply omap3_evm_vpll2_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply omap3_evm_vpll2_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data omap3_evm_vpll2 = {
        .constraints = {
@@ -573,8 +575,8 @@ static struct regulator_init_data omap3_evm_vpll2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &omap3_evm_vpll2_supply,
+       .num_consumer_supplies  = ARRAY_SIZE(omap3_evm_vpll2_supplies),
+       .consumer_supplies      = omap3_evm_vpll2_supplies,
 };
 
 /* ads7846 on SPI */
index 2e5dc21e3477b20e4399767f5cea265a5e33cf5c..07dba888f4502b4a4beb18389c56034439633e0f 100644 (file)
@@ -342,11 +342,12 @@ static struct regulator_consumer_supply pandora_vmmc3_supply =
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2");
 
 static struct regulator_consumer_supply pandora_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_consumer_supply pandora_vdds_supplies[] = {
        REGULATOR_SUPPLY("vdds_sdi", "omapdss"),
        REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
 };
 
 static struct regulator_consumer_supply pandora_vcc_lcd_supply =
index 8ebdbc38b9de89b253180d9d06d035dfa7262f9b..a6e0b9161c99ceac2b98122f7a5f78955bbf4c53 100644 (file)
@@ -439,7 +439,7 @@ static struct twl4030_codec_data omap3stalker_codec_data = {
 };
 
 static struct regulator_consumer_supply omap3_stalker_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 /* VDAC for DSS driving S-Video */
 static struct regulator_init_data omap3_stalker_vdac = {
@@ -457,8 +457,10 @@ static struct regulator_init_data omap3_stalker_vdac = {
 };
 
 /* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply omap3_stalker_vpll2_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply omap3_stalker_vpll2_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_init_data omap3_stalker_vpll2 = {
        .constraints            = {
@@ -471,8 +473,8 @@ static struct regulator_init_data omap3_stalker_vpll2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies  = 1,
-       .consumer_supplies      = &omap3_stalker_vpll2_supply,
+       .num_consumer_supplies  = ARRAY_SIZE(omap3_stalker_vpll2_supplies),
+       .consumer_supplies      = omap3_stalker_vpll2_supplies,
 };
 
 static struct twl4030_platform_data omap3stalker_twldata = {
index 0f4d8a762a7093e6e244b33693af40cc6c25a38f..c936c6d7ded08f49e5d6b3e713656f7497cbe1ac 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <plat/display.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+#include <plat/panel-generic-dpi.h>
 #include "timer-gp.h"
 
 #include "hsmmc.h"
@@ -49,6 +51,8 @@
 #define GPIO_HUB_NRESET                62
 #define GPIO_WIFI_PMENA                43
 #define GPIO_WIFI_IRQ          53
+#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
 
 /* wl127x BT, FM, GPS connectivity chip */
 static int wl1271_gpios[] = {46, -1, -1};
@@ -407,6 +411,12 @@ static struct regulator_init_data omap4_panda_vusb = {
        },
 };
 
+static struct regulator_init_data omap4_panda_clk32kg = {
+       .constraints = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+       },
+};
+
 static struct twl4030_platform_data omap4_panda_twldata = {
        .irq_base       = TWL6030_IRQ_BASE,
        .irq_end        = TWL6030_IRQ_END,
@@ -422,6 +432,7 @@ static struct twl4030_platform_data omap4_panda_twldata = {
        .vaux1          = &omap4_panda_vaux1,
        .vaux2          = &omap4_panda_vaux2,
        .vaux3          = &omap4_panda_vaux3,
+       .clk32kg        = &omap4_panda_clk32kg,
        .usb            = &omap4_usbphy_data,
 };
 
@@ -433,6 +444,17 @@ static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
                .platform_data = &omap4_panda_twldata,
        },
 };
+
+/*
+ * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
+ * is connected as I2C slave device, and can be accessed at address 0x50
+ */
+static struct i2c_board_info __initdata panda_i2c_eeprom[] = {
+       {
+               I2C_BOARD_INFO("eeprom", 0x50),
+       },
+};
+
 static int __init omap4_panda_i2c_init(void)
 {
        /*
@@ -442,7 +464,12 @@ static int __init omap4_panda_i2c_init(void)
        omap_register_i2c_bus(1, 400, omap4_panda_i2c_boardinfo,
                        ARRAY_SIZE(omap4_panda_i2c_boardinfo));
        omap_register_i2c_bus(2, 400, NULL, 0);
-       omap_register_i2c_bus(3, 400, NULL, 0);
+       /*
+        * Bus 3 is attached to the DVI port where devices like the pico DLP
+        * projector don't work reliably with 400kHz
+        */
+       omap_register_i2c_bus(3, 100, panda_i2c_eeprom,
+                                       ARRAY_SIZE(panda_i2c_eeprom));
        omap_register_i2c_bus(4, 400, NULL, 0);
        return 0;
 }
@@ -462,6 +489,64 @@ static struct omap_board_mux board_mux[] __initdata = {
        OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
        OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
        OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+       /* gpio 0 - TFP410 PD */
+       OMAP4_MUX(KPD_COL1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE3),
+       /* dispc2_data23 */
+       OMAP4_MUX(USBB2_ULPITLL_STP, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data22 */
+       OMAP4_MUX(USBB2_ULPITLL_DIR, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data21 */
+       OMAP4_MUX(USBB2_ULPITLL_NXT, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data20 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT0, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data19 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data18 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT2, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data15 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data14 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data13 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data12 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data11 */
+       OMAP4_MUX(USBB2_ULPITLL_DAT7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data10 */
+       OMAP4_MUX(DPM_EMU3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data9 */
+       OMAP4_MUX(DPM_EMU4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data16 */
+       OMAP4_MUX(DPM_EMU5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data17 */
+       OMAP4_MUX(DPM_EMU6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_hsync */
+       OMAP4_MUX(DPM_EMU7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_pclk */
+       OMAP4_MUX(DPM_EMU8, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_vsync */
+       OMAP4_MUX(DPM_EMU9, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_de */
+       OMAP4_MUX(DPM_EMU10, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data8 */
+       OMAP4_MUX(DPM_EMU11, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data7 */
+       OMAP4_MUX(DPM_EMU12, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data6 */
+       OMAP4_MUX(DPM_EMU13, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data5 */
+       OMAP4_MUX(DPM_EMU14, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data4 */
+       OMAP4_MUX(DPM_EMU15, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data3 */
+       OMAP4_MUX(DPM_EMU16, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data2 */
+       OMAP4_MUX(DPM_EMU17, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data1 */
+       OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+       /* dispc2_data0 */
+       OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 
@@ -535,6 +620,128 @@ static inline void board_serial_init(void)
 }
 #endif
 
+/* Display DVI */
+#define PANDA_DVI_TFP410_POWER_DOWN_GPIO       0
+
+static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev)
+{
+       gpio_set_value(dssdev->reset_gpio, 1);
+       return 0;
+}
+
+static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
+{
+       gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+/* Using generic display panel */
+static struct panel_generic_dpi_data omap4_dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = omap4_panda_enable_dvi,
+       .platform_disable       = omap4_panda_disable_dvi,
+};
+
+struct omap_dss_device omap4_panda_dvi_device = {
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .name                   = "dvi",
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &omap4_dvi_panel,
+       .phy.dpi.data_lines     = 24,
+       .reset_gpio             = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
+       .channel                = OMAP_DSS_CHANNEL_LCD2,
+};
+
+int __init omap4_panda_dvi_init(void)
+{
+       int r;
+
+       /* Requesting TFP410 DVI GPIO and disabling it, at bootup */
+       r = gpio_request_one(omap4_panda_dvi_device.reset_gpio,
+                               GPIOF_OUT_INIT_LOW, "DVI PD");
+       if (r)
+               pr_err("Failed to get DVI powerdown GPIO\n");
+
+       return r;
+}
+
+
+static void omap4_panda_hdmi_mux_init(void)
+{
+       /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+       omap_mux_init_signal("hdmi_hpd",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_cec",
+                       OMAP_PIN_INPUT_PULLUP);
+       /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+       omap_mux_init_signal("hdmi_ddc_scl",
+                       OMAP_PIN_INPUT_PULLUP);
+       omap_mux_init_signal("hdmi_ddc_sda",
+                       OMAP_PIN_INPUT_PULLUP);
+}
+
+static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+       int status;
+
+       status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
+                                                       "hdmi_gpio_hpd");
+       if (status) {
+               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
+               return status;
+       }
+       status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
+                                                       "hdmi_gpio_ls_oe");
+       if (status) {
+               pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
+               goto error1;
+       }
+
+       return 0;
+
+error1:
+       gpio_free(HDMI_GPIO_HPD);
+
+       return status;
+}
+
+static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+       gpio_free(HDMI_GPIO_LS_OE);
+       gpio_free(HDMI_GPIO_HPD);
+}
+
+static struct omap_dss_device  omap4_panda_hdmi_device = {
+       .name = "hdmi",
+       .driver_name = "hdmi_panel",
+       .type = OMAP_DISPLAY_TYPE_HDMI,
+       .platform_enable = omap4_panda_panel_enable_hdmi,
+       .platform_disable = omap4_panda_panel_disable_hdmi,
+       .channel = OMAP_DSS_CHANNEL_DIGIT,
+};
+
+static struct omap_dss_device *omap4_panda_dss_devices[] = {
+       &omap4_panda_dvi_device,
+       &omap4_panda_hdmi_device,
+};
+
+static struct omap_dss_board_info omap4_panda_dss_data = {
+       .num_devices    = ARRAY_SIZE(omap4_panda_dss_devices),
+       .devices        = omap4_panda_dss_devices,
+       .default_device = &omap4_panda_dvi_device,
+};
+
+void omap4_panda_display_init(void)
+{
+       int r;
+
+       r = omap4_panda_dvi_init();
+       if (r)
+               pr_err("error initializing panda DVI\n");
+
+       omap4_panda_hdmi_mux_init();
+       omap_display_init(&omap4_panda_dss_data);
+}
+
 static void __init omap4_panda_init(void)
 {
        int package = OMAP_PACKAGE_CBS;
@@ -553,6 +760,7 @@ static void __init omap4_panda_init(void)
        omap4_twl6030_hsmmc_init(mmc);
        omap4_ehci_init();
        usb_musb_init(&musb_board_data);
+       omap4_panda_display_init();
 }
 
 static void __init omap4_panda_map_io(void)
index d0961945c65a1e21ad24c73248c4d11e5ec4f934..59ca33326b8c630ff789bf3f003c1b6e4ecadd68 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/platform_device.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/spi/spi.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
+#include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
 #include <mach/gpio.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
 #include <plat/nand.h>
+#include <plat/mcspi.h>
+#include <plat/mux.h>
 #include <plat/usb.h>
 
 #include "mux.h"
@@ -68,8 +74,6 @@
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 
-#include <plat/mcspi.h>
-#include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
@@ -94,16 +98,32 @@ static struct ads7846_platform_data ads7846_config = {
        .keep_vref_on           = 1,
 };
 
-static struct spi_board_info overo_spi_board_info[] __initdata = {
-       {
-               .modalias               = "ads7846",
-               .bus_num                = 1,
-               .chip_select            = 0,
-               .max_speed_hz           = 1500000,
-               .controller_data        = &ads7846_mcspi_config,
-               .irq                    = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
-               .platform_data          = &ads7846_config,
-       }
+/* fixed regulator for ads7846 */
+static struct regulator_consumer_supply ads7846_supply =
+       REGULATOR_SUPPLY("vcc", "spi1.0");
+
+static struct regulator_init_data vads7846_regulator = {
+       .constraints = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &ads7846_supply,
+};
+
+static struct fixed_voltage_config vads7846 = {
+       .supply_name            = "vads7846",
+       .microvolts             = 3300000, /* 3.3V */
+       .gpio                   = -EINVAL,
+       .startup_delay          = 0,
+       .init_data              = &vads7846_regulator,
+};
+
+static struct platform_device vads7846_device = {
+       .name           = "reg-fixed-voltage",
+       .id             = 1,
+       .dev = {
+               .platform_data = &vads7846,
+       },
 };
 
 static void __init overo_ads7846_init(void)
@@ -116,8 +136,7 @@ static void __init overo_ads7846_init(void)
                return;
        }
 
-       spi_register_board_info(overo_spi_board_info,
-                       ARRAY_SIZE(overo_spi_board_info));
+       platform_device_register(&vads7846_device);
 }
 
 #else
@@ -233,6 +252,137 @@ static inline void __init overo_init_smsc911x(void)
 static inline void __init overo_init_smsc911x(void) { return; }
 #endif
 
+/* DSS */
+static int lcd_enabled;
+static int dvi_enabled;
+
+#define OVERO_GPIO_LCD_EN 144
+#define OVERO_GPIO_LCD_BL 145
+
+static void __init overo_display_init(void)
+{
+       if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
+               gpio_export(OVERO_GPIO_LCD_EN, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_LCD_EN\n");
+
+       if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
+               gpio_export(OVERO_GPIO_LCD_BL, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_LCD_BL\n");
+}
+
+static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
+{
+       if (lcd_enabled) {
+               printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
+               return -EINVAL;
+       }
+       dvi_enabled = 1;
+
+       return 0;
+}
+
+static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
+{
+       dvi_enabled = 0;
+}
+
+static struct panel_generic_dpi_data dvi_panel = {
+       .name                   = "generic",
+       .platform_enable        = overo_panel_enable_dvi,
+       .platform_disable       = overo_panel_disable_dvi,
+};
+
+static struct omap_dss_device overo_dvi_device = {
+       .name                   = "dvi",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &dvi_panel,
+       .phy.dpi.data_lines     = 24,
+};
+
+static struct omap_dss_device overo_tv_device = {
+       .name = "tv",
+       .driver_name = "venc",
+       .type = OMAP_DISPLAY_TYPE_VENC,
+       .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
+};
+
+static int overo_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+       if (dvi_enabled) {
+               printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
+               return -EINVAL;
+       }
+
+       gpio_set_value(OVERO_GPIO_LCD_EN, 1);
+       gpio_set_value(OVERO_GPIO_LCD_BL, 1);
+       lcd_enabled = 1;
+       return 0;
+}
+
+static void overo_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+       gpio_set_value(OVERO_GPIO_LCD_EN, 0);
+       gpio_set_value(OVERO_GPIO_LCD_BL, 0);
+       lcd_enabled = 0;
+}
+
+static struct panel_generic_dpi_data lcd43_panel = {
+       .name                   = "samsung_lte430wq_f0c",
+       .platform_enable        = overo_panel_enable_lcd,
+       .platform_disable       = overo_panel_disable_lcd,
+};
+
+static struct omap_dss_device overo_lcd43_device = {
+       .name                   = "lcd43",
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .driver_name            = "generic_dpi_panel",
+       .data                   = &lcd43_panel,
+       .phy.dpi.data_lines     = 24,
+};
+
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+       defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+static struct omap_dss_device overo_lcd35_device = {
+       .type                   = OMAP_DISPLAY_TYPE_DPI,
+       .name                   = "lcd35",
+       .driver_name            = "lgphilips_lb035q02_panel",
+       .phy.dpi.data_lines     = 24,
+       .platform_enable        = overo_panel_enable_lcd,
+       .platform_disable       = overo_panel_disable_lcd,
+};
+#endif
+
+static struct omap_dss_device *overo_dss_devices[] = {
+       &overo_dvi_device,
+       &overo_tv_device,
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+       defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+       &overo_lcd35_device,
+#endif
+       &overo_lcd43_device,
+};
+
+static struct omap_dss_board_info overo_dss_data = {
+       .num_devices    = ARRAY_SIZE(overo_dss_devices),
+       .devices        = overo_dss_devices,
+       .default_device = &overo_dvi_device,
+};
+
+static struct regulator_consumer_supply overo_vdda_dac_supply =
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
+
+static struct regulator_consumer_supply overo_vdds_dsi_supply[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
+
 static struct mtd_partition overo_nand_partitions[] = {
        {
                .name           = "xloader",
@@ -323,6 +473,93 @@ static struct regulator_consumer_supply overo_vmmc1_supply = {
        .supply                 = "vmmc",
 };
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "overo:red:gpio21",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 21,
+               .active_low             = true,
+       },
+       {
+               .name                   = "overo:blue:gpio22",
+               .default_trigger        = "none",
+               .gpio                   = 22,
+               .active_low             = true,
+       },
+       {
+               .name                   = "overo:blue:COM",
+               .default_trigger        = "mmc0",
+               .gpio                   = -EINVAL,      /* gets replaced */
+               .active_low             = true,
+       },
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device gpio_leds_device = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_leds_pdata,
+       },
+};
+
+static void __init overo_init_led(void)
+{
+       platform_device_register(&gpio_leds_device);
+}
+
+#else
+static inline void __init overo_init_led(void) { return; }
+#endif
+
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static struct gpio_keys_button gpio_buttons[] = {
+       {
+               .code                   = BTN_0,
+               .gpio                   = 23,
+               .desc                   = "button0",
+               .wakeup                 = 1,
+       },
+       {
+               .code                   = BTN_1,
+               .gpio                   = 14,
+               .desc                   = "button1",
+               .wakeup                 = 1,
+       },
+};
+
+static struct gpio_keys_platform_data gpio_keys_pdata = {
+       .buttons        = gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device gpio_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_keys_pdata,
+       },
+};
+
+static void __init overo_init_keys(void)
+{
+       platform_device_register(&gpio_keys_device);
+}
+
+#else
+static inline void __init overo_init_keys(void) { return; }
+#endif
+
 static int overo_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
@@ -330,6 +567,11 @@ static int overo_twl_gpio_setup(struct device *dev,
 
        overo_vmmc1_supply.dev = mmc[0].dev;
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+       /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
+
        return 0;
 }
 
@@ -337,6 +579,7 @@ static struct twl4030_gpio_platform_data overo_gpio_data = {
        .gpio_base      = OMAP_MAX_GPIO_LINES,
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
+       .use_leds       = true,
        .setup          = overo_twl_gpio_setup,
 };
 
@@ -358,6 +601,35 @@ static struct regulator_init_data overo_vmmc1 = {
        .consumer_supplies      = &overo_vmmc1_supply,
 };
 
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data overo_vdac = {
+       .constraints = {
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &overo_vdda_dac_supply,
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_init_data overo_vpll2 = {
+       .constraints = {
+               .name                   = "VDVI",
+               .min_uV                 = 1800000,
+               .max_uV                 = 1800000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(overo_vdds_dsi_supply),
+       .consumer_supplies      = overo_vdds_dsi_supply,
+};
+
 static struct twl4030_codec_audio_data overo_audio_data;
 
 static struct twl4030_codec_data overo_codec_data = {
@@ -365,8 +637,6 @@ static struct twl4030_codec_data overo_codec_data = {
        .audio = &overo_audio_data,
 };
 
-/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
-
 static struct twl4030_platform_data overo_twldata = {
        .irq_base       = TWL4030_IRQ_BASE,
        .irq_end        = TWL4030_IRQ_END,
@@ -374,6 +644,8 @@ static struct twl4030_platform_data overo_twldata = {
        .usb            = &overo_usb_data,
        .codec          = &overo_codec_data,
        .vmmc1          = &overo_vmmc1,
+       .vdac           = &overo_vdac,
+       .vpll2          = &overo_vpll2,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
@@ -394,18 +666,38 @@ static int __init overo_i2c_init(void)
        return 0;
 }
 
-static struct platform_device overo_lcd_device = {
-       .name           = "overo_lcd",
-       .id             = -1,
-};
-
-static struct omap_lcd_config overo_lcd_config __initdata = {
-       .ctrl_name      = "internal",
+static struct spi_board_info overo_spi_board_info[] __initdata = {
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+       defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+       {
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &ads7846_mcspi_config,
+               .irq                    = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
+               .platform_data          = &ads7846_config,
+       },
+#endif
+#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
+       defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
+       {
+               .modalias               = "lgphilips_lb035q02_panel-spi",
+               .bus_num                = 1,
+               .chip_select            = 1,
+               .max_speed_hz           = 500000,
+               .mode                   = SPI_MODE_3,
+       },
+#endif
 };
 
-static struct omap_board_config_kernel overo_config[] __initdata = {
-       { OMAP_TAG_LCD,         &overo_lcd_config },
-};
+static int __init overo_spi_init(void)
+{
+       overo_ads7846_init();
+       spi_register_board_info(overo_spi_board_info,
+                       ARRAY_SIZE(overo_spi_board_info));
+       return 0;
+}
 
 static void __init overo_init_early(void)
 {
@@ -414,15 +706,10 @@ static void __init overo_init_early(void)
                                  mt46h32m32lf6_sdrc_params);
 }
 
-static struct platform_device *overo_devices[] __initdata = {
-       &overo_lcd_device,
-};
-
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
        .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
        .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
-
        .phy_reset  = true,
        .reset_gpio_port[0]  = -EINVAL,
        .reset_gpio_port[1]  = OVERO_GPIO_USBH_NRESET,
@@ -444,16 +731,18 @@ static struct omap_musb_board_data musb_board_data = {
 static void __init overo_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-       omap_board_config = overo_config;
-       omap_board_config_size = ARRAY_SIZE(overo_config);
        overo_i2c_init();
-       platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices));
+       omap_display_init(&overo_dss_data);
        omap_serial_init();
        overo_flash_init();
        usb_musb_init(&musb_board_data);
        usbhs_init(&usbhs_bdata);
+       overo_spi_init();
        overo_ads7846_init();
        overo_init_smsc911x();
+       overo_display_init();
+       overo_init_led();
+       overo_init_keys();
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index 5f1900c532ec3af00a039f34255a0bb1ca17bddb..bbcb6775a6a3006486b5d64890aca629e66e3ab3 100644 (file)
@@ -372,7 +372,7 @@ static struct regulator_consumer_supply rx51_vaux1_consumers[] = {
 };
 
 static struct regulator_consumer_supply rx51_vdac_supply[] = {
-       REGULATOR_SUPPLY("vdda_dac", "omapdss"),
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc"),
 };
 
 static struct regulator_init_data rx51_vaux1 = {
index 448ab60195d5cac1d33de96a4661668fed2e9fa2..8dee7549fbdf5330553859c0df43bfed335fcf66 100644 (file)
@@ -226,11 +226,13 @@ static struct omap2_hsmmc_info mmc[] = {
        {}      /* Terminator */
 };
 
-static struct regulator_consumer_supply zoom_vpll2_supply =
-       REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+static struct regulator_consumer_supply zoom_vpll2_supplies[] = {
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+       REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
 
 static struct regulator_consumer_supply zoom_vdda_dac_supply =
-       REGULATOR_SUPPLY("vdda_dac", "omapdss");
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc");
 
 static struct regulator_init_data zoom_vpll2 = {
        .constraints = {
@@ -241,8 +243,8 @@ static struct regulator_init_data zoom_vpll2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
-       .num_consumer_supplies          = 1,
-       .consumer_supplies              = &zoom_vpll2_supply,
+       .num_consumer_supplies          = ARRAY_SIZE(zoom_vpll2_supplies),
+       .consumer_supplies              = zoom_vpll2_supplies,
 };
 
 static struct regulator_init_data zoom_vdac = {
index b6f65d4ac97dc2df0a690e066eb86b7b96b65143..2926d028b6e906094a7b4df7fb1402951b06a479 100644 (file)
@@ -1804,10 +1804,10 @@ static struct omap_clk omap2420_clks[] = {
        CLK(NULL,       "gfx_2d_fck",   &gfx_2d_fck,    CK_242X),
        CLK(NULL,       "gfx_ick",      &gfx_ick,       CK_242X),
        /* DSS domain clocks */
-       CLK("omapdss",  "ick",          &dss_ick,       CK_242X),
-       CLK("omapdss",  "dss1_fck",     &dss1_fck,      CK_242X),
-       CLK("omapdss",  "dss2_fck",     &dss2_fck,      CK_242X),
-       CLK("omapdss",  "tv_fck",       &dss_54m_fck,   CK_242X),
+       CLK("omapdss_dss",      "ick",          &dss_ick,       CK_242X),
+       CLK("omapdss_dss",      "fck",          &dss1_fck,      CK_242X),
+       CLK("omapdss_dss",      "sys_clk",      &dss2_fck,      CK_242X),
+       CLK("omapdss_dss",      "tv_clk",       &dss_54m_fck,   CK_242X),
        /* L3 domain clocks */
        CLK(NULL,       "core_l3_ck",   &core_l3_ck,    CK_242X),
        CLK(NULL,       "ssi_fck",      &ssi_ssr_sst_fck, CK_242X),
index bba018331a711b962a5fa398eb1a36dcaf1ed809..0c79d39e3021f02f59f54ab9aedfd9e10942e44e 100644 (file)
@@ -1894,10 +1894,10 @@ static struct omap_clk omap2430_clks[] = {
        CLK(NULL,       "mdm_ick",      &mdm_ick,       CK_243X),
        CLK(NULL,       "mdm_osc_ck",   &mdm_osc_ck,    CK_243X),
        /* DSS domain clocks */
-       CLK("omapdss",  "ick",          &dss_ick,       CK_243X),
-       CLK("omapdss",  "dss1_fck",     &dss1_fck,      CK_243X),
-       CLK("omapdss",  "dss2_fck",     &dss2_fck,      CK_243X),
-       CLK("omapdss",  "tv_fck",       &dss_54m_fck,   CK_243X),
+       CLK("omapdss_dss",      "ick",          &dss_ick,       CK_243X),
+       CLK("omapdss_dss",      "fck",          &dss1_fck,      CK_243X),
+       CLK("omapdss_dss",      "sys_clk",      &dss2_fck,      CK_243X),
+       CLK("omapdss_dss",      "tv_clk",       &dss_54m_fck,   CK_243X),
        /* L3 domain clocks */
        CLK(NULL,       "core_l3_ck",   &core_l3_ck,    CK_243X),
        CLK(NULL,       "ssi_fck",      &ssi_ssr_sst_fck, CK_243X),
index fcb321a64f136bb66da780e64ea5351a6d4d6470..75b119bd9cda8cf313cf4df080e26703ddb9a498 100644 (file)
@@ -3356,13 +3356,13 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK("omap_rng", "ick",          &rng_ick,       CK_34XX | CK_36XX),
        CLK(NULL,       "sha11_ick",    &sha11_ick,     CK_34XX | CK_36XX),
        CLK(NULL,       "des1_ick",     &des1_ick,      CK_34XX | CK_36XX),
-       CLK("omapdss",  "dss1_fck",     &dss1_alwon_fck_3430es1, CK_3430ES1),
-       CLK("omapdss",  "dss1_fck",     &dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
-       CLK("omapdss",  "tv_fck",       &dss_tv_fck,    CK_3XXX),
-       CLK("omapdss",  "video_fck",    &dss_96m_fck,   CK_3XXX),
-       CLK("omapdss",  "dss2_fck",     &dss2_alwon_fck, CK_3XXX),
-       CLK("omapdss",  "ick",          &dss_ick_3430es1,       CK_3430ES1),
-       CLK("omapdss",  "ick",          &dss_ick_3430es2,       CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+       CLK("omapdss_dss",      "fck",          &dss1_alwon_fck_3430es1, CK_3430ES1),
+       CLK("omapdss_dss",      "fck",          &dss1_alwon_fck_3430es2, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+       CLK("omapdss_dss",      "tv_clk",       &dss_tv_fck,    CK_3XXX),
+       CLK("omapdss_dss",      "video_clk",    &dss_96m_fck,   CK_3XXX),
+       CLK("omapdss_dss",      "sys_clk",      &dss2_alwon_fck, CK_3XXX),
+       CLK("omapdss_dss",      "ick",          &dss_ick_3430es1,       CK_3430ES1),
+       CLK("omapdss_dss",      "ick",          &dss_ick_3430es2,       CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
        CLK(NULL,       "cam_mclk",     &cam_mclk,      CK_34XX | CK_36XX),
        CLK(NULL,       "cam_ick",      &cam_ick,       CK_34XX | CK_36XX),
        CLK(NULL,       "csi2_96m_fck", &csi2_96m_fck,  CK_34XX | CK_36XX),
index d32ed979a8da2910644599e2c4ca527af83f7562..276992d3b7fba19b8873e2ff3cae068424b441e0 100644 (file)
@@ -3114,11 +3114,16 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "dmic_sync_mux_ck",             &dmic_sync_mux_ck,      CK_443X),
        CLK(NULL,       "dmic_fck",                     &dmic_fck,      CK_443X),
        CLK(NULL,       "dsp_fck",                      &dsp_fck,       CK_443X),
-       CLK(NULL,       "dss_sys_clk",                  &dss_sys_clk,   CK_443X),
-       CLK(NULL,       "dss_tv_clk",                   &dss_tv_clk,    CK_443X),
-       CLK(NULL,       "dss_dss_clk",                  &dss_dss_clk,   CK_443X),
-       CLK(NULL,       "dss_48mhz_clk",                &dss_48mhz_clk, CK_443X),
-       CLK(NULL,       "dss_fck",                      &dss_fck,       CK_443X),
+       CLK("omapdss_dss",      "sys_clk",                      &dss_sys_clk,   CK_443X),
+       CLK("omapdss_dss",      "tv_clk",                       &dss_tv_clk,    CK_443X),
+       CLK("omapdss_dss",      "dss_clk",                      &dss_dss_clk,   CK_443X),
+       CLK("omapdss_dss",      "video_clk",                    &dss_48mhz_clk, CK_443X),
+       CLK("omapdss_dss",      "fck",                          &dss_fck,       CK_443X),
+       /*
+        * On OMAP4, DSS ick is a dummy clock; this is needed for compatibility
+        * with OMAP2/3.
+        */
+       CLK("omapdss_dss",      "ick",                          &dummy_ck,      CK_443X),
        CLK(NULL,       "efuse_ctrl_cust_fck",          &efuse_ctrl_cust_fck,   CK_443X),
        CLK(NULL,       "emif1_fck",                    &emif1_fck,     CK_443X),
        CLK(NULL,       "emif2_fck",                    &emif2_fck,     CK_443X),
index 0d2d6a9c303c5f03ef952f6721d2d88b34f77d8b..e97851492847058f36c2c9056caddc6e830bbf9a 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "mux.h"
 #include "control.h"
+#include "devices.h"
 
 #define L3_MODULES_MAX_LEN 12
 #define L3_MODULES 3
@@ -102,7 +103,7 @@ postcore_initcall(omap4_l3_init);
 
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
-static struct resource cam_resources[] = {
+static struct resource omap2cam_resources[] = {
        {
                .start          = OMAP24XX_CAMERA_BASE,
                .end            = OMAP24XX_CAMERA_BASE + 0xfff,
@@ -114,19 +115,13 @@ static struct resource cam_resources[] = {
        }
 };
 
-static struct platform_device omap_cam_device = {
+static struct platform_device omap2cam_device = {
        .name           = "omap24xxcam",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(cam_resources),
-       .resource       = cam_resources,
+       .num_resources  = ARRAY_SIZE(omap2cam_resources),
+       .resource       = omap2cam_resources,
 };
-
-static inline void omap_init_camera(void)
-{
-       platform_device_register(&omap_cam_device);
-}
-
-#elif defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
+#endif
 
 static struct resource omap3isp_resources[] = {
        {
@@ -134,11 +129,6 @@ static struct resource omap3isp_resources[] = {
                .end            = OMAP3430_ISP_END,
                .flags          = IORESOURCE_MEM,
        },
-       {
-               .start          = OMAP3430_ISP_CBUFF_BASE,
-               .end            = OMAP3430_ISP_CBUFF_END,
-               .flags          = IORESOURCE_MEM,
-       },
        {
                .start          = OMAP3430_ISP_CCP2_BASE,
                .end            = OMAP3430_ISP_CCP2_END,
@@ -175,13 +165,33 @@ static struct resource omap3isp_resources[] = {
                .flags          = IORESOURCE_MEM,
        },
        {
-               .start          = OMAP3430_ISP_CSI2A_BASE,
-               .end            = OMAP3430_ISP_CSI2A_END,
+               .start          = OMAP3430_ISP_CSI2A_REGS1_BASE,
+               .end            = OMAP3430_ISP_CSI2A_REGS1_END,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3430_ISP_CSIPHY2_BASE,
+               .end            = OMAP3430_ISP_CSIPHY2_END,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3630_ISP_CSI2A_REGS2_BASE,
+               .end            = OMAP3630_ISP_CSI2A_REGS2_END,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3630_ISP_CSI2C_REGS1_BASE,
+               .end            = OMAP3630_ISP_CSI2C_REGS1_END,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3630_ISP_CSIPHY1_BASE,
+               .end            = OMAP3630_ISP_CSIPHY1_END,
                .flags          = IORESOURCE_MEM,
        },
        {
-               .start          = OMAP3430_ISP_CSI2PHY_BASE,
-               .end            = OMAP3430_ISP_CSI2PHY_END,
+               .start          = OMAP3630_ISP_CSI2C_REGS2_BASE,
+               .end            = OMAP3630_ISP_CSI2C_REGS2_END,
                .flags          = IORESOURCE_MEM,
        },
        {
@@ -197,15 +207,19 @@ static struct platform_device omap3isp_device = {
        .resource       = omap3isp_resources,
 };
 
-static inline void omap_init_camera(void)
+int omap3_init_camera(struct isp_platform_data *pdata)
 {
-       platform_device_register(&omap3isp_device);
+       omap3isp_device.dev.platform_data = pdata;
+       return platform_device_register(&omap3isp_device);
 }
-#else
+
 static inline void omap_init_camera(void)
 {
-}
+#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
+       if (cpu_is_omap24xx())
+               platform_device_register(&omap2cam_device);
 #endif
+}
 
 struct omap_device_pm_latency omap_keyboard_latency[] = {
        {
diff --git a/arch/arm/mach-omap2/devices.h b/arch/arm/mach-omap2/devices.h
new file mode 100644 (file)
index 0000000..f61eb6e
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * arch/arm/mach-omap2/devices.h
+ *
+ * OMAP2 platform device setup/initialization
+ *
+ * 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 __ARCH_ARM_MACH_OMAP_DEVICES_H
+#define __ARCH_ARM_MACH_OMAP_DEVICES_H
+
+struct isp_platform_data;
+
+int omap3_init_camera(struct isp_platform_data *pdata);
+
+#endif
index b18db84b034979f0faa4eb744c762a904513ae0d..256d23fb79abad7a3c40f15ea7905972e780ea7b 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/err.h>
 
 #include <plat/display.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 static struct platform_device omap_display_device = {
        .name          = "omapdss",
@@ -32,9 +34,87 @@ static struct platform_device omap_display_device = {
        },
 };
 
+static struct omap_device_pm_latency omap_dss_latency[] = {
+       [0] = {
+               .deactivate_func        = omap_device_idle_hwmods,
+               .activate_func          = omap_device_enable_hwmods,
+               .flags                  = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+       },
+};
+
+/* oh_core is used for getting opt-clocks */
+static struct omap_hwmod       *oh_core;
+
+static bool opt_clock_available(const char *clk_role)
+{
+       int i;
+
+       for (i = 0; i < oh_core->opt_clks_cnt; i++) {
+               if (!strcmp(oh_core->opt_clks[i].role, clk_role))
+                       return true;
+       }
+       return false;
+}
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
        int r = 0;
+       struct omap_hwmod *oh;
+       struct omap_device *od;
+       int i;
+       struct omap_display_platform_data pdata;
+
+       /*
+        * omap: valid DSS hwmod names
+        * omap2,3,4: dss_core, dss_dispc, dss_rfbi, dss_venc
+        * omap3,4: dss_dsi1
+        * omap4: dss_dsi2, dss_hdmi
+        */
+       char *oh_name[] = { "dss_core", "dss_dispc", "dss_rfbi", "dss_venc",
+               "dss_dsi1", "dss_dsi2", "dss_hdmi" };
+       char *dev_name[] = { "omapdss_dss", "omapdss_dispc", "omapdss_rfbi",
+               "omapdss_venc", "omapdss_dsi1", "omapdss_dsi2",
+               "omapdss_hdmi" };
+       int oh_count;
+
+       memset(&pdata, 0, sizeof(pdata));
+
+       if (cpu_is_omap24xx())
+               oh_count = ARRAY_SIZE(oh_name) - 3;
+               /* last 3 hwmod dev in oh_name are not available for omap2 */
+       else if (cpu_is_omap44xx())
+               oh_count = ARRAY_SIZE(oh_name);
+       else
+               oh_count = ARRAY_SIZE(oh_name) - 2;
+               /* last 2 hwmod dev in oh_name are not available for omap3 */
+
+       /* opt_clks are always associated with dss hwmod */
+       oh_core = omap_hwmod_lookup("dss_core");
+       if (!oh_core) {
+               pr_err("Could not look up dss_core.\n");
+               return -ENODEV;
+       }
+
+       pdata.board_data = board_data;
+       pdata.board_data->get_last_off_on_transaction_id = NULL;
+       pdata.opt_clock_available = opt_clock_available;
+
+       for (i = 0; i < oh_count; i++) {
+               oh = omap_hwmod_lookup(oh_name[i]);
+               if (!oh) {
+                       pr_err("Could not look up %s\n", oh_name[i]);
+                       return -ENODEV;
+               }
+
+               od = omap_device_build(dev_name[i], -1, oh, &pdata,
+                               sizeof(struct omap_display_platform_data),
+                               omap_dss_latency,
+                               ARRAY_SIZE(omap_dss_latency), 0);
+
+               if (WARN((IS_ERR(od)), "Could not build omap_device for %s\n",
+                               oh_name[i]))
+                       return -ENODEV;
+       }
        omap_display_device.dev.platform_data = board_data;
 
        r = platform_device_register(&omap_display_device);
index 62823467163b66f0c6d58c0c3f7fbfc4ebe15ea0..8eb3ce1bbfbe3b26ab9612fb015ca366ffd6bdb0 100644 (file)
@@ -1168,11 +1168,6 @@ static struct omap_hwmod_class omap2420_dss_hwmod_class = {
        .sysc = &omap2420_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap2420_dss_irqs[] = {
-       { .irq = 25 },
-};
-
 static struct omap_hwmod_dma_info omap2420_dss_sdma_chs[] = {
        { .name = "dispc", .dma_req = 5 },
 };
@@ -1221,8 +1216,6 @@ static struct omap_hwmod omap2420_dss_core_hwmod = {
        .name           = "dss_core",
        .class          = &omap2420_dss_hwmod_class,
        .main_clk       = "dss1_fck", /* instead of dss_fck */
-       .mpu_irqs       = omap2420_dss_irqs,
-       .mpu_irqs_cnt   = ARRAY_SIZE(omap2420_dss_irqs),
        .sdma_reqs      = omap2420_dss_sdma_chs,
        .sdma_reqs_cnt  = ARRAY_SIZE(omap2420_dss_sdma_chs),
        .prcm           = {
@@ -1265,6 +1258,10 @@ static struct omap_hwmod_class omap2420_dispc_hwmod_class = {
        .sysc = &omap2420_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap2420_dispc_irqs[] = {
+       { .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap2420_dss_dispc_addrs[] = {
        {
                .pa_start       = 0x48050400,
@@ -1297,6 +1294,8 @@ static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = {
 static struct omap_hwmod omap2420_dss_dispc_hwmod = {
        .name           = "dss_dispc",
        .class          = &omap2420_dispc_hwmod_class,
+       .mpu_irqs       = omap2420_dispc_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap2420_dispc_irqs),
        .main_clk       = "dss1_fck",
        .prcm           = {
                .omap2 = {
index 0fdf2cabfb12792614453fd434cdc65acde51c6d..a860fb5024c2f602a1573d05d4a11160f06353d6 100644 (file)
@@ -1268,10 +1268,6 @@ static struct omap_hwmod_class omap2430_dss_hwmod_class = {
        .sysc = &omap2430_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap2430_dss_irqs[] = {
-       { .irq = 25 },
-};
 static struct omap_hwmod_dma_info omap2430_dss_sdma_chs[] = {
        { .name = "dispc", .dma_req = 5 },
 };
@@ -1314,8 +1310,6 @@ static struct omap_hwmod omap2430_dss_core_hwmod = {
        .name           = "dss_core",
        .class          = &omap2430_dss_hwmod_class,
        .main_clk       = "dss1_fck", /* instead of dss_fck */
-       .mpu_irqs       = omap2430_dss_irqs,
-       .mpu_irqs_cnt   = ARRAY_SIZE(omap2430_dss_irqs),
        .sdma_reqs      = omap2430_dss_sdma_chs,
        .sdma_reqs_cnt  = ARRAY_SIZE(omap2430_dss_sdma_chs),
        .prcm           = {
@@ -1358,6 +1352,10 @@ static struct omap_hwmod_class omap2430_dispc_hwmod_class = {
        .sysc = &omap2430_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap2430_dispc_irqs[] = {
+       { .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap2430_dss_dispc_addrs[] = {
        {
                .pa_start       = 0x48050400,
@@ -1384,6 +1382,8 @@ static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = {
 static struct omap_hwmod omap2430_dss_dispc_hwmod = {
        .name           = "dss_dispc",
        .class          = &omap2430_dispc_hwmod_class,
+       .mpu_irqs       = omap2430_dispc_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap2430_dispc_irqs),
        .main_clk       = "dss1_fck",
        .prcm           = {
                .omap2 = {
index c819c306693a2b69dcd62e0f56c210bf6e6bb744..b98e2dfcba28c8b7a57f228472205b9266f4464b 100644 (file)
@@ -1480,11 +1480,6 @@ static struct omap_hwmod_class omap3xxx_dss_hwmod_class = {
        .sysc = &omap3xxx_dss_sysc,
 };
 
-/* dss */
-static struct omap_hwmod_irq_info omap3xxx_dss_irqs[] = {
-       { .irq = 25 },
-};
-
 static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
        { .name = "dispc", .dma_req = 5 },
        { .name = "dsi1", .dma_req = 74 },
@@ -1548,7 +1543,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = {
 
 static struct omap_hwmod_opt_clk dss_opt_clks[] = {
        { .role = "tv_clk", .clk = "dss_tv_fck" },
-       { .role = "dssclk", .clk = "dss_96m_fck" },
+       { .role = "video_clk", .clk = "dss_96m_fck" },
        { .role = "sys_clk", .clk = "dss2_alwon_fck" },
 };
 
@@ -1556,8 +1551,6 @@ static struct omap_hwmod omap3430es1_dss_core_hwmod = {
        .name           = "dss_core",
        .class          = &omap3xxx_dss_hwmod_class,
        .main_clk       = "dss1_alwon_fck", /* instead of dss_fck */
-       .mpu_irqs       = omap3xxx_dss_irqs,
-       .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_dss_irqs),
        .sdma_reqs      = omap3xxx_dss_sdma_chs,
        .sdma_reqs_cnt  = ARRAY_SIZE(omap3xxx_dss_sdma_chs),
 
@@ -1584,8 +1577,6 @@ static struct omap_hwmod omap3xxx_dss_core_hwmod = {
        .name           = "dss_core",
        .class          = &omap3xxx_dss_hwmod_class,
        .main_clk       = "dss1_alwon_fck", /* instead of dss_fck */
-       .mpu_irqs       = omap3xxx_dss_irqs,
-       .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_dss_irqs),
        .sdma_reqs      = omap3xxx_dss_sdma_chs,
        .sdma_reqs_cnt  = ARRAY_SIZE(omap3xxx_dss_sdma_chs),
 
@@ -1631,6 +1622,10 @@ static struct omap_hwmod_class omap3xxx_dispc_hwmod_class = {
        .sysc = &omap3xxx_dispc_sysc,
 };
 
+static struct omap_hwmod_irq_info omap3xxx_dispc_irqs[] = {
+       { .irq = 25 },
+};
+
 static struct omap_hwmod_addr_space omap3xxx_dss_dispc_addrs[] = {
        {
                .pa_start       = 0x48050400,
@@ -1664,6 +1659,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = {
 static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
        .name           = "dss_dispc",
        .class          = &omap3xxx_dispc_hwmod_class,
+       .mpu_irqs       = omap3xxx_dispc_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_dispc_irqs),
        .main_clk       = "dss1_alwon_fck",
        .prcm           = {
                .omap2 = {
@@ -1689,6 +1686,10 @@ static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
        .name = "dsi",
 };
 
+static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
+       { .irq = 25 },
+};
+
 /* dss_dsi1 */
 static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
        {
@@ -1722,6 +1723,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = {
 static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
        .name           = "dss_dsi1",
        .class          = &omap3xxx_dsi_hwmod_class,
+       .mpu_irqs       = omap3xxx_dsi1_irqs,
+       .mpu_irqs_cnt   = ARRAY_SIZE(omap3xxx_dsi1_irqs),
        .main_clk       = "dss1_alwon_fck",
        .prcm           = {
                .omap2 = {
index 954682e6439966c3e9dc834290fdeb72875b1104..31c0ac4cd66a457db1cdf42ece0973df8751c1bf 100644 (file)
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
+       /* Local timers are not supprted on OMAP4430 ES1.0 */
+       if (omap_rev() == OMAP4430_REV_ES1_0)
+               return -ENXIO;
+
        evt->irq = OMAP44XX_IRQ_LOCALTIMER;
        twd_timer_setup(evt);
+       return 0;
 }
 
index e194d928cdaa89161d4ca9e4efbce6f64e6294f6..d2af73321daee0b28162280c3075f465ef9eac4f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/types.h>
 #include <linux/i2c/pcf857x.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/max1586.h>
@@ -51,8 +52,6 @@
 #include <mach/irda.h>
 #include <mach/ohci.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index 7984268508b65cf2486330fd5e1c78efcfb57530..bfca7ed2fea3be49fb63181c5a86680a71a8a8f0 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <linux/mfd/da903x.h>
 #include <linux/regulator/machine.h>
@@ -48,7 +49,6 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 #include <mach/audio.h>
 #include <mach/pxa3xx-u2d.h>
index 28f667e52ef9265dd44c4de7bac2e6cb5072c2d1..81c3c433e2d6c8dc35a99b006cad812baf1f53e7 100644 (file)
@@ -20,6 +20,7 @@
 #include <mach/hardware.h>
 #include <asm/mach/arch.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <mach/pxa27x.h>
 #include <mach/colibri.h>
@@ -27,8 +28,6 @@
 #include <mach/ohci.h>
 #include <mach/pxa27x-udc.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index 07b62a096f1757f3f4d8e44220e264074494606c..ee797397dc5bf3b8ebf06d8fa4f646350d10dc4d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/pwm_backlight.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/sysdev.h>
 
 #include <asm/irq.h>
@@ -33,8 +34,6 @@
 #include <mach/pxa27x-udc.h>
 #include <mach/pxafb.h>
 
-#include <plat/i2c.h>
-
 #include "devices.h"
 #include "generic.h"
 
index a5452a3a276d87f741c00740450557e2fb8d6251..d4e705caefea5a594a4f22a1b04dc2a67a493db9 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/gpio.h>
 #include <linux/backlight.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/io.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -45,7 +46,6 @@
 #include <asm/mach/irq.h>
 
 #include <mach/pxa25x.h>
-#include <plat/i2c.h>
 #include <mach/irda.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
index a305424a967ddb5c67f4debd20d425d458661029..0481c29a70e8b9540f3419a120c4e0ca43724856 100644 (file)
 #include <linux/mtd/partitions.h>
 #include <linux/sm501.h>
 #include <linux/smsc911x.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/csb726.h>
 #include <mach/mfp-pxa27x.h>
-#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
 #include <mach/pxa2xx-regs.h>
index 4c766e3b4af3174c716cbe6a5233ebf928f0bb80..c4bf08b3eb610b477c91d66d2df42fec4d23d26f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/spi/pxa2xx_spi.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/pmu.h>
 #include <mach/udc.h>
@@ -16,7 +17,6 @@
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <mach/hardware.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
 #include "devices.h"
index a78bb3097739573478cae0a6c69760d31c709aca..b411d7cbf5a178f8b865beed6bbdeff4a57cb206 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/apm-emulation.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/regulator/userspace-consumer.h>
 
 #include <media/soc_camera.h>
@@ -45,7 +46,6 @@
 #include <mach/ohci.h>
 #include <mach/mmc.h>
 #include <plat/pxa27x_keypad.h>
-#include <plat/i2c.h>
 #include <mach/camera.h>
 
 #include "generic.h"
index 87cec0abe5b0a3df211c7e9465adce9017ce8492..93f05e024313340b17e40778848cff4d2b839b0c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds-lp3944.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <media/soc_camera.h>
 
@@ -30,7 +31,6 @@
 #include <mach/pxa27x.h>
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
-#include <plat/i2c.h>
 #include <mach/hardware.h>
 #include <plat/pxa27x_keypad.h>
 #include <mach/camera.h>
index a908e0a5f3966984a9c71bc07eae305b5aa0da83..6de0ad0eea654f7c5ef4148005b69ead76871f7b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/usb/gpio_vbus.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -42,7 +43,6 @@
 
 #include <mach/pxa27x.h>
 #include <mach/hx4700.h>
-#include <plat/i2c.h>
 #include <mach/irda.h>
 
 #include <video/platform_lcd.h>
index ccb7bfad17ca94e7dddd15eea58ed0a3629175b8..87c1ed9ccd2f746a3c613a2f4361bdaa9612df13 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/leds.h>
 #include <linux/mfd/da903x.h>
 #include <linux/i2c/max732x.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -45,7 +46,6 @@
 #include <mach/mmc.h>
 #include <plat/pxa27x_keypad.h>
 #include <mach/littleton.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
 #include "generic.h"
index 41198f0dc3ac7ad2838f611ad49e458d6c8a8f86..5535991c4a3c15f8e162c35639fb350daacf6aa3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/regulator/bq24022.h>
 #include <linux/regulator/machine.h>
 #include <linux/usb/gpio_vbus.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -36,7 +37,6 @@
 #include <mach/pxa27x.h>
 #include <mach/magician.h>
 #include <mach/pxafb.h>
-#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
index d4b6f2375f2c47587aad661cab152e1998c6b01f..f9542220595a6beaaa1f9ffe1694df0971a2a3ea 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -46,7 +47,6 @@
 #include <mach/mainstone.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
index faafea3542fbb65edc795cae818cc8fb8f911e90..78d98a8607ecaf71609483a25c58f83c1718af9c 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/usb/gpio_vbus.h>
 #include <linux/regulator/max1586.h>
 #include <linux/slab.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -50,7 +51,6 @@
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
-#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
 #include <media/soc_camera.h>
index cdf7f41e2bb335d6fb4c917a76258c8c45e8094f..b5a8fd3fce04cff4f5ad83f20c285f985eeb3c7e 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/serial_8250.h>
 #include <linux/dm9000.h>
 #include <linux/gpio.h>
+#include <linux/i2c/pxa-i2c.h>
 
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
 #include <mach/pxafb.h>
index 35572c427fa8449a16cfc35e0300001b5114e9b0..72adb3ae2b43fcdd07c3f8cac01b9e6a4650120c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/power_supply.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/regulator/max1586.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -36,8 +37,6 @@
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index 90820faa711acd4ae8ec02203b9723f68f2a709f..9dbf3ccd4150c88eadfbbb4f79aa72d38c1f321a 100644 (file)
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/pwm_backlight.h>
 
 #include <media/soc_camera.h>
 
 #include <asm/gpio.h>
-#include <plat/i2c.h>
 #include <mach/camera.h>
 #include <asm/mach/map.h>
 #include <mach/pxa27x.h>
index 4f0ff1ab623d11ccbfe81968a179406f74501a46..35353af345d56d1aa6f65a2fc97339573e49e21e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 #include <linux/spi/pxa2xx_spi.h>
@@ -44,7 +45,6 @@
 #include <mach/irda.h>
 #include <mach/poodle.h>
 #include <mach/pxafb.h>
-#include <plat/i2c.h>
 
 #include <asm/hardware/scoop.h>
 #include <asm/hardware/locomo.h>
index 28b11be00b3f84b8e5efbe16878f8c3827c80bd7..1cb5d0f9723fb28ea9c5c1dabe441646c3dfcf25 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sysdev.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
@@ -32,8 +33,6 @@
 #include <mach/dma.h>
 #include <mach/smemc.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 #include "clock.h"
index 1230343d9c70d828f69ef004a17c93dbe2af7a90..f374247b8466d358fab0ed529f3b2d1704806978 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/sysdev.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach/map.h>
 #include <mach/hardware.h>
@@ -32,7 +33,6 @@
 #include <mach/dma.h>
 #include <mach/regs-intc.h>
 #include <mach/smemc.h>
-#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
index 437980f72710d2ea6b07492e771448bb680dae77..23b229bd06e9a39a66d788b6fb6bea3e5346d038 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/sysdev.h>
@@ -27,7 +28,6 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/regs-intc.h>
-#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
index 8361151be054174d85c64e96ba7403671d450767..47094188e029fb565d301dda87b6bee76f5c3dd6 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/sched.h>
 #include <linux/pwm_backlight.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
 #include <linux/lis3lv02d.h>
@@ -53,7 +54,6 @@
 #include <mach/ohci.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
-#include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 
 #include "generic.h"
index c1ca8cb467fcc354f4456331f65e4caf34fe1af3..eb83c89428ef0f9a3f22e6b822218255344ef6c2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/smc91x.h>
 #include <linux/mfd/da903x.h>
 #include <linux/mtd/mtd.h>
@@ -31,7 +32,6 @@
 #include <asm/mach/flash.h>
 
 #include <mach/pxa930.h>
-#include <plat/i2c.h>
 #include <mach/pxafb.h>
 
 #include "devices.h"
index e497922f761aaff481e96c06eb7f0889086370ca..9322fe527c7f9cb017eb537ee0db9957c06bce9e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/mfd/88pm860x.h>
 
 #include <asm/mach-types.h>
@@ -24,8 +25,6 @@
 #include <mach/mfp-pxa930.h>
 #include <mach/gpio.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 
 #define SAARB_NR_IRQS  (IRQ_BOARD_START + 40)
index b49a2c21124c4c42391d81e054bd004fe024500d..38e2c0912b9a28006ecfbc739383bec212b68d10 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -47,8 +48,6 @@
 #include <mach/sharpsl_pm.h>
 #include <mach/smemc.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index 9a14fdb83c82b3517ba522cba936fab646c3148f..cb5611daf5fe21ddc193ab3f910ab69a878fe861 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mtd/plat-ram.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/i2c/pcf857x.h>
 #include <linux/i2c/at24.h>
 #include <linux/smc91x.h>
@@ -43,7 +44,6 @@
 #include <asm/mach/flash.h>
 
 #include <mach/pxa27x.h>
-#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
index 70191a9450eb279e2b4b31b70489716e83424b5a..79f4422f12f4d13b2ae051bbb5c9828138ae1e7a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/gpio.h>
 #include <linux/mfd/88pm860x.h>
 
@@ -23,8 +24,6 @@
 
 #include <mach/pxa930.h>
 
-#include <plat/i2c.h>
-
 #include "devices.h"
 #include "generic.h"
 
index f2582ec300d9ef7311b8392ba9e532628a471c6d..5ad3807af33442a8c0812a23ea46b90ffcb0d144 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -41,7 +42,6 @@
 #include <mach/pxa25x.h>
 #include <mach/reset.h>
 #include <mach/irda.h>
-#include <plat/i2c.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/tosa_bt.h>
index 423261d63d073213c5ca0f4d01e5fa25e237f2f1..857bb2e6348661e8a3f0cfef21c4449ba25bf539 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/dm9000.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -47,7 +48,6 @@
 #include <mach/irda.h>
 #include <mach/ohci.h>
 #include <mach/smemc.h>
-#include <plat/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
index 49eeeab2368909a5d40c866d98e90e75eabccb0e..12279214c875a88f242c79dbc8fe02fdeca45ca7 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/gpio.h>
 #include <linux/jiffies.h>
 #include <linux/i2c-gpio.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/serial_8250.h>
 #include <linux/smc91x.h>
 #include <linux/pwm_backlight.h>
@@ -47,7 +48,6 @@
 #include <mach/pxa25x.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
-#include <plat/i2c.h>
 #include <mach/regs-uart.h>
 #include <mach/arcom-pcmcia.h>
 #include <mach/viper.h>
index b9b579715ff65e9e65ea2de154273435e16250fc..e709fd4592689b6f1e9c857cb668c53cbf7acb86 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ucb1400.h>
 #include <linux/ata_platform.h>
 #include <linux/regulator/max1586.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -40,8 +41,6 @@
 #include <mach/udc.h>
 #include <mach/pata_pxa.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index 51c0281c6e0a8cb8f946e443b5431fd9939953b6..f55f8f2e0db3219720e7fc5ed30b22108b8fb6ae 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/smc91x.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -26,8 +27,6 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 
-#include <plat/i2c.h>
-
 #include <mach/hardware.h>
 #include <mach/pxa2xx-regs.h>
 #include <mach/mfp-pxa25x.h>
index a323e076129e933eae1164ce7bde102d98189deb..aaf883754ef4d7d2e602dcb04bfa950d342f2adf 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
 #include <linux/regulator/machine.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -40,8 +41,6 @@
 #include <mach/mmc.h>
 #include <plat/pxa27x_keypad.h>
 
-#include <plat/i2c.h>
-
 #include "generic.h"
 #include "devices.h"
 
index b92aa3b8c4f795894b73fe4ea8e846959ffe25d3..730f51e57c17105fd2184967095b8fa78582fb6e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/apm-emulation.h>
 #include <linux/can/platform/mcp251x.h>
@@ -33,8 +34,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/i2c.h>
-
 #include <mach/pxa2xx-regs.h>
 #include <mach/regs-uart.h>
 #include <mach/ohci.h>
index 3aa73b3e33f27dd1db5747578d7eefe5a2304104..93c64d8d7de9714e52e1a37b0af18f123fd79611 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/i2c/pxa-i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/gpio.h>
 
 #include <mach/pxa300.h>
-#include <plat/i2c.h>
 #include <mach/zylonite.h>
 
 #include "generic.h"
index a01b76b7c9567978d1ef85912473c0a5d72c1748..541fa4c109ef0e800869d8640affd82ec7fe0442 100644 (file)
@@ -8,6 +8,5 @@ obj-$(CONFIG_MACH_REALVIEW_PB11MP)      += realview_pb11mp.o
 obj-$(CONFIG_MACH_REALVIEW_PB1176)     += realview_pb1176.o
 obj-$(CONFIG_MACH_REALVIEW_PBA8)       += realview_pba8.o
 obj-$(CONFIG_MACH_REALVIEW_PBX)                += realview_pbx.o
-obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
+obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
index 1c6602cf50e4dd53c8f5d8022118aca0d008968e..75dbc8791d05e5fea4df2da1407071a527f31c95 100644 (file)
@@ -51,6 +51,7 @@
 #include <mach/irqs.h>
 #include <asm/hardware/timer-sp.h>
 
+#include <plat/clcd.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
@@ -359,18 +360,19 @@ static struct clk_lookup lookups[] = {
        }
 };
 
-static int __init clk_init(void)
+void __init realview_init_early(void)
 {
+       void __iomem *sys = __io_address(REALVIEW_SYS_BASE);
+
        if (machine_is_realview_pb1176())
-               oscvco_clk.vcoreg = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET;
+               oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC0_OFFSET;
        else
-               oscvco_clk.vcoreg = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
+               oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC4_OFFSET;
 
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
-       return 0;
+       versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000);
 }
-core_initcall(clk_init);
 
 /*
  * CLCD support.
@@ -385,157 +387,6 @@ core_initcall(clk_init);
 #define SYS_CLCD_ID_SANYO_2_5  (0x07 << 8)
 #define SYS_CLCD_ID_VGA                (0x1f << 8)
 
-static struct clcd_panel vga = {
-       .mode           = {
-               .name           = "VGA",
-               .refresh        = 60,
-               .xres           = 640,
-               .yres           = 480,
-               .pixclock       = 39721,
-               .left_margin    = 40,
-               .right_margin   = 24,
-               .upper_margin   = 32,
-               .lower_margin   = 11,
-               .hsync_len      = 96,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel xvga = {
-       .mode           = {
-               .name           = "XVGA",
-               .refresh        = 60,
-               .xres           = 1024,
-               .yres           = 768,
-               .pixclock       = 15748,
-               .left_margin    = 152,
-               .right_margin   = 48,
-               .upper_margin   = 23,
-               .lower_margin   = 3,
-               .hsync_len      = 104,
-               .vsync_len      = 4,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel sanyo_3_8_in = {
-       .mode           = {
-               .name           = "Sanyo QVGA",
-               .refresh        = 116,
-               .xres           = 320,
-               .yres           = 240,
-               .pixclock       = 100000,
-               .left_margin    = 6,
-               .right_margin   = 6,
-               .upper_margin   = 5,
-               .lower_margin   = 5,
-               .hsync_len      = 6,
-               .vsync_len      = 6,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel sanyo_2_5_in = {
-       .mode           = {
-               .name           = "Sanyo QVGA Portrait",
-               .refresh        = 116,
-               .xres           = 240,
-               .yres           = 320,
-               .pixclock       = 100000,
-               .left_margin    = 20,
-               .right_margin   = 10,
-               .upper_margin   = 2,
-               .lower_margin   = 2,
-               .hsync_len      = 10,
-               .vsync_len      = 2,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel epson_2_2_in = {
-       .mode           = {
-               .name           = "Epson QCIF",
-               .refresh        = 390,
-               .xres           = 176,
-               .yres           = 220,
-               .pixclock       = 62500,
-               .left_margin    = 3,
-               .right_margin   = 2,
-               .upper_margin   = 1,
-               .lower_margin   = 0,
-               .hsync_len      = 3,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure.  Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static struct clcd_panel *realview_clcd_panel(void)
-{
-       void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
-       struct clcd_panel *vga_panel;
-       struct clcd_panel *panel;
-       u32 val;
-
-       if (machine_is_realview_eb())
-               vga_panel = &vga;
-       else
-               vga_panel = &xvga;
-
-       val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
-       if (val == SYS_CLCD_ID_SANYO_3_8)
-               panel = &sanyo_3_8_in;
-       else if (val == SYS_CLCD_ID_SANYO_2_5)
-               panel = &sanyo_2_5_in;
-       else if (val == SYS_CLCD_ID_EPSON_2_2)
-               panel = &epson_2_2_in;
-       else if (val == SYS_CLCD_ID_VGA)
-               panel = vga_panel;
-       else {
-               printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
-                       val);
-               panel = vga_panel;
-       }
-
-       return panel;
-}
-
 /*
  * Disable all display connectors on the interface module.
  */
@@ -565,56 +416,60 @@ static void realview_clcd_enable(struct clcd_fb *fb)
        writel(val, sys_clcd);
 }
 
+/*
+ * Detect which LCD panel is connected, and return the appropriate
+ * clcd_panel structure.  Note: we do not have any information on
+ * the required timings for the 8.4in panel, so we presently assume
+ * VGA timings.
+ */
 static int realview_clcd_setup(struct clcd_fb *fb)
 {
+       void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
+       const char *panel_name, *vga_panel_name;
        unsigned long framesize;
-       dma_addr_t dma;
+       u32 val;
 
-       if (machine_is_realview_eb())
+       if (machine_is_realview_eb()) {
                /* VGA, 16bpp */
                framesize = 640 * 480 * 2;
-       else
+               vga_panel_name = "VGA";
+       } else {
                /* XVGA, 16bpp */
                framesize = 1024 * 768 * 2;
-
-       fb->panel               = realview_clcd_panel();
-
-       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
-                                                   &dma, GFP_KERNEL | GFP_DMA);
-       if (!fb->fb.screen_base) {
-               printk(KERN_ERR "CLCD: unable to map framebuffer\n");
-               return -ENOMEM;
+               vga_panel_name = "XVGA";
        }
 
-       fb->fb.fix.smem_start   = dma;
-       fb->fb.fix.smem_len     = framesize;
-
-       return 0;
-}
+       val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
+       if (val == SYS_CLCD_ID_SANYO_3_8)
+               panel_name = "Sanyo TM38QV67A02A";
+       else if (val == SYS_CLCD_ID_SANYO_2_5)
+               panel_name = "Sanyo QVGA Portrait";
+       else if (val == SYS_CLCD_ID_EPSON_2_2)
+               panel_name = "Epson L2F50113T00";
+       else if (val == SYS_CLCD_ID_VGA)
+               panel_name = vga_panel_name;
+       else {
+               pr_err("CLCD: unknown LCD panel ID 0x%08x, using VGA\n", val);
+               panel_name = vga_panel_name;
+       }
 
-static int realview_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
-       return dma_mmap_writecombine(&fb->dev->dev, vma,
-                                    fb->fb.screen_base,
-                                    fb->fb.fix.smem_start,
-                                    fb->fb.fix.smem_len);
-}
+       fb->panel = versatile_clcd_get_panel(panel_name);
+       if (!fb->panel)
+               return -EINVAL;
 
-static void realview_clcd_remove(struct clcd_fb *fb)
-{
-       dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
-                             fb->fb.screen_base, fb->fb.fix.smem_start);
+       return versatile_clcd_setup_dma(fb, framesize);
 }
 
 struct clcd_board clcd_plat_data = {
        .name           = "RealView",
+       .caps           = CLCD_CAP_ALL,
        .check          = clcdfb_check,
        .decode         = clcdfb_decode,
        .disable        = realview_clcd_disable,
        .enable         = realview_clcd_enable,
        .setup          = realview_clcd_setup,
-       .mmap           = realview_clcd_mmap,
-       .remove         = realview_clcd_remove,
+       .mmap           = versatile_clcd_mmap_dma,
+       .remove         = versatile_clcd_remove_dma,
 };
 
 #ifdef CONFIG_LEDS
@@ -655,12 +510,6 @@ void realview_leds_event(led_event_t ledevt)
 }
 #endif /* CONFIG_LEDS */
 
-/*
- * The sched_clock counter
- */
-#define REFCOUNTER             (__io_address(REALVIEW_SYS_BASE) + \
-                                REALVIEW_SYS_24MHz_OFFSET)
-
 /*
  * Where is the timer (VA)?
  */
@@ -676,8 +525,6 @@ void __init realview_timer_init(unsigned int timer_irq)
 {
        u32 val;
 
-       versatile_sched_clock_init(REFCOUNTER, 24000000);
-
        /* 
         * set clock frequency: 
         *      REALVIEW_REFCLK is 32KHz
index 693239ddc39e4cc15653575c9c50081cf10c9213..5c83d1e87a03bd71694578a70e3070f43cdb8569 100644 (file)
@@ -42,7 +42,6 @@ static struct amba_device name##_device = {                   \
        },                                                      \
        .dma_mask       = ~0,                                   \
        .irq            = base##_IRQ,                           \
-       /* .dma         = base##_DMA,*/                         \
 }
 
 struct machine_desc;
@@ -63,6 +62,7 @@ extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
 extern int realview_eth_register(const char *name, struct resource *res);
 extern int realview_usb_register(struct resource *res);
+extern void realview_init_early(void);
 extern void realview_fixup(struct machine_desc *mdesc, struct tag *tags,
                           char **from, struct meminfo *meminfo);
 extern void (*realview_reset)(char);
diff --git a/arch/arm/mach-realview/headsmp.S b/arch/arm/mach-realview/headsmp.S
deleted file mode 100644 (file)
index b34be45..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  linux/arch/arm/mach-realview/headsmp.S
- *
- *  Copyright (c) 2003 ARM Limited
- *  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.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-       __INIT
-
-/*
- * Realview specific entry point for secondary CPUs.  This provides
- * a "holding pen" into which all secondary cores are held until we're
- * ready for them to initialise.
- */
-ENTRY(realview_secondary_startup)
-       mrc     p15, 0, r0, c0, c0, 5
-       and     r0, r0, #15
-       adr     r4, 1f
-       ldmia   r4, {r5, r6}
-       sub     r4, r4, r5
-       add     r6, r6, r4
-pen:   ldr     r7, [r6]
-       cmp     r7, r0
-       bne     pen
-
-       /*
-        * we've been released from the holding pen: secondary_stack
-        * should now contain the SVC stack for this core
-        */
-       b       secondary_startup
-
-       .align
-1:     .long   .
-       .long   pen_release
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
deleted file mode 100644 (file)
index 60b4e11..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/arch/arm/mach-realview/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  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.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-}
index 6959d13d908a1e1242abe96e8b064b859f67ca11..23919229e12de14454945997b68941bda05e0077 100644 (file)
  */
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/io.h>
 
-#include <asm/cacheflush.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
+#include <asm/smp_scu.h>
 #include <asm/unified.h>
 
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
 #include <mach/board-pbx.h>
-#include <asm/smp_scu.h>
 
 #include "core.h"
 
-extern void realview_secondary_startup(void);
-
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int __cpuinitdata pen_release = -1;
-
-/*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
- * or not.  This is necessary for the hotplug code to work reliably.
- */
-static void __cpuinit write_pen_release(int val)
-{
-       pen_release = val;
-       smp_wmb();
-       __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
-       outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-}
+extern void versatile_secondary_startup(void);
 
 static void __iomem *scu_base_addr(void)
 {
@@ -62,75 +39,6 @@ static void __iomem *scu_base_addr(void)
                return (void __iomem *)0;
 }
 
-static DEFINE_SPINLOCK(boot_lock);
-
-void __cpuinit platform_secondary_init(unsigned int cpu)
-{
-       /*
-        * if any interrupts are already enabled for the primary
-        * core (e.g. timer irq), then they will not have been enabled
-        * for us: do so
-        */
-       gic_secondary_init(0);
-
-       /*
-        * let the primary processor know we're out of the
-        * pen, then head off into the C entry point
-        */
-       write_pen_release(-1);
-
-       /*
-        * Synchronise with the boot thread.
-        */
-       spin_lock(&boot_lock);
-       spin_unlock(&boot_lock);
-}
-
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
-{
-       unsigned long timeout;
-
-       /*
-        * set synchronisation state between this boot processor
-        * and the secondary one
-        */
-       spin_lock(&boot_lock);
-
-       /*
-        * The secondary processor is waiting to be released from
-        * the holding pen - release it, then wait for it to flag
-        * that it has been released by resetting pen_release.
-        *
-        * Note that "pen_release" is the hardware CPU ID, whereas
-        * "cpu" is Linux's internal ID.
-        */
-       write_pen_release(cpu);
-
-       /*
-        * Send the secondary CPU a soft interrupt, thereby causing
-        * the boot monitor to read the system wide flags register,
-        * and branch to the address found there.
-        */
-       smp_cross_call(cpumask_of(cpu), 1);
-
-       timeout = jiffies + (1 * HZ);
-       while (time_before(jiffies, timeout)) {
-               smp_rmb();
-               if (pen_release == -1)
-                       break;
-
-               udelay(10);
-       }
-
-       /*
-        * now the secondary core is starting up let it run its
-        * calibrations, then wait for it to finish
-        */
-       spin_unlock(&boot_lock);
-
-       return pen_release != -1 ? -ENOSYS : 0;
-}
-
 /*
  * Initialise the CPU possible map early - this describes the CPUs
  * which may be present or become present in the system.
@@ -174,6 +82,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * until it receives a soft interrupt, and then the
         * secondary CPU branches to this address.
         */
-       __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)),
+       __raw_writel(BSYM(virt_to_phys(versatile_secondary_startup)),
                     __io_address(REALVIEW_SYS_FLAGSSET));
 }
index 8ede983b861c1af616c7133420b29f052ec86682..2ecc1d94284e0a02e63ca2f54b42989b3e122cc2 100644 (file)
@@ -144,60 +144,39 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * These devices are connected via the core APB bridge
  */
 #define GPIO2_IRQ      { IRQ_EB_GPIO2, NO_IRQ }
-#define GPIO2_DMA      { 0, 0 }
 #define GPIO3_IRQ      { IRQ_EB_GPIO3, NO_IRQ }
-#define GPIO3_DMA      { 0, 0 }
 
 #define AACI_IRQ       { IRQ_EB_AACI, NO_IRQ }
-#define AACI_DMA       { 0x80, 0x81 }
 #define MMCI0_IRQ      { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
-#define MMCI0_DMA      { 0x84, 0 }
 #define KMI0_IRQ       { IRQ_EB_KMI0, NO_IRQ }
-#define KMI0_DMA       { 0, 0 }
 #define KMI1_IRQ       { IRQ_EB_KMI1, NO_IRQ }
-#define KMI1_DMA       { 0, 0 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
 #define EB_SMC_IRQ     { NO_IRQ, NO_IRQ }
-#define EB_SMC_DMA     { 0, 0 }
 #define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define MPMC_DMA       { 0, 0 }
 #define EB_CLCD_IRQ    { IRQ_EB_CLCD, NO_IRQ }
-#define EB_CLCD_DMA    { 0, 0 }
 #define DMAC_IRQ       { IRQ_EB_DMA, NO_IRQ }
-#define DMAC_DMA       { 0, 0 }
 
 /*
  * These devices are connected via the core APB bridge
  */
 #define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define SCTL_DMA       { 0, 0 }
 #define EB_WATCHDOG_IRQ        { IRQ_EB_WDOG, NO_IRQ }
-#define EB_WATCHDOG_DMA        { 0, 0 }
 #define EB_GPIO0_IRQ   { IRQ_EB_GPIO0, NO_IRQ }
-#define EB_GPIO0_DMA   { 0, 0 }
 #define GPIO1_IRQ      { IRQ_EB_GPIO1, NO_IRQ }
-#define GPIO1_DMA      { 0, 0 }
 #define EB_RTC_IRQ     { IRQ_EB_RTC, NO_IRQ }
-#define EB_RTC_DMA     { 0, 0 }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ                { IRQ_EB_SCI, NO_IRQ }
-#define SCI_DMA                { 7, 6 }
 #define EB_UART0_IRQ   { IRQ_EB_UART0, NO_IRQ }
-#define EB_UART0_DMA   { 15, 14 }
 #define EB_UART1_IRQ   { IRQ_EB_UART1, NO_IRQ }
-#define EB_UART1_DMA   { 13, 12 }
 #define EB_UART2_IRQ   { IRQ_EB_UART2, NO_IRQ }
-#define EB_UART2_DMA   { 11, 10 }
 #define EB_UART3_IRQ   { IRQ_EB_UART3, NO_IRQ }
-#define EB_UART3_DMA   { 0x86, 0x87 }
 #define EB_SSP_IRQ     { IRQ_EB_SSP, NO_IRQ }
-#define EB_SSP_DMA     { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,  "fpga:aaci",  AACI,     NULL);
@@ -487,6 +466,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
        .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_eb_map_io,
+       .init_early     = realview_init_early,
        .init_irq       = gic_init_irq,
        .timer          = &realview_eb_timer,
        .init_machine   = realview_eb_init,
index 9f26369555c75a0f13ad9ad0ca8231745909f4f9..eab6070f66d093c701d0e8c1a47ee7f77fc76b73 100644 (file)
@@ -134,47 +134,26 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * RealView PB1176 AMBA devices
  */
 #define GPIO2_IRQ      { IRQ_PB1176_GPIO2, NO_IRQ }
-#define GPIO2_DMA      { 0, 0 }
 #define GPIO3_IRQ      { IRQ_PB1176_GPIO3, NO_IRQ }
-#define GPIO3_DMA      { 0, 0 }
 #define AACI_IRQ       { IRQ_PB1176_AACI, NO_IRQ }
-#define AACI_DMA       { 0x80, 0x81 }
 #define MMCI0_IRQ      { IRQ_PB1176_MMCI0A, IRQ_PB1176_MMCI0B }
-#define MMCI0_DMA      { 0x84, 0 }
 #define KMI0_IRQ       { IRQ_PB1176_KMI0, NO_IRQ }
-#define KMI0_DMA       { 0, 0 }
 #define KMI1_IRQ       { IRQ_PB1176_KMI1, NO_IRQ }
-#define KMI1_DMA       { 0, 0 }
 #define PB1176_SMC_IRQ { NO_IRQ, NO_IRQ }
-#define PB1176_SMC_DMA { 0, 0 }
 #define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define MPMC_DMA       { 0, 0 }
 #define PB1176_CLCD_IRQ        { IRQ_DC1176_CLCD, NO_IRQ }
-#define PB1176_CLCD_DMA        { 0, 0 }
 #define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define SCTL_DMA       { 0, 0 }
 #define PB1176_WATCHDOG_IRQ    { IRQ_DC1176_WATCHDOG, NO_IRQ }
-#define PB1176_WATCHDOG_DMA    { 0, 0 }
 #define PB1176_GPIO0_IRQ       { IRQ_PB1176_GPIO0, NO_IRQ }
-#define PB1176_GPIO0_DMA       { 0, 0 }
 #define GPIO1_IRQ      { IRQ_PB1176_GPIO1, NO_IRQ }
-#define GPIO1_DMA      { 0, 0 }
 #define PB1176_RTC_IRQ { IRQ_DC1176_RTC, NO_IRQ }
-#define PB1176_RTC_DMA { 0, 0 }
 #define SCI_IRQ                { IRQ_PB1176_SCI, NO_IRQ }
-#define SCI_DMA                { 7, 6 }
 #define PB1176_UART0_IRQ       { IRQ_DC1176_UART0, NO_IRQ }
-#define PB1176_UART0_DMA       { 15, 14 }
 #define PB1176_UART1_IRQ       { IRQ_DC1176_UART1, NO_IRQ }
-#define PB1176_UART1_DMA       { 13, 12 }
 #define PB1176_UART2_IRQ       { IRQ_DC1176_UART2, NO_IRQ }
-#define PB1176_UART2_DMA       { 11, 10 }
 #define PB1176_UART3_IRQ       { IRQ_DC1176_UART3, NO_IRQ }
-#define PB1176_UART3_DMA       { 0x86, 0x87 }
 #define PB1176_UART4_IRQ       { IRQ_PB1176_UART4, NO_IRQ }
-#define PB1176_UART4_DMA       { 0, 0 }
 #define PB1176_SSP_IRQ         { IRQ_DC1176_SSP, NO_IRQ }
-#define PB1176_SSP_DMA         { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
@@ -382,6 +361,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
        .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
        .fixup          = realview_pb1176_fixup,
        .map_io         = realview_pb1176_map_io,
+       .init_early     = realview_init_early,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pb1176_timer,
        .init_machine   = realview_pb1176_init,
index dea06b2da3a287e9e6ed254880caef0ee47e3d96..b2985fc7cd4e4f22e521365fda110c78b924a7a7 100644 (file)
@@ -136,47 +136,26 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  */
 
 #define GPIO2_IRQ              { IRQ_PB11MP_GPIO2, NO_IRQ }
-#define GPIO2_DMA              { 0, 0 }
 #define GPIO3_IRQ              { IRQ_PB11MP_GPIO3, NO_IRQ }
-#define GPIO3_DMA              { 0, 0 }
 #define AACI_IRQ               { IRQ_TC11MP_AACI, NO_IRQ }
-#define AACI_DMA               { 0x80, 0x81 }
 #define MMCI0_IRQ              { IRQ_TC11MP_MMCI0A, IRQ_TC11MP_MMCI0B }
-#define MMCI0_DMA              { 0x84, 0 }
 #define KMI0_IRQ               { IRQ_TC11MP_KMI0, NO_IRQ }
-#define KMI0_DMA               { 0, 0 }
 #define KMI1_IRQ               { IRQ_TC11MP_KMI1, NO_IRQ }
-#define KMI1_DMA               { 0, 0 }
 #define PB11MP_SMC_IRQ         { NO_IRQ, NO_IRQ }
-#define PB11MP_SMC_DMA         { 0, 0 }
 #define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define MPMC_DMA               { 0, 0 }
 #define PB11MP_CLCD_IRQ                { IRQ_PB11MP_CLCD, NO_IRQ }
-#define PB11MP_CLCD_DMA                { 0, 0 }
 #define DMAC_IRQ               { IRQ_PB11MP_DMAC, NO_IRQ }
-#define DMAC_DMA               { 0, 0 }
 #define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define SCTL_DMA               { 0, 0 }
 #define PB11MP_WATCHDOG_IRQ    { IRQ_PB11MP_WATCHDOG, NO_IRQ }
-#define PB11MP_WATCHDOG_DMA    { 0, 0 }
 #define PB11MP_GPIO0_IRQ       { IRQ_PB11MP_GPIO0, NO_IRQ }
-#define PB11MP_GPIO0_DMA       { 0, 0 }
 #define GPIO1_IRQ              { IRQ_PB11MP_GPIO1, NO_IRQ }
-#define GPIO1_DMA              { 0, 0 }
 #define PB11MP_RTC_IRQ         { IRQ_TC11MP_RTC, NO_IRQ }
-#define PB11MP_RTC_DMA         { 0, 0 }
 #define SCI_IRQ                        { IRQ_PB11MP_SCI, NO_IRQ }
-#define SCI_DMA                        { 7, 6 }
 #define PB11MP_UART0_IRQ       { IRQ_TC11MP_UART0, NO_IRQ }
-#define PB11MP_UART0_DMA       { 15, 14 }
 #define PB11MP_UART1_IRQ       { IRQ_TC11MP_UART1, NO_IRQ }
-#define PB11MP_UART1_DMA       { 13, 12 }
 #define PB11MP_UART2_IRQ       { IRQ_PB11MP_UART2, NO_IRQ }
-#define PB11MP_UART2_DMA       { 11, 10 }
 #define PB11MP_UART3_IRQ       { IRQ_PB11MP_UART3, NO_IRQ }
-#define PB11MP_UART3_DMA       { 0x86, 0x87 }
 #define PB11MP_SSP_IRQ         { IRQ_PB11MP_SSP, NO_IRQ }
-#define PB11MP_SSP_DMA         { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
@@ -384,6 +363,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
        .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_pb11mp_map_io,
+       .init_early     = realview_init_early,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pb11mp_timer,
        .init_machine   = realview_pb11mp_init,
index 7d0f1734a2178a1681c7d41b61ead5e367d8e19b..fb686655876023464fa7af1256f96ccc993f0c4d 100644 (file)
@@ -126,47 +126,26 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  */
 
 #define GPIO2_IRQ              { IRQ_PBA8_GPIO2, NO_IRQ }
-#define GPIO2_DMA              { 0, 0 }
 #define GPIO3_IRQ              { IRQ_PBA8_GPIO3, NO_IRQ }
-#define GPIO3_DMA              { 0, 0 }
 #define AACI_IRQ               { IRQ_PBA8_AACI, NO_IRQ }
-#define AACI_DMA               { 0x80, 0x81 }
 #define MMCI0_IRQ              { IRQ_PBA8_MMCI0A, IRQ_PBA8_MMCI0B }
-#define MMCI0_DMA              { 0x84, 0 }
 #define KMI0_IRQ               { IRQ_PBA8_KMI0, NO_IRQ }
-#define KMI0_DMA               { 0, 0 }
 #define KMI1_IRQ               { IRQ_PBA8_KMI1, NO_IRQ }
-#define KMI1_DMA               { 0, 0 }
 #define PBA8_SMC_IRQ           { NO_IRQ, NO_IRQ }
-#define PBA8_SMC_DMA           { 0, 0 }
 #define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define MPMC_DMA               { 0, 0 }
 #define PBA8_CLCD_IRQ          { IRQ_PBA8_CLCD, NO_IRQ }
-#define PBA8_CLCD_DMA          { 0, 0 }
 #define DMAC_IRQ               { IRQ_PBA8_DMAC, NO_IRQ }
-#define DMAC_DMA               { 0, 0 }
 #define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define SCTL_DMA               { 0, 0 }
 #define PBA8_WATCHDOG_IRQ      { IRQ_PBA8_WATCHDOG, NO_IRQ }
-#define PBA8_WATCHDOG_DMA      { 0, 0 }
 #define PBA8_GPIO0_IRQ         { IRQ_PBA8_GPIO0, NO_IRQ }
-#define PBA8_GPIO0_DMA         { 0, 0 }
 #define GPIO1_IRQ              { IRQ_PBA8_GPIO1, NO_IRQ }
-#define GPIO1_DMA              { 0, 0 }
 #define PBA8_RTC_IRQ           { IRQ_PBA8_RTC, NO_IRQ }
-#define PBA8_RTC_DMA           { 0, 0 }
 #define SCI_IRQ                        { IRQ_PBA8_SCI, NO_IRQ }
-#define SCI_DMA                        { 7, 6 }
 #define PBA8_UART0_IRQ         { IRQ_PBA8_UART0, NO_IRQ }
-#define PBA8_UART0_DMA         { 15, 14 }
 #define PBA8_UART1_IRQ         { IRQ_PBA8_UART1, NO_IRQ }
-#define PBA8_UART1_DMA         { 13, 12 }
 #define PBA8_UART2_IRQ         { IRQ_PBA8_UART2, NO_IRQ }
-#define PBA8_UART2_DMA         { 11, 10 }
 #define PBA8_UART3_IRQ         { IRQ_PBA8_UART3, NO_IRQ }
-#define PBA8_UART3_DMA         { 0x86, 0x87 }
 #define PBA8_SSP_IRQ           { IRQ_PBA8_SSP, NO_IRQ }
-#define PBA8_SSP_DMA           { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
@@ -334,6 +313,7 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
        .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_pba8_map_io,
+       .init_early     = realview_init_early,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pba8_timer,
        .init_machine   = realview_pba8_init,
index b89e28f8853eb27ec5943cc51e7c853f504de2b9..92ace2cf2b2c6963dcf55bf360a87146c6e8193e 100644 (file)
@@ -148,47 +148,26 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  */
 
 #define GPIO2_IRQ              { IRQ_PBX_GPIO2, NO_IRQ }
-#define GPIO2_DMA              { 0, 0 }
 #define GPIO3_IRQ              { IRQ_PBX_GPIO3, NO_IRQ }
-#define GPIO3_DMA              { 0, 0 }
 #define AACI_IRQ               { IRQ_PBX_AACI, NO_IRQ }
-#define AACI_DMA               { 0x80, 0x81 }
 #define MMCI0_IRQ              { IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
-#define MMCI0_DMA              { 0x84, 0 }
 #define KMI0_IRQ               { IRQ_PBX_KMI0, NO_IRQ }
-#define KMI0_DMA               { 0, 0 }
 #define KMI1_IRQ               { IRQ_PBX_KMI1, NO_IRQ }
-#define KMI1_DMA               { 0, 0 }
 #define PBX_SMC_IRQ            { NO_IRQ, NO_IRQ }
-#define PBX_SMC_DMA            { 0, 0 }
 #define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define MPMC_DMA               { 0, 0 }
 #define PBX_CLCD_IRQ           { IRQ_PBX_CLCD, NO_IRQ }
-#define PBX_CLCD_DMA           { 0, 0 }
 #define DMAC_IRQ               { IRQ_PBX_DMAC, NO_IRQ }
-#define DMAC_DMA               { 0, 0 }
 #define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define SCTL_DMA               { 0, 0 }
 #define PBX_WATCHDOG_IRQ       { IRQ_PBX_WATCHDOG, NO_IRQ }
-#define PBX_WATCHDOG_DMA       { 0, 0 }
 #define PBX_GPIO0_IRQ          { IRQ_PBX_GPIO0, NO_IRQ }
-#define PBX_GPIO0_DMA          { 0, 0 }
 #define GPIO1_IRQ              { IRQ_PBX_GPIO1, NO_IRQ }
-#define GPIO1_DMA              { 0, 0 }
 #define PBX_RTC_IRQ            { IRQ_PBX_RTC, NO_IRQ }
-#define PBX_RTC_DMA            { 0, 0 }
 #define SCI_IRQ                        { IRQ_PBX_SCI, NO_IRQ }
-#define SCI_DMA                        { 7, 6 }
 #define PBX_UART0_IRQ          { IRQ_PBX_UART0, NO_IRQ }
-#define PBX_UART0_DMA          { 15, 14 }
 #define PBX_UART1_IRQ          { IRQ_PBX_UART1, NO_IRQ }
-#define PBX_UART1_DMA          { 13, 12 }
 #define PBX_UART2_IRQ          { IRQ_PBX_UART2, NO_IRQ }
-#define PBX_UART2_DMA          { 11, 10 }
 #define PBX_UART3_IRQ          { IRQ_PBX_UART3, NO_IRQ }
-#define PBX_UART3_DMA          { 0x86, 0x87 }
 #define PBX_SSP_IRQ            { IRQ_PBX_SSP, NO_IRQ }
-#define PBX_SSP_DMA            { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
@@ -417,6 +396,7 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
        .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
        .fixup          = realview_pbx_fixup,
        .map_io         = realview_pbx_map_io,
+       .init_early     = realview_init_early,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pbx_timer,
        .init_machine   = realview_pbx_init,
index 6b86a722a7db22343f4bf8226f680964c7620ff7..2c126bbca08da168f8c7d4fc76285dd141a27ba3 100644 (file)
 #include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/rfkill.h>
+#include <linux/leds.h>
 
 #include <mach/regs-gpio.h>
 #include <mach/hardware.h>
 #include <mach/h1940-latch.h>
+#include <mach/h1940.h>
 
-#define DRV_NAME              "h1940-bt"
+#define DRV_NAME "h1940-bt"
 
 /* Bluetooth control */
 static void h1940bt_enable(int on)
@@ -37,6 +39,8 @@ static void h1940bt_enable(int on)
                gpio_set_value(S3C2410_GPH(1), 1);
                mdelay(10);
                gpio_set_value(S3C2410_GPH(1), 0);
+
+               h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
        }
        else {
                gpio_set_value(S3C2410_GPH(1), 1);
@@ -44,6 +48,8 @@ static void h1940bt_enable(int on)
                gpio_set_value(S3C2410_GPH(1), 0);
                mdelay(10);
                gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
+
+               h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
        }
 }
 
@@ -85,7 +91,6 @@ static int __devinit h1940bt_probe(struct platform_device *pdev)
        s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
        s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
 
-
        rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
                        &h1940bt_rfkill_ops, NULL);
        if (!rfk) {
@@ -93,8 +98,6 @@ static int __devinit h1940bt_probe(struct platform_device *pdev)
                goto err_rfk_alloc;
        }
 
-       rfkill_set_led_trigger_name(rfk, "h1940-bluetooth");
-
        ret = rfkill_register(rfk);
        if (ret)
                goto err_rfkill;
index 4559784129c0ca13cc761b2f4d2421835f817746..2aa683c8d3d675f60bb5f082e493f2dda759beef 100644 (file)
@@ -17,5 +17,8 @@
 #define H1940_SUSPEND_CHECK            (0x30080000)
 
 extern void h1940_pm_return(void);
+extern int h1940_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off);
+
 
 #endif /* __ASM_ARCH_H1940_H */
index 1e93f176c1de8ebe0d9bd9231f109630bc8cb70a..2a2fa0620133cdee7086e44034764e703bfefd2a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
 #include <linux/pwm_backlight.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/pda_power.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/delay.h>
+
 #include <video/platform_lcd.h>
 
 #include <linux/mmc/host.h>
@@ -203,20 +210,239 @@ static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
        .num_displays = 1,
        .default_display = 0,
 
-       .lpcsel       0x02,
-       .gpccon       0xaa940659,
-       .gpccon_mask=   0xffffffff,
-       .gpcup        0x0000ffff,
-       .gpcup_mask   0xffffffff,
-       .gpdcon       0xaa84aaa0,
-       .gpdcon_mask  0xffffffff,
-       .gpdup        0x0000faff,
-       .gpdup_mask   0xffffffff,
+       .lpcsel =       0x02,
+       .gpccon =       0xaa940659,
+       .gpccon_mask =  0xffffc0f0,
+       .gpcup =        0x0000ffff,
+       .gpcup_mask =   0xffffffff,
+       .gpdcon =       0xaa84aaa0,
+       .gpdcon_mask =  0xffffffff,
+       .gpdup =        0x0000faff,
+       .gpdup_mask =   0xffffffff,
 };
 
-static struct platform_device h1940_device_leds = {
-       .name             = "h1940-leds",
+static int power_supply_init(struct device *dev)
+{
+       return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int h1940_is_ac_online(void)
+{
+       return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+       gpio_free(S3C2410_GPF(2));
+}
+
+static char *h1940_supplicants[] = {
+       "main-battery",
+       "backup-battery",
+};
+
+static struct pda_power_pdata power_supply_info = {
+       .init                   = power_supply_init,
+       .is_ac_online           = h1940_is_ac_online,
+       .exit                   = power_supply_exit,
+       .supplied_to            = h1940_supplicants,
+       .num_supplicants        = ARRAY_SIZE(h1940_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+       [0] = {
+                       .name   = "ac",
+                       .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+                                         IORESOURCE_IRQ_HIGHEDGE,
+                       .start  = IRQ_EINT2,
+                       .end    = IRQ_EINT2,
+       },
+};
+
+static struct platform_device power_supply = {
+       .name           = "pda-power",
+       .id             = -1,
+       .dev            = {
+                               .platform_data =
+                                       &power_supply_info,
+       },
+       .resource       = power_supply_resources,
+       .num_resources  = ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+       { .volt = 4070, .cur = 162, .level = 100},
+       { .volt = 4040, .cur = 165, .level = 95},
+       { .volt = 4016, .cur = 164, .level = 90},
+       { .volt = 3996, .cur = 166, .level = 85},
+       { .volt = 3971, .cur = 168, .level = 80},
+       { .volt = 3951, .cur = 168, .level = 75},
+       { .volt = 3931, .cur = 170, .level = 70},
+       { .volt = 3903, .cur = 172, .level = 65},
+       { .volt = 3886, .cur = 172, .level = 60},
+       { .volt = 3858, .cur = 176, .level = 55},
+       { .volt = 3842, .cur = 176, .level = 50},
+       { .volt = 3818, .cur = 176, .level = 45},
+       { .volt = 3789, .cur = 180, .level = 40},
+       { .volt = 3769, .cur = 180, .level = 35},
+       { .volt = 3749, .cur = 184, .level = 30},
+       { .volt = 3732, .cur = 184, .level = 25},
+       { .volt = 3716, .cur = 184, .level = 20},
+       { .volt = 3708, .cur = 184, .level = 15},
+       { .volt = 3716, .cur = 96, .level = 10},
+       { .volt = 3700, .cur = 96, .level = 5},
+       { .volt = 3684, .cur = 96, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+       { .volt = 4130, .cur = 0, .level = 100},
+       { .volt = 3982, .cur = 0, .level = 50},
+       { .volt = 3854, .cur = 0, .level = 10},
+       { .volt = 3841, .cur = 0, .level = 0},
+};
+
+int h1940_bat_init(void)
+{
+       int ret;
+
+       ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable");
+       if (ret)
+               return ret;
+       gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0);
+
+       return 0;
+
+}
+
+void h1940_bat_exit(void)
+{
+       gpio_free(H1940_LATCH_SM803_ENABLE);
+}
+
+void h1940_enable_charger(void)
+{
+       gpio_set_value(H1940_LATCH_SM803_ENABLE, 1);
+}
+
+void h1940_disable_charger(void)
+{
+       gpio_set_value(H1940_LATCH_SM803_ENABLE, 0);
+}
+
+static struct s3c_adc_bat_pdata h1940_bat_cfg = {
+       .init = h1940_bat_init,
+       .exit = h1940_bat_exit,
+       .enable_charger = h1940_enable_charger,
+       .disable_charger = h1940_disable_charger,
+       .gpio_charge_finished = S3C2410_GPF(3),
+       .gpio_inverted = 1,
+       .lut_noac = bat_lut_noac,
+       .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+       .lut_acin = bat_lut_acin,
+       .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+       .volt_channel = 0,
+       .current_channel = 1,
+       .volt_mult = 4056,
+       .current_mult = 1893,
+       .internal_impedance = 200,
+       .backup_volt_channel = 3,
+       /* TODO Check backup volt multiplier */
+       .backup_volt_mult = 4056,
+       .backup_volt_min = 0,
+       .backup_volt_max = 4149288
+};
+
+static struct platform_device h1940_battery = {
+       .name             = "s3c-adc-battery",
        .id               = -1,
+       .dev = {
+               .parent = &s3c_device_adc.dev,
+               .platform_data = &h1940_bat_cfg,
+       },
+};
+
+DEFINE_SPINLOCK(h1940_blink_spin);
+
+int h1940_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off)
+{
+       int blink_gpio, check_gpio1, check_gpio2;
+
+       switch (gpio) {
+       case H1940_LATCH_LED_GREEN:
+               blink_gpio = S3C2410_GPA(7);
+               check_gpio1 = S3C2410_GPA(1);
+               check_gpio2 = S3C2410_GPA(3);
+               break;
+       case H1940_LATCH_LED_RED:
+               blink_gpio = S3C2410_GPA(1);
+               check_gpio1 = S3C2410_GPA(7);
+               check_gpio2 = S3C2410_GPA(3);
+               break;
+       default:
+               blink_gpio = S3C2410_GPA(3);
+               check_gpio1 = S3C2410_GPA(1);
+               check_gpio1 = S3C2410_GPA(7);
+               break;
+       }
+
+       if (delay_on && delay_off && !*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       spin_lock(&h1940_blink_spin);
+
+       switch (state) {
+       case GPIO_LED_NO_BLINK_LOW:
+       case GPIO_LED_NO_BLINK_HIGH:
+               if (!gpio_get_value(check_gpio1) &&
+                   !gpio_get_value(check_gpio2))
+                       gpio_set_value(H1940_LATCH_LED_FLASH, 0);
+               gpio_set_value(blink_gpio, 0);
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, state);
+               break;
+       case GPIO_LED_BLINK:
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, 0);
+               gpio_set_value(H1940_LATCH_LED_FLASH, 1);
+               gpio_set_value(blink_gpio, 1);
+               break;
+       }
+
+       spin_unlock(&h1940_blink_spin);
+
+       return 0;
+}
+EXPORT_SYMBOL(h1940_led_blink_set);
+
+static struct gpio_led h1940_leds_desc[] = {
+       {
+               .name                   = "Green",
+               .default_trigger        = "main-battery-full",
+               .gpio                   = H1940_LATCH_LED_GREEN,
+               .retain_state_suspended = 1,
+       },
+       {
+               .name                   = "Red",
+               .default_trigger
+                       = "main-battery-charging-blink-full-solid",
+               .gpio                   = H1940_LATCH_LED_RED,
+               .retain_state_suspended = 1,
+       },
+};
+
+static struct gpio_led_platform_data h1940_leds_pdata = {
+       .num_leds       = ARRAY_SIZE(h1940_leds_desc),
+       .leds           = h1940_leds_desc,
+       .gpio_blink_set = h1940_led_blink_set,
+};
+
+static struct platform_device h1940_device_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+                       .platform_data = &h1940_leds_pdata,
+       },
 };
 
 static struct platform_device h1940_device_bluetooth = {
@@ -302,14 +528,14 @@ static struct platform_device h1940_backlight = {
 static void h1940_lcd_power_set(struct plat_lcd_data *pd,
                                        unsigned int power)
 {
-       int value;
+       int value, retries = 100;
 
        if (!power) {
                gpio_set_value(S3C2410_GPC(0), 0);
                /* wait for 3ac */
                do {
                        value = gpio_get_value(S3C2410_GPC(6));
-               } while (value);
+               } while (value && retries--);
 
                gpio_set_value(H1940_LATCH_LCD_P2, 0);
                gpio_set_value(H1940_LATCH_LCD_P3, 0);
@@ -327,6 +553,9 @@ static void h1940_lcd_power_set(struct plat_lcd_data *pd,
                gpio_set_value(H1940_LATCH_LCD_P0, 1);
                gpio_set_value(H1940_LATCH_LCD_P1, 1);
 
+               gpio_direction_input(S3C2410_GPC(1));
+               gpio_direction_input(S3C2410_GPC(4));
+               mdelay(10);
                s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
                s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
 
@@ -362,7 +591,44 @@ static struct i2c_board_info h1940_i2c_devices[] = {
        },
 };
 
+#define DECLARE_BUTTON(p, k, n, w)     \
+       {                               \
+               .gpio           = p,    \
+               .code           = k,    \
+               .desc           = n,    \
+               .wakeup         = w,    \
+               .active_low     = 1,    \
+       }
+
+static struct gpio_keys_button h1940_buttons[] = {
+       DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1),
+       DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1),
+       DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0),
+       DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0),
+       DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0),
+       DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0),
+       DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0),
+       DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0),
+};
+
+static struct gpio_keys_platform_data h1940_buttons_data = {
+       .buttons        = h1940_buttons,
+       .nbuttons       = ARRAY_SIZE(h1940_buttons),
+};
+
+static struct platform_device h1940_dev_buttons = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &h1940_buttons_data,
+       }
+};
+
 static struct platform_device *h1940_devices[] __initdata = {
+       &h1940_dev_buttons,
        &s3c_device_ohci,
        &s3c_device_lcd,
        &s3c_device_wdt,
@@ -379,6 +645,8 @@ static struct platform_device *h1940_devices[] __initdata = {
        &h1940_lcd_powerdev,
        &s3c_device_adc,
        &s3c_device_ts,
+       &power_supply,
+       &h1940_battery,
 };
 
 static void __init h1940_map_io(void)
@@ -461,6 +729,15 @@ static void __init h1940_init(void)
 
        platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
 
+       gpio_request(S3C2410_GPA(1), "Red LED blink");
+       gpio_request(S3C2410_GPA(3), "Blue LED blink");
+       gpio_request(S3C2410_GPA(7), "Green LED blink");
+       gpio_request(H1940_LATCH_LED_FLASH, "LED blink");
+       gpio_direction_output(S3C2410_GPA(1), 0);
+       gpio_direction_output(S3C2410_GPA(3), 0);
+       gpio_direction_output(S3C2410_GPA(7), 0);
+       gpio_direction_output(H1940_LATCH_LED_FLASH, 0);
+
        i2c_register_board_info(0, h1940_i2c_devices,
                ARRAY_SIZE(h1940_i2c_devices));
 }
index d80f129bca94bdec20618dc4d91603aeabc79cf8..dfedc9c9e0054db295e8a7815c3eb257b1e093d5 100644 (file)
@@ -488,6 +488,11 @@ static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
        },
 };
 
+static struct platform_device uda1340_codec = {
+               .name = "uda134x-codec",
+               .id = -1,
+};
+
 static struct platform_device *mini2440_devices[] __initdata = {
        &s3c_device_ohci,
        &s3c_device_wdt,
@@ -503,7 +508,9 @@ static struct platform_device *mini2440_devices[] __initdata = {
        &s3c_device_nand,
        &s3c_device_sdi,
        &s3c_device_iis,
+       &uda1340_codec,
        &mini2440_audio,
+       &samsung_asoc_dma,
 };
 
 static void __init mini2440_map_io(void)
index 86bbc233b31c7dbc18ba62e8eb4334b204d1d9d9..27ea95096fe19a33187af0e9a34e7ca58c071ea6 100644 (file)
@@ -263,27 +263,78 @@ void rx1950_disable_charger(void)
        gpio_direction_output(S3C2410_GPJ(3), 0);
 }
 
+DEFINE_SPINLOCK(rx1950_blink_spin);
+
+static int rx1950_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off)
+{
+       int blink_gpio, check_gpio;
+
+       switch (gpio) {
+       case S3C2410_GPA(6):
+               blink_gpio = S3C2410_GPA(4);
+               check_gpio = S3C2410_GPA(3);
+               break;
+       case S3C2410_GPA(7):
+               blink_gpio = S3C2410_GPA(3);
+               check_gpio = S3C2410_GPA(4);
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+
+       if (delay_on && delay_off && !*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       spin_lock(&rx1950_blink_spin);
+
+       switch (state) {
+       case GPIO_LED_NO_BLINK_LOW:
+       case GPIO_LED_NO_BLINK_HIGH:
+               if (!gpio_get_value(check_gpio))
+                       gpio_set_value(S3C2410_GPJ(6), 0);
+               gpio_set_value(blink_gpio, 0);
+               gpio_set_value(gpio, state);
+               break;
+       case GPIO_LED_BLINK:
+               gpio_set_value(gpio, 0);
+               gpio_set_value(S3C2410_GPJ(6), 1);
+               gpio_set_value(blink_gpio, 1);
+               break;
+       }
+
+       spin_unlock(&rx1950_blink_spin);
+
+       return 0;
+}
+
 static struct gpio_led rx1950_leds_desc[] = {
        {
-               .name                           = "Green",
-               .default_trigger        = "main-battery-charging-or-full",
-               .gpio                           = S3C2410_GPA(6),
+               .name                   = "Green",
+               .default_trigger        = "main-battery-full",
+               .gpio                   = S3C2410_GPA(6),
+               .retain_state_suspended = 1,
        },
        {
-               .name                           = "Red",
-               .default_trigger        = "main-battery-full",
-               .gpio                           = S3C2410_GPA(7),
+               .name                   = "Red",
+               .default_trigger
+                       = "main-battery-charging-blink-full-solid",
+               .gpio                   = S3C2410_GPA(7),
+               .retain_state_suspended = 1,
        },
        {
-               .name                           = "Blue",
+               .name                   = "Blue",
                .default_trigger        = "rx1950-acx-mem",
-               .gpio                           = S3C2410_GPA(11),
+               .gpio                   = S3C2410_GPA(11),
+               .retain_state_suspended = 1,
        },
 };
 
 static struct gpio_led_platform_data rx1950_leds_pdata = {
        .num_leds       = ARRAY_SIZE(rx1950_leds_desc),
        .leds           = rx1950_leds_desc,
+       .gpio_blink_set = rx1950_led_blink_set,
 };
 
 static struct platform_device rx1950_leds = {
@@ -752,6 +803,13 @@ static void __init rx1950_init_machine(void)
 
        WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
 
+       WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink"));
+       WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink"));
+       WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink"));
+       gpio_direction_output(S3C2410_GPA(3), 0);
+       gpio_direction_output(S3C2410_GPA(4), 0);
+       gpio_direction_output(S3C2410_GPJ(6), 0);
+
        platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
 
        i2c_register_board_info(0, rx1950_i2c_devices,
index 243291722c667484a22ec85337cc17b3f521f89e..31d5aa76975310a529084e575e0116e08a7846df 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
-#include <linux/i2c/qt602240_ts.h>
+#include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/wm8994/pdata.h>
 #include <linux/regulator/fixed.h>
@@ -25,6 +25,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -225,7 +226,7 @@ static void __init goni_radio_init(void)
 }
 
 /* TSP */
-static struct qt602240_platform_data qt602240_platform_data = {
+static struct mxt_platform_data qt602240_platform_data = {
        .x_line         = 17,
        .y_line         = 11,
        .x_size         = 800,
@@ -233,7 +234,8 @@ static struct qt602240_platform_data qt602240_platform_data = {
        .blen           = 0x21,
        .threshold      = 0x28,
        .voltage        = 2800000,              /* 2.8V */
-       .orient         = QT602240_DIAGONAL,
+       .orient         = MXT_DIAGONAL,
+       .irqflags       = IRQF_TRIGGER_FALLING,
 };
 
 static struct s3c2410_platform_i2c i2c2_data __initdata = {
index 1a8118c929be26ebee043d90bb170b8677fa0157..a94f29da5d308adaf216159fbc9184a5f1eb75b3 100644 (file)
@@ -923,7 +923,8 @@ static struct platform_device ceu_device = {
        .num_resources  = ARRAY_SIZE(ceu_resources),
        .resource       = ceu_resources,
        .dev    = {
-               .platform_data  = &sh_mobile_ceu_info,
+               .platform_data          = &sh_mobile_ceu_info,
+               .coherent_dma_mask      = 0xffffffff,
        },
 };
 
index 1a63c213e45dfa96957a00cd402fca815327fd5a..49bc07482179b3c5fd64bd1bbc14ff558de2da06 100644 (file)
@@ -295,6 +295,18 @@ static struct fb_videomode mackerel_lcdc_modes[] = {
        },
 };
 
+static int mackerel_set_brightness(void *board_data, int brightness)
+{
+       gpio_set_value(GPIO_PORT31, brightness);
+
+       return 0;
+}
+
+static int mackerel_get_brightness(void *board_data)
+{
+       return gpio_get_value(GPIO_PORT31);
+}
+
 static struct sh_mobile_lcdc_info lcdc_info = {
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
@@ -307,6 +319,14 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                .flags                  = 0,
                .lcd_size_cfg.width     = 152,
                .lcd_size_cfg.height    = 91,
+               .board_cfg = {
+                       .set_brightness = mackerel_set_brightness,
+                       .get_brightness = mackerel_get_brightness,
+               },
+               .bl_info = {
+                       .name = "sh_mobile_lcdc_bl",
+                       .max_brightness = 1,
+               },
        }
 };
 
@@ -901,7 +921,8 @@ static struct platform_device ceu_device = {
        .num_resources  = ARRAY_SIZE(ceu_resources),
        .resource       = ceu_resources,
        .dev            = {
-               .platform_data  = &sh_mobile_ceu_info,
+               .platform_data          = &sh_mobile_ceu_info,
+               .coherent_dma_mask      = 0xffffffff,
        },
 };
 
@@ -1059,7 +1080,7 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_LCDDCK,   NULL);
 
        gpio_request(GPIO_PORT31, NULL); /* backlight */
-       gpio_direction_output(GPIO_PORT31, 1);
+       gpio_direction_output(GPIO_PORT31, 0); /* off by default */
 
        gpio_request(GPIO_PORT151, NULL); /* LCDDON */
        gpio_direction_output(GPIO_PORT151, 1);
diff --git a/arch/arm/mach-shmobile/include/mach/mmc-ap4eb.h b/arch/arm/mach-shmobile/include/mach/mmc-ap4eb.h
new file mode 100644 (file)
index 0000000..db59fdb
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef MMC_AP4EB_H
+#define MMC_AP4EB_H
+
+#define PORT185CR      (void __iomem *)0xe60520b9
+#define PORT186CR      (void __iomem *)0xe60520ba
+#define PORT187CR      (void __iomem *)0xe60520bb
+#define PORT188CR      (void __iomem *)0xe60520bc
+
+#define PORTR191_160DR (void __iomem *)0xe6056014
+
+static inline void mmc_init_progress(void)
+{
+       /* Initialise LEDS1-4
+        * registers: PORT185CR-PORT188CR (LED1-LED4 Control)
+        * value:     0x10 - enable output
+        */
+       __raw_writeb(0x10, PORT185CR);
+       __raw_writeb(0x10, PORT186CR);
+       __raw_writeb(0x10, PORT187CR);
+       __raw_writeb(0x10, PORT188CR);
+}
+
+static inline void mmc_update_progress(int n)
+{
+       __raw_writel((__raw_readl(PORTR191_160DR) & ~(0xf << 25)) |
+                    (1 << (25 + n)), PORTR191_160DR);
+}
+
+#endif /* MMC_AP4EB_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmc-mackerel.h b/arch/arm/mach-shmobile/include/mach/mmc-mackerel.h
new file mode 100644 (file)
index 0000000..15d3a9e
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef MMC_MACKEREL_H
+#define MMC_MACKEREL_H
+
+#define PORT0CR      (void __iomem *)0xe6051000
+#define PORT1CR      (void __iomem *)0xe6051001
+#define PORT2CR      (void __iomem *)0xe6051002
+#define PORT159CR    (void __iomem *)0xe605009f
+
+#define PORTR031_000DR (void __iomem *)0xe6055000
+#define PORTL159_128DR (void __iomem *)0xe6054010
+
+static inline void mmc_init_progress(void)
+{
+       /* Initialise LEDS0-3
+        * registers: PORT0CR-PORT2CR,PORT159CR (LED0-LED3 Control)
+        * value:     0x10 - enable output
+        */
+       __raw_writeb(0x10, PORT0CR);
+       __raw_writeb(0x10, PORT1CR);
+       __raw_writeb(0x10, PORT2CR);
+       __raw_writeb(0x10, PORT159CR);
+}
+
+static inline void mmc_update_progress(int n)
+{
+       unsigned a = 0, b = 0;
+
+       if (n < 3)
+               a = 1 << n;
+       else
+               b = 1 << 31;
+
+       __raw_writel((__raw_readl(PORTR031_000DR) & ~0x7) | a,
+                    PORTR031_000DR);
+       __raw_writel((__raw_readl(PORTL159_128DR) & ~(1 << 31)) | b,
+                    PORTL159_128DR);
+}
+#endif /* MMC_MACKEREL_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmc.h b/arch/arm/mach-shmobile/include/mach/mmc.h
new file mode 100644 (file)
index 0000000..e11560a
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef MMC_H
+#define MMC_H
+
+/**************************************************
+ *
+ *             board specific settings
+ *
+ **************************************************/
+
+#ifdef CONFIG_MACH_AP4EVB
+#include "mach/mmc-ap4eb.h"
+#elif CONFIG_MACH_MACKEREL
+#include "mach/mmc-mackerel.h"
+#else
+#error "unsupported board."
+#endif
+
+#endif /* MMC_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h b/arch/arm/mach-shmobile/include/mach/mmcif-ap4eb.h
deleted file mode 100644 (file)
index a8d02be..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef MMCIF_AP4EB_H
-#define MMCIF_AP4EB_H
-
-#define PORT185CR      (void __iomem *)0xe60520b9
-#define PORT186CR      (void __iomem *)0xe60520ba
-#define PORT187CR      (void __iomem *)0xe60520bb
-#define PORT188CR      (void __iomem *)0xe60520bc
-
-#define PORTR191_160DR (void __iomem *)0xe6056014
-
-static inline void mmcif_init_progress(void)
-{
-       /* Initialise LEDS1-4
-        * registers: PORT185CR-PORT188CR (LED1-LED4 Control)
-        * value:     0x10 - enable output
-        */
-       __raw_writeb(0x10, PORT185CR);
-       __raw_writeb(0x10, PORT186CR);
-       __raw_writeb(0x10, PORT187CR);
-       __raw_writeb(0x10, PORT188CR);
-}
-
-static inline void mmcif_update_progress(int n)
-{
-       __raw_writel((__raw_readl(PORTR191_160DR) & ~(0xf << 25)) |
-                    (1 << (25 + n)), PORTR191_160DR);
-}
-
-#endif /* MMCIF_AP4EB_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h b/arch/arm/mach-shmobile/include/mach/mmcif-mackerel.h
deleted file mode 100644 (file)
index 4b4f694..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef MMCIF_MACKEREL_H
-#define MMCIF_MACKEREL_H
-
-#define PORT0CR      (void __iomem *)0xe6051000
-#define PORT1CR      (void __iomem *)0xe6051001
-#define PORT2CR      (void __iomem *)0xe6051002
-#define PORT159CR    (void __iomem *)0xe605009f
-
-#define PORTR031_000DR (void __iomem *)0xe6055000
-#define PORTL159_128DR (void __iomem *)0xe6054010
-
-static inline void mmcif_init_progress(void)
-{
-       /* Initialise LEDS0-3
-        * registers: PORT0CR-PORT2CR,PORT159CR (LED0-LED3 Control)
-        * value:     0x10 - enable output
-        */
-       __raw_writeb(0x10, PORT0CR);
-       __raw_writeb(0x10, PORT1CR);
-       __raw_writeb(0x10, PORT2CR);
-       __raw_writeb(0x10, PORT159CR);
-}
-
-static inline void mmcif_update_progress(int n)
-{
-       unsigned a = 0, b = 0;
-
-       if (n < 3)
-               a = 1 << n;
-       else
-               b = 1 << 31;
-
-       __raw_writel((__raw_readl(PORTR031_000DR) & ~0x7) | a,
-                    PORTR031_000DR);
-       __raw_writel((__raw_readl(PORTL159_128DR) & ~(1 << 31)) | b,
-                    PORTL159_128DR);
-}
-
-#endif /* MMCIF_MACKEREL_H */
diff --git a/arch/arm/mach-shmobile/include/mach/mmcif.h b/arch/arm/mach-shmobile/include/mach/mmcif.h
deleted file mode 100644 (file)
index f4dc327..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef MMCIF_H
-#define MMCIF_H
-
-/**************************************************
- *
- *             board specific settings
- *
- **************************************************/
-
-#ifdef CONFIG_MACH_AP4EVB
-#include "mach/mmcif-ap4eb.h"
-#elif CONFIG_MACH_MACKEREL
-#include "mach/mmcif-mackerel.h"
-#else
-#error "unsupported board."
-#endif
-
-#endif /* MMCIF_H */
index 2111c28b724e24580a4a19a08649787aa9385344..ad9ccc9900c825bf874b94ebd9fc4e2cb84576d2 100644 (file)
@@ -18,8 +18,9 @@
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
        evt->irq = 29;
        twd_timer_setup(evt);
+       return 0;
 }
index 622a9ec1ff08dcf00b086c188c773051c85a449f..3cdeffc97b4452f7e1abb34c34b02f40f25cbadf 100644 (file)
@@ -36,6 +36,11 @@ config MACH_KAEN
        help
          Support for the Kaen version of Seaboard
 
+config MACH_PAZ00
+       bool "Paz00 board"
+       help
+         Support for the Toshiba AC100/Dynabook AZ netbook
+
 config MACH_SEABOARD
        bool "Seaboard board"
        help
index 9f7a7e1e0c38356f655d6b99e047c8b3f3a4b8f1..1afe05038c27c4b47396475108d926a6a18713ad 100644 (file)
@@ -22,6 +22,10 @@ obj-$(CONFIG_USB_SUPPORT)            += usb_phy.o
 obj-${CONFIG_MACH_HARMONY}              += board-harmony.o
 obj-${CONFIG_MACH_HARMONY}              += board-harmony-pinmux.o
 obj-${CONFIG_MACH_HARMONY}              += board-harmony-pcie.o
+obj-${CONFIG_MACH_HARMONY}              += board-harmony-power.o
+
+obj-${CONFIG_MACH_PAZ00}               += board-paz00.o
+obj-${CONFIG_MACH_PAZ00}               += board-paz00-pinmux.o
 
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard-pinmux.o
index f7e7d4514b6ad7ffc28ba86bcf5377c2749b604f..9c27b95b8d869f975ae382c2eb076c6671034ba1 100644 (file)
 
 #ifdef CONFIG_TEGRA_PCI
 
+/* GPIO 3 of the PMIC */
+#define EN_VDD_1V05_GPIO       (TEGRA_NR_GPIOS + 2)
+
 static int __init harmony_pcie_init(void)
 {
+       struct regulator *regulator = NULL;
        int err;
 
        if (!machine_is_harmony())
                return 0;
 
+       err = gpio_request(EN_VDD_1V05_GPIO, "EN_VDD_1V05");
+       if (err)
+               return err;
+
+       gpio_direction_output(EN_VDD_1V05_GPIO, 1);
+
+       regulator = regulator_get(NULL, "pex_clk");
+       if (IS_ERR_OR_NULL(regulator))
+               goto err_reg;
+
+       regulator_enable(regulator);
+
        tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_NORMAL);
        tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_NORMAL);
        tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
@@ -49,9 +65,15 @@ err_pcie:
        tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
        tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
 
+       regulator_disable(regulator);
+       regulator_put(regulator);
+err_reg:
+       gpio_free(EN_VDD_1V05_GPIO);
+
        return err;
 }
 
-subsys_initcall(harmony_pcie_init);
+/* PCI should be initialized after I2C, mfd and regulators */
+subsys_initcall_sync(harmony_pcie_init);
 
 #endif
index 98368d947be3145a6f31a1dbef2cb53bf2f80975..4d63e2e97a8d44d08c539bc954dcf7b30d1d78f4 100644 (file)
@@ -27,11 +27,11 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
        {TEGRA_PINGROUP_ATC,   TEGRA_MUX_NAND,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-       {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_OSC,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_CSUS,  TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_DAP2,  TEGRA_MUX_DAP2,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
@@ -114,13 +114,13 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
        {TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPID,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPIE,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPIF,  TEGRA_MUX_SPI1,          TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
@@ -141,12 +141,16 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
 };
 
 static struct tegra_gpio_table gpio_table[] = {
-       { .gpio = TEGRA_GPIO_PI5,       .enable = true  }, /* mmc2 cd   */
-       { .gpio = TEGRA_GPIO_PH1,       .enable = true  }, /* mmc2 wp   */
-       { .gpio = TEGRA_GPIO_PT3,       .enable = true  }, /* mmc2 pwr  */
-       { .gpio = TEGRA_GPIO_PH2,       .enable = true  }, /* mmc4 cd   */
-       { .gpio = TEGRA_GPIO_PH3,       .enable = true  }, /* mmc4 wp   */
-       { .gpio = TEGRA_GPIO_PI6,       .enable = true  }, /* mmc4 pwr  */
+       { .gpio = TEGRA_GPIO_SD2_CD,            .enable = true  },
+       { .gpio = TEGRA_GPIO_SD2_WP,            .enable = true  },
+       { .gpio = TEGRA_GPIO_SD2_POWER,         .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_CD,            .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_WP,            .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_POWER,         .enable = true  },
+       { .gpio = TEGRA_GPIO_CDC_IRQ,           .enable = true  },
+       { .gpio = TEGRA_GPIO_HP_DET,            .enable = true  },
+       { .gpio = TEGRA_GPIO_INT_MIC_EN,        .enable = true  },
+       { .gpio = TEGRA_GPIO_EXT_MIC_EN,        .enable = true  },
 };
 
 void harmony_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
new file mode 100644 (file)
index 0000000..c84442c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2010 NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps6586x.h>
+
+#include <mach/irqs.h>
+
+#define PMC_CTRL               0x0
+#define PMC_CTRL_INTR_LOW      (1 << 17)
+
+static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
+       REGULATOR_SUPPLY("pex_clk", NULL),
+};
+
+static struct regulator_init_data ldo0_data = {
+       .constraints = {
+               .min_uV = 1250 * 1000,
+               .max_uV = 3300 * 1000,
+               .valid_modes_mask = (REGULATOR_MODE_NORMAL |
+                                    REGULATOR_MODE_STANDBY),
+               .valid_ops_mask = (REGULATOR_CHANGE_MODE |
+                                  REGULATOR_CHANGE_STATUS |
+                                  REGULATOR_CHANGE_VOLTAGE),
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps658621_ldo0_supply),
+       .consumer_supplies = tps658621_ldo0_supply,
+};
+
+#define HARMONY_REGULATOR_INIT(_id, _minmv, _maxmv)                    \
+       static struct regulator_init_data _id##_data = {                \
+               .constraints = {                                        \
+                       .min_uV = (_minmv)*1000,                        \
+                       .max_uV = (_maxmv)*1000,                        \
+                       .valid_modes_mask = (REGULATOR_MODE_NORMAL |    \
+                                            REGULATOR_MODE_STANDBY),   \
+                       .valid_ops_mask = (REGULATOR_CHANGE_MODE |      \
+                                          REGULATOR_CHANGE_STATUS |    \
+                                          REGULATOR_CHANGE_VOLTAGE),   \
+               },                                                      \
+       }
+
+HARMONY_REGULATOR_INIT(sm0, 725, 1500);
+HARMONY_REGULATOR_INIT(sm1, 725, 1500);
+HARMONY_REGULATOR_INIT(sm2, 3000, 4550);
+HARMONY_REGULATOR_INIT(ldo1, 725, 1500);
+HARMONY_REGULATOR_INIT(ldo2, 725, 1500);
+HARMONY_REGULATOR_INIT(ldo3, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo4, 1700, 2475);
+HARMONY_REGULATOR_INIT(ldo5, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo6, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo7, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo8, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo9, 1250, 3300);
+
+#define TPS_REG(_id, _data)                    \
+       {                                       \
+               .id = TPS6586X_ID_##_id,        \
+               .name = "tps6586x-regulator",   \
+               .platform_data = _data,         \
+       }
+
+static struct tps6586x_subdev_info tps_devs[] = {
+       TPS_REG(SM_0, &sm0_data),
+       TPS_REG(SM_1, &sm1_data),
+       TPS_REG(SM_2, &sm2_data),
+       TPS_REG(LDO_0, &ldo0_data),
+       TPS_REG(LDO_1, &ldo1_data),
+       TPS_REG(LDO_2, &ldo2_data),
+       TPS_REG(LDO_3, &ldo3_data),
+       TPS_REG(LDO_4, &ldo4_data),
+       TPS_REG(LDO_5, &ldo5_data),
+       TPS_REG(LDO_6, &ldo6_data),
+       TPS_REG(LDO_7, &ldo7_data),
+       TPS_REG(LDO_8, &ldo8_data),
+       TPS_REG(LDO_9, &ldo9_data),
+};
+
+static struct tps6586x_platform_data tps_platform = {
+       .irq_base       = TEGRA_NR_IRQS,
+       .num_subdevs    = ARRAY_SIZE(tps_devs),
+       .subdevs        = tps_devs,
+       .gpio_base      = TEGRA_NR_GPIOS,
+};
+
+static struct i2c_board_info __initdata harmony_regulators[] = {
+       {
+               I2C_BOARD_INFO("tps6586x", 0x34),
+               .irq            = INT_EXTERNAL_PMU,
+               .platform_data  = &tps_platform,
+       },
+};
+
+int __init harmony_regulator_init(void)
+{
+       i2c_register_board_info(3, harmony_regulators, 1);
+
+       return 0;
+}
index 49224e936eb48464bf05f1af2077db0bfbf89c10..75c918a86a31d44605b87569ccbe22bda237070d 100644 (file)
@@ -2,6 +2,7 @@
  * arch/arm/mach-tegra/board-harmony.c
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 NVIDIA, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/dma-mapping.h>
 #include <linux/pda_power.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+
+#include <sound/wm8903.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/setup.h>
 
+#include <mach/harmony_audio.h>
 #include <mach/iomap.h>
 #include <mach/irqs.h>
 #include <mach/sdhci.h>
@@ -60,11 +67,81 @@ static struct platform_device debug_uart = {
        },
 };
 
+static struct harmony_audio_platform_data harmony_audio_pdata = {
+       .gpio_spkr_en           = TEGRA_GPIO_SPKR_EN,
+       .gpio_hp_det            = TEGRA_GPIO_HP_DET,
+       .gpio_int_mic_en        = TEGRA_GPIO_INT_MIC_EN,
+       .gpio_ext_mic_en        = TEGRA_GPIO_EXT_MIC_EN,
+};
+
+static struct platform_device harmony_audio_device = {
+       .name   = "tegra-snd-harmony",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &harmony_audio_pdata,
+       },
+};
+
+static struct tegra_i2c_platform_data harmony_i2c1_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_i2c2_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_i2c3_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_dvc_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct wm8903_platform_data harmony_wm8903_pdata = {
+       .irq_active_low = 0,
+       .micdet_cfg = 0,
+       .micdet_delay = 100,
+       .gpio_base = HARMONY_GPIO_WM8903(0),
+       .gpio_cfg = {
+               WM8903_GPIO_NO_CONFIG,
+               WM8903_GPIO_NO_CONFIG,
+               0,
+               WM8903_GPIO_NO_CONFIG,
+               WM8903_GPIO_NO_CONFIG,
+       },
+};
+
+static struct i2c_board_info __initdata wm8903_board_info = {
+       I2C_BOARD_INFO("wm8903", 0x1a),
+       .platform_data = &harmony_wm8903_pdata,
+       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
+};
+
+static void __init harmony_i2c_init(void)
+{
+       tegra_i2c_device1.dev.platform_data = &harmony_i2c1_platform_data;
+       tegra_i2c_device2.dev.platform_data = &harmony_i2c2_platform_data;
+       tegra_i2c_device3.dev.platform_data = &harmony_i2c3_platform_data;
+       tegra_i2c_device4.dev.platform_data = &harmony_dvc_platform_data;
+
+       platform_device_register(&tegra_i2c_device1);
+       platform_device_register(&tegra_i2c_device2);
+       platform_device_register(&tegra_i2c_device3);
+       platform_device_register(&tegra_i2c_device4);
+
+       i2c_register_board_info(0, &wm8903_board_info, 1);
+}
+
 static struct platform_device *harmony_devices[] __initdata = {
        &debug_uart,
        &tegra_sdhci_device1,
        &tegra_sdhci_device2,
        &tegra_sdhci_device4,
+       &tegra_i2s_device1,
+       &tegra_das_device,
+       &tegra_pcm_device,
+       &harmony_audio_device,
 };
 
 static void __init tegra_harmony_fixup(struct machine_desc *desc,
@@ -80,6 +157,10 @@ static void __init tegra_harmony_fixup(struct machine_desc *desc,
 static __initdata struct tegra_clk_init_table harmony_clk_init_table[] = {
        /* name         parent          rate            enabled */
        { "uartd",      "pll_p",        216000000,      true },
+       { "pll_a",      "pll_p_out1",   56448000,       true },
+       { "pll_a_out0", "pll_a",        11289600,       true },
+       { "cdev1",      NULL,           0,              true },
+       { "i2s1",       "pll_a_out0",   11289600,       false},
        { NULL,         NULL,           0,              0},
 };
 
@@ -91,15 +172,15 @@ static struct tegra_sdhci_platform_data sdhci_pdata1 = {
 };
 
 static struct tegra_sdhci_platform_data sdhci_pdata2 = {
-       .cd_gpio        = TEGRA_GPIO_PI5,
-       .wp_gpio        = TEGRA_GPIO_PH1,
-       .power_gpio     = TEGRA_GPIO_PT3,
+       .cd_gpio        = TEGRA_GPIO_SD2_CD,
+       .wp_gpio        = TEGRA_GPIO_SD2_WP,
+       .power_gpio     = TEGRA_GPIO_SD2_POWER,
 };
 
 static struct tegra_sdhci_platform_data sdhci_pdata4 = {
-       .cd_gpio        = TEGRA_GPIO_PH2,
-       .wp_gpio        = TEGRA_GPIO_PH3,
-       .power_gpio     = TEGRA_GPIO_PI6,
+       .cd_gpio        = TEGRA_GPIO_SD4_CD,
+       .wp_gpio        = TEGRA_GPIO_SD4_WP,
+       .power_gpio     = TEGRA_GPIO_SD4_POWER,
        .is_8bit        = 1,
 };
 
@@ -114,6 +195,8 @@ static void __init tegra_harmony_init(void)
        tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
 
        platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices));
+       harmony_i2c_init();
+       harmony_regulator_init();
 }
 
 MACHINE_START(HARMONY, "harmony")
index 09ca7755dd5558b966833be98ea75c18e5b6efd0..1e57b071f52de9c6d37178bca02f0d6a563db1e8 100644 (file)
 #ifndef _MACH_TEGRA_BOARD_HARMONY_H
 #define _MACH_TEGRA_BOARD_HARMONY_H
 
+#define HARMONY_GPIO_WM8903(_x_)       (TEGRA_NR_GPIOS + (_x_))
+
+#define TEGRA_GPIO_SD2_CD              TEGRA_GPIO_PI5
+#define TEGRA_GPIO_SD2_WP              TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD2_POWER           TEGRA_GPIO_PT3
+#define TEGRA_GPIO_SD4_CD              TEGRA_GPIO_PH2
+#define TEGRA_GPIO_SD4_WP              TEGRA_GPIO_PH3
+#define TEGRA_GPIO_SD4_POWER           TEGRA_GPIO_PI6
+#define TEGRA_GPIO_CDC_IRQ             TEGRA_GPIO_PX3
+#define TEGRA_GPIO_SPKR_EN             HARMONY_GPIO_WM8903(2)
+#define TEGRA_GPIO_HP_DET              TEGRA_GPIO_PW2
+#define TEGRA_GPIO_INT_MIC_EN          TEGRA_GPIO_PX0
+#define TEGRA_GPIO_EXT_MIC_EN          TEGRA_GPIO_PX1
+
 void harmony_pinmux_init(void);
+int harmony_regulator_init(void);
 
 #endif
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
new file mode 100644 (file)
index 0000000..2643d1b
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * arch/arm/mach-tegra/board-paz00-pinmux.c
+ *
+ * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/gpio.h>
+#include <mach/pinmux.h>
+
+#include "gpio-names.h"
+#include "board-paz00.h"
+
+static struct tegra_pingroup_config paz00_pinmux[] = {
+       {TEGRA_PINGROUP_ATA,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_ATB,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_ATC,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_ATD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_ATE,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_CRTP,  TEGRA_MUX_CRT,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_CSUS,  TEGRA_MUX_PLLC_OUT1,     TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DAP1,  TEGRA_MUX_DAP1,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_DAP2,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_DAP3,  TEGRA_MUX_DAP3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DAP4,  TEGRA_MUX_DAP4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DDC,   TEGRA_MUX_I2C2,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_DTA,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DTB,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DTC,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DTD,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DTE,   TEGRA_MUX_RSVD1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_DTF,   TEGRA_MUX_I2C3,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GMA,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GMB,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GMC,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GMD,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GPU,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_IRTX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCA,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCB,  TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCC,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCD,  TEGRA_MUX_SDIO2,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCE,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_KBCF,  TEGRA_MUX_KBC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LCSN,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LD0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD10,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD11,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD12,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD13,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD14,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD15,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD16,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD17,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD2,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD3,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD4,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD5,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD6,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD7,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD8,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LD9,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LDC,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LDI,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LHP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LHP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LHP2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LHS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LM0,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LM1,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LPP,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LPW0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LPW1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LPW2,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LSC0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LSC1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LSCK,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LSDA,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LSDI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LSPI,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_LVP0,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LVP1,  TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_LVS,   TEGRA_MUX_DISPLAYA,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_OWC,   TEGRA_MUX_OWR,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_PMC,   TEGRA_MUX_PWR_ON,        TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PTA,   TEGRA_MUX_HDMI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_RM,    TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SDB,   TEGRA_MUX_PWM,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SDC,   TEGRA_MUX_TWC,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPI4,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIB,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIC,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPID,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIE,  TEGRA_MUX_GMI,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIF,  TEGRA_MUX_RSVD4,         TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SPIG,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_SPIH,  TEGRA_MUX_SPI2_ALT,      TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_UAA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_UAB,   TEGRA_MUX_ULPI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_UAC,   TEGRA_MUX_RSVD4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_UAD,   TEGRA_MUX_SPDIF,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_UCA,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_UCB,   TEGRA_MUX_UARTC,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_UDA,   TEGRA_MUX_ULPI,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_CK32,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_DDRC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PMCA,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PMCB,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PMCC,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PMCD,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_PMCE,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_XM2C,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+       {TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
+};
+
+static struct tegra_gpio_table gpio_table[] = {
+       { .gpio = TEGRA_GPIO_SD1_CD,    .enable = true  },
+       { .gpio = TEGRA_GPIO_SD1_WP,    .enable = true  },
+       { .gpio = TEGRA_GPIO_SD1_POWER, .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_CD,    .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_WP,    .enable = true  },
+       { .gpio = TEGRA_GPIO_SD4_POWER, .enable = true  },
+};
+
+void paz00_pinmux_init(void)
+{
+       tegra_pinmux_config_table(paz00_pinmux, ARRAY_SIZE(paz00_pinmux));
+
+       tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
+}
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
new file mode 100644 (file)
index 0000000..57e50a8
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * arch/arm/mach-tegra/board-paz00.c
+ *
+ * Copyright (C) 2011 Marc Dietrich <marvin24@gmx.de>
+ *
+ * Based on board-harmony.c
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/pda_power.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/setup.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/sdhci.h>
+
+#include "board.h"
+#include "board-paz00.h"
+#include "clock.h"
+#include "devices.h"
+#include "gpio-names.h"
+
+static struct plat_serial8250_port debug_uart_platform_data[] = {
+       {
+               .membase        = IO_ADDRESS(TEGRA_UARTD_BASE),
+               .mapbase        = TEGRA_UARTD_BASE,
+               .irq            = INT_UARTD,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .iotype         = UPIO_MEM,
+               .regshift       = 2,
+               .uartclk        = 216000000,
+       }, {
+               .flags          = 0
+       }
+};
+
+static struct platform_device debug_uart = {
+       .name = "serial8250",
+       .id = PLAT8250_DEV_PLATFORM,
+       .dev = {
+               .platform_data = debug_uart_platform_data,
+       },
+};
+
+static struct platform_device *paz00_devices[] __initdata = {
+       &debug_uart,
+       &tegra_sdhci_device1,
+       &tegra_sdhci_device2,
+       &tegra_sdhci_device4,
+};
+
+static void __init tegra_paz00_fixup(struct machine_desc *desc,
+       struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+       mi->nr_banks = 1;
+       mi->bank[0].start = PHYS_OFFSET;
+       mi->bank[0].size = 448 * SZ_1M;
+}
+
+static __initdata struct tegra_clk_init_table paz00_clk_init_table[] = {
+       /* name         parent          rate            enabled */
+       { "uartd",      "pll_p",        216000000,      true },
+       { NULL,         NULL,           0,              0},
+};
+
+
+static struct tegra_sdhci_platform_data sdhci_pdata1 = {
+       .cd_gpio        = TEGRA_GPIO_SD1_CD,
+       .wp_gpio        = TEGRA_GPIO_SD1_WP,
+       .power_gpio     = TEGRA_GPIO_SD1_POWER,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata2 = {
+       .cd_gpio        = -1,
+       .wp_gpio        = -1,
+       .power_gpio     = -1,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata4 = {
+       .cd_gpio        = TEGRA_GPIO_SD4_CD,
+       .wp_gpio        = TEGRA_GPIO_SD4_WP,
+       .power_gpio     = TEGRA_GPIO_SD4_POWER,
+       .is_8bit        = 1,
+};
+
+static void __init tegra_paz00_init(void)
+{
+       tegra_clk_init_from_table(paz00_clk_init_table);
+
+       paz00_pinmux_init();
+
+       tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
+       tegra_sdhci_device2.dev.platform_data = &sdhci_pdata2;
+       tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
+
+       platform_add_devices(paz00_devices, ARRAY_SIZE(paz00_devices));
+}
+
+MACHINE_START(PAZ00, "paz00")
+       .boot_params    = 0x00000100,
+       .fixup          = tegra_paz00_fixup,
+       .map_io         = tegra_map_common_io,
+       .init_early     = tegra_init_early,
+       .init_irq       = tegra_init_irq,
+       .timer          = &tegra_timer,
+       .init_machine   = tegra_paz00_init,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-paz00.h b/arch/arm/mach-tegra/board-paz00.h
new file mode 100644 (file)
index 0000000..da193ca
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/board-paz00.h
+ *
+ * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 _MACH_TEGRA_BOARD_PAZ00_H
+#define _MACH_TEGRA_BOARD_PAZ00_H
+
+#define TEGRA_GPIO_SD1_CD               TEGRA_GPIO_PV5
+#define TEGRA_GPIO_SD1_WP               TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD1_POWER            TEGRA_GPIO_PT3
+#define TEGRA_GPIO_SD4_CD               TEGRA_GPIO_PH2
+#define TEGRA_GPIO_SD4_WP               TEGRA_GPIO_PH3
+#define TEGRA_GPIO_SD4_POWER            TEGRA_GPIO_PI6
+
+void paz00_pinmux_init(void);
+
+#endif
index 2d6ad83ed4b25d8f26876720cbfb999ed2dc0224..0bda495e974232a88dc3276beee623773d32b561 100644 (file)
@@ -161,11 +161,12 @@ static __initdata struct tegra_pingroup_config seaboard_pinmux[] = {
 
 
 static struct tegra_gpio_table gpio_table[] = {
-       { .gpio = TEGRA_GPIO_PI5,       .enable = true  }, /* mmc2 cd    */
-       { .gpio = TEGRA_GPIO_PH1,       .enable = true  }, /* mmc2 wp    */
-       { .gpio = TEGRA_GPIO_PI6,       .enable = true  }, /* mmc2 pwr   */
-       { .gpio = TEGRA_GPIO_LIDSWITCH, .enable = true  }, /* lid switch */
-       { .gpio = TEGRA_GPIO_POWERKEY,  .enable = true  }, /* power key  */
+       { .gpio = TEGRA_GPIO_SD2_CD,            .enable = true },
+       { .gpio = TEGRA_GPIO_SD2_WP,            .enable = true },
+       { .gpio = TEGRA_GPIO_SD2_POWER,         .enable = true },
+       { .gpio = TEGRA_GPIO_LIDSWITCH,         .enable = true },
+       { .gpio = TEGRA_GPIO_POWERKEY,          .enable = true },
+       { .gpio = TEGRA_GPIO_ISL29018_IRQ,      .enable = true },
 };
 
 void __init seaboard_pinmux_init(void)
index 6ca9e61f6cd098cb20c3281946c7bfb38592443a..a8d7ace9f958ef2fd4c6db3e5802e2a8d8a861e5 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 
 #include <mach/iomap.h>
@@ -63,6 +66,22 @@ static __initdata struct tegra_clk_init_table seaboard_clk_init_table[] = {
        { NULL,         NULL,           0,              0},
 };
 
+static struct tegra_i2c_platform_data seaboard_i2c1_platform_data = {
+       .bus_clk_rate   = 400000.
+};
+
+static struct tegra_i2c_platform_data seaboard_i2c2_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct tegra_i2c_platform_data seaboard_i2c3_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
+static struct tegra_i2c_platform_data seaboard_dvc_platform_data = {
+       .bus_clk_rate   = 400000,
+};
+
 static struct gpio_keys_button seaboard_gpio_keys_buttons[] = {
        {
                .code           = SW_LID,
@@ -103,9 +122,9 @@ static struct tegra_sdhci_platform_data sdhci_pdata1 = {
 };
 
 static struct tegra_sdhci_platform_data sdhci_pdata3 = {
-       .cd_gpio        = TEGRA_GPIO_PI5,
-       .wp_gpio        = TEGRA_GPIO_PH1,
-       .power_gpio     = TEGRA_GPIO_PI6,
+       .cd_gpio        = TEGRA_GPIO_SD2_CD,
+       .wp_gpio        = TEGRA_GPIO_SD2_WP,
+       .power_gpio     = TEGRA_GPIO_SD2_POWER,
 };
 
 static struct tegra_sdhci_platform_data sdhci_pdata4 = {
@@ -124,7 +143,36 @@ static struct platform_device *seaboard_devices[] __initdata = {
        &seaboard_gpio_keys_device,
 };
 
-static void __init __tegra_seaboard_init(void)
+static struct i2c_board_info __initdata isl29018_device = {
+       I2C_BOARD_INFO("isl29018", 0x44),
+       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
+};
+
+static struct i2c_board_info __initdata adt7461_device = {
+       I2C_BOARD_INFO("adt7461", 0x4c),
+};
+
+static void __init seaboard_i2c_init(void)
+{
+       gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
+       gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
+
+       i2c_register_board_info(0, &isl29018_device, 1);
+
+       i2c_register_board_info(4, &adt7461_device, 1);
+
+       tegra_i2c_device1.dev.platform_data = &seaboard_i2c1_platform_data;
+       tegra_i2c_device2.dev.platform_data = &seaboard_i2c2_platform_data;
+       tegra_i2c_device3.dev.platform_data = &seaboard_i2c3_platform_data;
+       tegra_i2c_device4.dev.platform_data = &seaboard_dvc_platform_data;
+
+       platform_device_register(&tegra_i2c_device1);
+       platform_device_register(&tegra_i2c_device2);
+       platform_device_register(&tegra_i2c_device3);
+       platform_device_register(&tegra_i2c_device4);
+}
+
+static void __init seaboard_common_init(void)
 {
        seaboard_pinmux_init();
 
@@ -144,7 +192,9 @@ static void __init tegra_seaboard_init(void)
        debug_uart_platform_data[0].mapbase = TEGRA_UARTD_BASE;
        debug_uart_platform_data[0].irq = INT_UARTD;
 
-       __tegra_seaboard_init();
+       seaboard_common_init();
+
+       seaboard_i2c_init();
 }
 
 static void __init tegra_kaen_init(void)
@@ -154,7 +204,9 @@ static void __init tegra_kaen_init(void)
        debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
        debug_uart_platform_data[0].irq = INT_UARTB;
 
-       __tegra_seaboard_init();
+       seaboard_common_init();
+
+       seaboard_i2c_init();
 }
 
 static void __init tegra_wario_init(void)
@@ -164,7 +216,9 @@ static void __init tegra_wario_init(void)
        debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
        debug_uart_platform_data[0].irq = INT_UARTB;
 
-       __tegra_seaboard_init();
+       seaboard_common_init();
+
+       seaboard_i2c_init();
 }
 
 
index a098e3599731ce39018a7a78d1bbefeb116e47b8..d8415e1a8434f21e61eace90c0585fb00268ee94 100644 (file)
@@ -17,6 +17,9 @@
 #ifndef _MACH_TEGRA_BOARD_SEABOARD_H
 #define _MACH_TEGRA_BOARD_SEABOARD_H
 
+#define TEGRA_GPIO_SD2_CD              TEGRA_GPIO_PI5
+#define TEGRA_GPIO_SD2_WP              TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD2_POWER           TEGRA_GPIO_PI6
 #define TEGRA_GPIO_LIDSWITCH           TEGRA_GPIO_PC7
 #define TEGRA_GPIO_USB1                        TEGRA_GPIO_PD0
 #define TEGRA_GPIO_POWERKEY            TEGRA_GPIO_PV2
index 6d4fc9f7f1fb29e9d9a50833d524f4b61df844d2..13534fa08abfd4b2586b0e983d776d51bfe5289f 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+
 #include <mach/pinmux.h>
+#include <mach/gpio.h>
 
+#include "gpio-names.h"
 #include "board-trimslice.h"
 
 static __initdata struct tegra_pingroup_config trimslice_pinmux[] = {
@@ -139,7 +142,13 @@ static __initdata struct tegra_pingroup_config trimslice_pinmux[] = {
        {TEGRA_PINGROUP_XM2D,  TEGRA_MUX_NONE,          TEGRA_PUPD_NORMAL,      TEGRA_TRI_NORMAL},
 };
 
+static struct tegra_gpio_table gpio_table[] = {
+       { .gpio = TRIMSLICE_GPIO_SD4_CD, .enable = true }, /* mmc4 cd */
+       { .gpio = TRIMSLICE_GPIO_SD4_WP, .enable = true }, /* mmc4 wp */
+};
+
 void __init trimslice_pinmux_init(void)
 {
        tegra_pinmux_config_table(trimslice_pinmux, ARRAY_SIZE(trimslice_pinmux));
+       tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
 }
index 7be7d4acd02f446bbc2e2cb5e7309fe5637fe856..cda4cfd78e8417f6f8af5fe0a30e2015f074efa9 100644 (file)
 #include <asm/setup.h>
 
 #include <mach/iomap.h>
+#include <mach/sdhci.h>
 
 #include "board.h"
 #include "clock.h"
+#include "devices.h"
+#include "gpio-names.h"
 
 #include "board-trimslice.h"
 
@@ -56,9 +59,22 @@ static struct platform_device debug_uart = {
                .platform_data  = debug_uart_platform_data,
        },
 };
+static struct tegra_sdhci_platform_data sdhci_pdata1 = {
+       .cd_gpio        = -1,
+       .wp_gpio        = -1,
+       .power_gpio     = -1,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata4 = {
+       .cd_gpio        = TRIMSLICE_GPIO_SD4_CD,
+       .wp_gpio        = TRIMSLICE_GPIO_SD4_WP,
+       .power_gpio     = -1,
+};
 
 static struct platform_device *trimslice_devices[] __initdata = {
        &debug_uart,
+       &tegra_sdhci_device1,
+       &tegra_sdhci_device4,
 };
 
 static void __init tegra_trimslice_fixup(struct machine_desc *desc,
@@ -92,6 +108,9 @@ static void __init tegra_trimslice_init(void)
 
        trimslice_pinmux_init();
 
+       tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
+       tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
+
        platform_add_devices(trimslice_devices, ARRAY_SIZE(trimslice_devices));
 }
 
index 16ec0f0d3bb14843e7b8a6c1e7aaf3c3aae66a87..e8ef6291c6f1945e7f7c8e8f51ef36749b8e0c7e 100644 (file)
@@ -17,6 +17,9 @@
 #ifndef _MACH_TEGRA_BOARD_TRIMSLICE_H
 #define _MACH_TEGRA_BOARD_TRIMSLICE_H
 
+#define TRIMSLICE_GPIO_SD4_CD  TEGRA_GPIO_PP1  /* mmc4 cd */
+#define TRIMSLICE_GPIO_SD4_WP  TEGRA_GPIO_PP2  /* mmc4 wp */
+
 void trimslice_pinmux_init(void);
 
 #endif
index 682e6d33108cda9104296e472e68d16105f65f38..1528f9daef1f2087cc7383b39dd0a3ed3fa8ce07 100644 (file)
@@ -503,3 +503,73 @@ struct platform_device tegra_uarte_device = {
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
 };
+
+static struct resource i2s_resource1[] = {
+       [0] = {
+               .start  = INT_I2S1,
+               .end    = INT_I2S1,
+               .flags  = IORESOURCE_IRQ
+       },
+       [1] = {
+               .start  = TEGRA_DMA_REQ_SEL_I2S_1,
+               .end    = TEGRA_DMA_REQ_SEL_I2S_1,
+               .flags  = IORESOURCE_DMA
+       },
+       [2] = {
+               .start  = TEGRA_I2S1_BASE,
+               .end    = TEGRA_I2S1_BASE + TEGRA_I2S1_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       }
+};
+
+static struct resource i2s_resource2[] = {
+       [0] = {
+               .start  = INT_I2S2,
+               .end    = INT_I2S2,
+               .flags  = IORESOURCE_IRQ
+       },
+       [1] = {
+               .start  = TEGRA_DMA_REQ_SEL_I2S2_1,
+               .end    = TEGRA_DMA_REQ_SEL_I2S2_1,
+               .flags  = IORESOURCE_DMA
+       },
+       [2] = {
+               .start  = TEGRA_I2S2_BASE,
+               .end    = TEGRA_I2S2_BASE + TEGRA_I2S2_SIZE - 1,
+               .flags  = IORESOURCE_MEM
+       }
+};
+
+struct platform_device tegra_i2s_device1 = {
+       .name           = "tegra-i2s",
+       .id             = 0,
+       .resource       = i2s_resource1,
+       .num_resources  = ARRAY_SIZE(i2s_resource1),
+};
+
+struct platform_device tegra_i2s_device2 = {
+       .name           = "tegra-i2s",
+       .id             = 1,
+       .resource       = i2s_resource2,
+       .num_resources  = ARRAY_SIZE(i2s_resource2),
+};
+
+static struct resource tegra_das_resources[] = {
+       [0] = {
+               .start = TEGRA_APB_MISC_DAS_BASE,
+               .end = TEGRA_APB_MISC_DAS_BASE + TEGRA_APB_MISC_DAS_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device tegra_das_device = {
+       .name           = "tegra-das",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(tegra_das_resources),
+       .resource       = tegra_das_resources,
+};
+
+struct platform_device tegra_pcm_device = {
+       .name = "tegra-pcm-audio",
+       .id = -1,
+};
index 888810c37ee9da3175bc4025550e76d7da4aa5cb..4a7dc0a097d60ad78e8842de036cea96ef0628aa 100644 (file)
@@ -42,5 +42,9 @@ extern struct platform_device tegra_uartc_device;
 extern struct platform_device tegra_uartd_device;
 extern struct platform_device tegra_uarte_device;
 extern struct platform_device tegra_pmu_device;
+extern struct platform_device tegra_i2s_device1;
+extern struct platform_device tegra_i2s_device2;
+extern struct platform_device tegra_das_device;
+extern struct platform_device tegra_pcm_device;
 
 #endif
index 691cdabd69cfdee102784ee9ca5c4637b0c1e716..19dec3ac0854a49218d107b78f00b26857ef7329 100644 (file)
 #define TEGRA_APB_MISC_BASE            0x70000000
 #define TEGRA_APB_MISC_SIZE            SZ_4K
 
+#define TEGRA_APB_MISC_DAS_BASE                0x70000c00
+#define TEGRA_APB_MISC_DAS_SIZE                SZ_128
+
 #define TEGRA_AC97_BASE                        0x70002000
 #define TEGRA_AC97_SIZE                        SZ_512
 
index f81ca7cbbc1f7279aea08174896aec401725fa54..e91d681d45a2d8593a49e3bf3406a173b2a250c2 100644 (file)
@@ -18,8 +18,9 @@
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
        evt->irq = IRQ_LOCALTIMER;
        twd_timer_setup(evt);
+       return 0;
 }
index 2288f6a7c5180c8920f0e0e9a04ea95217241489..5ba113309a0b3c451e1d3dcbb50010a171a94b1d 100644 (file)
@@ -21,8 +21,9 @@
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
        evt->irq = IRQ_LOCALTIMER;
        twd_timer_setup(evt);
+       return 0;
 }
index 136c32e7ed8eb44d5a1c59d20a86349e30c813c2..eb7ffa0ee8b544d77caf42cc542892413b055952 100644 (file)
@@ -50,6 +50,8 @@
 #include <mach/platform.h>
 #include <asm/hardware/timer-sp.h>
 
+#include <plat/clcd.h>
+#include <plat/fpga-irq.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
 #define VA_VIC_BASE            __io_address(VERSATILE_VIC_BASE)
 #define VA_SIC_BASE            __io_address(VERSATILE_SIC_BASE)
 
-static void sic_mask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_SIC_START;
-
-       writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
-}
-
-static void sic_unmask_irq(struct irq_data *d)
-{
-       unsigned int irq = d->irq - IRQ_SIC_START;
-
-       writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET);
-}
-
-static struct irq_chip sic_chip = {
-       .name           = "SIC",
-       .irq_ack        = sic_mask_irq,
-       .irq_mask       = sic_mask_irq,
-       .irq_unmask     = sic_unmask_irq,
+static struct fpga_irq_data sic_irq = {
+       .base           = VA_SIC_BASE,
+       .irq_start      = IRQ_SIC_START,
+       .chip.name      = "SIC",
 };
 
-static void
-sic_handle_irq(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS);
-
-       if (status == 0) {
-               do_bad_IRQ(irq, desc);
-               return;
-       }
-
-       do {
-               irq = ffs(status) - 1;
-               status &= ~(1 << irq);
-
-               irq += IRQ_SIC_START;
-
-               generic_handle_irq(irq);
-       } while (status);
-}
-
 #if 1
 #define IRQ_MMCI0A     IRQ_VICSOURCE22
 #define IRQ_AACI       IRQ_VICSOURCE24
@@ -118,22 +85,11 @@ sic_handle_irq(unsigned int irq, struct irq_desc *desc)
 
 void __init versatile_init_irq(void)
 {
-       unsigned int i;
-
        vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
 
-       set_irq_chained_handler(IRQ_VICSOURCE31, sic_handle_irq);
-
-       /* Do second interrupt controller */
        writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
-       for (i = IRQ_SIC_START; i <= IRQ_SIC_END; i++) {
-               if ((PIC_MASK & (1 << (i - IRQ_SIC_START))) == 0) {
-                       set_irq_chip(i, &sic_chip);
-                       set_irq_handler(i, handle_level_irq);
-                       set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-               }
-       }
+       fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq);
 
        /*
         * Interrupts on secondary controller from 0 to 8 are routed to
@@ -476,127 +432,7 @@ static struct clk_lookup lookups[] = {
 #define SYS_CLCD_ID_SANYO_2_5  (0x07 << 8)
 #define SYS_CLCD_ID_VGA                (0x1f << 8)
 
-static struct clcd_panel vga = {
-       .mode           = {
-               .name           = "VGA",
-               .refresh        = 60,
-               .xres           = 640,
-               .yres           = 480,
-               .pixclock       = 39721,
-               .left_margin    = 40,
-               .right_margin   = 24,
-               .upper_margin   = 32,
-               .lower_margin   = 11,
-               .hsync_len      = 96,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel sanyo_3_8_in = {
-       .mode           = {
-               .name           = "Sanyo QVGA",
-               .refresh        = 116,
-               .xres           = 320,
-               .yres           = 240,
-               .pixclock       = 100000,
-               .left_margin    = 6,
-               .right_margin   = 6,
-               .upper_margin   = 5,
-               .lower_margin   = 5,
-               .hsync_len      = 6,
-               .vsync_len      = 6,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel sanyo_2_5_in = {
-       .mode           = {
-               .name           = "Sanyo QVGA Portrait",
-               .refresh        = 116,
-               .xres           = 240,
-               .yres           = 320,
-               .pixclock       = 100000,
-               .left_margin    = 20,
-               .right_margin   = 10,
-               .upper_margin   = 2,
-               .lower_margin   = 2,
-               .hsync_len      = 10,
-               .vsync_len      = 2,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-static struct clcd_panel epson_2_2_in = {
-       .mode           = {
-               .name           = "Epson QCIF",
-               .refresh        = 390,
-               .xres           = 176,
-               .yres           = 220,
-               .pixclock       = 62500,
-               .left_margin    = 3,
-               .right_margin   = 2,
-               .upper_margin   = 1,
-               .lower_margin   = 0,
-               .hsync_len      = 3,
-               .vsync_len      = 2,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
-/*
- * Detect which LCD panel is connected, and return the appropriate
- * clcd_panel structure.  Note: we do not have any information on
- * the required timings for the 8.4in panel, so we presently assume
- * VGA timings.
- */
-static struct clcd_panel *versatile_clcd_panel(void)
-{
-       void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
-       struct clcd_panel *panel = &vga;
-       u32 val;
-
-       val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
-       if (val == SYS_CLCD_ID_SANYO_3_8)
-               panel = &sanyo_3_8_in;
-       else if (val == SYS_CLCD_ID_SANYO_2_5)
-               panel = &sanyo_2_5_in;
-       else if (val == SYS_CLCD_ID_EPSON_2_2)
-               panel = &epson_2_2_in;
-       else if (val == SYS_CLCD_ID_VGA)
-               panel = &vga;
-       else {
-               printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
-                       val);
-               panel = &vga;
-       }
-
-       return panel;
-}
+static bool is_sanyo_2_5_lcd;
 
 /*
  * Disable all display connectors on the interface module.
@@ -614,7 +450,7 @@ static void versatile_clcd_disable(struct clcd_fb *fb)
        /*
         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light off
         */
-       if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
+       if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
                void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
                unsigned long ctrl;
 
@@ -630,18 +466,22 @@ static void versatile_clcd_disable(struct clcd_fb *fb)
  */
 static void versatile_clcd_enable(struct clcd_fb *fb)
 {
+       struct fb_var_screeninfo *var = &fb->fb.var;
        void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
        u32 val;
 
        val = readl(sys_clcd);
        val &= ~SYS_CLCD_MODE_MASK;
 
-       switch (fb->fb.var.green.length) {
+       switch (var->green.length) {
        case 5:
                val |= SYS_CLCD_MODE_5551;
                break;
        case 6:
-               val |= SYS_CLCD_MODE_565_RLSB;
+               if (var->red.offset == 0)
+                       val |= SYS_CLCD_MODE_565_RLSB;
+               else
+                       val |= SYS_CLCD_MODE_565_BLSB;
                break;
        case 8:
                val |= SYS_CLCD_MODE_888;
@@ -663,7 +503,7 @@ static void versatile_clcd_enable(struct clcd_fb *fb)
        /*
         * If the LCD is Sanyo 2x5 in on the IB2 board, turn the back-light on
         */
-       if (machine_is_versatile_ab() && fb->panel == &sanyo_2_5_in) {
+       if (machine_is_versatile_ab() && is_sanyo_2_5_lcd) {
                void __iomem *versatile_ib2_ctrl = __io_address(VERSATILE_IB2_CTRL);
                unsigned long ctrl;
 
@@ -674,50 +514,62 @@ static void versatile_clcd_enable(struct clcd_fb *fb)
 #endif
 }
 
-static unsigned long framesize = SZ_1M;
-
+/*
+ * Detect which LCD panel is connected, and return the appropriate
+ * clcd_panel structure.  Note: we do not have any information on
+ * the required timings for the 8.4in panel, so we presently assume
+ * VGA timings.
+ */
 static int versatile_clcd_setup(struct clcd_fb *fb)
 {
-       dma_addr_t dma;
+       void __iomem *sys_clcd = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_CLCD_OFFSET;
+       const char *panel_name;
+       u32 val;
 
-       fb->panel               = versatile_clcd_panel();
+       is_sanyo_2_5_lcd = false;
 
-       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
-                                                   &dma, GFP_KERNEL);
-       if (!fb->fb.screen_base) {
-               printk(KERN_ERR "CLCD: unable to map framebuffer\n");
-               return -ENOMEM;
+       val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
+       if (val == SYS_CLCD_ID_SANYO_3_8)
+               panel_name = "Sanyo TM38QV67A02A";
+       else if (val == SYS_CLCD_ID_SANYO_2_5) {
+               panel_name = "Sanyo QVGA Portrait";
+               is_sanyo_2_5_lcd = true;
+       } else if (val == SYS_CLCD_ID_EPSON_2_2)
+               panel_name = "Epson L2F50113T00";
+       else if (val == SYS_CLCD_ID_VGA)
+               panel_name = "VGA";
+       else {
+               printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
+                       val);
+               panel_name = "VGA";
        }
 
-       fb->fb.fix.smem_start   = dma;
-       fb->fb.fix.smem_len     = framesize;
+       fb->panel = versatile_clcd_get_panel(panel_name);
+       if (!fb->panel)
+               return -EINVAL;
 
-       return 0;
+       return versatile_clcd_setup_dma(fb, SZ_1M);
 }
 
-static int versatile_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+static void versatile_clcd_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 {
-       return dma_mmap_writecombine(&fb->dev->dev, vma,
-                                    fb->fb.screen_base,
-                                    fb->fb.fix.smem_start,
-                                    fb->fb.fix.smem_len);
-}
+       clcdfb_decode(fb, regs);
 
-static void versatile_clcd_remove(struct clcd_fb *fb)
-{
-       dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
-                             fb->fb.screen_base, fb->fb.fix.smem_start);
+       /* Always clear BGR for RGB565: we do the routing externally */
+       if (fb->fb.var.green.length == 6)
+               regs->cntl &= ~CNTL_BGR;
 }
 
 static struct clcd_board clcd_plat_data = {
        .name           = "Versatile",
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
        .check          = clcdfb_check,
-       .decode         = clcdfb_decode,
+       .decode         = versatile_clcd_decode,
        .disable        = versatile_clcd_disable,
        .enable         = versatile_clcd_enable,
        .setup          = versatile_clcd_setup,
-       .mmap           = versatile_clcd_mmap,
-       .remove         = versatile_clcd_remove,
+       .mmap           = versatile_clcd_mmap_dma,
+       .remove         = versatile_clcd_remove_dma,
 };
 
 static struct pl061_platform_data gpio0_plat_data = {
@@ -737,53 +589,35 @@ static struct pl022_ssp_controller ssp0_plat_data = {
 };
 
 #define AACI_IRQ       { IRQ_AACI, NO_IRQ }
-#define AACI_DMA       { 0x80, 0x81 }
 #define MMCI0_IRQ      { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
-#define MMCI0_DMA      { 0x84, 0 }
 #define KMI0_IRQ       { IRQ_SIC_KMI0, NO_IRQ }
-#define KMI0_DMA       { 0, 0 }
 #define KMI1_IRQ       { IRQ_SIC_KMI1, NO_IRQ }
-#define KMI1_DMA       { 0, 0 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
 #define SMC_IRQ                { NO_IRQ, NO_IRQ }
-#define SMC_DMA                { 0, 0 }
 #define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define MPMC_DMA       { 0, 0 }
 #define CLCD_IRQ       { IRQ_CLCDINT, NO_IRQ }
-#define CLCD_DMA       { 0, 0 }
 #define DMAC_IRQ       { IRQ_DMAINT, NO_IRQ }
-#define DMAC_DMA       { 0, 0 }
 
 /*
  * These devices are connected via the core APB bridge
  */
 #define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define SCTL_DMA       { 0, 0 }
 #define WATCHDOG_IRQ   { IRQ_WDOGINT, NO_IRQ }
-#define WATCHDOG_DMA   { 0, 0 }
 #define GPIO0_IRQ      { IRQ_GPIOINT0, NO_IRQ }
-#define GPIO0_DMA      { 0, 0 }
 #define GPIO1_IRQ      { IRQ_GPIOINT1, NO_IRQ }
-#define GPIO1_DMA      { 0, 0 }
 #define RTC_IRQ                { IRQ_RTCINT, NO_IRQ }
-#define RTC_DMA                { 0, 0 }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
 #define SCI_IRQ                { IRQ_SCIINT, NO_IRQ }
-#define SCI_DMA                { 7, 6 }
 #define UART0_IRQ      { IRQ_UARTINT0, NO_IRQ }
-#define UART0_DMA      { 15, 14 }
 #define UART1_IRQ      { IRQ_UARTINT1, NO_IRQ }
-#define UART1_DMA      { 13, 12 }
 #define UART2_IRQ      { IRQ_UARTINT2, NO_IRQ }
-#define UART2_DMA      { 11, 10 }
 #define SSP_IRQ                { IRQ_SSPINT, NO_IRQ }
-#define SSP_DMA                { 9, 8 }
 
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,  "fpga:04", AACI,     NULL);
@@ -865,14 +699,21 @@ static void versatile_leds_event(led_event_t ledevt)
 }
 #endif /* CONFIG_LEDS */
 
-void __init versatile_init(void)
+/* Early initializations */
+void __init versatile_init_early(void)
 {
-       int i;
-
-       osc4_clk.vcoreg = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSCCLCD_OFFSET;
+       void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
 
+       osc4_clk.vcoreg = sys + VERSATILE_SYS_OSCCLCD_OFFSET;
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
+       versatile_sched_clock_init(sys + VERSATILE_SYS_24MHz_OFFSET, 24000000);
+}
+
+void __init versatile_init(void)
+{
+       int i;
+
        platform_device_register(&versatile_flash_device);
        platform_device_register(&versatile_i2c_device);
        platform_device_register(&smc91x_device);
@@ -888,12 +729,6 @@ void __init versatile_init(void)
 #endif
 }
 
-/*
- * The sched_clock counter
- */
-#define REFCOUNTER             (__io_address(VERSATILE_SYS_BASE) + \
-                                VERSATILE_SYS_24MHz_OFFSET)
-
 /*
  * Where is the timer (VA)?
  */
@@ -909,8 +744,6 @@ static void __init versatile_timer_init(void)
 {
        u32 val;
 
-       versatile_sched_clock_init(REFCOUNTER, 24000000);
-
        /* 
         * set clock frequency: 
         *      VERSATILE_REFCLK is 32KHz
index 9d39886a8351d360dac960830f1fa870e31bc7be..fd6404e5d788245174cfcbb9bf0e143f5c44950e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/amba/bus.h>
 
 extern void __init versatile_init(void);
+extern void __init versatile_init_early(void);
 extern void __init versatile_init_irq(void);
 extern void __init versatile_map_io(void);
 extern struct sys_timer versatile_timer;
@@ -44,7 +45,6 @@ static struct amba_device name##_device = {                   \
        },                                                      \
        .dma_mask       = ~0,                                   \
        .irq            = base##_IRQ,                           \
-       /* .dma         = base##_DMA,*/                         \
 }
 
 #endif
index b5e75bb4496516cd5858bc024a5b5d1a2490416d..6911e1f5f15601bfb3f8a590dc10496abda55b8e 100644 (file)
@@ -39,6 +39,6 @@
 /* macro to get at IO space when running virtually */
 #define IO_ADDRESS(x)          (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
 
-#define __io_address(n)                __io(IO_ADDRESS(n))
+#define __io_address(n)                ((void __iomem __force *)IO_ADDRESS(n))
 
 #endif
index aa9730fb13bfa287efcf8c53161da1bd97e6cf20..f8ae64b3eed09b132fe745fecddb5ca1cc2d2790 100644 (file)
@@ -37,6 +37,7 @@ MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .boot_params    = 0x00000100,
        .map_io         = versatile_map_io,
+       .init_early     = versatile_init_early,
        .init_irq       = versatile_init_irq,
        .timer          = &versatile_timer,
        .init_machine   = versatile_init,
index bf469642a3f811c9032dc34358d8f9ef556ffa10..37c23dfeefb7de46e35a1db708032a0ae097bd58 100644 (file)
@@ -59,19 +59,14 @@ static struct pl061_platform_data gpio3_plat_data = {
 };
 
 #define UART3_IRQ      { IRQ_SIC_UART3, NO_IRQ }
-#define UART3_DMA      { 0x86, 0x87 }
 #define SCI1_IRQ       { IRQ_SIC_SCI3, NO_IRQ }
-#define SCI1_DMA       { 0x88, 0x89 }
 #define MMCI1_IRQ      { IRQ_MMCI1A, IRQ_SIC_MMCI1B }
-#define MMCI1_DMA      { 0x85, 0 }
 
 /*
  * These devices are connected via the core APB bridge
  */
 #define GPIO2_IRQ      { IRQ_GPIOINT2, NO_IRQ }
-#define GPIO2_DMA      { 0, 0 }
 #define GPIO3_IRQ      { IRQ_GPIOINT3, NO_IRQ }
-#define GPIO3_DMA      { 0, 0 }
 
 /*
  * These devices are connected via the DMA APB bridge
@@ -110,6 +105,7 @@ MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .boot_params    = 0x00000100,
        .map_io         = versatile_map_io,
+       .init_early     = versatile_init_early,
        .init_irq       = versatile_init_irq,
        .timer          = &versatile_timer,
        .init_machine   = versatile_pb_init,
index 3f19b660a165452cc19bbba2b1a9b215ff6a6e17..931148487f0bc7938b26248b7607a9957f01d3cd 100644 (file)
@@ -5,5 +5,8 @@ config ARCH_VEXPRESS_CA9X4
        bool "Versatile Express Cortex-A9x4 tile"
        select CPU_V7
        select ARM_GIC
+       select ARM_ERRATA_720789
+       select ARM_ERRATA_751472
+       select ARM_ERRATA_753970
 
 endmenu
index 2c0ac7de28142dfb46ce9e4463c8bea03fff58eb..90551b9780ab1f31cd5e041c7babad44b8ca3e55 100644 (file)
@@ -4,6 +4,5 @@
 
 obj-y                                  := v2m.o
 obj-$(CONFIG_ARCH_VEXPRESS_CA9X4)      += ct-ca9x4.o
-obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
+obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
index 362780d868de02f5c5ea0e42c3d80e5b02f09607..f4397159c173277da92d7c1bb0dbb60549bab8f2 100644 (file)
@@ -17,8 +17,3 @@ struct amba_device name##_device = {          \
        .irq            = IRQ_##base,           \
        /* .dma         = DMA_##base,*/         \
 }
-
-struct map_desc;
-
-void v2m_map_io(struct map_desc *tile, size_t num);
-extern struct sys_timer v2m_timer;
index e9bccc5230c972bf5fdeeabdfccf09ab6a4e6257..ebc22e759325a8b11efa731e49f6ea451cce8cfc 100644 (file)
 #include <linux/amba/clcd.h>
 #include <linux/clkdev.h>
 
-#include <asm/pgtable.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
-#include <asm/mach-types.h>
 #include <asm/pmu.h>
+#include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
 
 #include <mach/ct-ca9x4.h>
 
 #include <asm/hardware/timer-sp.h>
 
-#include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
@@ -30,6 +28,8 @@
 
 #include <mach/motherboard.h>
 
+#include <plat/clcd.h>
+
 #define V2M_PA_CS7     0x10000000
 
 static struct map_desc ct_ca9x4_io_desc[] __initdata = {
@@ -56,7 +56,7 @@ static void __init ct_ca9x4_map_io(void)
 #ifdef CONFIG_LOCAL_TIMERS
        twd_base = MMIO_P2V(A9_MPCORE_TWD);
 #endif
-       v2m_map_io(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
+       iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
 static void __init ct_ca9x4_init_irq(void)
@@ -80,29 +80,6 @@ static struct sys_timer ct_ca9x4_timer = {
 };
 #endif
 
-static struct clcd_panel xvga_panel = {
-       .mode           = {
-               .name           = "XVGA",
-               .refresh        = 60,
-               .xres           = 1024,
-               .yres           = 768,
-               .pixclock       = 15384,
-               .left_margin    = 168,
-               .right_margin   = 8,
-               .upper_margin   = 29,
-               .lower_margin   = 3,
-               .hsync_len      = 144,
-               .vsync_len      = 6,
-               .sync           = 0,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-       .width          = -1,
-       .height         = -1,
-       .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
-       .bpp            = 16,
-};
-
 static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
 {
        v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0);
@@ -112,42 +89,23 @@ static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
 {
        unsigned long framesize = 1024 * 768 * 2;
-       dma_addr_t dma;
 
-       fb->panel = &xvga_panel;
+       fb->panel = versatile_clcd_get_panel("XVGA");
+       if (!fb->panel)
+               return -EINVAL;
 
-       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
-                               &dma, GFP_KERNEL);
-       if (!fb->fb.screen_base) {
-               printk(KERN_ERR "CLCD: unable to map frame buffer\n");
-               return -ENOMEM;
-       }
-       fb->fb.fix.smem_start = dma;
-       fb->fb.fix.smem_len = framesize;
-
-       return 0;
-}
-
-static int ct_ca9x4_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
-       return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
-               fb->fb.fix.smem_start, fb->fb.fix.smem_len);
-}
-
-static void ct_ca9x4_clcd_remove(struct clcd_fb *fb)
-{
-       dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
-               fb->fb.screen_base, fb->fb.fix.smem_start);
+       return versatile_clcd_setup_dma(fb, framesize);
 }
 
 static struct clcd_board ct_ca9x4_clcd_data = {
        .name           = "CT-CA9X4",
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_565,
        .check          = clcdfb_check,
        .decode         = clcdfb_decode,
        .enable         = ct_ca9x4_clcd_enable,
        .setup          = ct_ca9x4_clcd_setup,
-       .mmap           = ct_ca9x4_clcd_mmap,
-       .remove         = ct_ca9x4_clcd_remove,
+       .mmap           = versatile_clcd_mmap_dma,
+       .remove         = versatile_clcd_remove_dma,
 };
 
 static AMBA_DEVICE(clcd, "ct:clcd", CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
@@ -220,6 +178,11 @@ static struct platform_device pmu_device = {
        .resource       = pmu_resources,
 };
 
+static void __init ct_ca9x4_init_early(void)
+{
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+}
+
 static void __init ct_ca9x4_init(void)
 {
        int i;
@@ -234,22 +197,40 @@ static void __init ct_ca9x4_init(void)
        l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
 #endif
 
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
        for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
                amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
 
        platform_device_register(&pmu_device);
 }
 
-MACHINE_START(VEXPRESS, "ARM-Versatile Express CA9x4")
-       .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
+#ifdef CONFIG_SMP
+static void ct_ca9x4_init_cpu_map(void)
+{
+       int i, ncores = scu_get_core_count(MMIO_P2V(A9_MPCORE_SCU));
+
+       for (i = 0; i < ncores; ++i)
+               set_cpu_possible(i, true);
+}
+
+static void ct_ca9x4_smp_enable(unsigned int max_cpus)
+{
+       int i;
+       for (i = 0; i < max_cpus; i++)
+               set_cpu_present(i, true);
+
+       scu_enable(MMIO_P2V(A9_MPCORE_SCU));
+}
+#endif
+
+struct ct_desc ct_ca9x4_desc __initdata = {
+       .id             = V2M_CT_ID_CA9,
+       .name           = "CA9x4",
        .map_io         = ct_ca9x4_map_io,
+       .init_early     = ct_ca9x4_init_early,
        .init_irq       = ct_ca9x4_init_irq,
-#if 0
-       .timer          = &ct_ca9x4_timer,
-#else
-       .timer          = &v2m_timer,
+       .init_tile      = ct_ca9x4_init,
+#ifdef CONFIG_SMP
+       .init_cpu_map   = ct_ca9x4_init_cpu_map,
+       .smp_enable     = ct_ca9x4_smp_enable,
 #endif
-       .init_machine   = ct_ca9x4_init,
-MACHINE_END
+};
diff --git a/arch/arm/mach-vexpress/headsmp.S b/arch/arm/mach-vexpress/headsmp.S
deleted file mode 100644 (file)
index 7a3f063..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  linux/arch/arm/mach-vexpress/headsmp.S
- *
- *  Copyright (c) 2003 ARM Limited
- *  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.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-       __INIT
-
-/*
- * Versatile Express specific entry point for secondary CPUs.  This
- * provides a "holding pen" into which all secondary cores are held
- * until we're ready for them to initialise.
- */
-ENTRY(vexpress_secondary_startup)
-       mrc     p15, 0, r0, c0, c0, 5
-       and     r0, r0, #15
-       adr     r4, 1f
-       ldmia   r4, {r5, r6}
-       sub     r4, r4, r5
-       add     r6, r6, r4
-pen:   ldr     r7, [r6]
-       cmp     r7, r0
-       bne     pen
-
-       /*
-        * we've been released from the holding pen: secondary_stack
-        * should now contain the SVC stack for this core
-        */
-       b       secondary_startup
-
-       .align
-1:     .long   .
-       .long   pen_release
index f9e2f8d229623d5825251e1999b0bf501a18b4a6..a34d3d4faae19c264d34372c09a11b8b274b219c 100644 (file)
@@ -45,4 +45,6 @@
 #define IRQ_CT_CA9X4_PMU_CPU2  94
 #define IRQ_CT_CA9X4_PMU_CPU3  95
 
+extern struct ct_desc ct_ca9x4_desc;
+
 #endif
index 98a8ded055bf87cd01991c1c4703c46fd5637208..0a3a375184052a81ea64f7588555919aeee899a4 100644 (file)
 int v2m_cfg_write(u32 devfn, u32 data);
 int v2m_cfg_read(u32 devfn, u32 *data);
 
+/*
+ * Core tile IDs
+ */
+#define V2M_CT_ID_CA9          0x0c000191
+#define V2M_CT_ID_UNSUPPORTED  0xff000191
+#define V2M_CT_ID_MASK         0xff000fff
+
+struct ct_desc {
+       u32                     id;
+       const char              *name;
+       void                    (*map_io)(void);
+       void                    (*init_early)(void);
+       void                    (*init_irq)(void);
+       void                    (*init_tile)(void);
+#ifdef CONFIG_SMP
+       void                    (*init_cpu_map)(void);
+       void                    (*smp_enable)(unsigned int);
+#endif
+};
+
+extern struct ct_desc *ct_desc;
+
 #endif
diff --git a/arch/arm/mach-vexpress/localtimer.c b/arch/arm/mach-vexpress/localtimer.c
deleted file mode 100644 (file)
index c0e3a59..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/arch/arm/mach-vexpress/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  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.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-#include <mach/irqs.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-}
index 634bf1d3a311d13360c32c269fedbe81e146d3fd..2b5f7ac001a3326a160c346b9a3a0706d9e3c858 100644 (file)
  */
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
 #include <linux/smp.h>
 #include <linux/io.h>
 
-#include <asm/cacheflush.h>
-#include <asm/smp_scu.h>
 #include <asm/unified.h>
 
-#include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
 #define V2M_PA_CS7 0x10000000
 
 #include "core.h"
 
-extern void vexpress_secondary_startup(void);
-
-/*
- * control for which core is the next to come out of the secondary
- * boot "holding pen"
- */
-volatile int __cpuinitdata pen_release = -1;
-
-/*
- * Write pen_release in a way that is guaranteed to be visible to all
- * observers, irrespective of whether they're taking part in coherency
- * or not.  This is necessary for the hotplug code to work reliably.
- */
-static void __cpuinit write_pen_release(int val)
-{
-       pen_release = val;
-       smp_wmb();
-       __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
-       outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-}
-
-static void __iomem *scu_base_addr(void)
-{
-       return MMIO_P2V(A9_MPCORE_SCU);
-}
-
-static DEFINE_SPINLOCK(boot_lock);
-
-void __cpuinit platform_secondary_init(unsigned int cpu)
-{
-       /*
-        * if any interrupts are already enabled for the primary
-        * core (e.g. timer irq), then they will not have been enabled
-        * for us: do so
-        */
-       gic_secondary_init(0);
-
-       /*
-        * let the primary processor know we're out of the
-        * pen, then head off into the C entry point
-        */
-       write_pen_release(-1);
-
-       /*
-        * Synchronise with the boot thread.
-        */
-       spin_lock(&boot_lock);
-       spin_unlock(&boot_lock);
-}
-
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
-{
-       unsigned long timeout;
-
-       /*
-        * Set synchronisation state between this boot processor
-        * and the secondary one
-        */
-       spin_lock(&boot_lock);
-
-       /*
-        * This is really belt and braces; we hold unintended secondary
-        * CPUs in the holding pen until we're ready for them.  However,
-        * since we haven't sent them a soft interrupt, they shouldn't
-        * be there.
-        */
-       write_pen_release(cpu);
-
-       /*
-        * Send the secondary CPU a soft interrupt, thereby causing
-        * the boot monitor to read the system wide flags register,
-        * and branch to the address found there.
-        */
-       smp_cross_call(cpumask_of(cpu), 1);
-
-       timeout = jiffies + (1 * HZ);
-       while (time_before(jiffies, timeout)) {
-               smp_rmb();
-               if (pen_release == -1)
-                       break;
-
-               udelay(10);
-       }
-
-       /*
-        * now the secondary core is starting up let it run its
-        * calibrations, then wait for it to finish
-        */
-       spin_unlock(&boot_lock);
-
-       return pen_release != -1 ? -ENOSYS : 0;
-}
+extern void versatile_secondary_startup(void);
 
 /*
  * Initialise the CPU possible map early - this describes the CPUs
@@ -125,36 +28,16 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
  */
 void __init smp_init_cpus(void)
 {
-       void __iomem *scu_base = scu_base_addr();
-       unsigned int i, ncores;
-
-       ncores = scu_base ? scu_get_core_count(scu_base) : 1;
-
-       /* sanity check */
-       if (ncores > NR_CPUS) {
-               printk(KERN_WARNING
-                      "vexpress: no. of cores (%d) greater than configured "
-                      "maximum of %d - clipping\n",
-                      ncores, NR_CPUS);
-               ncores = NR_CPUS;
-       }
-
-       for (i = 0; i < ncores; i++)
-               set_cpu_possible(i, true);
+       ct_desc->init_cpu_map();
 }
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
-
        /*
         * Initialise the present map, which describes the set of CPUs
         * actually populated at the present time.
         */
-       for (i = 0; i < max_cpus; i++)
-               set_cpu_present(i, true);
-
-       scu_enable(scu_base_addr());
+       ct_desc->smp_enable(max_cpus);
 
        /*
         * Write the address of secondary startup into the
@@ -163,6 +46,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * secondary CPU branches to this address.
         */
        writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
-       writel(BSYM(virt_to_phys(vexpress_secondary_startup)),
+       writel(BSYM(virt_to_phys(versatile_secondary_startup)),
                MMIO_P2V(V2M_SYS_FLAGSSET));
 }
index 1edae65a0e72c4cec6edea8810b8f841a4c1b46a..ba46e8e0743713b4ddbfed79c2615600b8e37506 100644 (file)
@@ -7,13 +7,16 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/ata_platform.h>
 #include <linux/smsc911x.h>
 #include <linux/spinlock.h>
 #include <linux/sysdev.h>
 #include <linux/usb/isp1760.h>
 #include <linux/clkdev.h>
 
+#include <asm/mach-types.h>
 #include <asm/sizes.h>
+#include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -21,6 +24,7 @@
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/sp810.h>
 
+#include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
 
 #include <plat/sched_clock.h>
@@ -42,19 +46,16 @@ static struct map_desc v2m_io_desc[] __initdata = {
        },
 };
 
-void __init v2m_map_io(struct map_desc *tile, size_t num)
+static void __init v2m_init_early(void)
 {
-       iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
-       iotable_init(tile, num);
+       ct_desc->init_early();
+       versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
 }
 
-
 static void __init v2m_timer_init(void)
 {
        u32 scctrl;
 
-       versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
-
        /* Select 1MHz TIMCLK as the reference clock for SP804 timers */
        scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
        scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
@@ -68,7 +69,7 @@ static void __init v2m_timer_init(void)
        sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0);
 }
 
-struct sys_timer v2m_timer = {
+static struct sys_timer v2m_timer = {
        .init   = v2m_timer_init,
 };
 
@@ -249,6 +250,29 @@ static struct platform_device v2m_flash_device = {
        .dev.platform_data = &v2m_flash_data,
 };
 
+static struct pata_platform_info v2m_pata_data = {
+       .ioport_shift   = 2,
+};
+
+static struct resource v2m_pata_resources[] = {
+       {
+               .start  = V2M_CF,
+               .end    = V2M_CF + 0xff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = V2M_CF + 0x100,
+               .end    = V2M_CF + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device v2m_cf_device = {
+       .name           = "pata_platform",
+       .id             = -1,
+       .resource       = v2m_pata_resources,
+       .num_resources  = ARRAY_SIZE(v2m_pata_resources),
+       .dev.platform_data = &v2m_pata_data,
+};
 
 static unsigned int v2m_mmci_status(struct device *dev)
 {
@@ -354,7 +378,44 @@ static void v2m_restart(char str, const char *cmd)
                printk(KERN_EMERG "Unable to reboot\n");
 }
 
-static int __init v2m_init(void)
+struct ct_desc *ct_desc;
+
+static struct ct_desc *ct_descs[] __initdata = {
+#ifdef CONFIG_ARCH_VEXPRESS_CA9X4
+       &ct_ca9x4_desc,
+#endif
+};
+
+static void __init v2m_populate_ct_desc(void)
+{
+       int i;
+       u32 current_tile_id;
+
+       ct_desc = NULL;
+       current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+
+       for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
+               if (ct_descs[i]->id == current_tile_id)
+                       ct_desc = ct_descs[i];
+
+       if (!ct_desc)
+               panic("vexpress: failed to populate core tile description "
+                     "for tile ID 0x%8x\n", current_tile_id);
+}
+
+static void __init v2m_map_io(void)
+{
+       iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+       v2m_populate_ct_desc();
+       ct_desc->map_io();
+}
+
+static void __init v2m_init_irq(void)
+{
+       ct_desc->init_irq();
+}
+
+static void __init v2m_init(void)
 {
        int i;
 
@@ -363,6 +424,7 @@ static int __init v2m_init(void)
        platform_device_register(&v2m_pcie_i2c_device);
        platform_device_register(&v2m_ddc_i2c_device);
        platform_device_register(&v2m_flash_device);
+       platform_device_register(&v2m_cf_device);
        platform_device_register(&v2m_eth_device);
        platform_device_register(&v2m_usb_device);
 
@@ -372,6 +434,14 @@ static int __init v2m_init(void)
        pm_power_off = v2m_power_off;
        arm_pm_restart = v2m_restart;
 
-       return 0;
+       ct_desc->init_tile();
 }
-arch_initcall(v2m_init);
+
+MACHINE_START(VEXPRESS, "ARM-Versatile Express")
+       .boot_params    = PLAT_PHYS_OFFSET + 0x00000100,
+       .map_io         = v2m_map_io,
+       .init_early     = v2m_init_early,
+       .init_irq       = v2m_init_irq,
+       .timer          = &v2m_timer,
+       .init_machine   = v2m_init,
+MACHINE_END
index 4771dba6144811919dc800627a4d6b860bd3b84a..82a093cee09a781677ebf639a6450bcd9f4e59fd 100644 (file)
@@ -149,6 +149,7 @@ static int __init consistent_init(void)
 {
        int ret = 0;
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        int i = 0;
@@ -156,7 +157,15 @@ static int __init consistent_init(void)
 
        do {
                pgd = pgd_offset(&init_mm, base);
-               pmd = pmd_alloc(&init_mm, pgd, base);
+
+               pud = pud_alloc(&init_mm, pgd, base);
+               if (!pud) {
+                       printk(KERN_ERR "%s: no pud tables\n", __func__);
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               pmd = pmd_alloc(&init_mm, pud, base);
                if (!pmd) {
                        printk(KERN_ERR "%s: no pmd tables\n", __func__);
                        ret = -ENOMEM;
index 01210dba02217302a3757ecc93810d46d089d43a..7cab791794218b6c49917bf0471152ea810f9e55 100644 (file)
@@ -95,6 +95,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
 {
        spinlock_t *ptl;
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        int ret;
@@ -103,7 +104,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
        if (pgd_none_or_clear_bad(pgd))
                return 0;
 
-       pmd = pmd_offset(pgd, address);
+       pud = pud_offset(pgd, address);
+       if (pud_none_or_clear_bad(pud))
+               return 0;
+
+       pmd = pmd_offset(pud, address);
        if (pmd_none_or_clear_bad(pmd))
                return 0;
 
index f10f9bac220695d02037731e6715ad510bbfb33d..bc0e1d88fd3ba8b7863edfc9eca9cb11d90413dd 100644 (file)
@@ -76,9 +76,11 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
 
        printk(KERN_ALERT "pgd = %p\n", mm->pgd);
        pgd = pgd_offset(mm, addr);
-       printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
+       printk(KERN_ALERT "[%08lx] *pgd=%08llx",
+                       addr, (long long)pgd_val(*pgd));
 
        do {
+               pud_t *pud;
                pmd_t *pmd;
                pte_t *pte;
 
@@ -90,9 +92,21 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
                        break;
                }
 
-               pmd = pmd_offset(pgd, addr);
+               pud = pud_offset(pgd, addr);
+               if (PTRS_PER_PUD != 1)
+                       printk(", *pud=%08lx", pud_val(*pud));
+
+               if (pud_none(*pud))
+                       break;
+
+               if (pud_bad(*pud)) {
+                       printk("(bad)");
+                       break;
+               }
+
+               pmd = pmd_offset(pud, addr);
                if (PTRS_PER_PMD != 1)
-                       printk(", *pmd=%08lx", pmd_val(*pmd));
+                       printk(", *pmd=%08llx", (long long)pmd_val(*pmd));
 
                if (pmd_none(*pmd))
                        break;
@@ -107,8 +121,9 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
                        break;
 
                pte = pte_offset_map(pmd, addr);
-               printk(", *pte=%08lx", pte_val(*pte));
-               printk(", *ppte=%08lx", pte_val(pte[PTE_HWTABLE_PTRS]));
+               printk(", *pte=%08llx", (long long)pte_val(*pte));
+               printk(", *ppte=%08llx",
+                      (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
                pte_unmap(pte);
        } while(0);
 
@@ -388,6 +403,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
 {
        unsigned int index;
        pgd_t *pgd, *pgd_k;
+       pud_t *pud, *pud_k;
        pmd_t *pmd, *pmd_k;
 
        if (addr < TASK_SIZE)
@@ -406,12 +422,19 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
 
        if (pgd_none(*pgd_k))
                goto bad_area;
-
        if (!pgd_present(*pgd))
                set_pgd(pgd, *pgd_k);
 
-       pmd_k = pmd_offset(pgd_k, addr);
-       pmd   = pmd_offset(pgd, addr);
+       pud = pud_offset(pgd, addr);
+       pud_k = pud_offset(pgd_k, addr);
+
+       if (pud_none(*pud_k))
+               goto bad_area;
+       if (!pud_present(*pud))
+               set_pud(pud, *pud_k);
+
+       pmd = pmd_offset(pud, addr);
+       pmd_k = pmd_offset(pud_k, addr);
 
        /*
         * On ARM one Linux PGD entry contains two hardware entries (see page
index 57299446f7871d8b77adacdc27f7644b5e4c2168..2be9139a4ef3cc5af97f03a30eefefe7d019740e 100644 (file)
@@ -4,10 +4,10 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 
-static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end,
+static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
        unsigned long prot)
 {
-       pmd_t *pmd = pmd_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
 
        addr = (addr & PMD_MASK) | prot;
        pmd[0] = __pmd(addr);
@@ -16,6 +16,18 @@ static void idmap_add_pmd(pgd_t *pgd, unsigned long addr, unsigned long end,
        flush_pmd_entry(pmd);
 }
 
+static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
+       unsigned long prot)
+{
+       pud_t *pud = pud_offset(pgd, addr);
+       unsigned long next;
+
+       do {
+               next = pud_addr_end(addr, end);
+               idmap_add_pmd(pud, addr, next, prot);
+       } while (pud++, addr = next, addr != end);
+}
+
 void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
 {
        unsigned long prot, next;
@@ -27,17 +39,28 @@ void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
        pgd += pgd_index(addr);
        do {
                next = pgd_addr_end(addr, end);
-               idmap_add_pmd(pgd, addr, next, prot);
+               idmap_add_pud(pgd, addr, next, prot);
        } while (pgd++, addr = next, addr != end);
 }
 
 #ifdef CONFIG_SMP
-static void idmap_del_pmd(pgd_t *pgd, unsigned long addr, unsigned long end)
+static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end)
 {
-       pmd_t *pmd = pmd_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
        pmd_clear(pmd);
 }
 
+static void idmap_del_pud(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       pud_t *pud = pud_offset(pgd, addr);
+       unsigned long next;
+
+       do {
+               next = pud_addr_end(addr, end);
+               idmap_del_pmd(pud, addr, next);
+       } while (pud++, addr = next, addr != end);
+}
+
 void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
 {
        unsigned long next;
@@ -45,7 +68,7 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end)
        pgd += pgd_index(addr);
        do {
                next = pgd_addr_end(addr, end);
-               idmap_del_pmd(pgd, addr, next);
+               idmap_del_pud(pgd, addr, next);
        } while (pgd++, addr = next, addr != end);
 }
 #endif
index cddd684364dab2f6503d20132d8f5047615a2a52..e5f6fc42834892e7622664b496d3aa0288eaa2ff 100644 (file)
@@ -78,7 +78,7 @@ __tagtable(ATAG_INITRD2, parse_tag_initrd2);
  */
 struct meminfo meminfo;
 
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        int free = 0, total = 0, reserved = 0;
        int shared = 0, cached = 0, slab = 0, i;
@@ -350,7 +350,7 @@ void __init bootmem_init(void)
         */
        arm_bootmem_free(min, max_low, max_high);
 
-       high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
+       high_memory = __va(((phys_addr_t)max_low << PAGE_SHIFT) - 1) + 1;
 
        /*
         * This doesn't seem to be used by the Linux memory manager any
@@ -398,8 +398,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
         * Convert to physical addresses, and
         * round start upwards and end downwards.
         */
-       pg = PAGE_ALIGN(__pa(start_pg));
-       pgend = __pa(end_pg) & PAGE_MASK;
+       pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
+       pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
 
        /*
         * If there are free pages between these,
index 36960df5fb762a990be65bba9d92efba3657d8ed..d2384106af9cbb32f96a61d54570ef39d391c5b7 100644 (file)
@@ -7,7 +7,7 @@ extern pmd_t *top_pmd;
 
 static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
 {
-       return pmd_offset(pgd, virt);
+       return pmd_offset(pud_offset(pgd, virt), virt);
 }
 
 static inline pmd_t *pmd_off_k(unsigned long virt)
index ff7b43b5885ab7834d0953b1cba376de6c7242ed..6cf76b3b68d1f374fcbc6be0c38224161f7db477 100644 (file)
@@ -533,7 +533,7 @@ static void __init *early_alloc(unsigned long sz)
 static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
 {
        if (pmd_none(*pmd)) {
-               pte_t *pte = early_alloc(2 * PTRS_PER_PTE * sizeof(pte_t));
+               pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
                __pmd_populate(pmd, __pa(pte), prot);
        }
        BUG_ON(pmd_bad(*pmd));
@@ -551,11 +551,11 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
        } while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
-static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
+static void __init alloc_init_section(pud_t *pud, unsigned long addr,
                                      unsigned long end, phys_addr_t phys,
                                      const struct mem_type *type)
 {
-       pmd_t *pmd = pmd_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
 
        /*
         * Try a section mapping - end, addr and phys must all be aligned
@@ -584,6 +584,19 @@ static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
        }
 }
 
+static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
+       unsigned long phys, const struct mem_type *type)
+{
+       pud_t *pud = pud_offset(pgd, addr);
+       unsigned long next;
+
+       do {
+               next = pud_addr_end(addr, end);
+               alloc_init_section(pud, addr, next, phys, type);
+               phys += next - addr;
+       } while (pud++, addr = next, addr != end);
+}
+
 static void __init create_36bit_mapping(struct map_desc *md,
                                        const struct mem_type *type)
 {
@@ -592,13 +605,13 @@ static void __init create_36bit_mapping(struct map_desc *md,
        pgd_t *pgd;
 
        addr = md->virtual;
-       phys = (unsigned long)__pfn_to_phys(md->pfn);
+       phys = __pfn_to_phys(md->pfn);
        length = PAGE_ALIGN(md->length);
 
        if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
                printk(KERN_ERR "MM: CPU does not support supersection "
                       "mapping for 0x%08llx at 0x%08lx\n",
-                      __pfn_to_phys((u64)md->pfn), addr);
+                      (long long)__pfn_to_phys((u64)md->pfn), addr);
                return;
        }
 
@@ -611,14 +624,14 @@ static void __init create_36bit_mapping(struct map_desc *md,
        if (type->domain) {
                printk(KERN_ERR "MM: invalid domain in supersection "
                       "mapping for 0x%08llx at 0x%08lx\n",
-                      __pfn_to_phys((u64)md->pfn), addr);
+                      (long long)__pfn_to_phys((u64)md->pfn), addr);
                return;
        }
 
        if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) {
-               printk(KERN_ERR "MM: cannot create mapping for "
-                      "0x%08llx at 0x%08lx invalid alignment\n",
-                      __pfn_to_phys((u64)md->pfn), addr);
+               printk(KERN_ERR "MM: cannot create mapping for 0x%08llx"
+                      " at 0x%08lx invalid alignment\n",
+                      (long long)__pfn_to_phys((u64)md->pfn), addr);
                return;
        }
 
@@ -631,7 +644,8 @@ static void __init create_36bit_mapping(struct map_desc *md,
        pgd = pgd_offset_k(addr);
        end = addr + length;
        do {
-               pmd_t *pmd = pmd_offset(pgd, addr);
+               pud_t *pud = pud_offset(pgd, addr);
+               pmd_t *pmd = pmd_offset(pud, addr);
                int i;
 
                for (i = 0; i < 16; i++)
@@ -652,22 +666,23 @@ static void __init create_36bit_mapping(struct map_desc *md,
  */
 static void __init create_mapping(struct map_desc *md)
 {
-       unsigned long phys, addr, length, end;
+       unsigned long addr, length, end;
+       phys_addr_t phys;
        const struct mem_type *type;
        pgd_t *pgd;
 
        if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
-               printk(KERN_WARNING "BUG: not creating mapping for "
-                      "0x%08llx at 0x%08lx in user region\n",
-                      __pfn_to_phys((u64)md->pfn), md->virtual);
+               printk(KERN_WARNING "BUG: not creating mapping for 0x%08llx"
+                      " at 0x%08lx in user region\n",
+                      (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
                return;
        }
 
        if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
            md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
-               printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
-                      "overlaps vmalloc space\n",
-                      __pfn_to_phys((u64)md->pfn), md->virtual);
+               printk(KERN_WARNING "BUG: mapping for 0x%08llx"
+                      " at 0x%08lx overlaps vmalloc space\n",
+                      (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
        }
 
        type = &mem_types[md->type];
@@ -681,13 +696,13 @@ static void __init create_mapping(struct map_desc *md)
        }
 
        addr = md->virtual & PAGE_MASK;
-       phys = (unsigned long)__pfn_to_phys(md->pfn);
+       phys = __pfn_to_phys(md->pfn);
        length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
 
        if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
-               printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
+               printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not "
                       "be mapped using pages, ignoring.\n",
-                      __pfn_to_phys(md->pfn), addr);
+                      (long long)__pfn_to_phys(md->pfn), addr);
                return;
        }
 
@@ -696,7 +711,7 @@ static void __init create_mapping(struct map_desc *md)
        do {
                unsigned long next = pgd_addr_end(addr, end);
 
-               alloc_init_section(pgd, addr, next, phys, type);
+               alloc_init_pud(pgd, addr, next, phys, type);
 
                phys += next - addr;
                addr = next;
@@ -794,9 +809,10 @@ static void __init sanity_check_meminfo(void)
                 */
                if (__va(bank->start) >= vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET) {
-                       printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
+                       printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
                               "(vmalloc region overlap).\n",
-                              bank->start, bank->start + bank->size - 1);
+                              (unsigned long long)bank->start,
+                              (unsigned long long)bank->start + bank->size - 1);
                        continue;
                }
 
@@ -807,10 +823,11 @@ static void __init sanity_check_meminfo(void)
                if (__va(bank->start + bank->size) > vmalloc_min ||
                    __va(bank->start + bank->size) < __va(bank->start)) {
                        unsigned long newsize = vmalloc_min - __va(bank->start);
-                       printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx "
-                              "to -%.8lx (vmalloc region overlap).\n",
-                              bank->start, bank->start + bank->size - 1,
-                              bank->start + newsize - 1);
+                       printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
+                              "to -%.8llx (vmalloc region overlap).\n",
+                              (unsigned long long)bank->start,
+                              (unsigned long long)bank->start + bank->size - 1,
+                              (unsigned long long)bank->start + newsize - 1);
                        bank->size = newsize;
                }
 #endif
index 709244c66fa3148b3f144310216240fdadfac9a6..b2027c154b2a0c946198de99370a89be2f60b6eb 100644 (file)
@@ -23,6 +23,7 @@
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *new_pgd, *init_pgd;
+       pud_t *new_pud, *init_pud;
        pmd_t *new_pmd, *init_pmd;
        pte_t *new_pte, *init_pte;
 
@@ -46,7 +47,11 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
                 * On ARM, first page must always be allocated since it
                 * contains the machine vectors.
                 */
-               new_pmd = pmd_alloc(mm, new_pgd, 0);
+               new_pud = pud_alloc(mm, new_pgd, 0);
+               if (!new_pud)
+                       goto no_pud;
+
+               new_pmd = pmd_alloc(mm, new_pud, 0);
                if (!new_pmd)
                        goto no_pmd;
 
@@ -54,7 +59,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
                if (!new_pte)
                        goto no_pte;
 
-               init_pmd = pmd_offset(init_pgd, 0);
+               init_pud = pud_offset(init_pgd, 0);
+               init_pmd = pmd_offset(init_pud, 0);
                init_pte = pte_offset_map(init_pmd, 0);
                set_pte_ext(new_pte, *init_pte, 0);
                pte_unmap(init_pte);
@@ -66,6 +72,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 no_pte:
        pmd_free(mm, new_pmd);
 no_pmd:
+       pud_free(mm, new_pud);
+no_pud:
        free_pages((unsigned long)new_pgd, 2);
 no_pgd:
        return NULL;
@@ -74,6 +82,7 @@ no_pgd:
 void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
 {
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pgtable_t pte;
 
@@ -84,7 +93,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
        if (pgd_none_or_clear_bad(pgd))
                goto no_pgd;
 
-       pmd = pmd_offset(pgd, 0);
+       pud = pud_offset(pgd, 0);
+       if (pud_none_or_clear_bad(pud))
+               goto no_pud;
+
+       pmd = pmd_offset(pud, 0);
        if (pmd_none_or_clear_bad(pmd))
                goto no_pmd;
 
@@ -92,8 +105,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
        pmd_clear(pmd);
        pte_free(mm, pte);
 no_pmd:
-       pgd_clear(pgd);
+       pud_clear(pud);
        pmd_free(mm, pmd);
+no_pud:
+       pgd_clear(pgd);
+       pud_free(mm, pud);
 no_pgd:
        free_pages((unsigned long) pgd_base, 2);
 }
index a48a9aaa56b1dd46093eb94288080bd2262c5062..86003f411755f02d29a937e547b9191a39cf4b77 100644 (file)
 #ifndef __ASM_ARCH_IMX_ESDHC_H
 #define __ASM_ARCH_IMX_ESDHC_H
 
+/**
+ * struct esdhc_platform_data - optional platform data for esdhc on i.MX
+ *
+ * strongly recommended for i.MX25/35, not needed for other variants
+ *
+ * @wp_gpio:   gpio for write_protect (-EINVAL if unused)
+ * @cd_gpio:   gpio for card_detect interrupt (-EINVAL if unused)
+ */
+
 struct esdhc_platform_data {
-       unsigned int wp_gpio;   /* write protect pin */
+       unsigned int wp_gpio;
+       unsigned int cd_gpio;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
index 70620426ee550fb4ecb8300e1ad144fd7d429623..80643bc38e10deb1695d210d9ec29bab823275ab 100644 (file)
@@ -832,51 +832,6 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                                : "?  ",
                        (mode < 0) ? "unknown" : modes[mode],
                        pull ? "pull" : "none");
-
-               if (!is_out) {
-                       int             irq = gpio_to_irq(gpio);
-                       struct irq_desc *desc = irq_to_desc(irq);
-
-                       /* This races with request_irq(), set_irq_type(),
-                        * and set_irq_wake() ... but those are "rare".
-                        *
-                        * More significantly, trigger type flags aren't
-                        * currently maintained by genirq.
-                        */
-                       if (irq >= 0 && desc->action) {
-                               char *trigger;
-
-                               switch (desc->status & IRQ_TYPE_SENSE_MASK) {
-                               case IRQ_TYPE_NONE:
-                                       trigger = "(default)";
-                                       break;
-                               case IRQ_TYPE_EDGE_FALLING:
-                                       trigger = "edge-falling";
-                                       break;
-                               case IRQ_TYPE_EDGE_RISING:
-                                       trigger = "edge-rising";
-                                       break;
-                               case IRQ_TYPE_EDGE_BOTH:
-                                       trigger = "edge-both";
-                                       break;
-                               case IRQ_TYPE_LEVEL_HIGH:
-                                       trigger = "level-high";
-                                       break;
-                               case IRQ_TYPE_LEVEL_LOW:
-                                       trigger = "level-low";
-                                       break;
-                               default:
-                                       trigger = "?trigger?";
-                                       break;
-                               }
-
-                               seq_printf(s, " irq-%d %s%s",
-                                       irq, trigger,
-                                       (desc->status & IRQ_WAKEUP)
-                                               ? " wakeup" : "");
-                       }
-               }
-
                seq_printf(s, "\n");
        }
 }
index 4d6dd4c39b750e76cdf199f6ee00713d3e3731cb..c44886062f8ed7673884e2402422e9443c7bab99 100644 (file)
@@ -104,6 +104,8 @@ struct stedma40_half_channel_info {
  *
  * @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH
  * @high_priority: true if high-priority
+ * @realtime: true if realtime mode is to be enabled.  Only available on DMA40
+ * version 3+, i.e DB8500v2+
  * @mode: channel mode: physical, logical, or operation
  * @mode_opt: options for the chosen channel mode
  * @src_dev_type: Src device type
@@ -119,6 +121,7 @@ struct stedma40_half_channel_info {
 struct stedma40_chan_cfg {
        enum stedma40_xfer_dir                   dir;
        bool                                     high_priority;
+       bool                                     realtime;
        enum stedma40_mode                       mode;
        enum stedma40_mode_opt                   mode_opt;
        int                                      src_dev_type;
@@ -168,25 +171,6 @@ struct stedma40_platform_data {
 
 bool stedma40_filter(struct dma_chan *chan, void *data);
 
-/**
- * stedma40_memcpy_sg() - extension of the dma framework, memcpy to/from
- * scattergatter lists.
- *
- * @chan: dmaengine handle
- * @sgl_dst: Destination scatter list
- * @sgl_src: Source scatter list
- * @sgl_len: The length of each scatterlist. Both lists must be of equal length
- * and each element must match the corresponding element in the other scatter
- * list.
- * @flags: is actually enum dma_ctrl_flags. See dmaengine.h
- */
-
-struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
-                                                  struct scatterlist *sgl_dst,
-                                                  struct scatterlist *sgl_src,
-                                                  unsigned int sgl_len,
-                                                  unsigned long flags);
-
 /**
  * stedma40_slave_mem() - Transfers a raw data buffer to or from a slave
  * (=device)
index 0f140ecedb01da592e8f8d923a5a3a31b093cee1..5e04ddc18fa8c512fbafb205e6818d1b064e2335 100644 (file)
@@ -58,6 +58,7 @@ enum omap_display_type {
        OMAP_DISPLAY_TYPE_SDI           = 1 << 2,
        OMAP_DISPLAY_TYPE_DSI           = 1 << 3,
        OMAP_DISPLAY_TYPE_VENC          = 1 << 4,
+       OMAP_DISPLAY_TYPE_HDMI          = 1 << 5,
 };
 
 enum omap_plane {
@@ -237,6 +238,13 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data)
 }
 #endif
 
+struct omap_display_platform_data {
+       struct omap_dss_board_info *board_data;
+       /* TODO: Additional members to be added when PM is considered */
+
+       bool (*opt_clock_available)(const char *clk_role);
+};
+
 struct omap_video_timings {
        /* Unit: pixels */
        u16 x_res;
@@ -396,8 +404,8 @@ struct omap_dss_device {
                        struct {
                                u16 regn;
                                u16 regm;
-                               u16 regm3;
-                               u16 regm4;
+                               u16 regm_dispc;
+                               u16 regm_dsi;
 
                                u16 lp_clk_div;
 
@@ -555,6 +563,9 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
                int channel,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(int, void *), void *data);
+int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel);
+int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
+void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dsi_display_disable(struct omap_dss_device *dssdev);
index 98fc8b4a4cc4df60300327449080d52674caeefa..b9e85886b9d641964267361041a70e3fa7741467 100644 (file)
 #define OMAP3430_ISP_RESZ_BASE         (OMAP3430_ISP_BASE + 0x1000)
 #define OMAP3430_ISP_SBL_BASE          (OMAP3430_ISP_BASE + 0x1200)
 #define OMAP3430_ISP_MMU_BASE          (OMAP3430_ISP_BASE + 0x1400)
-#define OMAP3430_ISP_CSI2A_BASE                (OMAP3430_ISP_BASE + 0x1800)
-#define OMAP3430_ISP_CSI2PHY_BASE      (OMAP3430_ISP_BASE + 0x1970)
+#define OMAP3430_ISP_CSI2A_REGS1_BASE  (OMAP3430_ISP_BASE + 0x1800)
+#define OMAP3430_ISP_CSIPHY2_BASE      (OMAP3430_ISP_BASE + 0x1970)
+#define OMAP3630_ISP_CSI2A_REGS2_BASE  (OMAP3430_ISP_BASE + 0x19C0)
+#define OMAP3630_ISP_CSI2C_REGS1_BASE  (OMAP3430_ISP_BASE + 0x1C00)
+#define OMAP3630_ISP_CSIPHY1_BASE      (OMAP3430_ISP_BASE + 0x1D70)
+#define OMAP3630_ISP_CSI2C_REGS2_BASE  (OMAP3430_ISP_BASE + 0x1DC0)
 
 #define OMAP3430_ISP_END               (OMAP3430_ISP_BASE         + 0x06F)
 #define OMAP3430_ISP_CBUFF_END         (OMAP3430_ISP_CBUFF_BASE   + 0x077)
 #define OMAP3430_ISP_RESZ_END          (OMAP3430_ISP_RESZ_BASE    + 0x0AB)
 #define OMAP3430_ISP_SBL_END           (OMAP3430_ISP_SBL_BASE     + 0x0FB)
 #define OMAP3430_ISP_MMU_END           (OMAP3430_ISP_MMU_BASE     + 0x06F)
-#define OMAP3430_ISP_CSI2A_END         (OMAP3430_ISP_CSI2A_BASE   + 0x16F)
-#define OMAP3430_ISP_CSI2PHY_END       (OMAP3430_ISP_CSI2PHY_BASE + 0x007)
+#define OMAP3430_ISP_CSI2A_REGS1_END   (OMAP3430_ISP_CSI2A_REGS1_BASE + 0x16F)
+#define OMAP3430_ISP_CSIPHY2_END       (OMAP3430_ISP_CSIPHY2_BASE + 0x00B)
+#define OMAP3630_ISP_CSI2A_REGS2_END   (OMAP3630_ISP_CSI2A_REGS2_BASE + 0x3F)
+#define OMAP3630_ISP_CSI2C_REGS1_END   (OMAP3630_ISP_CSI2C_REGS1_BASE + 0x16F)
+#define OMAP3630_ISP_CSIPHY1_END       (OMAP3630_ISP_CSIPHY1_BASE + 0x00B)
+#define OMAP3630_ISP_CSI2C_REGS2_END   (OMAP3630_ISP_CSI2C_REGS2_BASE + 0x3F)
 
 #define OMAP34XX_HSUSB_OTG_BASE        (L4_34XX_BASE + 0xAB000)
 #define OMAP34XX_USBTLL_BASE   (L4_34XX_BASE + 0x62000)
diff --git a/arch/arm/plat-pxa/include/plat/i2c.h b/arch/arm/plat-pxa/include/plat/i2c.h
deleted file mode 100644 (file)
index 1a9f65e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *  i2c_pxa.h
- *
- *  Copyright (C) 2002 Intrinsyc Software Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- */
-#ifndef _I2C_PXA_H_
-#define _I2C_PXA_H_
-
-#if 0
-#define DEF_TIMEOUT             3
-#else
-/* need a longer timeout if we're dealing with the fact we may well be
- * looking at a multi-master environment
-*/
-#define DEF_TIMEOUT             32
-#endif
-
-#define BUS_ERROR               (-EREMOTEIO)
-#define XFER_NAKED              (-ECONNREFUSED)
-#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
-
-/* ICR initialize bit values
-*
-*  15. FM       0 (100 Khz operation)
-*  14. UR       0 (No unit reset)
-*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
-*                                       matching its slave address)
-*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
-*                                       in master mode)
-*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
-*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
-*  9.  IRFIE    1 (Enable interrupts from full buffer received)
-*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
-*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
-*  6.  IUE      0 (Disable unit until we change settings)
-*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
-*  4.  MA       0 (Only send stop with the ICR stop bit)
-*  3.  TB       0 (We are not transmitting a byte initially)
-*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
-*  1.  STOP     0 (Do not send a STOP)
-*  0.  START    0 (Do not send a START)
-*
-*/
-#define I2C_ICR_INIT   (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
-
-/* I2C status register init values
- *
- * 10. BED      1 (Clear bus error detected)
- * 9.  SAD      1 (Clear slave address detected)
- * 7.  IRF      1 (Clear IDBR Receive Full)
- * 6.  ITE      1 (Clear IDBR Transmit Empty)
- * 5.  ALD      1 (Clear Arbitration Loss Detected)
- * 4.  SSD      1 (Clear Slave Stop Detected)
- */
-#define I2C_ISR_INIT   0x7FF  /* status register init */
-
-struct i2c_slave_client;
-
-struct i2c_pxa_platform_data {
-       unsigned int            slave_addr;
-       struct i2c_slave_client *slave;
-       unsigned int            class;
-       unsigned int            use_pio :1;
-       unsigned int            fast_mode :1;
-};
-
-extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
-
-#ifdef CONFIG_PXA27x
-extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info);
-#endif
-
-#ifdef CONFIG_PXA3xx
-extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info);
-#endif
-
-#endif
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
new file mode 100644 (file)
index 0000000..52353be
--- /dev/null
@@ -0,0 +1,17 @@
+if PLAT_VERSATILE
+
+config PLAT_VERSATILE_CLCD
+       bool
+
+config PLAT_VERSATILE_FPGA_IRQ
+       bool
+
+config PLAT_VERSATILE_LEDS
+       def_bool y if LEDS_CLASS
+       depends on ARCH_REALVIEW || ARCH_VERSATILE
+
+config PLAT_VERSATILE_SCHED_CLOCK
+       def_bool y if !ARCH_INTEGRATOR_AP
+       select HAVE_SCHED_CLOCK
+
+endif
index 16dde08199349b4a004ab58746f43d40d0d88424..69714db47c33395e286027f285aacc10bffbbf42 100644 (file)
@@ -1,8 +1,7 @@
 obj-y  := clock.o
-ifneq ($(CONFIG_ARCH_INTEGRATOR),y)
-obj-y  += sched-clock.o
-endif
-ifeq ($(CONFIG_LEDS_CLASS),y)
-obj-$(CONFIG_ARCH_REALVIEW) += leds.o
-obj-$(CONFIG_ARCH_VERSATILE) += leds.o
-endif
+obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
+obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
+obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
+obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
+obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o
+obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/plat-versatile/clcd.c b/arch/arm/plat-versatile/clcd.c
new file mode 100644 (file)
index 0000000..6628cc2
--- /dev/null
@@ -0,0 +1,182 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <plat/clcd.h>
+
+static struct clcd_panel vga = {
+       .mode           = {
+               .name           = "VGA",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 39721,
+               .left_margin    = 40,
+               .right_margin   = 24,
+               .upper_margin   = 32,
+               .lower_margin   = 11,
+               .hsync_len      = 96,
+               .vsync_len      = 2,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
+       .bpp            = 16,
+};
+
+static struct clcd_panel xvga = {
+       .mode           = {
+               .name           = "XVGA",
+               .refresh        = 60,
+               .xres           = 1024,
+               .yres           = 768,
+               .pixclock       = 15748,
+               .left_margin    = 152,
+               .right_margin   = 48,
+               .upper_margin   = 23,
+               .lower_margin   = 3,
+               .hsync_len      = 104,
+               .vsync_len      = 4,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551 | CLCD_CAP_565 | CLCD_CAP_888,
+       .bpp            = 16,
+};
+
+/* Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT */
+static struct clcd_panel sanyo_tm38qv67a02a = {
+       .mode           = {
+               .name           = "Sanyo TM38QV67A02A",
+               .refresh        = 116,
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = 100000,
+               .left_margin    = 6,
+               .right_margin   = 6,
+               .upper_margin   = 5,
+               .lower_margin   = 5,
+               .hsync_len      = 6,
+               .vsync_len      = 6,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
+       .bpp            = 16,
+};
+
+static struct clcd_panel sanyo_2_5_in = {
+       .mode           = {
+               .name           = "Sanyo QVGA Portrait",
+               .refresh        = 116,
+               .xres           = 240,
+               .yres           = 320,
+               .pixclock       = 100000,
+               .left_margin    = 20,
+               .right_margin   = 10,
+               .upper_margin   = 2,
+               .lower_margin   = 2,
+               .hsync_len      = 10,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
+       .bpp            = 16,
+};
+
+/* Epson L2F50113T00 - 2.2 inch 176x220 Color TFT */
+static struct clcd_panel epson_l2f50113t00 = {
+       .mode           = {
+               .name           = "Epson L2F50113T00",
+               .refresh        = 390,
+               .xres           = 176,
+               .yres           = 220,
+               .pixclock       = 62500,
+               .left_margin    = 3,
+               .right_margin   = 2,
+               .upper_margin   = 1,
+               .lower_margin   = 0,
+               .hsync_len      = 3,
+               .vsync_len      = 2,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .caps           = CLCD_CAP_5551,
+       .bpp            = 16,
+};
+
+static struct clcd_panel *panels[] = {
+       &vga,
+       &xvga,
+       &sanyo_tm38qv67a02a,
+       &sanyo_2_5_in,
+       &epson_l2f50113t00,
+};
+
+struct clcd_panel *versatile_clcd_get_panel(const char *name)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(panels); i++)
+               if (strcmp(panels[i]->mode.name, name) == 0)
+                       break;
+
+       if (i < ARRAY_SIZE(panels))
+               return panels[i];
+
+       pr_err("CLCD: couldn't get parameters for panel %s\n", name);
+
+       return NULL;
+}
+
+int versatile_clcd_setup_dma(struct clcd_fb *fb, unsigned long framesize)
+{
+       dma_addr_t dma;
+
+       fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
+                                                   &dma, GFP_KERNEL);
+       if (!fb->fb.screen_base) {
+               pr_err("CLCD: unable to map framebuffer\n");
+               return -ENOMEM;
+       }
+
+       fb->fb.fix.smem_start   = dma;
+       fb->fb.fix.smem_len     = framesize;
+
+       return 0;
+}
+
+int versatile_clcd_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+       return dma_mmap_writecombine(&fb->dev->dev, vma,
+                                    fb->fb.screen_base,
+                                    fb->fb.fix.smem_start,
+                                    fb->fb.fix.smem_len);
+}
+
+void versatile_clcd_remove_dma(struct clcd_fb *fb)
+{
+       dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+                             fb->fb.screen_base, fb->fb.fix.smem_start);
+}
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c
new file mode 100644 (file)
index 0000000..31d945d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  Support for Versatile FPGA-based IRQ controllers
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/mach/irq.h>
+#include <plat/fpga-irq.h>
+
+#define IRQ_STATUS             0x00
+#define IRQ_RAW_STATUS         0x04
+#define IRQ_ENABLE_SET         0x08
+#define IRQ_ENABLE_CLEAR       0x0c
+
+static void fpga_irq_mask(struct irq_data *d)
+{
+       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - f->irq_start);
+
+       writel(mask, f->base + IRQ_ENABLE_CLEAR);
+}
+
+static void fpga_irq_unmask(struct irq_data *d)
+{
+       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << (d->irq - f->irq_start);
+
+       writel(mask, f->base + IRQ_ENABLE_SET);
+}
+
+static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc)
+{
+       struct fpga_irq_data *f = get_irq_desc_data(desc);
+       u32 status = readl(f->base + IRQ_STATUS);
+
+       if (status == 0) {
+               do_bad_IRQ(irq, desc);
+               return;
+       }
+
+       do {
+               irq = ffs(status) - 1;
+               status &= ~(1 << irq);
+
+               generic_handle_irq(irq + f->irq_start);
+       } while (status);
+}
+
+void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f)
+{
+       unsigned int i;
+
+       f->chip.irq_ack = fpga_irq_mask;
+       f->chip.irq_mask = fpga_irq_mask;
+       f->chip.irq_unmask = fpga_irq_unmask;
+
+       if (parent_irq != -1) {
+               set_irq_data(parent_irq, f);
+               set_irq_chained_handler(parent_irq, fpga_irq_handle);
+       }
+
+       for (i = 0; i < 32; i++) {
+               if (valid & (1 << i)) {
+                       unsigned int irq = f->irq_start + i;
+
+                       set_irq_chip_data(irq, f);
+                       set_irq_chip(irq, &f->chip);
+                       set_irq_handler(irq, handle_level_irq);
+                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+               }
+       }
+}
diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S
new file mode 100644 (file)
index 0000000..d397a1f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  linux/arch/arm/plat-versatile/headsmp.S
+ *
+ *  Copyright (c) 2003 ARM Limited
+ *  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.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+       __INIT
+
+/*
+ * Realview/Versatile Express specific entry point for secondary CPUs.
+ * This provides a "holding pen" into which all secondary cores are held
+ * until we're ready for them to initialise.
+ */
+ENTRY(versatile_secondary_startup)
+       mrc     p15, 0, r0, c0, c0, 5
+       and     r0, r0, #15
+       adr     r4, 1f
+       ldmia   r4, {r5, r6}
+       sub     r4, r4, r5
+       add     r6, r6, r4
+pen:   ldr     r7, [r6]
+       cmp     r7, r0
+       bne     pen
+
+       /*
+        * we've been released from the holding pen: secondary_stack
+        * should now contain the SVC stack for this core
+        */
+       b       secondary_startup
+
+       .align
+1:     .long   .
+       .long   pen_release
diff --git a/arch/arm/plat-versatile/include/plat/clcd.h b/arch/arm/plat-versatile/include/plat/clcd.h
new file mode 100644 (file)
index 0000000..6bb6a1d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef PLAT_CLCD_H
+#define PLAT_CLCD_H
+
+struct clcd_panel *versatile_clcd_get_panel(const char *);
+int versatile_clcd_setup_dma(struct clcd_fb *, unsigned long);
+int versatile_clcd_mmap_dma(struct clcd_fb *, struct vm_area_struct *);
+void versatile_clcd_remove_dma(struct clcd_fb *);
+
+#endif
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h
new file mode 100644 (file)
index 0000000..627fafd
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef PLAT_FPGA_IRQ_H
+#define PLAT_FPGA_IRQ_H
+
+struct fpga_irq_data {
+       void __iomem *base;
+       unsigned int irq_start;
+       struct irq_chip chip;
+};
+
+void fpga_irq_init(int, u32, struct fpga_irq_data *);
+
+#endif
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c
new file mode 100644 (file)
index 0000000..0fb3961
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  linux/arch/arm/plat-versatile/localtimer.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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.
+ */
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/clockchips.h>
+
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <mach/irqs.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+       evt->irq = IRQ_LOCALTIMER;
+       twd_timer_setup(evt);
+       return 0;
+}
diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c
new file mode 100644 (file)
index 0000000..ba3d471
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  linux/arch/arm/plat-versatile/platsmp.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  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.
+ */
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+
+/*
+ * control for which core is the next to come out of the secondary
+ * boot "holding pen"
+ */
+volatile int __cpuinitdata pen_release = -1;
+
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not.  This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+       pen_release = val;
+       smp_wmb();
+       __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+       outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+       /*
+        * if any interrupts are already enabled for the primary
+        * core (e.g. timer irq), then they will not have been enabled
+        * for us: do so
+        */
+       gic_secondary_init(0);
+
+       /*
+        * let the primary processor know we're out of the
+        * pen, then head off into the C entry point
+        */
+       write_pen_release(-1);
+
+       /*
+        * Synchronise with the boot thread.
+        */
+       spin_lock(&boot_lock);
+       spin_unlock(&boot_lock);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       unsigned long timeout;
+
+       /*
+        * Set synchronisation state between this boot processor
+        * and the secondary one
+        */
+       spin_lock(&boot_lock);
+
+       /*
+        * This is really belt and braces; we hold unintended secondary
+        * CPUs in the holding pen until we're ready for them.  However,
+        * since we haven't sent them a soft interrupt, they shouldn't
+        * be there.
+        */
+       write_pen_release(cpu);
+
+       /*
+        * Send the secondary CPU a soft interrupt, thereby causing
+        * the boot monitor to read the system wide flags register,
+        * and branch to the address found there.
+        */
+       smp_cross_call(cpumask_of(cpu), 1);
+
+       timeout = jiffies + (1 * HZ);
+       while (time_before(jiffies, timeout)) {
+               smp_rmb();
+               if (pen_release == -1)
+                       break;
+
+               udelay(10);
+       }
+
+       /*
+        * now the secondary core is starting up let it run its
+        * calibrations, then wait for it to finish
+        */
+       spin_unlock(&boot_lock);
+
+       return pen_release != -1 ? -ENOSYS : 0;
+}
index 9d6feaabbe7d10007a32fc71e846f234d10682ec..7ca41f0a09b125ecd1c86e12e580a0edddb11e0e 100644 (file)
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Mon Feb 7 08:59:27 2011
+# XXX: This is a cut-down version of the file; it contains only machines that
+# XXX: are in mainline or have been submitted to the machine database within
+# XXX: the last 12 months.  If your entry is missing please email rmk at
+# XXX: <linux@arm.linux.org.uk>
+#
+# Last update: Sun Mar 20 18:06:11 2011
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
 ebsa110                        ARCH_EBSA110            EBSA110                 0
 riscpc                 ARCH_RPC                RISCPC                  1
-nexuspci               ARCH_NEXUSPCI           NEXUSPCI                3
 ebsa285                        ARCH_EBSA285            EBSA285                 4
 netwinder              ARCH_NETWINDER          NETWINDER               5
 cats                   ARCH_CATS               CATS                    6
-tbox                   ARCH_TBOX               TBOX                    7
-co285                  ARCH_CO285              CO285                   8
-clps7110               ARCH_CLPS7110           CLPS7110                9
-archimedes             ARCH_ARC                ARCHIMEDES              10
-a5k                    ARCH_A5K                A5K                     11
-etoile                 ARCH_ETOILE             ETOILE                  12
-lacie_nas              ARCH_LACIE_NAS          LACIE_NAS               13
-clps7500               ARCH_CLPS7500           CLPS7500                14
 shark                  ARCH_SHARK              SHARK                   15
 brutus                 SA1100_BRUTUS           BRUTUS                  16
 personal_server                ARCH_PERSONAL_SERVER    PERSONAL_SERVER         17
-itsy                   SA1100_ITSY             ITSY                    18
 l7200                  ARCH_L7200              L7200                   19
 pleb                   SA1100_PLEB             PLEB                    20
 integrator             ARCH_INTEGRATOR         INTEGRATOR              21
 h3600                  SA1100_H3600            H3600                   22
-ixp1200                        ARCH_IXP1200            IXP1200                 23
 p720t                  ARCH_P720T              P720T                   24
 assabet                        SA1100_ASSABET          ASSABET                 25
-victor                 SA1100_VICTOR           VICTOR                  26
 lart                   SA1100_LART             LART                    27
-ranger                 SA1100_RANGER           RANGER                  28
 graphicsclient         SA1100_GRAPHICSCLIENT   GRAPHICSCLIENT          29
 xp860                  SA1100_XP860            XP860                   30
 cerf                   SA1100_CERF             CERF                    31
 nanoengine             SA1100_NANOENGINE       NANOENGINE              32
-fpic                   SA1100_FPIC             FPIC                    33
-extenex1               SA1100_EXTENEX1         EXTENEX1                34
-sherman                        SA1100_SHERMAN          SHERMAN                 35
-accelent_sa            SA1100_ACCELENT         ACCELENT_SA             36
-accelent_l7200         ARCH_L7200_ACCELENT     ACCELENT_L7200          37
-netport                        SA1100_NETPORT          NETPORT                 38
-pangolin               SA1100_PANGOLIN         PANGOLIN                39
-yopy                   SA1100_YOPY             YOPY                    40
-coolidge               SA1100_COOLIDGE         COOLIDGE                41
-huw_webpanel           SA1100_HUW_WEBPANEL     HUW_WEBPANEL            42
-spotme                 ARCH_SPOTME             SPOTME                  43
-freebird               ARCH_FREEBIRD           FREEBIRD                44
-ti925                  ARCH_TI925              TI925                   45
-riscstation            ARCH_RISCSTATION        RISCSTATION             46
-cavy                   SA1100_CAVY             CAVY                    47
 jornada720             SA1100_JORNADA720       JORNADA720              48
-omnimeter              SA1100_OMNIMETER        OMNIMETER               49
 edb7211                        ARCH_EDB7211            EDB7211                 50
-citygo                 SA1100_CITYGO           CITYGO                  51
 pfs168                 SA1100_PFS168           PFS168                  52
-spot                   SA1100_SPOT             SPOT                    53
 flexanet               SA1100_FLEXANET         FLEXANET                54
-webpal                 ARCH_WEBPAL             WEBPAL                  55
-linpda                 SA1100_LINPDA           LINPDA                  56
-anakin                 ARCH_ANAKIN             ANAKIN                  57
-mvi                    SA1100_MVI              MVI                     58
-jupiter                        SA1100_JUPITER          JUPITER                 59
-psionw                 ARCH_PSIONW             PSIONW                  60
-aln                    SA1100_ALN              ALN                     61
-epxa                   ARCH_CAMELOT            CAMELOT                 62
-gds2200                        SA1100_GDS2200          GDS2200                 63
-netbook                        SA1100_PSION_SERIES7    PSION_SERIES7           64
-xfile                  SA1100_XFILE            XFILE                   65
-accelent_ep9312                ARCH_ACCELENT_EP9312    ACCELENT_EP9312         66
-ic200                  ARCH_IC200              IC200                   67
-creditlart             SA1100_CREDITLART       CREDITLART              68
-htm                    SA1100_HTM              HTM                     69
-iq80310                        ARCH_IQ80310            IQ80310                 70
-freebot                        SA1100_FREEBOT          FREEBOT                 71
-entel                  ARCH_ENTEL              ENTEL                   72
-enp3510                        ARCH_ENP3510            ENP3510                 73
-trizeps                        SA1100_TRIZEPS          TRIZEPS                 74
-nesa                   SA1100_NESA             NESA                    75
-venus                  ARCH_VENUS              VENUS                   76
-tardis                 ARCH_TARDIS             TARDIS                  77
-mercury                        ARCH_MERCURY            MERCURY                 78
-empeg                  SA1100_EMPEG            EMPEG                   79
-adi_evb                        ARCH_I80200FCC          I80200FCC               80
-itt_cpb                        SA1100_ITT_CPB          ITT_CPB                 81
-svc                    SA1100_SVC              SVC                     82
-alpha2                 SA1100_ALPHA2           ALPHA2                  84
-alpha1                 SA1100_ALPHA1           ALPHA1                  85
-netarm                 ARCH_NETARM             NETARM                  86
 simpad                 SA1100_SIMPAD           SIMPAD                  87
-pda1                   ARCH_PDA1               PDA1                    88
 lubbock                        ARCH_LUBBOCK            LUBBOCK                 89
-aniko                  ARCH_ANIKO              ANIKO                   90
 clep7212               ARCH_CLEP7212           CLEP7212                91
-cs89712                        ARCH_CS89712            CS89712                 92
-weararm                        SA1100_WEARARM          WEARARM                 93
-possio_px              SA1100_POSSIO_PX        POSSIO_PX               94
-sidearm                        SA1100_SIDEARM          SIDEARM                 95
-stork                  SA1100_STORK            STORK                   96
 shannon                        SA1100_SHANNON          SHANNON                 97
-ace                    ARCH_ACE                ACE                     98
-ballyarm               SA1100_BALLYARM         BALLYARM                99
-simputer               SA1100_SIMPUTER         SIMPUTER                100
-nexterm                        SA1100_NEXTERM          NEXTERM                 101
-sa1100_elf             SA1100_SA1100_ELF       SA1100_ELF              102
-gator                  SA1100_GATOR            GATOR                   103
-granite                        ARCH_GRANITE            GRANITE                 104
 consus                 SA1100_CONSUS           CONSUS                  105
 aaed2000               ARCH_AAED2000           AAED2000                106
 cdb89712               ARCH_CDB89712           CDB89712                107
 graphicsmaster         SA1100_GRAPHICSMASTER   GRAPHICSMASTER          108
 adsbitsy               SA1100_ADSBITSY         ADSBITSY                109
 pxa_idp                        ARCH_PXA_IDP            PXA_IDP                 110
-plce                   ARCH_PLCE               PLCE                    111
 pt_system3             SA1100_PT_SYSTEM3       PT_SYSTEM3              112
-murphy                 ARCH_MEDALB             MEDALB                  113
-eagle                  ARCH_EAGLE              EAGLE                   114
-dsc21                  ARCH_DSC21              DSC21                   115
-dsc24                  ARCH_DSC24              DSC24                   116
-ti5472                 ARCH_TI5472             TI5472                  117
 autcpu12               ARCH_AUTCPU12           AUTCPU12                118
-uengine                        ARCH_UENGINE            UENGINE                 119
-bluestem               SA1100_BLUESTEM         BLUESTEM                120
-xingu8                 ARCH_XINGU8             XINGU8                  121
-bushstb                        ARCH_BUSHSTB            BUSHSTB                 122
-epsilon1               SA1100_EPSILON1         EPSILON1                123
-balloon                        SA1100_BALLOON          BALLOON                 124
-puppy                  ARCH_PUPPY              PUPPY                   125
-elroy                  SA1100_ELROY            ELROY                   126
-gms720                 ARCH_GMS720             GMS720                  127
-s24x                   ARCH_S24X               S24X                    128
-jtel_clep7312          ARCH_JTEL_CLEP7312      JTEL_CLEP7312           129
-cx821xx                        ARCH_CX821XX            CX821XX                 130
-edb7312                        ARCH_EDB7312            EDB7312                 131
-bsa1110                        SA1100_BSA1110          BSA1110                 132
-powerpin               ARCH_POWERPIN           POWERPIN                133
-openarm                        ARCH_OPENARM            OPENARM                 134
-whitechapel            SA1100_WHITECHAPEL      WHITECHAPEL             135
 h3100                  SA1100_H3100            H3100                   136
-h3800                  SA1100_H3800            H3800                   137
-blue_v1                        ARCH_BLUE_V1            BLUE_V1                 138
-pxa_cerf               ARCH_PXA_CERF           PXA_CERF                139
-arm7tevb               ARCH_ARM7TEVB           ARM7TEVB                140
-d7400                  SA1100_D7400            D7400                   141
-piranha                        ARCH_PIRANHA            PIRANHA                 142
-sbcamelot              SA1100_SBCAMELOT        SBCAMELOT               143
-kings                  SA1100_KINGS            KINGS                   144
-smdk2400               ARCH_SMDK2400           SMDK2400                145
 collie                 SA1100_COLLIE           COLLIE                  146
-idr                    ARCH_IDR                IDR                     147
 badge4                 SA1100_BADGE4           BADGE4                  148
-webnet                 ARCH_WEBNET             WEBNET                  149
-d7300                  SA1100_D7300            D7300                   150
-cep                    SA1100_CEP              CEP                     151
 fortunet               ARCH_FORTUNET           FORTUNET                152
-vc547x                 ARCH_VC547X             VC547X                  153
-filewalker             SA1100_FILEWALKER       FILEWALKER              154
-netgateway             SA1100_NETGATEWAY       NETGATEWAY              155
-symbol2800             SA1100_SYMBOL2800       SYMBOL2800              156
-suns                   SA1100_SUNS             SUNS                    157
-frodo                  SA1100_FRODO            FRODO                   158
-ms301                  SA1100_MACH_TYTE_MS301  MACH_TYTE_MS301         159
 mx1ads                 ARCH_MX1ADS             MX1ADS                  160
 h7201                  ARCH_H7201              H7201                   161
 h7202                  ARCH_H7202              H7202                   162
-amico                  ARCH_AMICO              AMICO                   163
-iam                    SA1100_IAM              IAM                     164
-tt530                  SA1100_TT530            TT530                   165
-sam2400                        ARCH_SAM2400            SAM2400                 166
-jornada56x             SA1100_JORNADA56X       JORNADA56X              167
-active                 SA1100_ACTIVE           ACTIVE                  168
 iq80321                        ARCH_IQ80321            IQ80321                 169
-wid                    SA1100_WID              WID                     170
-sabinal                        ARCH_SABINAL            SABINAL                 171
-ixp425_matacumbe       ARCH_IXP425_MATACUMBE   IXP425_MATACUMBE        172
-miniprint              SA1100_MINIPRINT        MINIPRINT               173
-adm510x                        ARCH_ADM510X            ADM510X                 174
-svs200                 SA1100_SVS200           SVS200                  175
-atg_tcu                        ARCH_ATG_TCU            ATG_TCU                 176
-jornada820             SA1100_JORNADA820       JORNADA820              177
-s3c44b0                        ARCH_S3C44B0            S3C44B0                 178
-margis2                        ARCH_MARGIS2            MARGIS2                 179
 ks8695                 ARCH_KS8695             KS8695                  180
-brh                    ARCH_BRH                BRH                     181
-s3c2410                        ARCH_S3C2410            S3C2410                 182
-possio_px30            ARCH_POSSIO_PX30        POSSIO_PX30             183
-s3c2800                        ARCH_S3C2800            S3C2800                 184
-fleetwood              SA1100_FLEETWOOD        FLEETWOOD               185
-omaha                  ARCH_OMAHA              OMAHA                   186
-ta7                    ARCH_TA7                TA7                     187
-nova                   SA1100_NOVA             NOVA                    188
-hmk                    ARCH_HMK                HMK                     189
-karo                   ARCH_KARO               KARO                    190
-fester                 SA1100_FESTER           FESTER                  191
-gpi                    ARCH_GPI                GPI                     192
 smdk2410               ARCH_SMDK2410           SMDK2410                193
-i519                   ARCH_I519               I519                    194
-nexio                  SA1100_NEXIO            NEXIO                   195
-bitbox                 SA1100_BITBOX           BITBOX                  196
-g200                   SA1100_G200             G200                    197
-gill                   SA1100_GILL             GILL                    198
-pxa_mercury            ARCH_PXA_MERCURY        PXA_MERCURY             199
 ceiva                  ARCH_CEIVA              CEIVA                   200
-fret                   SA1100_FRET             FRET                    201
-emailphone             SA1100_EMAILPHONE       EMAILPHONE              202
-h3900                  ARCH_H3900              H3900                   203
-pxa1                   ARCH_PXA1               PXA1                    204
-koan369                        SA1100_KOAN369          KOAN369                 205
-cogent                 ARCH_COGENT             COGENT                  206
-esl_simputer           ARCH_ESL_SIMPUTER       ESL_SIMPUTER            207
-esl_simputer_clr       ARCH_ESL_SIMPUTER_CLR   ESL_SIMPUTER_CLR        208
-esl_simputer_bw                ARCH_ESL_SIMPUTER_BW    ESL_SIMPUTER_BW         209
-hhp_cradle             ARCH_HHP_CRADLE         HHP_CRADLE              210
-he500                  ARCH_HE500              HE500                   211
-inhandelf2             SA1100_INHANDELF2       INHANDELF2              212
-inhandftip             SA1100_INHANDFTIP       INHANDFTIP              213
-dnp1110                        SA1100_DNP1110          DNP1110                 214
-pnp1110                        SA1100_PNP1110          PNP1110                 215
-csb226                 ARCH_CSB226             CSB226                  216
-arnold                 SA1100_ARNOLD           ARNOLD                  217
 voiceblue              MACH_VOICEBLUE          VOICEBLUE               218
-jz8028                 ARCH_JZ8028             JZ8028                  219
 h5400                  ARCH_H5400              H5400                   220
-forte                  SA1100_FORTE            FORTE                   221
-acam                   SA1100_ACAM             ACAM                    222
-abox                   SA1100_ABOX             ABOX                    223
-atmel                  ARCH_ATMEL              ATMEL                   224
-sitsang                        ARCH_SITSANG            SITSANG                 225
-cpu1110lcdnet          SA1100_CPU1110LCDNET    CPU1110LCDNET           226
-mpl_vcma9              ARCH_MPL_VCMA9          MPL_VCMA9               227
-opus_a1                        ARCH_OPUS_A1            OPUS_A1                 228
-daytona                        ARCH_DAYTONA            DAYTONA                 229
-killbear               SA1100_KILLBEAR         KILLBEAR                230
-yoho                   ARCH_YOHO               YOHO                    231
-jasper                 ARCH_JASPER             JASPER                  232
-dsc25                  ARCH_DSC25              DSC25                   233
 omap_innovator         MACH_OMAP_INNOVATOR     OMAP_INNOVATOR          234
-mnci                   ARCH_RAMSES             RAMSES                  235
-s28x                   ARCH_S28X               S28X                    236
-mport3                 ARCH_MPORT3             MPORT3                  237
-pxa_eagle250           ARCH_PXA_EAGLE250       PXA_EAGLE250            238
-pdb                    ARCH_PDB                PDB                     239
-blue_2g                        SA1100_BLUE_2G          BLUE_2G                 240
-bluearch               SA1100_BLUEARCH         BLUEARCH                241
 ixdp2400               ARCH_IXDP2400           IXDP2400                242
 ixdp2800               ARCH_IXDP2800           IXDP2800                243
-explorer               SA1100_EXPLORER         EXPLORER                244
 ixdp425                        ARCH_IXDP425            IXDP425                 245
-chimp                  ARCH_CHIMP              CHIMP                   246
-stork_nest             ARCH_STORK_NEST         STORK_NEST              247
-stork_egg              ARCH_STORK_EGG          STORK_EGG               248
-wismo                  SA1100_WISMO            WISMO                   249
-ezlinx                 ARCH_EZLINX             EZLINX                  250
-at91rm9200             ARCH_AT91RM9200         AT91RM9200              251
-adtech_orion           ARCH_ADTECH_ORION       ADTECH_ORION            252
-neptune                        ARCH_NEPTUNE            NEPTUNE                 253
 hackkit                        SA1100_HACKKIT          HACKKIT                 254
-pxa_wins30             ARCH_PXA_WINS30         PXA_WINS30              255
-lavinna                        SA1100_LAVINNA          LAVINNA                 256
-pxa_uengine            ARCH_PXA_UENGINE        PXA_UENGINE             257
-innokom                        ARCH_INNOKOM            INNOKOM                 258
-bms                    ARCH_BMS                BMS                     259
 ixcdp1100              ARCH_IXCDP1100          IXCDP1100               260
-prpmc1100              ARCH_PRPMC1100          PRPMC1100               261
 at91rm9200dk           ARCH_AT91RM9200DK       AT91RM9200DK            262
-armstick               ARCH_ARMSTICK           ARMSTICK                263
-armonie                        ARCH_ARMONIE            ARMONIE                 264
-mport1                 ARCH_MPORT1             MPORT1                  265
-s3c5410                        ARCH_S3C5410            S3C5410                 266
-zcp320a                        ARCH_ZCP320A            ZCP320A                 267
-i_box                  ARCH_I_BOX              I_BOX                   268
-stlc1502               ARCH_STLC1502           STLC1502                269
-siren                  ARCH_SIREN              SIREN                   270
-greenlake              ARCH_GREENLAKE          GREENLAKE               271
-argus                  ARCH_ARGUS              ARGUS                   272
-combadge               SA1100_COMBADGE         COMBADGE                273
-rokepxa                        ARCH_ROKEPXA            ROKEPXA                 274
 cintegrator            ARCH_CINTEGRATOR        CINTEGRATOR             275
-guidea07               ARCH_GUIDEA07           GUIDEA07                276
-tat257                 ARCH_TAT257             TAT257                  277
-igp2425                        ARCH_IGP2425            IGP2425                 278
-bluegrama              ARCH_BLUEGRAMMA         BLUEGRAMMA              279
-ipod                   ARCH_IPOD               IPOD                    280
-adsbitsyx              ARCH_ADSBITSYX          ADSBITSYX               281
-trizeps2               ARCH_TRIZEPS2           TRIZEPS2                282
 viper                  ARCH_VIPER              VIPER                   283
-adsbitsyplus           SA1100_ADSBITSYPLUS     ADSBITSYPLUS            284
-adsagc                 SA1100_ADSAGC           ADSAGC                  285
-stp7312                        ARCH_STP7312            STP7312                 286
-nx_phnx                        MACH_NX_PHNX            NX_PHNX                 287
-wep_ep250              ARCH_WEP_EP250          WEP_EP250               288
-inhandelf3             ARCH_INHANDELF3         INHANDELF3              289
 adi_coyote             ARCH_ADI_COYOTE         ADI_COYOTE              290
-iyonix                 ARCH_IYONIX             IYONIX                  291
-damicam1               ARCH_DAMICAM_SA1110     DAMICAM_SA1110          292
-meg03                  ARCH_MEG03              MEG03                   293
-pxa_whitechapel                ARCH_PXA_WHITECHAPEL    PXA_WHITECHAPEL         294
-nwsc                   ARCH_NWSC               NWSC                    295
-nwlarm                 ARCH_NWLARM             NWLARM                  296
-ixp425_mguard          ARCH_IXP425_MGUARD      IXP425_MGUARD           297
-pxa_netdcu4            ARCH_PXA_NETDCU4        PXA_NETDCU4             298
 ixdp2401               ARCH_IXDP2401           IXDP2401                299
 ixdp2801               ARCH_IXDP2801           IXDP2801                300
-zodiac                 ARCH_ZODIAC             ZODIAC                  301
-armmodul               ARCH_ARMMODUL           ARMMODUL                302
-ketop                  SA1100_KETOP            KETOP                   303
-av7200                 ARCH_AV7200             AV7200                  304
-arch_ti925             ARCH_ARCH_TI925         ARCH_TI925              305
-acq200                 ARCH_ACQ200             ACQ200                  306
-pt_dafit               SA1100_PT_DAFIT         PT_DAFIT                307
-ihba                   ARCH_IHBA               IHBA                    308
-quinque                        ARCH_QUINQUE            QUINQUE                 309
-nimbraone              ARCH_NIMBRAONE          NIMBRAONE               310
-nimbra29x              ARCH_NIMBRA29X          NIMBRA29X               311
-nimbra210              ARCH_NIMBRA210          NIMBRA210               312
-hhp_d95xx              ARCH_HHP_D95XX          HHP_D95XX               313
-labarm                 ARCH_LABARM             LABARM                  314
-m825xx                 ARCH_M825XX             M825XX                  315
-m7100                  SA1100_M7100            M7100                   316
-nipc2                  ARCH_NIPC2              NIPC2                   317
-fu7202                 ARCH_FU7202             FU7202                  318
-adsagx                 ARCH_ADSAGX             ADSAGX                  319
-pxa_pooh               ARCH_PXA_POOH           PXA_POOH                320
-bandon                 ARCH_BANDON             BANDON                  321
-pcm7210                        ARCH_PCM7210            PCM7210                 322
-nms9200                        ARCH_NMS9200            NMS9200                 323
-logodl                 ARCH_LOGODL             LOGODL                  324
-m7140                  SA1100_M7140            M7140                   325
-korebot                        ARCH_KOREBOT            KOREBOT                 326
 iq31244                        ARCH_IQ31244            IQ31244                 327
-koan393                        SA1100_KOAN393          KOAN393                 328
-inhandftip3            ARCH_INHANDFTIP3        INHANDFTIP3             329
-gonzo                  ARCH_GONZO              GONZO                   330
 bast                   ARCH_BAST               BAST                    331
-scanpass               ARCH_SCANPASS           SCANPASS                332
-ep7312_pooh            ARCH_EP7312_POOH        EP7312_POOH             333
-ta7s                   ARCH_TA7S               TA7S                    334
-ta7v                   ARCH_TA7V               TA7V                    335
-icarus                 SA1100_ICARUS           ICARUS                  336
-h1900                  ARCH_H1900              H1900                   337
-gemini                 SA1100_GEMINI           GEMINI                  338
-axim                   ARCH_AXIM               AXIM                    339
-audiotron              ARCH_AUDIOTRON          AUDIOTRON               340
-h2200                  ARCH_H2200              H2200                   341
-loox600                        ARCH_LOOX600            LOOX600                 342
-niop                   ARCH_NIOP               NIOP                    343
-dm310                  ARCH_DM310              DM310                   344
-seedpxa_c2             ARCH_SEEDPXA_C2         SEEDPXA_C2              345
-ixp4xx_mguardpci       ARCH_IXP4XX_MGUARD_PCI  IXP4XX_MGUARD_PCI       346
 h1940                  ARCH_H1940              H1940                   347
-scorpio                        ARCH_SCORPIO            SCORPIO                 348
-viva                   ARCH_VIVA               VIVA                    349
-pxa_xcard              ARCH_PXA_XCARD          PXA_XCARD               350
-csb335                 ARCH_CSB335             CSB335                  351
-ixrd425                        ARCH_IXRD425            IXRD425                 352
-iq80315                        ARCH_IQ80315            IQ80315                 353
-nmp7312                        ARCH_NMP7312            NMP7312                 354
-cx861xx                        ARCH_CX861XX            CX861XX                 355
 enp2611                        ARCH_ENP2611            ENP2611                 356
-xda                    SA1100_XDA              XDA                     357
-csir_ims               ARCH_CSIR_IMS           CSIR_IMS                358
-ixp421_dnaeeth         ARCH_IXP421_DNAEETH     IXP421_DNAEETH          359
-pocketserv9200         ARCH_POCKETSERV9200     POCKETSERV9200          360
-toto                   ARCH_TOTO               TOTO                    361
 s3c2440                        ARCH_S3C2440            S3C2440                 362
-ks8695p                        ARCH_KS8695P            KS8695P                 363
-se4000                 ARCH_SE4000             SE4000                  364
-quadriceps             ARCH_QUADRICEPS         QUADRICEPS              365
-bronco                 ARCH_BRONCO             BRONCO                  366
-esl_wireless_tab       ARCH_ESL_WIRELESS_TAB   ESL_WIRELESS_TAB        367
-esl_sofcomp            ARCH_ESL_SOFCOMP        ESL_SOFCOMP             368
-s5c7375                        ARCH_S5C7375            S5C7375                 369
-spearhead              ARCH_SPEARHEAD          SPEARHEAD               370
-pantera                        ARCH_PANTERA            PANTERA                 371
-prayoglite             ARCH_PRAYOGLITE         PRAYOGLITE              372
 gumstix                        ARCH_GUMSTIX            GUMSTIX                 373
-rcube                  ARCH_RCUBE              RCUBE                   374
-rea_olv                        ARCH_REA_OLV            REA_OLV                 375
-pxa_iphone             ARCH_PXA_IPHONE         PXA_IPHONE              376
-s3c3410                        ARCH_S3C3410            S3C3410                 377
-espd_4510b             ARCH_ESPD_4510B         ESPD_4510B              378
-mp1x                   ARCH_MP1X               MP1X                    379
-at91rm9200tb           ARCH_AT91RM9200TB       AT91RM9200TB            380
-adsvgx                 ARCH_ADSVGX             ADSVGX                  381
 omap_h2                        MACH_OMAP_H2            OMAP_H2                 382
-pelee                  ARCH_PELEE              PELEE                   383
 e740                   MACH_E740               E740                    384
 iq80331                        ARCH_IQ80331            IQ80331                 385
 versatile_pb           ARCH_VERSATILE_PB       VERSATILE_PB            387
 kev7a400               MACH_KEV7A400           KEV7A400                388
 lpd7a400               MACH_LPD7A400           LPD7A400                389
 lpd7a404               MACH_LPD7A404           LPD7A404                390
-fujitsu_camelot                ARCH_FUJITSU_CAMELOT    FUJITSU_CAMELOT         391
-janus2m                        ARCH_JANUS2M            JANUS2M                 392
-embtf                  MACH_EMBTF              EMBTF                   393
-hpm                    MACH_HPM                HPM                     394
-smdk2410tk             MACH_SMDK2410TK         SMDK2410TK              395
-smdk2410aj             MACH_SMDK2410AJ         SMDK2410AJ              396
-streetracer            MACH_STREETRACER        STREETRACER             397
-eframe                 MACH_EFRAME             EFRAME                  398
 csb337                 MACH_CSB337             CSB337                  399
-pxa_lark               MACH_PXA_LARK           PXA_LARK                400
-pxa_pnp2110            MACH_PNP2110            PNP2110                 401
-tcc72x                 MACH_TCC72X             TCC72X                  402
-altair                 MACH_ALTAIR             ALTAIR                  403
-kc3                    MACH_KC3                KC3                     404
-sinteftd               MACH_SINTEFTD           SINTEFTD                405
 mainstone              MACH_MAINSTONE          MAINSTONE               406
-aday4x                 MACH_ADAY4X             ADAY4X                  407
-lite300                        MACH_LITE300            LITE300                 408
-s5c7376                        MACH_S5C7376            S5C7376                 409
-mt02                   MACH_MT02               MT02                    410
-mport3s                        MACH_MPORT3S            MPORT3S                 411
-ra_alpha               MACH_RA_ALPHA           RA_ALPHA                412
 xcep                   MACH_XCEP               XCEP                    413
 arcom_vulcan           MACH_ARCOM_VULCAN       ARCOM_VULCAN            414
-stargate               MACH_STARGATE           STARGATE                415
-armadilloj             MACH_ARMADILLOJ         ARMADILLOJ              416
-elroy_jack             MACH_ELROY_JACK         ELROY_JACK              417
-backend                        MACH_BACKEND            BACKEND                 418
-s5linbox               MACH_S5LINBOX           S5LINBOX                419
 nomadik                        MACH_NOMADIK            NOMADIK                 420
-ia_cpu_9200            MACH_IA_CPU_9200        IA_CPU_9200             421
-at91_bja1              MACH_AT91_BJA1          AT91_BJA1               422
 corgi                  MACH_CORGI              CORGI                   423
 poodle                 MACH_POODLE             POODLE                  424
-ten                    MACH_TEN                TEN                     425
-roverp5p               MACH_ROVERP5P           ROVERP5P                426
-sc2700                 MACH_SC2700             SC2700                  427
-ex_eagle               MACH_EX_EAGLE           EX_EAGLE                428
-nx_pxa12               MACH_NX_PXA12           NX_PXA12                429
-nx_pxa5                        MACH_NX_PXA5            NX_PXA5                 430
-blackboard2            MACH_BLACKBOARD2        BLACKBOARD2             431
-i819                   MACH_I819               I819                    432
-ixmb995e               MACH_IXMB995E           IXMB995E                433
-skyrider               MACH_SKYRIDER           SKYRIDER                434
-skyhawk                        MACH_SKYHAWK            SKYHAWK                 435
-enterprise             MACH_ENTERPRISE         ENTERPRISE              436
-dep2410                        MACH_DEP2410            DEP2410                 437
 armcore                        MACH_ARMCORE            ARMCORE                 438
-hobbit                 MACH_HOBBIT             HOBBIT                  439
-h7210                  MACH_H7210              H7210                   440
-pxa_netdcu5            MACH_PXA_NETDCU5        PXA_NETDCU5             441
-acc                    MACH_ACC                ACC                     442
-esl_sarva              MACH_ESL_SARVA          ESL_SARVA               443
-xm250                  MACH_XM250              XM250                   444
-t6tc1xb                        MACH_T6TC1XB            T6TC1XB                 445
-ess710                 MACH_ESS710             ESS710                  446
 mx31ads                        MACH_MX31ADS            MX31ADS                 447
 himalaya               MACH_HIMALAYA           HIMALAYA                448
-bolfenk                        MACH_BOLFENK            BOLFENK                 449
-at91rm9200kr           MACH_AT91RM9200KR       AT91RM9200KR            450
 edb9312                        MACH_EDB9312            EDB9312                 451
 omap_generic           MACH_OMAP_GENERIC       OMAP_GENERIC            452
-aximx3                 MACH_AXIMX3             AXIMX3                  453
-eb67xdip               MACH_EB67XDIP           EB67XDIP                454
-webtxs                 MACH_WEBTXS             WEBTXS                  455
-hawk                   MACH_HAWK               HAWK                    456
-ccat91sbc001           MACH_CCAT91SBC001       CCAT91SBC001            457
-expresso               MACH_EXPRESSO           EXPRESSO                458
-h4000                  MACH_H4000              H4000                   459
-dino                   MACH_DINO               DINO                    460
-ml675k                 MACH_ML675K             ML675K                  461
 edb9301                        MACH_EDB9301            EDB9301                 462
 edb9315                        MACH_EDB9315            EDB9315                 463
-reciva_tt              MACH_RECIVA_TT          RECIVA_TT               464
-cstcb01                        MACH_CSTCB01            CSTCB01                 465
-cstcb1                 MACH_CSTCB1             CSTCB1                  466
-shadwell               MACH_SHADWELL           SHADWELL                467
-goepel263              MACH_GOEPEL263          GOEPEL263               468
-acq100                 MACH_ACQ100             ACQ100                  469
-mx1fs2                 MACH_MX1FS2             MX1FS2                  470
-hiptop_g1              MACH_HIPTOP_G1          HIPTOP_G1               471
-sparky                 MACH_SPARKY             SPARKY                  472
-ns9750                 MACH_NS9750             NS9750                  473
-phoenix                        MACH_PHOENIX            PHOENIX                 474
 vr1000                 MACH_VR1000             VR1000                  475
-deisterpxa             MACH_DEISTERPXA         DEISTERPXA              476
-bcm1160                        MACH_BCM1160            BCM1160                 477
-pcm022                 MACH_PCM022             PCM022                  478
-adsgcx                 MACH_ADSGCX             ADSGCX                  479
-dreadnaught            MACH_DREADNAUGHT        DREADNAUGHT             480
-dm320                  MACH_DM320              DM320                   481
-markov                 MACH_MARKOV             MARKOV                  482
-cos7a400               MACH_COS7A400           COS7A400                483
-milano                 MACH_MILANO             MILANO                  484
-ue9328                 MACH_UE9328             UE9328                  485
-uex255                 MACH_UEX255             UEX255                  486
-ue2410                 MACH_UE2410             UE2410                  487
-a620                   MACH_A620               A620                    488
-ocelot                 MACH_OCELOT             OCELOT                  489
-cheetah                        MACH_CHEETAH            CHEETAH                 490
 omap_perseus2          MACH_OMAP_PERSEUS2      OMAP_PERSEUS2           491
-zvue                   MACH_ZVUE               ZVUE                    492
-roverp1                        MACH_ROVERP1            ROVERP1                 493
-asidial2               MACH_ASIDIAL2           ASIDIAL2                494
-s3c24a0                        MACH_S3C24A0            S3C24A0                 495
 e800                   MACH_E800               E800                    496
 e750                   MACH_E750               E750                    497
-s3c5500                        MACH_S3C5500            S3C5500                 498
-smdk5500               MACH_SMDK5500           SMDK5500                499
-signalsync             MACH_SIGNALSYNC         SIGNALSYNC              500
-nbc                    MACH_NBC                NBC                     501
-kodiak                 MACH_KODIAK             KODIAK                  502
-netbookpro             MACH_NETBOOKPRO         NETBOOKPRO              503
-hw90200                        MACH_HW90200            HW90200                 504
-condor                 MACH_CONDOR             CONDOR                  505
-cup                    MACH_CUP                CUP                     506
-kite                   MACH_KITE               KITE                    507
 scb9328                        MACH_SCB9328            SCB9328                 508
 omap_h3                        MACH_OMAP_H3            OMAP_H3                 509
 omap_h4                        MACH_OMAP_H4            OMAP_H4                 510
-n10                    MACH_N10                N10                     511
-montejade              MACH_MONTAJADE          MONTAJADE               512
-sg560                  MACH_SG560              SG560                   513
-dp1000                 MACH_DP1000             DP1000                  514
 omap_osk               MACH_OMAP_OSK           OMAP_OSK                515
-rg100v3                        MACH_RG100V3            RG100V3                 516
-mx2ads                 MACH_MX2ADS             MX2ADS                  517
-pxa_kilo               MACH_PXA_KILO           PXA_KILO                518
-ixp4xx_eagle           MACH_IXP4XX_EAGLE       IXP4XX_EAGLE            519
 tosa                   MACH_TOSA               TOSA                    520
-mb2520f                        MACH_MB2520F            MB2520F                 521
-emc1000                        MACH_EMC1000            EMC1000                 522
-tidsc25                        MACH_TIDSC25            TIDSC25                 523
-akcpmxl                        MACH_AKCPMXL            AKCPMXL                 524
-av3xx                  MACH_AV3XX              AV3XX                   525
 avila                  MACH_AVILA              AVILA                   526
-pxa_mpm10              MACH_PXA_MPM10          PXA_MPM10               527
-pxa_kyanite            MACH_PXA_KYANITE        PXA_KYANITE             528
-sgold                  MACH_SGOLD              SGOLD                   529
-oscar                  MACH_OSCAR              OSCAR                   530
-epxa4usb2              MACH_EPXA4USB2          EPXA4USB2               531
-xsengine               MACH_XSENGINE           XSENGINE                532
-ip600                  MACH_IP600              IP600                   533
-mcan2                  MACH_MCAN2              MCAN2                   534
-ddi_blueridge          MACH_DDI_BLUERIDGE      DDI_BLUERIDGE           535
-skyminder              MACH_SKYMINDER          SKYMINDER               536
-lpd79520               MACH_LPD79520           LPD79520                537
 edb9302                        MACH_EDB9302            EDB9302                 538
-hw90340                        MACH_HW90340            HW90340                 539
-cip_box                        MACH_CIP_BOX            CIP_BOX                 540
-ivpn                   MACH_IVPN               IVPN                    541
-rsoc2                  MACH_RSOC2              RSOC2                   542
 husky                  MACH_HUSKY              HUSKY                   543
-boxer                  MACH_BOXER              BOXER                   544
 shepherd               MACH_SHEPHERD           SHEPHERD                545
-aml42800aa             MACH_AML42800AA         AML42800AA              546
-lpc2294                        MACH_LPC2294            LPC2294                 548
-switchgrass            MACH_SWITCHGRASS        SWITCHGRASS             549
-ens_cmu                        MACH_ENS_CMU            ENS_CMU                 550
-mm6_sdb                        MACH_MM6_SDB            MM6_SDB                 551
-saturn                 MACH_SATURN             SATURN                  552
-i30030evb              MACH_I30030EVB          I30030EVB               553
-mxc27530evb            MACH_MXC27530EVB        MXC27530EVB             554
-smdk2800               MACH_SMDK2800           SMDK2800                555
-mtwilson               MACH_MTWILSON           MTWILSON                556
-ziti                   MACH_ZITI               ZITI                    557
-grandfather            MACH_GRANDFATHER        GRANDFATHER             558
-tengine                        MACH_TENGINE            TENGINE                 559
-s3c2460                        MACH_S3C2460            S3C2460                 560
-pdm                    MACH_PDM                PDM                     561
 h4700                  MACH_H4700              H4700                   562
-h6300                  MACH_H6300              H6300                   563
-rz1700                 MACH_RZ1700             RZ1700                  564
-a716                   MACH_A716               A716                    565
-estk2440a              MACH_ESTK2440A          ESTK2440A               566
-atwixp425              MACH_ATWIXP425          ATWIXP425               567
-csb336                 MACH_CSB336             CSB336                  568
-rirm2                  MACH_RIRM2              RIRM2                   569
-cx23518                        MACH_CX23518            CX23518                 570
-cx2351x                        MACH_CX2351X            CX2351X                 571
-computime              MACH_COMPUTIME          COMPUTIME               572
-izarus                 MACH_IZARUS             IZARUS                  573
-pxa_rts                        MACH_RTS                RTS                     574
-se5100                 MACH_SE5100             SE5100                  575
-s3c2510                        MACH_S3C2510            S3C2510                 576
-csb437tl               MACH_CSB437TL           CSB437TL                577
-slauson                        MACH_SLAUSON            SLAUSON                 578
-pearlriver             MACH_PEARLRIVER         PEARLRIVER              579
-tdc_p210               MACH_TDC_P210           TDC_P210                580
-sg580                  MACH_SG580              SG580                   581
-wrsbcarm7              MACH_WRSBCARM7          WRSBCARM7               582
-ipd                    MACH_IPD                IPD                     583
-pxa_dnp2110            MACH_PXA_DNP2110        PXA_DNP2110             584
-xaeniax                        MACH_XAENIAX            XAENIAX                 585
-somn4250               MACH_SOMN4250           SOMN4250                586
-pleb2                  MACH_PLEB2              PLEB2                   587
-cornwallis             MACH_CORNWALLIS         CORNWALLIS              588
-gurney_drv             MACH_GURNEY_DRV         GURNEY_DRV              589
-chaffee                        MACH_CHAFFEE            CHAFFEE                 590
-rms101                 MACH_RMS101             RMS101                  591
 rx3715                 MACH_RX3715             RX3715                  592
-swift                  MACH_SWIFT              SWIFT                   593
-roverp7                        MACH_ROVERP7            ROVERP7                 594
-pr818s                 MACH_PR818S             PR818S                  595
-trxpro                 MACH_TRXPRO             TRXPRO                  596
 nslu2                  MACH_NSLU2              NSLU2                   597
 e400                   MACH_E400               E400                    598
-trab                   MACH_TRAB               TRAB                    599
-cmc_pu2                        MACH_CMC_PU2            CMC_PU2                 600
-fulcrum                        MACH_FULCRUM            FULCRUM                 601
-netgate42x             MACH_NETGATE42X         NETGATE42X              602
-str710                 MACH_STR710             STR710                  603
 ixdpg425               MACH_IXDPG425           IXDPG425                604
-tomtomgo               MACH_TOMTOMGO           TOMTOMGO                605
 versatile_ab           MACH_VERSATILE_AB       VERSATILE_AB            606
 edb9307                        MACH_EDB9307            EDB9307                 607
-sg565                  MACH_SG565              SG565                   608
-lpd79524               MACH_LPD79524           LPD79524                609
-lpd79525               MACH_LPD79525           LPD79525                610
-rms100                 MACH_RMS100             RMS100                  611
 kb9200                 MACH_KB9200             KB9200                  612
 sx1                    MACH_SX1                SX1                     613
-hms39c7092             MACH_HMS39C7092         HMS39C7092              614
-armadillo              MACH_ARMADILLO          ARMADILLO               615
-ipcu                   MACH_IPCU               IPCU                    616
-loox720                        MACH_LOOX720            LOOX720                 617
 ixdp465                        MACH_IXDP465            IXDP465                 618
 ixdp2351               MACH_IXDP2351           IXDP2351                619
-adsvix                 MACH_ADSVIX             ADSVIX                  620
-dm270                  MACH_DM270              DM270                   621
-socltplus              MACH_SOCLTPLUS          SOCLTPLUS               622
-ecia                   MACH_ECIA               ECIA                    623
-cm4008                 MACH_CM4008             CM4008                  624
-p2001                  MACH_P2001              P2001                   625
-twister                        MACH_TWISTER            TWISTER                 626
-mudshark               MACH_MUDSHARK           MUDSHARK                627
-hb2                    MACH_HB2                HB2                     628
 iq80332                        MACH_IQ80332            IQ80332                 629
-sendt                  MACH_SENDT              SENDT                   630
-mx2jazz                        MACH_MX2JAZZ            MX2JAZZ                 631
-multiio                        MACH_MULTIIO            MULTIIO                 632
-hrdisplay              MACH_HRDISPLAY          HRDISPLAY               633
-mxc27530ads            MACH_MXC27530ADS        MXC27530ADS             634
-trizeps3               MACH_TRIZEPS3           TRIZEPS3                635
-zefeerdza              MACH_ZEFEERDZA          ZEFEERDZA               636
-zefeerdzb              MACH_ZEFEERDZB          ZEFEERDZB               637
-zefeerdzg              MACH_ZEFEERDZG          ZEFEERDZG               638
-zefeerdzn              MACH_ZEFEERDZN          ZEFEERDZN               639
-zefeerdzq              MACH_ZEFEERDZQ          ZEFEERDZQ               640
 gtwx5715               MACH_GTWX5715           GTWX5715                641
-astro_jack             MACH_ASTRO_JACK         ASTRO_JACK              643
-tip03                  MACH_TIP03              TIP03                   644
-a9200ec                        MACH_A9200EC            A9200EC                 645
-pnx0105                        MACH_PNX0105            PNX0105                 646
-adcpoecpu              MACH_ADCPOECPU          ADCPOECPU               647
 csb637                 MACH_CSB637             CSB637                  648
-mb9200                 MACH_MB9200             MB9200                  650
-kulun                  MACH_KULUN              KULUN                   651
-snapper                        MACH_SNAPPER            SNAPPER                 652
-optima                 MACH_OPTIMA             OPTIMA                  653
-dlhsbc                 MACH_DLHSBC             DLHSBC                  654
-x30                    MACH_X30                X30                     655
 n30                    MACH_N30                N30                     656
-manga_ks8695           MACH_MANGA_KS8695       MANGA_KS8695            657
-ajax                   MACH_AJAX               AJAX                    658
 nec_mp900              MACH_NEC_MP900          NEC_MP900               659
-vvtk1000               MACH_VVTK1000           VVTK1000                661
 kafa                   MACH_KAFA               KAFA                    662
-vvtk3000               MACH_VVTK3000           VVTK3000                663
-pimx1                  MACH_PIMX1              PIMX1                   664
-ollie                  MACH_OLLIE              OLLIE                   665
-skymax                 MACH_SKYMAX             SKYMAX                  666
-jazz                   MACH_JAZZ               JAZZ                    667
-tel_t3                 MACH_TEL_T3             TEL_T3                  668
-aisino_fcr255          MACH_AISINO_FCR255      AISINO_FCR255           669
-btweb                  MACH_BTWEB              BTWEB                   670
-dbg_lh79520            MACH_DBG_LH79520        DBG_LH79520             671
-cm41xx                 MACH_CM41XX             CM41XX                  672
 ts72xx                 MACH_TS72XX             TS72XX                  673
-nggpxa                 MACH_NGGPXA             NGGPXA                  674
-csb535                 MACH_CSB535             CSB535                  675
-csb536                 MACH_CSB536             CSB536                  676
-pxa_trakpod            MACH_PXA_TRAKPOD        PXA_TRAKPOD             677
-praxis                 MACH_PRAXIS             PRAXIS                  678
-lh75411                        MACH_LH75411            LH75411                 679
 otom                   MACH_OTOM               OTOM                    680
 nexcoder_2440          MACH_NEXCODER_2440      NEXCODER_2440           681
-loox410                        MACH_LOOX410            LOOX410                 682
-westlake               MACH_WESTLAKE           WESTLAKE                683
-nsb                    MACH_NSB                NSB                     684
-esl_sarva_stn          MACH_ESL_SARVA_STN      ESL_SARVA_STN           685
-esl_sarva_tft          MACH_ESL_SARVA_TFT      ESL_SARVA_TFT           686
-esl_sarva_iad          MACH_ESL_SARVA_IAD      ESL_SARVA_IAD           687
-esl_sarva_acc          MACH_ESL_SARVA_ACC      ESL_SARVA_ACC           688
-typhoon                        MACH_TYPHOON            TYPHOON                 689
-cnav                   MACH_CNAV               CNAV                    690
-a730                   MACH_A730               A730                    691
-netstar                        MACH_NETSTAR            NETSTAR                 692
-supercon               MACH_PHASEFALE_SUPERCON PHASEFALE_SUPERCON      693
-shiva1100              MACH_SHIVA1100          SHIVA1100               694
-etexsc                 MACH_ETEXSC             ETEXSC                  695
-ixdpg465               MACH_IXDPG465           IXDPG465                696
-a9m2410                        MACH_A9M2410            A9M2410                 697
-a9m2440                        MACH_A9M2440            A9M2440                 698
-a9m9750                        MACH_A9M9750            A9M9750                 699
-a9m9360                        MACH_A9M9360            A9M9360                 700
-unc90                  MACH_UNC90              UNC90                   701
 eco920                 MACH_ECO920             ECO920                  702
-satview                        MACH_SATVIEW            SATVIEW                 703
 roadrunner             MACH_ROADRUNNER         ROADRUNNER              704
 at91rm9200ek           MACH_AT91RM9200EK       AT91RM9200EK            705
-gp32                   MACH_GP32               GP32                    706
-gem                    MACH_GEM                GEM                     707
-i858                   MACH_I858               I858                    708
-hx2750                 MACH_HX2750             HX2750                  709
-mxc91131evb            MACH_MXC91131EVB        MXC91131EVB             710
-p700                   MACH_P700               P700                    711
-cpe                    MACH_CPE                CPE                     712
 spitz                  MACH_SPITZ              SPITZ                   713
-nimbra340              MACH_NIMBRA340          NIMBRA340               714
-lpc22xx                        MACH_LPC22XX            LPC22XX                 715
-omap_comet3            MACH_COMET3             COMET3                  716
-omap_comet4            MACH_COMET4             COMET4                  717
-csb625                 MACH_CSB625             CSB625                  718
-fortunet2              MACH_FORTUNET2          FORTUNET2               719
-s5h2200                        MACH_S5H2200            S5H2200                 720
-optorm920              MACH_OPTORM920          OPTORM920               721
-adsbitsyxb             MACH_ADSBITSYXB         ADSBITSYXB              722
 adssphere              MACH_ADSSPHERE          ADSSPHERE               723
-adsportal              MACH_ADSPORTAL          ADSPORTAL               724
-ln2410sbc              MACH_LN2410SBC          LN2410SBC               725
-cb3rufc                        MACH_CB3RUFC            CB3RUFC                 726
-mp2usb                 MACH_MP2USB             MP2USB                  727
-ntnp425c               MACH_NTNP425C           NTNP425C                728
 colibri                        MACH_COLIBRI            COLIBRI                 729
-pcm7220                        MACH_PCM7220            PCM7220                 730
 gateway7001            MACH_GATEWAY7001        GATEWAY7001             731
 pcm027                 MACH_PCM027             PCM027                  732
-cmpxa                  MACH_CMPXA              CMPXA                   733
 anubis                 MACH_ANUBIS             ANUBIS                  734
-ite8152                        MACH_ITE8152            ITE8152                 735
-lpc3xxx                        MACH_LPC3XXX            LPC3XXX                 736
-puppeteer              MACH_PUPPETEER          PUPPETEER               737
-e570                   MACH_E570               E570                    739
-x50                    MACH_X50                X50                     740
-recon                  MACH_RECON              RECON                   741
-xboardgp8              MACH_XBOARDGP8          XBOARDGP8               742
-fpic2                  MACH_FPIC2              FPIC2                   743
 akita                  MACH_AKITA              AKITA                   744
-a81                    MACH_A81                A81                     745
-svm_sc25x              MACH_SVM_SC25X          SVM_SC25X               746
-vt020                  MACH_VADATECH020        VADATECH020             747
-tli                    MACH_TLI                TLI                     748
-edb9315lc              MACH_EDB9315LC          EDB9315LC               749
-passec                 MACH_PASSEC             PASSEC                  750
-ds_tiger               MACH_DS_TIGER           DS_TIGER                751
-e310                   MACH_E310               E310                    752
 e330                   MACH_E330               E330                    753
-rt3000                 MACH_RT3000             RT3000                  754
 nokia770               MACH_NOKIA770           NOKIA770                755
-pnx0106                        MACH_PNX0106            PNX0106                 756
-hx21xx                 MACH_HX21XX             HX21XX                  757
-faraday                        MACH_FARADAY            FARADAY                 758
-sbc9312                        MACH_SBC9312            SBC9312                 759
-batman                 MACH_BATMAN             BATMAN                  760
-jpd201                 MACH_JPD201             JPD201                  761
-mipsa                  MACH_MIPSA              MIPSA                   762
-kacom                  MACH_KACOM              KACOM                   763
-swarcocpu              MACH_SWARCOCPU          SWARCOCPU               764
-swarcodsl              MACH_SWARCODSL          SWARCODSL               765
-blueangel              MACH_BLUEANGEL          BLUEANGEL               766
-hairygrama             MACH_HAIRYGRAMA         HAIRYGRAMA              767
-banff                  MACH_BANFF              BANFF                   768
 carmeva                        MACH_CARMEVA            CARMEVA                 769
-sam255                 MACH_SAM255             SAM255                  770
-ppm10                  MACH_PPM10              PPM10                   771
 edb9315a               MACH_EDB9315A           EDB9315A                772
-sunset                 MACH_SUNSET             SUNSET                  773
 stargate2              MACH_STARGATE2          STARGATE2               774
 intelmote2             MACH_INTELMOTE2         INTELMOTE2              775
 trizeps4               MACH_TRIZEPS4           TRIZEPS4                776
-mainstone2             MACH_MAINSTONE2         MAINSTONE2              777
-ez_ixp42x              MACH_EZ_IXP42X          EZ_IXP42X               778
-tapwave_zodiac         MACH_TAPWAVE_ZODIAC     TAPWAVE_ZODIAC          779
-universalmeter         MACH_UNIVERSALMETER     UNIVERSALMETER          780
-hicoarm9               MACH_HICOARM9           HICOARM9                781
 pnx4008                        MACH_PNX4008            PNX4008                 782
-kws6000                        MACH_KWS6000            KWS6000                 783
-portux920t             MACH_PORTUX920T         PORTUX920T              784
-ez_x5                  MACH_EZ_X5              EZ_X5                   785
-omap_rudolph           MACH_OMAP_RUDOLPH       OMAP_RUDOLPH            786
 cpuat91                        MACH_CPUAT91            CPUAT91                 787
-rea9200                        MACH_REA9200            REA9200                 788
-acts_pune_sa1110       MACH_ACTS_PUNE_SA1110   ACTS_PUNE_SA1110        789
-ixp425                 MACH_IXP425             IXP425                  790
-i30030ads              MACH_I30030ADS          I30030ADS               791
-perch                  MACH_PERCH              PERCH                   792
-eis05r1                        MACH_EIS05R1            EIS05R1                 793
-pepperpad              MACH_PEPPERPAD          PEPPERPAD               794
-sb3010                 MACH_SB3010             SB3010                  795
-rm9200                 MACH_RM9200             RM9200                  796
-dma03                  MACH_DMA03              DMA03                   797
-road_s101              MACH_ROAD_S101          ROAD_S101               798
 iq81340sc              MACH_IQ81340SC          IQ81340SC               799
-iq_nextgen_b           MACH_IQ_NEXTGEN_B       IQ_NEXTGEN_B            800
 iq81340mc              MACH_IQ81340MC          IQ81340MC               801
-iq_nextgen_d           MACH_IQ_NEXTGEN_D       IQ_NEXTGEN_D            802
-iq_nextgen_e           MACH_IQ_NEXTGEN_E       IQ_NEXTGEN_E            803
-mallow_at91            MACH_MALLOW_AT91        MALLOW_AT91             804
-cybertracker_i         MACH_CYBERTRACKER_I     CYBERTRACKER_I          805
-gesbc931x              MACH_GESBC931X          GESBC931X               806
-centipad               MACH_CENTIPAD           CENTIPAD                807
-armsoc                 MACH_ARMSOC             ARMSOC                  808
-se4200                 MACH_SE4200             SE4200                  809
-ems197a                        MACH_EMS197A            EMS197A                 810
 micro9                 MACH_MICRO9             MICRO9                  811
 micro9l                        MACH_MICRO9L            MICRO9L                 812
-uc5471dsp              MACH_UC5471DSP          UC5471DSP               813
-sj5471eng              MACH_SJ5471ENG          SJ5471ENG               814
-none                   MACH_CMPXA26X           CMPXA26X                815
-nc1                    MACH_NC                 NC                      816
 omap_palmte            MACH_OMAP_PALMTE        OMAP_PALMTE             817
-ajax52x                        MACH_AJAX52X            AJAX52X                 818
-siriustar              MACH_SIRIUSTAR          SIRIUSTAR               819
-iodata_hdlg            MACH_IODATA_HDLG        IODATA_HDLG             820
-at91rm9200utl          MACH_AT91RM9200UTL      AT91RM9200UTL           821
-biosafe                        MACH_BIOSAFE            BIOSAFE                 822
-mp1000                 MACH_MP1000             MP1000                  823
-parsy                  MACH_PARSY              PARSY                   824
-ccxp270                        MACH_CCXP               CCXP                    825
-omap_gsample           MACH_OMAP_GSAMPLE       OMAP_GSAMPLE            826
 realview_eb            MACH_REALVIEW_EB        REALVIEW_EB             827
-samoa                  MACH_SAMOA              SAMOA                   828
-palmt3                 MACH_PALMT3             PALMT3                  829
-i878                   MACH_I878               I878                    830
 borzoi                 MACH_BORZOI             BORZOI                  831
-gecko                  MACH_GECKO              GECKO                   832
-ds101                  MACH_DS101              DS101                   833
-omap_palmtt2           MACH_OMAP_PALMTT2       OMAP_PALMTT2            834
 palmld                 MACH_PALMLD             PALMLD                  835
-cc9c                   MACH_CC9C               CC9C                    836
-sbc1670                        MACH_SBC1670            SBC1670                 837
 ixdp28x5               MACH_IXDP28X5           IXDP28X5                838
 omap_palmtt            MACH_OMAP_PALMTT        OMAP_PALMTT             839
-ml696k                 MACH_ML696K             ML696K                  840
 arcom_zeus             MACH_ARCOM_ZEUS         ARCOM_ZEUS              841
 osiris                 MACH_OSIRIS             OSIRIS                  842
-maestro                        MACH_MAESTRO            MAESTRO                 843
 palmte2                        MACH_PALMTE2            PALMTE2                 844
-ixbbm                  MACH_IXBBM              IXBBM                   845
 mx27ads                        MACH_MX27ADS            MX27ADS                 846
-ax8004                 MACH_AX8004             AX8004                  847
 at91sam9261ek          MACH_AT91SAM9261EK      AT91SAM9261EK           848
 loft                   MACH_LOFT               LOFT                    849
-magpie                 MACH_MAGPIE             MAGPIE                  850
 mx21ads                        MACH_MX21ADS            MX21ADS                 851
-mb87m3400              MACH_MB87M3400          MB87M3400               852
-mguard_delta           MACH_MGUARD_DELTA       MGUARD_DELTA            853
-davinci_dvdp           MACH_DAVINCI_DVDP       DAVINCI_DVDP            854
-htcuniversal           MACH_HTCUNIVERSAL       HTCUNIVERSAL            855
-tpad                   MACH_TPAD               TPAD                    856
-roverp3                        MACH_ROVERP3            ROVERP3                 857
-jornada928             MACH_JORNADA928         JORNADA928              858
-mv88fxx81              MACH_MV88FXX81          MV88FXX81               859
-stmp36xx               MACH_STMP36XX           STMP36XX                860
-sxni79524              MACH_SXNI79524          SXNI79524               861
 ams_delta              MACH_AMS_DELTA          AMS_DELTA               862
-uranium                        MACH_URANIUM            URANIUM                 863
-ucon                   MACH_UCON               UCON                    864
 nas100d                        MACH_NAS100D            NAS100D                 865
-l083                   MACH_L083_1000          L083_1000               866
-ezx                    MACH_EZX                EZX                     867
-pnx5220                        MACH_PNX5220            PNX5220                 868
-butte                  MACH_BUTTE              BUTTE                   869
-srm2                   MACH_SRM2               SRM2                    870
-dsbr                   MACH_DSBR               DSBR                    871
-crystalball            MACH_CRYSTALBALL        CRYSTALBALL             872
-tinypxa27x             MACH_TINYPXA27X         TINYPXA27X              873
-herbie                 MACH_HERBIE             HERBIE                  874
 magician               MACH_MAGICIAN           MAGICIAN                875
-cm4002                 MACH_CM4002             CM4002                  876
-b4                     MACH_B4                 B4                      877
-maui                   MACH_MAUI               MAUI                    878
-cybertracker_g         MACH_CYBERTRACKER_G     CYBERTRACKER_G          879
 nxdkn                  MACH_NXDKN              NXDKN                   880
-mio8390                        MACH_MIO8390            MIO8390                 881
-omi_board              MACH_OMI_BOARD          OMI_BOARD               882
-mx21civ                        MACH_MX21CIV            MX21CIV                 883
-mahi_cdac              MACH_MAHI_CDAC          MAHI_CDAC               884
 palmtx                 MACH_PALMTX             PALMTX                  885
 s3c2413                        MACH_S3C2413            S3C2413                 887
-samsys_ep0             MACH_SAMSYS_EP0         SAMSYS_EP0              888
-wg302v1                        MACH_WG302V1            WG302V1                 889
 wg302v2                        MACH_WG302V2            WG302V2                 890
-eb42x                  MACH_EB42X              EB42X                   891
-iq331es                        MACH_IQ331ES            IQ331ES                 892
-cosydsp                        MACH_COSYDSP            COSYDSP                 893
-uplat7d_proto          MACH_UPLAT7D            UPLAT7D                 894
-ptdavinci              MACH_PTDAVINCI          PTDAVINCI               895
-mbus                   MACH_MBUS               MBUS                    896
-nadia2vb               MACH_NADIA2VB           NADIA2VB                897
-r1000                  MACH_R1000              R1000                   898
-hw90250                        MACH_HW90250            HW90250                 899
 omap_2430sdp           MACH_OMAP_2430SDP       OMAP_2430SDP            900
 davinci_evm            MACH_DAVINCI_EVM        DAVINCI_EVM             901
-omap_tornado           MACH_OMAP_TORNADO       OMAP_TORNADO            902
-olocreek               MACH_OLOCREEK           OLOCREEK                903
 palmz72                        MACH_PALMZ72            PALMZ72                 904
 nxdb500                        MACH_NXDB500            NXDB500                 905
-apf9328                        MACH_APF9328            APF9328                 906
-omap_wipoq             MACH_OMAP_WIPOQ         OMAP_WIPOQ              907
-omap_twip              MACH_OMAP_TWIP          OMAP_TWIP               908
-treo650                        MACH_TREO650            TREO650                 909
-acumen                 MACH_ACUMEN             ACUMEN                  910
-xp100                  MACH_XP100              XP100                   911
-fs2410                 MACH_FS2410             FS2410                  912
-pxa270_cerf            MACH_PXA270_CERF        PXA270_CERF             913
-sq2ftlpalm             MACH_SQ2FTLPALM         SQ2FTLPALM              914
-bsemserver             MACH_BSEMSERVER         BSEMSERVER              915
-netclient              MACH_NETCLIENT          NETCLIENT               916
 palmt5                 MACH_PALMT5             PALMT5                  917
 palmtc                 MACH_PALMTC             PALMTC                  918
 omap_apollon           MACH_OMAP_APOLLON       OMAP_APOLLON            919
-mxc30030evb            MACH_MXC30030EVB        MXC30030EVB             920
-rea_cpu2               MACH_REA_2D             REA_2D                  921
-eti3e524               MACH_TI3E524            TI3E524                 922
 ateb9200               MACH_ATEB9200           ATEB9200                923
-auckland               MACH_AUCKLAND           AUCKLAND                924
-ak3220m                        MACH_AK3320M            AK3320M                 925
-duramax                        MACH_DURAMAX            DURAMAX                 926
 n35                    MACH_N35                N35                     927
-pronghorn              MACH_PRONGHORN          PRONGHORN               928
-fundy                  MACH_FUNDY              FUNDY                   929
 logicpd_pxa270         MACH_LOGICPD_PXA270     LOGICPD_PXA270          930
-cpu777                 MACH_CPU777             CPU777                  931
-simicon9201            MACH_SIMICON9201        SIMICON9201             932
-leap2_hpm              MACH_LEAP2_HPM          LEAP2_HPM               933
-cm922txa10             MACH_CM922TXA10         CM922TXA10              934
-sandgate               MACH_PXA                PXA                     935
-sandgate2              MACH_SANDGATE2          SANDGATE2               936
-sandgate2g             MACH_SANDGATE2G         SANDGATE2G              937
-sandgate2p             MACH_SANDGATE2P         SANDGATE2P              938
-fred_jack              MACH_FRED_JACK          FRED_JACK               939
-ttg_color1             MACH_TTG_COLOR1         TTG_COLOR1              940
 nxeb500hmi             MACH_NXEB500HMI         NXEB500HMI              941
-netdcu8                        MACH_NETDCU8            NETDCU8                 942
-ng_fvx538              MACH_NG_FVX538          NG_FVX538               944
-ng_fvs338              MACH_NG_FVS338          NG_FVS338               945
-pnx4103                        MACH_PNX4103            PNX4103                 946
-hesdb                  MACH_HESDB              HESDB                   947
-xsilo                  MACH_XSILO              XSILO                   948
 espresso               MACH_ESPRESSO           ESPRESSO                949
-emlc                   MACH_EMLC               EMLC                    950
-sisteron               MACH_SISTERON           SISTERON                951
 rx1950                 MACH_RX1950             RX1950                  952
-tsc_venus              MACH_TSC_VENUS          TSC_VENUS               953
-ds101j                 MACH_DS101J             DS101J                  954
-mxc30030ads            MACH_MXC30030ADS        MXC30030ADS             955
-fujitsu_wimaxsoc       MACH_FUJITSU_WIMAXSOC   FUJITSU_WIMAXSOC        956
-dualpcmodem            MACH_DUALPCMODEM        DUALPCMODEM             957
 gesbc9312              MACH_GESBC9312          GESBC9312               958
-htcapache              MACH_HTCAPACHE          HTCAPACHE               959
-ixdp435                        MACH_IXDP435            IXDP435                 960
-catprovt100            MACH_CATPROVT100        CATPROVT100             961
-picotux1xx             MACH_PICOTUX1XX         PICOTUX1XX              962
 picotux2xx             MACH_PICOTUX2XX         PICOTUX2XX              963
 dsmg600                        MACH_DSMG600            DSMG600                 964
-empc2                  MACH_EMPC2              EMPC2                   965
-ventura                        MACH_VENTURA            VENTURA                 966
-phidget_sbc            MACH_PHIDGET_SBC        PHIDGET_SBC             967
-ij3k                   MACH_IJ3K               IJ3K                    968
-pisgah                 MACH_PISGAH             PISGAH                  969
 omap_fsample           MACH_OMAP_FSAMPLE       OMAP_FSAMPLE            970
-sg720                  MACH_SG720              SG720                   971
-redfox                 MACH_REDFOX             REDFOX                  972
-mysh_ep9315_1          MACH_MYSH_EP9315_1      MYSH_EP9315_1           973
-tpf106                 MACH_TPF106             TPF106                  974
-at91rm9200kg           MACH_AT91RM9200KG       AT91RM9200KG            975
-rcmt2                  MACH_SLEDB              SLEDB                   976
-ontrack                        MACH_ONTRACK            ONTRACK                 977
-pm1200                 MACH_PM1200             PM1200                  978
-ess24562               MACH_ESS24XXX           ESS24XXX                979
-coremp7                        MACH_COREMP7            COREMP7                 980
-nexcoder_6446          MACH_NEXCODER_6446      NEXCODER_6446           981
-stvc8380               MACH_STVC8380           STVC8380                982
-teklynx                        MACH_TEKLYNX            TEKLYNX                 983
-carbonado              MACH_CARBONADO          CARBONADO               984
-sysmos_mp730           MACH_SYSMOS_MP730       SYSMOS_MP730            985
 snapper_cl15           MACH_SNAPPER_CL15       SNAPPER_CL15            986
-pgigim                 MACH_PGIGIM             PGIGIM                  987
-ptx9160p2              MACH_PTX9160P2          PTX9160P2               988
-dcore1                 MACH_DCORE1             DCORE1                  989
-victorpxa              MACH_VICTORPXA          VICTORPXA               990
-mx2dtb                 MACH_MX2DTB             MX2DTB                  991
-pxa_irex_er0100                MACH_PXA_IREX_ER0100    PXA_IREX_ER0100         992
 omap_palmz71           MACH_OMAP_PALMZ71       OMAP_PALMZ71            993
-bartec_deg             MACH_BARTEC_DEG         BARTEC_DEG              994
-hw50251                        MACH_HW50251            HW50251                 995
-ibox                   MACH_IBOX               IBOX                    996
-atlaslh7a404           MACH_ATLASLH7A404       ATLASLH7A404            997
-pt2026                 MACH_PT2026             PT2026                  998
-htcalpine              MACH_HTCALPINE          HTCALPINE               999
-bartec_vtu             MACH_BARTEC_VTU         BARTEC_VTU              1000
-vcoreii                        MACH_VCOREII            VCOREII                 1001
-pdnb3                  MACH_PDNB3              PDNB3                   1002
-htcbeetles             MACH_HTCBEETLES         HTCBEETLES              1003
-s3c6400                        MACH_S3C6400            S3C6400                 1004
-s3c2443                        MACH_S3C2443            S3C2443                 1005
-omap_ldk               MACH_OMAP_LDK           OMAP_LDK                1006
-smdk2460               MACH_SMDK2460           SMDK2460                1007
-smdk2440               MACH_SMDK2440           SMDK2440                1008
 smdk2412               MACH_SMDK2412           SMDK2412                1009
-webbox                 MACH_WEBBOX             WEBBOX                  1010
-cwwndp                 MACH_CWWNDP             CWWNDP                  1011
-i839                   MACH_DRAGON             DRAGON                  1012
-opendo_cpu_board       MACH_OPENDO_CPU_BOARD   OPENDO_CPU_BOARD        1013
-ccm2200                        MACH_CCM2200            CCM2200                 1014
-etwarm                 MACH_ETWARM             ETWARM                  1015
-m93030                 MACH_M93030             M93030                  1016
-cc7u                   MACH_CC7U               CC7U                    1017
-mtt_ranger             MACH_MTT_RANGER         MTT_RANGER              1018
-nexus                  MACH_NEXUS              NEXUS                   1019
-desman                 MACH_DESMAN             DESMAN                  1020
-bkde303                        MACH_BKDE303            BKDE303                 1021
 smdk2413               MACH_SMDK2413           SMDK2413                1022
-aml_m7200              MACH_AML_M7200          AML_M7200               1023
 aml_m5900              MACH_AML_M5900          AML_M5900               1024
-sg640                  MACH_SG640              SG640                   1025
-edg79524               MACH_EDG79524           EDG79524                1026
-ai2410                 MACH_AI2410             AI2410                  1027
-ixp465                 MACH_IXP465             IXP465                  1028
 balloon3               MACH_BALLOON3           BALLOON3                1029
-heins                  MACH_HEINS              HEINS                   1030
-mpluseva               MACH_MPLUSEVA           MPLUSEVA                1031
-rt042                  MACH_RT042              RT042                   1032
-cwiem                  MACH_CWIEM              CWIEM                   1033
-cm_x270                        MACH_CM_X270            CM_X270                 1034
-cm_x255                        MACH_CM_X255            CM_X255                 1035
-esh_at91               MACH_ESH_AT91           ESH_AT91                1036
-sandgate3              MACH_SANDGATE3          SANDGATE3               1037
-primo                  MACH_PRIMO              PRIMO                   1038
-gemstone               MACH_GEMSTONE           GEMSTONE                1039
-pronghorn_metro                MACH_PRONGHORNMETRO     PRONGHORNMETRO          1040
-sidewinder             MACH_SIDEWINDER         SIDEWINDER              1041
-picomod1               MACH_PICOMOD1           PICOMOD1                1042
-sg590                  MACH_SG590              SG590                   1043
-akai9307               MACH_AKAI9307           AKAI9307                1044
-fontaine               MACH_FONTAINE           FONTAINE                1045
-wombat                 MACH_WOMBAT             WOMBAT                  1046
-acq300                 MACH_ACQ300             ACQ300                  1047
-mod272                 MACH_MOD_270            MOD_270                 1048
-vmc_vc0820             MACH_VC0820             VC0820                  1049
-ani_aim                        MACH_ANI_AIM            ANI_AIM                 1050
-jellyfish              MACH_JELLYFISH          JELLYFISH               1051
-amanita                        MACH_AMANITA            AMANITA                 1052
-vlink                  MACH_VLINK              VLINK                   1053
-dexflex                        MACH_DEXFLEX            DEXFLEX                 1054
-eigen_ttq              MACH_EIGEN_TTQ          EIGEN_TTQ               1055
-arcom_titan            MACH_ARCOM_TITAN        ARCOM_TITAN             1056
-tabla                  MACH_TABLA              TABLA                   1057
-mdirac3                        MACH_MDIRAC3            MDIRAC3                 1058
-mrhfbp2                        MACH_MRHFBP2            MRHFBP2                 1059
-at91rm9200rb           MACH_AT91RM9200RB       AT91RM9200RB            1060
-ani_apm                        MACH_ANI_APM            ANI_APM                 1061
-ella1                  MACH_ELLA1              ELLA1                   1062
-inhand_pxa27x          MACH_INHAND_PXA27X      INHAND_PXA27X           1063
-inhand_pxa25x          MACH_INHAND_PXA25X      INHAND_PXA25X           1064
-empos_xm               MACH_EMPOS_XM           EMPOS_XM                1065
-empos                  MACH_EMPOS              EMPOS                   1066
-empos_tiny             MACH_EMPOS_TINY         EMPOS_TINY              1067
-empos_sm               MACH_EMPOS_SM           EMPOS_SM                1068
-egret                  MACH_EGRET              EGRET                   1069
-ostrich                        MACH_OSTRICH            OSTRICH                 1070
-n50                    MACH_N50                N50                     1071
 ecbat91                        MACH_ECBAT91            ECBAT91                 1072
-stareast               MACH_STAREAST           STAREAST                1073
-dspg_dw                        MACH_DSPG_DW            DSPG_DW                 1074
 onearm                 MACH_ONEARM             ONEARM                  1075
-mrg110_6               MACH_MRG110_6           MRG110_6                1076
-wrt300nv2              MACH_WRT300NV2          WRT300NV2               1077
-xm_bulverde            MACH_XM_BULVERDE        XM_BULVERDE             1078
-msm6100                        MACH_MSM6100            MSM6100                 1079
-eti_b1                 MACH_ETI_B1             ETI_B1                  1080
-za9l_series            MACH_ZILOG_ZA9L         ZILOG_ZA9L              1081
-bit2440                        MACH_BIT2440            BIT2440                 1082
-nbi                    MACH_NBI                NBI                     1083
 smdk2443               MACH_SMDK2443           SMDK2443                1084
-vdavinci               MACH_VDAVINCI           VDAVINCI                1085
-atc6                   MACH_ATC6               ATC6                    1086
-multmdw                        MACH_MULTMDW            MULTMDW                 1087
-mba2440                        MACH_MBA2440            MBA2440                 1088
-ecsd                   MACH_ECSD               ECSD                    1089
-palmz31                        MACH_PALMZ31            PALMZ31                 1090
 fsg                    MACH_FSG                FSG                     1091
-razor101               MACH_RAZOR101           RAZOR101                1092
-opera_tdm              MACH_OPERA_TDM          OPERA_TDM               1093
-comcerto               MACH_COMCERTO           COMCERTO                1094
-tb0319                 MACH_TB0319             TB0319                  1095
-kws8000                        MACH_KWS8000            KWS8000                 1096
-b2                     MACH_B2                 B2                      1097
-lcl54                  MACH_LCL54              LCL54                   1098
 at91sam9260ek          MACH_AT91SAM9260EK      AT91SAM9260EK           1099
 glantank               MACH_GLANTANK           GLANTANK                1100
 n2100                  MACH_N2100              N2100                   1101
-n4100                  MACH_N4100              N4100                   1102
-rsc4                   MACH_VERTICAL_RSC4      VERTICAL_RSC4           1103
-sg8100                 MACH_SG8100             SG8100                  1104
-im42xx                 MACH_IM42XX             IM42XX                  1105
-ftxx                   MACH_FTXX               FTXX                    1106
-lwfusion               MACH_LWFUSION           LWFUSION                1107
 qt2410                 MACH_QT2410             QT2410                  1108
 kixrp435               MACH_KIXRP435           KIXRP435                1109
-ccw9c                  MACH_CCW9C              CCW9C                   1110
-dabhs                  MACH_DABHS              DABHS                   1111
-gzmx                   MACH_GZMX               GZMX                    1112
-ipnw100ap              MACH_IPNW100AP          IPNW100AP               1113
 cc9p9360dev            MACH_CC9P9360DEV        CC9P9360DEV             1114
-cc9p9750dev            MACH_CC9P9750DEV        CC9P9750DEV             1115
-cc9p9360val            MACH_CC9P9360VAL        CC9P9360VAL             1116
-cc9p9750val            MACH_CC9P9750VAL        CC9P9750VAL             1117
-nx70v                  MACH_NX70V              NX70V                   1118
-at91rm9200df           MACH_AT91RM9200DF       AT91RM9200DF            1119
-se_pilot2              MACH_SE_PILOT2          SE_PILOT2               1120
-mtcn_t800              MACH_MTCN_T800          MTCN_T800               1121
-vcmx212                        MACH_VCMX212            VCMX212                 1122
-lynx                   MACH_LYNX               LYNX                    1123
-at91sam9260id          MACH_AT91SAM9260ID      AT91SAM9260ID           1124
-hw86052                        MACH_HW86052            HW86052                 1125
-pilz_pmi3              MACH_PILZ_PMI3          PILZ_PMI3               1126
 edb9302a               MACH_EDB9302A           EDB9302A                1127
 edb9307a               MACH_EDB9307A           EDB9307A                1128
-ct_dfs                 MACH_CT_DFS             CT_DFS                  1129
-pilz_pmi4              MACH_PILZ_PMI4          PILZ_PMI4               1130
-xceednp_ixp            MACH_XCEEDNP_IXP        XCEEDNP_IXP             1131
-smdk2442b              MACH_SMDK2442B          SMDK2442B               1132
-xnode                  MACH_XNODE              XNODE                   1133
-aidx270                        MACH_AIDX270            AIDX270                 1134
-rema                   MACH_REMA               REMA                    1135
-bps1000                        MACH_BPS1000            BPS1000                 1136
-hw90350                        MACH_HW90350            HW90350                 1137
 omap_3430sdp           MACH_OMAP_3430SDP       OMAP_3430SDP            1138
-bluetouch              MACH_BLUETOUCH          BLUETOUCH               1139
 vstms                  MACH_VSTMS              VSTMS                   1140
-xsbase270              MACH_XSBASE270          XSBASE270               1141
-at91sam9260ek_cn       MACH_AT91SAM9260EK_CN   AT91SAM9260EK_CN        1142
-adsturboxb             MACH_ADSTURBOXB         ADSTURBOXB              1143
-oti4110                        MACH_OTI4110            OTI4110                 1144
-hme_pxa                        MACH_HME_PXA            HME_PXA                 1145
-deisterdca             MACH_DEISTERDCA         DEISTERDCA              1146
-ces_ssem2              MACH_CES_SSEM2          CES_SSEM2               1147
-ces_mtr                        MACH_CES_MTR            CES_MTR                 1148
-tds_avng_sbc           MACH_TDS_AVNG_SBC       TDS_AVNG_SBC            1149
-everest                        MACH_EVEREST            EVEREST                 1150
-pnx4010                        MACH_PNX4010            PNX4010                 1151
-oxnas                  MACH_OXNAS              OXNAS                   1152
-fiori                  MACH_FIORI              FIORI                   1153
-ml1200                 MACH_ML1200             ML1200                  1154
-pecos                  MACH_PECOS              PECOS                   1155
-nb2xxx                 MACH_NB2XXX             NB2XXX                  1156
-hw6900                 MACH_HW6900             HW6900                  1157
-cdcs_quoll             MACH_CDCS_QUOLL         CDCS_QUOLL              1158
-quicksilver            MACH_QUICKSILVER        QUICKSILVER             1159
-uplat926               MACH_UPLAT926           UPLAT926                1160
-dep2410_dep2410                MACH_DEP2410_THOMAS     DEP2410_THOMAS          1161
-dtk2410                        MACH_DTK2410            DTK2410                 1162
-chili                  MACH_CHILI              CHILI                   1163
-demeter                        MACH_DEMETER            DEMETER                 1164
-dionysus               MACH_DIONYSUS           DIONYSUS                1165
-as352x                 MACH_AS352X             AS352X                  1166
-service                        MACH_SERVICE            SERVICE                 1167
-cs_e9301               MACH_CS_E9301           CS_E9301                1168
 micro9m                        MACH_MICRO9M            MICRO9M                 1169
-ia_mospck              MACH_IA_MOSPCK          IA_MOSPCK               1170
-ql201b                 MACH_QL201B             QL201B                  1171
-bbm                    MACH_BBM                BBM                     1174
-exxx                   MACH_EXXX               EXXX                    1175
-wma11b                 MACH_WMA11B             WMA11B                  1176
-pelco_atlas            MACH_PELCO_ATLAS        PELCO_ATLAS             1177
-g500                   MACH_G500               G500                    1178
 bug                    MACH_BUG                BUG                     1179
-mx33ads                        MACH_MX33ADS            MX33ADS                 1180
-chub                   MACH_CHUB               CHUB                    1181
-neo1973_gta01          MACH_NEO1973_GTA01      NEO1973_GTA01           1182
-w90n740                        MACH_W90N740            W90N740                 1183
-medallion_sa2410       MACH_MEDALLION_SA2410   MEDALLION_SA2410        1184
-ia_cpu_9200_2          MACH_IA_CPU_9200_2      IA_CPU_9200_2           1185
-dimmrm9200             MACH_DIMMRM9200         DIMMRM9200              1186
-pm9261                 MACH_PM9261             PM9261                  1187
-ml7304                 MACH_ML7304             ML7304                  1189
-ucp250                 MACH_UCP250             UCP250                  1190
-intboard               MACH_INTBOARD           INTBOARD                1191
-gulfstream             MACH_GULFSTREAM         GULFSTREAM              1192
-labquest               MACH_LABQUEST           LABQUEST                1193
-vcmx313                        MACH_VCMX313            VCMX313                 1194
-urg200                 MACH_URG200             URG200                  1195
-cpux255lcdnet          MACH_CPUX255LCDNET      CPUX255LCDNET           1196
-netdcu9                        MACH_NETDCU9            NETDCU9                 1197
-netdcu10               MACH_NETDCU10           NETDCU10                1198
-dspg_dga               MACH_DSPG_DGA           DSPG_DGA                1199
-dspg_dvw               MACH_DSPG_DVW           DSPG_DVW                1200
-solos                  MACH_SOLOS              SOLOS                   1201
 at91sam9263ek          MACH_AT91SAM9263EK      AT91SAM9263EK           1202
-osstbox                        MACH_OSSTBOX            OSSTBOX                 1203
-kbat9261               MACH_KBAT9261           KBAT9261                1204
-ct1100                 MACH_CT1100             CT1100                  1205
-akcppxa                        MACH_AKCPPXA            AKCPPXA                 1206
-ochaya1020             MACH_OCHAYA1020         OCHAYA1020              1207
-hitrack                        MACH_HITRACK            HITRACK                 1208
-syme1                  MACH_SYME1              SYME1                   1209
-syhl1                  MACH_SYHL1              SYHL1                   1210
-empca400               MACH_EMPCA400           EMPCA400                1211
 em7210                 MACH_EM7210             EM7210                  1212
-htchermes              MACH_HTCHERMES          HTCHERMES               1213
-eti_c1                 MACH_ETI_C1             ETI_C1                  1214
-ac100                  MACH_AC100              AC100                   1216
-sneetch                        MACH_SNEETCH            SNEETCH                 1217
-studentmate            MACH_STUDENTMATE        STUDENTMATE             1218
-zir2410                        MACH_ZIR2410            ZIR2410                 1219
-zir2413                        MACH_ZIR2413            ZIR2413                 1220
-dlonip3                        MACH_DLONIP3            DLONIP3                 1221
-instream               MACH_INSTREAM           INSTREAM                1222
-ambarella              MACH_AMBARELLA          AMBARELLA               1223
-nevis                  MACH_NEVIS              NEVIS                   1224
-htc_trinity            MACH_HTC_TRINITY        HTC_TRINITY             1225
-ql202b                 MACH_QL202B             QL202B                  1226
 vpac270                        MACH_VPAC270            VPAC270                 1227
-rd129                  MACH_RD129              RD129                   1228
-htcwizard              MACH_HTCWIZARD          HTCWIZARD               1229
 treo680                        MACH_TREO680            TREO680                 1230
-tecon_tmezon           MACH_TECON_TMEZON       TECON_TMEZON            1231
 zylonite               MACH_ZYLONITE           ZYLONITE                1233
-gene1270               MACH_GENE1270           GENE1270                1234
-zir2412                        MACH_ZIR2412            ZIR2412                 1235
 mx31lite               MACH_MX31LITE           MX31LITE                1236
-t700wx                 MACH_T700WX             T700WX                  1237
-vf100                  MACH_VF100              VF100                   1238
-nsb2                   MACH_NSB2               NSB2                    1239
-nxhmi_bb               MACH_NXHMI_BB           NXHMI_BB                1240
-nxhmi_re               MACH_NXHMI_RE           NXHMI_RE                1241
-n4100pro               MACH_N4100PRO           N4100PRO                1242
-sam9260                        MACH_SAM9260            SAM9260                 1243
-omap_treo600           MACH_OMAP_TREO600       OMAP_TREO600            1244
-indy2410               MACH_INDY2410           INDY2410                1245
-nelt_a                 MACH_NELT_A             NELT_A                  1246
-n311                   MACH_N311               N311                    1248
-at91sam9260vgk         MACH_AT91SAM9260VGK     AT91SAM9260VGK          1249
-at91leppe              MACH_AT91LEPPE          AT91LEPPE               1250
-at91lepccn             MACH_AT91LEPCCN         AT91LEPCCN              1251
-apc7100                        MACH_APC7100            APC7100                 1252
-stargazer              MACH_STARGAZER          STARGAZER               1253
-sonata                 MACH_SONATA             SONATA                  1254
-schmoogie              MACH_SCHMOOGIE          SCHMOOGIE               1255
-aztool                 MACH_AZTOOL             AZTOOL                  1256
 mioa701                        MACH_MIOA701            MIOA701                 1257
-sxni9260               MACH_SXNI9260           SXNI9260                1258
-mxc27520evb            MACH_MXC27520EVB        MXC27520EVB             1259
 armadillo5x0           MACH_ARMADILLO5X0       ARMADILLO5X0            1260
-mb9260                 MACH_MB9260             MB9260                  1261
-mb9263                 MACH_MB9263             MB9263                  1262
-ipac9302               MACH_IPAC9302           IPAC9302                1263
 cc9p9360js             MACH_CC9P9360JS         CC9P9360JS              1264
-gallium                        MACH_GALLIUM            GALLIUM                 1265
-msc2410                        MACH_MSC2410            MSC2410                 1266
-ghi270                 MACH_GHI270             GHI270                  1267
-davinci_leonardo       MACH_DAVINCI_LEONARDO   DAVINCI_LEONARDO        1268
-oiab                   MACH_OIAB               OIAB                    1269
 smdk6400               MACH_SMDK6400           SMDK6400                1270
 nokia_n800             MACH_NOKIA_N800         NOKIA_N800              1271
-greenphone             MACH_GREENPHONE         GREENPHONE              1272
-compex42x              MACH_COMPEXWP18         COMPEXWP18              1273
-xmate                  MACH_XMATE              XMATE                   1274
-energizer              MACH_ENERGIZER          ENERGIZER               1275
-ime1                   MACH_IME1               IME1                    1276
-sweda_tms              MACH_SWEDATMS           SWEDATMS                1277
-ntnp435c               MACH_NTNP435C           NTNP435C                1278
-spectro2               MACH_SPECTRO2           SPECTRO2                1279
-h6039                  MACH_H6039              H6039                   1280
 ep80219                        MACH_EP80219            EP80219                 1281
-samoa_ii               MACH_SAMOA_II           SAMOA_II                1282
-cwmxl                  MACH_CWMXL              CWMXL                   1283
-as9200                 MACH_AS9200             AS9200                  1284
-sfx1149                        MACH_SFX1149            SFX1149                 1285
-navi010                        MACH_NAVI010            NAVI010                 1286
-multmdp                        MACH_MULTMDP            MULTMDP                 1287
-scb9520                        MACH_SCB9520            SCB9520                 1288
-htcathena              MACH_HTCATHENA          HTCATHENA               1289
-xp179                  MACH_XP179              XP179                   1290
-h4300                  MACH_H4300              H4300                   1291
 goramo_mlr             MACH_GORAMO_MLR         GORAMO_MLR              1292
-mxc30020evb            MACH_MXC30020EVB        MXC30020EVB             1293
-adsbitsyg5             MACH_ADSBITSYG5         ADSBITSYG5              1294
-adsportalplus          MACH_ADSPORTALPLUS      ADSPORTALPLUS           1295
-mmsp2plus              MACH_MMSP2PLUS          MMSP2PLUS               1296
 em_x270                        MACH_EM_X270            EM_X270                 1297
-tpp302                 MACH_TPP302             TPP302                  1298
-tpp104                 MACH_TPM104             TPM104                  1299
-tpm102                 MACH_TPM102             TPM102                  1300
-tpm109                 MACH_TPM109             TPM109                  1301
-fbxo1                  MACH_FBXO1              FBXO1                   1302
-hxd8                   MACH_HXD8               HXD8                    1303
 neo1973_gta02          MACH_NEO1973_GTA02      NEO1973_GTA02           1304
-emtest                 MACH_EMTEST             EMTEST                  1305
-ad6900                 MACH_AD6900             AD6900                  1306
-europa                 MACH_EUROPA             EUROPA                  1307
-metroconnect           MACH_METROCONNECT       METROCONNECT            1308
-ez_s2410               MACH_EZ_S2410           EZ_S2410                1309
-ez_s2440               MACH_EZ_S2440           EZ_S2440                1310
-ez_ep9312              MACH_EZ_EP9312          EZ_EP9312               1311
-ez_ep9315              MACH_EZ_EP9315          EZ_EP9315               1312
-ez_x7                  MACH_EZ_X7              EZ_X7                   1313
-godotdb                        MACH_GODOTDB            GODOTDB                 1314
-mistral                        MACH_MISTRAL            MISTRAL                 1315
-msm                    MACH_MSM                MSM                     1316
-ct5910                 MACH_CT5910             CT5910                  1317
-ct5912                 MACH_CT5912             CT5912                  1318
-hynet_ine              MACH_HYNET_INE          HYNET_INE               1319
-hynet_app              MACH_HYNET_APP          HYNET_APP               1320
-msm7200                        MACH_MSM7200            MSM7200                 1321
-msm7600                        MACH_MSM7600            MSM7600                 1322
-ceb255                 MACH_CEB255             CEB255                  1323
-ciel                   MACH_CIEL               CIEL                    1324
-slm5650                        MACH_SLM5650            SLM5650                 1325
 at91sam9rlek           MACH_AT91SAM9RLEK       AT91SAM9RLEK            1326
-comtech_router         MACH_COMTECH_ROUTER     COMTECH_ROUTER          1327
-sbc2410x               MACH_SBC2410X           SBC2410X                1328
-at4x0bd                        MACH_AT4X0BD            AT4X0BD                 1329
-cbifr                  MACH_CBIFR              CBIFR                   1330
-arcom_quantum          MACH_ARCOM_QUANTUM      ARCOM_QUANTUM           1331
-matrix520              MACH_MATRIX520          MATRIX520               1332
-matrix510              MACH_MATRIX510          MATRIX510               1333
-matrix500              MACH_MATRIX500          MATRIX500               1334
-m501                   MACH_M501               M501                    1335
-aaeon1270              MACH_AAEON1270          AAEON1270               1336
-matrix500ev            MACH_MATRIX500EV        MATRIX500EV             1337
-pac500                 MACH_PAC500             PAC500                  1338
-pnx8181                        MACH_PNX8181            PNX8181                 1339
 colibri320             MACH_COLIBRI320         COLIBRI320              1340
-aztoolbb               MACH_AZTOOLBB           AZTOOLBB                1341
-aztoolg2               MACH_AZTOOLG2           AZTOOLG2                1342
-dvlhost                        MACH_DVLHOST            DVLHOST                 1343
-zir9200                        MACH_ZIR9200            ZIR9200                 1344
-zir9260                        MACH_ZIR9260            ZIR9260                 1345
-cocopah                        MACH_COCOPAH            COCOPAH                 1346
-nds                    MACH_NDS                NDS                     1347
-rosencrantz            MACH_ROSENCRANTZ        ROSENCRANTZ             1348
-fttx_odsc              MACH_FTTX_ODSC          FTTX_ODSC               1349
-classe_r6904           MACH_CLASSE_R6904       CLASSE_R6904            1350
 cam60                  MACH_CAM60              CAM60                   1351
-mxc30031ads            MACH_MXC30031ADS        MXC30031ADS             1352
-datacall               MACH_DATACALL           DATACALL                1353
 at91eb01               MACH_AT91EB01           AT91EB01                1354
-rty                    MACH_RTY                RTY                     1355
-dwl2100                        MACH_DWL2100            DWL2100                 1356
-vinsi                  MACH_VINSI              VINSI                   1357
 db88f5281              MACH_DB88F5281          DB88F5281               1358
 csb726                 MACH_CSB726             CSB726                  1359
-tik27                  MACH_TIK27              TIK27                   1360
-mx_uc7420              MACH_MX_UC7420          MX_UC7420               1361
-rirm3                  MACH_RIRM3              RIRM3                   1362
-pelco_odyssey          MACH_PELCO_ODYSSEY      PELCO_ODYSSEY           1363
-adx_abox               MACH_ADX_ABOX           ADX_ABOX                1365
-adx_tpid               MACH_ADX_TPID           ADX_TPID                1366
-minicheck              MACH_MINICHECK          MINICHECK               1367
-idam                   MACH_IDAM               IDAM                    1368
-mario_mx               MACH_MARIO_MX           MARIO_MX                1369
-vi1888                 MACH_VI1888             VI1888                  1370
-zr4230                 MACH_ZR4230             ZR4230                  1371
-t1_ix_blue             MACH_T1_IX_BLUE         T1_IX_BLUE              1372
-syhq2                  MACH_SYHQ2              SYHQ2                   1373
-computime_r3           MACH_COMPUTIME_R3       COMPUTIME_R3            1374
-oratis                 MACH_ORATIS             ORATIS                  1375
-mikko                  MACH_MIKKO              MIKKO                   1376
-holon                  MACH_HOLON              HOLON                   1377
-olip8                  MACH_OLIP8              OLIP8                   1378
-ghi270hg               MACH_GHI270HG           GHI270HG                1379
 davinci_dm6467_evm     MACH_DAVINCI_DM6467_EVM DAVINCI_DM6467_EVM      1380
 davinci_dm355_evm      MACH_DAVINCI_DM355_EVM  DAVINCI_DM355_EVM       1381
-blackriver             MACH_BLACKRIVER         BLACKRIVER              1383
-sandgate_wp            MACH_SANDGATEWP         SANDGATEWP              1384
-cdotbwsg               MACH_CDOTBWSG           CDOTBWSG                1385
-quark963               MACH_QUARK963           QUARK963                1386
-csb735                 MACH_CSB735             CSB735                  1387
 littleton              MACH_LITTLETON          LITTLETON               1388
-mio_p550               MACH_MIO_P550           MIO_P550                1389
-motion2440             MACH_MOTION2440         MOTION2440              1390
-imm500                 MACH_IMM500             IMM500                  1391
-homematic              MACH_HOMEMATIC          HOMEMATIC               1392
-ermine                 MACH_ERMINE             ERMINE                  1393
-kb9202b                        MACH_KB9202B            KB9202B                 1394
-hs1xx                  MACH_HS1XX              HS1XX                   1395
-studentmate2440                MACH_STUDENTMATE2440    STUDENTMATE2440         1396
-arvoo_l1_z1            MACH_ARVOO_L1_Z1        ARVOO_L1_Z1             1397
-dep2410k               MACH_DEP2410K           DEP2410K                1398
-xxsvideo               MACH_XXSVIDEO           XXSVIDEO                1399
-im4004                 MACH_IM4004             IM4004                  1400
-ochaya1050             MACH_OCHAYA1050         OCHAYA1050              1401
-lep9261                        MACH_LEP9261            LEP9261                 1402
-svenmeb                        MACH_SVENMEB            SVENMEB                 1403
-fortunet2ne            MACH_FORTUNET2NE        FORTUNET2NE             1404
-nxhx                   MACH_NXHX               NXHX                    1406
 realview_pb11mp                MACH_REALVIEW_PB11MP    REALVIEW_PB11MP         1407
-ids500                 MACH_IDS500             IDS500                  1408
-ors_n725               MACH_ORS_N725           ORS_N725                1409
-hsdarm                 MACH_HSDARM             HSDARM                  1410
-sha_pon003             MACH_SHA_PON003         SHA_PON003              1411
-sha_pon004             MACH_SHA_PON004         SHA_PON004              1412
-sha_pon007             MACH_SHA_PON007         SHA_PON007              1413
-sha_pon011             MACH_SHA_PON011         SHA_PON011              1414
-h6042                  MACH_H6042              H6042                   1415
-h6043                  MACH_H6043              H6043                   1416
-looxc550               MACH_LOOXC550           LOOXC550                1417
-cnty_titan             MACH_CNTY_TITAN         CNTY_TITAN              1418
-app3xx                 MACH_APP3XX             APP3XX                  1419
-sideoatsgrama          MACH_SIDEOATSGRAMA      SIDEOATSGRAMA           1420
-treo700p               MACH_TREO700P           TREO700P                1421
-treo700w               MACH_TREO700W           TREO700W                1422
-treo750                        MACH_TREO750            TREO750                 1423
-treo755p               MACH_TREO755P           TREO755P                1424
-ezreganut9200          MACH_EZREGANUT9200      EZREGANUT9200           1425
-sarge                  MACH_SARGE              SARGE                   1426
-a696                   MACH_A696               A696                    1427
-turtle1916             MACH_TURTLE             TURTLE                  1428
 mx27_3ds               MACH_MX27_3DS           MX27_3DS                1430
-bishop                 MACH_BISHOP             BISHOP                  1431
-pxx                    MACH_PXX                PXX                     1432
-redwood                        MACH_REDWOOD            REDWOOD                 1433
-omap_2430dlp           MACH_OMAP_2430DLP       OMAP_2430DLP            1436
-omap_2430osk           MACH_OMAP_2430OSK       OMAP_2430OSK            1437
-sardine                        MACH_SARDINE            SARDINE                 1438
 halibut                        MACH_HALIBUT            HALIBUT                 1439
 trout                  MACH_TROUT              TROUT                   1440
-goldfish               MACH_GOLDFISH           GOLDFISH                1441
-gesbc2440              MACH_GESBC2440          GESBC2440               1442
-nomad                  MACH_NOMAD              NOMAD                   1443
-rosalind               MACH_ROSALIND           ROSALIND                1444
-cc9p9215               MACH_CC9P9215           CC9P9215                1445
-cc9p9210               MACH_CC9P9210           CC9P9210                1446
-cc9p9215js             MACH_CC9P9215JS         CC9P9215JS              1447
-cc9p9210js             MACH_CC9P9210JS         CC9P9210JS              1448
-nasffe                 MACH_NASFFE             NASFFE                  1449
-tn2x0bd                        MACH_TN2X0BD            TN2X0BD                 1450
-gwmpxa                 MACH_GWMPXA             GWMPXA                  1451
-exyplus                        MACH_EXYPLUS            EXYPLUS                 1452
-jadoo21                        MACH_JADOO21            JADOO21                 1453
-looxn560               MACH_LOOXN560           LOOXN560                1454
-bonsai                 MACH_BONSAI             BONSAI                  1455
-adsmilgato             MACH_ADSMILGATO         ADSMILGATO              1456
-gba                    MACH_GBA                GBA                     1457
-h6044                  MACH_H6044              H6044                   1458
-app                    MACH_APP                APP                     1459
 tct_hammer             MACH_TCT_HAMMER         TCT_HAMMER              1460
 herald                 MACH_HERALD             HERALD                  1461
-artemis                        MACH_ARTEMIS            ARTEMIS                 1462
-htctitan               MACH_HTCTITAN           HTCTITAN                1463
-qranium                        MACH_QRANIUM            QRANIUM                 1464
-adx_wsc2               MACH_ADX_WSC2           ADX_WSC2                1465
-adx_medcom             MACH_ADX_MEDCOM         ADX_MEDCOM              1466
-bboard                 MACH_BBOARD             BBOARD                  1467
-cambria                        MACH_CAMBRIA            CAMBRIA                 1468
-mt7xxx                 MACH_MT7XXX             MT7XXX                  1469
-matrix512              MACH_MATRIX512          MATRIX512               1470
-matrix522              MACH_MATRIX522          MATRIX522               1471
-ipac5010               MACH_IPAC5010           IPAC5010                1472
-sakura                 MACH_SAKURA             SAKURA                  1473
-grocx                  MACH_GROCX              GROCX                   1474
-pm9263                 MACH_PM9263             PM9263                  1475
 sim_one                        MACH_SIM_ONE            SIM_ONE                 1476
-acq132                 MACH_ACQ132             ACQ132                  1477
-datr                   MACH_DATR               DATR                    1478
-actux1                 MACH_ACTUX1             ACTUX1                  1479
-actux2                 MACH_ACTUX2             ACTUX2                  1480
-actux3                 MACH_ACTUX3             ACTUX3                  1481
-flexit                 MACH_FLEXIT             FLEXIT                  1482
-bh2x0bd                        MACH_BH2X0BD            BH2X0BD                 1483
-atb2002                        MACH_ATB2002            ATB2002                 1484
-xenon                  MACH_XENON              XENON                   1485
-fm607                  MACH_FM607              FM607                   1486
-matrix514              MACH_MATRIX514          MATRIX514               1487
-matrix524              MACH_MATRIX524          MATRIX524               1488
-inpod                  MACH_INPOD              INPOD                   1489
 jive                   MACH_JIVE               JIVE                    1490
-tll_mx21               MACH_TLL_MX21           TLL_MX21                1491
-sbc2800                        MACH_SBC2800            SBC2800                 1492
-cc7ucamry              MACH_CC7UCAMRY          CC7UCAMRY               1493
-ubisys_p9_sc15         MACH_UBISYS_P9_SC15     UBISYS_P9_SC15          1494
-ubisys_p9_ssc2d10      MACH_UBISYS_P9_SSC2D10  UBISYS_P9_SSC2D10       1495
-ubisys_p9_rcu3         MACH_UBISYS_P9_RCU3     UBISYS_P9_RCU3          1496
-aml_m8000              MACH_AML_M8000          AML_M8000               1497
-snapper_270            MACH_SNAPPER_270        SNAPPER_270             1498
-omap_bbx               MACH_OMAP_BBX           OMAP_BBX                1499
-ucn2410                        MACH_UCN2410            UCN2410                 1500
 sam9_l9260             MACH_SAM9_L9260         SAM9_L9260              1501
-eti_c2                 MACH_ETI_C2             ETI_C2                  1502
-avalanche              MACH_AVALANCHE          AVALANCHE               1503
 realview_pb1176                MACH_REALVIEW_PB1176    REALVIEW_PB1176         1504
-dp1500                 MACH_DP1500             DP1500                  1505
-apple_iphone           MACH_APPLE_IPHONE       APPLE_IPHONE            1506
 yl9200                 MACH_YL9200             YL9200                  1507
 rd88f5182              MACH_RD88F5182          RD88F5182               1508
 kurobox_pro            MACH_KUROBOX_PRO        KUROBOX_PRO             1509
-se_poet                        MACH_SE_POET            SE_POET                 1510
 mx31_3ds               MACH_MX31_3DS           MX31_3DS                1511
-r270                   MACH_R270               R270                    1512
-armour21               MACH_ARMOUR21           ARMOUR21                1513
-dt2                    MACH_DT2                DT2                     1514
-vt4                    MACH_VT4                VT4                     1515
-tyco320                        MACH_TYCO320            TYCO320                 1516
-adma                   MACH_ADMA               ADMA                    1517
-wp188                  MACH_WP188              WP188                   1518
-corsica                        MACH_CORSICA            CORSICA                 1519
-bigeye                 MACH_BIGEYE             BIGEYE                  1520
-tll5000                        MACH_TLL5000            TLL5000                 1522
-bebot                  MACH_BEBOT              BEBOT                   1523
 qong                   MACH_QONG               QONG                    1524
-tcompact               MACH_TCOMPACT           TCOMPACT                1525
-puma5                  MACH_PUMA5              PUMA5                   1526
-elara                  MACH_ELARA              ELARA                   1527
-ellington              MACH_ELLINGTON          ELLINGTON               1528
-xda_atom               MACH_XDA_ATOM           XDA_ATOM                1529
-energizer2             MACH_ENERGIZER2         ENERGIZER2              1530
-odin                   MACH_ODIN               ODIN                    1531
-actux4                 MACH_ACTUX4             ACTUX4                  1532
-esl_omap               MACH_ESL_OMAP           ESL_OMAP                1533
 omap2evm               MACH_OMAP2EVM           OMAP2EVM                1534
 omap3evm               MACH_OMAP3EVM           OMAP3EVM                1535
-adx_pcu57              MACH_ADX_PCU57          ADX_PCU57               1536
-monaco                 MACH_MONACO             MONACO                  1537
-levante                        MACH_LEVANTE            LEVANTE                 1538
-tmxipx425              MACH_TMXIPX425          TMXIPX425               1539
-leep                   MACH_LEEP               LEEP                    1540
-raad                   MACH_RAAD               RAAD                    1541
 dns323                 MACH_DNS323             DNS323                  1542
-ap1000                 MACH_AP1000             AP1000                  1543
-a9sam6432              MACH_A9SAM6432          A9SAM6432               1544
-shiny                  MACH_SHINY              SHINY                   1545
 omap3_beagle           MACH_OMAP3_BEAGLE       OMAP3_BEAGLE            1546
-csr_bdb2               MACH_CSR_BDB2           CSR_BDB2                1547
 nokia_n810             MACH_NOKIA_N810         NOKIA_N810              1548
-c270                   MACH_C270               C270                    1549
-sentry                 MACH_SENTRY             SENTRY                  1550
 pcm038                 MACH_PCM038             PCM038                  1551
-anc300                 MACH_ANC300             ANC300                  1552
-htckaiser              MACH_HTCKAISER          HTCKAISER               1553
-sbat100                        MACH_SBAT100            SBAT100                 1554
-modunorm               MACH_MODUNORM           MODUNORM                1555
-pelos_twarm            MACH_PELOS_TWARM        PELOS_TWARM             1556
-flank                  MACH_FLANK              FLANK                   1557
-sirloin                        MACH_SIRLOIN            SIRLOIN                 1558
-brisket                        MACH_BRISKET            BRISKET                 1559
-chuck                  MACH_CHUCK              CHUCK                   1560
-otter                  MACH_OTTER              OTTER                   1561
-davinci_ldk            MACH_DAVINCI_LDK        DAVINCI_LDK             1562
-phreedom               MACH_PHREEDOM           PHREEDOM                1563
-sg310                  MACH_SG310              SG310                   1564
 ts_x09                 MACH_TS209              TS209                   1565
 at91cap9adk            MACH_AT91CAP9ADK        AT91CAP9ADK             1566
-tion9315               MACH_TION9315           TION9315                1567
-mast                   MACH_MAST               MAST                    1568
-pfw                    MACH_PFW                PFW                     1569
-yl_p2440               MACH_YL_P2440           YL_P2440                1570
-zsbc32                 MACH_ZSBC32             ZSBC32                  1571
-omap_pace2             MACH_OMAP_PACE2         OMAP_PACE2              1572
-imx_pace2              MACH_IMX_PACE2          IMX_PACE2               1573
 mx31moboard            MACH_MX31MOBOARD        MX31MOBOARD             1574
-mx37_3ds               MACH_MX37_3DS           MX37_3DS                1575
-rcc                    MACH_RCC                RCC                     1576
-dmp                    MACH_ARM9               ARM9                    1577
-vision_ep9307          MACH_VISION_EP9307      VISION_EP9307           1578
-scly1000               MACH_SCLY1000           SCLY1000                1579
-fontel_ep              MACH_FONTEL_EP          FONTEL_EP               1580
-voiceblue3g            MACH_VOICEBLUE3G        VOICEBLUE3G             1581
-tt9200                 MACH_TT9200             TT9200                  1582
-digi2410               MACH_DIGI2410           DIGI2410                1583
 terastation_pro2       MACH_TERASTATION_PRO2   TERASTATION_PRO2        1584
 linkstation_pro                MACH_LINKSTATION_PRO    LINKSTATION_PRO         1585
-motorola_a780          MACH_MOTOROLA_A780      MOTOROLA_A780           1587
-motorola_e6            MACH_MOTOROLA_E6        MOTOROLA_E6             1588
-motorola_e2            MACH_MOTOROLA_E2        MOTOROLA_E2             1589
-motorola_e680          MACH_MOTOROLA_E680      MOTOROLA_E680           1590
-ur2410                 MACH_UR2410             UR2410                  1591
-tas9261                        MACH_TAS9261            TAS9261                 1592
-davinci_hermes_hd      MACH_HERMES_HD          HERMES_HD               1593
-davinci_perseo_hd      MACH_PERSEO_HD          PERSEO_HD               1594
-stargazer2             MACH_STARGAZER2         STARGAZER2              1595
 e350                   MACH_E350               E350                    1596
-wpcm450                        MACH_WPCM450            WPCM450                 1597
-cartesio               MACH_CARTESIO           CARTESIO                1598
-toybox                 MACH_TOYBOX             TOYBOX                  1599
-tx27                   MACH_TX27               TX27                    1600
 ts409                  MACH_TS409              TS409                   1601
-p300                   MACH_P300               P300                    1602
-xdacomet               MACH_XDACOMET           XDACOMET                1603
-dexflex2               MACH_DEXFLEX2           DEXFLEX2                1604
-ow                     MACH_OW                 OW                      1605
-armebs3                        MACH_ARMEBS3            ARMEBS3                 1606
-u3                     MACH_U3                 U3                      1607
-smdk2450               MACH_SMDK2450           SMDK2450                1608
-rsi_ews                        MACH_RSI_EWS            RSI_EWS                 1609
-tnb                    MACH_TNB                TNB                     1610
-toepath                        MACH_TOEPATH            TOEPATH                 1611
-kb9263                 MACH_KB9263             KB9263                  1612
-mt7108                 MACH_MT7108             MT7108                  1613
-smtr2440               MACH_SMTR2440           SMTR2440                1614
-manao                  MACH_MANAO              MANAO                   1615
 cm_x300                        MACH_CM_X300            CM_X300                 1616
-gulfstream_kp          MACH_GULFSTREAM_KP      GULFSTREAM_KP           1617
-lanreadyfn522          MACH_LANREADYFN522      LANREADYFN522           1618
-arma37                 MACH_ARMA37             ARMA37                  1619
-mendel                 MACH_MENDEL             MENDEL                  1620
-pelco_iliad            MACH_PELCO_ILIAD        PELCO_ILIAD             1621
-unit2p                 MACH_UNIT2P             UNIT2P                  1622
-inc20otter             MACH_INC20OTTER         INC20OTTER              1623
 at91sam9g20ek          MACH_AT91SAM9G20EK      AT91SAM9G20EK           1624
-sc_ge2                 MACH_STORCENTER         STORCENTER              1625
 smdk6410               MACH_SMDK6410           SMDK6410                1626
 u300                   MACH_U300               U300                    1627
-u500                   MACH_U500               U500                    1628
-ds9260                 MACH_DS9260             DS9260                  1629
-riverrock              MACH_RIVERROCK          RIVERROCK               1630
-scibath                        MACH_SCIBATH            SCIBATH                 1631
-at91sam7se             MACH_AT91SAM7SE512EK    AT91SAM7SE512EK         1632
 wrt350n_v2             MACH_WRT350N_V2         WRT350N_V2              1633
-multimedia             MACH_MULTIMEDIA         MULTIMEDIA              1634
-marvin                 MACH_MARVIN             MARVIN                  1635
-x500                   MACH_X500               X500                    1636
-awlug4lcu              MACH_AWLUG4LCU          AWLUG4LCU               1637
-palermoc               MACH_PALERMOC           PALERMOC                1638
 omap_ldp               MACH_OMAP_LDP           OMAP_LDP                1639
-ip500                  MACH_IP500              IP500                   1640
-ase2                   MACH_ASE2               ASE2                    1642
-mx35evb                        MACH_MX35EVB            MX35EVB                 1643
-aml_m8050              MACH_AML_M8050          AML_M8050               1644
 mx35_3ds               MACH_MX35_3DS           MX35_3DS                1645
-mars                   MACH_MARS               MARS                    1646
 neuros_osd2            MACH_NEUROS_OSD2        NEUROS_OSD2             1647
-badger                 MACH_BADGER             BADGER                  1648
 trizeps4wl             MACH_TRIZEPS4WL         TRIZEPS4WL              1649
-trizeps5               MACH_TRIZEPS5           TRIZEPS5                1650
-marlin                 MACH_MARLIN             MARLIN                  1651
 ts78xx                 MACH_TS78XX             TS78XX                  1652
-hpipaq214              MACH_HPIPAQ214          HPIPAQ214               1653
-at572d940dcm           MACH_AT572D940DCM       AT572D940DCM            1654
-ne1board               MACH_NE1BOARD           NE1BOARD                1655
-zante                  MACH_ZANTE              ZANTE                   1656
 sffsdr                 MACH_SFFSDR             SFFSDR                  1657
-tw2662                 MACH_TW2662             TW2662                  1658
-vf10xx                 MACH_VF10XX             VF10XX                  1659
-zoran43xx              MACH_ZORAN43XX          ZORAN43XX               1660
-sonix926               MACH_SONIX926           SONIX926                1661
-celestialsemi          MACH_CELESTIALSEMI      CELESTIALSEMI           1662
-cc9m2443js             MACH_CC9M2443JS         CC9M2443JS              1663
-tw5334                 MACH_TW5334             TW5334                  1664
-omap_htcartemis                MACH_HTCARTEMIS         HTCARTEMIS              1665
-nal_hlite              MACH_NAL_HLITE          NAL_HLITE               1666
-htcvogue               MACH_HTCVOGUE           HTCVOGUE                1667
-smartweb               MACH_SMARTWEB           SMARTWEB                1668
-mv86xx                 MACH_MV86XX             MV86XX                  1669
-mv87xx                 MACH_MV87XX             MV87XX                  1670
-songyoungho            MACH_SONGYOUNGHO        SONGYOUNGHO             1671
-younghotema            MACH_YOUNGHOTEMA        YOUNGHOTEMA             1672
 pcm037                 MACH_PCM037             PCM037                  1673
-mmvp                   MACH_MMVP               MMVP                    1674
-mmap                   MACH_MMAP               MMAP                    1675
-ptid2410               MACH_PTID2410           PTID2410                1676
-james_926              MACH_JAMES_926          JAMES_926               1677
-fm6000                 MACH_FM6000             FM6000                  1678
 db88f6281_bp           MACH_DB88F6281_BP       DB88F6281_BP            1680
 rd88f6192_nas          MACH_RD88F6192_NAS      RD88F6192_NAS           1681
 rd88f6281              MACH_RD88F6281          RD88F6281               1682
 db78x00_bp             MACH_DB78X00_BP         DB78X00_BP              1683
 smdk2416               MACH_SMDK2416           SMDK2416                1685
-oce_spider_si          MACH_OCE_SPIDER_SI      OCE_SPIDER_SI           1686
-oce_spider_sk          MACH_OCE_SPIDER_SK      OCE_SPIDER_SK           1687
-rovern6                        MACH_ROVERN6            ROVERN6                 1688
-pelco_evolution                MACH_PELCO_EVOLUTION    PELCO_EVOLUTION         1689
 wbd111                 MACH_WBD111             WBD111                  1690
-elaracpe               MACH_ELARACPE           ELARACPE                1691
-mabv3                  MACH_MABV3              MABV3                   1692
 mv2120                 MACH_MV2120             MV2120                  1693
-csb737                 MACH_CSB737             CSB737                  1695
 mx51_3ds               MACH_MX51_3DS           MX51_3DS                1696
-g900                   MACH_G900               G900                    1697
-apf27                  MACH_APF27              APF27                   1698
-ggus2000               MACH_GGUS2000           GGUS2000                1699
-omap_2430_mimic                MACH_OMAP_2430_MIMIC    OMAP_2430_MIMIC         1700
 imx27lite              MACH_IMX27LITE          IMX27LITE               1701
-almex                  MACH_ALMEX              ALMEX                   1702
-control                        MACH_CONTROL            CONTROL                 1703
-mba2410                        MACH_MBA2410            MBA2410                 1704
-volcano                        MACH_VOLCANO            VOLCANO                 1705
-zenith                 MACH_ZENITH             ZENITH                  1706
-muchip                 MACH_MUCHIP             MUCHIP                  1707
-magellan               MACH_MAGELLAN           MAGELLAN                1708
 usb_a9260              MACH_USB_A9260          USB_A9260               1709
 usb_a9263              MACH_USB_A9263          USB_A9263               1710
 qil_a9260              MACH_QIL_A9260          QIL_A9260               1711
-cme9210                        MACH_CME9210            CME9210                 1712
-hczh4                  MACH_HCZH4              HCZH4                   1713
-spearbasic             MACH_SPEARBASIC         SPEARBASIC              1714
-dep2440                        MACH_DEP2440            DEP2440                 1715
-hdl_gxr                        MACH_HDL_GXR            HDL_GXR                 1716
-hdl_gt                 MACH_HDL_GT             HDL_GT                  1717
-hdl_4g                 MACH_HDL_4G             HDL_4G                  1718
-s3c6000                        MACH_S3C6000            S3C6000                 1719
-mmsp2_mdk              MACH_MMSP2_MDK          MMSP2_MDK               1720
-mpx220                 MACH_MPX220             MPX220                  1721
 kzm_arm11_01           MACH_KZM_ARM11_01       KZM_ARM11_01            1722
-htc_polaris            MACH_HTC_POLARIS        HTC_POLARIS             1723
-htc_kaiser             MACH_HTC_KAISER         HTC_KAISER              1724
-lg_ks20                        MACH_LG_KS20            LG_KS20                 1725
-hhgps                  MACH_HHGPS              HHGPS                   1726
 nokia_n810_wimax       MACH_NOKIA_N810_WIMAX   NOKIA_N810_WIMAX        1727
-insight                        MACH_INSIGHT            INSIGHT                 1728
 sapphire               MACH_SAPPHIRE           SAPPHIRE                1729
-csb637xo               MACH_CSB637XO           CSB637XO                1730
-evisiong               MACH_EVISIONG           EVISIONG                1731
 stmp37xx               MACH_STMP37XX           STMP37XX                1732
 stmp378x               MACH_STMP378X           STMP378X                1733
-tnt                    MACH_TNT                TNT                     1734
-tbxt                   MACH_TBXT               TBXT                    1735
-playmate               MACH_PLAYMATE           PLAYMATE                1736
-pns10                  MACH_PNS10              PNS10                   1737
-eznavi                 MACH_EZNAVI             EZNAVI                  1738
-ps4000                 MACH_PS4000             PS4000                  1739
 ezx_a780               MACH_EZX_A780           EZX_A780                1740
 ezx_e680               MACH_EZX_E680           EZX_E680                1741
 ezx_a1200              MACH_EZX_A1200          EZX_A1200               1742
 ezx_e6                 MACH_EZX_E6             EZX_E6                  1743
 ezx_e2                 MACH_EZX_E2             EZX_E2                  1744
 ezx_a910               MACH_EZX_A910           EZX_A910                1745
-cwmx31                 MACH_CWMX31             CWMX31                  1746
-sl2312                 MACH_SL2312             SL2312                  1747
-blenny                 MACH_BLENNY             BLENNY                  1748
-ds107                  MACH_DS107              DS107                   1749
-dsx07                  MACH_DSX07              DSX07                   1750
-picocom1               MACH_PICOCOM1           PICOCOM1                1751
-lynx_wolverine         MACH_LYNX_WOLVERINE     LYNX_WOLVERINE          1752
-ubisys_p9_sc19         MACH_UBISYS_P9_SC19     UBISYS_P9_SC19          1753
-kratos_low             MACH_KRATOS_LOW         KRATOS_LOW              1754
-m700                   MACH_M700               M700                    1755
 edmini_v2              MACH_EDMINI_V2          EDMINI_V2               1756
 zipit2                 MACH_ZIPIT2             ZIPIT2                  1757
-hslfemtocell           MACH_HSLFEMTOCELL       HSLFEMTOCELL            1758
-daintree_at91          MACH_DAINTREE_AT91      DAINTREE_AT91           1759
-sg560usb               MACH_SG560USB           SG560USB                1760
 omap3_pandora          MACH_OMAP3_PANDORA      OMAP3_PANDORA           1761
-usr8200                        MACH_USR8200            USR8200                 1762
-s1s65k                 MACH_S1S65K             S1S65K                  1763
-s2s65a                 MACH_S2S65A             S2S65A                  1764
-icore                  MACH_ICORE              ICORE                   1765
 mss2                   MACH_MSS2               MSS2                    1766
-belmont                        MACH_BELMONT            BELMONT                 1767
-asusp525               MACH_ASUSP525           ASUSP525                1768
 lb88rc8480             MACH_LB88RC8480         LB88RC8480              1769
-hipxa                  MACH_HIPXA              HIPXA                   1770
 mx25_3ds               MACH_MX25_3DS           MX25_3DS                1771
-m800                   MACH_M800               M800                    1772
 omap3530_lv_som                MACH_OMAP3530_LV_SOM    OMAP3530_LV_SOM         1773
-prima_evb              MACH_PRIMA_EVB          PRIMA_EVB               1774
-mx31bt1                        MACH_MX31BT1            MX31BT1                 1775
-atlas4_evb             MACH_ATLAS4_EVB         ATLAS4_EVB              1776
-mx31cicada             MACH_MX31CICADA         MX31CICADA              1777
-mi424wr                        MACH_MI424WR            MI424WR                 1778
-axs_ultrax             MACH_AXS_ULTRAX         AXS_ULTRAX              1779
-at572d940deb           MACH_AT572D940DEB       AT572D940DEB            1780
 davinci_da830_evm      MACH_DAVINCI_DA830_EVM  DAVINCI_DA830_EVM       1781
-ep9302                 MACH_EP9302             EP9302                  1782
 at572d940hfek          MACH_AT572D940HFEB      AT572D940HFEB           1783
-cybook3                        MACH_CYBOOK3            CYBOOK3                 1784
-wdg002                 MACH_WDG002             WDG002                  1785
-sg560adsl              MACH_SG560ADSL          SG560ADSL               1786
-nextio_n2800_ica       MACH_NEXTIO_N2800_ICA   NEXTIO_N2800_ICA        1787
 dove_db                        MACH_DOVE_DB            DOVE_DB                 1788
-marvell_newdb          MACH_MARVELL_NEWDB      MARVELL_NEWDB           1789
-vandihud               MACH_VANDIHUD           VANDIHUD                1790
-magx_e8                        MACH_MAGX_E8            MAGX_E8                 1791
-magx_z6                        MACH_MAGX_Z6            MAGX_Z6                 1792
-magx_v8                        MACH_MAGX_V8            MAGX_V8                 1793
-magx_u9                        MACH_MAGX_U9            MAGX_U9                 1794
-toughcf08              MACH_TOUGHCF08          TOUGHCF08               1795
-zw4400                 MACH_ZW4400             ZW4400                  1796
-marat91                        MACH_MARAT91            MARAT91                 1797
 overo                  MACH_OVERO              OVERO                   1798
 at2440evb              MACH_AT2440EVB          AT2440EVB               1799
 neocore926             MACH_NEOCORE926         NEOCORE926              1800
 wnr854t                        MACH_WNR854T            WNR854T                 1801
-imx27                  MACH_IMX27              IMX27                   1802
-moose_db               MACH_MOOSE_DB           MOOSE_DB                1803
-fab4                   MACH_FAB4               FAB4                    1804
-htcdiamond             MACH_HTCDIAMOND         HTCDIAMOND              1805
-fiona                  MACH_FIONA              FIONA                   1806
-mxc30030_x             MACH_MXC30030_X         MXC30030_X              1807
-bmp1000                        MACH_BMP1000            BMP1000                 1808
-logi9200               MACH_LOGI9200           LOGI9200                1809
-tqma31                 MACH_TQMA31             TQMA31                  1810
-ccw9p9215js            MACH_CCW9P9215JS        CCW9P9215JS             1811
 rd88f5181l_ge          MACH_RD88F5181L_GE      RD88F5181L_GE           1812
-sifmain                        MACH_SIFMAIN            SIFMAIN                 1813
-sam9_l9261             MACH_SAM9_L9261         SAM9_L9261              1814
-cc9m2443               MACH_CC9M2443           CC9M2443                1815
-xaria300               MACH_XARIA300           XARIA300                1816
-it9200                 MACH_IT9200             IT9200                  1817
 rd88f5181l_fxo         MACH_RD88F5181L_FXO     RD88F5181L_FXO          1818
-kriss_sensor           MACH_KRISS_SENSOR       KRISS_SENSOR            1819
-pilz_pmi5              MACH_PILZ_PMI5          PILZ_PMI5               1820
-jade                   MACH_JADE               JADE                    1821
-ks8695_softplc         MACH_KS8695_SOFTPLC     KS8695_SOFTPLC          1822
-gprisc3                        MACH_GPRISC3            GPRISC3                 1823
 stamp9g20              MACH_STAMP9G20          STAMP9G20               1824
-smdk6430               MACH_SMDK6430           SMDK6430                1825
 smdkc100               MACH_SMDKC100           SMDKC100                1826
 tavorevb               MACH_TAVOREVB           TAVOREVB                1827
 saar                   MACH_SAAR               SAAR                    1828
-deister_eyecam         MACH_DEISTER_EYECAM     DEISTER_EYECAM          1829
 at91sam9m10g45ek       MACH_AT91SAM9M10G45EK   AT91SAM9M10G45EK        1830
-linkstation_produo     MACH_LINKSTATION_PRODUO LINKSTATION_PRODUO      1831
-hit_b0                 MACH_HIT_B0             HIT_B0                  1832
-adx_rmu                        MACH_ADX_RMU            ADX_RMU                 1833
-xg_cpe_main            MACH_XG_CPE_MAIN        XG_CPE_MAIN             1834
-edb9407a               MACH_EDB9407A           EDB9407A                1835
-dtb9608                        MACH_DTB9608            DTB9608                 1836
-em104v1                        MACH_EM104V1            EM104V1                 1837
-demo                   MACH_DEMO               DEMO                    1838
-logi9260               MACH_LOGI9260           LOGI9260                1839
-mx31_exm32             MACH_MX31_EXM32         MX31_EXM32              1840
-usb_a9g20              MACH_USB_A9G20          USB_A9G20               1841
-picproje2008           MACH_PICPROJE2008       PICPROJE2008            1842
-cs_e9315               MACH_CS_E9315           CS_E9315                1843
-qil_a9g20              MACH_QIL_A9G20          QIL_A9G20               1844
-sha_pon020             MACH_SHA_PON020         SHA_PON020              1845
-nad                    MACH_NAD                NAD                     1846
-sbc35_a9260            MACH_SBC35_A9260        SBC35_A9260             1847
-sbc35_a9g20            MACH_SBC35_A9G20        SBC35_A9G20             1848
-davinci_beginning      MACH_DAVINCI_BEGINNING  DAVINCI_BEGINNING       1849
-uwc                    MACH_UWC                UWC                     1850
 mxlads                 MACH_MXLADS             MXLADS                  1851
-htcnike                        MACH_HTCNIKE            HTCNIKE                 1852
-deister_pxa270         MACH_DEISTER_PXA270     DEISTER_PXA270          1853
-cme9210js              MACH_CME9210JS          CME9210JS               1854
-cc9p9360               MACH_CC9P9360           CC9P9360                1855
-mocha                  MACH_MOCHA              MOCHA                   1856
-wapd170ag              MACH_WAPD170AG          WAPD170AG               1857
 linkstation_mini       MACH_LINKSTATION_MINI   LINKSTATION_MINI        1858
 afeb9260               MACH_AFEB9260           AFEB9260                1859
-w90x900                        MACH_W90X900            W90X900                 1860
-w90x700                        MACH_W90X700            W90X700                 1861
-kt300ip                        MACH_KT300IP            KT300IP                 1862
-kt300ip_g20            MACH_KT300IP_G20        KT300IP_G20             1863
-srcm                   MACH_SRCM               SRCM                    1864
-wlnx_9260              MACH_WLNX_9260          WLNX_9260               1865
-openmoko_gta03         MACH_OPENMOKO_GTA03     OPENMOKO_GTA03          1866
-osprey2                        MACH_OSPREY2            OSPREY2                 1867
-kbio9260               MACH_KBIO9260           KBIO9260                1868
-ginza                  MACH_GINZA              GINZA                   1869
-a636n                  MACH_A636N              A636N                   1870
 imx27ipcam             MACH_IMX27IPCAM         IMX27IPCAM              1871
-nemoc                  MACH_NEMOC              NEMOC                   1872
-geneva                 MACH_GENEVA             GENEVA                  1873
-htcpharos              MACH_HTCPHAROS          HTCPHAROS               1874
-neonc                  MACH_NEONC              NEONC                   1875
-nas7100                        MACH_NAS7100            NAS7100                 1876
-teuphone               MACH_TEUPHONE           TEUPHONE                1877
-annax_eth2             MACH_ANNAX_ETH2         ANNAX_ETH2              1878
-csb733                 MACH_CSB733             CSB733                  1879
-bk3                    MACH_BK3                BK3                     1880
-omap_em32              MACH_OMAP_EM32          OMAP_EM32               1881
-et9261cp               MACH_ET9261CP           ET9261CP                1882
-jasperc                        MACH_JASPERC            JASPERC                 1883
-issi_arm9              MACH_ISSI_ARM9          ISSI_ARM9               1884
-ued                    MACH_UED                UED                     1885
-esiblade               MACH_ESIBLADE           ESIBLADE                1886
-eye02                  MACH_EYE02              EYE02                   1887
-imx27kbd               MACH_IMX27KBD           IMX27KBD                1888
-sst61vc010_fpga                MACH_SST61VC010_FPGA    SST61VC010_FPGA         1889
-kixvp435               MACH_KIXVP435           KIXVP435                1890
-kixnp435               MACH_KIXNP435           KIXNP435                1891
-africa                 MACH_AFRICA             AFRICA                  1892
-nh233                  MACH_NH233              NH233                   1893
 rd88f6183ap_ge         MACH_RD88F6183AP_GE     RD88F6183AP_GE          1894
-bcm4760                        MACH_BCM4760            BCM4760                 1895
-eddy_v2                        MACH_EDDY_V2            EDDY_V2                 1896
 realview_pba8          MACH_REALVIEW_PBA8      REALVIEW_PBA8           1897
-hid_a7                 MACH_HID_A7             HID_A7                  1898
-hero                   MACH_HERO               HERO                    1899
-omap_poseidon          MACH_OMAP_POSEIDON      OMAP_POSEIDON           1900
 realview_pbx           MACH_REALVIEW_PBX       REALVIEW_PBX            1901
 micro9s                        MACH_MICRO9S            MICRO9S                 1902
-mako                   MACH_MAKO               MAKO                    1903
-xdaflame               MACH_XDAFLAME           XDAFLAME                1904
-phidget_sbc2           MACH_PHIDGET_SBC2       PHIDGET_SBC2            1905
-limestone              MACH_LIMESTONE          LIMESTONE               1906
-iprobe_c32             MACH_IPROBE_C32         IPROBE_C32              1907
 rut100                 MACH_RUT100             RUT100                  1908
-asusp535               MACH_ASUSP535           ASUSP535                1909
-htcraphael             MACH_HTCRAPHAEL         HTCRAPHAEL              1910
-sygdg1                 MACH_SYGDG1             SYGDG1                  1911
-sygdg2                 MACH_SYGDG2             SYGDG2                  1912
-seoul                  MACH_SEOUL              SEOUL                   1913
-salerno                        MACH_SALERNO            SALERNO                 1914
-ucn_s3c64xx            MACH_UCN_S3C64XX        UCN_S3C64XX             1915
-msm7201a               MACH_MSM7201A           MSM7201A                1916
-lpr1                   MACH_LPR1               LPR1                    1917
-armadillo500fx         MACH_ARMADILLO500FX     ARMADILLO500FX          1918
 g3evm                  MACH_G3EVM              G3EVM                   1919
-z3_dm355               MACH_Z3_DM355           Z3_DM355                1920
 w90p910evb             MACH_W90P910EVB         W90P910EVB              1921
-w90p920evb             MACH_W90P920EVB         W90P920EVB              1922
 w90p950evb             MACH_W90P950EVB         W90P950EVB              1923
 w90n960evb             MACH_W90N960EVB         W90N960EVB              1924
-camhd                  MACH_CAMHD              CAMHD                   1925
-mvc100                 MACH_MVC100             MVC100                  1926
-electrum_200           MACH_ELECTRUM_200       ELECTRUM_200            1927
-htcjade                        MACH_HTCJADE            HTCJADE                 1928
-memphis                        MACH_MEMPHIS            MEMPHIS                 1929
-imx27sbc               MACH_IMX27SBC           IMX27SBC                1930
-lextar                 MACH_LEXTAR             LEXTAR                  1931
 mv88f6281gtw_ge                MACH_MV88F6281GTW_GE    MV88F6281GTW_GE         1932
 ncp                    MACH_NCP                NCP                     1933
-z32an_series           MACH_Z32AN              Z32AN                   1934
-tmq_capd               MACH_TMQ_CAPD           TMQ_CAPD                1935
-omap3_wl               MACH_OMAP3_WL           OMAP3_WL                1936
-chumby                 MACH_CHUMBY             CHUMBY                  1937
-atsarm9                        MACH_ATSARM9            ATSARM9                 1938
 davinci_dm365_evm      MACH_DAVINCI_DM365_EVM  DAVINCI_DM365_EVM       1939
-bahamas                        MACH_BAHAMAS            BAHAMAS                 1940
-das                    MACH_DAS                DAS                     1941
-minidas                        MACH_MINIDAS            MINIDAS                 1942
-vk1000                 MACH_VK1000             VK1000                  1943
 centro                 MACH_CENTRO             CENTRO                  1944
-ctera_2bay             MACH_CTERA_2BAY         CTERA_2BAY              1945
-edgeconnect            MACH_EDGECONNECT        EDGECONNECT             1946
-nd27000                        MACH_ND27000            ND27000                 1947
-cobra                  MACH_GEMALTO_COBRA      GEMALTO_COBRA           1948
-ingelabs_comet         MACH_INGELABS_COMET     INGELABS_COMET          1949
-pollux_wiz             MACH_POLLUX_WIZ         POLLUX_WIZ              1950
-blackstone             MACH_BLACKSTONE         BLACKSTONE              1951
-topaz                  MACH_TOPAZ              TOPAZ                   1952
-aixle                  MACH_AIXLE              AIXLE                   1953
-mw998                  MACH_MW998              MW998                   1954
 nokia_rx51             MACH_NOKIA_RX51         NOKIA_RX51              1955
-vsc5605ev              MACH_VSC5605EV          VSC5605EV               1956
-nt98700dk              MACH_NT98700DK          NT98700DK               1957
-icontact               MACH_ICONTACT           ICONTACT                1958
-swarco_frcpu           MACH_SWARCO_FRCPU       SWARCO_FRCPU            1959
-swarco_scpu            MACH_SWARCO_SCPU        SWARCO_SCPU             1960
-bbox_p16               MACH_BBOX_P16           BBOX_P16                1961
-bstd                   MACH_BSTD               BSTD                    1962
-sbc2440ii              MACH_SBC2440II          SBC2440II               1963
-pcm034                 MACH_PCM034             PCM034                  1964
-neso                   MACH_NESO               NESO                    1965
-wlnx_9g20              MACH_WLNX_9G20          WLNX_9G20               1966
 omap_zoom2             MACH_OMAP_ZOOM2         OMAP_ZOOM2              1967
-totemnova              MACH_TOTEMNOVA          TOTEMNOVA               1968
-c5000                  MACH_C5000              C5000                   1969
-unipo_at91sam9263      MACH_UNIPO_AT91SAM9263  UNIPO_AT91SAM9263       1970
-ethernut5              MACH_ETHERNUT5          ETHERNUT5               1971
-arm11                  MACH_ARM11              ARM11                   1972
 cpuat9260              MACH_CPUAT9260          CPUAT9260               1973
-cpupxa255              MACH_CPUPXA255          CPUPXA255               1974
 eukrea_cpuimx27                MACH_CPUIMX27           CPUIMX27                1975
-cheflux                        MACH_CHEFLUX            CHEFLUX                 1976
-eb_cpux9k2             MACH_EB_CPUX9K2         EB_CPUX9K2              1977
-opcotec                        MACH_OPCOTEC            OPCOTEC                 1978
-yt                     MACH_YT                 YT                      1979
-motoq                  MACH_MOTOQ              MOTOQ                   1980
-bsb1                   MACH_BSB1               BSB1                    1981
 acs5k                  MACH_ACS5K              ACS5K                   1982
-milan                  MACH_MILAN              MILAN                   1983
-quartzv2               MACH_QUARTZV2           QUARTZV2                1984
-rsvp                   MACH_RSVP               RSVP                    1985
-rmp200                 MACH_RMP200             RMP200                  1986
 snapper_9260           MACH_SNAPPER_9260       SNAPPER_9260            1987
 dsm320                 MACH_DSM320             DSM320                  1988
-adsgcm                 MACH_ADSGCM             ADSGCM                  1989
-ase2_400               MACH_ASE2_400           ASE2_400                1990
-pizza                  MACH_PIZZA              PIZZA                   1991
-spot_ngpl              MACH_SPOT_NGPL          SPOT_NGPL               1992
-armata                 MACH_ARMATA             ARMATA                  1993
 exeda                  MACH_EXEDA              EXEDA                   1994
-mx31sf005              MACH_MX31SF005          MX31SF005               1995
-f5d8231_4_v2           MACH_F5D8231_4_V2       F5D8231_4_V2            1996
-q2440                  MACH_Q2440              Q2440                   1997
-qq2440                 MACH_QQ2440             QQ2440                  1998
 mini2440               MACH_MINI2440           MINI2440                1999
 colibri300             MACH_COLIBRI300         COLIBRI300              2000
-jades                  MACH_JADES              JADES                   2001
-spark                  MACH_SPARK              SPARK                   2002
-benzina                        MACH_BENZINA            BENZINA                 2003
-blaze                  MACH_BLAZE              BLAZE                   2004
 linkstation_ls_hgl     MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL      2005
-htckovsky              MACH_HTCKOVSKY          HTCKOVSKY               2006
-sony_prs505            MACH_SONY_PRS505        SONY_PRS505             2007
-hanlin_v3              MACH_HANLIN_V3          HANLIN_V3               2008
-sapphira               MACH_SAPPHIRA           SAPPHIRA                2009
-dack_sda_01            MACH_DACK_SDA_01        DACK_SDA_01             2010
-armbox                 MACH_ARMBOX             ARMBOX                  2011
-harris_rvp             MACH_HARRIS_RVP         HARRIS_RVP              2012
-ribaldo                        MACH_RIBALDO            RIBALDO                 2013
-agora                  MACH_AGORA              AGORA                   2014
-omap3_mini             MACH_OMAP3_MINI         OMAP3_MINI              2015
-a9sam6432_b            MACH_A9SAM6432_B        A9SAM6432_B             2016
-usg2410                        MACH_USG2410            USG2410                 2017
-pc72052_i10_revb       MACH_PC72052_I10_REVB   PC72052_I10_REVB        2018
-mx35_exm32             MACH_MX35_EXM32         MX35_EXM32              2019
-topas910               MACH_TOPAS910           TOPAS910                2020
-hyena                  MACH_HYENA              HYENA                   2021
-pospax                 MACH_POSPAX             POSPAX                  2022
-hdl_gx                 MACH_HDL_GX             HDL_GX                  2023
-ctera_4bay             MACH_CTERA_4BAY         CTERA_4BAY              2024
-ctera_plug_c           MACH_CTERA_PLUG_C       CTERA_PLUG_C            2025
-crwea_plug_i           MACH_CRWEA_PLUG_I       CRWEA_PLUG_I            2026
-egauge2                        MACH_EGAUGE2            EGAUGE2                 2027
-didj                   MACH_DIDJ               DIDJ                    2028
-m_s3c2443              MACH_MEISTER            MEISTER                 2029
-htcblackstone          MACH_HTCBLACKSTONE      HTCBLACKSTONE           2030
 cpuat9g20              MACH_CPUAT9G20          CPUAT9G20               2031
 smdk6440               MACH_SMDK6440           SMDK6440                2032
-omap_35xx_mvp          MACH_OMAP_35XX_MVP      OMAP_35XX_MVP           2033
-ctera_plug_i           MACH_CTERA_PLUG_I       CTERA_PLUG_I            2034
-pvg610_100             MACH_PVG610             PVG610                  2035
-hprw6815               MACH_HPRW6815           HPRW6815                2036
-omap3_oswald           MACH_OMAP3_OSWALD       OMAP3_OSWALD            2037
 nas4220b               MACH_NAS4220B           NAS4220B                2038
-htcraphael_cdma                MACH_HTCRAPHAEL_CDMA    HTCRAPHAEL_CDMA         2039
-htcdiamond_cdma                MACH_HTCDIAMOND_CDMA    HTCDIAMOND_CDMA         2040
-scaler                 MACH_SCALER             SCALER                  2041
 zylonite2              MACH_ZYLONITE2          ZYLONITE2               2042
 aspenite               MACH_ASPENITE           ASPENITE                2043
-teton                  MACH_TETON              TETON                   2044
 ttc_dkb                        MACH_TTC_DKB            TTC_DKB                 2045
-bishop2                        MACH_BISHOP2            BISHOP2                 2046
-ippv5                  MACH_IPPV5              IPPV5                   2047
-farm926                        MACH_FARM926            FARM926                 2048
-mmccpu                 MACH_MMCCPU             MMCCPU                  2049
-sgmsfl                 MACH_SGMSFL             SGMSFL                  2050
-tt8000                 MACH_TT8000             TT8000                  2051
-zrn4300lp              MACH_ZRN4300LP          ZRN4300LP               2052
-mptc                   MACH_MPTC               MPTC                    2053
-h6051                  MACH_H6051              H6051                   2054
-pvg610_101             MACH_PVG610_101         PVG610_101              2055
-stamp9261_pc_evb       MACH_STAMP9261_PC_EVB   STAMP9261_PC_EVB        2056
-pelco_odysseus         MACH_PELCO_ODYSSEUS     PELCO_ODYSSEUS          2057
-tny_a9260              MACH_TNY_A9260          TNY_A9260               2058
-tny_a9g20              MACH_TNY_A9G20          TNY_A9G20               2059
-aesop_mp2530f          MACH_AESOP_MP2530F      AESOP_MP2530F           2060
-dx900                  MACH_DX900              DX900                   2061
-cpodc2                 MACH_CPODC2             CPODC2                  2062
-tilt_8925              MACH_TILT_8925          TILT_8925               2063
-davinci_dm357_evm      MACH_DAVINCI_DM357_EVM  DAVINCI_DM357_EVM       2064
-swordfish              MACH_SWORDFISH          SWORDFISH               2065
-corvus                 MACH_CORVUS             CORVUS                  2066
-taurus                 MACH_TAURUS             TAURUS                  2067
-axm                    MACH_AXM                AXM                     2068
-axc                    MACH_AXC                AXC                     2069
-baby                   MACH_BABY               BABY                    2070
-mp200                  MACH_MP200              MP200                   2071
 pcm043                 MACH_PCM043             PCM043                  2072
-hanlin_v3c             MACH_HANLIN_V3C         HANLIN_V3C              2073
-kbk9g20                        MACH_KBK9G20            KBK9G20                 2074
-adsturbog5             MACH_ADSTURBOG5         ADSTURBOG5              2075
-avenger_lite1          MACH_AVENGER_LITE1      AVENGER_LITE1           2076
-suc82x                 MACH_SUC                SUC                     2077
-at91sam7s256           MACH_AT91SAM7S256       AT91SAM7S256            2078
-mendoza                        MACH_MENDOZA            MENDOZA                 2079
-kira                   MACH_KIRA               KIRA                    2080
-mx1hbm                 MACH_MX1HBM             MX1HBM                  2081
-quatro43xx             MACH_QUATRO43XX         QUATRO43XX              2082
-quatro4230             MACH_QUATRO4230         QUATRO4230              2083
-nsb400                 MACH_NSB400             NSB400                  2084
-drp255                 MACH_DRP255             DRP255                  2085
-thoth                  MACH_THOTH              THOTH                   2086
-firestone              MACH_FIRESTONE          FIRESTONE               2087
-asusp750               MACH_ASUSP750           ASUSP750                2088
-ctera_dl               MACH_CTERA_DL           CTERA_DL                2089
-socr                   MACH_SOCR               SOCR                    2090
-htcoxygen              MACH_HTCOXYGEN          HTCOXYGEN               2091
-heroc                  MACH_HEROC              HEROC                   2092
-zeno6800               MACH_ZENO6800           ZENO6800                2093
-sc2mcs                 MACH_SC2MCS             SC2MCS                  2094
-gene100                        MACH_GENE100            GENE100                 2095
-as353x                 MACH_AS353X             AS353X                  2096
 sheevaplug             MACH_SHEEVAPLUG         SHEEVAPLUG              2097
-at91sam9g20            MACH_AT91SAM9G20        AT91SAM9G20             2098
-mv88f6192gtw_fe                MACH_MV88F6192GTW_FE    MV88F6192GTW_FE         2099
-cc9200                 MACH_CC9200             CC9200                  2100
-sm9200                 MACH_SM9200             SM9200                  2101
-tp9200                 MACH_TP9200             TP9200                  2102
-snapperdv              MACH_SNAPPERDV          SNAPPERDV               2103
 avengers_lite          MACH_AVENGERS_LITE      AVENGERS_LITE           2104
-avengers_lite1         MACH_AVENGERS_LITE1     AVENGERS_LITE1          2105
-omap3axon              MACH_OMAP3AXON          OMAP3AXON               2106
-ma8xx                  MACH_MA8XX              MA8XX                   2107
-mp201ek                        MACH_MP201EK            MP201EK                 2108
-davinci_tux            MACH_DAVINCI_TUX        DAVINCI_TUX             2109
-mpa1600                        MACH_MPA1600            MPA1600                 2110
-pelco_troy             MACH_PELCO_TROY         PELCO_TROY              2111
-nsb667                 MACH_NSB667             NSB667                  2112
-rovers5_4mpix          MACH_ROVERS5_4MPIX      ROVERS5_4MPIX           2113
-twocom                 MACH_TWOCOM             TWOCOM                  2114
-ubisys_p9_rcu3r2       MACH_UBISYS_P9_RCU3R2   UBISYS_P9_RCU3R2        2115
-hero_espresso          MACH_HERO_ESPRESSO      HERO_ESPRESSO           2116
-afeusb                 MACH_AFEUSB             AFEUSB                  2117
-t830                   MACH_T830               T830                    2118
-spd8020_cc             MACH_SPD8020_CC         SPD8020_CC              2119
-om_3d7k                        MACH_OM_3D7K            OM_3D7K                 2120
-picocom2               MACH_PICOCOM2           PICOCOM2                2121
-uwg4mx27               MACH_UWG4MX27           UWG4MX27                2122
-uwg4mx31               MACH_UWG4MX31           UWG4MX31                2123
-cherry                 MACH_CHERRY             CHERRY                  2124
 mx51_babbage           MACH_MX51_BABBAGE       MX51_BABBAGE            2125
-s3c2440turkiye         MACH_S3C2440TURKIYE     S3C2440TURKIYE          2126
-tx37                   MACH_TX37               TX37                    2127
-sbc2800_9g20           MACH_SBC2800_9G20       SBC2800_9G20            2128
-benzglb                        MACH_BENZGLB            BENZGLB                 2129
-benztd                 MACH_BENZTD             BENZTD                  2130
-cartesio_plus          MACH_CARTESIO_PLUS      CARTESIO_PLUS           2131
-solrad_g20             MACH_SOLRAD_G20         SOLRAD_G20              2132
-mx27wallace            MACH_MX27WALLACE        MX27WALLACE             2133
-fmzwebmodul            MACH_FMZWEBMODUL        FMZWEBMODUL             2134
 rd78x00_masa           MACH_RD78X00_MASA       RD78X00_MASA            2135
-smallogger             MACH_SMALLOGGER         SMALLOGGER              2136
-ccw9p9215              MACH_CCW9P9215          CCW9P9215               2137
 dm355_leopard          MACH_DM355_LEOPARD      DM355_LEOPARD           2138
 ts219                  MACH_TS219              TS219                   2139
-tny_a9263              MACH_TNY_A9263          TNY_A9263               2140
-apollo                 MACH_APOLLO             APOLLO                  2141
-at91cap9stk            MACH_AT91CAP9STK        AT91CAP9STK             2142
-spc300                 MACH_SPC300             SPC300                  2143
-eko                    MACH_EKO                EKO                     2144
-ccw9m2443              MACH_CCW9M2443          CCW9M2443               2145
-ccw9m2443js            MACH_CCW9M2443JS        CCW9M2443JS             2146
-m2m_router_device      MACH_M2M_ROUTER_DEVICE  M2M_ROUTER_DEVICE       2147
-str9104nas             MACH_STAR9104NAS        STAR9104NAS             2148
 pca100                 MACH_PCA100             PCA100                  2149
-z3_dm365_mod_01                MACH_Z3_DM365_MOD_01    Z3_DM365_MOD_01         2150
-hipox                  MACH_HIPOX              HIPOX                   2151
-omap3_piteds           MACH_OMAP3_PITEDS       OMAP3_PITEDS            2152
-bm150r                 MACH_BM150R             BM150R                  2153
-tbone                  MACH_TBONE              TBONE                   2154
-merlin                 MACH_MERLIN             MERLIN                  2155
-falcon                 MACH_FALCON             FALCON                  2156
 davinci_da850_evm      MACH_DAVINCI_DA850_EVM  DAVINCI_DA850_EVM       2157
-s5p6440                        MACH_S5P6440            S5P6440                 2158
 at91sam9g10ek          MACH_AT91SAM9G10EK      AT91SAM9G10EK           2159
 omap_4430sdp           MACH_OMAP_4430SDP       OMAP_4430SDP            2160
-lpc313x                        MACH_LPC313X            LPC313X                 2161
 magx_zn5               MACH_MAGX_ZN5           MAGX_ZN5                2162
-magx_em30              MACH_MAGX_EM30          MAGX_EM30               2163
-magx_ve66              MACH_MAGX_VE66          MAGX_VE66               2164
-meesc                  MACH_MEESC              MEESC                   2165
-otc570                 MACH_OTC570             OTC570                  2166
-bcu2412                        MACH_BCU2412            BCU2412                 2167
-beacon                 MACH_BEACON             BEACON                  2168
-actia_tgw              MACH_ACTIA_TGW          ACTIA_TGW               2169
-e4430                  MACH_E4430              E4430                   2170
-ql300                  MACH_QL300              QL300                   2171
-btmavb101              MACH_BTMAVB101          BTMAVB101               2172
-btmawb101              MACH_BTMAWB101          BTMAWB101               2173
-sq201                  MACH_SQ201              SQ201                   2174
-quatro45xx             MACH_QUATRO45XX         QUATRO45XX              2175
-openpad                        MACH_OPENPAD            OPENPAD                 2176
-tx25                   MACH_TX25               TX25                    2177
 omap3_torpedo          MACH_OMAP3_TORPEDO      OMAP3_TORPEDO           2178
-htcraphael_k           MACH_HTCRAPHAEL_K       HTCRAPHAEL_K            2179
-lal43                  MACH_LAL43              LAL43                   2181
-htcraphael_cdma500     MACH_HTCRAPHAEL_CDMA500 HTCRAPHAEL_CDMA500      2182
 anw6410                        MACH_ANW6410            ANW6410                 2183
-htcprophet             MACH_HTCPROPHET         HTCPROPHET              2185
-cfa_10022              MACH_CFA_10022          CFA_10022               2186
 imx27_visstrim_m10     MACH_IMX27_VISSTRIM_M10 IMX27_VISSTRIM_M10      2187
-px2imx27               MACH_PX2IMX27           PX2IMX27                2188
-stm3210e_eval          MACH_STM3210E_EVAL      STM3210E_EVAL           2189
-dvs10                  MACH_DVS10              DVS10                   2190
 portuxg20              MACH_PORTUXG20          PORTUXG20               2191
-arm_spv                        MACH_ARM_SPV            ARM_SPV                 2192
 smdkc110               MACH_SMDKC110           SMDKC110                2193
-cabespresso            MACH_CABESPRESSO        CABESPRESSO             2194
-hmc800                 MACH_HMC800             HMC800                  2195
-sholes                 MACH_SHOLES             SHOLES                  2196
-btmxc31                        MACH_BTMXC31            BTMXC31                 2197
-dt501                  MACH_DT501              DT501                   2198
-ktx                    MACH_KTX                KTX                     2199
 omap3517evm            MACH_OMAP3517EVM        OMAP3517EVM             2200
 netspace_v2            MACH_NETSPACE_V2        NETSPACE_V2             2201
 netspace_max_v2                MACH_NETSPACE_MAX_V2    NETSPACE_MAX_V2         2202
 d2net_v2               MACH_D2NET_V2           D2NET_V2                2203
 net2big_v2             MACH_NET2BIG_V2         NET2BIG_V2              2204
-net4big_v2             MACH_NET4BIG_V2         NET4BIG_V2              2205
 net5big_v2             MACH_NET5BIG_V2         NET5BIG_V2              2206
-endb2443               MACH_ENDB2443           ENDB2443                2207
 inetspace_v2           MACH_INETSPACE_V2       INETSPACE_V2            2208
-tros                   MACH_TROS               TROS                    2209
-pelco_homer            MACH_PELCO_HOMER        PELCO_HOMER             2210
-ofsp8                  MACH_OFSP8              OFSP8                   2211
 at91sam9g45ekes                MACH_AT91SAM9G45EKES    AT91SAM9G45EKES         2212
-guf_cupid              MACH_GUF_CUPID          GUF_CUPID               2213
-eab1r                  MACH_EAB1R              EAB1R                   2214
-desirec                        MACH_DESIREC            DESIREC                 2215
-cordoba                        MACH_CORDOBA            CORDOBA                 2216
-irvine                 MACH_IRVINE             IRVINE                  2217
-sff772                 MACH_SFF772             SFF772                  2218
-pelco_milano           MACH_PELCO_MILANO       PELCO_MILANO            2219
 pc7302                 MACH_PC7302             PC7302                  2220
-bip6000                        MACH_BIP6000            BIP6000                 2221
-silvermoon             MACH_SILVERMOON         SILVERMOON              2222
-vc0830                 MACH_VC0830             VC0830                  2223
-dt430                  MACH_DT430              DT430                   2224
-ji42pf                 MACH_JI42PF             JI42PF                  2225
-gnet_ksm               MACH_GNET_KSM           GNET_KSM                2226
-gnet_sgm               MACH_GNET_SGM           GNET_SGM                2227
-gnet_sgr               MACH_GNET_SGR           GNET_SGR                2228
-omap3_icetekevm                MACH_OMAP3_ICETEKEVM    OMAP3_ICETEKEVM         2229
-pnp                    MACH_PNP                PNP                     2230
-ctera_2bay_k           MACH_CTERA_2BAY_K       CTERA_2BAY_K            2231
-ctera_2bay_u           MACH_CTERA_2BAY_U       CTERA_2BAY_U            2232
-sas_c                  MACH_SAS_C              SAS_C                   2233
-vma2315                        MACH_VMA2315            VMA2315                 2234
-vcs                    MACH_VCS                VCS                     2235
 spear600               MACH_SPEAR600           SPEAR600                2236
 spear300               MACH_SPEAR300           SPEAR300                2237
-spear1300              MACH_SPEAR1300          SPEAR1300               2238
 lilly1131              MACH_LILLY1131          LILLY1131               2239
-arvoo_ax301            MACH_ARVOO_AX301        ARVOO_AX301             2240
-mapphone               MACH_MAPPHONE           MAPPHONE                2241
-legend                 MACH_LEGEND             LEGEND                  2242
-salsa                  MACH_SALSA              SALSA                   2243
-lounge                 MACH_LOUNGE             LOUNGE                  2244
-vision                 MACH_VISION             VISION                  2245
-vmb20                  MACH_VMB20              VMB20                   2246
-hy2410                 MACH_HY2410             HY2410                  2247
-hy9315                 MACH_HY9315             HY9315                  2248
-bullwinkle             MACH_BULLWINKLE         BULLWINKLE              2249
-arm_ultimator2         MACH_ARM_ULTIMATOR2     ARM_ULTIMATOR2          2250
-vs_v210                        MACH_VS_V210            VS_V210                 2252
-vs_v212                        MACH_VS_V212            VS_V212                 2253
 hmt                    MACH_HMT                HMT                     2254
-km_kirkwood            MACH_KM_KIRKWOOD        KM_KIRKWOOD             2255
-vesper                 MACH_VESPER             VESPER                  2256
-str9                   MACH_STR9               STR9                    2257
-omap3_wl_ff            MACH_OMAP3_WL_FF        OMAP3_WL_FF             2258
-simcom                 MACH_SIMCOM             SIMCOM                  2259
-mcwebio                        MACH_MCWEBIO            MCWEBIO                 2260
-omap3_phrazer          MACH_OMAP3_PHRAZER      OMAP3_PHRAZER           2261
-darwin                 MACH_DARWIN             DARWIN                  2262
-oratiscomu             MACH_ORATISCOMU         ORATISCOMU              2263
-rtsbc20                        MACH_RTSBC20            RTSBC20                 2264
-sgh_i780               MACH_I780               I780                    2265
-gemini324              MACH_GEMINI324          GEMINI324               2266
-oratislan              MACH_ORATISLAN          ORATISLAN               2267
-oratisalog             MACH_ORATISALOG         ORATISALOG              2268
-oratismadi             MACH_ORATISMADI         ORATISMADI              2269
-oratisot16             MACH_ORATISOT16         ORATISOT16              2270
-oratisdesk             MACH_ORATISDESK         ORATISDESK              2271
 vexpress               MACH_VEXPRESS           VEXPRESS                2272
-sintexo                        MACH_SINTEXO            SINTEXO                 2273
-cm3389                 MACH_CM3389             CM3389                  2274
-omap3_cio              MACH_OMAP3_CIO          OMAP3_CIO               2275
-sgh_i900               MACH_SGH_I900           SGH_I900                2276
-bst100                 MACH_BST100             BST100                  2277
-passion                        MACH_PASSION            PASSION                 2278
-indesign_at91sam       MACH_INDESIGN_AT91SAM   INDESIGN_AT91SAM        2279
-c4_badger              MACH_C4_BADGER          C4_BADGER               2280
-c4_viper               MACH_C4_VIPER           C4_VIPER                2281
 d2net                  MACH_D2NET              D2NET                   2282
 bigdisk                        MACH_BIGDISK            BIGDISK                 2283
-notalvision            MACH_NOTALVISION        NOTALVISION             2284
-omap3_kboc             MACH_OMAP3_KBOC         OMAP3_KBOC              2285
-cyclone                        MACH_CYCLONE            CYCLONE                 2286
-ninja                  MACH_NINJA              NINJA                   2287
 at91sam9g20ek_2mmc     MACH_AT91SAM9G20EK_2MMC AT91SAM9G20EK_2MMC      2288
 bcmring                        MACH_BCMRING            BCMRING                 2289
-resol_dl2              MACH_RESOL_DL2          RESOL_DL2               2290
-ifosw                  MACH_IFOSW              IFOSW                   2291
-htcrhodium             MACH_HTCRHODIUM         HTCRHODIUM              2292
-htctopaz               MACH_HTCTOPAZ           HTCTOPAZ                2293
-matrix504              MACH_MATRIX504          MATRIX504               2294
-mrfsa                  MACH_MRFSA              MRFSA                   2295
-sc_p270                        MACH_SC_P270            SC_P270                 2296
-atlas5_evb             MACH_ATLAS5_EVB         ATLAS5_EVB              2297
-pelco_lobox            MACH_PELCO_LOBOX        PELCO_LOBOX             2298
-dilax_pcu200           MACH_DILAX_PCU200       DILAX_PCU200            2299
-leonardo               MACH_LEONARDO           LEONARDO                2300
-zoran_approach7                MACH_ZORAN_APPROACH7    ZORAN_APPROACH7         2301
-dp6xx                  MACH_DP6XX              DP6XX                   2302
-bcm2153_vesper         MACH_BCM2153_VESPER     BCM2153_VESPER          2303
 mahimahi               MACH_MAHIMAHI           MAHIMAHI                2304
-clickc                 MACH_CLICKC             CLICKC                  2305
-zb_gateway             MACH_ZB_GATEWAY         ZB_GATEWAY              2306
-tazcard                        MACH_TAZCARD            TAZCARD                 2307
-tazdev                 MACH_TAZDEV             TAZDEV                  2308
-annax_cb_arm           MACH_ANNAX_CB_ARM       ANNAX_CB_ARM            2309
-annax_dm3              MACH_ANNAX_DM3          ANNAX_DM3               2310
-cerebric               MACH_CEREBRIC           CEREBRIC                2311
-orca                   MACH_ORCA               ORCA                    2312
-pc9260                 MACH_PC9260             PC9260                  2313
-ems285a                        MACH_EMS285A            EMS285A                 2314
-gec2410                        MACH_GEC2410            GEC2410                 2315
-gec2440                        MACH_GEC2440            GEC2440                 2316
-mw903                  MACH_ARCH_MW903         ARCH_MW903              2317
-mw2440                 MACH_MW2440             MW2440                  2318
-ecac2378               MACH_ECAC2378           ECAC2378                2319
-tazkiosk               MACH_TAZKIOSK           TAZKIOSK                2320
-whiterabbit_mch                MACH_WHITERABBIT_MCH    WHITERABBIT_MCH         2321
-sbox9263               MACH_SBOX9263           SBOX9263                2322
-oreo                   MACH_OREO               OREO                    2323
 smdk6442               MACH_SMDK6442           SMDK6442                2324
 openrd_base            MACH_OPENRD_BASE        OPENRD_BASE             2325
-incredible             MACH_INCREDIBLE         INCREDIBLE              2326
-incrediblec            MACH_INCREDIBLEC        INCREDIBLEC             2327
-heroct                 MACH_HEROCT             HEROCT                  2328
-mmnet1000              MACH_MMNET1000          MMNET1000               2329
 devkit8000             MACH_DEVKIT8000         DEVKIT8000              2330
-devkit9000             MACH_DEVKIT9000         DEVKIT9000              2331
-mx31txtr               MACH_MX31TXTR           MX31TXTR                2332
-u380                   MACH_U380               U380                    2333
-oamp3_hualu            MACH_HUALU_BOARD        HUALU_BOARD             2334
-npcmx50                        MACH_NPCMX50            NPCMX50                 2335
 mx51_efikamx           MACH_MX51_EFIKAMX       MX51_EFIKAMX            2336
-mx51_lange52           MACH_MX51_LANGE52       MX51_LANGE52            2337
-riom                   MACH_RIOM               RIOM                    2338
-comcas                 MACH_COMCAS             COMCAS                  2339
-wsi_mx27               MACH_WSI_MX27           WSI_MX27                2340
 cm_t35                 MACH_CM_T35             CM_T35                  2341
 net2big                        MACH_NET2BIG            NET2BIG                 2342
-motorola_a1600         MACH_MOTOROLA_A1600     MOTOROLA_A1600          2343
 igep0020               MACH_IGEP0020           IGEP0020                2344
-igep0010               MACH_IGEP0010           IGEP0010                2345
-mv6281gtwge2           MACH_MV6281GTWGE2       MV6281GTWGE2            2346
-scat100                        MACH_SCAT100            SCAT100                 2347
-sanmina                        MACH_SANMINA            SANMINA                 2348
-momento                        MACH_MOMENTO            MOMENTO                 2349
-nuc9xx                 MACH_NUC9XX             NUC9XX                  2350
-nuc910evb              MACH_NUC910EVB          NUC910EVB               2351
-nuc920evb              MACH_NUC920EVB          NUC920EVB               2352
-nuc950evb              MACH_NUC950EVB          NUC950EVB               2353
-nuc945evb              MACH_NUC945EVB          NUC945EVB               2354
-nuc960evb              MACH_NUC960EVB          NUC960EVB               2355
 nuc932evb              MACH_NUC932EVB          NUC932EVB               2356
-nuc900                 MACH_NUC900             NUC900                  2357
-sd1soc                 MACH_SD1SOC             SD1SOC                  2358
-ln2440bc               MACH_LN2440BC           LN2440BC                2359
-rsbc                   MACH_RSBC               RSBC                    2360
 openrd_client          MACH_OPENRD_CLIENT      OPENRD_CLIENT           2361
-hpipaq11x              MACH_HPIPAQ11X          HPIPAQ11X               2362
-wayland                        MACH_WAYLAND            WAYLAND                 2363
-acnbsx102              MACH_ACNBSX102          ACNBSX102               2364
-hwat91                 MACH_HWAT91             HWAT91                  2365
-at91sam9263cs          MACH_AT91SAM9263CS      AT91SAM9263CS           2366
-csb732                 MACH_CSB732             CSB732                  2367
 u8500                  MACH_U8500              U8500                   2368
-huqiu                  MACH_HUQIU              HUQIU                   2369
 mx51_efikasb           MACH_MX51_EFIKASB       MX51_EFIKASB            2370
-pmt1g                  MACH_PMT1G              PMT1G                   2371
-htcelf                 MACH_HTCELF             HTCELF                  2372
-armadillo420           MACH_ARMADILLO420       ARMADILLO420            2373
-armadillo440           MACH_ARMADILLO440       ARMADILLO440            2374
-u_chip_dual_arm                MACH_U_CHIP_DUAL_ARM    U_CHIP_DUAL_ARM         2375
-csr_bdb3               MACH_CSR_BDB3           CSR_BDB3                2376
-dolby_cat1018          MACH_DOLBY_CAT1018      DOLBY_CAT1018           2377
-hy9307                 MACH_HY9307             HY9307                  2378
-aspire_easystore       MACH_A_ES               A_ES                    2379
-davinci_irif           MACH_DAVINCI_IRIF       DAVINCI_IRIF            2380
-agama9263              MACH_AGAMA9263          AGAMA9263               2381
 marvell_jasper         MACH_MARVELL_JASPER     MARVELL_JASPER          2382
 flint                  MACH_FLINT              FLINT                   2383
 tavorevb3              MACH_TAVOREVB3          TAVOREVB3               2384
-sch_m490               MACH_SCH_M490           SCH_M490                2386
-rbl01                  MACH_RBL01              RBL01                   2387
-omnifi                 MACH_OMNIFI             OMNIFI                  2388
-otavalo                        MACH_OTAVALO            OTAVALO                 2389
-sienna                 MACH_SIENNA             SIENNA                  2390
-htc_excalibur_s620     MACH_HTC_EXCALIBUR_S620 HTC_EXCALIBUR_S620      2391
-htc_opal               MACH_HTC_OPAL           HTC_OPAL                2392
 touchbook              MACH_TOUCHBOOK          TOUCHBOOK               2393
-latte                  MACH_LATTE              LATTE                   2394
-xa200                  MACH_XA200              XA200                   2395
-nimrod                 MACH_NIMROD             NIMROD                  2396
-cc9p9215_3g            MACH_CC9P9215_3G        CC9P9215_3G             2397
-cc9p9215_3gjs          MACH_CC9P9215_3GJS      CC9P9215_3GJS           2398
-tk71                   MACH_TK71               TK71                    2399
-comham3525             MACH_COMHAM3525         COMHAM3525              2400
-mx31erebus             MACH_MX31EREBUS         MX31EREBUS              2401
-mcardmx27              MACH_MCARDMX27          MCARDMX27               2402
-paradise               MACH_PARADISE           PARADISE                2403
-tide                   MACH_TIDE               TIDE                    2404
-wzl2440                        MACH_WZL2440            WZL2440                 2405
-sdrdemo                        MACH_SDRDEMO            SDRDEMO                 2406
-ethercan2              MACH_ETHERCAN2          ETHERCAN2               2407
-ecmimg20               MACH_ECMIMG20           ECMIMG20                2408
-omap_dragon            MACH_OMAP_DRAGON        OMAP_DRAGON             2409
-halo                   MACH_HALO               HALO                    2410
-huangshan              MACH_HUANGSHAN          HUANGSHAN               2411
-vl_ma2sc               MACH_VL_MA2SC           VL_MA2SC                2412
 raumfeld_rc            MACH_RAUMFELD_RC        RAUMFELD_RC             2413
 raumfeld_connector     MACH_RAUMFELD_CONNECTOR RAUMFELD_CONNECTOR      2414
 raumfeld_speaker       MACH_RAUMFELD_SPEAKER   RAUMFELD_SPEAKER        2415
-multibus_master                MACH_MULTIBUS_MASTER    MULTIBUS_MASTER         2416
-multibus_pbk           MACH_MULTIBUS_PBK       MULTIBUS_PBK            2417
 tnetv107x              MACH_TNETV107X          TNETV107X               2418
-snake                  MACH_SNAKE              SNAKE                   2419
-cwmx27                 MACH_CWMX27             CWMX27                  2420
-sch_m480               MACH_SCH_M480           SCH_M480                2421
-platypus               MACH_PLATYPUS           PLATYPUS                2422
-pss2                   MACH_PSS2               PSS2                    2423
-davinci_apm150         MACH_DAVINCI_APM150     DAVINCI_APM150          2424
-str9100                        MACH_STR9100            STR9100                 2425
-net5big                        MACH_NET5BIG            NET5BIG                 2426
-seabed9263             MACH_SEABED9263         SEABED9263              2427
-mx51_m2id              MACH_MX51_M2ID          MX51_M2ID               2428
-octvocplus_eb          MACH_OCTVOCPLUS_EB      OCTVOCPLUS_EB           2429
-klk_firefox            MACH_KLK_FIREFOX        KLK_FIREFOX             2430
-klk_wirma_module       MACH_KLK_WIRMA_MODULE   KLK_WIRMA_MODULE        2431
-klk_wirma_mmi          MACH_KLK_WIRMA_MMI      KLK_WIRMA_MMI           2432
-supersonic             MACH_SUPERSONIC         SUPERSONIC              2433
-liberty                        MACH_LIBERTY            LIBERTY                 2434
-mh355                  MACH_MH355              MH355                   2435
-pc7802                 MACH_PC7802             PC7802                  2436
-gnet_sgc               MACH_GNET_SGC           GNET_SGC                2437
-einstein15             MACH_EINSTEIN15         EINSTEIN15              2438
-cmpd                   MACH_CMPD               CMPD                    2439
-davinci_hase1          MACH_DAVINCI_HASE1      DAVINCI_HASE1           2440
-lgeincitephone         MACH_LGEINCITEPHONE     LGEINCITEPHONE          2441
-ea313x                 MACH_EA313X             EA313X                  2442
-fwbd_39064             MACH_FWBD_39064         FWBD_39064              2443
-fwbd_390128            MACH_FWBD_390128        FWBD_390128             2444
-pelco_moe              MACH_PELCO_MOE          PELCO_MOE               2445
-minimix27              MACH_MINIMIX27          MINIMIX27               2446
-omap3_thunder          MACH_OMAP3_THUNDER      OMAP3_THUNDER           2447
-passionc               MACH_PASSIONC           PASSIONC                2448
-mx27amata              MACH_MX27AMATA          MX27AMATA               2449
-bgat1                  MACH_BGAT1              BGAT1                   2450
-buzz                   MACH_BUZZ               BUZZ                    2451
-mb9g20                 MACH_MB9G20             MB9G20                  2452
-yushan                 MACH_YUSHAN             YUSHAN                  2453
-lizard                 MACH_LIZARD             LIZARD                  2454
-omap3polycom           MACH_OMAP3POLYCOM       OMAP3POLYCOM            2455
 smdkv210               MACH_SMDKV210           SMDKV210                2456
-bravo                  MACH_BRAVO              BRAVO                   2457
-siogentoo1             MACH_SIOGENTOO1         SIOGENTOO1              2458
-siogentoo2             MACH_SIOGENTOO2         SIOGENTOO2              2459
-sm3k                   MACH_SM3K               SM3K                    2460
-acer_tempo_f900                MACH_ACER_TEMPO_F900    ACER_TEMPO_F900         2461
-sst61vc010_dev         MACH_SST61VC010_DEV     SST61VC010_DEV          2462
-glittertind            MACH_GLITTERTIND        GLITTERTIND             2463
 omap_zoom3             MACH_OMAP_ZOOM3         OMAP_ZOOM3              2464
 omap_3630sdp           MACH_OMAP_3630SDP       OMAP_3630SDP            2465
-cybook2440             MACH_CYBOOK2440         CYBOOK2440              2466
-torino_s               MACH_TORINO_S           TORINO_S                2467
-havana                 MACH_HAVANA             HAVANA                  2468
-beaumont_11            MACH_BEAUMONT_11        BEAUMONT_11             2469
-vanguard               MACH_VANGUARD           VANGUARD                2470
-s5pc110_draco          MACH_S5PC110_DRACO      S5PC110_DRACO           2471
-cartesio_two           MACH_CARTESIO_TWO       CARTESIO_TWO            2472
-aster                  MACH_ASTER              ASTER                   2473
-voguesv210             MACH_VOGUESV210         VOGUESV210              2474
-acm500x                        MACH_ACM500X            ACM500X                 2475
-km9260                 MACH_KM9260             KM9260                  2476
-nideflexg1             MACH_NIDEFLEXG1         NIDEFLEXG1              2477
-ctera_plug_io          MACH_CTERA_PLUG_IO      CTERA_PLUG_IO           2478
 smartq7                        MACH_SMARTQ7            SMARTQ7                 2479
-at91sam9g10ek2         MACH_AT91SAM9G10EK2     AT91SAM9G10EK2          2480
-asusp527               MACH_ASUSP527           ASUSP527                2481
-at91sam9g20mpm2                MACH_AT91SAM9G20MPM2    AT91SAM9G20MPM2         2482
-topasa900              MACH_TOPASA900          TOPASA900               2483
-electrum_100           MACH_ELECTRUM_100       ELECTRUM_100            2484
-mx51grb                        MACH_MX51GRB            MX51GRB                 2485
-xea300                 MACH_XEA300             XEA300                  2486
-htcstartrek            MACH_HTCSTARTREK        HTCSTARTREK             2487
-lima                   MACH_LIMA               LIMA                    2488
-csb740                 MACH_CSB740             CSB740                  2489
-usb_s8815              MACH_USB_S8815          USB_S8815               2490
-watson_efm_plugin      MACH_WATSON_EFM_PLUGIN  WATSON_EFM_PLUGIN       2491
-milkyway               MACH_MILKYWAY           MILKYWAY                2492
 g4evm                  MACH_G4EVM              G4EVM                   2493
-picomod6               MACH_PICOMOD6           PICOMOD6                2494
 omapl138_hawkboard     MACH_OMAPL138_HAWKBOARD OMAPL138_HAWKBOARD      2495
-ip6000                 MACH_IP6000             IP6000                  2496
-ip6010                 MACH_IP6010             IP6010                  2497
-utm400                 MACH_UTM400             UTM400                  2498
-omap3_zybex            MACH_OMAP3_ZYBEX        OMAP3_ZYBEX             2499
-wireless_space         MACH_WIRELESS_SPACE     WIRELESS_SPACE          2500
-sx560                  MACH_SX560              SX560                   2501
 ts41x                  MACH_TS41X              TS41X                   2502
-elphel10373            MACH_ELPHEL10373        ELPHEL10373             2503
-rhobot                 MACH_RHOBOT             RHOBOT                  2504
-mx51_refresh           MACH_MX51_REFRESH       MX51_REFRESH            2505
-ls9260                 MACH_LS9260             LS9260                  2506
-shank                  MACH_SHANK              SHANK                   2507
-qsd8x50_st1            MACH_QSD8X50_ST1        QSD8X50_ST1             2508
-at91sam9m10ekes                MACH_AT91SAM9M10EKES    AT91SAM9M10EKES         2509
-hiram                  MACH_HIRAM              HIRAM                   2510
 phy3250                        MACH_PHY3250            PHY3250                 2511
-ea3250                 MACH_EA3250             EA3250                  2512
-fdi3250                        MACH_FDI3250            FDI3250                 2513
-whitestone             MACH_WHITESTONE         WHITESTONE              2514
-at91sam9263nit         MACH_AT91SAM9263NIT     AT91SAM9263NIT          2515
-ccmx51                 MACH_CCMX51             CCMX51                  2516
-ccmx51js               MACH_CCMX51JS           CCMX51JS                2517
-ccwmx51                        MACH_CCWMX51            CCWMX51                 2518
-ccwmx51js              MACH_CCWMX51JS          CCWMX51JS               2519
 mini6410               MACH_MINI6410           MINI6410                2520
-tiny6410               MACH_TINY6410           TINY6410                2521
-nano6410               MACH_NANO6410           NANO6410                2522
-at572d940hfnldb                MACH_AT572D940HFNLDB    AT572D940HFNLDB         2523
-htcleo                 MACH_HTCLEO             HTCLEO                  2524
-avp13                  MACH_AVP13              AVP13                   2525
-xxsvideod              MACH_XXSVIDEOD          XXSVIDEOD               2526
-vpnext                 MACH_VPNEXT             VPNEXT                  2527
-swarco_itc3            MACH_SWARCO_ITC3        SWARCO_ITC3             2528
-tx51                   MACH_TX51               TX51                    2529
-dolby_cat1021          MACH_DOLBY_CAT1021      DOLBY_CAT1021           2530
 mx28evk                        MACH_MX28EVK            MX28EVK                 2531
-phoenix260             MACH_PHOENIX260         PHOENIX260              2532
-uvaca_stork            MACH_UVACA_STORK        UVACA_STORK             2533
 smartq5                        MACH_SMARTQ5            SMARTQ5                 2534
-all3078                        MACH_ALL3078            ALL3078                 2535
-ctera_2bay_ds          MACH_CTERA_2BAY_DS      CTERA_2BAY_DS           2536
-siogentoo3             MACH_SIOGENTOO3         SIOGENTOO3              2537
-epb5000                        MACH_EPB5000            EPB5000                 2538
-hy9263                 MACH_HY9263             HY9263                  2539
-acer_tempo_m900                MACH_ACER_TEMPO_M900    ACER_TEMPO_M900         2540
-acer_tempo_dx650       MACH_ACER_TEMPO_DX900   ACER_TEMPO_DX900        2541
-acer_tempo_x960                MACH_ACER_TEMPO_X960    ACER_TEMPO_X960         2542
-acer_eten_v900         MACH_ACER_ETEN_V900     ACER_ETEN_V900          2543
-acer_eten_x900         MACH_ACER_ETEN_X900     ACER_ETEN_X900          2544
-bonnell                        MACH_BONNELL            BONNELL                 2545
-oht_mx27               MACH_OHT_MX27           OHT_MX27                2546
-htcquartz              MACH_HTCQUARTZ          HTCQUARTZ               2547
 davinci_dm6467tevm     MACH_DAVINCI_DM6467TEVM DAVINCI_DM6467TEVM      2548
-c3ax03                 MACH_C3AX03             C3AX03                  2549
 mxt_td60               MACH_MXT_TD60           MXT_TD60                2550
-esyx                   MACH_ESYX               ESYX                    2551
-dove_db2               MACH_DOVE_DB2           DOVE_DB2                2552
-bulldog                        MACH_BULLDOG            BULLDOG                 2553
-derell_me2000          MACH_DERELL_ME2000      DERELL_ME2000           2554
-bcmring_base           MACH_BCMRING_BASE       BCMRING_BASE            2555
-bcmring_evm            MACH_BCMRING_EVM        BCMRING_EVM             2556
-bcmring_evm_jazz       MACH_BCMRING_EVM_JAZZ   BCMRING_EVM_JAZZ        2557
-bcmring_sp             MACH_BCMRING_SP         BCMRING_SP              2558
-bcmring_sv             MACH_BCMRING_SV         BCMRING_SV              2559
-bcmring_sv_jazz                MACH_BCMRING_SV_JAZZ    BCMRING_SV_JAZZ         2560
-bcmring_tablet         MACH_BCMRING_TABLET     BCMRING_TABLET          2561
-bcmring_vp             MACH_BCMRING_VP         BCMRING_VP              2562
-bcmring_evm_seikor     MACH_BCMRING_EVM_SEIKOR BCMRING_EVM_SEIKOR      2563
-bcmring_sp_wqvga       MACH_BCMRING_SP_WQVGA   BCMRING_SP_WQVGA        2564
-bcmring_custom         MACH_BCMRING_CUSTOM     BCMRING_CUSTOM          2565
-acer_s200              MACH_ACER_S200          ACER_S200               2566
-bt270                  MACH_BT270              BT270                   2567
-iseo                   MACH_ISEO               ISEO                    2568
-cezanne                        MACH_CEZANNE            CEZANNE                 2569
-lucca                  MACH_LUCCA              LUCCA                   2570
-supersmart             MACH_SUPERSMART         SUPERSMART              2571
-arm11_board            MACH_CS_MISANO          CS_MISANO               2572
-magnolia2              MACH_MAGNOLIA2          MAGNOLIA2               2573
-emxx                   MACH_EMXX               EMXX                    2574
-outlaw                 MACH_OUTLAW             OUTLAW                  2575
-riot_bei2              MACH_RIOT_BEI2          RIOT_BEI2               2576
-riot_vox               MACH_RIOT_VOX           RIOT_VOX                2577
-riot_x37               MACH_RIOT_X37           RIOT_X37                2578
-mega25mx               MACH_MEGA25MX           MEGA25MX                2579
-benzina2               MACH_BENZINA2           BENZINA2                2580
-ignite                 MACH_IGNITE             IGNITE                  2581
-foggia                 MACH_FOGGIA             FOGGIA                  2582
-arezzo                 MACH_AREZZO             AREZZO                  2583
-leica_skywalker                MACH_LEICA_SKYWALKER    LEICA_SKYWALKER         2584
-jacinto2_jamr          MACH_JACINTO2_JAMR      JACINTO2_JAMR           2585
-gts_nova               MACH_GTS_NOVA           GTS_NOVA                2586
-p3600                  MACH_P3600              P3600                   2587
-dlt2                   MACH_DLT2               DLT2                    2588
-df3120                 MACH_DF3120             DF3120                  2589
-ecucore_9g20           MACH_ECUCORE_9G20       ECUCORE_9G20            2590
-nautel_lpc3240         MACH_NAUTEL_LPC3240     NAUTEL_LPC3240          2591
-glacier                        MACH_GLACIER            GLACIER                 2592
-phrazer_bulldog                MACH_PHRAZER_BULLDOG    PHRAZER_BULLDOG         2593
-omap3_bulldog          MACH_OMAP3_BULLDOG      OMAP3_BULLDOG           2594
-pca101                 MACH_PCA101             PCA101                  2595
-buzzc                  MACH_BUZZC              BUZZC                   2596
-sasie2                 MACH_SASIE2             SASIE2                  2597
-davinci_cio            MACH_DAVINCI_CIO        DAVINCI_CIO             2598
-smartmeter_dl          MACH_SMARTMETER_DL      SMARTMETER_DL           2599
-wzl6410                        MACH_WZL6410            WZL6410                 2600
-wzl6410m               MACH_WZL6410M           WZL6410M                2601
-wzl6410f               MACH_WZL6410F           WZL6410F                2602
-wzl6410i               MACH_WZL6410I           WZL6410I                2603
-spacecom1              MACH_SPACECOM1          SPACECOM1               2604
-pingu920               MACH_PINGU920           PINGU920                2605
-bravoc                 MACH_BRAVOC             BRAVOC                  2606
-cybo2440               MACH_CYBO2440           CYBO2440                2607
-vdssw                  MACH_VDSSW              VDSSW                   2608
-romulus                        MACH_ROMULUS            ROMULUS                 2609
-omap_magic             MACH_OMAP_MAGIC         OMAP_MAGIC              2610
-eltd100                        MACH_ELTD100            ELTD100                 2611
 capc7117               MACH_CAPC7117           CAPC7117                2612
-swan                   MACH_SWAN               SWAN                    2613
-veu                    MACH_VEU                VEU                     2614
-rm2                    MACH_RM2                RM2                     2615
-tt2100                 MACH_TT2100             TT2100                  2616
-venice                 MACH_VENICE             VENICE                  2617
-pc7323                 MACH_PC7323             PC7323                  2618
-masp                   MACH_MASP               MASP                    2619
-fujitsu_tvstbsoc0      MACH_FUJITSU_TVSTBSOC   FUJITSU_TVSTBSOC        2620
-fujitsu_tvstbsoc1      MACH_FUJITSU_TVSTBSOC1  FUJITSU_TVSTBSOC1       2621
-lexikon                        MACH_LEXIKON            LEXIKON                 2622
-mini2440v2             MACH_MINI2440V2         MINI2440V2              2623
 icontrol               MACH_ICONTROL           ICONTROL                2624
-gplugd                 MACH_SHEEVAD            SHEEVAD                 2625
-qsd8x50a_st1_1         MACH_QSD8X50A_ST1_1     QSD8X50A_ST1_1          2626
 qsd8x50a_st1_5         MACH_QSD8X50A_ST1_5     QSD8X50A_ST1_5          2627
-bee                    MACH_BEE                BEE                     2628
 mx23evk                        MACH_MX23EVK            MX23EVK                 2629
 ap4evb                 MACH_AP4EVB             AP4EVB                  2630
-stockholm              MACH_STOCKHOLM          STOCKHOLM               2631
-lpc_h3131              MACH_LPC_H3131          LPC_H3131               2632
-stingray               MACH_STINGRAY           STINGRAY                2633
-kraken                 MACH_KRAKEN             KRAKEN                  2634
-gw2388                 MACH_GW2388             GW2388                  2635
-jadecpu                        MACH_JADECPU            JADECPU                 2636
-carlisle               MACH_CARLISLE           CARLISLE                2637
-lux_sf9                        MACH_LUX_SF9            LUX_SF9                 2638
-nemid_tb               MACH_NEMID_TB           NEMID_TB                2639
-terrier                        MACH_TERRIER            TERRIER                 2640
-turbot                 MACH_TURBOT             TURBOT                  2641
-sanddab                        MACH_SANDDAB            SANDDAB                 2642
-mx35_cicada            MACH_MX35_CICADA        MX35_CICADA             2643
-ghi2703d               MACH_GHI2703D           GHI2703D                2644
-lux_sfx9               MACH_LUX_SFX9           LUX_SFX9                2645
-lux_sf9g               MACH_LUX_SF9G           LUX_SF9G                2646
-lux_edk9               MACH_LUX_EDK9           LUX_EDK9                2647
-hw90240                        MACH_HW90240            HW90240                 2648
-dm365_leopard          MACH_DM365_LEOPARD      DM365_LEOPARD           2649
 mityomapl138           MACH_MITYOMAPL138       MITYOMAPL138            2650
-scat110                        MACH_SCAT110            SCAT110                 2651
-acer_a1                        MACH_ACER_A1            ACER_A1                 2652
-cmcontrol              MACH_CMCONTROL          CMCONTROL               2653
-pelco_lamar            MACH_PELCO_LAMAR        PELCO_LAMAR             2654
-rfp43                  MACH_RFP43              RFP43                   2655
-sk86r0301              MACH_SK86R0301          SK86R0301               2656
-ctpxa                  MACH_CTPXA              CTPXA                   2657
-epb_arm9_a             MACH_EPB_ARM9_A         EPB_ARM9_A              2658
 guruplug               MACH_GURUPLUG           GURUPLUG                2659
 spear310               MACH_SPEAR310           SPEAR310                2660
 spear320               MACH_SPEAR320           SPEAR320                2661
-robotx                 MACH_ROBOTX             ROBOTX                  2662
-lsxhl                  MACH_LSXHL              LSXHL                   2663
-smartlite              MACH_SMARTLITE          SMARTLITE               2664
-cws2                   MACH_CWS2               CWS2                    2665
-m619                   MACH_M619               M619                    2666
-smartview              MACH_SMARTVIEW          SMARTVIEW               2667
-lsa_salsa              MACH_LSA_SALSA          LSA_SALSA               2668
-kizbox                 MACH_KIZBOX             KIZBOX                  2669
-htccharmer             MACH_HTCCHARMER         HTCCHARMER              2670
-guf_neso_lt            MACH_GUF_NESO_LT        GUF_NESO_LT             2671
-pm9g45                 MACH_PM9G45             PM9G45                  2672
-htcpanther             MACH_HTCPANTHER         HTCPANTHER              2673
-htcpanther_cdma                MACH_HTCPANTHER_CDMA    HTCPANTHER_CDMA         2674
-reb01                  MACH_REB01              REB01                   2675
 aquila                 MACH_AQUILA             AQUILA                  2676
-spark_sls_hw2          MACH_SPARK_SLS_HW2      SPARK_SLS_HW2           2677
 sheeva_esata           MACH_ESATA_SHEEVAPLUG   ESATA_SHEEVAPLUG        2678
 msm7x30_surf           MACH_MSM7X30_SURF       MSM7X30_SURF            2679
-micro2440              MACH_MICRO2440          MICRO2440               2680
-am2440                 MACH_AM2440             AM2440                  2681
-tq2440                 MACH_TQ2440             TQ2440                  2682
-lpc2478oem             MACH_LPC2478OEM         LPC2478OEM              2683
-ak880x                 MACH_AK880X             AK880X                  2684
-cobra3530              MACH_COBRA3530          COBRA3530               2685
-pmppb                  MACH_PMPPB              PMPPB                   2686
-u6715                  MACH_U6715              U6715                   2687
-axar1500_sender                MACH_AXAR1500_SENDER    AXAR1500_SENDER         2688
-g30_dvb                        MACH_G30_DVB            G30_DVB                 2689
-vc088x                 MACH_VC088X             VC088X                  2690
-mioa702                        MACH_MIOA702            MIOA702                 2691
-hpmin                  MACH_HPMIN              HPMIN                   2692
-ak880xak               MACH_AK880XAK           AK880XAK                2693
-arm926tomap850         MACH_ARM926TOMAP850     ARM926TOMAP850          2694
-lkevm                  MACH_LKEVM              LKEVM                   2695
-mw6410                 MACH_MW6410             MW6410                  2696
 terastation_wxl                MACH_TERASTATION_WXL    TERASTATION_WXL         2697
-cpu8000e               MACH_CPU8000E           CPU8000E                2698
-catania                        MACH_CATANIA            CATANIA                 2699
-tokyo                  MACH_TOKYO              TOKYO                   2700
-msm7201a_surf          MACH_MSM7201A_SURF      MSM7201A_SURF           2701
-msm7201a_ffa           MACH_MSM7201A_FFA       MSM7201A_FFA            2702
 msm7x25_surf           MACH_MSM7X25_SURF       MSM7X25_SURF            2703
 msm7x25_ffa            MACH_MSM7X25_FFA        MSM7X25_FFA             2704
 msm7x27_surf           MACH_MSM7X27_SURF       MSM7X27_SURF            2705
 msm7x27_ffa            MACH_MSM7X27_FFA        MSM7X27_FFA             2706
 msm7x30_ffa            MACH_MSM7X30_FFA        MSM7X30_FFA             2707
 qsd8x50_surf           MACH_QSD8X50_SURF       QSD8X50_SURF            2708
-qsd8x50_comet          MACH_QSD8X50_COMET      QSD8X50_COMET           2709
-qsd8x50_ffa            MACH_QSD8X50_FFA        QSD8X50_FFA             2710
-qsd8x50a_surf          MACH_QSD8X50A_SURF      QSD8X50A_SURF           2711
-qsd8x50a_ffa           MACH_QSD8X50A_FFA       QSD8X50A_FFA            2712
-adx_xgcp10             MACH_ADX_XGCP10         ADX_XGCP10              2713
-mcgwumts2a             MACH_MCGWUMTS2A         MCGWUMTS2A              2714
-mobikt                 MACH_MOBIKT             MOBIKT                  2715
 mx53_evk               MACH_MX53_EVK           MX53_EVK                2716
 igep0030               MACH_IGEP0030           IGEP0030                2717
-axell_h40_h50_ctrl     MACH_AXELL_H40_H50_CTRL AXELL_H40_H50_CTRL      2718
-dtcommod               MACH_DTCOMMOD           DTCOMMOD                2719
-gould                  MACH_GOULD              GOULD                   2720
-siberia                        MACH_SIBERIA            SIBERIA                 2721
 sbc3530                        MACH_SBC3530            SBC3530                 2722
-qarm                   MACH_QARM               QARM                    2723
-mips                   MACH_MIPS               MIPS                    2724
-mx27grb                        MACH_MX27GRB            MX27GRB                 2725
-sbc8100                        MACH_SBC8100            SBC8100                 2726
 saarb                  MACH_SAARB              SAARB                   2727
-omap3mini              MACH_OMAP3MINI          OMAP3MINI               2728
-cnmbook7se             MACH_CNMBOOK7SE         CNMBOOK7SE              2729
-catan                  MACH_CATAN              CATAN                   2730
 harmony                        MACH_HARMONY            HARMONY                 2731
-tonga                  MACH_TONGA              TONGA                   2732
-cybook_orizon          MACH_CYBOOK_ORIZON      CYBOOK_ORIZON           2733
-htcrhodiumcdma         MACH_HTCRHODIUMCDMA     HTCRHODIUMCDMA          2734
-epc_g45                        MACH_EPC_G45            EPC_G45                 2735
-epc_lpc3250            MACH_EPC_LPC3250        EPC_LPC3250             2736
-mxc91341evb            MACH_MXC91341EVB        MXC91341EVB             2737
-rtw1000                        MACH_RTW1000            RTW1000                 2738
-bobcat                 MACH_BOBCAT             BOBCAT                  2739
-trizeps6               MACH_TRIZEPS6           TRIZEPS6                2740
 msm7x30_fluid          MACH_MSM7X30_FLUID      MSM7X30_FLUID           2741
-nedap9263              MACH_NEDAP9263          NEDAP9263               2742
-netgear_ms2110         MACH_NETGEAR_MS2110     NETGEAR_MS2110          2743
-bmx                    MACH_BMX                BMX                     2744
-netstream              MACH_NETSTREAM          NETSTREAM               2745
-vpnext_rcu             MACH_VPNEXT_RCU         VPNEXT_RCU              2746
-vpnext_mpu             MACH_VPNEXT_MPU         VPNEXT_MPU              2747
-bcmring_tablet_v1      MACH_BCMRING_TABLET_V1  BCMRING_TABLET_V1       2748
-sgarm10                        MACH_SGARM10            SGARM10                 2749
 cm_t3517               MACH_CM_T3517           CM_T3517                2750
-omap3_cps              MACH_OMAP3_CPS          OMAP3_CPS               2751
-axar1500_receiver      MACH_AXAR1500_RECEIVER  AXAR1500_RECEIVER       2752
 wbd222                 MACH_WBD222             WBD222                  2753
-mt65xx                 MACH_MT65XX             MT65XX                  2754
 msm8x60_surf           MACH_MSM8X60_SURF       MSM8X60_SURF            2755
 msm8x60_sim            MACH_MSM8X60_SIM        MSM8X60_SIM             2756
-vmc300                 MACH_VMC300             VMC300                  2757
 tcc8000_sdk            MACH_TCC8000_SDK        TCC8000_SDK             2758
-nanos                  MACH_NANOS              NANOS                   2759
-stamp9g10              MACH_STAMP9G10          STAMP9G10               2760
-stamp9g45              MACH_STAMP9G45          STAMP9G45               2761
-h6053                  MACH_H6053              H6053                   2762
-smint01                        MACH_SMINT01            SMINT01                 2763
-prtlvt2                        MACH_PRTLVT2            PRTLVT2                 2764
 ap420                  MACH_AP420              AP420                   2765
-htcshift               MACH_HTCSHIFT           HTCSHIFT                2766
 davinci_dm365_fc       MACH_DAVINCI_DM365_FC   DAVINCI_DM365_FC        2767
 msm8x55_surf           MACH_MSM8X55_SURF       MSM8X55_SURF            2768
 msm8x55_ffa            MACH_MSM8X55_FFA        MSM8X55_FFA             2769
@@ -2761,7 +474,6 @@ oreo_controller            MACH_OREO_CONTROLLER    OREO_CONTROLLER         2773
 kopin_models           MACH_KOPIN_MODELS       KOPIN_MODELS            2774
 ttc_vision2            MACH_TTC_VISION2        TTC_VISION2             2775
 cns3420vb              MACH_CNS3420VB          CNS3420VB               2776
-lpc2                   MACH_LPC2               LPC2                    2777
 olympus                        MACH_OLYMPUS            OLYMPUS                 2778
 vortex                 MACH_VORTEX             VORTEX                  2779
 s5pc200                        MACH_S5PC200            S5PC200                 2780
@@ -2788,7 +500,6 @@ ti8168evm          MACH_TI8168EVM          TI8168EVM               2800
 neocoreomap            MACH_NEOCOREOMAP        NEOCOREOMAP             2801
 withings_wbp           MACH_WITHINGS_WBP       WITHINGS_WBP            2802
 dbps                   MACH_DBPS               DBPS                    2803
-sbc9261                        MACH_SBC9261            SBC9261                 2804
 pcbfp0001              MACH_PCBFP0001          PCBFP0001               2805
 speedy                 MACH_SPEEDY             SPEEDY                  2806
 chrysaor               MACH_CHRYSAOR           CHRYSAOR                2807
@@ -2812,7 +523,6 @@ p565                       MACH_P565               P565                    2824
 acer_a4                        MACH_ACER_A4            ACER_A4                 2825
 davinci_dm368_bip      MACH_DAVINCI_DM368_BIP  DAVINCI_DM368_BIP       2826
 eshare                 MACH_ESHARE             ESHARE                  2827
-hw_omapl138_europa     MACH_HW_OMAPL138_EUROPA HW_OMAPL138_EUROPA      2828
 wlbargn                        MACH_WLBARGN            WLBARGN                 2829
 bm170                  MACH_BM170              BM170                   2830
 netspace_mini_v2       MACH_NETSPACE_MINI_V2   NETSPACE_MINI_V2        2831
@@ -2879,7 +589,6 @@ davinci_picto              MACH_DAVINCI_PICTO      DAVINCI_PICTO           2891
 mecha                  MACH_MECHA              MECHA                   2892
 bubba3                 MACH_BUBBA3             BUBBA3                  2893
 pupitre                        MACH_PUPITRE            PUPITRE                 2894
-tegra_harmony          MACH_TEGRA_HARMONY      TEGRA_HARMONY           2895
 tegra_vogue            MACH_TEGRA_VOGUE        TEGRA_VOGUE             2896
 tegra_e1165            MACH_TEGRA_E1165        TEGRA_E1165             2897
 simplenet              MACH_SIMPLENET          SIMPLENET               2898
@@ -2969,7 +678,6 @@ netspace_lite_v2   MACH_NETSPACE_LITE_V2   NETSPACE_LITE_V2        2983
 ssc                    MACH_SSC                SSC                     2984
 premierwave_en         MACH_PREMIERWAVE_EN     PREMIERWAVE_EN          2985
 wasabi                 MACH_WASABI             WASABI                  2986
-vivow                  MACH_VIVOW              VIVOW                   2987
 mx50_rdp               MACH_MX50_RDP           MX50_RDP                2988
 universal_c210         MACH_UNIVERSAL_C210     UNIVERSAL_C210          2989
 real6410               MACH_REAL6410           REAL6410                2990
@@ -3017,12 +725,10 @@ remus                    MACH_REMUS              REMUS                   3031
 at91cap7xdk            MACH_AT91CAP7XDK        AT91CAP7XDK             3032
 at91cap7stk            MACH_AT91CAP7STK        AT91CAP7STK             3033
 kt_sbc_sam9_1          MACH_KT_SBC_SAM9_1      KT_SBC_SAM9_1           3034
-oratisrouter           MACH_ORATISROUTER       ORATISROUTER            3035
 armada_xp_db           MACH_ARMADA_XP_DB       ARMADA_XP_DB            3036
 spdm                   MACH_SPDM               SPDM                    3037
 gtib                   MACH_GTIB               GTIB                    3038
 dgm3240                        MACH_DGM3240            DGM3240                 3039
-atlas_i_lpe            MACH_ATLAS_I_LPE        ATLAS_I_LPE             3040
 htcmega                        MACH_HTCMEGA            HTCMEGA                 3041
 tricorder              MACH_TRICORDER          TRICORDER               3042
 tx28                   MACH_TX28               TX28                    3043
@@ -3062,7 +768,6 @@ clod                       MACH_CLOD               CLOD                    3077
 rump                   MACH_RUMP               RUMP                    3078
 tenderloin             MACH_TENDERLOIN         TENDERLOIN              3079
 shortloin              MACH_SHORTLOIN          SHORTLOIN               3080
-crespo                 MACH_CRESPO             CRESPO                  3081
 antares                        MACH_ANTARES            ANTARES                 3082
 wb40n                  MACH_WB40N              WB40N                   3083
 herring                        MACH_HERRING            HERRING                 3084
@@ -3111,7 +816,6 @@ smartqv3           MACH_SMARTQV3           SMARTQV3                3126
 smartqv7               MACH_SMARTQV7           SMARTQV7                3127
 paz00                  MACH_PAZ00              PAZ00                   3128
 acmenetusfoxg20                MACH_ACMENETUSFOXG20    ACMENETUSFOXG20         3129
-htcwillow              MACH_HTCWILLOW          HTCWILLOW               3130
 fwbd_0404              MACH_FWBD_0404          FWBD_0404               3131
 hdgu                   MACH_HDGU               HDGU                    3132
 pyramid                        MACH_PYRAMID            PYRAMID                 3133
@@ -3162,7 +866,6 @@ b5500                      MACH_B5500              B5500                   3177
 s5500                  MACH_S5500              S5500                   3178
 icon                   MACH_ICON               ICON                    3179
 elephant               MACH_ELEPHANT           ELEPHANT                3180
-msm8x60_fusion         MACH_MSM8X60_FUSION     MSM8X60_FUSION          3181
 shooter                        MACH_SHOOTER            SHOOTER                 3182
 spade_lte              MACH_SPADE_LTE          SPADE_LTE               3183
 philhwani              MACH_PHILHWANI          PHILHWANI               3184
@@ -3174,13 +877,11 @@ ag5evm                   MACH_AG5EVM             AG5EVM                  3189
 sc575plc               MACH_SC575PLC           SC575PLC                3190
 sc575hmi               MACH_SC575IPC           SC575IPC                3191
 omap3_tdm3730          MACH_OMAP3_TDM3730      OMAP3_TDM3730           3192
-g7                     MACH_G7                 G7                      3193
 top9000_eval           MACH_TOP9000_EVAL       TOP9000_EVAL            3194
 top9000_su             MACH_TOP9000_SU         TOP9000_SU              3195
 utm300                 MACH_UTM300             UTM300                  3196
 tsunagi                        MACH_TSUNAGI            TSUNAGI                 3197
 ts75xx                 MACH_TS75XX             TS75XX                  3198
-msm8x60_fusn_ffa       MACH_MSM8X60_FUSN_FFA   MSM8X60_FUSN_FFA        3199
 ts47xx                 MACH_TS47XX             TS47XX                  3200
 da850_k5               MACH_DA850_K5           DA850_K5                3201
 ax502                  MACH_AX502              AX502                   3202
@@ -3285,7 +986,6 @@ rfl109145_ssrv             MACH_RFL109145_SSRV     RFL109145_SSRV          3304
 nmh                    MACH_NMH                NMH                     3305
 wn802t                 MACH_WN802T             WN802T                  3306
 dragonet               MACH_DRAGONET           DRAGONET                3307
-geneva_b               MACH_GENEVA_B           GENEVA_B                3308
 at91sam9263desk16l     MACH_AT91SAM9263DESK16L AT91SAM9263DESK16L      3309
 bcmhana_sv             MACH_BCMHANA_SV         BCMHANA_SV              3310
 bcmhana_tablet         MACH_BCMHANA_TABLET     BCMHANA_TABLET          3311
@@ -3316,3 +1016,86 @@ rover_g8         MACH_ROVER_G8           ROVER_G8                3335
 t5388p                 MACH_T5388P             T5388P                  3336
 dingo                  MACH_DINGO              DINGO                   3337
 goflexhome             MACH_GOFLEXHOME         GOFLEXHOME              3338
+lanreadyfn511          MACH_LANREADYFN511      LANREADYFN511           3340
+omap3_baia             MACH_OMAP3_BAIA         OMAP3_BAIA              3341
+omap3smartdisplay      MACH_OMAP3SMARTDISPLAY  OMAP3SMARTDISPLAY       3342
+xilinx                 MACH_XILINX             XILINX                  3343
+a2f                    MACH_A2F                A2F                     3344
+sky25                  MACH_SKY25              SKY25                   3345
+ccmx53                 MACH_CCMX53             CCMX53                  3346
+ccmx53js               MACH_CCMX53JS           CCMX53JS                3347
+ccwmx53                        MACH_CCWMX53            CCWMX53                 3348
+ccwmx53js              MACH_CCWMX53JS          CCWMX53JS               3349
+frisms                 MACH_FRISMS             FRISMS                  3350
+msm7x27a_ffa           MACH_MSM7X27A_FFA       MSM7X27A_FFA            3351
+msm7x27a_surf          MACH_MSM7X27A_SURF      MSM7X27A_SURF           3352
+msm7x27a_rumi3         MACH_MSM7X27A_RUMI3     MSM7X27A_RUMI3          3353
+dimmsam9g20            MACH_DIMMSAM9G20        DIMMSAM9G20             3354
+dimm_imx28             MACH_DIMM_IMX28         DIMM_IMX28              3355
+amk_a4                 MACH_AMK_A4             AMK_A4                  3356
+gnet_sgme              MACH_GNET_SGME          GNET_SGME               3357
+shooter_u              MACH_SHOOTER_U          SHOOTER_U               3358
+vmx53                  MACH_VMX53              VMX53                   3359
+rhino                  MACH_RHINO              RHINO                   3360
+armlex4210             MACH_ARMLEX4210         ARMLEX4210              3361
+swarcoextmodem         MACH_SWARCOEXTMODEM     SWARCOEXTMODEM          3362
+snowball               MACH_SNOWBALL           SNOWBALL                3363
+pcm049                 MACH_PCM049             PCM049                  3364
+vigor                  MACH_VIGOR              VIGOR                   3365
+oslo_amundsen          MACH_OSLO_AMUNDSEN      OSLO_AMUNDSEN           3366
+gsl_diamond            MACH_GSL_DIAMOND        GSL_DIAMOND             3367
+cv2201                 MACH_CV2201             CV2201                  3368
+cv2202                 MACH_CV2202             CV2202                  3369
+cv2203                 MACH_CV2203             CV2203                  3370
+vit_ibox               MACH_VIT_IBOX           VIT_IBOX                3371
+dm6441_esp             MACH_DM6441_ESP         DM6441_ESP              3372
+at91sam9x5ek           MACH_AT91SAM9X5EK       AT91SAM9X5EK            3373
+libra                  MACH_LIBRA              LIBRA                   3374
+easycrrh               MACH_EASYCRRH           EASYCRRH                3375
+tripel                 MACH_TRIPEL             TRIPEL                  3376
+endian_mini            MACH_ENDIAN_MINI        ENDIAN_MINI             3377
+xilinx_ep107           MACH_XILINX_EP107       XILINX_EP107            3378
+nuri                   MACH_NURI               NURI                    3379
+janus                  MACH_JANUS              JANUS                   3380
+ddnas                  MACH_DDNAS              DDNAS                   3381
+tag                    MACH_TAG                TAG                     3382
+tagw                   MACH_TAGW               TAGW                    3383
+nitrogen_vm_imx51      MACH_NITROGEN_VM_IMX51  NITROGEN_VM_IMX51       3384
+viprinet               MACH_VIPRINET           VIPRINET                3385
+bockw                  MACH_BOCKW              BOCKW                   3386
+eva2000                        MACH_EVA2000            EVA2000                 3387
+steelyard              MACH_STEELYARD          STEELYARD               3388
+sdh001                 MACH_MACH_SDH001        MACH_SDH001             3390
+nsslsboard             MACH_NSSLSBOARD         NSSLSBOARD              3392
+geneva_b5              MACH_GENEVA_B5          GENEVA_B5               3393
+spear1340              MACH_SPEAR1340          SPEAR1340               3394
+rexmas                 MACH_REXMAS             REXMAS                  3395
+msm8960_cdp            MACH_MSM8960_CDP        MSM8960_CDP             3396
+msm8960_mdp            MACH_MSM8960_MDP        MSM8960_MDP             3397
+msm8960_fluid          MACH_MSM8960_FLUID      MSM8960_FLUID           3398
+msm8960_apq            MACH_MSM8960_APQ        MSM8960_APQ             3399
+helios_v2              MACH_HELIOS_V2          HELIOS_V2               3400
+mif10p                 MACH_MIF10P             MIF10P                  3401
+iam28                  MACH_IAM28              IAM28                   3402
+picasso                        MACH_PICASSO            PICASSO                 3403
+mr301a                 MACH_MR301A             MR301A                  3404
+notle                  MACH_NOTLE              NOTLE                   3405
+eelx2                  MACH_EELX2              EELX2                   3406
+moon                   MACH_MOON               MOON                    3407
+ruby                   MACH_RUBY               RUBY                    3408
+goldengate             MACH_GOLDENGATE         GOLDENGATE              3409
+ctbu_gen2              MACH_CTBU_GEN2          CTBU_GEN2               3410
+kmp_am17_01            MACH_KMP_AM17_01        KMP_AM17_01             3411
+wtplug                 MACH_WTPLUG             WTPLUG                  3412
+mx27su2                        MACH_MX27SU2            MX27SU2                 3413
+nb31                   MACH_NB31               NB31                    3414
+hjsdu                  MACH_HJSDU              HJSDU                   3415
+td3_rev1               MACH_TD3_REV1           TD3_REV1                3416
+eag_ci4000             MACH_EAG_CI4000         EAG_CI4000              3417
+net5big_nand_v2                MACH_NET5BIG_NAND_V2    NET5BIG_NAND_V2         3418
+cpx2                   MACH_CPX2               CPX2                    3419
+net2big_nand_v2                MACH_NET2BIG_NAND_V2    NET2BIG_NAND_V2         3420
+ecuv5                  MACH_ECUV5              ECUV5                   3421
+hsgx6d                 MACH_HSGX6D             HSGX6D                  3422
+dawad7                 MACH_DAWAD7             DAWAD7                  3423
+sam9repeater           MACH_SAM9REPEATER       SAM9REPEATER            3424
index 39f6d8e1af73043890adcf8761b226b5f2e82d4d..6de73aab019599fd4a53abdffa39b863a090128f 100644 (file)
@@ -4,8 +4,8 @@
 # Copyright (C) 2001 ARM Limited
 #
 
-# EXTRA_CFLAGS := -DDEBUG
-# EXTRA_AFLAGS := -DDEBUG
+# ccflags-y := -DDEBUG
+# asflags-y := -DDEBUG
 
 KBUILD_AFLAGS  :=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp)
 LDFLAGS                +=--no-warn-mismatch
index cd2062fe0f611e54fdb6e5528b6af24e13d3b509..49642b59f73d983df3bd480094b8249a9d10acb7 100644 (file)
@@ -6,6 +6,11 @@ config AVR32
        select HAVE_CLK
        select HAVE_OPROFILE
        select HAVE_KPROBES
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_PROBE
+       select HARDIRQS_SW_RESEND
+       select GENERIC_IRQ_SHOW
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
@@ -17,9 +22,6 @@ config AVR32
 config GENERIC_GPIO
        def_bool y
 
-config GENERIC_HARDIRQS
-       def_bool y
-
 config STACKTRACE_SUPPORT
        def_bool y
 
@@ -29,12 +31,6 @@ config LOCKDEP_SUPPORT
 config TRACE_IRQFLAGS_SUPPORT
        def_bool y
 
-config HARDIRQS_SW_RESEND
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       def_bool y
-
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
index 7919be311f4ab99c7f78d1e476a9088a6c2c67c4..f9143196345271698a674b360769cf05c8173de4 100644 (file)
@@ -301,7 +301,7 @@ static int __init mrmt1_init(void)
        /* Select the Touchscreen interrupt pin mode */
        at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ),
                        GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
-       set_irq_type( AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING );
+       irq_set_irq_type(AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING);
        at32_spi_setup_slaves(0,spi01_board_info,ARRAY_SIZE(spi01_board_info));
        spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info));
 #endif
index 659d119ce7129e03bc9b3f819f3a8595a2b8b3a6..fafed4c38fd25c18989661edcd1150b5dd3a5b4f 100644 (file)
@@ -322,6 +322,6 @@ static int __init atngw100_arch_init(void)
        /* set_irq_type() after the arch_initcall for EIC has run, and
         * before the I2C subsystem could try using this IRQ.
         */
-       return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
+       return irq_set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
 }
 arch_initcall(atngw100_arch_init);
index f7dd5f71edf7e497537a31725cf05f514f7de5ca..72444d97f80cd759551256591bc1b9d8ff733b15 100644 (file)
@@ -299,8 +299,7 @@ static inline int ffs(unsigned long word)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix-le.h>
 
 #endif /* __ASM_AVR32_BITOPS_H */
index 9cefda6f534a19f641cf467a758a0e88c0d900a8..72667a3b1af77822f9a6ea3081adeec188f66f22 100644 (file)
@@ -23,14 +23,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 
index 11e310c567a967bee5bb8ad31c13ed4c9a389cd8..d93ead02daeda4635e772268b328dc652f1d86df 100644 (file)
@@ -58,8 +58,8 @@ EXPORT_SYMBOL(find_first_zero_bit);
 EXPORT_SYMBOL(find_next_zero_bit);
 EXPORT_SYMBOL(find_first_bit);
 EXPORT_SYMBOL(find_next_bit);
-EXPORT_SYMBOL(generic_find_next_le_bit);
-EXPORT_SYMBOL(generic_find_next_zero_le_bit);
+EXPORT_SYMBOL(find_next_bit_le);
+EXPORT_SYMBOL(find_next_zero_bit_le);
 
 /* I/O primitives (lib/io-*.S) */
 EXPORT_SYMBOL(__raw_readsb);
index 9604f7758f9a6e84f00779e036c4625073e9fd46..bc3aa18293df1e4abd4dc2b38365b7c9b020400c 100644 (file)
@@ -26,40 +26,3 @@ void __weak nmi_disable(void)
 {
 
 }
-
-#ifdef CONFIG_PROC_FS
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *)v, cpu;
-       struct irqaction *action;
-       unsigned long flags;
-
-       if (i == 0) {
-               seq_puts(p, "           ");
-               for_each_online_cpu(cpu)
-                       seq_printf(p, "CPU%d       ", cpu);
-               seq_putc(p, '\n');
-       }
-
-       if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
-               if (!action)
-                       goto unlock;
-
-               seq_printf(p, "%3d: ", i);
-               for_each_online_cpu(cpu)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
-               seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-");
-               seq_printf(p, "  %s", action->name);
-               for (action = action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-
-               seq_putc(p, '\n');
-       unlock:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-       }
-
-       return 0;
-}
-#endif
index 997b33b2288a6989aa3bdac94b0417967d7f6208..b93586460be6e534f01c8a635cd94debb2c90818 100644 (file)
@@ -123,7 +123,7 @@ ENTRY(find_next_bit)
        brgt    1b
        retal   r11
 
-ENTRY(generic_find_next_le_bit)
+ENTRY(find_next_bit_le)
        lsr     r8, r10, 5
        sub     r9, r11, r10
        retle   r11
@@ -153,7 +153,7 @@ ENTRY(generic_find_next_le_bit)
        brgt    1b
        retal   r11
 
-ENTRY(generic_find_next_zero_le_bit)
+ENTRY(find_next_zero_bit_le)
        lsr     r8, r10, 5
        sub     r9, r11, r10
        retle   r11
index e67c999454284f46dee1c3ba0742cbbe0221ba23..bfc9d071db9bce219985b62a5c80446ff7a1f3e5 100644 (file)
@@ -2048,6 +2048,11 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data,
                rx_dws->reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
                rx_dws->cfg_hi = DWC_CFGH_SRC_PER(3);
                rx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
+               rx_dws->src_master = 0;
+               rx_dws->dst_master = 1;
+               rx_dws->src_msize = DW_DMA_MSIZE_1;
+               rx_dws->dst_msize = DW_DMA_MSIZE_1;
+               rx_dws->fc = DW_DMA_FC_D_P2M;
        }
 
        /* Check if DMA slave interface for playback should be configured. */
@@ -2056,6 +2061,11 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data,
                tx_dws->reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
                tx_dws->cfg_hi = DWC_CFGH_DST_PER(4);
                tx_dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
+               tx_dws->src_master = 0;
+               tx_dws->dst_master = 1;
+               tx_dws->src_msize = DW_DMA_MSIZE_1;
+               tx_dws->dst_msize = DW_DMA_MSIZE_1;
+               tx_dws->fc = DW_DMA_FC_D_M2P;
        }
 
        if (platform_device_add_data(pdev, data,
@@ -2128,6 +2138,11 @@ at32_add_device_abdac(unsigned int id, struct atmel_abdac_pdata *data)
        dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
        dws->cfg_hi = DWC_CFGH_DST_PER(2);
        dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL);
+       dws->src_master = 0;
+       dws->dst_master = 1;
+       dws->src_msize = DW_DMA_MSIZE_1;
+       dws->dst_msize = DW_DMA_MSIZE_1;
+       dws->fc = DW_DMA_FC_D_M2P;
 
        if (platform_device_add_data(pdev, data,
                                sizeof(struct atmel_abdac_pdata)))
index e9d12058ffd379287bd4044e522a6a6736dd727c..47ba4b9b6db16b5852a0f857236e3d73e5349e75 100644 (file)
@@ -61,45 +61,42 @@ struct eic {
 static struct eic *nmi_eic;
 static bool nmi_enabled;
 
-static void eic_ack_irq(unsigned int irq)
+static void eic_ack_irq(struct irq_chip *d)
 {
-       struct eic *eic = get_irq_chip_data(irq);
-       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
+       struct eic *eic = irq_data_get_irq_chip_data(data);
+       eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_mask_irq(unsigned int irq)
+static void eic_mask_irq(struct irq_chip *d)
 {
-       struct eic *eic = get_irq_chip_data(irq);
-       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
+       struct eic *eic = irq_data_get_irq_chip_data(data);
+       eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_mask_ack_irq(unsigned int irq)
+static void eic_mask_ack_irq(struct irq_chip *d)
 {
-       struct eic *eic = get_irq_chip_data(irq);
-       eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
-       eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
+       struct eic *eic = irq_data_get_irq_chip_data(data);
+       eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
+       eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 }
 
-static void eic_unmask_irq(unsigned int irq)
+static void eic_unmask_irq(struct irq_chip *d)
 {
-       struct eic *eic = get_irq_chip_data(irq);
-       eic_writel(eic, IER, 1 << (irq - eic->first_irq));
+       struct eic *eic = irq_data_get_irq_chip_data(data);
+       eic_writel(eic, IER, 1 << (d->irq - eic->first_irq));
 }
 
-static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int eic_set_irq_type(struct irq_chip *d, unsigned int flow_type)
 {
-       struct eic *eic = get_irq_chip_data(irq);
-       struct irq_desc *desc;
+       struct eic *eic = irq_data_get_irq_chip_data(data);
+       unsigned int irq = d->irq;
        unsigned int i = irq - eic->first_irq;
        u32 mode, edge, level;
-       int ret = 0;
 
        flow_type &= IRQ_TYPE_SENSE_MASK;
        if (flow_type == IRQ_TYPE_NONE)
                flow_type = IRQ_TYPE_LEVEL_LOW;
 
-       desc = &irq_desc[irq];
-
        mode = eic_readl(eic, MODE);
        edge = eic_readl(eic, EDGE);
        level = eic_readl(eic, LEVEL);
@@ -122,39 +119,34 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
                edge &= ~(1 << i);
                break;
        default:
-               ret = -EINVAL;
-               break;
+               return -EINVAL;
        }
 
-       if (ret == 0) {
-               eic_writel(eic, MODE, mode);
-               eic_writel(eic, EDGE, edge);
-               eic_writel(eic, LEVEL, level);
-
-               if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
-                       flow_type |= IRQ_LEVEL;
-                       __set_irq_handler_unlocked(irq, handle_level_irq);
-               } else
-                       __set_irq_handler_unlocked(irq, handle_edge_irq);
-               desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
-               desc->status |= flow_type;
-       }
+       eic_writel(eic, MODE, mode);
+       eic_writel(eic, EDGE, edge);
+       eic_writel(eic, LEVEL, level);
 
-       return ret;
+       irqd_set_trigger_type(d, flow_type);
+       if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               __irq_set_handler_locked(irq, handle_level_irq);
+       else
+               __irq_set_handler_locked(irq, handle_edge_irq);
+
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
 static struct irq_chip eic_chip = {
        .name           = "eic",
-       .ack            = eic_ack_irq,
-       .mask           = eic_mask_irq,
-       .mask_ack       = eic_mask_ack_irq,
-       .unmask         = eic_unmask_irq,
-       .set_type       = eic_set_irq_type,
+       .irq_ack        = eic_ack_irq,
+       .irq_mask       = eic_mask_irq,
+       .irq_mask_ack   = eic_mask_ack_irq,
+       .irq_unmask     = eic_unmask_irq,
+       .irq_set_type   = eic_set_irq_type,
 };
 
 static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct eic *eic = desc->handler_data;
+       struct eic *eic = irq_desc_get_handler_data(desc);
        unsigned long status, pending;
        unsigned int i;
 
@@ -234,13 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
        eic->chip = &eic_chip;
 
        for (i = 0; i < nr_of_irqs; i++) {
-               set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
+               irq_set_chip_and_handler(eic->first_irq + i, &eic_chip,
                                         handle_level_irq);
-               set_irq_chip_data(eic->first_irq + i, eic);
+               irq_set_chip_data(eic->first_irq + i, eic);
        }
 
-       set_irq_chained_handler(int_irq, demux_eic_irq);
-       set_irq_data(int_irq, eic);
+       irq_set_chained_handler(int_irq, demux_eic_irq);
+       irq_set_handler_data(int_irq, eic);
 
        if (pdev->id == 0) {
                nmi_eic = eic;
index 994c4545e2b7ecac3bc50b95db9e871aebf7d8e4..21ce35f33aa5294af0a4ce8bb747be066913ba19 100644 (file)
@@ -34,12 +34,12 @@ extern struct platform_device at32_intc0_device;
  * TODO: We may be able to implement mask/unmask by setting IxM flags
  * in the status register.
  */
-static void intc_mask_irq(unsigned int irq)
+static void intc_mask_irq(struct irq_data *d)
 {
 
 }
 
-static void intc_unmask_irq(unsigned int irq)
+static void intc_unmask_irq(struct irq_data *d)
 {
 
 }
@@ -47,8 +47,8 @@ static void intc_unmask_irq(unsigned int irq)
 static struct intc intc0 = {
        .chip = {
                .name           = "intc",
-               .mask           = intc_mask_irq,
-               .unmask         = intc_unmask_irq,
+               .irq_mask       = intc_mask_irq,
+               .irq_unmask     = intc_unmask_irq,
        },
 };
 
@@ -57,7 +57,6 @@ static struct intc intc0 = {
  */
 asmlinkage void do_IRQ(int level, struct pt_regs *regs)
 {
-       struct irq_desc *desc;
        struct pt_regs *old_regs;
        unsigned int irq;
        unsigned long status_reg;
@@ -69,8 +68,7 @@ asmlinkage void do_IRQ(int level, struct pt_regs *regs)
        irq_enter();
 
        irq = intc_readl(&intc0, INTCAUSE0 - 4 * level);
-       desc = irq_desc + irq;
-       desc->handle_irq(irq, desc);
+       generic_handle_irq(irq);
 
        /*
         * Clear all interrupt level masks so that we may handle
@@ -128,7 +126,7 @@ void __init init_IRQ(void)
                intc_writel(&intc0, INTPR0 + 4 * i, offset);
                readback = intc_readl(&intc0, INTPR0 + 4 * i);
                if (readback == offset)
-                       set_irq_chip_and_handler(i, &intc0.chip,
+                       irq_set_chip_and_handler(i, &intc0.chip,
                                                 handle_simple_irq);
        }
 
index 09a274c9d0b72a5b336478280d4c5d9df5ec2df5..37534103574e5e39eb3bd1b36cea08d0540e80c2 100644 (file)
@@ -249,23 +249,23 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
 /* GPIO IRQ support */
 
-static void gpio_irq_mask(unsigned irq)
+static void gpio_irq_mask(struct irq_data *d)
 {
-       unsigned                gpio = irq_to_gpio(irq);
+       unsigned                gpio = irq_to_gpio(d->irq);
        struct pio_device       *pio = &pio_dev[gpio >> 5];
 
        pio_writel(pio, IDR, 1 << (gpio & 0x1f));
 }
 
-static void gpio_irq_unmask(unsigned irq)
+static void gpio_irq_unmask(struct irq_data *d))
 {
-       unsigned                gpio = irq_to_gpio(irq);
+       unsigned                gpio = irq_to_gpio(d->irq);
        struct pio_device       *pio = &pio_dev[gpio >> 5];
 
        pio_writel(pio, IER, 1 << (gpio & 0x1f));
 }
 
-static int gpio_irq_type(unsigned irq, unsigned type)
+static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
        if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE)
                return -EINVAL;
@@ -275,20 +275,19 @@ static int gpio_irq_type(unsigned irq, unsigned type)
 
 static struct irq_chip gpio_irqchip = {
        .name           = "gpio",
-       .mask           = gpio_irq_mask,
-       .unmask         = gpio_irq_unmask,
-       .set_type       = gpio_irq_type,
+       .irq_mask       = gpio_irq_mask,
+       .irq_unmask     = gpio_irq_unmask,
+       .irq_set_type   = gpio_irq_type,
 };
 
 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct pio_device       *pio = get_irq_chip_data(irq);
+       struct pio_device       *pio = get_irq_desc_chip_data(desc);
        unsigned                gpio_irq;
 
-       gpio_irq = (unsigned) get_irq_data(irq);
+       gpio_irq = (unsigned) irq_get_handler_data(irq);
        for (;;) {
                u32             isr;
-               struct irq_desc *d;
 
                /* ack pending GPIO interrupts */
                isr = pio_readl(pio, ISR) & pio_readl(pio, IMR);
@@ -301,9 +300,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                        isr &= ~(1 << i);
 
                        i += gpio_irq;
-                       d = &irq_desc[i];
-
-                       d->handle_irq(i, d);
+                       generic_handle_irq(i);
                } while (isr);
        }
 }
@@ -313,16 +310,16 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
 {
        unsigned        i;
 
-       set_irq_chip_data(irq, pio);
-       set_irq_data(irq, (void *) gpio_irq);
+       irq_set_chip_data(irq, pio);
+       irq_set_handler_data(irq, (void *)gpio_irq);
 
        for (i = 0; i < 32; i++, gpio_irq++) {
-               set_irq_chip_data(gpio_irq, pio);
-               set_irq_chip_and_handler(gpio_irq, &gpio_irqchip,
-                               handle_simple_irq);
+               irq_set_chip_data(gpio_irq, pio);
+               irq_set_chip_and_handler(gpio_irq, &gpio_irqchip,
+                                        handle_simple_irq);
        }
 
-       set_irq_chained_handler(irq, gpio_irq_handler);
+       irq_set_chained_handler(irq, gpio_irq_handler);
 }
 
 /*--------------------------------------------------------------------------*/
index c09577ddc3c5b1ee9c93fd07ccf160e9b6ceae33..672c21632f2fc8ca5bbc37e266395477a2150af7 100644 (file)
@@ -31,8 +31,10 @@ config BLACKFIN
        select HAVE_OPROFILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_GENERIC_HARDIRQS
+       select GENERIC_ATOMIC64
        select GENERIC_IRQ_PROBE
        select IRQ_PER_CPU if SMP
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
 config GENERIC_CSUM
        def_bool y
@@ -690,13 +692,13 @@ endmenu
 
 
 menu "Blackfin Kernel Optimizations"
-       depends on !SMP
 
 comment "Memory Optimizations"
 
 config I_ENTRY_L1
        bool "Locate interrupt entry code in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, interrupt entry code (STORE/RESTORE CONTEXT) is linked
          into L1 instruction memory. (less latency)
@@ -704,6 +706,7 @@ config I_ENTRY_L1
 config EXCPT_IRQ_SYSC_L1
        bool "Locate entire ASM lowlevel exception / interrupt - Syscall and CPLB handler code in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the entire ASM lowlevel exception and interrupt entry code
          (STORE/RESTORE CONTEXT) is linked into L1 instruction memory.
@@ -712,6 +715,7 @@ config EXCPT_IRQ_SYSC_L1
 config DO_IRQ_L1
        bool "Locate frequently called do_irq dispatcher function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the frequently called do_irq dispatcher function is linked
          into L1 instruction memory. (less latency)
@@ -719,6 +723,7 @@ config DO_IRQ_L1
 config CORE_TIMER_IRQ_L1
        bool "Locate frequently called timer_interrupt() function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the frequently called timer_interrupt() function is linked
          into L1 instruction memory. (less latency)
@@ -726,6 +731,7 @@ config CORE_TIMER_IRQ_L1
 config IDLE_L1
        bool "Locate frequently idle function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the frequently called idle function is linked
          into L1 instruction memory. (less latency)
@@ -733,6 +739,7 @@ config IDLE_L1
 config SCHEDULE_L1
        bool "Locate kernel schedule function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the frequently called kernel schedule is linked
          into L1 instruction memory. (less latency)
@@ -740,6 +747,7 @@ config SCHEDULE_L1
 config ARITHMETIC_OPS_L1
        bool "Locate kernel owned arithmetic functions in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, arithmetic functions are linked
          into L1 instruction memory. (less latency)
@@ -747,6 +755,7 @@ config ARITHMETIC_OPS_L1
 config ACCESS_OK_L1
        bool "Locate access_ok function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the access_ok function is linked
          into L1 instruction memory. (less latency)
@@ -754,6 +763,7 @@ config ACCESS_OK_L1
 config MEMSET_L1
        bool "Locate memset function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the memset function is linked
          into L1 instruction memory. (less latency)
@@ -761,6 +771,7 @@ config MEMSET_L1
 config MEMCPY_L1
        bool "Locate memcpy function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the memcpy function is linked
          into L1 instruction memory. (less latency)
@@ -768,6 +779,7 @@ config MEMCPY_L1
 config STRCMP_L1
        bool "locate strcmp function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the strcmp function is linked
          into L1 instruction memory (less latency).
@@ -775,6 +787,7 @@ config STRCMP_L1
 config STRNCMP_L1
        bool "locate strncmp function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the strncmp function is linked
          into L1 instruction memory (less latency).
@@ -782,6 +795,7 @@ config STRNCMP_L1
 config STRCPY_L1
        bool "locate strcpy function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the strcpy function is linked
          into L1 instruction memory (less latency).
@@ -789,6 +803,7 @@ config STRCPY_L1
 config STRNCPY_L1
        bool "locate strncpy function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, the strncpy function is linked
          into L1 instruction memory (less latency).
@@ -796,6 +811,7 @@ config STRNCPY_L1
 config SYS_BFIN_SPINLOCK_L1
        bool "Locate sys_bfin_spinlock function in L1 Memory"
        default y
+       depends on !SMP
        help
          If enabled, sys_bfin_spinlock function is linked
          into L1 instruction memory. (less latency)
@@ -803,6 +819,7 @@ config SYS_BFIN_SPINLOCK_L1
 config IP_CHECKSUM_L1
        bool "Locate IP Checksum function in L1 Memory"
        default n
+       depends on !SMP
        help
          If enabled, the IP Checksum function is linked
          into L1 instruction memory. (less latency)
@@ -811,7 +828,7 @@ config CACHELINE_ALIGNED_L1
        bool "Locate cacheline_aligned data to L1 Data Memory"
        default y if !BF54x
        default n if BF54x
-       depends on !BF531
+       depends on !SMP && !BF531
        help
          If enabled, cacheline_aligned data is linked
          into L1 data memory. (less latency)
@@ -819,7 +836,7 @@ config CACHELINE_ALIGNED_L1
 config SYSCALL_TAB_L1
        bool "Locate Syscall Table L1 Data Memory"
        default n
-       depends on !BF531
+       depends on !SMP && !BF531
        help
          If enabled, the Syscall LUT is linked
          into L1 data memory. (less latency)
@@ -827,16 +844,16 @@ config SYSCALL_TAB_L1
 config CPLB_SWITCH_TAB_L1
        bool "Locate CPLB Switch Tables L1 Data Memory"
        default n
-       depends on !BF531
+       depends on !SMP && !BF531
        help
          If enabled, the CPLB Switch Tables are linked
          into L1 data memory. (less latency)
 
-config CACHE_FLUSH_L1
-       bool "Locate cache flush funcs in L1 Inst Memory"
+config ICACHE_FLUSH_L1
+       bool "Locate icache flush funcs in L1 Inst Memory"
        default y
        help
-         If enabled, the Blackfin cache flushing functions are linked
+         If enabled, the Blackfin icache flushing functions are linked
          into L1 instruction memory.
 
          Note that this might be required to address anomalies, but
@@ -844,9 +861,18 @@ config CACHE_FLUSH_L1
          If you are using a processor affected by an anomaly, the build
          system will double check for you and prevent it.
 
+config DCACHE_FLUSH_L1
+       bool "Locate dcache flush funcs in L1 Inst Memory"
+       default y
+       depends on !SMP
+       help
+         If enabled, the Blackfin dcache flushing functions are linked
+         into L1 instruction memory.
+
 config APP_STACK_L1
        bool "Support locating application stack in L1 Scratch Memory"
        default y
+       depends on !SMP
        help
          If enabled the application stack can be located in L1
          scratch memory (less latency).
@@ -856,7 +882,7 @@ config APP_STACK_L1
 config EXCEPTION_L1_SCRATCH
        bool "Locate exception stack in L1 Scratch Memory"
        default n
-       depends on !APP_STACK_L1
+       depends on !SMP && !APP_STACK_L1
        help
          Whenever an exception occurs, use the L1 Scratch memory for
          stack storage.  You cannot place the stacks of FLAT binaries
@@ -868,6 +894,7 @@ comment "Speed Optimizations"
 config BFIN_INS_LOWOVERHEAD
        bool "ins[bwl] low overhead, higher interrupt latency"
        default y
+       depends on !SMP
        help
          Reads on the Blackfin are speculative. In Blackfin terms, this means
          they can be interrupted at any time (even after they have been issued
index db8d38a12a9aeb79522ddbbb819514ec0b6c97f0..5edcb58d6f737f49a69a8dcf9784c2c2935e1dea 100644 (file)
@@ -115,6 +115,7 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 3e50d7857c2725bc05dcffaa0ffcab3212b9e10d..2e549572d4f59c5ff73ab137c56fd13a4b312dd2 100644 (file)
@@ -153,6 +153,7 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
index 023ff0df2692c2d2146908fe9d1ce391b83141c8..95cf2ba9de17ba2e95337efc8de0d14f3a21e754 100644 (file)
@@ -183,5 +183,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 4e5a121b3c563b9a9b42479c6164614e9e67bd3f..8be8e33fac526c7eb6526f39ce9f44c7a1521ab9 100644 (file)
@@ -175,5 +175,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 9f8fc84e4ac949be9b8c3b1105626bb5d8b5b3c6..a7eb54bf3089916359b3f178a3e26fc5980df1be 100644 (file)
@@ -108,5 +108,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index ccc432b722a0746681945133699484ec89b31615..0aafde6c8c2d00fd079c62999fb60cf7023dcc87 100644 (file)
@@ -122,5 +122,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 566695472a8486148ca1d230aa59567a770a6ba6..c9077fb581354bc621fe5e1ee152e9ae1933a56a 100644 (file)
@@ -133,5 +133,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index ac22124ccb6cc0515c9ac31317f32f25e04e6e90..6883803e6ca8902addc92ef80688bfd1aeac786a 100644 (file)
@@ -131,5 +131,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 944404b6ff08ad723cce862bb22815be4bb1b555..56151b5dbc4446e4f5710ec8ca263d48fe0fcba2 100644 (file)
@@ -205,5 +205,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 7e67ba31e9919655eb833e259ed970bd707b3e81..f5ed34e12e0ca9928e3b7b1a9bcbd339a076e6bd 100644 (file)
@@ -109,5 +109,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 141e5933e1aaf7f2be33a4617f43e7257288320e..1c0a82a105919aaf1b6523cd0d8afe8114e0c4ae 100644 (file)
@@ -111,5 +111,6 @@ CONFIG_DEBUG_DOUBLEFAULT=y
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
+CONFIG_BFIN_PSEUDODBG_INSNS=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index d27c6274247df5e74612c18d25ba8647adfe386d..e48508957160b2053001008dc01d86e6fcd1e59c 100644 (file)
@@ -121,4 +121,6 @@ static inline int atomic_test_mask(int mask, atomic_t *v)
 
 #endif
 
+#include <asm-generic/atomic64.h>
+
 #endif
index 29f4fd8861748892cb1192860519f0e6355c8e97..49762c6bb0d56f549f090fd98216ababccc75045 100644 (file)
@@ -25,9 +25,8 @@
 #include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #ifndef CONFIG_SMP
 #include <linux/irqflags.h>
index e3f0f4c49819e4a0d3823d6344f71fbf61a2ffc6..7600fe0696af1c9cda33471b1bf8a963e43df303 100644 (file)
     ({ BUG(); 0; }); \
 })
 #define bfin_write(addr, val) \
-({ \
+do { \
        switch (sizeof(*(addr))) { \
        case 1: bfin_write8(addr, val);  break; \
        case 2: bfin_write16(addr, val); break; \
        case 4: bfin_write32(addr, val); break; \
        default: BUG(); \
        } \
-})
+} while (0)
+
+#define bfin_write_or(addr, bits) \
+do { \
+       void *__addr = (void *)(addr); \
+       bfin_write(__addr, bfin_read(__addr) | (bits)); \
+} while (0)
+
+#define bfin_write_and(addr, bits) \
+do { \
+       void *__addr = (void *)(addr); \
+       bfin_write(__addr, bfin_read(__addr) & (bits)); \
+} while (0)
 
 #endif /* __ASSEMBLY__ */
 
index 3047120cfcff4b5ce9a7e8bca467a6df820f4aef..edf2a2ad518313883ff26cb8fc49168a1d4db669 100644 (file)
@@ -125,6 +125,9 @@ void unset_dram_srfs(void);
 
 #define VRPAIR(vlev, freq) (((vlev) << 16) | ((freq) >> 16))
 
+#ifdef CONFIG_CPU_FREQ
+#define CPUFREQ_CPU 0
+#endif
 struct bfin_dpmc_platform_data {
        const unsigned int *tuple_tab;
        unsigned short tabsize;
index 40f94a704c0202ace94e99429d7b67cb241d40f1..9e0cc0e2534f67376769410059b6fe76bf00600e 100644 (file)
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 #include <asm/traps.h>
+#include <asm/bitsperlong.h>
 
-#define IPIPE_ARCH_STRING     "1.12-00"
+#define IPIPE_ARCH_STRING     "1.16-01"
 #define IPIPE_MAJOR_NUMBER    1
-#define IPIPE_MINOR_NUMBER    12
-#define IPIPE_PATCH_NUMBER    0
+#define IPIPE_MINOR_NUMBER    16
+#define IPIPE_PATCH_NUMBER    1
 
 #ifdef CONFIG_SMP
 #error "I-pipe/blackfin: SMP not implemented"
@@ -55,25 +56,19 @@ do {                                                \
 #define task_hijacked(p)                                               \
        ({                                                              \
                int __x__ = __ipipe_root_domain_p;                      \
-               __clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
                if (__x__)                                              \
-                       hard_local_irq_enable();                                \
+                       hard_local_irq_enable();                        \
                !__x__;                                                 \
        })
 
 struct ipipe_domain;
 
 struct ipipe_sysinfo {
-
-       int ncpus;              /* Number of CPUs on board */
-       u64 cpufreq;            /* CPU frequency (in Hz) */
-
-       /* Arch-dependent block */
-
-       struct {
-               unsigned tmirq; /* Timer tick IRQ */
-               u64 tmfreq;     /* Timer frequency */
-       } archdep;
+       int sys_nr_cpus;        /* Number of CPUs on board */
+       int sys_hrtimer_irq;    /* hrtimer device IRQ */
+       u64 sys_hrtimer_freq;   /* hrtimer device frequency */
+       u64 sys_hrclock_freq;   /* hrclock device frequency */
+       u64 sys_cpu_freq;       /* CPU frequency (Hz) */
 };
 
 #define ipipe_read_tsc(t)                                      \
@@ -115,9 +110,19 @@ void __ipipe_enable_irqdesc(struct ipipe_domain *ipd,
 void __ipipe_disable_irqdesc(struct ipipe_domain *ipd,
                             unsigned irq);
 
-#define __ipipe_enable_irq(irq)                (irq_desc[irq].chip->unmask(irq))
+#define __ipipe_enable_irq(irq)                                                \
+       do {                                                            \
+               struct irq_desc *desc = irq_to_desc(irq);               \
+               struct irq_chip *chip = get_irq_desc_chip(desc);        \
+               chip->irq_unmask(&desc->irq_data);                      \
+       } while (0)
 
-#define __ipipe_disable_irq(irq)       (irq_desc[irq].chip->mask(irq))
+#define __ipipe_disable_irq(irq)                                       \
+       do {                                                            \
+               struct irq_desc *desc = irq_to_desc(irq);               \
+               struct irq_chip *chip = get_irq_desc_chip(desc);        \
+               chip->irq_mask(&desc->irq_data);                        \
+       } while (0)
 
 static inline int __ipipe_check_tickdev(const char *devname)
 {
@@ -128,12 +133,11 @@ void __ipipe_enable_pipeline(void);
 
 #define __ipipe_hook_critical_ipi(ipd) do { } while (0)
 
-#define __ipipe_sync_pipeline  ___ipipe_sync_pipeline
-void ___ipipe_sync_pipeline(unsigned long syncmask);
+void ___ipipe_sync_pipeline(void);
 
 void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs);
 
-int __ipipe_get_irq_priority(unsigned irq);
+int __ipipe_get_irq_priority(unsigned int irq);
 
 void __ipipe_serial_debug(const char *fmt, ...);
 
@@ -152,7 +156,10 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
        return ffs(ul) - 1;
 }
 
-#define __ipipe_run_irqtail()  /* Must be a macro */                   \
+#define __ipipe_do_root_xirq(ipd, irq)                                 \
+       ((ipd)->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)))
+
+#define __ipipe_run_irqtail(irq)  /* Must be a macro */                        \
        do {                                                            \
                unsigned long __pending;                                \
                CSYNC();                                                \
@@ -164,42 +171,8 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
                }                                                       \
        } while (0)
 
-#define __ipipe_run_isr(ipd, irq)                                      \
-       do {                                                            \
-               if (!__ipipe_pipeline_head_p(ipd))                      \
-                       hard_local_irq_enable();                                \
-               if (ipd == ipipe_root_domain) {                         \
-                       if (unlikely(ipipe_virtual_irq_p(irq))) {       \
-                               irq_enter();                            \
-                               ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
-                               irq_exit();                             \
-                       } else                                          \
-                               ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \
-               } else {                                                \
-                       __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
-                       ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
-                       /* Attempt to exit the outer interrupt level before \
-                        * starting the deferred IRQ processing. */     \
-                       __ipipe_run_irqtail();                          \
-                       __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
-               }                                                       \
-               hard_local_irq_disable();                                       \
-       } while (0)
-
 #define __ipipe_syscall_watched_p(p, sc)       \
-       (((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= NR_syscalls)
-
-void ipipe_init_irq_threads(void);
-
-int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);
-
-#ifdef CONFIG_TICKSOURCE_CORETMR
-#define IRQ_SYSTMR             IRQ_CORETMR
-#define IRQ_PRIOTMR            IRQ_CORETMR
-#else
-#define IRQ_SYSTMR             IRQ_TIMER0
-#define IRQ_PRIOTMR            CONFIG_IRQ_TIMER0
-#endif
+       (ipipe_notifier_enabled_p(p) || (unsigned long)sc >= NR_syscalls)
 
 #ifdef CONFIG_BF561
 #define bfin_write_TIMER_DISABLE(val)  bfin_write_TMRS8_DISABLE(val)
@@ -219,11 +192,11 @@ int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);
 
 #define task_hijacked(p)               0
 #define ipipe_trap_notify(t, r)        0
+#define __ipipe_root_tick_p(regs)      1
 
-#define ipipe_init_irq_threads()               do { } while (0)
-#define ipipe_start_irq_thread(irq, desc)      0
+#endif /* !CONFIG_IPIPE */
 
-#ifndef CONFIG_TICKSOURCE_GPTMR0
+#ifdef CONFIG_TICKSOURCE_CORETMR
 #define IRQ_SYSTMR             IRQ_CORETMR
 #define IRQ_PRIOTMR            IRQ_CORETMR
 #else
@@ -231,10 +204,6 @@ int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc);
 #define IRQ_PRIOTMR            CONFIG_IRQ_TIMER0
 #endif
 
-#define __ipipe_root_tick_p(regs)      1
-
-#endif /* !CONFIG_IPIPE */
-
 #define ipipe_update_tick_evtdev(evtdev)       do { } while (0)
 
 #endif /* !__ASM_BLACKFIN_IPIPE_H */
index 00409201d9edc7d69a225562caef7582e636d447..84a4ffd367475ef9c2cd32ab54f242844100fb12 100644 (file)
 
 #ifdef CONFIG_IPIPE
 
+#include <asm/bitsperlong.h>
+#include <mach/irq.h>
+
 #define IPIPE_NR_XIRQS         NR_IRQS
-#define IPIPE_IRQ_ISHIFT       5       /* 2^5 for 32bits arch. */
 
 /* Blackfin-specific, per-cpu pipeline status */
 #define IPIPE_SYNCDEFER_FLAG   15
 #define IPIPE_EVENT_INIT       (IPIPE_FIRST_EVENT + 4)
 #define IPIPE_EVENT_EXIT       (IPIPE_FIRST_EVENT + 5)
 #define IPIPE_EVENT_CLEANUP    (IPIPE_FIRST_EVENT + 6)
-#define IPIPE_LAST_EVENT       IPIPE_EVENT_CLEANUP
+#define IPIPE_EVENT_RETURN     (IPIPE_FIRST_EVENT + 7)
+#define IPIPE_LAST_EVENT       IPIPE_EVENT_RETURN
 #define IPIPE_NR_EVENTS                (IPIPE_LAST_EVENT + 1)
 
 #define IPIPE_TIMER_IRQ                IRQ_CORETMR
 
+#define __IPIPE_FEATURE_SYSINFO_V2     1
+
 #ifndef __ASSEMBLY__
 
 extern unsigned long __ipipe_root_status; /* Alias to ipipe_root_cpudom_var(status) */
@@ -63,6 +68,8 @@ void __ipipe_unlock_root(void);
 
 #endif /* !__ASSEMBLY__ */
 
+#define __IPIPE_FEATURE_SYSINFO_V2     1
+
 #endif /* CONFIG_IPIPE */
 
 #endif /* !__ASM_BLACKFIN_IPIPE_BASE_H */
index 3365cb97f539a7ede6d2a6e225b2ec69b579b4b6..b4bbb75a9e15a2483358a59599ca0eb677defc73 100644 (file)
@@ -89,15 +89,33 @@ static inline void __hard_local_irq_restore(unsigned long flags)
 #ifdef CONFIG_IPIPE
 
 #include <linux/compiler.h>
-#include <linux/ipipe_base.h>
 #include <linux/ipipe_trace.h>
+/*
+ * Way too many inter-deps between low-level headers in this port, so
+ * we redeclare the required bits we cannot pick from
+ * <asm/ipipe_base.h> to prevent circular dependencies.
+ */
+void __ipipe_stall_root(void);
+void __ipipe_unstall_root(void);
+unsigned long __ipipe_test_root(void);
+unsigned long __ipipe_test_and_stall_root(void);
+void __ipipe_restore_root(unsigned long flags);
+
+#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
+struct ipipe_domain;
+extern struct ipipe_domain ipipe_root;
+void ipipe_check_context(struct ipipe_domain *ipd);
+#define __check_irqop_context(ipd)  ipipe_check_context(&ipipe_root)
+#else /* !CONFIG_IPIPE_DEBUG_CONTEXT */
+#define __check_irqop_context(ipd)  do { } while (0)
+#endif /* !CONFIG_IPIPE_DEBUG_CONTEXT */
 
 /*
  * Interrupt pipe interface to linux/irqflags.h.
  */
 static inline void arch_local_irq_disable(void)
 {
-       ipipe_check_context(ipipe_root_domain);
+       __check_irqop_context();
        __ipipe_stall_root();
        barrier();
 }
@@ -105,7 +123,7 @@ static inline void arch_local_irq_disable(void)
 static inline void arch_local_irq_enable(void)
 {
        barrier();
-       ipipe_check_context(ipipe_root_domain);
+       __check_irqop_context();
        __ipipe_unstall_root();
 }
 
@@ -119,16 +137,21 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
        return flags == bfin_no_irqs;
 }
 
-static inline void arch_local_irq_save_ptr(unsigned long *_flags)
+static inline unsigned long arch_local_irq_save(void)
 {
-       x = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags;
+       unsigned long flags;
+
+       __check_irqop_context();
+       flags = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags;
        barrier();
+
+       return flags;
 }
 
-static inline unsigned long arch_local_irq_save(void)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
-       ipipe_check_context(ipipe_root_domain);
-       return __hard_local_irq_save();
+       __check_irqop_context();
+       __ipipe_restore_root(flags == bfin_no_irqs);
 }
 
 static inline unsigned long arch_mangle_irq_bits(int virt, unsigned long real)
@@ -192,7 +215,10 @@ static inline void hard_local_irq_restore(unsigned long flags)
 # define hard_local_irq_restore(flags) __hard_local_irq_restore(flags)
 #endif /* !CONFIG_IPIPE_TRACE_IRQSOFF */
 
-#else /* CONFIG_IPIPE */
+#define hard_local_irq_save_cond()             hard_local_irq_save()
+#define hard_local_irq_restore_cond(flags)     hard_local_irq_restore(flags)
+
+#else /* !CONFIG_IPIPE */
 
 /*
  * Direct interface to linux/irqflags.h.
@@ -212,7 +238,48 @@ static inline void hard_local_irq_restore(unsigned long flags)
 #define hard_local_irq_restore(flags)  __hard_local_irq_restore(flags)
 #define hard_local_irq_enable()                __hard_local_irq_enable()
 #define hard_local_irq_disable()       __hard_local_irq_disable()
-
+#define hard_local_irq_save_cond()             hard_local_save_flags()
+#define hard_local_irq_restore_cond(flags)     do { (void)(flags); } while (0)
 
 #endif /* !CONFIG_IPIPE */
+
+#ifdef CONFIG_SMP
+#define hard_local_irq_save_smp()              hard_local_irq_save()
+#define hard_local_irq_restore_smp(flags)      hard_local_irq_restore(flags)
+#else
+#define hard_local_irq_save_smp()              hard_local_save_flags()
+#define hard_local_irq_restore_smp(flags)      do { (void)(flags); } while (0)
+#endif
+
+/*
+ * Remap the arch-neutral IRQ state manipulation macros to the
+ * blackfin-specific hard_local_irq_* API.
+ */
+#define local_irq_save_hw(flags)                       \
+       do {                                            \
+               (flags) = hard_local_irq_save();        \
+       } while (0)
+#define local_irq_restore_hw(flags)            \
+       do {                                    \
+               hard_local_irq_restore(flags);  \
+       } while (0)
+#define local_irq_disable_hw()                 \
+       do {                                    \
+               hard_local_irq_disable();       \
+       } while (0)
+#define local_irq_enable_hw()                  \
+       do {                                    \
+               hard_local_irq_enable();        \
+       } while (0)
+#define local_irq_save_hw_notrace(flags)               \
+       do {                                            \
+               (flags) = __hard_local_irq_save();      \
+       } while (0)
+#define local_irq_restore_hw_notrace(flags)            \
+       do {                                            \
+               __hard_local_irq_restore(flags);        \
+       } while (0)
+
+#define irqs_disabled_hw()     hard_irqs_disabled()
+
 #endif
index f5b537967116d151c828eac66b2166b3d5f179eb..af6c0aa79bae9435ea5dff4f92f2c945051352aa 100644 (file)
 
 #define raw_smp_processor_id()  blackfin_core_id()
 
-extern char coreb_trampoline_start, coreb_trampoline_end;
+extern void bfin_relocate_coreb_l1_mem(void);
+
+#if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1)
+asmlinkage void blackfin_icache_flush_range_l1(unsigned long *ptr);
+extern unsigned long blackfin_iflush_l1_entry[NR_CPUS];
+#endif
 
 struct corelock_slot {
        int lock;
@@ -34,7 +39,7 @@ extern unsigned long dcache_invld_count[NR_CPUS];
 void smp_icache_flush_range_others(unsigned long start,
                                   unsigned long end);
 #ifdef CONFIG_HOTPLUG_CPU
-void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
+void coreb_die(void);
 void cpu_die(void);
 void platform_cpu_die(void);
 int __cpu_disable(void);
index 928ae975b87e20f978c6a29244093273623e1f78..ff9a9f35d50b0d53c09fda181041050f01224962 100644 (file)
 #define __NR_fanotify_mark     372
 #define __NR_prlimit64         373
 #define __NR_cacheflush                374
+#define __NR_name_to_handle_at 375
+#define __NR_open_by_handle_at 376
+#define __NR_clock_adjtime     377
+#define __NR_syncfs            378
 
-#define __NR_syscall           375
+#define __NR_syscall           379
 #define NR_syscalls            __NR_syscall
 
 /* Old optional stuff no one actually uses */
index 1e485dfdc9f2133a37d1d7d8b81af47b6bf53814..6ce8dce753c9a49039a615e56cf8e83fbb8097bf 100644 (file)
@@ -84,6 +84,24 @@ static int __init proc_dma_init(void)
 late_initcall(proc_dma_init);
 #endif
 
+static void set_dma_peripheral_map(unsigned int channel, const char *device_id)
+{
+#ifdef CONFIG_BF54x
+       unsigned int per_map;
+
+       switch (channel) {
+               case CH_UART2_RX: per_map = 0xC << 12; break;
+               case CH_UART2_TX: per_map = 0xD << 12; break;
+               case CH_UART3_RX: per_map = 0xE << 12; break;
+               case CH_UART3_TX: per_map = 0xF << 12; break;
+               default:          return;
+       }
+
+       if (strncmp(device_id, "BFIN_UART", 9) == 0)
+               dma_ch[channel].regs->peripheral_map = per_map;
+#endif
+}
+
 /**
  *     request_dma - request a DMA channel
  *
@@ -111,19 +129,7 @@ int request_dma(unsigned int channel, const char *device_id)
                return -EBUSY;
        }
 
-#ifdef CONFIG_BF54x
-       if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-               unsigned int per_map;
-               per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
-               if (strncmp(device_id, "BFIN_UART", 9) == 0)
-                       dma_ch[channel].regs->peripheral_map = per_map |
-                               ((channel - CH_UART2_RX + 0xC)<<12);
-               else
-                       dma_ch[channel].regs->peripheral_map = per_map |
-                               ((channel - CH_UART2_RX + 0x6)<<12);
-       }
-#endif
-
+       set_dma_peripheral_map(channel, device_id);
        dma_ch[channel].device_id = device_id;
        dma_ch[channel].irq = 0;
 
index 3b1da4aff2a1ed560f2c7041d85ccdf571f4972e..f37019c847c9b643c04676d0a2423f870286f16c 100644 (file)
@@ -154,7 +154,7 @@ void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs)
         * pending for it.
         */
        if (test_bit(IPIPE_AHEAD_FLAG, &this_domain->flags) &&
-           ipipe_head_cpudom_var(irqpend_himask) == 0)
+           !__ipipe_ipending_p(ipipe_head_cpudom_ptr()))
                goto out;
 
        __ipipe_walk_pipeline(head);
@@ -185,25 +185,21 @@ void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq)
 }
 EXPORT_SYMBOL(__ipipe_disable_irqdesc);
 
-int __ipipe_syscall_root(struct pt_regs *regs)
+asmlinkage int __ipipe_syscall_root(struct pt_regs *regs)
 {
        struct ipipe_percpu_domain_data *p;
-       unsigned long flags;
+       void (*hook)(void);
        int ret;
 
+       WARN_ON_ONCE(irqs_disabled_hw());
+
        /*
-        * We need to run the IRQ tail hook whenever we don't
-        * propagate a syscall to higher domains, because we know that
-        * important operations might be pending there (e.g. Xenomai
-        * deferred rescheduling).
+        * We need to run the IRQ tail hook each time we intercept a
+        * syscall, because we know that important operations might be
+        * pending there (e.g. Xenomai deferred rescheduling).
         */
-
-       if (regs->orig_p0 < NR_syscalls) {
-               void (*hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
-               hook();
-               if ((current->flags & PF_EVNOTIFY) == 0)
-                       return 0;
-       }
+       hook = (__typeof__(hook))__ipipe_irq_tail_hook;
+       hook();
 
        /*
         * This routine either returns:
@@ -214,51 +210,47 @@ int __ipipe_syscall_root(struct pt_regs *regs)
         * tail work has to be performed (for handling signals etc).
         */
 
-       if (!__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
+       if (!__ipipe_syscall_watched_p(current, regs->orig_p0) ||
+           !__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
                return 0;
 
        ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
 
-       flags = hard_local_irq_save();
+       hard_local_irq_disable();
 
-       if (!__ipipe_root_domain_p) {
-               hard_local_irq_restore(flags);
-               return 1;
+       /*
+        * This is the end of the syscall path, so we may
+        * safely assume a valid Linux task stack here.
+        */
+       if (current->ipipe_flags & PF_EVTRET) {
+               current->ipipe_flags &= ~PF_EVTRET;
+               __ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs);
        }
 
-       p = ipipe_root_cpudom_ptr();
-       if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
-               __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+       if (!__ipipe_root_domain_p)
+               ret = -1;
+       else {
+               p = ipipe_root_cpudom_ptr();
+               if (__ipipe_ipending_p(p))
+                       __ipipe_sync_pipeline();
+       }
 
-       hard_local_irq_restore(flags);
+       hard_local_irq_enable();
 
        return -ret;
 }
 
-unsigned long ipipe_critical_enter(void (*syncfn) (void))
-{
-       unsigned long flags;
-
-       flags = hard_local_irq_save();
-
-       return flags;
-}
-
-void ipipe_critical_exit(unsigned long flags)
-{
-       hard_local_irq_restore(flags);
-}
-
 static void __ipipe_no_irqtail(void)
 {
 }
 
 int ipipe_get_sysinfo(struct ipipe_sysinfo *info)
 {
-       info->ncpus = num_online_cpus();
-       info->cpufreq = ipipe_cpu_freq();
-       info->archdep.tmirq = IPIPE_TIMER_IRQ;
-       info->archdep.tmfreq = info->cpufreq;
+       info->sys_nr_cpus = num_online_cpus();
+       info->sys_cpu_freq = ipipe_cpu_freq();
+       info->sys_hrtimer_irq = IPIPE_TIMER_IRQ;
+       info->sys_hrtimer_freq = __ipipe_core_clock;
+       info->sys_hrclock_freq = __ipipe_core_clock;
 
        return 0;
 }
@@ -289,6 +281,7 @@ int ipipe_trigger_irq(unsigned irq)
 asmlinkage void __ipipe_sync_root(void)
 {
        void (*irq_tail_hook)(void) = (void (*)(void))__ipipe_irq_tail_hook;
+       struct ipipe_percpu_domain_data *p;
        unsigned long flags;
 
        BUG_ON(irqs_disabled());
@@ -300,19 +293,20 @@ asmlinkage void __ipipe_sync_root(void)
 
        clear_thread_flag(TIF_IRQ_SYNC);
 
-       if (ipipe_root_cpudom_var(irqpend_himask) != 0)
-               __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
+       p = ipipe_root_cpudom_ptr();
+       if (__ipipe_ipending_p(p))
+               __ipipe_sync_pipeline();
 
        hard_local_irq_restore(flags);
 }
 
-void ___ipipe_sync_pipeline(unsigned long syncmask)
+void ___ipipe_sync_pipeline(void)
 {
        if (__ipipe_root_domain_p &&
            test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status)))
                return;
 
-       __ipipe_sync_stage(syncmask);
+       __ipipe_sync_stage();
 }
 
 void __ipipe_disable_root_irqs_hw(void)
index 64cff54a8a58c488175b4fde8f88037107bc6c68..8f079392aff07796ac1cc46edef17ba829649b10 100644 (file)
@@ -39,21 +39,23 @@ int show_interrupts(struct seq_file *p, void *v)
        unsigned long flags;
 
        if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
+               struct irq_desc *desc = irq_to_desc(i);
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+               action = desc->action;
                if (!action)
                        goto skip;
                seq_printf(p, "%3d: ", i);
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-               seq_printf(p, " %8s", irq_desc[i].chip->name);
+               seq_printf(p, " %8s", get_irq_desc_chip(desc)->name);
                seq_printf(p, "  %s", action->name);
                for (action = action->next; action; action = action->next)
                        seq_printf(p, "  %s", action->name);
 
                seq_putc(p, '\n');
  skip:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
        } else if (i == NR_IRQS) {
                seq_printf(p, "NMI: ");
                for_each_online_cpu(j)
index eb92592fd80ccb4beddb6ee828179c05f03d3d90..b8cfe34989e4e01fdcb4bff88fe992d950ef347f 100644 (file)
@@ -422,11 +422,7 @@ int kgdb_arch_handle_exception(int vector, int signo,
 
 struct kgdb_arch arch_kgdb_ops = {
        .gdb_bpt_instr = {0xa1},
-#ifdef CONFIG_SMP
-       .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP,
-#else
        .flags = KGDB_HW_BREAKPOINT,
-#endif
        .set_hw_breakpoint = bfin_set_hw_break,
        .remove_hw_breakpoint = bfin_remove_hw_break,
        .disable_hw_break = bfin_disable_hw_debug,
index ac71dc15cbdb501d82e6c7fe1301ae738f444368..805c6132c7796b26a632c85df14b8a58d508e1de 100644 (file)
@@ -215,11 +215,48 @@ void __init bfin_relocate_l1_mem(void)
 
        early_dma_memcpy_done();
 
+#if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1)
+       blackfin_iflush_l1_entry[0] = (unsigned long)blackfin_icache_flush_range_l1;
+#endif
+
        /* if necessary, copy L2 text/data to L2 SRAM */
        if (L2_LENGTH && l2_len)
                memcpy(_stext_l2, _l2_lma, l2_len);
 }
 
+#ifdef CONFIG_SMP
+void __init bfin_relocate_coreb_l1_mem(void)
+{
+       unsigned long text_l1_len = (unsigned long)_text_l1_len;
+       unsigned long data_l1_len = (unsigned long)_data_l1_len;
+       unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len;
+
+       blackfin_dma_early_init();
+
+       /* if necessary, copy L1 text to L1 instruction SRAM */
+       if (L1_CODE_LENGTH && text_l1_len)
+               early_dma_memcpy((void *)COREB_L1_CODE_START, _text_l1_lma,
+                               text_l1_len);
+
+       /* if necessary, copy L1 data to L1 data bank A SRAM */
+       if (L1_DATA_A_LENGTH && data_l1_len)
+               early_dma_memcpy((void *)COREB_L1_DATA_A_START, _data_l1_lma,
+                               data_l1_len);
+
+       /* if necessary, copy L1 data B to L1 data bank B SRAM */
+       if (L1_DATA_B_LENGTH && data_b_l1_len)
+               early_dma_memcpy((void *)COREB_L1_DATA_B_START, _data_b_l1_lma,
+                               data_b_l1_len);
+
+       early_dma_memcpy_done();
+
+#ifdef CONFIG_ICACHE_FLUSH_L1
+       blackfin_iflush_l1_entry[1] = (unsigned long)blackfin_icache_flush_range_l1 -
+                       (unsigned long)_stext_l1 + COREB_L1_CODE_START;
+#endif
+}
+#endif
+
 #ifdef CONFIG_ROMKERNEL
 void __init bfin_relocate_xip_data(void)
 {
index c40d07f708e8daabebcecd09fffc960f646dfaab..854fa49f1c3ec964f7f105fd9c0019d133cca420 100644 (file)
@@ -136,7 +136,7 @@ SECTIONS
 
        . = ALIGN(16);
        INIT_DATA_SECTION(16)
-       PERCPU(32, 4)
+       PERCPU(32, PAGE_SIZE)
 
        .exit.data :
        {
@@ -176,6 +176,7 @@ SECTIONS
        {
                . = ALIGN(4);
                __stext_l1 = .;
+               *(.l1.text.head)
                *(.l1.text)
 #ifdef CONFIG_SCHEDULE_L1
                SCHED_TEXT
index 27285823fb252613a1886ea71b48ee07ba200dab..cb1172f5075729994a12c27680b881fba226cffe 100644 (file)
 #define        PGTE_PPI                0x0000                  /*              Enable PPI D15:13                       */
 #define        PGTE_SPORT              0x0800                  /*              Enable DT1PRI/TFS1/TSCLK1       */
 
-
-/*  ******************  HANDSHAKE DMA (HDMA) MASKS  *********************/
-/* HDMAx_CTL Masks                                                                                                             */
-#define        HMDMAEN         0x0001  /* Enable Handshake DMA 0/1                                     */
-#define        REP                     0x0002  /* HDMA Request Polarity                                        */
-#define        UTE                     0x0004  /* Urgency Threshold Enable                                     */
-#define        OIE                     0x0010  /* Overflow Interrupt Enable                            */
-#define        BDIE            0x0020  /* Block Done Interrupt Enable                          */
-#define        MBDI            0x0040  /* Mask Block Done IRQ If Pending ECNT          */
-#define        DRQ                     0x0300  /* HDMA Request Type                                            */
-#define        DRQ_NONE        0x0000  /*              No Request                                                      */
-#define        DRQ_SINGLE      0x0100  /*              Channels Request Single                         */
-#define        DRQ_MULTI       0x0200  /*              Channels Request Multi (Default)        */
-#define        DRQ_URGENT      0x0300  /*              Channels Request Multi Urgent           */
-#define        RBC                     0x1000  /* Reload BCNT With IBCNT                                       */
-#define        PS                      0x2000  /* HDMA Pin Status                                                      */
-#define        OI                      0x4000  /* Overflow Interrupt Generated                         */
-#define        BDI                     0x8000  /* Block Done Interrupt Generated                       */
-
 /* entry addresses of the user-callable Boot ROM functions */
 
 #define _BOOTROM_RESET 0xEF000000
index 89f5420ee6cd35592b92c33729ef56560778e0b2..84ef11e52644cea94f70ca235a8b2888cdf0859d 100644 (file)
 #define        PGTE_PPI                0x0000                  /*              Enable PPI D15:13                       */
 #define        PGTE_SPORT              0x0800                  /*              Enable DT1PRI/TFS1/TSCLK1       */
 
-
-/*  ******************  HANDSHAKE DMA (HDMA) MASKS  *********************/
-/* HDMAx_CTL Masks                                                                                                             */
-#define        HMDMAEN         0x0001  /* Enable Handshake DMA 0/1                                     */
-#define        REP                     0x0002  /* HDMA Request Polarity                                        */
-#define        UTE                     0x0004  /* Urgency Threshold Enable                                     */
-#define        OIE                     0x0010  /* Overflow Interrupt Enable                            */
-#define        BDIE            0x0020  /* Block Done Interrupt Enable                          */
-#define        MBDI            0x0040  /* Mask Block Done IRQ If Pending ECNT          */
-#define        DRQ                     0x0300  /* HDMA Request Type                                            */
-#define        DRQ_NONE        0x0000  /*              No Request                                                      */
-#define        DRQ_SINGLE      0x0100  /*              Channels Request Single                         */
-#define        DRQ_MULTI       0x0200  /*              Channels Request Multi (Default)        */
-#define        DRQ_URGENT      0x0300  /*              Channels Request Multi Urgent           */
-#define        RBC                     0x1000  /* Reload BCNT With IBCNT                                       */
-#define        PS                      0x2000  /* HDMA Pin Status                                                      */
-#define        OI                      0x4000  /* Overflow Interrupt Generated                         */
-#define        BDI                     0x8000  /* Block Done Interrupt Generated                       */
-
 /* entry addresses of the user-callable Boot ROM functions */
 
 #define _BOOTROM_RESET 0xEF000000
index f869a3711480d233af5e61b9f5292c603709f57f..a377d8afea0389523e386ddc98046af3463ab947 100644 (file)
@@ -289,8 +289,6 @@ static struct platform_device *ip0x_devices[] __initdata = {
 
 static int __init ip0x_init(void)
 {
-       int i;
-
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(ip0x_devices, ARRAY_SIZE(ip0x_devices));
 
index 2c776e188a94403929f46e63870f7bc37669b346..d582b810e7a74b1bf3b0bd0a22946a3910845586 100644 (file)
@@ -775,7 +775,7 @@ static int __init cm_bf537e_init(void)
 #endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
-       irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
+       irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN);
 #endif
        return 0;
 }
index 085661175ec7b0bc73922ce7d61c87dce387a828..cbb8098604c56834a520fe6885247be4220df3f7 100644 (file)
@@ -740,7 +740,7 @@ static int __init cm_bf537u_init(void)
 #endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
-       irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
+       irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN);
 #endif
        return 0;
 }
index e1e9ea02ad898db7a8bc7fcccf72b434a3bfdc5c..6b4ff4605bffd9f44d12a1f32b4de004acae8429 100644 (file)
@@ -128,30 +128,11 @@ static struct platform_device asmb_flash_device = {
 
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
 
-#define MMC_SPI_CARD_DETECT_INT IRQ_PF5
-
-static int bfin_mmc_spi_init(struct device *dev,
-       irqreturn_t (*detect_int)(int, void *), void *data)
-{
-       return request_irq(MMC_SPI_CARD_DETECT_INT, detect_int,
-               IRQF_TRIGGER_FALLING, "mmc-spi-detect", data);
-}
-
-static void bfin_mmc_spi_exit(struct device *dev, void *data)
-{
-       free_irq(MMC_SPI_CARD_DETECT_INT, data);
-}
-
 static struct bfin5xx_spi_chip mmc_spi_chip_info = {
        .enable_dma    = 0,      /* use no dma transfer with this chip*/
        .bits_per_word = 8,
 };
 
-static struct mmc_spi_platform_data bfin_mmc_spi_pdata = {
-       .init = bfin_mmc_spi_init,
-       .exit = bfin_mmc_spi_exit,
-       .detect_delay = 100, /* msecs */
-};
 #endif
 
 #if defined(CONFIG_MTD_DATAFLASH) || defined(CONFIG_MTD_DATAFLASH_MODULE)
@@ -192,7 +173,6 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .max_speed_hz    = 20000000,
                .bus_num         = 0,
                .chip_select     = 1,
-               .platform_data   = &bfin_mmc_spi_pdata,
                .controller_data = &mmc_spi_chip_info,
                .mode            = SPI_MODE_3,
        },
index 0761b201abcab248d08483af8cb7946ddb124155..164a7e02c022ccdb2971899682d89653c94e3a15 100644 (file)
@@ -742,7 +742,7 @@ static int __init tcm_bf537_init(void)
 #endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
-       irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
+       irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN);
 #endif
        return 0;
 }
index 725bb35f3aaa035e0bba4483be23d68d23554005..4a031dde173fb0ac965908b10727a95aa87f57cc 100644 (file)
 #define        PGTE_PPI                0x0000  /*              Enable PPI D15:13                       */
 #define        PGTE_SPORT              0x0800  /*              Enable DT1PRI/TFS1/TSCLK1       */
 
-/*  ******************  HANDSHAKE DMA (HDMA) MASKS  *********************/
-/* HDMAx_CTL Masks                                                                                                             */
-#define        HMDMAEN         0x0001  /* Enable Handshake DMA 0/1                                     */
-#define        REP                     0x0002  /* HDMA Request Polarity                                        */
-#define        UTE                     0x0004  /* Urgency Threshold Enable                                     */
-#define        OIE                     0x0010  /* Overflow Interrupt Enable                            */
-#define        BDIE            0x0020  /* Block Done Interrupt Enable                          */
-#define        MBDI            0x0040  /* Mask Block Done IRQ If Pending ECNT          */
-#define        DRQ                     0x0300  /* HDMA Request Type                                            */
-#define        DRQ_NONE        0x0000  /*              No Request                                                      */
-#define        DRQ_SINGLE      0x0100  /*              Channels Request Single                         */
-#define        DRQ_MULTI       0x0200  /*              Channels Request Multi (Default)        */
-#define        DRQ_URGENT      0x0300  /*              Channels Request Multi Urgent           */
-#define        RBC                     0x1000  /* Reload BCNT With IBCNT                                       */
-#define        PS                      0x2000  /* HDMA Pin Status                                                      */
-#define        OI                      0x4000  /* Overflow Interrupt Generated                         */
-#define        BDI                     0x8000  /* Block Done Interrupt Generated                       */
-
 /* entry addresses of the user-callable Boot ROM functions */
 
 #define _BOOTROM_RESET 0xEF000000 
index 70189a0d1a1905d95dbf6c243f0f1c4e88d6e6d8..94acb586832e69a23036e6967ceb0a3142876d66 100644 (file)
@@ -42,6 +42,65 @@ config BF548_ATAPI_ALTERNATIVE_PORT
          async address or GPIO port F and G. Select y to route it
          to GPIO.
 
+choice
+       prompt "UART2 DMA channel selection"
+       depends on SERIAL_BFIN_UART2
+       default UART2_DMA_RX_ON_DMA18
+       help
+               UART2 DMA channel selection
+               RX -> DMA18
+               TX -> DMA19
+               or
+               RX -> DMA13
+               TX -> DMA14
+
+config UART2_DMA_RX_ON_DMA18
+       bool "UART2 DMA RX -> DMA18 TX -> DMA19"
+       help
+               UART2 DMA channel assignment
+               RX -> DMA18
+               TX -> DMA19
+               use SPORT2 default DMA channel
+
+config UART2_DMA_RX_ON_DMA13
+       bool "UART2 DMA RX -> DMA13 TX -> DMA14"
+       help
+               UART2 DMA channel assignment
+               RX -> DMA13
+               TX -> DMA14
+               use EPPI1 EPPI2 default DMA channel
+endchoice
+
+choice
+       prompt "UART3 DMA channel selection"
+       depends on SERIAL_BFIN_UART3
+       default UART3_DMA_RX_ON_DMA20
+       help
+               UART3 DMA channel selection
+               RX -> DMA20
+               TX -> DMA21
+               or
+               RX -> DMA15
+               TX -> DMA16
+
+config UART3_DMA_RX_ON_DMA20
+       bool "UART3 DMA RX -> DMA20 TX -> DMA21"
+       help
+               UART3 DMA channel assignment
+               RX -> DMA20
+               TX -> DMA21
+               use SPORT3 default DMA channel
+
+config UART3_DMA_RX_ON_DMA15
+       bool "UART3 DMA RX -> DMA15 TX -> DMA16"
+       help
+               UART3 DMA channel assignment
+               RX -> DMA15
+               TX -> DMA16
+               use PIXC default DMA channel
+
+endchoice
+
 comment "Interrupt Priority Assignment"
 menu "Priority"
 
index ce5a2bb147dc273219e5129675072fdc8e1393b2..93e19a54a8803d639fd5586a155954610861dbc7 100644 (file)
@@ -778,11 +778,12 @@ static struct platform_device bfin_sport3_uart_device = {
 #endif
 
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
-static unsigned short bfin_can_peripherals[] = {
+
+static unsigned short bfin_can0_peripherals[] = {
        P_CAN0_RX, P_CAN0_TX, 0
 };
 
-static struct resource bfin_can_resources[] = {
+static struct resource bfin_can0_resources[] = {
        {
                .start = 0xFFC02A00,
                .end = 0xFFC02FFF,
@@ -805,14 +806,53 @@ static struct resource bfin_can_resources[] = {
        },
 };
 
-static struct platform_device bfin_can_device = {
+static struct platform_device bfin_can0_device = {
        .name = "bfin_can",
-       .num_resources = ARRAY_SIZE(bfin_can_resources),
-       .resource = bfin_can_resources,
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_can0_resources),
+       .resource = bfin_can0_resources,
        .dev = {
-               .platform_data = &bfin_can_peripherals, /* Passed to driver */
+               .platform_data = &bfin_can0_peripherals, /* Passed to driver */
        },
 };
+
+static unsigned short bfin_can1_peripherals[] = {
+       P_CAN1_RX, P_CAN1_TX, 0
+};
+
+static struct resource bfin_can1_resources[] = {
+       {
+               .start = 0xFFC03200,
+               .end = 0xFFC037FF,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_CAN1_RX,
+               .end = IRQ_CAN1_RX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_CAN1_TX,
+               .end = IRQ_CAN1_TX,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_CAN1_ERROR,
+               .end = IRQ_CAN1_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bfin_can1_device = {
+       .name = "bfin_can",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(bfin_can1_resources),
+       .resource = bfin_can1_resources,
+       .dev = {
+               .platform_data = &bfin_can1_peripherals, /* Passed to driver */
+       },
+};
+
 #endif
 
 #if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
@@ -1366,7 +1406,8 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
-       &bfin_can_device,
+       &bfin_can0_device,
+       &bfin_can1_device,
 #endif
 
 #if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
index 4070079e2c00a46e3703545ffc23001f41388922..ffd0537295ac4d5c348bdf1e747b1f48caafc92f 100644 (file)
 /* PLL Status Register Is Inaccurate */
 #define ANOMALY_05000351 (__SILICON_REVISION__ < 1)
 /* bfrom_SysControl() Firmware Function Performs Improper System Reset */
-#define ANOMALY_05000353 (__SILICON_REVISION__ < 2)
+/*
+ * Note: anomaly sheet says this is fixed with bf54x-0.2+, but testing
+ *       shows that the fix itself does not cover all cases.
+ */
+#define ANOMALY_05000353 (1)
 /* Regulator Programming Blocked when Hibernate Wakeup Source Remains Active */
 #define ANOMALY_05000355 (__SILICON_REVISION__ < 1)
 /* System Stalled During A Core Access To AMC While A Core Access To NFC FIFO Is Required */
index 642468c1bcb1ce7d7bc9b00479525d9dda2c7c58..bcccab36629c34295f107f6af44b81e58b9029a7 100644 (file)
 
 /* Bit masks for EPPI0 are obtained from common base header for EPPIx (EPPI1 and EPPI2) */
 
-/* Bit masks for HMDMAx_CONTROL */
-
-#define                   HMDMAEN  0x1        /* Handshake MDMA Enable */
-#define                       REP  0x2        /* Handshake MDMA Request Polarity */
-#define                       UTE  0x8        /* Urgency Threshold Enable */
-#define                       OIE  0x10       /* Overflow Interrupt Enable */
-#define                      BDIE  0x20       /* Block Done Interrupt Enable */
-#define                      MBDI  0x40       /* Mask Block Done Interrupt */
-#define                       DRQ  0x300      /* Handshake MDMA Request Type */
-#define                       RBC  0x1000     /* Force Reload of BCOUNT */
-#define                        PS  0x2000     /* Pin Status */
-#define                        OI  0x4000     /* Overflow Interrupt Generated */
-#define                       BDI  0x8000     /* Block Done Interrupt Generated */
-
-/* ******************************************* */
-/*     MULTI BIT MACRO ENUMERATIONS            */
-/* ******************************************* */
-
 #endif /* _DEF_BF544_H */
index 2f3337cd311e880cc37d1f7fdebdc34559bae2b6..1cbba115f96f3d518eead9457913bcd8ca39ab7f 100644 (file)
 
 #define             DMA_COUNT_LOW  0xffff     /* Lower 16-bits of byte count of DMA transfer for DMA master channel */
 
-/* Bit masks for HMDMAx_CONTROL */
-
-#define                   HMDMAEN  0x1        /* Handshake MDMA Enable */
-#define                       REP  0x2        /* Handshake MDMA Request Polarity */
-#define                       UTE  0x8        /* Urgency Threshold Enable */
-#define                       OIE  0x10       /* Overflow Interrupt Enable */
-#define                      BDIE  0x20       /* Block Done Interrupt Enable */
-#define                      MBDI  0x40       /* Mask Block Done Interrupt */
-#define                       DRQ  0x300      /* Handshake MDMA Request Type */
-#define                       RBC  0x1000     /* Force Reload of BCOUNT */
-#define                        PS  0x2000     /* Pin Status */
-#define                        OI  0x4000     /* Overflow Interrupt Generated */
-#define                       BDI  0x8000     /* Block Done Interrupt Generated */
-
-/* ******************************************* */
-/*     MULTI BIT MACRO ENUMERATIONS            */
-/* ******************************************* */
-
-
 #endif /* _DEF_BF547_H */
index a30d242c7398d378269bcd80b3a29d4f86674cc6..1a1091b071fd5a5168c078502dc4325c86fd3a72 100644 (file)
 #define CH_PIXC_OVERLAY                16
 #define CH_PIXC_OUTPUT         17
 #define CH_SPORT2_RX           18
-#define CH_UART2_RX            18
 #define CH_SPORT2_TX           19
-#define CH_UART2_TX            19
 #define CH_SPORT3_RX           20
-#define CH_UART3_RX            20
 #define CH_SPORT3_TX           21
-#define CH_UART3_TX            21
 #define CH_SDH                 22
 #define CH_NFC                 22
 #define CH_SPI2                        23
 
+#if defined(CONFIG_UART2_DMA_RX_ON_DMA13)
+#define CH_UART2_RX            13
+#define IRQ_UART2_RX           BFIN_IRQ(37)    /* UART2 RX USE EPP1 (DMA13) Interrupt */
+#define CH_UART2_TX            14
+#define IRQ_UART2_TX           BFIN_IRQ(38)    /* UART2 RX USE EPP1 (DMA14) Interrupt */
+#else                                          /* Default USE SPORT2's DMA Channel */
+#define CH_UART2_RX            18
+#define IRQ_UART2_RX           BFIN_IRQ(33)    /* UART2 RX (DMA18) Interrupt */
+#define CH_UART2_TX            19
+#define IRQ_UART2_TX           BFIN_IRQ(34)    /* UART2 TX (DMA19) Interrupt */
+#endif
+
+#if defined(CONFIG_UART3_DMA_RX_ON_DMA15)
+#define CH_UART3_RX            15
+#define IRQ_UART3_RX           BFIN_IRQ(64)    /* UART3 RX USE PIXC IN0 (DMA15) Interrupt */
+#define CH_UART3_TX            16
+#define IRQ_UART3_TX           BFIN_IRQ(65)    /* UART3 TX USE PIXC IN1 (DMA16) Interrupt */
+#else                                          /* Default USE SPORT3's DMA Channel */
+#define CH_UART3_RX            20
+#define IRQ_UART3_RX           BFIN_IRQ(35)    /* UART3 RX (DMA20) Interrupt */
+#define CH_UART3_TX            21
+#define IRQ_UART3_TX           BFIN_IRQ(36)    /* UART3 TX (DMA21) Interrupt */
+#endif
+
 #define CH_MEM_STREAM0_DEST    24
 #define CH_MEM_STREAM0_SRC     25
 #define CH_MEM_STREAM1_DEST    26
index 99fd1b2c53d8c3c3534fece60bcc3991bd97d193..7f87787e77382279a35a75b0f65a1ea3bbbdf505 100644 (file)
@@ -74,13 +74,9 @@ Events         (highest priority)  EMU         0
 #define IRQ_UART2_ERROR                BFIN_IRQ(31)    /* UART2 Status (Error) Interrupt */
 #define IRQ_CAN0_ERROR         BFIN_IRQ(32)    /* CAN0 Status (Error) Interrupt */
 #define IRQ_SPORT2_RX          BFIN_IRQ(33)    /* SPORT2 RX (DMA18) Interrupt */
-#define IRQ_UART2_RX           BFIN_IRQ(33)    /* UART2 RX (DMA18) Interrupt */
 #define IRQ_SPORT2_TX          BFIN_IRQ(34)    /* SPORT2 TX (DMA19) Interrupt */
-#define IRQ_UART2_TX           BFIN_IRQ(34)    /* UART2 TX (DMA19) Interrupt */
 #define IRQ_SPORT3_RX          BFIN_IRQ(35)    /* SPORT3 RX (DMA20) Interrupt */
-#define IRQ_UART3_RX           BFIN_IRQ(35)    /* UART3 RX (DMA20) Interrupt */
 #define IRQ_SPORT3_TX          BFIN_IRQ(36)    /* SPORT3 TX (DMA21) Interrupt */
-#define IRQ_UART3_TX           BFIN_IRQ(36)    /* UART3 TX (DMA21) Interrupt */
 #define IRQ_EPPI1              BFIN_IRQ(37)    /* EPP1 (DMA13) Interrupt */
 #define IRQ_EPPI2              BFIN_IRQ(38)    /* EPP2 (DMA14) Interrupt */
 #define IRQ_SPI1               BFIN_IRQ(39)    /* SPI1 (DMA5) Interrupt */
index 3b67929d4c0a5c75c25c1e29c311b0656fcc23e7..87595cd38afe1edc0c0ac9bd2f366f21389187c3 100644 (file)
@@ -541,7 +541,7 @@ static int __init cm_bf561_init(void)
 #endif
 
 #if defined(CONFIG_PATA_PLATFORM) || defined(CONFIG_PATA_PLATFORM_MODULE)
-       irq_desc[PATA_INT].status |= IRQ_NOAUTOEN;
+       irq_set_status_flags(PATA_INT, IRQ_NOAUTOEN);
 #endif
        return 0;
 }
index 4cd3b28cd046d86d51973fe0037abdeb63279ea6..0123117b8ff2c88c876963202a0bd02cf4a0f318 100644 (file)
@@ -5,30 +5,36 @@
  * Licensed under the GPL-2 or later.
  */
 
+#include <linux/smp.h>
 #include <asm/blackfin.h>
-#include <asm/irq.h>
-#include <asm/smp.h>
-
-#define SIC_SYSIRQ(irq)        (irq - (IRQ_CORETMR + 1))
+#include <asm/cacheflush.h>
+#include <mach/pll.h>
 
 int hotplug_coreb;
 
 void platform_cpu_die(void)
 {
-       unsigned long iwr[2] = {0, 0};
-       unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
-       unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
+       unsigned long iwr;
 
        hotplug_coreb = 1;
 
-       iwr[bank] = bit;
+       /*
+        * When CoreB wakes up, the code in _coreb_trampoline_start cannot
+        * turn off the data cache. This causes the CoreB failed to boot.
+        * As a workaround, we invalidate all the data cache before sleep.
+        */
+       blackfin_invalidate_entire_dcache();
 
        /* disable core timer */
        bfin_write_TCNTL(0);
 
-       /* clear ipi interrupt IRQ_SUPPLE_0 */
+       /* clear ipi interrupt IRQ_SUPPLE_0 of CoreB */
        bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
        SSYNC();
 
-       coreb_sleep(iwr[0], iwr[1], 0);
+       /* set CoreB wakeup by ipi0, iwr will be discarded */
+       bfin_iwr_set_sup0(&iwr, &iwr, &iwr);
+       SSYNC();
+
+       coreb_die();
 }
index 4624eebbf9c4c92b5e95220282b3f676dd6dbf76..4c462838f4e1fc0f45123d6415fb445441d7d6c3 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
 
-__INIT
+/*
+ * This code must come first as CoreB is hardcoded (in hardware)
+ * to start at the beginning of its L1 instruction memory.
+ */
+.section .l1.text.head
 
 /* Lay the initial stack into the L1 scratch area of Core B */
 #define INITIAL_STACK  (COREB_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
@@ -160,43 +164,34 @@ ENTRY(_coreb_trampoline_start)
 .LWAIT_HERE:
        jump .LWAIT_HERE;
 ENDPROC(_coreb_trampoline_start)
-ENTRY(_coreb_trampoline_end)
 
+#ifdef CONFIG_HOTPLUG_CPU
 .section ".text"
-ENTRY(_set_sicb_iwr)
-       P0.H = hi(SICB_IWR0);
-       P0.L = lo(SICB_IWR0);
-       P1.H = hi(SICB_IWR1);
-       P1.L = lo(SICB_IWR1);
-       [P0] = R0;
-       [P1] = R1;
-       SSYNC;
-       RTS;
-ENDPROC(_set_sicb_iwr)
-
-ENTRY(_coreb_sleep)
+ENTRY(_coreb_die)
        sp.l = lo(INITIAL_STACK);
        sp.h = hi(INITIAL_STACK);
        fp = sp;
        usp = sp;
 
-       call _set_sicb_iwr;
-
        CLI R2;
        SSYNC;
        IDLE;
        STI R2;
 
        R0 = IWR_DISABLE_ALL;
-       R1 = IWR_DISABLE_ALL;
-       call _set_sicb_iwr;
+       P0.H = hi(SYSMMR_BASE);
+       P0.L = lo(SYSMMR_BASE);
+       [P0 + (SICB_IWR0 - SYSMMR_BASE)] = R0;
+       [P0 + (SICB_IWR1 - SYSMMR_BASE)] = R0;
+       SSYNC;
 
        p0.h = hi(COREB_L1_CODE_START);
        p0.l = lo(COREB_L1_CODE_START);
        jump (p0);
-ENDPROC(_coreb_sleep)
+ENDPROC(_coreb_die)
+#endif
 
-__CPUINIT
+__INIT
 ENTRY(_coreb_start)
        [--sp] = reti;
 
index 1074a7ef81c7ec3b530ef932212e9f5a2af9e238..5d68bf613b0b9dbe0fde9e2e3055fe23c0375f63 100644 (file)
@@ -30,18 +30,11 @@ void __init platform_init_cpus(void)
 
 void __init platform_prepare_cpus(unsigned int max_cpus)
 {
-       int len;
-
-       len = &coreb_trampoline_end - &coreb_trampoline_start + 1;
-       BUG_ON(len > L1_CODE_LENGTH);
-
-       dma_memcpy((void *)COREB_L1_CODE_START, &coreb_trampoline_start, len);
+       bfin_relocate_coreb_l1_mem();
 
        /* Both cores ought to be present on a bf561! */
        cpu_set(0, cpu_present_map); /* CoreA */
        cpu_set(1, cpu_present_map); /* CoreB */
-
-       printk(KERN_INFO "CoreB bootstrap code to SRAM %p via DMA.\n", (void *)COREB_L1_CODE_START);
 }
 
 int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
@@ -161,9 +154,13 @@ void platform_clear_ipi(unsigned int cpu, int irq)
 void __cpuinit bfin_local_timer_setup(void)
 {
 #if defined(CONFIG_TICKSOURCE_CORETMR)
+       struct irq_chip *chip = get_irq_chip(IRQ_CORETMR);
+       struct irq_desc *desc = irq_to_desc(IRQ_CORETMR);
+
        bfin_coretmr_init();
        bfin_coretmr_clockevent_init();
-       get_irq_chip(IRQ_CORETMR)->unmask(IRQ_CORETMR);
+
+       chip->irq_unmask(&desc->irq_data);
 #else
        /* Power down the core timer, just to play safe. */
        bfin_write_TCNTL(0);
index bceb98126c21e8eb4f71cb1a44e2110e0c08c49f..d8643fdd0fcf1d9ccc7812c7a46c9fd822d08213 100644 (file)
@@ -61,6 +61,6 @@
 # error "Anomaly 05000220 does not allow you to use Write Back cache with L2 or External Memory"
 #endif
 
-#if ANOMALY_05000491 && !defined(CONFIG_CACHE_FLUSH_L1)
+#if ANOMALY_05000491 && !defined(CONFIG_ICACHE_FLUSH_L1)
 # error You need IFLUSH in L1 inst while Anomaly 05000491 applies
 #endif
index ab4a925a443e4e82001df0beb146b7b7b8e3b40a..9f4dd35bfd743fbc91cf680c6f4cc90867fc0a05 100644 (file)
 #include <asm/cache.h>
 #include <asm/page.h>
 
-#ifdef CONFIG_CACHE_FLUSH_L1
-.section .l1.text
-#else
-.text
-#endif
-
 /* 05000443 - IFLUSH cannot be last instruction in hardware loop */
 #if ANOMALY_05000443
 # define BROK_FLUSH_INST "IFLUSH"
        RTS;
 .endm
 
+#ifdef CONFIG_ICACHE_FLUSH_L1
+.section .l1.text
+#else
+.text
+#endif
+
 /* Invalidate all instruction cache lines assocoiated with this memory area */
+#ifdef CONFIG_SMP
+# define _blackfin_icache_flush_range _blackfin_icache_flush_range_l1
+#endif
 ENTRY(_blackfin_icache_flush_range)
        do_flush IFLUSH
 ENDPROC(_blackfin_icache_flush_range)
 
+#ifdef CONFIG_SMP
+.text
+# undef _blackfin_icache_flush_range
+ENTRY(_blackfin_icache_flush_range)
+       p0.L = LO(DSPID);
+       p0.H = HI(DSPID);
+       r3 = [p0];
+       r3 = r3.b (z);
+       p2 = r3;
+       p0.L = _blackfin_iflush_l1_entry;
+       p0.H = _blackfin_iflush_l1_entry;
+       p0 = p0 + (p2 << 2);
+       p1 = [p0];
+       jump (p1);
+ENDPROC(_blackfin_icache_flush_range)
+#endif
+
+#ifdef CONFIG_DCACHE_FLUSH_L1
+.section .l1.text
+#else
+.text
+#endif
+
 /* Throw away all D-cached data in specified region without any obligation to
  * write them back.  Since the Blackfin ISA does not have an "invalidate"
  * instruction, we use flush/invalidate.  Perhaps as a speed optimization we
index f4cf11d362e1df4f67315a68714cac5faf6b293b..85dc6d69f9c02e1c58a8f438b8bbedf75aba50f3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Blackfin core clock scaling
  *
- * Copyright 2008-2009 Analog Devices Inc.
+ * Copyright 2008-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
 #include <asm/time.h>
 #include <asm/dpmc.h>
 
-#define CPUFREQ_CPU 0
-
 /* this is the table of CCLK frequencies, in Hz */
-/* .index is the entry in the auxillary dpm_state_table[] */
+/* .index is the entry in the auxiliary dpm_state_table[] */
 static struct cpufreq_frequency_table bfin_freq_table[] = {
        {
                .frequency = CPUFREQ_TABLE_END,
@@ -46,7 +44,7 @@ static struct bfin_dpm_state {
 
 #if defined(CONFIG_CYCLES_CLOCKSOURCE)
 /*
- * normalized to maximum frequncy offset for CYCLES,
+ * normalized to maximum frequency offset for CYCLES,
  * used in time-ts cycles clock source, but could be used
  * somewhere also.
  */
index 02c7efd1bcf4807939135734a5f41e159b1af224..382099fd55619be3a4f1d40c99cdf034143943a4 100644 (file)
@@ -61,17 +61,63 @@ err_out:
 }
 
 #ifdef CONFIG_CPU_FREQ
+# ifdef CONFIG_SMP
+static void bfin_idle_this_cpu(void *info)
+{
+       unsigned long flags = 0;
+       unsigned long iwr0, iwr1, iwr2;
+       unsigned int cpu = smp_processor_id();
+
+       local_irq_save_hw(flags);
+       bfin_iwr_set_sup0(&iwr0, &iwr1, &iwr2);
+
+       platform_clear_ipi(cpu, IRQ_SUPPLE_0);
+       SSYNC();
+       asm("IDLE;");
+       bfin_iwr_restore(iwr0, iwr1, iwr2);
+
+       local_irq_restore_hw(flags);
+}
+
+static void bfin_idle_cpu(void)
+{
+       smp_call_function(bfin_idle_this_cpu, NULL, 0);
+}
+
+static void bfin_wakeup_cpu(void)
+{
+       unsigned int cpu;
+       unsigned int this_cpu = smp_processor_id();
+       cpumask_t mask = cpu_online_map;
+
+       cpu_clear(this_cpu, mask);
+       for_each_cpu_mask(cpu, mask)
+               platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
+}
+
+# else
+static void bfin_idle_cpu(void) {}
+static void bfin_wakeup_cpu(void) {}
+# endif
+
 static int
 vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
 {
        struct cpufreq_freqs *freq = data;
 
+       if (freq->cpu != CPUFREQ_CPU)
+               return 0;
+
        if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) {
+               bfin_idle_cpu();
                bfin_set_vlev(bfin_get_vlev(freq->new));
                udelay(pdata->vr_settling_time); /* Wait until Volatge settled */
-
-       } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)
+               bfin_wakeup_cpu();
+       } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) {
+               bfin_idle_cpu();
                bfin_set_vlev(bfin_get_vlev(freq->new));
+               bfin_wakeup_cpu();
+       }
 
        return 0;
 }
index bc08c98d008d8cf66e806476f4ce570b6cae396e..46ab45704c89e8d9f376f924ededc92dfcb3e908 100644 (file)
@@ -952,8 +952,17 @@ ENDPROC(_evt_up_evt14)
 #ifdef CONFIG_IPIPE
 
 _resume_kernel_from_int:
+       r1 = LO(~0x8000) (Z);
+       r1 = r0 & r1;
+       r0 = 1;
+       r0 = r1 - r0;
+       r2 = r1 & r0;
+       cc = r2 == 0;
+       /* Sync the root stage only from the outer interrupt level. */
+       if !cc jump .Lnosync;
        r0.l = ___ipipe_sync_root;
        r0.h = ___ipipe_sync_root;
+       [--sp] = reti;
        [--sp] = rets;
        [--sp] = ( r7:4, p5:3 );
        SP += -12;
@@ -961,6 +970,8 @@ _resume_kernel_from_int:
        SP += 12;
        ( r7:4, p5:3 ) = [sp++];
        rets = [sp++];
+       reti = [sp++];
+.Lnosync:
        rts
 #elif defined(CONFIG_PREEMPT)
 
@@ -1738,6 +1749,10 @@ ENTRY(_sys_call_table)
        .long _sys_fanotify_mark
        .long _sys_prlimit64
        .long _sys_cacheflush
+       .long _sys_name_to_handle_at    /* 375 */
+       .long _sys_open_by_handle_at
+       .long _sys_clock_adjtime
+       .long _sys_syncfs
 
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
index 4391621d90488a1fcb7f89f72efca8bf707ecc6a..581e2b0a71ace2468cbb29e7b82ecd2f179ae3e7 100644 (file)
@@ -31,6 +31,7 @@ ENDPROC(__init_clear_bss)
 ENTRY(__start)
        /* R0: argument of command line string, passed from uboot, save it */
        R7 = R0;
+
        /* Enable Cycle Counter and Nesting Of Interrupts */
 #ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES
        R0 = SYSCFG_SNEN;
@@ -38,76 +39,49 @@ ENTRY(__start)
        R0 = SYSCFG_SNEN | SYSCFG_CCEN;
 #endif
        SYSCFG = R0;
-       R0 = 0;
-
-       /* Clear Out All the data and pointer Registers */
-       R1 = R0;
-       R2 = R0;
-       R3 = R0;
-       R4 = R0;
-       R5 = R0;
-       R6 = R0;
-
-       P0 = R0;
-       P1 = R0;
-       P2 = R0;
-       P3 = R0;
-       P4 = R0;
-       P5 = R0;
-
-       LC0 = r0;
-       LC1 = r0;
-       L0 = r0;
-       L1 = r0;
-       L2 = r0;
-       L3 = r0;
-
-       /* Clear Out All the DAG Registers */
-       B0 = r0;
-       B1 = r0;
-       B2 = r0;
-       B3 = r0;
-
-       I0 = r0;
-       I1 = r0;
-       I2 = r0;
-       I3 = r0;
-
-       M0 = r0;
-       M1 = r0;
-       M2 = r0;
-       M3 = r0;
+
+       /* Optimization register tricks: keep a base value in the
+        * reserved P registers so we use the load/store with an
+        * offset syntax.  R0 = [P5 + <constant>];
+        *   P5 - core MMR base
+        *   R6 - 0
+        */
+       r6 = 0;
+       p5.l = 0;
+       p5.h = hi(COREMMR_BASE);
+
+       /* Zero out registers required by Blackfin ABI */
+
+       /* Disable circular buffers */
+       L0 = r6;
+       L1 = r6;
+       L2 = r6;
+       L3 = r6;
+
+       /* Disable hardware loops in case we were started by 'go' */
+       LC0 = r6;
+       LC1 = r6;
 
        /*
         * Clear ITEST_COMMAND and DTEST_COMMAND registers,
         * Leaving these as non-zero can confuse the emulator
         */
-       p0.L = LO(DTEST_COMMAND);
-       p0.H = HI(DTEST_COMMAND);
-       [p0] = R0;
-       [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0;
+       [p5 + (DTEST_COMMAND - COREMMR_BASE)] = r6;
+       [p5 + (ITEST_COMMAND - COREMMR_BASE)] = r6;
        CSYNC;
 
        trace_buffer_init(p0,r0);
-       P0 = R1;
-       R0 = R1;
 
        /* Turn off the icache */
-       p0.l = LO(IMEM_CONTROL);
-       p0.h = HI(IMEM_CONTROL);
-       R1 = [p0];
-       R0 = ~ENICPLB;
-       R0 = R0 & R1;
-       [p0] = R0;
+       r1 = [p5 + (IMEM_CONTROL - COREMMR_BASE)];
+       BITCLR (r1, ENICPLB_P);
+       [p5 + (IMEM_CONTROL - COREMMR_BASE)] = r1;
        SSYNC;
 
        /* Turn off the dcache */
-       p0.l = LO(DMEM_CONTROL);
-       p0.h = HI(DMEM_CONTROL);
-       R1 = [p0];
-       R0 = ~ENDCPLB;
-       R0 = R0 & R1;
-       [p0] = R0;
+       r1 = [p5 + (DMEM_CONTROL - COREMMR_BASE)];
+       BITCLR (r1, ENDCPLB_P);
+       [p5 + (DMEM_CONTROL - COREMMR_BASE)] = r1;
        SSYNC;
 
        /* in case of double faults, save a few things */
@@ -122,25 +96,25 @@ ENTRY(__start)
         * below
         */
        GET_PDA(p0, r0);
-       r6 = [p0 + PDA_DF_RETX];
+       r5 = [p0 + PDA_DF_RETX];
        p1.l = _init_saved_retx;
        p1.h = _init_saved_retx;
-       [p1] = r6;
+       [p1] = r5;
 
-       r6 = [p0 + PDA_DF_DCPLB];
+       r5 = [p0 + PDA_DF_DCPLB];
        p1.l = _init_saved_dcplb_fault_addr;
        p1.h = _init_saved_dcplb_fault_addr;
-       [p1] = r6;
+       [p1] = r5;
 
-       r6 = [p0 + PDA_DF_ICPLB];
+       r5 = [p0 + PDA_DF_ICPLB];
        p1.l = _init_saved_icplb_fault_addr;
        p1.h = _init_saved_icplb_fault_addr;
-       [p1] = r6;
+       [p1] = r5;
 
-       r6 = [p0 + PDA_DF_SEQSTAT];
+       r5 = [p0 + PDA_DF_SEQSTAT];
        p1.l = _init_saved_seqstat;
        p1.h = _init_saved_seqstat;
-       [p1] = r6;
+       [p1] = r5;
 #endif
 
        /* Initialize stack pointer */
@@ -155,7 +129,7 @@ ENTRY(__start)
        sti r0;
 #endif
 
-       r0 = 0 (x);
+       r0 = r6;
        /* Zero out all of the fun bss regions */
 #if L1_DATA_A_LENGTH > 0
        r1.l = __sbss_l1;
@@ -210,11 +184,9 @@ ENTRY(__start)
 
        /* EVT15 = _real_start */
 
-       p0.l = lo(EVT15);
-       p0.h = hi(EVT15);
        p1.l = _real_start;
        p1.h = _real_start;
-       [p0] = p1;
+       [p5 + (EVT15 - COREMMR_BASE)] = p1;
        csync;
 
 #ifdef CONFIG_EARLY_PRINTK
index 2df37db3b49b60dbe9df7e768b0fb31cf5946c69..469ce7282dc8b5f0d789382712be43924543a4e0 100644 (file)
@@ -274,16 +274,16 @@ ENDPROC(_evt_system_call)
  * level to EVT14 to prepare the caller for a normal interrupt
  * return through RTI.
  *
- * We currently use this facility in two occasions:
+ * We currently use this feature in two occasions:
  *
- * - to branch to __ipipe_irq_tail_hook as requested by a high
+ * - before branching to __ipipe_irq_tail_hook as requested by a high
  *   priority domain after the pipeline delivered an interrupt,
  *   e.g. such as Xenomai, in order to start its rescheduling
  *   procedure, since we may not switch tasks when IRQ levels are
  *   nested on the Blackfin, so we have to fake an interrupt return
  *   so that we may reschedule immediately.
  *
- * - to branch to sync_root_irqs, in order to play any interrupt
+ * - before branching to __ipipe_sync_root(), in order to play any interrupt
  *   pending for the root domain (i.e. the Linux kernel). This lowers
  *   the core priority level enough so that Linux IRQ handlers may
  *   never delay interrupts handled by high priority domains; we defer
index a604f19d8dc315df316058942042ef7ee9f8b5b6..6cd52395a999866f778d6d89e8b879ee7ab8386e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
+#include <linux/sched.h>
 #ifdef CONFIG_IPIPE
 #include <linux/ipipe.h>
 #endif
@@ -124,21 +125,21 @@ static void __init search_IAR(void)
  * This is for core internal IRQs
  */
 
-static void bfin_ack_noop(unsigned int irq)
+static void bfin_ack_noop(struct irq_data *d)
 {
        /* Dummy function.  */
 }
 
-static void bfin_core_mask_irq(unsigned int irq)
+static void bfin_core_mask_irq(struct irq_data *d)
 {
-       bfin_irq_flags &= ~(1 << irq);
+       bfin_irq_flags &= ~(1 << d->irq);
        if (!hard_irqs_disabled())
                hard_local_irq_enable();
 }
 
-static void bfin_core_unmask_irq(unsigned int irq)
+static void bfin_core_unmask_irq(struct irq_data *d)
 {
-       bfin_irq_flags |= 1 << irq;
+       bfin_irq_flags |= 1 << d->irq;
        /*
         * If interrupts are enabled, IMASK must contain the same value
         * as bfin_irq_flags.  Make sure that invariant holds.  If interrupts
@@ -176,6 +177,11 @@ static void bfin_internal_mask_irq(unsigned int irq)
        hard_local_irq_restore(flags);
 }
 
+static void bfin_internal_mask_irq_chip(struct irq_data *d)
+{
+       bfin_internal_mask_irq(d->irq);
+}
+
 #ifdef CONFIG_SMP
 static void bfin_internal_unmask_irq_affinity(unsigned int irq,
                const struct cpumask *affinity)
@@ -211,19 +217,24 @@ static void bfin_internal_unmask_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-static void bfin_internal_unmask_irq(unsigned int irq)
+static void bfin_internal_unmask_irq_chip(struct irq_data *d)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       bfin_internal_unmask_irq_affinity(irq, desc->affinity);
+       bfin_internal_unmask_irq_affinity(d->irq, d->affinity);
 }
 
-static int bfin_internal_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int bfin_internal_set_affinity(struct irq_data *d,
+                                     const struct cpumask *mask, bool force)
 {
-       bfin_internal_mask_irq(irq);
-       bfin_internal_unmask_irq_affinity(irq, mask);
+       bfin_internal_mask_irq(d->irq);
+       bfin_internal_unmask_irq_affinity(d->irq, mask);
 
        return 0;
 }
+#else
+static void bfin_internal_unmask_irq_chip(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(d->irq);
+}
 #endif
 
 #ifdef CONFIG_PM
@@ -279,28 +290,33 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
 
        return 0;
 }
+
+static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
+{
+       return bfin_internal_set_wake(d->irq, state);
+}
 #endif
 
 static struct irq_chip bfin_core_irqchip = {
        .name = "CORE",
-       .ack = bfin_ack_noop,
-       .mask = bfin_core_mask_irq,
-       .unmask = bfin_core_unmask_irq,
+       .irq_ack = bfin_ack_noop,
+       .irq_mask = bfin_core_mask_irq,
+       .irq_unmask = bfin_core_unmask_irq,
 };
 
 static struct irq_chip bfin_internal_irqchip = {
        .name = "INTN",
-       .ack = bfin_ack_noop,
-       .mask = bfin_internal_mask_irq,
-       .unmask = bfin_internal_unmask_irq,
-       .mask_ack = bfin_internal_mask_irq,
-       .disable = bfin_internal_mask_irq,
-       .enable = bfin_internal_unmask_irq,
+       .irq_ack = bfin_ack_noop,
+       .irq_mask = bfin_internal_mask_irq_chip,
+       .irq_unmask = bfin_internal_unmask_irq_chip,
+       .irq_mask_ack = bfin_internal_mask_irq_chip,
+       .irq_disable = bfin_internal_mask_irq_chip,
+       .irq_enable = bfin_internal_unmask_irq_chip,
 #ifdef CONFIG_SMP
-       .set_affinity = bfin_internal_set_affinity,
+       .irq_set_affinity = bfin_internal_set_affinity,
 #endif
 #ifdef CONFIG_PM
-       .set_wake = bfin_internal_set_wake,
+       .irq_set_wake = bfin_internal_set_wake_chip,
 #endif
 };
 
@@ -312,33 +328,32 @@ static void bfin_handle_irq(unsigned irq)
        __ipipe_handle_irq(irq, &regs);
        ipipe_trace_irq_exit(irq);
 #else /* !CONFIG_IPIPE */
-       struct irq_desc *desc = irq_desc + irq;
-       desc->handle_irq(irq, desc);
+       generic_handle_irq(irq);
 #endif  /* !CONFIG_IPIPE */
 }
 
 #ifdef BF537_GENERIC_ERROR_INT_DEMUX
 static int error_int_mask;
 
-static void bfin_generic_error_mask_irq(unsigned int irq)
+static void bfin_generic_error_mask_irq(struct irq_data *d)
 {
-       error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
+       error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
        if (!error_int_mask)
                bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
 }
 
-static void bfin_generic_error_unmask_irq(unsigned int irq)
+static void bfin_generic_error_unmask_irq(struct irq_data *d)
 {
        bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
-       error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
+       error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
 }
 
 static struct irq_chip bfin_generic_error_irqchip = {
        .name = "ERROR",
-       .ack = bfin_ack_noop,
-       .mask_ack = bfin_generic_error_mask_irq,
-       .mask = bfin_generic_error_mask_irq,
-       .unmask = bfin_generic_error_unmask_irq,
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bfin_generic_error_mask_irq,
+       .irq_mask = bfin_generic_error_mask_irq,
+       .irq_unmask = bfin_generic_error_unmask_irq,
 };
 
 static void bfin_demux_error_irq(unsigned int int_err_irq,
@@ -448,8 +463,10 @@ static void bfin_mac_status_ack_irq(unsigned int irq)
        }
 }
 
-static void bfin_mac_status_mask_irq(unsigned int irq)
+static void bfin_mac_status_mask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
 #ifdef BF537_GENERIC_ERROR_INT_DEMUX
        switch (irq) {
@@ -466,8 +483,10 @@ static void bfin_mac_status_mask_irq(unsigned int irq)
        bfin_mac_status_ack_irq(irq);
 }
 
-static void bfin_mac_status_unmask_irq(unsigned int irq)
+static void bfin_mac_status_unmask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
 #ifdef BF537_GENERIC_ERROR_INT_DEMUX
        switch (irq) {
        case IRQ_MAC_PHYINT:
@@ -484,7 +503,7 @@ static void bfin_mac_status_unmask_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_PM
-int bfin_mac_status_set_wake(unsigned int irq, unsigned int state)
+int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state)
 {
 #ifdef BF537_GENERIC_ERROR_INT_DEMUX
        return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
@@ -496,12 +515,12 @@ int bfin_mac_status_set_wake(unsigned int irq, unsigned int state)
 
 static struct irq_chip bfin_mac_status_irqchip = {
        .name = "MACST",
-       .ack = bfin_ack_noop,
-       .mask_ack = bfin_mac_status_mask_irq,
-       .mask = bfin_mac_status_mask_irq,
-       .unmask = bfin_mac_status_unmask_irq,
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bfin_mac_status_mask_irq,
+       .irq_mask = bfin_mac_status_mask_irq,
+       .irq_unmask = bfin_mac_status_unmask_irq,
 #ifdef CONFIG_PM
-       .set_wake = bfin_mac_status_set_wake,
+       .irq_set_wake = bfin_mac_status_set_wake,
 #endif
 };
 
@@ -538,13 +557,9 @@ static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
 static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle)
 {
 #ifdef CONFIG_IPIPE
-       _set_irq_handler(irq, handle_level_irq);
-#else
-       struct irq_desc *desc = irq_desc + irq;
-       /* May not call generic set_irq_handler() due to spinlock
-          recursion. */
-       desc->handle_irq = handle;
+       handle = handle_level_irq;
 #endif
+       __set_irq_handler_unlocked(irq, handle);
 }
 
 static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS);
@@ -552,17 +567,18 @@ extern void bfin_gpio_irq_prepare(unsigned gpio);
 
 #if !defined(CONFIG_BF54x)
 
-static void bfin_gpio_ack_irq(unsigned int irq)
+static void bfin_gpio_ack_irq(struct irq_data *d)
 {
        /* AFAIK ack_irq in case mask_ack is provided
         * get's only called for edge sense irqs
         */
-       set_gpio_data(irq_to_gpio(irq), 0);
+       set_gpio_data(irq_to_gpio(d->irq), 0);
 }
 
-static void bfin_gpio_mask_ack_irq(unsigned int irq)
+static void bfin_gpio_mask_ack_irq(struct irq_data *d)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       unsigned int irq = d->irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        u32 gpionr = irq_to_gpio(irq);
 
        if (desc->handle_irq == handle_edge_irq)
@@ -571,39 +587,40 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
        set_gpio_maska(gpionr, 0);
 }
 
-static void bfin_gpio_mask_irq(unsigned int irq)
+static void bfin_gpio_mask_irq(struct irq_data *d)
 {
-       set_gpio_maska(irq_to_gpio(irq), 0);
+       set_gpio_maska(irq_to_gpio(d->irq), 0);
 }
 
-static void bfin_gpio_unmask_irq(unsigned int irq)
+static void bfin_gpio_unmask_irq(struct irq_data *d)
 {
-       set_gpio_maska(irq_to_gpio(irq), 1);
+       set_gpio_maska(irq_to_gpio(d->irq), 1);
 }
 
-static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+static unsigned int bfin_gpio_irq_startup(struct irq_data *d)
 {
-       u32 gpionr = irq_to_gpio(irq);
+       u32 gpionr = irq_to_gpio(d->irq);
 
        if (__test_and_set_bit(gpionr, gpio_enabled))
                bfin_gpio_irq_prepare(gpionr);
 
-       bfin_gpio_unmask_irq(irq);
+       bfin_gpio_unmask_irq(d);
 
        return 0;
 }
 
-static void bfin_gpio_irq_shutdown(unsigned int irq)
+static void bfin_gpio_irq_shutdown(struct irq_data *d)
 {
-       u32 gpionr = irq_to_gpio(irq);
+       u32 gpionr = irq_to_gpio(d->irq);
 
-       bfin_gpio_mask_irq(irq);
+       bfin_gpio_mask_irq(d);
        __clear_bit(gpionr, gpio_enabled);
        bfin_gpio_irq_free(gpionr);
 }
 
-static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
+       unsigned int irq = d->irq;
        int ret;
        char buf[16];
        u32 gpionr = irq_to_gpio(irq);
@@ -664,9 +681,9 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 }
 
 #ifdef CONFIG_PM
-int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
+int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
-       return gpio_pm_wakeup_ctrl(irq_to_gpio(irq), state);
+       return gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state);
 }
 #endif
 
@@ -818,10 +835,10 @@ void init_pint_lut(void)
        }
 }
 
-static void bfin_gpio_ack_irq(unsigned int irq)
+static void bfin_gpio_ack_irq(struct irq_data *d)
 {
-       struct irq_desc *desc = irq_desc + irq;
-       u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       struct irq_desc *desc = irq_to_desc(d->irq);
+       u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 pintbit = PINT_BIT(pint_val);
        u32 bank = PINT_2_BANK(pint_val);
 
@@ -835,10 +852,10 @@ static void bfin_gpio_ack_irq(unsigned int irq)
 
 }
 
-static void bfin_gpio_mask_ack_irq(unsigned int irq)
+static void bfin_gpio_mask_ack_irq(struct irq_data *d)
 {
-       struct irq_desc *desc = irq_desc + irq;
-       u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       struct irq_desc *desc = irq_to_desc(d->irq);
+       u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 pintbit = PINT_BIT(pint_val);
        u32 bank = PINT_2_BANK(pint_val);
 
@@ -853,24 +870,25 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
        pint[bank]->mask_clear = pintbit;
 }
 
-static void bfin_gpio_mask_irq(unsigned int irq)
+static void bfin_gpio_mask_irq(struct irq_data *d)
 {
-       u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
 
        pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
 }
 
-static void bfin_gpio_unmask_irq(unsigned int irq)
+static void bfin_gpio_unmask_irq(struct irq_data *d)
 {
-       u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 pintbit = PINT_BIT(pint_val);
        u32 bank = PINT_2_BANK(pint_val);
 
        pint[bank]->mask_set = pintbit;
 }
 
-static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+static unsigned int bfin_gpio_irq_startup(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        u32 gpionr = irq_to_gpio(irq);
        u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
 
@@ -884,22 +902,23 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
        if (__test_and_set_bit(gpionr, gpio_enabled))
                bfin_gpio_irq_prepare(gpionr);
 
-       bfin_gpio_unmask_irq(irq);
+       bfin_gpio_unmask_irq(d);
 
        return 0;
 }
 
-static void bfin_gpio_irq_shutdown(unsigned int irq)
+static void bfin_gpio_irq_shutdown(struct irq_data *d)
 {
-       u32 gpionr = irq_to_gpio(irq);
+       u32 gpionr = irq_to_gpio(d->irq);
 
-       bfin_gpio_mask_irq(irq);
+       bfin_gpio_mask_irq(d);
        __clear_bit(gpionr, gpio_enabled);
        bfin_gpio_irq_free(gpionr);
 }
 
-static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
+       unsigned int irq = d->irq;
        int ret;
        char buf[16];
        u32 gpionr = irq_to_gpio(irq);
@@ -961,10 +980,10 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 u32 pint_saved_masks[NR_PINT_SYS_IRQS];
 u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
 
-int bfin_gpio_set_wake(unsigned int irq, unsigned int state)
+int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
        u32 pint_irq;
-       u32 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 bank = PINT_2_BANK(pint_val);
        u32 pintbit = PINT_BIT(pint_val);
 
@@ -1066,17 +1085,17 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
 
 static struct irq_chip bfin_gpio_irqchip = {
        .name = "GPIO",
-       .ack = bfin_gpio_ack_irq,
-       .mask = bfin_gpio_mask_irq,
-       .mask_ack = bfin_gpio_mask_ack_irq,
-       .unmask = bfin_gpio_unmask_irq,
-       .disable = bfin_gpio_mask_irq,
-       .enable = bfin_gpio_unmask_irq,
-       .set_type = bfin_gpio_irq_type,
-       .startup = bfin_gpio_irq_startup,
-       .shutdown = bfin_gpio_irq_shutdown,
+       .irq_ack = bfin_gpio_ack_irq,
+       .irq_mask = bfin_gpio_mask_irq,
+       .irq_mask_ack = bfin_gpio_mask_ack_irq,
+       .irq_unmask = bfin_gpio_unmask_irq,
+       .irq_disable = bfin_gpio_mask_irq,
+       .irq_enable = bfin_gpio_unmask_irq,
+       .irq_set_type = bfin_gpio_irq_type,
+       .irq_startup = bfin_gpio_irq_startup,
+       .irq_shutdown = bfin_gpio_irq_shutdown,
 #ifdef CONFIG_PM
-       .set_wake = bfin_gpio_set_wake,
+       .irq_set_wake = bfin_gpio_set_wake,
 #endif
 };
 
@@ -1373,7 +1392,7 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
        struct ipipe_domain *this_domain = __ipipe_current_domain;
        struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop;
        struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
-       int irq, s;
+       int irq, s = 0;
 
        if (likely(vec == EVT_IVTMR_P))
                irq = IRQ_CORETMR;
@@ -1423,6 +1442,21 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
                        __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10;
        }
 
+       /*
+        * We don't want Linux interrupt handlers to run at the
+        * current core priority level (i.e. < EVT15), since this
+        * might delay other interrupts handled by a high priority
+        * domain. Here is what we do instead:
+        *
+        * - we raise the SYNCDEFER bit to prevent
+        * __ipipe_handle_irq() to sync the pipeline for the root
+        * stage for the incoming interrupt. Upon return, that IRQ is
+        * pending in the interrupt log.
+        *
+        * - we raise the TIF_IRQ_SYNC bit for the current thread, so
+        * that _schedule_and_signal_from_int will eventually sync the
+        * pipeline from EVT15.
+        */
        if (this_domain == ipipe_root_domain) {
                s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status);
                barrier();
@@ -1432,6 +1466,24 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
        __ipipe_handle_irq(irq, regs);
        ipipe_trace_irq_exit(irq);
 
+       if (user_mode(regs) &&
+           !ipipe_test_foreign_stack() &&
+           (current->ipipe_flags & PF_EVTRET) != 0) {
+               /*
+                * Testing for user_regs() does NOT fully eliminate
+                * foreign stack contexts, because of the forged
+                * interrupt returns we do through
+                * __ipipe_call_irqtail. In that case, we might have
+                * preempted a foreign stack context in a high
+                * priority domain, with a single interrupt level now
+                * pending after the irqtail unwinding is done. In
+                * which case user_mode() is now true, and the event
+                * gets dispatched spuriously.
+                */
+               current->ipipe_flags &= ~PF_EVTRET;
+               __ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs);
+       }
+
        if (this_domain == ipipe_root_domain) {
                set_thread_flag(TIF_IRQ_SYNC);
                if (!s) {
index 9f251406a76aced1985dc69f3d461ad5bf5bdaca..6e17a265c4d3158761450463b3c5a66e63a39bab 100644 (file)
  */
 struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
 
+#ifdef CONFIG_ICACHE_FLUSH_L1
+unsigned long blackfin_iflush_l1_entry[NR_CPUS];
+#endif
+
 void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
        *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb,
        *init_saved_dcplb_fault_addr_coreb;
@@ -105,10 +109,10 @@ static void ipi_flush_icache(void *info)
        struct blackfin_flush_data *fdata = info;
 
        /* Invalidate the memory holding the bounds of the flushed region. */
-       blackfin_dcache_invalidate_range((unsigned long)fdata,
-                                        (unsigned long)fdata + sizeof(*fdata));
+       invalidate_dcache_range((unsigned long)fdata,
+               (unsigned long)fdata + sizeof(*fdata));
 
-       blackfin_icache_flush_range(fdata->start, fdata->end);
+       flush_icache_range(fdata->start, fdata->end);
 }
 
 static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
@@ -244,12 +248,13 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
 {
        cpumask_t callmap;
 
+       preempt_disable();
        callmap = cpu_online_map;
        cpu_clear(smp_processor_id(), callmap);
-       if (cpus_empty(callmap))
-               return 0;
+       if (!cpus_empty(callmap))
+               smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
 
-       smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
+       preempt_enable();
 
        return 0;
 }
@@ -286,12 +291,13 @@ void smp_send_stop(void)
 {
        cpumask_t callmap;
 
+       preempt_disable();
        callmap = cpu_online_map;
        cpu_clear(smp_processor_id(), callmap);
-       if (cpus_empty(callmap))
-               return;
+       if (!cpus_empty(callmap))
+               smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0);
 
-       smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0);
+       preempt_enable();
 
        return;
 }
@@ -361,8 +367,6 @@ void __cpuinit secondary_start_kernel(void)
         */
        init_exception_vectors();
 
-       bfin_setup_caches(cpu);
-
        local_irq_disable();
 
        /* Attach the new idle task to the global mm. */
@@ -381,6 +385,8 @@ void __cpuinit secondary_start_kernel(void)
 
        local_irq_enable();
 
+       bfin_setup_caches(cpu);
+
        /*
         * Calibrate loops per jiffy value.
         * IRQs need to be enabled here - D-cache can be invalidated
index 9e69cfb7f1342a86c4e22617d36cefbf6289de80..310e0de67aa6c80911ad99fdaf91b522787ba8f0 100644 (file)
@@ -154,12 +154,11 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/lock.h>
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(l,n,a)   test_and_set_bit(n,a)
 #define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a)
 
-#include <asm-generic/bitops/minix.h>
 #include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
index 91776069ca807b30c3902922b70889d9e5bb5746..29b74a10583039b474e3fd941665af8f88fd41e9 100644 (file)
@@ -68,7 +68,7 @@ struct thread_info {
 #define init_thread_info       (init_thread_union.thread_info)
 
 /* thread information allocation */
-#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define alloc_thread_info(tsk, node) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
 #define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
 
 #endif /* !__ASSEMBLY__ */
index 5790262cbe8ae8c0da682c622e07b0da13606e7d..551a12c0aa010a5b9507f0c92d5c8979e597a4c9 100644 (file)
@@ -16,15 +16,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide, just like our other addresses.  */
-typedef u32 dma_addr_t;
-typedef u32 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif
index 747499a1b31ef709fb42bed7f0c0acca23a07a74..f6037b2da25ef6f9af5ed31187afac45058c7256 100644 (file)
@@ -22,6 +22,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_HWEIGHT
        bool
        default y
index 50ae91b29674584743e5935aa49e0717fb260b34..a1d00b0c6ed71135c0ce113fb70b4080940fd49f 100644 (file)
@@ -401,13 +401,11 @@ int __ilog2_u64(u64 n)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(lock,nr,addr)      test_and_set_bit  ((nr) ^ 0x18, (addr))
 #define ext2_clear_bit_atomic(lock,nr,addr)    test_and_clear_bit((nr) ^ 0x18, (addr))
 
-#include <asm-generic/bitops/minix-le.h>
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_BITOPS_H */
index 3744f2e47f48fcd92fe03e9e89b550b841736e6d..4b789ab182b0879e008cb4a8b63943e3390c3bb2 100644 (file)
@@ -137,7 +137,7 @@ unsigned long get_wchan(struct task_struct *p);
 #define        KSTK_ESP(tsk)   ((tsk)->thread.frame0->sp)
 
 /* Allocation and freeing of basic task resources. */
-extern struct task_struct *alloc_task_struct(void);
+extern struct task_struct *alloc_task_struct_node(int node);
 extern void free_task_struct(struct task_struct *p);
 
 #define cpu_relax()    barrier()
index 11f33ead29bf3244b5169cf2073692782b8a9233..8582e9c7531c8f3433f0749fec1861cf92847919 100644 (file)
@@ -84,16 +84,11 @@ register struct thread_info *__current_thread_info asm("gr15");
 
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk)                                 \
-       ({                                                      \
-               struct thread_info *ret;                        \
-                                                               \
-               ret = kzalloc(THREAD_SIZE, GFP_KERNEL);         \
-                                                               \
-               ret;                                            \
-       })
+#define alloc_thread_info_node(tsk, node)                      \
+               kzalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk)                            \
+               kmalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #endif
 
 #define free_thread_info(info) kfree(info)
index 613bf1e962f07b08fdef6b512b0cfd87da468791..aa3e7fdc7f29ecea5b1ff5e569100e463c9e4c82 100644 (file)
@@ -27,14 +27,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TYPES_H */
index efad12071c2e7b95324e9a1f0a8f7e88a6a7d645..9d359752646741b426596f4fb43671e6000cf18d 100644 (file)
@@ -44,9 +44,10 @@ asmlinkage void ret_from_fork(void);
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
-struct task_struct *alloc_task_struct(void)
+struct task_struct *alloc_task_struct_node(int node)
 {
-       struct task_struct *p = kmalloc(THREAD_SIZE, GFP_KERNEL);
+       struct task_struct *p = kmalloc_node(THREAD_SIZE, GFP_KERNEL, node);
+
        if (p)
                atomic_set((atomic_t *)(p+1), 1);
        return p;
index 6df692d1475f7ffb2549ab62929374a2daafcb54..931a1ac99ff18ed8f5970ea06d389f7fd7e2010e 100644 (file)
@@ -4,6 +4,7 @@ config H8300
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_HARDIRQS_NO_DEPRECATED
+       select GENERIC_IRQ_SHOW
 
 config SYMBOL_PREFIX
        string
@@ -45,6 +46,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_HWEIGHT
        bool
        default y
index d6189e057ed354804f04822ee78e73f2e069b827..6745cb1ffb4f71340f50a3710f9f8ec9bc2c840e 100644 (file)
@@ -5,7 +5,7 @@
 #
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
-EXTRA_AFLAGS   := -traditional
+asflags-y      := -traditional
 
 OBJECTS = $(obj)/head.o $(obj)/misc.o
 
index cb9ddf5fc54ff3837c8393a8e891a8e4766216f9..e856c1bb34157e36ad433400b1d10945e0c056e0 100644 (file)
@@ -200,9 +200,8 @@ static __inline__ unsigned long __ffs(unsigned long word)
 #include <asm-generic/bitops/sched.h>
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
index 12875190b156647b430033ff61b7894b14e3f53b..bb2c91a3522e71c185ab6bfb58ff915b5d1ac9f3 100644 (file)
@@ -22,10 +22,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index 7643d39925d68d0fb7bd37d6ed4f0c2d3a5ea426..1f67fed476afdead1be58fe924aace28cd89b558 100644 (file)
@@ -155,7 +155,7 @@ void __init init_IRQ(void)
        setup_vector();
 
        for (c = 0; c < NR_IRQS; c++)
-               set_irq_chip_and_handler(c, &h8300irq_chip, handle_simple_irq);
+               irq_set_chip_and_handler(c, &h8300irq_chip, handle_simple_irq);
 }
 
 asmlinkage void do_IRQ(int irq)
@@ -164,34 +164,3 @@ asmlinkage void do_IRQ(int irq)
        generic_handle_irq(irq);
        irq_exit();
 }
-
-#if defined(CONFIG_PROC_FS)
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v;
-       struct irqaction * action;
-       unsigned long flags;
-
-       if (i == 0)
-               seq_puts(p, "           CPU0");
-
-       if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
-               if (!action)
-                       goto unlock;
-               seq_printf(p, "%3d: ",i);
-               seq_printf(p, "%10u ", kstat_irqs(i));
-               seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
-               seq_printf(p, "-%-8s", irq_desc[i].name);
-               seq_printf(p, "  %s", action->name);
-
-               for (action=action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-               seq_putc(p, '\n');
-unlock:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-       }
-       return 0;
-}
-#endif
index 837dc82a013eb7f93b792bf0d4c713ce1939ba81..a06dfb13d518cbf350f70df5c68621ef65a145c3 100644 (file)
@@ -128,9 +128,9 @@ static inline const char *acpi_get_sysname (void)
 int acpi_request_vector (u32 int_type);
 int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
-/* routines for saving/restoring kernel state */
-extern int acpi_save_state_mem(void);
-extern void acpi_restore_state_mem(void);
+/* Low-level suspend routine. */
+extern int acpi_suspend_lowlevel(void);
+
 extern unsigned long acpi_wakeup_address;
 
 /*
index 9da3df6f1a522b7ac46330918967776343d67652..b76f7e009218bec2ed2327caa715f15ce7981aef 100644 (file)
@@ -456,12 +456,11 @@ static __inline__ unsigned long __arch_hweight64(unsigned long x)
 
 #ifdef __KERNEL__
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(l,n,a)     test_and_set_bit(n,a)
 #define ext2_clear_bit_atomic(l,n,a)   test_and_clear_bit(n,a)
 
-#include <asm-generic/bitops/minix.h>
 #include <asm-generic/bitops/sched.h>
 
 #endif /* __KERNEL__ */
index b6a5ba2aca3429f7bd4a7602c21f81f011bf0205..ff0cc84e7bcc11cfb4af82d819d25e9610bdd387 100644 (file)
@@ -59,11 +59,12 @@ struct thread_info {
 #ifndef ASM_OFFSETS_C
 /* how to get the thread information struct from C */
 #define current_thread_info()  ((struct thread_info *) ((char *) current + IA64_TASK_SIZE))
-#define alloc_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
+#define alloc_thread_info_node(tsk, node)      \
+               ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
 #define task_thread_info(tsk)  ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
 #else
 #define current_thread_info()  ((struct thread_info *) 0)
-#define alloc_thread_info(tsk) ((struct thread_info *) 0)
+#define alloc_thread_info_node(tsk, node)      ((struct thread_info *) 0)
 #define task_thread_info(tsk)  ((struct thread_info *) 0)
 #endif
 #define free_thread_info(ti)   /* nothing */
@@ -84,7 +85,14 @@ struct thread_info {
 #define end_of_stack(p) (unsigned long *)((void *)(p) + IA64_RBS_OFFSET)
 
 #define __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
-#define alloc_task_struct()    ((struct task_struct *)__get_free_pages(GFP_KERNEL | __GFP_COMP, KERNEL_STACK_SIZE_ORDER))
+#define alloc_task_struct_node(node)                                           \
+({                                                                             \
+       struct page *page = alloc_pages_node(node, GFP_KERNEL | __GFP_COMP,     \
+                                            KERNEL_STACK_SIZE_ORDER);          \
+       struct task_struct *ret = page ? page_address(page) : NULL;             \
+                                                                               \
+       ret;                                                                    \
+})
 #define free_task_struct(tsk)  free_pages((unsigned long) (tsk), KERNEL_STACK_SIZE_ORDER)
 
 #endif /* !__ASSEMBLY */
index 93773fd37be0fec66fbc10f702da8aad4c91f62c..82b3939d2718fe80698b8ce04924fdafc7cf42d6 100644 (file)
@@ -40,9 +40,6 @@ struct fnptr {
        unsigned long gp;
 };
 
-/* DMA addresses are 64-bits wide, in general.  */
-typedef u64 dma_addr_t;
-
 # endif /* __KERNEL__ */
 #endif /* !__ASSEMBLY__ */
 
index 954d398a54b4e7f60de2aaeabef172a0774fd93f..404d037c5e10e4460ac04373051986fae9f874d5 100644 (file)
 #define __NR_fanotify_init             1323
 #define __NR_fanotify_mark             1324
 #define __NR_prlimit64                 1325
+#define __NR_name_to_handle_at         1326
+#define __NR_open_by_handle_at         1327
+#define __NR_clock_adjtime             1328
+#define __NR_syncfs                    1329
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    302 /* length of syscall table */
+#define NR_syscalls                    306 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 90ebceb899a0840bd66deae5e9d4446ed027c7f4..3be485a300b1426af87db0d545a4ca176e8d67be 100644 (file)
@@ -803,7 +803,7 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
  *  ACPI based hotplug CPU support
  */
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
-static
+static __cpuinit
 int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
 {
 #ifdef CONFIG_ACPI_NUMA
@@ -878,7 +878,7 @@ __init void prefill_possible_map(void)
                set_cpu_possible(i, true);
 }
 
-int acpi_map_lsapic(acpi_handle handle, int *pcpu)
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
@@ -929,6 +929,11 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
        return (0);
 }
 
+/* wrapper to silence section mismatch warning */
+int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+       return _acpi_map_lsapic(handle, pcpu);
+}
 EXPORT_SYMBOL(acpi_map_lsapic);
 
 int acpi_unmap_lsapic(int cpu)
@@ -1034,18 +1039,8 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 EXPORT_SYMBOL(acpi_unregister_ioapic);
 
 /*
- * acpi_save_state_mem() - save kernel state
+ * acpi_suspend_lowlevel() - save kernel state and suspend.
  *
  * TBD when when IA64 starts to support suspend...
  */
-int acpi_save_state_mem(void) { return 0; } 
-
-/*
- * acpi_restore_state()
- */
-void acpi_restore_state_mem(void) {}
-
-/*
- * do_suspend_lowlevel()
- */
-void do_suspend_lowlevel(void) {}
+int acpi_suspend_lowlevel(void) { return 0; }
index 23e91290e41faf3151bbb93a7bfdde76553ecb3a..c8c9298666fb65cefdf1b5991b7dafa3ad8238dc 100644 (file)
@@ -13,9 +13,6 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 
-/* Stores the physical address of elf header of crash image. */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
 /**
  * copy_oldmem_page - copy one page from "oldmem"
  * @pfn: page frame number to be copied
index a0f001928502b6c1b8e692e36095df36e6b7f3b5..6fc03aff046c6a133a79d1305aa7b163fd310b70 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include <linux/module.h>
 #include <linux/bootmem.h>
+#include <linux/crash_dump.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
index 244704a174dec2d79efca8481165cc978a1a7c3a..6de2e23b3636e422e6e3e7ca09f69decb6b9a310 100644 (file)
@@ -1771,6 +1771,10 @@ sys_call_table:
        data8 sys_fanotify_init
        data8 sys_fanotify_mark
        data8 sys_prlimit64                     // 1325
+       data8 sys_name_to_handle_at
+       data8 sys_open_by_handle_at
+       data8 sys_clock_adjtime
+       data8 sys_syncfs
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 911cf974970008c6e01a92c36c2d1233ece62f8a..5e2c72498c516322d14b293b81b4365593bff1d1 100644 (file)
@@ -479,25 +479,7 @@ static __init int setup_nomca(char *s)
 }
 early_param("nomca", setup_nomca);
 
-/*
- * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
- * is_kdump_kernel() to determine if we are booting after a panic. Hence
- * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
- */
 #ifdef CONFIG_CRASH_DUMP
-/* elfcorehdr= specifies the location of elf core header
- * stored by the crashed kernel.
- */
-static int __init parse_elfcorehdr(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-        elfcorehdr_addr = memparse(arg, &arg);
-       return 0;
-}
-early_param("elfcorehdr", parse_elfcorehdr);
-
 int __init reserve_elfcorehdr(u64 *start, u64 *end)
 {
        u64 length;
index 1089b3e918ace7d533bbecd96de0be54deb26cad..db3d7c5d10711a1d0357a0c179e752f1d6f0df58 100644 (file)
@@ -45,8 +45,8 @@ FORCE : $(obj)/$(offsets-file)
 # Makefile for Kernel-based Virtual Machine module
 #
 
-EXTRA_CFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
-EXTRA_AFLAGS += -Ivirt/kvm -Iarch/ia64/kvm/
+ccflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
+asflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
 
 common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
                coalesced_mmio.o irq_comm.o assigned-dev.o)
index 54bf540598118339a04919e1f08c505a5ad57cd8..9a018cde5d84d5c3718c3fef41d6557aa392d14b 100644 (file)
@@ -36,7 +36,7 @@ static unsigned long max_gap;
  * Shows a simple page count of reserved and used pages in the system.
  * For discontig machines, it does this on a per-pgdat basis.
  */
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        int i, total_reserved = 0;
        int total_shared = 0, total_cached = 0;
index 61620323bb60adadf942288b53446604d8323b69..82ab1bc6afb1236460c0e380a2a5fbf61a5b8e1b 100644 (file)
@@ -614,7 +614,7 @@ void __cpuinit *per_cpu_init(void)
  * Shows a simple page count of reserved and used pages in the system.
  * For discontig machines, it does this on a per-pgdat basis.
  */
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        int i, total_reserved = 0;
        int total_shared = 0, total_cached = 0;
index 0591038735af53e40e128dd0b7fc0e4f4e7ab286..d27df1d45da7b224a184758b831d264030169903 100644 (file)
@@ -7,7 +7,7 @@
 # Copyright (C) 1999,2001-2006,2008 Silicon Graphics, Inc.  All Rights Reserved.
 #
 
-EXTRA_CFLAGS += -Iarch/ia64/sn/include
+ccflags-y := -Iarch/ia64/sn/include
 
 obj-y                          += setup.o bte.o bte_error.o irq.o mca.o idle.o \
                                   huberror.o io_acpi_init.o io_common.o \
index 08e6565dc908d0b0f5e8358a14698211439bb1c0..3d09108d42776658d193c9e57b59becdfadec881 100644 (file)
@@ -9,7 +9,7 @@
 # sn2 specific kernel files
 #
 
-EXTRA_CFLAGS += -Iarch/ia64/sn/include
+ccflags-y := -Iarch/ia64/sn/include
 
 obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \
         prominfo_proc.o timer.o timer_interrupt.o sn_hwperf.o
index ad4ef34dfe263cd66b496c445fd26e61246d02b7..df2a9014542664cf34b0c6f89b76fa898f95bb6d 100644 (file)
@@ -7,6 +7,6 @@
 #
 # Makefile for the sn pci general routines.
 
-EXTRA_CFLAGS += -Iarch/ia64/sn/include
+ccflags-y := -Iarch/ia64/sn/include
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
index 01192d3247ddef19b1388cf39be80c03e3ee6d88..396bcae36309ab35e45e827546fd48db3b55e88e 100644 (file)
@@ -7,7 +7,7 @@
 #
 # Makefile for the sn2 io routines.
 
-EXTRA_CFLAGS += -Iarch/ia64/sn/include
+ccflags-y := -Iarch/ia64/sn/include
 
 obj-y                          +=  pcibr_dma.o pcibr_reg.o \
                                    pcibr_ate.o pcibr_provider.o
index 8d92b4684d8e06714b06fbaacfcaec452c58a086..124e441d383d89d72ef72a5965e1d4875ece3b79 100644 (file)
@@ -7,7 +7,7 @@
 # Copyright (C) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 #
 
-EXTRA_CFLAGS += -Iarch/ia64/sn/include
+ccflags-y := -Iarch/ia64/sn/include
 
 obj-y                          += setup.o
 obj-$(CONFIG_IA64_GENERIC)      += machvec.o
index ef4c1e442be34a4d9c3289e1b5b9d7b262617047..b28d0908a402d7bbdd7ced55a785713a314e4203 100644 (file)
@@ -10,6 +10,7 @@ config M32R
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_HARDIRQS_NO_DEPRECATED
        select GENERIC_IRQ_PROBE
+       select GENERIC_IRQ_SHOW
 
 config SBUS
        bool
@@ -260,6 +261,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_HWEIGHT
        bool
        default y
index aaddf0d5760326626616ecfdf3c884c196f924bb..6300f22cdbdbce380e7333f382dc70655ce73cd0 100644 (file)
@@ -266,9 +266,8 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 
 #ifdef __KERNEL__
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
index 71faff5bcc278e4dff72c942629a6a1b5dd6a789..0227dba44068b87b8e4406f05d57340fcdec3c87 100644 (file)
@@ -96,16 +96,11 @@ static inline struct thread_info *current_thread_info(void)
 
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk)                                 \
-       ({                                                      \
-               struct thread_info *ret;                        \
-                                                               \
-               ret = kzalloc(THREAD_SIZE, GFP_KERNEL);         \
-                                                               \
-               ret;                                            \
-        })
+#define alloc_thread_info_node(tsk, node)                      \
+               kzalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node)                      \
+               kmalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #endif
 
 #define free_thread_info(info) kfree(info)
index bc9f7fff0ac399da986bfc54bba6003aa9828b07..bd0035597b3bcf65ce82150cfaffc50f97a97348 100644 (file)
@@ -16,15 +16,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* DMA addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-typedef u64 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_M32R_TYPES_H */
index 76eaf3883fbd700f74a72a4afd88d0c07d494485..c7272b8942835adb9f39a80d8026ea6cbfd42798 100644 (file)
 
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <linux/seq_file.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-/*
- * Generic, controller-independent functions:
- */
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v, j;
-       struct irqaction * action;
-       unsigned long flags;
-
-       if (i == 0) {
-               seq_printf(p, "           ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ",j);
-               seq_putc(p, '\n');
-       }
-
-       if (i < NR_IRQS) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               raw_spin_lock_irqsave(&desc->lock, flags);
-               action = desc->action;
-               if (!action)
-                       goto skip;
-               seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
-               seq_printf(p, " %14s", desc->irq_data.chip->name);
-               seq_printf(p, "  %s", action->name);
-
-               for (action=action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-
-               seq_putc(p, '\n');
-skip:
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-       }
-       return 0;
-}
-
 /*
  * do_IRQ handles all normal device IRQs (the special
  * SMP cross-CPU interrupts have their own specific
index 4a693d02c1e133cc58a94bdb62acd918f8af1383..34671d32cefc3daff49c2a05378a26769d6c15a1 100644 (file)
@@ -76,7 +76,7 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/
-       set_irq_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type,
                                 handle_level_irq);
        /* "H" level sense */
        cu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11;
@@ -84,20 +84,20 @@ void __init init_IRQ(void)
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN;
        disable_m32104ut_irq(M32R_IRQ_SIO0_S);
index 2074bcc841eba775047c178a798fa399750c66ef..1053e1cb7401771160f98a306ab0d59cade65016 100644 (file)
@@ -259,76 +259,76 @@ void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
-       set_irq_chip_and_handler(M32700UT_LAN_IRQ_LAN,
+       irq_set_chip_and_handler(M32700UT_LAN_IRQ_LAN,
                                 &m32700ut_lanpld_irq_type, handle_level_irq);
        lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;   /* "H" edge sense */
        disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_m32700ut_irq(M32R_IRQ_MFT2);
 
        /* SIO0 : receive */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0 : send */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1 : receive */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1 : send */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_SIO1_S);
 
        /* DMA1 : */
-       set_irq_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_DMA1].icucr = 0;
        disable_m32700ut_irq(M32R_IRQ_DMA1);
 
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV);
 
        /* INT#1: SIO0 Send on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND);
 #endif  /* CONFIG_SERIAL_M32R_PLDSIO */
 
        /* INT#1: CFC IREQ on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ);
 
        /* INT#1: CFC Insert on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT);
 
        /* INT#1: CFC Eject on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
        disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT);
@@ -349,7 +349,7 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_USB)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
-       set_irq_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1,
+       irq_set_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1,
                                 &m32700ut_lcdpld_irq_type, handle_level_irq);
 
        lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;      /* "L" level sense */
@@ -366,7 +366,7 @@ void __init init_IRQ(void)
        /*
         * INT3# is used for AR
         */
-       set_irq_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_m32700ut_irq(M32R_IRQ_INT3);
index cdd8c457402700fac38db075cfb279fb4bdf0f1f..35130ac3f8d1931c089b3b31cdf913fb8de167af 100644 (file)
@@ -75,39 +75,39 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_NE2000
        /* INT0 : LAN controller (RTL8019AS) */
-       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
        disable_mappi_irq(M32R_IRQ_INT0);
 #endif /* CONFIG_M32R_NE2000 */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_S);
@@ -115,13 +115,13 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_M32R_PCC)
        /* INT1 : pccard0 interrupt */
-       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
        disable_mappi_irq(M32R_IRQ_INT1);
 
        /* INT2 : pccard1 interrupt */
-       set_irq_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
        disable_mappi_irq(M32R_IRQ_INT2);
index 9117c30ea3652386d8d56770df21839ccdf40fd2..f3ed6b60a5f8a271fadd73951268d3111f214405 100644 (file)
@@ -76,38 +76,38 @@ void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
-       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi2_irq(M32R_IRQ_INT0);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi2_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi2_irq(M32R_IRQ_SIO1_S);
@@ -115,27 +115,27 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
-       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
        disable_mappi2_irq(M32R_IRQ_INT1);
 #endif /* CONFIG_USB */
 
        /* ICUCR40: CFC IREQ */
-       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        disable_mappi2_irq(PLD_IRQ_CFIREQ);
 
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
        disable_mappi2_irq(PLD_IRQ_CFC_INSERT);
 
        /* ICUCR42: CFC Eject */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi2_irq(PLD_IRQ_CFC_EJECT);
index b44f5ded2bbeff9fcf96a07ad6e47be6f59fdc3c..2408e356ad1062c88423f73f8c15df5e6791a207 100644 (file)
@@ -75,38 +75,38 @@ void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT0 : LAN controller (SMC91111) */
-       set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi3_irq(M32R_IRQ_INT0);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi3_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO0_S);
        /* SIO1_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi3_irq(M32R_IRQ_SIO1_S);
@@ -114,21 +114,21 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_USB)
        /* INT1 : USB Host controller interrupt */
-       set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
        disable_mappi3_irq(M32R_IRQ_INT1);
 #endif /* CONFIG_USB */
 
        /* CFC IREQ */
-       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
        disable_mappi3_irq(PLD_IRQ_CFIREQ);
 
 #if defined(CONFIG_M32R_CFC)
        /* ICUCR41: CFC Insert & eject */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
        disable_mappi3_irq(PLD_IRQ_CFC_INSERT);
@@ -136,7 +136,7 @@ void __init init_IRQ(void)
 #endif /* CONFIG_M32R_CFC */
 
        /* IDE IREQ */
-       set_irq_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type,
                                 handle_level_irq);
        icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_mappi3_irq(PLD_IRQ_IDEIREQ);
index 19a02db7b818f50e64b79ccd8b3d5804525845a1..83b46b067a17386a401fa7ea867bfa13c8c1c0bc 100644 (file)
@@ -74,39 +74,39 @@ void __init init_IRQ(void)
 
 #ifdef CONFIG_NE2000
        /* INT3 : LAN controller (RTL8019AS) */
-       set_irq_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_oaks32r_irq(M32R_IRQ_INT3);
 #endif /* CONFIG_M32R_NE2000 */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_oaks32r_irq(M32R_IRQ_MFT2);
 
 #ifdef CONFIG_SERIAL_M32R_SIO
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_oaks32r_irq(M32R_IRQ_SIO1_S);
index 12731547e8bf3b104b87a6dfb17c8440ab3a5cb7..32660705f5fdf751741c0cd9ba87afafab56e248 100644 (file)
@@ -259,76 +259,76 @@ void __init init_IRQ(void)
 {
 #if defined(CONFIG_SMC91X)
        /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
-       set_irq_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type,
+       irq_set_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type,
                                 handle_level_irq);
        lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;     /* "H" edge sense */
        disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN);
 #endif  /* CONFIG_SMC91X */
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_opsput_irq(M32R_IRQ_MFT2);
 
        /* SIO0 : receive */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0 : send */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1 : receive */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1 : send */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_opsput_irq(M32R_IRQ_SIO1_S);
 
        /* DMA1 : */
-       set_irq_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_DMA1].icucr = 0;
        disable_opsput_irq(M32R_IRQ_DMA1);
 
 #ifdef CONFIG_SERIAL_M32R_PLDSIO
        /* INT#1: SIO0 Receive on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV);
 
        /* INT#1: SIO0 Send on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
        disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
 #endif  /* CONFIG_SERIAL_M32R_PLDSIO */
 
        /* INT#1: CFC IREQ on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;       /* 'L' level sense */
        disable_opsput_pld_irq(PLD_IRQ_CFIREQ);
 
        /* INT#1: CFC Insert on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00;   /* 'L' edge sense */
        disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT);
 
        /* INT#1: CFC Eject on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02;    /* 'H' edge sense */
        disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
@@ -349,7 +349,7 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_USB)
        outw(USBCR_OTGS, USBCR);        /* USBCR: non-OTG */
-       set_irq_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1,
+       irq_set_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1,
                                 &opsput_lcdpld_irq_type, handle_level_irq);
        lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01;        /* "L" level sense */
        disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
@@ -365,7 +365,7 @@ void __init init_IRQ(void)
        /*
         * INT3# is used for AR
         */
-       set_irq_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
        disable_opsput_irq(M32R_IRQ_INT3);
index f3cff26d6e740c983ebbe34b15b222a1adf66e68..0c7a1e8c77b055d3990a19dc729d5a701abdb848 100644 (file)
@@ -138,32 +138,32 @@ void __init init_IRQ(void)
                once++;
 
        /* MFT2 : system timer */
-       set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
        disable_mappi_irq(M32R_IRQ_MFT2);
 
 #if defined(CONFIG_SERIAL_M32R_SIO)
        /* SIO0_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_R);
 
        /* SIO0_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO0_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO0_S);
 
        /* SIO1_R : uart receive data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_R].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_R);
 
        /* SIO1_S : uart send data */
-       set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+       irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
                                 handle_level_irq);
        icu_data[M32R_IRQ_SIO1_S].icucr = 0;
        disable_mappi_irq(M32R_IRQ_SIO1_S);
@@ -171,7 +171,7 @@ void __init init_IRQ(void)
 
        /* INT#67-#71: CFC#0 IREQ on PLD */
        for (i = 0 ; i < CONFIG_M32R_CFC_NUM ; i++ ) {
-               set_irq_chip_and_handler(PLD_IRQ_CF0 + i,
+               irq_set_chip_and_handler(PLD_IRQ_CF0 + i,
                                         &m32700ut_pld_irq_type,
                                         handle_level_irq);
                pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
@@ -181,14 +181,14 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        /* INT#76: 16552D#0 IREQ on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
                = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
        disable_m32700ut_pld_irq(PLD_IRQ_UART0);
 
        /* INT#77: 16552D#1 IREQ on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
                = PLD_ICUCR_ISMOD03;    /* 'H' level sense */
@@ -197,7 +197,7 @@ void __init init_IRQ(void)
 
 #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
        /* INT#80: AK4524 IREQ on PLD */
-       set_irq_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type,
+       irq_set_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type,
                                 handle_level_irq);
        pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
                = PLD_ICUCR_ISMOD01;    /* 'L' level sense */
index 525174d4167953cd7b14a770f2fc6ba0fbd3775a..6e056d3c5d01a3f7edfabcb99ff5f370f6f6be2c 100644 (file)
@@ -1,13 +1,11 @@
 config M68K
        bool
        default y
-       select HAVE_AOUT
        select HAVE_IDE
-       select GENERIC_ATOMIC64
-
-config MMU
-       bool
-       default y
+       select HAVE_AOUT if MMU
+       select GENERIC_ATOMIC64 if MMU
+       select HAVE_GENERIC_HARDIRQS if !MMU
+       select GENERIC_HARDIRQS_NO_DEPRECATED if !MMU
 
 config RWSEM_GENERIC_SPINLOCK
        bool
@@ -34,457 +32,67 @@ config TIME_LOW_RES
        bool
        default y
 
-config GENERIC_IOMAP
-       bool
-       default y
-
-config ARCH_MAY_HAVE_PC_FDC
-       bool
-       depends on BROKEN && (Q40 || SUN3X)
-       default y
-
 config NO_IOPORT
        def_bool y
 
 config NO_DMA
-       def_bool SUN3
+       def_bool (MMU && SUN3) || (!MMU && !COLDFIRE)
 
+config ZONE_DMA
+       bool
+       default y
 config HZ
        int
+       default 1000 if CLEOPATRA
        default 100
 
-config ARCH_USES_GETTIMEOFFSET
-       def_bool y
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
 
-menu "Platform dependent setup"
-
-config EISA
-       bool
-       ---help---
-         The Extended Industry Standard Architecture (EISA) bus was
-         developed as an open alternative to the IBM MicroChannel bus.
-
-         The EISA bus provided some of the features of the IBM MicroChannel
-         bus while maintaining backward compatibility with cards made for
-         the older ISA bus.  The EISA bus saw limited use between 1988 and
-         1995 when it was made obsolete by the PCI bus.
-
-         Say Y here if you are building a kernel for an EISA-based machine.
-
-         Otherwise, say N.
-
-config MCA
-       bool
-       help
-         MicroChannel Architecture is found in some IBM PS/2 machines and
-         laptops.  It is a bus system similar to PCI or ISA. See
-         <file:Documentation/mca.txt> (and especially the web page given
-         there) before attempting to build an MCA bus kernel.
-
-config PCMCIA
-       tristate
-       ---help---
-         Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
-         computer.  These are credit-card size devices such as network cards,
-         modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.  If you want to use CardBus
-         cards, you need to say Y here and also to "CardBus support" below.
-
-         To use your PC-cards, you will need supporting software from David
-         Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-         for location).  Please also read the PCMCIA-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as modules, choose M here: the
-         modules will be called pcmcia_core and ds.
-
-config AMIGA
-       bool "Amiga support"
-       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
-         material available in <file:Documentation/m68k>; otherwise say N.
-
-config ATARI
-       bool "Atari support"
-       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 MAC
-       bool "Macintosh support"
-       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
-         of the series).
-
-         Say N unless you're willing to code the remaining necessary support.
-         ;)
-
-config NUBUS
-       bool
-       depends on MAC
-       default y
-
-config M68K_L2_CACHE
-       bool
-       depends on MAC
-       default y
-
-config APOLLO
-       bool "Apollo support"
-       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"
-       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,
-         MVME162, MVME166, MVME167, MVME172, and MVME177.  BVME4000 and
-         BVME6000 boards from BVM Ltd are also supported.
-
-config MVME147
-       bool "MVME147 support"
-       depends on VME
-       help
-         Say Y to include support for early Motorola VME boards.  This will
-         build a kernel which can run on MVME147 single-board computers.  If
-         you select this option you will have to select the appropriate
-         drivers for SCSI, Ethernet and serial ports later on.
-
-config MVME16x
-       bool "MVME162, 166 and 167 support"
-       depends on VME
-       help
-         Say Y to include support for Motorola VME boards.  This will build a
-         kernel which can run on MVME162, MVME166, MVME167, MVME172, and
-         MVME177 boards.  If you select this option you will have to select
-         the appropriate drivers for SCSI, Ethernet and serial ports later
-         on.
-
-config BVME6000
-       bool "BVME4000 and BVME6000 support"
-       depends on VME
-       help
-         Say Y to include support for VME boards from BVM Ltd.  This will
-         build a kernel which can run on BVME4000 and BVME6000 boards.  If
-         you select this option you will have to select the appropriate
-         drivers for SCSI, Ethernet and serial ports later on.
-
-config HP300
-       bool "HP9000/300 and HP9000/400 support"
-       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
-         experimental. If you plan to try to use the kernel on such a machine
-         say Y here.
-         Everybody else says N.
-
-config DIO
-       bool "DIO bus support"
-       depends on HP300
+config MMU
+       bool "MMU-based Paged Memory Management Support"
        default y
        help
-         Say Y here to enable support for the "DIO" expansion bus used in
-         HP300 machines. If you are using such a system you almost certainly
-         want this.
-
-config SUN3X
-       bool "Sun3x support"
-       select MMU_MOTOROLA if MMU
-       select M68030
-       help
-         This option enables support for the Sun 3x series of workstations.
-         Be warned that this support is very experimental.
-         Note that Sun 3x kernels are not compatible with Sun 3 hardware.
-         General Linux information on the Sun 3x series (now discontinued)
-         is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
-
-         If you don't want to compile a kernel for a Sun 3x, say N.
-
-config Q40
-       bool "Q40/Q60 support"
-       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
-         <http://www.q40.de/>.  This option enables support for the Q40 and
-         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.
-
-config NATFEAT
-       bool "ARAnyM emulator support"
-       depends on ATARI
-       help
-         This option enables support for ARAnyM native features, such as
-         access to a disk image as /dev/hda.
-
-config NFBLOCK
-       tristate "NatFeat block device support"
-       depends on BLOCK && NATFEAT
-       help
-         Say Y to include support for the ARAnyM NatFeat block device
-         which allows direct access to the hard drives without using
-         the hardware emulation.
-
-config NFCON
-       tristate "NatFeat console driver"
-       depends on NATFEAT
-       help
-         Say Y to include support for the ARAnyM NatFeat console driver
-         which allows the console output to be redirected to the stderr
-         output of ARAnyM.
-
-config NFETH
-       tristate "NatFeat Ethernet support"
-       depends on NET_ETHERNET && NATFEAT
-       help
-         Say Y to include support for the ARAnyM NatFeat network device
-         which will emulate a regular ethernet device while presenting an
-         ethertap device to the host system.
-
-comment "Processor type"
-
-config M68020
-       bool "68020 support"
-       help
-         If you anticipate running this kernel on a computer with a MC68020
-         processor, say Y. Otherwise, say N. Note that the 68020 requires a
-         68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
-         Sun 3, which provides its own version.
-
-config M68030
-       bool "68030 support"
-       depends on !MMU_SUN3
-       help
-         If you anticipate running this kernel on a computer with a MC68030
-         processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
-         work, as it does not include an MMU (Memory Management Unit).
-
-config M68040
-       bool "68040 support"
-       depends on !MMU_SUN3
-       help
-         If you anticipate running this kernel on a computer with a MC68LC040
-         or MC68040 processor, say Y. Otherwise, say N. Note that an
-         MC68EC040 will not work, as it does not include an MMU (Memory
-         Management Unit).
-
-config M68060
-       bool "68060 support"
-       depends on !MMU_SUN3
-       help
-         If you anticipate running this kernel on a computer with a MC68060
-         processor, say Y. Otherwise, say N.
-
-config MMU_MOTOROLA
-       bool
-
-config MMU_SUN3
-       bool
-       depends on MMU && !MMU_MOTOROLA
-
-config M68KFPU_EMU
-       bool "Math emulation support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
-       help
-         At some point in the future, this will cause floating-point math
-         instructions to be emulated by the kernel on machines that lack a
-         floating-point math coprocessor.  Thrill-seekers and chronically
-         sleep-deprived psychotic hacker types can say Y now, everyone else
-         should probably wait a while.
-
-config M68KFPU_EMU_EXTRAPREC
-       bool "Math emulation extra precision"
-       depends on M68KFPU_EMU
-       help
-         The fpu uses normally a few bit more during calculations for
-         correct rounding, the emulator can (often) do the same but this
-         extra calculation can cost quite some time, so you can disable
-         it here. The emulator will then "only" calculate with a 64 bit
-         mantissa and round slightly incorrect, what is more than enough
-         for normal usage.
-
-config M68KFPU_EMU_ONLY
-       bool "Math emulation only kernel"
-       depends on M68KFPU_EMU
-       help
-         This option prevents any floating-point instructions from being
-         compiled into the kernel, thereby the kernel doesn't save any
-         floating point context anymore during task switches, so this
-         kernel will only be usable on machines without a floating-point
-         math coprocessor. This makes the kernel a bit faster as no tests
-         needs to be executed whether a floating-point instruction in the
-         kernel should be executed or not.
-
-config ADVANCED
-       bool "Advanced configuration options"
-       ---help---
-         This gives you access to some advanced options for the CPU. The
-         defaults should be fine for most users, but these options may make
-         it possible for you to improve performance somewhat if you know what
-         you are doing.
-
-         Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about these options.
+         Select if you want MMU-based virtualised addressing space
+         support by paged memory management. If unsure, say 'Y'.
 
-         Most users should say N to this question.
-
-config RMW_INSNS
-       bool "Use read-modify-write instructions"
-       depends on ADVANCED
-       ---help---
-         This allows to use certain instructions that work with indivisible
-         read-modify-write bus cycles. While this is faster than the
-         workaround of disabling interrupts, it can conflict with DMA
-         ( = direct memory access) on many Amiga systems, and it is also said
-         to destabilize other machines. It is very likely that this will
-         cause serious problems on any Amiga or Atari Medusa if set. The only
-         configuration where it should work are 68030-based Ataris, where it
-         apparently improves performance. But you've been warned! Unless you
-         really know what you are doing, say N. Try Y only if you're quite
-         adventurous.
-
-config SINGLE_MEMORY_CHUNK
-       bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
-       default y if SUN3
-       select NEED_MULTIPLE_NODES
-       help
-         Ignore all but the first contiguous chunk of physical memory for VM
-         purposes.  This will save a few bytes kernel size and may speed up
-         some operations.  Say N if not sure.
+menu "Platform dependent setup"
 
-config 060_WRITETHROUGH
-       bool "Use write-through caching for 68060 supervisor accesses"
-       depends on ADVANCED && M68060
-       ---help---
-         The 68060 generally uses copyback caching of recently accessed data.
-         Copyback caching means that memory writes will be held in an on-chip
-         cache and only written back to memory some time later.  Saying Y
-         here will force supervisor (kernel) accesses to use writethrough
-         caching.  Writethrough caching means that data is written to memory
-         straight away, so that cache and memory data always agree.
-         Writethrough caching is less efficient, but is needed for some
-         drivers on 68060 based systems where the 68060 bus snooping signal
-         is hardwired on.  The 53c710 SCSI driver is known to suffer from
-         this problem.
-
-config ARCH_DISCONTIGMEM_ENABLE
-       def_bool !SINGLE_MEMORY_CHUNK
-
-config NODES_SHIFT
-       int
-       default "3"
-       depends on !SINGLE_MEMORY_CHUNK
+if MMU
+source arch/m68k/Kconfig.mmu
+endif
+if !MMU
+source arch/m68k/Kconfig.nommu
+endif
 
 source "mm/Kconfig"
 
 endmenu
 
-menu "General setup"
+menu "Executable file formats"
 
 source "fs/Kconfig.binfmt"
 
-config ZORRO
-       bool "Amiga Zorro (AutoConfig) bus support"
-       depends on AMIGA
-       help
-         This enables support for the Zorro bus in the Amiga. If you have
-         expansion cards in your Amiga that conform to the Amiga
-         AutoConfig(tm) specification, say Y, otherwise N. Note that even
-         expansion cards that do not fit in the Zorro slots but fit in e.g.
-         the CPU slot may fall in this category, so you have to say Y to let
-         Linux use these.
-
-config AMIGA_PCMCIA
-       bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)"
-       depends on AMIGA && EXPERIMENTAL
-       help
-         Include support in the kernel for pcmcia on Amiga 1200 and Amiga
-         600. If you intend to use pcmcia cards say Y; otherwise say N.
-
-config STRAM_PROC
-       bool "ST-RAM statistics in /proc"
-       depends on ATARI
-       help
-         Say Y here to report ST-RAM usage statistics in /proc/stram.
-
-config HEARTBEAT
-       bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
-       default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
-       help
-         Use the power-on LED on your machine as a load meter.  The exact
-         behavior is platform-dependent, but normally the flash frequency is
-         a hyperbolic function of the 5-minute load average.
-
-# We have a dedicated heartbeat LED. :-)
-config PROC_HARDWARE
-       bool "/proc/hardware support"
-       help
-         Say Y here to support the /proc/hardware file, which gives you
-         access to information about the machine you're running on,
-         including the model, CPU, MMU, clock speed, BogoMIPS rating,
-         and memory size.
-
-config ISA
-       bool
-       depends on Q40 || AMIGA_PCMCIA
-       default y
-       help
-         Find out whether you have ISA slots on your motherboard.  ISA 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 PCI, EISA, MicroChannel
-         (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
-         newer boards don't support it.  If you have ISA, say Y, otherwise N.
-
-config GENERIC_ISA_DMA
-       bool
-       depends on Q40 || AMIGA_PCMCIA
-       default y
-
-config ZONE_DMA
-       bool
-       default y
+endmenu
 
-source "drivers/pci/Kconfig"
+if !MMU
+menu "Power management options"
 
-source "drivers/zorro/Kconfig"
+config PM
+        bool "Power Management support"
+        help
+          Support processor power management modes
 
 endmenu
+endif
 
 source "net/Kconfig"
 
 source "drivers/Kconfig"
 
+if MMU
+
 menu "Character devices"
 
 config ATARI_MFPSER
@@ -627,6 +235,8 @@ config SERIAL_CONSOLE
 
 endmenu
 
+endif
+
 source "fs/Kconfig"
 
 source "arch/m68k/Kconfig.debug"
index f53b6d5300e579f49fc20942b89f4385712ea3d4..2bdb1b01115c24f93a21e9e095918a3d44ab89ea 100644 (file)
@@ -2,4 +2,38 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+if !MMU
+
+config FULLDEBUG
+       bool "Full Symbolic/Source Debugging support"
+       help
+         Enable debugging symbols on kernel build.
+
+config HIGHPROFILE
+       bool "Use fast second timer for profiling"
+       depends on COLDFIRE
+       help
+         Use a fast secondary clock to produce profiling information.
+
+config BOOTPARAM
+       bool 'Compiled-in Kernel Boot Parameter'
+
+config BOOTPARAM_STRING
+       string 'Kernel Boot Parameter'
+       default 'console=ttyS0,19200'
+       depends on BOOTPARAM
+
+config NO_KERNEL_MSG
+       bool "Suppress Kernel BUG Messages"
+       help
+         Do not output any debug BUG messages within the kernel.
+
+config BDM_DISABLE
+       bool "Disable BDM signals"
+       depends on (EXPERIMENTAL && COLDFIRE)
+       help
+         Disable the ColdFire CPU's BDM signals.
+
+endif
+
 endmenu
diff --git a/arch/m68k/Kconfig.mmu b/arch/m68k/Kconfig.mmu
new file mode 100644 (file)
index 0000000..16539b1
--- /dev/null
@@ -0,0 +1,417 @@
+config GENERIC_IOMAP
+       bool
+       default y
+
+config ARCH_MAY_HAVE_PC_FDC
+       bool
+       depends on BROKEN && (Q40 || SUN3X)
+       default y
+
+config ARCH_USES_GETTIMEOFFSET
+       def_bool y
+
+config EISA
+       bool
+       ---help---
+         The Extended Industry Standard Architecture (EISA) bus was
+         developed as an open alternative to the IBM MicroChannel bus.
+
+         The EISA bus provided some of the features of the IBM MicroChannel
+         bus while maintaining backward compatibility with cards made for
+         the older ISA bus.  The EISA bus saw limited use between 1988 and
+         1995 when it was made obsolete by the PCI bus.
+
+         Say Y here if you are building a kernel for an EISA-based machine.
+
+         Otherwise, say N.
+
+config MCA
+       bool
+       help
+         MicroChannel Architecture is found in some IBM PS/2 machines and
+         laptops.  It is a bus system similar to PCI or ISA. See
+         <file:Documentation/mca.txt> (and especially the web page given
+         there) before attempting to build an MCA bus kernel.
+
+config PCMCIA
+       tristate
+       ---help---
+         Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
+         computer.  These are credit-card size devices such as network cards,
+         modems or hard drives often used with laptops computers.  There are
+         actually two varieties of these cards: the older 16 bit PCMCIA cards
+         and the newer 32 bit CardBus cards.  If you want to use CardBus
+         cards, you need to say Y here and also to "CardBus support" below.
+
+         To use your PC-cards, you will need supporting software from David
+         Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
+         for location).  Please also read the PCMCIA-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as modules, choose M here: the
+         modules will be called pcmcia_core and ds.
+
+config AMIGA
+       bool "Amiga support"
+       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
+         material available in <file:Documentation/m68k>; otherwise say N.
+
+config ATARI
+       bool "Atari support"
+       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 MAC
+       bool "Macintosh support"
+       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
+         of the series).
+
+         Say N unless you're willing to code the remaining necessary support.
+         ;)
+
+config NUBUS
+       bool
+       depends on MAC
+       default y
+
+config M68K_L2_CACHE
+       bool
+       depends on MAC
+       default y
+
+config APOLLO
+       bool "Apollo support"
+       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"
+       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,
+         MVME162, MVME166, MVME167, MVME172, and MVME177.  BVME4000 and
+         BVME6000 boards from BVM Ltd are also supported.
+
+config MVME147
+       bool "MVME147 support"
+       depends on VME
+       help
+         Say Y to include support for early Motorola VME boards.  This will
+         build a kernel which can run on MVME147 single-board computers.  If
+         you select this option you will have to select the appropriate
+         drivers for SCSI, Ethernet and serial ports later on.
+
+config MVME16x
+       bool "MVME162, 166 and 167 support"
+       depends on VME
+       help
+         Say Y to include support for Motorola VME boards.  This will build a
+         kernel which can run on MVME162, MVME166, MVME167, MVME172, and
+         MVME177 boards.  If you select this option you will have to select
+         the appropriate drivers for SCSI, Ethernet and serial ports later
+         on.
+
+config BVME6000
+       bool "BVME4000 and BVME6000 support"
+       depends on VME
+       help
+         Say Y to include support for VME boards from BVM Ltd.  This will
+         build a kernel which can run on BVME4000 and BVME6000 boards.  If
+         you select this option you will have to select the appropriate
+         drivers for SCSI, Ethernet and serial ports later on.
+
+config HP300
+       bool "HP9000/300 and HP9000/400 support"
+       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
+         experimental. If you plan to try to use the kernel on such a machine
+         say Y here.
+         Everybody else says N.
+
+config DIO
+       bool "DIO bus support"
+       depends on HP300
+       default y
+       help
+         Say Y here to enable support for the "DIO" expansion bus used in
+         HP300 machines. If you are using such a system you almost certainly
+         want this.
+
+config SUN3X
+       bool "Sun3x support"
+       select MMU_MOTOROLA if MMU
+       select M68030
+       help
+         This option enables support for the Sun 3x series of workstations.
+         Be warned that this support is very experimental.
+         Note that Sun 3x kernels are not compatible with Sun 3 hardware.
+         General Linux information on the Sun 3x series (now discontinued)
+         is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+         If you don't want to compile a kernel for a Sun 3x, say N.
+
+config Q40
+       bool "Q40/Q60 support"
+       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
+         <http://www.q40.de/>.  This option enables support for the Q40 and
+         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.
+
+config NATFEAT
+       bool "ARAnyM emulator support"
+       depends on ATARI
+       help
+         This option enables support for ARAnyM native features, such as
+         access to a disk image as /dev/hda.
+
+config NFBLOCK
+       tristate "NatFeat block device support"
+       depends on BLOCK && NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat block device
+         which allows direct access to the hard drives without using
+         the hardware emulation.
+
+config NFCON
+       tristate "NatFeat console driver"
+       depends on NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat console driver
+         which allows the console output to be redirected to the stderr
+         output of ARAnyM.
+
+config NFETH
+       tristate "NatFeat Ethernet support"
+       depends on NET_ETHERNET && NATFEAT
+       help
+         Say Y to include support for the ARAnyM NatFeat network device
+         which will emulate a regular ethernet device while presenting an
+         ethertap device to the host system.
+
+comment "Processor type"
+
+config M68020
+       bool "68020 support"
+       help
+         If you anticipate running this kernel on a computer with a MC68020
+         processor, say Y. Otherwise, say N. Note that the 68020 requires a
+         68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
+         Sun 3, which provides its own version.
+
+config M68030
+       bool "68030 support"
+       depends on !MMU_SUN3
+       help
+         If you anticipate running this kernel on a computer with a MC68030
+         processor, say Y. Otherwise, say N. Note that a MC68EC030 will not
+         work, as it does not include an MMU (Memory Management Unit).
+
+config M68040
+       bool "68040 support"
+       depends on !MMU_SUN3
+       help
+         If you anticipate running this kernel on a computer with a MC68LC040
+         or MC68040 processor, say Y. Otherwise, say N. Note that an
+         MC68EC040 will not work, as it does not include an MMU (Memory
+         Management Unit).
+
+config M68060
+       bool "68060 support"
+       depends on !MMU_SUN3
+       help
+         If you anticipate running this kernel on a computer with a MC68060
+         processor, say Y. Otherwise, say N.
+
+config MMU_MOTOROLA
+       bool
+
+config MMU_SUN3
+       bool
+       depends on MMU && !MMU_MOTOROLA
+
+config M68KFPU_EMU
+       bool "Math emulation support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         At some point in the future, this will cause floating-point math
+         instructions to be emulated by the kernel on machines that lack a
+         floating-point math coprocessor.  Thrill-seekers and chronically
+         sleep-deprived psychotic hacker types can say Y now, everyone else
+         should probably wait a while.
+
+config M68KFPU_EMU_EXTRAPREC
+       bool "Math emulation extra precision"
+       depends on M68KFPU_EMU
+       help
+         The fpu uses normally a few bit more during calculations for
+         correct rounding, the emulator can (often) do the same but this
+         extra calculation can cost quite some time, so you can disable
+         it here. The emulator will then "only" calculate with a 64 bit
+         mantissa and round slightly incorrect, what is more than enough
+         for normal usage.
+
+config M68KFPU_EMU_ONLY
+       bool "Math emulation only kernel"
+       depends on M68KFPU_EMU
+       help
+         This option prevents any floating-point instructions from being
+         compiled into the kernel, thereby the kernel doesn't save any
+         floating point context anymore during task switches, so this
+         kernel will only be usable on machines without a floating-point
+         math coprocessor. This makes the kernel a bit faster as no tests
+         needs to be executed whether a floating-point instruction in the
+         kernel should be executed or not.
+
+config ADVANCED
+       bool "Advanced configuration options"
+       ---help---
+         This gives you access to some advanced options for the CPU. The
+         defaults should be fine for most users, but these options may make
+         it possible for you to improve performance somewhat if you know what
+         you are doing.
+
+         Note that the answer to this question won't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about these options.
+
+         Most users should say N to this question.
+
+config RMW_INSNS
+       bool "Use read-modify-write instructions"
+       depends on ADVANCED
+       ---help---
+         This allows to use certain instructions that work with indivisible
+         read-modify-write bus cycles. While this is faster than the
+         workaround of disabling interrupts, it can conflict with DMA
+         ( = direct memory access) on many Amiga systems, and it is also said
+         to destabilize other machines. It is very likely that this will
+         cause serious problems on any Amiga or Atari Medusa if set. The only
+         configuration where it should work are 68030-based Ataris, where it
+         apparently improves performance. But you've been warned! Unless you
+         really know what you are doing, say N. Try Y only if you're quite
+         adventurous.
+
+config SINGLE_MEMORY_CHUNK
+       bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
+       default y if SUN3
+       select NEED_MULTIPLE_NODES
+       help
+         Ignore all but the first contiguous chunk of physical memory for VM
+         purposes.  This will save a few bytes kernel size and may speed up
+         some operations.  Say N if not sure.
+
+config 060_WRITETHROUGH
+       bool "Use write-through caching for 68060 supervisor accesses"
+       depends on ADVANCED && M68060
+       ---help---
+         The 68060 generally uses copyback caching of recently accessed data.
+         Copyback caching means that memory writes will be held in an on-chip
+         cache and only written back to memory some time later.  Saying Y
+         here will force supervisor (kernel) accesses to use writethrough
+         caching.  Writethrough caching means that data is written to memory
+         straight away, so that cache and memory data always agree.
+         Writethrough caching is less efficient, but is needed for some
+         drivers on 68060 based systems where the 68060 bus snooping signal
+         is hardwired on.  The 53c710 SCSI driver is known to suffer from
+         this problem.
+
+config ARCH_DISCONTIGMEM_ENABLE
+       def_bool !SINGLE_MEMORY_CHUNK
+
+config NODES_SHIFT
+       int
+       default "3"
+       depends on !SINGLE_MEMORY_CHUNK
+
+config ZORRO
+       bool "Amiga Zorro (AutoConfig) bus support"
+       depends on AMIGA
+       help
+         This enables support for the Zorro bus in the Amiga. If you have
+         expansion cards in your Amiga that conform to the Amiga
+         AutoConfig(tm) specification, say Y, otherwise N. Note that even
+         expansion cards that do not fit in the Zorro slots but fit in e.g.
+         the CPU slot may fall in this category, so you have to say Y to let
+         Linux use these.
+
+config AMIGA_PCMCIA
+       bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)"
+       depends on AMIGA && EXPERIMENTAL
+       help
+         Include support in the kernel for pcmcia on Amiga 1200 and Amiga
+         600. If you intend to use pcmcia cards say Y; otherwise say N.
+
+config STRAM_PROC
+       bool "ST-RAM statistics in /proc"
+       depends on ATARI
+       help
+         Say Y here to report ST-RAM usage statistics in /proc/stram.
+
+config HEARTBEAT
+       bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
+       default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
+       help
+         Use the power-on LED on your machine as a load meter.  The exact
+         behavior is platform-dependent, but normally the flash frequency is
+         a hyperbolic function of the 5-minute load average.
+
+# We have a dedicated heartbeat LED. :-)
+config PROC_HARDWARE
+       bool "/proc/hardware support"
+       help
+         Say Y here to support the /proc/hardware file, which gives you
+         access to information about the machine you're running on,
+         including the model, CPU, MMU, clock speed, BogoMIPS rating,
+         and memory size.
+
+config ISA
+       bool
+       depends on Q40 || AMIGA_PCMCIA
+       default y
+       help
+         Find out whether you have ISA slots on your motherboard.  ISA 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 PCI, EISA, MicroChannel
+         (MCA) or VESA.  ISA is an older system, now being displaced by PCI;
+         newer boards don't support it.  If you have ISA, say Y, otherwise N.
+
+config GENERIC_ISA_DMA
+       bool
+       depends on Q40 || AMIGA_PCMCIA
+       default y
+
+source "drivers/pci/Kconfig"
+
+source "drivers/zorro/Kconfig"
+
diff --git a/arch/m68k/Kconfig.nommu b/arch/m68k/Kconfig.nommu
new file mode 100644 (file)
index 0000000..273bcca
--- /dev/null
@@ -0,0 +1,750 @@
+config FPU
+       bool
+       default n
+
+config GENERIC_FIND_NEXT_BIT
+       bool
+       default y
+
+config GENERIC_GPIO
+       bool
+       default n
+
+config GENERIC_CMOS_UPDATE
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default n
+
+config COLDFIRE_SW_A7
+       bool
+       default n
+
+config HAVE_CACHE_SPLIT
+       bool
+
+config HAVE_CACHE_CB
+       bool
+
+config HAVE_MBAR
+       bool
+
+config HAVE_IPSBAR
+       bool
+
+choice
+       prompt "CPU"
+       default M68EZ328
+
+config M68328
+       bool "MC68328"
+       help
+         Motorola 68328 processor support.
+
+config M68EZ328
+       bool "MC68EZ328"
+       help
+         Motorola 68EX328 processor support.
+
+config M68VZ328
+       bool "MC68VZ328"
+       help
+         Motorola 68VZ328 processor support.
+
+config M68360
+       bool "MC68360"
+       help
+         Motorola 68360 processor support.
+
+config M5206
+       bool "MCF5206"
+       select COLDFIRE_SW_A7
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5206 processor support.
+
+config M5206e
+       bool "MCF5206e"
+       select COLDFIRE_SW_A7
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5206e processor support.
+
+config M520x
+       bool "MCF520x"
+       select GENERIC_CLOCKEVENTS
+       select HAVE_CACHE_SPLIT
+       help
+          Freescale Coldfire 5207/5208 processor support.
+
+config M523x
+       bool "MCF523x"
+       select GENERIC_CLOCKEVENTS
+       select HAVE_CACHE_SPLIT
+       select HAVE_IPSBAR
+       help
+         Freescale Coldfire 5230/1/2/4/5 processor support
+
+config M5249
+       bool "MCF5249"
+       select COLDFIRE_SW_A7
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5249 processor support.
+
+config M5271
+       bool "MCF5271"
+       select HAVE_CACHE_SPLIT
+       select HAVE_IPSBAR
+       help
+         Freescale (Motorola) ColdFire 5270/5271 processor support.
+
+config M5272
+       bool "MCF5272"
+       select COLDFIRE_SW_A7
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5272 processor support.
+
+config M5275
+       bool "MCF5275"
+       select HAVE_CACHE_SPLIT
+       select HAVE_IPSBAR
+       help
+         Freescale (Motorola) ColdFire 5274/5275 processor support.
+
+config M528x
+       bool "MCF528x"
+       select GENERIC_CLOCKEVENTS
+       select HAVE_CACHE_SPLIT
+       select HAVE_IPSBAR
+       help
+         Motorola ColdFire 5280/5282 processor support.
+
+config M5307
+       bool "MCF5307"
+       select COLDFIRE_SW_A7
+       select HAVE_CACHE_CB
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5307 processor support.
+
+config M532x
+       bool "MCF532x"
+       select HAVE_CACHE_CB
+       help
+         Freescale (Motorola) ColdFire 532x processor support.
+
+config M5407
+       bool "MCF5407"
+       select COLDFIRE_SW_A7
+       select HAVE_CACHE_CB
+       select HAVE_MBAR
+       help
+         Motorola ColdFire 5407 processor support.
+
+config M547x
+       bool "MCF547x"
+       select HAVE_CACHE_CB
+       select HAVE_MBAR
+       help
+         Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support.
+
+config M548x
+       bool "MCF548x"
+       select HAVE_CACHE_CB
+       select HAVE_MBAR
+       help
+         Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
+endchoice
+
+config M527x
+       bool
+       depends on (M5271 || M5275)
+       select GENERIC_CLOCKEVENTS
+       default y
+
+config M54xx
+       bool
+       depends on (M548x || M547x)
+       default y
+
+config COLDFIRE
+       bool
+       depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M54xx)
+       select GENERIC_GPIO
+       select ARCH_REQUIRE_GPIOLIB
+       default y
+
+config CLOCK_SET
+       bool "Enable setting the CPU clock frequency"
+       default n
+       help
+         On some CPU's you do not need to know what the core CPU clock
+         frequency is. On these you can disable clock setting. On some
+         traditional 68K parts, and on all ColdFire parts you need to set
+         the appropriate CPU clock frequency. On these devices many of the
+         onboard peripherals derive their timing from the master CPU clock
+         frequency.
+
+config CLOCK_FREQ
+       int "Set the core clock frequency"
+       default "66666666"
+       depends on CLOCK_SET
+       help
+         Define the CPU clock frequency in use. This is the core clock
+         frequency, it may or may not be the same as the external clock
+         crystal fitted to your board. Some processors have an internal
+         PLL and can have their frequency programmed at run time, others
+         use internal dividers. In general the kernel won't setup a PLL
+         if it is fitted (there are some exceptions). This value will be
+         specific to the exact CPU that you are using.
+
+config OLDMASK
+       bool "Old mask 5307 (1H55J) silicon"
+       depends on M5307
+       help
+         Build support for the older revision ColdFire 5307 silicon.
+         Specifically this is the 1H55J mask revision.
+
+if HAVE_CACHE_SPLIT
+choice
+       prompt "Split Cache Configuration"
+       default CACHE_I
+
+config CACHE_I
+       bool "Instruction"
+       help
+         Use all of the ColdFire CPU cache memory as an instruction cache.
+
+config CACHE_D
+       bool "Data"
+       help
+         Use all of the ColdFire CPU cache memory as a data cache.
+
+config CACHE_BOTH
+       bool "Both"
+       help
+         Split the ColdFire CPU cache, and use half as an instruction cache
+         and half as a data cache.
+endchoice
+endif
+
+if HAVE_CACHE_CB
+choice
+       prompt "Data cache mode"
+       default CACHE_WRITETHRU
+
+config CACHE_WRITETHRU
+       bool "Write-through"
+       help
+         The ColdFire CPU cache is set into Write-through mode.
+
+config CACHE_COPYBACK
+       bool "Copy-back"
+       help
+         The ColdFire CPU cache is set into Copy-back mode.
+endchoice
+endif
+
+comment "Platform"
+
+config PILOT3
+       bool "Pilot 1000/5000, PalmPilot Personal/Pro, or PalmIII support"
+       depends on M68328
+       help
+         Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII.
+
+config XCOPILOT_BUGS
+       bool "(X)Copilot support"
+       depends on PILOT3
+       help
+         Support the bugs of Xcopilot.
+
+config UC5272
+       bool 'Arcturus Networks uC5272 dimm board support'
+       depends on M5272
+       help
+         Support for the Arcturus Networks uC5272 dimm board.
+
+config UC5282
+       bool "Arcturus Networks uC5282 board support"
+       depends on M528x
+       help
+         Support for the Arcturus Networks uC5282 dimm board.
+
+config UCSIMM
+       bool "uCsimm module support"
+       depends on M68EZ328
+       help
+         Support for the Arcturus Networks uCsimm module.
+
+config UCDIMM
+       bool "uDsimm module support"
+       depends on M68VZ328
+       help
+         Support for the Arcturus Networks uDsimm module.
+
+config DRAGEN2
+       bool "DragenEngine II board support"
+       depends on M68VZ328
+       help
+         Support for the DragenEngine II board.
+
+config DIRECT_IO_ACCESS
+       bool "Allow user to access IO directly"
+       depends on (UCSIMM || UCDIMM || DRAGEN2)
+       help
+         Disable the CPU internal registers protection in user mode,
+         to allow a user application to read/write them.
+
+config INIT_LCD
+       bool "Initialize LCD"
+       depends on (UCSIMM || UCDIMM || DRAGEN2)
+       help
+         Initialize the LCD controller of the 68x328 processor.
+
+config MEMORY_RESERVE
+       int "Memory reservation (MiB)"
+       depends on (UCSIMM || UCDIMM)
+       help
+         Reserve certain memory regions on 68x328 based boards.
+
+config UCQUICC
+       bool "Lineo uCquicc board support"
+       depends on M68360
+       help
+         Support for the Lineo uCquicc board.
+
+config ARN5206
+       bool "Arnewsh 5206 board support"
+       depends on M5206
+       help
+         Support for the Arnewsh 5206 board.
+
+config M5206eC3
+       bool "Motorola M5206eC3 board support"
+       depends on M5206e
+       help
+         Support for the Motorola M5206eC3 board.
+
+config ELITE
+       bool "Motorola M5206eLITE board support"
+       depends on M5206e
+       help
+         Support for the Motorola M5206eLITE board.
+
+config M5208EVB
+       bool "Freescale M5208EVB board support"
+       depends on M520x
+       help
+         Support for the Freescale Coldfire M5208EVB.
+
+config M5235EVB
+       bool "Freescale M5235EVB support"
+       depends on M523x
+       help
+         Support for the Freescale M5235EVB board.
+
+config M5249C3
+       bool "Motorola M5249C3 board support"
+       depends on M5249
+       help
+         Support for the Motorola M5249C3 board.
+
+config M5271EVB
+       bool "Freescale (Motorola) M5271EVB board support"
+       depends on M5271
+       help
+         Support for the Freescale (Motorola) M5271EVB board.
+
+config M5275EVB
+       bool "Freescale (Motorola) M5275EVB board support"
+       depends on M5275
+       help
+         Support for the Freescale (Motorola) M5275EVB board.
+
+config M5272C3
+       bool "Motorola M5272C3 board support"
+       depends on M5272
+       help
+         Support for the Motorola M5272C3 board.
+
+config COBRA5272
+       bool "senTec COBRA5272 board support"
+       depends on M5272
+       help
+         Support for the senTec COBRA5272 board.
+
+config AVNET5282
+       bool "Avnet 5282 board support"
+       depends on M528x
+       help
+         Support for the Avnet 5282 board.  
+         
+config M5282EVB
+       bool "Motorola M5282EVB board support"
+       depends on M528x
+       help
+         Support for the Motorola M5282EVB board.
+
+config COBRA5282
+       bool "senTec COBRA5282 board support"
+       depends on M528x
+       help
+         Support for the senTec COBRA5282 board.
+         
+config SOM5282EM
+       bool "EMAC.Inc SOM5282EM board support"
+       depends on M528x
+       help
+         Support for the EMAC.Inc SOM5282EM module.  
+         
+config WILDFIRE
+       bool "Intec Automation Inc. WildFire board support"
+       depends on M528x
+       help
+         Support for the Intec Automation Inc. WildFire.
+         
+config WILDFIREMOD
+       bool "Intec Automation Inc. WildFire module support"
+       depends on M528x
+       help
+         Support for the Intec Automation Inc. WildFire module.
+
+config ARN5307
+       bool "Arnewsh 5307 board support"
+       depends on M5307
+       help
+         Support for the Arnewsh 5307 board.
+
+config M5307C3
+       bool "Motorola M5307C3 board support"
+       depends on M5307
+       help
+         Support for the Motorola M5307C3 board.
+
+config SECUREEDGEMP3
+       bool "SnapGear SecureEdge/MP3 platform support"
+       depends on M5307
+       help
+         Support for the SnapGear SecureEdge/MP3 platform.
+
+config M5329EVB
+       bool "Freescale (Motorola) M5329EVB board support"
+       depends on M532x
+       help
+         Support for the Freescale (Motorola) M5329EVB board.
+
+config COBRA5329
+       bool "senTec COBRA5329 board support"
+       depends on M532x
+       help
+         Support for the senTec COBRA5329 board.
+
+config M5407C3
+       bool "Motorola M5407C3 board support"
+       depends on M5407
+       help
+         Support for the Motorola M5407C3 board.
+
+config FIREBEE
+       bool "FireBee board support"
+       depends on M547x
+       help
+         Support for the FireBee ColdFire 5475 based board.
+
+config CLEOPATRA
+       bool "Feith CLEOPATRA board support"
+       depends on (M5307 || M5407)
+       help
+         Support for the Feith Cleopatra boards.
+
+config CANCam
+       bool "Feith CANCam board support"
+       depends on M5272
+       help
+         Support for the Feith CANCam board.
+
+config SCALES
+       bool "Feith SCALES board support"
+       depends on M5272
+       help
+         Support for the Feith SCALES board.
+
+config NETtel
+       bool "SecureEdge/NETtel board support"
+       depends on (M5206e || M5272 || M5307)
+       help
+         Support for the SnapGear NETtel/SecureEdge/SnapGear boards.
+
+config SNAPGEAR
+       bool "SnapGear router board support"
+       depends on NETtel
+       help
+         Special additional support for SnapGear router boards.
+
+config CPU16B
+       bool "Sneha Technologies S.L. Sarasvati board support"
+       depends on M5272
+       help
+         Support for the SNEHA CPU16B board.
+
+config MOD5272
+       bool "Netburner MOD-5272 board support"
+       depends on M5272
+       help
+         Support for the Netburner MOD-5272 board.
+
+config SAVANTrosie1
+       bool "Savant Rosie1 board support"
+       depends on M523x
+       help
+         Support for the Savant Rosie1 board.
+
+config ROMFS_FROM_ROM
+       bool "ROMFS image not RAM resident"
+       depends on (NETtel || SNAPGEAR)
+       help
+         The ROMfs filesystem will stay resident in the FLASH/ROM, not be
+         moved into RAM.
+
+config PILOT
+       bool
+       default y
+       depends on (PILOT3 || PILOT5)
+
+config ARNEWSH
+       bool
+       default y
+       depends on (ARN5206 || ARN5307)
+
+config FREESCALE
+       bool
+       default y
+       depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5329EVB || M5407C3)
+
+config HW_FEITH
+       bool
+       default y
+       depends on (CLEOPATRA || CANCam || SCALES)
+
+config senTec
+       bool
+       default y
+       depends on (COBRA5272 || COBRA5282)
+       
+config EMAC_INC
+       bool
+       default y
+       depends on (SOM5282EM)
+
+config SNEHA
+       bool
+       default y
+       depends on CPU16B
+
+config SAVANT
+       bool
+       default y
+       depends on SAVANTrosie1
+
+config AVNET
+       bool
+       default y
+       depends on (AVNET5282)
+
+config UBOOT
+       bool "Support for U-Boot command line parameters"
+       help
+         If you say Y here kernel will try to collect command
+         line parameters from the initial u-boot stack.
+       default n
+
+config 4KSTACKS
+       bool "Use 4Kb for kernel stacks instead of 8Kb"
+       default y
+       help
+         If you say Y here the kernel will use a 4Kb stacksize for the
+         kernel stack attached to each process/thread. This facilitates
+         running more threads on a system and also reduces the pressure
+         on the VM subsystem for higher order allocations.
+
+comment "RAM configuration"
+
+config RAMBASE
+       hex "Address of the base of RAM"
+       default "0"
+       help
+         Define the address that RAM starts at. On many platforms this is
+         0, the base of the address space. And this is the default. Some
+         platforms choose to setup their RAM at other addresses within the
+         processor address space.
+
+config RAMSIZE
+       hex "Size of RAM (in bytes), or 0 for automatic"
+       default "0x400000"
+       help
+         Define the size of the system RAM. If you select 0 then the
+         kernel will try to probe the RAM size at runtime. This is not
+         supported on all CPU types.
+
+config VECTORBASE
+       hex "Address of the base of system vectors"
+       default "0"
+       help
+         Define the address of the system vectors. Commonly this is
+         put at the start of RAM, but it doesn't have to be. On ColdFire
+         platforms this address is programmed into the VBR register, thus
+         actually setting the address to use.
+
+config MBAR
+       hex "Address of the MBAR (internal peripherals)"
+       default "0x10000000"
+       depends on HAVE_MBAR
+       help
+         Define the address of the internal system peripherals. This value
+         is set in the processors MBAR register. This is generally setup by
+         the boot loader, and will not be written by the kernel. By far most
+         ColdFire boards use the default 0x10000000 value, so if unsure then
+         use this.
+
+config IPSBAR
+       hex "Address of the IPSBAR (internal peripherals)"
+       default "0x40000000"
+       depends on HAVE_IPSBAR
+       help
+         Define the address of the internal system peripherals. This value
+         is set in the processors IPSBAR register. This is generally setup by
+         the boot loader, and will not be written by the kernel. By far most
+         ColdFire boards use the default 0x40000000 value, so if unsure then
+         use this.
+
+config KERNELBASE
+       hex "Address of the base of kernel code"
+       default "0x400"
+       help
+         Typically on m68k systems the kernel will not start at the base
+         of RAM, but usually some small offset from it. Define the start
+         address of the kernel here. The most common setup will have the
+         processor vectors at the base of RAM and then the start of the
+         kernel. On some platforms some RAM is reserved for boot loaders
+         and the kernel starts after that. The 0x400 default was based on
+         a system with the RAM based at address 0, and leaving enough room
+         for the theoretical maximum number of 256 vectors.
+
+choice
+       prompt "RAM bus width"
+       default RAMAUTOBIT
+
+config RAMAUTOBIT
+       bool "AUTO"
+       help
+         Select the physical RAM data bus size. Not needed on most platforms,
+         so you can generally choose AUTO.
+
+config RAM8BIT
+       bool "8bit"
+       help
+         Configure RAM bus to be 8 bits wide.
+
+config RAM16BIT
+       bool "16bit"
+       help
+         Configure RAM bus to be 16 bits wide.
+
+config RAM32BIT
+       bool "32bit"
+       help
+         Configure RAM bus to be 32 bits wide.
+
+endchoice
+
+comment "ROM configuration"
+
+config ROM
+       bool "Specify ROM linker regions"
+       default n
+       help
+         Define a ROM region for the linker script. This creates a kernel
+         that can be stored in flash, with possibly the text, and data
+         regions being copied out to RAM at startup.
+
+config ROMBASE
+       hex "Address of the base of ROM device"
+       default "0"
+       depends on ROM
+       help
+         Define the address that the ROM region starts at. Some platforms
+         use this to set their chip select region accordingly for the boot
+         device.
+
+config ROMVEC
+       hex "Address of the base of the ROM vectors"
+       default "0"
+       depends on ROM
+       help
+         This is almost always the same as the base of the ROM. Since on all
+         68000 type variants the vectors are at the base of the boot device
+         on system startup.
+
+config ROMVECSIZE
+       hex "Size of ROM vector region (in bytes)"
+       default "0x400"
+       depends on ROM
+       help
+         Define the size of the vector region in ROM. For most 68000
+         variants this would be 0x400 bytes in size. Set to 0 if you do
+         not want a vector region at the start of the ROM.
+
+config ROMSTART
+       hex "Address of the base of system image in ROM"
+       default "0x400"
+       depends on ROM
+       help
+         Define the start address of the system image in ROM. Commonly this
+         is strait after the ROM vectors.
+
+config ROMSIZE
+       hex "Size of the ROM device"
+       default "0x100000"
+       depends on ROM
+       help
+         Size of the ROM device. On some platforms this is used to setup
+         the chip select that controls the boot ROM device.
+
+choice
+       prompt "Kernel executes from"
+       ---help---
+         Choose the memory type that the kernel will be running in.
+
+config RAMKERNEL
+       bool "RAM"
+       help
+         The kernel will be resident in RAM when running.
+
+config ROMKERNEL
+       bool "ROM"
+       help
+         The kernel will be resident in FLASH/ROM when running. This is
+         often referred to as Execute-in-Place (XIP), since the kernel
+         code executes from the position it is stored in the FLASH/ROM.
+
+endchoice
+
+if COLDFIRE
+source "kernel/Kconfig.preempt"
+endif
+
+source "kernel/time/Kconfig"
+
+config ISA_DMA_API
+       bool
+       depends on !M5272
+       default y
+
+source "drivers/pcmcia/Kconfig"
+
index b793163abc610212618f38a2c1680d6048b41322..be46cadd401781b6796a3888e18085b864080e0b 100644 (file)
@@ -1,123 +1,7 @@
-#
-# m68k/Makefile
-#
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1994 by Hamish Macdonald
-#
-
 KBUILD_DEFCONFIG := multi_defconfig
 
-# override top level makefile
-AS += -m68020
-LDFLAGS := -m m68kelf
-KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
-ifneq ($(SUBARCH),$(ARCH))
-       ifeq ($(CROSS_COMPILE),)
-               CROSS_COMPILE := $(call cc-cross-prefix, \
-                       m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
-       endif
-endif
-
-ifdef CONFIG_SUN3
-LDFLAGS_vmlinux = -N
-endif
-
-CHECKFLAGS += -D__mc68000__
-
-# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
-KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
-
-# enable processor switch if compiled only for a single cpu
-ifndef CONFIG_M68020
-ifndef CONFIG_M68030
-
-ifndef CONFIG_M68060
-KBUILD_CFLAGS += -m68040
-endif
-
-ifndef CONFIG_M68040
-KBUILD_CFLAGS += -m68060
-endif
-
-endif
-endif
-
-ifdef CONFIG_KGDB
-# If configured for kgdb support, include debugging infos and keep the
-# frame pointer
-KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
-endif
-
-ifndef CONFIG_SUN3
-head-y := arch/m68k/kernel/head.o
+ifdef CONFIG_MMU
+include $(srctree)/arch/m68k/Makefile_mm
 else
-head-y := arch/m68k/kernel/sun3-head.o
+include $(srctree)/arch/m68k/Makefile_no
 endif
-
-core-y                         += arch/m68k/kernel/    arch/m68k/mm/
-libs-y                         += arch/m68k/lib/
-
-core-$(CONFIG_Q40)             += arch/m68k/q40/
-core-$(CONFIG_AMIGA)           += arch/m68k/amiga/
-core-$(CONFIG_ATARI)           += arch/m68k/atari/
-core-$(CONFIG_MAC)             += arch/m68k/mac/
-core-$(CONFIG_HP300)           += arch/m68k/hp300/
-core-$(CONFIG_APOLLO)          += arch/m68k/apollo/
-core-$(CONFIG_MVME147)         += arch/m68k/mvme147/
-core-$(CONFIG_MVME16x)         += arch/m68k/mvme16x/
-core-$(CONFIG_BVME6000)                += arch/m68k/bvme6000/
-core-$(CONFIG_SUN3X)           += arch/m68k/sun3x/     arch/m68k/sun3/
-core-$(CONFIG_SUN3)            += arch/m68k/sun3/      arch/m68k/sun3/prom/
-core-$(CONFIG_NATFEAT)         += arch/m68k/emu/
-core-$(CONFIG_M68040)          += arch/m68k/fpsp040/
-core-$(CONFIG_M68060)          += arch/m68k/ifpsp060/
-core-$(CONFIG_M68KFPU_EMU)     += arch/m68k/math-emu/
-
-all:   zImage
-
-lilo:  vmlinux
-       if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
-       if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
-       cat vmlinux > $(INSTALL_PATH)/vmlinux
-       cp System.map $(INSTALL_PATH)/System.map
-       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
-
-zImage compressed: vmlinux.gz
-
-vmlinux.gz: vmlinux
-
-ifndef CONFIG_KGDB
-       cp vmlinux vmlinux.tmp
-       $(STRIP) vmlinux.tmp
-       gzip -9c vmlinux.tmp >vmlinux.gz
-       rm vmlinux.tmp
-else
-       gzip -9c vmlinux >vmlinux.gz
-endif
-
-bzImage: vmlinux.bz2
-
-vmlinux.bz2: vmlinux
-
-ifndef CONFIG_KGDB
-       cp vmlinux vmlinux.tmp
-       $(STRIP) vmlinux.tmp
-       bzip2 -1c vmlinux.tmp >vmlinux.bz2
-       rm vmlinux.tmp
-else
-       bzip2 -1c vmlinux >vmlinux.bz2
-endif
-
-archclean:
-       rm -f vmlinux.gz vmlinux.bz2
-
-install:
-       sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
diff --git a/arch/m68k/Makefile_mm b/arch/m68k/Makefile_mm
new file mode 100644 (file)
index 0000000..d449b6d
--- /dev/null
@@ -0,0 +1,121 @@
+#
+# m68k/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Hamish Macdonald
+#
+
+# override top level makefile
+AS += -m68020
+LDFLAGS := -m m68kelf
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+ifneq ($(SUBARCH),$(ARCH))
+       ifeq ($(CROSS_COMPILE),)
+               CROSS_COMPILE := $(call cc-cross-prefix, \
+                       m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
+       endif
+endif
+
+ifdef CONFIG_SUN3
+LDFLAGS_vmlinux = -N
+endif
+
+CHECKFLAGS += -D__mc68000__
+
+# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
+KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
+
+# enable processor switch if compiled only for a single cpu
+ifndef CONFIG_M68020
+ifndef CONFIG_M68030
+
+ifndef CONFIG_M68060
+KBUILD_CFLAGS += -m68040
+endif
+
+ifndef CONFIG_M68040
+KBUILD_CFLAGS += -m68060
+endif
+
+endif
+endif
+
+ifdef CONFIG_KGDB
+# If configured for kgdb support, include debugging infos and keep the
+# frame pointer
+KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
+endif
+
+ifndef CONFIG_SUN3
+head-y := arch/m68k/kernel/head.o
+else
+head-y := arch/m68k/kernel/sun3-head.o
+endif
+
+core-y                         += arch/m68k/kernel/    arch/m68k/mm/
+libs-y                         += arch/m68k/lib/
+
+core-$(CONFIG_Q40)             += arch/m68k/q40/
+core-$(CONFIG_AMIGA)           += arch/m68k/amiga/
+core-$(CONFIG_ATARI)           += arch/m68k/atari/
+core-$(CONFIG_MAC)             += arch/m68k/mac/
+core-$(CONFIG_HP300)           += arch/m68k/hp300/
+core-$(CONFIG_APOLLO)          += arch/m68k/apollo/
+core-$(CONFIG_MVME147)         += arch/m68k/mvme147/
+core-$(CONFIG_MVME16x)         += arch/m68k/mvme16x/
+core-$(CONFIG_BVME6000)                += arch/m68k/bvme6000/
+core-$(CONFIG_SUN3X)           += arch/m68k/sun3x/     arch/m68k/sun3/
+core-$(CONFIG_SUN3)            += arch/m68k/sun3/      arch/m68k/sun3/prom/
+core-$(CONFIG_NATFEAT)         += arch/m68k/emu/
+core-$(CONFIG_M68040)          += arch/m68k/fpsp040/
+core-$(CONFIG_M68060)          += arch/m68k/ifpsp060/
+core-$(CONFIG_M68KFPU_EMU)     += arch/m68k/math-emu/
+
+all:   zImage
+
+lilo:  vmlinux
+       if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
+       if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+       cat vmlinux > $(INSTALL_PATH)/vmlinux
+       cp System.map $(INSTALL_PATH)/System.map
+       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+zImage compressed: vmlinux.gz
+
+vmlinux.gz: vmlinux
+
+ifndef CONFIG_KGDB
+       cp vmlinux vmlinux.tmp
+       $(STRIP) vmlinux.tmp
+       gzip -9c vmlinux.tmp >vmlinux.gz
+       rm vmlinux.tmp
+else
+       gzip -9c vmlinux >vmlinux.gz
+endif
+
+bzImage: vmlinux.bz2
+
+vmlinux.bz2: vmlinux
+
+ifndef CONFIG_KGDB
+       cp vmlinux vmlinux.tmp
+       $(STRIP) vmlinux.tmp
+       bzip2 -1c vmlinux.tmp >vmlinux.bz2
+       rm vmlinux.tmp
+else
+       bzip2 -1c vmlinux >vmlinux.bz2
+endif
+
+archclean:
+       rm -f vmlinux.gz vmlinux.bz2
+
+install:
+       sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
diff --git a/arch/m68k/Makefile_no b/arch/m68k/Makefile_no
new file mode 100644 (file)
index 0000000..81652ab
--- /dev/null
@@ -0,0 +1,124 @@
+#
+# arch/m68k/Makefile
+#
+# 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.
+#
+# (C) Copyright 2002, Greg Ungerer <gerg@snapgear.com>
+#
+
+platform-$(CONFIG_M68328)      := 68328
+platform-$(CONFIG_M68EZ328)    := 68EZ328
+platform-$(CONFIG_M68VZ328)    := 68VZ328
+platform-$(CONFIG_M68360)      := 68360
+platform-$(CONFIG_M5206)       := 5206
+platform-$(CONFIG_M5206e)      := 5206e
+platform-$(CONFIG_M520x)       := 520x
+platform-$(CONFIG_M523x)       := 523x
+platform-$(CONFIG_M5249)       := 5249
+platform-$(CONFIG_M527x)       := 527x
+platform-$(CONFIG_M5272)       := 5272
+platform-$(CONFIG_M528x)       := 528x
+platform-$(CONFIG_M5307)       := 5307
+platform-$(CONFIG_M532x)       := 532x
+platform-$(CONFIG_M5407)       := 5407
+platform-$(CONFIG_M54xx)       := 54xx
+PLATFORM := $(platform-y)
+
+board-$(CONFIG_PILOT)          := pilot
+board-$(CONFIG_UC5272)          := UC5272
+board-$(CONFIG_UC5282)          := UC5282
+board-$(CONFIG_UCSIMM)         := ucsimm
+board-$(CONFIG_UCDIMM)         := ucdimm
+board-$(CONFIG_UCQUICC)                := uCquicc
+board-$(CONFIG_DRAGEN2)                := de2
+board-$(CONFIG_ARNEWSH)                := ARNEWSH
+board-$(CONFIG_FREESCALE)      := FREESCALE
+board-$(CONFIG_M5235EVB)       := M5235EVB
+board-$(CONFIG_M5271EVB)       := M5271EVB
+board-$(CONFIG_M5275EVB)       := M5275EVB
+board-$(CONFIG_M5282EVB)       := M5282EVB
+board-$(CONFIG_ELITE)          := eLITE
+board-$(CONFIG_NETtel)         := NETtel
+board-$(CONFIG_SECUREEDGEMP3)  := MP3
+board-$(CONFIG_CLEOPATRA)      := CLEOPATRA
+board-$(CONFIG_senTec)         := senTec
+board-$(CONFIG_SNEHA)          := SNEHA
+board-$(CONFIG_M5208EVB)       := M5208EVB
+board-$(CONFIG_MOD5272)                := MOD5272
+board-$(CONFIG_AVNET)           := AVNET
+board-$(CONFIG_SAVANT)         := SAVANT
+BOARD := $(board-y)
+
+model-$(CONFIG_RAMKERNEL)      := ram
+model-$(CONFIG_ROMKERNEL)      := rom
+MODEL := $(model-y)
+
+#
+# Some code support is grouped together for a common cpu-subclass (for
+# example all ColdFire cpu's are very similar). Determine the sub-class
+# for the selected cpu. ONLY need to define this for the non-base member
+# of the family.
+#
+cpuclass-$(CONFIG_M5206)       := coldfire
+cpuclass-$(CONFIG_M5206e)      := coldfire
+cpuclass-$(CONFIG_M520x)       := coldfire
+cpuclass-$(CONFIG_M523x)       := coldfire
+cpuclass-$(CONFIG_M5249)       := coldfire
+cpuclass-$(CONFIG_M527x)       := coldfire
+cpuclass-$(CONFIG_M5272)       := coldfire
+cpuclass-$(CONFIG_M528x)       := coldfire
+cpuclass-$(CONFIG_M5307)       := coldfire
+cpuclass-$(CONFIG_M532x)       := coldfire
+cpuclass-$(CONFIG_M5407)       := coldfire
+cpuclass-$(CONFIG_M54xx)       := coldfire
+cpuclass-$(CONFIG_M68328)      := 68328
+cpuclass-$(CONFIG_M68EZ328)    := 68328
+cpuclass-$(CONFIG_M68VZ328)    := 68328
+cpuclass-$(CONFIG_M68360)      := 68360
+CPUCLASS := $(cpuclass-y)
+
+ifneq ($(CPUCLASS),$(PLATFORM))
+CLASSDIR := arch/m68k/platform/$(cpuclass-y)/
+endif
+
+export PLATFORM BOARD MODEL CPUCLASS
+
+#
+# Some CFLAG additions based on specific CPU type.
+#
+cflags-$(CONFIG_M5206)         := $(call cc-option,-mcpu=5206,-m5200)
+cflags-$(CONFIG_M5206e)                := $(call cc-option,-mcpu=5206e,-m5200)
+cflags-$(CONFIG_M520x)         := $(call cc-option,-mcpu=5208,-m5200)
+cflags-$(CONFIG_M523x)         := $(call cc-option,-mcpu=523x,-m5307)
+cflags-$(CONFIG_M5249)         := $(call cc-option,-mcpu=5249,-m5200)
+cflags-$(CONFIG_M5271)         := $(call cc-option,-mcpu=5271,-m5307)
+cflags-$(CONFIG_M5272)         := $(call cc-option,-mcpu=5272,-m5307)
+cflags-$(CONFIG_M5275)         := $(call cc-option,-mcpu=5275,-m5307)
+cflags-$(CONFIG_M528x)         := $(call cc-option,-mcpu=528x,-m5307)
+cflags-$(CONFIG_M5307)         := $(call cc-option,-mcpu=5307,-m5200)
+cflags-$(CONFIG_M532x)         := $(call cc-option,-mcpu=532x,-m5307)
+cflags-$(CONFIG_M5407)         := $(call cc-option,-mcpu=5407,-m5200)
+cflags-$(CONFIG_M54xx)         := $(call cc-option,-mcpu=5475,-m5200)
+cflags-$(CONFIG_M68328)                := -m68000
+cflags-$(CONFIG_M68EZ328)      := -m68000
+cflags-$(CONFIG_M68VZ328)      := -m68000
+cflags-$(CONFIG_M68360)                := -m68332
+
+KBUILD_AFLAGS += $(cflags-y)
+
+KBUILD_CFLAGS += $(cflags-y)
+KBUILD_CFLAGS += -D__linux__
+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
+
+head-y := arch/m68k/platform/$(cpuclass-y)/head.o
+
+core-y += arch/m68k/kernel/ \
+          arch/m68k/mm/ \
+          $(CLASSDIR) \
+          arch/m68k/platform/$(PLATFORM)/
+libs-y += arch/m68k/lib/
+
+archclean:
+
diff --git a/arch/m68k/configs/m5208evb_defconfig b/arch/m68k/configs/m5208evb_defconfig
new file mode 100644 (file)
index 0000000..c161682
--- /dev/null
@@ -0,0 +1,76 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M520x=y
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=166666666
+CONFIG_CLOCK_DIV=2
+CONFIG_M5208EVB=y
+# CONFIG_4KSTACKS is not set
+CONFIG_RAMBASE=0x40000000
+CONFIG_RAMSIZE=0x2000000
+CONFIG_VECTORBASE=0x40000000
+CONFIG_KERNELBASE=0x40020000
+CONFIG_RAM16BIT=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_BAUDRATE=115200
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_SYSFS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_FULLDEBUG=y
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68k/configs/m5249evb_defconfig b/arch/m68k/configs/m5249evb_defconfig
new file mode 100644 (file)
index 0000000..a6599e4
--- /dev/null
@@ -0,0 +1,69 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M5249=y
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=140000000
+CONFIG_CLOCK_DIV=2
+CONFIG_M5249C3=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00800000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_PPP=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
+# CONFIG_CRC32 is not set
diff --git a/arch/m68k/configs/m5272c3_defconfig b/arch/m68k/configs/m5272c3_defconfig
new file mode 100644 (file)
index 0000000..3fa60a5
--- /dev/null
@@ -0,0 +1,67 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M5272=y
+CONFIG_CLOCK_SET=y
+CONFIG_M5272C3=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00800000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68k/configs/m5275evb_defconfig b/arch/m68k/configs/m5275evb_defconfig
new file mode 100644 (file)
index 0000000..33c32ae
--- /dev/null
@@ -0,0 +1,74 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M5275=y
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=150000000
+CONFIG_CLOCK_DIV=2
+CONFIG_M5275EVB=y
+# CONFIG_4KSTACKS is not set
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00000000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_FEC=y
+CONFIG_FEC2=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_PPP=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
+# CONFIG_CRC32 is not set
diff --git a/arch/m68k/configs/m5307c3_defconfig b/arch/m68k/configs/m5307c3_defconfig
new file mode 100644 (file)
index 0000000..43795f4
--- /dev/null
@@ -0,0 +1,77 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M5307=y
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=90000000
+CONFIG_CLOCK_DIV=2
+CONFIG_M5307C3=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00800000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_PPP=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_FULLDEBUG=y
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
+# CONFIG_CRC32 is not set
diff --git a/arch/m68k/configs/m5407c3_defconfig b/arch/m68k/configs/m5407c3_defconfig
new file mode 100644 (file)
index 0000000..72746c5
--- /dev/null
@@ -0,0 +1,71 @@
+# CONFIG_MMU is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_M5407=y
+CONFIG_CLOCK_SET=y
+CONFIG_CLOCK_FREQ=50000000
+CONFIG_M5407C3=y
+CONFIG_RAMBASE=0x00000000
+CONFIG_RAMSIZE=0x00000000
+CONFIG_VECTORBASE=0x00000000
+CONFIG_KERNELBASE=0x00020000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=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 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_UCLINUX=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_PPP=y
+# CONFIG_INPUT is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_MCF=y
+CONFIG_SERIAL_MCF_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_ROMFS_FS=y
+CONFIG_ROMFS_BACKED_BY_MTD=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_BOOTPARAM=y
+CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
+# CONFIG_CRC32 is not set
index b4ecdaada5201b11281f57548d36daf3fff16342..9d69f6e6236544156af6af6f002ddc3122b49b92 100644 (file)
@@ -325,58 +325,45 @@ static inline int __fls(int x)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-/* Bitmap functions for the minix filesystem */
+/* Bitmap functions for the little endian bitmap. */
 
-static inline int minix_find_first_zero_bit(const void *vaddr, unsigned size)
+static inline void __set_bit_le(int nr, void *addr)
 {
-       const unsigned short *p = vaddr, *addr = vaddr;
-       int res;
-       unsigned short num;
-
-       if (!size)
-               return 0;
-
-       size = (size >> 4) + ((size & 15) > 0);
-       while (*p++ == 0xffff)
-       {
-               if (--size == 0)
-                       return (p - addr) << 4;
-       }
+       __set_bit(nr ^ 24, addr);
+}
 
-       num = ~*--p;
-       __asm__ __volatile__ ("bfffo %1{#16,#16},%0"
-                             : "=d" (res) : "d" (num & -num));
-       return ((p - addr) << 4) + (res ^ 31);
+static inline void __clear_bit_le(int nr, void *addr)
+{
+       __clear_bit(nr ^ 24, addr);
 }
 
-#define minix_test_and_set_bit(nr, addr)       __test_and_set_bit((nr) ^ 16, (unsigned long *)(addr))
-#define minix_set_bit(nr,addr)                 __set_bit((nr) ^ 16, (unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr, addr)     __test_and_clear_bit((nr) ^ 16, (unsigned long *)(addr))
+static inline int __test_and_set_bit_le(int nr, void *addr)
+{
+       return __test_and_set_bit(nr ^ 24, addr);
+}
 
-static inline int minix_test_bit(int nr, const void *vaddr)
+static inline int test_and_set_bit_le(int nr, void *addr)
 {
-       const unsigned short *p = vaddr;
-       return (p[nr >> 4] & (1U << (nr & 15))) != 0;
+       return test_and_set_bit(nr ^ 24, addr);
 }
 
-/* Bitmap functions for the ext2 filesystem. */
+static inline int __test_and_clear_bit_le(int nr, void *addr)
+{
+       return __test_and_clear_bit(nr ^ 24, addr);
+}
 
-#define ext2_set_bit(nr, addr)                 __test_and_set_bit((nr) ^ 24, (unsigned long *)(addr))
-#define ext2_set_bit_atomic(lock, nr, addr)    test_and_set_bit((nr) ^ 24, (unsigned long *)(addr))
-#define ext2_clear_bit(nr, addr)               __test_and_clear_bit((nr) ^ 24, (unsigned long *)(addr))
-#define ext2_clear_bit_atomic(lock, nr, addr)  test_and_clear_bit((nr) ^ 24, (unsigned long *)(addr))
-#define ext2_find_next_zero_bit(addr, size, offset) \
-       generic_find_next_zero_le_bit((unsigned long *)addr, size, offset)
-#define ext2_find_next_bit(addr, size, offset) \
-       generic_find_next_le_bit((unsigned long *)addr, size, offset)
+static inline int test_and_clear_bit_le(int nr, void *addr)
+{
+       return test_and_clear_bit(nr ^ 24, addr);
+}
 
-static inline int ext2_test_bit(int nr, const void *vaddr)
+static inline int test_bit_le(int nr, const void *vaddr)
 {
        const unsigned char *p = vaddr;
        return (p[nr >> 3] & (1U << (nr & 7))) != 0;
 }
 
-static inline int ext2_find_first_zero_bit(const void *vaddr, unsigned size)
+static inline int find_first_zero_bit_le(const void *vaddr, unsigned size)
 {
        const unsigned long *p = vaddr, *addr = vaddr;
        int res;
@@ -393,33 +380,36 @@ static inline int ext2_find_first_zero_bit(const void *vaddr, unsigned size)
 
        --p;
        for (res = 0; res < 32; res++)
-               if (!ext2_test_bit (res, p))
+               if (!test_bit_le(res, p))
                        break;
        return (p - addr) * 32 + res;
 }
 
-static inline unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
+static inline unsigned long find_next_zero_bit_le(const void *addr,
                unsigned long size, unsigned long offset)
 {
-       const unsigned long *p = addr + (offset >> 5);
+       const unsigned long *p = addr;
        int bit = offset & 31UL, res;
 
        if (offset >= size)
                return size;
 
+       p += offset >> 5;
+
        if (bit) {
+               offset -= bit;
                /* Look for zero in first longword */
                for (res = bit; res < 32; res++)
-                       if (!ext2_test_bit (res, p))
-                               return (p - addr) * 32 + res;
+                       if (!test_bit_le(res, p))
+                               return offset + res;
                p++;
+               offset += 32;
        }
        /* No zero yet, search remaining full bytes for a zero */
-       res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
-       return (p - addr) * 32 + res;
+       return offset + find_first_zero_bit_le(p, size - offset);
 }
 
-static inline int ext2_find_first_bit(const void *vaddr, unsigned size)
+static inline int find_first_bit_le(const void *vaddr, unsigned size)
 {
        const unsigned long *p = vaddr, *addr = vaddr;
        int res;
@@ -435,32 +425,42 @@ static inline int ext2_find_first_bit(const void *vaddr, unsigned size)
 
        --p;
        for (res = 0; res < 32; res++)
-               if (ext2_test_bit(res, p))
+               if (test_bit_le(res, p))
                        break;
        return (p - addr) * 32 + res;
 }
 
-static inline unsigned long generic_find_next_le_bit(const unsigned long *addr,
+static inline unsigned long find_next_bit_le(const void *addr,
                unsigned long size, unsigned long offset)
 {
-       const unsigned long *p = addr + (offset >> 5);
+       const unsigned long *p = addr;
        int bit = offset & 31UL, res;
 
        if (offset >= size)
                return size;
 
+       p += offset >> 5;
+
        if (bit) {
+               offset -= bit;
                /* Look for one in first longword */
                for (res = bit; res < 32; res++)
-                       if (ext2_test_bit(res, p))
-                               return (p - addr) * 32 + res;
+                       if (test_bit_le(res, p))
+                               return offset + res;
                p++;
+               offset += 32;
        }
        /* No set bit yet, search remaining full bytes for a set bit */
-       res = ext2_find_first_bit(p, size - 32 * (p - addr));
-       return (p - addr) * 32 + res;
+       return offset + find_first_bit_le(p, size - offset);
 }
 
+/* Bitmap functions for the ext2 filesystem. */
+
+#define ext2_set_bit_atomic(lock, nr, addr)    \
+       test_and_set_bit_le(nr, addr)
+#define ext2_clear_bit_atomic(lock, nr, addr)  \
+       test_and_clear_bit_le(nr, addr)
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_BITOPS_H */
index 9d3cbe5fad1efa3e9d9c4bb974a79aa63dd99718..7d3779fdc5b6ffa68c6b7374fa106cbb50fd4bb8 100644 (file)
@@ -196,7 +196,19 @@ static __inline__ int __test_bit(int nr, const volatile unsigned long * addr)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 
-static __inline__ int ext2_set_bit(int nr, volatile void * addr)
+#define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
+
+static inline void __set_bit_le(int nr, void *addr)
+{
+       __set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline void __clear_bit_le(int nr, void *addr)
+{
+       __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int __test_and_set_bit_le(int nr, volatile void *addr)
 {
        char retval;
 
@@ -215,7 +227,7 @@ static __inline__ int ext2_set_bit(int nr, volatile void * addr)
        return retval;
 }
 
-static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
+static inline int __test_and_clear_bit_le(int nr, volatile void *addr)
 {
        char retval;
 
@@ -238,7 +250,7 @@ static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
        ({                                              \
                int ret;                                \
                spin_lock(lock);                        \
-               ret = ext2_set_bit((nr), (addr));       \
+               ret = __test_and_set_bit_le((nr), (addr));      \
                spin_unlock(lock);                      \
                ret;                                    \
        })
@@ -247,12 +259,12 @@ static __inline__ int ext2_clear_bit(int nr, volatile void * addr)
        ({                                              \
                int ret;                                \
                spin_lock(lock);                        \
-               ret = ext2_clear_bit((nr), (addr));     \
+               ret = __test_and_clear_bit_le((nr), (addr));    \
                spin_unlock(lock);                      \
                ret;                                    \
        })
 
-static __inline__ int ext2_test_bit(int nr, const volatile void * addr)
+static inline int test_bit_le(int nr, const volatile void *addr)
 {
        char retval;
 
@@ -271,10 +283,10 @@ static __inline__ int ext2_test_bit(int nr, const volatile void * addr)
        return retval;
 }
 
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
+#define find_first_zero_bit_le(addr, size)     \
+       find_next_zero_bit_le((addr), (size), 0)
 
-static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+static inline unsigned long find_next_zero_bit_le(void *addr, unsigned long size, unsigned long offset)
 {
        unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
        unsigned long result = offset & ~31UL;
@@ -324,10 +336,6 @@ found_middle:
        return result + ffz(__swab32(tmp));
 }
 
-#define ext2_find_next_bit(addr, size, off) \
-       generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
-#include <asm-generic/bitops/minix.h>
-
 #endif /* __KERNEL__ */
 
 #include <asm-generic/bitops/fls.h>
index 6441cb5f8e7c84765716a782c0974a5d692f1b3a..b17fd115a4e7e716888f04e61f908965feeec858 100644 (file)
@@ -23,15 +23,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* DMA addresses are always 32-bits wide */
-
-typedef u32 dma_addr_t;
-typedef u32 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_TYPES_H */
index 55d5d6b680a211376390499ee2aee7d2e5d41b61..c482ebc9dd543515b1d413653a2f88616d1722f2 100644 (file)
@@ -1,17 +1,5 @@
-#
-# Makefile for the linux kernel.
-#
-
-ifndef CONFIG_SUN3
-  extra-y := head.o
+ifdef CONFIG_MMU
+include arch/m68k/kernel/Makefile_mm
 else
-  extra-y := sun3-head.o
+include arch/m68k/kernel/Makefile_no
 endif
-extra-y        += vmlinux.lds
-
-obj-y  := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
-          sys_m68k.o time.o setup.o m68k_ksyms.o devres.o
-
-devres-y = ../../../kernel/irq/devres.o
-
-obj-y$(CONFIG_MMU_SUN3) += dma.o       # no, it's not a typo
diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm
new file mode 100644 (file)
index 0000000..55d5d6b
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux kernel.
+#
+
+ifndef CONFIG_SUN3
+  extra-y := head.o
+else
+  extra-y := sun3-head.o
+endif
+extra-y        += vmlinux.lds
+
+obj-y  := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
+          sys_m68k.o time.o setup.o m68k_ksyms.o devres.o
+
+devres-y = ../../../kernel/irq/devres.o
+
+obj-y$(CONFIG_MMU_SUN3) += dma.o       # no, it's not a typo
diff --git a/arch/m68k/kernel/Makefile_no b/arch/m68k/kernel/Makefile_no
new file mode 100644 (file)
index 0000000..37c3fc0
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for arch/m68knommu/kernel.
+#
+
+extra-y := vmlinux.lds
+
+obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
+        setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
+
+obj-$(CONFIG_MODULES)  += module.o
index 78e59b82ebc397ca8f1f4f0df0878aaeb3083be2..59a69a5c62f25243bb9ddbb3195ee1b3d1469bf8 100644 (file)
@@ -1,100 +1,5 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#define ASM_OFFSETS_C
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <linux/font.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
 #ifdef CONFIG_MMU
-       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
+#include "asm-offsets_mm.c"
+#else
+#include "asm-offsets_no.c"
 #endif
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the thread_info struct */
-       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
-       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the bi_record struct */
-       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
-       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
-       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
-
-       /* offsets into font_desc (drivers/video/console/font.h) */
-       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
-       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
-       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
-       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
-       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
-       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
-
-       /* signal defines */
-       DEFINE(LSIGSEGV, SIGSEGV);
-       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(LSIGTRAP, SIGTRAP);
-       DEFINE(LTRAP_TRACE, TRAP_TRACE);
-
-       /* offsets into the custom struct */
-       DEFINE(CUSTOMBASE, &amiga_custom);
-       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
-       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
-       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
-       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
-       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
-       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
-       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
-       DEFINE(CIAABASE, &ciaa);
-       DEFINE(CIABBASE, &ciab);
-       DEFINE(C_PRA, offsetof(struct CIA, pra));
-       DEFINE(ZTWOBASE, zTwoBase);
-
-       return 0;
-}
diff --git a/arch/m68k/kernel/asm-offsets_mm.c b/arch/m68k/kernel/asm-offsets_mm.c
new file mode 100644 (file)
index 0000000..78e59b8
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#define ASM_OFFSETS_C
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/kbuild.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <linux/font.h>
+
+int main(void)
+{
+       /* offsets into the task struct */
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+#ifdef CONFIG_MMU
+       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
+#endif
+
+       /* offsets into the thread struct */
+       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+       /* offsets into the thread_info struct */
+       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
+       /* offsets into the pt_regs */
+       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
+       /* bitfields are a bit difficult */
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
+
+       /* offsets into the irq_cpustat_t struct */
+       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+       /* offsets into the bi_record struct */
+       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+       /* offsets into font_desc (drivers/video/console/font.h) */
+       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
+       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
+       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
+       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
+       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
+       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
+
+       /* signal defines */
+       DEFINE(LSIGSEGV, SIGSEGV);
+       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
+       DEFINE(LSIGTRAP, SIGTRAP);
+       DEFINE(LTRAP_TRACE, TRAP_TRACE);
+
+       /* offsets into the custom struct */
+       DEFINE(CUSTOMBASE, &amiga_custom);
+       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+       DEFINE(CIAABASE, &ciaa);
+       DEFINE(CIABBASE, &ciab);
+       DEFINE(C_PRA, offsetof(struct CIA, pra));
+       DEFINE(ZTWOBASE, zTwoBase);
+
+       return 0;
+}
diff --git a/arch/m68k/kernel/asm-offsets_no.c b/arch/m68k/kernel/asm-offsets_no.c
new file mode 100644 (file)
index 0000000..ffe02f4
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/kbuild.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/thread_info.h>
+
+int main(void)
+{
+       /* offsets into the task struct */
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+
+       /* offsets into the irq_cpustat_t struct */
+       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+       /* offsets into the thread struct */
+       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+       /* offsets into the pt_regs */
+       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
+
+#ifdef CONFIG_COLDFIRE
+       /* bitfields are a bit difficult */
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
+#else
+       /* bitfields are a bit difficult */
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
+#endif
+
+       /* signal defines */
+       DEFINE(SIGSEGV, SIGSEGV);
+       DEFINE(SEGV_MAPERR, SEGV_MAPERR);
+       DEFINE(SIGTRAP, SIGTRAP);
+       DEFINE(TRAP_TRACE, TRAP_TRACE);
+
+       DEFINE(PT_PTRACED, PT_PTRACED);
+
+       /* Offsets in thread_info structure */
+       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
+
+       return 0;
+}
index 4bbb3c2a888057e93c264c76e029909dc7bd8884..90e8cb726c8ca25bdfaa31178672ee8a99af6f4f 100644 (file)
@@ -1,130 +1,5 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#undef DEBUG
-
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/pgalloc.h>
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-                        dma_addr_t *handle, gfp_t flag)
-{
-       struct page *page, **map;
-       pgprot_t pgprot;
-       void *addr;
-       int i, order;
-
-       pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
-
-       size = PAGE_ALIGN(size);
-       order = get_order(size);
-
-       page = alloc_pages(flag, order);
-       if (!page)
-               return NULL;
-
-       *handle = page_to_phys(page);
-       map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
-       if (!map) {
-               __free_pages(page, order);
-               return NULL;
-       }
-       split_page(page, order);
-
-       order = 1 << order;
-       size >>= PAGE_SHIFT;
-       map[0] = page;
-       for (i = 1; i < size; i++)
-               map[i] = page + i;
-       for (; i < order; i++)
-               __free_page(page + i);
-       pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
-       if (CPU_IS_040_OR_060)
-               pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
-       else
-               pgprot_val(pgprot) |= _PAGE_NOCACHE030;
-       addr = vmap(map, size, VM_MAP, pgprot);
-       kfree(map);
-
-       return addr;
-}
-EXPORT_SYMBOL(dma_alloc_coherent);
-
-void dma_free_coherent(struct device *dev, size_t size,
-                      void *addr, dma_addr_t handle)
-{
-       pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
-       vfree(addr);
-}
-EXPORT_SYMBOL(dma_free_coherent);
-
-void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
-                               size_t size, enum dma_data_direction dir)
-{
-       switch (dir) {
-       case DMA_TO_DEVICE:
-               cache_push(handle, size);
-               break;
-       case DMA_FROM_DEVICE:
-               cache_clear(handle, size);
-               break;
-       default:
-               if (printk_ratelimit())
-                       printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
-               break;
-       }
-}
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
-                           enum dma_data_direction dir)
-{
-       int i;
-
-       for (i = 0; i < nents; sg++, i++)
-               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
-}
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-
-dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
-                         enum dma_data_direction dir)
-{
-       dma_addr_t handle = virt_to_bus(addr);
-
-       dma_sync_single_for_device(dev, handle, size, dir);
-       return handle;
-}
-EXPORT_SYMBOL(dma_map_single);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                       unsigned long offset, size_t size,
-                       enum dma_data_direction dir)
-{
-       dma_addr_t handle = page_to_phys(page) + offset;
-
-       dma_sync_single_for_device(dev, handle, size, dir);
-       return handle;
-}
-EXPORT_SYMBOL(dma_map_page);
-
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-              enum dma_data_direction dir)
-{
-       int i;
-
-       for (i = 0; i < nents; sg++, i++) {
-               sg->dma_address = sg_phys(sg);
-               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
-       }
-       return nents;
-}
-EXPORT_SYMBOL(dma_map_sg);
+#ifdef CONFIG_MMU
+#include "dma_mm.c"
+#else
+#include "dma_no.c"
+#endif
diff --git a/arch/m68k/kernel/dma_mm.c b/arch/m68k/kernel/dma_mm.c
new file mode 100644 (file)
index 0000000..4bbb3c2
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#undef DEBUG
+
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/pgalloc.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                        dma_addr_t *handle, gfp_t flag)
+{
+       struct page *page, **map;
+       pgprot_t pgprot;
+       void *addr;
+       int i, order;
+
+       pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
+
+       size = PAGE_ALIGN(size);
+       order = get_order(size);
+
+       page = alloc_pages(flag, order);
+       if (!page)
+               return NULL;
+
+       *handle = page_to_phys(page);
+       map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
+       if (!map) {
+               __free_pages(page, order);
+               return NULL;
+       }
+       split_page(page, order);
+
+       order = 1 << order;
+       size >>= PAGE_SHIFT;
+       map[0] = page;
+       for (i = 1; i < size; i++)
+               map[i] = page + i;
+       for (; i < order; i++)
+               __free_page(page + i);
+       pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+       if (CPU_IS_040_OR_060)
+               pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
+       else
+               pgprot_val(pgprot) |= _PAGE_NOCACHE030;
+       addr = vmap(map, size, VM_MAP, pgprot);
+       kfree(map);
+
+       return addr;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+                      void *addr, dma_addr_t handle)
+{
+       pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
+       vfree(addr);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+                               size_t size, enum dma_data_direction dir)
+{
+       switch (dir) {
+       case DMA_TO_DEVICE:
+               cache_push(handle, size);
+               break;
+       case DMA_FROM_DEVICE:
+               cache_clear(handle, size);
+               break;
+       default:
+               if (printk_ratelimit())
+                       printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
+               break;
+       }
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
+                           enum dma_data_direction dir)
+{
+       int i;
+
+       for (i = 0; i < nents; sg++, i++)
+               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
+                         enum dma_data_direction dir)
+{
+       dma_addr_t handle = virt_to_bus(addr);
+
+       dma_sync_single_for_device(dev, handle, size, dir);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                       unsigned long offset, size_t size,
+                       enum dma_data_direction dir)
+{
+       dma_addr_t handle = page_to_phys(page) + offset;
+
+       dma_sync_single_for_device(dev, handle, size, dir);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+              enum dma_data_direction dir)
+{
+       int i;
+
+       for (i = 0; i < nents; sg++, i++) {
+               sg->dma_address = sg_phys(sg);
+               dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
+       }
+       return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
diff --git a/arch/m68k/kernel/dma_no.c b/arch/m68k/kernel/dma_no.c
new file mode 100644 (file)
index 0000000..fc61541
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Dynamic DMA mapping support.
+ *
+ * We never have any address translations to worry about, so this
+ * is just alloc/free.
+ */
+
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, gfp_t gfp)
+{
+       void *ret;
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (dev == NULL || (*dev->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_phys(ret);
+       }
+       return ret;
+}
+
+void dma_free_coherent(struct device *dev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       free_pages((unsigned long)vaddr, get_order(size));
+}
+
+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:
+               flush_dcache_range(handle, size);
+               break;
+       case DMA_FROM_DEVICE:
+               /* Should be clear already */
+               break;
+       default:
+               if (printk_ratelimit())
+                       printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
+               break;
+       }
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_device);
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
+                         enum dma_data_direction dir)
+{
+       dma_addr_t handle = virt_to_phys(addr);
+       flush_dcache_range(handle, size);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                       unsigned long offset, size_t size,
+                       enum dma_data_direction dir)
+{
+       dma_addr_t handle = page_to_phys(page) + offset;
+       dma_sync_single_for_device(dev, handle, size, dir);
+       return handle;
+}
+EXPORT_SYMBOL(dma_map_page);
index 1559dea36e5581f62bf2d8b4b1fe6c6da37308f4..081cf96f243b01ee4cbea14b415f7364c08fd0fe 100644 (file)
@@ -1,753 +1,5 @@
-/* -*- mode: asm -*-
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- *
- */
-
-/*
- * entry.S  contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- *
- * NOTE: This code handles signal-recognition, which happens every time
- * after a timer-interrupt and after each system call.
- *
- */
-
-/*
- * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
- *               all pointers that used to be 'current' are now entry
- *               number 0 in the 'current_set' list.
- *
- *  6/05/00 RZ:         addedd writeback completion after return from sighandler
- *              for 68040
- */
-
-#include <linux/linkage.h>
-#include <asm/entry.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/unistd.h>
-
-#include <asm/asm-offsets.h>
-
-.globl system_call, buserr, trap, resume
-.globl sys_call_table
-.globl sys_fork, sys_clone, sys_vfork
-.globl ret_from_interrupt, bad_interrupt
-.globl auto_irqhandler_fixup
-.globl user_irqvec_fixup, user_irqhandler_fixup
-
-.text
-ENTRY(buserr)
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-       movel   %sp,%sp@-               | stack frame pointer argument
-       bsrl    buserr_c
-       addql   #4,%sp
-       jra     .Lret_from_exception
-
-ENTRY(trap)
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-       movel   %sp,%sp@-               | stack frame pointer argument
-       bsrl    trap_c
-       addql   #4,%sp
-       jra     .Lret_from_exception
-
-       | After a fork we jump here directly from resume,
-       | so that %d1 contains the previous task
-       | schedule_tail now used regardless of CONFIG_SMP
-ENTRY(ret_from_fork)
-       movel   %d1,%sp@-
-       jsr     schedule_tail
-       addql   #4,%sp
-       jra     .Lret_from_exception
-
-do_trace_entry:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %sp@(PT_OFF_ORIG_D0),%d0
-       cmpl    #NR_syscalls,%d0
-       jcs     syscall
-badsys:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)
-       jra     ret_from_syscall
-
-do_trace_exit:
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     .Lret_from_exception
-
-ENTRY(ret_from_signal)
-       tstb    %curptr@(TASK_INFO+TINFO_FLAGS+2)
-       jge     1f
-       jbsr    syscall_trace
-1:     RESTORE_SWITCH_STACK
-       addql   #4,%sp
-/* on 68040 complete pending writebacks if any */
-#ifdef CONFIG_M68040
-       bfextu  %sp@(PT_OFF_FORMATVEC){#0,#4},%d0
-       subql   #7,%d0                          | bus error frame ?
-       jbne    1f
-       movel   %sp,%sp@-
-       jbsr    berr_040cleanup
-       addql   #4,%sp
-1:
+#ifdef CONFIG_MMU
+#include "entry_mm.S"
+#else
+#include "entry_no.S"
 #endif
-       jra     .Lret_from_exception
-
-ENTRY(system_call)
-       SAVE_ALL_SYS
-
-       GET_CURRENT(%d1)
-       | save top of frame
-       movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
-
-       | syscall trace?
-       tstb    %curptr@(TASK_INFO+TINFO_FLAGS+2)
-       jmi     do_trace_entry
-       cmpl    #NR_syscalls,%d0
-       jcc     badsys
-syscall:
-       jbsr    @(sys_call_table,%d0:l:4)@(0)
-       movel   %d0,%sp@(PT_OFF_D0)     | save the return value
-ret_from_syscall:
-       |oriw   #0x0700,%sr
-       movew   %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
-       jne     syscall_exit_work
-1:     RESTORE_ALL
-
-syscall_exit_work:
-       btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
-       bnes    1b                      | if so, skip resched, signals
-       lslw    #1,%d0
-       jcs     do_trace_exit
-       jmi     do_delayed_trace
-       lslw    #8,%d0
-       jmi     do_signal_return
-       pea     resume_userspace
-       jra     schedule
-
-
-ENTRY(ret_from_exception)
-.Lret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
-       bnes    1f                      | if so, skip resched, signals
-       | only allow interrupts when we are really the last one on the
-       | kernel stack, otherwise stack overflow can occur during
-       | heavy interrupt load
-       andw    #ALLOWINT,%sr
-
-resume_userspace:
-       moveb   %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
-       jne     exit_work
-1:     RESTORE_ALL
-
-exit_work:
-       | save top of frame
-       movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
-       lslb    #1,%d0
-       jmi     do_signal_return
-       pea     resume_userspace
-       jra     schedule
-
-
-do_signal_return:
-       |andw   #ALLOWINT,%sr
-       subql   #4,%sp                  | dummy return address
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       bsrl    do_signal
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jbra    resume_userspace
-
-do_delayed_trace:
-       bclr    #7,%sp@(PT_OFF_SR)      | clear trace bit in SR
-       pea     1                       | send SIGTRAP
-       movel   %curptr,%sp@-
-       pea     LSIGTRAP
-       jbsr    send_sig
-       addql   #8,%sp
-       addql   #4,%sp
-       jbra    resume_userspace
-
-
-/* This is the main interrupt handler for autovector interrupts */
-
-ENTRY(auto_inthandler)
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-                                       |  put exception # in d0
-       bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
-       subw    #VEC_SPUR,%d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               |  put vector # on stack
-auto_irqhandler_fixup = . + 2
-       jsr     __m68k_handle_int       |  process the IRQ
-       addql   #8,%sp                  |  pop parameters off stack
-
-ret_from_interrupt:
-       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-       jeq     ret_from_last_interrupt
-2:     RESTORE_ALL
-
-       ALIGN
-ret_from_last_interrupt:
-       moveq   #(~ALLOWINT>>8)&0xff,%d0
-       andb    %sp@(PT_OFF_SR),%d0
-       jne     2b
-
-       /* check if we need to do software interrupts */
-       tstl    irq_stat+CPUSTAT_SOFTIRQ_PENDING
-       jeq     .Lret_from_exception
-       pea     ret_from_exception
-       jra     do_softirq
-
-/* Handler for user defined interrupt vectors */
-
-ENTRY(user_inthandler)
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-                                       |  put exception # in d0
-       bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
-user_irqvec_fixup = . + 2
-       subw    #VEC_USER,%d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               |  put vector # on stack
-user_irqhandler_fixup = . + 2
-       jsr     __m68k_handle_int       |  process the IRQ
-       addql   #8,%sp                  |  pop parameters off stack
-
-       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-       jeq     ret_from_last_interrupt
-       RESTORE_ALL
-
-/* Handler for uninitialized and spurious interrupts */
-
-ENTRY(bad_inthandler)
-       SAVE_ALL_INT
-       GET_CURRENT(%d0)
-       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-
-       movel   %sp,%sp@-
-       jsr     handle_badint
-       addql   #4,%sp
-
-       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
-       jeq     ret_from_last_interrupt
-       RESTORE_ALL
-
-
-ENTRY(sys_fork)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_fork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_clone)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_clone
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_vfork)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_vfork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_sigreturn)
-       SAVE_SWITCH_STACK
-       jbsr    do_sigreturn
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_rt_sigreturn)
-       SAVE_SWITCH_STACK
-       jbsr    do_rt_sigreturn
-       RESTORE_SWITCH_STACK
-       rts
-
-resume:
-       /*
-        * Beware - when entering resume, prev (the current task) is
-        * in a0, next (the new task) is in a1,so don't change these
-        * registers until their contents are no longer needed.
-        */
-
-       /* save sr */
-       movew   %sr,%a0@(TASK_THREAD+THREAD_SR)
-
-       /* save fs (sfc,%dfc) (may be pointing to kernel memory) */
-       movec   %sfc,%d0
-       movew   %d0,%a0@(TASK_THREAD+THREAD_FS)
-
-       /* save usp */
-       /* it is better to use a movel here instead of a movew 8*) */
-       movec   %usp,%d0
-       movel   %d0,%a0@(TASK_THREAD+THREAD_USP)
-
-       /* save non-scratch registers on stack */
-       SAVE_SWITCH_STACK
-
-       /* save current kernel stack pointer */
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP)
-
-       /* save floating point context */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
-       tstl    m68k_fputype
-       jeq     3f
-#endif
-       fsave   %a0@(TASK_THREAD+THREAD_FPSTATE)
-
-#if defined(CONFIG_M68060)
-#if !defined(CPU_M68060_ONLY)
-       btst    #3,m68k_cputype+3
-       beqs    1f
-#endif
-       /* The 060 FPU keeps status in bits 15-8 of the first longword */
-       tstb    %a0@(TASK_THREAD+THREAD_FPSTATE+2)
-       jeq     3f
-#if !defined(CPU_M68060_ONLY)
-       jra     2f
-#endif
-#endif /* CONFIG_M68060 */
-#if !defined(CPU_M68060_ONLY)
-1:     tstb    %a0@(TASK_THREAD+THREAD_FPSTATE)
-       jeq     3f
-#endif
-2:     fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
-       fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
-3:
-#endif /* CONFIG_M68KFPU_EMU_ONLY */
-       /* Return previous task in %d1 */
-       movel   %curptr,%d1
-
-       /* switch to new task (a1 contains new task) */
-       movel   %a1,%curptr
-
-       /* restore floating point context */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-#ifdef CONFIG_M68KFPU_EMU
-       tstl    m68k_fputype
-       jeq     4f
-#endif
-#if defined(CONFIG_M68060)
-#if !defined(CPU_M68060_ONLY)
-       btst    #3,m68k_cputype+3
-       beqs    1f
-#endif
-       /* The 060 FPU keeps status in bits 15-8 of the first longword */
-       tstb    %a1@(TASK_THREAD+THREAD_FPSTATE+2)
-       jeq     3f
-#if !defined(CPU_M68060_ONLY)
-       jra     2f
-#endif
-#endif /* CONFIG_M68060 */
-#if !defined(CPU_M68060_ONLY)
-1:     tstb    %a1@(TASK_THREAD+THREAD_FPSTATE)
-       jeq     3f
-#endif
-2:     fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
-       fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
-3:     frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
-4:
-#endif /* CONFIG_M68KFPU_EMU_ONLY */
-
-       /* restore the kernel stack pointer */
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp
-
-       /* restore non-scratch registers */
-       RESTORE_SWITCH_STACK
-
-       /* restore user stack pointer */
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a0
-       movel   %a0,%usp
-
-       /* restore fs (sfc,%dfc) */
-       movew   %a1@(TASK_THREAD+THREAD_FS),%a0
-       movec   %a0,%sfc
-       movec   %a0,%dfc
-
-       /* restore status register */
-       movew   %a1@(TASK_THREAD+THREAD_SR),%sr
-
-       rts
-
-.data
-ALIGN
-sys_call_table:
-       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
-       .long sys_exit
-       .long sys_fork
-       .long sys_read
-       .long sys_write
-       .long sys_open          /* 5 */
-       .long sys_close
-       .long sys_waitpid
-       .long sys_creat
-       .long sys_link
-       .long sys_unlink        /* 10 */
-       .long sys_execve
-       .long sys_chdir
-       .long sys_time
-       .long sys_mknod
-       .long sys_chmod         /* 15 */
-       .long sys_chown16
-       .long sys_ni_syscall                            /* old break syscall holder */
-       .long sys_stat
-       .long sys_lseek
-       .long sys_getpid        /* 20 */
-       .long sys_mount
-       .long sys_oldumount
-       .long sys_setuid16
-       .long sys_getuid16
-       .long sys_stime         /* 25 */
-       .long sys_ptrace
-       .long sys_alarm
-       .long sys_fstat
-       .long sys_pause
-       .long sys_utime         /* 30 */
-       .long sys_ni_syscall                            /* old stty syscall holder */
-       .long sys_ni_syscall                            /* old gtty syscall holder */
-       .long sys_access
-       .long sys_nice
-       .long sys_ni_syscall    /* 35 */        /* old ftime syscall holder */
-       .long sys_sync
-       .long sys_kill
-       .long sys_rename
-       .long sys_mkdir
-       .long sys_rmdir         /* 40 */
-       .long sys_dup
-       .long sys_pipe
-       .long sys_times
-       .long sys_ni_syscall                            /* old prof syscall holder */
-       .long sys_brk           /* 45 */
-       .long sys_setgid16
-       .long sys_getgid16
-       .long sys_signal
-       .long sys_geteuid16
-       .long sys_getegid16     /* 50 */
-       .long sys_acct
-       .long sys_umount                                /* recycled never used phys() */
-       .long sys_ni_syscall                            /* old lock syscall holder */
-       .long sys_ioctl
-       .long sys_fcntl         /* 55 */
-       .long sys_ni_syscall                            /* old mpx syscall holder */
-       .long sys_setpgid
-       .long sys_ni_syscall                            /* old ulimit syscall holder */
-       .long sys_ni_syscall
-       .long sys_umask         /* 60 */
-       .long sys_chroot
-       .long sys_ustat
-       .long sys_dup2
-       .long sys_getppid
-       .long sys_getpgrp       /* 65 */
-       .long sys_setsid
-       .long sys_sigaction
-       .long sys_sgetmask
-       .long sys_ssetmask
-       .long sys_setreuid16    /* 70 */
-       .long sys_setregid16
-       .long sys_sigsuspend
-       .long sys_sigpending
-       .long sys_sethostname
-       .long sys_setrlimit     /* 75 */
-       .long sys_old_getrlimit
-       .long sys_getrusage
-       .long sys_gettimeofday
-       .long sys_settimeofday
-       .long sys_getgroups16   /* 80 */
-       .long sys_setgroups16
-       .long sys_old_select
-       .long sys_symlink
-       .long sys_lstat
-       .long sys_readlink      /* 85 */
-       .long sys_uselib
-       .long sys_swapon
-       .long sys_reboot
-       .long sys_old_readdir
-       .long sys_old_mmap      /* 90 */
-       .long sys_munmap
-       .long sys_truncate
-       .long sys_ftruncate
-       .long sys_fchmod
-       .long sys_fchown16      /* 95 */
-       .long sys_getpriority
-       .long sys_setpriority
-       .long sys_ni_syscall                            /* old profil syscall holder */
-       .long sys_statfs
-       .long sys_fstatfs       /* 100 */
-       .long sys_ni_syscall                            /* ioperm for i386 */
-       .long sys_socketcall
-       .long sys_syslog
-       .long sys_setitimer
-       .long sys_getitimer     /* 105 */
-       .long sys_newstat
-       .long sys_newlstat
-       .long sys_newfstat
-       .long sys_ni_syscall
-       .long sys_ni_syscall    /* 110 */       /* iopl for i386 */
-       .long sys_vhangup
-       .long sys_ni_syscall                            /* obsolete idle() syscall */
-       .long sys_ni_syscall                            /* vm86old for i386 */
-       .long sys_wait4
-       .long sys_swapoff       /* 115 */
-       .long sys_sysinfo
-       .long sys_ipc
-       .long sys_fsync
-       .long sys_sigreturn
-       .long sys_clone         /* 120 */
-       .long sys_setdomainname
-       .long sys_newuname
-       .long sys_cacheflush                            /* modify_ldt for i386 */
-       .long sys_adjtimex
-       .long sys_mprotect      /* 125 */
-       .long sys_sigprocmask
-       .long sys_ni_syscall            /* old "create_module" */
-       .long sys_init_module
-       .long sys_delete_module
-       .long sys_ni_syscall    /* 130 - old "get_kernel_syms" */
-       .long sys_quotactl
-       .long sys_getpgid
-       .long sys_fchdir
-       .long sys_bdflush
-       .long sys_sysfs         /* 135 */
-       .long sys_personality
-       .long sys_ni_syscall                            /* for afs_syscall */
-       .long sys_setfsuid16
-       .long sys_setfsgid16
-       .long sys_llseek        /* 140 */
-       .long sys_getdents
-       .long sys_select
-       .long sys_flock
-       .long sys_msync
-       .long sys_readv         /* 145 */
-       .long sys_writev
-       .long sys_getsid
-       .long sys_fdatasync
-       .long sys_sysctl
-       .long sys_mlock         /* 150 */
-       .long sys_munlock
-       .long sys_mlockall
-       .long sys_munlockall
-       .long sys_sched_setparam
-       .long sys_sched_getparam        /* 155 */
-       .long sys_sched_setscheduler
-       .long sys_sched_getscheduler
-       .long sys_sched_yield
-       .long sys_sched_get_priority_max
-       .long sys_sched_get_priority_min  /* 160 */
-       .long sys_sched_rr_get_interval
-       .long sys_nanosleep
-       .long sys_mremap
-       .long sys_setresuid16
-       .long sys_getresuid16   /* 165 */
-       .long sys_getpagesize
-       .long sys_ni_syscall            /* old sys_query_module */
-       .long sys_poll
-       .long sys_nfsservctl
-       .long sys_setresgid16   /* 170 */
-       .long sys_getresgid16
-       .long sys_prctl
-       .long sys_rt_sigreturn
-       .long sys_rt_sigaction
-       .long sys_rt_sigprocmask        /* 175 */
-       .long sys_rt_sigpending
-       .long sys_rt_sigtimedwait
-       .long sys_rt_sigqueueinfo
-       .long sys_rt_sigsuspend
-       .long sys_pread64       /* 180 */
-       .long sys_pwrite64
-       .long sys_lchown16;
-       .long sys_getcwd
-       .long sys_capget
-       .long sys_capset        /* 185 */
-       .long sys_sigaltstack
-       .long sys_sendfile
-       .long sys_ni_syscall                            /* streams1 */
-       .long sys_ni_syscall                            /* streams2 */
-       .long sys_vfork         /* 190 */
-       .long sys_getrlimit
-       .long sys_mmap2
-       .long sys_truncate64
-       .long sys_ftruncate64
-       .long sys_stat64        /* 195 */
-       .long sys_lstat64
-       .long sys_fstat64
-       .long sys_chown
-       .long sys_getuid
-       .long sys_getgid        /* 200 */
-       .long sys_geteuid
-       .long sys_getegid
-       .long sys_setreuid
-       .long sys_setregid
-       .long sys_getgroups     /* 205 */
-       .long sys_setgroups
-       .long sys_fchown
-       .long sys_setresuid
-       .long sys_getresuid
-       .long sys_setresgid     /* 210 */
-       .long sys_getresgid
-       .long sys_lchown
-       .long sys_setuid
-       .long sys_setgid
-       .long sys_setfsuid      /* 215 */
-       .long sys_setfsgid
-       .long sys_pivot_root
-       .long sys_ni_syscall
-       .long sys_ni_syscall
-       .long sys_getdents64    /* 220 */
-       .long sys_gettid
-       .long sys_tkill
-       .long sys_setxattr
-       .long sys_lsetxattr
-       .long sys_fsetxattr     /* 225 */
-       .long sys_getxattr
-       .long sys_lgetxattr
-       .long sys_fgetxattr
-       .long sys_listxattr
-       .long sys_llistxattr    /* 230 */
-       .long sys_flistxattr
-       .long sys_removexattr
-       .long sys_lremovexattr
-       .long sys_fremovexattr
-       .long sys_futex         /* 235 */
-       .long sys_sendfile64
-       .long sys_mincore
-       .long sys_madvise
-       .long sys_fcntl64
-       .long sys_readahead     /* 240 */
-       .long sys_io_setup
-       .long sys_io_destroy
-       .long sys_io_getevents
-       .long sys_io_submit
-       .long sys_io_cancel     /* 245 */
-       .long sys_fadvise64
-       .long sys_exit_group
-       .long sys_lookup_dcookie
-       .long sys_epoll_create
-       .long sys_epoll_ctl     /* 250 */
-       .long sys_epoll_wait
-       .long sys_remap_file_pages
-       .long sys_set_tid_address
-       .long sys_timer_create
-       .long sys_timer_settime /* 255 */
-       .long sys_timer_gettime
-       .long sys_timer_getoverrun
-       .long sys_timer_delete
-       .long sys_clock_settime
-       .long sys_clock_gettime /* 260 */
-       .long sys_clock_getres
-       .long sys_clock_nanosleep
-       .long sys_statfs64
-       .long sys_fstatfs64
-       .long sys_tgkill        /* 265 */
-       .long sys_utimes
-       .long sys_fadvise64_64
-       .long sys_mbind
-       .long sys_get_mempolicy
-       .long sys_set_mempolicy /* 270 */
-       .long sys_mq_open
-       .long sys_mq_unlink
-       .long sys_mq_timedsend
-       .long sys_mq_timedreceive
-       .long sys_mq_notify     /* 275 */
-       .long sys_mq_getsetattr
-       .long sys_waitid
-       .long sys_ni_syscall    /* for sys_vserver */
-       .long sys_add_key
-       .long sys_request_key   /* 280 */
-       .long sys_keyctl
-       .long sys_ioprio_set
-       .long sys_ioprio_get
-       .long sys_inotify_init
-       .long sys_inotify_add_watch     /* 285 */
-       .long sys_inotify_rm_watch
-       .long sys_migrate_pages
-       .long sys_openat
-       .long sys_mkdirat
-       .long sys_mknodat               /* 290 */
-       .long sys_fchownat
-       .long sys_futimesat
-       .long sys_fstatat64
-       .long sys_unlinkat
-       .long sys_renameat              /* 295 */
-       .long sys_linkat
-       .long sys_symlinkat
-       .long sys_readlinkat
-       .long sys_fchmodat
-       .long sys_faccessat             /* 300 */
-       .long sys_ni_syscall            /* Reserved for pselect6 */
-       .long sys_ni_syscall            /* Reserved for ppoll */
-       .long sys_unshare
-       .long sys_set_robust_list
-       .long sys_get_robust_list       /* 305 */
-       .long sys_splice
-       .long sys_sync_file_range
-       .long sys_tee
-       .long sys_vmsplice
-       .long sys_move_pages            /* 310 */
-       .long sys_sched_setaffinity
-       .long sys_sched_getaffinity
-       .long sys_kexec_load
-       .long sys_getcpu
-       .long sys_epoll_pwait           /* 315 */
-       .long sys_utimensat
-       .long sys_signalfd
-       .long sys_timerfd_create
-       .long sys_eventfd
-       .long sys_fallocate             /* 320 */
-       .long sys_timerfd_settime
-       .long sys_timerfd_gettime
-       .long sys_signalfd4
-       .long sys_eventfd2
-       .long sys_epoll_create1         /* 325 */
-       .long sys_dup3
-       .long sys_pipe2
-       .long sys_inotify_init1
-       .long sys_preadv
-       .long sys_pwritev               /* 330 */
-       .long sys_rt_tgsigqueueinfo
-       .long sys_perf_event_open
-       .long sys_get_thread_area
-       .long sys_set_thread_area
-       .long sys_atomic_cmpxchg_32     /* 335 */
-       .long sys_atomic_barrier
-       .long sys_fanotify_init
-       .long sys_fanotify_mark
-       .long sys_prlimit64
-
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
new file mode 100644 (file)
index 0000000..1559dea
--- /dev/null
@@ -0,0 +1,753 @@
+/* -*- mode: asm -*-
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ *
+ */
+
+/*
+ * entry.S  contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ */
+
+/*
+ * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
+ *               all pointers that used to be 'current' are now entry
+ *               number 0 in the 'current_set' list.
+ *
+ *  6/05/00 RZ:         addedd writeback completion after return from sighandler
+ *              for 68040
+ */
+
+#include <linux/linkage.h>
+#include <asm/entry.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/unistd.h>
+
+#include <asm/asm-offsets.h>
+
+.globl system_call, buserr, trap, resume
+.globl sys_call_table
+.globl sys_fork, sys_clone, sys_vfork
+.globl ret_from_interrupt, bad_interrupt
+.globl auto_irqhandler_fixup
+.globl user_irqvec_fixup, user_irqhandler_fixup
+
+.text
+ENTRY(buserr)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       movel   %sp,%sp@-               | stack frame pointer argument
+       bsrl    buserr_c
+       addql   #4,%sp
+       jra     .Lret_from_exception
+
+ENTRY(trap)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       movel   %sp,%sp@-               | stack frame pointer argument
+       bsrl    trap_c
+       addql   #4,%sp
+       jra     .Lret_from_exception
+
+       | After a fork we jump here directly from resume,
+       | so that %d1 contains the previous task
+       | schedule_tail now used regardless of CONFIG_SMP
+ENTRY(ret_from_fork)
+       movel   %d1,%sp@-
+       jsr     schedule_tail
+       addql   #4,%sp
+       jra     .Lret_from_exception
+
+do_trace_entry:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+       cmpl    #NR_syscalls,%d0
+       jcs     syscall
+badsys:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
+       jra     ret_from_syscall
+
+do_trace_exit:
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     .Lret_from_exception
+
+ENTRY(ret_from_signal)
+       tstb    %curptr@(TASK_INFO+TINFO_FLAGS+2)
+       jge     1f
+       jbsr    syscall_trace
+1:     RESTORE_SWITCH_STACK
+       addql   #4,%sp
+/* on 68040 complete pending writebacks if any */
+#ifdef CONFIG_M68040
+       bfextu  %sp@(PT_OFF_FORMATVEC){#0,#4},%d0
+       subql   #7,%d0                          | bus error frame ?
+       jbne    1f
+       movel   %sp,%sp@-
+       jbsr    berr_040cleanup
+       addql   #4,%sp
+1:
+#endif
+       jra     .Lret_from_exception
+
+ENTRY(system_call)
+       SAVE_ALL_SYS
+
+       GET_CURRENT(%d1)
+       | save top of frame
+       movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+
+       | syscall trace?
+       tstb    %curptr@(TASK_INFO+TINFO_FLAGS+2)
+       jmi     do_trace_entry
+       cmpl    #NR_syscalls,%d0
+       jcc     badsys
+syscall:
+       jbsr    @(sys_call_table,%d0:l:4)@(0)
+       movel   %d0,%sp@(PT_OFF_D0)     | save the return value
+ret_from_syscall:
+       |oriw   #0x0700,%sr
+       movew   %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
+       jne     syscall_exit_work
+1:     RESTORE_ALL
+
+syscall_exit_work:
+       btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
+       bnes    1b                      | if so, skip resched, signals
+       lslw    #1,%d0
+       jcs     do_trace_exit
+       jmi     do_delayed_trace
+       lslw    #8,%d0
+       jmi     do_signal_return
+       pea     resume_userspace
+       jra     schedule
+
+
+ENTRY(ret_from_exception)
+.Lret_from_exception:
+       btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
+       bnes    1f                      | if so, skip resched, signals
+       | only allow interrupts when we are really the last one on the
+       | kernel stack, otherwise stack overflow can occur during
+       | heavy interrupt load
+       andw    #ALLOWINT,%sr
+
+resume_userspace:
+       moveb   %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
+       jne     exit_work
+1:     RESTORE_ALL
+
+exit_work:
+       | save top of frame
+       movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
+       lslb    #1,%d0
+       jmi     do_signal_return
+       pea     resume_userspace
+       jra     schedule
+
+
+do_signal_return:
+       |andw   #ALLOWINT,%sr
+       subql   #4,%sp                  | dummy return address
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       bsrl    do_signal
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jbra    resume_userspace
+
+do_delayed_trace:
+       bclr    #7,%sp@(PT_OFF_SR)      | clear trace bit in SR
+       pea     1                       | send SIGTRAP
+       movel   %curptr,%sp@-
+       pea     LSIGTRAP
+       jbsr    send_sig
+       addql   #8,%sp
+       addql   #4,%sp
+       jbra    resume_userspace
+
+
+/* This is the main interrupt handler for autovector interrupts */
+
+ENTRY(auto_inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+                                       |  put exception # in d0
+       bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
+       subw    #VEC_SPUR,%d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               |  put vector # on stack
+auto_irqhandler_fixup = . + 2
+       jsr     __m68k_handle_int       |  process the IRQ
+       addql   #8,%sp                  |  pop parameters off stack
+
+ret_from_interrupt:
+       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+       jeq     ret_from_last_interrupt
+2:     RESTORE_ALL
+
+       ALIGN
+ret_from_last_interrupt:
+       moveq   #(~ALLOWINT>>8)&0xff,%d0
+       andb    %sp@(PT_OFF_SR),%d0
+       jne     2b
+
+       /* check if we need to do software interrupts */
+       tstl    irq_stat+CPUSTAT_SOFTIRQ_PENDING
+       jeq     .Lret_from_exception
+       pea     ret_from_exception
+       jra     do_softirq
+
+/* Handler for user defined interrupt vectors */
+
+ENTRY(user_inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+                                       |  put exception # in d0
+       bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
+user_irqvec_fixup = . + 2
+       subw    #VEC_USER,%d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               |  put vector # on stack
+user_irqhandler_fixup = . + 2
+       jsr     __m68k_handle_int       |  process the IRQ
+       addql   #8,%sp                  |  pop parameters off stack
+
+       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+       jeq     ret_from_last_interrupt
+       RESTORE_ALL
+
+/* Handler for uninitialized and spurious interrupts */
+
+ENTRY(bad_inthandler)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+       addqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+
+       movel   %sp,%sp@-
+       jsr     handle_badint
+       addql   #4,%sp
+
+       subqb   #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+       jeq     ret_from_last_interrupt
+       RESTORE_ALL
+
+
+ENTRY(sys_fork)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_fork
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_clone)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_clone
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_vfork)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_vfork
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_sigreturn)
+       SAVE_SWITCH_STACK
+       jbsr    do_sigreturn
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_rt_sigreturn)
+       SAVE_SWITCH_STACK
+       jbsr    do_rt_sigreturn
+       RESTORE_SWITCH_STACK
+       rts
+
+resume:
+       /*
+        * Beware - when entering resume, prev (the current task) is
+        * in a0, next (the new task) is in a1,so don't change these
+        * registers until their contents are no longer needed.
+        */
+
+       /* save sr */
+       movew   %sr,%a0@(TASK_THREAD+THREAD_SR)
+
+       /* save fs (sfc,%dfc) (may be pointing to kernel memory) */
+       movec   %sfc,%d0
+       movew   %d0,%a0@(TASK_THREAD+THREAD_FS)
+
+       /* save usp */
+       /* it is better to use a movel here instead of a movew 8*) */
+       movec   %usp,%d0
+       movel   %d0,%a0@(TASK_THREAD+THREAD_USP)
+
+       /* save non-scratch registers on stack */
+       SAVE_SWITCH_STACK
+
+       /* save current kernel stack pointer */
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP)
+
+       /* save floating point context */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+       tstl    m68k_fputype
+       jeq     3f
+#endif
+       fsave   %a0@(TASK_THREAD+THREAD_FPSTATE)
+
+#if defined(CONFIG_M68060)
+#if !defined(CPU_M68060_ONLY)
+       btst    #3,m68k_cputype+3
+       beqs    1f
+#endif
+       /* The 060 FPU keeps status in bits 15-8 of the first longword */
+       tstb    %a0@(TASK_THREAD+THREAD_FPSTATE+2)
+       jeq     3f
+#if !defined(CPU_M68060_ONLY)
+       jra     2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CPU_M68060_ONLY)
+1:     tstb    %a0@(TASK_THREAD+THREAD_FPSTATE)
+       jeq     3f
+#endif
+2:     fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
+       fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
+3:
+#endif /* CONFIG_M68KFPU_EMU_ONLY */
+       /* Return previous task in %d1 */
+       movel   %curptr,%d1
+
+       /* switch to new task (a1 contains new task) */
+       movel   %a1,%curptr
+
+       /* restore floating point context */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+       tstl    m68k_fputype
+       jeq     4f
+#endif
+#if defined(CONFIG_M68060)
+#if !defined(CPU_M68060_ONLY)
+       btst    #3,m68k_cputype+3
+       beqs    1f
+#endif
+       /* The 060 FPU keeps status in bits 15-8 of the first longword */
+       tstb    %a1@(TASK_THREAD+THREAD_FPSTATE+2)
+       jeq     3f
+#if !defined(CPU_M68060_ONLY)
+       jra     2f
+#endif
+#endif /* CONFIG_M68060 */
+#if !defined(CPU_M68060_ONLY)
+1:     tstb    %a1@(TASK_THREAD+THREAD_FPSTATE)
+       jeq     3f
+#endif
+2:     fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
+       fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
+3:     frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
+4:
+#endif /* CONFIG_M68KFPU_EMU_ONLY */
+
+       /* restore the kernel stack pointer */
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp
+
+       /* restore non-scratch registers */
+       RESTORE_SWITCH_STACK
+
+       /* restore user stack pointer */
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a0
+       movel   %a0,%usp
+
+       /* restore fs (sfc,%dfc) */
+       movew   %a1@(TASK_THREAD+THREAD_FS),%a0
+       movec   %a0,%sfc
+       movec   %a0,%dfc
+
+       /* restore status register */
+       movew   %a1@(TASK_THREAD+THREAD_SR),%sr
+
+       rts
+
+.data
+ALIGN
+sys_call_table:
+       .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open          /* 5 */
+       .long sys_close
+       .long sys_waitpid
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink        /* 10 */
+       .long sys_execve
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod         /* 15 */
+       .long sys_chown16
+       .long sys_ni_syscall                            /* old break syscall holder */
+       .long sys_stat
+       .long sys_lseek
+       .long sys_getpid        /* 20 */
+       .long sys_mount
+       .long sys_oldumount
+       .long sys_setuid16
+       .long sys_getuid16
+       .long sys_stime         /* 25 */
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_fstat
+       .long sys_pause
+       .long sys_utime         /* 30 */
+       .long sys_ni_syscall                            /* old stty syscall holder */
+       .long sys_ni_syscall                            /* old gtty syscall holder */
+       .long sys_access
+       .long sys_nice
+       .long sys_ni_syscall    /* 35 */        /* old ftime syscall holder */
+       .long sys_sync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir         /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_ni_syscall                            /* old prof syscall holder */
+       .long sys_brk           /* 45 */
+       .long sys_setgid16
+       .long sys_getgid16
+       .long sys_signal
+       .long sys_geteuid16
+       .long sys_getegid16     /* 50 */
+       .long sys_acct
+       .long sys_umount                                /* recycled never used phys() */
+       .long sys_ni_syscall                            /* old lock syscall holder */
+       .long sys_ioctl
+       .long sys_fcntl         /* 55 */
+       .long sys_ni_syscall                            /* old mpx syscall holder */
+       .long sys_setpgid
+       .long sys_ni_syscall                            /* old ulimit syscall holder */
+       .long sys_ni_syscall
+       .long sys_umask         /* 60 */
+       .long sys_chroot
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp       /* 65 */
+       .long sys_setsid
+       .long sys_sigaction
+       .long sys_sgetmask
+       .long sys_ssetmask
+       .long sys_setreuid16    /* 70 */
+       .long sys_setregid16
+       .long sys_sigsuspend
+       .long sys_sigpending
+       .long sys_sethostname
+       .long sys_setrlimit     /* 75 */
+       .long sys_old_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups16   /* 80 */
+       .long sys_setgroups16
+       .long sys_old_select
+       .long sys_symlink
+       .long sys_lstat
+       .long sys_readlink      /* 85 */
+       .long sys_uselib
+       .long sys_swapon
+       .long sys_reboot
+       .long sys_old_readdir
+       .long sys_old_mmap      /* 90 */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown16      /* 95 */
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_ni_syscall                            /* old profil syscall holder */
+       .long sys_statfs
+       .long sys_fstatfs       /* 100 */
+       .long sys_ni_syscall                            /* ioperm for i386 */
+       .long sys_socketcall
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer     /* 105 */
+       .long sys_newstat
+       .long sys_newlstat
+       .long sys_newfstat
+       .long sys_ni_syscall
+       .long sys_ni_syscall    /* 110 */       /* iopl for i386 */
+       .long sys_vhangup
+       .long sys_ni_syscall                            /* obsolete idle() syscall */
+       .long sys_ni_syscall                            /* vm86old for i386 */
+       .long sys_wait4
+       .long sys_swapoff       /* 115 */
+       .long sys_sysinfo
+       .long sys_ipc
+       .long sys_fsync
+       .long sys_sigreturn
+       .long sys_clone         /* 120 */
+       .long sys_setdomainname
+       .long sys_newuname
+       .long sys_cacheflush                            /* modify_ldt for i386 */
+       .long sys_adjtimex
+       .long sys_mprotect      /* 125 */
+       .long sys_sigprocmask
+       .long sys_ni_syscall            /* old "create_module" */
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_ni_syscall    /* 130 - old "get_kernel_syms" */
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_fchdir
+       .long sys_bdflush
+       .long sys_sysfs         /* 135 */
+       .long sys_personality
+       .long sys_ni_syscall                            /* for afs_syscall */
+       .long sys_setfsuid16
+       .long sys_setfsgid16
+       .long sys_llseek        /* 140 */
+       .long sys_getdents
+       .long sys_select
+       .long sys_flock
+       .long sys_msync
+       .long sys_readv         /* 145 */
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl
+       .long sys_mlock         /* 150 */
+       .long sys_munlock
+       .long sys_mlockall
+       .long sys_munlockall
+       .long sys_sched_setparam
+       .long sys_sched_getparam        /* 155 */
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max
+       .long sys_sched_get_priority_min  /* 160 */
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_mremap
+       .long sys_setresuid16
+       .long sys_getresuid16   /* 165 */
+       .long sys_getpagesize
+       .long sys_ni_syscall            /* old sys_query_module */
+       .long sys_poll
+       .long sys_nfsservctl
+       .long sys_setresgid16   /* 170 */
+       .long sys_getresgid16
+       .long sys_prctl
+       .long sys_rt_sigreturn
+       .long sys_rt_sigaction
+       .long sys_rt_sigprocmask        /* 175 */
+       .long sys_rt_sigpending
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long sys_rt_sigsuspend
+       .long sys_pread64       /* 180 */
+       .long sys_pwrite64
+       .long sys_lchown16;
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset        /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall                            /* streams1 */
+       .long sys_ni_syscall                            /* streams2 */
+       .long sys_vfork         /* 190 */
+       .long sys_getrlimit
+       .long sys_mmap2
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64        /* 195 */
+       .long sys_lstat64
+       .long sys_fstat64
+       .long sys_chown
+       .long sys_getuid
+       .long sys_getgid        /* 200 */
+       .long sys_geteuid
+       .long sys_getegid
+       .long sys_setreuid
+       .long sys_setregid
+       .long sys_getgroups     /* 205 */
+       .long sys_setgroups
+       .long sys_fchown
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setresgid     /* 210 */
+       .long sys_getresgid
+       .long sys_lchown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid      /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_ni_syscall
+       .long sys_ni_syscall
+       .long sys_getdents64    /* 220 */
+       .long sys_gettid
+       .long sys_tkill
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr     /* 225 */
+       .long sys_getxattr
+       .long sys_lgetxattr
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr    /* 230 */
+       .long sys_flistxattr
+       .long sys_removexattr
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_futex         /* 235 */
+       .long sys_sendfile64
+       .long sys_mincore
+       .long sys_madvise
+       .long sys_fcntl64
+       .long sys_readahead     /* 240 */
+       .long sys_io_setup
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel     /* 245 */
+       .long sys_fadvise64
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 250 */
+       .long sys_epoll_wait
+       .long sys_remap_file_pages
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime /* 255 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime /* 260 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill        /* 265 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_mbind
+       .long sys_get_mempolicy
+       .long sys_set_mempolicy /* 270 */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive
+       .long sys_mq_notify     /* 275 */
+       .long sys_mq_getsetattr
+       .long sys_waitid
+       .long sys_ni_syscall    /* for sys_vserver */
+       .long sys_add_key
+       .long sys_request_key   /* 280 */
+       .long sys_keyctl
+       .long sys_ioprio_set
+       .long sys_ioprio_get
+       .long sys_inotify_init
+       .long sys_inotify_add_watch     /* 285 */
+       .long sys_inotify_rm_watch
+       .long sys_migrate_pages
+       .long sys_openat
+       .long sys_mkdirat
+       .long sys_mknodat               /* 290 */
+       .long sys_fchownat
+       .long sys_futimesat
+       .long sys_fstatat64
+       .long sys_unlinkat
+       .long sys_renameat              /* 295 */
+       .long sys_linkat
+       .long sys_symlinkat
+       .long sys_readlinkat
+       .long sys_fchmodat
+       .long sys_faccessat             /* 300 */
+       .long sys_ni_syscall            /* Reserved for pselect6 */
+       .long sys_ni_syscall            /* Reserved for ppoll */
+       .long sys_unshare
+       .long sys_set_robust_list
+       .long sys_get_robust_list       /* 305 */
+       .long sys_splice
+       .long sys_sync_file_range
+       .long sys_tee
+       .long sys_vmsplice
+       .long sys_move_pages            /* 310 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_kexec_load
+       .long sys_getcpu
+       .long sys_epoll_pwait           /* 315 */
+       .long sys_utimensat
+       .long sys_signalfd
+       .long sys_timerfd_create
+       .long sys_eventfd
+       .long sys_fallocate             /* 320 */
+       .long sys_timerfd_settime
+       .long sys_timerfd_gettime
+       .long sys_signalfd4
+       .long sys_eventfd2
+       .long sys_epoll_create1         /* 325 */
+       .long sys_dup3
+       .long sys_pipe2
+       .long sys_inotify_init1
+       .long sys_preadv
+       .long sys_pwritev               /* 330 */
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_event_open
+       .long sys_get_thread_area
+       .long sys_set_thread_area
+       .long sys_atomic_cmpxchg_32     /* 335 */
+       .long sys_atomic_barrier
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
+
diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S
new file mode 100644 (file)
index 0000000..2783f25
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  linux/arch/m68knommu/kernel/entry.S
+ *
+ *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
+ *
+ * Based on:
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ * ColdFire support by Greg Ungerer (gerg@snapgear.com)
+ * 5307 fixes by David W. Miller
+ * linux 2.4 support David McCullough <davidm@snapgear.com>
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+#include <asm/unistd.h>
+
+.text
+
+.globl buserr
+.globl trap
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_fork
+.globl sys_clone
+.globl sys_vfork
+
+ENTRY(buserr)
+       SAVE_ALL
+       moveq   #-1,%d0
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
+       movel   %sp,%sp@-               /* stack frame pointer argument */
+       jsr     buserr_c
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(trap)
+       SAVE_ALL
+       moveq   #-1,%d0
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
+       movel   %sp,%sp@-               /* stack frame pointer argument */
+       jsr     trap_c
+       addql   #4,%sp
+       jra     ret_from_exception
+
+#ifdef TRAP_DBG_INTERRUPT
+
+.globl dbginterrupt
+ENTRY(dbginterrupt)
+       SAVE_ALL
+       moveq   #-1,%d0
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
+       movel   %sp,%sp@-               /* stack frame pointer argument */
+       jsr     dbginterrupt_c
+       addql   #4,%sp
+       jra     ret_from_exception
+#endif
+
+ENTRY(reschedule)
+       /* save top of frame */
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
+       pea     ret_from_exception
+       jmp     schedule
+
+ENTRY(ret_from_fork)
+       movel   %d1,%sp@-
+       jsr     schedule_tail
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(sys_fork)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_fork
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_vfork)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_vfork
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_clone)
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jbsr    m68k_clone
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_sigreturn)
+       SAVE_SWITCH_STACK
+       jbsr    do_sigreturn
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(sys_rt_sigreturn)
+       SAVE_SWITCH_STACK
+       jbsr    do_rt_sigreturn
+       RESTORE_SWITCH_STACK
+       rts
+
+ENTRY(ret_from_user_signal)
+       moveq #__NR_sigreturn,%d0
+       trap #0
+
+ENTRY(ret_from_user_rt_signal)
+       movel #__NR_rt_sigreturn,%d0
+       trap #0
+
diff --git a/arch/m68k/kernel/init_task.c b/arch/m68k/kernel/init_task.c
new file mode 100644 (file)
index 0000000..cbf9dc3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  linux/arch/m68knommu/kernel/init_task.c
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+__asm__(".align 4");
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union __init_task_data =
+       { INIT_THREAD_INFO(init_task) };
+
diff --git a/arch/m68k/kernel/irq.c b/arch/m68k/kernel/irq.c
new file mode 100644 (file)
index 0000000..c7dd48f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * irq.c
+ *
+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+       struct pt_regs *oldregs = set_irq_regs(regs);
+
+       irq_enter();
+       generic_handle_irq(irq);
+       irq_exit();
+
+       set_irq_regs(oldregs);
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+       struct irqaction *ap;
+       int irq = *((loff_t *) v);
+
+       if (irq == 0)
+               seq_puts(p, "           CPU0\n");
+
+       if (irq < NR_IRQS) {
+               struct irq_desc *desc = irq_to_desc(irq);
+
+               ap = desc->action;
+               if (ap) {
+                       seq_printf(p, "%3d: ", irq);
+                       seq_printf(p, "%10u ", kstat_irqs(irq));
+                       seq_printf(p, "%14s  ", get_irq_desc_chip(desc)->name);
+
+                       seq_printf(p, "%s", ap->name);
+                       for (ap = ap->next; ap; ap = ap->next)
+                               seq_printf(p, ", %s", ap->name);
+                       seq_putc(p, '\n');
+               }
+       }
+
+       return 0;
+}
+
index d900e77e53632fd28b734245842d735a1e3323b7..4752c28ce0acefbb42a3f374db1636d425fcda07 100644 (file)
@@ -1,16 +1,5 @@
-#include <linux/module.h>
-
-asmlinkage long long __ashldi3 (long long, int);
-asmlinkage long long __ashrdi3 (long long, int);
-asmlinkage long long __lshrdi3 (long long, int);
-asmlinkage long long __muldi3 (long long, long long);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-
+#ifdef CONFIG_MMU
+#include "m68k_ksyms_mm.c"
+#else
+#include "m68k_ksyms_no.c"
+#endif
diff --git a/arch/m68k/kernel/m68k_ksyms_mm.c b/arch/m68k/kernel/m68k_ksyms_mm.c
new file mode 100644 (file)
index 0000000..d900e77
--- /dev/null
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+
+asmlinkage long long __ashldi3 (long long, int);
+asmlinkage long long __ashrdi3 (long long, int);
+asmlinkage long long __lshrdi3 (long long, int);
+asmlinkage long long __muldi3 (long long, long long);
+
+/* The following are special because they're not called
+   explicitly (the C compiler generates them).  Fortunately,
+   their interface isn't gonna change any time soon now, so
+   it's OK to leave it out of version control.  */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+
diff --git a/arch/m68k/kernel/m68k_ksyms_no.c b/arch/m68k/kernel/m68k_ksyms_no.c
new file mode 100644 (file)
index 0000000..39fe0a7
--- /dev/null
@@ -0,0 +1,78 @@
+#include <linux/module.h>
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/machdep.h>
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/checksum.h>
+#include <asm/current.h>
+
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+
+/* platform dependent support */
+
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(dump_fpu);
+
+EXPORT_SYMBOL(ip_fast_csum);
+
+EXPORT_SYMBOL(kernel_thread);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+/* The following are special because they're not called
+   explicitly (the C compiler generates them).  Fortunately,
+   their interface isn't gonna change any time soon now, so
+   it's OK to leave it out of version control.  */
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __mulsi3(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+
+        /* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+
+#ifdef CONFIG_COLDFIRE
+extern unsigned int *dma_device_address;
+extern unsigned long dma_base_addr, _ramend;
+EXPORT_SYMBOL(dma_base_addr);
+EXPORT_SYMBOL(dma_device_address);
+EXPORT_SYMBOL(_ramend);
+
+extern asmlinkage void trap(void);
+extern void    *_ramvec;
+EXPORT_SYMBOL(trap);
+EXPORT_SYMBOL(_ramvec);
+#endif /* CONFIG_COLDFIRE */
index cd6bcb1c957e925c55583a0249961f09e395b74d..7ea203ce6b1a35321ae4229cb14cd626c1417841 100644 (file)
@@ -1,155 +1,5 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#if 0
-#define DEBUGP printk
+#ifdef CONFIG_MMU
+#include "module_mm.c"
 #else
-#define DEBUGP(fmt...)
+#include "module_no.c"
 #endif
-
-#ifdef CONFIG_MODULES
-
-void *module_alloc(unsigned long size)
-{
-       if (size == 0)
-               return NULL;
-       return vmalloc(size);
-}
-
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-}
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       unsigned int i;
-       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       uint32_t *location;
-
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_68K_32:
-                       /* We add the value into the location given */
-                       *location += sym->st_value;
-                       break;
-               case R_68K_PC32:
-                       /* Add the value, subtract its postition */
-                       *location += sym->st_value - (uint32_t)location;
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-                              me->name, ELF32_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-       unsigned int i;
-       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       uint32_t *location;
-
-       DEBUGP("Applying relocate_add section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_68K_32:
-                       /* We add the value into the location given */
-                       *location = rel[i].r_addend + sym->st_value;
-                       break;
-               case R_68K_PC32:
-                       /* Add the value, subtract its postition */
-                       *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-                              me->name, ELF32_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *mod)
-{
-       module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
-
-       return 0;
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-}
-
-#endif /* CONFIG_MODULES */
-
-void module_fixup(struct module *mod, struct m68k_fixup_info *start,
-                 struct m68k_fixup_info *end)
-{
-       struct m68k_fixup_info *fixup;
-
-       for (fixup = start; fixup < end; fixup++) {
-               switch (fixup->type) {
-               case m68k_fixup_memoffset:
-                       *(u32 *)fixup->addr = m68k_memoffset;
-                       break;
-               case m68k_fixup_vnode_shift:
-                       *(u16 *)fixup->addr += m68k_virt_to_node_shift;
-                       break;
-               }
-       }
-}
diff --git a/arch/m68k/kernel/module_mm.c b/arch/m68k/kernel/module_mm.c
new file mode 100644 (file)
index 0000000..cd6bcb1
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+#ifdef CONFIG_MODULES
+
+void *module_alloc(unsigned long size)
+{
+       if (size == 0)
+               return NULL;
+       return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       unsigned int i;
+       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_68K_32:
+                       /* We add the value into the location given */
+                       *location += sym->st_value;
+                       break;
+               case R_68K_PC32:
+                       /* Add the value, subtract its postition */
+                       *location += sym->st_value - (uint32_t)location;
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate_add section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_68K_32:
+                       /* We add the value into the location given */
+                       *location = rel[i].r_addend + sym->st_value;
+                       break;
+               case R_68K_PC32:
+                       /* Add the value, subtract its postition */
+                       *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *mod)
+{
+       module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
+
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
+
+#endif /* CONFIG_MODULES */
+
+void module_fixup(struct module *mod, struct m68k_fixup_info *start,
+                 struct m68k_fixup_info *end)
+{
+       struct m68k_fixup_info *fixup;
+
+       for (fixup = start; fixup < end; fixup++) {
+               switch (fixup->type) {
+               case m68k_fixup_memoffset:
+                       *(u32 *)fixup->addr = m68k_memoffset;
+                       break;
+               case m68k_fixup_vnode_shift:
+                       *(u16 *)fixup->addr += m68k_virt_to_node_shift;
+                       break;
+               }
+       }
+}
diff --git a/arch/m68k/kernel/module_no.c b/arch/m68k/kernel/module_no.c
new file mode 100644 (file)
index 0000000..d11ffae
--- /dev/null
@@ -0,0 +1,126 @@
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+       if (size == 0)
+               return NULL;
+       return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       unsigned int i;
+       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_68K_32:
+                       /* We add the value into the location given */
+                       *location += sym->st_value;
+                       break;
+               case R_68K_PC32:
+                       /* Add the value, subtract its postition */
+                       *location += sym->st_value - (uint32_t)location;
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+
+       DEBUGP("Applying relocate_add section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_68K_32:
+                       /* We add the value into the location given */
+                       *location = rel[i].r_addend + sym->st_value;
+                       break;
+               case R_68K_PC32:
+                       /* Add the value, subtract its postition */
+                       *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
+                       break;
+               default:
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *me)
+{
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
index c2a1fc23dd758e69a49bb45d6e62247f4adf68ce..6cf4bd6e34f8c80641697de7dd8d37c5c9bc0c14 100644 (file)
@@ -1,354 +1,5 @@
-/*
- *  linux/arch/m68k/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/reboot.h>
-#include <linux/init_task.h>
-#include <linux/mqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-/*
- * Initial task/thread structure. Make this a per-architecture thing,
- * because different architectures tend to have different
- * alignment requirements and potentially different initial
- * setup.
- */
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-union thread_union init_thread_union __init_task_data
-       __attribute__((aligned(THREAD_SIZE))) =
-               { INIT_THREAD_INFO(init_task) };
-
-/* initial task structure */
-struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_task);
-
-asmlinkage void ret_from_fork(void);
-
-
-/*
- * Return saved PC from a blocked thread
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-       /* Check whether the thread is blocked in resume() */
-       if (in_sched_functions(sw->retpc))
-               return ((unsigned long *)sw->a6)[1];
-       else
-               return sw->retpc;
-}
-
-/*
- * The idle loop on an m68k..
- */
-static void default_idle(void)
-{
-       if (!need_resched())
-#if defined(MACH_ATARI_ONLY)
-               /* block out HSYNC on the atari (falcon) */
-               __asm__("stop #0x2200" : : : "cc");
+#ifdef CONFIG_MMU
+#include "process_mm.c"
 #else
-               __asm__("stop #0x2000" : : : "cc");
+#include "process_no.c"
 #endif
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-       /* endless idle loop with no priority at all */
-       while (1) {
-               while (!need_resched())
-                       idle();
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-       }
-}
-
-void machine_restart(char * __unused)
-{
-       if (mach_reset)
-               mach_reset();
-       for (;;);
-}
-
-void machine_halt(void)
-{
-       if (mach_halt)
-               mach_halt();
-       for (;;);
-}
-
-void machine_power_off(void)
-{
-       if (mach_power_off)
-               mach_power_off();
-       for (;;);
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
-void show_regs(struct pt_regs * regs)
-{
-       printk("\n");
-       printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-       printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-              regs->orig_d0, regs->d0, regs->a2, regs->a1);
-       printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
-              regs->a0, regs->d5, regs->d4);
-       printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
-              regs->d3, regs->d2, regs->d1);
-       if (!(regs->sr & PS_S))
-               printk("USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       int pid;
-       mm_segment_t fs;
-
-       fs = get_fs();
-       set_fs (KERNEL_DS);
-
-       {
-       register long retval __asm__ ("d0");
-       register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
-
-       retval = __NR_clone;
-       __asm__ __volatile__
-         ("clrl %%d2\n\t"
-          "trap #0\n\t"                /* Linux/m68k system call */
-          "tstl %0\n\t"                /* child or parent */
-          "jne 1f\n\t"                 /* parent - jump */
-          "lea %%sp@(%c7),%6\n\t"      /* reload current */
-          "movel %6@,%6\n\t"
-          "movel %3,%%sp@-\n\t"        /* push argument */
-          "jsr %4@\n\t"                /* call fn */
-          "movel %0,%%d1\n\t"          /* pass exit value */
-          "movel %2,%%d0\n\t"          /* exit */
-          "trap #0\n"
-          "1:"
-          : "+d" (retval)
-          : "i" (__NR_clone), "i" (__NR_exit),
-            "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
-            "i" (-THREAD_SIZE)
-          : "d2");
-
-       pid = retval;
-       }
-
-       set_fs (fs);
-       return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
-void flush_thread(void)
-{
-       unsigned long zero = 0;
-       set_fs(USER_DS);
-       current->thread.fs = __USER_DS;
-       if (!FPU_IS_EMU)
-               asm volatile (".chip 68k/68881\n\t"
-                             "frestore %0@\n\t"
-                             ".chip 68k" : : "a" (&zero));
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
-                      NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-       int __user *parent_tidptr, *child_tidptr;
-
-       /* syscall2 puts clone_flags in d1 and usp in d2 */
-       clone_flags = regs->d1;
-       newsp = regs->d2;
-       parent_tidptr = (int __user *)regs->d3;
-       child_tidptr = (int __user *)regs->d4;
-       if (!newsp)
-               newsp = rdusp();
-       return do_fork(clone_flags, newsp, regs, 0,
-                      parent_tidptr, child_tidptr);
-}
-
-int copy_thread(unsigned long clone_flags, unsigned long usp,
-                unsigned long unused,
-                struct task_struct * p, struct pt_regs * regs)
-{
-       struct pt_regs * childregs;
-       struct switch_stack * childstack, *stack;
-       unsigned long *retp;
-
-       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-       *childregs = *regs;
-       childregs->d0 = 0;
-
-       retp = ((unsigned long *) regs);
-       stack = ((struct switch_stack *) retp) - 1;
-
-       childstack = ((struct switch_stack *) childregs) - 1;
-       *childstack = *stack;
-       childstack->retpc = (unsigned long)ret_from_fork;
-
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childstack;
-
-       if (clone_flags & CLONE_SETTLS)
-               task_thread_info(p)->tp_value = regs->d5;
-
-       /*
-        * Must save the current SFC/DFC value, NOT the value when
-        * the parent was last descheduled - RGH  10-08-96
-        */
-       p->thread.fs = get_fs().seg;
-
-       if (!FPU_IS_EMU) {
-               /* Copy the current fpu state */
-               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-               if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
-                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
-                               : "memory");
-               /* Restore the state in case the fpu was busy */
-               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-       }
-
-       return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-       char fpustate[216];
-
-       if (FPU_IS_EMU) {
-               int i;
-
-               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-               memcpy(fpu->fpregs, current->thread.fp, 96);
-               /* Convert internal fpu reg representation
-                * into long double format
-                */
-               for (i = 0; i < 24; i += 3)
-                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
-               return 1;
-       }
-
-       /* First dump the fpu context to avoid protocol violation.  */
-       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-       if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
-               return 0;
-
-       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-               :: "m" (fpu->fpcntl[0])
-               : "memory");
-       asm volatile ("fmovemx %/fp0-%/fp7,%0"
-               :: "m" (fpu->fpregs[0])
-               : "memory");
-       return 1;
-}
-EXPORT_SYMBOL(dump_fpu);
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
-                         const char __user *const __user *argv,
-                         const char __user *const __user *envp)
-{
-       int error;
-       char * filename;
-       struct pt_regs *regs = (struct pt_regs *) &name;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-       unsigned long fp, pc;
-       unsigned long stack_page;
-       int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
-               return 0;
-
-       stack_page = (unsigned long)task_stack_page(p);
-       fp = ((struct switch_stack *)p->thread.ksp)->a6;
-       do {
-               if (fp < stack_page+sizeof(struct thread_info) ||
-                   fp >= 8184+stack_page)
-                       return 0;
-               pc = ((unsigned long *)fp)[1];
-               if (!in_sched_functions(pc))
-                       return pc;
-               fp = *(unsigned long *) fp;
-       } while (count++ < 16);
-       return 0;
-}
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
new file mode 100644 (file)
index 0000000..c2a1fc2
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ *  linux/arch/m68k/kernel/process.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  68060 fixes by Jesper Skov
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/reboot.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+/*
+ * Initial task/thread structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+union thread_union init_thread_union __init_task_data
+       __attribute__((aligned(THREAD_SIZE))) =
+               { INIT_THREAD_INFO(init_task) };
+
+/* initial task structure */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
+asmlinkage void ret_from_fork(void);
+
+
+/*
+ * Return saved PC from a blocked thread
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
+       /* Check whether the thread is blocked in resume() */
+       if (in_sched_functions(sw->retpc))
+               return ((unsigned long *)sw->a6)[1];
+       else
+               return sw->retpc;
+}
+
+/*
+ * The idle loop on an m68k..
+ */
+static void default_idle(void)
+{
+       if (!need_resched())
+#if defined(MACH_ATARI_ONLY)
+               /* block out HSYNC on the atari (falcon) */
+               __asm__("stop #0x2200" : : : "cc");
+#else
+               __asm__("stop #0x2000" : : : "cc");
+#endif
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       while (1) {
+               while (!need_resched())
+                       idle();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+void machine_restart(char * __unused)
+{
+       if (mach_reset)
+               mach_reset();
+       for (;;);
+}
+
+void machine_halt(void)
+{
+       if (mach_halt)
+               mach_halt();
+       for (;;);
+}
+
+void machine_power_off(void)
+{
+       if (mach_power_off)
+               mach_power_off();
+       for (;;);
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+       printk("\n");
+       printk("Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
+              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
+       printk("ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
+              regs->orig_d0, regs->d0, regs->a2, regs->a1);
+       printk("A0: %08lx  D5: %08lx  D4: %08lx\n",
+              regs->a0, regs->d5, regs->d4);
+       printk("D3: %08lx  D2: %08lx  D1: %08lx\n",
+              regs->d3, regs->d2, regs->d1);
+       if (!(regs->sr & PS_S))
+               printk("USP: %08lx\n", rdusp());
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       int pid;
+       mm_segment_t fs;
+
+       fs = get_fs();
+       set_fs (KERNEL_DS);
+
+       {
+       register long retval __asm__ ("d0");
+       register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
+
+       retval = __NR_clone;
+       __asm__ __volatile__
+         ("clrl %%d2\n\t"
+          "trap #0\n\t"                /* Linux/m68k system call */
+          "tstl %0\n\t"                /* child or parent */
+          "jne 1f\n\t"                 /* parent - jump */
+          "lea %%sp@(%c7),%6\n\t"      /* reload current */
+          "movel %6@,%6\n\t"
+          "movel %3,%%sp@-\n\t"        /* push argument */
+          "jsr %4@\n\t"                /* call fn */
+          "movel %0,%%d1\n\t"          /* pass exit value */
+          "movel %2,%%d0\n\t"          /* exit */
+          "trap #0\n"
+          "1:"
+          : "+d" (retval)
+          : "i" (__NR_clone), "i" (__NR_exit),
+            "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
+            "i" (-THREAD_SIZE)
+          : "d2");
+
+       pid = retval;
+       }
+
+       set_fs (fs);
+       return pid;
+}
+EXPORT_SYMBOL(kernel_thread);
+
+void flush_thread(void)
+{
+       unsigned long zero = 0;
+       set_fs(USER_DS);
+       current->thread.fs = __USER_DS;
+       if (!FPU_IS_EMU)
+               asm volatile (".chip 68k/68881\n\t"
+                             "frestore %0@\n\t"
+                             ".chip 68k" : : "a" (&zero));
+}
+
+/*
+ * "m68k_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+
+asmlinkage int m68k_fork(struct pt_regs *regs)
+{
+       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
+                      NULL, NULL);
+}
+
+asmlinkage int m68k_clone(struct pt_regs *regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+       int __user *parent_tidptr, *child_tidptr;
+
+       /* syscall2 puts clone_flags in d1 and usp in d2 */
+       clone_flags = regs->d1;
+       newsp = regs->d2;
+       parent_tidptr = (int __user *)regs->d3;
+       child_tidptr = (int __user *)regs->d4;
+       if (!newsp)
+               newsp = rdusp();
+       return do_fork(clone_flags, newsp, regs, 0,
+                      parent_tidptr, child_tidptr);
+}
+
+int copy_thread(unsigned long clone_flags, unsigned long usp,
+                unsigned long unused,
+                struct task_struct * p, struct pt_regs * regs)
+{
+       struct pt_regs * childregs;
+       struct switch_stack * childstack, *stack;
+       unsigned long *retp;
+
+       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+
+       *childregs = *regs;
+       childregs->d0 = 0;
+
+       retp = ((unsigned long *) regs);
+       stack = ((struct switch_stack *) retp) - 1;
+
+       childstack = ((struct switch_stack *) childregs) - 1;
+       *childstack = *stack;
+       childstack->retpc = (unsigned long)ret_from_fork;
+
+       p->thread.usp = usp;
+       p->thread.ksp = (unsigned long)childstack;
+
+       if (clone_flags & CLONE_SETTLS)
+               task_thread_info(p)->tp_value = regs->d5;
+
+       /*
+        * Must save the current SFC/DFC value, NOT the value when
+        * the parent was last descheduled - RGH  10-08-96
+        */
+       p->thread.fs = get_fs().seg;
+
+       if (!FPU_IS_EMU) {
+               /* Copy the current fpu state */
+               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
+
+               if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
+                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
+                               : "memory");
+               /* Restore the state in case the fpu was busy */
+               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+       }
+
+       return 0;
+}
+
+/* Fill in the fpu structure for a core dump.  */
+
+int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+{
+       char fpustate[216];
+
+       if (FPU_IS_EMU) {
+               int i;
+
+               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
+               memcpy(fpu->fpregs, current->thread.fp, 96);
+               /* Convert internal fpu reg representation
+                * into long double format
+                */
+               for (i = 0; i < 24; i += 3)
+                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
+                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
+               return 1;
+       }
+
+       /* First dump the fpu context to avoid protocol violation.  */
+       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+       if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
+               return 0;
+
+       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+               :: "m" (fpu->fpcntl[0])
+               : "memory");
+       asm volatile ("fmovemx %/fp0-%/fp7,%0"
+               :: "m" (fpu->fpregs[0])
+               : "memory");
+       return 1;
+}
+EXPORT_SYMBOL(dump_fpu);
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char __user *name,
+                         const char __user *const __user *argv,
+                         const char __user *const __user *envp)
+{
+       int error;
+       char * filename;
+       struct pt_regs *regs = (struct pt_regs *) &name;
+
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               return error;
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+       return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long fp, pc;
+       unsigned long stack_page;
+       int count = 0;
+       if (!p || p == current || p->state == TASK_RUNNING)
+               return 0;
+
+       stack_page = (unsigned long)task_stack_page(p);
+       fp = ((struct switch_stack *)p->thread.ksp)->a6;
+       do {
+               if (fp < stack_page+sizeof(struct thread_info) ||
+                   fp >= 8184+stack_page)
+                       return 0;
+               pc = ((unsigned long *)fp)[1];
+               if (!in_sched_functions(pc))
+                       return pc;
+               fp = *(unsigned long *) fp;
+       } while (count++ < 16);
+       return 0;
+}
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
new file mode 100644 (file)
index 0000000..e2a63af
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  linux/arch/m68knommu/kernel/process.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  68060 fixes by Jesper Skov
+ *
+ *  uClinux changes
+ *  Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+
+asmlinkage void ret_from_fork(void);
+
+/*
+ * The following aren't currently used.
+ */
+void (*pm_idle)(void);
+EXPORT_SYMBOL(pm_idle);
+
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+/*
+ * The idle loop on an m68knommu..
+ */
+static void default_idle(void)
+{
+       local_irq_disable();
+       while (!need_resched()) {
+               /* This stop will re-enable interrupts */
+               __asm__("stop #0x2000" : : : "cc");
+               local_irq_disable();
+       }
+       local_irq_enable();
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       while (1) {
+               idle();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+void machine_restart(char * __unused)
+{
+       if (mach_reset)
+               mach_reset();
+       for (;;);
+}
+
+void machine_halt(void)
+{
+       if (mach_halt)
+               mach_halt();
+       for (;;);
+}
+
+void machine_power_off(void)
+{
+       if (mach_power_off)
+               mach_power_off();
+       for (;;);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+       printk(KERN_NOTICE "\n");
+       printk(KERN_NOTICE "Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
+              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
+       printk(KERN_NOTICE "ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
+              regs->orig_d0, regs->d0, regs->a2, regs->a1);
+       printk(KERN_NOTICE "A0: %08lx  D5: %08lx  D4: %08lx\n",
+              regs->a0, regs->d5, regs->d4);
+       printk(KERN_NOTICE "D3: %08lx  D2: %08lx  D1: %08lx\n",
+              regs->d3, regs->d2, regs->d1);
+       if (!(regs->sr & PS_S))
+               printk(KERN_NOTICE "USP: %08lx\n", rdusp());
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       int retval;
+       long clone_arg = flags | CLONE_VM;
+       mm_segment_t fs;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       __asm__ __volatile__ (
+                       "movel  %%sp, %%d2\n\t"
+                       "movel  %5, %%d1\n\t"
+                       "movel  %1, %%d0\n\t"
+                       "trap   #0\n\t"
+                       "cmpl   %%sp, %%d2\n\t"
+                       "jeq    1f\n\t"
+                       "movel  %3, %%sp@-\n\t"
+                       "jsr    %4@\n\t"
+                       "movel  %2, %%d0\n\t"
+                       "trap   #0\n"
+                       "1:\n\t"
+                       "movel  %%d0, %0\n"
+               : "=d" (retval)
+               : "i" (__NR_clone),
+                 "i" (__NR_exit),
+                 "a" (arg),
+                 "a" (fn),
+                 "a" (clone_arg)
+               : "cc", "%d0", "%d1", "%d2");
+
+       set_fs(fs);
+       return retval;
+}
+
+void flush_thread(void)
+{
+#ifdef CONFIG_FPU
+       unsigned long zero = 0;
+#endif
+       set_fs(USER_DS);
+       current->thread.fs = __USER_DS;
+#ifdef CONFIG_FPU
+       if (!FPU_IS_EMU)
+               asm volatile (".chip 68k/68881\n\t"
+                             "frestore %0@\n\t"
+                             ".chip 68k" : : "a" (&zero));
+#endif
+}
+
+/*
+ * "m68k_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+
+asmlinkage int m68k_fork(struct pt_regs *regs)
+{
+       /* fork almost works, enough to trick you into looking elsewhere :-( */
+       return(-EINVAL);
+}
+
+asmlinkage int m68k_vfork(struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+asmlinkage int m68k_clone(struct pt_regs *regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+
+       /* syscall2 puts clone_flags in d1 and usp in d2 */
+       clone_flags = regs->d1;
+       newsp = regs->d2;
+       if (!newsp)
+               newsp = rdusp();
+        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
+}
+
+int copy_thread(unsigned long clone_flags,
+               unsigned long usp, unsigned long topstk,
+               struct task_struct * p, struct pt_regs * regs)
+{
+       struct pt_regs * childregs;
+       struct switch_stack * childstack, *stack;
+       unsigned long *retp;
+
+       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+
+       *childregs = *regs;
+       childregs->d0 = 0;
+
+       retp = ((unsigned long *) regs);
+       stack = ((struct switch_stack *) retp) - 1;
+
+       childstack = ((struct switch_stack *) childregs) - 1;
+       *childstack = *stack;
+       childstack->retpc = (unsigned long)ret_from_fork;
+
+       p->thread.usp = usp;
+       p->thread.ksp = (unsigned long)childstack;
+
+       if (clone_flags & CLONE_SETTLS)
+               task_thread_info(p)->tp_value = regs->d5;
+
+       /*
+        * Must save the current SFC/DFC value, NOT the value when
+        * the parent was last descheduled - RGH  10-08-96
+        */
+       p->thread.fs = get_fs().seg;
+
+#ifdef CONFIG_FPU
+       if (!FPU_IS_EMU) {
+               /* Copy the current fpu state */
+               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
+
+               if (p->thread.fpstate[0])
+                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
+                               : "memory");
+               /* Restore the state in case the fpu was busy */
+               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+       }
+#endif
+
+       return 0;
+}
+
+/* Fill in the fpu structure for a core dump.  */
+
+int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+{
+#ifdef CONFIG_FPU
+       char fpustate[216];
+
+       if (FPU_IS_EMU) {
+               int i;
+
+               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
+               memcpy(fpu->fpregs, current->thread.fp, 96);
+               /* Convert internal fpu reg representation
+                * into long double format
+                */
+               for (i = 0; i < 24; i += 3)
+                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
+                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
+               return 1;
+       }
+
+       /* First dump the fpu context to avoid protocol violation.  */
+       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+       if (!fpustate[0])
+               return 0;
+
+       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+               :: "m" (fpu->fpcntl[0])
+               : "memory");
+       asm volatile ("fmovemx %/fp0-%/fp7,%0"
+               :: "m" (fpu->fpregs[0])
+               : "memory");
+#endif
+       return 1;
+}
+
+/*
+ *     Generic dumping code. Used for panic and debug.
+ */
+void dump(struct pt_regs *fp)
+{
+       unsigned long   *sp;
+       unsigned char   *tp;
+       int             i;
+
+       printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
+       printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
+
+       if (current->mm) {
+               printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
+                       (int) current->mm->start_code,
+                       (int) current->mm->end_code,
+                       (int) current->mm->start_data,
+                       (int) current->mm->end_data,
+                       (int) current->mm->end_data,
+                       (int) current->mm->brk);
+               printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
+                       (int) current->mm->start_stack,
+                       (int)(((unsigned long) current) + THREAD_SIZE));
+       }
+
+       printk(KERN_EMERG "PC: %08lx\n", fp->pc);
+       printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
+       printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
+               fp->d0, fp->d1, fp->d2, fp->d3);
+       printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
+               fp->d4, fp->d5, fp->a0, fp->a1);
+       printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %p\n",
+               (unsigned int) rdusp(), fp);
+
+       printk(KERN_EMERG "\nCODE:");
+       tp = ((unsigned char *) fp->pc) - 0x20;
+       for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
+               if ((i % 0x10) == 0)
+                       printk(KERN_EMERG "%p: ", tp + i);
+               printk("%08x ", (int) *sp++);
+       }
+       printk(KERN_EMERG "\n");
+
+       printk(KERN_EMERG "KERNEL STACK:");
+       tp = ((unsigned char *) fp) - 0x40;
+       for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
+               if ((i % 0x10) == 0)
+                       printk(KERN_EMERG "%p: ", tp + i);
+               printk("%08x ", (int) *sp++);
+       }
+       printk(KERN_EMERG "\n");
+
+       printk(KERN_EMERG "USER STACK:");
+       tp = (unsigned char *) (rdusp() - 0x10);
+       for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
+               if ((i % 0x10) == 0)
+                       printk(KERN_EMERG "%p: ", tp + i);
+               printk("%08x ", (int) *sp++);
+       }
+       printk(KERN_EMERG "\n");
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char *name,
+                         const char *const *argv,
+                         const char *const *envp)
+{
+       int error;
+       char * filename;
+       struct pt_regs *regs = (struct pt_regs *) &name;
+
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               return error;
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+       return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long fp, pc;
+       unsigned long stack_page;
+       int count = 0;
+       if (!p || p == current || p->state == TASK_RUNNING)
+               return 0;
+
+       stack_page = (unsigned long)p;
+       fp = ((struct switch_stack *)p->thread.ksp)->a6;
+       do {
+               if (fp < stack_page+sizeof(struct thread_info) ||
+                   fp >= THREAD_SIZE-8+stack_page)
+                       return 0;
+               pc = ((unsigned long *)fp)[1];
+               if (!in_sched_functions(pc))
+                       return pc;
+               fp = *(unsigned long *) fp;
+       } while (count++ < 16);
+       return 0;
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
+
+       /* Check whether the thread is blocked in resume() */
+       if (in_sched_functions(sw->retpc))
+               return ((unsigned long *)sw->a6)[1];
+       else
+               return sw->retpc;
+}
+
index 0b252683cefb21a3d057987833a22ce1ea8b17be..07a417550e9421156be8636088a3ea3ce7c265c0 100644 (file)
@@ -1,277 +1,5 @@
-/*
- *  linux/arch/m68k/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file COPYING in the main directory of
- * this archive for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0xC000
-#define T1_BIT 0x8000
-#define T0_BIT 0x4000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
-                        - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static const int regoff[] = {
-       [0]     = PT_REG(d1),
-       [1]     = PT_REG(d2),
-       [2]     = PT_REG(d3),
-       [3]     = PT_REG(d4),
-       [4]     = PT_REG(d5),
-       [5]     = SW_REG(d6),
-       [6]     = SW_REG(d7),
-       [7]     = PT_REG(a0),
-       [8]     = PT_REG(a1),
-       [9]     = PT_REG(a2),
-       [10]    = SW_REG(a3),
-       [11]    = SW_REG(a4),
-       [12]    = SW_REG(a5),
-       [13]    = SW_REG(a6),
-       [14]    = PT_REG(d0),
-       [15]    = -1,
-       [16]    = PT_REG(orig_d0),
-       [17]    = PT_REG(sr),
-       [18]    = PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return 0;
-       /* Need to take stkadj into account. */
-       if (regno == PT_SR || regno == PT_PC) {
-               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-               addr = (unsigned long *) ((unsigned long)addr + stkadj);
-               /* The sr is actually a 16 bit register.  */
-               if (regno == PT_SR)
-                       return *(unsigned short *)addr;
-       }
-       return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-                         unsigned long data)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return -1;
-       /* Need to take stkadj into account. */
-       if (regno == PT_SR || regno == PT_PC) {
-               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
-               addr = (unsigned long *) ((unsigned long)addr + stkadj);
-               /* The sr is actually a 16 bit register.  */
-               if (regno == PT_SR) {
-                       *(unsigned short *)addr = data;
-                       return 0;
-               }
-       }
-       *addr = data;
-       return 0;
-}
-
-/*
- * Make sure the single step bit is not set.
- */
-static inline void singlestep_disable(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp);
-       clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- */
-void ptrace_disable(struct task_struct *child)
-{
-       singlestep_disable(child);
-}
-
-void user_enable_single_step(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp | T1_BIT);
-       set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
-}
-
-void user_enable_block_step(struct task_struct *child)
-{
-       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
-       put_reg(child, PT_SR, tmp | T0_BIT);
-}
-
-void user_disable_single_step(struct task_struct *child)
-{
-       singlestep_disable(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-                unsigned long addr, unsigned long data)
-{
-       unsigned long tmp;
-       int i, ret = 0;
-       int regno = addr >> 2; /* temporary hack. */
-       unsigned long __user *datap = (unsigned long __user *) data;
-
-       switch (request) {
-       /* read the word at location addr in the USER area. */
-       case PTRACE_PEEKUSR:
-               if (addr & 3)
-                       goto out_eio;
-
-               if (regno >= 0 && regno < 19) {
-                       tmp = get_reg(child, regno);
-               } else if (regno >= 21 && regno < 49) {
-                       tmp = child->thread.fp[regno - 21];
-                       /* Convert internal fpu reg representation
-                        * into long double format
-                        */
-                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
-                               tmp = ((tmp & 0xffff0000) << 15) |
-                                     ((tmp & 0x0000ffff) << 16);
-               } else
-                       goto out_eio;
-               ret = put_user(tmp, datap);
-               break;
-
-       case PTRACE_POKEUSR:
-       /* write the word at location addr in the USER area */
-               if (addr & 3)
-                       goto out_eio;
-
-               if (regno == PT_SR) {
-                       data &= SR_MASK;
-                       data |= get_reg(child, PT_SR) & ~SR_MASK;
-               }
-               if (regno >= 0 && regno < 19) {
-                       if (put_reg(child, regno, data))
-                               goto out_eio;
-               } else if (regno >= 21 && regno < 48) {
-                       /* Convert long double format
-                        * into internal fpu reg representation
-                        */
-                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
-                               data <<= 15;
-                               data = (data & 0xffff0000) |
-                                      ((data & 0x0000ffff) >> 1);
-                       }
-                       child->thread.fp[regno - 21] = data;
-               } else
-                       goto out_eio;
-               break;
-
-       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
-               for (i = 0; i < 19; i++) {
-                       tmp = get_reg(child, i);
-                       ret = put_user(tmp, datap);
-                       if (ret)
-                               break;
-                       datap++;
-               }
-               break;
-
-       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
-               for (i = 0; i < 19; i++) {
-                       ret = get_user(tmp, datap);
-                       if (ret)
-                               break;
-                       if (i == PT_SR) {
-                               tmp &= SR_MASK;
-                               tmp |= get_reg(child, PT_SR) & ~SR_MASK;
-                       }
-                       put_reg(child, i, tmp);
-                       datap++;
-               }
-               break;
-
-       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
-               if (copy_to_user(datap, &child->thread.fp,
-                                sizeof(struct user_m68kfp_struct)))
-                       ret = -EFAULT;
-               break;
-
-       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
-               if (copy_from_user(&child->thread.fp, datap,
-                                  sizeof(struct user_m68kfp_struct)))
-                       ret = -EFAULT;
-               break;
-
-       case PTRACE_GET_THREAD_AREA:
-               ret = put_user(task_thread_info(child)->tp_value, datap);
-               break;
-
-       default:
-               ret = ptrace_request(child, request, addr, data);
-               break;
-       }
-
-       return ret;
-out_eio:
-       return -EIO;
-}
-
-asmlinkage void syscall_trace(void)
-{
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-                                ? 0x80 : 0));
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
-}
+#ifdef CONFIG_MMU
+#include "ptrace_mm.c"
+#else
+#include "ptrace_no.c"
+#endif
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c
new file mode 100644 (file)
index 0000000..0b25268
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *  linux/arch/m68k/kernel/ptrace.c
+ *
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x001f
+
+/* sets the trace bits. */
+#define TRACE_BITS 0xC000
+#define T1_BIT 0x8000
+#define T0_BIT 0x4000
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
+                        - sizeof(struct switch_stack))
+/* Mapping from PT_xxx to the stack offset at which the register is
+   saved.  Notice that usp has no stack-slot and needs to be treated
+   specially (see get_reg/put_reg below). */
+static const int regoff[] = {
+       [0]     = PT_REG(d1),
+       [1]     = PT_REG(d2),
+       [2]     = PT_REG(d3),
+       [3]     = PT_REG(d4),
+       [4]     = PT_REG(d5),
+       [5]     = SW_REG(d6),
+       [6]     = SW_REG(d7),
+       [7]     = PT_REG(a0),
+       [8]     = PT_REG(a1),
+       [9]     = PT_REG(a2),
+       [10]    = SW_REG(a3),
+       [11]    = SW_REG(a4),
+       [12]    = SW_REG(a5),
+       [13]    = SW_REG(a6),
+       [14]    = PT_REG(d0),
+       [15]    = -1,
+       [16]    = PT_REG(orig_d0),
+       [17]    = PT_REG(sr),
+       [18]    = PT_REG(pc),
+};
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+       else
+               return 0;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR)
+                       return *(unsigned short *)addr;
+       }
+       return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+                         unsigned long data)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+       else
+               return -1;
+       /* Need to take stkadj into account. */
+       if (regno == PT_SR || regno == PT_PC) {
+               long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
+               addr = (unsigned long *) ((unsigned long)addr + stkadj);
+               /* The sr is actually a 16 bit register.  */
+               if (regno == PT_SR) {
+                       *(unsigned short *)addr = data;
+                       return 0;
+               }
+       }
+       *addr = data;
+       return 0;
+}
+
+/*
+ * Make sure the single step bit is not set.
+ */
+static inline void singlestep_disable(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp);
+       clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       singlestep_disable(child);
+}
+
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T1_BIT);
+       set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
+}
+
+void user_enable_block_step(struct task_struct *child)
+{
+       unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
+       put_reg(child, PT_SR, tmp | T0_BIT);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+       singlestep_disable(child);
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+                unsigned long addr, unsigned long data)
+{
+       unsigned long tmp;
+       int i, ret = 0;
+       int regno = addr >> 2; /* temporary hack. */
+       unsigned long __user *datap = (unsigned long __user *) data;
+
+       switch (request) {
+       /* read the word at location addr in the USER area. */
+       case PTRACE_PEEKUSR:
+               if (addr & 3)
+                       goto out_eio;
+
+               if (regno >= 0 && regno < 19) {
+                       tmp = get_reg(child, regno);
+               } else if (regno >= 21 && regno < 49) {
+                       tmp = child->thread.fp[regno - 21];
+                       /* Convert internal fpu reg representation
+                        * into long double format
+                        */
+                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
+                               tmp = ((tmp & 0xffff0000) << 15) |
+                                     ((tmp & 0x0000ffff) << 16);
+               } else
+                       goto out_eio;
+               ret = put_user(tmp, datap);
+               break;
+
+       case PTRACE_POKEUSR:
+       /* write the word at location addr in the USER area */
+               if (addr & 3)
+                       goto out_eio;
+
+               if (regno == PT_SR) {
+                       data &= SR_MASK;
+                       data |= get_reg(child, PT_SR) & ~SR_MASK;
+               }
+               if (regno >= 0 && regno < 19) {
+                       if (put_reg(child, regno, data))
+                               goto out_eio;
+               } else if (regno >= 21 && regno < 48) {
+                       /* Convert long double format
+                        * into internal fpu reg representation
+                        */
+                       if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
+                               data <<= 15;
+                               data = (data & 0xffff0000) |
+                                      ((data & 0x0000ffff) >> 1);
+                       }
+                       child->thread.fp[regno - 21] = data;
+               } else
+                       goto out_eio;
+               break;
+
+       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
+               for (i = 0; i < 19; i++) {
+                       tmp = get_reg(child, i);
+                       ret = put_user(tmp, datap);
+                       if (ret)
+                               break;
+                       datap++;
+               }
+               break;
+
+       case PTRACE_SETREGS:    /* Set all gp regs in the child. */
+               for (i = 0; i < 19; i++) {
+                       ret = get_user(tmp, datap);
+                       if (ret)
+                               break;
+                       if (i == PT_SR) {
+                               tmp &= SR_MASK;
+                               tmp |= get_reg(child, PT_SR) & ~SR_MASK;
+                       }
+                       put_reg(child, i, tmp);
+                       datap++;
+               }
+               break;
+
+       case PTRACE_GETFPREGS:  /* Get the child FPU state. */
+               if (copy_to_user(datap, &child->thread.fp,
+                                sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       case PTRACE_SETFPREGS:  /* Set the child FPU state. */
+               if (copy_from_user(&child->thread.fp, datap,
+                                  sizeof(struct user_m68kfp_struct)))
+                       ret = -EFAULT;
+               break;
+
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(task_thread_info(child)->tp_value, datap);
+               break;
+
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       }
+
+       return ret;
+out_eio:
+       return -EIO;
+}
+
+asmlinkage void syscall_trace(void)
+{
+       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+                                ? 0x80 : 0));
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+        * for normal use.  strace only continues with a signal if the
+        * stopping signal is not SIGTRAP.  -brl
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c
new file mode 100644 (file)
index 0000000..6709fb7
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  linux/arch/m68knommu/kernel/ptrace.c
+ *
+ *  Copyright (C) 1994 by Hamish Macdonald
+ *  Taken from linux/kernel/ptrace.c and modified for M680x0.
+ *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/tracehook.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SR the user has access to. */
+/* 1 = access 0 = no access */
+#define SR_MASK 0x001f
+
+/* sets the trace bits. */
+#define TRACE_BITS 0x8000
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
+#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
+                        - sizeof(struct switch_stack))
+/* Mapping from PT_xxx to the stack offset at which the register is
+   saved.  Notice that usp has no stack-slot and needs to be treated
+   specially (see get_reg/put_reg below). */
+static int regoff[] = {
+       PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
+       PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
+       PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
+       SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
+       PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
+};
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
+       else
+               return 0;
+       return *addr;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+                         unsigned long data)
+{
+       unsigned long *addr;
+
+       if (regno == PT_USP)
+               addr = &task->thread.usp;
+       else if (regno < ARRAY_SIZE(regoff))
+               addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
+       else
+               return -1;
+       *addr = data;
+       return 0;
+}
+
+void user_enable_single_step(struct task_struct *task)
+{
+       unsigned long srflags;
+       srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
+       put_reg(task, PT_SR, srflags);
+}
+
+void user_disable_single_step(struct task_struct *task)
+{
+       unsigned long srflags;
+       srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
+       put_reg(task, PT_SR, srflags);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* make sure the single step bit is not set. */
+       user_disable_single_step(child);
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+                unsigned long addr, unsigned long data)
+{
+       int ret;
+       int regno = addr >> 2;
+       unsigned long __user *datap = (unsigned long __user *) data;
+
+       switch (request) {
+               /* read the word at location addr in the USER area. */
+               case PTRACE_PEEKUSR: {
+                       unsigned long tmp;
+                       
+                       ret = -EIO;
+                       if ((addr & 3) || addr > sizeof(struct user) - 3)
+                               break;
+                       
+                       tmp = 0;  /* Default return condition */
+                       ret = -EIO;
+                       if (regno < 19) {
+                               tmp = get_reg(child, regno);
+                               if (regno == PT_SR)
+                                       tmp >>= 16;
+                       } else if (regno >= 21 && regno < 49) {
+                               tmp = child->thread.fp[regno - 21];
+                       } else if (regno == 49) {
+                               tmp = child->mm->start_code;
+                       } else if (regno == 50) {
+                               tmp = child->mm->start_data;
+                       } else if (regno == 51) {
+                               tmp = child->mm->end_code;
+                       } else
+                               break;
+                       ret = put_user(tmp, datap);
+                       break;
+               }
+
+               case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+                       ret = -EIO;
+                       if ((addr & 3) || addr > sizeof(struct user) - 3)
+                               break;
+
+                       if (regno == PT_SR) {
+                               data &= SR_MASK;
+                               data <<= 16;
+                               data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+                       }
+                       if (regno < 19) {
+                               if (put_reg(child, regno, data))
+                                       break;
+                               ret = 0;
+                               break;
+                       }
+                       if (regno >= 21 && regno < 48)
+                       {
+                               child->thread.fp[regno - 21] = data;
+                               ret = 0;
+                       }
+                       break;
+
+               case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+                       int i;
+                       unsigned long tmp;
+                       for (i = 0; i < 19; i++) {
+                           tmp = get_reg(child, i);
+                           if (i == PT_SR)
+                               tmp >>= 16;
+                           if (put_user(tmp, datap)) {
+                               ret = -EFAULT;
+                               break;
+                           }
+                           datap++;
+                       }
+                       ret = 0;
+                       break;
+               }
+
+               case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+                       int i;
+                       unsigned long tmp;
+                       for (i = 0; i < 19; i++) {
+                           if (get_user(tmp, datap)) {
+                               ret = -EFAULT;
+                               break;
+                           }
+                           if (i == PT_SR) {
+                               tmp &= SR_MASK;
+                               tmp <<= 16;
+                               tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+                           }
+                           put_reg(child, i, tmp);
+                           datap++;
+                       }
+                       ret = 0;
+                       break;
+               }
+
+#ifdef PTRACE_GETFPREGS
+               case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+                       ret = 0;
+                       if (copy_to_user(datap, &child->thread.fp,
+                                        sizeof(struct user_m68kfp_struct)))
+                               ret = -EFAULT;
+                       break;
+               }
+#endif
+
+#ifdef PTRACE_SETFPREGS
+               case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+                       ret = 0;
+                       if (copy_from_user(&child->thread.fp, datap,
+                                          sizeof(struct user_m68kfp_struct)))
+                               ret = -EFAULT;
+                       break;
+               }
+#endif
+
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(task_thread_info(child)->tp_value, datap);
+               break;
+
+               default:
+                       ret = ptrace_request(child, request, addr, data);
+                       break;
+       }
+       return ret;
+}
+
+asmlinkage int syscall_trace_enter(void)
+{
+       int ret = 0;
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(task_pt_regs(current));
+       return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(task_pt_regs(current), 0);
+}
index 334d83640376762b058a7a4010e2878fffe21439..4bf129f1d2e2f83a7c9a86d5c5d129a9ba03b382 100644 (file)
@@ -1,533 +1,5 @@
-/*
- *  linux/arch/m68k/kernel/setup.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- */
-
-/*
- * This file handles the architecture-dependent parts of system setup
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/console.h>
-#include <linux/genhd.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/initrd.h>
-
-#include <asm/bootinfo.h>
-#include <asm/sections.h>
-#include <asm/setup.h>
-#include <asm/fpu.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#endif
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atari_stram.h>
-#endif
-#ifdef CONFIG_SUN3X
-#include <asm/dvma.h>
-#endif
-#include <asm/natfeat.h>
-
-#if !FPSTATESIZE || !NR_IRQS
-#warning No CPU/platform type selected, your kernel will not work!
-#warning Are you building an allnoconfig kernel?
-#endif
-
-unsigned long m68k_machtype;
-EXPORT_SYMBOL(m68k_machtype);
-unsigned long m68k_cputype;
-EXPORT_SYMBOL(m68k_cputype);
-unsigned long m68k_fputype;
-unsigned long m68k_mmutype;
-EXPORT_SYMBOL(m68k_mmutype);
-#ifdef CONFIG_VME
-unsigned long vme_brdtype;
-EXPORT_SYMBOL(vme_brdtype);
-#endif
-
-int m68k_is040or060;
-EXPORT_SYMBOL(m68k_is040or060);
-
-extern unsigned long availmem;
-
-int m68k_num_memory;
-EXPORT_SYMBOL(m68k_num_memory);
-int m68k_realnum_memory;
-EXPORT_SYMBOL(m68k_realnum_memory);
-unsigned long m68k_memoffset;
-struct mem_info m68k_memory[NUM_MEMINFO];
-EXPORT_SYMBOL(m68k_memory);
-
-struct mem_info m68k_ramdisk;
-
-static char m68k_command_line[CL_SIZE];
-
-void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
-/* machine dependent irq functions */
-void (*mach_init_IRQ) (void) __initdata = NULL;
-void (*mach_get_model) (char *model);
-void (*mach_get_hardware_list) (struct seq_file *m);
-/* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
-int (*mach_hwclk) (int, struct rtc_time*);
-EXPORT_SYMBOL(mach_hwclk);
-int (*mach_set_clock_mmss) (unsigned long);
-unsigned int (*mach_get_ss)(void);
-int (*mach_get_rtc_pll)(struct rtc_pll_info *);
-int (*mach_set_rtc_pll)(struct rtc_pll_info *);
-EXPORT_SYMBOL(mach_get_ss);
-EXPORT_SYMBOL(mach_get_rtc_pll);
-EXPORT_SYMBOL(mach_set_rtc_pll);
-void (*mach_reset)( void );
-void (*mach_halt)( void );
-void (*mach_power_off)( void );
-long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#ifdef CONFIG_HEARTBEAT
-void (*mach_heartbeat) (int);
-EXPORT_SYMBOL(mach_heartbeat);
-#endif
-#ifdef CONFIG_M68K_L2_CACHE
-void (*mach_l2_flush) (int);
-#endif
-#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
-void (*mach_beep)(unsigned int, unsigned int);
-EXPORT_SYMBOL(mach_beep);
-#endif
-#if defined(CONFIG_ISA) && defined(MULTI_ISA)
-int isa_type;
-int isa_sex;
-EXPORT_SYMBOL(isa_type);
-EXPORT_SYMBOL(isa_sex);
-#endif
-
-extern int amiga_parse_bootinfo(const struct bi_record *);
-extern int atari_parse_bootinfo(const struct bi_record *);
-extern int mac_parse_bootinfo(const struct bi_record *);
-extern int q40_parse_bootinfo(const struct bi_record *);
-extern int bvme6000_parse_bootinfo(const struct bi_record *);
-extern int mvme16x_parse_bootinfo(const struct bi_record *);
-extern int mvme147_parse_bootinfo(const struct bi_record *);
-extern int hp300_parse_bootinfo(const struct bi_record *);
-extern int apollo_parse_bootinfo(const struct bi_record *);
-
-extern void config_amiga(void);
-extern void config_atari(void);
-extern void config_mac(void);
-extern void config_sun3(void);
-extern void config_apollo(void);
-extern void config_mvme147(void);
-extern void config_mvme16x(void);
-extern void config_bvme6000(void);
-extern void config_hp300(void);
-extern void config_q40(void);
-extern void config_sun3x(void);
-
-#define MASK_256K 0xfffc0000
-
-extern void paging_init(void);
-
-static void __init m68k_parse_bootinfo(const struct bi_record *record)
-{
-       while (record->tag != BI_LAST) {
-               int unknown = 0;
-               const unsigned long *data = record->data;
-
-               switch (record->tag) {
-               case BI_MACHTYPE:
-               case BI_CPUTYPE:
-               case BI_FPUTYPE:
-               case BI_MMUTYPE:
-                       /* Already set up by head.S */
-                       break;
-
-               case BI_MEMCHUNK:
-                       if (m68k_num_memory < NUM_MEMINFO) {
-                               m68k_memory[m68k_num_memory].addr = data[0];
-                               m68k_memory[m68k_num_memory].size = data[1];
-                               m68k_num_memory++;
-                       } else
-                               printk("m68k_parse_bootinfo: too many memory chunks\n");
-                       break;
-
-               case BI_RAMDISK:
-                       m68k_ramdisk.addr = data[0];
-                       m68k_ramdisk.size = data[1];
-                       break;
-
-               case BI_COMMAND_LINE:
-                       strlcpy(m68k_command_line, (const char *)data,
-                               sizeof(m68k_command_line));
-                       break;
-
-               default:
-                       if (MACH_IS_AMIGA)
-                               unknown = amiga_parse_bootinfo(record);
-                       else if (MACH_IS_ATARI)
-                               unknown = atari_parse_bootinfo(record);
-                       else if (MACH_IS_MAC)
-                               unknown = mac_parse_bootinfo(record);
-                       else if (MACH_IS_Q40)
-                               unknown = q40_parse_bootinfo(record);
-                       else if (MACH_IS_BVME6000)
-                               unknown = bvme6000_parse_bootinfo(record);
-                       else if (MACH_IS_MVME16x)
-                               unknown = mvme16x_parse_bootinfo(record);
-                       else if (MACH_IS_MVME147)
-                               unknown = mvme147_parse_bootinfo(record);
-                       else if (MACH_IS_HP300)
-                               unknown = hp300_parse_bootinfo(record);
-                       else if (MACH_IS_APOLLO)
-                               unknown = apollo_parse_bootinfo(record);
-                       else
-                               unknown = 1;
-               }
-               if (unknown)
-                       printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
-                              record->tag);
-               record = (struct bi_record *)((unsigned long)record +
-                                             record->size);
-       }
-
-       m68k_realnum_memory = m68k_num_memory;
-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
-       if (m68k_num_memory > 1) {
-               printk("Ignoring last %i chunks of physical memory\n",
-                      (m68k_num_memory - 1));
-               m68k_num_memory = 1;
-       }
-#endif
-}
-
-void __init setup_arch(char **cmdline_p)
-{
-       int i;
-
-       /* The bootinfo is located right after the kernel bss */
-       m68k_parse_bootinfo((const struct bi_record *)_end);
-
-       if (CPU_IS_040)
-               m68k_is040or060 = 4;
-       else if (CPU_IS_060)
-               m68k_is040or060 = 6;
-
-       /* FIXME: m68k_fputype is passed in by Penguin booter, which can
-        * be confused by software FPU emulation. BEWARE.
-        * We should really do our own FPU check at startup.
-        * [what do we do with buggy 68LC040s? if we have problems
-        *  with them, we should add a test to check_bugs() below] */
-#ifndef CONFIG_M68KFPU_EMU_ONLY
-       /* clear the fpu if we have one */
-       if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
-               volatile int zero = 0;
-               asm volatile ("frestore %0" : : "m" (zero));
-       }
-#endif
-
-       if (CPU_IS_060) {
-               u32 pcr;
-
-               asm (".chip 68060; movec %%pcr,%0; .chip 68k"
-                    : "=d" (pcr));
-               if (((pcr >> 8) & 0xff) <= 5) {
-                       printk("Enabling workaround for errata I14\n");
-                       asm (".chip 68060; movec %0,%%pcr; .chip 68k"
-                            : : "d" (pcr | 0x20));
-               }
-       }
-
-       init_mm.start_code = PAGE_OFFSET;
-       init_mm.end_code = (unsigned long)_etext;
-       init_mm.end_data = (unsigned long)_edata;
-       init_mm.brk = (unsigned long)_end;
-
-       *cmdline_p = m68k_command_line;
-       memcpy(boot_command_line, *cmdline_p, CL_SIZE);
-
-       parse_early_param();
-
-#ifdef CONFIG_DUMMY_CONSOLE
-       conswitchp = &dummy_con;
-#endif
-
-       switch (m68k_machtype) {
-#ifdef CONFIG_AMIGA
-       case MACH_AMIGA:
-               config_amiga();
-               break;
-#endif
-#ifdef CONFIG_ATARI
-       case MACH_ATARI:
-               config_atari();
-               break;
-#endif
-#ifdef CONFIG_MAC
-       case MACH_MAC:
-               config_mac();
-               break;
-#endif
-#ifdef CONFIG_SUN3
-       case MACH_SUN3:
-               config_sun3();
-               break;
-#endif
-#ifdef CONFIG_APOLLO
-       case MACH_APOLLO:
-               config_apollo();
-               break;
-#endif
-#ifdef CONFIG_MVME147
-       case MACH_MVME147:
-               config_mvme147();
-               break;
-#endif
-#ifdef CONFIG_MVME16x
-       case MACH_MVME16x:
-               config_mvme16x();
-               break;
-#endif
-#ifdef CONFIG_BVME6000
-       case MACH_BVME6000:
-               config_bvme6000();
-               break;
-#endif
-#ifdef CONFIG_HP300
-       case MACH_HP300:
-               config_hp300();
-               break;
-#endif
-#ifdef CONFIG_Q40
-       case MACH_Q40:
-               config_q40();
-               break;
-#endif
-#ifdef CONFIG_SUN3X
-       case MACH_SUN3X:
-               config_sun3x();
-               break;
-#endif
-       default:
-               panic("No configuration setup");
-       }
-
-#ifdef CONFIG_NATFEAT
-       nf_init();
-#endif
-
-       paging_init();
-
-#ifndef CONFIG_SUN3
-       for (i = 1; i < m68k_num_memory; i++)
-               free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
-                                 m68k_memory[i].size);
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (m68k_ramdisk.size) {
-               reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
-                                    m68k_ramdisk.addr, m68k_ramdisk.size,
-                                    BOOTMEM_DEFAULT);
-               initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
-               initrd_end = initrd_start + m68k_ramdisk.size;
-               printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
-       }
-#endif
-
-#ifdef CONFIG_ATARI
-       if (MACH_IS_ATARI)
-               atari_stram_reserve_pages((void *)availmem);
-#endif
-#ifdef CONFIG_SUN3X
-       if (MACH_IS_SUN3X) {
-               dvma_init();
-       }
-#endif
-
-#endif /* !CONFIG_SUN3 */
-
-/* set ISA defs early as possible */
-#if defined(CONFIG_ISA) && defined(MULTI_ISA)
-       if (MACH_IS_Q40) {
-               isa_type = ISA_TYPE_Q40;
-               isa_sex = 0;
-       }
-#ifdef CONFIG_AMIGA_PCMCIA
-       if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
-               isa_type = ISA_TYPE_AG;
-               isa_sex = 1;
-       }
-#endif
-#endif
-}
-
-static int show_cpuinfo(struct seq_file *m, void *v)
-{
-       const char *cpu, *mmu, *fpu;
-       unsigned long clockfreq, clockfactor;
-
-#define LOOP_CYCLES_68020      (8)
-#define LOOP_CYCLES_68030      (8)
-#define LOOP_CYCLES_68040      (3)
-#define LOOP_CYCLES_68060      (1)
-
-       if (CPU_IS_020) {
-               cpu = "68020";
-               clockfactor = LOOP_CYCLES_68020;
-       } else if (CPU_IS_030) {
-               cpu = "68030";
-               clockfactor = LOOP_CYCLES_68030;
-       } else if (CPU_IS_040) {
-               cpu = "68040";
-               clockfactor = LOOP_CYCLES_68040;
-       } else if (CPU_IS_060) {
-               cpu = "68060";
-               clockfactor = LOOP_CYCLES_68060;
-       } else {
-               cpu = "680x0";
-               clockfactor = 0;
-       }
-
-#ifdef CONFIG_M68KFPU_EMU_ONLY
-       fpu = "none(soft float)";
+#ifdef CONFIG_MMU
+#include "setup_mm.c"
 #else
-       if (m68k_fputype & FPU_68881)
-               fpu = "68881";
-       else if (m68k_fputype & FPU_68882)
-               fpu = "68882";
-       else if (m68k_fputype & FPU_68040)
-               fpu = "68040";
-       else if (m68k_fputype & FPU_68060)
-               fpu = "68060";
-       else if (m68k_fputype & FPU_SUNFPA)
-               fpu = "Sun FPA";
-       else
-               fpu = "none";
-#endif
-
-       if (m68k_mmutype & MMU_68851)
-               mmu = "68851";
-       else if (m68k_mmutype & MMU_68030)
-               mmu = "68030";
-       else if (m68k_mmutype & MMU_68040)
-               mmu = "68040";
-       else if (m68k_mmutype & MMU_68060)
-               mmu = "68060";
-       else if (m68k_mmutype & MMU_SUN3)
-               mmu = "Sun-3";
-       else if (m68k_mmutype & MMU_APOLLO)
-               mmu = "Apollo";
-       else
-               mmu = "unknown";
-
-       clockfreq = loops_per_jiffy * HZ * clockfactor;
-
-       seq_printf(m, "CPU:\t\t%s\n"
-                  "MMU:\t\t%s\n"
-                  "FPU:\t\t%s\n"
-                  "Clocking:\t%lu.%1luMHz\n"
-                  "BogoMips:\t%lu.%02lu\n"
-                  "Calibration:\t%lu loops\n",
-                  cpu, mmu, fpu,
-                  clockfreq/1000000,(clockfreq/100000)%10,
-                  loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
-                  loops_per_jiffy);
-       return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-       return *pos < 1 ? (void *)1 : NULL;
-}
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return NULL;
-}
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-const struct seq_operations cpuinfo_op = {
-       .start  = c_start,
-       .next   = c_next,
-       .stop   = c_stop,
-       .show   = show_cpuinfo,
-};
-
-#ifdef CONFIG_PROC_HARDWARE
-static int hardware_proc_show(struct seq_file *m, void *v)
-{
-       char model[80];
-       unsigned long mem;
-       int i;
-
-       if (mach_get_model)
-               mach_get_model(model);
-       else
-               strcpy(model, "Unknown m68k");
-
-       seq_printf(m, "Model:\t\t%s\n", model);
-       for (mem = 0, i = 0; i < m68k_num_memory; i++)
-               mem += m68k_memory[i].size;
-       seq_printf(m, "System Memory:\t%ldK\n", mem >> 10);
-
-       if (mach_get_hardware_list)
-               mach_get_hardware_list(m);
-
-       return 0;
-}
-
-static int hardware_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, hardware_proc_show, NULL);
-}
-
-static const struct file_operations hardware_proc_fops = {
-       .open           = hardware_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init proc_hardware_init(void)
-{
-       proc_create("hardware", 0, NULL, &hardware_proc_fops);
-       return 0;
-}
-module_init(proc_hardware_init);
+#include "setup_no.c"
 #endif
-
-void check_bugs(void)
-{
-#ifndef CONFIG_M68KFPU_EMU
-       if (m68k_fputype == 0) {
-               printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
-                       "WHICH IS REQUIRED BY LINUX/M68K ***\n");
-               printk(KERN_EMERG "Upgrade your hardware or join the FPU "
-                       "emulation project\n");
-               panic("no FPU");
-       }
-#endif /* !CONFIG_M68KFPU_EMU */
-}
-
-#ifdef CONFIG_ADB
-static int __init adb_probe_sync_enable (char *str) {
-       extern int __adb_probe_sync;
-       __adb_probe_sync = 1;
-       return 1;
-}
-
-__setup("adb_sync", adb_probe_sync_enable);
-#endif /* CONFIG_ADB */
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
new file mode 100644 (file)
index 0000000..334d836
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ *  linux/arch/m68k/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ */
+
+/*
+ * This file handles the architecture-dependent parts of system setup
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/genhd.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/initrd.h>
+
+#include <asm/bootinfo.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#endif
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atari_stram.h>
+#endif
+#ifdef CONFIG_SUN3X
+#include <asm/dvma.h>
+#endif
+#include <asm/natfeat.h>
+
+#if !FPSTATESIZE || !NR_IRQS
+#warning No CPU/platform type selected, your kernel will not work!
+#warning Are you building an allnoconfig kernel?
+#endif
+
+unsigned long m68k_machtype;
+EXPORT_SYMBOL(m68k_machtype);
+unsigned long m68k_cputype;
+EXPORT_SYMBOL(m68k_cputype);
+unsigned long m68k_fputype;
+unsigned long m68k_mmutype;
+EXPORT_SYMBOL(m68k_mmutype);
+#ifdef CONFIG_VME
+unsigned long vme_brdtype;
+EXPORT_SYMBOL(vme_brdtype);
+#endif
+
+int m68k_is040or060;
+EXPORT_SYMBOL(m68k_is040or060);
+
+extern unsigned long availmem;
+
+int m68k_num_memory;
+EXPORT_SYMBOL(m68k_num_memory);
+int m68k_realnum_memory;
+EXPORT_SYMBOL(m68k_realnum_memory);
+unsigned long m68k_memoffset;
+struct mem_info m68k_memory[NUM_MEMINFO];
+EXPORT_SYMBOL(m68k_memory);
+
+struct mem_info m68k_ramdisk;
+
+static char m68k_command_line[CL_SIZE];
+
+void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
+/* machine dependent irq functions */
+void (*mach_init_IRQ) (void) __initdata = NULL;
+void (*mach_get_model) (char *model);
+void (*mach_get_hardware_list) (struct seq_file *m);
+/* machine dependent timer functions */
+unsigned long (*mach_gettimeoffset) (void);
+int (*mach_hwclk) (int, struct rtc_time*);
+EXPORT_SYMBOL(mach_hwclk);
+int (*mach_set_clock_mmss) (unsigned long);
+unsigned int (*mach_get_ss)(void);
+int (*mach_get_rtc_pll)(struct rtc_pll_info *);
+int (*mach_set_rtc_pll)(struct rtc_pll_info *);
+EXPORT_SYMBOL(mach_get_ss);
+EXPORT_SYMBOL(mach_get_rtc_pll);
+EXPORT_SYMBOL(mach_set_rtc_pll);
+void (*mach_reset)( void );
+void (*mach_halt)( void );
+void (*mach_power_off)( void );
+long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int);
+EXPORT_SYMBOL(mach_heartbeat);
+#endif
+#ifdef CONFIG_M68K_L2_CACHE
+void (*mach_l2_flush) (int);
+#endif
+#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+void (*mach_beep)(unsigned int, unsigned int);
+EXPORT_SYMBOL(mach_beep);
+#endif
+#if defined(CONFIG_ISA) && defined(MULTI_ISA)
+int isa_type;
+int isa_sex;
+EXPORT_SYMBOL(isa_type);
+EXPORT_SYMBOL(isa_sex);
+#endif
+
+extern int amiga_parse_bootinfo(const struct bi_record *);
+extern int atari_parse_bootinfo(const struct bi_record *);
+extern int mac_parse_bootinfo(const struct bi_record *);
+extern int q40_parse_bootinfo(const struct bi_record *);
+extern int bvme6000_parse_bootinfo(const struct bi_record *);
+extern int mvme16x_parse_bootinfo(const struct bi_record *);
+extern int mvme147_parse_bootinfo(const struct bi_record *);
+extern int hp300_parse_bootinfo(const struct bi_record *);
+extern int apollo_parse_bootinfo(const struct bi_record *);
+
+extern void config_amiga(void);
+extern void config_atari(void);
+extern void config_mac(void);
+extern void config_sun3(void);
+extern void config_apollo(void);
+extern void config_mvme147(void);
+extern void config_mvme16x(void);
+extern void config_bvme6000(void);
+extern void config_hp300(void);
+extern void config_q40(void);
+extern void config_sun3x(void);
+
+#define MASK_256K 0xfffc0000
+
+extern void paging_init(void);
+
+static void __init m68k_parse_bootinfo(const struct bi_record *record)
+{
+       while (record->tag != BI_LAST) {
+               int unknown = 0;
+               const unsigned long *data = record->data;
+
+               switch (record->tag) {
+               case BI_MACHTYPE:
+               case BI_CPUTYPE:
+               case BI_FPUTYPE:
+               case BI_MMUTYPE:
+                       /* Already set up by head.S */
+                       break;
+
+               case BI_MEMCHUNK:
+                       if (m68k_num_memory < NUM_MEMINFO) {
+                               m68k_memory[m68k_num_memory].addr = data[0];
+                               m68k_memory[m68k_num_memory].size = data[1];
+                               m68k_num_memory++;
+                       } else
+                               printk("m68k_parse_bootinfo: too many memory chunks\n");
+                       break;
+
+               case BI_RAMDISK:
+                       m68k_ramdisk.addr = data[0];
+                       m68k_ramdisk.size = data[1];
+                       break;
+
+               case BI_COMMAND_LINE:
+                       strlcpy(m68k_command_line, (const char *)data,
+                               sizeof(m68k_command_line));
+                       break;
+
+               default:
+                       if (MACH_IS_AMIGA)
+                               unknown = amiga_parse_bootinfo(record);
+                       else if (MACH_IS_ATARI)
+                               unknown = atari_parse_bootinfo(record);
+                       else if (MACH_IS_MAC)
+                               unknown = mac_parse_bootinfo(record);
+                       else if (MACH_IS_Q40)
+                               unknown = q40_parse_bootinfo(record);
+                       else if (MACH_IS_BVME6000)
+                               unknown = bvme6000_parse_bootinfo(record);
+                       else if (MACH_IS_MVME16x)
+                               unknown = mvme16x_parse_bootinfo(record);
+                       else if (MACH_IS_MVME147)
+                               unknown = mvme147_parse_bootinfo(record);
+                       else if (MACH_IS_HP300)
+                               unknown = hp300_parse_bootinfo(record);
+                       else if (MACH_IS_APOLLO)
+                               unknown = apollo_parse_bootinfo(record);
+                       else
+                               unknown = 1;
+               }
+               if (unknown)
+                       printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
+                              record->tag);
+               record = (struct bi_record *)((unsigned long)record +
+                                             record->size);
+       }
+
+       m68k_realnum_memory = m68k_num_memory;
+#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+       if (m68k_num_memory > 1) {
+               printk("Ignoring last %i chunks of physical memory\n",
+                      (m68k_num_memory - 1));
+               m68k_num_memory = 1;
+       }
+#endif
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+       int i;
+
+       /* The bootinfo is located right after the kernel bss */
+       m68k_parse_bootinfo((const struct bi_record *)_end);
+
+       if (CPU_IS_040)
+               m68k_is040or060 = 4;
+       else if (CPU_IS_060)
+               m68k_is040or060 = 6;
+
+       /* FIXME: m68k_fputype is passed in by Penguin booter, which can
+        * be confused by software FPU emulation. BEWARE.
+        * We should really do our own FPU check at startup.
+        * [what do we do with buggy 68LC040s? if we have problems
+        *  with them, we should add a test to check_bugs() below] */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+       /* clear the fpu if we have one */
+       if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
+               volatile int zero = 0;
+               asm volatile ("frestore %0" : : "m" (zero));
+       }
+#endif
+
+       if (CPU_IS_060) {
+               u32 pcr;
+
+               asm (".chip 68060; movec %%pcr,%0; .chip 68k"
+                    : "=d" (pcr));
+               if (((pcr >> 8) & 0xff) <= 5) {
+                       printk("Enabling workaround for errata I14\n");
+                       asm (".chip 68060; movec %0,%%pcr; .chip 68k"
+                            : : "d" (pcr | 0x20));
+               }
+       }
+
+       init_mm.start_code = PAGE_OFFSET;
+       init_mm.end_code = (unsigned long)_etext;
+       init_mm.end_data = (unsigned long)_edata;
+       init_mm.brk = (unsigned long)_end;
+
+       *cmdline_p = m68k_command_line;
+       memcpy(boot_command_line, *cmdline_p, CL_SIZE);
+
+       parse_early_param();
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+
+       switch (m68k_machtype) {
+#ifdef CONFIG_AMIGA
+       case MACH_AMIGA:
+               config_amiga();
+               break;
+#endif
+#ifdef CONFIG_ATARI
+       case MACH_ATARI:
+               config_atari();
+               break;
+#endif
+#ifdef CONFIG_MAC
+       case MACH_MAC:
+               config_mac();
+               break;
+#endif
+#ifdef CONFIG_SUN3
+       case MACH_SUN3:
+               config_sun3();
+               break;
+#endif
+#ifdef CONFIG_APOLLO
+       case MACH_APOLLO:
+               config_apollo();
+               break;
+#endif
+#ifdef CONFIG_MVME147
+       case MACH_MVME147:
+               config_mvme147();
+               break;
+#endif
+#ifdef CONFIG_MVME16x
+       case MACH_MVME16x:
+               config_mvme16x();
+               break;
+#endif
+#ifdef CONFIG_BVME6000
+       case MACH_BVME6000:
+               config_bvme6000();
+               break;
+#endif
+#ifdef CONFIG_HP300
+       case MACH_HP300:
+               config_hp300();
+               break;
+#endif
+#ifdef CONFIG_Q40
+       case MACH_Q40:
+               config_q40();
+               break;
+#endif
+#ifdef CONFIG_SUN3X
+       case MACH_SUN3X:
+               config_sun3x();
+               break;
+#endif
+       default:
+               panic("No configuration setup");
+       }
+
+#ifdef CONFIG_NATFEAT
+       nf_init();
+#endif
+
+       paging_init();
+
+#ifndef CONFIG_SUN3
+       for (i = 1; i < m68k_num_memory; i++)
+               free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
+                                 m68k_memory[i].size);
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (m68k_ramdisk.size) {
+               reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
+                                    m68k_ramdisk.addr, m68k_ramdisk.size,
+                                    BOOTMEM_DEFAULT);
+               initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
+               initrd_end = initrd_start + m68k_ramdisk.size;
+               printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
+       }
+#endif
+
+#ifdef CONFIG_ATARI
+       if (MACH_IS_ATARI)
+               atari_stram_reserve_pages((void *)availmem);
+#endif
+#ifdef CONFIG_SUN3X
+       if (MACH_IS_SUN3X) {
+               dvma_init();
+       }
+#endif
+
+#endif /* !CONFIG_SUN3 */
+
+/* set ISA defs early as possible */
+#if defined(CONFIG_ISA) && defined(MULTI_ISA)
+       if (MACH_IS_Q40) {
+               isa_type = ISA_TYPE_Q40;
+               isa_sex = 0;
+       }
+#ifdef CONFIG_AMIGA_PCMCIA
+       if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
+               isa_type = ISA_TYPE_AG;
+               isa_sex = 1;
+       }
+#endif
+#endif
+}
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+       const char *cpu, *mmu, *fpu;
+       unsigned long clockfreq, clockfactor;
+
+#define LOOP_CYCLES_68020      (8)
+#define LOOP_CYCLES_68030      (8)
+#define LOOP_CYCLES_68040      (3)
+#define LOOP_CYCLES_68060      (1)
+
+       if (CPU_IS_020) {
+               cpu = "68020";
+               clockfactor = LOOP_CYCLES_68020;
+       } else if (CPU_IS_030) {
+               cpu = "68030";
+               clockfactor = LOOP_CYCLES_68030;
+       } else if (CPU_IS_040) {
+               cpu = "68040";
+               clockfactor = LOOP_CYCLES_68040;
+       } else if (CPU_IS_060) {
+               cpu = "68060";
+               clockfactor = LOOP_CYCLES_68060;
+       } else {
+               cpu = "680x0";
+               clockfactor = 0;
+       }
+
+#ifdef CONFIG_M68KFPU_EMU_ONLY
+       fpu = "none(soft float)";
+#else
+       if (m68k_fputype & FPU_68881)
+               fpu = "68881";
+       else if (m68k_fputype & FPU_68882)
+               fpu = "68882";
+       else if (m68k_fputype & FPU_68040)
+               fpu = "68040";
+       else if (m68k_fputype & FPU_68060)
+               fpu = "68060";
+       else if (m68k_fputype & FPU_SUNFPA)
+               fpu = "Sun FPA";
+       else
+               fpu = "none";
+#endif
+
+       if (m68k_mmutype & MMU_68851)
+               mmu = "68851";
+       else if (m68k_mmutype & MMU_68030)
+               mmu = "68030";
+       else if (m68k_mmutype & MMU_68040)
+               mmu = "68040";
+       else if (m68k_mmutype & MMU_68060)
+               mmu = "68060";
+       else if (m68k_mmutype & MMU_SUN3)
+               mmu = "Sun-3";
+       else if (m68k_mmutype & MMU_APOLLO)
+               mmu = "Apollo";
+       else
+               mmu = "unknown";
+
+       clockfreq = loops_per_jiffy * HZ * clockfactor;
+
+       seq_printf(m, "CPU:\t\t%s\n"
+                  "MMU:\t\t%s\n"
+                  "FPU:\t\t%s\n"
+                  "Clocking:\t%lu.%1luMHz\n"
+                  "BogoMips:\t%lu.%02lu\n"
+                  "Calibration:\t%lu loops\n",
+                  cpu, mmu, fpu,
+                  clockfreq/1000000,(clockfreq/100000)%10,
+                  loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
+                  loops_per_jiffy);
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < 1 ? (void *)1 : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return NULL;
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+const struct seq_operations cpuinfo_op = {
+       .start  = c_start,
+       .next   = c_next,
+       .stop   = c_stop,
+       .show   = show_cpuinfo,
+};
+
+#ifdef CONFIG_PROC_HARDWARE
+static int hardware_proc_show(struct seq_file *m, void *v)
+{
+       char model[80];
+       unsigned long mem;
+       int i;
+
+       if (mach_get_model)
+               mach_get_model(model);
+       else
+               strcpy(model, "Unknown m68k");
+
+       seq_printf(m, "Model:\t\t%s\n", model);
+       for (mem = 0, i = 0; i < m68k_num_memory; i++)
+               mem += m68k_memory[i].size;
+       seq_printf(m, "System Memory:\t%ldK\n", mem >> 10);
+
+       if (mach_get_hardware_list)
+               mach_get_hardware_list(m);
+
+       return 0;
+}
+
+static int hardware_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hardware_proc_show, NULL);
+}
+
+static const struct file_operations hardware_proc_fops = {
+       .open           = hardware_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init proc_hardware_init(void)
+{
+       proc_create("hardware", 0, NULL, &hardware_proc_fops);
+       return 0;
+}
+module_init(proc_hardware_init);
+#endif
+
+void check_bugs(void)
+{
+#ifndef CONFIG_M68KFPU_EMU
+       if (m68k_fputype == 0) {
+               printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+                       "WHICH IS REQUIRED BY LINUX/M68K ***\n");
+               printk(KERN_EMERG "Upgrade your hardware or join the FPU "
+                       "emulation project\n");
+               panic("no FPU");
+       }
+#endif /* !CONFIG_M68KFPU_EMU */
+}
+
+#ifdef CONFIG_ADB
+static int __init adb_probe_sync_enable (char *str) {
+       extern int __adb_probe_sync;
+       __adb_probe_sync = 1;
+       return 1;
+}
+
+__setup("adb_sync", adb_probe_sync_enable);
+#endif /* CONFIG_ADB */
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
new file mode 100644 (file)
index 0000000..16b2de7
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *  linux/arch/m68knommu/kernel/setup.c
+ *
+ *  Copyright (C) 1999-2007  Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1998,1999  D. Jeff Dionne <jeff@uClinux.org>
+ *  Copyleft  ()) 2000       James D. Schettine {james@telos-systems.com}
+ *  Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ *  Copyright (C) 1995       Hamish Macdonald
+ *  Copyright (C) 2000       Lineo Inc. (www.lineo.com)
+ *  Copyright (C) 2001              Lineo, Inc. <www.lineo.com>
+ *
+ *  68VZ328 Fixes/support    Evan Stawnyczy <e@lineo.ca>
+ */
+
+/*
+ * This file handles the architecture-dependent parts of system setup
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/root_dev.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/pgtable.h>
+
+unsigned long memory_start;
+unsigned long memory_end;
+
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+
+char __initdata command_line[COMMAND_LINE_SIZE];
+
+/* machine dependent timer functions */
+void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
+int (*mach_set_clock_mmss)(unsigned long);
+
+/* machine dependent reboot functions */
+void (*mach_reset)(void);
+void (*mach_halt)(void);
+void (*mach_power_off)(void);
+
+#ifdef CONFIG_M68328
+#define CPU_NAME       "MC68328"
+#endif
+#ifdef CONFIG_M68EZ328
+#define CPU_NAME       "MC68EZ328"
+#endif
+#ifdef CONFIG_M68VZ328
+#define CPU_NAME       "MC68VZ328"
+#endif
+#ifdef CONFIG_M68360
+#define CPU_NAME       "MC68360"
+#endif
+#ifndef CPU_NAME
+#define        CPU_NAME        "UNKNOWN"
+#endif
+
+/*
+ * Different cores have different instruction execution timings.
+ * The old/traditional 68000 cores are basically all the same, at 16.
+ * The ColdFire cores vary a little, their values are defined in their
+ * headers. We default to the standard 68000 value here.
+ */
+#ifndef CPU_INSTR_PER_JIFFY
+#define        CPU_INSTR_PER_JIFFY     16
+#endif
+
+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
+extern int _ramstart, _ramend;
+
+#if defined(CONFIG_UBOOT)
+/*
+ * parse_uboot_commandline
+ *
+ * Copies u-boot commandline arguments and store them in the proper linux
+ * variables.
+ *
+ * Assumes:
+ *     _init_sp global contains the address in the stack pointer when the
+ *     kernel starts (see head.S::_start)
+ *
+ *     U-Boot calling convention:
+ *     (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
+ *
+ *     _init_sp can be parsed as such
+ *
+ *     _init_sp+00 = u-boot cmd after jsr into kernel (skip)
+ *     _init_sp+04 = &kernel board_info (residual data)
+ *     _init_sp+08 = &initrd_start
+ *     _init_sp+12 = &initrd_end
+ *     _init_sp+16 = &cmd_start
+ *     _init_sp+20 = &cmd_end
+ *
+ *     This also assumes that the memory locations pointed to are still
+ *     unmodified. U-boot places them near the end of external SDRAM.
+ *
+ * Argument(s):
+ *     commandp = the linux commandline arg container to fill.
+ *     size     = the sizeof commandp.
+ *
+ * Returns:
+ */
+void parse_uboot_commandline(char *commandp, int size)
+{
+       extern unsigned long _init_sp;
+       unsigned long *sp;
+       unsigned long uboot_kbd;
+       unsigned long uboot_initrd_start, uboot_initrd_end;
+       unsigned long uboot_cmd_start, uboot_cmd_end;
+
+
+       sp = (unsigned long *)_init_sp;
+       uboot_kbd = sp[1];
+       uboot_initrd_start = sp[2];
+       uboot_initrd_end = sp[3];
+       uboot_cmd_start = sp[4];
+       uboot_cmd_end = sp[5];
+
+       if (uboot_cmd_start && uboot_cmd_end)
+               strncpy(commandp, (const char *)uboot_cmd_start, size);
+#if defined(CONFIG_BLK_DEV_INITRD)
+       if (uboot_initrd_start && uboot_initrd_end &&
+               (uboot_initrd_end > uboot_initrd_start)) {
+               initrd_start = uboot_initrd_start;
+               initrd_end = uboot_initrd_end;
+               ROOT_DEV = Root_RAM0;
+               printk(KERN_INFO "initrd at 0x%lx:0x%lx\n",
+                       initrd_start, initrd_end);
+       }
+#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
+}
+#endif /* #if defined(CONFIG_UBOOT) */
+
+void __init setup_arch(char **cmdline_p)
+{
+       int bootmap_size;
+
+       memory_start = PAGE_ALIGN(_ramstart);
+       memory_end = _ramend;
+
+       init_mm.start_code = (unsigned long) &_stext;
+       init_mm.end_code = (unsigned long) &_etext;
+       init_mm.end_data = (unsigned long) &_edata;
+       init_mm.brk = (unsigned long) 0;
+
+       config_BSP(&command_line[0], sizeof(command_line));
+
+#if defined(CONFIG_BOOTPARAM)
+       strncpy(&command_line[0], CONFIG_BOOTPARAM_STRING, sizeof(command_line));
+       command_line[sizeof(command_line) - 1] = 0;
+#endif /* CONFIG_BOOTPARAM */
+
+#if defined(CONFIG_UBOOT)
+       /* CONFIG_UBOOT and CONFIG_BOOTPARAM defined, concatenate cmdline */
+       #if defined(CONFIG_BOOTPARAM)
+               /* Add the whitespace separator */
+               command_line[strlen(CONFIG_BOOTPARAM_STRING)] = ' ';
+               /* Parse uboot command line into the rest of the buffer */
+               parse_uboot_commandline(
+                       &command_line[(strlen(CONFIG_BOOTPARAM_STRING)+1)],
+                       (sizeof(command_line) -
+                       (strlen(CONFIG_BOOTPARAM_STRING)+1)));
+       /* Only CONFIG_UBOOT defined, create cmdline */
+       #else
+               parse_uboot_commandline(&command_line[0], sizeof(command_line));
+       #endif /* CONFIG_BOOTPARAM */
+       command_line[sizeof(command_line) - 1] = 0;
+#endif /* CONFIG_UBOOT */
+
+       printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU_NAME "\n");
+
+#ifdef CONFIG_UCDIMM
+       printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n");
+#endif
+#ifdef CONFIG_M68VZ328
+       printk(KERN_INFO "M68VZ328 support by Evan Stawnyczy <e@lineo.ca>\n");
+#endif
+#ifdef CONFIG_COLDFIRE
+       printk(KERN_INFO "COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n");
+#ifdef CONFIG_M5307
+       printk(KERN_INFO "Modified for M5307 by Dave Miller, dmiller@intellistor.com\n");
+#endif
+#ifdef CONFIG_ELITE
+       printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
+#endif
+#endif
+       printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
+
+#if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )
+       printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n");
+#endif
+#if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 )
+       printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n");
+#endif
+#if defined (CONFIG_M68360)
+       printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n");
+       printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n");
+#endif
+#ifdef CONFIG_DRAGEN2
+       printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
+#endif
+#ifdef CONFIG_M5235EVB
+       printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
+#endif
+
+       pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
+                "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
+                (int) &_sdata, (int) &_edata,
+                (int) &_sbss, (int) &_ebss);
+       pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
+                (int) &_ebss, (int) memory_start,
+                (int) memory_start, (int) memory_end);
+
+       /* Keep a copy of command line */
+       *cmdline_p = &command_line[0];
+       memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+       boot_command_line[COMMAND_LINE_SIZE-1] = 0;
+
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+
+       /*
+        * Give all the memory to the bootmap allocator, tell it to put the
+        * boot mem_map at the start of memory.
+        */
+       bootmap_size = init_bootmem_node(
+                       NODE_DATA(0),
+                       memory_start >> PAGE_SHIFT, /* map goes here */
+                       PAGE_OFFSET >> PAGE_SHIFT,      /* 0 on coldfire */
+                       memory_end >> PAGE_SHIFT);
+       /*
+        * Free the usable memory, we have to make sure we do not free
+        * the bootmem bitmap so we then reserve it after freeing it :-)
+        */
+       free_bootmem(memory_start, memory_end - memory_start);
+       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+
+#if defined(CONFIG_UBOOT) && defined(CONFIG_BLK_DEV_INITRD)
+       if ((initrd_start > 0) && (initrd_start < initrd_end) &&
+                       (initrd_end < memory_end))
+               reserve_bootmem(initrd_start, initrd_end - initrd_start,
+                                BOOTMEM_DEFAULT);
+#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
+
+       /*
+        * Get kmalloc into gear.
+        */
+       paging_init();
+}
+
+/*
+ *     Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+       char *cpu, *mmu, *fpu;
+       u_long clockfreq;
+
+       cpu = CPU_NAME;
+       mmu = "none";
+       fpu = "none";
+       clockfreq = (loops_per_jiffy * HZ) * CPU_INSTR_PER_JIFFY;
+
+       seq_printf(m, "CPU:\t\t%s\n"
+                     "MMU:\t\t%s\n"
+                     "FPU:\t\t%s\n"
+                     "Clocking:\t%lu.%1luMHz\n"
+                     "BogoMips:\t%lu.%02lu\n"
+                     "Calibration:\t%lu loops\n",
+                     cpu, mmu, fpu,
+                     clockfreq / 1000000,
+                     (clockfreq / 100000) % 10,
+                     (loops_per_jiffy * HZ) / 500000,
+                     ((loops_per_jiffy * HZ) / 5000) % 100,
+                     (loops_per_jiffy * HZ));
+
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+       .start  = c_start,
+       .next   = c_next,
+       .stop   = c_stop,
+       .show   = show_cpuinfo,
+};
+
index a0afc239304eb9eb40fcbcbffdf21c005cced264..2e25713e2eadf104dd7fcb9c6c2024c4302fbc97 100644 (file)
-/*
- *  linux/arch/m68k/kernel/signal.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * 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.
- */
-
-/*
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- *
- * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
- *
- * mathemu support by Roman Zippel
- *  (Note: fpstate in the signal context is completely ignored for the emulator
- *         and the internal floating point format is put on stack)
- */
-
-/*
- * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
- * Atari :-) Current limitation: Only one sigstack can be active at one time.
- * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
- * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
- * signal handlers!
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/syscalls.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/unistd.h>
-#include <linux/stddef.h>
-#include <linux/highuid.h>
-#include <linux/personality.h>
-#include <linux/tty.h>
-#include <linux/binfmts.h>
-#include <linux/module.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/traps.h>
-#include <asm/ucontext.h>
-
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-static const int frame_extra_sizes[16] = {
-  [1]  = -1, /* sizeof(((struct frame *)0)->un.fmt1), */
-  [2]  = sizeof(((struct frame *)0)->un.fmt2),
-  [3]  = sizeof(((struct frame *)0)->un.fmt3),
-  [4]  = sizeof(((struct frame *)0)->un.fmt4),
-  [5]  = -1, /* sizeof(((struct frame *)0)->un.fmt5), */
-  [6]  = -1, /* sizeof(((struct frame *)0)->un.fmt6), */
-  [7]  = sizeof(((struct frame *)0)->un.fmt7),
-  [8]  = -1, /* sizeof(((struct frame *)0)->un.fmt8), */
-  [9]  = sizeof(((struct frame *)0)->un.fmt9),
-  [10] = sizeof(((struct frame *)0)->un.fmta),
-  [11] = sizeof(((struct frame *)0)->un.fmtb),
-  [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */
-  [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */
-  [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */
-  [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */
-};
-
-int handle_kernel_fault(struct pt_regs *regs)
-{
-       const struct exception_table_entry *fixup;
-       struct pt_regs *tregs;
-
-       /* Are we prepared to handle this kernel fault? */
-       fixup = search_exception_tables(regs->pc);
-       if (!fixup)
-               return 0;
-
-       /* Create a new four word stack frame, discarding the old one. */
-       regs->stkadj = frame_extra_sizes[regs->format];
-       tregs = (struct pt_regs *)((long)regs + regs->stkadj);
-       tregs->vector = regs->vector;
-       tregs->format = 0;
-       tregs->pc = fixup->fixup;
-       tregs->sr = regs->sr;
-
-       return 1;
-}
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
-{
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       set_restore_sigmask();
-
-       return -ERESTARTNOHAND;
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
-             struct old_sigaction __user *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       if (act) {
-               old_sigset_t mask;
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
-                   __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
-                   __get_user(mask, &act->sa_mask))
-                       return -EFAULT;
-               siginitset(&new_ka.sa.sa_mask, mask);
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
-                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
-                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
-                       return -EFAULT;
-       }
-
-       return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
-       return do_sigaltstack(uss, uoss, rdusp());
-}
-
-
-/*
- * Do a signal return; undo the signal stack.
- *
- * Keep the return code on the stack quadword aligned!
- * That makes the cache flush below easier.
- */
-
-struct sigframe
-{
-       char __user *pretcode;
-       int sig;
-       int code;
-       struct sigcontext __user *psc;
-       char retcode[8];
-       unsigned long extramask[_NSIG_WORDS-1];
-       struct sigcontext sc;
-};
-
-struct rt_sigframe
-{
-       char __user *pretcode;
-       int sig;
-       struct siginfo __user *pinfo;
-       void __user *puc;
-       char retcode[8];
-       struct siginfo info;
-       struct ucontext uc;
-};
-
-
-static unsigned char fpu_version;      /* version number of fpu, set by setup_frame */
-
-static inline int restore_fpu_state(struct sigcontext *sc)
-{
-       int err = 1;
-
-       if (FPU_IS_EMU) {
-           /* restore registers */
-           memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
-           memcpy(current->thread.fp, sc->sc_fpregs, 24);
-           return 0;
-       }
-
-       if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
-           /* Verify the frame format.  */
-           if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
-               goto out;
-           if (CPU_IS_020_OR_030) {
-               if (m68k_fputype & FPU_68881 &&
-                   !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
-                   goto out;
-               if (m68k_fputype & FPU_68882 &&
-                   !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
-                   goto out;
-           } else if (CPU_IS_040) {
-               if (!(sc->sc_fpstate[1] == 0x00 ||
-                      sc->sc_fpstate[1] == 0x28 ||
-                      sc->sc_fpstate[1] == 0x60))
-                   goto out;
-           } else if (CPU_IS_060) {
-               if (!(sc->sc_fpstate[3] == 0x00 ||
-                      sc->sc_fpstate[3] == 0x60 ||
-                     sc->sc_fpstate[3] == 0xe0))
-                   goto out;
-           } else
-               goto out;
-
-           __asm__ volatile (".chip 68k/68881\n\t"
-                             "fmovemx %0,%%fp0-%%fp1\n\t"
-                             "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
-                             ".chip 68k"
-                             : /* no outputs */
-                             : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
-       }
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "frestore %0\n\t"
-                         ".chip 68k" : : "m" (*sc->sc_fpstate));
-       err = 0;
-
-out:
-       return err;
-}
-
-#define FPCONTEXT_SIZE 216
-#define uc_fpstate     uc_filler[0]
-#define uc_formatvec   uc_filler[FPCONTEXT_SIZE/4]
-#define uc_extra       uc_filler[FPCONTEXT_SIZE/4+1]
-
-static inline int rt_restore_fpu_state(struct ucontext __user *uc)
-{
-       unsigned char fpstate[FPCONTEXT_SIZE];
-       int context_size = CPU_IS_060 ? 8 : 0;
-       fpregset_t fpregs;
-       int err = 1;
-
-       if (FPU_IS_EMU) {
-               /* restore fpu control register */
-               if (__copy_from_user(current->thread.fpcntl,
-                               uc->uc_mcontext.fpregs.f_fpcntl, 12))
-                       goto out;
-               /* restore all other fpu register */
-               if (__copy_from_user(current->thread.fp,
-                               uc->uc_mcontext.fpregs.f_fpregs, 96))
-                       goto out;
-               return 0;
-       }
-
-       if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
-               goto out;
-       if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
-               if (!CPU_IS_060)
-                       context_size = fpstate[1];
-               /* Verify the frame format.  */
-               if (!CPU_IS_060 && (fpstate[0] != fpu_version))
-                       goto out;
-               if (CPU_IS_020_OR_030) {
-                       if (m68k_fputype & FPU_68881 &&
-                           !(context_size == 0x18 || context_size == 0xb4))
-                               goto out;
-                       if (m68k_fputype & FPU_68882 &&
-                           !(context_size == 0x38 || context_size == 0xd4))
-                               goto out;
-               } else if (CPU_IS_040) {
-                       if (!(context_size == 0x00 ||
-                             context_size == 0x28 ||
-                             context_size == 0x60))
-                               goto out;
-               } else if (CPU_IS_060) {
-                       if (!(fpstate[3] == 0x00 ||
-                             fpstate[3] == 0x60 ||
-                             fpstate[3] == 0xe0))
-                               goto out;
-               } else
-                       goto out;
-               if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
-                                    sizeof(fpregs)))
-                       goto out;
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %0,%%fp0-%%fp7\n\t"
-                                 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
-                                 ".chip 68k"
-                                 : /* no outputs */
-                                 : "m" (*fpregs.f_fpregs),
-                                   "m" (*fpregs.f_fpcntl));
-       }
-       if (context_size &&
-           __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
-                            context_size))
-               goto out;
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "frestore %0\n\t"
-                         ".chip 68k" : : "m" (*fpstate));
-       err = 0;
-
-out:
-       return err;
-}
-
-static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
-                              void __user *fp)
-{
-       int fsize = frame_extra_sizes[formatvec >> 12];
-       if (fsize < 0) {
-               /*
-                * user process trying to return with weird frame format
-                */
-#ifdef DEBUG
-               printk("user process returning with weird frame format\n");
-#endif
-               return 1;
-       }
-       if (!fsize) {
-               regs->format = formatvec >> 12;
-               regs->vector = formatvec & 0xfff;
-       } else {
-               struct switch_stack *sw = (struct switch_stack *)regs - 1;
-               unsigned long buf[fsize / 2]; /* yes, twice as much */
-
-               /* that'll make sure that expansion won't crap over data */
-               if (copy_from_user(buf + fsize / 4, fp, fsize))
-                       return 1;
-
-               /* point of no return */
-               regs->format = formatvec >> 12;
-               regs->vector = formatvec & 0xfff;
-#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
-               __asm__ __volatile__
-                       ("   movel %0,%/a0\n\t"
-                        "   subl %1,%/a0\n\t"     /* make room on stack */
-                        "   movel %/a0,%/sp\n\t"  /* set stack pointer */
-                        /* move switch_stack and pt_regs */
-                        "1: movel %0@+,%/a0@+\n\t"
-                        "   dbra %2,1b\n\t"
-                        "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
-                        "   lsrl  #2,%1\n\t"
-                        "   subql #1,%1\n\t"
-                        /* copy to the gap we'd made */
-                        "2: movel %4@+,%/a0@+\n\t"
-                        "   dbra %1,2b\n\t"
-                        "   bral ret_from_signal\n"
-                        : /* no outputs, it doesn't ever return */
-                        : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
-                          "n" (frame_offset), "a" (buf + fsize/4)
-                        : "a0");
-#undef frame_offset
-       }
-       return 0;
-}
-
-static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
-{
-       int formatvec;
-       struct sigcontext context;
-       int err;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       /* get previous context */
-       if (copy_from_user(&context, usc, sizeof(context)))
-               goto badframe;
-
-       /* restore passed registers */
-       regs->d0 = context.sc_d0;
-       regs->d1 = context.sc_d1;
-       regs->a0 = context.sc_a0;
-       regs->a1 = context.sc_a1;
-       regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
-       regs->pc = context.sc_pc;
-       regs->orig_d0 = -1;             /* disable syscall checks */
-       wrusp(context.sc_usp);
-       formatvec = context.sc_formatvec;
-
-       err = restore_fpu_state(&context);
-
-       if (err || mangle_kernel_stack(regs, formatvec, fp))
-               goto badframe;
-
-       return 0;
-
-badframe:
-       return 1;
-}
-
-static inline int
-rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
-                   struct ucontext __user *uc)
-{
-       int temp;
-       greg_t __user *gregs = uc->uc_mcontext.gregs;
-       unsigned long usp;
-       int err;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       err = __get_user(temp, &uc->uc_mcontext.version);
-       if (temp != MCONTEXT_VERSION)
-               goto badframe;
-       /* restore passed registers */
-       err |= __get_user(regs->d0, &gregs[0]);
-       err |= __get_user(regs->d1, &gregs[1]);
-       err |= __get_user(regs->d2, &gregs[2]);
-       err |= __get_user(regs->d3, &gregs[3]);
-       err |= __get_user(regs->d4, &gregs[4]);
-       err |= __get_user(regs->d5, &gregs[5]);
-       err |= __get_user(sw->d6, &gregs[6]);
-       err |= __get_user(sw->d7, &gregs[7]);
-       err |= __get_user(regs->a0, &gregs[8]);
-       err |= __get_user(regs->a1, &gregs[9]);
-       err |= __get_user(regs->a2, &gregs[10]);
-       err |= __get_user(sw->a3, &gregs[11]);
-       err |= __get_user(sw->a4, &gregs[12]);
-       err |= __get_user(sw->a5, &gregs[13]);
-       err |= __get_user(sw->a6, &gregs[14]);
-       err |= __get_user(usp, &gregs[15]);
-       wrusp(usp);
-       err |= __get_user(regs->pc, &gregs[16]);
-       err |= __get_user(temp, &gregs[17]);
-       regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
-       regs->orig_d0 = -1;             /* disable syscall checks */
-       err |= __get_user(temp, &uc->uc_formatvec);
-
-       err |= rt_restore_fpu_state(uc);
-
-       if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
-               goto badframe;
-
-       if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
-               goto badframe;
-
-       return 0;
-
-badframe:
-       return 1;
-}
-
-asmlinkage int do_sigreturn(unsigned long __unused)
-{
-       struct switch_stack *sw = (struct switch_stack *) &__unused;
-       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
-       unsigned long usp = rdusp();
-       struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
-       sigset_t set;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
-           (_NSIG_WORDS > 1 &&
-            __copy_from_user(&set.sig[1], &frame->extramask,
-                             sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       current->blocked = set;
-       recalc_sigpending();
-
-       if (restore_sigcontext(regs, &frame->sc, frame + 1))
-               goto badframe;
-       return regs->d0;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-asmlinkage int do_rt_sigreturn(unsigned long __unused)
-{
-       struct switch_stack *sw = (struct switch_stack *) &__unused;
-       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
-       unsigned long usp = rdusp();
-       struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
-       sigset_t set;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       current->blocked = set;
-       recalc_sigpending();
-
-       if (rt_restore_ucontext(regs, sw, &frame->uc))
-               goto badframe;
-       return regs->d0;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-/*
- * Set up a signal frame.
- */
-
-static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
-{
-       if (FPU_IS_EMU) {
-               /* save registers */
-               memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
-               memcpy(sc->sc_fpregs, current->thread.fp, 24);
-               return;
-       }
-
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "fsave %0\n\t"
-                         ".chip 68k"
-                         : : "m" (*sc->sc_fpstate) : "memory");
-
-       if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
-               fpu_version = sc->sc_fpstate[0];
-               if (CPU_IS_020_OR_030 &&
-                   regs->vector >= (VEC_FPBRUC * 4) &&
-                   regs->vector <= (VEC_FPNAN * 4)) {
-                       /* Clear pending exception in 68882 idle frame */
-                       if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
-                               sc->sc_fpstate[0x38] |= 1 << 3;
-               }
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %%fp0-%%fp1,%0\n\t"
-                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
-                                 ".chip 68k"
-                                 : "=m" (*sc->sc_fpregs),
-                                   "=m" (*sc->sc_fpcntl)
-                                 : /* no inputs */
-                                 : "memory");
-       }
-}
-
-static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
-{
-       unsigned char fpstate[FPCONTEXT_SIZE];
-       int context_size = CPU_IS_060 ? 8 : 0;
-       int err = 0;
-
-       if (FPU_IS_EMU) {
-               /* save fpu control register */
-               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
-                               current->thread.fpcntl, 12);
-               /* save all other fpu register */
-               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
-                               current->thread.fp, 96);
-               return err;
-       }
-
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "fsave %0\n\t"
-                         ".chip 68k"
-                         : : "m" (*fpstate) : "memory");
-
-       err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
-       if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
-               fpregset_t fpregs;
-               if (!CPU_IS_060)
-                       context_size = fpstate[1];
-               fpu_version = fpstate[0];
-               if (CPU_IS_020_OR_030 &&
-                   regs->vector >= (VEC_FPBRUC * 4) &&
-                   regs->vector <= (VEC_FPNAN * 4)) {
-                       /* Clear pending exception in 68882 idle frame */
-                       if (*(unsigned short *) fpstate == 0x1f38)
-                               fpstate[0x38] |= 1 << 3;
-               }
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %%fp0-%%fp7,%0\n\t"
-                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
-                                 ".chip 68k"
-                                 : "=m" (*fpregs.f_fpregs),
-                                   "=m" (*fpregs.f_fpcntl)
-                                 : /* no inputs */
-                                 : "memory");
-               err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
-                                   sizeof(fpregs));
-       }
-       if (context_size)
-               err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
-                                   context_size);
-       return err;
-}
-
-static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
-                            unsigned long mask)
-{
-       sc->sc_mask = mask;
-       sc->sc_usp = rdusp();
-       sc->sc_d0 = regs->d0;
-       sc->sc_d1 = regs->d1;
-       sc->sc_a0 = regs->a0;
-       sc->sc_a1 = regs->a1;
-       sc->sc_sr = regs->sr;
-       sc->sc_pc = regs->pc;
-       sc->sc_formatvec = regs->format << 12 | regs->vector;
-       save_fpu_state(sc, regs);
-}
-
-static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
-{
-       struct switch_stack *sw = (struct switch_stack *)regs - 1;
-       greg_t __user *gregs = uc->uc_mcontext.gregs;
-       int err = 0;
-
-       err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
-       err |= __put_user(regs->d0, &gregs[0]);
-       err |= __put_user(regs->d1, &gregs[1]);
-       err |= __put_user(regs->d2, &gregs[2]);
-       err |= __put_user(regs->d3, &gregs[3]);
-       err |= __put_user(regs->d4, &gregs[4]);
-       err |= __put_user(regs->d5, &gregs[5]);
-       err |= __put_user(sw->d6, &gregs[6]);
-       err |= __put_user(sw->d7, &gregs[7]);
-       err |= __put_user(regs->a0, &gregs[8]);
-       err |= __put_user(regs->a1, &gregs[9]);
-       err |= __put_user(regs->a2, &gregs[10]);
-       err |= __put_user(sw->a3, &gregs[11]);
-       err |= __put_user(sw->a4, &gregs[12]);
-       err |= __put_user(sw->a5, &gregs[13]);
-       err |= __put_user(sw->a6, &gregs[14]);
-       err |= __put_user(rdusp(), &gregs[15]);
-       err |= __put_user(regs->pc, &gregs[16]);
-       err |= __put_user(regs->sr, &gregs[17]);
-       err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
-       err |= rt_save_fpu_state(uc, regs);
-       return err;
-}
-
-static inline void push_cache (unsigned long vaddr)
-{
-       /*
-        * Using the old cache_push_v() was really a big waste.
-        *
-        * What we are trying to do is to flush 8 bytes to ram.
-        * Flushing 2 cache lines of 16 bytes is much cheaper than
-        * flushing 1 or 2 pages, as previously done in
-        * cache_push_v().
-        *                                                     Jes
-        */
-       if (CPU_IS_040) {
-               unsigned long temp;
-
-               __asm__ __volatile__ (".chip 68040\n\t"
-                                     "nop\n\t"
-                                     "ptestr (%1)\n\t"
-                                     "movec %%mmusr,%0\n\t"
-                                     ".chip 68k"
-                                     : "=r" (temp)
-                                     : "a" (vaddr));
-
-               temp &= PAGE_MASK;
-               temp |= vaddr & ~PAGE_MASK;
-
-               __asm__ __volatile__ (".chip 68040\n\t"
-                                     "nop\n\t"
-                                     "cpushl %%bc,(%0)\n\t"
-                                     ".chip 68k"
-                                     : : "a" (temp));
-       }
-       else if (CPU_IS_060) {
-               unsigned long temp;
-               __asm__ __volatile__ (".chip 68060\n\t"
-                                     "plpar (%0)\n\t"
-                                     ".chip 68k"
-                                     : "=a" (temp)
-                                     : "0" (vaddr));
-               __asm__ __volatile__ (".chip 68060\n\t"
-                                     "cpushl %%bc,(%0)\n\t"
-                                     ".chip 68k"
-                                     : : "a" (temp));
-       }
-       else {
-               /*
-                * 68030/68020 have no writeback cache;
-                * still need to clear icache.
-                * Note that vaddr is guaranteed to be long word aligned.
-                */
-               unsigned long temp;
-               asm volatile ("movec %%cacr,%0" : "=r" (temp));
-               temp += 4;
-               asm volatile ("movec %0,%%caar\n\t"
-                             "movec %1,%%cacr"
-                             : : "r" (vaddr), "r" (temp));
-               asm volatile ("movec %0,%%caar\n\t"
-                             "movec %1,%%cacr"
-                             : : "r" (vaddr + 4), "r" (temp));
-       }
-}
-
-static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
-{
-       unsigned long usp;
-
-       /* Default to using normal stack.  */
-       usp = rdusp();
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (!sas_ss_flags(usp))
-                       usp = current->sas_ss_sp + current->sas_ss_size;
-       }
-       return (void __user *)((usp - frame_size) & -8UL);
-}
-
-static int setup_frame (int sig, struct k_sigaction *ka,
-                        sigset_t *set, struct pt_regs *regs)
-{
-       struct sigframe __user *frame;
-       int fsize = frame_extra_sizes[regs->format];
-       struct sigcontext context;
-       int err = 0;
-
-       if (fsize < 0) {
-#ifdef DEBUG
-               printk ("setup_frame: Unknown frame format %#x\n",
-                       regs->format);
-#endif
-               goto give_sigsegv;
-       }
-
-       frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
-
-       if (fsize)
-               err |= copy_to_user (frame + 1, regs + 1, fsize);
-
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-
-       err |= __put_user(regs->vector, &frame->code);
-       err |= __put_user(&frame->sc, &frame->psc);
-
-       if (_NSIG_WORDS > 1)
-               err |= copy_to_user(frame->extramask, &set->sig[1],
-                                   sizeof(frame->extramask));
-
-       setup_sigcontext(&context, regs, set->sig[0]);
-       err |= copy_to_user (&frame->sc, &context, sizeof(context));
-
-       /* Set up to return from userspace.  */
-       err |= __put_user(frame->retcode, &frame->pretcode);
-       /* moveq #,d0; trap #0 */
-       err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
-                         (long __user *)(frame->retcode));
-
-       if (err)
-               goto give_sigsegv;
-
-       push_cache ((unsigned long) &frame->retcode);
-
-       /*
-        * Set up registers for signal handler.  All the state we are about
-        * to destroy is successfully copied to sigframe.
-        */
-       wrusp ((unsigned long) frame);
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-
-       /*
-        * This is subtle; if we build more than one sigframe, all but the
-        * first one will see frame format 0 and have fsize == 0, so we won't
-        * screw stkadj.
-        */
-       if (fsize)
-               regs->stkadj = fsize;
-
-       /* Prepare to skip over the extra stuff in the exception frame.  */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                       (struct pt_regs *)((ulong)regs + regs->stkadj);
-#ifdef DEBUG
-               printk("Performing stackadjust=%04x\n", regs->stkadj);
-#endif
-               /* This must be copied with decreasing addresses to
-                   handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
-       }
-       return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return err;
-}
-
-static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
-                           sigset_t *set, struct pt_regs *regs)
-{
-       struct rt_sigframe __user *frame;
-       int fsize = frame_extra_sizes[regs->format];
-       int err = 0;
-
-       if (fsize < 0) {
-#ifdef DEBUG
-               printk ("setup_frame: Unknown frame format %#x\n",
-                       regs->format);
-#endif
-               goto give_sigsegv;
-       }
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       if (fsize)
-               err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
-
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-       err |= __put_user(&frame->info, &frame->pinfo);
-       err |= __put_user(&frame->uc, &frame->puc);
-       err |= copy_siginfo_to_user(&frame->info, info);
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(NULL, &frame->uc.uc_link);
-       err |= __put_user((void __user *)current->sas_ss_sp,
-                         &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(rdusp()),
-                         &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= rt_setup_ucontext(&frame->uc, regs);
-       err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
-
-       /* Set up to return from userspace.  */
-       err |= __put_user(frame->retcode, &frame->pretcode);
-#ifdef __mcoldfire__
-       /* movel #__NR_rt_sigreturn,d0; trap #0 */
-       err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0));
-       err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16),
-                         (long __user *)(frame->retcode + 4));
+#ifdef CONFIG_MMU
+#include "signal_mm.c"
 #else
-       /* moveq #,d0; notb d0; trap #0 */
-       err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
-                         (long __user *)(frame->retcode + 0));
-       err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
-#endif
-
-       if (err)
-               goto give_sigsegv;
-
-       push_cache ((unsigned long) &frame->retcode);
-
-       /*
-        * Set up registers for signal handler.  All the state we are about
-        * to destroy is successfully copied to sigframe.
-        */
-       wrusp ((unsigned long) frame);
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-
-       /*
-        * This is subtle; if we build more than one sigframe, all but the
-        * first one will see frame format 0 and have fsize == 0, so we won't
-        * screw stkadj.
-        */
-       if (fsize)
-               regs->stkadj = fsize;
-
-       /* Prepare to skip over the extra stuff in the exception frame.  */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                       (struct pt_regs *)((ulong)regs + regs->stkadj);
-#ifdef DEBUG
-               printk("Performing stackadjust=%04x\n", regs->stkadj);
+#include "signal_no.c"
 #endif
-               /* This must be copied with decreasing addresses to
-                   handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
-       }
-       return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return err;
-}
-
-static inline void
-handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
-{
-       switch (regs->d0) {
-       case -ERESTARTNOHAND:
-               if (!has_handler)
-                       goto do_restart;
-               regs->d0 = -EINTR;
-               break;
-
-       case -ERESTART_RESTARTBLOCK:
-               if (!has_handler) {
-                       regs->d0 = __NR_restart_syscall;
-                       regs->pc -= 2;
-                       break;
-               }
-               regs->d0 = -EINTR;
-               break;
-
-       case -ERESTARTSYS:
-               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
-                       regs->d0 = -EINTR;
-                       break;
-               }
-       /* fallthrough */
-       case -ERESTARTNOINTR:
-       do_restart:
-               regs->d0 = regs->orig_d0;
-               regs->pc -= 2;
-               break;
-       }
-}
-
-void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
-{
-       if (regs->orig_d0 < 0)
-               return;
-       switch (regs->d0) {
-       case -ERESTARTNOHAND:
-       case -ERESTARTSYS:
-       case -ERESTARTNOINTR:
-               regs->d0 = regs->orig_d0;
-               regs->orig_d0 = -1;
-               regs->pc -= 2;
-               break;
-       }
-}
-
-/*
- * OK, we're invoking a handler
- */
-static void
-handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
-             sigset_t *oldset, struct pt_regs *regs)
-{
-       int err;
-       /* are we from a system call? */
-       if (regs->orig_d0 >= 0)
-               /* If so, check system call restarting.. */
-               handle_restart(regs, ka, 1);
-
-       /* set up the stack frame */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               err = setup_rt_frame(sig, ka, info, oldset, regs);
-       else
-               err = setup_frame(sig, ka, oldset, regs);
-
-       if (err)
-               return;
-
-       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked,sig);
-       recalc_sigpending();
-
-       if (test_thread_flag(TIF_DELAYED_TRACE)) {
-               regs->sr &= ~0x8000;
-               send_sig(SIGTRAP, current, 1);
-       }
-
-       clear_thread_flag(TIF_RESTORE_SIGMASK);
-}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-asmlinkage void do_signal(struct pt_regs *regs)
-{
-       siginfo_t info;
-       struct k_sigaction ka;
-       int signr;
-       sigset_t *oldset;
-
-       current->thread.esp0 = (unsigned long) regs;
-
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = &current->saved_sigmask;
-       else
-               oldset = &current->blocked;
-
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-       if (signr > 0) {
-               /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &ka, &info, oldset, regs);
-               return;
-       }
-
-       /* Did we come from a system call? */
-       if (regs->orig_d0 >= 0)
-               /* Restart the system call - no handlers present */
-               handle_restart(regs, NULL, 0);
-
-       /* If there's no signal to deliver, we just restore the saved mask.  */
-       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-               clear_thread_flag(TIF_RESTORE_SIGMASK);
-               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-       }
-}
diff --git a/arch/m68k/kernel/signal_mm.c b/arch/m68k/kernel/signal_mm.c
new file mode 100644 (file)
index 0000000..a0afc23
--- /dev/null
@@ -0,0 +1,1017 @@
+/*
+ *  linux/arch/m68k/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * 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.
+ */
+
+/*
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ *
+ * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
+ *
+ * mathemu support by Roman Zippel
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
+ *         and the internal floating point format is put on stack)
+ */
+
+/*
+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
+ * signal handlers!
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/highuid.h>
+#include <linux/personality.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
+#include <linux/module.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+static const int frame_extra_sizes[16] = {
+  [1]  = -1, /* sizeof(((struct frame *)0)->un.fmt1), */
+  [2]  = sizeof(((struct frame *)0)->un.fmt2),
+  [3]  = sizeof(((struct frame *)0)->un.fmt3),
+  [4]  = sizeof(((struct frame *)0)->un.fmt4),
+  [5]  = -1, /* sizeof(((struct frame *)0)->un.fmt5), */
+  [6]  = -1, /* sizeof(((struct frame *)0)->un.fmt6), */
+  [7]  = sizeof(((struct frame *)0)->un.fmt7),
+  [8]  = -1, /* sizeof(((struct frame *)0)->un.fmt8), */
+  [9]  = sizeof(((struct frame *)0)->un.fmt9),
+  [10] = sizeof(((struct frame *)0)->un.fmta),
+  [11] = sizeof(((struct frame *)0)->un.fmtb),
+  [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */
+  [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */
+  [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */
+  [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */
+};
+
+int handle_kernel_fault(struct pt_regs *regs)
+{
+       const struct exception_table_entry *fixup;
+       struct pt_regs *tregs;
+
+       /* Are we prepared to handle this kernel fault? */
+       fixup = search_exception_tables(regs->pc);
+       if (!fixup)
+               return 0;
+
+       /* Create a new four word stack frame, discarding the old one. */
+       regs->stkadj = frame_extra_sizes[regs->format];
+       tregs = (struct pt_regs *)((long)regs + regs->stkadj);
+       tregs->vector = regs->vector;
+       tregs->format = 0;
+       tregs->pc = fixup->fixup;
+       tregs->sr = regs->sr;
+
+       return 1;
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
+{
+       mask &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+       current->saved_sigmask = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_restore_sigmask();
+
+       return -ERESTARTNOHAND;
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+             struct old_sigaction __user *oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       if (act) {
+               old_sigset_t mask;
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+                   __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+                   __get_user(mask, &act->sa_mask))
+                       return -EFAULT;
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+                       return -EFAULT;
+       }
+
+       return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
+{
+       return do_sigaltstack(uss, uoss, rdusp());
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
+ */
+
+struct sigframe
+{
+       char __user *pretcode;
+       int sig;
+       int code;
+       struct sigcontext __user *psc;
+       char retcode[8];
+       unsigned long extramask[_NSIG_WORDS-1];
+       struct sigcontext sc;
+};
+
+struct rt_sigframe
+{
+       char __user *pretcode;
+       int sig;
+       struct siginfo __user *pinfo;
+       void __user *puc;
+       char retcode[8];
+       struct siginfo info;
+       struct ucontext uc;
+};
+
+
+static unsigned char fpu_version;      /* version number of fpu, set by setup_frame */
+
+static inline int restore_fpu_state(struct sigcontext *sc)
+{
+       int err = 1;
+
+       if (FPU_IS_EMU) {
+           /* restore registers */
+           memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
+           memcpy(current->thread.fp, sc->sc_fpregs, 24);
+           return 0;
+       }
+
+       if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+           /* Verify the frame format.  */
+           if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
+               goto out;
+           if (CPU_IS_020_OR_030) {
+               if (m68k_fputype & FPU_68881 &&
+                   !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
+                   goto out;
+               if (m68k_fputype & FPU_68882 &&
+                   !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
+                   goto out;
+           } else if (CPU_IS_040) {
+               if (!(sc->sc_fpstate[1] == 0x00 ||
+                      sc->sc_fpstate[1] == 0x28 ||
+                      sc->sc_fpstate[1] == 0x60))
+                   goto out;
+           } else if (CPU_IS_060) {
+               if (!(sc->sc_fpstate[3] == 0x00 ||
+                      sc->sc_fpstate[3] == 0x60 ||
+                     sc->sc_fpstate[3] == 0xe0))
+                   goto out;
+           } else
+               goto out;
+
+           __asm__ volatile (".chip 68k/68881\n\t"
+                             "fmovemx %0,%%fp0-%%fp1\n\t"
+                             "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
+                             ".chip 68k"
+                             : /* no outputs */
+                             : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
+       }
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "frestore %0\n\t"
+                         ".chip 68k" : : "m" (*sc->sc_fpstate));
+       err = 0;
+
+out:
+       return err;
+}
+
+#define FPCONTEXT_SIZE 216
+#define uc_fpstate     uc_filler[0]
+#define uc_formatvec   uc_filler[FPCONTEXT_SIZE/4]
+#define uc_extra       uc_filler[FPCONTEXT_SIZE/4+1]
+
+static inline int rt_restore_fpu_state(struct ucontext __user *uc)
+{
+       unsigned char fpstate[FPCONTEXT_SIZE];
+       int context_size = CPU_IS_060 ? 8 : 0;
+       fpregset_t fpregs;
+       int err = 1;
+
+       if (FPU_IS_EMU) {
+               /* restore fpu control register */
+               if (__copy_from_user(current->thread.fpcntl,
+                               uc->uc_mcontext.fpregs.f_fpcntl, 12))
+                       goto out;
+               /* restore all other fpu register */
+               if (__copy_from_user(current->thread.fp,
+                               uc->uc_mcontext.fpregs.f_fpregs, 96))
+                       goto out;
+               return 0;
+       }
+
+       if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
+               goto out;
+       if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+               if (!CPU_IS_060)
+                       context_size = fpstate[1];
+               /* Verify the frame format.  */
+               if (!CPU_IS_060 && (fpstate[0] != fpu_version))
+                       goto out;
+               if (CPU_IS_020_OR_030) {
+                       if (m68k_fputype & FPU_68881 &&
+                           !(context_size == 0x18 || context_size == 0xb4))
+                               goto out;
+                       if (m68k_fputype & FPU_68882 &&
+                           !(context_size == 0x38 || context_size == 0xd4))
+                               goto out;
+               } else if (CPU_IS_040) {
+                       if (!(context_size == 0x00 ||
+                             context_size == 0x28 ||
+                             context_size == 0x60))
+                               goto out;
+               } else if (CPU_IS_060) {
+                       if (!(fpstate[3] == 0x00 ||
+                             fpstate[3] == 0x60 ||
+                             fpstate[3] == 0xe0))
+                               goto out;
+               } else
+                       goto out;
+               if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
+                                    sizeof(fpregs)))
+                       goto out;
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %0,%%fp0-%%fp7\n\t"
+                                 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
+                                 ".chip 68k"
+                                 : /* no outputs */
+                                 : "m" (*fpregs.f_fpregs),
+                                   "m" (*fpregs.f_fpcntl));
+       }
+       if (context_size &&
+           __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
+                            context_size))
+               goto out;
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "frestore %0\n\t"
+                         ".chip 68k" : : "m" (*fpstate));
+       err = 0;
+
+out:
+       return err;
+}
+
+static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
+                              void __user *fp)
+{
+       int fsize = frame_extra_sizes[formatvec >> 12];
+       if (fsize < 0) {
+               /*
+                * user process trying to return with weird frame format
+                */
+#ifdef DEBUG
+               printk("user process returning with weird frame format\n");
+#endif
+               return 1;
+       }
+       if (!fsize) {
+               regs->format = formatvec >> 12;
+               regs->vector = formatvec & 0xfff;
+       } else {
+               struct switch_stack *sw = (struct switch_stack *)regs - 1;
+               unsigned long buf[fsize / 2]; /* yes, twice as much */
+
+               /* that'll make sure that expansion won't crap over data */
+               if (copy_from_user(buf + fsize / 4, fp, fsize))
+                       return 1;
+
+               /* point of no return */
+               regs->format = formatvec >> 12;
+               regs->vector = formatvec & 0xfff;
+#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
+               __asm__ __volatile__
+                       ("   movel %0,%/a0\n\t"
+                        "   subl %1,%/a0\n\t"     /* make room on stack */
+                        "   movel %/a0,%/sp\n\t"  /* set stack pointer */
+                        /* move switch_stack and pt_regs */
+                        "1: movel %0@+,%/a0@+\n\t"
+                        "   dbra %2,1b\n\t"
+                        "   lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
+                        "   lsrl  #2,%1\n\t"
+                        "   subql #1,%1\n\t"
+                        /* copy to the gap we'd made */
+                        "2: movel %4@+,%/a0@+\n\t"
+                        "   dbra %1,2b\n\t"
+                        "   bral ret_from_signal\n"
+                        : /* no outputs, it doesn't ever return */
+                        : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
+                          "n" (frame_offset), "a" (buf + fsize/4)
+                        : "a0");
+#undef frame_offset
+       }
+       return 0;
+}
+
+static inline int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
+{
+       int formatvec;
+       struct sigcontext context;
+       int err;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       /* get previous context */
+       if (copy_from_user(&context, usc, sizeof(context)))
+               goto badframe;
+
+       /* restore passed registers */
+       regs->d0 = context.sc_d0;
+       regs->d1 = context.sc_d1;
+       regs->a0 = context.sc_a0;
+       regs->a1 = context.sc_a1;
+       regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
+       regs->pc = context.sc_pc;
+       regs->orig_d0 = -1;             /* disable syscall checks */
+       wrusp(context.sc_usp);
+       formatvec = context.sc_formatvec;
+
+       err = restore_fpu_state(&context);
+
+       if (err || mangle_kernel_stack(regs, formatvec, fp))
+               goto badframe;
+
+       return 0;
+
+badframe:
+       return 1;
+}
+
+static inline int
+rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
+                   struct ucontext __user *uc)
+{
+       int temp;
+       greg_t __user *gregs = uc->uc_mcontext.gregs;
+       unsigned long usp;
+       int err;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       err = __get_user(temp, &uc->uc_mcontext.version);
+       if (temp != MCONTEXT_VERSION)
+               goto badframe;
+       /* restore passed registers */
+       err |= __get_user(regs->d0, &gregs[0]);
+       err |= __get_user(regs->d1, &gregs[1]);
+       err |= __get_user(regs->d2, &gregs[2]);
+       err |= __get_user(regs->d3, &gregs[3]);
+       err |= __get_user(regs->d4, &gregs[4]);
+       err |= __get_user(regs->d5, &gregs[5]);
+       err |= __get_user(sw->d6, &gregs[6]);
+       err |= __get_user(sw->d7, &gregs[7]);
+       err |= __get_user(regs->a0, &gregs[8]);
+       err |= __get_user(regs->a1, &gregs[9]);
+       err |= __get_user(regs->a2, &gregs[10]);
+       err |= __get_user(sw->a3, &gregs[11]);
+       err |= __get_user(sw->a4, &gregs[12]);
+       err |= __get_user(sw->a5, &gregs[13]);
+       err |= __get_user(sw->a6, &gregs[14]);
+       err |= __get_user(usp, &gregs[15]);
+       wrusp(usp);
+       err |= __get_user(regs->pc, &gregs[16]);
+       err |= __get_user(temp, &gregs[17]);
+       regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
+       regs->orig_d0 = -1;             /* disable syscall checks */
+       err |= __get_user(temp, &uc->uc_formatvec);
+
+       err |= rt_restore_fpu_state(uc);
+
+       if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+               goto badframe;
+
+       if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
+               goto badframe;
+
+       return 0;
+
+badframe:
+       return 1;
+}
+
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+       struct switch_stack *sw = (struct switch_stack *) &__unused;
+       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+       unsigned long usp = rdusp();
+       struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
+       sigset_t set;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
+           (_NSIG_WORDS > 1 &&
+            __copy_from_user(&set.sig[1], &frame->extramask,
+                             sizeof(frame->extramask))))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       current->blocked = set;
+       recalc_sigpending();
+
+       if (restore_sigcontext(regs, &frame->sc, frame + 1))
+               goto badframe;
+       return regs->d0;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+       struct switch_stack *sw = (struct switch_stack *) &__unused;
+       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+       unsigned long usp = rdusp();
+       struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
+       sigset_t set;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       current->blocked = set;
+       recalc_sigpending();
+
+       if (rt_restore_ucontext(regs, sw, &frame->uc))
+               goto badframe;
+       return regs->d0;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
+{
+       if (FPU_IS_EMU) {
+               /* save registers */
+               memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
+               memcpy(sc->sc_fpregs, current->thread.fp, 24);
+               return;
+       }
+
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "fsave %0\n\t"
+                         ".chip 68k"
+                         : : "m" (*sc->sc_fpstate) : "memory");
+
+       if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+               fpu_version = sc->sc_fpstate[0];
+               if (CPU_IS_020_OR_030 &&
+                   regs->vector >= (VEC_FPBRUC * 4) &&
+                   regs->vector <= (VEC_FPNAN * 4)) {
+                       /* Clear pending exception in 68882 idle frame */
+                       if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
+                               sc->sc_fpstate[0x38] |= 1 << 3;
+               }
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %%fp0-%%fp1,%0\n\t"
+                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
+                                 ".chip 68k"
+                                 : "=m" (*sc->sc_fpregs),
+                                   "=m" (*sc->sc_fpcntl)
+                                 : /* no inputs */
+                                 : "memory");
+       }
+}
+
+static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
+{
+       unsigned char fpstate[FPCONTEXT_SIZE];
+       int context_size = CPU_IS_060 ? 8 : 0;
+       int err = 0;
+
+       if (FPU_IS_EMU) {
+               /* save fpu control register */
+               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
+                               current->thread.fpcntl, 12);
+               /* save all other fpu register */
+               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
+                               current->thread.fp, 96);
+               return err;
+       }
+
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "fsave %0\n\t"
+                         ".chip 68k"
+                         : : "m" (*fpstate) : "memory");
+
+       err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
+       if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+               fpregset_t fpregs;
+               if (!CPU_IS_060)
+                       context_size = fpstate[1];
+               fpu_version = fpstate[0];
+               if (CPU_IS_020_OR_030 &&
+                   regs->vector >= (VEC_FPBRUC * 4) &&
+                   regs->vector <= (VEC_FPNAN * 4)) {
+                       /* Clear pending exception in 68882 idle frame */
+                       if (*(unsigned short *) fpstate == 0x1f38)
+                               fpstate[0x38] |= 1 << 3;
+               }
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %%fp0-%%fp7,%0\n\t"
+                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
+                                 ".chip 68k"
+                                 : "=m" (*fpregs.f_fpregs),
+                                   "=m" (*fpregs.f_fpcntl)
+                                 : /* no inputs */
+                                 : "memory");
+               err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
+                                   sizeof(fpregs));
+       }
+       if (context_size)
+               err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
+                                   context_size);
+       return err;
+}
+
+static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+                            unsigned long mask)
+{
+       sc->sc_mask = mask;
+       sc->sc_usp = rdusp();
+       sc->sc_d0 = regs->d0;
+       sc->sc_d1 = regs->d1;
+       sc->sc_a0 = regs->a0;
+       sc->sc_a1 = regs->a1;
+       sc->sc_sr = regs->sr;
+       sc->sc_pc = regs->pc;
+       sc->sc_formatvec = regs->format << 12 | regs->vector;
+       save_fpu_state(sc, regs);
+}
+
+static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
+{
+       struct switch_stack *sw = (struct switch_stack *)regs - 1;
+       greg_t __user *gregs = uc->uc_mcontext.gregs;
+       int err = 0;
+
+       err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+       err |= __put_user(regs->d0, &gregs[0]);
+       err |= __put_user(regs->d1, &gregs[1]);
+       err |= __put_user(regs->d2, &gregs[2]);
+       err |= __put_user(regs->d3, &gregs[3]);
+       err |= __put_user(regs->d4, &gregs[4]);
+       err |= __put_user(regs->d5, &gregs[5]);
+       err |= __put_user(sw->d6, &gregs[6]);
+       err |= __put_user(sw->d7, &gregs[7]);
+       err |= __put_user(regs->a0, &gregs[8]);
+       err |= __put_user(regs->a1, &gregs[9]);
+       err |= __put_user(regs->a2, &gregs[10]);
+       err |= __put_user(sw->a3, &gregs[11]);
+       err |= __put_user(sw->a4, &gregs[12]);
+       err |= __put_user(sw->a5, &gregs[13]);
+       err |= __put_user(sw->a6, &gregs[14]);
+       err |= __put_user(rdusp(), &gregs[15]);
+       err |= __put_user(regs->pc, &gregs[16]);
+       err |= __put_user(regs->sr, &gregs[17]);
+       err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+       err |= rt_save_fpu_state(uc, regs);
+       return err;
+}
+
+static inline void push_cache (unsigned long vaddr)
+{
+       /*
+        * Using the old cache_push_v() was really a big waste.
+        *
+        * What we are trying to do is to flush 8 bytes to ram.
+        * Flushing 2 cache lines of 16 bytes is much cheaper than
+        * flushing 1 or 2 pages, as previously done in
+        * cache_push_v().
+        *                                                     Jes
+        */
+       if (CPU_IS_040) {
+               unsigned long temp;
+
+               __asm__ __volatile__ (".chip 68040\n\t"
+                                     "nop\n\t"
+                                     "ptestr (%1)\n\t"
+                                     "movec %%mmusr,%0\n\t"
+                                     ".chip 68k"
+                                     : "=r" (temp)
+                                     : "a" (vaddr));
+
+               temp &= PAGE_MASK;
+               temp |= vaddr & ~PAGE_MASK;
+
+               __asm__ __volatile__ (".chip 68040\n\t"
+                                     "nop\n\t"
+                                     "cpushl %%bc,(%0)\n\t"
+                                     ".chip 68k"
+                                     : : "a" (temp));
+       }
+       else if (CPU_IS_060) {
+               unsigned long temp;
+               __asm__ __volatile__ (".chip 68060\n\t"
+                                     "plpar (%0)\n\t"
+                                     ".chip 68k"
+                                     : "=a" (temp)
+                                     : "0" (vaddr));
+               __asm__ __volatile__ (".chip 68060\n\t"
+                                     "cpushl %%bc,(%0)\n\t"
+                                     ".chip 68k"
+                                     : : "a" (temp));
+       }
+       else {
+               /*
+                * 68030/68020 have no writeback cache;
+                * still need to clear icache.
+                * Note that vaddr is guaranteed to be long word aligned.
+                */
+               unsigned long temp;
+               asm volatile ("movec %%cacr,%0" : "=r" (temp));
+               temp += 4;
+               asm volatile ("movec %0,%%caar\n\t"
+                             "movec %1,%%cacr"
+                             : : "r" (vaddr), "r" (temp));
+               asm volatile ("movec %0,%%caar\n\t"
+                             "movec %1,%%cacr"
+                             : : "r" (vaddr + 4), "r" (temp));
+       }
+}
+
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+       unsigned long usp;
+
+       /* Default to using normal stack.  */
+       usp = rdusp();
+
+       /* This is the X/Open sanctioned signal stack switching.  */
+       if (ka->sa.sa_flags & SA_ONSTACK) {
+               if (!sas_ss_flags(usp))
+                       usp = current->sas_ss_sp + current->sas_ss_size;
+       }
+       return (void __user *)((usp - frame_size) & -8UL);
+}
+
+static int setup_frame (int sig, struct k_sigaction *ka,
+                        sigset_t *set, struct pt_regs *regs)
+{
+       struct sigframe __user *frame;
+       int fsize = frame_extra_sizes[regs->format];
+       struct sigcontext context;
+       int err = 0;
+
+       if (fsize < 0) {
+#ifdef DEBUG
+               printk ("setup_frame: Unknown frame format %#x\n",
+                       regs->format);
+#endif
+               goto give_sigsegv;
+       }
+
+       frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
+
+       if (fsize)
+               err |= copy_to_user (frame + 1, regs + 1, fsize);
+
+       err |= __put_user((current_thread_info()->exec_domain
+                          && current_thread_info()->exec_domain->signal_invmap
+                          && sig < 32
+                          ? current_thread_info()->exec_domain->signal_invmap[sig]
+                          : sig),
+                         &frame->sig);
+
+       err |= __put_user(regs->vector, &frame->code);
+       err |= __put_user(&frame->sc, &frame->psc);
+
+       if (_NSIG_WORDS > 1)
+               err |= copy_to_user(frame->extramask, &set->sig[1],
+                                   sizeof(frame->extramask));
+
+       setup_sigcontext(&context, regs, set->sig[0]);
+       err |= copy_to_user (&frame->sc, &context, sizeof(context));
+
+       /* Set up to return from userspace.  */
+       err |= __put_user(frame->retcode, &frame->pretcode);
+       /* moveq #,d0; trap #0 */
+       err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
+                         (long __user *)(frame->retcode));
+
+       if (err)
+               goto give_sigsegv;
+
+       push_cache ((unsigned long) &frame->retcode);
+
+       /*
+        * Set up registers for signal handler.  All the state we are about
+        * to destroy is successfully copied to sigframe.
+        */
+       wrusp ((unsigned long) frame);
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+
+       /*
+        * This is subtle; if we build more than one sigframe, all but the
+        * first one will see frame format 0 and have fsize == 0, so we won't
+        * screw stkadj.
+        */
+       if (fsize)
+               regs->stkadj = fsize;
+
+       /* Prepare to skip over the extra stuff in the exception frame.  */
+       if (regs->stkadj) {
+               struct pt_regs *tregs =
+                       (struct pt_regs *)((ulong)regs + regs->stkadj);
+#ifdef DEBUG
+               printk("Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+               /* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+               tregs->vector = 0;
+               tregs->format = 0;
+               tregs->pc = regs->pc;
+               tregs->sr = regs->sr;
+       }
+       return 0;
+
+give_sigsegv:
+       force_sigsegv(sig, current);
+       return err;
+}
+
+static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
+{
+       struct rt_sigframe __user *frame;
+       int fsize = frame_extra_sizes[regs->format];
+       int err = 0;
+
+       if (fsize < 0) {
+#ifdef DEBUG
+               printk ("setup_frame: Unknown frame format %#x\n",
+                       regs->format);
+#endif
+               goto give_sigsegv;
+       }
+
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       if (fsize)
+               err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
+
+       err |= __put_user((current_thread_info()->exec_domain
+                          && current_thread_info()->exec_domain->signal_invmap
+                          && sig < 32
+                          ? current_thread_info()->exec_domain->signal_invmap[sig]
+                          : sig),
+                         &frame->sig);
+       err |= __put_user(&frame->info, &frame->pinfo);
+       err |= __put_user(&frame->uc, &frame->puc);
+       err |= copy_siginfo_to_user(&frame->info, info);
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(NULL, &frame->uc.uc_link);
+       err |= __put_user((void __user *)current->sas_ss_sp,
+                         &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(rdusp()),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= rt_setup_ucontext(&frame->uc, regs);
+       err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       /* Set up to return from userspace.  */
+       err |= __put_user(frame->retcode, &frame->pretcode);
+#ifdef __mcoldfire__
+       /* movel #__NR_rt_sigreturn,d0; trap #0 */
+       err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0));
+       err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16),
+                         (long __user *)(frame->retcode + 4));
+#else
+       /* moveq #,d0; notb d0; trap #0 */
+       err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
+                         (long __user *)(frame->retcode + 0));
+       err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
+#endif
+
+       if (err)
+               goto give_sigsegv;
+
+       push_cache ((unsigned long) &frame->retcode);
+
+       /*
+        * Set up registers for signal handler.  All the state we are about
+        * to destroy is successfully copied to sigframe.
+        */
+       wrusp ((unsigned long) frame);
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+
+       /*
+        * This is subtle; if we build more than one sigframe, all but the
+        * first one will see frame format 0 and have fsize == 0, so we won't
+        * screw stkadj.
+        */
+       if (fsize)
+               regs->stkadj = fsize;
+
+       /* Prepare to skip over the extra stuff in the exception frame.  */
+       if (regs->stkadj) {
+               struct pt_regs *tregs =
+                       (struct pt_regs *)((ulong)regs + regs->stkadj);
+#ifdef DEBUG
+               printk("Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+               /* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+               tregs->vector = 0;
+               tregs->format = 0;
+               tregs->pc = regs->pc;
+               tregs->sr = regs->sr;
+       }
+       return 0;
+
+give_sigsegv:
+       force_sigsegv(sig, current);
+       return err;
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+       switch (regs->d0) {
+       case -ERESTARTNOHAND:
+               if (!has_handler)
+                       goto do_restart;
+               regs->d0 = -EINTR;
+               break;
+
+       case -ERESTART_RESTARTBLOCK:
+               if (!has_handler) {
+                       regs->d0 = __NR_restart_syscall;
+                       regs->pc -= 2;
+                       break;
+               }
+               regs->d0 = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+                       regs->d0 = -EINTR;
+                       break;
+               }
+       /* fallthrough */
+       case -ERESTARTNOINTR:
+       do_restart:
+               regs->d0 = regs->orig_d0;
+               regs->pc -= 2;
+               break;
+       }
+}
+
+void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
+{
+       if (regs->orig_d0 < 0)
+               return;
+       switch (regs->d0) {
+       case -ERESTARTNOHAND:
+       case -ERESTARTSYS:
+       case -ERESTARTNOINTR:
+               regs->d0 = regs->orig_d0;
+               regs->orig_d0 = -1;
+               regs->pc -= 2;
+               break;
+       }
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+             sigset_t *oldset, struct pt_regs *regs)
+{
+       int err;
+       /* are we from a system call? */
+       if (regs->orig_d0 >= 0)
+               /* If so, check system call restarting.. */
+               handle_restart(regs, ka, 1);
+
+       /* set up the stack frame */
+       if (ka->sa.sa_flags & SA_SIGINFO)
+               err = setup_rt_frame(sig, ka, info, oldset, regs);
+       else
+               err = setup_frame(sig, ka, oldset, regs);
+
+       if (err)
+               return;
+
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked,sig);
+       recalc_sigpending();
+
+       if (test_thread_flag(TIF_DELAYED_TRACE)) {
+               regs->sr &= ~0x8000;
+               send_sig(SIGTRAP, current, 1);
+       }
+
+       clear_thread_flag(TIF_RESTORE_SIGMASK);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+asmlinkage void do_signal(struct pt_regs *regs)
+{
+       siginfo_t info;
+       struct k_sigaction ka;
+       int signr;
+       sigset_t *oldset;
+
+       current->thread.esp0 = (unsigned long) regs;
+
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &ka, &info, oldset, regs);
+               return;
+       }
+
+       /* Did we come from a system call? */
+       if (regs->orig_d0 >= 0)
+               /* Restart the system call - no handlers present */
+               handle_restart(regs, NULL, 0);
+
+       /* If there's no signal to deliver, we just restore the saved mask.  */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+}
diff --git a/arch/m68k/kernel/signal_no.c b/arch/m68k/kernel/signal_no.c
new file mode 100644 (file)
index 0000000..36a81bb
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ *  linux/arch/m68knommu/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * 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.
+ */
+
+/*
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ *
+ * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
+ *
+ * mathemu support by Roman Zippel
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
+ *         and the internal floating point format is put on stack)
+ */
+
+/*
+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
+ * signal handlers!
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/highuid.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+void ret_from_user_signal(void);
+void ret_from_user_rt_signal(void);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
+{
+       mask &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+       current->saved_sigmask = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_restore_sigmask();
+
+       return -ERESTARTNOHAND;
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+             struct old_sigaction __user *oact)
+{
+       struct k_sigaction new_ka, old_ka;
+       int ret;
+
+       if (act) {
+               old_sigset_t mask;
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+                   __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+                   __get_user(mask, &act->sa_mask))
+                       return -EFAULT;
+               siginitset(&new_ka.sa.sa_mask, mask);
+       }
+
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+       if (!ret && oact) {
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+                       return -EFAULT;
+       }
+
+       return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
+{
+       return do_sigaltstack(uss, uoss, rdusp());
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
+ */
+
+struct sigframe
+{
+       char __user *pretcode;
+       int sig;
+       int code;
+       struct sigcontext __user *psc;
+       char retcode[8];
+       unsigned long extramask[_NSIG_WORDS-1];
+       struct sigcontext sc;
+};
+
+struct rt_sigframe
+{
+       char __user *pretcode;
+       int sig;
+       struct siginfo __user *pinfo;
+       void __user *puc;
+       char retcode[8];
+       struct siginfo info;
+       struct ucontext uc;
+};
+
+#ifdef CONFIG_FPU
+
+static unsigned char fpu_version = 0;  /* version number of fpu, set by setup_frame */
+
+static inline int restore_fpu_state(struct sigcontext *sc)
+{
+       int err = 1;
+
+       if (FPU_IS_EMU) {
+           /* restore registers */
+           memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
+           memcpy(current->thread.fp, sc->sc_fpregs, 24);
+           return 0;
+       }
+
+       if (sc->sc_fpstate[0]) {
+           /* Verify the frame format.  */
+           if (sc->sc_fpstate[0] != fpu_version)
+               goto out;
+
+           __asm__ volatile (".chip 68k/68881\n\t"
+                             "fmovemx %0,%%fp0-%%fp1\n\t"
+                             "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
+                             ".chip 68k"
+                             : /* no outputs */
+                             : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
+       }
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "frestore %0\n\t"
+                         ".chip 68k" : : "m" (*sc->sc_fpstate));
+       err = 0;
+
+out:
+       return err;
+}
+
+#define FPCONTEXT_SIZE 216
+#define uc_fpstate     uc_filler[0]
+#define uc_formatvec   uc_filler[FPCONTEXT_SIZE/4]
+#define uc_extra       uc_filler[FPCONTEXT_SIZE/4+1]
+
+static inline int rt_restore_fpu_state(struct ucontext __user *uc)
+{
+       unsigned char fpstate[FPCONTEXT_SIZE];
+       int context_size = 0;
+       fpregset_t fpregs;
+       int err = 1;
+
+       if (FPU_IS_EMU) {
+               /* restore fpu control register */
+               if (__copy_from_user(current->thread.fpcntl,
+                               uc->uc_mcontext.fpregs.f_fpcntl, 12))
+                       goto out;
+               /* restore all other fpu register */
+               if (__copy_from_user(current->thread.fp,
+                               uc->uc_mcontext.fpregs.f_fpregs, 96))
+                       goto out;
+               return 0;
+       }
+
+       if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
+               goto out;
+       if (fpstate[0]) {
+               context_size = fpstate[1];
+
+               /* Verify the frame format.  */
+               if (fpstate[0] != fpu_version)
+                       goto out;
+               if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
+                    sizeof(fpregs)))
+                       goto out;
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %0,%%fp0-%%fp7\n\t"
+                                 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
+                                 ".chip 68k"
+                                 : /* no outputs */
+                                 : "m" (*fpregs.f_fpregs),
+                                   "m" (*fpregs.f_fpcntl));
+       }
+       if (context_size &&
+           __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
+                            context_size))
+               goto out;
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "frestore %0\n\t"
+                         ".chip 68k" : : "m" (*fpstate));
+       err = 0;
+
+out:
+       return err;
+}
+
+#endif
+
+static inline int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
+                  int *pd0)
+{
+       int formatvec;
+       struct sigcontext context;
+       int err = 0;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       /* get previous context */
+       if (copy_from_user(&context, usc, sizeof(context)))
+               goto badframe;
+       
+       /* restore passed registers */
+       regs->d1 = context.sc_d1;
+       regs->a0 = context.sc_a0;
+       regs->a1 = context.sc_a1;
+       ((struct switch_stack *)regs - 1)->a5 = context.sc_a5;
+       regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
+       regs->pc = context.sc_pc;
+       regs->orig_d0 = -1;             /* disable syscall checks */
+       wrusp(context.sc_usp);
+       formatvec = context.sc_formatvec;
+       regs->format = formatvec >> 12;
+       regs->vector = formatvec & 0xfff;
+
+#ifdef CONFIG_FPU
+       err = restore_fpu_state(&context);
+#endif
+
+       *pd0 = context.sc_d0;
+       return err;
+
+badframe:
+       return 1;
+}
+
+static inline int
+rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
+                   struct ucontext __user *uc, int *pd0)
+{
+       int temp;
+       greg_t __user *gregs = uc->uc_mcontext.gregs;
+       unsigned long usp;
+       int err;
+
+       /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       err = __get_user(temp, &uc->uc_mcontext.version);
+       if (temp != MCONTEXT_VERSION)
+               goto badframe;
+       /* restore passed registers */
+       err |= __get_user(regs->d0, &gregs[0]);
+       err |= __get_user(regs->d1, &gregs[1]);
+       err |= __get_user(regs->d2, &gregs[2]);
+       err |= __get_user(regs->d3, &gregs[3]);
+       err |= __get_user(regs->d4, &gregs[4]);
+       err |= __get_user(regs->d5, &gregs[5]);
+       err |= __get_user(sw->d6, &gregs[6]);
+       err |= __get_user(sw->d7, &gregs[7]);
+       err |= __get_user(regs->a0, &gregs[8]);
+       err |= __get_user(regs->a1, &gregs[9]);
+       err |= __get_user(regs->a2, &gregs[10]);
+       err |= __get_user(sw->a3, &gregs[11]);
+       err |= __get_user(sw->a4, &gregs[12]);
+       err |= __get_user(sw->a5, &gregs[13]);
+       err |= __get_user(sw->a6, &gregs[14]);
+       err |= __get_user(usp, &gregs[15]);
+       wrusp(usp);
+       err |= __get_user(regs->pc, &gregs[16]);
+       err |= __get_user(temp, &gregs[17]);
+       regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
+       regs->orig_d0 = -1;             /* disable syscall checks */
+       regs->format = temp >> 12;
+       regs->vector = temp & 0xfff;
+
+       if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+               goto badframe;
+
+       *pd0 = regs->d0;
+       return err;
+
+badframe:
+       return 1;
+}
+
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+       struct switch_stack *sw = (struct switch_stack *) &__unused;
+       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+       unsigned long usp = rdusp();
+       struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
+       sigset_t set;
+       int d0;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
+           (_NSIG_WORDS > 1 &&
+            __copy_from_user(&set.sig[1], &frame->extramask,
+                             sizeof(frame->extramask))))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+       
+       if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
+               goto badframe;
+       return d0;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+       struct switch_stack *sw = (struct switch_stack *) &__unused;
+       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+       unsigned long usp = rdusp();
+       struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
+       sigset_t set;
+       int d0;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+       
+       if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
+               goto badframe;
+       return d0;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+#ifdef CONFIG_FPU
+/*
+ * Set up a signal frame.
+ */
+
+static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
+{
+       if (FPU_IS_EMU) {
+               /* save registers */
+               memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
+               memcpy(sc->sc_fpregs, current->thread.fp, 24);
+               return;
+       }
+
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "fsave %0\n\t"
+                         ".chip 68k"
+                         : : "m" (*sc->sc_fpstate) : "memory");
+
+       if (sc->sc_fpstate[0]) {
+               fpu_version = sc->sc_fpstate[0];
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %%fp0-%%fp1,%0\n\t"
+                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
+                                 ".chip 68k"
+                                 : "=m" (*sc->sc_fpregs),
+                                   "=m" (*sc->sc_fpcntl)
+                                 : /* no inputs */
+                                 : "memory");
+       }
+}
+
+static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
+{
+       unsigned char fpstate[FPCONTEXT_SIZE];
+       int context_size = 0;
+       int err = 0;
+
+       if (FPU_IS_EMU) {
+               /* save fpu control register */
+               err |= copy_to_user(uc->uc_mcontext.fpregs.f_pcntl,
+                               current->thread.fpcntl, 12);
+               /* save all other fpu register */
+               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
+                               current->thread.fp, 96);
+               return err;
+       }
+
+       __asm__ volatile (".chip 68k/68881\n\t"
+                         "fsave %0\n\t"
+                         ".chip 68k"
+                         : : "m" (*fpstate) : "memory");
+
+       err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
+       if (fpstate[0]) {
+               fpregset_t fpregs;
+               context_size = fpstate[1];
+               fpu_version = fpstate[0];
+               __asm__ volatile (".chip 68k/68881\n\t"
+                                 "fmovemx %%fp0-%%fp7,%0\n\t"
+                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
+                                 ".chip 68k"
+                                 : "=m" (*fpregs.f_fpregs),
+                                   "=m" (*fpregs.f_fpcntl)
+                                 : /* no inputs */
+                                 : "memory");
+               err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
+                                   sizeof(fpregs));
+       }
+       if (context_size)
+               err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
+                                   context_size);
+       return err;
+}
+
+#endif
+
+static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+                            unsigned long mask)
+{
+       sc->sc_mask = mask;
+       sc->sc_usp = rdusp();
+       sc->sc_d0 = regs->d0;
+       sc->sc_d1 = regs->d1;
+       sc->sc_a0 = regs->a0;
+       sc->sc_a1 = regs->a1;
+       sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
+       sc->sc_sr = regs->sr;
+       sc->sc_pc = regs->pc;
+       sc->sc_formatvec = regs->format << 12 | regs->vector;
+#ifdef CONFIG_FPU
+       save_fpu_state(sc, regs);
+#endif
+}
+
+static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
+{
+       struct switch_stack *sw = (struct switch_stack *)regs - 1;
+       greg_t __user *gregs = uc->uc_mcontext.gregs;
+       int err = 0;
+
+       err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+       err |= __put_user(regs->d0, &gregs[0]);
+       err |= __put_user(regs->d1, &gregs[1]);
+       err |= __put_user(regs->d2, &gregs[2]);
+       err |= __put_user(regs->d3, &gregs[3]);
+       err |= __put_user(regs->d4, &gregs[4]);
+       err |= __put_user(regs->d5, &gregs[5]);
+       err |= __put_user(sw->d6, &gregs[6]);
+       err |= __put_user(sw->d7, &gregs[7]);
+       err |= __put_user(regs->a0, &gregs[8]);
+       err |= __put_user(regs->a1, &gregs[9]);
+       err |= __put_user(regs->a2, &gregs[10]);
+       err |= __put_user(sw->a3, &gregs[11]);
+       err |= __put_user(sw->a4, &gregs[12]);
+       err |= __put_user(sw->a5, &gregs[13]);
+       err |= __put_user(sw->a6, &gregs[14]);
+       err |= __put_user(rdusp(), &gregs[15]);
+       err |= __put_user(regs->pc, &gregs[16]);
+       err |= __put_user(regs->sr, &gregs[17]);
+#ifdef CONFIG_FPU
+       err |= rt_save_fpu_state(uc, regs);
+#endif
+       return err;
+}
+
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+       unsigned long usp;
+
+       /* Default to using normal stack.  */
+       usp = rdusp();
+
+       /* This is the X/Open sanctioned signal stack switching.  */
+       if (ka->sa.sa_flags & SA_ONSTACK) {
+               if (!sas_ss_flags(usp))
+                       usp = current->sas_ss_sp + current->sas_ss_size;
+       }
+       return (void __user *)((usp - frame_size) & -8UL);
+}
+
+static int setup_frame (int sig, struct k_sigaction *ka,
+                        sigset_t *set, struct pt_regs *regs)
+{
+       struct sigframe __user *frame;
+       struct sigcontext context;
+       int err = 0;
+
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       err |= __put_user((current_thread_info()->exec_domain
+                          && current_thread_info()->exec_domain->signal_invmap
+                          && sig < 32
+                          ? current_thread_info()->exec_domain->signal_invmap[sig]
+                          : sig),
+                         &frame->sig);
+
+       err |= __put_user(regs->vector, &frame->code);
+       err |= __put_user(&frame->sc, &frame->psc);
+
+       if (_NSIG_WORDS > 1)
+               err |= copy_to_user(frame->extramask, &set->sig[1],
+                                   sizeof(frame->extramask));
+
+       setup_sigcontext(&context, regs, set->sig[0]);
+       err |= copy_to_user (&frame->sc, &context, sizeof(context));
+
+       /* Set up to return from userspace.  */
+       err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
+
+       if (err)
+               goto give_sigsegv;
+
+       /* Set up registers for signal handler */
+       wrusp ((unsigned long) frame);
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
+       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
+                                               which it will be when doing the rte */
+
+adjust_stack:
+       /* Prepare to skip over the extra stuff in the exception frame.  */
+       if (regs->stkadj) {
+               struct pt_regs *tregs =
+                       (struct pt_regs *)((ulong)regs + regs->stkadj);
+#if defined(DEBUG)
+               printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+               /* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+               tregs->vector = 0;
+               tregs->format = 0;
+               tregs->pc = regs->pc;
+               tregs->sr = regs->sr;
+       }
+       return err;
+
+give_sigsegv:
+       force_sigsegv(sig, current);
+       goto adjust_stack;
+}
+
+static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
+{
+       struct rt_sigframe __user *frame;
+       int err = 0;
+
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       err |= __put_user((current_thread_info()->exec_domain
+                          && current_thread_info()->exec_domain->signal_invmap
+                          && sig < 32
+                          ? current_thread_info()->exec_domain->signal_invmap[sig]
+                          : sig),
+                         &frame->sig);
+       err |= __put_user(&frame->info, &frame->pinfo);
+       err |= __put_user(&frame->uc, &frame->puc);
+       err |= copy_siginfo_to_user(&frame->info, info);
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(NULL, &frame->uc.uc_link);
+       err |= __put_user((void __user *)current->sas_ss_sp,
+                         &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(rdusp()),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= rt_setup_ucontext(&frame->uc, regs);
+       err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       /* Set up to return from userspace.  */
+       err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
+
+       if (err)
+               goto give_sigsegv;
+
+       /* Set up registers for signal handler */
+       wrusp ((unsigned long) frame);
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
+       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
+                                               which it will be when doing the rte */
+
+adjust_stack:
+       /* Prepare to skip over the extra stuff in the exception frame.  */
+       if (regs->stkadj) {
+               struct pt_regs *tregs =
+                       (struct pt_regs *)((ulong)regs + regs->stkadj);
+#if defined(DEBUG)
+               printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+               /* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+               tregs->vector = 0;
+               tregs->format = 0;
+               tregs->pc = regs->pc;
+               tregs->sr = regs->sr;
+       }
+       return err;
+
+give_sigsegv:
+       force_sigsegv(sig, current);
+       goto adjust_stack;
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+       switch (regs->d0) {
+       case -ERESTARTNOHAND:
+               if (!has_handler)
+                       goto do_restart;
+               regs->d0 = -EINTR;
+               break;
+
+       case -ERESTART_RESTARTBLOCK:
+               if (!has_handler) {
+                       regs->d0 = __NR_restart_syscall;
+                       regs->pc -= 2;
+                       break;
+               }
+               regs->d0 = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+                       regs->d0 = -EINTR;
+                       break;
+               }
+       /* fallthrough */
+       case -ERESTARTNOINTR:
+       do_restart:
+               regs->d0 = regs->orig_d0;
+               regs->pc -= 2;
+               break;
+       }
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+             sigset_t *oldset, struct pt_regs *regs)
+{
+       int err;
+       /* are we from a system call? */
+       if (regs->orig_d0 >= 0)
+               /* If so, check system call restarting.. */
+               handle_restart(regs, ka, 1);
+
+       /* set up the stack frame */
+       if (ka->sa.sa_flags & SA_SIGINFO)
+               err = setup_rt_frame(sig, ka, info, oldset, regs);
+       else
+               err = setup_frame(sig, ka, oldset, regs);
+
+       if (err)
+               return;
+
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked,sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       clear_thread_flag(TIF_RESTORE_SIGMASK);
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+asmlinkage void do_signal(struct pt_regs *regs)
+{
+       struct k_sigaction ka;
+       siginfo_t info;
+       int signr;
+       sigset_t *oldset;
+
+       /*
+        * We want the common case to go fast, which
+        * is why we may in certain cases get here from
+        * kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return;
+
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &ka, &info, oldset, regs);
+               return;
+       }
+
+       /* Did we come from a system call? */
+       if (regs->orig_d0 >= 0) {
+               /* Restart the system call - no handlers present */
+               handle_restart(regs, NULL, 0);
+       }
+
+       /* If there's no signal to deliver, we just restore the saved mask.  */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+}
index 3db2e7f902aae8edb79209df2352800112f26028..63013df33584d79a8047f623d7f93814b1a31626 100644 (file)
@@ -1,546 +1,5 @@
-/*
- * linux/arch/m68k/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <linux/elf.h>
-#include <asm/tlb.h>
-
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-                            unsigned long error_code);
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       /*
-        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
-        * so we need to shift the argument down by 1; m68k mmap64(3)
-        * (in libc) expects the last argument of mmap2 in 4Kb units.
-        */
-       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
-}
-
-/* Convert virtual (user) address VADDR to physical address PADDR */
-#define virt_to_phys_040(vaddr)                                                \
-({                                                                     \
-  unsigned long _mmusr, _paddr;                                                \
-                                                                       \
-  __asm__ __volatile__ (".chip 68040\n\t"                              \
-                       "ptestr (%1)\n\t"                               \
-                       "movec %%mmusr,%0\n\t"                          \
-                       ".chip 68k"                                     \
-                       : "=r" (_mmusr)                                 \
-                       : "a" (vaddr));                                 \
-  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
-  _paddr;                                                              \
-})
-
-static inline int
-cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         /* This nop is needed for some broken versions of the 68040.  */
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      if ((paddr = virt_to_phys_040(addr))) {
-        paddr += addr & ~(PAGE_MASK | 15);
-        len = (len + (addr & 15) + 15) >> 4;
-      } else {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_040(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-       len = (len + 15) >> 4;
-      }
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-             /*
-              * No need to page align here since it is done by
-              * virt_to_phys_040().
-              */
-             addr += PAGE_SIZE;
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_040(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_040(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-#define virt_to_phys_060(vaddr)                                \
-({                                                     \
-  unsigned long paddr;                                 \
-  __asm__ __volatile__ (".chip 68060\n\t"              \
-                       "plpar (%0)\n\t"                \
-                       ".chip 68k"                     \
-                       : "=a" (paddr)                  \
-                       : "0" (vaddr));                 \
-  (paddr); /* XXX */                                   \
-})
-
-static inline int
-cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  /*
-   * 68060 manual says:
-   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
-   *  cpush %ic : invalidate IC
-   *  cpush %bc : flush DC + invalidate IC
-   */
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      len += addr & 15;
-      addr &= -16;
-      if (!(paddr = virt_to_phys_060(addr))) {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_060(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-      }
-      len = (len + 15) >> 4;
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-
-             /*
-              * We just want to jump to the first cache line
-              * in the next page.
-              */
-             addr += PAGE_SIZE;
-             addr &= PAGE_MASK;
-
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_060(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      addr &= PAGE_MASK;       /* Workaround for bug in some
-                                  revisions of the 68060 */
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_060(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       struct vm_area_struct *vma;
-       int ret = -EINVAL;
-
-       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
-           cache & ~FLUSH_CACHE_BOTH)
-               goto out;
-
-       if (scope == FLUSH_SCOPE_ALL) {
-               /* Only the superuser may explicitly flush the whole cache. */
-               ret = -EPERM;
-               if (!capable(CAP_SYS_ADMIN))
-                       goto out;
-       } else {
-               /*
-                * Verify that the specified address region actually belongs
-                * to this process.
-                */
-               vma = find_vma (current->mm, addr);
-               ret = -EINVAL;
-               /* Check for overflow.  */
-               if (addr + len < addr)
-                       goto out;
-               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
-                       goto out;
-       }
-
-       if (CPU_IS_020_OR_030) {
-               if (scope == FLUSH_SCOPE_LINE && len < 256) {
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 4;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x400;
-                       len >>= 2;
-                       while (len--) {
-                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
-                                                     "movec %0, %%cacr"
-                                                     : /* no outputs */
-                                                     : "r" (cacr), "r" (addr));
-                               addr += 4;
-                       }
-               } else {
-                       /* Flush the whole cache, even if page granularity requested. */
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 8;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x800;
-                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
-               }
-               ret = 0;
-               goto out;
-       } else {
-           /*
-            * 040 or 060: don't blindly trust 'scope', someone could
-            * try to flush a few megs of memory.
-            */
-
-           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
-               scope=FLUSH_SCOPE_PAGE;
-           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
-               scope=FLUSH_SCOPE_ALL;
-           if (CPU_IS_040) {
-               ret = cache_flush_040 (addr, scope, cache, len);
-           } else if (CPU_IS_060) {
-               ret = cache_flush_060 (addr, scope, cache, len);
-           }
-       }
-out:
-       return ret;
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       /* This was borrowed from ARM's implementation.  */
-       for (;;) {
-               struct mm_struct *mm = current->mm;
-               pgd_t *pgd;
-               pmd_t *pmd;
-               pte_t *pte;
-               spinlock_t *ptl;
-               unsigned long mem_value;
-
-               down_read(&mm->mmap_sem);
-               pgd = pgd_offset(mm, (unsigned long)mem);
-               if (!pgd_present(*pgd))
-                       goto bad_access;
-               pmd = pmd_offset(pgd, (unsigned long)mem);
-               if (!pmd_present(*pmd))
-                       goto bad_access;
-               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
-               if (!pte_present(*pte) || !pte_dirty(*pte)
-                   || !pte_write(*pte)) {
-                       pte_unmap_unlock(pte, ptl);
-                       goto bad_access;
-               }
-
-               mem_value = *mem;
-               if (mem_value == oldval)
-                       *mem = newval;
-
-               pte_unmap_unlock(pte, ptl);
-               up_read(&mm->mmap_sem);
-               return mem_value;
-
-             bad_access:
-               up_read(&mm->mmap_sem);
-               /* This is not necessarily a bad access, we can get here if
-                  a memory we're trying to write to should be copied-on-write.
-                  Make the kernel do the necessary page stuff, then re-iterate.
-                  Simulate a write access fault to do that.  */
-               {
-                       /* The first argument of the function corresponds to
-                          D1, which is the first field of struct pt_regs.  */
-                       struct pt_regs *fp = (struct pt_regs *)&newval;
-
-                       /* '3' is an RMW flag.  */
-                       if (do_page_fault(fp, (unsigned long)mem, 3))
-                               /* If the do_page_fault() failed, we don't
-                                  have anything meaningful to return.
-                                  There should be a SIGSEGV pending for
-                                  the process.  */
-                               return 0xdeadbeef;
-               }
-       }
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
+#ifdef CONFIG_MMU
+#include "sys_m68k_mm.c"
+#else
+#include "sys_m68k_no.c"
+#endif
diff --git a/arch/m68k/kernel/sys_m68k_mm.c b/arch/m68k/kernel/sys_m68k_mm.c
new file mode 100644 (file)
index 0000000..3db2e7f
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * linux/arch/m68k/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <linux/elf.h>
+#include <asm/tlb.h>
+
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+                            unsigned long error_code);
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags,
+       unsigned long fd, unsigned long pgoff)
+{
+       /*
+        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
+        * so we need to shift the argument down by 1; m68k mmap64(3)
+        * (in libc) expects the last argument of mmap2 in 4Kb units.
+        */
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
+}
+
+/* Convert virtual (user) address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr)                                                \
+({                                                                     \
+  unsigned long _mmusr, _paddr;                                                \
+                                                                       \
+  __asm__ __volatile__ (".chip 68040\n\t"                              \
+                       "ptestr (%1)\n\t"                               \
+                       "movec %%mmusr,%0\n\t"                          \
+                       ".chip 68k"                                     \
+                       : "=r" (_mmusr)                                 \
+                       : "a" (vaddr));                                 \
+  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
+  _paddr;                                                              \
+})
+
+static inline int
+cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         /* This nop is needed for some broken versions of the 68040.  */
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      if ((paddr = virt_to_phys_040(addr))) {
+        paddr += addr & ~(PAGE_MASK | 15);
+        len = (len + (addr & 15) + 15) >> 4;
+      } else {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_040(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+       len = (len + 15) >> 4;
+      }
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+             /*
+              * No need to page align here since it is done by
+              * virt_to_phys_040().
+              */
+             addr += PAGE_SIZE;
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_040(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_040(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+#define virt_to_phys_060(vaddr)                                \
+({                                                     \
+  unsigned long paddr;                                 \
+  __asm__ __volatile__ (".chip 68060\n\t"              \
+                       "plpar (%0)\n\t"                \
+                       ".chip 68k"                     \
+                       : "=a" (paddr)                  \
+                       : "0" (vaddr));                 \
+  (paddr); /* XXX */                                   \
+})
+
+static inline int
+cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  /*
+   * 68060 manual says:
+   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
+   *  cpush %ic : invalidate IC
+   *  cpush %bc : flush DC + invalidate IC
+   */
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      len += addr & 15;
+      addr &= -16;
+      if (!(paddr = virt_to_phys_060(addr))) {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_060(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+      }
+      len = (len + 15) >> 4;
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+
+             /*
+              * We just want to jump to the first cache line
+              * in the next page.
+              */
+             addr += PAGE_SIZE;
+             addr &= PAGE_MASK;
+
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_060(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      addr &= PAGE_MASK;       /* Workaround for bug in some
+                                  revisions of the 68060 */
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_060(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       struct vm_area_struct *vma;
+       int ret = -EINVAL;
+
+       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
+           cache & ~FLUSH_CACHE_BOTH)
+               goto out;
+
+       if (scope == FLUSH_SCOPE_ALL) {
+               /* Only the superuser may explicitly flush the whole cache. */
+               ret = -EPERM;
+               if (!capable(CAP_SYS_ADMIN))
+                       goto out;
+       } else {
+               /*
+                * Verify that the specified address region actually belongs
+                * to this process.
+                */
+               vma = find_vma (current->mm, addr);
+               ret = -EINVAL;
+               /* Check for overflow.  */
+               if (addr + len < addr)
+                       goto out;
+               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+                       goto out;
+       }
+
+       if (CPU_IS_020_OR_030) {
+               if (scope == FLUSH_SCOPE_LINE && len < 256) {
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 4;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x400;
+                       len >>= 2;
+                       while (len--) {
+                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
+                                                     "movec %0, %%cacr"
+                                                     : /* no outputs */
+                                                     : "r" (cacr), "r" (addr));
+                               addr += 4;
+                       }
+               } else {
+                       /* Flush the whole cache, even if page granularity requested. */
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 8;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x800;
+                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
+               }
+               ret = 0;
+               goto out;
+       } else {
+           /*
+            * 040 or 060: don't blindly trust 'scope', someone could
+            * try to flush a few megs of memory.
+            */
+
+           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
+               scope=FLUSH_SCOPE_PAGE;
+           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
+               scope=FLUSH_SCOPE_ALL;
+           if (CPU_IS_040) {
+               ret = cache_flush_040 (addr, scope, cache, len);
+           } else if (CPU_IS_060) {
+               ret = cache_flush_060 (addr, scope, cache, len);
+           }
+       }
+out:
+       return ret;
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+       return PAGE_SIZE;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename,
+                 const char *const argv[],
+                 const char *const envp[])
+{
+       register long __res asm ("%d0") = __NR_execve;
+       register long __a asm ("%d1") = (long)(filename);
+       register long __b asm ("%d2") = (long)(argv);
+       register long __c asm ("%d3") = (long)(envp);
+       asm volatile ("trap  #0" : "+d" (__res)
+                       : "d" (__a), "d" (__b), "d" (__c));
+       return __res;
+}
+
+asmlinkage unsigned long sys_get_thread_area(void)
+{
+       return current_thread_info()->tp_value;
+}
+
+asmlinkage int sys_set_thread_area(unsigned long tp)
+{
+       current_thread_info()->tp_value = tp;
+       return 0;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       /* This was borrowed from ARM's implementation.  */
+       for (;;) {
+               struct mm_struct *mm = current->mm;
+               pgd_t *pgd;
+               pmd_t *pmd;
+               pte_t *pte;
+               spinlock_t *ptl;
+               unsigned long mem_value;
+
+               down_read(&mm->mmap_sem);
+               pgd = pgd_offset(mm, (unsigned long)mem);
+               if (!pgd_present(*pgd))
+                       goto bad_access;
+               pmd = pmd_offset(pgd, (unsigned long)mem);
+               if (!pmd_present(*pmd))
+                       goto bad_access;
+               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
+               if (!pte_present(*pte) || !pte_dirty(*pte)
+                   || !pte_write(*pte)) {
+                       pte_unmap_unlock(pte, ptl);
+                       goto bad_access;
+               }
+
+               mem_value = *mem;
+               if (mem_value == oldval)
+                       *mem = newval;
+
+               pte_unmap_unlock(pte, ptl);
+               up_read(&mm->mmap_sem);
+               return mem_value;
+
+             bad_access:
+               up_read(&mm->mmap_sem);
+               /* This is not necessarily a bad access, we can get here if
+                  a memory we're trying to write to should be copied-on-write.
+                  Make the kernel do the necessary page stuff, then re-iterate.
+                  Simulate a write access fault to do that.  */
+               {
+                       /* The first argument of the function corresponds to
+                          D1, which is the first field of struct pt_regs.  */
+                       struct pt_regs *fp = (struct pt_regs *)&newval;
+
+                       /* '3' is an RMW flag.  */
+                       if (do_page_fault(fp, (unsigned long)mem, 3))
+                               /* If the do_page_fault() failed, we don't
+                                  have anything meaningful to return.
+                                  There should be a SIGSEGV pending for
+                                  the process.  */
+                               return 0xdeadbeef;
+               }
+       }
+}
+
+asmlinkage int sys_atomic_barrier(void)
+{
+       /* no code needed for uniprocs */
+       return 0;
+}
diff --git a/arch/m68k/kernel/sys_m68k_no.c b/arch/m68k/kernel/sys_m68k_no.c
new file mode 100644 (file)
index 0000000..68488ae
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * linux/arch/m68knommu/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+#include <linux/fs.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
+#include <asm/unistd.h>
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       flush_cache_all();
+       return(0);
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+       return PAGE_SIZE;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename,
+                 const char *const argv[],
+                 const char *const envp[])
+{
+       register long __res asm ("%d0") = __NR_execve;
+       register long __a asm ("%d1") = (long)(filename);
+       register long __b asm ("%d2") = (long)(argv);
+       register long __c asm ("%d3") = (long)(envp);
+       asm volatile ("trap  #0" : "+d" (__res)
+                       : "d" (__a), "d" (__b), "d" (__c));
+       return __res;
+}
+
+asmlinkage unsigned long sys_get_thread_area(void)
+{
+       return current_thread_info()->tp_value;
+}
+
+asmlinkage int sys_set_thread_area(unsigned long tp)
+{
+       current_thread_info()->tp_value = tp;
+       return 0;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long mem_value;
+
+       down_read(&mm->mmap_sem);
+
+       mem_value = *mem;
+       if (mem_value == oldval)
+               *mem = newval;
+
+       up_read(&mm->mmap_sem);
+       return mem_value;
+}
+
+asmlinkage int sys_atomic_barrier(void)
+{
+       /* no code needed for uniprocs */
+       return 0;
+}
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
new file mode 100644 (file)
index 0000000..79b1ed1
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *  linux/arch/m68knommu/kernel/syscalltable.S
+ *
+ *  Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ *  Based on older entry.S files, the following copyrights apply:
+ *
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+.text
+ALIGN
+ENTRY(sys_call_table)
+       .long sys_restart_syscall       /* 0  -  old "setup()" system call */
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open          /* 5 */
+       .long sys_close
+       .long sys_waitpid
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink        /* 10 */
+       .long sys_execve
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod         /* 15 */
+       .long sys_chown16
+       .long sys_ni_syscall    /* old break syscall holder */
+       .long sys_stat
+       .long sys_lseek
+       .long sys_getpid        /* 20 */
+       .long sys_mount
+       .long sys_oldumount
+       .long sys_setuid16
+       .long sys_getuid16
+       .long sys_stime         /* 25 */
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_fstat
+       .long sys_pause
+       .long sys_utime         /* 30 */
+       .long sys_ni_syscall    /* old stty syscall holder */
+       .long sys_ni_syscall    /* old gtty syscall holder */
+       .long sys_access
+       .long sys_nice
+       .long sys_ni_syscall    /* 35 */ /* old ftime syscall holder */
+       .long sys_sync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir         /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_ni_syscall    /* old prof syscall holder */
+       .long sys_brk           /* 45 */
+       .long sys_setgid16
+       .long sys_getgid16
+       .long sys_signal
+       .long sys_geteuid16
+       .long sys_getegid16     /* 50 */
+       .long sys_acct
+       .long sys_umount        /* recycled never used phys() */
+       .long sys_ni_syscall    /* old lock syscall holder */
+       .long sys_ioctl
+       .long sys_fcntl         /* 55 */
+       .long sys_ni_syscall    /* old mpx syscall holder */
+       .long sys_setpgid
+       .long sys_ni_syscall    /* old ulimit syscall holder */
+       .long sys_ni_syscall
+       .long sys_umask         /* 60 */
+       .long sys_chroot
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp       /* 65 */
+       .long sys_setsid
+       .long sys_sigaction
+       .long sys_sgetmask
+       .long sys_ssetmask
+       .long sys_setreuid16    /* 70 */
+       .long sys_setregid16
+       .long sys_sigsuspend
+       .long sys_sigpending
+       .long sys_sethostname
+       .long sys_setrlimit     /* 75 */
+       .long sys_old_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups16   /* 80 */
+       .long sys_setgroups16
+       .long sys_old_select
+       .long sys_symlink
+       .long sys_lstat
+       .long sys_readlink      /* 85 */
+       .long sys_uselib
+       .long sys_ni_syscall    /* sys_swapon */
+       .long sys_reboot
+       .long sys_old_readdir
+       .long sys_old_mmap      /* 90 */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown16      /* 95 */
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_ni_syscall    /* old profil syscall holder */
+       .long sys_statfs
+       .long sys_fstatfs       /* 100 */
+       .long sys_ni_syscall    /* ioperm for i386 */
+       .long sys_socketcall
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer     /* 105 */
+       .long sys_newstat
+       .long sys_newlstat
+       .long sys_newfstat
+       .long sys_ni_syscall
+       .long sys_ni_syscall    /* iopl for i386 */ /* 110 */
+       .long sys_vhangup
+       .long sys_ni_syscall    /* obsolete idle() syscall */
+       .long sys_ni_syscall    /* vm86old for i386 */
+       .long sys_wait4
+       .long sys_ni_syscall    /* 115 */ /* sys_swapoff */
+       .long sys_sysinfo
+       .long sys_ipc
+       .long sys_fsync
+       .long sys_sigreturn
+       .long sys_clone         /* 120 */
+       .long sys_setdomainname
+       .long sys_newuname
+       .long sys_cacheflush    /* modify_ldt for i386 */
+       .long sys_adjtimex
+       .long sys_ni_syscall    /* 125 */ /* sys_mprotect */
+       .long sys_sigprocmask
+       .long sys_ni_syscall    /* old "creat_module" */
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_fchdir
+       .long sys_bdflush
+       .long sys_sysfs         /* 135 */
+       .long sys_personality
+       .long sys_ni_syscall    /* for afs_syscall */
+       .long sys_setfsuid16
+       .long sys_setfsgid16
+       .long sys_llseek        /* 140 */
+       .long sys_getdents
+       .long sys_select
+       .long sys_flock
+       .long sys_ni_syscall    /* sys_msync */
+       .long sys_readv         /* 145 */
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl
+       .long sys_ni_syscall    /* 150 */ /* sys_mlock */
+       .long sys_ni_syscall    /* sys_munlock */
+       .long sys_ni_syscall    /* sys_mlockall */
+       .long sys_ni_syscall    /* sys_munlockall */
+       .long sys_sched_setparam
+       .long sys_sched_getparam /* 155 */
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max
+       .long sys_sched_get_priority_min  /* 160 */
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_ni_syscall    /* sys_mremap */
+       .long sys_setresuid16
+       .long sys_getresuid16   /* 165 */
+       .long sys_getpagesize   /* sys_getpagesize */
+       .long sys_ni_syscall    /* old "query_module" */
+       .long sys_poll
+       .long sys_ni_syscall    /* sys_nfsservctl */
+       .long sys_setresgid16   /* 170 */
+       .long sys_getresgid16
+       .long sys_prctl
+       .long sys_rt_sigreturn
+       .long sys_rt_sigaction
+       .long sys_rt_sigprocmask /* 175 */
+       .long sys_rt_sigpending
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long sys_rt_sigsuspend
+       .long sys_pread64       /* 180 */
+       .long sys_pwrite64
+       .long sys_lchown16
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset        /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall    /* streams1 */
+       .long sys_ni_syscall    /* streams2 */
+       .long sys_vfork         /* 190 */
+       .long sys_getrlimit
+       .long sys_mmap_pgoff
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64        /* 195 */
+       .long sys_lstat64
+       .long sys_fstat64
+       .long sys_chown
+       .long sys_getuid
+       .long sys_getgid        /* 200 */
+       .long sys_geteuid
+       .long sys_getegid
+       .long sys_setreuid
+       .long sys_setregid
+       .long sys_getgroups     /* 205 */
+       .long sys_setgroups
+       .long sys_fchown
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setresgid     /* 210 */
+       .long sys_getresgid
+       .long sys_lchown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid      /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_ni_syscall
+       .long sys_ni_syscall
+       .long sys_getdents64    /* 220 */
+       .long sys_gettid
+       .long sys_tkill
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr     /* 225 */
+       .long sys_getxattr
+       .long sys_lgetxattr
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr    /* 230 */
+       .long sys_flistxattr
+       .long sys_removexattr
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_futex         /* 235 */
+       .long sys_sendfile64
+       .long sys_ni_syscall    /* sys_mincore */
+       .long sys_ni_syscall    /* sys_madvise */
+       .long sys_fcntl64
+       .long sys_readahead     /* 240 */
+       .long sys_io_setup
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel     /* 245 */
+       .long sys_fadvise64
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 250 */
+       .long sys_epoll_wait
+       .long sys_ni_syscall    /* sys_remap_file_pages */
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime /* 255 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime /* 260 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill        /* 265 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_mbind 
+       .long sys_get_mempolicy
+       .long sys_set_mempolicy /* 270 */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive
+       .long sys_mq_notify     /* 275 */
+       .long sys_mq_getsetattr
+       .long sys_waitid
+       .long sys_ni_syscall    /* for sys_vserver */
+       .long sys_add_key
+       .long sys_request_key   /* 280 */
+       .long sys_keyctl
+       .long sys_ioprio_set
+       .long sys_ioprio_get
+       .long sys_inotify_init
+       .long sys_inotify_add_watch     /* 285 */
+       .long sys_inotify_rm_watch
+       .long sys_migrate_pages
+       .long sys_openat
+       .long sys_mkdirat
+       .long sys_mknodat               /* 290 */
+       .long sys_fchownat
+       .long sys_futimesat
+       .long sys_fstatat64
+       .long sys_unlinkat
+       .long sys_renameat              /* 295 */
+       .long sys_linkat
+       .long sys_symlinkat
+       .long sys_readlinkat
+       .long sys_fchmodat
+       .long sys_faccessat             /* 300 */
+       .long sys_ni_syscall            /* Reserved for pselect6 */
+       .long sys_ni_syscall            /* Reserved for ppoll */
+       .long sys_unshare
+       .long sys_set_robust_list
+       .long sys_get_robust_list       /* 305 */
+       .long sys_splice
+       .long sys_sync_file_range
+       .long sys_tee
+       .long sys_vmsplice
+       .long sys_move_pages            /* 310 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_kexec_load
+       .long sys_getcpu
+       .long sys_epoll_pwait           /* 315 */
+       .long sys_utimensat
+       .long sys_signalfd
+       .long sys_timerfd_create
+       .long sys_eventfd
+       .long sys_fallocate             /* 320 */
+       .long sys_timerfd_settime
+       .long sys_timerfd_gettime
+       .long sys_signalfd4
+       .long sys_eventfd2
+       .long sys_epoll_create1         /* 325 */
+       .long sys_dup3
+       .long sys_pipe2
+       .long sys_inotify_init1
+       .long sys_preadv
+       .long sys_pwritev               /* 330 */
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_event_open
+       .long sys_get_thread_area
+       .long sys_set_thread_area
+       .long sys_atomic_cmpxchg_32     /* 335 */
+       .long sys_atomic_barrier
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
+
+       .rept NR_syscalls-(.-sys_call_table)/4
+               .long sys_ni_syscall
+       .endr
+
index 18b34ee5db3bb94f9fadd5d5e2935a3056dc39e5..a5cf40c26de58abc6c89caa9d800e51ed0095c07 100644 (file)
@@ -1,114 +1,5 @@
-/*
- *  linux/arch/m68k/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/rtc.h>
-#include <linux/platform_device.h>
-
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/irq_regs.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
-#include <linux/profile.h>
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-  if (mach_set_clock_mmss)
-    return mach_set_clock_mmss (nowtime);
-  return -1;
-}
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-static irqreturn_t timer_interrupt(int irq, void *dummy)
-{
-       xtime_update(1);
-       update_process_times(user_mode(get_irq_regs()));
-       profile_tick(CPU_PROFILING);
-
-#ifdef CONFIG_HEARTBEAT
-       /* use power LED as a heartbeat instead -- much more useful
-          for debugging -- based on the version for PReP by Cort */
-       /* acts like an actual heart beat -- ie thump-thump-pause... */
-       if (mach_heartbeat) {
-           static unsigned cnt = 0, period = 0, dist = 0;
-
-           if (cnt == 0 || cnt == dist)
-               mach_heartbeat( 1 );
-           else if (cnt == 7 || cnt == dist+7)
-               mach_heartbeat( 0 );
-
-           if (++cnt > period) {
-               cnt = 0;
-               /* The hyperbolic function below modifies the heartbeat period
-                * length in dependency of the current (5min) load. It goes
-                * through the points f(0)=126, f(1)=86, f(5)=51,
-                * f(inf)->30. */
-               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
-               dist = period / 4;
-           }
-       }
-#endif /* CONFIG_HEARTBEAT */
-       return IRQ_HANDLED;
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-       struct rtc_time time;
-       ts->tv_sec = 0;
-       ts->tv_nsec = 0;
-
-       if (mach_hwclk) {
-               mach_hwclk(0, &time);
-
-               if ((time.tm_year += 1900) < 1970)
-                       time.tm_year += 100;
-               ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
-                                     time.tm_hour, time.tm_min, time.tm_sec);
-       }
-}
-
-void __init time_init(void)
-{
-       mach_sched_init(timer_interrupt);
-}
-
-u32 arch_gettimeoffset(void)
-{
-       return mach_gettimeoffset() * 1000;
-}
-
-static int __init rtc_init(void)
-{
-       struct platform_device *pdev;
-
-       if (!mach_hwclk)
-               return -ENODEV;
-
-       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-
-       return 0;
-}
-
-module_init(rtc_init);
+#ifdef CONFIG_MMU
+#include "time_mm.c"
+#else
+#include "time_no.c"
+#endif
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c
new file mode 100644 (file)
index 0000000..18b34ee
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  linux/arch/m68k/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the m68k-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/irq_regs.h>
+
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+static inline int set_rtc_mmss(unsigned long nowtime)
+{
+  if (mach_set_clock_mmss)
+    return mach_set_clock_mmss (nowtime);
+  return -1;
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "xtime_update()" routine every clocktick
+ */
+static irqreturn_t timer_interrupt(int irq, void *dummy)
+{
+       xtime_update(1);
+       update_process_times(user_mode(get_irq_regs()));
+       profile_tick(CPU_PROFILING);
+
+#ifdef CONFIG_HEARTBEAT
+       /* use power LED as a heartbeat instead -- much more useful
+          for debugging -- based on the version for PReP by Cort */
+       /* acts like an actual heart beat -- ie thump-thump-pause... */
+       if (mach_heartbeat) {
+           static unsigned cnt = 0, period = 0, dist = 0;
+
+           if (cnt == 0 || cnt == dist)
+               mach_heartbeat( 1 );
+           else if (cnt == 7 || cnt == dist+7)
+               mach_heartbeat( 0 );
+
+           if (++cnt > period) {
+               cnt = 0;
+               /* The hyperbolic function below modifies the heartbeat period
+                * length in dependency of the current (5min) load. It goes
+                * through the points f(0)=126, f(1)=86, f(5)=51,
+                * f(inf)->30. */
+               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+               dist = period / 4;
+           }
+       }
+#endif /* CONFIG_HEARTBEAT */
+       return IRQ_HANDLED;
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+       struct rtc_time time;
+       ts->tv_sec = 0;
+       ts->tv_nsec = 0;
+
+       if (mach_hwclk) {
+               mach_hwclk(0, &time);
+
+               if ((time.tm_year += 1900) < 1970)
+                       time.tm_year += 100;
+               ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
+                                     time.tm_hour, time.tm_min, time.tm_sec);
+       }
+}
+
+void __init time_init(void)
+{
+       mach_sched_init(timer_interrupt);
+}
+
+u32 arch_gettimeoffset(void)
+{
+       return mach_gettimeoffset() * 1000;
+}
+
+static int __init rtc_init(void)
+{
+       struct platform_device *pdev;
+
+       if (!mach_hwclk)
+               return -ENODEV;
+
+       pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       return 0;
+}
+
+module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c
new file mode 100644 (file)
index 0000000..6623909
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  linux/arch/m68knommu/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the m68k-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
+ *             "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/profile.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/machdep.h>
+#include <asm/irq_regs.h>
+
+#define        TICK_SIZE (tick_nsec / 1000)
+
+static inline int set_rtc_mmss(unsigned long nowtime)
+{
+       if (mach_set_clock_mmss)
+               return mach_set_clock_mmss (nowtime);
+       return -1;
+}
+
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "xtime_update()" routine every clocktick
+ */
+irqreturn_t arch_timer_interrupt(int irq, void *dummy)
+{
+
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+
+       xtime_update(1);
+
+       update_process_times(user_mode(get_irq_regs()));
+
+       return(IRQ_HANDLED);
+}
+#endif
+
+static unsigned long read_rtc_mmss(void)
+{
+       unsigned int year, mon, day, hour, min, sec;
+
+       if (mach_gettod) {
+               mach_gettod(&year, &mon, &day, &hour, &min, &sec);
+               if ((year += 1900) < 1970)
+                       year += 100;
+       } else {
+               year = 1970;
+               mon = day = 1;
+               hour = min = sec = 0;
+       }
+
+
+       return  mktime(year, mon, day, hour, min, sec);
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+       ts->tv_sec = read_rtc_mmss();
+       ts->tv_nsec = 0;
+}
+
+int update_persistent_clock(struct timespec now)
+{
+       return set_rtc_mmss(now.tv_sec);
+}
+
+void time_init(void)
+{
+       hw_timer_init();
+}
index 4022bbc288782357fa339c17e2254d6462ca6327..c98add3f5f0f45b106925a4f79be435ee83443c2 100644 (file)
-/*
- *  linux/arch/m68k/kernel/traps.c
- *
- *  Copyright (C) 1993, 1994 by Hamish Macdonald
- *
- *  68040 fixes by Michael Rausch
- *  68040 fixes by Martin Apel
- *  68040 fixes and writeback by Richard Zidlicky
- *  68060 fixes by Roman Hodek
- *  68060 fixes by Jesper Skov
- *
- * 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.
- */
-
-/*
- * Sets up all exception vectors
- */
-
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/user.h>
-#include <linux/string.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/kallsyms.h>
-
-#include <asm/setup.h>
-#include <asm/fpu.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/traps.h>
-#include <asm/pgalloc.h>
-#include <asm/machdep.h>
-#include <asm/siginfo.h>
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void nmihandler(void);
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpu_emu(void);
-#endif
-
-e_vector vectors[256];
-
-/* nmi handler for the Amiga */
-asm(".text\n"
-    __ALIGN_STR "\n"
-    "nmihandler: rte");
-
-/*
- * this must be called very early as the kernel might
- * use some instruction that are emulated on the 060
- * and so we're prepared for early probe attempts (e.g. nf_init).
- */
-void __init base_trap_init(void)
-{
-       if (MACH_IS_SUN3X) {
-               extern e_vector *sun3x_prom_vbr;
-
-               __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
-       }
-
-       /* setup the exception vector table */
-       __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
-
-       if (CPU_IS_060) {
-               /* set up ISP entry points */
-               asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
-
-               vectors[VEC_UNIMPII] = unimp_vec;
-       }
-
-       vectors[VEC_BUSERR] = buserr;
-       vectors[VEC_ILLEGAL] = trap;
-       vectors[VEC_SYS] = system_call;
-}
-
-void __init trap_init (void)
-{
-       int i;
-
-       for (i = VEC_SPUR; i <= VEC_INT7; i++)
-               vectors[i] = bad_inthandler;
-
-       for (i = 0; i < VEC_USER; i++)
-               if (!vectors[i])
-                       vectors[i] = trap;
-
-       for (i = VEC_USER; i < 256; i++)
-               vectors[i] = bad_inthandler;
-
-#ifdef CONFIG_M68KFPU_EMU
-       if (FPU_IS_EMU)
-               vectors[VEC_LINE11] = fpu_emu;
-#endif
-
-       if (CPU_IS_040 && !FPU_IS_EMU) {
-               /* set up FPSP entry points */
-               asmlinkage void dz_vec(void) asm ("dz");
-               asmlinkage void inex_vec(void) asm ("inex");
-               asmlinkage void ovfl_vec(void) asm ("ovfl");
-               asmlinkage void unfl_vec(void) asm ("unfl");
-               asmlinkage void snan_vec(void) asm ("snan");
-               asmlinkage void operr_vec(void) asm ("operr");
-               asmlinkage void bsun_vec(void) asm ("bsun");
-               asmlinkage void fline_vec(void) asm ("fline");
-               asmlinkage void unsupp_vec(void) asm ("unsupp");
-
-               vectors[VEC_FPDIVZ] = dz_vec;
-               vectors[VEC_FPIR] = inex_vec;
-               vectors[VEC_FPOVER] = ovfl_vec;
-               vectors[VEC_FPUNDER] = unfl_vec;
-               vectors[VEC_FPNAN] = snan_vec;
-               vectors[VEC_FPOE] = operr_vec;
-               vectors[VEC_FPBRUC] = bsun_vec;
-               vectors[VEC_LINE11] = fline_vec;
-               vectors[VEC_FPUNSUP] = unsupp_vec;
-       }
-
-       if (CPU_IS_060 && !FPU_IS_EMU) {
-               /* set up IFPSP entry points */
-               asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
-               asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
-               asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
-               asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
-               asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
-               asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
-               asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
-               asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
-               asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
-
-               vectors[VEC_FPNAN] = snan_vec6;
-               vectors[VEC_FPOE] = operr_vec6;
-               vectors[VEC_FPOVER] = ovfl_vec6;
-               vectors[VEC_FPUNDER] = unfl_vec6;
-               vectors[VEC_FPDIVZ] = dz_vec6;
-               vectors[VEC_FPIR] = inex_vec6;
-               vectors[VEC_LINE11] = fline_vec6;
-               vectors[VEC_FPUNSUP] = unsupp_vec6;
-               vectors[VEC_UNIMPEA] = effadd_vec6;
-       }
-
-        /* if running on an amiga, make the NMI interrupt do nothing */
-       if (MACH_IS_AMIGA) {
-               vectors[VEC_INT7] = nmihandler;
-       }
-}
-
-
-static const char *vec_names[] = {
-       [VEC_RESETSP]   = "RESET SP",
-       [VEC_RESETPC]   = "RESET PC",
-       [VEC_BUSERR]    = "BUS ERROR",
-       [VEC_ADDRERR]   = "ADDRESS ERROR",
-       [VEC_ILLEGAL]   = "ILLEGAL INSTRUCTION",
-       [VEC_ZERODIV]   = "ZERO DIVIDE",
-       [VEC_CHK]       = "CHK",
-       [VEC_TRAP]      = "TRAPcc",
-       [VEC_PRIV]      = "PRIVILEGE VIOLATION",
-       [VEC_TRACE]     = "TRACE",
-       [VEC_LINE10]    = "LINE 1010",
-       [VEC_LINE11]    = "LINE 1111",
-       [VEC_RESV12]    = "UNASSIGNED RESERVED 12",
-       [VEC_COPROC]    = "COPROCESSOR PROTOCOL VIOLATION",
-       [VEC_FORMAT]    = "FORMAT ERROR",
-       [VEC_UNINT]     = "UNINITIALIZED INTERRUPT",
-       [VEC_RESV16]    = "UNASSIGNED RESERVED 16",
-       [VEC_RESV17]    = "UNASSIGNED RESERVED 17",
-       [VEC_RESV18]    = "UNASSIGNED RESERVED 18",
-       [VEC_RESV19]    = "UNASSIGNED RESERVED 19",
-       [VEC_RESV20]    = "UNASSIGNED RESERVED 20",
-       [VEC_RESV21]    = "UNASSIGNED RESERVED 21",
-       [VEC_RESV22]    = "UNASSIGNED RESERVED 22",
-       [VEC_RESV23]    = "UNASSIGNED RESERVED 23",
-       [VEC_SPUR]      = "SPURIOUS INTERRUPT",
-       [VEC_INT1]      = "LEVEL 1 INT",
-       [VEC_INT2]      = "LEVEL 2 INT",
-       [VEC_INT3]      = "LEVEL 3 INT",
-       [VEC_INT4]      = "LEVEL 4 INT",
-       [VEC_INT5]      = "LEVEL 5 INT",
-       [VEC_INT6]      = "LEVEL 6 INT",
-       [VEC_INT7]      = "LEVEL 7 INT",
-       [VEC_SYS]       = "SYSCALL",
-       [VEC_TRAP1]     = "TRAP #1",
-       [VEC_TRAP2]     = "TRAP #2",
-       [VEC_TRAP3]     = "TRAP #3",
-       [VEC_TRAP4]     = "TRAP #4",
-       [VEC_TRAP5]     = "TRAP #5",
-       [VEC_TRAP6]     = "TRAP #6",
-       [VEC_TRAP7]     = "TRAP #7",
-       [VEC_TRAP8]     = "TRAP #8",
-       [VEC_TRAP9]     = "TRAP #9",
-       [VEC_TRAP10]    = "TRAP #10",
-       [VEC_TRAP11]    = "TRAP #11",
-       [VEC_TRAP12]    = "TRAP #12",
-       [VEC_TRAP13]    = "TRAP #13",
-       [VEC_TRAP14]    = "TRAP #14",
-       [VEC_TRAP15]    = "TRAP #15",
-       [VEC_FPBRUC]    = "FPCP BSUN",
-       [VEC_FPIR]      = "FPCP INEXACT",
-       [VEC_FPDIVZ]    = "FPCP DIV BY 0",
-       [VEC_FPUNDER]   = "FPCP UNDERFLOW",
-       [VEC_FPOE]      = "FPCP OPERAND ERROR",
-       [VEC_FPOVER]    = "FPCP OVERFLOW",
-       [VEC_FPNAN]     = "FPCP SNAN",
-       [VEC_FPUNSUP]   = "FPCP UNSUPPORTED OPERATION",
-       [VEC_MMUCFG]    = "MMU CONFIGURATION ERROR",
-       [VEC_MMUILL]    = "MMU ILLEGAL OPERATION ERROR",
-       [VEC_MMUACC]    = "MMU ACCESS LEVEL VIOLATION ERROR",
-       [VEC_RESV59]    = "UNASSIGNED RESERVED 59",
-       [VEC_UNIMPEA]   = "UNASSIGNED RESERVED 60",
-       [VEC_UNIMPII]   = "UNASSIGNED RESERVED 61",
-       [VEC_RESV62]    = "UNASSIGNED RESERVED 62",
-       [VEC_RESV63]    = "UNASSIGNED RESERVED 63",
-};
-
-static const char *space_names[] = {
-       [0]             = "Space 0",
-       [USER_DATA]     = "User Data",
-       [USER_PROGRAM]  = "User Program",
-#ifndef CONFIG_SUN3
-       [3]             = "Space 3",
+#ifdef CONFIG_MMU
+#include "traps_mm.c"
 #else
-       [FC_CONTROL]    = "Control",
-#endif
-       [4]             = "Space 4",
-       [SUPER_DATA]    = "Super Data",
-       [SUPER_PROGRAM] = "Super Program",
-       [CPU_SPACE]     = "CPU"
-};
-
-void die_if_kernel(char *,struct pt_regs *,int);
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-                             unsigned long error_code);
-int send_fault_sig(struct pt_regs *regs);
-
-asmlinkage void trap_c(struct frame *fp);
-
-#if defined (CONFIG_M68060)
-static inline void access_error060 (struct frame *fp)
-{
-       unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
-
-#ifdef DEBUG
-       printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
-#endif
-
-       if (fslw & MMU060_BPE) {
-               /* branch prediction error -> clear branch cache */
-               __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
-                                     "orl   #0x00400000,%/d0\n\t"
-                                     "movec %/d0,%/cacr"
-                                     : : : "d0" );
-               /* return if there's no other error */
-               if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
-                       return;
-       }
-
-       if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
-               unsigned long errorcode;
-               unsigned long addr = fp->un.fmt4.effaddr;
-
-               if (fslw & MMU060_MA)
-                       addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
-
-               errorcode = 1;
-               if (fslw & MMU060_DESC_ERR) {
-                       __flush_tlb040_one(addr);
-                       errorcode = 0;
-               }
-               if (fslw & MMU060_W)
-                       errorcode |= 2;
-#ifdef DEBUG
-               printk("errorcode = %d\n", errorcode );
-#endif
-               do_page_fault(&fp->ptregs, addr, errorcode);
-       } else if (fslw & (MMU060_SEE)){
-               /* Software Emulation Error.
-                * fault during mem_read/mem_write in ifpsp060/os.S
-                */
-               send_fault_sig(&fp->ptregs);
-       } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
-                  send_fault_sig(&fp->ptregs) > 0) {
-               printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
-               printk( "68060 access error, fslw=%lx\n", fslw );
-               trap_c( fp );
-       }
-}
-#endif /* CONFIG_M68060 */
-
-#if defined (CONFIG_M68040)
-static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
-{
-       unsigned long mmusr;
-       mm_segment_t old_fs = get_fs();
-
-       set_fs(MAKE_MM_SEG(wbs));
-
-       if (iswrite)
-               asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
-       else
-               asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
-
-       asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
-
-       set_fs(old_fs);
-
-       return mmusr;
-}
-
-static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
-                                  unsigned long wbd)
-{
-       int res = 0;
-       mm_segment_t old_fs = get_fs();
-
-       /* set_fs can not be moved, otherwise put_user() may oops */
-       set_fs(MAKE_MM_SEG(wbs));
-
-       switch (wbs & WBSIZ_040) {
-       case BA_SIZE_BYTE:
-               res = put_user(wbd & 0xff, (char __user *)wba);
-               break;
-       case BA_SIZE_WORD:
-               res = put_user(wbd & 0xffff, (short __user *)wba);
-               break;
-       case BA_SIZE_LONG:
-               res = put_user(wbd, (int __user *)wba);
-               break;
-       }
-
-       /* set_fs can not be moved, otherwise put_user() may oops */
-       set_fs(old_fs);
-
-
-#ifdef DEBUG
-       printk("do_040writeback1, res=%d\n",res);
-#endif
-
-       return res;
-}
-
-/* after an exception in a writeback the stack frame corresponding
- * to that exception is discarded, set a few bits in the old frame
- * to simulate what it should look like
- */
-static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
-{
-       fp->un.fmt7.faddr = wba;
-       fp->un.fmt7.ssw = wbs & 0xff;
-       if (wba != current->thread.faddr)
-           fp->un.fmt7.ssw |= MA_040;
-}
-
-static inline void do_040writebacks(struct frame *fp)
-{
-       int res = 0;
-#if 0
-       if (fp->un.fmt7.wb1s & WBV_040)
-               printk("access_error040: cannot handle 1st writeback. oops.\n");
-#endif
-
-       if ((fp->un.fmt7.wb2s & WBV_040) &&
-           !(fp->un.fmt7.wb2s & WBTT_040)) {
-               res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
-                                      fp->un.fmt7.wb2d);
-               if (res)
-                       fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
-               else
-                       fp->un.fmt7.wb2s = 0;
-       }
-
-       /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
-       if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
-               res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
-                                      fp->un.fmt7.wb3d);
-               if (res)
-                   {
-                       fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
-
-                       fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
-                       fp->un.fmt7.wb3s &= (~WBV_040);
-                       fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
-                       fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
-                   }
-               else
-                       fp->un.fmt7.wb3s = 0;
-       }
-
-       if (res)
-               send_fault_sig(&fp->ptregs);
-}
-
-/*
- * called from sigreturn(), must ensure userspace code didn't
- * manipulate exception frame to circumvent protection, then complete
- * pending writebacks
- * we just clear TM2 to turn it into a userspace access
- */
-asmlinkage void berr_040cleanup(struct frame *fp)
-{
-       fp->un.fmt7.wb2s &= ~4;
-       fp->un.fmt7.wb3s &= ~4;
-
-       do_040writebacks(fp);
-}
-
-static inline void access_error040(struct frame *fp)
-{
-       unsigned short ssw = fp->un.fmt7.ssw;
-       unsigned long mmusr;
-
-#ifdef DEBUG
-       printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
-        printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
-               fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
-       printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
-               fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
-               fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
-#endif
-
-       if (ssw & ATC_040) {
-               unsigned long addr = fp->un.fmt7.faddr;
-               unsigned long errorcode;
-
-               /*
-                * The MMU status has to be determined AFTER the address
-                * has been corrected if there was a misaligned access (MA).
-                */
-               if (ssw & MA_040)
-                       addr = (addr + 7) & -8;
-
-               /* MMU error, get the MMUSR info for this access */
-               mmusr = probe040(!(ssw & RW_040), addr, ssw);
-#ifdef DEBUG
-               printk("mmusr = %lx\n", mmusr);
-#endif
-               errorcode = 1;
-               if (!(mmusr & MMU_R_040)) {
-                       /* clear the invalid atc entry */
-                       __flush_tlb040_one(addr);
-                       errorcode = 0;
-               }
-
-               /* despite what documentation seems to say, RMW
-                * accesses have always both the LK and RW bits set */
-               if (!(ssw & RW_040) || (ssw & LK_040))
-                       errorcode |= 2;
-
-               if (do_page_fault(&fp->ptregs, addr, errorcode)) {
-#ifdef DEBUG
-                       printk("do_page_fault() !=0\n");
-#endif
-                       if (user_mode(&fp->ptregs)){
-                               /* delay writebacks after signal delivery */
-#ifdef DEBUG
-                               printk(".. was usermode - return\n");
-#endif
-                               return;
-                       }
-                       /* disable writeback into user space from kernel
-                        * (if do_page_fault didn't fix the mapping,
-                         * the writeback won't do good)
-                        */
-disable_wb:
-#ifdef DEBUG
-                       printk(".. disabling wb2\n");
-#endif
-                       if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
-                               fp->un.fmt7.wb2s &= ~WBV_040;
-                       if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
-                               fp->un.fmt7.wb3s &= ~WBV_040;
-               }
-       } else {
-               /* In case of a bus error we either kill the process or expect
-                * the kernel to catch the fault, which then is also responsible
-                * for cleaning up the mess.
-                */
-               current->thread.signo = SIGBUS;
-               current->thread.faddr = fp->un.fmt7.faddr;
-               if (send_fault_sig(&fp->ptregs) >= 0)
-                       printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
-                              fp->un.fmt7.faddr);
-               goto disable_wb;
-       }
-
-       do_040writebacks(fp);
-}
-#endif /* CONFIG_M68040 */
-
-#if defined(CONFIG_SUN3)
-#include <asm/sun3mmu.h>
-
-extern int mmu_emu_handle_fault (unsigned long, int, int);
-
-/* sun3 version of bus_error030 */
-
-static inline void bus_error030 (struct frame *fp)
-{
-       unsigned char buserr_type = sun3_get_buserr ();
-       unsigned long addr, errorcode;
-       unsigned short ssw = fp->un.fmtb.ssw;
-       extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
-
-#ifdef DEBUG
-       if (ssw & (FC | FB))
-               printk ("Instruction fault at %#010lx\n",
-                       ssw & FC ?
-                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
-                       :
-                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
-       if (ssw & DF)
-               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
-                       ssw & RW ? "read" : "write",
-                       fp->un.fmtb.daddr,
-                       space_names[ssw & DFC], fp->ptregs.pc);
-#endif
-
-       /*
-        * Check if this page should be demand-mapped. This needs to go before
-        * the testing for a bad kernel-space access (demand-mapping applies
-        * to kernel accesses too).
-        */
-
-       if ((ssw & DF)
-           && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
-               if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
-                       return;
-       }
-
-       /* Check for kernel-space pagefault (BAD). */
-       if (fp->ptregs.sr & PS_S) {
-               /* kernel fault must be a data fault to user space */
-               if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
-                    // try checking the kernel mappings before surrender
-                    if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
-                         return;
-                       /* instruction fault or kernel data fault! */
-                       if (ssw & (FC | FB))
-                               printk ("Instruction fault at %#010lx\n",
-                                       fp->ptregs.pc);
-                       if (ssw & DF) {
-                               /* was this fault incurred testing bus mappings? */
-                               if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
-                                  (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
-                                       send_fault_sig(&fp->ptregs);
-                                       return;
-                               }
-
-                               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
-                                       ssw & RW ? "read" : "write",
-                                       fp->un.fmtb.daddr,
-                                       space_names[ssw & DFC], fp->ptregs.pc);
-                       }
-                       printk ("BAD KERNEL BUSERR\n");
-
-                       die_if_kernel("Oops", &fp->ptregs,0);
-                       force_sig(SIGKILL, current);
-                       return;
-               }
-       } else {
-               /* user fault */
-               if (!(ssw & (FC | FB)) && !(ssw & DF))
-                       /* not an instruction fault or data fault! BAD */
-                       panic ("USER BUSERR w/o instruction or data fault");
-       }
-
-
-       /* First handle the data fault, if any.  */
-       if (ssw & DF) {
-               addr = fp->un.fmtb.daddr;
-
-// errorcode bit 0:    0 -> no page            1 -> protection fault
-// errorcode bit 1:    0 -> read fault         1 -> write fault
-
-// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
-// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
-
-               if (buserr_type & SUN3_BUSERR_PROTERR)
-                       errorcode = 0x01;
-               else if (buserr_type & SUN3_BUSERR_INVALID)
-                       errorcode = 0x00;
-               else {
-#ifdef DEBUG
-                       printk ("*** unexpected busfault type=%#04x\n", buserr_type);
-                       printk ("invalid %s access at %#lx from pc %#lx\n",
-                               !(ssw & RW) ? "write" : "read", addr,
-                               fp->ptregs.pc);
-#endif
-                       die_if_kernel ("Oops", &fp->ptregs, buserr_type);
-                       force_sig (SIGBUS, current);
-                       return;
-               }
-
-//todo: wtf is RM bit? --m
-               if (!(ssw & RW) || ssw & RM)
-                       errorcode |= 0x02;
-
-               /* Handle page fault. */
-               do_page_fault (&fp->ptregs, addr, errorcode);
-
-               /* Retry the data fault now. */
-               return;
-       }
-
-       /* Now handle the instruction fault. */
-
-       /* Get the fault address. */
-       if (fp->ptregs.format == 0xA)
-               addr = fp->ptregs.pc + 4;
-       else
-               addr = fp->un.fmtb.baddr;
-       if (ssw & FC)
-               addr -= 2;
-
-       if (buserr_type & SUN3_BUSERR_INVALID) {
-               if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
-                       do_page_fault (&fp->ptregs, addr, 0);
-       } else {
-#ifdef DEBUG
-               printk ("protection fault on insn access (segv).\n");
-#endif
-               force_sig (SIGSEGV, current);
-       }
-}
-#else
-#if defined(CPU_M68020_OR_M68030)
-static inline void bus_error030 (struct frame *fp)
-{
-       volatile unsigned short temp;
-       unsigned short mmusr;
-       unsigned long addr, errorcode;
-       unsigned short ssw = fp->un.fmtb.ssw;
-#ifdef DEBUG
-       unsigned long desc;
-
-       printk ("pid = %x  ", current->pid);
-       printk ("SSW=%#06x  ", ssw);
-
-       if (ssw & (FC | FB))
-               printk ("Instruction fault at %#010lx\n",
-                       ssw & FC ?
-                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
-                       :
-                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
-       if (ssw & DF)
-               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
-                       ssw & RW ? "read" : "write",
-                       fp->un.fmtb.daddr,
-                       space_names[ssw & DFC], fp->ptregs.pc);
-#endif
-
-       /* ++andreas: If a data fault and an instruction fault happen
-          at the same time map in both pages.  */
-
-       /* First handle the data fault, if any.  */
-       if (ssw & DF) {
-               addr = fp->un.fmtb.daddr;
-
-#ifdef DEBUG
-               asm volatile ("ptestr %3,%2@,#7,%0\n\t"
-                             "pmove %%psr,%1@"
-                             : "=a&" (desc)
-                             : "a" (&temp), "a" (addr), "d" (ssw));
-#else
-               asm volatile ("ptestr %2,%1@,#7\n\t"
-                             "pmove %%psr,%0@"
-                             : : "a" (&temp), "a" (addr), "d" (ssw));
-#endif
-               mmusr = temp;
-
-#ifdef DEBUG
-               printk("mmusr is %#x for addr %#lx in task %p\n",
-                      mmusr, addr, current);
-               printk("descriptor address is %#lx, contents %#lx\n",
-                      __va(desc), *(unsigned long *)__va(desc));
-#endif
-
-               errorcode = (mmusr & MMU_I) ? 0 : 1;
-               if (!(ssw & RW) || (ssw & RM))
-                       errorcode |= 2;
-
-               if (mmusr & (MMU_I | MMU_WP)) {
-                       if (ssw & 4) {
-                               printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
-                                      ssw & RW ? "read" : "write",
-                                      fp->un.fmtb.daddr,
-                                      space_names[ssw & DFC], fp->ptregs.pc);
-                               goto buserr;
-                       }
-                       /* Don't try to do anything further if an exception was
-                          handled. */
-                       if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
-                               return;
-               } else if (!(mmusr & MMU_I)) {
-                       /* probably a 020 cas fault */
-                       if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
-                               printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
-               } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
-                       printk("invalid %s access at %#lx from pc %#lx\n",
-                              !(ssw & RW) ? "write" : "read", addr,
-                              fp->ptregs.pc);
-                       die_if_kernel("Oops",&fp->ptregs,mmusr);
-                       force_sig(SIGSEGV, current);
-                       return;
-               } else {
-#if 0
-                       static volatile long tlong;
-#endif
-
-                       printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
-                              !(ssw & RW) ? "write" : "read", addr,
-                              fp->ptregs.pc, ssw);
-                       asm volatile ("ptestr #1,%1@,#0\n\t"
-                                     "pmove %%psr,%0@"
-                                     : /* no outputs */
-                                     : "a" (&temp), "a" (addr));
-                       mmusr = temp;
-
-                       printk ("level 0 mmusr is %#x\n", mmusr);
-#if 0
-                       asm volatile ("pmove %%tt0,%0@"
-                                     : /* no outputs */
-                                     : "a" (&tlong));
-                       printk("tt0 is %#lx, ", tlong);
-                       asm volatile ("pmove %%tt1,%0@"
-                                     : /* no outputs */
-                                     : "a" (&tlong));
-                       printk("tt1 is %#lx\n", tlong);
-#endif
-#ifdef DEBUG
-                       printk("Unknown SIGSEGV - 1\n");
-#endif
-                       die_if_kernel("Oops",&fp->ptregs,mmusr);
-                       force_sig(SIGSEGV, current);
-                       return;
-               }
-
-               /* setup an ATC entry for the access about to be retried */
-               if (!(ssw & RW) || (ssw & RM))
-                       asm volatile ("ploadw %1,%0@" : /* no outputs */
-                                     : "a" (addr), "d" (ssw));
-               else
-                       asm volatile ("ploadr %1,%0@" : /* no outputs */
-                                     : "a" (addr), "d" (ssw));
-       }
-
-       /* Now handle the instruction fault. */
-
-       if (!(ssw & (FC|FB)))
-               return;
-
-       if (fp->ptregs.sr & PS_S) {
-               printk("Instruction fault at %#010lx\n",
-                       fp->ptregs.pc);
-       buserr:
-               printk ("BAD KERNEL BUSERR\n");
-               die_if_kernel("Oops",&fp->ptregs,0);
-               force_sig(SIGKILL, current);
-               return;
-       }
-
-       /* get the fault address */
-       if (fp->ptregs.format == 10)
-               addr = fp->ptregs.pc + 4;
-       else
-               addr = fp->un.fmtb.baddr;
-       if (ssw & FC)
-               addr -= 2;
-
-       if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
-               /* Insn fault on same page as data fault.  But we
-                  should still create the ATC entry.  */
-               goto create_atc_entry;
-
-#ifdef DEBUG
-       asm volatile ("ptestr #1,%2@,#7,%0\n\t"
-                     "pmove %%psr,%1@"
-                     : "=a&" (desc)
-                     : "a" (&temp), "a" (addr));
-#else
-       asm volatile ("ptestr #1,%1@,#7\n\t"
-                     "pmove %%psr,%0@"
-                     : : "a" (&temp), "a" (addr));
-#endif
-       mmusr = temp;
-
-#ifdef DEBUG
-       printk ("mmusr is %#x for addr %#lx in task %p\n",
-               mmusr, addr, current);
-       printk ("descriptor address is %#lx, contents %#lx\n",
-               __va(desc), *(unsigned long *)__va(desc));
-#endif
-
-       if (mmusr & MMU_I)
-               do_page_fault (&fp->ptregs, addr, 0);
-       else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
-               printk ("invalid insn access at %#lx from pc %#lx\n",
-                       addr, fp->ptregs.pc);
-#ifdef DEBUG
-               printk("Unknown SIGSEGV - 2\n");
-#endif
-               die_if_kernel("Oops",&fp->ptregs,mmusr);
-               force_sig(SIGSEGV, current);
-               return;
-       }
-
-create_atc_entry:
-       /* setup an ATC entry for the access about to be retried */
-       asm volatile ("ploadr #2,%0@" : /* no outputs */
-                     : "a" (addr));
-}
-#endif /* CPU_M68020_OR_M68030 */
-#endif /* !CONFIG_SUN3 */
-
-asmlinkage void buserr_c(struct frame *fp)
-{
-       /* Only set esp0 if coming from user mode */
-       if (user_mode(&fp->ptregs))
-               current->thread.esp0 = (unsigned long) fp;
-
-#ifdef DEBUG
-       printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
-#endif
-
-       switch (fp->ptregs.format) {
-#if defined (CONFIG_M68060)
-       case 4:                         /* 68060 access error */
-         access_error060 (fp);
-         break;
-#endif
-#if defined (CONFIG_M68040)
-       case 0x7:                       /* 68040 access error */
-         access_error040 (fp);
-         break;
-#endif
-#if defined (CPU_M68020_OR_M68030)
-       case 0xa:
-       case 0xb:
-         bus_error030 (fp);
-         break;
-#endif
-       default:
-         die_if_kernel("bad frame format",&fp->ptregs,0);
-#ifdef DEBUG
-         printk("Unknown SIGSEGV - 4\n");
-#endif
-         force_sig(SIGSEGV, current);
-       }
-}
-
-
-static int kstack_depth_to_print = 48;
-
-void show_trace(unsigned long *stack)
-{
-       unsigned long *endstack;
-       unsigned long addr;
-       int i;
-
-       printk("Call Trace:");
-       addr = (unsigned long)stack + THREAD_SIZE - 1;
-       endstack = (unsigned long *)(addr & -THREAD_SIZE);
-       i = 0;
-       while (stack + 1 <= endstack) {
-               addr = *stack++;
-               /*
-                * If the address is either in the text segment of the
-                * kernel, or in the region which contains vmalloc'ed
-                * memory, it *may* be the address of a calling
-                * routine; if so, print it so that someone tracing
-                * down the cause of the crash will be able to figure
-                * out the call path that was taken.
-                */
-               if (__kernel_text_address(addr)) {
-#ifndef CONFIG_KALLSYMS
-                       if (i % 5 == 0)
-                               printk("\n       ");
-#endif
-                       printk(" [<%08lx>] %pS\n", addr, (void *)addr);
-                       i++;
-               }
-       }
-       printk("\n");
-}
-
-void show_registers(struct pt_regs *regs)
-{
-       struct frame *fp = (struct frame *)regs;
-       mm_segment_t old_fs = get_fs();
-       u16 c, *cp;
-       unsigned long addr;
-       int i;
-
-       print_modules();
-       printk("PC: [<%08lx>] %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",
-              regs->d4, regs->d5, regs->a0, regs->a1);
-
-       printk("Process %s (pid: %d, task=%p)\n",
-               current->comm, task_pid_nr(current), current);
-       addr = (unsigned long)&fp->un;
-       printk("Frame format=%X ", regs->format);
-       switch (regs->format) {
-       case 0x2:
-               printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
-               addr += sizeof(fp->un.fmt2);
-               break;
-       case 0x3:
-               printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
-               addr += sizeof(fp->un.fmt3);
-               break;
-       case 0x4:
-               printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
-                       : "eff addr=%08lx pc=%08lx\n"),
-                       fp->un.fmt4.effaddr, fp->un.fmt4.pc);
-               addr += sizeof(fp->un.fmt4);
-               break;
-       case 0x7:
-               printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
-                       fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
-               printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
-                       fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
-               printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
-                       fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
-               printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
-                       fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
-               printk("push data: %08lx %08lx %08lx %08lx\n",
-                       fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
-                       fp->un.fmt7.pd3);
-               addr += sizeof(fp->un.fmt7);
-               break;
-       case 0x9:
-               printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
-               addr += sizeof(fp->un.fmt9);
-               break;
-       case 0xa:
-               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-                       fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
-                       fp->un.fmta.daddr, fp->un.fmta.dobuf);
-               addr += sizeof(fp->un.fmta);
-               break;
-       case 0xb:
-               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
-                       fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
-                       fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
-               printk("baddr=%08lx dibuf=%08lx ver=%x\n",
-                       fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
-               addr += sizeof(fp->un.fmtb);
-               break;
-       default:
-               printk("\n");
-       }
-       show_stack(NULL, (unsigned long *)addr);
-
-       printk("Code:");
-       set_fs(KERNEL_DS);
-       cp = (u16 *)regs->pc;
-       for (i = -8; i < 16; i++) {
-               if (get_user(c, cp + i) && i >= 0) {
-                       printk(" Bad PC value.");
-                       break;
-               }
-               printk(i ? " %04x" : " <%04x>", c);
-       }
-       set_fs(old_fs);
-       printk ("\n");
-}
-
-void show_stack(struct task_struct *task, unsigned long *stack)
-{
-       unsigned long *p;
-       unsigned long *endstack;
-       int i;
-
-       if (!stack) {
-               if (task)
-                       stack = (unsigned long *)task->thread.esp0;
-               else
-                       stack = (unsigned long *)&stack;
-       }
-       endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
-
-       printk("Stack from %08lx:", (unsigned long)stack);
-       p = stack;
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (p + 1 > endstack)
-                       break;
-               if (i % 8 == 0)
-                       printk("\n       ");
-               printk(" %08lx", *p++);
-       }
-       printk("\n");
-       show_trace(stack);
-}
-
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
-       unsigned long stack;
-
-       show_trace(&stack);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void bad_super_trap (struct frame *fp)
-{
-       console_verbose();
-       if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
-               printk ("*** %s ***   FORMAT=%X\n",
-                       vec_names[(fp->ptregs.vector) >> 2],
-                       fp->ptregs.format);
-       else
-               printk ("*** Exception %d ***   FORMAT=%X\n",
-                       (fp->ptregs.vector) >> 2,
-                       fp->ptregs.format);
-       if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
-               unsigned short ssw = fp->un.fmtb.ssw;
-
-               printk ("SSW=%#06x  ", ssw);
-
-               if (ssw & RC)
-                       printk ("Pipe stage C instruction fault at %#010lx\n",
-                               (fp->ptregs.format) == 0xA ?
-                               fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
-               if (ssw & RB)
-                       printk ("Pipe stage B instruction fault at %#010lx\n",
-                               (fp->ptregs.format) == 0xA ?
-                               fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
-               if (ssw & DF)
-                       printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
-                               ssw & RW ? "read" : "write",
-                               fp->un.fmtb.daddr, space_names[ssw & DFC],
-                               fp->ptregs.pc);
-       }
-       printk ("Current process id is %d\n", task_pid_nr(current));
-       die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
-}
-
-asmlinkage void trap_c(struct frame *fp)
-{
-       int sig;
-       siginfo_t info;
-
-       if (fp->ptregs.sr & PS_S) {
-               if (fp->ptregs.vector == VEC_TRACE << 2) {
-                       /* traced a trapping instruction on a 68020/30,
-                        * real exception will be executed afterwards.
-                        */
-               } else if (!handle_kernel_fault(&fp->ptregs))
-                       bad_super_trap(fp);
-               return;
-       }
-
-       /* send the appropriate signal to the user program */
-       switch ((fp->ptregs.vector) >> 2) {
-           case VEC_ADDRERR:
-               info.si_code = BUS_ADRALN;
-               sig = SIGBUS;
-               break;
-           case VEC_ILLEGAL:
-           case VEC_LINE10:
-           case VEC_LINE11:
-               info.si_code = ILL_ILLOPC;
-               sig = SIGILL;
-               break;
-           case VEC_PRIV:
-               info.si_code = ILL_PRVOPC;
-               sig = SIGILL;
-               break;
-           case VEC_COPROC:
-               info.si_code = ILL_COPROC;
-               sig = SIGILL;
-               break;
-           case VEC_TRAP1:
-           case VEC_TRAP2:
-           case VEC_TRAP3:
-           case VEC_TRAP4:
-           case VEC_TRAP5:
-           case VEC_TRAP6:
-           case VEC_TRAP7:
-           case VEC_TRAP8:
-           case VEC_TRAP9:
-           case VEC_TRAP10:
-           case VEC_TRAP11:
-           case VEC_TRAP12:
-           case VEC_TRAP13:
-           case VEC_TRAP14:
-               info.si_code = ILL_ILLTRP;
-               sig = SIGILL;
-               break;
-           case VEC_FPBRUC:
-           case VEC_FPOE:
-           case VEC_FPNAN:
-               info.si_code = FPE_FLTINV;
-               sig = SIGFPE;
-               break;
-           case VEC_FPIR:
-               info.si_code = FPE_FLTRES;
-               sig = SIGFPE;
-               break;
-           case VEC_FPDIVZ:
-               info.si_code = FPE_FLTDIV;
-               sig = SIGFPE;
-               break;
-           case VEC_FPUNDER:
-               info.si_code = FPE_FLTUND;
-               sig = SIGFPE;
-               break;
-           case VEC_FPOVER:
-               info.si_code = FPE_FLTOVF;
-               sig = SIGFPE;
-               break;
-           case VEC_ZERODIV:
-               info.si_code = FPE_INTDIV;
-               sig = SIGFPE;
-               break;
-           case VEC_CHK:
-           case VEC_TRAP:
-               info.si_code = FPE_INTOVF;
-               sig = SIGFPE;
-               break;
-           case VEC_TRACE:             /* ptrace single step */
-               info.si_code = TRAP_TRACE;
-               sig = SIGTRAP;
-               break;
-           case VEC_TRAP15:            /* breakpoint */
-               info.si_code = TRAP_BRKPT;
-               sig = SIGTRAP;
-               break;
-           default:
-               info.si_code = ILL_ILLOPC;
-               sig = SIGILL;
-               break;
-       }
-       info.si_signo = sig;
-       info.si_errno = 0;
-       switch (fp->ptregs.format) {
-           default:
-               info.si_addr = (void *) fp->ptregs.pc;
-               break;
-           case 2:
-               info.si_addr = (void *) fp->un.fmt2.iaddr;
-               break;
-           case 7:
-               info.si_addr = (void *) fp->un.fmt7.effaddr;
-               break;
-           case 9:
-               info.si_addr = (void *) fp->un.fmt9.iaddr;
-               break;
-           case 10:
-               info.si_addr = (void *) fp->un.fmta.daddr;
-               break;
-           case 11:
-               info.si_addr = (void *) fp->un.fmtb.daddr;
-               break;
-       }
-       force_sig_info (sig, &info, current);
-}
-
-void die_if_kernel (char *str, struct pt_regs *fp, int nr)
-{
-       if (!(fp->sr & PS_S))
-               return;
-
-       console_verbose();
-       printk("%s: %08x\n",str,nr);
-       show_registers(fp);
-       add_taint(TAINT_DIE);
-       do_exit(SIGSEGV);
-}
-
-/*
- * This function is called if an error occur while accessing
- * user-space from the fpsp040 code.
- */
-asmlinkage void fpsp040_die(void)
-{
-       do_exit(SIGSEGV);
-}
-
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpemu_signal(int signal, int code, void *addr)
-{
-       siginfo_t info;
-
-       info.si_signo = signal;
-       info.si_errno = 0;
-       info.si_code = code;
-       info.si_addr = addr;
-       force_sig_info(signal, &info, current);
-}
+#include "traps_no.c"
 #endif
diff --git a/arch/m68k/kernel/traps_mm.c b/arch/m68k/kernel/traps_mm.c
new file mode 100644 (file)
index 0000000..4022bbc
--- /dev/null
@@ -0,0 +1,1207 @@
+/*
+ *  linux/arch/m68k/kernel/traps.c
+ *
+ *  Copyright (C) 1993, 1994 by Hamish Macdonald
+ *
+ *  68040 fixes by Michael Rausch
+ *  68040 fixes by Martin Apel
+ *  68040 fixes and writeback by Richard Zidlicky
+ *  68060 fixes by Roman Hodek
+ *  68060 fixes by Jesper Skov
+ *
+ * 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.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/pgalloc.h>
+#include <asm/machdep.h>
+#include <asm/siginfo.h>
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void nmihandler(void);
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpu_emu(void);
+#endif
+
+e_vector vectors[256];
+
+/* nmi handler for the Amiga */
+asm(".text\n"
+    __ALIGN_STR "\n"
+    "nmihandler: rte");
+
+/*
+ * this must be called very early as the kernel might
+ * use some instruction that are emulated on the 060
+ * and so we're prepared for early probe attempts (e.g. nf_init).
+ */
+void __init base_trap_init(void)
+{
+       if (MACH_IS_SUN3X) {
+               extern e_vector *sun3x_prom_vbr;
+
+               __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
+       }
+
+       /* setup the exception vector table */
+       __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+
+       if (CPU_IS_060) {
+               /* set up ISP entry points */
+               asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
+
+               vectors[VEC_UNIMPII] = unimp_vec;
+       }
+
+       vectors[VEC_BUSERR] = buserr;
+       vectors[VEC_ILLEGAL] = trap;
+       vectors[VEC_SYS] = system_call;
+}
+
+void __init trap_init (void)
+{
+       int i;
+
+       for (i = VEC_SPUR; i <= VEC_INT7; i++)
+               vectors[i] = bad_inthandler;
+
+       for (i = 0; i < VEC_USER; i++)
+               if (!vectors[i])
+                       vectors[i] = trap;
+
+       for (i = VEC_USER; i < 256; i++)
+               vectors[i] = bad_inthandler;
+
+#ifdef CONFIG_M68KFPU_EMU
+       if (FPU_IS_EMU)
+               vectors[VEC_LINE11] = fpu_emu;
+#endif
+
+       if (CPU_IS_040 && !FPU_IS_EMU) {
+               /* set up FPSP entry points */
+               asmlinkage void dz_vec(void) asm ("dz");
+               asmlinkage void inex_vec(void) asm ("inex");
+               asmlinkage void ovfl_vec(void) asm ("ovfl");
+               asmlinkage void unfl_vec(void) asm ("unfl");
+               asmlinkage void snan_vec(void) asm ("snan");
+               asmlinkage void operr_vec(void) asm ("operr");
+               asmlinkage void bsun_vec(void) asm ("bsun");
+               asmlinkage void fline_vec(void) asm ("fline");
+               asmlinkage void unsupp_vec(void) asm ("unsupp");
+
+               vectors[VEC_FPDIVZ] = dz_vec;
+               vectors[VEC_FPIR] = inex_vec;
+               vectors[VEC_FPOVER] = ovfl_vec;
+               vectors[VEC_FPUNDER] = unfl_vec;
+               vectors[VEC_FPNAN] = snan_vec;
+               vectors[VEC_FPOE] = operr_vec;
+               vectors[VEC_FPBRUC] = bsun_vec;
+               vectors[VEC_LINE11] = fline_vec;
+               vectors[VEC_FPUNSUP] = unsupp_vec;
+       }
+
+       if (CPU_IS_060 && !FPU_IS_EMU) {
+               /* set up IFPSP entry points */
+               asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
+               asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
+               asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
+               asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
+               asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
+               asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
+               asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
+               asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
+               asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
+
+               vectors[VEC_FPNAN] = snan_vec6;
+               vectors[VEC_FPOE] = operr_vec6;
+               vectors[VEC_FPOVER] = ovfl_vec6;
+               vectors[VEC_FPUNDER] = unfl_vec6;
+               vectors[VEC_FPDIVZ] = dz_vec6;
+               vectors[VEC_FPIR] = inex_vec6;
+               vectors[VEC_LINE11] = fline_vec6;
+               vectors[VEC_FPUNSUP] = unsupp_vec6;
+               vectors[VEC_UNIMPEA] = effadd_vec6;
+       }
+
+        /* if running on an amiga, make the NMI interrupt do nothing */
+       if (MACH_IS_AMIGA) {
+               vectors[VEC_INT7] = nmihandler;
+       }
+}
+
+
+static const char *vec_names[] = {
+       [VEC_RESETSP]   = "RESET SP",
+       [VEC_RESETPC]   = "RESET PC",
+       [VEC_BUSERR]    = "BUS ERROR",
+       [VEC_ADDRERR]   = "ADDRESS ERROR",
+       [VEC_ILLEGAL]   = "ILLEGAL INSTRUCTION",
+       [VEC_ZERODIV]   = "ZERO DIVIDE",
+       [VEC_CHK]       = "CHK",
+       [VEC_TRAP]      = "TRAPcc",
+       [VEC_PRIV]      = "PRIVILEGE VIOLATION",
+       [VEC_TRACE]     = "TRACE",
+       [VEC_LINE10]    = "LINE 1010",
+       [VEC_LINE11]    = "LINE 1111",
+       [VEC_RESV12]    = "UNASSIGNED RESERVED 12",
+       [VEC_COPROC]    = "COPROCESSOR PROTOCOL VIOLATION",
+       [VEC_FORMAT]    = "FORMAT ERROR",
+       [VEC_UNINT]     = "UNINITIALIZED INTERRUPT",
+       [VEC_RESV16]    = "UNASSIGNED RESERVED 16",
+       [VEC_RESV17]    = "UNASSIGNED RESERVED 17",
+       [VEC_RESV18]    = "UNASSIGNED RESERVED 18",
+       [VEC_RESV19]    = "UNASSIGNED RESERVED 19",
+       [VEC_RESV20]    = "UNASSIGNED RESERVED 20",
+       [VEC_RESV21]    = "UNASSIGNED RESERVED 21",
+       [VEC_RESV22]    = "UNASSIGNED RESERVED 22",
+       [VEC_RESV23]    = "UNASSIGNED RESERVED 23",
+       [VEC_SPUR]      = "SPURIOUS INTERRUPT",
+       [VEC_INT1]      = "LEVEL 1 INT",
+       [VEC_INT2]      = "LEVEL 2 INT",
+       [VEC_INT3]      = "LEVEL 3 INT",
+       [VEC_INT4]      = "LEVEL 4 INT",
+       [VEC_INT5]      = "LEVEL 5 INT",
+       [VEC_INT6]      = "LEVEL 6 INT",
+       [VEC_INT7]      = "LEVEL 7 INT",
+       [VEC_SYS]       = "SYSCALL",
+       [VEC_TRAP1]     = "TRAP #1",
+       [VEC_TRAP2]     = "TRAP #2",
+       [VEC_TRAP3]     = "TRAP #3",
+       [VEC_TRAP4]     = "TRAP #4",
+       [VEC_TRAP5]     = "TRAP #5",
+       [VEC_TRAP6]     = "TRAP #6",
+       [VEC_TRAP7]     = "TRAP #7",
+       [VEC_TRAP8]     = "TRAP #8",
+       [VEC_TRAP9]     = "TRAP #9",
+       [VEC_TRAP10]    = "TRAP #10",
+       [VEC_TRAP11]    = "TRAP #11",
+       [VEC_TRAP12]    = "TRAP #12",
+       [VEC_TRAP13]    = "TRAP #13",
+       [VEC_TRAP14]    = "TRAP #14",
+       [VEC_TRAP15]    = "TRAP #15",
+       [VEC_FPBRUC]    = "FPCP BSUN",
+       [VEC_FPIR]      = "FPCP INEXACT",
+       [VEC_FPDIVZ]    = "FPCP DIV BY 0",
+       [VEC_FPUNDER]   = "FPCP UNDERFLOW",
+       [VEC_FPOE]      = "FPCP OPERAND ERROR",
+       [VEC_FPOVER]    = "FPCP OVERFLOW",
+       [VEC_FPNAN]     = "FPCP SNAN",
+       [VEC_FPUNSUP]   = "FPCP UNSUPPORTED OPERATION",
+       [VEC_MMUCFG]    = "MMU CONFIGURATION ERROR",
+       [VEC_MMUILL]    = "MMU ILLEGAL OPERATION ERROR",
+       [VEC_MMUACC]    = "MMU ACCESS LEVEL VIOLATION ERROR",
+       [VEC_RESV59]    = "UNASSIGNED RESERVED 59",
+       [VEC_UNIMPEA]   = "UNASSIGNED RESERVED 60",
+       [VEC_UNIMPII]   = "UNASSIGNED RESERVED 61",
+       [VEC_RESV62]    = "UNASSIGNED RESERVED 62",
+       [VEC_RESV63]    = "UNASSIGNED RESERVED 63",
+};
+
+static const char *space_names[] = {
+       [0]             = "Space 0",
+       [USER_DATA]     = "User Data",
+       [USER_PROGRAM]  = "User Program",
+#ifndef CONFIG_SUN3
+       [3]             = "Space 3",
+#else
+       [FC_CONTROL]    = "Control",
+#endif
+       [4]             = "Space 4",
+       [SUPER_DATA]    = "Super Data",
+       [SUPER_PROGRAM] = "Super Program",
+       [CPU_SPACE]     = "CPU"
+};
+
+void die_if_kernel(char *,struct pt_regs *,int);
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+                             unsigned long error_code);
+int send_fault_sig(struct pt_regs *regs);
+
+asmlinkage void trap_c(struct frame *fp);
+
+#if defined (CONFIG_M68060)
+static inline void access_error060 (struct frame *fp)
+{
+       unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
+
+#ifdef DEBUG
+       printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
+#endif
+
+       if (fslw & MMU060_BPE) {
+               /* branch prediction error -> clear branch cache */
+               __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
+                                     "orl   #0x00400000,%/d0\n\t"
+                                     "movec %/d0,%/cacr"
+                                     : : : "d0" );
+               /* return if there's no other error */
+               if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
+                       return;
+       }
+
+       if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
+               unsigned long errorcode;
+               unsigned long addr = fp->un.fmt4.effaddr;
+
+               if (fslw & MMU060_MA)
+                       addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
+
+               errorcode = 1;
+               if (fslw & MMU060_DESC_ERR) {
+                       __flush_tlb040_one(addr);
+                       errorcode = 0;
+               }
+               if (fslw & MMU060_W)
+                       errorcode |= 2;
+#ifdef DEBUG
+               printk("errorcode = %d\n", errorcode );
+#endif
+               do_page_fault(&fp->ptregs, addr, errorcode);
+       } else if (fslw & (MMU060_SEE)){
+               /* Software Emulation Error.
+                * fault during mem_read/mem_write in ifpsp060/os.S
+                */
+               send_fault_sig(&fp->ptregs);
+       } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
+                  send_fault_sig(&fp->ptregs) > 0) {
+               printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
+               printk( "68060 access error, fslw=%lx\n", fslw );
+               trap_c( fp );
+       }
+}
+#endif /* CONFIG_M68060 */
+
+#if defined (CONFIG_M68040)
+static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
+{
+       unsigned long mmusr;
+       mm_segment_t old_fs = get_fs();
+
+       set_fs(MAKE_MM_SEG(wbs));
+
+       if (iswrite)
+               asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
+       else
+               asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
+
+       asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
+
+       set_fs(old_fs);
+
+       return mmusr;
+}
+
+static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
+                                  unsigned long wbd)
+{
+       int res = 0;
+       mm_segment_t old_fs = get_fs();
+
+       /* set_fs can not be moved, otherwise put_user() may oops */
+       set_fs(MAKE_MM_SEG(wbs));
+
+       switch (wbs & WBSIZ_040) {
+       case BA_SIZE_BYTE:
+               res = put_user(wbd & 0xff, (char __user *)wba);
+               break;
+       case BA_SIZE_WORD:
+               res = put_user(wbd & 0xffff, (short __user *)wba);
+               break;
+       case BA_SIZE_LONG:
+               res = put_user(wbd, (int __user *)wba);
+               break;
+       }
+
+       /* set_fs can not be moved, otherwise put_user() may oops */
+       set_fs(old_fs);
+
+
+#ifdef DEBUG
+       printk("do_040writeback1, res=%d\n",res);
+#endif
+
+       return res;
+}
+
+/* after an exception in a writeback the stack frame corresponding
+ * to that exception is discarded, set a few bits in the old frame
+ * to simulate what it should look like
+ */
+static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
+{
+       fp->un.fmt7.faddr = wba;
+       fp->un.fmt7.ssw = wbs & 0xff;
+       if (wba != current->thread.faddr)
+           fp->un.fmt7.ssw |= MA_040;
+}
+
+static inline void do_040writebacks(struct frame *fp)
+{
+       int res = 0;
+#if 0
+       if (fp->un.fmt7.wb1s & WBV_040)
+               printk("access_error040: cannot handle 1st writeback. oops.\n");
+#endif
+
+       if ((fp->un.fmt7.wb2s & WBV_040) &&
+           !(fp->un.fmt7.wb2s & WBTT_040)) {
+               res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
+                                      fp->un.fmt7.wb2d);
+               if (res)
+                       fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
+               else
+                       fp->un.fmt7.wb2s = 0;
+       }
+
+       /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
+       if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
+               res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
+                                      fp->un.fmt7.wb3d);
+               if (res)
+                   {
+                       fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
+
+                       fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
+                       fp->un.fmt7.wb3s &= (~WBV_040);
+                       fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
+                       fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
+                   }
+               else
+                       fp->un.fmt7.wb3s = 0;
+       }
+
+       if (res)
+               send_fault_sig(&fp->ptregs);
+}
+
+/*
+ * called from sigreturn(), must ensure userspace code didn't
+ * manipulate exception frame to circumvent protection, then complete
+ * pending writebacks
+ * we just clear TM2 to turn it into a userspace access
+ */
+asmlinkage void berr_040cleanup(struct frame *fp)
+{
+       fp->un.fmt7.wb2s &= ~4;
+       fp->un.fmt7.wb3s &= ~4;
+
+       do_040writebacks(fp);
+}
+
+static inline void access_error040(struct frame *fp)
+{
+       unsigned short ssw = fp->un.fmt7.ssw;
+       unsigned long mmusr;
+
+#ifdef DEBUG
+       printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
+        printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
+               fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
+       printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
+               fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
+               fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
+#endif
+
+       if (ssw & ATC_040) {
+               unsigned long addr = fp->un.fmt7.faddr;
+               unsigned long errorcode;
+
+               /*
+                * The MMU status has to be determined AFTER the address
+                * has been corrected if there was a misaligned access (MA).
+                */
+               if (ssw & MA_040)
+                       addr = (addr + 7) & -8;
+
+               /* MMU error, get the MMUSR info for this access */
+               mmusr = probe040(!(ssw & RW_040), addr, ssw);
+#ifdef DEBUG
+               printk("mmusr = %lx\n", mmusr);
+#endif
+               errorcode = 1;
+               if (!(mmusr & MMU_R_040)) {
+                       /* clear the invalid atc entry */
+                       __flush_tlb040_one(addr);
+                       errorcode = 0;
+               }
+
+               /* despite what documentation seems to say, RMW
+                * accesses have always both the LK and RW bits set */
+               if (!(ssw & RW_040) || (ssw & LK_040))
+                       errorcode |= 2;
+
+               if (do_page_fault(&fp->ptregs, addr, errorcode)) {
+#ifdef DEBUG
+                       printk("do_page_fault() !=0\n");
+#endif
+                       if (user_mode(&fp->ptregs)){
+                               /* delay writebacks after signal delivery */
+#ifdef DEBUG
+                               printk(".. was usermode - return\n");
+#endif
+                               return;
+                       }
+                       /* disable writeback into user space from kernel
+                        * (if do_page_fault didn't fix the mapping,
+                         * the writeback won't do good)
+                        */
+disable_wb:
+#ifdef DEBUG
+                       printk(".. disabling wb2\n");
+#endif
+                       if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
+                               fp->un.fmt7.wb2s &= ~WBV_040;
+                       if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
+                               fp->un.fmt7.wb3s &= ~WBV_040;
+               }
+       } else {
+               /* In case of a bus error we either kill the process or expect
+                * the kernel to catch the fault, which then is also responsible
+                * for cleaning up the mess.
+                */
+               current->thread.signo = SIGBUS;
+               current->thread.faddr = fp->un.fmt7.faddr;
+               if (send_fault_sig(&fp->ptregs) >= 0)
+                       printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
+                              fp->un.fmt7.faddr);
+               goto disable_wb;
+       }
+
+       do_040writebacks(fp);
+}
+#endif /* CONFIG_M68040 */
+
+#if defined(CONFIG_SUN3)
+#include <asm/sun3mmu.h>
+
+extern int mmu_emu_handle_fault (unsigned long, int, int);
+
+/* sun3 version of bus_error030 */
+
+static inline void bus_error030 (struct frame *fp)
+{
+       unsigned char buserr_type = sun3_get_buserr ();
+       unsigned long addr, errorcode;
+       unsigned short ssw = fp->un.fmtb.ssw;
+       extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
+
+#ifdef DEBUG
+       if (ssw & (FC | FB))
+               printk ("Instruction fault at %#010lx\n",
+                       ssw & FC ?
+                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+                       :
+                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+       if (ssw & DF)
+               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+                       ssw & RW ? "read" : "write",
+                       fp->un.fmtb.daddr,
+                       space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+       /*
+        * Check if this page should be demand-mapped. This needs to go before
+        * the testing for a bad kernel-space access (demand-mapping applies
+        * to kernel accesses too).
+        */
+
+       if ((ssw & DF)
+           && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
+               if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
+                       return;
+       }
+
+       /* Check for kernel-space pagefault (BAD). */
+       if (fp->ptregs.sr & PS_S) {
+               /* kernel fault must be a data fault to user space */
+               if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
+                    // try checking the kernel mappings before surrender
+                    if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
+                         return;
+                       /* instruction fault or kernel data fault! */
+                       if (ssw & (FC | FB))
+                               printk ("Instruction fault at %#010lx\n",
+                                       fp->ptregs.pc);
+                       if (ssw & DF) {
+                               /* was this fault incurred testing bus mappings? */
+                               if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
+                                  (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
+                                       send_fault_sig(&fp->ptregs);
+                                       return;
+                               }
+
+                               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+                                       ssw & RW ? "read" : "write",
+                                       fp->un.fmtb.daddr,
+                                       space_names[ssw & DFC], fp->ptregs.pc);
+                       }
+                       printk ("BAD KERNEL BUSERR\n");
+
+                       die_if_kernel("Oops", &fp->ptregs,0);
+                       force_sig(SIGKILL, current);
+                       return;
+               }
+       } else {
+               /* user fault */
+               if (!(ssw & (FC | FB)) && !(ssw & DF))
+                       /* not an instruction fault or data fault! BAD */
+                       panic ("USER BUSERR w/o instruction or data fault");
+       }
+
+
+       /* First handle the data fault, if any.  */
+       if (ssw & DF) {
+               addr = fp->un.fmtb.daddr;
+
+// errorcode bit 0:    0 -> no page            1 -> protection fault
+// errorcode bit 1:    0 -> read fault         1 -> write fault
+
+// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
+// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
+
+               if (buserr_type & SUN3_BUSERR_PROTERR)
+                       errorcode = 0x01;
+               else if (buserr_type & SUN3_BUSERR_INVALID)
+                       errorcode = 0x00;
+               else {
+#ifdef DEBUG
+                       printk ("*** unexpected busfault type=%#04x\n", buserr_type);
+                       printk ("invalid %s access at %#lx from pc %#lx\n",
+                               !(ssw & RW) ? "write" : "read", addr,
+                               fp->ptregs.pc);
+#endif
+                       die_if_kernel ("Oops", &fp->ptregs, buserr_type);
+                       force_sig (SIGBUS, current);
+                       return;
+               }
+
+//todo: wtf is RM bit? --m
+               if (!(ssw & RW) || ssw & RM)
+                       errorcode |= 0x02;
+
+               /* Handle page fault. */
+               do_page_fault (&fp->ptregs, addr, errorcode);
+
+               /* Retry the data fault now. */
+               return;
+       }
+
+       /* Now handle the instruction fault. */
+
+       /* Get the fault address. */
+       if (fp->ptregs.format == 0xA)
+               addr = fp->ptregs.pc + 4;
+       else
+               addr = fp->un.fmtb.baddr;
+       if (ssw & FC)
+               addr -= 2;
+
+       if (buserr_type & SUN3_BUSERR_INVALID) {
+               if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
+                       do_page_fault (&fp->ptregs, addr, 0);
+       } else {
+#ifdef DEBUG
+               printk ("protection fault on insn access (segv).\n");
+#endif
+               force_sig (SIGSEGV, current);
+       }
+}
+#else
+#if defined(CPU_M68020_OR_M68030)
+static inline void bus_error030 (struct frame *fp)
+{
+       volatile unsigned short temp;
+       unsigned short mmusr;
+       unsigned long addr, errorcode;
+       unsigned short ssw = fp->un.fmtb.ssw;
+#ifdef DEBUG
+       unsigned long desc;
+
+       printk ("pid = %x  ", current->pid);
+       printk ("SSW=%#06x  ", ssw);
+
+       if (ssw & (FC | FB))
+               printk ("Instruction fault at %#010lx\n",
+                       ssw & FC ?
+                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+                       :
+                       fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+       if (ssw & DF)
+               printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+                       ssw & RW ? "read" : "write",
+                       fp->un.fmtb.daddr,
+                       space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+       /* ++andreas: If a data fault and an instruction fault happen
+          at the same time map in both pages.  */
+
+       /* First handle the data fault, if any.  */
+       if (ssw & DF) {
+               addr = fp->un.fmtb.daddr;
+
+#ifdef DEBUG
+               asm volatile ("ptestr %3,%2@,#7,%0\n\t"
+                             "pmove %%psr,%1@"
+                             : "=a&" (desc)
+                             : "a" (&temp), "a" (addr), "d" (ssw));
+#else
+               asm volatile ("ptestr %2,%1@,#7\n\t"
+                             "pmove %%psr,%0@"
+                             : : "a" (&temp), "a" (addr), "d" (ssw));
+#endif
+               mmusr = temp;
+
+#ifdef DEBUG
+               printk("mmusr is %#x for addr %#lx in task %p\n",
+                      mmusr, addr, current);
+               printk("descriptor address is %#lx, contents %#lx\n",
+                      __va(desc), *(unsigned long *)__va(desc));
+#endif
+
+               errorcode = (mmusr & MMU_I) ? 0 : 1;
+               if (!(ssw & RW) || (ssw & RM))
+                       errorcode |= 2;
+
+               if (mmusr & (MMU_I | MMU_WP)) {
+                       if (ssw & 4) {
+                               printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+                                      ssw & RW ? "read" : "write",
+                                      fp->un.fmtb.daddr,
+                                      space_names[ssw & DFC], fp->ptregs.pc);
+                               goto buserr;
+                       }
+                       /* Don't try to do anything further if an exception was
+                          handled. */
+                       if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
+                               return;
+               } else if (!(mmusr & MMU_I)) {
+                       /* probably a 020 cas fault */
+                       if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
+                               printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
+               } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+                       printk("invalid %s access at %#lx from pc %#lx\n",
+                              !(ssw & RW) ? "write" : "read", addr,
+                              fp->ptregs.pc);
+                       die_if_kernel("Oops",&fp->ptregs,mmusr);
+                       force_sig(SIGSEGV, current);
+                       return;
+               } else {
+#if 0
+                       static volatile long tlong;
+#endif
+
+                       printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
+                              !(ssw & RW) ? "write" : "read", addr,
+                              fp->ptregs.pc, ssw);
+                       asm volatile ("ptestr #1,%1@,#0\n\t"
+                                     "pmove %%psr,%0@"
+                                     : /* no outputs */
+                                     : "a" (&temp), "a" (addr));
+                       mmusr = temp;
+
+                       printk ("level 0 mmusr is %#x\n", mmusr);
+#if 0
+                       asm volatile ("pmove %%tt0,%0@"
+                                     : /* no outputs */
+                                     : "a" (&tlong));
+                       printk("tt0 is %#lx, ", tlong);
+                       asm volatile ("pmove %%tt1,%0@"
+                                     : /* no outputs */
+                                     : "a" (&tlong));
+                       printk("tt1 is %#lx\n", tlong);
+#endif
+#ifdef DEBUG
+                       printk("Unknown SIGSEGV - 1\n");
+#endif
+                       die_if_kernel("Oops",&fp->ptregs,mmusr);
+                       force_sig(SIGSEGV, current);
+                       return;
+               }
+
+               /* setup an ATC entry for the access about to be retried */
+               if (!(ssw & RW) || (ssw & RM))
+                       asm volatile ("ploadw %1,%0@" : /* no outputs */
+                                     : "a" (addr), "d" (ssw));
+               else
+                       asm volatile ("ploadr %1,%0@" : /* no outputs */
+                                     : "a" (addr), "d" (ssw));
+       }
+
+       /* Now handle the instruction fault. */
+
+       if (!(ssw & (FC|FB)))
+               return;
+
+       if (fp->ptregs.sr & PS_S) {
+               printk("Instruction fault at %#010lx\n",
+                       fp->ptregs.pc);
+       buserr:
+               printk ("BAD KERNEL BUSERR\n");
+               die_if_kernel("Oops",&fp->ptregs,0);
+               force_sig(SIGKILL, current);
+               return;
+       }
+
+       /* get the fault address */
+       if (fp->ptregs.format == 10)
+               addr = fp->ptregs.pc + 4;
+       else
+               addr = fp->un.fmtb.baddr;
+       if (ssw & FC)
+               addr -= 2;
+
+       if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
+               /* Insn fault on same page as data fault.  But we
+                  should still create the ATC entry.  */
+               goto create_atc_entry;
+
+#ifdef DEBUG
+       asm volatile ("ptestr #1,%2@,#7,%0\n\t"
+                     "pmove %%psr,%1@"
+                     : "=a&" (desc)
+                     : "a" (&temp), "a" (addr));
+#else
+       asm volatile ("ptestr #1,%1@,#7\n\t"
+                     "pmove %%psr,%0@"
+                     : : "a" (&temp), "a" (addr));
+#endif
+       mmusr = temp;
+
+#ifdef DEBUG
+       printk ("mmusr is %#x for addr %#lx in task %p\n",
+               mmusr, addr, current);
+       printk ("descriptor address is %#lx, contents %#lx\n",
+               __va(desc), *(unsigned long *)__va(desc));
+#endif
+
+       if (mmusr & MMU_I)
+               do_page_fault (&fp->ptregs, addr, 0);
+       else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
+               printk ("invalid insn access at %#lx from pc %#lx\n",
+                       addr, fp->ptregs.pc);
+#ifdef DEBUG
+               printk("Unknown SIGSEGV - 2\n");
+#endif
+               die_if_kernel("Oops",&fp->ptregs,mmusr);
+               force_sig(SIGSEGV, current);
+               return;
+       }
+
+create_atc_entry:
+       /* setup an ATC entry for the access about to be retried */
+       asm volatile ("ploadr #2,%0@" : /* no outputs */
+                     : "a" (addr));
+}
+#endif /* CPU_M68020_OR_M68030 */
+#endif /* !CONFIG_SUN3 */
+
+asmlinkage void buserr_c(struct frame *fp)
+{
+       /* Only set esp0 if coming from user mode */
+       if (user_mode(&fp->ptregs))
+               current->thread.esp0 = (unsigned long) fp;
+
+#ifdef DEBUG
+       printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
+#endif
+
+       switch (fp->ptregs.format) {
+#if defined (CONFIG_M68060)
+       case 4:                         /* 68060 access error */
+         access_error060 (fp);
+         break;
+#endif
+#if defined (CONFIG_M68040)
+       case 0x7:                       /* 68040 access error */
+         access_error040 (fp);
+         break;
+#endif
+#if defined (CPU_M68020_OR_M68030)
+       case 0xa:
+       case 0xb:
+         bus_error030 (fp);
+         break;
+#endif
+       default:
+         die_if_kernel("bad frame format",&fp->ptregs,0);
+#ifdef DEBUG
+         printk("Unknown SIGSEGV - 4\n");
+#endif
+         force_sig(SIGSEGV, current);
+       }
+}
+
+
+static int kstack_depth_to_print = 48;
+
+void show_trace(unsigned long *stack)
+{
+       unsigned long *endstack;
+       unsigned long addr;
+       int i;
+
+       printk("Call Trace:");
+       addr = (unsigned long)stack + THREAD_SIZE - 1;
+       endstack = (unsigned long *)(addr & -THREAD_SIZE);
+       i = 0;
+       while (stack + 1 <= endstack) {
+               addr = *stack++;
+               /*
+                * If the address is either in the text segment of the
+                * kernel, or in the region which contains vmalloc'ed
+                * memory, it *may* be the address of a calling
+                * routine; if so, print it so that someone tracing
+                * down the cause of the crash will be able to figure
+                * out the call path that was taken.
+                */
+               if (__kernel_text_address(addr)) {
+#ifndef CONFIG_KALLSYMS
+                       if (i % 5 == 0)
+                               printk("\n       ");
+#endif
+                       printk(" [<%08lx>] %pS\n", addr, (void *)addr);
+                       i++;
+               }
+       }
+       printk("\n");
+}
+
+void show_registers(struct pt_regs *regs)
+{
+       struct frame *fp = (struct frame *)regs;
+       mm_segment_t old_fs = get_fs();
+       u16 c, *cp;
+       unsigned long addr;
+       int i;
+
+       print_modules();
+       printk("PC: [<%08lx>] %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",
+              regs->d4, regs->d5, regs->a0, regs->a1);
+
+       printk("Process %s (pid: %d, task=%p)\n",
+               current->comm, task_pid_nr(current), current);
+       addr = (unsigned long)&fp->un;
+       printk("Frame format=%X ", regs->format);
+       switch (regs->format) {
+       case 0x2:
+               printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
+               addr += sizeof(fp->un.fmt2);
+               break;
+       case 0x3:
+               printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
+               addr += sizeof(fp->un.fmt3);
+               break;
+       case 0x4:
+               printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
+                       : "eff addr=%08lx pc=%08lx\n"),
+                       fp->un.fmt4.effaddr, fp->un.fmt4.pc);
+               addr += sizeof(fp->un.fmt4);
+               break;
+       case 0x7:
+               printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
+                       fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
+               printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
+               printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
+               printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
+                       fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
+               printk("push data: %08lx %08lx %08lx %08lx\n",
+                       fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
+                       fp->un.fmt7.pd3);
+               addr += sizeof(fp->un.fmt7);
+               break;
+       case 0x9:
+               printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
+               addr += sizeof(fp->un.fmt9);
+               break;
+       case 0xa:
+               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+                       fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
+                       fp->un.fmta.daddr, fp->un.fmta.dobuf);
+               addr += sizeof(fp->un.fmta);
+               break;
+       case 0xb:
+               printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
+                       fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
+                       fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
+               printk("baddr=%08lx dibuf=%08lx ver=%x\n",
+                       fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
+               addr += sizeof(fp->un.fmtb);
+               break;
+       default:
+               printk("\n");
+       }
+       show_stack(NULL, (unsigned long *)addr);
+
+       printk("Code:");
+       set_fs(KERNEL_DS);
+       cp = (u16 *)regs->pc;
+       for (i = -8; i < 16; i++) {
+               if (get_user(c, cp + i) && i >= 0) {
+                       printk(" Bad PC value.");
+                       break;
+               }
+               printk(i ? " %04x" : " <%04x>", c);
+       }
+       set_fs(old_fs);
+       printk ("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+       unsigned long *p;
+       unsigned long *endstack;
+       int i;
+
+       if (!stack) {
+               if (task)
+                       stack = (unsigned long *)task->thread.esp0;
+               else
+                       stack = (unsigned long *)&stack;
+       }
+       endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
+
+       printk("Stack from %08lx:", (unsigned long)stack);
+       p = stack;
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (p + 1 > endstack)
+                       break;
+               if (i % 8 == 0)
+                       printk("\n       ");
+               printk(" %08lx", *p++);
+       }
+       printk("\n");
+       show_trace(stack);
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+       unsigned long stack;
+
+       show_trace(&stack);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void bad_super_trap (struct frame *fp)
+{
+       console_verbose();
+       if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
+               printk ("*** %s ***   FORMAT=%X\n",
+                       vec_names[(fp->ptregs.vector) >> 2],
+                       fp->ptregs.format);
+       else
+               printk ("*** Exception %d ***   FORMAT=%X\n",
+                       (fp->ptregs.vector) >> 2,
+                       fp->ptregs.format);
+       if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
+               unsigned short ssw = fp->un.fmtb.ssw;
+
+               printk ("SSW=%#06x  ", ssw);
+
+               if (ssw & RC)
+                       printk ("Pipe stage C instruction fault at %#010lx\n",
+                               (fp->ptregs.format) == 0xA ?
+                               fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
+               if (ssw & RB)
+                       printk ("Pipe stage B instruction fault at %#010lx\n",
+                               (fp->ptregs.format) == 0xA ?
+                               fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+               if (ssw & DF)
+                       printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+                               ssw & RW ? "read" : "write",
+                               fp->un.fmtb.daddr, space_names[ssw & DFC],
+                               fp->ptregs.pc);
+       }
+       printk ("Current process id is %d\n", task_pid_nr(current));
+       die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
+}
+
+asmlinkage void trap_c(struct frame *fp)
+{
+       int sig;
+       siginfo_t info;
+
+       if (fp->ptregs.sr & PS_S) {
+               if (fp->ptregs.vector == VEC_TRACE << 2) {
+                       /* traced a trapping instruction on a 68020/30,
+                        * real exception will be executed afterwards.
+                        */
+               } else if (!handle_kernel_fault(&fp->ptregs))
+                       bad_super_trap(fp);
+               return;
+       }
+
+       /* send the appropriate signal to the user program */
+       switch ((fp->ptregs.vector) >> 2) {
+           case VEC_ADDRERR:
+               info.si_code = BUS_ADRALN;
+               sig = SIGBUS;
+               break;
+           case VEC_ILLEGAL:
+           case VEC_LINE10:
+           case VEC_LINE11:
+               info.si_code = ILL_ILLOPC;
+               sig = SIGILL;
+               break;
+           case VEC_PRIV:
+               info.si_code = ILL_PRVOPC;
+               sig = SIGILL;
+               break;
+           case VEC_COPROC:
+               info.si_code = ILL_COPROC;
+               sig = SIGILL;
+               break;
+           case VEC_TRAP1:
+           case VEC_TRAP2:
+           case VEC_TRAP3:
+           case VEC_TRAP4:
+           case VEC_TRAP5:
+           case VEC_TRAP6:
+           case VEC_TRAP7:
+           case VEC_TRAP8:
+           case VEC_TRAP9:
+           case VEC_TRAP10:
+           case VEC_TRAP11:
+           case VEC_TRAP12:
+           case VEC_TRAP13:
+           case VEC_TRAP14:
+               info.si_code = ILL_ILLTRP;
+               sig = SIGILL;
+               break;
+           case VEC_FPBRUC:
+           case VEC_FPOE:
+           case VEC_FPNAN:
+               info.si_code = FPE_FLTINV;
+               sig = SIGFPE;
+               break;
+           case VEC_FPIR:
+               info.si_code = FPE_FLTRES;
+               sig = SIGFPE;
+               break;
+           case VEC_FPDIVZ:
+               info.si_code = FPE_FLTDIV;
+               sig = SIGFPE;
+               break;
+           case VEC_FPUNDER:
+               info.si_code = FPE_FLTUND;
+               sig = SIGFPE;
+               break;
+           case VEC_FPOVER:
+               info.si_code = FPE_FLTOVF;
+               sig = SIGFPE;
+               break;
+           case VEC_ZERODIV:
+               info.si_code = FPE_INTDIV;
+               sig = SIGFPE;
+               break;
+           case VEC_CHK:
+           case VEC_TRAP:
+               info.si_code = FPE_INTOVF;
+               sig = SIGFPE;
+               break;
+           case VEC_TRACE:             /* ptrace single step */
+               info.si_code = TRAP_TRACE;
+               sig = SIGTRAP;
+               break;
+           case VEC_TRAP15:            /* breakpoint */
+               info.si_code = TRAP_BRKPT;
+               sig = SIGTRAP;
+               break;
+           default:
+               info.si_code = ILL_ILLOPC;
+               sig = SIGILL;
+               break;
+       }
+       info.si_signo = sig;
+       info.si_errno = 0;
+       switch (fp->ptregs.format) {
+           default:
+               info.si_addr = (void *) fp->ptregs.pc;
+               break;
+           case 2:
+               info.si_addr = (void *) fp->un.fmt2.iaddr;
+               break;
+           case 7:
+               info.si_addr = (void *) fp->un.fmt7.effaddr;
+               break;
+           case 9:
+               info.si_addr = (void *) fp->un.fmt9.iaddr;
+               break;
+           case 10:
+               info.si_addr = (void *) fp->un.fmta.daddr;
+               break;
+           case 11:
+               info.si_addr = (void *) fp->un.fmtb.daddr;
+               break;
+       }
+       force_sig_info (sig, &info, current);
+}
+
+void die_if_kernel (char *str, struct pt_regs *fp, int nr)
+{
+       if (!(fp->sr & PS_S))
+               return;
+
+       console_verbose();
+       printk("%s: %08x\n",str,nr);
+       show_registers(fp);
+       add_taint(TAINT_DIE);
+       do_exit(SIGSEGV);
+}
+
+/*
+ * This function is called if an error occur while accessing
+ * user-space from the fpsp040 code.
+ */
+asmlinkage void fpsp040_die(void)
+{
+       do_exit(SIGSEGV);
+}
+
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpemu_signal(int signal, int code, void *addr)
+{
+       siginfo_t info;
+
+       info.si_signo = signal;
+       info.si_errno = 0;
+       info.si_code = code;
+       info.si_addr = addr;
+       force_sig_info(signal, &info, current);
+}
+#endif
diff --git a/arch/m68k/kernel/traps_no.c b/arch/m68k/kernel/traps_no.c
new file mode 100644 (file)
index 0000000..a768008
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *  linux/arch/m68knommu/kernel/traps.c
+ *
+ *  Copyright (C) 1993, 1994 by Hamish Macdonald
+ *
+ *  68040 fixes by Michael Rausch
+ *  68040 fixes by Martin Apel
+ *  68060 fixes by Roman Hodek
+ *  68060 fixes by Jesper Skov
+ *
+ * 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.
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
+
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/siginfo.h>
+
+static char const * const vec_names[] = {
+       "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
+       "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
+       "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
+       "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
+       "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
+       "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
+       "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
+       "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
+       "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
+       "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
+       "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
+       "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
+       "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
+       "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
+       "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
+       "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
+       "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
+       "FPCP UNSUPPORTED OPERATION",
+       "MMU CONFIGURATION ERROR"
+};
+
+void __init trap_init(void)
+{
+}
+
+void die_if_kernel(char *str, struct pt_regs *fp, int nr)
+{
+       if (!(fp->sr & PS_S))
+               return;
+
+       console_verbose();
+       printk(KERN_EMERG "%s: %08x\n",str,nr);
+       printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
+              fp->pc, fp->sr, fp, fp->a2);
+       printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
+              fp->d0, fp->d1, fp->d2, fp->d3);
+       printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
+              fp->d4, fp->d5, fp->a0, fp->a1);
+
+       printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
+               current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
+       show_stack(NULL, (unsigned long *)(fp + 1));
+       add_taint(TAINT_DIE);
+       do_exit(SIGSEGV);
+}
+
+asmlinkage void buserr_c(struct frame *fp)
+{
+       /* Only set esp0 if coming from user mode */
+       if (user_mode(&fp->ptregs))
+               current->thread.esp0 = (unsigned long) fp;
+
+#if defined(DEBUG)
+       printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
+#endif
+
+       die_if_kernel("bad frame format",&fp->ptregs,0);
+#if defined(DEBUG)
+       printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
+#endif
+       force_sig(SIGSEGV, current);
+}
+
+static void print_this_address(unsigned long addr, int i)
+{
+#ifdef CONFIG_KALLSYMS
+       printk(KERN_EMERG " [%08lx] ", addr);
+       print_symbol(KERN_CONT "%s\n", addr);
+#else
+       if (i % 5)
+               printk(KERN_CONT " [%08lx] ", addr);
+       else
+               printk(KERN_EMERG " [%08lx] ", addr);
+       i++;
+#endif
+}
+
+int kstack_depth_to_print = 48;
+
+static void __show_stack(struct task_struct *task, unsigned long *stack)
+{
+       unsigned long *endstack, addr;
+#ifdef CONFIG_FRAME_POINTER
+       unsigned long *last_stack;
+#endif
+       int i;
+
+       if (!stack)
+               stack = (unsigned long *)task->thread.ksp;
+
+       addr = (unsigned long) stack;
+       endstack = (unsigned long *) PAGE_ALIGN(addr);
+
+       printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
+       for (i = 0; i < kstack_depth_to_print; i++) {
+               if (stack + 1 + i > endstack)
+                       break;
+               if (i % 8 == 0)
+                       printk(KERN_EMERG "       ");
+               printk(KERN_CONT " %08lx", *(stack + i));
+       }
+       printk("\n");
+       i = 0;
+
+#ifdef CONFIG_FRAME_POINTER
+       printk(KERN_EMERG "Call Trace:\n");
+
+       last_stack = stack - 1;
+       while (stack <= endstack && stack > last_stack) {
+
+               addr = *(stack + 1);
+               print_this_address(addr, i);
+               i++;
+
+               last_stack = stack;
+               stack = (unsigned long *)*stack;
+       }
+       printk("\n");
+#else
+       printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
+       while (stack <= endstack) {
+               addr = *stack++;
+               /*
+                * If the address is either in the text segment of the kernel,
+                * or in a region which is occupied by a module then it *may*
+                * be the address of a calling routine; if so, print it so that
+                * someone tracing down the cause of the crash will be able to
+                * figure out the call path that was taken.
+                */
+               if (__kernel_text_address(addr)) {
+                       print_this_address(addr, i);
+                       i++;
+               }
+       }
+       printk(KERN_CONT "\n");
+#endif
+}
+
+void bad_super_trap(struct frame *fp)
+{
+       int vector = (fp->ptregs.vector >> 2) & 0xff;
+
+       console_verbose();
+       if (vector < ARRAY_SIZE(vec_names))
+               printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
+                       vec_names[vector],
+                       fp->ptregs.format);
+       else
+               printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
+                       vector,
+                       fp->ptregs.format);
+       printk (KERN_WARNING "Current process id is %d\n", current->pid);
+       die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
+}
+
+asmlinkage void trap_c(struct frame *fp)
+{
+       int sig;
+       int vector = (fp->ptregs.vector >> 2) & 0xff;
+       siginfo_t info;
+
+       if (fp->ptregs.sr & PS_S) {
+               if (vector == VEC_TRACE) {
+                       /* traced a trapping instruction */
+               } else
+                       bad_super_trap(fp);
+               return;
+       }
+
+       /* send the appropriate signal to the user program */
+       switch (vector) {
+           case VEC_ADDRERR:
+               info.si_code = BUS_ADRALN;
+               sig = SIGBUS;
+               break;
+           case VEC_ILLEGAL:
+           case VEC_LINE10:
+           case VEC_LINE11:
+               info.si_code = ILL_ILLOPC;
+               sig = SIGILL;
+               break;
+           case VEC_PRIV:
+               info.si_code = ILL_PRVOPC;
+               sig = SIGILL;
+               break;
+           case VEC_COPROC:
+               info.si_code = ILL_COPROC;
+               sig = SIGILL;
+               break;
+           case VEC_TRAP1: /* gdbserver breakpoint */
+               fp->ptregs.pc -= 2;
+               info.si_code = TRAP_TRACE;
+               sig = SIGTRAP;
+               break;
+           case VEC_TRAP2:
+           case VEC_TRAP3:
+           case VEC_TRAP4:
+           case VEC_TRAP5:
+           case VEC_TRAP6:
+           case VEC_TRAP7:
+           case VEC_TRAP8:
+           case VEC_TRAP9:
+           case VEC_TRAP10:
+           case VEC_TRAP11:
+           case VEC_TRAP12:
+           case VEC_TRAP13:
+           case VEC_TRAP14:
+               info.si_code = ILL_ILLTRP;
+               sig = SIGILL;
+               break;
+           case VEC_FPBRUC:
+           case VEC_FPOE:
+           case VEC_FPNAN:
+               info.si_code = FPE_FLTINV;
+               sig = SIGFPE;
+               break;
+           case VEC_FPIR:
+               info.si_code = FPE_FLTRES;
+               sig = SIGFPE;
+               break;
+           case VEC_FPDIVZ:
+               info.si_code = FPE_FLTDIV;
+               sig = SIGFPE;
+               break;
+           case VEC_FPUNDER:
+               info.si_code = FPE_FLTUND;
+               sig = SIGFPE;
+               break;
+           case VEC_FPOVER:
+               info.si_code = FPE_FLTOVF;
+               sig = SIGFPE;
+               break;
+           case VEC_ZERODIV:
+               info.si_code = FPE_INTDIV;
+               sig = SIGFPE;
+               break;
+           case VEC_CHK:
+           case VEC_TRAP:
+               info.si_code = FPE_INTOVF;
+               sig = SIGFPE;
+               break;
+           case VEC_TRACE:             /* ptrace single step */
+               info.si_code = TRAP_TRACE;
+               sig = SIGTRAP;
+               break;
+           case VEC_TRAP15:            /* breakpoint */
+               info.si_code = TRAP_BRKPT;
+               sig = SIGTRAP;
+               break;
+           default:
+               info.si_code = ILL_ILLOPC;
+               sig = SIGILL;
+               break;
+       }
+       info.si_signo = sig;
+       info.si_errno = 0;
+       switch (fp->ptregs.format) {
+           default:
+               info.si_addr = (void *) fp->ptregs.pc;
+               break;
+           case 2:
+               info.si_addr = (void *) fp->un.fmt2.iaddr;
+               break;
+           case 7:
+               info.si_addr = (void *) fp->un.fmt7.effaddr;
+               break;
+           case 9:
+               info.si_addr = (void *) fp->un.fmt9.iaddr;
+               break;
+           case 10:
+               info.si_addr = (void *) fp->un.fmta.daddr;
+               break;
+           case 11:
+               info.si_addr = (void *) fp->un.fmtb.daddr;
+               break;
+       }
+       force_sig_info (sig, &info, current);
+}
+
+asmlinkage void set_esp0(unsigned long ssp)
+{
+       current->thread.esp0 = ssp;
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+       /*
+        * We need frame pointers for this little trick, which works as follows:
+        *
+        * +------------+ 0x00
+        * | Next SP    |       -> 0x0c
+        * +------------+ 0x04
+        * | Caller     |
+        * +------------+ 0x08
+        * | Local vars |       -> our stack var
+        * +------------+ 0x0c
+        * | Next SP    |       -> 0x18, that is what we pass to show_stack()
+        * +------------+ 0x10
+        * | Caller     |
+        * +------------+ 0x14
+        * | Local vars |
+        * +------------+ 0x18
+        * | ...        |
+        * +------------+
+        */
+
+       unsigned long *stack;
+
+       stack = (unsigned long *)&stack;
+       stack++;
+       __show_stack(current, stack);
+}
+EXPORT_SYMBOL(dump_stack);
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+       if (!stack && !task)
+               dump_stack();
+       else
+               __show_stack(task, stack);
+}
index 99ba315bd0a857a884dd017fc7a3c42027b78879..030dabf0bc538ddca7fd7ba6bdee96432f2bde56 100644 (file)
@@ -1,10 +1,5 @@
-PHDRS
-{
-  text PT_LOAD FILEHDR PHDRS FLAGS (7);
-  data PT_LOAD FLAGS (7);
-}
-#ifdef CONFIG_SUN3
-#include "vmlinux-sun3.lds"
+#ifdef CONFIG_MMU
+#include "vmlinux.lds_mm.S"
 #else
-#include "vmlinux-std.lds"
+#include "vmlinux.lds_no.S"
 #endif
diff --git a/arch/m68k/kernel/vmlinux.lds_mm.S b/arch/m68k/kernel/vmlinux.lds_mm.S
new file mode 100644 (file)
index 0000000..99ba315
--- /dev/null
@@ -0,0 +1,10 @@
+PHDRS
+{
+  text PT_LOAD FILEHDR PHDRS FLAGS (7);
+  data PT_LOAD FLAGS (7);
+}
+#ifdef CONFIG_SUN3
+#include "vmlinux-sun3.lds"
+#else
+#include "vmlinux-std.lds"
+#endif
diff --git a/arch/m68k/kernel/vmlinux.lds_no.S b/arch/m68k/kernel/vmlinux.lds_no.S
new file mode 100644 (file)
index 0000000..47e15eb
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *     vmlinux.lds.S -- master linker script for m68knommu arch
+ *
+ *     (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
+ *
+ *     This linker script is equiped to build either ROM loaded or RAM
+ *     run kernels.
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+
+#if defined(CONFIG_RAMKERNEL)
+#define        RAM_START       CONFIG_KERNELBASE
+#define        RAM_LENGTH      (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
+#define        TEXT            ram
+#define        DATA            ram
+#define        INIT            ram
+#define        BSSS            ram
+#endif
+#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
+#define        RAM_START       CONFIG_RAMBASE
+#define        RAM_LENGTH      CONFIG_RAMSIZE
+#define        ROMVEC_START    CONFIG_ROMVEC
+#define        ROMVEC_LENGTH   CONFIG_ROMVECSIZE
+#define        ROM_START       CONFIG_ROMSTART
+#define        ROM_LENGTH      CONFIG_ROMSIZE
+#define        TEXT            rom
+#define        DATA            ram
+#define        INIT            ram
+#define        BSSS            ram
+#endif
+
+#ifndef DATA_ADDR
+#define        DATA_ADDR
+#endif
+
+
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+
+MEMORY {
+       ram     : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
+#ifdef ROM_START
+       romvec  : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
+       rom     : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
+#endif
+}
+
+jiffies = jiffies_64 + 4;
+
+SECTIONS {
+
+#ifdef ROMVEC_START
+       . = ROMVEC_START ;
+       .romvec : {
+               __rom_start = . ;
+               _romvec = .;
+               *(.data..initvect)
+       } > romvec
+#endif
+
+       .text : {
+               _text = .;
+               _stext = . ;
+               HEAD_TEXT
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               *(.text..lock)
+
+               . = ALIGN(16);          /* Exception table              */
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+
+               *(.rodata) *(.rodata.*)
+               *(__vermagic)           /* Kernel version magic */
+               *(__markers_strings)
+               *(.rodata1)
+               *(.rodata.str1.1)
+
+               /* Kernel symbol table: Normal symbols */
+               . = ALIGN(4);
+               __start___ksymtab = .;
+               *(__ksymtab)
+               __stop___ksymtab = .;
+
+               /* Kernel symbol table: GPL-only symbols */
+               __start___ksymtab_gpl = .;
+               *(__ksymtab_gpl)
+               __stop___ksymtab_gpl = .;
+
+               /* Kernel symbol table: Normal unused symbols */
+               __start___ksymtab_unused = .;
+               *(__ksymtab_unused)
+               __stop___ksymtab_unused = .;
+
+               /* Kernel symbol table: GPL-only unused symbols */
+               __start___ksymtab_unused_gpl = .;
+               *(__ksymtab_unused_gpl)
+               __stop___ksymtab_unused_gpl = .;
+
+               /* Kernel symbol table: GPL-future symbols */
+               __start___ksymtab_gpl_future = .;
+               *(__ksymtab_gpl_future)
+               __stop___ksymtab_gpl_future = .;
+
+               /* Kernel symbol table: Normal symbols */
+               __start___kcrctab = .;
+               *(__kcrctab)
+               __stop___kcrctab = .;
+
+               /* Kernel symbol table: GPL-only symbols */
+               __start___kcrctab_gpl = .;
+               *(__kcrctab_gpl)
+               __stop___kcrctab_gpl = .;
+
+               /* Kernel symbol table: Normal unused symbols */
+               __start___kcrctab_unused = .;
+               *(__kcrctab_unused)
+               __stop___kcrctab_unused = .;
+
+               /* Kernel symbol table: GPL-only unused symbols */
+               __start___kcrctab_unused_gpl = .;
+               *(__kcrctab_unused_gpl)
+               __stop___kcrctab_unused_gpl = .;
+
+               /* Kernel symbol table: GPL-future symbols */
+               __start___kcrctab_gpl_future = .;
+               *(__kcrctab_gpl_future)
+               __stop___kcrctab_gpl_future = .;
+
+               /* Kernel symbol table: strings */
+               *(__ksymtab_strings)
+
+               /* Built-in module parameters */
+               . = ALIGN(4) ;
+               __start___param = .;
+               *(__param)
+               __stop___param = .;
+
+               /* Built-in module versions */
+               . = ALIGN(4) ;
+               __start___modver = .;
+               *(__modver)
+               __stop___modver = .;
+
+               . = ALIGN(4) ;
+               _etext = . ;
+       } > TEXT
+
+       .data DATA_ADDR : {
+               . = ALIGN(4);
+               _sdata = . ;
+               DATA_DATA
+               CACHELINE_ALIGNED_DATA(32)
+               PAGE_ALIGNED_DATA(PAGE_SIZE)
+               *(.data..shared_aligned)
+               INIT_TASK_DATA(THREAD_SIZE)
+               _edata = . ;
+       } > DATA
+
+       .init.text : {
+               . = ALIGN(PAGE_SIZE);
+               __init_begin = .;
+       } > INIT
+       INIT_TEXT_SECTION(PAGE_SIZE) > INIT
+       INIT_DATA_SECTION(16) > INIT
+       .init.data : {
+               . = ALIGN(PAGE_SIZE);
+               __init_end = .;
+       } > INIT
+
+       .bss : {
+               . = ALIGN(4);
+               _sbss = . ;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4) ;
+               _ebss = . ;
+               _end = . ;
+       } > BSSS
+
+       DISCARDS
+}
+
index af9abf8d9d98921458ed7ee5ef71c2ad1712befa..1f95881d843732f1abed9b0186687d793e59ecdc 100644 (file)
@@ -1,6 +1,5 @@
-#
-# Makefile for m68k-specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
-          checksum.o string.o uaccess.o
+ifdef CONFIG_MMU
+include arch/m68k/lib/Makefile_mm
+else
+include arch/m68k/lib/Makefile_no
+endif
diff --git a/arch/m68k/lib/Makefile_mm b/arch/m68k/lib/Makefile_mm
new file mode 100644 (file)
index 0000000..af9abf8
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for m68k-specific library files..
+#
+
+lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+          checksum.o string.o uaccess.o
diff --git a/arch/m68k/lib/Makefile_no b/arch/m68k/lib/Makefile_no
new file mode 100644 (file)
index 0000000..32d852e
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for m68knommu specific library files..
+#
+
+lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
+          muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
+          checksum.o memcpy.o memmove.o memset.o delay.o
index 6216f12a756b56121361639116794e35d8356ad2..1297536060de6089b8d65dddc834655a83f9b3dc 100644 (file)
@@ -1,425 +1,5 @@
-/*
- * INET                An implementation of the TCP/IP protocol suite for the LINUX
- *             operating system.  INET is implemented using the  BSD Socket
- *             interface as the means of communication with the user level.
- *
- *             IP/TCP/UDP checksumming routines
- *
- * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
- *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *             Tom May, <ftom@netcom.com>
- *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
- *             Lots of code moved from tcp.c and ip.c; see those files
- *             for more names.
- *
- * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
- *             Fixed some nasty bugs, causing some horrible crashes.
- *             A: At some points, the sum (%0) was used as
- *             length-counter instead of the length counter
- *             (%1). Thanks to Roman Hodek for pointing this out.
- *             B: GCC seems to mess up if one uses too many
- *             data-registers to hold input values and one tries to
- *             specify d0 and d1 as scratch registers. Letting gcc
- *             choose these registers itself solves the problem.
- *
- *             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.
- *
- * 1998/8/31   Andreas Schwab:
- *             Zero out rest of buffer on exception in
- *             csum_partial_copy_from_user.
- */
-
-#include <linux/module.h>
-#include <net/checksum.h>
-
-/*
- * computes a partial checksum, e.g. for TCP/UDP fragments
- */
-
-__wsum csum_partial(const void *buff, int len, __wsum sum)
-{
-       unsigned long tmp1, tmp2;
-         /*
-          * Experiments with ethernet and slip connections show that buff
-          * is aligned on either a 2-byte or 4-byte boundary.
-          */
-       __asm__("movel %2,%3\n\t"
-               "btst #1,%3\n\t"        /* Check alignment */
-               "jeq 2f\n\t"
-               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
-               "jgt 1f\n\t"
-               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
-               "jra 4f\n"
-            "1:\t"
-               "addw %2@+,%0\n\t"      /* add first word to sum */
-               "clrl %3\n\t"
-               "addxl %3,%0\n"         /* add X bit */
-            "2:\t"
-               /* unrolled loop for the main part: do 8 longs at once */
-               "movel %1,%3\n\t"       /* save len in tmp1 */
-               "lsrl #5,%1\n\t"        /* len/32 */
-               "jeq 2f\n\t"            /* not enough... */
-               "subql #1,%1\n"
-            "1:\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "dbra %1,1b\n\t"
-               "clrl %4\n\t"
-               "addxl %4,%0\n\t"       /* add X bit */
-               "clrw %1\n\t"
-               "subql #1,%1\n\t"
-               "jcc 1b\n"
-            "2:\t"
-               "movel %3,%1\n\t"       /* restore len from tmp1 */
-               "andw #0x1c,%3\n\t"     /* number of rest longs */
-               "jeq 4f\n\t"
-               "lsrw #2,%3\n\t"
-               "subqw #1,%3\n"
-            "3:\t"
-               /* loop for rest longs */
-               "movel %2@+,%4\n\t"
-               "addxl %4,%0\n\t"
-               "dbra %3,3b\n\t"
-               "clrl %4\n\t"
-               "addxl %4,%0\n"         /* add X bit */
-            "4:\t"
-               /* now check for rest bytes that do not fit into longs */
-               "andw #3,%1\n\t"
-               "jeq 7f\n\t"
-               "clrl %4\n\t"           /* clear tmp2 for rest bytes */
-               "subqw #2,%1\n\t"
-               "jlt 5f\n\t"
-               "movew %2@+,%4\n\t"     /* have rest >= 2: get word */
-               "swap %4\n\t"           /* into bits 16..31 */
-               "tstw %1\n\t"           /* another byte? */
-               "jeq 6f\n"
-            "5:\t"
-               "moveb %2@,%4\n\t"      /* have odd rest: get byte */
-               "lslw #8,%4\n\t"        /* into bits 8..15; 16..31 untouched */
-            "6:\t"
-               "addl %4,%0\n\t"        /* now add rest long to sum */
-               "clrl %4\n\t"
-               "addxl %4,%0\n"         /* add X bit */
-            "7:\t"
-               : "=d" (sum), "=d" (len), "=a" (buff),
-                 "=&d" (tmp1), "=&d" (tmp2)
-               : "0" (sum), "1" (len), "2" (buff)
-           );
-       return(sum);
-}
-
-EXPORT_SYMBOL(csum_partial);
-
-
-/*
- * copy from user space while checksumming, with exception handling.
- */
-
-__wsum
-csum_partial_copy_from_user(const void __user *src, void *dst,
-                           int len, __wsum sum, int *csum_err)
-{
-       /*
-        * GCC doesn't like more than 10 operands for the asm
-        * statements so we have to use tmp2 for the error
-        * code.
-        */
-       unsigned long tmp1, tmp2;
-
-       __asm__("movel %2,%4\n\t"
-               "btst #1,%4\n\t"        /* Check alignment */
-               "jeq 2f\n\t"
-               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
-               "jgt 1f\n\t"
-               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
-               "jra 4f\n"
-            "1:\n"
-            "10:\t"
-               "movesw %2@+,%4\n\t"    /* add first word to sum */
-               "addw %4,%0\n\t"
-               "movew %4,%3@+\n\t"
-               "clrl %4\n\t"
-               "addxl %4,%0\n"         /* add X bit */
-            "2:\t"
-               /* unrolled loop for the main part: do 8 longs at once */
-               "movel %1,%4\n\t"       /* save len in tmp1 */
-               "lsrl #5,%1\n\t"        /* len/32 */
-               "jeq 2f\n\t"            /* not enough... */
-               "subql #1,%1\n"
-            "1:\n"
-            "11:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "12:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "13:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "14:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "15:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "16:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "17:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-            "18:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "dbra %1,1b\n\t"
-               "clrl %5\n\t"
-               "addxl %5,%0\n\t"       /* add X bit */
-               "clrw %1\n\t"
-               "subql #1,%1\n\t"
-               "jcc 1b\n"
-            "2:\t"
-               "movel %4,%1\n\t"       /* restore len from tmp1 */
-               "andw #0x1c,%4\n\t"     /* number of rest longs */
-               "jeq 4f\n\t"
-               "lsrw #2,%4\n\t"
-               "subqw #1,%4\n"
-            "3:\n"
-               /* loop for rest longs */
-            "19:\t"
-               "movesl %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "dbra %4,3b\n\t"
-               "clrl %5\n\t"
-               "addxl %5,%0\n"         /* add X bit */
-            "4:\t"
-               /* now check for rest bytes that do not fit into longs */
-               "andw #3,%1\n\t"
-               "jeq 7f\n\t"
-               "clrl %5\n\t"           /* clear tmp2 for rest bytes */
-               "subqw #2,%1\n\t"
-               "jlt 5f\n\t"
-            "20:\t"
-               "movesw %2@+,%5\n\t"    /* have rest >= 2: get word */
-               "movew %5,%3@+\n\t"
-               "swap %5\n\t"           /* into bits 16..31 */
-               "tstw %1\n\t"           /* another byte? */
-               "jeq 6f\n"
-            "5:\n"
-            "21:\t"
-               "movesb %2@,%5\n\t"     /* have odd rest: get byte */
-               "moveb %5,%3@+\n\t"
-               "lslw #8,%5\n\t"        /* into bits 8..15; 16..31 untouched */
-            "6:\t"
-               "addl %5,%0\n\t"        /* now add rest long to sum */
-               "clrl %5\n\t"
-               "addxl %5,%0\n\t"       /* add X bit */
-            "7:\t"
-               "clrl %5\n"             /* no error - clear return value */
-            "8:\n"
-               ".section .fixup,\"ax\"\n"
-               ".even\n"
-               /* If any exception occurs zero out the rest.
-                  Similarities with the code above are intentional :-) */
-            "90:\t"
-               "clrw %3@+\n\t"
-               "movel %1,%4\n\t"
-               "lsrl #5,%1\n\t"
-               "jeq 1f\n\t"
-               "subql #1,%1\n"
-            "91:\t"
-               "clrl %3@+\n"
-            "92:\t"
-               "clrl %3@+\n"
-            "93:\t"
-               "clrl %3@+\n"
-            "94:\t"
-               "clrl %3@+\n"
-            "95:\t"
-               "clrl %3@+\n"
-            "96:\t"
-               "clrl %3@+\n"
-            "97:\t"
-               "clrl %3@+\n"
-            "98:\t"
-               "clrl %3@+\n\t"
-               "dbra %1,91b\n\t"
-               "clrw %1\n\t"
-               "subql #1,%1\n\t"
-               "jcc 91b\n"
-            "1:\t"
-               "movel %4,%1\n\t"
-               "andw #0x1c,%4\n\t"
-               "jeq 1f\n\t"
-               "lsrw #2,%4\n\t"
-               "subqw #1,%4\n"
-            "99:\t"
-               "clrl %3@+\n\t"
-               "dbra %4,99b\n\t"
-            "1:\t"
-               "andw #3,%1\n\t"
-               "jeq 9f\n"
-            "100:\t"
-               "clrw %3@+\n\t"
-               "tstw %1\n\t"
-               "jeq 9f\n"
-            "101:\t"
-               "clrb %3@+\n"
-            "9:\t"
-#define STR(X) STR1(X)
-#define STR1(X) #X
-               "moveq #-" STR(EFAULT) ",%5\n\t"
-               "jra 8b\n"
-               ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               ".long 10b,90b\n"
-               ".long 11b,91b\n"
-               ".long 12b,92b\n"
-               ".long 13b,93b\n"
-               ".long 14b,94b\n"
-               ".long 15b,95b\n"
-               ".long 16b,96b\n"
-               ".long 17b,97b\n"
-               ".long 18b,98b\n"
-               ".long 19b,99b\n"
-               ".long 20b,100b\n"
-               ".long 21b,101b\n"
-               ".previous"
-               : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
-                 "=&d" (tmp1), "=d" (tmp2)
-               : "0" (sum), "1" (len), "2" (src), "3" (dst)
-           );
-
-       *csum_err = tmp2;
-
-       return(sum);
-}
-
-EXPORT_SYMBOL(csum_partial_copy_from_user);
-
-
-/*
- * copy from kernel space while checksumming, otherwise like csum_partial
- */
-
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       unsigned long tmp1, tmp2;
-       __asm__("movel %2,%4\n\t"
-               "btst #1,%4\n\t"        /* Check alignment */
-               "jeq 2f\n\t"
-               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
-               "jgt 1f\n\t"
-               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
-               "jra 4f\n"
-            "1:\t"
-               "movew %2@+,%4\n\t"     /* add first word to sum */
-               "addw %4,%0\n\t"
-               "movew %4,%3@+\n\t"
-               "clrl %4\n\t"
-               "addxl %4,%0\n"         /* add X bit */
-            "2:\t"
-               /* unrolled loop for the main part: do 8 longs at once */
-               "movel %1,%4\n\t"       /* save len in tmp1 */
-               "lsrl #5,%1\n\t"        /* len/32 */
-               "jeq 2f\n\t"            /* not enough... */
-               "subql #1,%1\n"
-            "1:\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "dbra %1,1b\n\t"
-               "clrl %5\n\t"
-               "addxl %5,%0\n\t"       /* add X bit */
-               "clrw %1\n\t"
-               "subql #1,%1\n\t"
-               "jcc 1b\n"
-            "2:\t"
-               "movel %4,%1\n\t"       /* restore len from tmp1 */
-               "andw #0x1c,%4\n\t"     /* number of rest longs */
-               "jeq 4f\n\t"
-               "lsrw #2,%4\n\t"
-               "subqw #1,%4\n"
-            "3:\t"
-               /* loop for rest longs */
-               "movel %2@+,%5\n\t"
-               "addxl %5,%0\n\t"
-               "movel %5,%3@+\n\t"
-               "dbra %4,3b\n\t"
-               "clrl %5\n\t"
-               "addxl %5,%0\n"         /* add X bit */
-            "4:\t"
-               /* now check for rest bytes that do not fit into longs */
-               "andw #3,%1\n\t"
-               "jeq 7f\n\t"
-               "clrl %5\n\t"           /* clear tmp2 for rest bytes */
-               "subqw #2,%1\n\t"
-               "jlt 5f\n\t"
-               "movew %2@+,%5\n\t"     /* have rest >= 2: get word */
-               "movew %5,%3@+\n\t"
-               "swap %5\n\t"           /* into bits 16..31 */
-               "tstw %1\n\t"           /* another byte? */
-               "jeq 6f\n"
-            "5:\t"
-               "moveb %2@,%5\n\t"      /* have odd rest: get byte */
-               "moveb %5,%3@+\n\t"
-               "lslw #8,%5\n"          /* into bits 8..15; 16..31 untouched */
-            "6:\t"
-               "addl %5,%0\n\t"        /* now add rest long to sum */
-               "clrl %5\n\t"
-               "addxl %5,%0\n"         /* add X bit */
-            "7:\t"
-               : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
-                 "=&d" (tmp1), "=&d" (tmp2)
-               : "0" (sum), "1" (len), "2" (src), "3" (dst)
-           );
-    return(sum);
-}
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
+#ifdef CONFIG_MMU
+#include "checksum_mm.c"
+#else
+#include "checksum_no.c"
+#endif
diff --git a/arch/m68k/lib/checksum_mm.c b/arch/m68k/lib/checksum_mm.c
new file mode 100644 (file)
index 0000000..6216f12
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
+ *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *             Tom May, <ftom@netcom.com>
+ *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *             Fixed some nasty bugs, causing some horrible crashes.
+ *             A: At some points, the sum (%0) was used as
+ *             length-counter instead of the length counter
+ *             (%1). Thanks to Roman Hodek for pointing this out.
+ *             B: GCC seems to mess up if one uses too many
+ *             data-registers to hold input values and one tries to
+ *             specify d0 and d1 as scratch registers. Letting gcc
+ *             choose these registers itself solves the problem.
+ *
+ *             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.
+ *
+ * 1998/8/31   Andreas Schwab:
+ *             Zero out rest of buffer on exception in
+ *             csum_partial_copy_from_user.
+ */
+
+#include <linux/module.h>
+#include <net/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+       unsigned long tmp1, tmp2;
+         /*
+          * Experiments with ethernet and slip connections show that buff
+          * is aligned on either a 2-byte or 4-byte boundary.
+          */
+       __asm__("movel %2,%3\n\t"
+               "btst #1,%3\n\t"        /* Check alignment */
+               "jeq 2f\n\t"
+               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
+               "jgt 1f\n\t"
+               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
+               "jra 4f\n"
+            "1:\t"
+               "addw %2@+,%0\n\t"      /* add first word to sum */
+               "clrl %3\n\t"
+               "addxl %3,%0\n"         /* add X bit */
+            "2:\t"
+               /* unrolled loop for the main part: do 8 longs at once */
+               "movel %1,%3\n\t"       /* save len in tmp1 */
+               "lsrl #5,%1\n\t"        /* len/32 */
+               "jeq 2f\n\t"            /* not enough... */
+               "subql #1,%1\n"
+            "1:\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "dbra %1,1b\n\t"
+               "clrl %4\n\t"
+               "addxl %4,%0\n\t"       /* add X bit */
+               "clrw %1\n\t"
+               "subql #1,%1\n\t"
+               "jcc 1b\n"
+            "2:\t"
+               "movel %3,%1\n\t"       /* restore len from tmp1 */
+               "andw #0x1c,%3\n\t"     /* number of rest longs */
+               "jeq 4f\n\t"
+               "lsrw #2,%3\n\t"
+               "subqw #1,%3\n"
+            "3:\t"
+               /* loop for rest longs */
+               "movel %2@+,%4\n\t"
+               "addxl %4,%0\n\t"
+               "dbra %3,3b\n\t"
+               "clrl %4\n\t"
+               "addxl %4,%0\n"         /* add X bit */
+            "4:\t"
+               /* now check for rest bytes that do not fit into longs */
+               "andw #3,%1\n\t"
+               "jeq 7f\n\t"
+               "clrl %4\n\t"           /* clear tmp2 for rest bytes */
+               "subqw #2,%1\n\t"
+               "jlt 5f\n\t"
+               "movew %2@+,%4\n\t"     /* have rest >= 2: get word */
+               "swap %4\n\t"           /* into bits 16..31 */
+               "tstw %1\n\t"           /* another byte? */
+               "jeq 6f\n"
+            "5:\t"
+               "moveb %2@,%4\n\t"      /* have odd rest: get byte */
+               "lslw #8,%4\n\t"        /* into bits 8..15; 16..31 untouched */
+            "6:\t"
+               "addl %4,%0\n\t"        /* now add rest long to sum */
+               "clrl %4\n\t"
+               "addxl %4,%0\n"         /* add X bit */
+            "7:\t"
+               : "=d" (sum), "=d" (len), "=a" (buff),
+                 "=&d" (tmp1), "=&d" (tmp2)
+               : "0" (sum), "1" (len), "2" (buff)
+           );
+       return(sum);
+}
+
+EXPORT_SYMBOL(csum_partial);
+
+
+/*
+ * copy from user space while checksumming, with exception handling.
+ */
+
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst,
+                           int len, __wsum sum, int *csum_err)
+{
+       /*
+        * GCC doesn't like more than 10 operands for the asm
+        * statements so we have to use tmp2 for the error
+        * code.
+        */
+       unsigned long tmp1, tmp2;
+
+       __asm__("movel %2,%4\n\t"
+               "btst #1,%4\n\t"        /* Check alignment */
+               "jeq 2f\n\t"
+               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
+               "jgt 1f\n\t"
+               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
+               "jra 4f\n"
+            "1:\n"
+            "10:\t"
+               "movesw %2@+,%4\n\t"    /* add first word to sum */
+               "addw %4,%0\n\t"
+               "movew %4,%3@+\n\t"
+               "clrl %4\n\t"
+               "addxl %4,%0\n"         /* add X bit */
+            "2:\t"
+               /* unrolled loop for the main part: do 8 longs at once */
+               "movel %1,%4\n\t"       /* save len in tmp1 */
+               "lsrl #5,%1\n\t"        /* len/32 */
+               "jeq 2f\n\t"            /* not enough... */
+               "subql #1,%1\n"
+            "1:\n"
+            "11:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "12:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "13:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "14:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "15:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "16:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "17:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+            "18:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "dbra %1,1b\n\t"
+               "clrl %5\n\t"
+               "addxl %5,%0\n\t"       /* add X bit */
+               "clrw %1\n\t"
+               "subql #1,%1\n\t"
+               "jcc 1b\n"
+            "2:\t"
+               "movel %4,%1\n\t"       /* restore len from tmp1 */
+               "andw #0x1c,%4\n\t"     /* number of rest longs */
+               "jeq 4f\n\t"
+               "lsrw #2,%4\n\t"
+               "subqw #1,%4\n"
+            "3:\n"
+               /* loop for rest longs */
+            "19:\t"
+               "movesl %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "dbra %4,3b\n\t"
+               "clrl %5\n\t"
+               "addxl %5,%0\n"         /* add X bit */
+            "4:\t"
+               /* now check for rest bytes that do not fit into longs */
+               "andw #3,%1\n\t"
+               "jeq 7f\n\t"
+               "clrl %5\n\t"           /* clear tmp2 for rest bytes */
+               "subqw #2,%1\n\t"
+               "jlt 5f\n\t"
+            "20:\t"
+               "movesw %2@+,%5\n\t"    /* have rest >= 2: get word */
+               "movew %5,%3@+\n\t"
+               "swap %5\n\t"           /* into bits 16..31 */
+               "tstw %1\n\t"           /* another byte? */
+               "jeq 6f\n"
+            "5:\n"
+            "21:\t"
+               "movesb %2@,%5\n\t"     /* have odd rest: get byte */
+               "moveb %5,%3@+\n\t"
+               "lslw #8,%5\n\t"        /* into bits 8..15; 16..31 untouched */
+            "6:\t"
+               "addl %5,%0\n\t"        /* now add rest long to sum */
+               "clrl %5\n\t"
+               "addxl %5,%0\n\t"       /* add X bit */
+            "7:\t"
+               "clrl %5\n"             /* no error - clear return value */
+            "8:\n"
+               ".section .fixup,\"ax\"\n"
+               ".even\n"
+               /* If any exception occurs zero out the rest.
+                  Similarities with the code above are intentional :-) */
+            "90:\t"
+               "clrw %3@+\n\t"
+               "movel %1,%4\n\t"
+               "lsrl #5,%1\n\t"
+               "jeq 1f\n\t"
+               "subql #1,%1\n"
+            "91:\t"
+               "clrl %3@+\n"
+            "92:\t"
+               "clrl %3@+\n"
+            "93:\t"
+               "clrl %3@+\n"
+            "94:\t"
+               "clrl %3@+\n"
+            "95:\t"
+               "clrl %3@+\n"
+            "96:\t"
+               "clrl %3@+\n"
+            "97:\t"
+               "clrl %3@+\n"
+            "98:\t"
+               "clrl %3@+\n\t"
+               "dbra %1,91b\n\t"
+               "clrw %1\n\t"
+               "subql #1,%1\n\t"
+               "jcc 91b\n"
+            "1:\t"
+               "movel %4,%1\n\t"
+               "andw #0x1c,%4\n\t"
+               "jeq 1f\n\t"
+               "lsrw #2,%4\n\t"
+               "subqw #1,%4\n"
+            "99:\t"
+               "clrl %3@+\n\t"
+               "dbra %4,99b\n\t"
+            "1:\t"
+               "andw #3,%1\n\t"
+               "jeq 9f\n"
+            "100:\t"
+               "clrw %3@+\n\t"
+               "tstw %1\n\t"
+               "jeq 9f\n"
+            "101:\t"
+               "clrb %3@+\n"
+            "9:\t"
+#define STR(X) STR1(X)
+#define STR1(X) #X
+               "moveq #-" STR(EFAULT) ",%5\n\t"
+               "jra 8b\n"
+               ".previous\n"
+               ".section __ex_table,\"a\"\n"
+               ".long 10b,90b\n"
+               ".long 11b,91b\n"
+               ".long 12b,92b\n"
+               ".long 13b,93b\n"
+               ".long 14b,94b\n"
+               ".long 15b,95b\n"
+               ".long 16b,96b\n"
+               ".long 17b,97b\n"
+               ".long 18b,98b\n"
+               ".long 19b,99b\n"
+               ".long 20b,100b\n"
+               ".long 21b,101b\n"
+               ".previous"
+               : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+                 "=&d" (tmp1), "=d" (tmp2)
+               : "0" (sum), "1" (len), "2" (src), "3" (dst)
+           );
+
+       *csum_err = tmp2;
+
+       return(sum);
+}
+
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+
+/*
+ * copy from kernel space while checksumming, otherwise like csum_partial
+ */
+
+__wsum
+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+{
+       unsigned long tmp1, tmp2;
+       __asm__("movel %2,%4\n\t"
+               "btst #1,%4\n\t"        /* Check alignment */
+               "jeq 2f\n\t"
+               "subql #2,%1\n\t"       /* buff%4==2: treat first word */
+               "jgt 1f\n\t"
+               "addql #2,%1\n\t"       /* len was == 2, treat only rest */
+               "jra 4f\n"
+            "1:\t"
+               "movew %2@+,%4\n\t"     /* add first word to sum */
+               "addw %4,%0\n\t"
+               "movew %4,%3@+\n\t"
+               "clrl %4\n\t"
+               "addxl %4,%0\n"         /* add X bit */
+            "2:\t"
+               /* unrolled loop for the main part: do 8 longs at once */
+               "movel %1,%4\n\t"       /* save len in tmp1 */
+               "lsrl #5,%1\n\t"        /* len/32 */
+               "jeq 2f\n\t"            /* not enough... */
+               "subql #1,%1\n"
+            "1:\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "dbra %1,1b\n\t"
+               "clrl %5\n\t"
+               "addxl %5,%0\n\t"       /* add X bit */
+               "clrw %1\n\t"
+               "subql #1,%1\n\t"
+               "jcc 1b\n"
+            "2:\t"
+               "movel %4,%1\n\t"       /* restore len from tmp1 */
+               "andw #0x1c,%4\n\t"     /* number of rest longs */
+               "jeq 4f\n\t"
+               "lsrw #2,%4\n\t"
+               "subqw #1,%4\n"
+            "3:\t"
+               /* loop for rest longs */
+               "movel %2@+,%5\n\t"
+               "addxl %5,%0\n\t"
+               "movel %5,%3@+\n\t"
+               "dbra %4,3b\n\t"
+               "clrl %5\n\t"
+               "addxl %5,%0\n"         /* add X bit */
+            "4:\t"
+               /* now check for rest bytes that do not fit into longs */
+               "andw #3,%1\n\t"
+               "jeq 7f\n\t"
+               "clrl %5\n\t"           /* clear tmp2 for rest bytes */
+               "subqw #2,%1\n\t"
+               "jlt 5f\n\t"
+               "movew %2@+,%5\n\t"     /* have rest >= 2: get word */
+               "movew %5,%3@+\n\t"
+               "swap %5\n\t"           /* into bits 16..31 */
+               "tstw %1\n\t"           /* another byte? */
+               "jeq 6f\n"
+            "5:\t"
+               "moveb %2@,%5\n\t"      /* have odd rest: get byte */
+               "moveb %5,%3@+\n\t"
+               "lslw #8,%5\n"          /* into bits 8..15; 16..31 untouched */
+            "6:\t"
+               "addl %5,%0\n\t"        /* now add rest long to sum */
+               "clrl %5\n\t"
+               "addxl %5,%0\n"         /* add X bit */
+            "7:\t"
+               : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+                 "=&d" (tmp1), "=&d" (tmp2)
+               : "0" (sum), "1" (len), "2" (src), "3" (dst)
+           );
+    return(sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
diff --git a/arch/m68k/lib/checksum_no.c b/arch/m68k/lib/checksum_no.c
new file mode 100644 (file)
index 0000000..eccf25d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
+ *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *             Tom May, <ftom@netcom.com>
+ *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *             Fixed some nasty bugs, causing some horrible crashes.
+ *             A: At some points, the sum (%0) was used as
+ *             length-counter instead of the length counter
+ *             (%1). Thanks to Roman Hodek for pointing this out.
+ *             B: GCC seems to mess up if one uses too many
+ *             data-registers to hold input values and one tries to
+ *             specify d0 and d1 as scratch registers. Letting gcc choose these
+ *      registers itself solves the problem.
+ *
+ *             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.
+ */
+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most
+   of the assembly has to go. */
+
+#include <linux/module.h>
+#include <net/checksum.h>
+
+static inline unsigned short from32to16(unsigned long x)
+{
+       /* add up 16-bit and 16-bit for 16+c bit */
+       x = (x & 0xffff) + (x >> 16);
+       /* add up carry.. */
+       x = (x & 0xffff) + (x >> 16);
+       return x;
+}
+
+static unsigned long do_csum(const unsigned char * buff, int len)
+{
+       int odd, count;
+       unsigned long result = 0;
+
+       if (len <= 0)
+               goto out;
+       odd = 1 & (unsigned long) buff;
+       if (odd) {
+               result = *buff;
+               len--;
+               buff++;
+       }
+       count = len >> 1;               /* nr of 16-bit words.. */
+       if (count) {
+               if (2 & (unsigned long) buff) {
+                       result += *(unsigned short *) buff;
+                       count--;
+                       len -= 2;
+                       buff += 2;
+               }
+               count >>= 1;            /* nr of 32-bit words.. */
+               if (count) {
+                       unsigned long carry = 0;
+                       do {
+                               unsigned long w = *(unsigned long *) buff;
+                               count--;
+                               buff += 4;
+                               result += carry;
+                               result += w;
+                               carry = (w > result);
+                       } while (count);
+                       result += carry;
+                       result = (result & 0xffff) + (result >> 16);
+               }
+               if (len & 2) {
+                       result += *(unsigned short *) buff;
+                       buff += 2;
+               }
+       }
+       if (len & 1)
+               result += (*buff << 8);
+       result = from32to16(result);
+       if (odd)
+               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+       return result;
+}
+
+#ifdef CONFIG_COLDFIRE
+/*
+ *     This is a version of ip_compute_csum() optimized for IP headers,
+ *     which always checksum on 4 octet boundaries.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+       return (__force __sum16)~do_csum(iph,ihl*4);
+}
+#endif
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+       unsigned int result = do_csum(buff, len);
+
+       /* add in old sum, and carry.. */
+       result += (__force u32)sum;
+       if ((__force u32)sum > result)
+               result += 1;
+       return (__force __wsum)result;
+}
+
+EXPORT_SYMBOL(csum_partial);
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst,
+                           int len, __wsum sum, int *csum_err)
+{
+       if (csum_err) *csum_err = 0;
+       memcpy(dst, (__force const void *)src, len);
+       return csum_partial(dst, len, sum);
+}
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+__wsum
+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+{
+       memcpy(dst, src, len);
+       return csum_partial(dst, len, sum);
+}
diff --git a/arch/m68k/lib/delay.c b/arch/m68k/lib/delay.c
new file mode 100644 (file)
index 0000000..5bd5472
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *     arch/m68knommu/lib/delay.c
+ *
+ *     (C) Copyright 2004, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <asm/param.h>
+#include <asm/delay.h>
+
+EXPORT_SYMBOL(udelay);
+
+void udelay(unsigned long usecs)
+{
+       _udelay(usecs);
+}
+
diff --git a/arch/m68k/lib/divsi3.S b/arch/m68k/lib/divsi3.S
new file mode 100644 (file)
index 0000000..ec307b6
--- /dev/null
@@ -0,0 +1,125 @@
+/* libgcc1 routines for 68000 w/o floating-point hardware.
+   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* Use this one for any 680x0; assumes no floating point hardware.
+   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
+   Some of this code comes from MINIX, via the folks at ericsson.
+   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
+*/
+
+/* These are predefined by new versions of GNU cpp.  */
+
+#ifndef __USER_LABEL_PREFIX__
+#define __USER_LABEL_PREFIX__ _
+#endif
+
+#ifndef __REGISTER_PREFIX__
+#define __REGISTER_PREFIX__
+#endif
+
+#ifndef __IMMEDIATE_PREFIX__
+#define __IMMEDIATE_PREFIX__ #
+#endif
+
+/* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+/* Use the right prefix for registers.  */
+
+#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
+
+/* Use the right prefix for immediate values.  */
+
+#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
+
+#define d0 REG (d0)
+#define d1 REG (d1)
+#define d2 REG (d2)
+#define d3 REG (d3)
+#define d4 REG (d4)
+#define d5 REG (d5)
+#define d6 REG (d6)
+#define d7 REG (d7)
+#define a0 REG (a0)
+#define a1 REG (a1)
+#define a2 REG (a2)
+#define a3 REG (a3)
+#define a4 REG (a4)
+#define a5 REG (a5)
+#define a6 REG (a6)
+#define fp REG (fp)
+#define sp REG (sp)
+
+       .text
+       .proc
+       .globl  SYM (__divsi3)
+SYM (__divsi3):
+       movel   d2, sp@-
+
+       moveq   IMM (1), d2     /* sign of result stored in d2 (=1 or =-1) */
+       movel   sp@(12), d1     /* d1 = divisor */
+       jpl     L1
+       negl    d1
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       negb    d2              /* change sign because divisor <0  */
+#else
+       negl    d2              /* change sign because divisor <0  */
+#endif
+L1:    movel   sp@(8), d0      /* d0 = dividend */
+       jpl     L2
+       negl    d0
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       negb    d2
+#else
+       negl    d2
+#endif
+
+L2:    movel   d1, sp@-
+       movel   d0, sp@-
+       jbsr    SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */
+       addql   IMM (8), sp
+
+       tstb    d2
+       jpl     L3
+       negl    d0
+
+L3:    movel   sp@+, d2
+       rts
+
diff --git a/arch/m68k/lib/memcpy.c b/arch/m68k/lib/memcpy.c
new file mode 100644 (file)
index 0000000..b50dbca
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include <linux/types.h>
+
+void * memcpy(void * to, const void * from, size_t n)
+{
+#ifdef CONFIG_COLDFIRE
+  void *xto = to;
+  size_t temp;
+
+  if (!n)
+    return xto;
+  if ((long) to & 1)
+    {
+      char *cto = to;
+      const char *cfrom = from;
+      *cto++ = *cfrom++;
+      to = cto;
+      from = cfrom;
+      n--;
+    }
+  if (n > 2 && (long) to & 2)
+    {
+      short *sto = to;
+      const short *sfrom = from;
+      *sto++ = *sfrom++;
+      to = sto;
+      from = sfrom;
+      n -= 2;
+    }
+  temp = n >> 2;
+  if (temp)
+    {
+      long *lto = to;
+      const long *lfrom = from;
+      for (; temp; temp--)
+       *lto++ = *lfrom++;
+      to = lto;
+      from = lfrom;
+    }
+  if (n & 2)
+    {
+      short *sto = to;
+      const short *sfrom = from;
+      *sto++ = *sfrom++;
+      to = sto;
+      from = sfrom;
+    }
+  if (n & 1)
+    {
+      char *cto = to;
+      const char *cfrom = from;
+      *cto = *cfrom;
+    }
+  return xto;
+#else
+  const char *c_from = from;
+  char *c_to = to;
+  while (n-- > 0)
+    *c_to++ = *c_from++;
+  return((void *) to);
+#endif
+}
diff --git a/arch/m68k/lib/memmove.c b/arch/m68k/lib/memmove.c
new file mode 100644 (file)
index 0000000..b3dcfe9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#define __IN_STRING_C
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       void *xdest = dest;
+       size_t temp;
+
+       if (!n)
+               return xdest;
+
+       if (dest < src) {
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest++ = *csrc++;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *ldest++ = *lsrc++;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest = *csrc;
+               }
+       } else {
+               dest = (char *)dest + n;
+               src = (const char *)src + n;
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *--ldest = *--lsrc;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+               }
+       }
+       return xdest;
+}
+EXPORT_SYMBOL(memmove);
diff --git a/arch/m68k/lib/memset.c b/arch/m68k/lib/memset.c
new file mode 100644 (file)
index 0000000..1389bf4
--- /dev/null
@@ -0,0 +1,47 @@
+#include <linux/types.h>
+
+void * memset(void * s, int c, size_t count)
+{
+  void *xs = s;
+  size_t temp;
+
+  if (!count)
+    return xs;
+  c &= 0xff;
+  c |= c << 8;
+  c |= c << 16;
+  if ((long) s & 1)
+    {
+      char *cs = s;
+      *cs++ = c;
+      s = cs;
+      count--;
+    }
+  if (count > 2 && (long) s & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+      count -= 2;
+    }
+  temp = count >> 2;
+  if (temp)
+    {
+      long *ls = s;
+      for (; temp; temp--)
+       *ls++ = c;
+      s = ls;
+    }
+  if (count & 2)
+    {
+      short *ss = s;
+      *ss++ = c;
+      s = ss;
+    }
+  if (count & 1)
+    {
+      char *cs = s;
+      *cs = c;
+    }
+  return xs;
+}
diff --git a/arch/m68k/lib/modsi3.S b/arch/m68k/lib/modsi3.S
new file mode 100644 (file)
index 0000000..ef38494
--- /dev/null
@@ -0,0 +1,113 @@
+/* libgcc1 routines for 68000 w/o floating-point hardware.
+   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* Use this one for any 680x0; assumes no floating point hardware.
+   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
+   Some of this code comes from MINIX, via the folks at ericsson.
+   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
+*/
+
+/* These are predefined by new versions of GNU cpp.  */
+
+#ifndef __USER_LABEL_PREFIX__
+#define __USER_LABEL_PREFIX__ _
+#endif
+
+#ifndef __REGISTER_PREFIX__
+#define __REGISTER_PREFIX__
+#endif
+
+#ifndef __IMMEDIATE_PREFIX__
+#define __IMMEDIATE_PREFIX__ #
+#endif
+
+/* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+/* Use the right prefix for registers.  */
+
+#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
+
+/* Use the right prefix for immediate values.  */
+
+#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
+
+#define d0 REG (d0)
+#define d1 REG (d1)
+#define d2 REG (d2)
+#define d3 REG (d3)
+#define d4 REG (d4)
+#define d5 REG (d5)
+#define d6 REG (d6)
+#define d7 REG (d7)
+#define a0 REG (a0)
+#define a1 REG (a1)
+#define a2 REG (a2)
+#define a3 REG (a3)
+#define a4 REG (a4)
+#define a5 REG (a5)
+#define a6 REG (a6)
+#define fp REG (fp)
+#define sp REG (sp)
+
+       .text
+       .proc
+       .globl  SYM (__modsi3)
+SYM (__modsi3):
+       movel   sp@(8), d1      /* d1 = divisor */
+       movel   sp@(4), d0      /* d0 = dividend */
+       movel   d1, sp@-
+       movel   d0, sp@-
+       jbsr    SYM (__divsi3)
+       addql   IMM (8), sp
+       movel   sp@(8), d1      /* d1 = divisor */
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       movel   d1, sp@-
+       movel   d0, sp@-
+       jbsr    SYM (__mulsi3)  /* d0 = (a/b)*b */
+       addql   IMM (8), sp
+#else
+       mulsl   d1,d0
+#endif
+       movel   sp@(4), d1      /* d1 = dividend */
+       subl    d0, d1          /* d1 = a - (a/b)*b */
+       movel   d1, d0
+       rts
+
index be4f275649e317a8ae10301d0ffec76c8b4f5441..16e0eb338ee0e5303a44fa3180f0bcdcd08e3d0d 100644 (file)
@@ -1,63 +1,5 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("mulu%.l %3,%1:%0"                                          \
-           : "=d" ((USItype)(w0)),                                     \
-             "=d" ((USItype)(w1))                                      \
-           : "%0" ((USItype)(u)),                                      \
-             "dmi" ((USItype)(v)))
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef                 int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
+#ifdef CONFIG_MMU
+#include "muldi3_mm.c"
+#else
+#include "muldi3_no.c"
+#endif
diff --git a/arch/m68k/lib/muldi3_mm.c b/arch/m68k/lib/muldi3_mm.c
new file mode 100644 (file)
index 0000000..be4f275
--- /dev/null
@@ -0,0 +1,63 @@
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
+                          gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu%.l %3,%1:%0"                                          \
+           : "=d" ((USItype)(w0)),                                     \
+             "=d" ((USItype)(w1))                                      \
+           : "%0" ((USItype)(u)),                                      \
+             "dmi" ((USItype)(v)))
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;                                                       \
+    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
+    __w.ll; })
+
+typedef                 int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+              + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
diff --git a/arch/m68k/lib/muldi3_no.c b/arch/m68k/lib/muldi3_no.c
new file mode 100644 (file)
index 0000000..34af72c
--- /dev/null
@@ -0,0 +1,86 @@
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
+                          gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+#define SI_TYPE_SIZE 32
+
+#define __BITS4 (SI_TYPE_SIZE / 4)
+#define __ll_B (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
+#define __ll_highpart(t) ((USItype) (t) / __ll_B)
+
+#define umul_ppmm(w1, w0, u, v)                                                \
+  do {                                                                 \
+    USItype __x0, __x1, __x2, __x3;                                    \
+    USItype __ul, __vl, __uh, __vh;                                    \
+                                                                       \
+    __ul = __ll_lowpart (u);                                           \
+    __uh = __ll_highpart (u);                                          \
+    __vl = __ll_lowpart (v);                                           \
+    __vh = __ll_highpart (v);                                          \
+                                                                       \
+    __x0 = (USItype) __ul * __vl;                                      \
+    __x1 = (USItype) __ul * __vh;                                      \
+    __x2 = (USItype) __uh * __vl;                                      \
+    __x3 = (USItype) __uh * __vh;                                      \
+                                                                       \
+    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
+    __x1 += __x2;              /* but this indeed can */               \
+    if (__x1 < __x2)           /* did we get it? */                    \
+      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
+                                                                       \
+    (w1) = __x3 + __ll_highpart (__x1);                                        \
+    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
+  } while (0)
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;                                                       \
+    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
+    __w.ll; })
+
+typedef         int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+              + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
diff --git a/arch/m68k/lib/mulsi3.S b/arch/m68k/lib/mulsi3.S
new file mode 100644 (file)
index 0000000..ce29ea3
--- /dev/null
@@ -0,0 +1,110 @@
+/* libgcc1 routines for 68000 w/o floating-point hardware.
+   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* Use this one for any 680x0; assumes no floating point hardware.
+   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
+   Some of this code comes from MINIX, via the folks at ericsson.
+   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
+*/
+
+/* These are predefined by new versions of GNU cpp.  */
+
+#ifndef __USER_LABEL_PREFIX__
+#define __USER_LABEL_PREFIX__ _
+#endif
+
+#ifndef __REGISTER_PREFIX__
+#define __REGISTER_PREFIX__
+#endif
+
+#ifndef __IMMEDIATE_PREFIX__
+#define __IMMEDIATE_PREFIX__ #
+#endif
+
+/* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+/* Use the right prefix for registers.  */
+
+#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
+
+/* Use the right prefix for immediate values.  */
+
+#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
+
+#define d0 REG (d0)
+#define d1 REG (d1)
+#define d2 REG (d2)
+#define d3 REG (d3)
+#define d4 REG (d4)
+#define d5 REG (d5)
+#define d6 REG (d6)
+#define d7 REG (d7)
+#define a0 REG (a0)
+#define a1 REG (a1)
+#define a2 REG (a2)
+#define a3 REG (a3)
+#define a4 REG (a4)
+#define a5 REG (a5)
+#define a6 REG (a6)
+#define fp REG (fp)
+#define sp REG (sp)
+
+       .text
+       .proc
+       .globl  SYM (__mulsi3)
+SYM (__mulsi3):
+       movew   sp@(4), d0      /* x0 -> d0 */
+       muluw   sp@(10), d0     /* x0*y1 */
+       movew   sp@(6), d1      /* x1 -> d1 */
+       muluw   sp@(8), d1      /* x1*y0 */
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       addw    d1, d0
+#else
+       addl    d1, d0
+#endif
+       swap    d0
+       clrw    d0
+       movew   sp@(6), d1      /* x1 -> d1 */
+       muluw   sp@(10), d1     /* x1*y1 */
+       addl    d1, d0
+
+       rts
+
diff --git a/arch/m68k/lib/udivsi3.S b/arch/m68k/lib/udivsi3.S
new file mode 100644 (file)
index 0000000..c424c4a
--- /dev/null
@@ -0,0 +1,162 @@
+/* libgcc1 routines for 68000 w/o floating-point hardware.
+   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* Use this one for any 680x0; assumes no floating point hardware.
+   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
+   Some of this code comes from MINIX, via the folks at ericsson.
+   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
+*/
+
+/* These are predefined by new versions of GNU cpp.  */
+
+#ifndef __USER_LABEL_PREFIX__
+#define __USER_LABEL_PREFIX__ _
+#endif
+
+#ifndef __REGISTER_PREFIX__
+#define __REGISTER_PREFIX__
+#endif
+
+#ifndef __IMMEDIATE_PREFIX__
+#define __IMMEDIATE_PREFIX__ #
+#endif
+
+/* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+/* Use the right prefix for registers.  */
+
+#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
+
+/* Use the right prefix for immediate values.  */
+
+#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
+
+#define d0 REG (d0)
+#define d1 REG (d1)
+#define d2 REG (d2)
+#define d3 REG (d3)
+#define d4 REG (d4)
+#define d5 REG (d5)
+#define d6 REG (d6)
+#define d7 REG (d7)
+#define a0 REG (a0)
+#define a1 REG (a1)
+#define a2 REG (a2)
+#define a3 REG (a3)
+#define a4 REG (a4)
+#define a5 REG (a5)
+#define a6 REG (a6)
+#define fp REG (fp)
+#define sp REG (sp)
+
+       .text
+       .proc
+       .globl  SYM (__udivsi3)
+SYM (__udivsi3):
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       movel   d2, sp@-
+       movel   sp@(12), d1     /* d1 = divisor */
+       movel   sp@(8), d0      /* d0 = dividend */
+
+       cmpl    IMM (0x10000), d1 /* divisor >= 2 ^ 16 ?   */
+       jcc     L3              /* then try next algorithm */
+       movel   d0, d2
+       clrw    d2
+       swap    d2
+       divu    d1, d2          /* high quotient in lower word */
+       movew   d2, d0          /* save high quotient */
+       swap    d0
+       movew   sp@(10), d2     /* get low dividend + high rest */
+       divu    d1, d2          /* low quotient */
+       movew   d2, d0
+       jra     L6
+
+L3:    movel   d1, d2          /* use d2 as divisor backup */
+L4:    lsrl    IMM (1), d1     /* shift divisor */
+       lsrl    IMM (1), d0     /* shift dividend */
+       cmpl    IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ?  */
+       jcc     L4
+       divu    d1, d0          /* now we have 16 bit divisor */
+       andl    IMM (0xffff), d0 /* mask out divisor, ignore remainder */
+
+/* Multiply the 16 bit tentative quotient with the 32 bit divisor.  Because of
+   the operand ranges, this might give a 33 bit product.  If this product is
+   greater than the dividend, the tentative quotient was too large. */
+       movel   d2, d1
+       mulu    d0, d1          /* low part, 32 bits */
+       swap    d2
+       mulu    d0, d2          /* high part, at most 17 bits */
+       swap    d2              /* align high part with low part */
+       tstw    d2              /* high part 17 bits? */
+       jne     L5              /* if 17 bits, quotient was too large */
+       addl    d2, d1          /* add parts */
+       jcs     L5              /* if sum is 33 bits, quotient was too large */
+       cmpl    sp@(8), d1      /* compare the sum with the dividend */
+       jls     L6              /* if sum > dividend, quotient was too large */
+L5:    subql   IMM (1), d0     /* adjust quotient */
+
+L6:    movel   sp@+, d2
+       rts
+
+#else /* __mcf5200__ || __mcoldfire__ */
+
+/* Coldfire implementation of non-restoring division algorithm from
+   Hennessy & Patterson, Appendix A. */
+       link    a6,IMM (-12)
+       moveml  d2-d4,sp@
+       movel   a6@(8),d0
+       movel   a6@(12),d1
+       clrl    d2              | clear p
+       moveq   IMM (31),d4
+L1:    addl    d0,d0           | shift reg pair (p,a) one bit left
+       addxl   d2,d2
+       movl    d2,d3           | subtract b from p, store in tmp.
+       subl    d1,d3
+       jcs     L2              | if no carry,
+       bset    IMM (0),d0      | set the low order bit of a to 1,
+       movl    d3,d2           | and store tmp in p.
+L2:    subql   IMM (1),d4
+       jcc     L1
+       moveml  sp@,d2-d4       | restore data registers
+       unlk    a6              | and return
+       rts
+#endif /* __mcf5200__ || __mcoldfire__ */
+
diff --git a/arch/m68k/lib/umodsi3.S b/arch/m68k/lib/umodsi3.S
new file mode 100644 (file)
index 0000000..5def5f6
--- /dev/null
@@ -0,0 +1,113 @@
+/* libgcc1 routines for 68000 w/o floating-point hardware.
+   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* Use this one for any 680x0; assumes no floating point hardware.
+   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
+   Some of this code comes from MINIX, via the folks at ericsson.
+   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
+*/
+
+/* These are predefined by new versions of GNU cpp.  */
+
+#ifndef __USER_LABEL_PREFIX__
+#define __USER_LABEL_PREFIX__ _
+#endif
+
+#ifndef __REGISTER_PREFIX__
+#define __REGISTER_PREFIX__
+#endif
+
+#ifndef __IMMEDIATE_PREFIX__
+#define __IMMEDIATE_PREFIX__ #
+#endif
+
+/* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+/* Use the right prefix for registers.  */
+
+#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
+
+/* Use the right prefix for immediate values.  */
+
+#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
+
+#define d0 REG (d0)
+#define d1 REG (d1)
+#define d2 REG (d2)
+#define d3 REG (d3)
+#define d4 REG (d4)
+#define d5 REG (d5)
+#define d6 REG (d6)
+#define d7 REG (d7)
+#define a0 REG (a0)
+#define a1 REG (a1)
+#define a2 REG (a2)
+#define a3 REG (a3)
+#define a4 REG (a4)
+#define a5 REG (a5)
+#define a6 REG (a6)
+#define fp REG (fp)
+#define sp REG (sp)
+
+       .text
+       .proc
+       .globl  SYM (__umodsi3)
+SYM (__umodsi3):
+       movel   sp@(8), d1      /* d1 = divisor */
+       movel   sp@(4), d0      /* d0 = dividend */
+       movel   d1, sp@-
+       movel   d0, sp@-
+       jbsr    SYM (__udivsi3)
+       addql   IMM (8), sp
+       movel   sp@(8), d1      /* d1 = divisor */
+#if !(defined(__mcf5200__) || defined(__mcoldfire__))
+       movel   d1, sp@-
+       movel   d0, sp@-
+       jbsr    SYM (__mulsi3)  /* d0 = (a/b)*b */
+       addql   IMM (8), sp
+#else
+       mulsl   d1,d0
+#endif
+       movel   sp@(4), d1      /* d1 = dividend */
+       subl    d0, d1          /* d1 = a - (a/b)*b */
+       movel   d1, d0
+       rts
+
index 5eaa43c4cb3c81c02317ad162c5404ad76f96b81..b60270e4954bb256e17ca0af97341d3d1766efec 100644 (file)
@@ -1,8 +1,5 @@
-#
-# Makefile for the linux m68k-specific parts of the memory manager.
-#
-
-obj-y          := cache.o init.o fault.o hwtest.o
-
-obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
-obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
+ifdef CONFIG_MMU
+include arch/m68k/mm/Makefile_mm
+else
+include arch/m68k/mm/Makefile_no
+endif
diff --git a/arch/m68k/mm/Makefile_mm b/arch/m68k/mm/Makefile_mm
new file mode 100644 (file)
index 0000000..5eaa43c
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux m68k-specific parts of the memory manager.
+#
+
+obj-y          := cache.o init.o fault.o hwtest.o
+
+obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
+obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_no b/arch/m68k/mm/Makefile_no
new file mode 100644 (file)
index 0000000..b54ab6b
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux m68knommu specific parts of the memory manager.
+#
+
+obj-y += init.o kmap.o
index 8bc842554e5b4618ad3e77208dc5872cd184fef2..27b5ce089a34f5e33afae745490f3462311482e2 100644 (file)
@@ -1,150 +1,5 @@
-/*
- *  linux/arch/m68k/mm/init.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  Contains common initialization routines, specific init code moved
- *  to motorola.c and sun3mmu.c
- */
-
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/gfp.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/system.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#ifdef CONFIG_ATARI
-#include <asm/atari_stram.h>
-#endif
-#include <asm/sections.h>
-#include <asm/tlb.h>
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-pg_data_t pg_data_map[MAX_NUMNODES];
-EXPORT_SYMBOL(pg_data_map);
-
-int m68k_virt_to_node_shift;
-
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-pg_data_t *pg_data_table[65];
-EXPORT_SYMBOL(pg_data_table);
-#endif
-
-void __init m68k_setup_node(int node)
-{
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-       struct mem_info *info = m68k_memory + node;
-       int i, end;
-
-       i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift();
-       end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift();
-       for (; i <= end; i++) {
-               if (pg_data_table[i])
-                       printk("overlap at %u for chunk %u\n", i, node);
-               pg_data_table[i] = pg_data_map + node;
-       }
-#endif
-       pg_data_map[node].bdata = bootmem_node_data + node;
-       node_set_online(node);
-}
-
-
-/*
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-
-void *empty_zero_page;
-EXPORT_SYMBOL(empty_zero_page);
-
-extern void init_pointer_table(unsigned long ptable);
-
-/* References to section boundaries */
-
-extern pmd_t *zero_pgtable;
-
-void __init mem_init(void)
-{
-       pg_data_t *pgdat;
-       int codepages = 0;
-       int datapages = 0;
-       int initpages = 0;
-       int i;
-
-#ifdef CONFIG_ATARI
-       if (MACH_IS_ATARI)
-               atari_stram_mem_init_hook();
-#endif
-
-       /* this will put all memory onto the freelists */
-       totalram_pages = num_physpages = 0;
-       for_each_online_pgdat(pgdat) {
-               num_physpages += pgdat->node_present_pages;
-
-               totalram_pages += free_all_bootmem_node(pgdat);
-               for (i = 0; i < pgdat->node_spanned_pages; i++) {
-                       struct page *page = pgdat->node_mem_map + i;
-                       char *addr = page_to_virt(page);
-
-                       if (!PageReserved(page))
-                               continue;
-                       if (addr >= _text &&
-                           addr < _etext)
-                               codepages++;
-                       else if (addr >= __init_begin &&
-                                addr < __init_end)
-                               initpages++;
-                       else
-                               datapages++;
-               }
-       }
-
-#ifndef CONFIG_SUN3
-       /* insert pointer tables allocated so far into the tablelist */
-       init_pointer_table((unsigned long)kernel_pg_dir);
-       for (i = 0; i < PTRS_PER_PGD; i++) {
-               if (pgd_present(kernel_pg_dir[i]))
-                       init_pointer_table(__pgd_page(kernel_pg_dir[i]));
-       }
-
-       /* insert also pointer table that we used to unmap the zero page */
-       if (zero_pgtable)
-               init_pointer_table((unsigned long)zero_pgtable);
-#endif
-
-       printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              totalram_pages << (PAGE_SHIFT-10),
-              codepages << (PAGE_SHIFT-10),
-              datapages << (PAGE_SHIFT-10),
-              initpages << (PAGE_SHIFT-10));
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       int pages = 0;
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               init_page_count(virt_to_page(start));
-               free_page(start);
-               totalram_pages++;
-               pages++;
-       }
-       printk ("Freeing initrd memory: %dk freed\n", pages);
-}
+#ifdef CONFIG_MMU
+#include "init_mm.c"
+#else
+#include "init_no.c"
 #endif
diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c
new file mode 100644 (file)
index 0000000..8bc8425
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  linux/arch/m68k/mm/init.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  Contains common initialization routines, specific init code moved
+ *  to motorola.c and sun3mmu.c
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#ifdef CONFIG_ATARI
+#include <asm/atari_stram.h>
+#endif
+#include <asm/sections.h>
+#include <asm/tlb.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+pg_data_t pg_data_map[MAX_NUMNODES];
+EXPORT_SYMBOL(pg_data_map);
+
+int m68k_virt_to_node_shift;
+
+#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+pg_data_t *pg_data_table[65];
+EXPORT_SYMBOL(pg_data_table);
+#endif
+
+void __init m68k_setup_node(int node)
+{
+#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+       struct mem_info *info = m68k_memory + node;
+       int i, end;
+
+       i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift();
+       end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift();
+       for (; i <= end; i++) {
+               if (pg_data_table[i])
+                       printk("overlap at %u for chunk %u\n", i, node);
+               pg_data_table[i] = pg_data_map + node;
+       }
+#endif
+       pg_data_map[node].bdata = bootmem_node_data + node;
+       node_set_online(node);
+}
+
+
+/*
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+
+void *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
+
+extern void init_pointer_table(unsigned long ptable);
+
+/* References to section boundaries */
+
+extern pmd_t *zero_pgtable;
+
+void __init mem_init(void)
+{
+       pg_data_t *pgdat;
+       int codepages = 0;
+       int datapages = 0;
+       int initpages = 0;
+       int i;
+
+#ifdef CONFIG_ATARI
+       if (MACH_IS_ATARI)
+               atari_stram_mem_init_hook();
+#endif
+
+       /* this will put all memory onto the freelists */
+       totalram_pages = num_physpages = 0;
+       for_each_online_pgdat(pgdat) {
+               num_physpages += pgdat->node_present_pages;
+
+               totalram_pages += free_all_bootmem_node(pgdat);
+               for (i = 0; i < pgdat->node_spanned_pages; i++) {
+                       struct page *page = pgdat->node_mem_map + i;
+                       char *addr = page_to_virt(page);
+
+                       if (!PageReserved(page))
+                               continue;
+                       if (addr >= _text &&
+                           addr < _etext)
+                               codepages++;
+                       else if (addr >= __init_begin &&
+                                addr < __init_end)
+                               initpages++;
+                       else
+                               datapages++;
+               }
+       }
+
+#ifndef CONFIG_SUN3
+       /* insert pointer tables allocated so far into the tablelist */
+       init_pointer_table((unsigned long)kernel_pg_dir);
+       for (i = 0; i < PTRS_PER_PGD; i++) {
+               if (pgd_present(kernel_pg_dir[i]))
+                       init_pointer_table(__pgd_page(kernel_pg_dir[i]));
+       }
+
+       /* insert also pointer table that we used to unmap the zero page */
+       if (zero_pgtable)
+               init_pointer_table((unsigned long)zero_pgtable);
+#endif
+
+       printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
+              nr_free_pages() << (PAGE_SHIFT-10),
+              totalram_pages << (PAGE_SHIFT-10),
+              codepages << (PAGE_SHIFT-10),
+              datapages << (PAGE_SHIFT-10),
+              initpages << (PAGE_SHIFT-10));
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       int pages = 0;
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               init_page_count(virt_to_page(start));
+               free_page(start);
+               totalram_pages++;
+               pages++;
+       }
+       printk ("Freeing initrd memory: %dk freed\n", pages);
+}
+#endif
diff --git a/arch/m68k/mm/init_no.c b/arch/m68k/mm/init_no.c
new file mode 100644 (file)
index 0000000..8a6653f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  linux/arch/m68knommu/mm/init.c
+ *
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com) 
+ *
+ *  Based on:
+ *
+ *  linux/arch/m68k/mm/init.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
+ *  DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+
+#undef DEBUG
+
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void free_initmem(void);
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+
+static unsigned long empty_bad_page;
+
+unsigned long empty_zero_page;
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses of available kernel virtual memory.
+ */
+void __init paging_init(void)
+{
+       /*
+        * Make sure start_mem is page aligned, otherwise bootmem and
+        * page_alloc get different views of the world.
+        */
+#ifdef DEBUG
+       unsigned long start_mem = PAGE_ALIGN(memory_start);
+#endif
+       unsigned long end_mem   = memory_end & PAGE_MASK;
+
+#ifdef DEBUG
+       printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
+               start_mem, end_mem);
+#endif
+
+       /*
+        * Initialize the bad page table and bad page to point
+        * to a couple of allocated pages.
+        */
+       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+       /*
+        * Set up SFC/DFC registers (user data space).
+        */
+       set_fs (USER_DS);
+
+#ifdef DEBUG
+       printk (KERN_DEBUG "before free_area_init\n");
+
+       printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
+               start_mem, end_mem);
+#endif
+
+       {
+               unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+               free_area_init(zones_size);
+       }
+}
+
+void __init mem_init(void)
+{
+       int codek = 0, datak = 0, initk = 0;
+       unsigned long tmp;
+       extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
+       extern unsigned int _ramend, _rambase;
+       unsigned long len = _ramend - _rambase;
+       unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
+       unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
+
+       pr_debug("Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
+
+       end_mem &= PAGE_MASK;
+       high_memory = (void *) end_mem;
+
+       start_mem = PAGE_ALIGN(start_mem);
+       max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT;
+
+       /* this will put all memory onto the freelists */
+       totalram_pages = free_all_bootmem();
+
+       codek = (&_etext - &_stext) >> 10;
+       datak = (&_ebss - &_sdata) >> 10;
+       initk = (&__init_begin - &__init_end) >> 10;
+
+       tmp = nr_free_pages() << PAGE_SHIFT;
+       printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
+              tmp >> 10,
+              len >> 10,
+              codek,
+              datak
+              );
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       int pages = 0;
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               init_page_count(virt_to_page(start));
+               free_page(start);
+               totalram_pages++;
+               pages++;
+       }
+       printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages * (PAGE_SIZE / 1024));
+}
+#endif
+
+void
+free_initmem()
+{
+#ifdef CONFIG_RAMKERNEL
+       unsigned long addr;
+       extern char __init_begin, __init_end;
+       /*
+        * The following code should be cool even if these sections
+        * are not page aligned.
+        */
+       addr = PAGE_ALIGN((unsigned long)(&__init_begin));
+       /* next to check that the page we free is not a partial page */
+       for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(addr));
+               init_page_count(virt_to_page(addr));
+               free_page(addr);
+               totalram_pages++;
+       }
+       printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
+                       (addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
+                       (int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
+                       (int)(addr - PAGE_SIZE));
+#endif
+}
+
index 69345849454b9c03991258aa1eff409472896e2b..a373d136b2b28547421a276b2789bc0d1f93b97d 100644 (file)
@@ -1,367 +1,5 @@
-/*
- *  linux/arch/m68k/mm/kmap.c
- *
- *  Copyright (C) 1997 Roman Hodek
- *
- *  10/01/99 cleaned up the code and changing to the same interface
- *          used by other architectures                /Roman Zippel
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-#define PTRTREESIZE    (256*1024)
-
-/*
- * For 040/060 we can use the virtual memory area like other architectures,
- * but for 020/030 we want to use early termination page descriptor and we
- * can't mix this with normal page descriptors, so we have to copy that code
- * (mm/vmalloc.c) and return appriorate aligned addresses.
- */
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-#define IO_SIZE                PAGE_SIZE
-
-static inline struct vm_struct *get_io_area(unsigned long size)
-{
-       return get_vm_area(size, VM_IOREMAP);
-}
-
-
-static inline void free_io_area(void *addr)
-{
-       vfree((void *)(PAGE_MASK & (unsigned long)addr));
-}
-
+#ifdef CONFIG_MMU
+#include "kmap_mm.c"
 #else
-
-#define IO_SIZE                (256*1024)
-
-static struct vm_struct *iolist;
-
-static struct vm_struct *get_io_area(unsigned long size)
-{
-       unsigned long addr;
-       struct vm_struct **p, *tmp, *area;
-
-       area = kmalloc(sizeof(*area), GFP_KERNEL);
-       if (!area)
-               return NULL;
-       addr = KMAP_START;
-       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
-               if (size + addr < (unsigned long)tmp->addr)
-                       break;
-               if (addr > KMAP_END-size) {
-                       kfree(area);
-                       return NULL;
-               }
-               addr = tmp->size + (unsigned long)tmp->addr;
-       }
-       area->addr = (void *)addr;
-       area->size = size + IO_SIZE;
-       area->next = *p;
-       *p = area;
-       return area;
-}
-
-static inline void free_io_area(void *addr)
-{
-       struct vm_struct **p, *tmp;
-
-       if (!addr)
-               return;
-       addr = (void *)((unsigned long)addr & -IO_SIZE);
-       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
-               if (tmp->addr == addr) {
-                       *p = tmp->next;
-                       __iounmap(tmp->addr, tmp->size);
-                       kfree(tmp);
-                       return;
-               }
-       }
-}
-
+#include "kmap_no.c"
 #endif
-
-/*
- * Map some physical address range into the kernel address space.
- */
-/* Rewritten by Andreas Schwab to remove all races. */
-
-void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       struct vm_struct *area;
-       unsigned long virtaddr, retaddr;
-       long offset;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       /*
-        * Don't allow mappings that wrap..
-        */
-       if (!size || physaddr > (unsigned long)(-size))
-               return NULL;
-
-#ifdef CONFIG_AMIGA
-       if (MACH_IS_AMIGA) {
-               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
-                   && (cacheflag == IOMAP_NOCACHE_SER))
-                       return (void __iomem *)physaddr;
-       }
-#endif
-
-#ifdef DEBUG
-       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
-#endif
-       /*
-        * Mappings have to be aligned
-        */
-       offset = physaddr & (IO_SIZE - 1);
-       physaddr &= -IO_SIZE;
-       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
-
-       /*
-        * Ok, go for it..
-        */
-       area = get_io_area(size);
-       if (!area)
-               return NULL;
-
-       virtaddr = (unsigned long)area->addr;
-       retaddr = virtaddr + offset;
-#ifdef DEBUG
-       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
-#endif
-
-       /*
-        * add cache and table flags to physical address
-        */
-       if (CPU_IS_040_OR_060) {
-               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
-                            _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_FULL_CACHING:
-                       physaddr |= _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       physaddr |= _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       physaddr |= _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       physaddr |= _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       physaddr |= _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       break;
-               }
-       }
-
-       while ((long)size > 0) {
-#ifdef DEBUG
-               if (!(virtaddr & (PTRTREESIZE-1)))
-                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
-               pgd_dir = pgd_offset_k(virtaddr);
-               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
-               if (!pmd_dir) {
-                       printk("ioremap: no mem for pmd_dir\n");
-                       return NULL;
-               }
-
-               if (CPU_IS_020_OR_030) {
-                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-                       physaddr += PTRTREESIZE;
-                       virtaddr += PTRTREESIZE;
-                       size -= PTRTREESIZE;
-               } else {
-                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
-                       if (!pte_dir) {
-                               printk("ioremap: no mem for pte_dir\n");
-                               return NULL;
-                       }
-
-                       pte_val(*pte_dir) = physaddr;
-                       virtaddr += PAGE_SIZE;
-                       physaddr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-#ifdef DEBUG
-       printk("\n");
-#endif
-       flush_tlb_all();
-
-       return (void __iomem *)retaddr;
-}
-EXPORT_SYMBOL(__ioremap);
-
-/*
- * Unmap a ioremap()ed region again
- */
-void iounmap(void __iomem *addr)
-{
-#ifdef CONFIG_AMIGA
-       if ((!MACH_IS_AMIGA) ||
-           (((unsigned long)addr < 0x40000000) ||
-            ((unsigned long)addr > 0x60000000)))
-                       free_io_area((__force void *)addr);
-#else
-       free_io_area((__force void *)addr);
-#endif
-}
-EXPORT_SYMBOL(iounmap);
-
-/*
- * __iounmap unmaps nearly everything, so be careful
- * it doesn't free currently pointer/page tables anymore but it
- * wans't used anyway and might be added later.
- */
-void __iounmap(void *addr, unsigned long size)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
-
-                       if (pmd_type == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = 0;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       } else if (pmd_type == 0)
-                               continue;
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = 0;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       if (CPU_IS_040_OR_060) {
-               switch (cmode) {
-               case IOMAP_FULL_CACHING:
-                       cmode = _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       cmode = _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       cmode = _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       cmode = _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               switch (cmode) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       cmode = _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       cmode = 0;
-               }
-       }
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-
-                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
-                                                        _CACHEMASK040) | cmode;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       }
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_mm.c b/arch/m68k/mm/kmap_mm.c
new file mode 100644 (file)
index 0000000..6934584
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ *  linux/arch/m68k/mm/kmap.c
+ *
+ *  Copyright (C) 1997 Roman Hodek
+ *
+ *  10/01/99 cleaned up the code and changing to the same interface
+ *          used by other architectures                /Roman Zippel
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+#define PTRTREESIZE    (256*1024)
+
+/*
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
+ */
+
+#ifdef CPU_M68040_OR_M68060_ONLY
+
+#define IO_SIZE                PAGE_SIZE
+
+static inline struct vm_struct *get_io_area(unsigned long size)
+{
+       return get_vm_area(size, VM_IOREMAP);
+}
+
+
+static inline void free_io_area(void *addr)
+{
+       vfree((void *)(PAGE_MASK & (unsigned long)addr));
+}
+
+#else
+
+#define IO_SIZE                (256*1024)
+
+static struct vm_struct *iolist;
+
+static struct vm_struct *get_io_area(unsigned long size)
+{
+       unsigned long addr;
+       struct vm_struct **p, *tmp, *area;
+
+       area = kmalloc(sizeof(*area), GFP_KERNEL);
+       if (!area)
+               return NULL;
+       addr = KMAP_START;
+       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+               if (size + addr < (unsigned long)tmp->addr)
+                       break;
+               if (addr > KMAP_END-size) {
+                       kfree(area);
+                       return NULL;
+               }
+               addr = tmp->size + (unsigned long)tmp->addr;
+       }
+       area->addr = (void *)addr;
+       area->size = size + IO_SIZE;
+       area->next = *p;
+       *p = area;
+       return area;
+}
+
+static inline void free_io_area(void *addr)
+{
+       struct vm_struct **p, *tmp;
+
+       if (!addr)
+               return;
+       addr = (void *)((unsigned long)addr & -IO_SIZE);
+       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+               if (tmp->addr == addr) {
+                       *p = tmp->next;
+                       __iounmap(tmp->addr, tmp->size);
+                       kfree(tmp);
+                       return;
+               }
+       }
+}
+
+#endif
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+/* Rewritten by Andreas Schwab to remove all races. */
+
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       struct vm_struct *area;
+       unsigned long virtaddr, retaddr;
+       long offset;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       /*
+        * Don't allow mappings that wrap..
+        */
+       if (!size || physaddr > (unsigned long)(-size))
+               return NULL;
+
+#ifdef CONFIG_AMIGA
+       if (MACH_IS_AMIGA) {
+               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+                   && (cacheflag == IOMAP_NOCACHE_SER))
+                       return (void __iomem *)physaddr;
+       }
+#endif
+
+#ifdef DEBUG
+       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+       /*
+        * Mappings have to be aligned
+        */
+       offset = physaddr & (IO_SIZE - 1);
+       physaddr &= -IO_SIZE;
+       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+       /*
+        * Ok, go for it..
+        */
+       area = get_io_area(size);
+       if (!area)
+               return NULL;
+
+       virtaddr = (unsigned long)area->addr;
+       retaddr = virtaddr + offset;
+#ifdef DEBUG
+       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+       /*
+        * add cache and table flags to physical address
+        */
+       if (CPU_IS_040_OR_060) {
+               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+                            _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_FULL_CACHING:
+                       physaddr |= _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       physaddr |= _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       physaddr |= _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       physaddr |= _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       physaddr |= _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       break;
+               }
+       }
+
+       while ((long)size > 0) {
+#ifdef DEBUG
+               if (!(virtaddr & (PTRTREESIZE-1)))
+                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+               pgd_dir = pgd_offset_k(virtaddr);
+               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
+               if (!pmd_dir) {
+                       printk("ioremap: no mem for pmd_dir\n");
+                       return NULL;
+               }
+
+               if (CPU_IS_020_OR_030) {
+                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+                       physaddr += PTRTREESIZE;
+                       virtaddr += PTRTREESIZE;
+                       size -= PTRTREESIZE;
+               } else {
+                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+                       if (!pte_dir) {
+                               printk("ioremap: no mem for pte_dir\n");
+                               return NULL;
+                       }
+
+                       pte_val(*pte_dir) = physaddr;
+                       virtaddr += PAGE_SIZE;
+                       physaddr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+#ifdef DEBUG
+       printk("\n");
+#endif
+       flush_tlb_all();
+
+       return (void __iomem *)retaddr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+void iounmap(void __iomem *addr)
+{
+#ifdef CONFIG_AMIGA
+       if ((!MACH_IS_AMIGA) ||
+           (((unsigned long)addr < 0x40000000) ||
+            ((unsigned long)addr > 0x60000000)))
+                       free_io_area((__force void *)addr);
+#else
+       free_io_area((__force void *)addr);
+#endif
+}
+EXPORT_SYMBOL(iounmap);
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+void __iounmap(void *addr, unsigned long size)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
+
+                       if (pmd_type == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = 0;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       } else if (pmd_type == 0)
+                               continue;
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = 0;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       if (CPU_IS_040_OR_060) {
+               switch (cmode) {
+               case IOMAP_FULL_CACHING:
+                       cmode = _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       cmode = _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       cmode = _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       cmode = _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               switch (cmode) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       cmode = _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       cmode = 0;
+               }
+       }
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+
+                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+                                                        _CACHEMASK040) | cmode;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       }
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_no.c b/arch/m68k/mm/kmap_no.c
new file mode 100644 (file)
index 0000000..ece8d5a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  linux/arch/m68knommu/mm/kmap.c
+ *
+ *  Copyright (C) 2000 Lineo, <davidm@snapgear.com>
+ *  Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       return (void *)physaddr;
+}
+
+/*
+ * Unmap a ioremap()ed region again.
+ */
+void iounmap(void *addr)
+{
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+}
diff --git a/arch/m68k/platform/5206/Makefile b/arch/m68k/platform/5206/Makefile
new file mode 100644 (file)
index 0000000..b5db056
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
+
diff --git a/arch/m68k/platform/5206/config.c b/arch/m68k/platform/5206/config.c
new file mode 100644 (file)
index 0000000..9c33546
--- /dev/null
@@ -0,0 +1,121 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5206/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000-2001, Lineo Inc. (www.lineo.com) 
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5206_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5206_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5206_uart_platform,
+};
+
+static struct platform_device *m5206_devices[] __initdata = {
+       &m5206_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5206_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
+       }
+}
+
+static void __init m5206_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5206_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5206_uart_init_line(line, m5206_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m5206_timers_init(void)
+{
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+}
+
+/***************************************************************************/
+
+void m5206_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m5206_cpu_reset;
+       m5206_timers_init();
+       m5206_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(28, MCFINTC_EINT4);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5206/gpio.c b/arch/m68k/platform/5206/gpio.c
new file mode 100644 (file)
index 0000000..b9ab4a1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PP",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PADDR,
+               .podr                           = (void __iomem *) MCFSIM_PADAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5206e/Makefile b/arch/m68k/platform/5206e/Makefile
new file mode 100644 (file)
index 0000000..b5db056
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
+
diff --git a/arch/m68k/platform/5206e/config.c b/arch/m68k/platform/5206e/config.c
new file mode 100644 (file)
index 0000000..9423979
--- /dev/null
@@ -0,0 +1,127 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5206e/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5206e_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5206e_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5206e_uart_platform,
+};
+
+static struct platform_device *m5206e_devices[] __initdata = {
+       &m5206e_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5206e_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
+       }
+}
+
+static void __init m5206e_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5206e_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5206e_uart_init_line(line, m5206e_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m5206e_timers_init(void)
+{
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+}
+
+/***************************************************************************/
+
+void m5206e_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined(CONFIG_NETtel)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#endif /* CONFIG_NETtel */
+
+       mach_reset = m5206e_cpu_reset;
+       m5206e_timers_init();
+       m5206e_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(28, MCFINTC_EINT4);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5206e/gpio.c b/arch/m68k/platform/5206e/gpio.c
new file mode 100644 (file)
index 0000000..b9ab4a1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PP",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PADDR,
+               .podr                           = (void __iomem *) MCFSIM_PADAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/520x/Makefile b/arch/m68k/platform/520x/Makefile
new file mode 100644 (file)
index 0000000..ad3f4e5
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the M5208 specific file.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
diff --git a/arch/m68k/platform/520x/config.c b/arch/m68k/platform/520x/config.c
new file mode 100644 (file)
index 0000000..621238f
--- /dev/null
@@ -0,0 +1,311 @@
+/***************************************************************************/
+
+/*
+ *  linux/arch/m68knommu/platform/520x/config.c
+ *
+ *  Copyright (C) 2005,      Freescale (www.freescale.com)
+ *  Copyright (C) 2005,      Intec Automation (mike@steroidmicros.com)
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m520x_uart_platform[] = {
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
+};
+
+static struct platform_device m520x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m520x_uart_platform,
+};
+
+static struct resource m520x_fec_resources[] = {
+       {
+               .start          = MCFFEC_BASE,
+               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 36,
+               .end            = 64 + 36,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 40,
+               .end            = 64 + 40,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 42,
+               .end            = 64 + 42,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m520x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m520x_fec_resources),
+       .resource               = m520x_fec_resources,
+};
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m520x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    62
+#define MCFQSPI_CS1    63
+#define MCFQSPI_CS2    44
+
+static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m520x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       }
+}
+
+static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m520x_cs_control = {
+       .setup                  = m520x_cs_setup,
+       .teardown               = m520x_cs_teardown,
+       .select                 = m520x_cs_select,
+       .deselect               = m520x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m520x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 3,
+       .cs_control             = &m520x_cs_control,
+};
+
+static struct platform_device m520x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m520x_qspi_resources),
+       .resource               = m520x_qspi_resources,
+       .dev.platform_data      = &m520x_qspi_data,
+};
+
+static void __init m520x_qspi_init(void)
+{
+       u16 par;
+       /* setup Port QS for QSPI with gpio CS control */
+       writeb(0x3f, MCF_GPIO_PAR_QSPI);
+       /* make U1CTS and U2RTS gpio for cs_control */
+       par = readw(MCF_GPIO_PAR_UART);
+       par &= 0x00ff;
+       writew(par, MCF_GPIO_PAR_UART);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
+static struct platform_device *m520x_devices[] __initdata = {
+       &m520x_uart,
+       &m520x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m520x_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m520x_uart_init_line(int line, int irq)
+{
+       u16 par;
+       u8 par2;
+
+       switch (line) {
+       case 0:
+               par = readw(MCF_GPIO_PAR_UART);
+               par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
+                      MCF_GPIO_PAR_UART_PAR_URXD0;
+               writew(par, MCF_GPIO_PAR_UART);
+               break;
+       case 1:
+               par = readw(MCF_GPIO_PAR_UART);
+               par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
+                      MCF_GPIO_PAR_UART_PAR_URXD1;
+               writew(par, MCF_GPIO_PAR_UART);
+               break;
+       case 2:
+               par2 = readb(MCF_GPIO_PAR_FECI2C);
+               par2 &= ~0x0F;
+               par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
+                       MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+               writeb(par2, MCF_GPIO_PAR_FECI2C);
+               break;
+       }
+}
+
+static void __init m520x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m520x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m520x_uart_init_line(line, m520x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m520x_fec_init(void)
+{
+       u8 v;
+
+       /* Set multi-function pins to ethernet mode */
+       v = readb(MCF_GPIO_PAR_FEC);
+       writeb(v | 0xf0, MCF_GPIO_PAR_FEC);
+
+       v = readb(MCF_GPIO_PAR_FECI2C);
+       writeb(v | 0x0f, MCF_GPIO_PAR_FECI2C);
+}
+
+/***************************************************************************/
+
+static void m520x_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m520x_cpu_reset;
+       m520x_uarts_init();
+       m520x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m520x_qspi_init();
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/520x/gpio.c b/arch/m68k/platform/520x/gpio.c
new file mode 100644 (file)
index 0000000..d757328
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PIRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *) MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BUSCTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 8,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BE",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 16,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BE,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BE,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BE,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "CS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 25,
+                       .ngpio                  = 3,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECI2C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QSPI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMER",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 48,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UART",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 56,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UART,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UART,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UART,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECL,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/523x/Makefile b/arch/m68k/platform/523x/Makefile
new file mode 100644 (file)
index 0000000..c04b8f7
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
diff --git a/arch/m68k/platform/523x/config.c b/arch/m68k/platform/523x/config.c
new file mode 100644 (file)
index 0000000..418a76f
--- /dev/null
@@ -0,0 +1,293 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/523x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Freescale
+ *     523x CPUs.
+ *
+ *     Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m523x_uart_platform[] = {
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
+       },
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
+       },
+       { },
+};
+
+static struct platform_device m523x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m523x_uart_platform,
+};
+
+static struct resource m523x_fec_resources[] = {
+       {
+               .start          = MCFFEC_BASE,
+               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m523x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m523x_fec_resources),
+       .resource               = m523x_fec_resources,
+};
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m523x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    91
+#define MCFQSPI_CS1    92
+#define MCFQSPI_CS2    103
+#define MCFQSPI_CS3    99
+
+static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m523x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m523x_cs_control = {
+       .setup                  = m523x_cs_setup,
+       .teardown               = m523x_cs_teardown,
+       .select                 = m523x_cs_select,
+       .deselect               = m523x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m523x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m523x_cs_control,
+};
+
+static struct platform_device m523x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m523x_qspi_resources),
+       .resource               = m523x_qspi_resources,
+       .dev.platform_data      = &m523x_qspi_data,
+};
+
+static void __init m523x_qspi_init(void)
+{
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+static struct platform_device *m523x_devices[] __initdata = {
+       &m523x_uart,
+       &m523x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m523x_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m523x_fec_init(void)
+{
+       u16 par;
+       u8 v;
+
+       /* Set multi-function pins to ethernet use */
+       par = readw(MCF_IPSBAR + 0x100082);
+       writew(par | 0xf00, MCF_IPSBAR + 0x100082);
+       v = readb(MCF_IPSBAR + 0x100078);
+       writeb(v | 0xc0, MCF_IPSBAR + 0x100078);
+}
+
+/***************************************************************************/
+
+static void m523x_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m523x_cpu_reset;
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m523x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m523x_qspi_init();
+#endif
+       platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/523x/gpio.c b/arch/m68k/platform/523x/gpio.c
new file mode 100644 (file)
index 0000000..327ebf1
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PIRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 1,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *) MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "ADDR",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 13,
+                       .ngpio                  = 3,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "DATAH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 16,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "DATAL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 24,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BUSCTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "CS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 49,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "SDRAM",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 56,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECI2C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 2,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 80,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QSPI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 88,
+                       .ngpio                  = 5,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMER",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 96,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "ETPU",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 104,
+                       .ngpio                  = 3,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ETPU,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_ETPU,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ETPU,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ETPU,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ETPU,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5249/Makefile b/arch/m68k/platform/5249/Makefile
new file mode 100644 (file)
index 0000000..4bed30f
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o intc2.o
+
diff --git a/arch/m68k/platform/5249/config.c b/arch/m68k/platform/5249/config.c
new file mode 100644 (file)
index 0000000..ceb31e5
--- /dev/null
@@ -0,0 +1,330 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5249/config.c
+ *
+ *     Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5249_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5249_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5249_uart_platform,
+};
+
+#ifdef CONFIG_M5249C3
+
+static struct resource m5249_smc91x_resources[] = {
+       {
+               .start          = 0xe0000300,
+               .end            = 0xe0000300 + 0x100,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINTC2_GPIOIRQ6,
+               .end            = MCFINTC2_GPIOIRQ6,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5249_smc91x = {
+       .name                   = "smc91x",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5249_smc91x_resources),
+       .resource               = m5249_smc91x_resources,
+};
+
+#endif /* CONFIG_M5249C3 */
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m5249_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_QSPI,
+               .end            = MCF_IRQ_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    29
+#define MCFQSPI_CS1    24
+#define MCFQSPI_CS2    21
+#define MCFQSPI_CS3    22
+
+static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m5249_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m5249_cs_control = {
+       .setup                  = m5249_cs_setup,
+       .teardown               = m5249_cs_teardown,
+       .select                 = m5249_cs_select,
+       .deselect               = m5249_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m5249_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m5249_cs_control,
+};
+
+static struct platform_device m5249_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5249_qspi_resources),
+       .resource               = m5249_qspi_resources,
+       .dev.platform_data      = &m5249_qspi_data,
+};
+
+static void __init m5249_qspi_init(void)
+{
+       /* QSPI irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
+              MCF_MBAR + MCFSIM_QSPIICR);
+       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
+static struct platform_device *m5249_devices[] __initdata = {
+       &m5249_uart,
+#ifdef CONFIG_M5249C3
+       &m5249_smc91x,
+#endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m5249_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m5249_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
+       } else if (line == 1) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
+       }
+}
+
+static void __init m5249_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5249_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5249_uart_init_line(line, m5249_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+#ifdef CONFIG_M5249C3
+
+static void __init m5249_smc91x_init(void)
+{
+       u32  gpio;
+
+       /* Set the GPIO line as interrupt source for smc91x device */
+       gpio = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+       writel(gpio | 0x40, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+
+       gpio = readl(MCF_MBAR2 + MCFSIM2_INTLEVEL5);
+       writel(gpio | 0x04000000, MCF_MBAR2 + MCFSIM2_INTLEVEL5);
+}
+
+#endif /* CONFIG_M5249C3 */
+
+/***************************************************************************/
+
+static void __init m5249_timers_init(void)
+{
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+}
+
+/***************************************************************************/
+
+void m5249_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m5249_cpu_reset;
+       m5249_timers_init();
+       m5249_uarts_init();
+#ifdef CONFIG_M5249C3
+       m5249_smc91x_init();
+#endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m5249_qspi_init();
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5249/gpio.c b/arch/m68k/platform/5249/gpio.c
new file mode 100644 (file)
index 0000000..2b56c6e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "GPIO0",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 32,
+               },
+               .pddr                           = (void __iomem *) MCFSIM2_GPIOENABLE,
+               .podr                           = (void __iomem *) MCFSIM2_GPIOWRITE,
+               .ppdr                           = (void __iomem *) MCFSIM2_GPIOREAD,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "GPIO1",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 32,
+                       .ngpio                  = 32,
+               },
+               .pddr                           = (void __iomem *) MCFSIM2_GPIO1ENABLE,
+               .podr                           = (void __iomem *) MCFSIM2_GPIO1WRITE,
+               .ppdr                           = (void __iomem *) MCFSIM2_GPIO1READ,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5249/intc2.c b/arch/m68k/platform/5249/intc2.c
new file mode 100644 (file)
index 0000000..8f4b63e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * intc2.c  -- support for the 2nd INTC controller of the 5249
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+static void intc2_irq_gpio_mask(struct irq_data *d)
+{
+       u32 imr;
+       imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+       imr &= ~(0x1 << (d->irq - MCFINTC2_GPIOIRQ0));
+       writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_unmask(struct irq_data *d)
+{
+       u32 imr;
+       imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+       imr |= (0x1 << (d->irq - MCFINTC2_GPIOIRQ0));
+       writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
+}
+
+static void intc2_irq_gpio_ack(struct irq_data *d)
+{
+       writel(0x1 << (d->irq - MCFINTC2_GPIOIRQ0), MCF_MBAR2 + MCFSIM2_GPIOINTCLEAR);
+}
+
+static struct irq_chip intc2_irq_gpio_chip = {
+       .name           = "CF-INTC2",
+       .irq_mask       = intc2_irq_gpio_mask,
+       .irq_unmask     = intc2_irq_gpio_unmask,
+       .irq_ack        = intc2_irq_gpio_ack,
+};
+
+static int __init mcf_intc2_init(void)
+{
+       int irq;
+
+       /* GPIO interrupt sources */
+       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++) {
+               set_irq_chip(irq, &intc2_irq_gpio_chip);
+               set_irq_handler(irq, handle_edge_irq);
+       }
+
+       return 0;
+}
+
+arch_initcall(mcf_intc2_init);
diff --git a/arch/m68k/platform/5272/Makefile b/arch/m68k/platform/5272/Makefile
new file mode 100644 (file)
index 0000000..34110fc
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o intc.o
+
diff --git a/arch/m68k/platform/5272/config.c b/arch/m68k/platform/5272/config.c
new file mode 100644 (file)
index 0000000..65bb582
--- /dev/null
@@ -0,0 +1,176 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5272/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2002, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+
+/***************************************************************************/
+
+/*
+ *     Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5272_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCF_IRQ_UART1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCF_IRQ_UART2,
+       },
+       { },
+};
+
+static struct platform_device m5272_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5272_uart_platform,
+};
+
+static struct resource m5272_fec_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x840,
+               .end            = MCF_MBAR + 0x840 + 0x1cf,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_ERX,
+               .end            = MCF_IRQ_ERX,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_ETX,
+               .end            = MCF_IRQ_ETX,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = MCF_IRQ_ENTC,
+               .end            = MCF_IRQ_ENTC,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5272_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5272_fec_resources),
+       .resource               = m5272_fec_resources,
+};
+
+static struct platform_device *m5272_devices[] __initdata = {
+       &m5272_uart,
+       &m5272_fec,
+};
+
+/***************************************************************************/
+
+static void __init m5272_uart_init_line(int line, int irq)
+{
+       u32 v;
+
+       if ((line >= 0) && (line < 2)) {
+               /* Enable the output lines for the serial ports */
+               v = readl(MCF_MBAR + MCFSIM_PBCNT);
+               v = (v & ~0x000000ff) | 0x00000055;
+               writel(v, MCF_MBAR + MCFSIM_PBCNT);
+
+               v = readl(MCF_MBAR + MCFSIM_PDCNT);
+               v = (v & ~0x000003fc) | 0x000002a8;
+               writel(v, MCF_MBAR + MCFSIM_PDCNT);
+       }
+}
+
+static void __init m5272_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5272_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5272_uart_init_line(line, m5272_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void m5272_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to reset, and enabled */
+       __raw_writew(0, MCF_MBAR + MCFSIM_WIRR);
+       __raw_writew(1, MCF_MBAR + MCFSIM_WRRR);
+       __raw_writew(0, MCF_MBAR + MCFSIM_WCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined (CONFIG_MOD5272)
+       volatile unsigned char  *pivrp;
+
+       /* Set base of device vectors to be 64 */
+       pivrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_PIVR);
+       *pivrp = 0x40;
+#endif
+
+#if defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#elif defined(CONFIG_CANCam)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0010000, size);
+       commandp[size-1] = 0;
+#endif
+
+       mach_reset = m5272_cpu_reset;
+}
+
+/***************************************************************************/
+
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+       .link   = 1,
+       .speed  = 100,
+       .duplex = 0,
+};
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5272_uarts_init();
+       fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
+       platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5272/gpio.c b/arch/m68k/platform/5272/gpio.c
new file mode 100644 (file)
index 0000000..57ac10a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PA",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 16,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PADDR,
+               .podr                           = (void __iomem *) MCFSIM_PADAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "PB",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 16,
+                       .ngpio                  = 16,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PBDDR,
+               .podr                           = (void __iomem *) MCFSIM_PBDAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PBDAT,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "PC",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 32,
+                       .ngpio                  = 16,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PCDDR,
+               .podr                           = (void __iomem *) MCFSIM_PCDAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PCDAT,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5272/intc.c b/arch/m68k/platform/5272/intc.c
new file mode 100644 (file)
index 0000000..969ff0a
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * intc.c  --  interrupt controller or ColdFire 5272 SoC
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * The 5272 ColdFire interrupt controller is nothing like any other
+ * ColdFire interrupt controller - it truly is completely different.
+ * Given its age it is unlikely to be used on any other ColdFire CPU.
+ */
+
+/*
+ * The masking and priproty setting of interrupts on the 5272 is done
+ * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
+ * loose mapping of vector number to register and internal bits, but
+ * a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledgeing via acknowledge bits.
+ */
+struct irqmap {
+       unsigned char   icr;
+       unsigned char   index;
+       unsigned char   ack;
+};
+
+static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
+       /*MCF_IRQ_SPURIOUS*/    { .icr = 0,           .index = 0,  .ack = 0, },
+       /*MCF_IRQ_EINT1*/       { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
+       /*MCF_IRQ_EINT2*/       { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
+       /*MCF_IRQ_EINT3*/       { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
+       /*MCF_IRQ_EINT4*/       { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
+       /*MCF_IRQ_TIMER1*/      { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
+       /*MCF_IRQ_TIMER2*/      { .icr = MCFSIM_ICR1, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_TIMER3*/      { .icr = MCFSIM_ICR1, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_TIMER4*/      { .icr = MCFSIM_ICR1, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_UART1*/       { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
+       /*MCF_IRQ_UART2*/       { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
+       /*MCF_IRQ_PLIP*/        { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
+       /*MCF_IRQ_PLIA*/        { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
+       /*MCF_IRQ_USB0*/        { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
+       /*MCF_IRQ_USB1*/        { .icr = MCFSIM_ICR2, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_USB2*/        { .icr = MCFSIM_ICR2, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_USB3*/        { .icr = MCFSIM_ICR2, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_USB4*/        { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
+       /*MCF_IRQ_USB5*/        { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
+       /*MCF_IRQ_USB6*/        { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
+       /*MCF_IRQ_USB7*/        { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
+       /*MCF_IRQ_DMA*/         { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
+       /*MCF_IRQ_ERX*/         { .icr = MCFSIM_ICR3, .index = 8,  .ack = 0, },
+       /*MCF_IRQ_ETX*/         { .icr = MCFSIM_ICR3, .index = 4,  .ack = 0, },
+       /*MCF_IRQ_ENTC*/        { .icr = MCFSIM_ICR3, .index = 0,  .ack = 0, },
+       /*MCF_IRQ_QSPI*/        { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
+       /*MCF_IRQ_EINT5*/       { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
+       /*MCF_IRQ_EINT6*/       { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
+       /*MCF_IRQ_SWTO*/        { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
+};
+
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               u32 v;
+               irq -= MCFINT_VECBASE;
+               v = 0x8 << intc_irqmap[irq].index;
+               writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+       }
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               u32 v;
+               irq -= MCFINT_VECBASE;
+               v = 0xd << intc_irqmap[irq].index;
+               writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+       }
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       /* Only external interrupts are acked */
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               irq -= MCFINT_VECBASE;
+               if (intc_irqmap[irq].ack) {
+                       u32 v;
+                       v = readl(MCF_MBAR + intc_irqmap[irq].icr);
+                       v &= (0x7 << intc_irqmap[irq].index);
+                       v |= (0x8 << intc_irqmap[irq].index);
+                       writel(v, MCF_MBAR + intc_irqmap[irq].icr);
+               }
+       }
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+               irq -= MCFINT_VECBASE;
+               if (intc_irqmap[irq].ack) {
+                       u32 v;
+                       v = readl(MCF_MBAR + MCFSIM_PITR);
+                       if (type == IRQ_TYPE_EDGE_FALLING)
+                               v &= ~(0x1 << (32 - irq));
+                       else
+                               v |= (0x1 << (32 - irq));
+                       writel(v, MCF_MBAR + MCFSIM_PITR);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+       get_irq_desc_chip(desc)->irq_ack(&desc->irq_data);
+       handle_simple_irq(irq, desc);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_mask_ack   = intc_irq_mask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq, edge;
+
+       init_vectors();
+
+       /* Mask all interrupt sources */
+       writel(0x88888888, MCF_MBAR + MCFSIM_ICR1);
+       writel(0x88888888, MCF_MBAR + MCFSIM_ICR2);
+       writel(0x88888888, MCF_MBAR + MCFSIM_ICR3);
+       writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
+
+       for (irq = 0; (irq < NR_IRQS); irq++) {
+               set_irq_chip(irq, &intc_irq_chip);
+               edge = 0;
+               if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+                       edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+               if (edge) {
+                       set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+                       set_irq_handler(irq, intc_external_irq);
+               } else {
+                       set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+                       set_irq_handler(irq, handle_level_irq);
+               }
+       }
+}
+
diff --git a/arch/m68k/platform/527x/Makefile b/arch/m68k/platform/527x/Makefile
new file mode 100644 (file)
index 0000000..6ac4b57
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
+
diff --git a/arch/m68k/platform/527x/config.c b/arch/m68k/platform/527x/config.c
new file mode 100644 (file)
index 0000000..fa35959
--- /dev/null
@@ -0,0 +1,384 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/527x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Freescale
+ *     5270/5271 CPUs.
+ *
+ *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m527x_uart_platform[] = {
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
+};
+
+static struct platform_device m527x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m527x_uart_platform,
+};
+
+static struct resource m527x_fec0_resources[] = {
+       {
+               .start          = MCFFEC_BASE0,
+               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource m527x_fec1_resources[] = {
+       {
+               .start          = MCFFEC_BASE1,
+               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 128 + 23,
+               .end            = 128 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 128 + 27,
+               .end            = 128 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 128 + 29,
+               .end            = 128 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m527x_fec[] = {
+       {
+               .name           = "fec",
+               .id             = 0,
+               .num_resources  = ARRAY_SIZE(m527x_fec0_resources),
+               .resource       = m527x_fec0_resources,
+       },
+       {
+               .name           = "fec",
+               .id             = 1,
+               .num_resources  = ARRAY_SIZE(m527x_fec1_resources),
+               .resource       = m527x_fec1_resources,
+       },
+};
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m527x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#if defined(CONFIG_M5271)
+#define MCFQSPI_CS0    91
+#define MCFQSPI_CS1    92
+#define MCFQSPI_CS2    99
+#define MCFQSPI_CS3    103
+#elif defined(CONFIG_M5275)
+#define MCFQSPI_CS0    59
+#define MCFQSPI_CS1    60
+#define MCFQSPI_CS2    61
+#define MCFQSPI_CS3    62
+#endif
+
+static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m527x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, cs_high);
+               break;
+       }
+}
+
+static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       switch (chip_select) {
+       case 0:
+               gpio_set_value(MCFQSPI_CS0, !cs_high);
+               break;
+       case 1:
+               gpio_set_value(MCFQSPI_CS1, !cs_high);
+               break;
+       case 2:
+               gpio_set_value(MCFQSPI_CS2, !cs_high);
+               break;
+       case 3:
+               gpio_set_value(MCFQSPI_CS3, !cs_high);
+               break;
+       }
+}
+
+static struct mcfqspi_cs_control m527x_cs_control = {
+       .setup                  = m527x_cs_setup,
+       .teardown               = m527x_cs_teardown,
+       .select                 = m527x_cs_select,
+       .deselect               = m527x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m527x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m527x_cs_control,
+};
+
+static struct platform_device m527x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m527x_qspi_resources),
+       .resource               = m527x_qspi_resources,
+       .dev.platform_data      = &m527x_qspi_data,
+};
+
+static void __init m527x_qspi_init(void)
+{
+#if defined(CONFIG_M5271)
+       u16 par;
+
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writeb(0x1f, MCFGPIO_PAR_QSPI);
+       /* and CS2 & CS3 as gpio */
+       par = readw(MCFGPIO_PAR_TIMER);
+       par &= 0x3f3f;
+       writew(par, MCFGPIO_PAR_TIMER);
+#elif defined(CONFIG_M5275)
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x003e, MCFGPIO_PAR_QSPI);
+#endif
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+static struct platform_device *m527x_devices[] __initdata = {
+       &m527x_uart,
+       &m527x_fec[0],
+#ifdef CONFIG_FEC2
+       &m527x_fec[1],
+#endif
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m527x_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m527x_uart_init_line(int line, int irq)
+{
+       u16 sepmask;
+
+       if ((line < 0) || (line > 2))
+               return;
+
+       /*
+        * External Pin Mask Setting & Enable External Pin for Interface
+        */
+       sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+       if (line == 0)
+               sepmask |= UART0_ENABLE_MASK;
+       else if (line == 1)
+               sepmask |= UART1_ENABLE_MASK;
+       else if (line == 2)
+               sepmask |= UART2_ENABLE_MASK;
+       writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
+}
+
+static void __init m527x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m527x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m527x_uart_init_line(line, m527x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m527x_fec_init(void)
+{
+       u16 par;
+       u8 v;
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+#if defined(CONFIG_M5271)
+       v = readb(MCF_IPSBAR + 0x100047);
+       writeb(v | 0xf0, MCF_IPSBAR + 0x100047);
+#else
+       par = readw(MCF_IPSBAR + 0x100082);
+       writew(par | 0xf00, MCF_IPSBAR + 0x100082);
+       v = readb(MCF_IPSBAR + 0x100078);
+       writeb(v | 0xc0, MCF_IPSBAR + 0x100078);
+#endif
+
+#ifdef CONFIG_FEC2
+       /* Set multi-function pins to ethernet mode for fec1 */
+       par = readw(MCF_IPSBAR + 0x100082);
+       writew(par | 0xa0, MCF_IPSBAR + 0x100082);
+       v = readb(MCF_IPSBAR + 0x100079);
+       writeb(v | 0xc0, MCF_IPSBAR + 0x100079);
+#endif
+}
+
+/***************************************************************************/
+
+static void m527x_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m527x_cpu_reset;
+       m527x_uarts_init();
+       m527x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m527x_qspi_init();
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/527x/gpio.c b/arch/m68k/platform/527x/gpio.c
new file mode 100644 (file)
index 0000000..205da0a
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+#if defined(CONFIG_M5271)
+       {
+               .gpio_chip                      = {
+                       .label                  = "PIRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 1,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *) MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "ADDR",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 13,
+                       .ngpio                  = 3,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "DATAH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 16,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "DATAL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 24,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BUSCTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "CS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 49,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "SDRAM",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 56,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECI2C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 2,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 80,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QSPI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 88,
+                       .ngpio                  = 5,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMER",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 96,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
+       },
+#elif defined(CONFIG_M5275)
+       {
+               .gpio_chip                      = {
+                       .label                  = "PIRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 1,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *) MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BUSCTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 8,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "ADDR",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 21,
+                       .ngpio                  = 3,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "CS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 25,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FEC0H",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC0H,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC0H,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0H,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0H,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC0H,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FEC0L",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC0L,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC0L,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0L,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0L,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC0L,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECI2C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 48,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QSPI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 56,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "SDRAM",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMERH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMERH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMERH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMERH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMERL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 80,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMERL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMERL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMERL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 88,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FEC1H",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 96,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC1H,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC1H,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1H,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1H,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC1H,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FEC1L",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 104,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC1L,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC1L,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1L,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1L,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC1L,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 114,
+                       .ngpio                  = 2,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "IRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 121,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_IRQ,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_IRQ,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_IRQ,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_IRQ,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_IRQ,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "USBH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 128,
+                       .ngpio                  = 1,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_USBH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_USBH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_USBH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_USBH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_USBH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "USBL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 136,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_USBL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_USBL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_USBL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_USBL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_USBL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UARTH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 144,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
+       },
+#endif
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/528x/Makefile b/arch/m68k/platform/528x/Makefile
new file mode 100644 (file)
index 0000000..6ac4b57
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs.  You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
+
diff --git a/arch/m68k/platform/528x/config.c b/arch/m68k/platform/528x/config.c
new file mode 100644 (file)
index 0000000..ac39fc6
--- /dev/null
@@ -0,0 +1,320 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/528x/config.c
+ *
+ *     Sub-architcture dependant initialization code for the Freescale
+ *     5280, 5281 and 5282 CPUs.
+ *
+ *     Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m528x_uart_platform[] = {
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
+       },
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
+       },
+       { },
+};
+
+static struct platform_device m528x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m528x_uart_platform,
+};
+
+static struct resource m528x_fec_resources[] = {
+       {
+               .start          = MCFFEC_BASE,
+               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m528x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m528x_fec_resources),
+       .resource               = m528x_fec_resources,
+};
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m528x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    147
+#define MCFQSPI_CS1    148
+#define MCFQSPI_CS2    149
+#define MCFQSPI_CS3    150
+
+static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+               goto fail3;
+       }
+       status = gpio_direction_output(MCFQSPI_CS3, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+               goto fail4;
+       }
+
+       return 0;
+
+fail4:
+       gpio_free(MCFQSPI_CS3);
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS3);
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m528x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
+}
+
+static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
+}
+
+static struct mcfqspi_cs_control m528x_cs_control = {
+       .setup                  = m528x_cs_setup,
+       .teardown               = m528x_cs_teardown,
+       .select                 = m528x_cs_select,
+       .deselect               = m528x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m528x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 4,
+       .cs_control             = &m528x_cs_control,
+};
+
+static struct platform_device m528x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m528x_qspi_resources),
+       .resource               = m528x_qspi_resources,
+       .dev.platform_data      = &m528x_qspi_data,
+};
+
+static void __init m528x_qspi_init(void)
+{
+       /* setup Port QS for QSPI with gpio CS control */
+       __raw_writeb(0x07, MCFGPIO_PQSPAR);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+static struct platform_device *m528x_devices[] __initdata = {
+       &m528x_uart,
+       &m528x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m528x_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m528x_uart_init_line(int line, int irq)
+{
+       u8 port;
+
+       if ((line < 0) || (line > 2))
+               return;
+
+       /* make sure PUAPAR is set for UART0 and UART1 */
+       if (line < 2) {
+               port = readb(MCF5282_GPIO_PUAPAR);
+               port |= (0x03 << (line * 2));
+               writeb(port, MCF5282_GPIO_PUAPAR);
+       }
+}
+
+static void __init m528x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m528x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m528x_uart_init_line(line, m528x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m528x_fec_init(void)
+{
+       u16 v16;
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       v16 = readw(MCF_IPSBAR + 0x100056);
+       writew(v16 | 0xf00, MCF_IPSBAR + 0x100056);
+       writeb(0xc0, MCF_IPSBAR + 0x100058);
+}
+
+/***************************************************************************/
+
+static void m528x_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
+}
+
+/***************************************************************************/
+
+#ifdef CONFIG_WILDFIRE
+void wildfire_halt(void)
+{
+       writeb(0, 0x30000007);
+       writeb(0x2, 0x30000007);
+}
+#endif
+
+#ifdef CONFIG_WILDFIREMOD
+void wildfiremod_halt(void)
+{
+       printk(KERN_INFO "WildFireMod hibernating...\n");
+
+       /* Set portE.5 to Digital IO */
+       MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
+
+       /* Make portE.5 an output */
+       MCF5282_GPIO_DDRE |= (1 << 5);
+
+       /* Now toggle portE.5 from low to high */
+       MCF5282_GPIO_PORTE &= ~(1 << 5);
+       MCF5282_GPIO_PORTE |= (1 << 5);
+
+       printk(KERN_EMERG "Failed to hibernate. Halting!\n");
+}
+#endif
+
+void __init config_BSP(char *commandp, int size)
+{
+#ifdef CONFIG_WILDFIRE
+       mach_halt = wildfire_halt;
+#endif
+#ifdef CONFIG_WILDFIREMOD
+       mach_halt = wildfiremod_halt;
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       mach_reset = m528x_cpu_reset;
+       m528x_uarts_init();
+       m528x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m528x_qspi_init();
+#endif
+       platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/528x/gpio.c b/arch/m68k/platform/528x/gpio.c
new file mode 100644 (file)
index 0000000..526db66
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "NQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .base                   = 1,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *)MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *)MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *)MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TA",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 8,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFGPTA_GPTDDR,
+               .podr                           = (void __iomem *)MCFGPTA_GPTPORT,
+               .ppdr                           = (void __iomem *)MCFGPTB_GPTPORT,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TB",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 16,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFGPTB_GPTDDR,
+               .podr                           = (void __iomem *)MCFGPTB_GPTPORT,
+               .ppdr                           = (void __iomem *)MCFGPTB_GPTPORT,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QA",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 24,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFQADC_DDRQA,
+               .podr                           = (void __iomem *)MCFQADC_PORTQA,
+               .ppdr                           = (void __iomem *)MCFQADC_PORTQA,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QB",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFQADC_DDRQB,
+               .podr                           = (void __iomem *)MCFQADC_PORTQB,
+               .ppdr                           = (void __iomem *)MCFQADC_PORTQB,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "A",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRA,
+               .podr                           = (void __iomem *)MCFGPIO_PORTA,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTAP,
+               .setr                           = (void __iomem *)MCFGPIO_SETA,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRA,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "B",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 48,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRB,
+               .podr                           = (void __iomem *)MCFGPIO_PORTB,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTBP,
+               .setr                           = (void __iomem *)MCFGPIO_SETB,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRB,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 56,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRC,
+               .podr                           = (void __iomem *)MCFGPIO_PORTC,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTCP,
+               .setr                           = (void __iomem *)MCFGPIO_SETC,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRC,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "D",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRD,
+               .podr                           = (void __iomem *)MCFGPIO_PORTD,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTDP,
+               .setr                           = (void __iomem *)MCFGPIO_SETD,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRD,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "E",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRE,
+               .podr                           = (void __iomem *)MCFGPIO_PORTE,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTEP,
+               .setr                           = (void __iomem *)MCFGPIO_SETE,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRE,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "F",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 80,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRF,
+               .podr                           = (void __iomem *)MCFGPIO_PORTF,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTFP,
+               .setr                           = (void __iomem *)MCFGPIO_SETF,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRF,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "G",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 88,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRG,
+               .podr                           = (void __iomem *)MCFGPIO_PORTG,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTGP,
+               .setr                           = (void __iomem *)MCFGPIO_SETG,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRG,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "H",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 96,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRH,
+               .podr                           = (void __iomem *)MCFGPIO_PORTH,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTHP,
+               .setr                           = (void __iomem *)MCFGPIO_SETH,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "J",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 104,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRJ,
+               .podr                           = (void __iomem *)MCFGPIO_PORTJ,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTJP,
+               .setr                           = (void __iomem *)MCFGPIO_SETJ,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRJ,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "DD",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 112,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRDD,
+               .podr                           = (void __iomem *)MCFGPIO_PORTDD,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTDDP,
+               .setr                           = (void __iomem *)MCFGPIO_SETDD,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRDD,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "EH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 120,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDREH,
+               .podr                           = (void __iomem *)MCFGPIO_PORTEH,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTEHP,
+               .setr                           = (void __iomem *)MCFGPIO_SETEH,
+               .clrr                           = (void __iomem *)MCFGPIO_CLREH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "EL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 128,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDREL,
+               .podr                           = (void __iomem *)MCFGPIO_PORTEL,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTELP,
+               .setr                           = (void __iomem *)MCFGPIO_SETEL,
+               .clrr                           = (void __iomem *)MCFGPIO_CLREL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "AS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 136,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRAS,
+               .podr                           = (void __iomem *)MCFGPIO_PORTAS,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTASP,
+               .setr                           = (void __iomem *)MCFGPIO_SETAS,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRAS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 144,
+                       .ngpio                  = 7,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRQS,
+               .podr                           = (void __iomem *)MCFGPIO_PORTQS,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTQSP,
+               .setr                           = (void __iomem *)MCFGPIO_SETQS,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRQS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "SD",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 152,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRSD,
+               .podr                           = (void __iomem *)MCFGPIO_PORTSD,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTSDP,
+               .setr                           = (void __iomem *)MCFGPIO_SETSD,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRSD,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TC",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 160,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRTC,
+               .podr                           = (void __iomem *)MCFGPIO_PORTTC,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTTCP,
+               .setr                           = (void __iomem *)MCFGPIO_SETTC,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRTC,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TD",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 168,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRTD,
+               .podr                           = (void __iomem *)MCFGPIO_PORTTD,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTTDP,
+               .setr                           = (void __iomem *)MCFGPIO_SETTD,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRTD,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UA",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 176,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *)MCFGPIO_DDRUA,
+               .podr                           = (void __iomem *)MCFGPIO_PORTUA,
+               .ppdr                           = (void __iomem *)MCFGPIO_PORTUAP,
+               .setr                           = (void __iomem *)MCFGPIO_SETUA,
+               .clrr                           = (void __iomem *)MCFGPIO_CLRUA,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5307/Makefile b/arch/m68k/platform/5307/Makefile
new file mode 100644 (file)
index 0000000..d4293b7
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Makefile for the m68knommu kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y                  += config.o gpio.o
+obj-$(CONFIG_NETtel)   += nettel.o
+obj-$(CONFIG_CLEOPATRA)        += nettel.o
+
diff --git a/arch/m68k/platform/5307/config.c b/arch/m68k/platform/5307/config.c
new file mode 100644 (file)
index 0000000..00900ac
--- /dev/null
@@ -0,0 +1,147 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5307/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfwdebug.h>
+
+/***************************************************************************/
+
+/*
+ *     Some platforms need software versions of the GPIO data registers.
+ */
+unsigned short ppdata;
+unsigned char ledbank = 0xff;
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5307_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5307_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5307_uart_platform,
+};
+
+static struct platform_device *m5307_devices[] __initdata = {
+       &m5307_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5307_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
+       } else if (line == 1) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
+       }
+}
+
+static void __init m5307_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5307_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5307_uart_init_line(line, m5307_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m5307_timers_init(void)
+{
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+}
+
+/***************************************************************************/
+
+void m5307_cpu_reset(void)
+{
+       local_irq_disable();
+       /* Set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if defined(CONFIG_NETtel) || \
+    defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0xf0004000, size);
+       commandp[size-1] = 0;
+#endif
+
+       mach_reset = m5307_cpu_reset;
+       m5307_timers_init();
+       m5307_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+
+#ifdef CONFIG_BDM_DISABLE
+       /*
+        * Disable the BDM clocking.  This also turns off most of the rest of
+        * the BDM device.  This is good for EMC reasons. This option is not
+        * incompatible with the memory protection option.
+        */
+       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5307/gpio.c b/arch/m68k/platform/5307/gpio.c
new file mode 100644 (file)
index 0000000..5850612
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PP",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 16,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PADDR,
+               .podr                           = (void __iomem *) MCFSIM_PADAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5307/nettel.c b/arch/m68k/platform/5307/nettel.c
new file mode 100644 (file)
index 0000000..e925ea4
--- /dev/null
@@ -0,0 +1,153 @@
+/***************************************************************************/
+
+/*
+ *     nettel.c -- startup code support for the NETtel boards
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/nettel.h>
+
+/***************************************************************************/
+
+/*
+ * Define the IO and interrupt resources of the 2 SMC9196 interfaces.
+ */
+#define        NETTEL_SMC0_ADDR        0x30600300
+#define        NETTEL_SMC0_IRQ         29
+
+#define        NETTEL_SMC1_ADDR        0x30600000
+#define        NETTEL_SMC1_IRQ         27
+
+/*
+ * We need some access into the SMC9196 registers. Define those registers
+ * we will need here (including the smc91x.h doesn't seem to give us these
+ * in a simple form).
+ */
+#define        SMC91xx_BANKSELECT      14
+#define        SMC91xx_BASEADDR        2
+#define        SMC91xx_BASEMAC         4
+
+/***************************************************************************/
+
+static struct resource nettel_smc91x_0_resources[] = {
+       {
+               .start          = NETTEL_SMC0_ADDR,
+               .end            = NETTEL_SMC0_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC0_IRQ,
+               .end            = NETTEL_SMC0_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource nettel_smc91x_1_resources[] = {
+       {
+               .start          = NETTEL_SMC1_ADDR,
+               .end            = NETTEL_SMC1_ADDR + 0x20,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = NETTEL_SMC1_IRQ,
+               .end            = NETTEL_SMC1_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device nettel_smc91x[] = {
+       {
+               .name                   = "smc91x",
+               .id                     = 0,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_0_resources),
+               .resource               = nettel_smc91x_0_resources,
+       },
+       {
+               .name                   = "smc91x",
+               .id                     = 1,
+               .num_resources          = ARRAY_SIZE(nettel_smc91x_1_resources),
+               .resource               = nettel_smc91x_1_resources,
+       },
+};
+
+static struct platform_device *nettel_devices[] __initdata = {
+       &nettel_smc91x[0],
+       &nettel_smc91x[1],
+};
+
+/***************************************************************************/
+
+static u8 nettel_macdefault[] __initdata = {
+       0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01,
+};
+
+/*
+ * Set flash contained MAC address into SMC9196 core. Make sure the flash
+ * MAC address is sane, and not an empty flash. If no good use the Moreton
+ * Bay default MAC address instead.
+ */
+
+static void __init nettel_smc91x_setmac(unsigned int ioaddr, unsigned int flashaddr)
+{
+       u16 *macp;
+
+       macp = (u16 *) flashaddr;
+       if ((macp[0] == 0xffff) && (macp[1] == 0xffff) && (macp[2] == 0xffff))
+               macp = (u16 *) &nettel_macdefault[0];
+
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(macp[0], ioaddr + SMC91xx_BASEMAC);
+       writew(macp[1], ioaddr + SMC91xx_BASEMAC + 2);
+       writew(macp[2], ioaddr + SMC91xx_BASEMAC + 4);
+}
+
+/***************************************************************************/
+
+/*
+ * Re-map the address space of at least one of the SMC ethernet
+ * parts. Both parts power up decoding the same address, so we
+ * need to move one of them first, before doing anything else.
+ */
+
+static void __init nettel_smc91x_init(void)
+{
+       writew(0x00ec, MCF_MBAR + MCFSIM_PADDR);
+       mcf_setppdata(0, 0x0080);
+       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
+       writew(0x0067, NETTEL_SMC0_ADDR + SMC91xx_BASEADDR);
+       mcf_setppdata(0x0080, 0);
+
+       /* Set correct chip select timing for SMC9196 accesses */
+       writew(0x1180, MCF_MBAR + MCFSIM_CSCR3);
+
+       /* Set the SMC interrupts to be auto-vectored */
+       mcf_autovector(NETTEL_SMC0_IRQ);
+       mcf_autovector(NETTEL_SMC1_IRQ);
+
+       /* Set MAC addresses from flash for both interfaces */
+       nettel_smc91x_setmac(NETTEL_SMC0_ADDR, 0xf0006000);
+       nettel_smc91x_setmac(NETTEL_SMC1_ADDR, 0xf0006006);
+}
+
+/***************************************************************************/
+
+static int __init init_nettel(void)
+{
+       nettel_smc91x_init();
+       platform_add_devices(nettel_devices, ARRAY_SIZE(nettel_devices));
+       return 0;
+}
+
+arch_initcall(init_nettel);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/532x/Makefile b/arch/m68k/platform/532x/Makefile
new file mode 100644 (file)
index 0000000..ce01669
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+#obj-y := config.o usb-mcf532x.o spi-mcf532x.o
+obj-y := config.o gpio.o
diff --git a/arch/m68k/platform/532x/config.c b/arch/m68k/platform/532x/config.c
new file mode 100644 (file)
index 0000000..ca51323
--- /dev/null
@@ -0,0 +1,648 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/532x/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ *     Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
+ *     Copyright Freescale Semiconductor, Inc 2006
+ *     Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.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/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfdma.h>
+#include <asm/mcfwdebug.h>
+#include <asm/mcfqspi.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m532x_uart_platform[] = {
+       {
+               .mapbase        = MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
+};
+
+static struct platform_device m532x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m532x_uart_platform,
+};
+
+static struct resource m532x_fec_resources[] = {
+       {
+               .start          = 0xfc030000,
+               .end            = 0xfc0307ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 36,
+               .end            = 64 + 36,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 40,
+               .end            = 64 + 40,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 42,
+               .end            = 64 + 42,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m532x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m532x_fec_resources),
+       .resource               = m532x_fec_resources,
+};
+
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+static struct resource m532x_qspi_resources[] = {
+       {
+               .start          = MCFQSPI_IOBASE,
+               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCFINT_VECBASE + MCFINT_QSPI,
+               .end            = MCFINT_VECBASE + MCFINT_QSPI,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+#define MCFQSPI_CS0    84
+#define MCFQSPI_CS1    85
+#define MCFQSPI_CS2    86
+
+static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+       int status;
+
+       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+               goto fail0;
+       }
+       status = gpio_direction_output(MCFQSPI_CS0, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+               goto fail1;
+       }
+
+       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+               goto fail1;
+       }
+       status = gpio_direction_output(MCFQSPI_CS1, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+               goto fail2;
+       }
+
+       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+       if (status) {
+               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+               goto fail2;
+       }
+       status = gpio_direction_output(MCFQSPI_CS2, 1);
+       if (status) {
+               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+               goto fail3;
+       }
+
+       return 0;
+
+fail3:
+       gpio_free(MCFQSPI_CS2);
+fail2:
+       gpio_free(MCFQSPI_CS1);
+fail1:
+       gpio_free(MCFQSPI_CS0);
+fail0:
+       return status;
+}
+
+static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+       gpio_free(MCFQSPI_CS2);
+       gpio_free(MCFQSPI_CS1);
+       gpio_free(MCFQSPI_CS0);
+}
+
+static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
+                           u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
+}
+
+static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
+                             u8 chip_select, bool cs_high)
+{
+       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
+}
+
+static struct mcfqspi_cs_control m532x_cs_control = {
+       .setup                  = m532x_cs_setup,
+       .teardown               = m532x_cs_teardown,
+       .select                 = m532x_cs_select,
+       .deselect               = m532x_cs_deselect,
+};
+
+static struct mcfqspi_platform_data m532x_qspi_data = {
+       .bus_num                = 0,
+       .num_chipselect         = 3,
+       .cs_control             = &m532x_cs_control,
+};
+
+static struct platform_device m532x_qspi = {
+       .name                   = "mcfqspi",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m532x_qspi_resources),
+       .resource               = m532x_qspi_resources,
+       .dev.platform_data      = &m532x_qspi_data,
+};
+
+static void __init m532x_qspi_init(void)
+{
+       /* setup QSPS pins for QSPI with gpio CS control */
+       writew(0x01f0, MCF_GPIO_PAR_QSPI);
+}
+#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
+
+
+static struct platform_device *m532x_devices[] __initdata = {
+       &m532x_uart,
+       &m532x_fec,
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       &m532x_qspi,
+#endif
+};
+
+/***************************************************************************/
+
+static void __init m532x_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               /* GPIO initialization */
+               MCF_GPIO_PAR_UART |= 0x000F;
+       } else if (line == 1) {
+               /* GPIO initialization */
+               MCF_GPIO_PAR_UART |= 0x0FF0;
+       }
+}
+
+static void __init m532x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m532x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m532x_uart_init_line(line, m532x_uart_platform[line].irq);
+}
+/***************************************************************************/
+
+static void __init m532x_fec_init(void)
+{
+       /* Set multi-function pins to ethernet mode for fec0 */
+       MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+       MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+}
+
+/***************************************************************************/
+
+static void m532x_cpu_reset(void)
+{
+       local_irq_disable();
+       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+#if !defined(CONFIG_BOOTPARAM)
+       /* Copy command line from FLASH to local buffer... */
+       memcpy(commandp, (char *) 0x4000, 4);
+       if(strncmp(commandp, "kcl ", 4) == 0){
+               memcpy(commandp, (char *) 0x4004, size);
+               commandp[size-1] = 0;
+       } else {
+               memset(commandp, 0, size);
+       }
+#endif
+
+#ifdef CONFIG_BDM_DISABLE
+       /*
+        * Disable the BDM clocking.  This also turns off most of the rest of
+        * the BDM device.  This is good for EMC reasons. This option is not
+        * incompatible with the memory protection option.
+        */
+       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
+#endif
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m532x_uarts_init();
+       m532x_fec_init();
+#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
+       m532x_qspi_init();
+#endif
+       platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
+/* Board initialization */
+/***************************************************************************/
+/* 
+ * PLL min/max specifications
+ */
+#define MAX_FVCO       500000  /* KHz */
+#define MAX_FSYS       80000   /* KHz */
+#define MIN_FSYS       58333   /* KHz */
+#define FREF           16000   /* KHz */
+
+
+#define MAX_MFD                135     /* Multiplier */
+#define MIN_MFD                88      /* Multiplier */
+#define BUSDIV         6       /* Divider */
+
+/*
+ * Low Power Divider specifications
+ */
+#define MIN_LPD                (1 << 0)    /* Divider (not encoded) */
+#define MAX_LPD                (1 << 15)   /* Divider (not encoded) */
+#define DEFAULT_LPD    (1 << 1)        /* Divider (not encoded) */
+
+#define SYS_CLK_KHZ    80000
+#define SYSTEM_PERIOD  12.5
+/*
+ *  SDRAM Timing Parameters
+ */  
+#define SDRAM_BL       8       /* # of beats in a burst */
+#define SDRAM_TWR      2       /* in clocks */
+#define SDRAM_CASL     2.5     /* CASL in clocks */
+#define SDRAM_TRCD     2       /* in clocks */
+#define SDRAM_TRP      2       /* in clocks */
+#define SDRAM_TRFC     7       /* in clocks */
+#define SDRAM_TREFI    7800    /* in ns */
+
+#define EXT_SRAM_ADDRESS       (0xC0000000)
+#define FLASH_ADDRESS          (0x00000000)
+#define SDRAM_ADDRESS          (0x40000000)
+
+#define NAND_FLASH_ADDRESS     (0xD0000000)
+
+int sys_clk_khz = 0;
+int sys_clk_mhz = 0;
+
+void wtm_init(void);
+void scm_init(void);
+void gpio_init(void);
+void fbcs_init(void);
+void sdramc_init(void);
+int  clock_pll (int fsys, int flags);
+int  clock_limp (int);
+int  clock_exit_limp (void);
+int  get_sys_clock (void);
+
+asmlinkage void __init sysinit(void)
+{
+       sys_clk_khz = clock_pll(0, 0);
+       sys_clk_mhz = sys_clk_khz/1000;
+       
+       wtm_init();
+       scm_init();
+       gpio_init();
+       fbcs_init();
+       sdramc_init();
+}
+
+void wtm_init(void)
+{
+       /* Disable watchdog timer */
+       MCF_WTM_WCR = 0;
+}
+
+#define MCF_SCM_BCR_GBW                (0x00000100)
+#define MCF_SCM_BCR_GBR                (0x00000200)
+
+void scm_init(void)
+{
+       /* All masters are trusted */
+       MCF_SCM_MPR = 0x77777777;
+    
+       /* Allow supervisor/user, read/write, and trusted/untrusted
+          access to all slaves */
+       MCF_SCM_PACRA = 0;
+       MCF_SCM_PACRB = 0;
+       MCF_SCM_PACRC = 0;
+       MCF_SCM_PACRD = 0;
+       MCF_SCM_PACRE = 0;
+       MCF_SCM_PACRF = 0;
+
+       /* Enable bursts */
+       MCF_SCM_BCR = (MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW);
+}
+
+
+void fbcs_init(void)
+{
+       MCF_GPIO_PAR_CS = 0x0000003E;
+
+       /* Latch chip select */
+       MCF_FBCS1_CSAR = 0x10080000;
+
+       MCF_FBCS1_CSCR = 0x002A3780;
+       MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V);
+
+       /* Initialize latch to drive signals to inactive states */
+       *((u16 *)(0x10080000)) = 0xFFFF;
+
+       /* External SRAM */
+       MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS;
+       MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16
+                       | MCF_FBCS_CSCR_AA
+                       | MCF_FBCS_CSCR_SBM
+                       | MCF_FBCS_CSCR_WS(1));
+       MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K
+                       | MCF_FBCS_CSMR_V);
+
+       /* Boot Flash connected to FBCS0 */
+       MCF_FBCS0_CSAR = FLASH_ADDRESS;
+       MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16
+                       | MCF_FBCS_CSCR_BEM
+                       | MCF_FBCS_CSCR_AA
+                       | MCF_FBCS_CSCR_SBM
+                       | MCF_FBCS_CSCR_WS(7));
+       MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M
+                       | MCF_FBCS_CSMR_V);
+}
+
+void sdramc_init(void)
+{
+       /*
+        * Check to see if the SDRAM has already been initialized
+        * by a run control tool
+        */
+       if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) {
+               /* SDRAM chip select initialization */
+               
+               /* Initialize SDRAM chip select */
+               MCF_SDRAMC_SDCS0 = (0
+                       | MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS)
+                       | MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE));
+
+       /*
+        * Basic configuration and initialization
+        */
+       MCF_SDRAMC_SDCFG1 = (0
+               | MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5 ))
+               | MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
+               | MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
+               | MCF_SDRAMC_SDCFG1_ACT2RW((int)((SDRAM_TRCD ) + 0.5))
+               | MCF_SDRAMC_SDCFG1_PRE2ACT((int)((SDRAM_TRP ) + 0.5))
+               | MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC) ) + 0.5))
+               | MCF_SDRAMC_SDCFG1_WTLAT(3));
+       MCF_SDRAMC_SDCFG2 = (0
+               | MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL/2 + 1)
+               | MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL/2 + SDRAM_TWR)
+               | MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL+SDRAM_BL/2-1.0)+0.5))
+               | MCF_SDRAMC_SDCFG2_BL(SDRAM_BL-1));
+
+            
+       /*
+        * Precharge and enable write to SDMR
+        */
+        MCF_SDRAMC_SDCR = (0
+               | MCF_SDRAMC_SDCR_MODE_EN
+               | MCF_SDRAMC_SDCR_CKE
+               | MCF_SDRAMC_SDCR_DDR
+               | MCF_SDRAMC_SDCR_MUX(1)
+               | MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
+               | MCF_SDRAMC_SDCR_PS_16
+               | MCF_SDRAMC_SDCR_IPALL);            
+
+       /*
+        * Write extended mode register
+        */
+       MCF_SDRAMC_SDMR = (0
+               | MCF_SDRAMC_SDMR_BNKAD_LEMR
+               | MCF_SDRAMC_SDMR_AD(0x0)
+               | MCF_SDRAMC_SDMR_CMD);
+
+       /*
+        * Write mode register and reset DLL
+        */
+       MCF_SDRAMC_SDMR = (0
+               | MCF_SDRAMC_SDMR_BNKAD_LMR
+               | MCF_SDRAMC_SDMR_AD(0x163)
+               | MCF_SDRAMC_SDMR_CMD);
+
+       /*
+        * Execute a PALL command
+        */
+       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL;
+
+       /*
+        * Perform two REF cycles
+        */
+       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
+       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
+
+       /*
+        * Write mode register and clear reset DLL
+        */
+       MCF_SDRAMC_SDMR = (0
+               | MCF_SDRAMC_SDMR_BNKAD_LMR
+               | MCF_SDRAMC_SDMR_AD(0x063)
+               | MCF_SDRAMC_SDMR_CMD);
+                               
+       /*
+        * Enable auto refresh and lock SDMR
+        */
+       MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
+       MCF_SDRAMC_SDCR |= (0
+               | MCF_SDRAMC_SDCR_REF
+               | MCF_SDRAMC_SDCR_DQS_OE(0xC));
+       }
+}
+
+void gpio_init(void)
+{
+       /* Enable UART0 pins */
+       MCF_GPIO_PAR_UART = ( 0
+               | MCF_GPIO_PAR_UART_PAR_URXD0
+               | MCF_GPIO_PAR_UART_PAR_UTXD0);
+
+       /* Initialize TIN3 as a GPIO output to enable the write
+          half of the latch */
+       MCF_GPIO_PAR_TIMER = 0x00;
+       __raw_writeb(0x08, MCFGPIO_PDDR_TIMER);
+       __raw_writeb(0x00, MCFGPIO_PCLRR_TIMER);
+
+}
+
+int clock_pll(int fsys, int flags)
+{
+       int fref, temp, fout, mfd;
+       u32 i;
+
+       fref = FREF;
+        
+       if (fsys == 0) {
+               /* Return current PLL output */
+               mfd = MCF_PLL_PFDR;
+
+               return (fref * mfd / (BUSDIV * 4));
+       }
+
+       /* Check bounds of requested system clock */
+       if (fsys > MAX_FSYS)
+               fsys = MAX_FSYS;
+       if (fsys < MIN_FSYS)
+               fsys = MIN_FSYS;
+
+       /* Multiplying by 100 when calculating the temp value,
+          and then dividing by 100 to calculate the mfd allows
+          for exact values without needing to include floating
+          point libraries. */
+       temp = 100 * fsys / fref;
+       mfd = 4 * BUSDIV * temp / 100;
+                       
+       /* Determine the output frequency for selected values */
+       fout = (fref * mfd / (BUSDIV * 4));
+
+       /*
+        * Check to see if the SDRAM has already been initialized.
+        * If it has then the SDRAM needs to be put into self refresh
+        * mode before reprogramming the PLL.
+        */
+       if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
+               /* Put SDRAM into self refresh mode */
+               MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;
+
+       /*
+        * Initialize the PLL to generate the new system clock frequency.
+        * The device must be put into LIMP mode to reprogram the PLL.
+        */
+
+       /* Enter LIMP mode */
+       clock_limp(DEFAULT_LPD);
+                                       
+       /* Reprogram PLL for desired fsys */
+       MCF_PLL_PODR = (0
+               | MCF_PLL_PODR_CPUDIV(BUSDIV/3)
+               | MCF_PLL_PODR_BUSDIV(BUSDIV));
+                                               
+       MCF_PLL_PFDR = mfd;
+               
+       /* Exit LIMP mode */
+       clock_exit_limp();
+       
+       /*
+        * Return the SDRAM to normal operation if it is in use.
+        */
+       if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
+               /* Exit self refresh mode */
+               MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;
+
+       /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
+       MCF_SDRAMC_LIMP_FIX = MCF_SDRAMC_REFRESH;
+
+       /* wait for DQS logic to relock */
+       for (i = 0; i < 0x200; i++)
+               ;
+
+       return fout;
+}
+
+int clock_limp(int div)
+{
+       u32 temp;
+
+       /* Check bounds of divider */
+       if (div < MIN_LPD)
+               div = MIN_LPD;
+       if (div > MAX_LPD)
+               div = MAX_LPD;
+    
+       /* Save of the current value of the SSIDIV so we don't
+          overwrite the value*/
+       temp = (MCF_CCM_CDR & MCF_CCM_CDR_SSIDIV(0xF));
+      
+       /* Apply the divider to the system clock */
+       MCF_CCM_CDR = ( 0
+               | MCF_CCM_CDR_LPDIV(div)
+               | MCF_CCM_CDR_SSIDIV(temp));
+    
+       MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;
+    
+       return (FREF/(3*(1 << div)));
+}
+
+int clock_exit_limp(void)
+{
+       int fout;
+       
+       /* Exit LIMP mode */
+       MCF_CCM_MISCCR = (MCF_CCM_MISCCR & ~ MCF_CCM_MISCCR_LIMP);
+
+       /* Wait for PLL to lock */
+       while (!(MCF_CCM_MISCCR & MCF_CCM_MISCCR_PLL_LOCK))
+               ;
+       
+       fout = get_sys_clock();
+
+       return fout;
+}
+
+int get_sys_clock(void)
+{
+       int divider;
+       
+       /* Test to see if device is in LIMP mode */
+       if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP) {
+               divider = MCF_CCM_CDR & MCF_CCM_CDR_LPDIV(0xF);
+               return (FREF/(2 << divider));
+       }
+       else
+               return ((FREF * MCF_PLL_PFDR) / (BUSDIV * 4));
+}
diff --git a/arch/m68k/platform/532x/gpio.c b/arch/m68k/platform/532x/gpio.c
new file mode 100644 (file)
index 0000000..212a85d
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PIRQ",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
+               .podr                           = (void __iomem *) MCFEPORT_EPDR,
+               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 8,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 16,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "SSI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 24,
+                       .ngpio                  = 5,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SSI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_SSI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SSI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SSI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SSI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BUSCTL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 32,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "BE",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 40,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BE,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_BE,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BE,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "CS",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 49,
+                       .ngpio                  = 5,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "PWM",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 58,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_PWM,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_PWM,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_PWM,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_PWM,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_PWM,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "FECI2C",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 64,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "UART",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 72,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UART,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_UART,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UART,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "QSPI",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 80,
+                       .ngpio                  = 6,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "TIMER",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 88,
+                       .ngpio                  = 4,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "LCDDATAH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 96,
+                       .ngpio                  = 2,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "LCDDATAM",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 104,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAM,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAM,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAM,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAM,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAM,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "LCDDATAL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 112,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAL,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "LCDCTLH",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 120,
+                       .ngpio                  = 1,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDCTLH,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDCTLH,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLH,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLH,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDCTLH,
+       },
+       {
+               .gpio_chip                      = {
+                       .label                  = "LCDCTLL",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value_fast,
+                       .base                   = 128,
+                       .ngpio                  = 8,
+               },
+               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDCTLL,
+               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDCTLL,
+               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLL,
+               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLL,
+               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDCTLL,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/5407/Makefile b/arch/m68k/platform/5407/Makefile
new file mode 100644 (file)
index 0000000..e83fe14
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o gpio.o
+
diff --git a/arch/m68k/platform/5407/config.c b/arch/m68k/platform/5407/config.c
new file mode 100644 (file)
index 0000000..70ea789
--- /dev/null
@@ -0,0 +1,122 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/5407/config.c
+ *
+ *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2000, Lineo (www.lineo.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m5407_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5407_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5407_uart_platform,
+};
+
+static struct platform_device *m5407_devices[] __initdata = {
+       &m5407_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5407_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
+       } else if (line == 1) {
+               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
+       }
+}
+
+static void __init m5407_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5407_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5407_uart_init_line(line, m5407_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void __init m5407_timers_init(void)
+{
+       /* Timer1 is always used as system timer */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+       /* Timer2 is to be used as a high speed profile timer  */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+               MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+}
+
+/***************************************************************************/
+
+void m5407_cpu_reset(void)
+{
+       local_irq_disable();
+       /* set watchdog to soft reset, and enabled */
+       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+       for (;;)
+               /* wait for watchdog to timeout */;
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = m5407_cpu_reset;
+       m5407_timers_init();
+       m5407_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/5407/gpio.c b/arch/m68k/platform/5407/gpio.c
new file mode 100644 (file)
index 0000000..5850612
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Coldfire generic GPIO support
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfgpio.h>
+
+static struct mcf_gpio_chip mcf_gpio_chips[] = {
+       {
+               .gpio_chip                      = {
+                       .label                  = "PP",
+                       .request                = mcf_gpio_request,
+                       .free                   = mcf_gpio_free,
+                       .direction_input        = mcf_gpio_direction_input,
+                       .direction_output       = mcf_gpio_direction_output,
+                       .get                    = mcf_gpio_get_value,
+                       .set                    = mcf_gpio_set_value,
+                       .ngpio                  = 16,
+               },
+               .pddr                           = (void __iomem *) MCFSIM_PADDR,
+               .podr                           = (void __iomem *) MCFSIM_PADAT,
+               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
+       },
+};
+
+static int __init mcf_gpio_init(void)
+{
+       unsigned i = 0;
+       while (i < ARRAY_SIZE(mcf_gpio_chips))
+               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
+       return 0;
+}
+
+core_initcall(mcf_gpio_init);
diff --git a/arch/m68k/platform/54xx/Makefile b/arch/m68k/platform/54xx/Makefile
new file mode 100644 (file)
index 0000000..6cfd090
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o
+obj-$(CONFIG_FIREBEE) += firebee.o
+
diff --git a/arch/m68k/platform/54xx/config.c b/arch/m68k/platform/54xx/config.c
new file mode 100644 (file)
index 0000000..7813098
--- /dev/null
@@ -0,0 +1,115 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/54xx/config.c
+ *
+ *     Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m54xxsim.h>
+#include <asm/mcfuart.h>
+#include <asm/m54xxgpt.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m54xx_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 64 + 35,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 64 + 34,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = 64 + 33,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE4,
+               .irq            = 64 + 32,
+       },
+};
+
+static struct platform_device m54xx_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m54xx_uart_platform,
+};
+
+static struct platform_device *m54xx_devices[] __initdata = {
+       &m54xx_uart,
+};
+
+
+/***************************************************************************/
+
+static void __init m54xx_uart_init_line(int line, int irq)
+{
+       int rts_cts;
+
+       /* enable io pins */
+       switch (line) {
+       case 0:
+               rts_cts = 0; break;
+       case 1:
+               rts_cts = MCF_PAR_PSC_RTS_RTS; break;
+       case 2:
+               rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
+       case 3:
+               rts_cts = 0; break;
+       }
+       __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
+                                               MCF_MBAR + MCF_PAR_PSC(line));
+}
+
+static void __init m54xx_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m54xx_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m54xx_uart_init_line(line, m54xx_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void mcf54xx_reset(void)
+{
+       /* disable interrupts and enable the watchdog */
+       asm("movew #0x2700, %sr\n");
+       __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
+       __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
+       __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+                                               MCF_MBAR + MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+       mach_reset = mcf54xx_reset;
+       m54xx_uarts_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+
+       platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/54xx/firebee.c b/arch/m68k/platform/54xx/firebee.c
new file mode 100644 (file)
index 0000000..46d5053
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************/
+
+/*
+ *     firebee.c -- extra startup code support for the FireBee boards
+ *
+ *     Copyright (C) 2011, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     8MB of NOR flash fitted to the FireBee board.
+ */
+#define        FLASH_PHYS_ADDR         0xe0000000      /* Physical address of flash */
+#define        FLASH_PHYS_SIZE         0x00800000      /* Size of flash */
+
+#define        PART_BOOT_START         0x00000000      /* Start at bottom of flash */
+#define        PART_BOOT_SIZE          0x00040000      /* 256k in size */
+#define        PART_IMAGE_START        0x00040000      /* Start after boot loader */
+#define        PART_IMAGE_SIZE         0x006c0000      /* Most of flash */
+#define        PART_FPGA_START         0x00700000      /* Start at offset 7MB */
+#define        PART_FPGA_SIZE          0x00100000      /* 1MB in size */
+
+static struct mtd_partition firebee_flash_parts[] = {
+       {
+               .name   = "dBUG",
+               .offset = PART_BOOT_START,
+               .size   = PART_BOOT_SIZE,
+       },
+       {
+               .name   = "FPGA",
+               .offset = PART_FPGA_START,
+               .size   = PART_FPGA_SIZE,
+       },
+       {
+               .name   = "image",
+               .offset = PART_IMAGE_START,
+               .size   = PART_IMAGE_SIZE,
+       },
+};
+
+static struct physmap_flash_data firebee_flash_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(firebee_flash_parts),
+       .parts          = firebee_flash_parts,
+};
+
+static struct resource firebee_flash_resource = {
+       .start          = FLASH_PHYS_ADDR,
+       .end            = FLASH_PHYS_ADDR + FLASH_PHYS_SIZE,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device firebee_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &firebee_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &firebee_flash_resource,
+};
+
+/***************************************************************************/
+
+static int __init init_firebee(void)
+{
+       platform_device_register(&firebee_flash);
+       return 0;
+}
+
+arch_initcall(init_firebee);
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/68328/Makefile b/arch/m68k/platform/68328/Makefile
new file mode 100644 (file)
index 0000000..5e54355
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Makefile for arch/m68knommu/platform/68328.
+#
+
+head-y                 = head-$(MODEL).o
+head-$(CONFIG_PILOT)   = head-pilot.o
+head-$(CONFIG_DRAGEN2) = head-de2.o
+
+obj-y                  += entry.o ints.o timers.o
+obj-$(CONFIG_M68328)   += config.o
+obj-$(CONFIG_ROM)      += romvec.o
+
+extra-y                        := head.o
+extra-$(CONFIG_M68328) += bootlogo.rh head.o
+
+$(obj)/bootlogo.rh: $(src)/bootlogo.h
+       perl $(src)/bootlogo.pl < $(src)/bootlogo.h > $(obj)/bootlogo.rh
+
+$(obj)/head.o: $(obj)/$(head-y)
+       ln -sf $(head-y) $(obj)/head.o
+
+clean-files := $(obj)/bootlogo.rh $(obj)/head.o $(head-y)
diff --git a/arch/m68k/platform/68328/bootlogo.h b/arch/m68k/platform/68328/bootlogo.h
new file mode 100644 (file)
index 0000000..67bc2c1
--- /dev/null
@@ -0,0 +1,270 @@
+#define bootlogo_width 160
+#define bootlogo_height 160
+static unsigned char bootlogo_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00,
+  0x00, 0xff, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x80, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x50, 0x04, 0x00, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00,
+  0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40,
+  0xa8, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x28, 0x01, 0x00, 0x00,
+  0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70,
+  0x54, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x3a, 0x78, 0x80, 0x0e,
+  0x50, 0xc0, 0x03, 0x0e, 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
+  0x00, 0x3e, 0xf0, 0x83, 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x1f,
+  0x00, 0x18, 0x00, 0x30, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0xc3,
+  0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x0f, 0x00, 0x20, 0x00, 0x10,
+  0x55, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc0, 0x03, 0x9f, 0xf3, 0x80, 0x0f,
+  0x78, 0x80, 0xc7, 0x0e, 0x00, 0x18, 0x00, 0x20, 0xaa, 0x00, 0x00, 0x00,
+  0x00, 0x1e, 0xe0, 0x03, 0x9f, 0xf1, 0x80, 0x07, 0x78, 0x80, 0x67, 0x00,
+  0x00, 0x24, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01,
+  0x5e, 0xf0, 0x80, 0x07, 0x3c, 0x00, 0x2f, 0x00, 0x00, 0x14, 0x00, 0x20,
+  0xaa, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, 0x7f, 0xf0, 0x80, 0x07,
+  0x3c, 0x00, 0x3f, 0x00, 0x00, 0x08, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00,
+  0x00, 0x0f, 0xe0, 0x00, 0x3f, 0xf0, 0xc0, 0x03, 0x1e, 0x00, 0x1f, 0x00,
+  0x00, 0x14, 0x00, 0x28, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00,
+  0x1f, 0xf0, 0xc0, 0x03, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x0c,
+  0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xc0, 0x03,
+  0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x12, 0xa8, 0x00, 0x00, 0x00,
+  0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1f, 0x00,
+  0x00, 0x04, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x80,
+  0x0f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x08,
+  0x50, 0x01, 0x00, 0x00, 0x84, 0x03, 0x78, 0x80, 0x07, 0x3c, 0xe0, 0xc1,
+  0x0f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x06, 0xa8, 0x00, 0x00, 0x00,
+  0xc0, 0x03, 0x78, 0xc0, 0x07, 0x3c, 0xe0, 0xc1, 0x0f, 0x00, 0x1f, 0x00,
+  0x00, 0x0a, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0xc2, 0x01, 0x38, 0xc0,
+  0x07, 0x3c, 0xe0, 0x60, 0x0f, 0x80, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x07,
+  0xa0, 0x00, 0x00, 0x80, 0xe0, 0x01, 0x3c, 0xc0, 0x07, 0x3c, 0xf0, 0xa0,
+  0x07, 0xc0, 0x1c, 0x00, 0x00, 0x0a, 0x80, 0x08, 0xa0, 0x02, 0x00, 0xa0,
+  0xe0, 0x21, 0x1c, 0xc0, 0x03, 0x1c, 0x71, 0x90, 0x47, 0x40, 0x3c, 0x04,
+  0x00, 0x05, 0x80, 0x06, 0xa0, 0x02, 0x00, 0x20, 0xe0, 0x31, 0x1e, 0xc3,
+  0x03, 0x1e, 0x79, 0x98, 0x47, 0x60, 0x38, 0x04, 0x00, 0x15, 0x40, 0x0a,
+  0xa0, 0x0a, 0x00, 0x1a, 0xe0, 0x19, 0x9e, 0xe1, 0x01, 0x9e, 0x78, 0xcc,
+  0xa7, 0x32, 0x78, 0x02, 0x80, 0x2a, 0x40, 0x05, 0x80, 0x2a, 0x00, 0x05,
+  0xe0, 0x0d, 0x9e, 0xe0, 0x01, 0xde, 0x78, 0xc6, 0x97, 0x1b, 0x78, 0x03,
+  0x80, 0x52, 0x30, 0x0a, 0x00, 0x95, 0xd2, 0x0a, 0xe0, 0x0f, 0xfe, 0xe0,
+  0x00, 0x7e, 0xf8, 0x87, 0x9f, 0x0f, 0xf8, 0x01, 0x00, 0xa1, 0x0e, 0x15,
+  0x80, 0x55, 0x55, 0x01, 0xe0, 0x01, 0x3c, 0xf0, 0x00, 0x3c, 0xf0, 0x80,
+  0x8f, 0x0f, 0x70, 0x00, 0x00, 0x81, 0x02, 0x14, 0x00, 0x54, 0x55, 0x00,
+  0xc0, 0x01, 0x3c, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x07, 0x03, 0x70, 0x00,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x01, 0x00, 0x11, 0x09, 0x00, 0x04, 0x00, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
+  0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x32, 0x49, 0x49, 0x91,
+  0x24, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x49, 0x0a, 0x09, 0xc9, 0x92, 0x14, 0x81, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49,
+  0x18, 0x01, 0x49, 0x92, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x30, 0x01, 0x49, 0x92,
+  0x14, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x08, 0x69, 0x22, 0x09, 0x49, 0xd2, 0x24, 0x24, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51,
+  0x1a, 0x09, 0x49, 0xa2, 0x44, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x87, 0x08, 0x00, 0x00, 0x00,
+  0xf2, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
+  0x09, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
+  0x88, 0x86, 0x48, 0x04, 0x09, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x71,
+  0x88, 0x66, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x89, 0x48, 0x84,
+  0x08, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x89, 0x88, 0x99, 0x00, 0x00,
+  0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x82, 0xf8, 0xf0, 0xe0, 0x80,
+  0xf0, 0xf8, 0x13, 0x81, 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
+  0x88, 0x88, 0x08, 0x81, 0x08, 0x09, 0x01, 0x41, 0x08, 0x01, 0xf0, 0xf0,
+  0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x42,
+  0x08, 0x09, 0x01, 0x21, 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00,
+  0x00, 0x40, 0x46, 0x88, 0x88, 0x88, 0x4c, 0x44, 0x08, 0x09, 0x09, 0x11,
+  0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x80, 0x85, 0x87,
+  0x88, 0x08, 0x4b, 0x24, 0xf0, 0xf0, 0xf0, 0xf8, 0xf1, 0x00, 0x10, 0x70,
+  0x89, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x08, 0x02, 0x04, 0x00,
+  0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x1f, 0x00, 0x00, 0x48, 0x62, 0xc4, 0x31, 0x4a, 0x18, 0x3c, 0x03,
+  0x21, 0x45, 0x92, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x1f, 0x00, 0x00,
+  0x48, 0x92, 0x24, 0x48, 0xb6, 0x24, 0x88, 0x04, 0x21, 0x4b, 0x92, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xa8, 0xf2, 0x24, 0x48,
+  0x92, 0x3c, 0x88, 0x04, 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04,
+  0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, 0x21, 0x49, 0x93, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xcf, 0x7e, 0x00, 0x00, 0x10, 0xe1, 0xc4, 0x31,
+  0x92, 0x38, 0x30, 0x03, 0x2f, 0x89, 0x92, 0x00, 0x00, 0x00, 0x80, 0xe3,
+  0x07, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x03, 0x7e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xc9, 0x23, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95,
+  0x33, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdd, 0xfb, 0x7e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x1d, 0xf8, 0x7e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x40, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b,
+  0x70, 0x7e, 0x00, 0x00, 0x08, 0x00, 0xe0, 0x00, 0x02, 0x00, 0x47, 0x80,
+  0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x03, 0x00, 0x7e, 0x00, 0x00,
+  0x3c, 0xa3, 0x20, 0x31, 0x52, 0x02, 0x49, 0xcc, 0x3f, 0xa3, 0x94, 0x08,
+  0x00, 0x00, 0x00, 0x27, 0x02, 0x7e, 0x00, 0x00, 0x88, 0xe4, 0x20, 0x41,
+  0xb2, 0x05, 0x49, 0x90, 0x88, 0xe4, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x7e, 0x00, 0x00, 0x88, 0x24, 0xe0, 0x70, 0x92, 0x04, 0x47, 0x9c,
+  0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x13, 0x48, 0x7e, 0x00, 0x00,
+  0x88, 0x24, 0x20, 0x48, 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x01,
+  0x00, 0x00, 0x00, 0x43, 0x00, 0xfe, 0x00, 0x00, 0x88, 0x24, 0x20, 0x48,
+  0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x07,
+  0x94, 0xce, 0x00, 0x00, 0x08, 0x23, 0x20, 0xb0, 0x92, 0x04, 0x41, 0x2c,
+  0x0b, 0x23, 0x24, 0x09, 0x00, 0x00, 0x00, 0x49, 0x02, 0xce, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x11, 0x08, 0xdc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x01, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01,
+  0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
+  0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
+  0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
+  0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00,
+  0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xfe, 0x0f,
+  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x08, 0x00,
+  0x00, 0xc0, 0x03, 0x00, 0x78, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x40, 0x10,
+  0x12, 0x10, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
+  0x84, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x20, 0x26, 0x0a, 0x10, 0x9d, 0x39,
+  0xa6, 0xb2, 0x0a, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x02, 0x00, 0xfe, 0x0f,
+  0x00, 0x00, 0x20, 0x21, 0x06, 0x28, 0x25, 0x4a, 0xa9, 0x8a, 0x09, 0x00,
+  0x00, 0xe0, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21,
+  0x0e, 0x38, 0xa5, 0x4b, 0xa9, 0xb2, 0x09, 0x00, 0x00, 0xf0, 0x01, 0x22,
+  0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, 0x12, 0x44, 0xa5, 0x4a,
+  0x49, 0xa1, 0x0a, 0x00, 0x00, 0xf8, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f,
+  0x00, 0x00, 0x20, 0x26, 0x52, 0x44, 0x9d, 0x4d, 0x46, 0x99, 0x0a, 0x00,
+  0x00, 0xfc, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x40, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xb2,
+  0x84, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x6e, 0x78, 0x00, 0xfc, 0x1f,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfc, 0x01, 0x02, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x02,
+  0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0xfc, 0x0f,
+  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x24, 0x06, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x40, 0x10,
+  0x1e, 0x20, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
+  0x00, 0x80, 0xfc, 0x03, 0x00, 0x00, 0x20, 0x26, 0x22, 0x20, 0xf9, 0x89,
+  0x32, 0xe7, 0x08, 0x00, 0x00, 0x92, 0x38, 0x00, 0x00, 0x00, 0xfc, 0x01,
+  0x00, 0x00, 0x20, 0x21, 0x22, 0xa0, 0x92, 0x88, 0x4a, 0x29, 0x15, 0x00,
+  0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0xfa, 0x04, 0x00, 0x00, 0x20, 0x21,
+  0x22, 0xa0, 0x93, 0x88, 0x4a, 0x29, 0x1d, 0x00, 0x00, 0x11, 0xf2, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0xa8, 0x90, 0x88,
+  0x4a, 0x29, 0x05, 0x00, 0x48, 0x40, 0xf0, 0x01, 0x00, 0x80, 0x14, 0x04,
+  0x00, 0x00, 0x20, 0x26, 0x9e, 0x10, 0x93, 0x78, 0x32, 0x29, 0x19, 0x00,
+  0x00, 0x09, 0xe0, 0x03, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x40, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc5, 0x03,
+  0x00, 0x40, 0x22, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x20, 0x08, 0x04,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x50, 0x90, 0x03, 0x00, 0xb0, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+  0x00, 0x38, 0x22, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x44, 0x00, 0x00, 0x3c, 0x08, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0xbf, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x80, 0x48, 0x02,
+  0xc0, 0x1f, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xf0, 0x3f, 0x09, 0x00,
+  0x00, 0x10, 0x24, 0x48, 0x10, 0x12, 0x41, 0x52, 0x24, 0x09, 0x46, 0x71,
+  0x90, 0x20, 0x02, 0xfc, 0xff, 0x1f, 0x80, 0x22, 0x00, 0x90, 0x24, 0x49,
+  0x12, 0x92, 0x40, 0xb2, 0x24, 0x09, 0xc9, 0x49, 0x04, 0x80, 0x90, 0xfc,
+  0xff, 0xbf, 0x24, 0x00, 0x00, 0x90, 0x24, 0x49, 0x12, 0x92, 0x40, 0x92,
+  0x24, 0x06, 0x49, 0x48, 0x50, 0x0a, 0x02, 0xfe, 0xff, 0x3f, 0x00, 0x05,
+  0x00, 0x50, 0xa5, 0x4a, 0x15, 0x92, 0x40, 0x92, 0x24, 0x06, 0x49, 0x48,
+  0x80, 0x40, 0x48, 0xfe, 0xff, 0x3f, 0x49, 0x00, 0x00, 0x20, 0x42, 0x84,
+  0x88, 0x1a, 0x41, 0x92, 0x34, 0x49, 0x49, 0x68, 0x00, 0x38, 0x10, 0x07,
+  0x00, 0x60, 0x80, 0x00, 0x00, 0x20, 0x42, 0x84, 0x88, 0x14, 0x4e, 0x92,
+  0x28, 0x49, 0x46, 0x50, 0x00, 0x80, 0x83, 0x01, 0x00, 0xa0, 0x6a, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+  0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, };
diff --git a/arch/m68k/platform/68328/bootlogo.pl b/arch/m68k/platform/68328/bootlogo.pl
new file mode 100644 (file)
index 0000000..b04ae3f
--- /dev/null
@@ -0,0 +1,10 @@
+
+$_ = join("", <>);
+
+s/(0x[0-9a-f]{2})/sprintf("0x%.2x",ord(pack("b8",unpack("B8",chr(hex($1))))))/gei;
+
+s/^ /  .byte /gm;
+s/[,};]+$//gm;
+s/^static.*//gm;
+
+print $_;
diff --git a/arch/m68k/platform/68328/config.c b/arch/m68k/platform/68328/config.c
new file mode 100644 (file)
index 0000000..a7bd21d
--- /dev/null
@@ -0,0 +1,52 @@
+/***************************************************************************/
+
+/*
+ *  linux/arch/m68knommu/platform/68328/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *
+ * 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.
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ */
+
+/***************************************************************************/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/MC68328.h>
+
+/***************************************************************************/
+
+void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+
+/***************************************************************************/
+
+void m68328_reset (void)
+{
+  local_irq_disable();
+  asm volatile ("moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);");
+}
+
+/***************************************************************************/
+
+void config_BSP(char *command, int len)
+{
+  printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
+  printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
+  printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
+
+  mach_gettod = m68328_timer_gettod;
+  mach_reset = m68328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S
new file mode 100644 (file)
index 0000000..676960c
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *  linux/arch/m68knommu/platform/68328/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl ret_from_interrupt
+.globl bad_interrupt
+.globl inthandler1
+.globl inthandler2
+.globl inthandler3
+.globl inthandler4
+.globl inthandler5
+.globl inthandler6
+.globl inthandler7
+
+badsys:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
+       jra     ret_from_exception
+
+do_trace:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
+       movel   #-ENOSYS,%d0
+       cmpl    #NR_syscalls,%d1
+       jcc     1f
+       lsl     #2,%d1
+       lea     sys_call_table, %a0
+       jbsr    %a0@(%d1)
+
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(system_call)
+       SAVE_ALL
+
+       /* save top of frame*/
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
+
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       jne     do_trace
+       cmpl    #NR_syscalls,%d0
+       jcc     badsys
+       lsl     #2,%d0
+       lea     sys_call_table,%a0
+       movel   %a0@(%d0), %a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
+
+ret_from_exception:
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
+       jeq     Luser_return            /* if so, skip resched, signals*/
+
+Lkernel_return:
+       RESTORE_ALL
+
+Luser_return:
+       /* only allow interrupts when we are really the last one on the*/
+       /* kernel stack, otherwise stack overflow can occur during*/
+       /* heavy interrupt load*/
+       andw    #ALLOWINT,%sr
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+1:
+       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       jne     Lwork_to_do
+       RESTORE_ALL
+
+Lwork_to_do:
+       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address*/
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       bsrw    do_signal
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     1b
+
+/*
+ * This is the main interrupt handler, responsible for calling process_int()
+ */
+inthandler1:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #65,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler2:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #66,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler3:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #67,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler4:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #68,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler5:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #69,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler6:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #70,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler7:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   #71,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+inthandler:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and     #0x3ff, %d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               /*  put vector # on stack*/
+       jbsr    process_int             /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+ret_from_interrupt:
+       jeq     1f
+2:
+       RESTORE_ALL
+1:
+       moveb   %sp@(PT_OFF_SR), %d0
+       and     #7, %d0
+       jhi     2b
+
+       /* check if we need to do software interrupts */
+       jeq     ret_from_exception
+
+       pea     ret_from_exception
+       jra     do_softirq
+
+
+/*
+ * Handler for uninitialized and spurious interrupts.
+ */
+ENTRY(bad_interrupt)
+       addql   #1,num_spurious
+       rte
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1,so don't change these
+ * registers until their contents are no longer needed.
+ */
+ENTRY(resume)
+       movel   %a0,%d1                         /* save prev thread in d1 */
+       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
+       movel   %usp,%a2                        /* save usp */
+       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
+
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+       RESTORE_SWITCH_STACK
+
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore user stack */
+       movel   %a0,%usp
+       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
+       rts
+
diff --git a/arch/m68k/platform/68328/head-de2.S b/arch/m68k/platform/68328/head-de2.S
new file mode 100644 (file)
index 0000000..f632fdc
--- /dev/null
@@ -0,0 +1,128 @@
+
+#define        MEM_END 0x00800000      /* Memory size 8Mb */
+
+#undef CRT_DEBUG
+
+.macro PUTC CHAR
+#ifdef CRT_DEBUG
+       moveq   #\CHAR, %d7
+       jsr     putc
+#endif
+.endm
+
+       .global _start
+       .global _rambase
+       .global _ramvec
+       .global _ramstart
+       .global _ramend
+       
+       .data
+
+/*
+ *     Set up the usable of RAM stuff
+ */
+_rambase:
+       .long   0
+_ramvec:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+
+       .text
+
+_start:
+
+/*
+ * Setup initial stack
+ */
+       /* disable all interrupts */
+       movew   #0x2700, %sr
+       movel   #-1, 0xfffff304
+       movel   #MEM_END-4, %sp
+
+       PUTC    '\r'
+       PUTC    '\n'
+       PUTC    'A'
+       PUTC    'B'
+
+/*
+ *     Determine end of RAM
+ */
+
+       movel   #MEM_END, %a0
+       movel   %a0, _ramend
+
+       PUTC    'C'
+
+/*
+ *     Move ROM filesystem above bss :-)
+ */
+
+       moveal  #_sbss, %a0                     /* romfs at the start of bss */
+       moveal  #_ebss, %a1                     /* Set up destination  */
+       movel   %a0, %a2                        /* Copy of bss start */
+
+       movel   8(%a0), %d1                     /* Get size of ROMFS */
+       addql   #8, %d1                         /* Allow for rounding */
+       andl    #0xfffffffc, %d1        /* Whole words */
+
+       addl    %d1, %a0                        /* Copy from end */
+       addl    %d1, %a1                        /* Copy from end */
+       movel   %a1, _ramstart          /* Set start of ram */
+
+1:
+       movel   -(%a0), %d0                     /* Copy dword */
+       movel   %d0, -(%a1)
+       cmpl    %a0, %a2                        /* Check if at end */
+       bne     1b
+
+       PUTC    'D'
+
+/*
+ * Initialize BSS segment to 0
+ */
+
+       lea     _sbss, %a0
+       lea     _ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+2:     cmpal   %a0, %a1
+       beq     1f
+       clrl    (%a0)+
+       bra     2b
+1:
+
+       PUTC    'E'
+
+/*
+ * Load the current task pointer and stack
+ */
+
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       PUTC    'F'
+       PUTC    '\r'
+       PUTC    '\n'
+
+/*
+ * Go
+ */
+
+       jmp     start_kernel
+
+/*
+ * Local functions
+ */
+#ifdef CRT_DEBUG
+putc:
+       moveb   %d7, 0xfffff907
+1:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     1b
+       rts
+#endif
diff --git a/arch/m68k/platform/68328/head-pilot.S b/arch/m68k/platform/68328/head-pilot.S
new file mode 100644 (file)
index 0000000..aecff53
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * linux/arch/m68knommu/platform/68328/head-pilot.S
+ * - A startup file for the MC68328
+ *
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
+ *                     Kenneth Albanowski <kjahds@kjahds.com>,
+ *                     The Silver Hammer Group, Ltd.
+ *
+ * (c) 1995, Dionne & Associates
+ * (c) 1995, DKG Display Tech.
+ */
+
+#define ASSEMBLY
+
+#define IMMED #
+#define        DBG_PUTC(x)     moveb IMMED x, 0xfffff907
+
+
+.global _stext
+.global _start
+
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global penguin_bits
+
+#ifdef CONFIG_PILOT
+
+#define IMR 0xFFFFF304
+
+       .data
+       .align 16
+
+penguin_bits:  
+#include "bootlogo.rh"
+
+#endif
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+.text
+       
+_start:
+_stext:
+
+
+#ifdef CONFIG_M68328
+
+#ifdef CONFIG_PILOT
+       .byte 0x4e, 0xfa, 0x00, 0x0a /* Jmp +X bytes */
+       .byte 'b', 'o', 'o', 't'
+       .word 10000
+
+       nop
+#endif
+
+       moveq   #0, %d0
+       movew   %d0, 0xfffff618 /* Watchdog off */
+       movel   #0x00011f07, 0xfffff114 /* CS A1 Mask */
+
+       movew   #0x0800, 0xfffff906 /* Ignore CTS */
+       movew   #0x010b, 0xfffff902 /* BAUD to 9600 */
+
+       movew   #0x2410, 0xfffff200 /* PLLCR */
+       movew   #0x123, 0xfffff202 /* PLLFSR */
+
+#ifdef CONFIG_PILOT
+       moveb   #0, 0xfffffA27 /* LCKCON */
+       movel   #_start, 0xfffffA00 /* LSSA */
+       moveb   #0xa, 0xfffffA05 /* LVPW */
+       movew   #0x9f, 0xFFFFFa08 /* LXMAX */
+       movew   #0x9f, 0xFFFFFa0a /* LYMAX */
+       moveb   #9, 0xfffffa29 /* LBAR */
+       moveb   #0, 0xfffffa25 /* LPXCD */
+       moveb   #0x04, 0xFFFFFa20 /* LPICF */
+       moveb   #0x58, 0xfffffA27 /* LCKCON */
+       moveb   #0x85, 0xfffff429 /* PFDATA */
+       moveb   #0xd8, 0xfffffA27 /* LCKCON */
+       moveb   #0xc5, 0xfffff429 /* PFDATA */
+       moveb   #0xd5, 0xfffff429 /* PFDATA */
+
+       moveal  #0x00100000, %a3
+       moveal  #0x100ffc00, %a4
+#endif /* CONFIG_PILOT */
+
+#endif /* CONFIG_M68328 */
+
+       movew   #0x2700, %sr
+       lea     %a4@(-4), %sp
+
+       DBG_PUTC('\r')
+       DBG_PUTC('\n')
+       DBG_PUTC('A')
+
+       moveq   #0,%d0
+       movew   #16384, %d0  /* PLL settle wait loop */
+L0:
+       subw    #1, %d0
+       bne     L0
+
+       DBG_PUTC('B')
+
+       /* Copy command line from beginning of RAM (+16) to end of bss */
+       movel   #CONFIG_VECTORBASE, %d7
+       addl    #16, %d7
+       moveal  %d7, %a0
+       moveal  #_ebss, %a1
+       lea     %a1@(512), %a2
+
+       DBG_PUTC('C')
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+L2:
+       movel   %a0@+, %d0
+       movel   %d0, %a1@+
+       cmpal   %a1, %a2
+       bhi     L2
+
+       /* Copy data+init segment from ROM to RAM */
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #__init_end, %a2
+
+       DBG_PUTC('D')
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       movel   %a0@+, %d0
+       movel   %d0, %a1@+
+       cmpal   %a1, %a2
+       bhi     LD1
+
+       DBG_PUTC('E')
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+       DBG_PUTC('F')
+
+       /* Copy command line from end of bss to command line */
+       moveal  #_ebss, %a0
+       moveal  #command_line, %a1
+       lea     %a1@(512), %a2
+
+       DBG_PUTC('G')
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+L3:
+       movel   %a0@+, %d0
+       movel   %d0, %a1@+
+       cmpal   %a1, %a2
+       bhi     L3
+
+       movel   #_sdata, %d0    
+       movel   %d0, _rambase   
+       movel   #_ebss, %d0
+       movel   %d0, _ramstart
+
+       movel   %a4, %d0
+       subl    #4096, %d0      /* Reserve 4K of stack */
+       moveq   #79, %d7
+       movel   %d0, _ramend
+
+       movel   %a3, %d0
+       movel   %d0, rom_length
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       DBG_PUTC('H')
+
+#ifdef CONFIG_PILOT
+       movel   #penguin_bits, 0xFFFFFA00
+       moveb   #10, 0xFFFFFA05
+       movew   #160, 0xFFFFFA08
+       movew   #160, 0xFFFFFA0A
+#endif /* CONFIG_PILOT */
+
+       DBG_PUTC('I')
+
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+       DBG_PUTC('J')
+       DBG_PUTC('\r')
+       DBG_PUTC('\n')
+
+       jsr     start_kernel
+_exit:
+
+       jmp     _exit
+
+
+       .data
+env:
+       .long   0
diff --git a/arch/m68k/platform/68328/head-ram.S b/arch/m68k/platform/68328/head-ram.S
new file mode 100644 (file)
index 0000000..7f1aeea
--- /dev/null
@@ -0,0 +1,141 @@
+
+       .global __main
+       .global __rom_start
+
+        .global _rambase
+        .global _ramstart
+       
+       .global splash_bits
+       .global _start
+       .global _stext
+       .global _edata
+
+#define DEBUG
+#define ROM_OFFSET 0x10C00000
+#define STACK_GAURD 0x10
+
+       .text
+       
+_start:
+_stext:
+       movew   #0x2700, %sr            /* Exceptions off! */
+
+#if 0
+       /* Init chip registers.  uCsimm specific */
+       moveb   #0x00,   0xfffffb0b     /* Watchdog off */
+       moveb   #0x10,   0xfffff000     /* SCR */
+
+       movew   #0x2400, 0xfffff200     /* PLLCR */
+       movew   #0x0123, 0xfffff202     /* PLLFSR */
+
+       moveb   #0x00,   0xfffff40b     /* enable chip select */
+       moveb   #0x00,   0xfffff423     /* enable /DWE */
+       moveb   #0x08,   0xfffffd0d     /* disable hardmap */
+       moveb   #0x07,   0xfffffd0e     /* level 7 interrupt clear */
+
+       movew   #0x8600, 0xfffff100     /* FLASH at 0x10c00000 */
+       movew   #0x018b, 0xfffff110     /* 2Meg, enable, 0ws */
+
+       movew   #0x8f00, 0xfffffc00     /* DRAM configuration */
+       movew   #0x9667, 0xfffffc02     /* DRAM control */
+       movew   #0x0000, 0xfffff106     /* DRAM at 0x00000000 */
+       movew   #0x068f, 0xfffff116     /* 8Meg, enable, 0ws */
+
+       moveb   #0x40,   0xfffff300     /* IVR */
+       movel   #0x007FFFFF, %d0        /* IMR */
+       movel   %d0,     0xfffff304
+
+       moveb   0xfffff42b, %d0
+       andb    #0xe0,   %d0
+       moveb   %d0,     0xfffff42b
+
+       moveb   #0x08,   0xfffff907     /* Ignore CTS */
+       movew   #0x010b, 0xfffff902     /* BAUD to 9600 */
+       movew   #0xe100, 0xfffff900     /* enable */
+#endif
+
+       movew   #16384, %d0  /* PLL settle wait loop */
+L0:
+       subw    #1, %d0
+       bne     L0
+#ifdef DEBUG
+       moveq   #70, %d7                /* 'F' */
+       moveb   %d7,0xfffff907          /* No absolute addresses */
+pclp1:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     pclp1
+#endif /* DEBUG */
+
+#ifdef DEBUG
+       moveq   #82, %d7                /* 'R' */
+       moveb   %d7,0xfffff907          /* No absolute addresses */
+pclp3:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     pclp3
+#endif /* DEBUG */
+       moveal  #0x007ffff0, %ssp
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 >= %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+#ifdef DEBUG
+       moveq   #67, %d7                /* 'C' */
+       jsr     putc
+#endif /* DEBUG */
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+#ifdef DEBUG
+       moveq   #70, %d7                /* 'F' */
+       jsr     putc
+#endif /* DEBUG */
+
+lp:
+       jsr     start_kernel
+        jmp lp
+_exit:
+
+       jmp     _exit
+
+__main:
+       /* nothing */
+       rts
+
+#ifdef DEBUG
+putc:
+       moveb   %d7,0xfffff907
+pclp:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     pclp
+       rts
+#endif /* DEBUG */
+
+       .data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+env:
+       .long   0
diff --git a/arch/m68k/platform/68328/head-rom.S b/arch/m68k/platform/68328/head-rom.S
new file mode 100644 (file)
index 0000000..6ec77d3
--- /dev/null
@@ -0,0 +1,110 @@
+       
+       .global _start
+       .global _stext
+
+       .global _rambase
+       .global _ramvec
+       .global _ramstart
+       .global _ramend
+
+#ifdef CONFIG_INIT_LCD
+       .global splash_bits
+#endif
+
+       .data
+
+/*
+ *      Set up the usable of RAM stuff. Size of RAM is determined then
+ *      an initial stack set up at the end.
+ */
+.align 4
+_ramvec:
+.long   0
+_rambase:
+.long   0
+_ramstart:
+.long   0
+_ramend:
+.long   0
+
+#define        RAMEND  (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
+#ifdef CONFIG_INIT_LCD
+splash_bits:
+#include "bootlogo.rh"
+#endif
+       
+       .text
+_start:
+_stext:        movew   #0x2700,%sr
+#ifdef CONFIG_INIT_LCD
+       movel   #splash_bits, 0xfffffA00 /* LSSA */
+       moveb   #0x28,   0xfffffA05     /* LVPW */
+       movew   #0x280,  0xFFFFFa08     /* LXMAX */
+       movew   #0x1df,  0xFFFFFa0a     /* LYMAX */
+       moveb   #0,      0xfffffa29     /* LBAR */
+       moveb   #0,      0xfffffa25     /* LPXCD */
+       moveb   #0x08,   0xFFFFFa20     /* LPICF */
+       moveb   #0x01,   0xFFFFFA21     /* -ve pol */
+       moveb   #0x81,   0xfffffA27     /* LCKCON */
+       movew   #0xff00, 0xfffff412     /* LCD pins */
+#endif
+       moveal  #RAMEND-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
+       movew   #32767, %d0  /* PLL settle wait loop */
+1:     subq    #1, %d0
+       bne     1b
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+1:     movel   %a0@+, %a1@+
+       cmpal   %a1, %a2
+       bhi     1b
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+       /* Copy 0 to %a0 until %a0 == %a1 */
+       
+1:
+       clrl    %a0@+
+       cmpal   %a0, %a1
+       bhi     1b
+
+        movel   #_sdata, %d0    
+        movel   %d0, _rambase        
+        movel   #_ebss, %d0
+        movel   %d0, _ramstart
+       movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
+       movel   %d0, _ramend
+       movel   #CONFIG_VECTORBASE,     %d0
+       movel   %d0, _ramvec
+       
+/*
+ * load the current task pointer and stack
+ */
+       lea     init_thread_union, %a0
+       lea     0x2000(%a0), %sp
+
+1:     jsr     start_kernel
+        bra 1b
+_exit:
+
+       jmp     _exit
+
+
+putc:
+       moveb   %d7,0xfffff907
+1:
+       movew   0xfffff906, %d7
+       andw    #0x2000, %d7
+       beq     1b
+       rts
+
+       .data
+env:
+       .long   0
+       .text
+
diff --git a/arch/m68k/platform/68328/ints.c b/arch/m68k/platform/68328/ints.c
new file mode 100644 (file)
index 0000000..e563183
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * linux/arch/m68knommu/platform/68328/ints.c
+ *
+ * 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 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#if defined(CONFIG_M68328)
+#include <asm/MC68328.h>
+#elif defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#elif defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#endif
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void trap3(void);
+asmlinkage void trap4(void);
+asmlinkage void trap5(void);
+asmlinkage void trap6(void);
+asmlinkage void trap7(void);
+asmlinkage void trap8(void);
+asmlinkage void trap9(void);
+asmlinkage void trap10(void);
+asmlinkage void trap11(void);
+asmlinkage void trap12(void);
+asmlinkage void trap13(void);
+asmlinkage void trap14(void);
+asmlinkage void trap15(void);
+asmlinkage void trap33(void);
+asmlinkage void trap34(void);
+asmlinkage void trap35(void);
+asmlinkage void trap36(void);
+asmlinkage void trap37(void);
+asmlinkage void trap38(void);
+asmlinkage void trap39(void);
+asmlinkage void trap40(void);
+asmlinkage void trap41(void);
+asmlinkage void trap42(void);
+asmlinkage void trap43(void);
+asmlinkage void trap44(void);
+asmlinkage void trap45(void);
+asmlinkage void trap46(void);
+asmlinkage void trap47(void);
+asmlinkage irqreturn_t bad_interrupt(int, void *);
+asmlinkage irqreturn_t inthandler(void);
+asmlinkage irqreturn_t inthandler1(void);
+asmlinkage irqreturn_t inthandler2(void);
+asmlinkage irqreturn_t inthandler3(void);
+asmlinkage irqreturn_t inthandler4(void);
+asmlinkage irqreturn_t inthandler5(void);
+asmlinkage irqreturn_t inthandler6(void);
+asmlinkage irqreturn_t inthandler7(void);
+
+extern e_vector *_ramvec;
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+/* The 68k family did not have a good way to determine the source
+ * of interrupts until later in the family.  The EC000 core does
+ * not provide the vector number on the stack, we vector everything
+ * into one vector and look in the blasted mask register...
+ * This code is designed to be fast, almost constant time, not clean!
+ */
+void process_int(int vec, struct pt_regs *fp)
+{
+       int irq;
+       int mask;
+
+       unsigned long pend = ISR;
+
+       while (pend) {
+               if (pend & 0x0000ffff) {
+                       if (pend & 0x000000ff) {
+                               if (pend & 0x0000000f) {
+                                       mask = 0x00000001;
+                                       irq = 0;
+                               } else {
+                                       mask = 0x00000010;
+                                       irq = 4;
+                               }
+                       } else {
+                               if (pend & 0x00000f00) {
+                                       mask = 0x00000100;
+                                       irq = 8;
+                               } else {
+                                       mask = 0x00001000;
+                                       irq = 12;
+                               }
+                       }
+               } else {
+                       if (pend & 0x00ff0000) {
+                               if (pend & 0x000f0000) {
+                                       mask = 0x00010000;
+                                       irq = 16;
+                               } else {
+                                       mask = 0x00100000;
+                                       irq = 20;
+                               }
+                       } else {
+                               if (pend & 0x0f000000) {
+                                       mask = 0x01000000;
+                                       irq = 24;
+                               } else {
+                                       mask = 0x10000000;
+                                       irq = 28;
+                               }
+                       }
+               }
+
+               while (! (mask & pend)) {
+                       mask <<=1;
+                       irq++;
+               }
+
+               do_IRQ(irq, fp);
+               pend &= ~mask;
+       }
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       IMR &= ~(1 << d->irq);
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       IMR |= (1 << d->irq);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "M68K-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the machine vector table.
+ */
+void __init init_IRQ(void)
+{
+       int i;
+
+       /* set up the vectors */
+       for (i = 72; i < 256; ++i)
+               _ramvec[i] = (e_vector) bad_interrupt;
+
+       _ramvec[32] = system_call;
+
+       _ramvec[65] = (e_vector) inthandler1;
+       _ramvec[66] = (e_vector) inthandler2;
+       _ramvec[67] = (e_vector) inthandler3;
+       _ramvec[68] = (e_vector) inthandler4;
+       _ramvec[69] = (e_vector) inthandler5;
+       _ramvec[70] = (e_vector) inthandler6;
+       _ramvec[71] = (e_vector) inthandler7;
+
+       IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
+
+       /* turn off all interrupts */
+       IMR = ~0;
+
+       for (i = 0; (i < NR_IRQS); i++) {
+               set_irq_chip(i, &intc_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/platform/68328/romvec.S b/arch/m68k/platform/68328/romvec.S
new file mode 100644 (file)
index 0000000..3108446
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * linux/arch/m68knommu/platform/68328/romvec.S
+ *
+ * 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 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
+ */
+
+.global _start
+.global _buserr
+.global trap
+.global system_call
+
+.section .romvec
+
+e_vectors:
+.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+/* TRAP #0-15 */
+.long system_call, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long trap, trap, trap, trap
+.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
diff --git a/arch/m68k/platform/68328/timers.c b/arch/m68k/platform/68328/timers.c
new file mode 100644 (file)
index 0000000..309f725
--- /dev/null
@@ -0,0 +1,134 @@
+/***************************************************************************/
+
+/*
+ *  linux/arch/m68knommu/platform/68328/timers.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *  Copyright (C) 2001 Georges Menie, Ken Desmet
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clocksource.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68VZ328.h>
+
+/***************************************************************************/
+
+#if defined(CONFIG_DRAGEN2)
+/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
+#define CLOCK_PRE      7
+#define TICKS_PER_JIFFY        41450
+
+#elif defined(CONFIG_XCOPILOT_BUGS)
+/*
+ * The only thing I know is that CLK32 is not available on Xcopilot
+ * I have little idea about what frequency SYSCLK has on Xcopilot.
+ * The values for prescaler and compare registers were simply
+ * taken from the original source
+ */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
+#define CLOCK_PRE      2
+#define TICKS_PER_JIFFY        0xd7e4
+
+#else
+/* default to using the 32Khz clock */
+#define CLOCK_SOURCE   TCTL_CLKSOURCE_32KHZ
+#define CLOCK_PRE      31
+#define TICKS_PER_JIFFY        10
+#endif
+
+static u32 m68328_tick_cnt;
+
+/***************************************************************************/
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+       /* Reset Timer1 */
+       TSTAT &= 0;
+
+       m68328_tick_cnt += TICKS_PER_JIFFY;
+       return arch_timer_interrupt(irq, dummy);
+}
+
+/***************************************************************************/
+
+static struct irqaction m68328_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = hw_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t m68328_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+
+       local_irq_save(flags);
+       cycles = m68328_tick_cnt + TCN;
+       local_irq_restore(flags);
+
+       return cycles;
+}
+
+/***************************************************************************/
+
+static struct clocksource m68328_clk = {
+       .name   = "timer",
+       .rating = 250,
+       .read   = m68328_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
+
+void hw_timer_init(void)
+{
+       /* disable timer 1 */
+       TCTL = 0;
+
+       /* set ISR */
+       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
+
+       /* Restart mode, Enable int, Set clock source */
+       TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
+       TPRER = CLOCK_PRE;
+       TCMP = TICKS_PER_JIFFY;
+
+       /* Enable timer 1 */
+       TCTL |= TCTL_TEN;
+       m68328_clk.mult = clocksource_hz2mult(TICKS_PER_JIFFY*HZ, m68328_clk.shift);
+       clocksource_register(&m68328_clk);
+}
+
+/***************************************************************************/
+
+void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec)
+{
+       long now = RTCTIME;
+
+       *year = *mon = *day = 1;
+       *hour = (now >> 24) % 24;
+       *min = (now >> 16) % 60;
+       *sec = now % 60;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/68360/Makefile b/arch/m68k/platform/68360/Makefile
new file mode 100644 (file)
index 0000000..cf5af73
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for arch/m68knommu/platform/68360.
+#
+
+obj-y := config.o commproc.o entry.o ints.o
+
+extra-y := head.o
+
+$(obj)/head.o: $(obj)/head-$(MODEL).o
+       ln -sf head-$(MODEL).o $(obj)/head.o
diff --git a/arch/m68k/platform/68360/commproc.c b/arch/m68k/platform/68360/commproc.c
new file mode 100644 (file)
index 0000000..8e4e10c
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ *
+ * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space.  The allocator for that is here.  When the communication
+ * process is reset, we reclaim the memory available.  There is
+ * currently no deallocator for this memory.
+ * The amount of space available is platform dependent.  On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose.  Current, the first 512 bytes and the last 256 bytes of
+ * memory are used.  Right now I am conservative and only use the
+ * memory that can never be used for microcode.  If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ *
+ */
+
+/*
+ * Michael Leslie <mleslie@lineo.com>
+ * adapted Dan Malek's ppc8xx drivers to M68360
+ *
+ */
+
+#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/irq.h>
+#include <asm/m68360.h>
+#include <asm/commproc.h>
+
+/* #include <asm/page.h> */
+/* #include <asm/pgtable.h> */
+extern void *_quicc_base;
+extern unsigned int system_clock;
+
+
+static uint dp_alloc_base;     /* Starting offset in DP ram */
+static uint dp_alloc_top;      /* Max offset + 1 */
+
+#if 0
+static void    *host_buffer;   /* One page of host buffer */
+static void    *host_end;          /* end + 1 */
+#endif
+
+/* struct  cpm360_t *cpmp; */         /* Pointer to comm processor space */
+
+QUICC  *pquicc;
+/* QUICC  *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */
+
+
+/* CPM interrupt vector functions. */
+struct cpm_action {
+       void    (*handler)(void *);
+       void    *dev_id;
+};
+static struct  cpm_action cpm_vecs[CPMVEC_NR];
+static void    cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
+static void    cpm_error_interrupt(void *);
+
+/* prototypes: */
+void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
+void m360_cpm_reset(void);
+
+
+
+
+void m360_cpm_reset()
+{
+/*     pte_t              *pte; */
+
+       pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */
+
+       /* Perform a CPM reset. */
+       pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG);
+
+       /* Wait for CPM to become ready (should be 2 clocks). */
+       while (pquicc->cp_cr & CMD_FLAG);
+
+       /* On the recommendation of the 68360 manual, p. 7-60
+        * - Set sdma interrupt service mask to 7
+        * - Set sdma arbitration ID to 4
+        */
+       pquicc->sdma_sdcr = 0x0740;
+
+
+       /* Claim the DP memory for our use.
+        */
+       dp_alloc_base = CPM_DATAONLY_BASE;
+       dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
+
+       /* Set the host page for allocation.
+        */
+       /*      host_buffer = host_page_addr; */
+       /*      host_end = host_page_addr + PAGE_SIZE; */
+
+       /*      pte = find_pte(&init_mm, host_page_addr); */
+       /*      pte_val(*pte) |= _PAGE_NO_CACHE; */
+       /*      flush_tlb_page(current->mm->mmap, host_buffer); */
+
+       /* Tell everyone where the comm processor resides.
+       */
+/*     cpmp = (cpm360_t *)commproc; */
+}
+
+
+/* This is called during init_IRQ.  We used to do it above, but this
+ * was too early since init_IRQ was not yet called.
+ */
+void
+cpm_interrupt_init(void)
+{
+       /* Initialize the CPM interrupt controller.
+        * NOTE THAT pquicc had better have been initialized!
+        * reference: MC68360UM p. 7-377
+        */
+       pquicc->intr_cicr =
+               (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+               (CPM_INTERRUPT << 13) |
+               CICR_HP_MASK |
+               (CPM_VECTOR_BASE << 5) |
+               CICR_SPS;
+
+       /* mask all CPM interrupts from reaching the cpu32 core: */
+       pquicc->intr_cimr = 0;
+
+
+       /* mles - If I understand correctly, the 360 just pops over to the CPM
+        * specific vector, obviating the necessity to vector through the IRQ
+        * whose priority the CPM is set to. This needs a closer look, though.
+        */
+
+       /* Set our interrupt handler with the core CPU. */
+/*     if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */
+/*             panic("Could not allocate CPM IRQ!"); */
+
+       /* Install our own error handler.
+        */
+       /* I think we want to hold off on this one for the moment - mles */
+       /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */
+
+       /* master CPM interrupt enable */
+       /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */
+}
+
+
+
+/* CPM interrupt controller interrupt.
+*/
+static void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+       /* uint vec; */
+
+       /* mles: Note that this stuff is currently being performed by
+        * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c  */
+
+       /* figure out the vector */
+       /* call that vector's handler */
+       /* clear the irq's bit in the service register */
+
+#if 0 /* old 860 stuff: */
+       /* Get the vector by setting the ACK bit and then reading
+        * the register.
+        */
+       ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
+       vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
+       vec >>= 11;
+
+
+       if (cpm_vecs[vec].handler != 0)
+               (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
+       else
+               ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+
+       /* After servicing the interrupt, we have to remove the status
+        * indicator.
+        */
+       ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
+#endif
+
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts.  All we have to do is ACK it
+ * and return.  This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static void
+cpm_error_interrupt(void *dev)
+{
+}
+
+/* Install a CPM interrupt handler.
+*/
+void
+cpm_install_handler(int vec, void (*handler)(), void *dev_id)
+{
+
+       request_irq(vec, handler, 0, "timer", dev_id);
+
+/*     if (cpm_vecs[vec].handler != 0) */
+/*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
+/*                     (uint)handler, (uint)cpm_vecs[vec].handler); */
+/*     cpm_vecs[vec].handler = handler; */
+/*     cpm_vecs[vec].dev_id = dev_id; */
+
+       /*              ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */
+/*     pquicc->intr_cimr |= (1 << vec); */
+
+}
+
+/* Free a CPM interrupt handler.
+*/
+void
+cpm_free_handler(int vec)
+{
+       cpm_vecs[vec].handler = NULL;
+       cpm_vecs[vec].dev_id = NULL;
+       /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */
+       pquicc->intr_cimr &= ~(1 << vec);
+}
+
+
+
+
+/* Allocate some memory from the dual ported ram.  We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint
+m360_cpm_dpalloc(uint size)
+{
+        uint    retloc;
+
+        if ((dp_alloc_base + size) >= dp_alloc_top)
+                return(CPM_DP_NOSPACE);
+
+        retloc = dp_alloc_base;
+        dp_alloc_base += size;
+
+        return(retloc);
+}
+
+
+#if 0 /* mleslie - for now these are simply kmalloc'd */
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+m360_cpm_hostalloc(uint size)
+{
+       uint    retloc;
+
+       if ((host_buffer + size) >= host_end)
+               return(0);
+
+       retloc = host_buffer;
+       host_buffer += size;
+
+       return(retloc);
+}
+#endif
+
+
+/* Set a baud rate generator.  This needs lots of work.  There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * This assumes the baudrate is 16x oversampled by the uart.
+ */
+/* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */
+#define BRG_INT_CLK            system_clock
+#define BRG_UART_CLK   (BRG_INT_CLK/16)
+
+void
+m360_cpm_setbrg(uint brg, uint rate)
+{
+       volatile uint   *bp;
+
+       /* This is good enough to get SMCs running.....
+        */
+       /* bp = (uint *)&cpmp->cp_brgc1; */
+       bp = (volatile uint *)(&pquicc->brgc[0].l);
+       bp += brg;
+       *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN;
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/arch/m68k/platform/68360/config.c b/arch/m68k/platform/68360/config.c
new file mode 100644 (file)
index 0000000..9dd5bca
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ *  linux/arch/m68knommu/platform/68360/config.c
+ *
+ *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne <jeff@uclinux.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/m68360.h>
+
+#ifdef CONFIG_UCQUICC
+#include <asm/bootstd.h>
+#endif
+
+extern void m360_cpm_reset(void);
+
+// Mask to select if the PLL prescaler is enabled.
+#define MCU_PREEN   ((unsigned short)(0x0001 << 13))
+
+#if defined(CONFIG_UCQUICC)
+#define OSCILLATOR  (unsigned long int)33000000
+#endif
+
+unsigned long int system_clock;
+
+extern QUICC *pquicc;
+
+/* TODO  DON"T Hard Code this */
+/* calculate properly using the right PLL and prescaller */
+// unsigned int system_clock = 33000000l;
+extern unsigned long int system_clock; //In kernel setup.c
+
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+  /* Reset Timer1 */
+  /* TSTAT &= 0; */
+
+  pquicc->timer_ter1 = 0x0002; /* clear timer event */
+
+  return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction m68360_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = hw_tick,
+};
+
+void hw_timer_init(void)
+{
+  unsigned char prescaler;
+  unsigned short tgcr_save;
+
+#if 0
+  /* Restart mode, Enable int, 32KHz, Enable timer */
+  TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN;
+  /* Set prescaler (Divide 32KHz by 32)*/
+  TPRER = 31;
+  /* Set compare register  32Khz / 32 / 10 = 100 */
+  TCMP = 10;                                                              
+
+  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
+#endif
+
+  /* General purpose quicc timers: MC68360UM p7-20 */
+
+  /* Set up timer 1 (in [1..4]) to do 100Hz */
+  tgcr_save = pquicc->timer_tgcr & 0xfff0;
+  pquicc->timer_tgcr  = tgcr_save; /* stop and reset timer 1 */
+  /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */
+
+  prescaler = 8;
+  pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */
+                           (unsigned short)((prescaler - 1) << 8);
+    
+  pquicc->timer_tcn1 = 0x0000; /* initial count */
+  /* calculate interval for 100Hz based on the _system_clock: */
+  pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */
+
+  pquicc->timer_ter1 = 0x0003; /* clear timer events */
+
+  /* enable timer 1 interrupt in CIMR */
+  setup_irq(CPMVEC_TIMER1, &m68360_timer_irq);
+
+  /* Start timer 1: */
+  tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001;
+  pquicc->timer_tgcr  = tgcr_save;
+}
+
+void BSP_gettod (int *yearp, int *monp, int *dayp,
+                  int *hourp, int *minp, int *secp)
+{
+}
+
+int BSP_set_clock_mmss(unsigned long nowtime)
+{
+#if 0
+  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+  tod->second1 = real_seconds / 10;
+  tod->second2 = real_seconds % 10;
+  tod->minute1 = real_minutes / 10;
+  tod->minute2 = real_minutes % 10;
+#endif
+  return 0;
+}
+
+void BSP_reset (void)
+{
+  local_irq_disable();
+  asm volatile (
+    "moveal #_start, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
+}
+
+unsigned char *scc1_hwaddr;
+static int errno;
+
+#if defined (CONFIG_UCQUICC)
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+#endif
+
+
+void config_BSP(char *command, int len)
+{
+  unsigned char *p;
+
+  m360_cpm_reset();
+
+  /* Calculate the real system clock value. */
+  {
+     unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr);
+     if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128
+     {
+         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
+         system_clock = (OSCILLATOR / 128) * (mf + 1);
+     }
+     else
+     {
+         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
+         system_clock = (OSCILLATOR) * (mf + 1);
+     }
+  }
+
+  printk(KERN_INFO "\n68360 QUICC support (C) 2000 Lineo Inc.\n");
+
+#if defined(CONFIG_UCQUICC) && 0
+  printk(KERN_INFO "uCquicc serial string [%s]\n",getserialnum());
+  p = scc1_hwaddr = gethwaddr(0);
+  printk(KERN_INFO "uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+         p[0], p[1], p[2], p[3], p[4], p[5]);
+
+  p = getbenv("APPEND");
+  if (p)
+    strcpy(p,command);
+  else
+    command[0] = 0;
+#else
+  scc1_hwaddr = "\00\01\02\03\04\05";
+#endif
+  mach_gettod          = BSP_gettod;
+  mach_reset           = BSP_reset;
+}
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
new file mode 100644 (file)
index 0000000..46c1b18
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *  linux/arch/m68knommu/platform/68360/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 2001 SED Systems, a Division of Calian Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ * M68360 Port by SED Systems, and Lineo.
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/traps.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl ret_from_interrupt
+.globl bad_interrupt
+.globl inthandler
+
+badsys:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
+       jra     ret_from_exception
+
+do_trace:
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
+       movel   #-ENOSYS,%d0
+       cmpl    #NR_syscalls,%d1
+       jcc     1f
+       lsl     #2,%d1
+       lea     sys_call_table, %a0
+       jbsr    %a0@(%d1)
+
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     ret_from_exception
+
+ENTRY(system_call)
+       SAVE_ALL
+
+       /* save top of frame*/
+       pea     %sp@
+       jbsr    set_esp0
+       addql   #4,%sp
+
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       jne     do_trace
+       cmpl    #NR_syscalls,%d0
+       jcc     badsys
+       lsl     #2,%d0
+       lea     sys_call_table,%a0
+       movel   %a0@(%d0), %a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
+
+ret_from_exception:
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
+       jeq     Luser_return            /* if so, skip resched, signals*/
+
+Lkernel_return:
+       RESTORE_ALL
+
+Luser_return:
+       /* only allow interrupts when we are really the last one on the*/
+       /* kernel stack, otherwise stack overflow can occur during*/
+       /* heavy interrupt load*/
+       andw    #ALLOWINT,%sr
+
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1
+       movel   %d1,%a2
+1:
+       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       jne     Lwork_to_do
+       RESTORE_ALL
+
+Lwork_to_do:
+       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address*/
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       bsrw    do_signal
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jra     1b
+
+/*
+ * This is the main interrupt handler, responsible for calling do_IRQ()
+ */
+inthandler:
+       SAVE_ALL
+       movew   %sp@(PT_OFF_FORMATVEC), %d0
+       and.l   #0x3ff, %d0
+       lsr.l   #0x02,  %d0
+
+       movel   %sp,%sp@-
+       movel   %d0,%sp@-               /*  put vector # on stack*/
+       jbsr    do_IRQ                  /*  process the IRQ*/
+3:             addql   #8,%sp                  /*  pop parameters off stack*/
+       bra     ret_from_interrupt
+
+ret_from_interrupt:
+       jeq     1f
+2:
+       RESTORE_ALL
+1:
+       moveb   %sp@(PT_OFF_SR), %d0
+       and     #7, %d0
+       jhi     2b
+       /* check if we need to do software interrupts */
+
+       movel   irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0
+       jeq     ret_from_exception
+
+       pea     ret_from_exception
+       jra     do_softirq
+
+
+/*
+ * Handler for uninitialized and spurious interrupts.
+ */
+bad_interrupt:
+       addql   #1,num_spurious
+       rte
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1,so don't change these
+ * registers until their contents are no longer needed.
+ */
+ENTRY(resume)
+       movel   %a0,%d1                         /* save prev thread in d1 */
+       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
+       movel   %usp,%a2                        /* save usp */
+       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
+
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+       RESTORE_SWITCH_STACK
+
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore user stack */
+       movel   %a0,%usp
+       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
+       rts
+
diff --git a/arch/m68k/platform/68360/head-ram.S b/arch/m68k/platform/68360/head-ram.S
new file mode 100644 (file)
index 0000000..8eb94fb
--- /dev/null
@@ -0,0 +1,403 @@
+/* arch/m68knommu/platform/68360/head-ram.S
+ *
+ * Startup code for Motorola 68360
+ *
+ * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+#define ASSEMBLY
+
+.global _stext
+.global _start
+
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+#define        ROMEND                      (CONFIG_ROMBASE + CONFIG_ROMSIZE)
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000002
+#define SIM_BR0_MASK                0x00000001
+
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *       configure system clock MC68360 p. 6-40
+        *       (value +1)*osc/128 = system clock
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #RAMEND, %d0
+       subi.l  #__ramstart, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__ramstart, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+configure_chip_select_1:
+       move.l  #ROMEND, %d0
+       subi.l  #__rom_start, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR1_MASK, %d0
+       move.l  %d0, OR1
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR1_MASK, %d0
+       move.l  %d0, BR1
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_stext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #_ebss, _ramstart
+       move.l  #RAMEND, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data..initvect","awx"
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
diff --git a/arch/m68k/platform/68360/head-rom.S b/arch/m68k/platform/68360/head-rom.S
new file mode 100644 (file)
index 0000000..97510e5
--- /dev/null
@@ -0,0 +1,414 @@
+/* arch/m68knommu/platform/68360/head-rom.S
+ *
+ * Startup code for Motorola 68360
+ *
+ * Copyright (C) SED Systems, a Division of Calian Ltd.
+ * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
+ * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
+ *           uClinux Kernel
+ * Copyright (C) Michael Leslie <mleslie@lineo.com>
+ * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
+ *
+ */
+
+.global _stext
+.global _sbss
+.global _start
+
+.global _rambase
+.global _ramvec
+.global _ramstart
+.global _ramend
+
+.global _quicc_base
+.global _periph_base
+
+#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
+
+#define REGB                        0x1000
+#define PEPAR                       (_dprbase + REGB + 0x0016)
+#define GMR                         (_dprbase + REGB + 0x0040)
+#define OR0                         (_dprbase + REGB + 0x0054)
+#define BR0                         (_dprbase + REGB + 0x0050)
+
+#define OR1                         (_dprbase + REGB + 0x0064)
+#define BR1                         (_dprbase + REGB + 0x0060)
+
+#define OR2                         (_dprbase + REGB + 0x0074)
+#define BR2                         (_dprbase + REGB + 0x0070)
+
+#define OR3                         (_dprbase + REGB + 0x0084)
+#define BR3                         (_dprbase + REGB + 0x0080)
+
+#define OR4                         (_dprbase + REGB + 0x0094)
+#define BR4                         (_dprbase + REGB + 0x0090)
+
+#define OR5                         (_dprbase + REGB + 0x00A4)
+#define BR5                         (_dprbase + REGB + 0x00A0)
+
+#define OR6                         (_dprbase + REGB + 0x00b4)
+#define BR6                         (_dprbase + REGB + 0x00b0)
+
+#define OR7                         (_dprbase + REGB + 0x00c4)
+#define BR7                         (_dprbase + REGB + 0x00c0)
+
+#define MCR                         (_dprbase + REGB + 0x0000)
+#define AVR                         (_dprbase + REGB + 0x0008)
+
+#define SYPCR                       (_dprbase + REGB + 0x0022)
+
+#define PLLCR                       (_dprbase + REGB + 0x0010)
+#define CLKOCR                      (_dprbase + REGB + 0x000C)
+#define CDVCR                       (_dprbase + REGB + 0x0014)
+
+#define BKAR                        (_dprbase + REGB + 0x0030)
+#define BKCR                        (_dprbase + REGB + 0x0034)
+#define SWIV                        (_dprbase + REGB + 0x0023)
+#define PICR                        (_dprbase + REGB + 0x0026)
+#define PITR                        (_dprbase + REGB + 0x002A)
+
+/* Define for all memory configuration */
+#define MCU_SIM_GMR                 0x00000000
+#define SIM_OR_MASK                 0x0fffffff
+
+/* Defines for chip select zero - the flash */
+#define SIM_OR0_MASK                0x20000000
+#define SIM_BR0_MASK                0x00000001
+
+/* Defines for chip select one - the RAM */
+#define SIM_OR1_MASK                0x10000000
+#define SIM_BR1_MASK                0x00000001
+
+#define MCU_SIM_MBAR_ADRS           0x0003ff00
+#define MCU_SIM_MBAR_BA_MASK        0xfffff000
+#define MCU_SIM_MBAR_AS_MASK        0x00000001
+
+#define MCU_SIM_PEPAR               0x00B4
+    
+#define MCU_DISABLE_INTRPTS         0x2700
+#define MCU_SIM_AVR                 0x00
+    
+#define MCU_SIM_MCR                 0x00005cff
+
+#define MCU_SIM_CLKOCR              0x00
+#define MCU_SIM_PLLCR               0x8000
+#define MCU_SIM_CDVCR               0x0000
+
+#define MCU_SIM_SYPCR               0x0000
+#define MCU_SIM_SWIV                0x00
+#define MCU_SIM_PICR                0x0000
+#define MCU_SIM_PITR                0x0000
+
+
+#include <asm/m68360_regs.h>
+
+       
+/*
+ * By the time this RAM specific code begins to execute, DPRAM
+ * and DRAM should already be mapped and accessible.
+ */
+
+       .text
+_start:
+_stext:
+       nop
+       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
+       /* We should not need to setup the boot stack the reset should do it. */
+       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
+
+
+set_mbar_register:
+       moveq.l #0x07, %d1                      /* Setup MBAR */
+       movec   %d1, %dfc
+
+       lea.l   MCU_SIM_MBAR_ADRS, %a0
+       move.l  #_dprbase, %d0
+       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
+       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
+       moves.l %d0, %a0@
+
+       moveq.l #0x05, %d1
+       movec.l %d1, %dfc
+
+       /* Now we can begin to access registers in DPRAM */
+
+set_sim_mcr:
+       /* Set Module Configuration Register */
+       move.l  #MCU_SIM_MCR, MCR
+
+       /* to do:       Determine cause of reset */
+
+       /*
+        *      configure system clock MC68360 p. 6-40
+        *      (value +1)*osc/128 = system clock
+        *                    or
+        *      (value + 1)*osc = system clock
+        *      You do not need to divide the oscillator by 128 unless you want to.
+        */
+set_sim_clock:
+       move.w  #MCU_SIM_PLLCR, PLLCR
+       move.b  #MCU_SIM_CLKOCR, CLKOCR
+       move.w  #MCU_SIM_CDVCR, CDVCR
+
+       /* Wait for the PLL to settle */
+       move.w  #16384, %d0
+pll_settle_wait:
+       subi.w  #1, %d0
+       bne     pll_settle_wait
+
+       /* Setup the system protection register, and watchdog timer register */
+       move.b  #MCU_SIM_SWIV, SWIV
+       move.w  #MCU_SIM_PICR, PICR
+       move.w  #MCU_SIM_PITR, PITR
+       move.w  #MCU_SIM_SYPCR, SYPCR
+
+       /* Clear DPRAM - system + parameter */
+       movea.l #_dprbase, %a0
+       movea.l #_dprbase+0x2000, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+clear_dpram:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     clear_dpram
+
+configure_memory_controller:    
+       /* Set up Global Memory Register (GMR) */
+       move.l  #MCU_SIM_GMR, %d0
+       move.l  %d0, GMR
+
+configure_chip_select_0:
+       move.l  #0x00400000, %d0
+       subq.l  #0x01, %d0
+       eori.l  #SIM_OR_MASK, %d0
+       ori.l   #SIM_OR0_MASK, %d0
+       move.l  %d0, OR0
+
+       move.l  #__rom_start, %d0
+       ori.l   #SIM_BR0_MASK, %d0
+       move.l  %d0, BR0
+
+       move.l  #0x0, BR1
+       move.l  #0x0, BR2
+       move.l  #0x0, BR3
+       move.l  #0x0, BR4
+       move.l  #0x0, BR5
+       move.l  #0x0, BR6
+       move.l  #0x0, BR7
+
+       move.w  #MCU_SIM_PEPAR, PEPAR 
+
+       /* point to vector table: */
+       move.l  #_romvec, %a0
+       move.l  #_ramvec, %a1
+copy_vectors:
+       move.l  %a0@, %d0
+       move.l  %d0, %a1@
+       move.l  %a0@, %a1@
+       addq.l  #0x04, %a0
+       addq.l  #0x04, %a1
+       cmp.l   #_start, %a0
+       blt     copy_vectors
+
+       move.l  #_ramvec, %a1
+       movec   %a1, %vbr
+
+
+       /* Copy data segment from ROM to RAM */
+       moveal  #_etext, %a0
+       moveal  #_sdata, %a1
+       moveal  #_edata, %a2
+
+       /* Copy %a0 to %a1 until %a1 == %a2 */
+LD1:
+       move.l  %a0@, %d0
+       addq.l  #0x04, %a0
+       move.l  %d0, %a1@
+       addq.l  #0x04, %a1
+       cmp.l   #_edata, %a1
+       blt     LD1
+
+       moveal  #_sbss, %a0
+       moveal  #_ebss, %a1
+
+       /* Copy 0 to %a0 until %a0 == %a1 */
+L1:
+       movel   #0, %a0@+
+       cmpal   %a0, %a1
+       bhi     L1
+
+load_quicc:
+       move.l  #_dprbase, _quicc_base
+
+store_ram_size:
+       /* Set ram size information */
+       move.l  #_sdata, _rambase
+       move.l  #_ebss, _ramstart
+       move.l  #RAMEND, %d0
+       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
+       move.l  %d0, _ramend                    /* Different from RAMEND.*/
+
+       pea     0
+       pea     env
+       pea     %sp@(4)
+       pea     0
+
+       lea     init_thread_union, %a2
+       lea     0x2000(%a2), %sp
+
+lp:
+       jsr     start_kernel
+
+_exit:
+       jmp     _exit
+
+
+       .data
+       .align 4
+env:
+       .long   0
+_quicc_base:
+       .long   0
+_periph_base:
+       .long   0
+_ramvec:
+       .long   0
+_rambase:
+       .long   0
+_ramstart:
+       .long   0
+_ramend:
+       .long   0
+_dprbase:
+       .long   0xffffe000
+
+
+       .text
+
+    /*
+     * These are the exception vectors at boot up, they are copied into RAM
+     * and then overwritten as needed.
+     */
+.section ".data..initvect","awx"
+    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
+    .long   _start      /* Reset: Initial Program Counter               - 1.  */
+    .long   buserr      /* Bus Error                                    - 2.  */
+    .long   trap        /* Address Error                                - 3.  */
+    .long   trap        /* Illegal Instruction                          - 4.  */
+    .long   trap        /* Divide by zero                               - 5.  */
+    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
+    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
+    .long   trap        /* Privilege Violation                          - 8.  */
+    .long   trap        /* Trace                                        - 9.  */
+    .long   trap        /* Line 1010 Emulator                           - 10. */
+    .long   trap        /* Line 1111 Emualtor                           - 11. */
+    .long   trap        /* Harware Breakpoint                           - 12. */
+    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
+    .long   trap        /* Format Error                                 - 14. */
+    .long   trap        /* Uninitialized Interrupt                      - 15. */
+    .long   trap        /* (Unassigned, Reserver)                       - 16. */
+    .long   trap        /* (Unassigned, Reserver)                       - 17. */
+    .long   trap        /* (Unassigned, Reserver)                       - 18. */
+    .long   trap        /* (Unassigned, Reserver)                       - 19. */
+    .long   trap        /* (Unassigned, Reserver)                       - 20. */
+    .long   trap        /* (Unassigned, Reserver)                       - 21. */
+    .long   trap        /* (Unassigned, Reserver)                       - 22. */
+    .long   trap        /* (Unassigned, Reserver)                       - 23. */
+    .long   trap        /* Spurious Interrupt                           - 24. */
+    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
+    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
+    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
+    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
+    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
+    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
+    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
+    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
+    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
+    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
+    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
+    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
+    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
+    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
+    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
+    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
+    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
+    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
+    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
+    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
+    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
+    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
+    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
+    .long   0           /* (Reserved for Coprocessor)                   - 48. */
+    .long   0           /* (Reserved for Coprocessor)                   - 49. */
+    .long   0           /* (Reserved for Coprocessor)                   - 50. */
+    .long   0           /* (Reserved for Coprocessor)                   - 51. */
+    .long   0           /* (Reserved for Coprocessor)                   - 52. */
+    .long   0           /* (Reserved for Coprocessor)                   - 53. */
+    .long   0           /* (Reserved for Coprocessor)                   - 54. */
+    .long   0           /* (Reserved for Coprocessor)                   - 55. */
+    .long   0           /* (Reserved for Coprocessor)                   - 56. */
+    .long   0           /* (Reserved for Coprocessor)                   - 57. */
+    .long   0           /* (Reserved for Coprocessor)                   - 58. */
+    .long   0           /* (Unassigned, Reserved)                       - 59. */
+    .long   0           /* (Unassigned, Reserved)                       - 60. */
+    .long   0           /* (Unassigned, Reserved)                       - 61. */
+    .long   0           /* (Unassigned, Reserved)                       - 62. */
+    .long   0           /* (Unassigned, Reserved)                       - 63. */
+    /*                  The assignment of these vectors to the CPM is         */
+    /*                  dependent on the configuration of the CPM vba         */
+    /*                          fields.                                       */
+    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
+    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
+    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
+    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
+    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
+    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
+    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
+    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
+    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
+    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
+    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
+    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
+    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
+    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
+    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
+    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
+    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
+    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
+    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
+    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
+    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
+    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
+    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
+    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
+    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
+    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
+    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
+    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
+    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
+    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
+    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
+    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
+    /*                  I don't think anything uses the vectors after here.   */
+    .long   0           /* (User-Defined Vectors 34)                    - 96. */
+    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
+    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
+    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
+.text
+ignore: rte
diff --git a/arch/m68k/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c
new file mode 100644 (file)
index 0000000..8de3feb
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
+ *
+ * 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) 2000  Michael Leslie <mleslie@lineo.com>
+ * Copyright (c) 1996 Roman Zippel
+ * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/m68360.h>
+
+/* from quicc/commproc.c: */
+extern QUICC *pquicc;
+extern void cpm_interrupt_init(void);
+
+#define INTERNAL_IRQS (96)
+
+/* assembler routines */
+asmlinkage void system_call(void);
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void bad_interrupt(void);
+asmlinkage void inthandler(void);
+
+extern void *_ramvec[];
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       pquicc->intr_cimr |= (1 << d->irq);
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       pquicc->intr_cimr &= ~(1 << d->irq);
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       pquicc->intr_cisr = (1 << d->irq);
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "M68K-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+};
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the vector table.
+ */
+void init_IRQ(void)
+{
+       int i;
+       int vba = (CPM_VECTOR_BASE<<4);
+
+       /* set up the vectors */
+       _ramvec[2] = buserr;
+       _ramvec[3] = trap;
+       _ramvec[4] = trap;
+       _ramvec[5] = trap;
+       _ramvec[6] = trap;
+       _ramvec[7] = trap;
+       _ramvec[8] = trap;
+       _ramvec[9] = trap;
+       _ramvec[10] = trap;
+       _ramvec[11] = trap;
+       _ramvec[12] = trap;
+       _ramvec[13] = trap;
+       _ramvec[14] = trap;
+       _ramvec[15] = trap;
+
+       _ramvec[32] = system_call;
+       _ramvec[33] = trap;
+
+       cpm_interrupt_init();
+
+       /* set up CICR for vector base address and irq level */
+       /* irl = 4, hp = 1f - see MC68360UM p 7-377 */
+       pquicc->intr_cicr = 0x00e49f00 | vba;
+
+       /* CPM interrupt vectors: (p 7-376) */
+       _ramvec[vba+CPMVEC_ERROR]       = bad_interrupt; /* Error */
+       _ramvec[vba+CPMVEC_PIO_PC11]    = inthandler;   /* pio - pc11 */
+       _ramvec[vba+CPMVEC_PIO_PC10]    = inthandler;   /* pio - pc10 */
+       _ramvec[vba+CPMVEC_SMC2]        = inthandler;   /* smc2/pip */
+       _ramvec[vba+CPMVEC_SMC1]        = inthandler;   /* smc1 */
+       _ramvec[vba+CPMVEC_SPI]         = inthandler;   /* spi */
+       _ramvec[vba+CPMVEC_PIO_PC9]     = inthandler;   /* pio - pc9 */
+       _ramvec[vba+CPMVEC_TIMER4]      = inthandler;   /* timer 4 */
+       _ramvec[vba+CPMVEC_RESERVED1]   = inthandler;   /* reserved */
+       _ramvec[vba+CPMVEC_PIO_PC8]     = inthandler;   /* pio - pc8 */
+       _ramvec[vba+CPMVEC_PIO_PC7]     = inthandler;  /* pio - pc7 */
+       _ramvec[vba+CPMVEC_PIO_PC6]     = inthandler;  /* pio - pc6 */
+       _ramvec[vba+CPMVEC_TIMER3]      = inthandler;  /* timer 3 */
+       _ramvec[vba+CPMVEC_PIO_PC5]     = inthandler;  /* pio - pc5 */
+       _ramvec[vba+CPMVEC_PIO_PC4]     = inthandler;  /* pio - pc4 */
+       _ramvec[vba+CPMVEC_RESERVED2]   = inthandler;  /* reserved */
+       _ramvec[vba+CPMVEC_RISCTIMER]   = inthandler;  /* timer table */
+       _ramvec[vba+CPMVEC_TIMER2]      = inthandler;  /* timer 2 */
+       _ramvec[vba+CPMVEC_RESERVED3]   = inthandler;  /* reserved */
+       _ramvec[vba+CPMVEC_IDMA2]       = inthandler;  /* idma 2 */
+       _ramvec[vba+CPMVEC_IDMA1]       = inthandler;  /* idma 1 */
+       _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler;  /* sdma channel bus error */
+       _ramvec[vba+CPMVEC_PIO_PC3]     = inthandler;  /* pio - pc3 */
+       _ramvec[vba+CPMVEC_PIO_PC2]     = inthandler;  /* pio - pc2 */
+       /* _ramvec[vba+CPMVEC_TIMER1]      = cpm_isr_timer1; */  /* timer 1 */
+       _ramvec[vba+CPMVEC_TIMER1]      = inthandler;  /* timer 1 */
+       _ramvec[vba+CPMVEC_PIO_PC1]     = inthandler;  /* pio - pc1 */
+       _ramvec[vba+CPMVEC_SCC4]        = inthandler;  /* scc 4 */
+       _ramvec[vba+CPMVEC_SCC3]        = inthandler;  /* scc 3 */
+       _ramvec[vba+CPMVEC_SCC2]        = inthandler;  /* scc 2 */
+       _ramvec[vba+CPMVEC_SCC1]        = inthandler;  /* scc 1 */
+       _ramvec[vba+CPMVEC_PIO_PC0]     = inthandler;  /* pio - pc0 */
+
+
+       /* turn off all CPM interrupts */
+       pquicc->intr_cimr = 0x00000000;
+
+       for (i = 0; (i < NR_IRQS); i++) {
+               set_irq_chip(i, &intc_irq_chip);
+               set_irq_handler(i, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/platform/68EZ328/Makefile b/arch/m68k/platform/68EZ328/Makefile
new file mode 100644 (file)
index 0000000..ee97735
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for arch/m68knommu/platform/68EZ328.
+#
+
+obj-y := config.o
+
+extra-y := bootlogo.rh
+
+$(obj)/bootlogo.rh: $(src)/bootlogo.h
+       perl $(src)/../68328/bootlogo.pl < $(src)/bootlogo.h \
+               > $(obj)/bootlogo.rh
diff --git a/arch/m68k/platform/68EZ328/bootlogo.h b/arch/m68k/platform/68EZ328/bootlogo.h
new file mode 100644 (file)
index 0000000..e842bda
--- /dev/null
@@ -0,0 +1,3204 @@
+#define splash_width 640
+#define splash_height 480
+static unsigned char splash_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xfe, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x7c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+  0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0x07, 0xfe, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
+  0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0xe0, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03,
+  0x3f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
+  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0xff, 0x3f, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff,
+  0xc1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x07, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
+  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x00, 0xe0, 0x07, 0x0e, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
+  0x3f, 0x1c, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
+  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x01, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
+  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x87, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0x00,
+  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0xf0, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xf0, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0x0c, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1c, 0x00,
+  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x07, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe2, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
+  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01,
+  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xf0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x9f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xf8, 0xff, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0xff, 0xff, 0x00,
+  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0xf8, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xfe, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0xf8, 0xff, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0x01,
+  0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xf8,
+  0x41, 0xc6, 0x84, 0x0c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xf8, 0x41, 0xc6, 0x84, 0x0c,
+  0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x0f, 0x00, 0x00, 0x18, 0x0c, 0x08, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xe4,
+  0xb1, 0xc1, 0x98, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0xe4, 0xb1, 0xc1, 0x98, 0x00,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x08, 0x00, 0x00, 0x1c, 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c,
+  0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00,
+  0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x09, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x9c,
+  0x01, 0x08, 0x83, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40,
+  0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, 0x30, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x9b,
+  0x01, 0xc0, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x9b, 0x01, 0xc0, 0x00, 0x00,
+  0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0x00, 0x00, 0x00, 0x07, 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xc1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07,
+  0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x10, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x7b, 0x00, 0x30, 0x03, 0x0c,
+  0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x07, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x09, 0x00, 0xc0, 0x84, 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xfd, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xc0, 0x84,
+  0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x03, 0xf0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40,
+  0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xfc, 0x01, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, 0x08, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+  0xf8, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x64,
+  0x42, 0x06, 0x1b, 0x03, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x64, 0x42, 0x06, 0x1b, 0x03,
+  0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x0f, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x3f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1b,
+  0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xc3, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xe0, 0x84, 0x31, 0x30, 0x04, 0x80,
+  0xc1, 0x18, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x09, 0x00, 0xc0, 0x63, 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x08, 0x00, 0xc0, 0x63,
+  0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c,
+  0x06, 0x81, 0x80, 0xfd, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, 0x06, 0x81, 0x80, 0xfd,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x20, 0x63,
+  0x0c, 0x08, 0x80, 0x00, 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x63, 0x0c, 0x08, 0x80, 0x00,
+  0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x0f, 0x00, 0xd8, 0x84, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x80, 0xf1,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x1b,
+  0x40, 0x08, 0x84, 0x0c, 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x1b, 0x40, 0x08, 0x84, 0x0c,
+  0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0xe4, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x09, 0x00, 0x38, 0x80, 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x38, 0x80,
+  0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x10, 0x84,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00,
+  0x00, 0x00, 0x03, 0xf2, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x08, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, 0x00, 0x00, 0x03, 0xf2,
+  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
+  0x08, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x3e, 0x00,
+  0x82, 0x01, 0x03, 0x40, 0x30, 0x98, 0x10, 0xf0, 0xe7, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x10, 0xe4,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0xfc,
+  0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x08, 0x00, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64,
+  0x30, 0xc6, 0x80, 0x80, 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf8, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0e, 0x00, 0xc0, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, 0x30, 0xc6, 0x80, 0x80,
+  0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc3, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x00, 0x39, 0x03, 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x39, 0x03,
+  0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0xe7, 0x04, 0x42, 0xc6, 0x00, 0x00,
+  0x00, 0x00, 0xec, 0xcf, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0xc0, 0x1f, 0x80, 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01,
+  0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x01, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x1f, 0x80,
+  0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, 0x00, 0xe0, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x08, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00,
+  0xc0, 0x60, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x1f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
+  0x00, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, 0xc0, 0x60, 0x7c, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xc0, 0x19, 0x60,
+  0x40, 0x00, 0x63, 0x30, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xf3, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x09, 0xc0, 0x19, 0x60, 0x40, 0x00, 0x63, 0x30,
+  0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf3, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xc0, 0x27, 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xc0, 0x27, 0x03,
+  0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x0f, 0xc0, 0xde, 0x04, 0x0c, 0x06, 0x03, 0x80,
+  0xc1, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0xc0, 0x19, 0x00, 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f,
+  0x07, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x19, 0x00,
+  0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x07, 0x00, 0x18, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03,
+  0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1c, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x1f, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
+  0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, 0xf0, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x7f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+  0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31,
+  0x04, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0xd9, 0x04,
+  0x00, 0x08, 0x00, 0x80, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x60, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0xd9, 0x04, 0x00, 0x08, 0x00, 0x80,
+  0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xc0, 0x27, 0x00, 0x30, 0xc0, 0x60, 0xb0, 0xff, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b,
+  0x8d, 0x01, 0x04, 0xc3, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0xf1, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x03, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, 0x8d, 0x01, 0x04, 0xc3,
+  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf1, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0x39, 0x04, 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x39, 0x04,
+  0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xff, 0x07,
+  0xb0, 0x09, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x30, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff,
+  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x08,
+  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07,
+  0xb0, 0xc9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, 0xb0, 0xc9, 0xf8, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x0f, 0x00, 0xe7, 0xfb, 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xe7, 0xfb,
+  0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xfe, 0x1c, 0xb2, 0x0f, 0xe0, 0xff,
+  0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xf8, 0xe7, 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0,
+  0xb1, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xf8, 0xe7,
+  0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, 0xb1, 0x3f, 0x00, 0x00,
+  0xf8, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff,
+  0x01, 0x00, 0xe0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x98, 0x4f, 0x0e, 0x18, 0x00, 0xf8, 0xff, 0xff, 0xff,
+  0x07, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x01, 0x00, 0xe0, 0x03,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+  0x4f, 0x0e, 0xf8, 0x1f, 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x1f,
+  0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
+  0x00, 0xce, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xe0, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xce, 0xff, 0x7f,
+  0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x1b, 0xb2, 0x31, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c,
+  0x00, 0xc0, 0xff, 0x73, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+  0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, 0x00, 0xc0, 0x7f, 0x1c,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x87, 0x31, 0x06, 0x7c, 0x1c, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x87,
+  0x31, 0x06, 0xfc, 0x0f, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x38,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0xe3, 0x0f,
+  0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xe0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff,
+  0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b,
+  0x4c, 0x00, 0x04, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x10,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x18, 0x80,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x78, 0xf3, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x08, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04,
+  0x02, 0x30, 0x60, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc0, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, 0x02, 0x30, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0x04, 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x04,
+  0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x67, 0x00, 0x06, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x04, 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04,
+  0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08,
+  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x02, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c,
+  0x0c, 0x06, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
+  0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xe0,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, 0x0c, 0x06, 0xfb, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x68, 0x7c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf8, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x18, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b,
+  0x81, 0x01, 0x60, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80,
+  0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, 0x81, 0x01, 0x00, 0x00,
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0x78, 0x0c, 0x30, 0x04, 0x00, 0xf6, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78,
+  0x0c, 0x30, 0x04, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8,
+  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0x1c, 0x00,
+  0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x58, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0,
+  0x01, 0x36, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
+  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x36, 0xfc, 0x1f,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc6, 0x87, 0x0f, 0x00, 0xff, 0x1f, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xcf, 0x03, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x40, 0xc0, 0xff, 0x7f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x03, 0x00, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0xc0, 0xff, 0x7f,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
+  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x7f,
+  0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0x07, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x4c, 0x00, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x1f,
+  0x00, 0xff, 0xff, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x0f, 0x00, 0xff, 0xff, 0x03,
+  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+  0x41, 0x00, 0xe0, 0x0f, 0x00, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x38,
+  0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x41, 0x00, 0x00, 0x80,
+  0xc9, 0xf9, 0xff, 0x3d, 0xff, 0x03, 0x00, 0x78, 0xc0, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0x32, 0x08, 0x00, 0x80, 0xc9, 0xf9, 0xff, 0x3d,
+  0xff, 0x03, 0x00, 0xf8, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x32, 0x08, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0xf8,
+  0x81, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0xf8, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0x38, 0x03, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0x3f, 0x00, 0x00, 0x38, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38,
+  0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, 0xfc, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x38, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+  0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x78,
+  0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff,
+  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0xc1, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x60, 0xf8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x67,
+  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xff,
+  0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf0, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x0f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x98,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x00, 0xc0, 0xff, 0x67, 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf8,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0xff, 0x67,
+  0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c,
+  0x37, 0x80, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
+  0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+  0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, 0x37, 0x80, 0x0c, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0xc0, 0xfe, 0x03,
+  0x8c, 0x09, 0xe3, 0x73, 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xfe, 0x03, 0x8c, 0x09, 0xe3, 0x73,
+  0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0xc0, 0x27, 0xe7, 0x31, 0x36, 0x04, 0x8c, 0x01, 0x60, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18,
+  0x42, 0xc0, 0x98, 0x30, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, 0x42, 0xc0, 0x98, 0x30,
+  0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0xc0, 0x27, 0x63, 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x27, 0x63,
+  0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0,
+  0x31, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff,
+  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, 0x31, 0x19, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0xc0, 0x1e, 0x63,
+  0x00, 0x30, 0x04, 0x03, 0xc8, 0x60, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0,
+  0x01, 0xe7, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0f, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, 0x01, 0xe7, 0xf3, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0xc0, 0x1e, 0x03,
+  0x02, 0x08, 0x04, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xd8, 0x0f, 0xc0, 0x1e, 0x03, 0x02, 0x08, 0x04, 0x00,
+  0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xc0, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x0b, 0x00, 0x21, 0x64, 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfb, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x21, 0x64,
+  0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfd, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00,
+  0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xf9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf,
+  0x01, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0e, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf0, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0b, 0xc0, 0xc0, 0x84,
+  0x31, 0xc0, 0x00, 0x4c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x83, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0f, 0x0e, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80,
+  0x09, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0xc3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0c, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, 0x09, 0xff, 0xff, 0x3f,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
+  0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xc0, 0xc1, 0x03,
+  0x4c, 0x00, 0x00, 0x30, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x90, 0x13, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0xc0, 0xc1, 0x03, 0x4c, 0x00, 0x00, 0x30,
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0xc0, 0x3f, 0x98, 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+  0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x98,
+  0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xc6, 0x03, 0x40, 0x00, 0x00, 0x80,
+  0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
+  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+  0x00, 0x00, 0x3f, 0x18, 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xef, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3f, 0x18,
+  0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xc7, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30,
+  0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
+  0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, 0x30, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04,
+  0x02, 0x00, 0x00, 0x83, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x38, 0x04, 0x02, 0x00, 0x00, 0x83,
+  0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+  0x03, 0x00, 0xe0, 0x1b, 0x0c, 0x08, 0x18, 0x40, 0x30, 0xfe, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84,
+  0x81, 0x01, 0x03, 0x0c, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, 0x81, 0x01, 0x03, 0x0c,
+  0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+  0x0e, 0x00, 0x00, 0x1b, 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x1b,
+  0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40,
+  0x00, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, 0x00, 0xe1, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+  0x30, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x9c,
+  0x01, 0x08, 0x60, 0x0c, 0x06, 0x86, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbf, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00,
+  0xc0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xf0, 0x9f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+  0x07, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xe0,
+  0x01, 0x06, 0x00, 0x30, 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x06, 0x00, 0x30,
+  0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+  0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff,
+  0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+  0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x0f,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00,
+  0x00, 0x06, 0x83, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, 0x00, 0x06, 0x83, 0xff,
+  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x00, 0xc0, 0x00, 0x8c, 0xc9, 0x60, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+  0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
+  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+  0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+  0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc6,
+  0x03, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xef, 0x07, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xd8, 0xef, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3,
+  0x0f, 0x00, 0x00, 0x00, 0x80, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x88, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13,
+  0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x88, 0xf3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3,
+  0x0f, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xe1, 0x1f, 0x00, 0x00, 0x00,
+  0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xf0, 0xc1, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc0, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
diff --git a/arch/m68k/platform/68EZ328/config.c b/arch/m68k/platform/68EZ328/config.c
new file mode 100644 (file)
index 0000000..1be1a16
--- /dev/null
@@ -0,0 +1,76 @@
+/***************************************************************************/
+
+/*
+ *  linux/arch/m68knommu/platform/68EZ328/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68EZ328.h>
+#ifdef CONFIG_UCSIMM
+#include <asm/bootstd.h>
+#endif
+
+/***************************************************************************/
+
+void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+
+/***************************************************************************/
+
+void m68ez328_reset(void)
+{
+  local_irq_disable();
+  asm volatile (
+    "moveal #0x10c00000, %a0;\n"
+    "moveb #0, 0xFFFFF300;\n"
+    "moveal 0(%a0), %sp;\n"
+    "moveal 4(%a0), %a0;\n"
+    "jmp (%a0);\n"
+    );
+}
+
+/***************************************************************************/
+
+unsigned char *cs8900a_hwaddr;
+static int errno;
+
+#ifdef CONFIG_UCSIMM
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+#endif
+
+void config_BSP(char *command, int len)
+{
+  unsigned char *p;
+
+  printk(KERN_INFO "\n68EZ328 DragonBallEZ support (C) 1999 Rt-Control, Inc\n");
+
+#ifdef CONFIG_UCSIMM
+  printk(KERN_INFO "uCsimm serial string [%s]\n",getserialnum());
+  p = cs8900a_hwaddr = gethwaddr(0);
+  printk(KERN_INFO "uCsimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+         p[0], p[1], p[2], p[3], p[4], p[5]);
+
+  p = getbenv("APPEND");
+  if (p) strcpy(p,command);
+  else command[0] = 0;
+#endif
+  mach_gettod = m68328_timer_gettod;
+  mach_reset = m68ez328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/68VZ328/Makefile b/arch/m68k/platform/68VZ328/Makefile
new file mode 100644 (file)
index 0000000..447ffa0
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Makefile for arch/m68knommu/platform/68VZ328.
+#
+
+obj-y          := config.o
+logo-$(UCDIMM) := bootlogo.rh
+logo-$(DRAGEN2)        := screen.h
+extra-y                := $(logo-y)
+
+$(obj)/bootlogo.rh: $(src)/../68EZ328/bootlogo.h
+       perl $(src)/bootlogo.pl < $(src)/../68328/bootlogo.h > $(obj)/bootlogo.rh
+
+$(obj)/screen.h: $(src)/screen.xbm $(src)/xbm2lcd.pl
+       perl $(src)/xbm2lcd.pl < $(src)/screen.xbm > $(obj)/screen.h
+
+clean-files := $(obj)/screen.h $(obj)/bootlogo.rh
diff --git a/arch/m68k/platform/68VZ328/config.c b/arch/m68k/platform/68VZ328/config.c
new file mode 100644 (file)
index 0000000..eabaabe
--- /dev/null
@@ -0,0 +1,188 @@
+/***************************************************************************/
+
+/*
+ *  linux/arch/m68knommu/platform/68VZ328/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *  Copyright (C) 1999 D. Jeff Dionne
+ *  Copyright (C) 2001 Georges Menie, Ken Desmet
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/***************************************************************************/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kd.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/MC68VZ328.h>
+#include <asm/bootstd.h>
+
+#ifdef CONFIG_INIT_LCD
+#include "bootlogo.h"
+#endif
+
+/***************************************************************************/
+
+void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
+
+/***************************************************************************/
+/*                        Init Drangon Engine hardware                     */
+/***************************************************************************/
+#if defined(CONFIG_DRAGEN2)
+
+static void m68vz328_reset(void)
+{
+       local_irq_disable();
+
+#ifdef CONFIG_INIT_LCD
+       PBDATA |= 0x20;                         /* disable CCFL light */
+       PKDATA |= 0x4;                          /* disable LCD controller */
+       LCKCON = 0;
+#endif
+
+       __asm__ __volatile__(
+               "reset\n\t"
+               "moveal #0x04000000, %a0\n\t"
+               "moveal 0(%a0), %sp\n\t"
+               "moveal 4(%a0), %a0\n\t"
+               "jmp (%a0)"
+       );
+}
+
+static void init_hardware(char *command, int size)
+{
+#ifdef CONFIG_DIRECT_IO_ACCESS
+       SCR = 0x10;                                     /* allow user access to internal registers */
+#endif
+
+       /* CSGB Init */
+       CSGBB = 0x4000;
+       CSB = 0x1a1;
+
+       /* CS8900 init */
+       /* PK3: hardware sleep function pin, active low */
+       PKSEL |= PK(3);                         /* select pin as I/O */
+       PKDIR |= PK(3);                         /* select pin as output */
+       PKDATA |= PK(3);                        /* set pin high */
+
+       /* PF5: hardware reset function pin, active high */
+       PFSEL |= PF(5);                         /* select pin as I/O */
+       PFDIR |= PF(5);                         /* select pin as output */
+       PFDATA &= ~PF(5);                       /* set pin low */
+
+       /* cs8900 hardware reset */
+       PFDATA |= PF(5);
+       { int i; for (i = 0; i < 32000; ++i); }
+       PFDATA &= ~PF(5);
+
+       /* INT1 enable (cs8900 IRQ) */
+       PDPOL &= ~PD(1);                        /* active high signal */
+       PDIQEG &= ~PD(1);
+       PDIRQEN |= PD(1);                       /* IRQ enabled */
+
+#ifdef CONFIG_INIT_LCD
+       /* initialize LCD controller */
+       LSSA = (long) screen_bits;
+       LVPW = 0x14;
+       LXMAX = 0x140;
+       LYMAX = 0xef;
+       LRRA = 0;
+       LPXCD = 3;
+       LPICF = 0x08;
+       LPOLCF = 0;
+       LCKCON = 0x80;
+       PCPDEN = 0xff;
+       PCSEL = 0;
+
+       /* Enable LCD controller */
+       PKDIR |= 0x4;
+       PKSEL |= 0x4;
+       PKDATA &= ~0x4;
+
+       /* Enable CCFL backlighting circuit */
+       PBDIR |= 0x20;
+       PBSEL |= 0x20;
+       PBDATA &= ~0x20;
+
+       /* contrast control register */
+       PFDIR |= 0x1;
+       PFSEL &= ~0x1;
+       PWMR = 0x037F;
+#endif
+}
+
+/***************************************************************************/
+/*                      Init RT-Control uCdimm hardware                    */
+/***************************************************************************/
+#elif defined(CONFIG_UCDIMM)
+
+static void m68vz328_reset(void)
+{
+       local_irq_disable();
+       asm volatile (
+               "moveal #0x10c00000, %a0;\n\t"
+               "moveb #0, 0xFFFFF300;\n\t"
+               "moveal 0(%a0), %sp;\n\t"
+               "moveal 4(%a0), %a0;\n\t"
+               "jmp (%a0);\n"
+       );
+}
+
+unsigned char *cs8900a_hwaddr;
+static int errno;
+
+_bsc0(char *, getserialnum)
+_bsc1(unsigned char *, gethwaddr, int, a)
+_bsc1(char *, getbenv, char *, a)
+
+static void init_hardware(char *command, int size)
+{
+       char *p;
+
+       printk(KERN_INFO "uCdimm serial string [%s]\n", getserialnum());
+       p = cs8900a_hwaddr = gethwaddr(0);
+       printk(KERN_INFO "uCdimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5]);
+       p = getbenv("APPEND");
+       if (p)
+               strcpy(p, command);
+       else
+               command[0] = 0;
+}
+
+/***************************************************************************/
+#else
+
+static void m68vz328_reset(void)
+{
+}
+
+static void init_hardware(char *command, int size)
+{
+}
+
+/***************************************************************************/
+#endif
+/***************************************************************************/
+
+void config_BSP(char *command, int size)
+{
+       printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
+
+       init_hardware(command, size);
+
+       mach_gettod = m68328_timer_gettod;
+       mach_reset = m68vz328_reset;
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/Makefile b/arch/m68k/platform/Makefile
new file mode 100644 (file)
index 0000000..fc932bf
--- /dev/null
@@ -0,0 +1,3 @@
+#
+# Makefile for the arch/m68knommu/platform.
+#
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile
new file mode 100644 (file)
index 0000000..a8967ba
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Makefile for the m68knommu kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o
+obj-$(CONFIG_M5206)    += timers.o intc.o
+obj-$(CONFIG_M5206e)   += timers.o intc.o
+obj-$(CONFIG_M520x)    += pit.o intc-simr.o
+obj-$(CONFIG_M523x)    += pit.o dma_timer.o intc-2.o
+obj-$(CONFIG_M5249)    += timers.o intc.o
+obj-$(CONFIG_M527x)    += pit.o intc-2.o
+obj-$(CONFIG_M5272)    += timers.o
+obj-$(CONFIG_M528x)    += pit.o intc-2.o
+obj-$(CONFIG_M5307)    += timers.o intc.o
+obj-$(CONFIG_M532x)    += timers.o intc-simr.o
+obj-$(CONFIG_M5407)    += timers.o intc.o
+obj-$(CONFIG_M54xx)    += sltimers.o intc-2.o
+
+obj-y                  += pinmux.o gpio.o
+extra-y := head.o
diff --git a/arch/m68k/platform/coldfire/cache.c b/arch/m68k/platform/coldfire/cache.c
new file mode 100644 (file)
index 0000000..235d3c4
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************/
+
+/*
+ *     cache.c -- general ColdFire Cache maintainence code
+ *
+ *     Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+#ifdef CACHE_PUSH
+/***************************************************************************/
+
+/*
+ *     Use cpushl to push all dirty cache lines back to memory.
+ *     Older versions of GAS don't seem to know how to generate the
+ *     ColdFire cpushl instruction... Oh well, bit stuff it for now.
+ */
+
+void mcf_cache_push(void)
+{
+       __asm__ __volatile__ (
+               "clrl   %%d0\n\t"
+               "1:\n\t"
+               "movel  %%d0,%%a0\n\t"
+               "2:\n\t"
+               ".word  0xf468\n\t"
+               "addl   %0,%%a0\n\t"
+               "cmpl   %1,%%a0\n\t"
+               "blt    2b\n\t"
+               "addql  #1,%%d0\n\t"
+               "cmpil  %2,%%d0\n\t"
+               "bne    1b\n\t"
+               : /* No output */
+               : "i" (CACHE_LINE_SIZE),
+                 "i" (DCACHE_SIZE / CACHE_WAYS),
+                 "i" (CACHE_WAYS)
+               : "d0", "a0" );
+}
+
+/***************************************************************************/
+#endif /* CACHE_PUSH */
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c
new file mode 100644 (file)
index 0000000..9f1260c
--- /dev/null
@@ -0,0 +1,45 @@
+/***************************************************************************/
+
+/*
+ *     clk.c -- general ColdFire CPU kernel clk handling
+ *
+ *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/coldfire.h>
+
+/***************************************************************************/
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return NULL;
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return MCF_CLK;
+}
+EXPORT_SYMBOL(clk_get_rate);
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/dma.c b/arch/m68k/platform/coldfire/dma.c
new file mode 100644 (file)
index 0000000..e88b95e
--- /dev/null
@@ -0,0 +1,39 @@
+/***************************************************************************/
+
+/*
+ *     dma.c -- Freescale ColdFire DMA support
+ *
+ *     Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+/*
+ *      DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+#ifdef MCFDMA_BASE0
+       MCFDMA_BASE0,
+#endif
+#ifdef MCFDMA_BASE1
+       MCFDMA_BASE1,
+#endif
+#ifdef MCFDMA_BASE2
+       MCFDMA_BASE2,
+#endif
+#ifdef MCFDMA_BASE3
+       MCFDMA_BASE3,
+#endif
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/dma_timer.c b/arch/m68k/platform/coldfire/dma_timer.c
new file mode 100644 (file)
index 0000000..a5f5628
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * dma_timer.c -- Freescale ColdFire DMA Timer.
+ *
+ * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright (C) 2008. Sebastian Siewior, Linutronix
+ *
+ */
+
+#include <linux/clocksource.h>
+#include <linux/io.h>
+
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+#define DMA_TIMER_0    (0x00)
+#define DMA_TIMER_1    (0x40)
+#define DMA_TIMER_2    (0x80)
+#define DMA_TIMER_3    (0xc0)
+
+#define DTMR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x400)
+#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402)
+#define DTER0  (MCF_IPSBAR + DMA_TIMER_0 + 0x403)
+#define DTRR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x404)
+#define DTCR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x408)
+#define DTCN0  (MCF_IPSBAR + DMA_TIMER_0 + 0x40c)
+
+#define DMA_FREQ    ((MCF_CLK / 2) / 16)
+
+/* DTMR */
+#define DMA_DTMR_RESTART       (1 << 3)
+#define DMA_DTMR_CLK_DIV_1     (1 << 1)
+#define DMA_DTMR_CLK_DIV_16    (2 << 1)
+#define DMA_DTMR_ENABLE                (1 << 0)
+
+static cycle_t cf_dt_get_cycles(struct clocksource *cs)
+{
+       return __raw_readl(DTCN0);
+}
+
+static struct clocksource clocksource_cf_dt = {
+       .name           = "coldfire_dma_timer",
+       .rating         = 200,
+       .read           = cf_dt_get_cycles,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 20,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init  init_cf_dt_clocksource(void)
+{
+       /*
+        * We setup DMA timer 0 in free run mode. This incrementing counter is
+        * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we
+        * get a ~213 ns resolution and the 32bit register will overflow almost
+        * every 15 minutes.
+        */
+       __raw_writeb(0x00, DTXMR0);
+       __raw_writeb(0x00, DTER0);
+       __raw_writel(0x00000000, DTRR0);
+       __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0);
+       clocksource_cf_dt.mult = clocksource_hz2mult(DMA_FREQ,
+                                                    clocksource_cf_dt.shift);
+       return clocksource_register(&clocksource_cf_dt);
+}
+
+arch_initcall(init_cf_dt_clocksource);
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+#define CYC2NS_SCALE   ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000))
+
+static unsigned long long cycles2ns(unsigned long cycl)
+{
+       return (unsigned long long) ((unsigned long long)cycl *
+                       CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR;
+}
+
+unsigned long long sched_clock(void)
+{
+       unsigned long cycl = __raw_readl(DTCN0);
+
+       return cycles2ns(cycl);
+}
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
new file mode 100644 (file)
index 0000000..5837cf0
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  linux/arch/m68knommu/platform/5307/entry.S
+ *
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
+ *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
+ *
+ * Based on:
+ *
+ *  linux/arch/m68k/kernel/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ * ColdFire support by Greg Ungerer (gerg@snapgear.com)
+ * 5307 fixes by David W. Miller
+ * linux 2.4 support David McCullough <davidm@snapgear.com>
+ * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/asm-offsets.h>
+#include <asm/entry.h>
+
+#ifdef CONFIG_COLDFIRE_SW_A7
+/*
+ *     Define software copies of the supervisor and user stack pointers.
+ */
+.bss
+sw_ksp:
+.long  0
+sw_usp:
+.long  0
+#endif /* CONFIG_COLDFIRE_SW_A7 */
+
+.text
+
+.globl system_call
+.globl resume
+.globl ret_from_exception
+.globl ret_from_signal
+.globl sys_call_table
+.globl inthandler
+.globl fasthandler
+
+enosys:
+       mov.l   #sys_ni_syscall,%d3
+       bra     1f
+
+ENTRY(system_call)
+       SAVE_ALL
+       move    #0x2000,%sr             /* enable intrs again */
+
+       cmpl    #NR_syscalls,%d0
+       jcc     enosys
+       lea     sys_call_table,%a0
+       lsll    #2,%d0                  /* movel %a0@(%d0:l:4),%d3 */
+       movel   %a0@(%d0),%d3
+       jeq     enosys
+
+1:
+       movel   %sp,%d2                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d2       /* at start of kernel stack */
+       movel   %d2,%a0
+       movel   %a0@,%a1                /* save top of frame */
+       movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
+       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       bnes    1f
+
+       movel   %d3,%a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
+       jra     ret_from_exception
+1:
+       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_OFF_D0 */
+       movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
+       subql   #4,%sp
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_enter
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       movel   %d3,%a0
+       jbsr    %a0@
+       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       jbsr    syscall_trace_leave
+
+ret_from_signal:
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+
+ret_from_exception:
+       move    #0x2700,%sr             /* disable intrs */
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
+       jeq     Luser_return            /* if so, skip resched, signals */
+
+#ifdef CONFIG_PREEMPT
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
+       movel   %d1,%a0
+       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       andl    #(1<<TIF_NEED_RESCHED),%d1
+       jeq     Lkernel_return
+
+       movel   %a0@(TI_PREEMPTCOUNT),%d1
+       cmpl    #0,%d1
+       jne     Lkernel_return
+
+       pea     Lkernel_return
+       jmp     preempt_schedule_irq    /* preempt the kernel */
+#endif
+
+Lkernel_return:
+       moveml  %sp@,%d1-%d5/%a0-%a2
+       lea     %sp@(32),%sp            /* space for 8 regs */
+       movel   %sp@+,%d0
+       addql   #4,%sp                  /* orig d0 */
+       addl    %sp@+,%sp               /* stk adj */
+       rte
+
+Luser_return:
+       movel   %sp,%d1                 /* get thread_info pointer */
+       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
+       movel   %d1,%a0
+       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       jne     Lwork_to_do             /* still work to do */
+
+Lreturn:
+       RESTORE_USER
+
+Lwork_to_do:
+       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       move    #0x2000,%sr             /* enable intrs again */
+       btst    #TIF_NEED_RESCHED,%d1
+       jne     reschedule
+
+       /* GERG: do we need something here for TRACEing?? */
+
+Lsignal_return:
+       subql   #4,%sp                  /* dummy return address */
+       SAVE_SWITCH_STACK
+       pea     %sp@(SWITCH_STACK_SIZE)
+       jsr     do_signal
+       addql   #4,%sp
+       RESTORE_SWITCH_STACK
+       addql   #4,%sp
+       jmp     Luser_return
+
+/*
+ * This is the generic interrupt handler (for all hardware interrupt
+ * sources). Calls upto high level code to do all the work.
+ */
+ENTRY(inthandler)
+       SAVE_ALL
+       moveq   #-1,%d0
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
+
+       movew   %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
+       andl    #0x03fc,%d0             /* mask out vector only */
+
+       movel   %sp,%sp@-               /* push regs arg */
+       lsrl    #2,%d0                  /* calculate real vector # */
+       movel   %d0,%sp@-               /* push vector number */
+       jbsr    do_IRQ                  /* call high level irq handler */
+       lea     %sp@(8),%sp             /* pop args off stack */
+
+       bra     ret_from_exception
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in a0, next (the new task) is in a1,so don't change these
+ * registers until their contents are no longer needed.
+ * This is always called in supervisor mode, so don't bother to save
+ * and restore sr; user's process sr is actually in the stack.
+ */
+ENTRY(resume)
+       movel   %a0, %d1                        /* get prev thread in d1 */
+       RDUSP
+       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
+
+       SAVE_SWITCH_STACK
+       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
+       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
+       RESTORE_SWITCH_STACK
+
+       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
+       WRUSP
+       rts
diff --git a/arch/m68k/platform/coldfire/gpio.c b/arch/m68k/platform/coldfire/gpio.c
new file mode 100644 (file)
index 0000000..ff00457
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Coldfire generic GPIO support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/gpio.h>
+#include <asm/pinmux.h>
+#include <asm/mcfgpio.h>
+
+#define MCF_CHIP(chip) container_of(chip, struct mcf_gpio_chip, gpio_chip)
+
+int mcf_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned long flags;
+       MCFGPIO_PORTTYPE dir;
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       local_irq_save(flags);
+       dir = mcfgpio_read(mcf_chip->pddr);
+       dir &= ~mcfgpio_bit(chip->base + offset);
+       mcfgpio_write(dir, mcf_chip->pddr);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+int mcf_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       return mcfgpio_read(mcf_chip->ppdr) & mcfgpio_bit(chip->base + offset);
+}
+
+int mcf_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+               int value)
+{
+       unsigned long flags;
+       MCFGPIO_PORTTYPE data;
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       local_irq_save(flags);
+       /* write the value to the output latch */
+       data = mcfgpio_read(mcf_chip->podr);
+       if (value)
+               data |= mcfgpio_bit(chip->base + offset);
+       else
+               data &= ~mcfgpio_bit(chip->base + offset);
+       mcfgpio_write(data, mcf_chip->podr);
+
+       /* now set the direction to output */
+       data = mcfgpio_read(mcf_chip->pddr);
+       data |= mcfgpio_bit(chip->base + offset);
+       mcfgpio_write(data, mcf_chip->pddr);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+void mcf_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       unsigned long flags;
+       MCFGPIO_PORTTYPE data;
+
+       local_irq_save(flags);
+       data = mcfgpio_read(mcf_chip->podr);
+       if (value)
+               data |= mcfgpio_bit(chip->base + offset);
+       else
+               data &= ~mcfgpio_bit(chip->base + offset);
+       mcfgpio_write(data, mcf_chip->podr);
+       local_irq_restore(flags);
+}
+
+void mcf_gpio_set_value_fast(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       if (value)
+               mcfgpio_write(mcfgpio_bit(chip->base + offset), mcf_chip->setr);
+       else
+               mcfgpio_write(~mcfgpio_bit(chip->base + offset), mcf_chip->clrr);
+}
+
+int mcf_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       return mcf_chip->gpio_to_pinmux ?
+               mcf_pinmux_request(mcf_chip->gpio_to_pinmux[offset], 0) : 0;
+}
+
+void mcf_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
+
+       mcf_gpio_direction_input(chip, offset);
+
+       if (mcf_chip->gpio_to_pinmux)
+               mcf_pinmux_release(mcf_chip->gpio_to_pinmux[offset], 0);
+}
+
+struct sysdev_class mcf_gpio_sysclass = {
+       .name   = "gpio",
+};
+
+static int __init mcf_gpio_sysinit(void)
+{
+       return sysdev_class_register(&mcf_gpio_sysclass);
+}
+
+core_initcall(mcf_gpio_sysinit);
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
new file mode 100644 (file)
index 0000000..129bff4
--- /dev/null
@@ -0,0 +1,250 @@
+/*****************************************************************************/
+
+/*
+ *     head.S -- common startup code for ColdFire CPUs.
+ *
+ *     (C) Copyright 1999-2010, Greg Ungerer <gerg@snapgear.com>.
+ */
+
+/*****************************************************************************/
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/asm-offsets.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/thread_info.h>
+
+/*****************************************************************************/
+
+/*
+ *     If we don't have a fixed memory size, then lets build in code
+ *     to auto detect the DRAM size. Obviously this is the prefered
+ *     method, and should work for most boards. It won't work for those
+ *     that do not have their RAM starting at address 0, and it only
+ *     works on SDRAM (not boards fitted with SRAM).
+ */
+#if CONFIG_RAMSIZE != 0
+.macro GET_MEM_SIZE
+       movel   #CONFIG_RAMSIZE,%d0     /* hard coded memory size */
+.endm
+
+#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
+      defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
+      defined(CONFIG_M528x) || defined(CONFIG_M5307) || \
+      defined(CONFIG_M5407)
+/*
+ *     Not all these devices have exactly the same DRAM controller,
+ *     but the DCMR register is virtually identical - give or take
+ *     a couple of bits. The only exception is the 5272 devices, their
+ *     DRAM controller is quite different.
+ */
+.macro GET_MEM_SIZE
+       movel   MCFSIM_DMR0,%d0         /* get mask for 1st bank */
+       btst    #0,%d0                  /* check if region enabled */
+       beq     1f
+       andl    #0xfffc0000,%d0
+       beq     1f
+       addl    #0x00040000,%d0         /* convert mask to size */
+1:
+       movel   MCFSIM_DMR1,%d1         /* get mask for 2nd bank */
+       btst    #0,%d1                  /* check if region enabled */
+       beq     2f
+       andl    #0xfffc0000,%d1
+       beq     2f
+       addl    #0x00040000,%d1
+       addl    %d1,%d0                 /* total mem size in d0 */
+2:
+.endm
+
+#elif defined(CONFIG_M5272)
+.macro GET_MEM_SIZE
+       movel   MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */
+       andil   #0xfffff000,%d0         /* mask out chip select options */
+       negl    %d0                     /* negate bits */
+.endm
+
+#elif defined(CONFIG_M520x)
+.macro GET_MEM_SIZE
+       clrl    %d0
+       movel   MCFSIM_SDCS0, %d2       /* Get SDRAM chip select 0 config */
+       andl    #0x1f, %d2              /* Get only the chip select size */
+       beq     3f                      /* Check if it is enabled */
+       addql   #1, %d2                 /* Form exponent */
+       moveql  #1, %d0
+       lsll    %d2, %d0                /* 2 ^ exponent */
+3:
+       movel   MCFSIM_SDCS1, %d2       /* Get SDRAM chip select 1 config */
+       andl    #0x1f, %d2              /* Get only the chip select size */
+       beq     4f                      /* Check if it is enabled */
+       addql   #1, %d2                 /* Form exponent */
+       moveql  #1, %d1
+       lsll    %d2, %d1                /* 2 ^ exponent */
+       addl    %d1, %d0                /* Total size of SDRAM in d0 */
+4:
+.endm
+
+#else
+#error "ERROR: I don't know how to probe your boards memory size?"
+#endif
+
+/*****************************************************************************/
+
+/*
+ *     Boards and platforms can do specific early hardware setup if
+ *     they need to. Most don't need this, define away if not required.
+ */
+#ifndef PLATFORM_SETUP
+#define        PLATFORM_SETUP
+#endif
+
+/*****************************************************************************/
+
+.global        _start
+.global _rambase
+.global _ramvec
+.global        _ramstart
+.global        _ramend
+#if defined(CONFIG_UBOOT)
+.global        _init_sp
+#endif
+
+/*****************************************************************************/
+
+.data
+
+/*
+ *     During startup we store away the RAM setup. These are not in the
+ *     bss, since their values are determined and written before the bss
+ *     has been cleared.
+ */
+_rambase:
+.long  0
+_ramvec:
+.long  0
+_ramstart:
+.long  0
+_ramend:
+.long  0
+#if defined(CONFIG_UBOOT)
+_init_sp:
+.long  0
+#endif
+
+/*****************************************************************************/
+
+__HEAD
+
+/*
+ *     This is the codes first entry point. This is where it all
+ *     begins...
+ */
+
+_start:
+       nop                                     /* filler */
+       movew   #0x2700, %sr                    /* no interrupts */
+#if defined(CONFIG_UBOOT)
+       movel   %sp,_init_sp                    /* save initial stack pointer */
+#endif
+
+       /*
+        *      Do any platform or board specific setup now. Most boards
+        *      don't need anything. Those exceptions are define this in
+        *      their board specific includes.
+        */
+       PLATFORM_SETUP
+
+       /*
+        *      Create basic memory configuration. Set VBR accordingly,
+        *      and size memory.
+        */
+       movel   #CONFIG_VECTORBASE,%a7
+       movec   %a7,%VBR                        /* set vectors addr */
+       movel   %a7,_ramvec
+
+       movel   #CONFIG_RAMBASE,%a7             /* mark the base of RAM */
+       movel   %a7,_rambase
+
+       GET_MEM_SIZE                            /* macro code determines size */
+       addl    %a7,%d0
+       movel   %d0,_ramend                     /* set end ram addr */
+
+       /*
+        *      Now that we know what the memory is, lets enable cache
+        *      and get things moving. This is Coldfire CPU specific. Not
+        *      all version cores have identical cache register setup. But
+        *      it is very similar. Define the exact settings in the headers
+        *      then the code here is the same for all.
+        */
+       movel   #CACHE_INIT,%d0                 /* invalidate whole cache */
+       movec   %d0,%CACR
+       nop
+       movel   #ACR0_MODE,%d0                  /* set RAM region for caching */
+       movec   %d0,%ACR0
+       movel   #ACR1_MODE,%d0                  /* anything else to cache? */
+       movec   %d0,%ACR1
+#ifdef ACR2_MODE
+       movel   #ACR2_MODE,%d0
+       movec   %d0,%ACR2
+       movel   #ACR3_MODE,%d0
+       movec   %d0,%ACR3
+#endif
+       movel   #CACHE_MODE,%d0                 /* enable cache */
+       movec   %d0,%CACR
+       nop
+
+#ifdef CONFIG_ROMFS_FS
+       /*
+        *      Move ROM filesystem above bss :-)
+        */
+       lea     _sbss,%a0                       /* get start of bss */
+       lea     _ebss,%a1                       /* set up destination  */
+       movel   %a0,%a2                         /* copy of bss start */
+
+       movel   8(%a0),%d0                      /* get size of ROMFS */
+       addql   #8,%d0                          /* allow for rounding */
+       andl    #0xfffffffc, %d0                /* whole words */
+
+       addl    %d0,%a0                         /* copy from end */
+       addl    %d0,%a1                         /* copy from end */
+       movel   %a1,_ramstart                   /* set start of ram */
+
+_copy_romfs:
+       movel   -(%a0),%d0                      /* copy dword */
+       movel   %d0,-(%a1)
+       cmpl    %a0,%a2                         /* check if at end */
+       bne     _copy_romfs
+
+#else /* CONFIG_ROMFS_FS */
+       lea     _ebss,%a1
+       movel   %a1,_ramstart
+#endif /* CONFIG_ROMFS_FS */
+
+
+       /*
+        *      Zero out the bss region.
+        */
+       lea     _sbss,%a0                       /* get start of bss */
+       lea     _ebss,%a1                       /* get end of bss */
+       clrl    %d0                             /* set value */
+_clear_bss:
+       movel   %d0,(%a0)+                      /* clear each word */
+       cmpl    %a0,%a1                         /* check if at end */
+       bne     _clear_bss
+
+       /*
+        *      Load the current task pointer and stack.
+        */
+       lea     init_thread_union,%a0
+       lea     THREAD_SIZE(%a0),%sp
+
+       /*
+        *      Assember start up done, start code proper.
+        */
+       jsr     start_kernel                    /* start Linux kernel */
+
+_exit:
+       jmp     _exit                           /* should never get here */
+
+/*****************************************************************************/
diff --git a/arch/m68k/platform/coldfire/intc-2.c b/arch/m68k/platform/coldfire/intc-2.c
new file mode 100644 (file)
index 0000000..2cbfbf0
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
+ *
+ * The external 7 fixed interrupts are part the the Edge Port unit of these
+ * ColdFire parts. They can be configured as level or edge triggered.
+ *
+ * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l)    ((l)<<3)        /* Level l intr */
+#define MCFSIM_ICR_PRI(p)      (p)             /* Priority p intr */
+
+/*
+ *     The EDGE Port interrupts are the fixed 7 external interrupts.
+ *     They need some special treatment, for example they need to be acked.
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT7   71      /* EDGE Port interrupt 7 */
+
+#ifdef MCFICM_INTC1
+#define NR_VECS        128
+#else
+#define NR_VECS        64
+#endif
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long imraddr;
+       u32 val, imrbit;
+
+#ifdef MCFICM_INTC1
+       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       imraddr = MCFICM_INTC0;
+#endif
+       imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
+       imrbit = 0x1 << (irq & 0x1f);
+
+       val = __raw_readl(imraddr);
+       __raw_writel(val | imrbit, imraddr);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long imraddr;
+       u32 val, imrbit;
+
+#ifdef MCFICM_INTC1
+       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       imraddr = MCFICM_INTC0;
+#endif
+       imraddr += ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
+       imrbit = 0x1 << (irq & 0x1f);
+
+       /* Don't set the "maskall" bit! */
+       if ((irq & 0x20) == 0)
+               imrbit |= 0x1;
+
+       val = __raw_readl(imraddr);
+       __raw_writel(val & ~imrbit, imraddr);
+}
+
+/*
+ *     Only the external (or EDGE Port) interrupts need to be acknowledged
+ *     here, as part of the IRQ handler. They only really need to be ack'ed
+ *     if they are in edge triggered mode, but there is no harm in doing it
+ *     for all types.
+ */
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR);
+}
+
+/*
+ *     Each vector needs a unique priority and level associated with it.
+ *     We don't really care so much what they are, we don't rely on the
+ *     traditional priority interrupt scheme of the m68k/ColdFire. This
+ *     only needs to be set once for an interrupt, and we will never change
+ *     these values once we have set them.
+ */
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+static unsigned int intc_irq_startup(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+       unsigned long icraddr;
+
+#ifdef MCFICM_INTC1
+       icraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+       icraddr = MCFICM_INTC0;
+#endif
+       icraddr += MCFINTC_ICR0 + (irq & 0x3f);
+       if (__raw_readb(icraddr) == 0)
+               __raw_writeb(intc_intpri--, icraddr);
+
+       irq = d->irq;
+       if ((irq >= EINT1) && (irq <= EINT7)) {
+               u8 v;
+
+               irq -= EINT0;
+
+               /* Set EPORT line as input */
+               v = __raw_readb(MCFEPORT_EPDDR);
+               __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR);
+
+               /* Set EPORT line as interrupt source */
+               v = __raw_readb(MCFEPORT_EPIER);
+               __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER);
+       }
+
+       intc_irq_unmask(d);
+       return 0;
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int irq = d->irq;
+       u16 pa, tb;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               tb = 0x1;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               tb = 0x2;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               tb = 0x3;
+               break;
+       default:
+               /* Level triggered */
+               tb = 0;
+               break;
+       }
+
+       if (tb)
+               set_irq_handler(irq, handle_edge_irq);
+
+       irq -= EINT0;
+       pa = __raw_readw(MCFEPORT_EPPAR);
+       pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2));
+       __raw_writew(pa, MCFEPORT_EPPAR);
+       
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+static struct irq_chip intc_irq_chip_edge_port = {
+       .name           = "CF-INTC-EP",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq;
+
+       init_vectors();
+
+       /* Mask all interrupt sources */
+       __raw_writel(0x1, MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
+       __raw_writel(0x1, MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
+
+       for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) {
+               if ((irq >= EINT1) && (irq <=EINT7))
+                       set_irq_chip(irq, &intc_irq_chip_edge_port);
+               else
+                       set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/platform/coldfire/intc-simr.c b/arch/m68k/platform/coldfire/intc-simr.c
new file mode 100644 (file)
index 0000000..e642b24
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * intc-simr.c
+ *
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
+ * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/traps.h>
+
+/*
+ *     The EDGE Port interrupts are the fixed 7 external interrupts.
+ *     They need some special treatment, for example they need to be acked.
+ */
+#ifdef CONFIG_M520x
+/*
+ *     The 520x parts only support a limited range of these external
+ *     interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67).
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT4   66      /* EDGE Port interrupt 4 */
+#define        EINT7   67      /* EDGE Port interrupt 7 */
+
+static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
+static unsigned int inline irq2ebit(unsigned int irq)
+{
+       return irqebitmap[irq - EINT0];
+}
+
+#else
+
+/*
+ *     Most of the ColdFire parts with the EDGE Port module just have
+ *     a strait direct mapping of the 7 external interrupts. Although
+ *     there is a bit reserved for 0, it is not used.
+ */
+#define        EINT0   64      /* Is not actually used, but spot reserved for it */
+#define        EINT1   65      /* EDGE Port interrupt 1 */
+#define        EINT7   71      /* EDGE Port interrupt 7 */
+
+static unsigned int inline irq2ebit(unsigned int irq)
+{
+       return irq - EINT0;
+}
+
+#endif
+
+/*
+ *     There maybe one or two interrupt control units, each has 64
+ *     interrupts. If there is no second unit then MCFINTC1_* defines
+ *     will be 0 (and code for them optimized away).
+ */
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+
+       if (MCFINTC1_SIMR && (irq > 64))
+               __raw_writeb(irq - 64, MCFINTC1_SIMR);
+       else
+               __raw_writeb(irq, MCFINTC0_SIMR);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       unsigned int irq = d->irq - MCFINT_VECBASE;
+
+       if (MCFINTC1_CIMR && (irq > 64))
+               __raw_writeb(irq - 64, MCFINTC1_CIMR);
+       else
+               __raw_writeb(irq, MCFINTC0_CIMR);
+}
+
+static void intc_irq_ack(struct irq_data *d)
+{
+       unsigned int ebit = irq2ebit(d->irq);
+
+       __raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
+}
+
+static unsigned int intc_irq_startup(struct irq_data *d)
+{
+       unsigned int irq = d->irq;
+
+       if ((irq >= EINT1) && (irq <= EINT7)) {
+               unsigned int ebit = irq2ebit(irq);
+               u8 v;
+
+               /* Set EPORT line as input */
+               v = __raw_readb(MCFEPORT_EPDDR);
+               __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
+
+               /* Set EPORT line as interrupt source */
+               v = __raw_readb(MCFEPORT_EPIER);
+               __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
+       }
+
+       irq -= MCFINT_VECBASE;
+       if (MCFINTC1_ICR0 && (irq > 64))
+               __raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
+       else
+               __raw_writeb(5, MCFINTC0_ICR0 + irq);
+
+
+       intc_irq_unmask(d);
+       return 0;
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       unsigned int ebit, irq = d->irq;
+       u16 pa, tb;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               tb = 0x1;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               tb = 0x2;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               tb = 0x3;
+               break;
+       default:
+               /* Level triggered */
+               tb = 0;
+               break;
+       }
+
+       if (tb)
+               set_irq_handler(irq, handle_edge_irq);
+
+       ebit = irq2ebit(irq) * 2;
+       pa = __raw_readw(MCFEPORT_EPPAR);
+       pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
+       __raw_writew(pa, MCFEPORT_EPPAR);
+       
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+};
+
+static struct irq_chip intc_irq_chip_edge_port = {
+       .name           = "CF-INTC-EP",
+       .irq_startup    = intc_irq_startup,
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_ack        = intc_irq_ack,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq, eirq;
+
+       init_vectors();
+
+       /* Mask all interrupt sources */
+       __raw_writeb(0xff, MCFINTC0_SIMR);
+       if (MCFINTC1_SIMR)
+               __raw_writeb(0xff, MCFINTC1_SIMR);
+
+       eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0);
+       for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
+               if ((irq >= EINT1) && (irq <= EINT7))
+                       set_irq_chip(irq, &intc_irq_chip_edge_port);
+               else
+                       set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/platform/coldfire/intc.c b/arch/m68k/platform/coldfire/intc.c
new file mode 100644 (file)
index 0000000..d648081
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * intc.c  -- support for the old ColdFire interrupt controller
+ *
+ * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ * The mapping of irq number to a mask register bit is not one-to-one.
+ * The irq numbers are either based on "level" of interrupt or fixed
+ * for an autovector-able interrupt. So we keep a local data structure
+ * that maps from irq to mask register. Not all interrupts will have
+ * an IMR bit.
+ */
+unsigned char mcf_irq2imr[NR_IRQS];
+
+/*
+ * Define the miniumun and maximum external interrupt numbers.
+ * This is also used as the "level" interrupt numbers.
+ */
+#define        EIRQ1   25
+#define        EIRQ7   31
+
+/*
+ * In the early version 2 core ColdFire parts the IMR register was 16 bits
+ * in size. Version 3 (and later version 2) core parts have a 32 bit
+ * sized IMR register. Provide some size independant methods to access the
+ * IMR register.
+ */
+#ifdef MCFSIM_IMR_IS_16BITS
+
+void mcf_setimr(int index)
+{
+       u16 imr;
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+       u16 imr;
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+       u16 imr;
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       imr |= mask;
+       __raw_writew(imr, MCF_MBAR + MCFSIM_IMR);
+}
+
+#else
+
+void mcf_setimr(int index)
+{
+       u32 imr;
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_clrimr(int index)
+{
+       u32 imr;
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
+}
+
+void mcf_maskimr(unsigned int mask)
+{
+       u32 imr;
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       imr |= mask;
+       __raw_writel(imr, MCF_MBAR + MCFSIM_IMR);
+}
+
+#endif
+
+/*
+ * Interrupts can be "vectored" on the ColdFire cores that support this old
+ * interrupt controller. That is, the device raising the interrupt can also
+ * supply the vector number to interrupt through. The AVR register of the
+ * interrupt controller enables or disables this for each external interrupt,
+ * so provide generic support for this. Setting this up is out-of-band for
+ * the interrupt system API's, and needs to be done by the driver that
+ * supports this device. Very few devices actually use this.
+ */
+void mcf_autovector(int irq)
+{
+#ifdef MCFSIM_AVR
+       if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
+               u8 avec;
+               avec = __raw_readb(MCF_MBAR + MCFSIM_AVR);
+               avec |= (0x1 << (irq - EIRQ1 + 1));
+               __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR);
+       }
+#endif
+}
+
+static void intc_irq_mask(struct irq_data *d)
+{
+       if (mcf_irq2imr[d->irq])
+               mcf_setimr(mcf_irq2imr[d->irq]);
+}
+
+static void intc_irq_unmask(struct irq_data *d)
+{
+       if (mcf_irq2imr[d->irq])
+               mcf_clrimr(mcf_irq2imr[d->irq]);
+}
+
+static int intc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       return 0;
+}
+
+static struct irq_chip intc_irq_chip = {
+       .name           = "CF-INTC",
+       .irq_mask       = intc_irq_mask,
+       .irq_unmask     = intc_irq_unmask,
+       .irq_set_type   = intc_irq_set_type,
+};
+
+void __init init_IRQ(void)
+{
+       int irq;
+
+       init_vectors();
+       mcf_maskimr(0xffffffff);
+
+       for (irq = 0; (irq < NR_IRQS); irq++) {
+               set_irq_chip(irq, &intc_irq_chip);
+               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+               set_irq_handler(irq, handle_level_irq);
+       }
+}
+
diff --git a/arch/m68k/platform/coldfire/pinmux.c b/arch/m68k/platform/coldfire/pinmux.c
new file mode 100644 (file)
index 0000000..8c62b82
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Coldfire generic GPIO pinmux support.
+ *
+ * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/pinmux.h>
+
+int mcf_pinmux_request(unsigned pinmux, unsigned func)
+{
+       return 0;
+}
+
+void mcf_pinmux_release(unsigned pinmux, unsigned func)
+{
+}
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c
new file mode 100644 (file)
index 0000000..c2b9809
--- /dev/null
@@ -0,0 +1,169 @@
+/***************************************************************************/
+
+/*
+ *     pit.c -- Freescale ColdFire PIT timer. Currently this type of
+ *              hardware timer only exists in the Freescale ColdFire
+ *              5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
+ *              family members will probably use it too.
+ *
+ *     Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     By default use timer1 as the system clock timer.
+ */
+#define        FREQ    ((MCF_CLK / 2) / 64)
+#define        TA(a)   (MCFPIT_BASE1 + (a))
+#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
+
+static u32 pit_cnt;
+
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+
+static void init_cf_pit_timer(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
+               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
+                               MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+
+               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
+                               TA(MCFPIT_PCSR));
+               break;
+
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
+       }
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int cf_pit_next_event(unsigned long delta,
+               struct clock_event_device *evt)
+{
+       __raw_writew(delta, TA(MCFPIT_PMR));
+       return 0;
+}
+
+struct clock_event_device cf_pit_clockevent = {
+       .name           = "pit",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = init_cf_pit_timer,
+       .set_next_event = cf_pit_next_event,
+       .shift          = 32,
+       .irq            = MCFINT_VECBASE + MCFINT_PIT1,
+};
+
+
+
+/***************************************************************************/
+
+static irqreturn_t pit_tick(int irq, void *dummy)
+{
+       struct clock_event_device *evt = &cf_pit_clockevent;
+       u16 pcsr;
+
+       /* Reset the ColdFire timer */
+       pcsr = __raw_readw(TA(MCFPIT_PCSR));
+       __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
+
+       pit_cnt += PIT_CYCLES_PER_JIFFY;
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+/***************************************************************************/
+
+static struct irqaction pit_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = pit_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t pit_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 pcntr;
+
+       local_irq_save(flags);
+       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+       cycles = pit_cnt;
+       local_irq_restore(flags);
+
+       return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
+}
+
+/***************************************************************************/
+
+static struct clocksource pit_clk = {
+       .name   = "pit",
+       .rating = 100,
+       .read   = pit_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+};
+
+/***************************************************************************/
+
+void hw_timer_init(void)
+{
+       cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
+       cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
+       cf_pit_clockevent.max_delta_ns =
+               clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
+       cf_pit_clockevent.min_delta_ns =
+               clockevent_delta2ns(0x3f, &cf_pit_clockevent);
+       clockevents_register_device(&cf_pit_clockevent);
+
+       setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
+
+       pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
+       clocksource_register(&pit_clk);
+}
+
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c
new file mode 100644 (file)
index 0000000..0a1b937
--- /dev/null
@@ -0,0 +1,145 @@
+/***************************************************************************/
+
+/*
+ *     sltimers.c -- generic ColdFire slice timer support.
+ *
+ *     Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ *     based on
+ *     timers.c -- generic ColdFire hardware timer support.
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ *     By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define        PA(a)   (MCF_MBAR + MCFSLT_TIMER1 + (a))
+
+/*
+ *     Choose a reasonably fast profile timer. Make it an odd value to
+ *     try and get good coverage of kernel operations.
+ */
+#define        PROFILEHZ       1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 1 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+       .name    = "profile timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+       printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+              PROFILEHZ);
+
+       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+       /* Set up TIMER 2 as high speed profile clock */
+       __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               PA(MCFSLT_SCR));
+
+}
+
+#endif /* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ *     By default use Slice Timer 0 as the system clock timer.
+ */
+#define        TA(a)   (MCF_MBAR + MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+       /* Reset Slice Timer 0 */
+       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+       mcfslt_cnt += mcfslt_cycles_per_jiffy;
+       return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 scnt;
+
+       local_irq_save(flags);
+       scnt = __raw_readl(TA(MCFSLT_SCNT));
+       cycles = mcfslt_cnt;
+       local_irq_restore(flags);
+
+       /* substract because slice timers count down */
+       return cycles - scnt;
+}
+
+static struct clocksource mcfslt_clk = {
+       .name   = "slt",
+       .rating = 250,
+       .read   = mcfslt_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(void)
+{
+       mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+       /*
+        *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
+        *      then STCNT again and so on.  It counts thus actually
+        *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
+        *      n cycles, initialize STCNT with n - 1.
+        */
+       __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+                                                               TA(MCFSLT_SCR));
+       /* initialize mcfslt_cnt knowing that slice timers count down */
+       mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+       mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
+       clocksource_register(&mcfslt_clk);
+
+#ifdef CONFIG_HIGHPROFILE
+       mcfslt_profile_init();
+#endif
+}
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c
new file mode 100644 (file)
index 0000000..60242f6
--- /dev/null
@@ -0,0 +1,174 @@
+/***************************************************************************/
+
+/*
+ *     timers.c -- generic ColdFire hardware timer support.
+ *
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcftimer.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ *     By default use timer1 as the system clock timer.
+ */
+#define        FREQ    (MCF_BUSCLK / 16)
+#define        TA(a)   (MCFTIMER_BASE1 + (a))
+
+/*
+ *     These provide the underlying interrupt vector support.
+ *     Unfortunately it is a little different on each ColdFire.
+ */
+void coldfire_profile_init(void);
+
+#if defined(CONFIG_M532x)
+#define        __raw_readtrr   __raw_readl
+#define        __raw_writetrr  __raw_writel
+#else
+#define        __raw_readtrr   __raw_readw
+#define        __raw_writetrr  __raw_writew
+#endif
+
+static u32 mcftmr_cycles_per_jiffy;
+static u32 mcftmr_cnt;
+
+/***************************************************************************/
+
+static irqreturn_t mcftmr_tick(int irq, void *dummy)
+{
+       /* Reset the ColdFire timer */
+       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
+
+       mcftmr_cnt += mcftmr_cycles_per_jiffy;
+       return arch_timer_interrupt(irq, dummy);
+}
+
+/***************************************************************************/
+
+static struct irqaction mcftmr_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = mcftmr_tick,
+};
+
+/***************************************************************************/
+
+static cycle_t mcftmr_read_clk(struct clocksource *cs)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 tcn;
+
+       local_irq_save(flags);
+       tcn = __raw_readw(TA(MCFTIMER_TCN));
+       cycles = mcftmr_cnt;
+       local_irq_restore(flags);
+
+       return cycles + tcn;
+}
+
+/***************************************************************************/
+
+static struct clocksource mcftmr_clk = {
+       .name   = "tmr",
+       .rating = 250,
+       .read   = mcftmr_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
+
+void hw_timer_init(void)
+{
+       __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
+       mcftmr_cycles_per_jiffy = FREQ / HZ;
+       /*
+        *      The coldfire timer runs from 0 to TRR included, then 0
+        *      again and so on.  It counts thus actually TRR + 1 steps
+        *      for 1 tick, not TRR.  So if you want n cycles,
+        *      initialize TRR with n - 1.
+        */
+       __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
+       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
+
+       mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);
+       clocksource_register(&mcftmr_clk);
+
+       setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
+
+#ifdef CONFIG_HIGHPROFILE
+       coldfire_profile_init();
+#endif
+}
+
+/***************************************************************************/
+#ifdef CONFIG_HIGHPROFILE
+/***************************************************************************/
+
+/*
+ *     By default use timer2 as the profiler clock timer.
+ */
+#define        PA(a)   (MCFTIMER_BASE2 + (a))
+
+/*
+ *     Choose a reasonably fast profile timer. Make it an odd value to
+ *     try and get good coverage of kernel operations.
+ */
+#define        PROFILEHZ       1013
+
+/*
+ *     Use the other timer to provide high accuracy profiling info.
+ */
+irqreturn_t coldfire_profile_tick(int irq, void *dummy)
+{
+       /* Reset ColdFire timer2 */
+       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
+       if (current->pid)
+               profile_tick(CPU_PROFILING);
+       return IRQ_HANDLED;
+}
+
+/***************************************************************************/
+
+static struct irqaction coldfire_profile_irq = {
+       .name    = "profile timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = coldfire_profile_tick,
+};
+
+void coldfire_profile_init(void)
+{
+       printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
+              PROFILEHZ);
+
+       /* Set up TIMER 2 as high speed profile clock */
+       __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
+
+       __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
+       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
+               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
+
+       setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
+}
+
+/***************************************************************************/
+#endif /* CONFIG_HIGHPROFILE */
+/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c
new file mode 100644 (file)
index 0000000..a21d3f8
--- /dev/null
@@ -0,0 +1,80 @@
+/***************************************************************************/
+
+/*
+ *     linux/arch/m68knommu/platform/coldfire/vectors.c
+ *
+ *     Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfwdebug.h>
+
+/***************************************************************************/
+
+#ifdef TRAP_DBG_INTERRUPT
+
+asmlinkage void dbginterrupt_c(struct frame *fp)
+{
+       extern void dump(struct pt_regs *fp);
+       printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
+       dump((struct pt_regs *) fp);
+       asm("halt");
+}
+
+#endif
+
+/***************************************************************************/
+
+extern e_vector        *_ramvec;
+
+void set_evector(int vecnum, void (*handler)(void))
+{
+       if (vecnum >= 0 && vecnum <= 255)
+               _ramvec[vecnum] = handler;
+}
+
+/***************************************************************************/
+
+/* Assembler routines */
+asmlinkage void buserr(void);
+asmlinkage void trap(void);
+asmlinkage void system_call(void);
+asmlinkage void inthandler(void);
+
+void __init init_vectors(void)
+{
+       int i;
+
+       /*
+        *      There is a common trap handler and common interrupt
+        *      handler that handle almost every vector. We treat
+        *      the system call and bus error special, they get their
+        *      own first level handlers.
+        */
+       for (i = 3; (i <= 23); i++)
+               _ramvec[i] = trap;
+       for (i = 33; (i <= 63); i++)
+               _ramvec[i] = trap;
+       for (i = 24; (i <= 31); i++)
+               _ramvec[i] = inthandler;
+       for (i = 64; (i < 255); i++)
+               _ramvec[i] = inthandler;
+       _ramvec[255] = 0;
+
+       _ramvec[2] = buserr;
+       _ramvec[32] = system_call;
+
+#ifdef TRAP_DBG_INTERRUPT
+       _ramvec[12] = dbginterrupt;
+#endif
+}
+
+/***************************************************************************/
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
deleted file mode 100644 (file)
index b5424cf..0000000
+++ /dev/null
@@ -1,844 +0,0 @@
-config M68K
-       bool
-       default y
-       select HAVE_IDE
-       select HAVE_GENERIC_HARDIRQS
-       select GENERIC_HARDIRQS_NO_DEPRECATED
-
-config MMU
-       bool
-       default n
-
-config NO_DMA
-       bool
-       depends on !COLDFIRE
-       default y
-
-config FPU
-       bool
-       default n
-
-config ZONE_DMA
-       bool
-       default y
-
-config RWSEM_GENERIC_SPINLOCK
-       bool
-       default y
-
-config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default n
-
-config ARCH_HAS_ILOG2_U32
-       bool
-       default n
-
-config ARCH_HAS_ILOG2_U64
-       bool
-       default n
-
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_GPIO
-       bool
-       default n
-
-config GENERIC_HWEIGHT
-       bool
-       default y
-
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
-config GENERIC_CMOS_UPDATE
-       bool
-       default y
-
-config TIME_LOW_RES
-       bool
-       default y
-
-config GENERIC_CLOCKEVENTS
-       bool
-       default n
-
-config NO_IOPORT
-       def_bool y
-
-config COLDFIRE_SW_A7
-       bool
-       default n
-
-config HAVE_CACHE_SPLIT
-       bool
-
-config HAVE_CACHE_CB
-       bool
-
-config HAVE_MBAR
-       bool
-
-config HAVE_IPSBAR
-       bool
-
-source "init/Kconfig"
-
-source "kernel/Kconfig.freezer"
-
-menu "Processor type and features"
-
-choice
-       prompt "CPU"
-       default M68EZ328
-
-config M68328
-       bool "MC68328"
-       help
-         Motorola 68328 processor support.
-
-config M68EZ328
-       bool "MC68EZ328"
-       help
-         Motorola 68EX328 processor support.
-
-config M68VZ328
-       bool "MC68VZ328"
-       help
-         Motorola 68VZ328 processor support.
-
-config M68360
-       bool "MC68360"
-       help
-         Motorola 68360 processor support.
-
-config M5206
-       bool "MCF5206"
-       select COLDFIRE_SW_A7
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5206 processor support.
-
-config M5206e
-       bool "MCF5206e"
-       select COLDFIRE_SW_A7
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5206e processor support.
-
-config M520x
-       bool "MCF520x"
-       select GENERIC_CLOCKEVENTS
-       select HAVE_CACHE_SPLIT
-       help
-          Freescale Coldfire 5207/5208 processor support.
-
-config M523x
-       bool "MCF523x"
-       select GENERIC_CLOCKEVENTS
-       select HAVE_CACHE_SPLIT
-       select HAVE_IPSBAR
-       help
-         Freescale Coldfire 5230/1/2/4/5 processor support
-
-config M5249
-       bool "MCF5249"
-       select COLDFIRE_SW_A7
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5249 processor support.
-
-config M5271
-       bool "MCF5271"
-       select HAVE_CACHE_SPLIT
-       select HAVE_IPSBAR
-       help
-         Freescale (Motorola) ColdFire 5270/5271 processor support.
-
-config M5272
-       bool "MCF5272"
-       select COLDFIRE_SW_A7
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5272 processor support.
-
-config M5275
-       bool "MCF5275"
-       select HAVE_CACHE_SPLIT
-       select HAVE_IPSBAR
-       help
-         Freescale (Motorola) ColdFire 5274/5275 processor support.
-
-config M528x
-       bool "MCF528x"
-       select GENERIC_CLOCKEVENTS
-       select HAVE_CACHE_SPLIT
-       select HAVE_IPSBAR
-       help
-         Motorola ColdFire 5280/5282 processor support.
-
-config M5307
-       bool "MCF5307"
-       select COLDFIRE_SW_A7
-       select HAVE_CACHE_CB
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5307 processor support.
-
-config M532x
-       bool "MCF532x"
-       select HAVE_CACHE_CB
-       help
-         Freescale (Motorola) ColdFire 532x processor support.
-
-config M5407
-       bool "MCF5407"
-       select COLDFIRE_SW_A7
-       select HAVE_CACHE_CB
-       select HAVE_MBAR
-       help
-         Motorola ColdFire 5407 processor support.
-
-config M547x
-       bool "MCF547x"
-       select HAVE_CACHE_CB
-       select HAVE_MBAR
-       help
-         Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support.
-
-config M548x
-       bool "MCF548x"
-       select HAVE_CACHE_CB
-       select HAVE_MBAR
-       help
-         Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
-
-endchoice
-
-config M527x
-       bool
-       depends on (M5271 || M5275)
-       select GENERIC_CLOCKEVENTS
-       default y
-
-config M54xx
-       bool
-       depends on (M548x || M547x)
-       default y
-
-config COLDFIRE
-       bool
-       depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M54xx)
-       select GENERIC_GPIO
-       select ARCH_REQUIRE_GPIOLIB
-       default y
-
-config CLOCK_SET
-       bool "Enable setting the CPU clock frequency"
-       default n
-       help
-         On some CPU's you do not need to know what the core CPU clock
-         frequency is. On these you can disable clock setting. On some
-         traditional 68K parts, and on all ColdFire parts you need to set
-         the appropriate CPU clock frequency. On these devices many of the
-         onboard peripherals derive their timing from the master CPU clock
-         frequency.
-
-config CLOCK_FREQ
-       int "Set the core clock frequency"
-       default "66666666"
-       depends on CLOCK_SET
-       help
-         Define the CPU clock frequency in use. This is the core clock
-         frequency, it may or may not be the same as the external clock
-         crystal fitted to your board. Some processors have an internal
-         PLL and can have their frequency programmed at run time, others
-         use internal dividers. In general the kernel won't setup a PLL
-         if it is fitted (there are some exceptions). This value will be
-         specific to the exact CPU that you are using.
-
-config OLDMASK
-       bool "Old mask 5307 (1H55J) silicon"
-       depends on M5307
-       help
-         Build support for the older revision ColdFire 5307 silicon.
-         Specifically this is the 1H55J mask revision.
-
-if HAVE_CACHE_SPLIT
-choice
-       prompt "Split Cache Configuration"
-       default CACHE_I
-
-config CACHE_I
-       bool "Instruction"
-       help
-         Use all of the ColdFire CPU cache memory as an instruction cache.
-
-config CACHE_D
-       bool "Data"
-       help
-         Use all of the ColdFire CPU cache memory as a data cache.
-
-config CACHE_BOTH
-       bool "Both"
-       help
-         Split the ColdFire CPU cache, and use half as an instruction cache
-         and half as a data cache.
-endchoice
-endif
-
-if HAVE_CACHE_CB
-choice
-       prompt "Data cache mode"
-       default CACHE_WRITETHRU
-
-config CACHE_WRITETHRU
-       bool "Write-through"
-       help
-         The ColdFire CPU cache is set into Write-through mode.
-
-config CACHE_COPYBACK
-       bool "Copy-back"
-       help
-         The ColdFire CPU cache is set into Copy-back mode.
-endchoice
-endif
-
-comment "Platform"
-
-config PILOT3
-       bool "Pilot 1000/5000, PalmPilot Personal/Pro, or PalmIII support"
-       depends on M68328
-       help
-         Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII.
-
-config XCOPILOT_BUGS
-       bool "(X)Copilot support"
-       depends on PILOT3
-       help
-         Support the bugs of Xcopilot.
-
-config UC5272
-       bool 'Arcturus Networks uC5272 dimm board support'
-       depends on M5272
-       help
-         Support for the Arcturus Networks uC5272 dimm board.
-
-config UC5282
-       bool "Arcturus Networks uC5282 board support"
-       depends on M528x
-       help
-         Support for the Arcturus Networks uC5282 dimm board.
-
-config UCSIMM
-       bool "uCsimm module support"
-       depends on M68EZ328
-       help
-         Support for the Arcturus Networks uCsimm module.
-
-config UCDIMM
-       bool "uDsimm module support"
-       depends on M68VZ328
-       help
-         Support for the Arcturus Networks uDsimm module.
-
-config DRAGEN2
-       bool "DragenEngine II board support"
-       depends on M68VZ328
-       help
-         Support for the DragenEngine II board.
-
-config DIRECT_IO_ACCESS
-       bool "Allow user to access IO directly"
-       depends on (UCSIMM || UCDIMM || DRAGEN2)
-       help
-         Disable the CPU internal registers protection in user mode,
-         to allow a user application to read/write them.
-
-config INIT_LCD
-       bool "Initialize LCD"
-       depends on (UCSIMM || UCDIMM || DRAGEN2)
-       help
-         Initialize the LCD controller of the 68x328 processor.
-
-config MEMORY_RESERVE
-       int "Memory reservation (MiB)"
-       depends on (UCSIMM || UCDIMM)
-       help
-         Reserve certain memory regions on 68x328 based boards.
-
-config UCQUICC
-       bool "Lineo uCquicc board support"
-       depends on M68360
-       help
-         Support for the Lineo uCquicc board.
-
-config ARN5206
-       bool "Arnewsh 5206 board support"
-       depends on M5206
-       help
-         Support for the Arnewsh 5206 board.
-
-config M5206eC3
-       bool "Motorola M5206eC3 board support"
-       depends on M5206e
-       help
-         Support for the Motorola M5206eC3 board.
-
-config ELITE
-       bool "Motorola M5206eLITE board support"
-       depends on M5206e
-       help
-         Support for the Motorola M5206eLITE board.
-
-config M5208EVB
-       bool "Freescale M5208EVB board support"
-       depends on M520x
-       help
-         Support for the Freescale Coldfire M5208EVB.
-
-config M5235EVB
-       bool "Freescale M5235EVB support"
-       depends on M523x
-       help
-         Support for the Freescale M5235EVB board.
-
-config M5249C3
-       bool "Motorola M5249C3 board support"
-       depends on M5249
-       help
-         Support for the Motorola M5249C3 board.
-
-config M5271EVB
-       bool "Freescale (Motorola) M5271EVB board support"
-       depends on M5271
-       help
-         Support for the Freescale (Motorola) M5271EVB board.
-
-config M5275EVB
-       bool "Freescale (Motorola) M5275EVB board support"
-       depends on M5275
-       help
-         Support for the Freescale (Motorola) M5275EVB board.
-
-config M5272C3
-       bool "Motorola M5272C3 board support"
-       depends on M5272
-       help
-         Support for the Motorola M5272C3 board.
-
-config COBRA5272
-       bool "senTec COBRA5272 board support"
-       depends on M5272
-       help
-         Support for the senTec COBRA5272 board.
-
-config AVNET5282
-       bool "Avnet 5282 board support"
-       depends on M528x
-       help
-         Support for the Avnet 5282 board.  
-         
-config M5282EVB
-       bool "Motorola M5282EVB board support"
-       depends on M528x
-       help
-         Support for the Motorola M5282EVB board.
-
-config COBRA5282
-       bool "senTec COBRA5282 board support"
-       depends on M528x
-       help
-         Support for the senTec COBRA5282 board.
-         
-config SOM5282EM
-       bool "EMAC.Inc SOM5282EM board support"
-       depends on M528x
-       help
-         Support for the EMAC.Inc SOM5282EM module.  
-         
-config WILDFIRE
-       bool "Intec Automation Inc. WildFire board support"
-       depends on M528x
-       help
-         Support for the Intec Automation Inc. WildFire.
-         
-config WILDFIREMOD
-       bool "Intec Automation Inc. WildFire module support"
-       depends on M528x
-       help
-         Support for the Intec Automation Inc. WildFire module.
-
-config ARN5307
-       bool "Arnewsh 5307 board support"
-       depends on M5307
-       help
-         Support for the Arnewsh 5307 board.
-
-config M5307C3
-       bool "Motorola M5307C3 board support"
-       depends on M5307
-       help
-         Support for the Motorola M5307C3 board.
-
-config SECUREEDGEMP3
-       bool "SnapGear SecureEdge/MP3 platform support"
-       depends on M5307
-       help
-         Support for the SnapGear SecureEdge/MP3 platform.
-
-config M5329EVB
-       bool "Freescale (Motorola) M5329EVB board support"
-       depends on M532x
-       help
-         Support for the Freescale (Motorola) M5329EVB board.
-
-config COBRA5329
-       bool "senTec COBRA5329 board support"
-       depends on M532x
-       help
-         Support for the senTec COBRA5329 board.
-
-config M5407C3
-       bool "Motorola M5407C3 board support"
-       depends on M5407
-       help
-         Support for the Motorola M5407C3 board.
-
-config FIREBEE
-       bool "FireBee board support"
-       depends on M547x
-       help
-         Support for the FireBee ColdFire 5475 based board.
-
-config CLEOPATRA
-       bool "Feith CLEOPATRA board support"
-       depends on (M5307 || M5407)
-       help
-         Support for the Feith Cleopatra boards.
-
-config CANCam
-       bool "Feith CANCam board support"
-       depends on M5272
-       help
-         Support for the Feith CANCam board.
-
-config SCALES
-       bool "Feith SCALES board support"
-       depends on M5272
-       help
-         Support for the Feith SCALES board.
-
-config NETtel
-       bool "SecureEdge/NETtel board support"
-       depends on (M5206e || M5272 || M5307)
-       help
-         Support for the SnapGear NETtel/SecureEdge/SnapGear boards.
-
-config SNAPGEAR
-       bool "SnapGear router board support"
-       depends on NETtel
-       help
-         Special additional support for SnapGear router boards.
-
-config CPU16B
-       bool "Sneha Technologies S.L. Sarasvati board support"
-       depends on M5272
-       help
-         Support for the SNEHA CPU16B board.
-
-config MOD5272
-       bool "Netburner MOD-5272 board support"
-       depends on M5272
-       help
-         Support for the Netburner MOD-5272 board.
-
-config SAVANTrosie1
-       bool "Savant Rosie1 board support"
-       depends on M523x
-       help
-         Support for the Savant Rosie1 board.
-
-config ROMFS_FROM_ROM
-       bool "ROMFS image not RAM resident"
-       depends on (NETtel || SNAPGEAR)
-       help
-         The ROMfs filesystem will stay resident in the FLASH/ROM, not be
-         moved into RAM.
-
-config PILOT
-       bool
-       default y
-       depends on (PILOT3 || PILOT5)
-
-config ARNEWSH
-       bool
-       default y
-       depends on (ARN5206 || ARN5307)
-
-config FREESCALE
-       bool
-       default y
-       depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5329EVB || M5407C3)
-
-config HW_FEITH
-       bool
-       default y
-       depends on (CLEOPATRA || CANCam || SCALES)
-
-config senTec
-       bool
-       default y
-       depends on (COBRA5272 || COBRA5282)
-       
-config EMAC_INC
-       bool
-       default y
-       depends on (SOM5282EM)
-
-config SNEHA
-       bool
-       default y
-       depends on CPU16B
-
-config SAVANT
-       bool
-       default y
-       depends on SAVANTrosie1
-
-config AVNET
-       bool
-       default y
-       depends on (AVNET5282)
-
-config UBOOT
-       bool "Support for U-Boot command line parameters"
-       help
-         If you say Y here kernel will try to collect command
-         line parameters from the initial u-boot stack.
-       default n
-
-config 4KSTACKS
-       bool "Use 4Kb for kernel stacks instead of 8Kb"
-       default y
-       help
-         If you say Y here the kernel will use a 4Kb stacksize for the
-         kernel stack attached to each process/thread. This facilitates
-         running more threads on a system and also reduces the pressure
-         on the VM subsystem for higher order allocations.
-
-config HZ
-       int
-       default 1000 if CLEOPATRA
-       default 100
-
-comment "RAM configuration"
-
-config RAMBASE
-       hex "Address of the base of RAM"
-       default "0"
-       help
-         Define the address that RAM starts at. On many platforms this is
-         0, the base of the address space. And this is the default. Some
-         platforms choose to setup their RAM at other addresses within the
-         processor address space.
-
-config RAMSIZE
-       hex "Size of RAM (in bytes), or 0 for automatic"
-       default "0x400000"
-       help
-         Define the size of the system RAM. If you select 0 then the
-         kernel will try to probe the RAM size at runtime. This is not
-         supported on all CPU types.
-
-config VECTORBASE
-       hex "Address of the base of system vectors"
-       default "0"
-       help
-         Define the address of the system vectors. Commonly this is
-         put at the start of RAM, but it doesn't have to be. On ColdFire
-         platforms this address is programmed into the VBR register, thus
-         actually setting the address to use.
-
-config MBAR
-       hex "Address of the MBAR (internal peripherals)"
-       default "0x10000000"
-       depends on HAVE_MBAR
-       help
-         Define the address of the internal system peripherals. This value
-         is set in the processors MBAR register. This is generally setup by
-         the boot loader, and will not be written by the kernel. By far most
-         ColdFire boards use the default 0x10000000 value, so if unsure then
-         use this.
-
-config IPSBAR
-       hex "Address of the IPSBAR (internal peripherals)"
-       default "0x40000000"
-       depends on HAVE_IPSBAR
-       help
-         Define the address of the internal system peripherals. This value
-         is set in the processors IPSBAR register. This is generally setup by
-         the boot loader, and will not be written by the kernel. By far most
-         ColdFire boards use the default 0x40000000 value, so if unsure then
-         use this.
-
-config KERNELBASE
-       hex "Address of the base of kernel code"
-       default "0x400"
-       help
-         Typically on m68k systems the kernel will not start at the base
-         of RAM, but usually some small offset from it. Define the start
-         address of the kernel here. The most common setup will have the
-         processor vectors at the base of RAM and then the start of the
-         kernel. On some platforms some RAM is reserved for boot loaders
-         and the kernel starts after that. The 0x400 default was based on
-         a system with the RAM based at address 0, and leaving enough room
-         for the theoretical maximum number of 256 vectors.
-
-choice
-       prompt "RAM bus width"
-       default RAMAUTOBIT
-
-config RAMAUTOBIT
-       bool "AUTO"
-       help
-         Select the physical RAM data bus size. Not needed on most platforms,
-         so you can generally choose AUTO.
-
-config RAM8BIT
-       bool "8bit"
-       help
-         Configure RAM bus to be 8 bits wide.
-
-config RAM16BIT
-       bool "16bit"
-       help
-         Configure RAM bus to be 16 bits wide.
-
-config RAM32BIT
-       bool "32bit"
-       help
-         Configure RAM bus to be 32 bits wide.
-
-endchoice
-
-comment "ROM configuration"
-
-config ROM
-       bool "Specify ROM linker regions"
-       default n
-       help
-         Define a ROM region for the linker script. This creates a kernel
-         that can be stored in flash, with possibly the text, and data
-         regions being copied out to RAM at startup.
-
-config ROMBASE
-       hex "Address of the base of ROM device"
-       default "0"
-       depends on ROM
-       help
-         Define the address that the ROM region starts at. Some platforms
-         use this to set their chip select region accordingly for the boot
-         device.
-
-config ROMVEC
-       hex "Address of the base of the ROM vectors"
-       default "0"
-       depends on ROM
-       help
-         This is almost always the same as the base of the ROM. Since on all
-         68000 type variants the vectors are at the base of the boot device
-         on system startup.
-
-config ROMVECSIZE
-       hex "Size of ROM vector region (in bytes)"
-       default "0x400"
-       depends on ROM
-       help
-         Define the size of the vector region in ROM. For most 68000
-         variants this would be 0x400 bytes in size. Set to 0 if you do
-         not want a vector region at the start of the ROM.
-
-config ROMSTART
-       hex "Address of the base of system image in ROM"
-       default "0x400"
-       depends on ROM
-       help
-         Define the start address of the system image in ROM. Commonly this
-         is strait after the ROM vectors.
-
-config ROMSIZE
-       hex "Size of the ROM device"
-       default "0x100000"
-       depends on ROM
-       help
-         Size of the ROM device. On some platforms this is used to setup
-         the chip select that controls the boot ROM device.
-
-choice
-       prompt "Kernel executes from"
-       ---help---
-         Choose the memory type that the kernel will be running in.
-
-config RAMKERNEL
-       bool "RAM"
-       help
-         The kernel will be resident in RAM when running.
-
-config ROMKERNEL
-       bool "ROM"
-       help
-         The kernel will be resident in FLASH/ROM when running. This is
-         often referred to as Execute-in-Place (XIP), since the kernel
-         code executes from the position it is stored in the FLASH/ROM.
-
-endchoice
-
-if COLDFIRE
-source "kernel/Kconfig.preempt"
-endif
-
-source "kernel/time/Kconfig"
-
-source "mm/Kconfig"
-
-endmenu
-
-config ISA_DMA_API
-       bool
-       depends on !M5272
-       default y
-
-source "drivers/pcmcia/Kconfig"
-
-menu "Executable file formats"
-
-source "fs/Kconfig.binfmt"
-
-endmenu
-
-menu "Power management options"
-
-config PM
-       bool "Power Management support"
-       help
-         Support processor power management modes
-
-endmenu
-
-source "net/Kconfig"
-
-source "drivers/Kconfig"
-
-source "fs/Kconfig"
-
-source "arch/m68knommu/Kconfig.debug"
-
-source "security/Kconfig"
-
-source "crypto/Kconfig"
-
-source "lib/Kconfig"
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug
deleted file mode 100644 (file)
index ed6d9a8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-menu "Kernel hacking"
-
-source "lib/Kconfig.debug"
-
-config FULLDEBUG
-       bool "Full Symbolic/Source Debugging support"
-       help
-         Enable debugging symbols on kernel build.
-
-config HIGHPROFILE
-       bool "Use fast second timer for profiling"
-       depends on COLDFIRE
-       help
-         Use a fast secondary clock to produce profiling information.
-
-config BOOTPARAM
-       bool 'Compiled-in Kernel Boot Parameter'
-
-config BOOTPARAM_STRING
-       string 'Kernel Boot Parameter'
-       default 'console=ttyS0,19200'
-       depends on BOOTPARAM
-
-config NO_KERNEL_MSG
-       bool "Suppress Kernel BUG Messages"
-       help
-         Do not output any debug BUG messages within the kernel.
-
-config BDM_DISABLE
-       bool "Disable BDM signals"
-       depends on (EXPERIMENTAL && COLDFIRE)
-       help
-         Disable the ColdFire CPU's BDM signals.
-
-endmenu
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
deleted file mode 100644 (file)
index 589613f..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#
-# arch/m68knommu/Makefile
-#
-# 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.
-#
-# (C) Copyright 2002, Greg Ungerer <gerg@snapgear.com>
-#
-
-KBUILD_DEFCONFIG := m5208evb_defconfig
-
-platform-$(CONFIG_M68328)      := 68328
-platform-$(CONFIG_M68EZ328)    := 68EZ328
-platform-$(CONFIG_M68VZ328)    := 68VZ328
-platform-$(CONFIG_M68360)      := 68360
-platform-$(CONFIG_M5206)       := 5206
-platform-$(CONFIG_M5206e)      := 5206e
-platform-$(CONFIG_M520x)       := 520x
-platform-$(CONFIG_M523x)       := 523x
-platform-$(CONFIG_M5249)       := 5249
-platform-$(CONFIG_M527x)       := 527x
-platform-$(CONFIG_M5272)       := 5272
-platform-$(CONFIG_M528x)       := 528x
-platform-$(CONFIG_M5307)       := 5307
-platform-$(CONFIG_M532x)       := 532x
-platform-$(CONFIG_M5407)       := 5407
-platform-$(CONFIG_M54xx)       := 54xx
-PLATFORM := $(platform-y)
-
-board-$(CONFIG_PILOT)          := pilot
-board-$(CONFIG_UC5272)          := UC5272
-board-$(CONFIG_UC5282)          := UC5282
-board-$(CONFIG_UCSIMM)         := ucsimm
-board-$(CONFIG_UCDIMM)         := ucdimm
-board-$(CONFIG_UCQUICC)                := uCquicc
-board-$(CONFIG_DRAGEN2)                := de2
-board-$(CONFIG_ARNEWSH)                := ARNEWSH
-board-$(CONFIG_FREESCALE)      := FREESCALE
-board-$(CONFIG_M5235EVB)       := M5235EVB
-board-$(CONFIG_M5271EVB)       := M5271EVB
-board-$(CONFIG_M5275EVB)       := M5275EVB
-board-$(CONFIG_M5282EVB)       := M5282EVB
-board-$(CONFIG_ELITE)          := eLITE
-board-$(CONFIG_NETtel)         := NETtel
-board-$(CONFIG_SECUREEDGEMP3)  := MP3
-board-$(CONFIG_CLEOPATRA)      := CLEOPATRA
-board-$(CONFIG_senTec)         := senTec
-board-$(CONFIG_SNEHA)          := SNEHA
-board-$(CONFIG_M5208EVB)       := M5208EVB
-board-$(CONFIG_MOD5272)                := MOD5272
-board-$(CONFIG_AVNET)           := AVNET
-board-$(CONFIG_SAVANT)         := SAVANT
-BOARD := $(board-y)
-
-model-$(CONFIG_RAMKERNEL)      := ram
-model-$(CONFIG_ROMKERNEL)      := rom
-MODEL := $(model-y)
-
-#
-# Some code support is grouped together for a common cpu-subclass (for
-# example all ColdFire cpu's are very similar). Determine the sub-class
-# for the selected cpu. ONLY need to define this for the non-base member
-# of the family.
-#
-cpuclass-$(CONFIG_M5206)       := coldfire
-cpuclass-$(CONFIG_M5206e)      := coldfire
-cpuclass-$(CONFIG_M520x)       := coldfire
-cpuclass-$(CONFIG_M523x)       := coldfire
-cpuclass-$(CONFIG_M5249)       := coldfire
-cpuclass-$(CONFIG_M527x)       := coldfire
-cpuclass-$(CONFIG_M5272)       := coldfire
-cpuclass-$(CONFIG_M528x)       := coldfire
-cpuclass-$(CONFIG_M5307)       := coldfire
-cpuclass-$(CONFIG_M532x)       := coldfire
-cpuclass-$(CONFIG_M5407)       := coldfire
-cpuclass-$(CONFIG_M54xx)       := coldfire
-cpuclass-$(CONFIG_M68328)      := 68328
-cpuclass-$(CONFIG_M68EZ328)    := 68328
-cpuclass-$(CONFIG_M68VZ328)    := 68328
-cpuclass-$(CONFIG_M68360)      := 68360
-CPUCLASS := $(cpuclass-y)
-
-ifneq ($(CPUCLASS),$(PLATFORM))
-CLASSDIR := arch/m68knommu/platform/$(cpuclass-y)/
-endif
-
-export PLATFORM BOARD MODEL CPUCLASS
-
-#
-# Some CFLAG additions based on specific CPU type.
-#
-cflags-$(CONFIG_M5206)         := $(call cc-option,-mcpu=5206,-m5200)
-cflags-$(CONFIG_M5206e)                := $(call cc-option,-mcpu=5206e,-m5200)
-cflags-$(CONFIG_M520x)         := $(call cc-option,-mcpu=5208,-m5200)
-cflags-$(CONFIG_M523x)         := $(call cc-option,-mcpu=523x,-m5307)
-cflags-$(CONFIG_M5249)         := $(call cc-option,-mcpu=5249,-m5200)
-cflags-$(CONFIG_M5271)         := $(call cc-option,-mcpu=5271,-m5307)
-cflags-$(CONFIG_M5272)         := $(call cc-option,-mcpu=5272,-m5307)
-cflags-$(CONFIG_M5275)         := $(call cc-option,-mcpu=5275,-m5307)
-cflags-$(CONFIG_M528x)         := $(call cc-option,-mcpu=528x,-m5307)
-cflags-$(CONFIG_M5307)         := $(call cc-option,-mcpu=5307,-m5200)
-cflags-$(CONFIG_M532x)         := $(call cc-option,-mcpu=532x,-m5307)
-cflags-$(CONFIG_M5407)         := $(call cc-option,-mcpu=5407,-m5200)
-cflags-$(CONFIG_M54xx)         := $(call cc-option,-mcpu=5475,-m5200)
-cflags-$(CONFIG_M68328)                := -m68000
-cflags-$(CONFIG_M68EZ328)      := -m68000
-cflags-$(CONFIG_M68VZ328)      := -m68000
-cflags-$(CONFIG_M68360)                := -m68332
-
-KBUILD_AFLAGS += $(cflags-y)
-
-KBUILD_CFLAGS += $(cflags-y)
-KBUILD_CFLAGS += -D__linux__
-KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
-
-head-y := arch/m68knommu/platform/$(cpuclass-y)/head.o
-
-core-y += arch/m68knommu/kernel/ \
-          arch/m68knommu/mm/ \
-          $(CLASSDIR) \
-          arch/m68knommu/platform/$(PLATFORM)/
-libs-y += arch/m68knommu/lib/
-
-archclean:
-
diff --git a/arch/m68knommu/configs/m5208evb_defconfig b/arch/m68knommu/configs/m5208evb_defconfig
deleted file mode 100644 (file)
index 2f5655c..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M520x=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=166666666
-CONFIG_CLOCK_DIV=2
-CONFIG_M5208EVB=y
-# CONFIG_4KSTACKS is not set
-CONFIG_RAMBASE=0x40000000
-CONFIG_RAMSIZE=0x2000000
-CONFIG_VECTORBASE=0x40000000
-CONFIG_KERNELBASE=0x40020000
-CONFIG_RAM16BIT=y
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FEC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_BAUDRATE=115200
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_SYSFS is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_FULLDEBUG=y
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68knommu/configs/m5249evb_defconfig b/arch/m68knommu/configs/m5249evb_defconfig
deleted file mode 100644 (file)
index 16df72b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M5249=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=140000000
-CONFIG_CLOCK_DIV=2
-CONFIG_M5249C3=y
-CONFIG_RAMBASE=0x00000000
-CONFIG_RAMSIZE=0x00800000
-CONFIG_VECTORBASE=0x00000000
-CONFIG_KERNELBASE=0x00020000
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
diff --git a/arch/m68knommu/configs/m5272c3_defconfig b/arch/m68knommu/configs/m5272c3_defconfig
deleted file mode 100644 (file)
index 4e6ea50..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M5272=y
-CONFIG_CLOCK_SET=y
-CONFIG_M5272C3=y
-CONFIG_RAMBASE=0x00000000
-CONFIG_RAMSIZE=0x00800000
-CONFIG_VECTORBASE=0x00000000
-CONFIG_KERNELBASE=0x00020000
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FEC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68knommu/configs/m5275evb_defconfig b/arch/m68knommu/configs/m5275evb_defconfig
deleted file mode 100644 (file)
index f3dd741..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M5275=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=150000000
-CONFIG_CLOCK_DIV=2
-CONFIG_M5275EVB=y
-# CONFIG_4KSTACKS is not set
-CONFIG_RAMBASE=0x00000000
-CONFIG_RAMSIZE=0x00000000
-CONFIG_VECTORBASE=0x00000000
-CONFIG_KERNELBASE=0x00020000
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FEC=y
-CONFIG_FEC2=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
diff --git a/arch/m68knommu/configs/m5307c3_defconfig b/arch/m68knommu/configs/m5307c3_defconfig
deleted file mode 100644 (file)
index bce0a20..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_SLUB_DEBUG is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M5307=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=90000000
-CONFIG_CLOCK_DIV=2
-CONFIG_M5307C3=y
-CONFIG_RAMBASE=0x00000000
-CONFIG_RAMSIZE=0x00800000
-CONFIG_VECTORBASE=0x00000000
-CONFIG_KERNELBASE=0x00020000
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_FULLDEBUG=y
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
diff --git a/arch/m68knommu/configs/m5407c3_defconfig b/arch/m68knommu/configs/m5407c3_defconfig
deleted file mode 100644 (file)
index 618cc32..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M5407=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=50000000
-CONFIG_M5407C3=y
-CONFIG_RAMBASE=0x00000000
-CONFIG_RAMSIZE=0x00000000
-CONFIG_VECTORBASE=0x00000000
-CONFIG_KERNELBASE=0x00020000
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-# CONFIG_INPUT is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
-# CONFIG_CRC32 is not set
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig
deleted file mode 100644 (file)
index 2f5655c..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_KALLSYMS is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_EVENTFD is not set
-# CONFIG_AIO is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_M520x=y
-CONFIG_CLOCK_SET=y
-CONFIG_CLOCK_FREQ=166666666
-CONFIG_CLOCK_DIV=2
-CONFIG_M5208EVB=y
-# CONFIG_4KSTACKS is not set
-CONFIG_RAMBASE=0x40000000
-CONFIG_RAMSIZE=0x2000000
-CONFIG_VECTORBASE=0x40000000
-CONFIG_KERNELBASE=0x40020000
-CONFIG_RAM16BIT=y
-CONFIG_BINFMT_FLAT=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=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 is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_UCLINUX=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FEC=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_MCF=y
-CONFIG_SERIAL_MCF_BAUDRATE=115200
-CONFIG_SERIAL_MCF_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_FILE_LOCKING is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_SYSFS is not set
-CONFIG_ROMFS_FS=y
-CONFIG_ROMFS_BACKED_BY_MTD=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_FULLDEBUG=y
-CONFIG_BOOTPARAM=y
-CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0"
diff --git a/arch/m68knommu/kernel/.gitignore b/arch/m68knommu/kernel/.gitignore
deleted file mode 100644 (file)
index c5f676c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-vmlinux.lds
diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile
deleted file mode 100644 (file)
index 37c3fc0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for arch/m68knommu/kernel.
-#
-
-extra-y := vmlinux.lds
-
-obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
-        setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
-
-obj-$(CONFIG_MODULES)  += module.o
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
deleted file mode 100644 (file)
index ffe02f4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/ptrace.h>
-#include <linux/hardirq.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/thread_info.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-
-#ifdef CONFIG_COLDFIRE
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
-#else
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-#endif
-
-       /* signal defines */
-       DEFINE(SIGSEGV, SIGSEGV);
-       DEFINE(SEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(SIGTRAP, SIGTRAP);
-       DEFINE(TRAP_TRACE, TRAP_TRACE);
-
-       DEFINE(PT_PTRACED, PT_PTRACED);
-
-       /* Offsets in thread_info structure */
-       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-
-       return 0;
-}
diff --git a/arch/m68knommu/kernel/dma.c b/arch/m68knommu/kernel/dma.c
deleted file mode 100644 (file)
index fc61541..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Dynamic DMA mapping support.
- *
- * We never have any address translations to worry about, so this
- * is just alloc/free.
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <asm/cacheflush.h>
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-                          dma_addr_t *dma_handle, gfp_t gfp)
-{
-       void *ret;
-       /* ignore region specifiers */
-       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
-       if (dev == NULL || (*dev->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_phys(ret);
-       }
-       return ret;
-}
-
-void dma_free_coherent(struct device *dev, size_t size,
-                        void *vaddr, dma_addr_t dma_handle)
-{
-       free_pages((unsigned long)vaddr, get_order(size));
-}
-
-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:
-               flush_dcache_range(handle, size);
-               break;
-       case DMA_FROM_DEVICE:
-               /* Should be clear already */
-               break;
-       default:
-               if (printk_ratelimit())
-                       printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
-               break;
-       }
-}
-
-EXPORT_SYMBOL(dma_sync_single_for_device);
-dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
-                         enum dma_data_direction dir)
-{
-       dma_addr_t handle = virt_to_phys(addr);
-       flush_dcache_range(handle, size);
-       return handle;
-}
-EXPORT_SYMBOL(dma_map_single);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                       unsigned long offset, size_t size,
-                       enum dma_data_direction dir)
-{
-       dma_addr_t handle = page_to_phys(page) + offset;
-       dma_sync_single_for_device(dev, handle, size, dir);
-       return handle;
-}
-EXPORT_SYMBOL(dma_map_page);
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S
deleted file mode 100644 (file)
index 2783f25..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/entry.S
- *
- *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * Based on:
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- * ColdFire support by Greg Ungerer (gerg@snapgear.com)
- * 5307 fixes by David W. Miller
- * linux 2.4 support David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-#include <asm/unistd.h>
-
-.text
-
-.globl buserr
-.globl trap
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_fork
-.globl sys_clone
-.globl sys_vfork
-
-ENTRY(buserr)
-       SAVE_ALL
-       moveq   #-1,%d0
-       movel   %d0,%sp@(PT_OFF_ORIG_D0)
-       movel   %sp,%sp@-               /* stack frame pointer argument */
-       jsr     buserr_c
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(trap)
-       SAVE_ALL
-       moveq   #-1,%d0
-       movel   %d0,%sp@(PT_OFF_ORIG_D0)
-       movel   %sp,%sp@-               /* stack frame pointer argument */
-       jsr     trap_c
-       addql   #4,%sp
-       jra     ret_from_exception
-
-#ifdef TRAP_DBG_INTERRUPT
-
-.globl dbginterrupt
-ENTRY(dbginterrupt)
-       SAVE_ALL
-       moveq   #-1,%d0
-       movel   %d0,%sp@(PT_OFF_ORIG_D0)
-       movel   %sp,%sp@-               /* stack frame pointer argument */
-       jsr     dbginterrupt_c
-       addql   #4,%sp
-       jra     ret_from_exception
-#endif
-
-ENTRY(reschedule)
-       /* save top of frame */
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
-       pea     ret_from_exception
-       jmp     schedule
-
-ENTRY(ret_from_fork)
-       movel   %d1,%sp@-
-       jsr     schedule_tail
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(sys_fork)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_fork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_vfork)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_vfork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_clone)
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_clone
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_sigreturn)
-       SAVE_SWITCH_STACK
-       jbsr    do_sigreturn
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(sys_rt_sigreturn)
-       SAVE_SWITCH_STACK
-       jbsr    do_rt_sigreturn
-       RESTORE_SWITCH_STACK
-       rts
-
-ENTRY(ret_from_user_signal)
-       moveq #__NR_sigreturn,%d0
-       trap #0
-
-ENTRY(ret_from_user_rt_signal)
-       movel #__NR_rt_sigreturn,%d0
-       trap #0
-
diff --git a/arch/m68knommu/kernel/init_task.c b/arch/m68knommu/kernel/init_task.c
deleted file mode 100644 (file)
index cbf9dc3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/init_task.c
- */
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/init_task.h>
-#include <linux/fs.h>
-#include <linux/mqueue.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-/*
- * Initial task structure.
- *
- * All other task structs will be allocated on slabs in fork.c
- */
-__asm__(".align 4");
-struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_task);
-
-/*
- * Initial thread structure.
- *
- * We need to make sure that this is 8192-byte aligned due to the
- * way process stacks are handled. This is done by having a special
- * "init_task" linker map entry..
- */
-union thread_union init_thread_union __init_task_data =
-       { INIT_THREAD_INFO(init_task) };
-
diff --git a/arch/m68knommu/kernel/irq.c b/arch/m68knommu/kernel/irq.c
deleted file mode 100644 (file)
index c7dd48f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * irq.c
- *
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/seq_file.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
-{
-       struct pt_regs *oldregs = set_irq_regs(regs);
-
-       irq_enter();
-       generic_handle_irq(irq);
-       irq_exit();
-
-       set_irq_regs(oldregs);
-}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       struct irqaction *ap;
-       int irq = *((loff_t *) v);
-
-       if (irq == 0)
-               seq_puts(p, "           CPU0\n");
-
-       if (irq < NR_IRQS) {
-               struct irq_desc *desc = irq_to_desc(irq);
-
-               ap = desc->action;
-               if (ap) {
-                       seq_printf(p, "%3d: ", irq);
-                       seq_printf(p, "%10u ", kstat_irqs(irq));
-                       seq_printf(p, "%14s  ", get_irq_desc_chip(desc)->name);
-
-                       seq_printf(p, "%s", ap->name);
-                       for (ap = ap->next; ap; ap = ap->next)
-                               seq_printf(p, ", %s", ap->name);
-                       seq_putc(p, '\n');
-               }
-       }
-
-       return 0;
-}
-
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c
deleted file mode 100644 (file)
index 39fe0a7..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <linux/module.h>
-#include <linux/linkage.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-
-#include <asm/setup.h>
-#include <asm/machdep.h>
-#include <asm/pgalloc.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/checksum.h>
-#include <asm/current.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(dump_fpu);
-
-EXPORT_SYMBOL(ip_fast_csum);
-
-EXPORT_SYMBOL(kernel_thread);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-
-/*
- * libgcc functions - functions that are used internally by the
- * compiler...  (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-extern void __ashrdi3(void);
-extern void __divsi3(void);
-extern void __lshrdi3(void);
-extern void __modsi3(void);
-extern void __muldi3(void);
-extern void __mulsi3(void);
-extern void __udivsi3(void);
-extern void __umodsi3(void);
-
-        /* gcc lib functions */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__divsi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__modsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__mulsi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__umodsi3);
-
-#ifdef CONFIG_COLDFIRE
-extern unsigned int *dma_device_address;
-extern unsigned long dma_base_addr, _ramend;
-EXPORT_SYMBOL(dma_base_addr);
-EXPORT_SYMBOL(dma_device_address);
-EXPORT_SYMBOL(_ramend);
-
-extern asmlinkage void trap(void);
-extern void    *_ramvec;
-EXPORT_SYMBOL(trap);
-EXPORT_SYMBOL(_ramvec);
-#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68knommu/kernel/module.c b/arch/m68knommu/kernel/module.c
deleted file mode 100644 (file)
index d11ffae..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <linux/moduleloader.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(fmt...)
-#endif
-
-void *module_alloc(unsigned long size)
-{
-       if (size == 0)
-               return NULL;
-       return vmalloc(size);
-}
-
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-}
-
-/* We don't need anything special. */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       return 0;
-}
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       unsigned int i;
-       Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       uint32_t *location;
-
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_68K_32:
-                       /* We add the value into the location given */
-                       *location += sym->st_value;
-                       break;
-               case R_68K_PC32:
-                       /* Add the value, subtract its postition */
-                       *location += sym->st_value - (uint32_t)location;
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-                              me->name, ELF32_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-}
-
-int apply_relocate_add(Elf32_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-       unsigned int i;
-       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
-       uint32_t *location;
-
-       DEBUGP("Applying relocate_add section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               /* This is where to make the change */
-               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
-
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
-               case R_68K_32:
-                       /* We add the value into the location given */
-                       *location = rel[i].r_addend + sym->st_value;
-                       break;
-               case R_68K_PC32:
-                       /* Add the value, subtract its postition */
-                       *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
-                       break;
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-                              me->name, ELF32_R_TYPE(rel[i].r_info));
-                       return -ENOEXEC;
-               }
-       }
-       return 0;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *me)
-{
-       return 0;
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-}
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
deleted file mode 100644 (file)
index e2a63af..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/process.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  68060 fixes by Jesper Skov
- *
- *  uClinux changes
- *  Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-
-asmlinkage void ret_from_fork(void);
-
-/*
- * The following aren't currently used.
- */
-void (*pm_idle)(void);
-EXPORT_SYMBOL(pm_idle);
-
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-/*
- * The idle loop on an m68knommu..
- */
-static void default_idle(void)
-{
-       local_irq_disable();
-       while (!need_resched()) {
-               /* This stop will re-enable interrupts */
-               __asm__("stop #0x2000" : : : "cc");
-               local_irq_disable();
-       }
-       local_irq_enable();
-}
-
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
-       /* endless idle loop with no priority at all */
-       while (1) {
-               idle();
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-       }
-}
-
-void machine_restart(char * __unused)
-{
-       if (mach_reset)
-               mach_reset();
-       for (;;);
-}
-
-void machine_halt(void)
-{
-       if (mach_halt)
-               mach_halt();
-       for (;;);
-}
-
-void machine_power_off(void)
-{
-       if (mach_power_off)
-               mach_power_off();
-       for (;;);
-}
-
-void show_regs(struct pt_regs * regs)
-{
-       printk(KERN_NOTICE "\n");
-       printk(KERN_NOTICE "Format %02x  Vector: %04x  PC: %08lx  Status: %04x    %s\n",
-              regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
-       printk(KERN_NOTICE "ORIG_D0: %08lx  D0: %08lx  A2: %08lx  A1: %08lx\n",
-              regs->orig_d0, regs->d0, regs->a2, regs->a1);
-       printk(KERN_NOTICE "A0: %08lx  D5: %08lx  D4: %08lx\n",
-              regs->a0, regs->d5, regs->d4);
-       printk(KERN_NOTICE "D3: %08lx  D2: %08lx  D1: %08lx\n",
-              regs->d3, regs->d2, regs->d1);
-       if (!(regs->sr & PS_S))
-               printk(KERN_NOTICE "USP: %08lx\n", rdusp());
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       int retval;
-       long clone_arg = flags | CLONE_VM;
-       mm_segment_t fs;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-
-       __asm__ __volatile__ (
-                       "movel  %%sp, %%d2\n\t"
-                       "movel  %5, %%d1\n\t"
-                       "movel  %1, %%d0\n\t"
-                       "trap   #0\n\t"
-                       "cmpl   %%sp, %%d2\n\t"
-                       "jeq    1f\n\t"
-                       "movel  %3, %%sp@-\n\t"
-                       "jsr    %4@\n\t"
-                       "movel  %2, %%d0\n\t"
-                       "trap   #0\n"
-                       "1:\n\t"
-                       "movel  %%d0, %0\n"
-               : "=d" (retval)
-               : "i" (__NR_clone),
-                 "i" (__NR_exit),
-                 "a" (arg),
-                 "a" (fn),
-                 "a" (clone_arg)
-               : "cc", "%d0", "%d1", "%d2");
-
-       set_fs(fs);
-       return retval;
-}
-
-void flush_thread(void)
-{
-#ifdef CONFIG_FPU
-       unsigned long zero = 0;
-#endif
-       set_fs(USER_DS);
-       current->thread.fs = __USER_DS;
-#ifdef CONFIG_FPU
-       if (!FPU_IS_EMU)
-               asm volatile (".chip 68k/68881\n\t"
-                             "frestore %0@\n\t"
-                             ".chip 68k" : : "a" (&zero));
-#endif
-}
-
-/*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-       /* fork almost works, enough to trick you into looking elsewhere :-( */
-       return(-EINVAL);
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int m68k_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-
-       /* syscall2 puts clone_flags in d1 and usp in d2 */
-       clone_flags = regs->d1;
-       newsp = regs->d2;
-       if (!newsp)
-               newsp = rdusp();
-        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
-}
-
-int copy_thread(unsigned long clone_flags,
-               unsigned long usp, unsigned long topstk,
-               struct task_struct * p, struct pt_regs * regs)
-{
-       struct pt_regs * childregs;
-       struct switch_stack * childstack, *stack;
-       unsigned long *retp;
-
-       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-
-       *childregs = *regs;
-       childregs->d0 = 0;
-
-       retp = ((unsigned long *) regs);
-       stack = ((struct switch_stack *) retp) - 1;
-
-       childstack = ((struct switch_stack *) childregs) - 1;
-       *childstack = *stack;
-       childstack->retpc = (unsigned long)ret_from_fork;
-
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childstack;
-
-       if (clone_flags & CLONE_SETTLS)
-               task_thread_info(p)->tp_value = regs->d5;
-
-       /*
-        * Must save the current SFC/DFC value, NOT the value when
-        * the parent was last descheduled - RGH  10-08-96
-        */
-       p->thread.fs = get_fs().seg;
-
-#ifdef CONFIG_FPU
-       if (!FPU_IS_EMU) {
-               /* Copy the current fpu state */
-               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-               if (p->thread.fpstate[0])
-                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
-                               : "memory");
-               /* Restore the state in case the fpu was busy */
-               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
-       }
-#endif
-
-       return 0;
-}
-
-/* Fill in the fpu structure for a core dump.  */
-
-int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
-{
-#ifdef CONFIG_FPU
-       char fpustate[216];
-
-       if (FPU_IS_EMU) {
-               int i;
-
-               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
-               memcpy(fpu->fpregs, current->thread.fp, 96);
-               /* Convert internal fpu reg representation
-                * into long double format
-                */
-               for (i = 0; i < 24; i += 3)
-                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
-                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
-               return 1;
-       }
-
-       /* First dump the fpu context to avoid protocol violation.  */
-       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-       if (!fpustate[0])
-               return 0;
-
-       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
-               :: "m" (fpu->fpcntl[0])
-               : "memory");
-       asm volatile ("fmovemx %/fp0-%/fp7,%0"
-               :: "m" (fpu->fpregs[0])
-               : "memory");
-#endif
-       return 1;
-}
-
-/*
- *     Generic dumping code. Used for panic and debug.
- */
-void dump(struct pt_regs *fp)
-{
-       unsigned long   *sp;
-       unsigned char   *tp;
-       int             i;
-
-       printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
-       printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
-
-       if (current->mm) {
-               printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
-                       (int) current->mm->start_code,
-                       (int) current->mm->end_code,
-                       (int) current->mm->start_data,
-                       (int) current->mm->end_data,
-                       (int) current->mm->end_data,
-                       (int) current->mm->brk);
-               printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
-                       (int) current->mm->start_stack,
-                       (int)(((unsigned long) current) + THREAD_SIZE));
-       }
-
-       printk(KERN_EMERG "PC: %08lx\n", fp->pc);
-       printk(KERN_EMERG "SR: %08lx    SP: %08lx\n", (long) fp->sr, (long) fp);
-       printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-               fp->d0, fp->d1, fp->d2, fp->d3);
-       printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-               fp->d4, fp->d5, fp->a0, fp->a1);
-       printk(KERN_EMERG "\nUSP: %08x   TRAPFRAME: %p\n",
-               (unsigned int) rdusp(), fp);
-
-       printk(KERN_EMERG "\nCODE:");
-       tp = ((unsigned char *) fp->pc) - 0x20;
-       for (sp = (unsigned long *) tp, i = 0; (i < 0x40);  i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-
-       printk(KERN_EMERG "KERNEL STACK:");
-       tp = ((unsigned char *) fp) - 0x40;
-       for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-
-       printk(KERN_EMERG "USER STACK:");
-       tp = (unsigned char *) (rdusp() - 0x10);
-       for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
-               if ((i % 0x10) == 0)
-                       printk(KERN_EMERG "%p: ", tp + i);
-               printk("%08x ", (int) *sp++);
-       }
-       printk(KERN_EMERG "\n");
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *name,
-                         const char *const *argv,
-                         const char *const *envp)
-{
-       int error;
-       char * filename;
-       struct pt_regs *regs = (struct pt_regs *) &name;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
-unsigned long get_wchan(struct task_struct *p)
-{
-       unsigned long fp, pc;
-       unsigned long stack_page;
-       int count = 0;
-       if (!p || p == current || p->state == TASK_RUNNING)
-               return 0;
-
-       stack_page = (unsigned long)p;
-       fp = ((struct switch_stack *)p->thread.ksp)->a6;
-       do {
-               if (fp < stack_page+sizeof(struct thread_info) ||
-                   fp >= THREAD_SIZE-8+stack_page)
-                       return 0;
-               pc = ((unsigned long *)fp)[1];
-               if (!in_sched_functions(pc))
-                       return pc;
-               fp = *(unsigned long *) fp;
-       } while (count++ < 16);
-       return 0;
-}
-
-/*
- * Return saved PC of a blocked thread.
- */
-unsigned long thread_saved_pc(struct task_struct *tsk)
-{
-       struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
-
-       /* Check whether the thread is blocked in resume() */
-       if (in_sched_functions(sw->retpc))
-               return ((unsigned long *)sw->a6)[1];
-       else
-               return sw->retpc;
-}
-
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
deleted file mode 100644 (file)
index 6709fb7..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/ptrace.c
- *
- *  Copyright (C) 1994 by Hamish Macdonald
- *  Taken from linux/kernel/ptrace.c and modified for M680x0.
- *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file COPYING in the main directory of
- * this archive for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-#include <linux/signal.h>
-#include <linux/tracehook.h>
-
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which bits in the SR the user has access to. */
-/* 1 = access 0 = no access */
-#define SR_MASK 0x001f
-
-/* sets the trace bits. */
-#define TRACE_BITS 0x8000
-
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)    ((long)&((struct pt_regs *)0)->reg)
-#define SW_REG(reg)    ((long)&((struct switch_stack *)0)->reg \
-                        - sizeof(struct switch_stack))
-/* Mapping from PT_xxx to the stack offset at which the register is
-   saved.  Notice that usp has no stack-slot and needs to be treated
-   specially (see get_reg/put_reg below). */
-static int regoff[] = {
-       PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
-       PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
-       PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
-       SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
-       PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
-};
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline long get_reg(struct task_struct *task, int regno)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-       else
-               return 0;
-       return *addr;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
-                         unsigned long data)
-{
-       unsigned long *addr;
-
-       if (regno == PT_USP)
-               addr = &task->thread.usp;
-       else if (regno < ARRAY_SIZE(regoff))
-               addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
-       else
-               return -1;
-       *addr = data;
-       return 0;
-}
-
-void user_enable_single_step(struct task_struct *task)
-{
-       unsigned long srflags;
-       srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
-       put_reg(task, PT_SR, srflags);
-}
-
-void user_disable_single_step(struct task_struct *task)
-{
-       unsigned long srflags;
-       srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
-       put_reg(task, PT_SR, srflags);
-}
-
-/*
- * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
- */
-void ptrace_disable(struct task_struct *child)
-{
-       /* make sure the single step bit is not set. */
-       user_disable_single_step(child);
-}
-
-long arch_ptrace(struct task_struct *child, long request,
-                unsigned long addr, unsigned long data)
-{
-       int ret;
-       int regno = addr >> 2;
-       unsigned long __user *datap = (unsigned long __user *) data;
-
-       switch (request) {
-               /* read the word at location addr in the USER area. */
-               case PTRACE_PEEKUSR: {
-                       unsigned long tmp;
-                       
-                       ret = -EIO;
-                       if ((addr & 3) || addr > sizeof(struct user) - 3)
-                               break;
-                       
-                       tmp = 0;  /* Default return condition */
-                       ret = -EIO;
-                       if (regno < 19) {
-                               tmp = get_reg(child, regno);
-                               if (regno == PT_SR)
-                                       tmp >>= 16;
-                       } else if (regno >= 21 && regno < 49) {
-                               tmp = child->thread.fp[regno - 21];
-                       } else if (regno == 49) {
-                               tmp = child->mm->start_code;
-                       } else if (regno == 50) {
-                               tmp = child->mm->start_data;
-                       } else if (regno == 51) {
-                               tmp = child->mm->end_code;
-                       } else
-                               break;
-                       ret = put_user(tmp, datap);
-                       break;
-               }
-
-               case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-                       ret = -EIO;
-                       if ((addr & 3) || addr > sizeof(struct user) - 3)
-                               break;
-
-                       if (regno == PT_SR) {
-                               data &= SR_MASK;
-                               data <<= 16;
-                               data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                       }
-                       if (regno < 19) {
-                               if (put_reg(child, regno, data))
-                                       break;
-                               ret = 0;
-                               break;
-                       }
-                       if (regno >= 21 && regno < 48)
-                       {
-                               child->thread.fp[regno - 21] = data;
-                               ret = 0;
-                       }
-                       break;
-
-               case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           tmp = get_reg(child, i);
-                           if (i == PT_SR)
-                               tmp >>= 16;
-                           if (put_user(tmp, datap)) {
-                               ret = -EFAULT;
-                               break;
-                           }
-                           datap++;
-                       }
-                       ret = 0;
-                       break;
-               }
-
-               case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-                       int i;
-                       unsigned long tmp;
-                       for (i = 0; i < 19; i++) {
-                           if (get_user(tmp, datap)) {
-                               ret = -EFAULT;
-                               break;
-                           }
-                           if (i == PT_SR) {
-                               tmp &= SR_MASK;
-                               tmp <<= 16;
-                               tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
-                           }
-                           put_reg(child, i, tmp);
-                           datap++;
-                       }
-                       ret = 0;
-                       break;
-               }
-
-#ifdef PTRACE_GETFPREGS
-               case PTRACE_GETFPREGS: { /* Get the child FPU state. */
-                       ret = 0;
-                       if (copy_to_user(datap, &child->thread.fp,
-                                        sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-#endif
-
-#ifdef PTRACE_SETFPREGS
-               case PTRACE_SETFPREGS: { /* Set the child FPU state. */
-                       ret = 0;
-                       if (copy_from_user(&child->thread.fp, datap,
-                                          sizeof(struct user_m68kfp_struct)))
-                               ret = -EFAULT;
-                       break;
-               }
-#endif
-
-       case PTRACE_GET_THREAD_AREA:
-               ret = put_user(task_thread_info(child)->tp_value, datap);
-               break;
-
-               default:
-                       ret = ptrace_request(child, request, addr, data);
-                       break;
-       }
-       return ret;
-}
-
-asmlinkage int syscall_trace_enter(void)
-{
-       int ret = 0;
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               ret = tracehook_report_syscall_entry(task_pt_regs(current));
-       return ret;
-}
-
-asmlinkage void syscall_trace_leave(void)
-{
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               tracehook_report_syscall_exit(task_pt_regs(current), 0);
-}
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
deleted file mode 100644 (file)
index 16b2de7..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/setup.c
- *
- *  Copyright (C) 1999-2007  Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 1998,1999  D. Jeff Dionne <jeff@uClinux.org>
- *  Copyleft  ()) 2000       James D. Schettine {james@telos-systems.com}
- *  Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- *  Copyright (C) 1995       Hamish Macdonald
- *  Copyright (C) 2000       Lineo Inc. (www.lineo.com)
- *  Copyright (C) 2001              Lineo, Inc. <www.lineo.com>
- *
- *  68VZ328 Fixes/support    Evan Stawnyczy <e@lineo.ca>
- */
-
-/*
- * This file handles the architecture-dependent parts of system setup
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/initrd.h>
-#include <linux/root_dev.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-#include <asm/pgtable.h>
-
-unsigned long memory_start;
-unsigned long memory_end;
-
-EXPORT_SYMBOL(memory_start);
-EXPORT_SYMBOL(memory_end);
-
-char __initdata command_line[COMMAND_LINE_SIZE];
-
-/* machine dependent timer functions */
-void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
-int (*mach_set_clock_mmss)(unsigned long);
-
-/* machine dependent reboot functions */
-void (*mach_reset)(void);
-void (*mach_halt)(void);
-void (*mach_power_off)(void);
-
-#ifdef CONFIG_M68328
-#define CPU_NAME       "MC68328"
-#endif
-#ifdef CONFIG_M68EZ328
-#define CPU_NAME       "MC68EZ328"
-#endif
-#ifdef CONFIG_M68VZ328
-#define CPU_NAME       "MC68VZ328"
-#endif
-#ifdef CONFIG_M68360
-#define CPU_NAME       "MC68360"
-#endif
-#ifndef CPU_NAME
-#define        CPU_NAME        "UNKNOWN"
-#endif
-
-/*
- * Different cores have different instruction execution timings.
- * The old/traditional 68000 cores are basically all the same, at 16.
- * The ColdFire cores vary a little, their values are defined in their
- * headers. We default to the standard 68000 value here.
- */
-#ifndef CPU_INSTR_PER_JIFFY
-#define        CPU_INSTR_PER_JIFFY     16
-#endif
-
-extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
-extern int _ramstart, _ramend;
-
-#if defined(CONFIG_UBOOT)
-/*
- * parse_uboot_commandline
- *
- * Copies u-boot commandline arguments and store them in the proper linux
- * variables.
- *
- * Assumes:
- *     _init_sp global contains the address in the stack pointer when the
- *     kernel starts (see head.S::_start)
- *
- *     U-Boot calling convention:
- *     (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
- *
- *     _init_sp can be parsed as such
- *
- *     _init_sp+00 = u-boot cmd after jsr into kernel (skip)
- *     _init_sp+04 = &kernel board_info (residual data)
- *     _init_sp+08 = &initrd_start
- *     _init_sp+12 = &initrd_end
- *     _init_sp+16 = &cmd_start
- *     _init_sp+20 = &cmd_end
- *
- *     This also assumes that the memory locations pointed to are still
- *     unmodified. U-boot places them near the end of external SDRAM.
- *
- * Argument(s):
- *     commandp = the linux commandline arg container to fill.
- *     size     = the sizeof commandp.
- *
- * Returns:
- */
-void parse_uboot_commandline(char *commandp, int size)
-{
-       extern unsigned long _init_sp;
-       unsigned long *sp;
-       unsigned long uboot_kbd;
-       unsigned long uboot_initrd_start, uboot_initrd_end;
-       unsigned long uboot_cmd_start, uboot_cmd_end;
-
-
-       sp = (unsigned long *)_init_sp;
-       uboot_kbd = sp[1];
-       uboot_initrd_start = sp[2];
-       uboot_initrd_end = sp[3];
-       uboot_cmd_start = sp[4];
-       uboot_cmd_end = sp[5];
-
-       if (uboot_cmd_start && uboot_cmd_end)
-               strncpy(commandp, (const char *)uboot_cmd_start, size);
-#if defined(CONFIG_BLK_DEV_INITRD)
-       if (uboot_initrd_start && uboot_initrd_end &&
-               (uboot_initrd_end > uboot_initrd_start)) {
-               initrd_start = uboot_initrd_start;
-               initrd_end = uboot_initrd_end;
-               ROOT_DEV = Root_RAM0;
-               printk(KERN_INFO "initrd at 0x%lx:0x%lx\n",
-                       initrd_start, initrd_end);
-       }
-#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
-}
-#endif /* #if defined(CONFIG_UBOOT) */
-
-void __init setup_arch(char **cmdline_p)
-{
-       int bootmap_size;
-
-       memory_start = PAGE_ALIGN(_ramstart);
-       memory_end = _ramend;
-
-       init_mm.start_code = (unsigned long) &_stext;
-       init_mm.end_code = (unsigned long) &_etext;
-       init_mm.end_data = (unsigned long) &_edata;
-       init_mm.brk = (unsigned long) 0;
-
-       config_BSP(&command_line[0], sizeof(command_line));
-
-#if defined(CONFIG_BOOTPARAM)
-       strncpy(&command_line[0], CONFIG_BOOTPARAM_STRING, sizeof(command_line));
-       command_line[sizeof(command_line) - 1] = 0;
-#endif /* CONFIG_BOOTPARAM */
-
-#if defined(CONFIG_UBOOT)
-       /* CONFIG_UBOOT and CONFIG_BOOTPARAM defined, concatenate cmdline */
-       #if defined(CONFIG_BOOTPARAM)
-               /* Add the whitespace separator */
-               command_line[strlen(CONFIG_BOOTPARAM_STRING)] = ' ';
-               /* Parse uboot command line into the rest of the buffer */
-               parse_uboot_commandline(
-                       &command_line[(strlen(CONFIG_BOOTPARAM_STRING)+1)],
-                       (sizeof(command_line) -
-                       (strlen(CONFIG_BOOTPARAM_STRING)+1)));
-       /* Only CONFIG_UBOOT defined, create cmdline */
-       #else
-               parse_uboot_commandline(&command_line[0], sizeof(command_line));
-       #endif /* CONFIG_BOOTPARAM */
-       command_line[sizeof(command_line) - 1] = 0;
-#endif /* CONFIG_UBOOT */
-
-       printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU_NAME "\n");
-
-#ifdef CONFIG_UCDIMM
-       printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n");
-#endif
-#ifdef CONFIG_M68VZ328
-       printk(KERN_INFO "M68VZ328 support by Evan Stawnyczy <e@lineo.ca>\n");
-#endif
-#ifdef CONFIG_COLDFIRE
-       printk(KERN_INFO "COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n");
-#ifdef CONFIG_M5307
-       printk(KERN_INFO "Modified for M5307 by Dave Miller, dmiller@intellistor.com\n");
-#endif
-#ifdef CONFIG_ELITE
-       printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
-#endif
-#endif
-       printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
-
-#if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )
-       printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n");
-#endif
-#if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 )
-       printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n");
-#endif
-#if defined (CONFIG_M68360)
-       printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n");
-       printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n");
-#endif
-#ifdef CONFIG_DRAGEN2
-       printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
-#endif
-#ifdef CONFIG_M5235EVB
-       printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
-#endif
-
-       pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
-                "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
-                (int) &_sdata, (int) &_edata,
-                (int) &_sbss, (int) &_ebss);
-       pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
-                (int) &_ebss, (int) memory_start,
-                (int) memory_start, (int) memory_end);
-
-       /* Keep a copy of command line */
-       *cmdline_p = &command_line[0];
-       memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
-       boot_command_line[COMMAND_LINE_SIZE-1] = 0;
-
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
-       conswitchp = &dummy_con;
-#endif
-
-       /*
-        * Give all the memory to the bootmap allocator, tell it to put the
-        * boot mem_map at the start of memory.
-        */
-       bootmap_size = init_bootmem_node(
-                       NODE_DATA(0),
-                       memory_start >> PAGE_SHIFT, /* map goes here */
-                       PAGE_OFFSET >> PAGE_SHIFT,      /* 0 on coldfire */
-                       memory_end >> PAGE_SHIFT);
-       /*
-        * Free the usable memory, we have to make sure we do not free
-        * the bootmem bitmap so we then reserve it after freeing it :-)
-        */
-       free_bootmem(memory_start, memory_end - memory_start);
-       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
-
-#if defined(CONFIG_UBOOT) && defined(CONFIG_BLK_DEV_INITRD)
-       if ((initrd_start > 0) && (initrd_start < initrd_end) &&
-                       (initrd_end < memory_end))
-               reserve_bootmem(initrd_start, initrd_end - initrd_start,
-                                BOOTMEM_DEFAULT);
-#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
-
-       /*
-        * Get kmalloc into gear.
-        */
-       paging_init();
-}
-
-/*
- *     Get CPU information for use by the procfs.
- */
-static int show_cpuinfo(struct seq_file *m, void *v)
-{
-       char *cpu, *mmu, *fpu;
-       u_long clockfreq;
-
-       cpu = CPU_NAME;
-       mmu = "none";
-       fpu = "none";
-       clockfreq = (loops_per_jiffy * HZ) * CPU_INSTR_PER_JIFFY;
-
-       seq_printf(m, "CPU:\t\t%s\n"
-                     "MMU:\t\t%s\n"
-                     "FPU:\t\t%s\n"
-                     "Clocking:\t%lu.%1luMHz\n"
-                     "BogoMips:\t%lu.%02lu\n"
-                     "Calibration:\t%lu loops\n",
-                     cpu, mmu, fpu,
-                     clockfreq / 1000000,
-                     (clockfreq / 100000) % 10,
-                     (loops_per_jiffy * HZ) / 500000,
-                     ((loops_per_jiffy * HZ) / 5000) % 100,
-                     (loops_per_jiffy * HZ));
-
-       return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-       return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       ++*pos;
-       return c_start(m, pos);
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-const struct seq_operations cpuinfo_op = {
-       .start  = c_start,
-       .next   = c_next,
-       .stop   = c_stop,
-       .show   = show_cpuinfo,
-};
-
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
deleted file mode 100644 (file)
index 36a81bb..0000000
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/signal.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * 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.
- */
-
-/*
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- *
- * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
- *
- * mathemu support by Roman Zippel
- *  (Note: fpstate in the signal context is completely ignored for the emulator
- *         and the internal floating point format is put on stack)
- */
-
-/*
- * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
- * Atari :-) Current limitation: Only one sigstack can be active at one time.
- * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
- * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
- * signal handlers!
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/syscalls.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/unistd.h>
-#include <linux/stddef.h>
-#include <linux/highuid.h>
-#include <linux/tty.h>
-#include <linux/personality.h>
-#include <linux/binfmts.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/traps.h>
-#include <asm/ucontext.h>
-
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
-void ret_from_user_signal(void);
-void ret_from_user_rt_signal(void);
-
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int
-sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
-{
-       mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       set_restore_sigmask();
-
-       return -ERESTARTNOHAND;
-}
-
-asmlinkage int
-sys_sigaction(int sig, const struct old_sigaction __user *act,
-             struct old_sigaction __user *oact)
-{
-       struct k_sigaction new_ka, old_ka;
-       int ret;
-
-       if (act) {
-               old_sigset_t mask;
-               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
-                   __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-                   __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
-                   __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
-                   __get_user(mask, &act->sa_mask))
-                       return -EFAULT;
-               siginitset(&new_ka.sa.sa_mask, mask);
-       }
-
-       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
-       if (!ret && oact) {
-               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
-                   __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-                   __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
-                   __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
-                   __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
-                       return -EFAULT;
-       }
-
-       return ret;
-}
-
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
-       return do_sigaltstack(uss, uoss, rdusp());
-}
-
-
-/*
- * Do a signal return; undo the signal stack.
- *
- * Keep the return code on the stack quadword aligned!
- * That makes the cache flush below easier.
- */
-
-struct sigframe
-{
-       char __user *pretcode;
-       int sig;
-       int code;
-       struct sigcontext __user *psc;
-       char retcode[8];
-       unsigned long extramask[_NSIG_WORDS-1];
-       struct sigcontext sc;
-};
-
-struct rt_sigframe
-{
-       char __user *pretcode;
-       int sig;
-       struct siginfo __user *pinfo;
-       void __user *puc;
-       char retcode[8];
-       struct siginfo info;
-       struct ucontext uc;
-};
-
-#ifdef CONFIG_FPU
-
-static unsigned char fpu_version = 0;  /* version number of fpu, set by setup_frame */
-
-static inline int restore_fpu_state(struct sigcontext *sc)
-{
-       int err = 1;
-
-       if (FPU_IS_EMU) {
-           /* restore registers */
-           memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
-           memcpy(current->thread.fp, sc->sc_fpregs, 24);
-           return 0;
-       }
-
-       if (sc->sc_fpstate[0]) {
-           /* Verify the frame format.  */
-           if (sc->sc_fpstate[0] != fpu_version)
-               goto out;
-
-           __asm__ volatile (".chip 68k/68881\n\t"
-                             "fmovemx %0,%%fp0-%%fp1\n\t"
-                             "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
-                             ".chip 68k"
-                             : /* no outputs */
-                             : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
-       }
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "frestore %0\n\t"
-                         ".chip 68k" : : "m" (*sc->sc_fpstate));
-       err = 0;
-
-out:
-       return err;
-}
-
-#define FPCONTEXT_SIZE 216
-#define uc_fpstate     uc_filler[0]
-#define uc_formatvec   uc_filler[FPCONTEXT_SIZE/4]
-#define uc_extra       uc_filler[FPCONTEXT_SIZE/4+1]
-
-static inline int rt_restore_fpu_state(struct ucontext __user *uc)
-{
-       unsigned char fpstate[FPCONTEXT_SIZE];
-       int context_size = 0;
-       fpregset_t fpregs;
-       int err = 1;
-
-       if (FPU_IS_EMU) {
-               /* restore fpu control register */
-               if (__copy_from_user(current->thread.fpcntl,
-                               uc->uc_mcontext.fpregs.f_fpcntl, 12))
-                       goto out;
-               /* restore all other fpu register */
-               if (__copy_from_user(current->thread.fp,
-                               uc->uc_mcontext.fpregs.f_fpregs, 96))
-                       goto out;
-               return 0;
-       }
-
-       if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
-               goto out;
-       if (fpstate[0]) {
-               context_size = fpstate[1];
-
-               /* Verify the frame format.  */
-               if (fpstate[0] != fpu_version)
-                       goto out;
-               if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
-                    sizeof(fpregs)))
-                       goto out;
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %0,%%fp0-%%fp7\n\t"
-                                 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
-                                 ".chip 68k"
-                                 : /* no outputs */
-                                 : "m" (*fpregs.f_fpregs),
-                                   "m" (*fpregs.f_fpcntl));
-       }
-       if (context_size &&
-           __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
-                            context_size))
-               goto out;
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "frestore %0\n\t"
-                         ".chip 68k" : : "m" (*fpstate));
-       err = 0;
-
-out:
-       return err;
-}
-
-#endif
-
-static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
-                  int *pd0)
-{
-       int formatvec;
-       struct sigcontext context;
-       int err = 0;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       /* get previous context */
-       if (copy_from_user(&context, usc, sizeof(context)))
-               goto badframe;
-       
-       /* restore passed registers */
-       regs->d1 = context.sc_d1;
-       regs->a0 = context.sc_a0;
-       regs->a1 = context.sc_a1;
-       ((struct switch_stack *)regs - 1)->a5 = context.sc_a5;
-       regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
-       regs->pc = context.sc_pc;
-       regs->orig_d0 = -1;             /* disable syscall checks */
-       wrusp(context.sc_usp);
-       formatvec = context.sc_formatvec;
-       regs->format = formatvec >> 12;
-       regs->vector = formatvec & 0xfff;
-
-#ifdef CONFIG_FPU
-       err = restore_fpu_state(&context);
-#endif
-
-       *pd0 = context.sc_d0;
-       return err;
-
-badframe:
-       return 1;
-}
-
-static inline int
-rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
-                   struct ucontext __user *uc, int *pd0)
-{
-       int temp;
-       greg_t __user *gregs = uc->uc_mcontext.gregs;
-       unsigned long usp;
-       int err;
-
-       /* Always make any pending restarted system calls return -EINTR */
-       current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
-       err = __get_user(temp, &uc->uc_mcontext.version);
-       if (temp != MCONTEXT_VERSION)
-               goto badframe;
-       /* restore passed registers */
-       err |= __get_user(regs->d0, &gregs[0]);
-       err |= __get_user(regs->d1, &gregs[1]);
-       err |= __get_user(regs->d2, &gregs[2]);
-       err |= __get_user(regs->d3, &gregs[3]);
-       err |= __get_user(regs->d4, &gregs[4]);
-       err |= __get_user(regs->d5, &gregs[5]);
-       err |= __get_user(sw->d6, &gregs[6]);
-       err |= __get_user(sw->d7, &gregs[7]);
-       err |= __get_user(regs->a0, &gregs[8]);
-       err |= __get_user(regs->a1, &gregs[9]);
-       err |= __get_user(regs->a2, &gregs[10]);
-       err |= __get_user(sw->a3, &gregs[11]);
-       err |= __get_user(sw->a4, &gregs[12]);
-       err |= __get_user(sw->a5, &gregs[13]);
-       err |= __get_user(sw->a6, &gregs[14]);
-       err |= __get_user(usp, &gregs[15]);
-       wrusp(usp);
-       err |= __get_user(regs->pc, &gregs[16]);
-       err |= __get_user(temp, &gregs[17]);
-       regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
-       regs->orig_d0 = -1;             /* disable syscall checks */
-       regs->format = temp >> 12;
-       regs->vector = temp & 0xfff;
-
-       if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
-               goto badframe;
-
-       *pd0 = regs->d0;
-       return err;
-
-badframe:
-       return 1;
-}
-
-asmlinkage int do_sigreturn(unsigned long __unused)
-{
-       struct switch_stack *sw = (struct switch_stack *) &__unused;
-       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
-       unsigned long usp = rdusp();
-       struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
-       sigset_t set;
-       int d0;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
-           (_NSIG_WORDS > 1 &&
-            __copy_from_user(&set.sig[1], &frame->extramask,
-                             sizeof(frame->extramask))))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-       
-       if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
-               goto badframe;
-       return d0;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-asmlinkage int do_rt_sigreturn(unsigned long __unused)
-{
-       struct switch_stack *sw = (struct switch_stack *) &__unused;
-       struct pt_regs *regs = (struct pt_regs *) (sw + 1);
-       unsigned long usp = rdusp();
-       struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
-       sigset_t set;
-       int d0;
-
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto badframe;
-       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
-               goto badframe;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-       
-       if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
-               goto badframe;
-       return d0;
-
-badframe:
-       force_sig(SIGSEGV, current);
-       return 0;
-}
-
-#ifdef CONFIG_FPU
-/*
- * Set up a signal frame.
- */
-
-static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
-{
-       if (FPU_IS_EMU) {
-               /* save registers */
-               memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
-               memcpy(sc->sc_fpregs, current->thread.fp, 24);
-               return;
-       }
-
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "fsave %0\n\t"
-                         ".chip 68k"
-                         : : "m" (*sc->sc_fpstate) : "memory");
-
-       if (sc->sc_fpstate[0]) {
-               fpu_version = sc->sc_fpstate[0];
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %%fp0-%%fp1,%0\n\t"
-                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
-                                 ".chip 68k"
-                                 : "=m" (*sc->sc_fpregs),
-                                   "=m" (*sc->sc_fpcntl)
-                                 : /* no inputs */
-                                 : "memory");
-       }
-}
-
-static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
-{
-       unsigned char fpstate[FPCONTEXT_SIZE];
-       int context_size = 0;
-       int err = 0;
-
-       if (FPU_IS_EMU) {
-               /* save fpu control register */
-               err |= copy_to_user(uc->uc_mcontext.fpregs.f_pcntl,
-                               current->thread.fpcntl, 12);
-               /* save all other fpu register */
-               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
-                               current->thread.fp, 96);
-               return err;
-       }
-
-       __asm__ volatile (".chip 68k/68881\n\t"
-                         "fsave %0\n\t"
-                         ".chip 68k"
-                         : : "m" (*fpstate) : "memory");
-
-       err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
-       if (fpstate[0]) {
-               fpregset_t fpregs;
-               context_size = fpstate[1];
-               fpu_version = fpstate[0];
-               __asm__ volatile (".chip 68k/68881\n\t"
-                                 "fmovemx %%fp0-%%fp7,%0\n\t"
-                                 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
-                                 ".chip 68k"
-                                 : "=m" (*fpregs.f_fpregs),
-                                   "=m" (*fpregs.f_fpcntl)
-                                 : /* no inputs */
-                                 : "memory");
-               err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
-                                   sizeof(fpregs));
-       }
-       if (context_size)
-               err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
-                                   context_size);
-       return err;
-}
-
-#endif
-
-static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
-                            unsigned long mask)
-{
-       sc->sc_mask = mask;
-       sc->sc_usp = rdusp();
-       sc->sc_d0 = regs->d0;
-       sc->sc_d1 = regs->d1;
-       sc->sc_a0 = regs->a0;
-       sc->sc_a1 = regs->a1;
-       sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
-       sc->sc_sr = regs->sr;
-       sc->sc_pc = regs->pc;
-       sc->sc_formatvec = regs->format << 12 | regs->vector;
-#ifdef CONFIG_FPU
-       save_fpu_state(sc, regs);
-#endif
-}
-
-static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
-{
-       struct switch_stack *sw = (struct switch_stack *)regs - 1;
-       greg_t __user *gregs = uc->uc_mcontext.gregs;
-       int err = 0;
-
-       err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
-       err |= __put_user(regs->d0, &gregs[0]);
-       err |= __put_user(regs->d1, &gregs[1]);
-       err |= __put_user(regs->d2, &gregs[2]);
-       err |= __put_user(regs->d3, &gregs[3]);
-       err |= __put_user(regs->d4, &gregs[4]);
-       err |= __put_user(regs->d5, &gregs[5]);
-       err |= __put_user(sw->d6, &gregs[6]);
-       err |= __put_user(sw->d7, &gregs[7]);
-       err |= __put_user(regs->a0, &gregs[8]);
-       err |= __put_user(regs->a1, &gregs[9]);
-       err |= __put_user(regs->a2, &gregs[10]);
-       err |= __put_user(sw->a3, &gregs[11]);
-       err |= __put_user(sw->a4, &gregs[12]);
-       err |= __put_user(sw->a5, &gregs[13]);
-       err |= __put_user(sw->a6, &gregs[14]);
-       err |= __put_user(rdusp(), &gregs[15]);
-       err |= __put_user(regs->pc, &gregs[16]);
-       err |= __put_user(regs->sr, &gregs[17]);
-#ifdef CONFIG_FPU
-       err |= rt_save_fpu_state(uc, regs);
-#endif
-       return err;
-}
-
-static inline void __user *
-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
-{
-       unsigned long usp;
-
-       /* Default to using normal stack.  */
-       usp = rdusp();
-
-       /* This is the X/Open sanctioned signal stack switching.  */
-       if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (!sas_ss_flags(usp))
-                       usp = current->sas_ss_sp + current->sas_ss_size;
-       }
-       return (void __user *)((usp - frame_size) & -8UL);
-}
-
-static int setup_frame (int sig, struct k_sigaction *ka,
-                        sigset_t *set, struct pt_regs *regs)
-{
-       struct sigframe __user *frame;
-       struct sigcontext context;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-
-       err |= __put_user(regs->vector, &frame->code);
-       err |= __put_user(&frame->sc, &frame->psc);
-
-       if (_NSIG_WORDS > 1)
-               err |= copy_to_user(frame->extramask, &set->sig[1],
-                                   sizeof(frame->extramask));
-
-       setup_sigcontext(&context, regs, set->sig[0]);
-       err |= copy_to_user (&frame->sc, &context, sizeof(context));
-
-       /* Set up to return from userspace.  */
-       err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       wrusp ((unsigned long) frame);
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
-       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
-                                               which it will be when doing the rte */
-
-adjust_stack:
-       /* Prepare to skip over the extra stuff in the exception frame.  */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                       (struct pt_regs *)((ulong)regs + regs->stkadj);
-#if defined(DEBUG)
-               printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
-#endif
-               /* This must be copied with decreasing addresses to
-                   handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
-       }
-       return err;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       goto adjust_stack;
-}
-
-static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
-                           sigset_t *set, struct pt_regs *regs)
-{
-       struct rt_sigframe __user *frame;
-       int err = 0;
-
-       frame = get_sigframe(ka, regs, sizeof(*frame));
-
-       err |= __put_user((current_thread_info()->exec_domain
-                          && current_thread_info()->exec_domain->signal_invmap
-                          && sig < 32
-                          ? current_thread_info()->exec_domain->signal_invmap[sig]
-                          : sig),
-                         &frame->sig);
-       err |= __put_user(&frame->info, &frame->pinfo);
-       err |= __put_user(&frame->uc, &frame->puc);
-       err |= copy_siginfo_to_user(&frame->info, info);
-
-       /* Create the ucontext.  */
-       err |= __put_user(0, &frame->uc.uc_flags);
-       err |= __put_user(NULL, &frame->uc.uc_link);
-       err |= __put_user((void __user *)current->sas_ss_sp,
-                         &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(rdusp()),
-                         &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-       err |= rt_setup_ucontext(&frame->uc, regs);
-       err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
-
-       /* Set up to return from userspace.  */
-       err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
-
-       if (err)
-               goto give_sigsegv;
-
-       /* Set up registers for signal handler */
-       wrusp ((unsigned long) frame);
-       regs->pc = (unsigned long) ka->sa.sa_handler;
-       ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
-       regs->format = 0x4; /*set format byte to make stack appear modulo 4 
-                                               which it will be when doing the rte */
-
-adjust_stack:
-       /* Prepare to skip over the extra stuff in the exception frame.  */
-       if (regs->stkadj) {
-               struct pt_regs *tregs =
-                       (struct pt_regs *)((ulong)regs + regs->stkadj);
-#if defined(DEBUG)
-               printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
-#endif
-               /* This must be copied with decreasing addresses to
-                   handle overlaps.  */
-               tregs->vector = 0;
-               tregs->format = 0;
-               tregs->pc = regs->pc;
-               tregs->sr = regs->sr;
-       }
-       return err;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       goto adjust_stack;
-}
-
-static inline void
-handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
-{
-       switch (regs->d0) {
-       case -ERESTARTNOHAND:
-               if (!has_handler)
-                       goto do_restart;
-               regs->d0 = -EINTR;
-               break;
-
-       case -ERESTART_RESTARTBLOCK:
-               if (!has_handler) {
-                       regs->d0 = __NR_restart_syscall;
-                       regs->pc -= 2;
-                       break;
-               }
-               regs->d0 = -EINTR;
-               break;
-
-       case -ERESTARTSYS:
-               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
-                       regs->d0 = -EINTR;
-                       break;
-               }
-       /* fallthrough */
-       case -ERESTARTNOINTR:
-       do_restart:
-               regs->d0 = regs->orig_d0;
-               regs->pc -= 2;
-               break;
-       }
-}
-
-/*
- * OK, we're invoking a handler
- */
-static void
-handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
-             sigset_t *oldset, struct pt_regs *regs)
-{
-       int err;
-       /* are we from a system call? */
-       if (regs->orig_d0 >= 0)
-               /* If so, check system call restarting.. */
-               handle_restart(regs, ka, 1);
-
-       /* set up the stack frame */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               err = setup_rt_frame(sig, ka, info, oldset, regs);
-       else
-               err = setup_frame(sig, ka, oldset, regs);
-
-       if (err)
-               return;
-
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked,sig);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       clear_thread_flag(TIF_RESTORE_SIGMASK);
-}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-asmlinkage void do_signal(struct pt_regs *regs)
-{
-       struct k_sigaction ka;
-       siginfo_t info;
-       int signr;
-       sigset_t *oldset;
-
-       /*
-        * We want the common case to go fast, which
-        * is why we may in certain cases get here from
-        * kernel mode. Just return without doing anything
-        * if so.
-        */
-       if (!user_mode(regs))
-               return;
-
-       if (test_thread_flag(TIF_RESTORE_SIGMASK))
-               oldset = &current->saved_sigmask;
-       else
-               oldset = &current->blocked;
-
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-       if (signr > 0) {
-               /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &ka, &info, oldset, regs);
-               return;
-       }
-
-       /* Did we come from a system call? */
-       if (regs->orig_d0 >= 0) {
-               /* Restart the system call - no handlers present */
-               handle_restart(regs, NULL, 0);
-       }
-
-       /* If there's no signal to deliver, we just restore the saved mask.  */
-       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-               clear_thread_flag(TIF_RESTORE_SIGMASK);
-               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
-       }
-}
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
deleted file mode 100644 (file)
index 68488ae..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-#include <linux/fs.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/cacheflush.h>
-#include <asm/unistd.h>
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       flush_cache_all();
-       return(0);
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long mem_value;
-
-       down_read(&mm->mmap_sem);
-
-       mem_value = *mem;
-       if (mem_value == oldval)
-               *mem = newval;
-
-       up_read(&mm->mmap_sem);
-       return mem_value;
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
deleted file mode 100644 (file)
index 79b1ed1..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/syscalltable.S
- *
- *  Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
- *
- *  Based on older entry.S files, the following copyrights apply:
- *
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/unistd.h>
-
-.text
-ALIGN
-ENTRY(sys_call_table)
-       .long sys_restart_syscall       /* 0  -  old "setup()" system call */
-       .long sys_exit
-       .long sys_fork
-       .long sys_read
-       .long sys_write
-       .long sys_open          /* 5 */
-       .long sys_close
-       .long sys_waitpid
-       .long sys_creat
-       .long sys_link
-       .long sys_unlink        /* 10 */
-       .long sys_execve
-       .long sys_chdir
-       .long sys_time
-       .long sys_mknod
-       .long sys_chmod         /* 15 */
-       .long sys_chown16
-       .long sys_ni_syscall    /* old break syscall holder */
-       .long sys_stat
-       .long sys_lseek
-       .long sys_getpid        /* 20 */
-       .long sys_mount
-       .long sys_oldumount
-       .long sys_setuid16
-       .long sys_getuid16
-       .long sys_stime         /* 25 */
-       .long sys_ptrace
-       .long sys_alarm
-       .long sys_fstat
-       .long sys_pause
-       .long sys_utime         /* 30 */
-       .long sys_ni_syscall    /* old stty syscall holder */
-       .long sys_ni_syscall    /* old gtty syscall holder */
-       .long sys_access
-       .long sys_nice
-       .long sys_ni_syscall    /* 35 */ /* old ftime syscall holder */
-       .long sys_sync
-       .long sys_kill
-       .long sys_rename
-       .long sys_mkdir
-       .long sys_rmdir         /* 40 */
-       .long sys_dup
-       .long sys_pipe
-       .long sys_times
-       .long sys_ni_syscall    /* old prof syscall holder */
-       .long sys_brk           /* 45 */
-       .long sys_setgid16
-       .long sys_getgid16
-       .long sys_signal
-       .long sys_geteuid16
-       .long sys_getegid16     /* 50 */
-       .long sys_acct
-       .long sys_umount        /* recycled never used phys() */
-       .long sys_ni_syscall    /* old lock syscall holder */
-       .long sys_ioctl
-       .long sys_fcntl         /* 55 */
-       .long sys_ni_syscall    /* old mpx syscall holder */
-       .long sys_setpgid
-       .long sys_ni_syscall    /* old ulimit syscall holder */
-       .long sys_ni_syscall
-       .long sys_umask         /* 60 */
-       .long sys_chroot
-       .long sys_ustat
-       .long sys_dup2
-       .long sys_getppid
-       .long sys_getpgrp       /* 65 */
-       .long sys_setsid
-       .long sys_sigaction
-       .long sys_sgetmask
-       .long sys_ssetmask
-       .long sys_setreuid16    /* 70 */
-       .long sys_setregid16
-       .long sys_sigsuspend
-       .long sys_sigpending
-       .long sys_sethostname
-       .long sys_setrlimit     /* 75 */
-       .long sys_old_getrlimit
-       .long sys_getrusage
-       .long sys_gettimeofday
-       .long sys_settimeofday
-       .long sys_getgroups16   /* 80 */
-       .long sys_setgroups16
-       .long sys_old_select
-       .long sys_symlink
-       .long sys_lstat
-       .long sys_readlink      /* 85 */
-       .long sys_uselib
-       .long sys_ni_syscall    /* sys_swapon */
-       .long sys_reboot
-       .long sys_old_readdir
-       .long sys_old_mmap      /* 90 */
-       .long sys_munmap
-       .long sys_truncate
-       .long sys_ftruncate
-       .long sys_fchmod
-       .long sys_fchown16      /* 95 */
-       .long sys_getpriority
-       .long sys_setpriority
-       .long sys_ni_syscall    /* old profil syscall holder */
-       .long sys_statfs
-       .long sys_fstatfs       /* 100 */
-       .long sys_ni_syscall    /* ioperm for i386 */
-       .long sys_socketcall
-       .long sys_syslog
-       .long sys_setitimer
-       .long sys_getitimer     /* 105 */
-       .long sys_newstat
-       .long sys_newlstat
-       .long sys_newfstat
-       .long sys_ni_syscall
-       .long sys_ni_syscall    /* iopl for i386 */ /* 110 */
-       .long sys_vhangup
-       .long sys_ni_syscall    /* obsolete idle() syscall */
-       .long sys_ni_syscall    /* vm86old for i386 */
-       .long sys_wait4
-       .long sys_ni_syscall    /* 115 */ /* sys_swapoff */
-       .long sys_sysinfo
-       .long sys_ipc
-       .long sys_fsync
-       .long sys_sigreturn
-       .long sys_clone         /* 120 */
-       .long sys_setdomainname
-       .long sys_newuname
-       .long sys_cacheflush    /* modify_ldt for i386 */
-       .long sys_adjtimex
-       .long sys_ni_syscall    /* 125 */ /* sys_mprotect */
-       .long sys_sigprocmask
-       .long sys_ni_syscall    /* old "creat_module" */
-       .long sys_init_module
-       .long sys_delete_module
-       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
-       .long sys_quotactl
-       .long sys_getpgid
-       .long sys_fchdir
-       .long sys_bdflush
-       .long sys_sysfs         /* 135 */
-       .long sys_personality
-       .long sys_ni_syscall    /* for afs_syscall */
-       .long sys_setfsuid16
-       .long sys_setfsgid16
-       .long sys_llseek        /* 140 */
-       .long sys_getdents
-       .long sys_select
-       .long sys_flock
-       .long sys_ni_syscall    /* sys_msync */
-       .long sys_readv         /* 145 */
-       .long sys_writev
-       .long sys_getsid
-       .long sys_fdatasync
-       .long sys_sysctl
-       .long sys_ni_syscall    /* 150 */ /* sys_mlock */
-       .long sys_ni_syscall    /* sys_munlock */
-       .long sys_ni_syscall    /* sys_mlockall */
-       .long sys_ni_syscall    /* sys_munlockall */
-       .long sys_sched_setparam
-       .long sys_sched_getparam /* 155 */
-       .long sys_sched_setscheduler
-       .long sys_sched_getscheduler
-       .long sys_sched_yield
-       .long sys_sched_get_priority_max
-       .long sys_sched_get_priority_min  /* 160 */
-       .long sys_sched_rr_get_interval
-       .long sys_nanosleep
-       .long sys_ni_syscall    /* sys_mremap */
-       .long sys_setresuid16
-       .long sys_getresuid16   /* 165 */
-       .long sys_getpagesize   /* sys_getpagesize */
-       .long sys_ni_syscall    /* old "query_module" */
-       .long sys_poll
-       .long sys_ni_syscall    /* sys_nfsservctl */
-       .long sys_setresgid16   /* 170 */
-       .long sys_getresgid16
-       .long sys_prctl
-       .long sys_rt_sigreturn
-       .long sys_rt_sigaction
-       .long sys_rt_sigprocmask /* 175 */
-       .long sys_rt_sigpending
-       .long sys_rt_sigtimedwait
-       .long sys_rt_sigqueueinfo
-       .long sys_rt_sigsuspend
-       .long sys_pread64       /* 180 */
-       .long sys_pwrite64
-       .long sys_lchown16
-       .long sys_getcwd
-       .long sys_capget
-       .long sys_capset        /* 185 */
-       .long sys_sigaltstack
-       .long sys_sendfile
-       .long sys_ni_syscall    /* streams1 */
-       .long sys_ni_syscall    /* streams2 */
-       .long sys_vfork         /* 190 */
-       .long sys_getrlimit
-       .long sys_mmap_pgoff
-       .long sys_truncate64
-       .long sys_ftruncate64
-       .long sys_stat64        /* 195 */
-       .long sys_lstat64
-       .long sys_fstat64
-       .long sys_chown
-       .long sys_getuid
-       .long sys_getgid        /* 200 */
-       .long sys_geteuid
-       .long sys_getegid
-       .long sys_setreuid
-       .long sys_setregid
-       .long sys_getgroups     /* 205 */
-       .long sys_setgroups
-       .long sys_fchown
-       .long sys_setresuid
-       .long sys_getresuid
-       .long sys_setresgid     /* 210 */
-       .long sys_getresgid
-       .long sys_lchown
-       .long sys_setuid
-       .long sys_setgid
-       .long sys_setfsuid      /* 215 */
-       .long sys_setfsgid
-       .long sys_pivot_root
-       .long sys_ni_syscall
-       .long sys_ni_syscall
-       .long sys_getdents64    /* 220 */
-       .long sys_gettid
-       .long sys_tkill
-       .long sys_setxattr
-       .long sys_lsetxattr
-       .long sys_fsetxattr     /* 225 */
-       .long sys_getxattr
-       .long sys_lgetxattr
-       .long sys_fgetxattr
-       .long sys_listxattr
-       .long sys_llistxattr    /* 230 */
-       .long sys_flistxattr
-       .long sys_removexattr
-       .long sys_lremovexattr
-       .long sys_fremovexattr
-       .long sys_futex         /* 235 */
-       .long sys_sendfile64
-       .long sys_ni_syscall    /* sys_mincore */
-       .long sys_ni_syscall    /* sys_madvise */
-       .long sys_fcntl64
-       .long sys_readahead     /* 240 */
-       .long sys_io_setup
-       .long sys_io_destroy
-       .long sys_io_getevents
-       .long sys_io_submit
-       .long sys_io_cancel     /* 245 */
-       .long sys_fadvise64
-       .long sys_exit_group
-       .long sys_lookup_dcookie
-       .long sys_epoll_create
-       .long sys_epoll_ctl     /* 250 */
-       .long sys_epoll_wait
-       .long sys_ni_syscall    /* sys_remap_file_pages */
-       .long sys_set_tid_address
-       .long sys_timer_create
-       .long sys_timer_settime /* 255 */
-       .long sys_timer_gettime
-       .long sys_timer_getoverrun
-       .long sys_timer_delete
-       .long sys_clock_settime
-       .long sys_clock_gettime /* 260 */
-       .long sys_clock_getres
-       .long sys_clock_nanosleep
-       .long sys_statfs64
-       .long sys_fstatfs64
-       .long sys_tgkill        /* 265 */
-       .long sys_utimes
-       .long sys_fadvise64_64
-       .long sys_mbind 
-       .long sys_get_mempolicy
-       .long sys_set_mempolicy /* 270 */
-       .long sys_mq_open
-       .long sys_mq_unlink
-       .long sys_mq_timedsend
-       .long sys_mq_timedreceive
-       .long sys_mq_notify     /* 275 */
-       .long sys_mq_getsetattr
-       .long sys_waitid
-       .long sys_ni_syscall    /* for sys_vserver */
-       .long sys_add_key
-       .long sys_request_key   /* 280 */
-       .long sys_keyctl
-       .long sys_ioprio_set
-       .long sys_ioprio_get
-       .long sys_inotify_init
-       .long sys_inotify_add_watch     /* 285 */
-       .long sys_inotify_rm_watch
-       .long sys_migrate_pages
-       .long sys_openat
-       .long sys_mkdirat
-       .long sys_mknodat               /* 290 */
-       .long sys_fchownat
-       .long sys_futimesat
-       .long sys_fstatat64
-       .long sys_unlinkat
-       .long sys_renameat              /* 295 */
-       .long sys_linkat
-       .long sys_symlinkat
-       .long sys_readlinkat
-       .long sys_fchmodat
-       .long sys_faccessat             /* 300 */
-       .long sys_ni_syscall            /* Reserved for pselect6 */
-       .long sys_ni_syscall            /* Reserved for ppoll */
-       .long sys_unshare
-       .long sys_set_robust_list
-       .long sys_get_robust_list       /* 305 */
-       .long sys_splice
-       .long sys_sync_file_range
-       .long sys_tee
-       .long sys_vmsplice
-       .long sys_move_pages            /* 310 */
-       .long sys_sched_setaffinity
-       .long sys_sched_getaffinity
-       .long sys_kexec_load
-       .long sys_getcpu
-       .long sys_epoll_pwait           /* 315 */
-       .long sys_utimensat
-       .long sys_signalfd
-       .long sys_timerfd_create
-       .long sys_eventfd
-       .long sys_fallocate             /* 320 */
-       .long sys_timerfd_settime
-       .long sys_timerfd_gettime
-       .long sys_signalfd4
-       .long sys_eventfd2
-       .long sys_epoll_create1         /* 325 */
-       .long sys_dup3
-       .long sys_pipe2
-       .long sys_inotify_init1
-       .long sys_preadv
-       .long sys_pwritev               /* 330 */
-       .long sys_rt_tgsigqueueinfo
-       .long sys_perf_event_open
-       .long sys_get_thread_area
-       .long sys_set_thread_area
-       .long sys_atomic_cmpxchg_32     /* 335 */
-       .long sys_atomic_barrier
-       .long sys_fanotify_init
-       .long sys_fanotify_mark
-       .long sys_prlimit64
-
-       .rept NR_syscalls-(.-sys_call_table)/4
-               .long sys_ni_syscall
-       .endr
-
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
deleted file mode 100644 (file)
index 6623909..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/time.c
- *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *
- * This file contains the m68k-specific time handling details.
- * Most of the stuff is located in the machine specific files.
- *
- * 1997-09-10  Updated NTP code according to technical memorandum Jan '96
- *             "A Kernel Model for Precision Timekeeping" by Dave Mills
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/profile.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/machdep.h>
-#include <asm/irq_regs.h>
-
-#define        TICK_SIZE (tick_nsec / 1000)
-
-static inline int set_rtc_mmss(unsigned long nowtime)
-{
-       if (mach_set_clock_mmss)
-               return mach_set_clock_mmss (nowtime);
-       return -1;
-}
-
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "xtime_update()" routine every clocktick
- */
-irqreturn_t arch_timer_interrupt(int irq, void *dummy)
-{
-
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-
-       xtime_update(1);
-
-       update_process_times(user_mode(get_irq_regs()));
-
-       return(IRQ_HANDLED);
-}
-#endif
-
-static unsigned long read_rtc_mmss(void)
-{
-       unsigned int year, mon, day, hour, min, sec;
-
-       if (mach_gettod) {
-               mach_gettod(&year, &mon, &day, &hour, &min, &sec);
-               if ((year += 1900) < 1970)
-                       year += 100;
-       } else {
-               year = 1970;
-               mon = day = 1;
-               hour = min = sec = 0;
-       }
-
-
-       return  mktime(year, mon, day, hour, min, sec);
-}
-
-void read_persistent_clock(struct timespec *ts)
-{
-       ts->tv_sec = read_rtc_mmss();
-       ts->tv_nsec = 0;
-}
-
-int update_persistent_clock(struct timespec now)
-{
-       return set_rtc_mmss(now.tv_sec);
-}
-
-void time_init(void)
-{
-       hw_timer_init();
-}
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
deleted file mode 100644 (file)
index a768008..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- *  linux/arch/m68knommu/kernel/traps.c
- *
- *  Copyright (C) 1993, 1994 by Hamish Macdonald
- *
- *  68040 fixes by Michael Rausch
- *  68040 fixes by Martin Apel
- *  68060 fixes by Roman Hodek
- *  68060 fixes by Jesper Skov
- *
- * 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.
- */
-
-/*
- * Sets up all exception vectors
- */
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/user.h>
-#include <linux/string.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/kallsyms.h>
-
-#include <asm/setup.h>
-#include <asm/fpu.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/traps.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/siginfo.h>
-
-static char const * const vec_names[] = {
-       "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
-       "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
-       "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
-       "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
-       "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
-       "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
-       "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
-       "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
-       "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
-       "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
-       "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
-       "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
-       "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
-       "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
-       "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
-       "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
-       "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
-       "FPCP UNSUPPORTED OPERATION",
-       "MMU CONFIGURATION ERROR"
-};
-
-void __init trap_init(void)
-{
-}
-
-void die_if_kernel(char *str, struct pt_regs *fp, int nr)
-{
-       if (!(fp->sr & PS_S))
-               return;
-
-       console_verbose();
-       printk(KERN_EMERG "%s: %08x\n",str,nr);
-       printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
-              fp->pc, fp->sr, fp, fp->a2);
-       printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
-              fp->d0, fp->d1, fp->d2, fp->d3);
-       printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
-              fp->d4, fp->d5, fp->a0, fp->a1);
-
-       printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
-               current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-       show_stack(NULL, (unsigned long *)(fp + 1));
-       add_taint(TAINT_DIE);
-       do_exit(SIGSEGV);
-}
-
-asmlinkage void buserr_c(struct frame *fp)
-{
-       /* Only set esp0 if coming from user mode */
-       if (user_mode(&fp->ptregs))
-               current->thread.esp0 = (unsigned long) fp;
-
-#if defined(DEBUG)
-       printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
-#endif
-
-       die_if_kernel("bad frame format",&fp->ptregs,0);
-#if defined(DEBUG)
-       printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
-#endif
-       force_sig(SIGSEGV, current);
-}
-
-static void print_this_address(unsigned long addr, int i)
-{
-#ifdef CONFIG_KALLSYMS
-       printk(KERN_EMERG " [%08lx] ", addr);
-       print_symbol(KERN_CONT "%s\n", addr);
-#else
-       if (i % 5)
-               printk(KERN_CONT " [%08lx] ", addr);
-       else
-               printk(KERN_EMERG " [%08lx] ", addr);
-       i++;
-#endif
-}
-
-int kstack_depth_to_print = 48;
-
-static void __show_stack(struct task_struct *task, unsigned long *stack)
-{
-       unsigned long *endstack, addr;
-#ifdef CONFIG_FRAME_POINTER
-       unsigned long *last_stack;
-#endif
-       int i;
-
-       if (!stack)
-               stack = (unsigned long *)task->thread.ksp;
-
-       addr = (unsigned long) stack;
-       endstack = (unsigned long *) PAGE_ALIGN(addr);
-
-       printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
-       for (i = 0; i < kstack_depth_to_print; i++) {
-               if (stack + 1 + i > endstack)
-                       break;
-               if (i % 8 == 0)
-                       printk(KERN_EMERG "       ");
-               printk(KERN_CONT " %08lx", *(stack + i));
-       }
-       printk("\n");
-       i = 0;
-
-#ifdef CONFIG_FRAME_POINTER
-       printk(KERN_EMERG "Call Trace:\n");
-
-       last_stack = stack - 1;
-       while (stack <= endstack && stack > last_stack) {
-
-               addr = *(stack + 1);
-               print_this_address(addr, i);
-               i++;
-
-               last_stack = stack;
-               stack = (unsigned long *)*stack;
-       }
-       printk("\n");
-#else
-       printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
-       while (stack <= endstack) {
-               addr = *stack++;
-               /*
-                * If the address is either in the text segment of the kernel,
-                * or in a region which is occupied by a module then it *may*
-                * be the address of a calling routine; if so, print it so that
-                * someone tracing down the cause of the crash will be able to
-                * figure out the call path that was taken.
-                */
-               if (__kernel_text_address(addr)) {
-                       print_this_address(addr, i);
-                       i++;
-               }
-       }
-       printk(KERN_CONT "\n");
-#endif
-}
-
-void bad_super_trap(struct frame *fp)
-{
-       int vector = (fp->ptregs.vector >> 2) & 0xff;
-
-       console_verbose();
-       if (vector < ARRAY_SIZE(vec_names))
-               printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
-                       vec_names[vector],
-                       fp->ptregs.format);
-       else
-               printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
-                       vector,
-                       fp->ptregs.format);
-       printk (KERN_WARNING "Current process id is %d\n", current->pid);
-       die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
-}
-
-asmlinkage void trap_c(struct frame *fp)
-{
-       int sig;
-       int vector = (fp->ptregs.vector >> 2) & 0xff;
-       siginfo_t info;
-
-       if (fp->ptregs.sr & PS_S) {
-               if (vector == VEC_TRACE) {
-                       /* traced a trapping instruction */
-               } else
-                       bad_super_trap(fp);
-               return;
-       }
-
-       /* send the appropriate signal to the user program */
-       switch (vector) {
-           case VEC_ADDRERR:
-               info.si_code = BUS_ADRALN;
-               sig = SIGBUS;
-               break;
-           case VEC_ILLEGAL:
-           case VEC_LINE10:
-           case VEC_LINE11:
-               info.si_code = ILL_ILLOPC;
-               sig = SIGILL;
-               break;
-           case VEC_PRIV:
-               info.si_code = ILL_PRVOPC;
-               sig = SIGILL;
-               break;
-           case VEC_COPROC:
-               info.si_code = ILL_COPROC;
-               sig = SIGILL;
-               break;
-           case VEC_TRAP1: /* gdbserver breakpoint */
-               fp->ptregs.pc -= 2;
-               info.si_code = TRAP_TRACE;
-               sig = SIGTRAP;
-               break;
-           case VEC_TRAP2:
-           case VEC_TRAP3:
-           case VEC_TRAP4:
-           case VEC_TRAP5:
-           case VEC_TRAP6:
-           case VEC_TRAP7:
-           case VEC_TRAP8:
-           case VEC_TRAP9:
-           case VEC_TRAP10:
-           case VEC_TRAP11:
-           case VEC_TRAP12:
-           case VEC_TRAP13:
-           case VEC_TRAP14:
-               info.si_code = ILL_ILLTRP;
-               sig = SIGILL;
-               break;
-           case VEC_FPBRUC:
-           case VEC_FPOE:
-           case VEC_FPNAN:
-               info.si_code = FPE_FLTINV;
-               sig = SIGFPE;
-               break;
-           case VEC_FPIR:
-               info.si_code = FPE_FLTRES;
-               sig = SIGFPE;
-               break;
-           case VEC_FPDIVZ:
-               info.si_code = FPE_FLTDIV;
-               sig = SIGFPE;
-               break;
-           case VEC_FPUNDER:
-               info.si_code = FPE_FLTUND;
-               sig = SIGFPE;
-               break;
-           case VEC_FPOVER:
-               info.si_code = FPE_FLTOVF;
-               sig = SIGFPE;
-               break;
-           case VEC_ZERODIV:
-               info.si_code = FPE_INTDIV;
-               sig = SIGFPE;
-               break;
-           case VEC_CHK:
-           case VEC_TRAP:
-               info.si_code = FPE_INTOVF;
-               sig = SIGFPE;
-               break;
-           case VEC_TRACE:             /* ptrace single step */
-               info.si_code = TRAP_TRACE;
-               sig = SIGTRAP;
-               break;
-           case VEC_TRAP15:            /* breakpoint */
-               info.si_code = TRAP_BRKPT;
-               sig = SIGTRAP;
-               break;
-           default:
-               info.si_code = ILL_ILLOPC;
-               sig = SIGILL;
-               break;
-       }
-       info.si_signo = sig;
-       info.si_errno = 0;
-       switch (fp->ptregs.format) {
-           default:
-               info.si_addr = (void *) fp->ptregs.pc;
-               break;
-           case 2:
-               info.si_addr = (void *) fp->un.fmt2.iaddr;
-               break;
-           case 7:
-               info.si_addr = (void *) fp->un.fmt7.effaddr;
-               break;
-           case 9:
-               info.si_addr = (void *) fp->un.fmt9.iaddr;
-               break;
-           case 10:
-               info.si_addr = (void *) fp->un.fmta.daddr;
-               break;
-           case 11:
-               info.si_addr = (void *) fp->un.fmtb.daddr;
-               break;
-       }
-       force_sig_info (sig, &info, current);
-}
-
-asmlinkage void set_esp0(unsigned long ssp)
-{
-       current->thread.esp0 = ssp;
-}
-
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
-       /*
-        * We need frame pointers for this little trick, which works as follows:
-        *
-        * +------------+ 0x00
-        * | Next SP    |       -> 0x0c
-        * +------------+ 0x04
-        * | Caller     |
-        * +------------+ 0x08
-        * | Local vars |       -> our stack var
-        * +------------+ 0x0c
-        * | Next SP    |       -> 0x18, that is what we pass to show_stack()
-        * +------------+ 0x10
-        * | Caller     |
-        * +------------+ 0x14
-        * | Local vars |
-        * +------------+ 0x18
-        * | ...        |
-        * +------------+
-        */
-
-       unsigned long *stack;
-
-       stack = (unsigned long *)&stack;
-       stack++;
-       __show_stack(current, stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void show_stack(struct task_struct *task, unsigned long *stack)
-{
-       if (!stack && !task)
-               dump_stack();
-       else
-               __show_stack(task, stack);
-}
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
deleted file mode 100644 (file)
index 47e15eb..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *     vmlinux.lds.S -- master linker script for m68knommu arch
- *
- *     (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
- *
- *     This linker script is equiped to build either ROM loaded or RAM
- *     run kernels.
- */
-
-#include <asm-generic/vmlinux.lds.h>
-#include <asm/page.h>
-#include <asm/thread_info.h>
-
-#if defined(CONFIG_RAMKERNEL)
-#define        RAM_START       CONFIG_KERNELBASE
-#define        RAM_LENGTH      (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
-#define        TEXT            ram
-#define        DATA            ram
-#define        INIT            ram
-#define        BSSS            ram
-#endif
-#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
-#define        RAM_START       CONFIG_RAMBASE
-#define        RAM_LENGTH      CONFIG_RAMSIZE
-#define        ROMVEC_START    CONFIG_ROMVEC
-#define        ROMVEC_LENGTH   CONFIG_ROMVECSIZE
-#define        ROM_START       CONFIG_ROMSTART
-#define        ROM_LENGTH      CONFIG_ROMSIZE
-#define        TEXT            rom
-#define        DATA            ram
-#define        INIT            ram
-#define        BSSS            ram
-#endif
-
-#ifndef DATA_ADDR
-#define        DATA_ADDR
-#endif
-
-
-OUTPUT_ARCH(m68k)
-ENTRY(_start)
-
-MEMORY {
-       ram     : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
-#ifdef ROM_START
-       romvec  : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
-       rom     : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
-#endif
-}
-
-jiffies = jiffies_64 + 4;
-
-SECTIONS {
-
-#ifdef ROMVEC_START
-       . = ROMVEC_START ;
-       .romvec : {
-               __rom_start = . ;
-               _romvec = .;
-               *(.data..initvect)
-       } > romvec
-#endif
-
-       .text : {
-               _text = .;
-               _stext = . ;
-               HEAD_TEXT
-               TEXT_TEXT
-               SCHED_TEXT
-               LOCK_TEXT
-               *(.text..lock)
-
-               . = ALIGN(16);          /* Exception table              */
-               __start___ex_table = .;
-               *(__ex_table)
-               __stop___ex_table = .;
-
-               *(.rodata) *(.rodata.*)
-               *(__vermagic)           /* Kernel version magic */
-               *(__markers_strings)
-               *(.rodata1)
-               *(.rodata.str1.1)
-
-               /* Kernel symbol table: Normal symbols */
-               . = ALIGN(4);
-               __start___ksymtab = .;
-               *(__ksymtab)
-               __stop___ksymtab = .;
-
-               /* Kernel symbol table: GPL-only symbols */
-               __start___ksymtab_gpl = .;
-               *(__ksymtab_gpl)
-               __stop___ksymtab_gpl = .;
-
-               /* Kernel symbol table: Normal unused symbols */
-               __start___ksymtab_unused = .;
-               *(__ksymtab_unused)
-               __stop___ksymtab_unused = .;
-
-               /* Kernel symbol table: GPL-only unused symbols */
-               __start___ksymtab_unused_gpl = .;
-               *(__ksymtab_unused_gpl)
-               __stop___ksymtab_unused_gpl = .;
-
-               /* Kernel symbol table: GPL-future symbols */
-               __start___ksymtab_gpl_future = .;
-               *(__ksymtab_gpl_future)
-               __stop___ksymtab_gpl_future = .;
-
-               /* Kernel symbol table: Normal symbols */
-               __start___kcrctab = .;
-               *(__kcrctab)
-               __stop___kcrctab = .;
-
-               /* Kernel symbol table: GPL-only symbols */
-               __start___kcrctab_gpl = .;
-               *(__kcrctab_gpl)
-               __stop___kcrctab_gpl = .;
-
-               /* Kernel symbol table: Normal unused symbols */
-               __start___kcrctab_unused = .;
-               *(__kcrctab_unused)
-               __stop___kcrctab_unused = .;
-
-               /* Kernel symbol table: GPL-only unused symbols */
-               __start___kcrctab_unused_gpl = .;
-               *(__kcrctab_unused_gpl)
-               __stop___kcrctab_unused_gpl = .;
-
-               /* Kernel symbol table: GPL-future symbols */
-               __start___kcrctab_gpl_future = .;
-               *(__kcrctab_gpl_future)
-               __stop___kcrctab_gpl_future = .;
-
-               /* Kernel symbol table: strings */
-               *(__ksymtab_strings)
-
-               /* Built-in module parameters */
-               . = ALIGN(4) ;
-               __start___param = .;
-               *(__param)
-               __stop___param = .;
-
-               /* Built-in module versions */
-               . = ALIGN(4) ;
-               __start___modver = .;
-               *(__modver)
-               __stop___modver = .;
-
-               . = ALIGN(4) ;
-               _etext = . ;
-       } > TEXT
-
-       .data DATA_ADDR : {
-               . = ALIGN(4);
-               _sdata = . ;
-               DATA_DATA
-               CACHELINE_ALIGNED_DATA(32)
-               PAGE_ALIGNED_DATA(PAGE_SIZE)
-               *(.data..shared_aligned)
-               INIT_TASK_DATA(THREAD_SIZE)
-               _edata = . ;
-       } > DATA
-
-       .init.text : {
-               . = ALIGN(PAGE_SIZE);
-               __init_begin = .;
-       } > INIT
-       INIT_TEXT_SECTION(PAGE_SIZE) > INIT
-       INIT_DATA_SECTION(16) > INIT
-       .init.data : {
-               . = ALIGN(PAGE_SIZE);
-               __init_end = .;
-       } > INIT
-
-       .bss : {
-               . = ALIGN(4);
-               _sbss = . ;
-               *(.bss)
-               *(COMMON)
-               . = ALIGN(4) ;
-               _ebss = . ;
-               _end = . ;
-       } > BSSS
-
-       DISCARDS
-}
-
diff --git a/arch/m68knommu/lib/Makefile b/arch/m68knommu/lib/Makefile
deleted file mode 100644 (file)
index 32d852e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for m68knommu specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
-          muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68knommu/lib/ashldi3.c b/arch/m68knommu/lib/ashldi3.c
deleted file mode 100644 (file)
index 008403e..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ashrdi3.c extracted from gcc-2.95.2/libgcc2.c which is: */
-/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__ashldi3 (DItype u, word_type b)
-{
-  DIunion w;
-  word_type bm;
-  DIunion uu;
-
-  if (b == 0)
-    return u;
-
-  uu.ll = u;
-
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
-  if (bm <= 0)
-    {
-      w.s.low = 0;
-      w.s.high = (USItype)uu.s.low << -bm;
-    }
-  else
-    {
-      USItype carries = (USItype)uu.s.low >> bm;
-      w.s.low = (USItype)uu.s.low << b;
-      w.s.high = ((USItype)uu.s.high << b) | carries;
-    }
-
-  return w.ll;
-}
diff --git a/arch/m68knommu/lib/ashrdi3.c b/arch/m68knommu/lib/ashrdi3.c
deleted file mode 100644 (file)
index 78efb65..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__ashrdi3 (DItype u, word_type b)
-{
-  DIunion w;
-  word_type bm;
-  DIunion uu;
-
-  if (b == 0)
-    return u;
-
-  uu.ll = u;
-
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
-  if (bm <= 0)
-    {
-      /* w.s.high = 1..1 or 0..0 */
-      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
-      w.s.low = uu.s.high >> -bm;
-    }
-  else
-    {
-      USItype carries = (USItype)uu.s.high << bm;
-      w.s.high = uu.s.high >> b;
-      w.s.low = ((USItype)uu.s.low >> b) | carries;
-    }
-
-  return w.ll;
-}
diff --git a/arch/m68knommu/lib/checksum.c b/arch/m68knommu/lib/checksum.c
deleted file mode 100644 (file)
index eccf25d..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * INET                An implementation of the TCP/IP protocol suite for the LINUX
- *             operating system.  INET is implemented using the  BSD Socket
- *             interface as the means of communication with the user level.
- *
- *             IP/TCP/UDP checksumming routines
- *
- * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
- *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *             Tom May, <ftom@netcom.com>
- *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
- *             Lots of code moved from tcp.c and ip.c; see those files
- *             for more names.
- *
- * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
- *             Fixed some nasty bugs, causing some horrible crashes.
- *             A: At some points, the sum (%0) was used as
- *             length-counter instead of the length counter
- *             (%1). Thanks to Roman Hodek for pointing this out.
- *             B: GCC seems to mess up if one uses too many
- *             data-registers to hold input values and one tries to
- *             specify d0 and d1 as scratch registers. Letting gcc choose these
- *      registers itself solves the problem.
- *
- *             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.
- */
-/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most
-   of the assembly has to go. */
-
-#include <linux/module.h>
-#include <net/checksum.h>
-
-static inline unsigned short from32to16(unsigned long x)
-{
-       /* add up 16-bit and 16-bit for 16+c bit */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
-}
-
-static unsigned long do_csum(const unsigned char * buff, int len)
-{
-       int odd, count;
-       unsigned long result = 0;
-
-       if (len <= 0)
-               goto out;
-       odd = 1 & (unsigned long) buff;
-       if (odd) {
-               result = *buff;
-               len--;
-               buff++;
-       }
-       count = len >> 1;               /* nr of 16-bit words.. */
-       if (count) {
-               if (2 & (unsigned long) buff) {
-                       result += *(unsigned short *) buff;
-                       count--;
-                       len -= 2;
-                       buff += 2;
-               }
-               count >>= 1;            /* nr of 32-bit words.. */
-               if (count) {
-                       unsigned long carry = 0;
-                       do {
-                               unsigned long w = *(unsigned long *) buff;
-                               count--;
-                               buff += 4;
-                               result += carry;
-                               result += w;
-                               carry = (w > result);
-                       } while (count);
-                       result += carry;
-                       result = (result & 0xffff) + (result >> 16);
-               }
-               if (len & 2) {
-                       result += *(unsigned short *) buff;
-                       buff += 2;
-               }
-       }
-       if (len & 1)
-               result += (*buff << 8);
-       result = from32to16(result);
-       if (odd)
-               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
-       return result;
-}
-
-#ifdef CONFIG_COLDFIRE
-/*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- */
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
-       return (__force __sum16)~do_csum(iph,ihl*4);
-}
-#endif
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum)
-{
-       unsigned int result = do_csum(buff, len);
-
-       /* add in old sum, and carry.. */
-       result += (__force u32)sum;
-       if ((__force u32)sum > result)
-               result += 1;
-       return (__force __wsum)result;
-}
-
-EXPORT_SYMBOL(csum_partial);
-
-/*
- * copy from fs while checksumming, otherwise like csum_partial
- */
-
-__wsum
-csum_partial_copy_from_user(const void __user *src, void *dst,
-                           int len, __wsum sum, int *csum_err)
-{
-       if (csum_err) *csum_err = 0;
-       memcpy(dst, (__force const void *)src, len);
-       return csum_partial(dst, len, sum);
-}
-
-/*
- * copy from ds while checksumming, otherwise like csum_partial
- */
-
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       memcpy(dst, src, len);
-       return csum_partial(dst, len, sum);
-}
diff --git a/arch/m68knommu/lib/delay.c b/arch/m68knommu/lib/delay.c
deleted file mode 100644 (file)
index 5bd5472..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *     arch/m68knommu/lib/delay.c
- *
- *     (C) Copyright 2004, Greg Ungerer <gerg@snapgear.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <asm/param.h>
-#include <asm/delay.h>
-
-EXPORT_SYMBOL(udelay);
-
-void udelay(unsigned long usecs)
-{
-       _udelay(usecs);
-}
-
diff --git a/arch/m68knommu/lib/divsi3.S b/arch/m68knommu/lib/divsi3.S
deleted file mode 100644 (file)
index ec307b6..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/* libgcc1 routines for 68000 w/o floating-point hardware.
-   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* Use this one for any 680x0; assumes no floating point hardware.
-   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
-   Some of this code comes from MINIX, via the folks at ericsson.
-   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
-*/
-
-/* These are predefined by new versions of GNU cpp.  */
-
-#ifndef __USER_LABEL_PREFIX__
-#define __USER_LABEL_PREFIX__ _
-#endif
-
-#ifndef __REGISTER_PREFIX__
-#define __REGISTER_PREFIX__
-#endif
-
-#ifndef __IMMEDIATE_PREFIX__
-#define __IMMEDIATE_PREFIX__ #
-#endif
-
-/* ANSI concatenation macros.  */
-
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels.  */
-
-#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-
-/* Use the right prefix for registers.  */
-
-#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
-
-/* Use the right prefix for immediate values.  */
-
-#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
-
-#define d0 REG (d0)
-#define d1 REG (d1)
-#define d2 REG (d2)
-#define d3 REG (d3)
-#define d4 REG (d4)
-#define d5 REG (d5)
-#define d6 REG (d6)
-#define d7 REG (d7)
-#define a0 REG (a0)
-#define a1 REG (a1)
-#define a2 REG (a2)
-#define a3 REG (a3)
-#define a4 REG (a4)
-#define a5 REG (a5)
-#define a6 REG (a6)
-#define fp REG (fp)
-#define sp REG (sp)
-
-       .text
-       .proc
-       .globl  SYM (__divsi3)
-SYM (__divsi3):
-       movel   d2, sp@-
-
-       moveq   IMM (1), d2     /* sign of result stored in d2 (=1 or =-1) */
-       movel   sp@(12), d1     /* d1 = divisor */
-       jpl     L1
-       negl    d1
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       negb    d2              /* change sign because divisor <0  */
-#else
-       negl    d2              /* change sign because divisor <0  */
-#endif
-L1:    movel   sp@(8), d0      /* d0 = dividend */
-       jpl     L2
-       negl    d0
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       negb    d2
-#else
-       negl    d2
-#endif
-
-L2:    movel   d1, sp@-
-       movel   d0, sp@-
-       jbsr    SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */
-       addql   IMM (8), sp
-
-       tstb    d2
-       jpl     L3
-       negl    d0
-
-L3:    movel   sp@+, d2
-       rts
-
diff --git a/arch/m68knommu/lib/lshrdi3.c b/arch/m68knommu/lib/lshrdi3.c
deleted file mode 100644 (file)
index 93b1cb6..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__lshrdi3 (DItype u, word_type b)
-{
-  DIunion w;
-  word_type bm;
-  DIunion uu;
-
-  if (b == 0)
-    return u;
-
-  uu.ll = u;
-
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
-  if (bm <= 0)
-    {
-      w.s.high = 0;
-      w.s.low = (USItype)uu.s.high >> -bm;
-    }
-  else
-    {
-      USItype carries = (USItype)uu.s.high << bm;
-      w.s.high = (USItype)uu.s.high >> b;
-      w.s.low = ((USItype)uu.s.low >> b) | carries;
-    }
-
-  return w.ll;
-}
diff --git a/arch/m68knommu/lib/memcpy.c b/arch/m68knommu/lib/memcpy.c
deleted file mode 100644 (file)
index b50dbca..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-
-#include <linux/types.h>
-
-void * memcpy(void * to, const void * from, size_t n)
-{
-#ifdef CONFIG_COLDFIRE
-  void *xto = to;
-  size_t temp;
-
-  if (!n)
-    return xto;
-  if ((long) to & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto++ = *cfrom++;
-      to = cto;
-      from = cfrom;
-      n--;
-    }
-  if (n > 2 && (long) to & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-      n -= 2;
-    }
-  temp = n >> 2;
-  if (temp)
-    {
-      long *lto = to;
-      const long *lfrom = from;
-      for (; temp; temp--)
-       *lto++ = *lfrom++;
-      to = lto;
-      from = lfrom;
-    }
-  if (n & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-    }
-  if (n & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto = *cfrom;
-    }
-  return xto;
-#else
-  const char *c_from = from;
-  char *c_to = to;
-  while (n-- > 0)
-    *c_to++ = *c_from++;
-  return((void *) to);
-#endif
-}
diff --git a/arch/m68knommu/lib/memmove.c b/arch/m68knommu/lib/memmove.c
deleted file mode 100644 (file)
index b3dcfe9..0000000
+++ /dev/null
@@ -1,105 +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.
- */
-
-#define __IN_STRING_C
-
-#include <linux/module.h>
-#include <linux/string.h>
-
-void *memmove(void *dest, const void *src, size_t n)
-{
-       void *xdest = dest;
-       size_t temp;
-
-       if (!n)
-               return xdest;
-
-       if (dest < src) {
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest++ = *csrc++;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *ldest++ = *lsrc++;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest = *csrc;
-               }
-       } else {
-               dest = (char *)dest + n;
-               src = (const char *)src + n;
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *--ldest = *--lsrc;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-               }
-       }
-       return xdest;
-}
-EXPORT_SYMBOL(memmove);
diff --git a/arch/m68knommu/lib/memset.c b/arch/m68knommu/lib/memset.c
deleted file mode 100644 (file)
index 1389bf4..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <linux/types.h>
-
-void * memset(void * s, int c, size_t count)
-{
-  void *xs = s;
-  size_t temp;
-
-  if (!count)
-    return xs;
-  c &= 0xff;
-  c |= c << 8;
-  c |= c << 16;
-  if ((long) s & 1)
-    {
-      char *cs = s;
-      *cs++ = c;
-      s = cs;
-      count--;
-    }
-  if (count > 2 && (long) s & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-      count -= 2;
-    }
-  temp = count >> 2;
-  if (temp)
-    {
-      long *ls = s;
-      for (; temp; temp--)
-       *ls++ = c;
-      s = ls;
-    }
-  if (count & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-    }
-  if (count & 1)
-    {
-      char *cs = s;
-      *cs = c;
-    }
-  return xs;
-}
diff --git a/arch/m68knommu/lib/modsi3.S b/arch/m68knommu/lib/modsi3.S
deleted file mode 100644 (file)
index ef38494..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* libgcc1 routines for 68000 w/o floating-point hardware.
-   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* Use this one for any 680x0; assumes no floating point hardware.
-   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
-   Some of this code comes from MINIX, via the folks at ericsson.
-   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
-*/
-
-/* These are predefined by new versions of GNU cpp.  */
-
-#ifndef __USER_LABEL_PREFIX__
-#define __USER_LABEL_PREFIX__ _
-#endif
-
-#ifndef __REGISTER_PREFIX__
-#define __REGISTER_PREFIX__
-#endif
-
-#ifndef __IMMEDIATE_PREFIX__
-#define __IMMEDIATE_PREFIX__ #
-#endif
-
-/* ANSI concatenation macros.  */
-
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels.  */
-
-#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-
-/* Use the right prefix for registers.  */
-
-#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
-
-/* Use the right prefix for immediate values.  */
-
-#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
-
-#define d0 REG (d0)
-#define d1 REG (d1)
-#define d2 REG (d2)
-#define d3 REG (d3)
-#define d4 REG (d4)
-#define d5 REG (d5)
-#define d6 REG (d6)
-#define d7 REG (d7)
-#define a0 REG (a0)
-#define a1 REG (a1)
-#define a2 REG (a2)
-#define a3 REG (a3)
-#define a4 REG (a4)
-#define a5 REG (a5)
-#define a6 REG (a6)
-#define fp REG (fp)
-#define sp REG (sp)
-
-       .text
-       .proc
-       .globl  SYM (__modsi3)
-SYM (__modsi3):
-       movel   sp@(8), d1      /* d1 = divisor */
-       movel   sp@(4), d0      /* d0 = dividend */
-       movel   d1, sp@-
-       movel   d0, sp@-
-       jbsr    SYM (__divsi3)
-       addql   IMM (8), sp
-       movel   sp@(8), d1      /* d1 = divisor */
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       movel   d1, sp@-
-       movel   d0, sp@-
-       jbsr    SYM (__mulsi3)  /* d0 = (a/b)*b */
-       addql   IMM (8), sp
-#else
-       mulsl   d1,d0
-#endif
-       movel   sp@(4), d1      /* d1 = dividend */
-       subl    d0, d1          /* d1 = a - (a/b)*b */
-       movel   d1, d0
-       rts
-
diff --git a/arch/m68knommu/lib/muldi3.c b/arch/m68knommu/lib/muldi3.c
deleted file mode 100644 (file)
index 34af72c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-#define SI_TYPE_SIZE 32
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
-#define __ll_highpart(t) ((USItype) (t) / __ll_B)
-
-#define umul_ppmm(w1, w0, u, v)                                                \
-  do {                                                                 \
-    USItype __x0, __x1, __x2, __x3;                                    \
-    USItype __ul, __vl, __uh, __vh;                                    \
-                                                                       \
-    __ul = __ll_lowpart (u);                                           \
-    __uh = __ll_highpart (u);                                          \
-    __vl = __ll_lowpart (v);                                           \
-    __vh = __ll_highpart (v);                                          \
-                                                                       \
-    __x0 = (USItype) __ul * __vl;                                      \
-    __x1 = (USItype) __ul * __vh;                                      \
-    __x2 = (USItype) __uh * __vl;                                      \
-    __x3 = (USItype) __uh * __vh;                                      \
-                                                                       \
-    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
-    __x1 += __x2;              /* but this indeed can */               \
-    if (__x1 < __x2)           /* did we get it? */                    \
-      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
-                                                                       \
-    (w1) = __x3 + __ll_highpart (__x1);                                        \
-    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
-  } while (0)
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
diff --git a/arch/m68knommu/lib/mulsi3.S b/arch/m68knommu/lib/mulsi3.S
deleted file mode 100644 (file)
index ce29ea3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* libgcc1 routines for 68000 w/o floating-point hardware.
-   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* Use this one for any 680x0; assumes no floating point hardware.
-   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
-   Some of this code comes from MINIX, via the folks at ericsson.
-   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
-*/
-
-/* These are predefined by new versions of GNU cpp.  */
-
-#ifndef __USER_LABEL_PREFIX__
-#define __USER_LABEL_PREFIX__ _
-#endif
-
-#ifndef __REGISTER_PREFIX__
-#define __REGISTER_PREFIX__
-#endif
-
-#ifndef __IMMEDIATE_PREFIX__
-#define __IMMEDIATE_PREFIX__ #
-#endif
-
-/* ANSI concatenation macros.  */
-
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels.  */
-
-#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-
-/* Use the right prefix for registers.  */
-
-#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
-
-/* Use the right prefix for immediate values.  */
-
-#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
-
-#define d0 REG (d0)
-#define d1 REG (d1)
-#define d2 REG (d2)
-#define d3 REG (d3)
-#define d4 REG (d4)
-#define d5 REG (d5)
-#define d6 REG (d6)
-#define d7 REG (d7)
-#define a0 REG (a0)
-#define a1 REG (a1)
-#define a2 REG (a2)
-#define a3 REG (a3)
-#define a4 REG (a4)
-#define a5 REG (a5)
-#define a6 REG (a6)
-#define fp REG (fp)
-#define sp REG (sp)
-
-       .text
-       .proc
-       .globl  SYM (__mulsi3)
-SYM (__mulsi3):
-       movew   sp@(4), d0      /* x0 -> d0 */
-       muluw   sp@(10), d0     /* x0*y1 */
-       movew   sp@(6), d1      /* x1 -> d1 */
-       muluw   sp@(8), d1      /* x1*y0 */
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       addw    d1, d0
-#else
-       addl    d1, d0
-#endif
-       swap    d0
-       clrw    d0
-       movew   sp@(6), d1      /* x1 -> d1 */
-       muluw   sp@(10), d1     /* x1*y1 */
-       addl    d1, d0
-
-       rts
-
diff --git a/arch/m68knommu/lib/udivsi3.S b/arch/m68knommu/lib/udivsi3.S
deleted file mode 100644 (file)
index c424c4a..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* libgcc1 routines for 68000 w/o floating-point hardware.
-   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* Use this one for any 680x0; assumes no floating point hardware.
-   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
-   Some of this code comes from MINIX, via the folks at ericsson.
-   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
-*/
-
-/* These are predefined by new versions of GNU cpp.  */
-
-#ifndef __USER_LABEL_PREFIX__
-#define __USER_LABEL_PREFIX__ _
-#endif
-
-#ifndef __REGISTER_PREFIX__
-#define __REGISTER_PREFIX__
-#endif
-
-#ifndef __IMMEDIATE_PREFIX__
-#define __IMMEDIATE_PREFIX__ #
-#endif
-
-/* ANSI concatenation macros.  */
-
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels.  */
-
-#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-
-/* Use the right prefix for registers.  */
-
-#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
-
-/* Use the right prefix for immediate values.  */
-
-#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
-
-#define d0 REG (d0)
-#define d1 REG (d1)
-#define d2 REG (d2)
-#define d3 REG (d3)
-#define d4 REG (d4)
-#define d5 REG (d5)
-#define d6 REG (d6)
-#define d7 REG (d7)
-#define a0 REG (a0)
-#define a1 REG (a1)
-#define a2 REG (a2)
-#define a3 REG (a3)
-#define a4 REG (a4)
-#define a5 REG (a5)
-#define a6 REG (a6)
-#define fp REG (fp)
-#define sp REG (sp)
-
-       .text
-       .proc
-       .globl  SYM (__udivsi3)
-SYM (__udivsi3):
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       movel   d2, sp@-
-       movel   sp@(12), d1     /* d1 = divisor */
-       movel   sp@(8), d0      /* d0 = dividend */
-
-       cmpl    IMM (0x10000), d1 /* divisor >= 2 ^ 16 ?   */
-       jcc     L3              /* then try next algorithm */
-       movel   d0, d2
-       clrw    d2
-       swap    d2
-       divu    d1, d2          /* high quotient in lower word */
-       movew   d2, d0          /* save high quotient */
-       swap    d0
-       movew   sp@(10), d2     /* get low dividend + high rest */
-       divu    d1, d2          /* low quotient */
-       movew   d2, d0
-       jra     L6
-
-L3:    movel   d1, d2          /* use d2 as divisor backup */
-L4:    lsrl    IMM (1), d1     /* shift divisor */
-       lsrl    IMM (1), d0     /* shift dividend */
-       cmpl    IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ?  */
-       jcc     L4
-       divu    d1, d0          /* now we have 16 bit divisor */
-       andl    IMM (0xffff), d0 /* mask out divisor, ignore remainder */
-
-/* Multiply the 16 bit tentative quotient with the 32 bit divisor.  Because of
-   the operand ranges, this might give a 33 bit product.  If this product is
-   greater than the dividend, the tentative quotient was too large. */
-       movel   d2, d1
-       mulu    d0, d1          /* low part, 32 bits */
-       swap    d2
-       mulu    d0, d2          /* high part, at most 17 bits */
-       swap    d2              /* align high part with low part */
-       tstw    d2              /* high part 17 bits? */
-       jne     L5              /* if 17 bits, quotient was too large */
-       addl    d2, d1          /* add parts */
-       jcs     L5              /* if sum is 33 bits, quotient was too large */
-       cmpl    sp@(8), d1      /* compare the sum with the dividend */
-       jls     L6              /* if sum > dividend, quotient was too large */
-L5:    subql   IMM (1), d0     /* adjust quotient */
-
-L6:    movel   sp@+, d2
-       rts
-
-#else /* __mcf5200__ || __mcoldfire__ */
-
-/* Coldfire implementation of non-restoring division algorithm from
-   Hennessy & Patterson, Appendix A. */
-       link    a6,IMM (-12)
-       moveml  d2-d4,sp@
-       movel   a6@(8),d0
-       movel   a6@(12),d1
-       clrl    d2              | clear p
-       moveq   IMM (31),d4
-L1:    addl    d0,d0           | shift reg pair (p,a) one bit left
-       addxl   d2,d2
-       movl    d2,d3           | subtract b from p, store in tmp.
-       subl    d1,d3
-       jcs     L2              | if no carry,
-       bset    IMM (0),d0      | set the low order bit of a to 1,
-       movl    d3,d2           | and store tmp in p.
-L2:    subql   IMM (1),d4
-       jcc     L1
-       moveml  sp@,d2-d4       | restore data registers
-       unlk    a6              | and return
-       rts
-#endif /* __mcf5200__ || __mcoldfire__ */
-
diff --git a/arch/m68knommu/lib/umodsi3.S b/arch/m68knommu/lib/umodsi3.S
deleted file mode 100644 (file)
index 5def5f6..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* libgcc1 routines for 68000 w/o floating-point hardware.
-   Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file.  (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, if you link this library with files
-   compiled with GCC to produce an executable, this does not cause
-   the resulting executable to be covered by the GNU General Public License.
-   This exception does not however invalidate any other reasons why
-   the executable file might be covered by the GNU General Public License.  */
-
-/* Use this one for any 680x0; assumes no floating point hardware.
-   The trailing " '" appearing on some lines is for ANSI preprocessors.  Yuk.
-   Some of this code comes from MINIX, via the folks at ericsson.
-   D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992
-*/
-
-/* These are predefined by new versions of GNU cpp.  */
-
-#ifndef __USER_LABEL_PREFIX__
-#define __USER_LABEL_PREFIX__ _
-#endif
-
-#ifndef __REGISTER_PREFIX__
-#define __REGISTER_PREFIX__
-#endif
-
-#ifndef __IMMEDIATE_PREFIX__
-#define __IMMEDIATE_PREFIX__ #
-#endif
-
-/* ANSI concatenation macros.  */
-
-#define CONCAT1(a, b) CONCAT2(a, b)
-#define CONCAT2(a, b) a ## b
-
-/* Use the right prefix for global labels.  */
-
-#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
-
-/* Use the right prefix for registers.  */
-
-#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
-
-/* Use the right prefix for immediate values.  */
-
-#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x)
-
-#define d0 REG (d0)
-#define d1 REG (d1)
-#define d2 REG (d2)
-#define d3 REG (d3)
-#define d4 REG (d4)
-#define d5 REG (d5)
-#define d6 REG (d6)
-#define d7 REG (d7)
-#define a0 REG (a0)
-#define a1 REG (a1)
-#define a2 REG (a2)
-#define a3 REG (a3)
-#define a4 REG (a4)
-#define a5 REG (a5)
-#define a6 REG (a6)
-#define fp REG (fp)
-#define sp REG (sp)
-
-       .text
-       .proc
-       .globl  SYM (__umodsi3)
-SYM (__umodsi3):
-       movel   sp@(8), d1      /* d1 = divisor */
-       movel   sp@(4), d0      /* d0 = dividend */
-       movel   d1, sp@-
-       movel   d0, sp@-
-       jbsr    SYM (__udivsi3)
-       addql   IMM (8), sp
-       movel   sp@(8), d1      /* d1 = divisor */
-#if !(defined(__mcf5200__) || defined(__mcoldfire__))
-       movel   d1, sp@-
-       movel   d0, sp@-
-       jbsr    SYM (__mulsi3)  /* d0 = (a/b)*b */
-       addql   IMM (8), sp
-#else
-       mulsl   d1,d0
-#endif
-       movel   sp@(4), d1      /* d1 = dividend */
-       subl    d0, d1          /* d1 = a - (a/b)*b */
-       movel   d1, d0
-       rts
-
diff --git a/arch/m68knommu/mm/Makefile b/arch/m68knommu/mm/Makefile
deleted file mode 100644 (file)
index b54ab6b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux m68knommu specific parts of the memory manager.
-#
-
-obj-y += init.o kmap.o
diff --git a/arch/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c
deleted file mode 100644 (file)
index 8a6653f..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- *  linux/arch/m68knommu/mm/init.c
- *
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com) 
- *
- *  Based on:
- *
- *  linux/arch/m68k/mm/init.c
- *
- *  Copyright (C) 1995  Hamish Macdonald
- *
- *  JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
- *  DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
- */
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-#include <linux/pagemap.h>
-#include <linux/bootmem.h>
-#include <linux/gfp.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/machdep.h>
-
-#undef DEBUG
-
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void free_initmem(void);
-
-/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
- */
-static unsigned long empty_bad_page_table;
-
-static unsigned long empty_bad_page;
-
-unsigned long empty_zero_page;
-
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
-/*
- * paging_init() continues the virtual memory environment setup which
- * was begun by the code in arch/head.S.
- * The parameters are pointers to where to stick the starting and ending
- * addresses of available kernel virtual memory.
- */
-void __init paging_init(void)
-{
-       /*
-        * Make sure start_mem is page aligned, otherwise bootmem and
-        * page_alloc get different views of the world.
-        */
-#ifdef DEBUG
-       unsigned long start_mem = PAGE_ALIGN(memory_start);
-#endif
-       unsigned long end_mem   = memory_end & PAGE_MASK;
-
-#ifdef DEBUG
-       printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       /*
-        * Initialize the bad page table and bad page to point
-        * to a couple of allocated pages.
-        */
-       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       memset((void *)empty_zero_page, 0, PAGE_SIZE);
-
-       /*
-        * Set up SFC/DFC registers (user data space).
-        */
-       set_fs (USER_DS);
-
-#ifdef DEBUG
-       printk (KERN_DEBUG "before free_area_init\n");
-
-       printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       {
-               unsigned long zones_size[MAX_NR_ZONES] = {0, };
-
-               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-               free_area_init(zones_size);
-       }
-}
-
-void __init mem_init(void)
-{
-       int codek = 0, datak = 0, initk = 0;
-       unsigned long tmp;
-       extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
-       extern unsigned int _ramend, _rambase;
-       unsigned long len = _ramend - _rambase;
-       unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
-       unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
-
-       pr_debug("Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
-
-       end_mem &= PAGE_MASK;
-       high_memory = (void *) end_mem;
-
-       start_mem = PAGE_ALIGN(start_mem);
-       max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT;
-
-       /* this will put all memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-       codek = (&_etext - &_stext) >> 10;
-       datak = (&_ebss - &_sdata) >> 10;
-       initk = (&__init_begin - &__init_end) >> 10;
-
-       tmp = nr_free_pages() << PAGE_SHIFT;
-       printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
-              tmp >> 10,
-              len >> 10,
-              codek,
-              datak
-              );
-}
-
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       int pages = 0;
-       for (; start < end; start += PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(start));
-               init_page_count(virt_to_page(start));
-               free_page(start);
-               totalram_pages++;
-               pages++;
-       }
-       printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages * (PAGE_SIZE / 1024));
-}
-#endif
-
-void
-free_initmem()
-{
-#ifdef CONFIG_RAMKERNEL
-       unsigned long addr;
-       extern char __init_begin, __init_end;
-       /*
-        * The following code should be cool even if these sections
-        * are not page aligned.
-        */
-       addr = PAGE_ALIGN((unsigned long)(&__init_begin));
-       /* next to check that the page we free is not a partial page */
-       for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
-               ClearPageReserved(virt_to_page(addr));
-               init_page_count(virt_to_page(addr));
-               free_page(addr);
-               totalram_pages++;
-       }
-       printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
-                       (addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
-                       (int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
-                       (int)(addr - PAGE_SIZE));
-#endif
-}
-
diff --git a/arch/m68knommu/mm/kmap.c b/arch/m68knommu/mm/kmap.c
deleted file mode 100644 (file)
index ece8d5a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  linux/arch/m68knommu/mm/kmap.c
- *
- *  Copyright (C) 2000 Lineo, <davidm@snapgear.com>
- *  Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-/*
- * Map some physical address range into the kernel address space.
- */
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       return (void *)physaddr;
-}
-
-/*
- * Unmap a ioremap()ed region again.
- */
-void iounmap(void *addr)
-{
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-}
diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile
deleted file mode 100644 (file)
index b5db056..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
-
diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
deleted file mode 100644 (file)
index 9c33546..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5206/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000-2001, Lineo Inc. (www.lineo.com) 
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5206_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5206_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5206_uart_platform,
-};
-
-static struct platform_device *m5206_devices[] __initdata = {
-       &m5206_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5206_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5206_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5206_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5206_uart_init_line(line, m5206_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5206_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5206_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m5206_cpu_reset;
-       m5206_timers_init();
-       m5206_uarts_init();
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(28, MCFINTC_EINT4);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5206/gpio.c b/arch/m68knommu/platform/5206/gpio.c
deleted file mode 100644 (file)
index b9ab4a1..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PP",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PADDR,
-               .podr                           = (void __iomem *) MCFSIM_PADAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile
deleted file mode 100644 (file)
index b5db056..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
-
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
deleted file mode 100644 (file)
index 9423979..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5206e/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfdma.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5206e_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5206e_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5206e_uart_platform,
-};
-
-static struct platform_device *m5206e_devices[] __initdata = {
-       &m5206e_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5206e_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5206e_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5206e_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5206e_uart_init_line(line, m5206e_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5206e_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5206e_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined(CONFIG_NETtel)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#endif /* CONFIG_NETtel */
-
-       mach_reset = m5206e_cpu_reset;
-       m5206e_timers_init();
-       m5206e_uarts_init();
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(28, MCFINTC_EINT4);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5206e/gpio.c b/arch/m68knommu/platform/5206e/gpio.c
deleted file mode 100644 (file)
index b9ab4a1..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PP",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PADDR,
-               .podr                           = (void __iomem *) MCFSIM_PADAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile
deleted file mode 100644 (file)
index ad3f4e5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for the M5208 specific file.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c
deleted file mode 100644 (file)
index 621238f..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/520x/config.c
- *
- *  Copyright (C) 2005,      Freescale (www.freescale.com)
- *  Copyright (C) 2005,      Intec Automation (mike@steroidmicros.com)
- *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m520x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m520x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m520x_uart_platform,
-};
-
-static struct resource m520x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 36,
-               .end            = 64 + 36,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 40,
-               .end            = 64 + 40,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 42,
-               .end            = 64 + 42,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m520x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m520x_fec_resources),
-       .resource               = m520x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m520x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    62
-#define MCFQSPI_CS1    63
-#define MCFQSPI_CS2    44
-
-static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m520x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       }
-}
-
-static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m520x_cs_control = {
-       .setup                  = m520x_cs_setup,
-       .teardown               = m520x_cs_teardown,
-       .select                 = m520x_cs_select,
-       .deselect               = m520x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m520x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 3,
-       .cs_control             = &m520x_cs_control,
-};
-
-static struct platform_device m520x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m520x_qspi_resources),
-       .resource               = m520x_qspi_resources,
-       .dev.platform_data      = &m520x_qspi_data,
-};
-
-static void __init m520x_qspi_init(void)
-{
-       u16 par;
-       /* setup Port QS for QSPI with gpio CS control */
-       writeb(0x3f, MCF_GPIO_PAR_QSPI);
-       /* make U1CTS and U2RTS gpio for cs_control */
-       par = readw(MCF_GPIO_PAR_UART);
-       par &= 0x00ff;
-       writew(par, MCF_GPIO_PAR_UART);
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-
-static struct platform_device *m520x_devices[] __initdata = {
-       &m520x_uart,
-       &m520x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m520x_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m520x_uart_init_line(int line, int irq)
-{
-       u16 par;
-       u8 par2;
-
-       switch (line) {
-       case 0:
-               par = readw(MCF_GPIO_PAR_UART);
-               par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
-                      MCF_GPIO_PAR_UART_PAR_URXD0;
-               writew(par, MCF_GPIO_PAR_UART);
-               break;
-       case 1:
-               par = readw(MCF_GPIO_PAR_UART);
-               par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
-                      MCF_GPIO_PAR_UART_PAR_URXD1;
-               writew(par, MCF_GPIO_PAR_UART);
-               break;
-       case 2:
-               par2 = readb(MCF_GPIO_PAR_FECI2C);
-               par2 &= ~0x0F;
-               par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
-                       MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
-               writeb(par2, MCF_GPIO_PAR_FECI2C);
-               break;
-       }
-}
-
-static void __init m520x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m520x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m520x_uart_init_line(line, m520x_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m520x_fec_init(void)
-{
-       u8 v;
-
-       /* Set multi-function pins to ethernet mode */
-       v = readb(MCF_GPIO_PAR_FEC);
-       writeb(v | 0xf0, MCF_GPIO_PAR_FEC);
-
-       v = readb(MCF_GPIO_PAR_FECI2C);
-       writeb(v | 0x0f, MCF_GPIO_PAR_FECI2C);
-}
-
-/***************************************************************************/
-
-static void m520x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m520x_cpu_reset;
-       m520x_uarts_init();
-       m520x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m520x_qspi_init();
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/520x/gpio.c b/arch/m68knommu/platform/520x/gpio.c
deleted file mode 100644 (file)
index d757328..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PIRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *) MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BUSCTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 8,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BE",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 16,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BE,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BE,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BE,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "CS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 25,
-                       .ngpio                  = 3,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECI2C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QSPI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMER",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 48,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UART",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 56,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UART,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UART,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UART,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECL,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68knommu/platform/523x/Makefile
deleted file mode 100644 (file)
index c04b8f7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68knommu/platform/523x/config.c
deleted file mode 100644 (file)
index 418a76f..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/523x/config.c
- *
- *     Sub-architcture dependant initialization code for the Freescale
- *     523x CPUs.
- *
- *     Copyright (C) 1999-2005, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m523x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
-       },
-       { },
-};
-
-static struct platform_device m523x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m523x_uart_platform,
-};
-
-static struct resource m523x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m523x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m523x_fec_resources),
-       .resource               = m523x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m523x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    103
-#define MCFQSPI_CS3    99
-
-static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m523x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m523x_cs_control = {
-       .setup                  = m523x_cs_setup,
-       .teardown               = m523x_cs_teardown,
-       .select                 = m523x_cs_select,
-       .deselect               = m523x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m523x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m523x_cs_control,
-};
-
-static struct platform_device m523x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m523x_qspi_resources),
-       .resource               = m523x_qspi_resources,
-       .dev.platform_data      = &m523x_qspi_data,
-};
-
-static void __init m523x_qspi_init(void)
-{
-       u16 par;
-
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writeb(0x1f, MCFGPIO_PAR_QSPI);
-       /* and CS2 & CS3 as gpio */
-       par = readw(MCFGPIO_PAR_TIMER);
-       par &= 0x3f3f;
-       writew(par, MCFGPIO_PAR_TIMER);
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-static struct platform_device *m523x_devices[] __initdata = {
-       &m523x_uart,
-       &m523x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m523x_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m523x_fec_init(void)
-{
-       u16 par;
-       u8 v;
-
-       /* Set multi-function pins to ethernet use */
-       par = readw(MCF_IPSBAR + 0x100082);
-       writew(par | 0xf00, MCF_IPSBAR + 0x100082);
-       v = readb(MCF_IPSBAR + 0x100078);
-       writeb(v | 0xc0, MCF_IPSBAR + 0x100078);
-}
-
-/***************************************************************************/
-
-static void m523x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m523x_cpu_reset;
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       m523x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m523x_qspi_init();
-#endif
-       platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/523x/gpio.c b/arch/m68knommu/platform/523x/gpio.c
deleted file mode 100644 (file)
index 327ebf1..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PIRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 1,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *) MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "ADDR",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 13,
-                       .ngpio                  = 3,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "DATAH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 16,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "DATAL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 24,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BUSCTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "CS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 49,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "SDRAM",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 56,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECI2C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 2,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 80,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QSPI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 88,
-                       .ngpio                  = 5,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMER",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 96,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "ETPU",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 104,
-                       .ngpio                  = 3,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ETPU,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_ETPU,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ETPU,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ETPU,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ETPU,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile
deleted file mode 100644 (file)
index 4bed30f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o intc2.o
-
diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c
deleted file mode 100644 (file)
index ceb31e5..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5249/config.c
- *
- *     Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5249_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5249_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5249_uart_platform,
-};
-
-#ifdef CONFIG_M5249C3
-
-static struct resource m5249_smc91x_resources[] = {
-       {
-               .start          = 0xe0000300,
-               .end            = 0xe0000300 + 0x100,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINTC2_GPIOIRQ6,
-               .end            = MCFINTC2_GPIOIRQ6,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m5249_smc91x = {
-       .name                   = "smc91x",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5249_smc91x_resources),
-       .resource               = m5249_smc91x_resources,
-};
-
-#endif /* CONFIG_M5249C3 */
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m5249_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_QSPI,
-               .end            = MCF_IRQ_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    29
-#define MCFQSPI_CS1    24
-#define MCFQSPI_CS2    21
-#define MCFQSPI_CS3    22
-
-static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m5249_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m5249_cs_control = {
-       .setup                  = m5249_cs_setup,
-       .teardown               = m5249_cs_teardown,
-       .select                 = m5249_cs_select,
-       .deselect               = m5249_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m5249_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m5249_cs_control,
-};
-
-static struct platform_device m5249_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5249_qspi_resources),
-       .resource               = m5249_qspi_resources,
-       .dev.platform_data      = &m5249_qspi_data,
-};
-
-static void __init m5249_qspi_init(void)
-{
-       /* QSPI irq setup */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI0,
-              MCF_MBAR + MCFSIM_QSPIICR);
-       mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI);
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-
-static struct platform_device *m5249_devices[] __initdata = {
-       &m5249_uart,
-#ifdef CONFIG_M5249C3
-       &m5249_smc91x,
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m5249_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m5249_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5249_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5249_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5249_uart_init_line(line, m5249_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-#ifdef CONFIG_M5249C3
-
-static void __init m5249_smc91x_init(void)
-{
-       u32  gpio;
-
-       /* Set the GPIO line as interrupt source for smc91x device */
-       gpio = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-       writel(gpio | 0x40, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-
-       gpio = readl(MCF_MBAR2 + MCFSIM2_INTLEVEL5);
-       writel(gpio | 0x04000000, MCF_MBAR2 + MCFSIM2_INTLEVEL5);
-}
-
-#endif /* CONFIG_M5249C3 */
-
-/***************************************************************************/
-
-static void __init m5249_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5249_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m5249_cpu_reset;
-       m5249_timers_init();
-       m5249_uarts_init();
-#ifdef CONFIG_M5249C3
-       m5249_smc91x_init();
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m5249_qspi_init();
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5249/gpio.c b/arch/m68knommu/platform/5249/gpio.c
deleted file mode 100644 (file)
index 2b56c6e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "GPIO0",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 32,
-               },
-               .pddr                           = (void __iomem *) MCFSIM2_GPIOENABLE,
-               .podr                           = (void __iomem *) MCFSIM2_GPIOWRITE,
-               .ppdr                           = (void __iomem *) MCFSIM2_GPIOREAD,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "GPIO1",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 32,
-                       .ngpio                  = 32,
-               },
-               .pddr                           = (void __iomem *) MCFSIM2_GPIO1ENABLE,
-               .podr                           = (void __iomem *) MCFSIM2_GPIO1WRITE,
-               .ppdr                           = (void __iomem *) MCFSIM2_GPIO1READ,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5249/intc2.c b/arch/m68knommu/platform/5249/intc2.c
deleted file mode 100644 (file)
index 8f4b63e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * intc2.c  -- support for the 2nd INTC controller of the 5249
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-static void intc2_irq_gpio_mask(struct irq_data *d)
-{
-       u32 imr;
-       imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-       imr &= ~(0x1 << (d->irq - MCFINTC2_GPIOIRQ0));
-       writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_unmask(struct irq_data *d)
-{
-       u32 imr;
-       imr = readl(MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-       imr |= (0x1 << (d->irq - MCFINTC2_GPIOIRQ0));
-       writel(imr, MCF_MBAR2 + MCFSIM2_GPIOINTENABLE);
-}
-
-static void intc2_irq_gpio_ack(struct irq_data *d)
-{
-       writel(0x1 << (d->irq - MCFINTC2_GPIOIRQ0), MCF_MBAR2 + MCFSIM2_GPIOINTCLEAR);
-}
-
-static struct irq_chip intc2_irq_gpio_chip = {
-       .name           = "CF-INTC2",
-       .irq_mask       = intc2_irq_gpio_mask,
-       .irq_unmask     = intc2_irq_gpio_unmask,
-       .irq_ack        = intc2_irq_gpio_ack,
-};
-
-static int __init mcf_intc2_init(void)
-{
-       int irq;
-
-       /* GPIO interrupt sources */
-       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++) {
-               set_irq_chip(irq, &intc2_irq_gpio_chip);
-               set_irq_handler(irq, handle_edge_irq);
-       }
-
-       return 0;
-}
-
-arch_initcall(mcf_intc2_init);
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile
deleted file mode 100644 (file)
index 34110fc..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o intc.o
-
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
deleted file mode 100644 (file)
index 65bb582..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5272/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2002, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/phy.h>
-#include <linux/phy_fixed.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-/*
- *     Some platforms need software versions of the GPIO data registers.
- */
-unsigned short ppdata;
-unsigned char ledbank = 0xff;
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5272_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = MCF_IRQ_UART1,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = MCF_IRQ_UART2,
-       },
-       { },
-};
-
-static struct platform_device m5272_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5272_uart_platform,
-};
-
-static struct resource m5272_fec_resources[] = {
-       {
-               .start          = MCF_MBAR + 0x840,
-               .end            = MCF_MBAR + 0x840 + 0x1cf,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCF_IRQ_ERX,
-               .end            = MCF_IRQ_ERX,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_ETX,
-               .end            = MCF_IRQ_ETX,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = MCF_IRQ_ENTC,
-               .end            = MCF_IRQ_ENTC,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m5272_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m5272_fec_resources),
-       .resource               = m5272_fec_resources,
-};
-
-static struct platform_device *m5272_devices[] __initdata = {
-       &m5272_uart,
-       &m5272_fec,
-};
-
-/***************************************************************************/
-
-static void __init m5272_uart_init_line(int line, int irq)
-{
-       u32 v;
-
-       if ((line >= 0) && (line < 2)) {
-               /* Enable the output lines for the serial ports */
-               v = readl(MCF_MBAR + MCFSIM_PBCNT);
-               v = (v & ~0x000000ff) | 0x00000055;
-               writel(v, MCF_MBAR + MCFSIM_PBCNT);
-
-               v = readl(MCF_MBAR + MCFSIM_PDCNT);
-               v = (v & ~0x000003fc) | 0x000002a8;
-               writel(v, MCF_MBAR + MCFSIM_PDCNT);
-       }
-}
-
-static void __init m5272_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5272_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5272_uart_init_line(line, m5272_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void m5272_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to reset, and enabled */
-       __raw_writew(0, MCF_MBAR + MCFSIM_WIRR);
-       __raw_writew(1, MCF_MBAR + MCFSIM_WRRR);
-       __raw_writew(0, MCF_MBAR + MCFSIM_WCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined (CONFIG_MOD5272)
-       volatile unsigned char  *pivrp;
-
-       /* Set base of device vectors to be 64 */
-       pivrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_PIVR);
-       *pivrp = 0x40;
-#endif
-
-#if defined(CONFIG_NETtel) || defined(CONFIG_SCALES)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#elif defined(CONFIG_CANCam)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0010000, size);
-       commandp[size-1] = 0;
-#endif
-
-       mach_reset = m5272_cpu_reset;
-}
-
-/***************************************************************************/
-
-/*
- * Some 5272 based boards have the FEC ethernet diectly connected to
- * an ethernet switch. In this case we need to use the fixed phy type,
- * and we need to declare it early in boot.
- */
-static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
-       .link   = 1,
-       .speed  = 100,
-       .duplex = 0,
-};
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       m5272_uarts_init();
-       fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
-       platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5272/gpio.c b/arch/m68knommu/platform/5272/gpio.c
deleted file mode 100644 (file)
index 57ac10a..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PA",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 16,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PADDR,
-               .podr                           = (void __iomem *) MCFSIM_PADAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "PB",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 16,
-                       .ngpio                  = 16,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PBDDR,
-               .podr                           = (void __iomem *) MCFSIM_PBDAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PBDAT,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "PC",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 32,
-                       .ngpio                  = 16,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PCDDR,
-               .podr                           = (void __iomem *) MCFSIM_PCDAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PCDAT,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68knommu/platform/5272/intc.c
deleted file mode 100644 (file)
index 969ff0a..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * intc.c  --  interrupt controller or ColdFire 5272 SoC
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- * The 5272 ColdFire interrupt controller is nothing like any other
- * ColdFire interrupt controller - it truly is completely different.
- * Given its age it is unlikely to be used on any other ColdFire CPU.
- */
-
-/*
- * The masking and priproty setting of interrupts on the 5272 is done
- * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
- * loose mapping of vector number to register and internal bits, but
- * a table is the easiest and quickest way to map them.
- *
- * Note that the external interrupts are edge triggered (unlike the
- * internal interrupt sources which are level triggered). Which means
- * they also need acknowledgeing via acknowledge bits.
- */
-struct irqmap {
-       unsigned char   icr;
-       unsigned char   index;
-       unsigned char   ack;
-};
-
-static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
-       /*MCF_IRQ_SPURIOUS*/    { .icr = 0,           .index = 0,  .ack = 0, },
-       /*MCF_IRQ_EINT1*/       { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
-       /*MCF_IRQ_EINT2*/       { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
-       /*MCF_IRQ_EINT3*/       { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
-       /*MCF_IRQ_EINT4*/       { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
-       /*MCF_IRQ_TIMER1*/      { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
-       /*MCF_IRQ_TIMER2*/      { .icr = MCFSIM_ICR1, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_TIMER3*/      { .icr = MCFSIM_ICR1, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_TIMER4*/      { .icr = MCFSIM_ICR1, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_UART1*/       { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
-       /*MCF_IRQ_UART2*/       { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
-       /*MCF_IRQ_PLIP*/        { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
-       /*MCF_IRQ_PLIA*/        { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
-       /*MCF_IRQ_USB0*/        { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
-       /*MCF_IRQ_USB1*/        { .icr = MCFSIM_ICR2, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_USB2*/        { .icr = MCFSIM_ICR2, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_USB3*/        { .icr = MCFSIM_ICR2, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_USB4*/        { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
-       /*MCF_IRQ_USB5*/        { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
-       /*MCF_IRQ_USB6*/        { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
-       /*MCF_IRQ_USB7*/        { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
-       /*MCF_IRQ_DMA*/         { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
-       /*MCF_IRQ_ERX*/         { .icr = MCFSIM_ICR3, .index = 8,  .ack = 0, },
-       /*MCF_IRQ_ETX*/         { .icr = MCFSIM_ICR3, .index = 4,  .ack = 0, },
-       /*MCF_IRQ_ENTC*/        { .icr = MCFSIM_ICR3, .index = 0,  .ack = 0, },
-       /*MCF_IRQ_QSPI*/        { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
-       /*MCF_IRQ_EINT5*/       { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
-       /*MCF_IRQ_EINT6*/       { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
-       /*MCF_IRQ_SWTO*/        { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
-};
-
-/*
- * The act of masking the interrupt also has a side effect of 'ack'ing
- * an interrupt on this irq (for the external irqs). So this mask function
- * is also an ack_mask function.
- */
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               u32 v;
-               irq -= MCFINT_VECBASE;
-               v = 0x8 << intc_irqmap[irq].index;
-               writel(v, MCF_MBAR + intc_irqmap[irq].icr);
-       }
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               u32 v;
-               irq -= MCFINT_VECBASE;
-               v = 0xd << intc_irqmap[irq].index;
-               writel(v, MCF_MBAR + intc_irqmap[irq].icr);
-       }
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       /* Only external interrupts are acked */
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               irq -= MCFINT_VECBASE;
-               if (intc_irqmap[irq].ack) {
-                       u32 v;
-                       v = readl(MCF_MBAR + intc_irqmap[irq].icr);
-                       v &= (0x7 << intc_irqmap[irq].index);
-                       v |= (0x8 << intc_irqmap[irq].index);
-                       writel(v, MCF_MBAR + intc_irqmap[irq].icr);
-               }
-       }
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
-               irq -= MCFINT_VECBASE;
-               if (intc_irqmap[irq].ack) {
-                       u32 v;
-                       v = readl(MCF_MBAR + MCFSIM_PITR);
-                       if (type == IRQ_TYPE_EDGE_FALLING)
-                               v &= ~(0x1 << (32 - irq));
-                       else
-                               v |= (0x1 << (32 - irq));
-                       writel(v, MCF_MBAR + MCFSIM_PITR);
-               }
-       }
-       return 0;
-}
-
-/*
- * Simple flow handler to deal with the external edge triggered interrupts.
- * We need to be careful with the masking/acking due to the side effects
- * of masking an interrupt.
- */
-static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
-{
-       get_irq_desc_chip(desc)->irq_ack(&desc->irq_data);
-       handle_simple_irq(irq, desc);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_mask_ack   = intc_irq_mask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq, edge;
-
-       init_vectors();
-
-       /* Mask all interrupt sources */
-       writel(0x88888888, MCF_MBAR + MCFSIM_ICR1);
-       writel(0x88888888, MCF_MBAR + MCFSIM_ICR2);
-       writel(0x88888888, MCF_MBAR + MCFSIM_ICR3);
-       writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
-
-       for (irq = 0; (irq < NR_IRQS); irq++) {
-               set_irq_chip(irq, &intc_irq_chip);
-               edge = 0;
-               if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
-                       edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
-               if (edge) {
-                       set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
-                       set_irq_handler(irq, intc_external_irq);
-               } else {
-                       set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-                       set_irq_handler(irq, handle_level_irq);
-               }
-       }
-}
-
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile
deleted file mode 100644 (file)
index 6ac4b57..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
-
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68knommu/platform/527x/config.c
deleted file mode 100644 (file)
index fa35959..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/527x/config.c
- *
- *     Sub-architcture dependant initialization code for the Freescale
- *     5270/5271 CPUs.
- *
- *     Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m527x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m527x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m527x_uart_platform,
-};
-
-static struct resource m527x_fec0_resources[] = {
-       {
-               .start          = MCFFEC_BASE0,
-               .end            = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource m527x_fec1_resources[] = {
-       {
-               .start          = MCFFEC_BASE1,
-               .end            = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 128 + 23,
-               .end            = 128 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 128 + 27,
-               .end            = 128 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 128 + 29,
-               .end            = 128 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m527x_fec[] = {
-       {
-               .name           = "fec",
-               .id             = 0,
-               .num_resources  = ARRAY_SIZE(m527x_fec0_resources),
-               .resource       = m527x_fec0_resources,
-       },
-       {
-               .name           = "fec",
-               .id             = 1,
-               .num_resources  = ARRAY_SIZE(m527x_fec1_resources),
-               .resource       = m527x_fec1_resources,
-       },
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m527x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#if defined(CONFIG_M5271)
-#define MCFQSPI_CS0    91
-#define MCFQSPI_CS1    92
-#define MCFQSPI_CS2    99
-#define MCFQSPI_CS3    103
-#elif defined(CONFIG_M5275)
-#define MCFQSPI_CS0    59
-#define MCFQSPI_CS1    60
-#define MCFQSPI_CS2    61
-#define MCFQSPI_CS3    62
-#endif
-
-static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m527x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, cs_high);
-               break;
-       }
-}
-
-static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       switch (chip_select) {
-       case 0:
-               gpio_set_value(MCFQSPI_CS0, !cs_high);
-               break;
-       case 1:
-               gpio_set_value(MCFQSPI_CS1, !cs_high);
-               break;
-       case 2:
-               gpio_set_value(MCFQSPI_CS2, !cs_high);
-               break;
-       case 3:
-               gpio_set_value(MCFQSPI_CS3, !cs_high);
-               break;
-       }
-}
-
-static struct mcfqspi_cs_control m527x_cs_control = {
-       .setup                  = m527x_cs_setup,
-       .teardown               = m527x_cs_teardown,
-       .select                 = m527x_cs_select,
-       .deselect               = m527x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m527x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m527x_cs_control,
-};
-
-static struct platform_device m527x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m527x_qspi_resources),
-       .resource               = m527x_qspi_resources,
-       .dev.platform_data      = &m527x_qspi_data,
-};
-
-static void __init m527x_qspi_init(void)
-{
-#if defined(CONFIG_M5271)
-       u16 par;
-
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writeb(0x1f, MCFGPIO_PAR_QSPI);
-       /* and CS2 & CS3 as gpio */
-       par = readw(MCFGPIO_PAR_TIMER);
-       par &= 0x3f3f;
-       writew(par, MCFGPIO_PAR_TIMER);
-#elif defined(CONFIG_M5275)
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writew(0x003e, MCFGPIO_PAR_QSPI);
-#endif
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-static struct platform_device *m527x_devices[] __initdata = {
-       &m527x_uart,
-       &m527x_fec[0],
-#ifdef CONFIG_FEC2
-       &m527x_fec[1],
-#endif
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m527x_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m527x_uart_init_line(int line, int irq)
-{
-       u16 sepmask;
-
-       if ((line < 0) || (line > 2))
-               return;
-
-       /*
-        * External Pin Mask Setting & Enable External Pin for Interface
-        */
-       sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
-       if (line == 0)
-               sepmask |= UART0_ENABLE_MASK;
-       else if (line == 1)
-               sepmask |= UART1_ENABLE_MASK;
-       else if (line == 2)
-               sepmask |= UART2_ENABLE_MASK;
-       writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
-}
-
-static void __init m527x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m527x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m527x_uart_init_line(line, m527x_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m527x_fec_init(void)
-{
-       u16 par;
-       u8 v;
-
-       /* Set multi-function pins to ethernet mode for fec0 */
-#if defined(CONFIG_M5271)
-       v = readb(MCF_IPSBAR + 0x100047);
-       writeb(v | 0xf0, MCF_IPSBAR + 0x100047);
-#else
-       par = readw(MCF_IPSBAR + 0x100082);
-       writew(par | 0xf00, MCF_IPSBAR + 0x100082);
-       v = readb(MCF_IPSBAR + 0x100078);
-       writeb(v | 0xc0, MCF_IPSBAR + 0x100078);
-#endif
-
-#ifdef CONFIG_FEC2
-       /* Set multi-function pins to ethernet mode for fec1 */
-       par = readw(MCF_IPSBAR + 0x100082);
-       writew(par | 0xa0, MCF_IPSBAR + 0x100082);
-       v = readb(MCF_IPSBAR + 0x100079);
-       writeb(v | 0xc0, MCF_IPSBAR + 0x100079);
-#endif
-}
-
-/***************************************************************************/
-
-static void m527x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m527x_cpu_reset;
-       m527x_uarts_init();
-       m527x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m527x_qspi_init();
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/527x/gpio.c b/arch/m68knommu/platform/527x/gpio.c
deleted file mode 100644 (file)
index 205da0a..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-#if defined(CONFIG_M5271)
-       {
-               .gpio_chip                      = {
-                       .label                  = "PIRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 1,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *) MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "ADDR",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 13,
-                       .ngpio                  = 3,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "DATAH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 16,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "DATAL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 24,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_DATAL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_DATAL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_DATAL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_DATAL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BUSCTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "CS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 49,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "SDRAM",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 56,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECI2C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 2,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 80,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QSPI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 88,
-                       .ngpio                  = 5,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMER",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 96,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
-       },
-#elif defined(CONFIG_M5275)
-       {
-               .gpio_chip                      = {
-                       .label                  = "PIRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 1,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *) MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BUSCTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 8,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "ADDR",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 21,
-                       .ngpio                  = 3,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_ADDR,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_ADDR,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_ADDR,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_ADDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "CS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 25,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FEC0H",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC0H,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC0H,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0H,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0H,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC0H,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FEC0L",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC0L,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC0L,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0L,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC0L,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC0L,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECI2C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 48,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QSPI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 56,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "SDRAM",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SDRAM,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_SDRAM,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SDRAM,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SDRAM,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMERH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMERH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMERH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMERH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMERL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 80,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMERL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMERL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMERL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMERL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 88,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FEC1H",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 96,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC1H,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC1H,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1H,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1H,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC1H,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FEC1L",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 104,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FEC1L,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FEC1L,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1L,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FEC1L,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FEC1L,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 114,
-                       .ngpio                  = 2,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "IRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 121,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_IRQ,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_IRQ,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_IRQ,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_IRQ,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_IRQ,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "USBH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 128,
-                       .ngpio                  = 1,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_USBH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_USBH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_USBH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_USBH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_USBH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "USBL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 136,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_USBL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_USBL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_USBL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_USBL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_USBL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UARTH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 144,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UARTH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UARTH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UARTH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UARTH,
-       },
-#endif
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile
deleted file mode 100644 (file)
index 6ac4b57..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs.  You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
-
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
deleted file mode 100644 (file)
index ac39fc6..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/528x/config.c
- *
- *     Sub-architcture dependant initialization code for the Freescale
- *     5280, 5281 and 5282 CPUs.
- *
- *     Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m528x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
-       },
-       { },
-};
-
-static struct platform_device m528x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m528x_uart_platform,
-};
-
-static struct resource m528x_fec_resources[] = {
-       {
-               .start          = MCFFEC_BASE,
-               .end            = MCFFEC_BASE + MCFFEC_SIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 23,
-               .end            = 64 + 23,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 27,
-               .end            = 64 + 27,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 29,
-               .end            = 64 + 29,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m528x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m528x_fec_resources),
-       .resource               = m528x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m528x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    147
-#define MCFQSPI_CS1    148
-#define MCFQSPI_CS2    149
-#define MCFQSPI_CS3    150
-
-static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
-               goto fail3;
-       }
-       status = gpio_direction_output(MCFQSPI_CS3, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
-               goto fail4;
-       }
-
-       return 0;
-
-fail4:
-       gpio_free(MCFQSPI_CS3);
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS3);
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m528x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m528x_cs_control = {
-       .setup                  = m528x_cs_setup,
-       .teardown               = m528x_cs_teardown,
-       .select                 = m528x_cs_select,
-       .deselect               = m528x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m528x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 4,
-       .cs_control             = &m528x_cs_control,
-};
-
-static struct platform_device m528x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m528x_qspi_resources),
-       .resource               = m528x_qspi_resources,
-       .dev.platform_data      = &m528x_qspi_data,
-};
-
-static void __init m528x_qspi_init(void)
-{
-       /* setup Port QS for QSPI with gpio CS control */
-       __raw_writeb(0x07, MCFGPIO_PQSPAR);
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-static struct platform_device *m528x_devices[] __initdata = {
-       &m528x_uart,
-       &m528x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m528x_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m528x_uart_init_line(int line, int irq)
-{
-       u8 port;
-
-       if ((line < 0) || (line > 2))
-               return;
-
-       /* make sure PUAPAR is set for UART0 and UART1 */
-       if (line < 2) {
-               port = readb(MCF5282_GPIO_PUAPAR);
-               port |= (0x03 << (line * 2));
-               writeb(port, MCF5282_GPIO_PUAPAR);
-       }
-}
-
-static void __init m528x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m528x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m528x_uart_init_line(line, m528x_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m528x_fec_init(void)
-{
-       u16 v16;
-
-       /* Set multi-function pins to ethernet mode for fec0 */
-       v16 = readw(MCF_IPSBAR + 0x100056);
-       writew(v16 | 0xf00, MCF_IPSBAR + 0x100056);
-       writeb(0xc0, MCF_IPSBAR + 0x100058);
-}
-
-/***************************************************************************/
-
-static void m528x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR);
-}
-
-/***************************************************************************/
-
-#ifdef CONFIG_WILDFIRE
-void wildfire_halt(void)
-{
-       writeb(0, 0x30000007);
-       writeb(0x2, 0x30000007);
-}
-#endif
-
-#ifdef CONFIG_WILDFIREMOD
-void wildfiremod_halt(void)
-{
-       printk(KERN_INFO "WildFireMod hibernating...\n");
-
-       /* Set portE.5 to Digital IO */
-       MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
-
-       /* Make portE.5 an output */
-       MCF5282_GPIO_DDRE |= (1 << 5);
-
-       /* Now toggle portE.5 from low to high */
-       MCF5282_GPIO_PORTE &= ~(1 << 5);
-       MCF5282_GPIO_PORTE |= (1 << 5);
-
-       printk(KERN_EMERG "Failed to hibernate. Halting!\n");
-}
-#endif
-
-void __init config_BSP(char *commandp, int size)
-{
-#ifdef CONFIG_WILDFIRE
-       mach_halt = wildfire_halt;
-#endif
-#ifdef CONFIG_WILDFIREMOD
-       mach_halt = wildfiremod_halt;
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       mach_reset = m528x_cpu_reset;
-       m528x_uarts_init();
-       m528x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m528x_qspi_init();
-#endif
-       platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/528x/gpio.c b/arch/m68knommu/platform/528x/gpio.c
deleted file mode 100644 (file)
index 526db66..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "NQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .base                   = 1,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *)MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *)MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *)MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TA",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 8,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFGPTA_GPTDDR,
-               .podr                           = (void __iomem *)MCFGPTA_GPTPORT,
-               .ppdr                           = (void __iomem *)MCFGPTB_GPTPORT,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TB",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 16,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFGPTB_GPTDDR,
-               .podr                           = (void __iomem *)MCFGPTB_GPTPORT,
-               .ppdr                           = (void __iomem *)MCFGPTB_GPTPORT,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QA",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 24,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFQADC_DDRQA,
-               .podr                           = (void __iomem *)MCFQADC_PORTQA,
-               .ppdr                           = (void __iomem *)MCFQADC_PORTQA,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QB",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFQADC_DDRQB,
-               .podr                           = (void __iomem *)MCFQADC_PORTQB,
-               .ppdr                           = (void __iomem *)MCFQADC_PORTQB,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "A",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRA,
-               .podr                           = (void __iomem *)MCFGPIO_PORTA,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTAP,
-               .setr                           = (void __iomem *)MCFGPIO_SETA,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRA,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "B",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 48,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRB,
-               .podr                           = (void __iomem *)MCFGPIO_PORTB,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTBP,
-               .setr                           = (void __iomem *)MCFGPIO_SETB,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRB,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 56,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRC,
-               .podr                           = (void __iomem *)MCFGPIO_PORTC,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTCP,
-               .setr                           = (void __iomem *)MCFGPIO_SETC,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRC,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "D",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRD,
-               .podr                           = (void __iomem *)MCFGPIO_PORTD,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTDP,
-               .setr                           = (void __iomem *)MCFGPIO_SETD,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRD,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "E",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRE,
-               .podr                           = (void __iomem *)MCFGPIO_PORTE,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTEP,
-               .setr                           = (void __iomem *)MCFGPIO_SETE,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRE,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "F",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 80,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRF,
-               .podr                           = (void __iomem *)MCFGPIO_PORTF,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTFP,
-               .setr                           = (void __iomem *)MCFGPIO_SETF,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRF,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "G",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 88,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRG,
-               .podr                           = (void __iomem *)MCFGPIO_PORTG,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTGP,
-               .setr                           = (void __iomem *)MCFGPIO_SETG,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRG,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "H",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 96,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRH,
-               .podr                           = (void __iomem *)MCFGPIO_PORTH,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTHP,
-               .setr                           = (void __iomem *)MCFGPIO_SETH,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "J",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 104,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRJ,
-               .podr                           = (void __iomem *)MCFGPIO_PORTJ,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTJP,
-               .setr                           = (void __iomem *)MCFGPIO_SETJ,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRJ,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "DD",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 112,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRDD,
-               .podr                           = (void __iomem *)MCFGPIO_PORTDD,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTDDP,
-               .setr                           = (void __iomem *)MCFGPIO_SETDD,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRDD,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "EH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 120,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDREH,
-               .podr                           = (void __iomem *)MCFGPIO_PORTEH,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTEHP,
-               .setr                           = (void __iomem *)MCFGPIO_SETEH,
-               .clrr                           = (void __iomem *)MCFGPIO_CLREH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "EL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 128,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDREL,
-               .podr                           = (void __iomem *)MCFGPIO_PORTEL,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTELP,
-               .setr                           = (void __iomem *)MCFGPIO_SETEL,
-               .clrr                           = (void __iomem *)MCFGPIO_CLREL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "AS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 136,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRAS,
-               .podr                           = (void __iomem *)MCFGPIO_PORTAS,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTASP,
-               .setr                           = (void __iomem *)MCFGPIO_SETAS,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRAS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 144,
-                       .ngpio                  = 7,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRQS,
-               .podr                           = (void __iomem *)MCFGPIO_PORTQS,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTQSP,
-               .setr                           = (void __iomem *)MCFGPIO_SETQS,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRQS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "SD",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 152,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRSD,
-               .podr                           = (void __iomem *)MCFGPIO_PORTSD,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTSDP,
-               .setr                           = (void __iomem *)MCFGPIO_SETSD,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRSD,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TC",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 160,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRTC,
-               .podr                           = (void __iomem *)MCFGPIO_PORTTC,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTTCP,
-               .setr                           = (void __iomem *)MCFGPIO_SETTC,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRTC,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TD",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 168,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRTD,
-               .podr                           = (void __iomem *)MCFGPIO_PORTTD,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTTDP,
-               .setr                           = (void __iomem *)MCFGPIO_SETTD,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRTD,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UA",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 176,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *)MCFGPIO_DDRUA,
-               .podr                           = (void __iomem *)MCFGPIO_PORTUA,
-               .ppdr                           = (void __iomem *)MCFGPIO_PORTUAP,
-               .setr                           = (void __iomem *)MCFGPIO_SETUA,
-               .clrr                           = (void __iomem *)MCFGPIO_CLRUA,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
deleted file mode 100644 (file)
index d4293b7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Makefile for the m68knommu kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y                  += config.o gpio.o
-obj-$(CONFIG_NETtel)   += nettel.o
-obj-$(CONFIG_CLEOPATRA)        += nettel.o
-
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
deleted file mode 100644 (file)
index 00900ac..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5307/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfwdebug.h>
-
-/***************************************************************************/
-
-/*
- *     Some platforms need software versions of the GPIO data registers.
- */
-unsigned short ppdata;
-unsigned char ledbank = 0xff;
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5307_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5307_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5307_uart_platform,
-};
-
-static struct platform_device *m5307_devices[] __initdata = {
-       &m5307_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5307_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5307_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5307_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5307_uart_init_line(line, m5307_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5307_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5307_cpu_reset(void)
-{
-       local_irq_disable();
-       /* Set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if defined(CONFIG_NETtel) || \
-    defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0xf0004000, size);
-       commandp[size-1] = 0;
-#endif
-
-       mach_reset = m5307_cpu_reset;
-       m5307_timers_init();
-       m5307_uarts_init();
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(27, MCFINTC_EINT3);
-       mcf_mapirq2imr(29, MCFINTC_EINT5);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-
-#ifdef CONFIG_BDM_DISABLE
-       /*
-        * Disable the BDM clocking.  This also turns off most of the rest of
-        * the BDM device.  This is good for EMC reasons. This option is not
-        * incompatible with the memory protection option.
-        */
-       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5307/gpio.c b/arch/m68knommu/platform/5307/gpio.c
deleted file mode 100644 (file)
index 5850612..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PP",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 16,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PADDR,
-               .podr                           = (void __iomem *) MCFSIM_PADAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5307/nettel.c b/arch/m68knommu/platform/5307/nettel.c
deleted file mode 100644 (file)
index e925ea4..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/***************************************************************************/
-
-/*
- *     nettel.c -- startup code support for the NETtel boards
- *
- *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/nettel.h>
-
-/***************************************************************************/
-
-/*
- * Define the IO and interrupt resources of the 2 SMC9196 interfaces.
- */
-#define        NETTEL_SMC0_ADDR        0x30600300
-#define        NETTEL_SMC0_IRQ         29
-
-#define        NETTEL_SMC1_ADDR        0x30600000
-#define        NETTEL_SMC1_IRQ         27
-
-/*
- * We need some access into the SMC9196 registers. Define those registers
- * we will need here (including the smc91x.h doesn't seem to give us these
- * in a simple form).
- */
-#define        SMC91xx_BANKSELECT      14
-#define        SMC91xx_BASEADDR        2
-#define        SMC91xx_BASEMAC         4
-
-/***************************************************************************/
-
-static struct resource nettel_smc91x_0_resources[] = {
-       {
-               .start          = NETTEL_SMC0_ADDR,
-               .end            = NETTEL_SMC0_ADDR + 0x20,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = NETTEL_SMC0_IRQ,
-               .end            = NETTEL_SMC0_IRQ,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource nettel_smc91x_1_resources[] = {
-       {
-               .start          = NETTEL_SMC1_ADDR,
-               .end            = NETTEL_SMC1_ADDR + 0x20,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = NETTEL_SMC1_IRQ,
-               .end            = NETTEL_SMC1_IRQ,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device nettel_smc91x[] = {
-       {
-               .name                   = "smc91x",
-               .id                     = 0,
-               .num_resources          = ARRAY_SIZE(nettel_smc91x_0_resources),
-               .resource               = nettel_smc91x_0_resources,
-       },
-       {
-               .name                   = "smc91x",
-               .id                     = 1,
-               .num_resources          = ARRAY_SIZE(nettel_smc91x_1_resources),
-               .resource               = nettel_smc91x_1_resources,
-       },
-};
-
-static struct platform_device *nettel_devices[] __initdata = {
-       &nettel_smc91x[0],
-       &nettel_smc91x[1],
-};
-
-/***************************************************************************/
-
-static u8 nettel_macdefault[] __initdata = {
-       0x00, 0xd0, 0xcf, 0x00, 0x00, 0x01,
-};
-
-/*
- * Set flash contained MAC address into SMC9196 core. Make sure the flash
- * MAC address is sane, and not an empty flash. If no good use the Moreton
- * Bay default MAC address instead.
- */
-
-static void __init nettel_smc91x_setmac(unsigned int ioaddr, unsigned int flashaddr)
-{
-       u16 *macp;
-
-       macp = (u16 *) flashaddr;
-       if ((macp[0] == 0xffff) && (macp[1] == 0xffff) && (macp[2] == 0xffff))
-               macp = (u16 *) &nettel_macdefault[0];
-
-       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
-       writew(macp[0], ioaddr + SMC91xx_BASEMAC);
-       writew(macp[1], ioaddr + SMC91xx_BASEMAC + 2);
-       writew(macp[2], ioaddr + SMC91xx_BASEMAC + 4);
-}
-
-/***************************************************************************/
-
-/*
- * Re-map the address space of at least one of the SMC ethernet
- * parts. Both parts power up decoding the same address, so we
- * need to move one of them first, before doing anything else.
- */
-
-static void __init nettel_smc91x_init(void)
-{
-       writew(0x00ec, MCF_MBAR + MCFSIM_PADDR);
-       mcf_setppdata(0, 0x0080);
-       writew(1, NETTEL_SMC0_ADDR + SMC91xx_BANKSELECT);
-       writew(0x0067, NETTEL_SMC0_ADDR + SMC91xx_BASEADDR);
-       mcf_setppdata(0x0080, 0);
-
-       /* Set correct chip select timing for SMC9196 accesses */
-       writew(0x1180, MCF_MBAR + MCFSIM_CSCR3);
-
-       /* Set the SMC interrupts to be auto-vectored */
-       mcf_autovector(NETTEL_SMC0_IRQ);
-       mcf_autovector(NETTEL_SMC1_IRQ);
-
-       /* Set MAC addresses from flash for both interfaces */
-       nettel_smc91x_setmac(NETTEL_SMC0_ADDR, 0xf0006000);
-       nettel_smc91x_setmac(NETTEL_SMC1_ADDR, 0xf0006006);
-}
-
-/***************************************************************************/
-
-static int __init init_nettel(void)
-{
-       nettel_smc91x_init();
-       platform_add_devices(nettel_devices, ARRAY_SIZE(nettel_devices));
-       return 0;
-}
-
-arch_initcall(init_nettel);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile
deleted file mode 100644 (file)
index ce01669..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-#obj-y := config.o usb-mcf532x.o spi-mcf532x.o
-obj-y := config.o gpio.o
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
deleted file mode 100644 (file)
index ca51323..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/532x/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- *     Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
- *     Copyright Freescale Semiconductor, Inc 2006
- *     Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.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/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/spi/spi.h>
-#include <linux/gpio.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-#include <asm/mcfdma.h>
-#include <asm/mcfwdebug.h>
-#include <asm/mcfqspi.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m532x_uart_platform[] = {
-       {
-               .mapbase        = MCFUART_BASE1,
-               .irq            = MCFINT_VECBASE + MCFINT_UART0,
-       },
-       {
-               .mapbase        = MCFUART_BASE2,
-               .irq            = MCFINT_VECBASE + MCFINT_UART1,
-       },
-       {
-               .mapbase        = MCFUART_BASE3,
-               .irq            = MCFINT_VECBASE + MCFINT_UART2,
-       },
-       { },
-};
-
-static struct platform_device m532x_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m532x_uart_platform,
-};
-
-static struct resource m532x_fec_resources[] = {
-       {
-               .start          = 0xfc030000,
-               .end            = 0xfc0307ff,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = 64 + 36,
-               .end            = 64 + 36,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 40,
-               .end            = 64 + 40,
-               .flags          = IORESOURCE_IRQ,
-       },
-       {
-               .start          = 64 + 42,
-               .end            = 64 + 42,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device m532x_fec = {
-       .name                   = "fec",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m532x_fec_resources),
-       .resource               = m532x_fec_resources,
-};
-
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-static struct resource m532x_qspi_resources[] = {
-       {
-               .start          = MCFQSPI_IOBASE,
-               .end            = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = MCFINT_VECBASE + MCFINT_QSPI,
-               .end            = MCFINT_VECBASE + MCFINT_QSPI,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-#define MCFQSPI_CS0    84
-#define MCFQSPI_CS1    85
-#define MCFQSPI_CS2    86
-
-static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control)
-{
-       int status;
-
-       status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
-               goto fail0;
-       }
-       status = gpio_direction_output(MCFQSPI_CS0, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
-               goto fail1;
-       }
-
-       status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
-               goto fail1;
-       }
-       status = gpio_direction_output(MCFQSPI_CS1, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
-               goto fail2;
-       }
-
-       status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
-       if (status) {
-               pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
-               goto fail2;
-       }
-       status = gpio_direction_output(MCFQSPI_CS2, 1);
-       if (status) {
-               pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
-               goto fail3;
-       }
-
-       return 0;
-
-fail3:
-       gpio_free(MCFQSPI_CS2);
-fail2:
-       gpio_free(MCFQSPI_CS1);
-fail1:
-       gpio_free(MCFQSPI_CS0);
-fail0:
-       return status;
-}
-
-static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control)
-{
-       gpio_free(MCFQSPI_CS2);
-       gpio_free(MCFQSPI_CS1);
-       gpio_free(MCFQSPI_CS0);
-}
-
-static void m532x_cs_select(struct mcfqspi_cs_control *cs_control,
-                           u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high);
-}
-
-static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control,
-                             u8 chip_select, bool cs_high)
-{
-       gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high);
-}
-
-static struct mcfqspi_cs_control m532x_cs_control = {
-       .setup                  = m532x_cs_setup,
-       .teardown               = m532x_cs_teardown,
-       .select                 = m532x_cs_select,
-       .deselect               = m532x_cs_deselect,
-};
-
-static struct mcfqspi_platform_data m532x_qspi_data = {
-       .bus_num                = 0,
-       .num_chipselect         = 3,
-       .cs_control             = &m532x_cs_control,
-};
-
-static struct platform_device m532x_qspi = {
-       .name                   = "mcfqspi",
-       .id                     = 0,
-       .num_resources          = ARRAY_SIZE(m532x_qspi_resources),
-       .resource               = m532x_qspi_resources,
-       .dev.platform_data      = &m532x_qspi_data,
-};
-
-static void __init m532x_qspi_init(void)
-{
-       /* setup QSPS pins for QSPI with gpio CS control */
-       writew(0x01f0, MCF_GPIO_PAR_QSPI);
-}
-#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */
-
-
-static struct platform_device *m532x_devices[] __initdata = {
-       &m532x_uart,
-       &m532x_fec,
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       &m532x_qspi,
-#endif
-};
-
-/***************************************************************************/
-
-static void __init m532x_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x000F;
-       } else if (line == 1) {
-               /* GPIO initialization */
-               MCF_GPIO_PAR_UART |= 0x0FF0;
-       }
-}
-
-static void __init m532x_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m532x_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m532x_uart_init_line(line, m532x_uart_platform[line].irq);
-}
-/***************************************************************************/
-
-static void __init m532x_fec_init(void)
-{
-       /* Set multi-function pins to ethernet mode for fec0 */
-       MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
-               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
-       MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
-               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
-}
-
-/***************************************************************************/
-
-static void m532x_cpu_reset(void)
-{
-       local_irq_disable();
-       __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-#if !defined(CONFIG_BOOTPARAM)
-       /* Copy command line from FLASH to local buffer... */
-       memcpy(commandp, (char *) 0x4000, 4);
-       if(strncmp(commandp, "kcl ", 4) == 0){
-               memcpy(commandp, (char *) 0x4004, size);
-               commandp[size-1] = 0;
-       } else {
-               memset(commandp, 0, size);
-       }
-#endif
-
-#ifdef CONFIG_BDM_DISABLE
-       /*
-        * Disable the BDM clocking.  This also turns off most of the rest of
-        * the BDM device.  This is good for EMC reasons. This option is not
-        * incompatible with the memory protection option.
-        */
-       wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
-#endif
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       m532x_uarts_init();
-       m532x_fec_init();
-#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE)
-       m532x_qspi_init();
-#endif
-       platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
-/* Board initialization */
-/***************************************************************************/
-/* 
- * PLL min/max specifications
- */
-#define MAX_FVCO       500000  /* KHz */
-#define MAX_FSYS       80000   /* KHz */
-#define MIN_FSYS       58333   /* KHz */
-#define FREF           16000   /* KHz */
-
-
-#define MAX_MFD                135     /* Multiplier */
-#define MIN_MFD                88      /* Multiplier */
-#define BUSDIV         6       /* Divider */
-
-/*
- * Low Power Divider specifications
- */
-#define MIN_LPD                (1 << 0)    /* Divider (not encoded) */
-#define MAX_LPD                (1 << 15)   /* Divider (not encoded) */
-#define DEFAULT_LPD    (1 << 1)        /* Divider (not encoded) */
-
-#define SYS_CLK_KHZ    80000
-#define SYSTEM_PERIOD  12.5
-/*
- *  SDRAM Timing Parameters
- */  
-#define SDRAM_BL       8       /* # of beats in a burst */
-#define SDRAM_TWR      2       /* in clocks */
-#define SDRAM_CASL     2.5     /* CASL in clocks */
-#define SDRAM_TRCD     2       /* in clocks */
-#define SDRAM_TRP      2       /* in clocks */
-#define SDRAM_TRFC     7       /* in clocks */
-#define SDRAM_TREFI    7800    /* in ns */
-
-#define EXT_SRAM_ADDRESS       (0xC0000000)
-#define FLASH_ADDRESS          (0x00000000)
-#define SDRAM_ADDRESS          (0x40000000)
-
-#define NAND_FLASH_ADDRESS     (0xD0000000)
-
-int sys_clk_khz = 0;
-int sys_clk_mhz = 0;
-
-void wtm_init(void);
-void scm_init(void);
-void gpio_init(void);
-void fbcs_init(void);
-void sdramc_init(void);
-int  clock_pll (int fsys, int flags);
-int  clock_limp (int);
-int  clock_exit_limp (void);
-int  get_sys_clock (void);
-
-asmlinkage void __init sysinit(void)
-{
-       sys_clk_khz = clock_pll(0, 0);
-       sys_clk_mhz = sys_clk_khz/1000;
-       
-       wtm_init();
-       scm_init();
-       gpio_init();
-       fbcs_init();
-       sdramc_init();
-}
-
-void wtm_init(void)
-{
-       /* Disable watchdog timer */
-       MCF_WTM_WCR = 0;
-}
-
-#define MCF_SCM_BCR_GBW                (0x00000100)
-#define MCF_SCM_BCR_GBR                (0x00000200)
-
-void scm_init(void)
-{
-       /* All masters are trusted */
-       MCF_SCM_MPR = 0x77777777;
-    
-       /* Allow supervisor/user, read/write, and trusted/untrusted
-          access to all slaves */
-       MCF_SCM_PACRA = 0;
-       MCF_SCM_PACRB = 0;
-       MCF_SCM_PACRC = 0;
-       MCF_SCM_PACRD = 0;
-       MCF_SCM_PACRE = 0;
-       MCF_SCM_PACRF = 0;
-
-       /* Enable bursts */
-       MCF_SCM_BCR = (MCF_SCM_BCR_GBR | MCF_SCM_BCR_GBW);
-}
-
-
-void fbcs_init(void)
-{
-       MCF_GPIO_PAR_CS = 0x0000003E;
-
-       /* Latch chip select */
-       MCF_FBCS1_CSAR = 0x10080000;
-
-       MCF_FBCS1_CSCR = 0x002A3780;
-       MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_2M | MCF_FBCS_CSMR_V);
-
-       /* Initialize latch to drive signals to inactive states */
-       *((u16 *)(0x10080000)) = 0xFFFF;
-
-       /* External SRAM */
-       MCF_FBCS1_CSAR = EXT_SRAM_ADDRESS;
-       MCF_FBCS1_CSCR = (MCF_FBCS_CSCR_PS_16
-                       | MCF_FBCS_CSCR_AA
-                       | MCF_FBCS_CSCR_SBM
-                       | MCF_FBCS_CSCR_WS(1));
-       MCF_FBCS1_CSMR = (MCF_FBCS_CSMR_BAM_512K
-                       | MCF_FBCS_CSMR_V);
-
-       /* Boot Flash connected to FBCS0 */
-       MCF_FBCS0_CSAR = FLASH_ADDRESS;
-       MCF_FBCS0_CSCR = (MCF_FBCS_CSCR_PS_16
-                       | MCF_FBCS_CSCR_BEM
-                       | MCF_FBCS_CSCR_AA
-                       | MCF_FBCS_CSCR_SBM
-                       | MCF_FBCS_CSCR_WS(7));
-       MCF_FBCS0_CSMR = (MCF_FBCS_CSMR_BAM_32M
-                       | MCF_FBCS_CSMR_V);
-}
-
-void sdramc_init(void)
-{
-       /*
-        * Check to see if the SDRAM has already been initialized
-        * by a run control tool
-        */
-       if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) {
-               /* SDRAM chip select initialization */
-               
-               /* Initialize SDRAM chip select */
-               MCF_SDRAMC_SDCS0 = (0
-                       | MCF_SDRAMC_SDCS_BA(SDRAM_ADDRESS)
-                       | MCF_SDRAMC_SDCS_CSSZ(MCF_SDRAMC_SDCS_CSSZ_32MBYTE));
-
-       /*
-        * Basic configuration and initialization
-        */
-       MCF_SDRAMC_SDCFG1 = (0
-               | MCF_SDRAMC_SDCFG1_SRD2RW((int)((SDRAM_CASL + 2) + 0.5 ))
-               | MCF_SDRAMC_SDCFG1_SWT2RD(SDRAM_TWR + 1)
-               | MCF_SDRAMC_SDCFG1_RDLAT((int)((SDRAM_CASL*2) + 2))
-               | MCF_SDRAMC_SDCFG1_ACT2RW((int)((SDRAM_TRCD ) + 0.5))
-               | MCF_SDRAMC_SDCFG1_PRE2ACT((int)((SDRAM_TRP ) + 0.5))
-               | MCF_SDRAMC_SDCFG1_REF2ACT((int)(((SDRAM_TRFC) ) + 0.5))
-               | MCF_SDRAMC_SDCFG1_WTLAT(3));
-       MCF_SDRAMC_SDCFG2 = (0
-               | MCF_SDRAMC_SDCFG2_BRD2PRE(SDRAM_BL/2 + 1)
-               | MCF_SDRAMC_SDCFG2_BWT2RW(SDRAM_BL/2 + SDRAM_TWR)
-               | MCF_SDRAMC_SDCFG2_BRD2WT((int)((SDRAM_CASL+SDRAM_BL/2-1.0)+0.5))
-               | MCF_SDRAMC_SDCFG2_BL(SDRAM_BL-1));
-
-            
-       /*
-        * Precharge and enable write to SDMR
-        */
-        MCF_SDRAMC_SDCR = (0
-               | MCF_SDRAMC_SDCR_MODE_EN
-               | MCF_SDRAMC_SDCR_CKE
-               | MCF_SDRAMC_SDCR_DDR
-               | MCF_SDRAMC_SDCR_MUX(1)
-               | MCF_SDRAMC_SDCR_RCNT((int)(((SDRAM_TREFI/(SYSTEM_PERIOD*64)) - 1) + 0.5))
-               | MCF_SDRAMC_SDCR_PS_16
-               | MCF_SDRAMC_SDCR_IPALL);            
-
-       /*
-        * Write extended mode register
-        */
-       MCF_SDRAMC_SDMR = (0
-               | MCF_SDRAMC_SDMR_BNKAD_LEMR
-               | MCF_SDRAMC_SDMR_AD(0x0)
-               | MCF_SDRAMC_SDMR_CMD);
-
-       /*
-        * Write mode register and reset DLL
-        */
-       MCF_SDRAMC_SDMR = (0
-               | MCF_SDRAMC_SDMR_BNKAD_LMR
-               | MCF_SDRAMC_SDMR_AD(0x163)
-               | MCF_SDRAMC_SDMR_CMD);
-
-       /*
-        * Execute a PALL command
-        */
-       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL;
-
-       /*
-        * Perform two REF cycles
-        */
-       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
-       MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF;
-
-       /*
-        * Write mode register and clear reset DLL
-        */
-       MCF_SDRAMC_SDMR = (0
-               | MCF_SDRAMC_SDMR_BNKAD_LMR
-               | MCF_SDRAMC_SDMR_AD(0x063)
-               | MCF_SDRAMC_SDMR_CMD);
-                               
-       /*
-        * Enable auto refresh and lock SDMR
-        */
-       MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN;
-       MCF_SDRAMC_SDCR |= (0
-               | MCF_SDRAMC_SDCR_REF
-               | MCF_SDRAMC_SDCR_DQS_OE(0xC));
-       }
-}
-
-void gpio_init(void)
-{
-       /* Enable UART0 pins */
-       MCF_GPIO_PAR_UART = ( 0
-               | MCF_GPIO_PAR_UART_PAR_URXD0
-               | MCF_GPIO_PAR_UART_PAR_UTXD0);
-
-       /* Initialize TIN3 as a GPIO output to enable the write
-          half of the latch */
-       MCF_GPIO_PAR_TIMER = 0x00;
-       __raw_writeb(0x08, MCFGPIO_PDDR_TIMER);
-       __raw_writeb(0x00, MCFGPIO_PCLRR_TIMER);
-
-}
-
-int clock_pll(int fsys, int flags)
-{
-       int fref, temp, fout, mfd;
-       u32 i;
-
-       fref = FREF;
-        
-       if (fsys == 0) {
-               /* Return current PLL output */
-               mfd = MCF_PLL_PFDR;
-
-               return (fref * mfd / (BUSDIV * 4));
-       }
-
-       /* Check bounds of requested system clock */
-       if (fsys > MAX_FSYS)
-               fsys = MAX_FSYS;
-       if (fsys < MIN_FSYS)
-               fsys = MIN_FSYS;
-
-       /* Multiplying by 100 when calculating the temp value,
-          and then dividing by 100 to calculate the mfd allows
-          for exact values without needing to include floating
-          point libraries. */
-       temp = 100 * fsys / fref;
-       mfd = 4 * BUSDIV * temp / 100;
-                       
-       /* Determine the output frequency for selected values */
-       fout = (fref * mfd / (BUSDIV * 4));
-
-       /*
-        * Check to see if the SDRAM has already been initialized.
-        * If it has then the SDRAM needs to be put into self refresh
-        * mode before reprogramming the PLL.
-        */
-       if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
-               /* Put SDRAM into self refresh mode */
-               MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_CKE;
-
-       /*
-        * Initialize the PLL to generate the new system clock frequency.
-        * The device must be put into LIMP mode to reprogram the PLL.
-        */
-
-       /* Enter LIMP mode */
-       clock_limp(DEFAULT_LPD);
-                                       
-       /* Reprogram PLL for desired fsys */
-       MCF_PLL_PODR = (0
-               | MCF_PLL_PODR_CPUDIV(BUSDIV/3)
-               | MCF_PLL_PODR_BUSDIV(BUSDIV));
-                                               
-       MCF_PLL_PFDR = mfd;
-               
-       /* Exit LIMP mode */
-       clock_exit_limp();
-       
-       /*
-        * Return the SDRAM to normal operation if it is in use.
-        */
-       if (MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)
-               /* Exit self refresh mode */
-               MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_CKE;
-
-       /* Errata - workaround for SDRAM opeartion after exiting LIMP mode */
-       MCF_SDRAMC_LIMP_FIX = MCF_SDRAMC_REFRESH;
-
-       /* wait for DQS logic to relock */
-       for (i = 0; i < 0x200; i++)
-               ;
-
-       return fout;
-}
-
-int clock_limp(int div)
-{
-       u32 temp;
-
-       /* Check bounds of divider */
-       if (div < MIN_LPD)
-               div = MIN_LPD;
-       if (div > MAX_LPD)
-               div = MAX_LPD;
-    
-       /* Save of the current value of the SSIDIV so we don't
-          overwrite the value*/
-       temp = (MCF_CCM_CDR & MCF_CCM_CDR_SSIDIV(0xF));
-      
-       /* Apply the divider to the system clock */
-       MCF_CCM_CDR = ( 0
-               | MCF_CCM_CDR_LPDIV(div)
-               | MCF_CCM_CDR_SSIDIV(temp));
-    
-       MCF_CCM_MISCCR |= MCF_CCM_MISCCR_LIMP;
-    
-       return (FREF/(3*(1 << div)));
-}
-
-int clock_exit_limp(void)
-{
-       int fout;
-       
-       /* Exit LIMP mode */
-       MCF_CCM_MISCCR = (MCF_CCM_MISCCR & ~ MCF_CCM_MISCCR_LIMP);
-
-       /* Wait for PLL to lock */
-       while (!(MCF_CCM_MISCCR & MCF_CCM_MISCCR_PLL_LOCK))
-               ;
-       
-       fout = get_sys_clock();
-
-       return fout;
-}
-
-int get_sys_clock(void)
-{
-       int divider;
-       
-       /* Test to see if device is in LIMP mode */
-       if (MCF_CCM_MISCCR & MCF_CCM_MISCCR_LIMP) {
-               divider = MCF_CCM_CDR & MCF_CCM_CDR_LPDIV(0xF);
-               return (FREF/(2 << divider));
-       }
-       else
-               return ((FREF * MCF_PLL_PFDR) / (BUSDIV * 4));
-}
diff --git a/arch/m68knommu/platform/532x/gpio.c b/arch/m68knommu/platform/532x/gpio.c
deleted file mode 100644 (file)
index 212a85d..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PIRQ",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFEPORT_EPDDR,
-               .podr                           = (void __iomem *) MCFEPORT_EPDR,
-               .ppdr                           = (void __iomem *) MCFEPORT_EPPDR,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 8,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 16,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "SSI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 24,
-                       .ngpio                  = 5,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_SSI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_SSI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_SSI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_SSI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_SSI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BUSCTL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 32,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BUSCTL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BUSCTL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BUSCTL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BUSCTL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "BE",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 40,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_BE,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_BE,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_BE,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_BE,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "CS",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 49,
-                       .ngpio                  = 5,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_CS,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_CS,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_CS,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_CS,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "PWM",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 58,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_PWM,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_PWM,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_PWM,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_PWM,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_PWM,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "FECI2C",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 64,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_FECI2C,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_FECI2C,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_FECI2C,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_FECI2C,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "UART",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 72,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_UART,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_UART,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_UART,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_UART,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "QSPI",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 80,
-                       .ngpio                  = 6,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_QSPI,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_QSPI,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_QSPI,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_QSPI,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "TIMER",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 88,
-                       .ngpio                  = 4,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_TIMER,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_TIMER,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_TIMER,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_TIMER,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "LCDDATAH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 96,
-                       .ngpio                  = 2,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "LCDDATAM",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 104,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAM,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAM,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAM,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAM,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAM,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "LCDDATAL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 112,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDDATAL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDDATAL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDDATAL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDDATAL,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "LCDCTLH",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 120,
-                       .ngpio                  = 1,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDCTLH,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDCTLH,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLH,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLH,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDCTLH,
-       },
-       {
-               .gpio_chip                      = {
-                       .label                  = "LCDCTLL",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value_fast,
-                       .base                   = 128,
-                       .ngpio                  = 8,
-               },
-               .pddr                           = (void __iomem *) MCFGPIO_PDDR_LCDCTLL,
-               .podr                           = (void __iomem *) MCFGPIO_PODR_LCDCTLL,
-               .ppdr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLL,
-               .setr                           = (void __iomem *) MCFGPIO_PPDSDR_LCDCTLL,
-               .clrr                           = (void __iomem *) MCFGPIO_PCLRR_LCDCTLL,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile
deleted file mode 100644 (file)
index e83fe14..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o gpio.o
-
diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c
deleted file mode 100644 (file)
index 70ea789..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/5407/config.c
- *
- *     Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2000, Lineo (www.lineo.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfuart.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m5407_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 73,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 74,
-       },
-       { },
-};
-
-static struct platform_device m5407_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m5407_uart_platform,
-};
-
-static struct platform_device *m5407_devices[] __initdata = {
-       &m5407_uart,
-};
-
-/***************************************************************************/
-
-static void __init m5407_uart_init_line(int line, int irq)
-{
-       if (line == 0) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART0);
-       } else if (line == 1) {
-               writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
-               writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_mapirq2imr(irq, MCFINTC_UART1);
-       }
-}
-
-static void __init m5407_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m5407_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m5407_uart_init_line(line, m5407_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void __init m5407_timers_init(void)
-{
-       /* Timer1 is always used as system timer */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER1ICR);
-       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
-
-#ifdef CONFIG_HIGHPROFILE
-       /* Timer2 is to be used as a high speed profile timer  */
-       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
-               MCF_MBAR + MCFSIM_TIMER2ICR);
-       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
-#endif
-}
-
-/***************************************************************************/
-
-void m5407_cpu_reset(void)
-{
-       local_irq_disable();
-       /* set watchdog to soft reset, and enabled */
-       __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
-       for (;;)
-               /* wait for watchdog to timeout */;
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = m5407_cpu_reset;
-       m5407_timers_init();
-       m5407_uarts_init();
-
-       /* Only support the external interrupts on their primary level */
-       mcf_mapirq2imr(25, MCFINTC_EINT1);
-       mcf_mapirq2imr(27, MCFINTC_EINT3);
-       mcf_mapirq2imr(29, MCFINTC_EINT5);
-       mcf_mapirq2imr(31, MCFINTC_EINT7);
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-       platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/5407/gpio.c b/arch/m68knommu/platform/5407/gpio.c
deleted file mode 100644 (file)
index 5850612..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Coldfire generic GPIO support
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfgpio.h>
-
-static struct mcf_gpio_chip mcf_gpio_chips[] = {
-       {
-               .gpio_chip                      = {
-                       .label                  = "PP",
-                       .request                = mcf_gpio_request,
-                       .free                   = mcf_gpio_free,
-                       .direction_input        = mcf_gpio_direction_input,
-                       .direction_output       = mcf_gpio_direction_output,
-                       .get                    = mcf_gpio_get_value,
-                       .set                    = mcf_gpio_set_value,
-                       .ngpio                  = 16,
-               },
-               .pddr                           = (void __iomem *) MCFSIM_PADDR,
-               .podr                           = (void __iomem *) MCFSIM_PADAT,
-               .ppdr                           = (void __iomem *) MCFSIM_PADAT,
-       },
-};
-
-static int __init mcf_gpio_init(void)
-{
-       unsigned i = 0;
-       while (i < ARRAY_SIZE(mcf_gpio_chips))
-               (void)gpiochip_add((struct gpio_chip *)&mcf_gpio_chips[i++]);
-       return 0;
-}
-
-core_initcall(mcf_gpio_init);
diff --git a/arch/m68knommu/platform/54xx/Makefile b/arch/m68knommu/platform/54xx/Makefile
deleted file mode 100644 (file)
index 6cfd090..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Makefile for the m68knommu linux kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-y := config.o
-obj-$(CONFIG_FIREBEE) += firebee.o
-
diff --git a/arch/m68knommu/platform/54xx/config.c b/arch/m68knommu/platform/54xx/config.c
deleted file mode 100644 (file)
index 7813098..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/54xx/config.c
- *
- *     Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/m54xxsim.h>
-#include <asm/mcfuart.h>
-#include <asm/m54xxgpt.h>
-
-/***************************************************************************/
-
-static struct mcf_platform_uart m54xx_uart_platform[] = {
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE1,
-               .irq            = 64 + 35,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE2,
-               .irq            = 64 + 34,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE3,
-               .irq            = 64 + 33,
-       },
-       {
-               .mapbase        = MCF_MBAR + MCFUART_BASE4,
-               .irq            = 64 + 32,
-       },
-};
-
-static struct platform_device m54xx_uart = {
-       .name                   = "mcfuart",
-       .id                     = 0,
-       .dev.platform_data      = m54xx_uart_platform,
-};
-
-static struct platform_device *m54xx_devices[] __initdata = {
-       &m54xx_uart,
-};
-
-
-/***************************************************************************/
-
-static void __init m54xx_uart_init_line(int line, int irq)
-{
-       int rts_cts;
-
-       /* enable io pins */
-       switch (line) {
-       case 0:
-               rts_cts = 0; break;
-       case 1:
-               rts_cts = MCF_PAR_PSC_RTS_RTS; break;
-       case 2:
-               rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
-       case 3:
-               rts_cts = 0; break;
-       }
-       __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
-                                               MCF_MBAR + MCF_PAR_PSC(line));
-}
-
-static void __init m54xx_uarts_init(void)
-{
-       const int nrlines = ARRAY_SIZE(m54xx_uart_platform);
-       int line;
-
-       for (line = 0; (line < nrlines); line++)
-               m54xx_uart_init_line(line, m54xx_uart_platform[line].irq);
-}
-
-/***************************************************************************/
-
-static void mcf54xx_reset(void)
-{
-       /* disable interrupts and enable the watchdog */
-       asm("movew #0x2700, %sr\n");
-       __raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
-       __raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
-       __raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
-                                               MCF_MBAR + MCF_GPT_GMS0);
-}
-
-/***************************************************************************/
-
-void __init config_BSP(char *commandp, int size)
-{
-       mach_reset = mcf54xx_reset;
-       m54xx_uarts_init();
-}
-
-/***************************************************************************/
-
-static int __init init_BSP(void)
-{
-
-       platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices));
-       return 0;
-}
-
-arch_initcall(init_BSP);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/54xx/firebee.c b/arch/m68knommu/platform/54xx/firebee.c
deleted file mode 100644 (file)
index 46d5053..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************/
-
-/*
- *     firebee.c -- extra startup code support for the FireBee boards
- *
- *     Copyright (C) 2011, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     8MB of NOR flash fitted to the FireBee board.
- */
-#define        FLASH_PHYS_ADDR         0xe0000000      /* Physical address of flash */
-#define        FLASH_PHYS_SIZE         0x00800000      /* Size of flash */
-
-#define        PART_BOOT_START         0x00000000      /* Start at bottom of flash */
-#define        PART_BOOT_SIZE          0x00040000      /* 256k in size */
-#define        PART_IMAGE_START        0x00040000      /* Start after boot loader */
-#define        PART_IMAGE_SIZE         0x006c0000      /* Most of flash */
-#define        PART_FPGA_START         0x00700000      /* Start at offset 7MB */
-#define        PART_FPGA_SIZE          0x00100000      /* 1MB in size */
-
-static struct mtd_partition firebee_flash_parts[] = {
-       {
-               .name   = "dBUG",
-               .offset = PART_BOOT_START,
-               .size   = PART_BOOT_SIZE,
-       },
-       {
-               .name   = "FPGA",
-               .offset = PART_FPGA_START,
-               .size   = PART_FPGA_SIZE,
-       },
-       {
-               .name   = "image",
-               .offset = PART_IMAGE_START,
-               .size   = PART_IMAGE_SIZE,
-       },
-};
-
-static struct physmap_flash_data firebee_flash_data = {
-       .width          = 2,
-       .nr_parts       = ARRAY_SIZE(firebee_flash_parts),
-       .parts          = firebee_flash_parts,
-};
-
-static struct resource firebee_flash_resource = {
-       .start          = FLASH_PHYS_ADDR,
-       .end            = FLASH_PHYS_ADDR + FLASH_PHYS_SIZE,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device firebee_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data = &firebee_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &firebee_flash_resource,
-};
-
-/***************************************************************************/
-
-static int __init init_firebee(void)
-{
-       platform_device_register(&firebee_flash);
-       return 0;
-}
-
-arch_initcall(init_firebee);
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/68328/Makefile b/arch/m68knommu/platform/68328/Makefile
deleted file mode 100644 (file)
index 5e54355..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68328.
-#
-
-head-y                 = head-$(MODEL).o
-head-$(CONFIG_PILOT)   = head-pilot.o
-head-$(CONFIG_DRAGEN2) = head-de2.o
-
-obj-y                  += entry.o ints.o timers.o
-obj-$(CONFIG_M68328)   += config.o
-obj-$(CONFIG_ROM)      += romvec.o
-
-extra-y                        := head.o
-extra-$(CONFIG_M68328) += bootlogo.rh head.o
-
-$(obj)/bootlogo.rh: $(src)/bootlogo.h
-       perl $(src)/bootlogo.pl < $(src)/bootlogo.h > $(obj)/bootlogo.rh
-
-$(obj)/head.o: $(obj)/$(head-y)
-       ln -sf $(head-y) $(obj)/head.o
-
-clean-files := $(obj)/bootlogo.rh $(obj)/head.o $(head-y)
diff --git a/arch/m68knommu/platform/68328/bootlogo.h b/arch/m68knommu/platform/68328/bootlogo.h
deleted file mode 100644 (file)
index 67bc2c1..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#define bootlogo_width 160
-#define bootlogo_height 160
-static unsigned char bootlogo_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00,
-  0x00, 0xff, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x80, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x50, 0x04, 0x00, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00,
-  0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40,
-  0xa8, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x28, 0x01, 0x00, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70,
-  0x54, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x3a, 0x78, 0x80, 0x0e,
-  0x50, 0xc0, 0x03, 0x0e, 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
-  0x00, 0x3e, 0xf0, 0x83, 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x1f,
-  0x00, 0x18, 0x00, 0x30, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0xc3,
-  0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x0f, 0x00, 0x20, 0x00, 0x10,
-  0x55, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc0, 0x03, 0x9f, 0xf3, 0x80, 0x0f,
-  0x78, 0x80, 0xc7, 0x0e, 0x00, 0x18, 0x00, 0x20, 0xaa, 0x00, 0x00, 0x00,
-  0x00, 0x1e, 0xe0, 0x03, 0x9f, 0xf1, 0x80, 0x07, 0x78, 0x80, 0x67, 0x00,
-  0x00, 0x24, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01,
-  0x5e, 0xf0, 0x80, 0x07, 0x3c, 0x00, 0x2f, 0x00, 0x00, 0x14, 0x00, 0x20,
-  0xaa, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, 0x7f, 0xf0, 0x80, 0x07,
-  0x3c, 0x00, 0x3f, 0x00, 0x00, 0x08, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00,
-  0x00, 0x0f, 0xe0, 0x00, 0x3f, 0xf0, 0xc0, 0x03, 0x1e, 0x00, 0x1f, 0x00,
-  0x00, 0x14, 0x00, 0x28, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00,
-  0x1f, 0xf0, 0xc0, 0x03, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x0c,
-  0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xc0, 0x03,
-  0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x12, 0xa8, 0x00, 0x00, 0x00,
-  0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1f, 0x00,
-  0x00, 0x04, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x80,
-  0x0f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x08,
-  0x50, 0x01, 0x00, 0x00, 0x84, 0x03, 0x78, 0x80, 0x07, 0x3c, 0xe0, 0xc1,
-  0x0f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x06, 0xa8, 0x00, 0x00, 0x00,
-  0xc0, 0x03, 0x78, 0xc0, 0x07, 0x3c, 0xe0, 0xc1, 0x0f, 0x00, 0x1f, 0x00,
-  0x00, 0x0a, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0xc2, 0x01, 0x38, 0xc0,
-  0x07, 0x3c, 0xe0, 0x60, 0x0f, 0x80, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x07,
-  0xa0, 0x00, 0x00, 0x80, 0xe0, 0x01, 0x3c, 0xc0, 0x07, 0x3c, 0xf0, 0xa0,
-  0x07, 0xc0, 0x1c, 0x00, 0x00, 0x0a, 0x80, 0x08, 0xa0, 0x02, 0x00, 0xa0,
-  0xe0, 0x21, 0x1c, 0xc0, 0x03, 0x1c, 0x71, 0x90, 0x47, 0x40, 0x3c, 0x04,
-  0x00, 0x05, 0x80, 0x06, 0xa0, 0x02, 0x00, 0x20, 0xe0, 0x31, 0x1e, 0xc3,
-  0x03, 0x1e, 0x79, 0x98, 0x47, 0x60, 0x38, 0x04, 0x00, 0x15, 0x40, 0x0a,
-  0xa0, 0x0a, 0x00, 0x1a, 0xe0, 0x19, 0x9e, 0xe1, 0x01, 0x9e, 0x78, 0xcc,
-  0xa7, 0x32, 0x78, 0x02, 0x80, 0x2a, 0x40, 0x05, 0x80, 0x2a, 0x00, 0x05,
-  0xe0, 0x0d, 0x9e, 0xe0, 0x01, 0xde, 0x78, 0xc6, 0x97, 0x1b, 0x78, 0x03,
-  0x80, 0x52, 0x30, 0x0a, 0x00, 0x95, 0xd2, 0x0a, 0xe0, 0x0f, 0xfe, 0xe0,
-  0x00, 0x7e, 0xf8, 0x87, 0x9f, 0x0f, 0xf8, 0x01, 0x00, 0xa1, 0x0e, 0x15,
-  0x80, 0x55, 0x55, 0x01, 0xe0, 0x01, 0x3c, 0xf0, 0x00, 0x3c, 0xf0, 0x80,
-  0x8f, 0x0f, 0x70, 0x00, 0x00, 0x81, 0x02, 0x14, 0x00, 0x54, 0x55, 0x00,
-  0xc0, 0x01, 0x3c, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x07, 0x03, 0x70, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x01, 0x00, 0x11, 0x09, 0x00, 0x04, 0x00, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
-  0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x32, 0x49, 0x49, 0x91,
-  0x24, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x49, 0x0a, 0x09, 0xc9, 0x92, 0x14, 0x81, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49,
-  0x18, 0x01, 0x49, 0x92, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x30, 0x01, 0x49, 0x92,
-  0x14, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x08, 0x69, 0x22, 0x09, 0x49, 0xd2, 0x24, 0x24, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51,
-  0x1a, 0x09, 0x49, 0xa2, 0x44, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x87, 0x08, 0x00, 0x00, 0x00,
-  0xf2, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
-  0x09, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
-  0x88, 0x86, 0x48, 0x04, 0x09, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x71,
-  0x88, 0x66, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x89, 0x48, 0x84,
-  0x08, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x89, 0x88, 0x99, 0x00, 0x00,
-  0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x82, 0xf8, 0xf0, 0xe0, 0x80,
-  0xf0, 0xf8, 0x13, 0x81, 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80,
-  0x88, 0x88, 0x08, 0x81, 0x08, 0x09, 0x01, 0x41, 0x08, 0x01, 0xf0, 0xf0,
-  0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x42,
-  0x08, 0x09, 0x01, 0x21, 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00,
-  0x00, 0x40, 0x46, 0x88, 0x88, 0x88, 0x4c, 0x44, 0x08, 0x09, 0x09, 0x11,
-  0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x80, 0x85, 0x87,
-  0x88, 0x08, 0x4b, 0x24, 0xf0, 0xf0, 0xf0, 0xf8, 0xf1, 0x00, 0x10, 0x70,
-  0x89, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x08, 0x02, 0x04, 0x00,
-  0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x1f, 0x00, 0x00, 0x48, 0x62, 0xc4, 0x31, 0x4a, 0x18, 0x3c, 0x03,
-  0x21, 0x45, 0x92, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x1f, 0x00, 0x00,
-  0x48, 0x92, 0x24, 0x48, 0xb6, 0x24, 0x88, 0x04, 0x21, 0x4b, 0x92, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xa8, 0xf2, 0x24, 0x48,
-  0x92, 0x3c, 0x88, 0x04, 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04,
-  0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, 0x21, 0x49, 0x93, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xcf, 0x7e, 0x00, 0x00, 0x10, 0xe1, 0xc4, 0x31,
-  0x92, 0x38, 0x30, 0x03, 0x2f, 0x89, 0x92, 0x00, 0x00, 0x00, 0x80, 0xe3,
-  0x07, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x03, 0x7e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xc9, 0x23, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95,
-  0x33, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdd, 0xfb, 0x7e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x1d, 0xf8, 0x7e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x40, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b,
-  0x70, 0x7e, 0x00, 0x00, 0x08, 0x00, 0xe0, 0x00, 0x02, 0x00, 0x47, 0x80,
-  0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x03, 0x00, 0x7e, 0x00, 0x00,
-  0x3c, 0xa3, 0x20, 0x31, 0x52, 0x02, 0x49, 0xcc, 0x3f, 0xa3, 0x94, 0x08,
-  0x00, 0x00, 0x00, 0x27, 0x02, 0x7e, 0x00, 0x00, 0x88, 0xe4, 0x20, 0x41,
-  0xb2, 0x05, 0x49, 0x90, 0x88, 0xe4, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x7e, 0x00, 0x00, 0x88, 0x24, 0xe0, 0x70, 0x92, 0x04, 0x47, 0x9c,
-  0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x13, 0x48, 0x7e, 0x00, 0x00,
-  0x88, 0x24, 0x20, 0x48, 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x01,
-  0x00, 0x00, 0x00, 0x43, 0x00, 0xfe, 0x00, 0x00, 0x88, 0x24, 0x20, 0x48,
-  0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x07,
-  0x94, 0xce, 0x00, 0x00, 0x08, 0x23, 0x20, 0xb0, 0x92, 0x04, 0x41, 0x2c,
-  0x0b, 0x23, 0x24, 0x09, 0x00, 0x00, 0x00, 0x49, 0x02, 0xce, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x11, 0x08, 0xdc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x01, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01,
-  0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
-  0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
-  0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
-  0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00,
-  0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xfe, 0x0f,
-  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x08, 0x00,
-  0x00, 0xc0, 0x03, 0x00, 0x78, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x40, 0x10,
-  0x12, 0x10, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
-  0x84, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x20, 0x26, 0x0a, 0x10, 0x9d, 0x39,
-  0xa6, 0xb2, 0x0a, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x02, 0x00, 0xfe, 0x0f,
-  0x00, 0x00, 0x20, 0x21, 0x06, 0x28, 0x25, 0x4a, 0xa9, 0x8a, 0x09, 0x00,
-  0x00, 0xe0, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21,
-  0x0e, 0x38, 0xa5, 0x4b, 0xa9, 0xb2, 0x09, 0x00, 0x00, 0xf0, 0x01, 0x22,
-  0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, 0x12, 0x44, 0xa5, 0x4a,
-  0x49, 0xa1, 0x0a, 0x00, 0x00, 0xf8, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f,
-  0x00, 0x00, 0x20, 0x26, 0x52, 0x44, 0x9d, 0x4d, 0x46, 0x99, 0x0a, 0x00,
-  0x00, 0xfc, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x40, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xb2,
-  0x84, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x6e, 0x78, 0x00, 0xfc, 0x1f,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfc, 0x01, 0x02, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x02,
-  0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0xfc, 0x0f,
-  0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x24, 0x06, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x40, 0x10,
-  0x1e, 0x20, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
-  0x00, 0x80, 0xfc, 0x03, 0x00, 0x00, 0x20, 0x26, 0x22, 0x20, 0xf9, 0x89,
-  0x32, 0xe7, 0x08, 0x00, 0x00, 0x92, 0x38, 0x00, 0x00, 0x00, 0xfc, 0x01,
-  0x00, 0x00, 0x20, 0x21, 0x22, 0xa0, 0x92, 0x88, 0x4a, 0x29, 0x15, 0x00,
-  0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0xfa, 0x04, 0x00, 0x00, 0x20, 0x21,
-  0x22, 0xa0, 0x93, 0x88, 0x4a, 0x29, 0x1d, 0x00, 0x00, 0x11, 0xf2, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0xa8, 0x90, 0x88,
-  0x4a, 0x29, 0x05, 0x00, 0x48, 0x40, 0xf0, 0x01, 0x00, 0x80, 0x14, 0x04,
-  0x00, 0x00, 0x20, 0x26, 0x9e, 0x10, 0x93, 0x78, 0x32, 0x29, 0x19, 0x00,
-  0x00, 0x09, 0xe0, 0x03, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x40, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc5, 0x03,
-  0x00, 0x40, 0x22, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x20, 0x08, 0x04,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x50, 0x90, 0x03, 0x00, 0xb0, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
-  0x00, 0x38, 0x22, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x44, 0x00, 0x00, 0x3c, 0x08, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0xbf, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x80, 0x48, 0x02,
-  0xc0, 0x1f, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xf0, 0x3f, 0x09, 0x00,
-  0x00, 0x10, 0x24, 0x48, 0x10, 0x12, 0x41, 0x52, 0x24, 0x09, 0x46, 0x71,
-  0x90, 0x20, 0x02, 0xfc, 0xff, 0x1f, 0x80, 0x22, 0x00, 0x90, 0x24, 0x49,
-  0x12, 0x92, 0x40, 0xb2, 0x24, 0x09, 0xc9, 0x49, 0x04, 0x80, 0x90, 0xfc,
-  0xff, 0xbf, 0x24, 0x00, 0x00, 0x90, 0x24, 0x49, 0x12, 0x92, 0x40, 0x92,
-  0x24, 0x06, 0x49, 0x48, 0x50, 0x0a, 0x02, 0xfe, 0xff, 0x3f, 0x00, 0x05,
-  0x00, 0x50, 0xa5, 0x4a, 0x15, 0x92, 0x40, 0x92, 0x24, 0x06, 0x49, 0x48,
-  0x80, 0x40, 0x48, 0xfe, 0xff, 0x3f, 0x49, 0x00, 0x00, 0x20, 0x42, 0x84,
-  0x88, 0x1a, 0x41, 0x92, 0x34, 0x49, 0x49, 0x68, 0x00, 0x38, 0x10, 0x07,
-  0x00, 0x60, 0x80, 0x00, 0x00, 0x20, 0x42, 0x84, 0x88, 0x14, 0x4e, 0x92,
-  0x28, 0x49, 0x46, 0x50, 0x00, 0x80, 0x83, 0x01, 0x00, 0xa0, 0x6a, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-  0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, };
diff --git a/arch/m68knommu/platform/68328/bootlogo.pl b/arch/m68knommu/platform/68328/bootlogo.pl
deleted file mode 100644 (file)
index b04ae3f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-$_ = join("", <>);
-
-s/(0x[0-9a-f]{2})/sprintf("0x%.2x",ord(pack("b8",unpack("B8",chr(hex($1))))))/gei;
-
-s/^ /  .byte /gm;
-s/[,};]+$//gm;
-s/^static.*//gm;
-
-print $_;
diff --git a/arch/m68knommu/platform/68328/config.c b/arch/m68knommu/platform/68328/config.c
deleted file mode 100644 (file)
index a7bd21d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/68328/config.c
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *
- * 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.
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/system.h>
-#include <asm/machdep.h>
-#include <asm/MC68328.h>
-
-/***************************************************************************/
-
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
-
-/***************************************************************************/
-
-void m68328_reset (void)
-{
-  local_irq_disable();
-  asm volatile ("moveal #0x10c00000, %a0;\n\t"
-               "moveb #0, 0xFFFFF300;\n\t"
-               "moveal 0(%a0), %sp;\n\t"
-               "moveal 4(%a0), %a0;\n\t"
-               "jmp (%a0);");
-}
-
-/***************************************************************************/
-
-void config_BSP(char *command, int len)
-{
-  printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
-  printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
-  printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n");
-
-  mach_gettod = m68328_timer_gettod;
-  mach_reset = m68328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
deleted file mode 100644 (file)
index 676960c..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68328/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/thread_info.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl ret_from_interrupt
-.globl bad_interrupt
-.globl inthandler1
-.globl inthandler2
-.globl inthandler3
-.globl inthandler4
-.globl inthandler5
-.globl inthandler6
-.globl inthandler7
-
-badsys:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)
-       jra     ret_from_exception
-
-do_trace:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %sp@(PT_OFF_ORIG_D0),%d1
-       movel   #-ENOSYS,%d0
-       cmpl    #NR_syscalls,%d1
-       jcc     1f
-       lsl     #2,%d1
-       lea     sys_call_table, %a0
-       jbsr    %a0@(%d1)
-
-1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(system_call)
-       SAVE_ALL
-
-       /* save top of frame*/
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
-
-       movel   %sp@(PT_OFF_ORIG_D0),%d0
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       jne     do_trace
-       cmpl    #NR_syscalls,%d0
-       jcc     badsys
-       lsl     #2,%d0
-       lea     sys_call_table,%a0
-       movel   %a0@(%d0), %a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
-
-ret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
-       jeq     Luser_return            /* if so, skip resched, signals*/
-
-Lkernel_return:
-       RESTORE_ALL
-
-Luser_return:
-       /* only allow interrupts when we are really the last one on the*/
-       /* kernel stack, otherwise stack overflow can occur during*/
-       /* heavy interrupt load*/
-       andw    #ALLOWINT,%sr
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       jne     Lwork_to_do
-       RESTORE_ALL
-
-Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address*/
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       bsrw    do_signal
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     1b
-
-/*
- * This is the main interrupt handler, responsible for calling process_int()
- */
-inthandler1:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #65,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler2:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #66,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler3:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #67,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler4:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #68,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler5:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #69,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler6:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #70,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler7:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   #71,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-inthandler:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and     #0x3ff, %d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               /*  put vector # on stack*/
-       jbsr    process_int             /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-ret_from_interrupt:
-       jeq     1f
-2:
-       RESTORE_ALL
-1:
-       moveb   %sp@(PT_OFF_SR), %d0
-       and     #7, %d0
-       jhi     2b
-
-       /* check if we need to do software interrupts */
-       jeq     ret_from_exception
-
-       pea     ret_from_exception
-       jra     do_softirq
-
-
-/*
- * Handler for uninitialized and spurious interrupts.
- */
-ENTRY(bad_interrupt)
-       addql   #1,num_spurious
-       rte
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1,so don't change these
- * registers until their contents are no longer needed.
- */
-ENTRY(resume)
-       movel   %a0,%d1                         /* save prev thread in d1 */
-       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
-       movel   %usp,%a2                        /* save usp */
-       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
-
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
-       RESTORE_SWITCH_STACK
-
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore user stack */
-       movel   %a0,%usp
-       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
-       rts
-
diff --git a/arch/m68knommu/platform/68328/head-de2.S b/arch/m68knommu/platform/68328/head-de2.S
deleted file mode 100644 (file)
index f632fdc..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-
-#define        MEM_END 0x00800000      /* Memory size 8Mb */
-
-#undef CRT_DEBUG
-
-.macro PUTC CHAR
-#ifdef CRT_DEBUG
-       moveq   #\CHAR, %d7
-       jsr     putc
-#endif
-.endm
-
-       .global _start
-       .global _rambase
-       .global _ramvec
-       .global _ramstart
-       .global _ramend
-       
-       .data
-
-/*
- *     Set up the usable of RAM stuff
- */
-_rambase:
-       .long   0
-_ramvec:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-
-       .text
-
-_start:
-
-/*
- * Setup initial stack
- */
-       /* disable all interrupts */
-       movew   #0x2700, %sr
-       movel   #-1, 0xfffff304
-       movel   #MEM_END-4, %sp
-
-       PUTC    '\r'
-       PUTC    '\n'
-       PUTC    'A'
-       PUTC    'B'
-
-/*
- *     Determine end of RAM
- */
-
-       movel   #MEM_END, %a0
-       movel   %a0, _ramend
-
-       PUTC    'C'
-
-/*
- *     Move ROM filesystem above bss :-)
- */
-
-       moveal  #_sbss, %a0                     /* romfs at the start of bss */
-       moveal  #_ebss, %a1                     /* Set up destination  */
-       movel   %a0, %a2                        /* Copy of bss start */
-
-       movel   8(%a0), %d1                     /* Get size of ROMFS */
-       addql   #8, %d1                         /* Allow for rounding */
-       andl    #0xfffffffc, %d1        /* Whole words */
-
-       addl    %d1, %a0                        /* Copy from end */
-       addl    %d1, %a1                        /* Copy from end */
-       movel   %a1, _ramstart          /* Set start of ram */
-
-1:
-       movel   -(%a0), %d0                     /* Copy dword */
-       movel   %d0, -(%a1)
-       cmpl    %a0, %a2                        /* Check if at end */
-       bne     1b
-
-       PUTC    'D'
-
-/*
- * Initialize BSS segment to 0
- */
-
-       lea     _sbss, %a0
-       lea     _ebss, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-2:     cmpal   %a0, %a1
-       beq     1f
-       clrl    (%a0)+
-       bra     2b
-1:
-
-       PUTC    'E'
-
-/*
- * Load the current task pointer and stack
- */
-
-       lea     init_thread_union, %a0
-       lea     0x2000(%a0), %sp
-
-       PUTC    'F'
-       PUTC    '\r'
-       PUTC    '\n'
-
-/*
- * Go
- */
-
-       jmp     start_kernel
-
-/*
- * Local functions
- */
-#ifdef CRT_DEBUG
-putc:
-       moveb   %d7, 0xfffff907
-1:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     1b
-       rts
-#endif
diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S
deleted file mode 100644 (file)
index aecff53..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * linux/arch/m68knommu/platform/68328/head-pilot.S
- * - A startup file for the MC68328
- *
- * Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
- *                     Kenneth Albanowski <kjahds@kjahds.com>,
- *                     The Silver Hammer Group, Ltd.
- *
- * (c) 1995, Dionne & Associates
- * (c) 1995, DKG Display Tech.
- */
-
-#define ASSEMBLY
-
-#define IMMED #
-#define        DBG_PUTC(x)     moveb IMMED x, 0xfffff907
-
-
-.global _stext
-.global _start
-
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global penguin_bits
-
-#ifdef CONFIG_PILOT
-
-#define IMR 0xFFFFF304
-
-       .data
-       .align 16
-
-penguin_bits:  
-#include "bootlogo.rh"
-
-#endif
-
-/*****************************************************************************/
-
-.data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-.text
-       
-_start:
-_stext:
-
-
-#ifdef CONFIG_M68328
-
-#ifdef CONFIG_PILOT
-       .byte 0x4e, 0xfa, 0x00, 0x0a /* Jmp +X bytes */
-       .byte 'b', 'o', 'o', 't'
-       .word 10000
-
-       nop
-#endif
-
-       moveq   #0, %d0
-       movew   %d0, 0xfffff618 /* Watchdog off */
-       movel   #0x00011f07, 0xfffff114 /* CS A1 Mask */
-
-       movew   #0x0800, 0xfffff906 /* Ignore CTS */
-       movew   #0x010b, 0xfffff902 /* BAUD to 9600 */
-
-       movew   #0x2410, 0xfffff200 /* PLLCR */
-       movew   #0x123, 0xfffff202 /* PLLFSR */
-
-#ifdef CONFIG_PILOT
-       moveb   #0, 0xfffffA27 /* LCKCON */
-       movel   #_start, 0xfffffA00 /* LSSA */
-       moveb   #0xa, 0xfffffA05 /* LVPW */
-       movew   #0x9f, 0xFFFFFa08 /* LXMAX */
-       movew   #0x9f, 0xFFFFFa0a /* LYMAX */
-       moveb   #9, 0xfffffa29 /* LBAR */
-       moveb   #0, 0xfffffa25 /* LPXCD */
-       moveb   #0x04, 0xFFFFFa20 /* LPICF */
-       moveb   #0x58, 0xfffffA27 /* LCKCON */
-       moveb   #0x85, 0xfffff429 /* PFDATA */
-       moveb   #0xd8, 0xfffffA27 /* LCKCON */
-       moveb   #0xc5, 0xfffff429 /* PFDATA */
-       moveb   #0xd5, 0xfffff429 /* PFDATA */
-
-       moveal  #0x00100000, %a3
-       moveal  #0x100ffc00, %a4
-#endif /* CONFIG_PILOT */
-
-#endif /* CONFIG_M68328 */
-
-       movew   #0x2700, %sr
-       lea     %a4@(-4), %sp
-
-       DBG_PUTC('\r')
-       DBG_PUTC('\n')
-       DBG_PUTC('A')
-
-       moveq   #0,%d0
-       movew   #16384, %d0  /* PLL settle wait loop */
-L0:
-       subw    #1, %d0
-       bne     L0
-
-       DBG_PUTC('B')
-
-       /* Copy command line from beginning of RAM (+16) to end of bss */
-       movel   #CONFIG_VECTORBASE, %d7
-       addl    #16, %d7
-       moveal  %d7, %a0
-       moveal  #_ebss, %a1
-       lea     %a1@(512), %a2
-
-       DBG_PUTC('C')
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-L2:
-       movel   %a0@+, %d0
-       movel   %d0, %a1@+
-       cmpal   %a1, %a2
-       bhi     L2
-
-       /* Copy data+init segment from ROM to RAM */
-       moveal  #_etext, %a0
-       moveal  #_sdata, %a1
-       moveal  #__init_end, %a2
-
-       DBG_PUTC('D')
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       movel   %a0@+, %d0
-       movel   %d0, %a1@+
-       cmpal   %a1, %a2
-       bhi     LD1
-
-       DBG_PUTC('E')
-
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-       DBG_PUTC('F')
-
-       /* Copy command line from end of bss to command line */
-       moveal  #_ebss, %a0
-       moveal  #command_line, %a1
-       lea     %a1@(512), %a2
-
-       DBG_PUTC('G')
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-L3:
-       movel   %a0@+, %d0
-       movel   %d0, %a1@+
-       cmpal   %a1, %a2
-       bhi     L3
-
-       movel   #_sdata, %d0    
-       movel   %d0, _rambase   
-       movel   #_ebss, %d0
-       movel   %d0, _ramstart
-
-       movel   %a4, %d0
-       subl    #4096, %d0      /* Reserve 4K of stack */
-       moveq   #79, %d7
-       movel   %d0, _ramend
-
-       movel   %a3, %d0
-       movel   %d0, rom_length
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-       DBG_PUTC('H')
-
-#ifdef CONFIG_PILOT
-       movel   #penguin_bits, 0xFFFFFA00
-       moveb   #10, 0xFFFFFA05
-       movew   #160, 0xFFFFFA08
-       movew   #160, 0xFFFFFA0A
-#endif /* CONFIG_PILOT */
-
-       DBG_PUTC('I')
-
-       lea     init_thread_union, %a0
-       lea     0x2000(%a0), %sp
-
-       DBG_PUTC('J')
-       DBG_PUTC('\r')
-       DBG_PUTC('\n')
-
-       jsr     start_kernel
-_exit:
-
-       jmp     _exit
-
-
-       .data
-env:
-       .long   0
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68knommu/platform/68328/head-ram.S
deleted file mode 100644 (file)
index 7f1aeea..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-       .global __main
-       .global __rom_start
-
-        .global _rambase
-        .global _ramstart
-       
-       .global splash_bits
-       .global _start
-       .global _stext
-       .global _edata
-
-#define DEBUG
-#define ROM_OFFSET 0x10C00000
-#define STACK_GAURD 0x10
-
-       .text
-       
-_start:
-_stext:
-       movew   #0x2700, %sr            /* Exceptions off! */
-
-#if 0
-       /* Init chip registers.  uCsimm specific */
-       moveb   #0x00,   0xfffffb0b     /* Watchdog off */
-       moveb   #0x10,   0xfffff000     /* SCR */
-
-       movew   #0x2400, 0xfffff200     /* PLLCR */
-       movew   #0x0123, 0xfffff202     /* PLLFSR */
-
-       moveb   #0x00,   0xfffff40b     /* enable chip select */
-       moveb   #0x00,   0xfffff423     /* enable /DWE */
-       moveb   #0x08,   0xfffffd0d     /* disable hardmap */
-       moveb   #0x07,   0xfffffd0e     /* level 7 interrupt clear */
-
-       movew   #0x8600, 0xfffff100     /* FLASH at 0x10c00000 */
-       movew   #0x018b, 0xfffff110     /* 2Meg, enable, 0ws */
-
-       movew   #0x8f00, 0xfffffc00     /* DRAM configuration */
-       movew   #0x9667, 0xfffffc02     /* DRAM control */
-       movew   #0x0000, 0xfffff106     /* DRAM at 0x00000000 */
-       movew   #0x068f, 0xfffff116     /* 8Meg, enable, 0ws */
-
-       moveb   #0x40,   0xfffff300     /* IVR */
-       movel   #0x007FFFFF, %d0        /* IMR */
-       movel   %d0,     0xfffff304
-
-       moveb   0xfffff42b, %d0
-       andb    #0xe0,   %d0
-       moveb   %d0,     0xfffff42b
-
-       moveb   #0x08,   0xfffff907     /* Ignore CTS */
-       movew   #0x010b, 0xfffff902     /* BAUD to 9600 */
-       movew   #0xe100, 0xfffff900     /* enable */
-#endif
-
-       movew   #16384, %d0  /* PLL settle wait loop */
-L0:
-       subw    #1, %d0
-       bne     L0
-#ifdef DEBUG
-       moveq   #70, %d7                /* 'F' */
-       moveb   %d7,0xfffff907          /* No absolute addresses */
-pclp1:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     pclp1
-#endif /* DEBUG */
-
-#ifdef DEBUG
-       moveq   #82, %d7                /* 'R' */
-       moveb   %d7,0xfffff907          /* No absolute addresses */
-pclp3:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     pclp3
-#endif /* DEBUG */
-       moveal  #0x007ffff0, %ssp
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
-
-       /* Copy 0 to %a0 until %a0 >= %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-#ifdef DEBUG
-       moveq   #67, %d7                /* 'C' */
-       jsr     putc
-#endif /* DEBUG */
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-#ifdef DEBUG
-       moveq   #70, %d7                /* 'F' */
-       jsr     putc
-#endif /* DEBUG */
-
-lp:
-       jsr     start_kernel
-        jmp lp
-_exit:
-
-       jmp     _exit
-
-__main:
-       /* nothing */
-       rts
-
-#ifdef DEBUG
-putc:
-       moveb   %d7,0xfffff907
-pclp:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     pclp
-       rts
-#endif /* DEBUG */
-
-       .data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-env:
-       .long   0
diff --git a/arch/m68knommu/platform/68328/head-rom.S b/arch/m68knommu/platform/68328/head-rom.S
deleted file mode 100644 (file)
index 6ec77d3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-       
-       .global _start
-       .global _stext
-
-       .global _rambase
-       .global _ramvec
-       .global _ramstart
-       .global _ramend
-
-#ifdef CONFIG_INIT_LCD
-       .global splash_bits
-#endif
-
-       .data
-
-/*
- *      Set up the usable of RAM stuff. Size of RAM is determined then
- *      an initial stack set up at the end.
- */
-.align 4
-_ramvec:
-.long   0
-_rambase:
-.long   0
-_ramstart:
-.long   0
-_ramend:
-.long   0
-
-#define        RAMEND  (CONFIG_RAMBASE + CONFIG_RAMSIZE)
-
-#ifdef CONFIG_INIT_LCD
-splash_bits:
-#include "bootlogo.rh"
-#endif
-       
-       .text
-_start:
-_stext:        movew   #0x2700,%sr
-#ifdef CONFIG_INIT_LCD
-       movel   #splash_bits, 0xfffffA00 /* LSSA */
-       moveb   #0x28,   0xfffffA05     /* LVPW */
-       movew   #0x280,  0xFFFFFa08     /* LXMAX */
-       movew   #0x1df,  0xFFFFFa0a     /* LYMAX */
-       moveb   #0,      0xfffffa29     /* LBAR */
-       moveb   #0,      0xfffffa25     /* LPXCD */
-       moveb   #0x08,   0xFFFFFa20     /* LPICF */
-       moveb   #0x01,   0xFFFFFA21     /* -ve pol */
-       moveb   #0x81,   0xfffffA27     /* LCKCON */
-       movew   #0xff00, 0xfffff412     /* LCD pins */
-#endif
-       moveal  #RAMEND-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp
-       movew   #32767, %d0  /* PLL settle wait loop */
-1:     subq    #1, %d0
-       bne     1b
-
-       /* Copy data segment from ROM to RAM */
-       moveal  #_etext, %a0
-       moveal  #_sdata, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-1:     movel   %a0@+, %a1@+
-       cmpal   %a1, %a2
-       bhi     1b
-
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
-       /* Copy 0 to %a0 until %a0 == %a1 */
-       
-1:
-       clrl    %a0@+
-       cmpal   %a0, %a1
-       bhi     1b
-
-        movel   #_sdata, %d0    
-        movel   %d0, _rambase        
-        movel   #_ebss, %d0
-        movel   %d0, _ramstart
-       movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
-       movel   %d0, _ramend
-       movel   #CONFIG_VECTORBASE,     %d0
-       movel   %d0, _ramvec
-       
-/*
- * load the current task pointer and stack
- */
-       lea     init_thread_union, %a0
-       lea     0x2000(%a0), %sp
-
-1:     jsr     start_kernel
-        bra 1b
-_exit:
-
-       jmp     _exit
-
-
-putc:
-       moveb   %d7,0xfffff907
-1:
-       movew   0xfffff906, %d7
-       andw    #0x2000, %d7
-       beq     1b
-       rts
-
-       .data
-env:
-       .long   0
-       .text
-
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
deleted file mode 100644 (file)
index e563183..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * linux/arch/m68knommu/platform/68328/ints.c
- *
- * 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 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-
-#if defined(CONFIG_M68328)
-#include <asm/MC68328.h>
-#elif defined(CONFIG_M68EZ328)
-#include <asm/MC68EZ328.h>
-#elif defined(CONFIG_M68VZ328)
-#include <asm/MC68VZ328.h>
-#endif
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void trap3(void);
-asmlinkage void trap4(void);
-asmlinkage void trap5(void);
-asmlinkage void trap6(void);
-asmlinkage void trap7(void);
-asmlinkage void trap8(void);
-asmlinkage void trap9(void);
-asmlinkage void trap10(void);
-asmlinkage void trap11(void);
-asmlinkage void trap12(void);
-asmlinkage void trap13(void);
-asmlinkage void trap14(void);
-asmlinkage void trap15(void);
-asmlinkage void trap33(void);
-asmlinkage void trap34(void);
-asmlinkage void trap35(void);
-asmlinkage void trap36(void);
-asmlinkage void trap37(void);
-asmlinkage void trap38(void);
-asmlinkage void trap39(void);
-asmlinkage void trap40(void);
-asmlinkage void trap41(void);
-asmlinkage void trap42(void);
-asmlinkage void trap43(void);
-asmlinkage void trap44(void);
-asmlinkage void trap45(void);
-asmlinkage void trap46(void);
-asmlinkage void trap47(void);
-asmlinkage irqreturn_t bad_interrupt(int, void *);
-asmlinkage irqreturn_t inthandler(void);
-asmlinkage irqreturn_t inthandler1(void);
-asmlinkage irqreturn_t inthandler2(void);
-asmlinkage irqreturn_t inthandler3(void);
-asmlinkage irqreturn_t inthandler4(void);
-asmlinkage irqreturn_t inthandler5(void);
-asmlinkage irqreturn_t inthandler6(void);
-asmlinkage irqreturn_t inthandler7(void);
-
-extern e_vector *_ramvec;
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-/* The 68k family did not have a good way to determine the source
- * of interrupts until later in the family.  The EC000 core does
- * not provide the vector number on the stack, we vector everything
- * into one vector and look in the blasted mask register...
- * This code is designed to be fast, almost constant time, not clean!
- */
-void process_int(int vec, struct pt_regs *fp)
-{
-       int irq;
-       int mask;
-
-       unsigned long pend = ISR;
-
-       while (pend) {
-               if (pend & 0x0000ffff) {
-                       if (pend & 0x000000ff) {
-                               if (pend & 0x0000000f) {
-                                       mask = 0x00000001;
-                                       irq = 0;
-                               } else {
-                                       mask = 0x00000010;
-                                       irq = 4;
-                               }
-                       } else {
-                               if (pend & 0x00000f00) {
-                                       mask = 0x00000100;
-                                       irq = 8;
-                               } else {
-                                       mask = 0x00001000;
-                                       irq = 12;
-                               }
-                       }
-               } else {
-                       if (pend & 0x00ff0000) {
-                               if (pend & 0x000f0000) {
-                                       mask = 0x00010000;
-                                       irq = 16;
-                               } else {
-                                       mask = 0x00100000;
-                                       irq = 20;
-                               }
-                       } else {
-                               if (pend & 0x0f000000) {
-                                       mask = 0x01000000;
-                                       irq = 24;
-                               } else {
-                                       mask = 0x10000000;
-                                       irq = 28;
-                               }
-                       }
-               }
-
-               while (! (mask & pend)) {
-                       mask <<=1;
-                       irq++;
-               }
-
-               do_IRQ(irq, fp);
-               pend &= ~mask;
-       }
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       IMR &= ~(1 << d->irq);
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       IMR |= (1 << d->irq);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "M68K-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-/*
- * This function should be called during kernel startup to initialize
- * the machine vector table.
- */
-void __init init_IRQ(void)
-{
-       int i;
-
-       /* set up the vectors */
-       for (i = 72; i < 256; ++i)
-               _ramvec[i] = (e_vector) bad_interrupt;
-
-       _ramvec[32] = system_call;
-
-       _ramvec[65] = (e_vector) inthandler1;
-       _ramvec[66] = (e_vector) inthandler2;
-       _ramvec[67] = (e_vector) inthandler3;
-       _ramvec[68] = (e_vector) inthandler4;
-       _ramvec[69] = (e_vector) inthandler5;
-       _ramvec[70] = (e_vector) inthandler6;
-       _ramvec[71] = (e_vector) inthandler7;
-
-       IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
-
-       /* turn off all interrupts */
-       IMR = ~0;
-
-       for (i = 0; (i < NR_IRQS); i++) {
-               set_irq_chip(i, &intc_irq_chip);
-               set_irq_handler(i, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
deleted file mode 100644 (file)
index 3108446..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * linux/arch/m68knommu/platform/68328/romvec.S
- *
- * 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 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
- */
-
-.global _start
-.global _buserr
-.global trap
-.global system_call
-
-.section .romvec
-
-e_vectors:
-.long CONFIG_RAMBASE+CONFIG_RAMSIZE-4, _start, buserr, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-/* TRAP #0-15 */
-.long system_call, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long trap, trap, trap, trap
-.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
diff --git a/arch/m68knommu/platform/68328/timers.c b/arch/m68knommu/platform/68328/timers.c
deleted file mode 100644 (file)
index 309f725..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/68328/timers.c
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *  Copyright (C) 2001 Georges Menie, Ken Desmet
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clocksource.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68VZ328.h>
-
-/***************************************************************************/
-
-#if defined(CONFIG_DRAGEN2)
-/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
-#define CLOCK_PRE      7
-#define TICKS_PER_JIFFY        41450
-
-#elif defined(CONFIG_XCOPILOT_BUGS)
-/*
- * The only thing I know is that CLK32 is not available on Xcopilot
- * I have little idea about what frequency SYSCLK has on Xcopilot.
- * The values for prescaler and compare registers were simply
- * taken from the original source
- */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_SYSCLK
-#define CLOCK_PRE      2
-#define TICKS_PER_JIFFY        0xd7e4
-
-#else
-/* default to using the 32Khz clock */
-#define CLOCK_SOURCE   TCTL_CLKSOURCE_32KHZ
-#define CLOCK_PRE      31
-#define TICKS_PER_JIFFY        10
-#endif
-
-static u32 m68328_tick_cnt;
-
-/***************************************************************************/
-
-static irqreturn_t hw_tick(int irq, void *dummy)
-{
-       /* Reset Timer1 */
-       TSTAT &= 0;
-
-       m68328_tick_cnt += TICKS_PER_JIFFY;
-       return arch_timer_interrupt(irq, dummy);
-}
-
-/***************************************************************************/
-
-static struct irqaction m68328_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = hw_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t m68328_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-
-       local_irq_save(flags);
-       cycles = m68328_tick_cnt + TCN;
-       local_irq_restore(flags);
-
-       return cycles;
-}
-
-/***************************************************************************/
-
-static struct clocksource m68328_clk = {
-       .name   = "timer",
-       .rating = 250,
-       .read   = m68328_read_clk,
-       .shift  = 20,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/***************************************************************************/
-
-void hw_timer_init(void)
-{
-       /* disable timer 1 */
-       TCTL = 0;
-
-       /* set ISR */
-       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
-
-       /* Restart mode, Enable int, Set clock source */
-       TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
-       TPRER = CLOCK_PRE;
-       TCMP = TICKS_PER_JIFFY;
-
-       /* Enable timer 1 */
-       TCTL |= TCTL_TEN;
-       m68328_clk.mult = clocksource_hz2mult(TICKS_PER_JIFFY*HZ, m68328_clk.shift);
-       clocksource_register(&m68328_clk);
-}
-
-/***************************************************************************/
-
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec)
-{
-       long now = RTCTIME;
-
-       *year = *mon = *day = 1;
-       *hour = (now >> 24) % 24;
-       *min = (now >> 16) % 60;
-       *sec = now % 60;
-}
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/68360/Makefile b/arch/m68knommu/platform/68360/Makefile
deleted file mode 100644 (file)
index cf5af73..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68360.
-#
-
-obj-y := config.o commproc.o entry.o ints.o
-
-extra-y := head.o
-
-$(obj)/head.o: $(obj)/head-$(MODEL).o
-       ln -sf head-$(MODEL).o $(obj)/head.o
diff --git a/arch/m68knommu/platform/68360/commproc.c b/arch/m68knommu/platform/68360/commproc.c
deleted file mode 100644 (file)
index 8e4e10c..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * General Purpose functions for the global management of the
- * Communication Processor Module.
- *
- * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
- * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- *
- * In addition to the individual control of the communication
- * channels, there are a few functions that globally affect the
- * communication processor.
- *
- * Buffer descriptors must be allocated from the dual ported memory
- * space.  The allocator for that is here.  When the communication
- * process is reset, we reclaim the memory available.  There is
- * currently no deallocator for this memory.
- * The amount of space available is platform dependent.  On the
- * MBX, the EPPC software loads additional microcode into the
- * communication processor, and uses some of the DP ram for this
- * purpose.  Current, the first 512 bytes and the last 256 bytes of
- * memory are used.  Right now I am conservative and only use the
- * memory that can never be used for microcode.  If there are
- * applications that require more DP ram, we can expand the boundaries
- * but then we have to be careful of any downloaded microcode.
- *
- */
-
-/*
- * Michael Leslie <mleslie@lineo.com>
- * adapted Dan Malek's ppc8xx drivers to M68360
- *
- */
-
-#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/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-/* #include <asm/page.h> */
-/* #include <asm/pgtable.h> */
-extern void *_quicc_base;
-extern unsigned int system_clock;
-
-
-static uint dp_alloc_base;     /* Starting offset in DP ram */
-static uint dp_alloc_top;      /* Max offset + 1 */
-
-#if 0
-static void    *host_buffer;   /* One page of host buffer */
-static void    *host_end;          /* end + 1 */
-#endif
-
-/* struct  cpm360_t *cpmp; */         /* Pointer to comm processor space */
-
-QUICC  *pquicc;
-/* QUICC  *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */
-
-
-/* CPM interrupt vector functions. */
-struct cpm_action {
-       void    (*handler)(void *);
-       void    *dev_id;
-};
-static struct  cpm_action cpm_vecs[CPMVEC_NR];
-static void    cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static void    cpm_error_interrupt(void *);
-
-/* prototypes: */
-void cpm_install_handler(int vec, void (*handler)(), void *dev_id);
-void m360_cpm_reset(void);
-
-
-
-
-void m360_cpm_reset()
-{
-/*     pte_t              *pte; */
-
-       pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */
-
-       /* Perform a CPM reset. */
-       pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG);
-
-       /* Wait for CPM to become ready (should be 2 clocks). */
-       while (pquicc->cp_cr & CMD_FLAG);
-
-       /* On the recommendation of the 68360 manual, p. 7-60
-        * - Set sdma interrupt service mask to 7
-        * - Set sdma arbitration ID to 4
-        */
-       pquicc->sdma_sdcr = 0x0740;
-
-
-       /* Claim the DP memory for our use.
-        */
-       dp_alloc_base = CPM_DATAONLY_BASE;
-       dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
-
-
-       /* Set the host page for allocation.
-        */
-       /*      host_buffer = host_page_addr; */
-       /*      host_end = host_page_addr + PAGE_SIZE; */
-
-       /*      pte = find_pte(&init_mm, host_page_addr); */
-       /*      pte_val(*pte) |= _PAGE_NO_CACHE; */
-       /*      flush_tlb_page(current->mm->mmap, host_buffer); */
-
-       /* Tell everyone where the comm processor resides.
-       */
-/*     cpmp = (cpm360_t *)commproc; */
-}
-
-
-/* This is called during init_IRQ.  We used to do it above, but this
- * was too early since init_IRQ was not yet called.
- */
-void
-cpm_interrupt_init(void)
-{
-       /* Initialize the CPM interrupt controller.
-        * NOTE THAT pquicc had better have been initialized!
-        * reference: MC68360UM p. 7-377
-        */
-       pquicc->intr_cicr =
-               (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
-               (CPM_INTERRUPT << 13) |
-               CICR_HP_MASK |
-               (CPM_VECTOR_BASE << 5) |
-               CICR_SPS;
-
-       /* mask all CPM interrupts from reaching the cpu32 core: */
-       pquicc->intr_cimr = 0;
-
-
-       /* mles - If I understand correctly, the 360 just pops over to the CPM
-        * specific vector, obviating the necessity to vector through the IRQ
-        * whose priority the CPM is set to. This needs a closer look, though.
-        */
-
-       /* Set our interrupt handler with the core CPU. */
-/*     if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */
-/*             panic("Could not allocate CPM IRQ!"); */
-
-       /* Install our own error handler.
-        */
-       /* I think we want to hold off on this one for the moment - mles */
-       /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */
-
-       /* master CPM interrupt enable */
-       /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */
-}
-
-
-
-/* CPM interrupt controller interrupt.
-*/
-static void
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-       /* uint vec; */
-
-       /* mles: Note that this stuff is currently being performed by
-        * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c  */
-
-       /* figure out the vector */
-       /* call that vector's handler */
-       /* clear the irq's bit in the service register */
-
-#if 0 /* old 860 stuff: */
-       /* Get the vector by setting the ACK bit and then reading
-        * the register.
-        */
-       ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
-       vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
-       vec >>= 11;
-
-
-       if (cpm_vecs[vec].handler != 0)
-               (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
-       else
-               ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
-
-       /* After servicing the interrupt, we have to remove the status
-        * indicator.
-        */
-       ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
-#endif
-
-}
-
-/* The CPM can generate the error interrupt when there is a race condition
- * between generating and masking interrupts.  All we have to do is ACK it
- * and return.  This is a no-op function so we don't need any special
- * tests in the interrupt handler.
- */
-static void
-cpm_error_interrupt(void *dev)
-{
-}
-
-/* Install a CPM interrupt handler.
-*/
-void
-cpm_install_handler(int vec, void (*handler)(), void *dev_id)
-{
-
-       request_irq(vec, handler, 0, "timer", dev_id);
-
-/*     if (cpm_vecs[vec].handler != 0) */
-/*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
-/*                     (uint)handler, (uint)cpm_vecs[vec].handler); */
-/*     cpm_vecs[vec].handler = handler; */
-/*     cpm_vecs[vec].dev_id = dev_id; */
-
-       /*              ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */
-/*     pquicc->intr_cimr |= (1 << vec); */
-
-}
-
-/* Free a CPM interrupt handler.
-*/
-void
-cpm_free_handler(int vec)
-{
-       cpm_vecs[vec].handler = NULL;
-       cpm_vecs[vec].dev_id = NULL;
-       /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */
-       pquicc->intr_cimr &= ~(1 << vec);
-}
-
-
-
-
-/* Allocate some memory from the dual ported ram.  We may want to
- * enforce alignment restrictions, but right now everyone is a good
- * citizen.
- */
-uint
-m360_cpm_dpalloc(uint size)
-{
-        uint    retloc;
-
-        if ((dp_alloc_base + size) >= dp_alloc_top)
-                return(CPM_DP_NOSPACE);
-
-        retloc = dp_alloc_base;
-        dp_alloc_base += size;
-
-        return(retloc);
-}
-
-
-#if 0 /* mleslie - for now these are simply kmalloc'd */
-/* We also own one page of host buffer space for the allocation of
- * UART "fifos" and the like.
- */
-uint
-m360_cpm_hostalloc(uint size)
-{
-       uint    retloc;
-
-       if ((host_buffer + size) >= host_end)
-               return(0);
-
-       retloc = host_buffer;
-       host_buffer += size;
-
-       return(retloc);
-}
-#endif
-
-
-/* Set a baud rate generator.  This needs lots of work.  There are
- * four BRGs, any of which can be wired to any channel.
- * The internal baud rate clock is the system clock divided by 16.
- * This assumes the baudrate is 16x oversampled by the uart.
- */
-/* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */
-#define BRG_INT_CLK            system_clock
-#define BRG_UART_CLK   (BRG_INT_CLK/16)
-
-void
-m360_cpm_setbrg(uint brg, uint rate)
-{
-       volatile uint   *bp;
-
-       /* This is good enough to get SMCs running.....
-        */
-       /* bp = (uint *)&cpmp->cp_brgc1; */
-       bp = (volatile uint *)(&pquicc->brgc[0].l);
-       bp += brg;
-       *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN;
-}
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c
deleted file mode 100644 (file)
index 9dd5bca..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68360/config.c
- *
- *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.com>
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne <jeff@uclinux.org>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <stdarg.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/m68360.h>
-
-#ifdef CONFIG_UCQUICC
-#include <asm/bootstd.h>
-#endif
-
-extern void m360_cpm_reset(void);
-
-// Mask to select if the PLL prescaler is enabled.
-#define MCU_PREEN   ((unsigned short)(0x0001 << 13))
-
-#if defined(CONFIG_UCQUICC)
-#define OSCILLATOR  (unsigned long int)33000000
-#endif
-
-unsigned long int system_clock;
-
-extern QUICC *pquicc;
-
-/* TODO  DON"T Hard Code this */
-/* calculate properly using the right PLL and prescaller */
-// unsigned int system_clock = 33000000l;
-extern unsigned long int system_clock; //In kernel setup.c
-
-
-static irqreturn_t hw_tick(int irq, void *dummy)
-{
-  /* Reset Timer1 */
-  /* TSTAT &= 0; */
-
-  pquicc->timer_ter1 = 0x0002; /* clear timer event */
-
-  return arch_timer_interrupt(irq, dummy);
-}
-
-static struct irqaction m68360_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = hw_tick,
-};
-
-void hw_timer_init(void)
-{
-  unsigned char prescaler;
-  unsigned short tgcr_save;
-
-#if 0
-  /* Restart mode, Enable int, 32KHz, Enable timer */
-  TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN;
-  /* Set prescaler (Divide 32KHz by 32)*/
-  TPRER = 31;
-  /* Set compare register  32Khz / 32 / 10 = 100 */
-  TCMP = 10;                                                              
-
-  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
-#endif
-
-  /* General purpose quicc timers: MC68360UM p7-20 */
-
-  /* Set up timer 1 (in [1..4]) to do 100Hz */
-  tgcr_save = pquicc->timer_tgcr & 0xfff0;
-  pquicc->timer_tgcr  = tgcr_save; /* stop and reset timer 1 */
-  /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */
-
-  prescaler = 8;
-  pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */
-                           (unsigned short)((prescaler - 1) << 8);
-    
-  pquicc->timer_tcn1 = 0x0000; /* initial count */
-  /* calculate interval for 100Hz based on the _system_clock: */
-  pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */
-
-  pquicc->timer_ter1 = 0x0003; /* clear timer events */
-
-  /* enable timer 1 interrupt in CIMR */
-  setup_irq(CPMVEC_TIMER1, &m68360_timer_irq);
-
-  /* Start timer 1: */
-  tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001;
-  pquicc->timer_tgcr  = tgcr_save;
-}
-
-void BSP_gettod (int *yearp, int *monp, int *dayp,
-                  int *hourp, int *minp, int *secp)
-{
-}
-
-int BSP_set_clock_mmss(unsigned long nowtime)
-{
-#if 0
-  short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-
-  tod->second1 = real_seconds / 10;
-  tod->second2 = real_seconds % 10;
-  tod->minute1 = real_minutes / 10;
-  tod->minute2 = real_minutes % 10;
-#endif
-  return 0;
-}
-
-void BSP_reset (void)
-{
-  local_irq_disable();
-  asm volatile (
-    "moveal #_start, %a0;\n"
-    "moveb #0, 0xFFFFF300;\n"
-    "moveal 0(%a0), %sp;\n"
-    "moveal 4(%a0), %a0;\n"
-    "jmp (%a0);\n"
-    );
-}
-
-unsigned char *scc1_hwaddr;
-static int errno;
-
-#if defined (CONFIG_UCQUICC)
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-#endif
-
-
-void config_BSP(char *command, int len)
-{
-  unsigned char *p;
-
-  m360_cpm_reset();
-
-  /* Calculate the real system clock value. */
-  {
-     unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr);
-     if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128
-     {
-         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
-         system_clock = (OSCILLATOR / 128) * (mf + 1);
-     }
-     else
-     {
-         int mf = (int)(pquicc->sim_pllcr & 0x0fff);
-         system_clock = (OSCILLATOR) * (mf + 1);
-     }
-  }
-
-  printk(KERN_INFO "\n68360 QUICC support (C) 2000 Lineo Inc.\n");
-
-#if defined(CONFIG_UCQUICC) && 0
-  printk(KERN_INFO "uCquicc serial string [%s]\n",getserialnum());
-  p = scc1_hwaddr = gethwaddr(0);
-  printk(KERN_INFO "uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-         p[0], p[1], p[2], p[3], p[4], p[5]);
-
-  p = getbenv("APPEND");
-  if (p)
-    strcpy(p,command);
-  else
-    command[0] = 0;
-#else
-  scc1_hwaddr = "\00\01\02\03\04\05";
-#endif
-  mach_gettod          = BSP_gettod;
-  mach_reset           = BSP_reset;
-}
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
deleted file mode 100644 (file)
index 46c1b18..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/68360/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *  Copyright (C) 2001 SED Systems, a Division of Calian Ltd.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- * M68360 Port by SED Systems, and Lineo.
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/thread_info.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/traps.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl ret_from_interrupt
-.globl bad_interrupt
-.globl inthandler
-
-badsys:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0)
-       jra     ret_from_exception
-
-do_trace:
-       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %sp@(PT_OFF_ORIG_D0),%d1
-       movel   #-ENOSYS,%d0
-       cmpl    #NR_syscalls,%d1
-       jcc     1f
-       lsl     #2,%d1
-       lea     sys_call_table, %a0
-       jbsr    %a0@(%d1)
-
-1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     ret_from_exception
-
-ENTRY(system_call)
-       SAVE_ALL
-
-       /* save top of frame*/
-       pea     %sp@
-       jbsr    set_esp0
-       addql   #4,%sp
-
-       movel   %sp@(PT_OFF_ORIG_D0),%d0
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       jne     do_trace
-       cmpl    #NR_syscalls,%d0
-       jcc     badsys
-       lsl     #2,%d0
-       lea     sys_call_table,%a0
-       movel   %a0@(%d0), %a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
-
-ret_from_exception:
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
-       jeq     Luser_return            /* if so, skip resched, signals*/
-
-Lkernel_return:
-       RESTORE_ALL
-
-Luser_return:
-       /* only allow interrupts when we are really the last one on the*/
-       /* kernel stack, otherwise stack overflow can occur during*/
-       /* heavy interrupt load*/
-       andw    #ALLOWINT,%sr
-
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1
-       movel   %d1,%a2
-1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       jne     Lwork_to_do
-       RESTORE_ALL
-
-Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address*/
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       bsrw    do_signal
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jra     1b
-
-/*
- * This is the main interrupt handler, responsible for calling do_IRQ()
- */
-inthandler:
-       SAVE_ALL
-       movew   %sp@(PT_OFF_FORMATVEC), %d0
-       and.l   #0x3ff, %d0
-       lsr.l   #0x02,  %d0
-
-       movel   %sp,%sp@-
-       movel   %d0,%sp@-               /*  put vector # on stack*/
-       jbsr    do_IRQ                  /*  process the IRQ*/
-3:             addql   #8,%sp                  /*  pop parameters off stack*/
-       bra     ret_from_interrupt
-
-ret_from_interrupt:
-       jeq     1f
-2:
-       RESTORE_ALL
-1:
-       moveb   %sp@(PT_OFF_SR), %d0
-       and     #7, %d0
-       jhi     2b
-       /* check if we need to do software interrupts */
-
-       movel   irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0
-       jeq     ret_from_exception
-
-       pea     ret_from_exception
-       jra     do_softirq
-
-
-/*
- * Handler for uninitialized and spurious interrupts.
- */
-bad_interrupt:
-       addql   #1,num_spurious
-       rte
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1,so don't change these
- * registers until their contents are no longer needed.
- */
-ENTRY(resume)
-       movel   %a0,%d1                         /* save prev thread in d1 */
-       movew   %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */
-       movel   %usp,%a2                        /* save usp */
-       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
-
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
-       RESTORE_SWITCH_STACK
-
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore user stack */
-       movel   %a0,%usp
-       movew   %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */
-       rts
-
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S
deleted file mode 100644 (file)
index 8eb94fb..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/* arch/m68knommu/platform/68360/head-ram.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright 2001 (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-#define ASSEMBLY
-
-.global _stext
-.global _start
-
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
-#define        ROMEND                      (CONFIG_ROMBASE + CONFIG_ROMSIZE)
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000002
-#define SIM_BR0_MASK                0x00000001
-
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-       
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-       .text
-_start:
-_stext:
-       nop
-       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
-       /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #RAMEND, %sp                    /*set up stack at the end of DRAM:*/
-
-set_mbar_register:
-       moveq.l #0x07, %d1                      /* Setup MBAR */
-       movec   %d1, %dfc
-
-       lea.l   MCU_SIM_MBAR_ADRS, %a0
-       move.l  #_dprbase, %d0
-       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
-       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
-       moves.l %d0, %a0@
-
-       moveq.l #0x05, %d1
-       movec.l %d1, %dfc
-
-       /* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-       /* Set Module Configuration Register */
-       move.l  #MCU_SIM_MCR, MCR
-
-       /* to do:       Determine cause of reset */
-
-       /*
-        *       configure system clock MC68360 p. 6-40
-        *       (value +1)*osc/128 = system clock
-        */
-set_sim_clock:
-       move.w  #MCU_SIM_PLLCR, PLLCR
-       move.b  #MCU_SIM_CLKOCR, CLKOCR
-       move.w  #MCU_SIM_CDVCR, CDVCR
-
-       /* Wait for the PLL to settle */
-       move.w  #16384, %d0
-pll_settle_wait:
-       subi.w  #1, %d0
-       bne     pll_settle_wait
-
-       /* Setup the system protection register, and watchdog timer register */
-       move.b  #MCU_SIM_SWIV, SWIV
-       move.w  #MCU_SIM_PICR, PICR
-       move.w  #MCU_SIM_PITR, PITR
-       move.w  #MCU_SIM_SYPCR, SYPCR
-
-       /* Clear DPRAM - system + parameter */
-       movea.l #_dprbase, %a0
-       movea.l #_dprbase+0x2000, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     clear_dpram
-
-configure_memory_controller:    
-       /* Set up Global Memory Register (GMR) */
-       move.l  #MCU_SIM_GMR, %d0
-       move.l  %d0, GMR
-
-configure_chip_select_0:
-       move.l  #RAMEND, %d0
-       subi.l  #__ramstart, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR0_MASK, %d0
-       move.l  %d0, OR0
-
-       move.l  #__ramstart, %d0
-       ori.l   #SIM_BR0_MASK, %d0
-       move.l  %d0, BR0
-
-configure_chip_select_1:
-       move.l  #ROMEND, %d0
-       subi.l  #__rom_start, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR1_MASK, %d0
-       move.l  %d0, OR1
-
-       move.l  #__rom_start, %d0
-       ori.l   #SIM_BR1_MASK, %d0
-       move.l  %d0, BR1
-
-       move.w  #MCU_SIM_PEPAR, PEPAR 
-
-       /* point to vector table: */
-       move.l  #_romvec, %a0
-       move.l  #_ramvec, %a1
-copy_vectors:
-       move.l  %a0@, %d0
-       move.l  %d0, %a1@
-       move.l  %a0@, %a1@
-       addq.l  #0x04, %a0
-       addq.l  #0x04, %a1
-       cmp.l   #_start, %a0
-       blt     copy_vectors
-
-       move.l  #_ramvec, %a1
-       movec   %a1, %vbr
-
-
-       /* Copy data segment from ROM to RAM */
-       moveal  #_stext, %a0
-       moveal  #_sdata, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       move.l  %a0@, %d0
-       addq.l  #0x04, %a0
-       move.l  %d0, %a1@
-       addq.l  #0x04, %a1
-       cmp.l   #_edata, %a1
-       blt     LD1
-
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-load_quicc:
-       move.l  #_dprbase, _quicc_base
-
-store_ram_size:
-       /* Set ram size information */
-       move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
-       move.l  #RAMEND, %d0
-       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from RAMEND.*/
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-       lea     init_thread_union, %a2
-       lea     0x2000(%a2), %sp
-
-lp:
-       jsr     start_kernel
-
-_exit:
-       jmp     _exit
-
-
-       .data
-       .align 4
-env:
-       .long   0
-_quicc_base:
-       .long   0
-_periph_base:
-       .long   0
-_ramvec:
-       .long   0
-_rambase:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-_dprbase:
-       .long   0xffffe000
-
-       .text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
-.section ".data..initvect","awx"
-    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S
deleted file mode 100644 (file)
index 97510e5..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/* arch/m68knommu/platform/68360/head-rom.S
- *
- * Startup code for Motorola 68360
- *
- * Copyright (C) SED Systems, a Division of Calian Ltd.
- * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S
- * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7
- *           uClinux Kernel
- * Copyright (C) Michael Leslie <mleslie@lineo.com>
- * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S
- * Copyright (C) 1998  D. Jeff Dionne <jeff@uclinux.org>,
- *
- */
-
-.global _stext
-.global _sbss
-.global _start
-
-.global _rambase
-.global _ramvec
-.global _ramstart
-.global _ramend
-
-.global _quicc_base
-.global _periph_base
-
-#define        RAMEND                      (CONFIG_RAMBASE + CONFIG_RAMSIZE)
-
-#define REGB                        0x1000
-#define PEPAR                       (_dprbase + REGB + 0x0016)
-#define GMR                         (_dprbase + REGB + 0x0040)
-#define OR0                         (_dprbase + REGB + 0x0054)
-#define BR0                         (_dprbase + REGB + 0x0050)
-
-#define OR1                         (_dprbase + REGB + 0x0064)
-#define BR1                         (_dprbase + REGB + 0x0060)
-
-#define OR2                         (_dprbase + REGB + 0x0074)
-#define BR2                         (_dprbase + REGB + 0x0070)
-
-#define OR3                         (_dprbase + REGB + 0x0084)
-#define BR3                         (_dprbase + REGB + 0x0080)
-
-#define OR4                         (_dprbase + REGB + 0x0094)
-#define BR4                         (_dprbase + REGB + 0x0090)
-
-#define OR5                         (_dprbase + REGB + 0x00A4)
-#define BR5                         (_dprbase + REGB + 0x00A0)
-
-#define OR6                         (_dprbase + REGB + 0x00b4)
-#define BR6                         (_dprbase + REGB + 0x00b0)
-
-#define OR7                         (_dprbase + REGB + 0x00c4)
-#define BR7                         (_dprbase + REGB + 0x00c0)
-
-#define MCR                         (_dprbase + REGB + 0x0000)
-#define AVR                         (_dprbase + REGB + 0x0008)
-
-#define SYPCR                       (_dprbase + REGB + 0x0022)
-
-#define PLLCR                       (_dprbase + REGB + 0x0010)
-#define CLKOCR                      (_dprbase + REGB + 0x000C)
-#define CDVCR                       (_dprbase + REGB + 0x0014)
-
-#define BKAR                        (_dprbase + REGB + 0x0030)
-#define BKCR                        (_dprbase + REGB + 0x0034)
-#define SWIV                        (_dprbase + REGB + 0x0023)
-#define PICR                        (_dprbase + REGB + 0x0026)
-#define PITR                        (_dprbase + REGB + 0x002A)
-
-/* Define for all memory configuration */
-#define MCU_SIM_GMR                 0x00000000
-#define SIM_OR_MASK                 0x0fffffff
-
-/* Defines for chip select zero - the flash */
-#define SIM_OR0_MASK                0x20000000
-#define SIM_BR0_MASK                0x00000001
-
-/* Defines for chip select one - the RAM */
-#define SIM_OR1_MASK                0x10000000
-#define SIM_BR1_MASK                0x00000001
-
-#define MCU_SIM_MBAR_ADRS           0x0003ff00
-#define MCU_SIM_MBAR_BA_MASK        0xfffff000
-#define MCU_SIM_MBAR_AS_MASK        0x00000001
-
-#define MCU_SIM_PEPAR               0x00B4
-    
-#define MCU_DISABLE_INTRPTS         0x2700
-#define MCU_SIM_AVR                 0x00
-    
-#define MCU_SIM_MCR                 0x00005cff
-
-#define MCU_SIM_CLKOCR              0x00
-#define MCU_SIM_PLLCR               0x8000
-#define MCU_SIM_CDVCR               0x0000
-
-#define MCU_SIM_SYPCR               0x0000
-#define MCU_SIM_SWIV                0x00
-#define MCU_SIM_PICR                0x0000
-#define MCU_SIM_PITR                0x0000
-
-
-#include <asm/m68360_regs.h>
-
-       
-/*
- * By the time this RAM specific code begins to execute, DPRAM
- * and DRAM should already be mapped and accessible.
- */
-
-       .text
-_start:
-_stext:
-       nop
-       ori.w   #MCU_DISABLE_INTRPTS, %sr       /* disable interrupts: */
-       /* We should not need to setup the boot stack the reset should do it. */
-       movea.l #RAMEND, %sp            /* set up stack at the end of DRAM:*/
-
-
-set_mbar_register:
-       moveq.l #0x07, %d1                      /* Setup MBAR */
-       movec   %d1, %dfc
-
-       lea.l   MCU_SIM_MBAR_ADRS, %a0
-       move.l  #_dprbase, %d0
-       andi.l  #MCU_SIM_MBAR_BA_MASK, %d0
-       ori.l   #MCU_SIM_MBAR_AS_MASK, %d0
-       moves.l %d0, %a0@
-
-       moveq.l #0x05, %d1
-       movec.l %d1, %dfc
-
-       /* Now we can begin to access registers in DPRAM */
-
-set_sim_mcr:
-       /* Set Module Configuration Register */
-       move.l  #MCU_SIM_MCR, MCR
-
-       /* to do:       Determine cause of reset */
-
-       /*
-        *      configure system clock MC68360 p. 6-40
-        *      (value +1)*osc/128 = system clock
-        *                    or
-        *      (value + 1)*osc = system clock
-        *      You do not need to divide the oscillator by 128 unless you want to.
-        */
-set_sim_clock:
-       move.w  #MCU_SIM_PLLCR, PLLCR
-       move.b  #MCU_SIM_CLKOCR, CLKOCR
-       move.w  #MCU_SIM_CDVCR, CDVCR
-
-       /* Wait for the PLL to settle */
-       move.w  #16384, %d0
-pll_settle_wait:
-       subi.w  #1, %d0
-       bne     pll_settle_wait
-
-       /* Setup the system protection register, and watchdog timer register */
-       move.b  #MCU_SIM_SWIV, SWIV
-       move.w  #MCU_SIM_PICR, PICR
-       move.w  #MCU_SIM_PITR, PITR
-       move.w  #MCU_SIM_SYPCR, SYPCR
-
-       /* Clear DPRAM - system + parameter */
-       movea.l #_dprbase, %a0
-       movea.l #_dprbase+0x2000, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-clear_dpram:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     clear_dpram
-
-configure_memory_controller:    
-       /* Set up Global Memory Register (GMR) */
-       move.l  #MCU_SIM_GMR, %d0
-       move.l  %d0, GMR
-
-configure_chip_select_0:
-       move.l  #0x00400000, %d0
-       subq.l  #0x01, %d0
-       eori.l  #SIM_OR_MASK, %d0
-       ori.l   #SIM_OR0_MASK, %d0
-       move.l  %d0, OR0
-
-       move.l  #__rom_start, %d0
-       ori.l   #SIM_BR0_MASK, %d0
-       move.l  %d0, BR0
-
-       move.l  #0x0, BR1
-       move.l  #0x0, BR2
-       move.l  #0x0, BR3
-       move.l  #0x0, BR4
-       move.l  #0x0, BR5
-       move.l  #0x0, BR6
-       move.l  #0x0, BR7
-
-       move.w  #MCU_SIM_PEPAR, PEPAR 
-
-       /* point to vector table: */
-       move.l  #_romvec, %a0
-       move.l  #_ramvec, %a1
-copy_vectors:
-       move.l  %a0@, %d0
-       move.l  %d0, %a1@
-       move.l  %a0@, %a1@
-       addq.l  #0x04, %a0
-       addq.l  #0x04, %a1
-       cmp.l   #_start, %a0
-       blt     copy_vectors
-
-       move.l  #_ramvec, %a1
-       movec   %a1, %vbr
-
-
-       /* Copy data segment from ROM to RAM */
-       moveal  #_etext, %a0
-       moveal  #_sdata, %a1
-       moveal  #_edata, %a2
-
-       /* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-       move.l  %a0@, %d0
-       addq.l  #0x04, %a0
-       move.l  %d0, %a1@
-       addq.l  #0x04, %a1
-       cmp.l   #_edata, %a1
-       blt     LD1
-
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
-
-       /* Copy 0 to %a0 until %a0 == %a1 */
-L1:
-       movel   #0, %a0@+
-       cmpal   %a0, %a1
-       bhi     L1
-
-load_quicc:
-       move.l  #_dprbase, _quicc_base
-
-store_ram_size:
-       /* Set ram size information */
-       move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
-       move.l  #RAMEND, %d0
-       sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
-       move.l  %d0, _ramend                    /* Different from RAMEND.*/
-
-       pea     0
-       pea     env
-       pea     %sp@(4)
-       pea     0
-
-       lea     init_thread_union, %a2
-       lea     0x2000(%a2), %sp
-
-lp:
-       jsr     start_kernel
-
-_exit:
-       jmp     _exit
-
-
-       .data
-       .align 4
-env:
-       .long   0
-_quicc_base:
-       .long   0
-_periph_base:
-       .long   0
-_ramvec:
-       .long   0
-_rambase:
-       .long   0
-_ramstart:
-       .long   0
-_ramend:
-       .long   0
-_dprbase:
-       .long   0xffffe000
-
-
-       .text
-
-    /*
-     * These are the exception vectors at boot up, they are copied into RAM
-     * and then overwritten as needed.
-     */
-.section ".data..initvect","awx"
-    .long   RAMEND     /* Reset: Initial Stack Pointer                 - 0.  */
-    .long   _start      /* Reset: Initial Program Counter               - 1.  */
-    .long   buserr      /* Bus Error                                    - 2.  */
-    .long   trap        /* Address Error                                - 3.  */
-    .long   trap        /* Illegal Instruction                          - 4.  */
-    .long   trap        /* Divide by zero                               - 5.  */
-    .long   trap        /* CHK, CHK2 Instructions                       - 6.  */
-    .long   trap        /* TRAPcc, TRAPV Instructions                   - 7.  */
-    .long   trap        /* Privilege Violation                          - 8.  */
-    .long   trap        /* Trace                                        - 9.  */
-    .long   trap        /* Line 1010 Emulator                           - 10. */
-    .long   trap        /* Line 1111 Emualtor                           - 11. */
-    .long   trap        /* Harware Breakpoint                           - 12. */
-    .long   trap        /* (Reserved for Coprocessor Protocol Violation)- 13. */
-    .long   trap        /* Format Error                                 - 14. */
-    .long   trap        /* Uninitialized Interrupt                      - 15. */
-    .long   trap        /* (Unassigned, Reserver)                       - 16. */
-    .long   trap        /* (Unassigned, Reserver)                       - 17. */
-    .long   trap        /* (Unassigned, Reserver)                       - 18. */
-    .long   trap        /* (Unassigned, Reserver)                       - 19. */
-    .long   trap        /* (Unassigned, Reserver)                       - 20. */
-    .long   trap        /* (Unassigned, Reserver)                       - 21. */
-    .long   trap        /* (Unassigned, Reserver)                       - 22. */
-    .long   trap        /* (Unassigned, Reserver)                       - 23. */
-    .long   trap        /* Spurious Interrupt                           - 24. */
-    .long   trap        /* Level 1 Interrupt Autovector                 - 25. */
-    .long   trap        /* Level 2 Interrupt Autovector                 - 26. */
-    .long   trap        /* Level 3 Interrupt Autovector                 - 27. */
-    .long   trap        /* Level 4 Interrupt Autovector                 - 28. */
-    .long   trap        /* Level 5 Interrupt Autovector                 - 29. */
-    .long   trap        /* Level 6 Interrupt Autovector                 - 30. */
-    .long   trap        /* Level 7 Interrupt Autovector                 - 31. */
-    .long   system_call /* Trap Instruction Vectors 0                   - 32. */
-    .long   trap        /* Trap Instruction Vectors 1                   - 33. */
-    .long   trap        /* Trap Instruction Vectors 2                   - 34. */
-    .long   trap        /* Trap Instruction Vectors 3                   - 35. */
-    .long   trap        /* Trap Instruction Vectors 4                   - 36. */
-    .long   trap        /* Trap Instruction Vectors 5                   - 37. */
-    .long   trap        /* Trap Instruction Vectors 6                   - 38. */
-    .long   trap        /* Trap Instruction Vectors 7                   - 39. */
-    .long   trap        /* Trap Instruction Vectors 8                   - 40. */
-    .long   trap        /* Trap Instruction Vectors 9                   - 41. */
-    .long   trap        /* Trap Instruction Vectors 10                  - 42. */
-    .long   trap        /* Trap Instruction Vectors 11                  - 43. */
-    .long   trap        /* Trap Instruction Vectors 12                  - 44. */
-    .long   trap        /* Trap Instruction Vectors 13                  - 45. */
-    .long   trap        /* Trap Instruction Vectors 14                  - 46. */
-    .long   trap        /* Trap Instruction Vectors 15                  - 47. */
-    .long   0           /* (Reserved for Coprocessor)                   - 48. */
-    .long   0           /* (Reserved for Coprocessor)                   - 49. */
-    .long   0           /* (Reserved for Coprocessor)                   - 50. */
-    .long   0           /* (Reserved for Coprocessor)                   - 51. */
-    .long   0           /* (Reserved for Coprocessor)                   - 52. */
-    .long   0           /* (Reserved for Coprocessor)                   - 53. */
-    .long   0           /* (Reserved for Coprocessor)                   - 54. */
-    .long   0           /* (Reserved for Coprocessor)                   - 55. */
-    .long   0           /* (Reserved for Coprocessor)                   - 56. */
-    .long   0           /* (Reserved for Coprocessor)                   - 57. */
-    .long   0           /* (Reserved for Coprocessor)                   - 58. */
-    .long   0           /* (Unassigned, Reserved)                       - 59. */
-    .long   0           /* (Unassigned, Reserved)                       - 60. */
-    .long   0           /* (Unassigned, Reserved)                       - 61. */
-    .long   0           /* (Unassigned, Reserved)                       - 62. */
-    .long   0           /* (Unassigned, Reserved)                       - 63. */
-    /*                  The assignment of these vectors to the CPM is         */
-    /*                  dependent on the configuration of the CPM vba         */
-    /*                          fields.                                       */
-    .long   0           /* (User-Defined Vectors 1) CPM Error           - 64. */
-    .long   0           /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */
-    .long   0           /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */
-    .long   0           /* (User-Defined Vectors 4) CPM SMC2 / PIP      - 67. */
-    .long   0           /* (User-Defined Vectors 5) CPM SMC1            - 68. */
-    .long   0           /* (User-Defined Vectors 6) CPM SPI             - 69. */
-    .long   0           /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */
-    .long   0           /* (User-Defined Vectors 8) CPM Timer 4         - 71. */
-    .long   0           /* (User-Defined Vectors 9) CPM Reserved        - 72. */
-    .long   0           /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */
-    .long   0           /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */
-    .long   0           /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */
-    .long   0           /* (User-Defined Vectors 13) CPM Timer 3        - 76. */
-    .long   0           /* (User-Defined Vectors 14) CPM Reserved       - 77. */
-    .long   0           /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */
-    .long   0           /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */
-    .long   0           /* (User-Defined Vectors 17) CPM Reserved       - 80. */
-    .long   0           /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */
-    .long   0           /* (User-Defined Vectors 19) CPM Timer 2        - 82. */
-    .long   0           /* (User-Defined Vectors 21) CPM Reserved       - 83. */
-    .long   0           /* (User-Defined Vectors 22) CPM IDMA2          - 84. */
-    .long   0           /* (User-Defined Vectors 23) CPM IDMA1          - 85. */
-    .long   0           /* (User-Defined Vectors 24) CPM SDMA Bus Err   - 86. */
-    .long   0           /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */
-    .long   0           /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */
-    .long   0           /* (User-Defined Vectors 27) CPM Timer 1        - 89. */
-    .long   0           /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */
-    .long   0           /* (User-Defined Vectors 29) CPM SCC 4          - 91. */
-    .long   0           /* (User-Defined Vectors 30) CPM SCC 3          - 92. */
-    .long   0           /* (User-Defined Vectors 31) CPM SCC 2          - 93. */
-    .long   0           /* (User-Defined Vectors 32) CPM SCC 1          - 94. */
-    .long   0           /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */
-    /*                  I don't think anything uses the vectors after here.   */
-    .long   0           /* (User-Defined Vectors 34)                    - 96. */
-    .long   0,0,0,0,0               /* (User-Defined Vectors 35  -  39). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 40  -  49). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 50  -  59). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 60  -  69). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 70  -  79). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 80  -  89). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 90  -  99). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 100 - 109). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 110 - 119). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 120 - 129). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 130 - 139). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 140 - 149). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 150 - 159). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 160 - 169). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 170 - 179). */
-    .long   0,0,0,0,0,0,0,0,0,0     /* (User-Defined Vectors 180 - 189). */
-    .long   0,0,0                   /* (User-Defined Vectors 190 - 192). */
-.text
-ignore: rte
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c
deleted file mode 100644 (file)
index 8de3feb..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
- *
- * 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) 2000  Michael Leslie <mleslie@lineo.com>
- * Copyright (c) 1996 Roman Zippel
- * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/m68360.h>
-
-/* from quicc/commproc.c: */
-extern QUICC *pquicc;
-extern void cpm_interrupt_init(void);
-
-#define INTERNAL_IRQS (96)
-
-/* assembler routines */
-asmlinkage void system_call(void);
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void bad_interrupt(void);
-asmlinkage void inthandler(void);
-
-extern void *_ramvec[];
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       pquicc->intr_cimr |= (1 << d->irq);
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       pquicc->intr_cimr &= ~(1 << d->irq);
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       pquicc->intr_cisr = (1 << d->irq);
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "M68K-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-};
-
-/*
- * This function should be called during kernel startup to initialize
- * the vector table.
- */
-void init_IRQ(void)
-{
-       int i;
-       int vba = (CPM_VECTOR_BASE<<4);
-
-       /* set up the vectors */
-       _ramvec[2] = buserr;
-       _ramvec[3] = trap;
-       _ramvec[4] = trap;
-       _ramvec[5] = trap;
-       _ramvec[6] = trap;
-       _ramvec[7] = trap;
-       _ramvec[8] = trap;
-       _ramvec[9] = trap;
-       _ramvec[10] = trap;
-       _ramvec[11] = trap;
-       _ramvec[12] = trap;
-       _ramvec[13] = trap;
-       _ramvec[14] = trap;
-       _ramvec[15] = trap;
-
-       _ramvec[32] = system_call;
-       _ramvec[33] = trap;
-
-       cpm_interrupt_init();
-
-       /* set up CICR for vector base address and irq level */
-       /* irl = 4, hp = 1f - see MC68360UM p 7-377 */
-       pquicc->intr_cicr = 0x00e49f00 | vba;
-
-       /* CPM interrupt vectors: (p 7-376) */
-       _ramvec[vba+CPMVEC_ERROR]       = bad_interrupt; /* Error */
-       _ramvec[vba+CPMVEC_PIO_PC11]    = inthandler;   /* pio - pc11 */
-       _ramvec[vba+CPMVEC_PIO_PC10]    = inthandler;   /* pio - pc10 */
-       _ramvec[vba+CPMVEC_SMC2]        = inthandler;   /* smc2/pip */
-       _ramvec[vba+CPMVEC_SMC1]        = inthandler;   /* smc1 */
-       _ramvec[vba+CPMVEC_SPI]         = inthandler;   /* spi */
-       _ramvec[vba+CPMVEC_PIO_PC9]     = inthandler;   /* pio - pc9 */
-       _ramvec[vba+CPMVEC_TIMER4]      = inthandler;   /* timer 4 */
-       _ramvec[vba+CPMVEC_RESERVED1]   = inthandler;   /* reserved */
-       _ramvec[vba+CPMVEC_PIO_PC8]     = inthandler;   /* pio - pc8 */
-       _ramvec[vba+CPMVEC_PIO_PC7]     = inthandler;  /* pio - pc7 */
-       _ramvec[vba+CPMVEC_PIO_PC6]     = inthandler;  /* pio - pc6 */
-       _ramvec[vba+CPMVEC_TIMER3]      = inthandler;  /* timer 3 */
-       _ramvec[vba+CPMVEC_PIO_PC5]     = inthandler;  /* pio - pc5 */
-       _ramvec[vba+CPMVEC_PIO_PC4]     = inthandler;  /* pio - pc4 */
-       _ramvec[vba+CPMVEC_RESERVED2]   = inthandler;  /* reserved */
-       _ramvec[vba+CPMVEC_RISCTIMER]   = inthandler;  /* timer table */
-       _ramvec[vba+CPMVEC_TIMER2]      = inthandler;  /* timer 2 */
-       _ramvec[vba+CPMVEC_RESERVED3]   = inthandler;  /* reserved */
-       _ramvec[vba+CPMVEC_IDMA2]       = inthandler;  /* idma 2 */
-       _ramvec[vba+CPMVEC_IDMA1]       = inthandler;  /* idma 1 */
-       _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler;  /* sdma channel bus error */
-       _ramvec[vba+CPMVEC_PIO_PC3]     = inthandler;  /* pio - pc3 */
-       _ramvec[vba+CPMVEC_PIO_PC2]     = inthandler;  /* pio - pc2 */
-       /* _ramvec[vba+CPMVEC_TIMER1]      = cpm_isr_timer1; */  /* timer 1 */
-       _ramvec[vba+CPMVEC_TIMER1]      = inthandler;  /* timer 1 */
-       _ramvec[vba+CPMVEC_PIO_PC1]     = inthandler;  /* pio - pc1 */
-       _ramvec[vba+CPMVEC_SCC4]        = inthandler;  /* scc 4 */
-       _ramvec[vba+CPMVEC_SCC3]        = inthandler;  /* scc 3 */
-       _ramvec[vba+CPMVEC_SCC2]        = inthandler;  /* scc 2 */
-       _ramvec[vba+CPMVEC_SCC1]        = inthandler;  /* scc 1 */
-       _ramvec[vba+CPMVEC_PIO_PC0]     = inthandler;  /* pio - pc0 */
-
-
-       /* turn off all CPM interrupts */
-       pquicc->intr_cimr = 0x00000000;
-
-       for (i = 0; (i < NR_IRQS); i++) {
-               set_irq_chip(i, &intc_irq_chip);
-               set_irq_handler(i, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68knommu/platform/68EZ328/Makefile b/arch/m68knommu/platform/68EZ328/Makefile
deleted file mode 100644 (file)
index ee97735..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68EZ328.
-#
-
-obj-y := config.o
-
-extra-y := bootlogo.rh
-
-$(obj)/bootlogo.rh: $(src)/bootlogo.h
-       perl $(src)/../68328/bootlogo.pl < $(src)/bootlogo.h \
-               > $(obj)/bootlogo.rh
diff --git a/arch/m68knommu/platform/68EZ328/bootlogo.h b/arch/m68knommu/platform/68EZ328/bootlogo.h
deleted file mode 100644 (file)
index e842bda..0000000
+++ /dev/null
@@ -1,3204 +0,0 @@
-#define splash_width 640
-#define splash_height 480
-static unsigned char splash_bits[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xfe, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x7c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
-  0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0x07, 0xfe, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
-  0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0xe0, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03,
-  0x3f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
-  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0xff, 0x3f, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff,
-  0xc1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x07, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
-  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x00, 0xe0, 0x07, 0x0e, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
-  0x3f, 0x1c, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f,
-  0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
-  0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x01, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
-  0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x87, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0x00,
-  0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0xf0, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xf0, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0x0c, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1c, 0x00,
-  0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x07, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0xe0, 0xff, 0x7f, 0xe0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe2, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
-  0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01,
-  0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
-  0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xf0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x9f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xf8, 0xff, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0xff, 0xff, 0x00,
-  0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0xf8, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xfe, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0xf8, 0xff, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0x01,
-  0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xf8,
-  0x41, 0xc6, 0x84, 0x0c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xf8, 0x41, 0xc6, 0x84, 0x0c,
-  0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x0f, 0x00, 0x00, 0x18, 0x0c, 0x08, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xe4,
-  0xb1, 0xc1, 0x98, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0xe4, 0xb1, 0xc1, 0x98, 0x00,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x08, 0x00, 0x00, 0x1c, 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c,
-  0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00,
-  0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x09, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x9c,
-  0x01, 0x08, 0x83, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40,
-  0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, 0x30, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x9b,
-  0x01, 0xc0, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x9b, 0x01, 0xc0, 0x00, 0x00,
-  0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0x00, 0x00, 0x00, 0x07, 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xc1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07,
-  0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x10, 0xe0,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x7b, 0x00, 0x30, 0x03, 0x0c,
-  0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x07, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x09, 0x00, 0xc0, 0x84, 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xfd, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xc0, 0x84,
-  0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x03, 0xf0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40,
-  0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xfc, 0x01, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, 0x08, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-  0xf8, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x64,
-  0x42, 0x06, 0x1b, 0x03, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x64, 0x42, 0x06, 0x1b, 0x03,
-  0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x0f, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x3f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1b,
-  0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xc3, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xe0, 0x84, 0x31, 0x30, 0x04, 0x80,
-  0xc1, 0x18, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x09, 0x00, 0xc0, 0x63, 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x08, 0x00, 0xc0, 0x63,
-  0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c,
-  0x06, 0x81, 0x80, 0xfd, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, 0x06, 0x81, 0x80, 0xfd,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x20, 0x63,
-  0x0c, 0x08, 0x80, 0x00, 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x63, 0x0c, 0x08, 0x80, 0x00,
-  0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x0f, 0x00, 0xd8, 0x84, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x80, 0xf1,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x1b,
-  0x40, 0x08, 0x84, 0x0c, 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x1b, 0x40, 0x08, 0x84, 0x0c,
-  0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0xe4, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x09, 0x00, 0x38, 0x80, 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x38, 0x80,
-  0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x10, 0x84,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00,
-  0x00, 0x00, 0x03, 0xf2, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x08, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, 0x00, 0x00, 0x03, 0xf2,
-  0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
-  0x08, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x3e, 0x00,
-  0x82, 0x01, 0x03, 0x40, 0x30, 0x98, 0x10, 0xf0, 0xe7, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x10, 0xe4,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0xfc,
-  0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x08, 0x00, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64,
-  0x30, 0xc6, 0x80, 0x80, 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf8, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0e, 0x00, 0xc0, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, 0x30, 0xc6, 0x80, 0x80,
-  0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc3, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x00, 0x39, 0x03, 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x39, 0x03,
-  0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0xe7, 0x04, 0x42, 0xc6, 0x00, 0x00,
-  0x00, 0x00, 0xec, 0xcf, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0xc0, 0x1f, 0x80, 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01,
-  0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x01, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x1f, 0x80,
-  0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, 0x00, 0xe0, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x08, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00,
-  0xc0, 0x60, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x1f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
-  0x00, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, 0xc0, 0x60, 0x7c, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xc0, 0x19, 0x60,
-  0x40, 0x00, 0x63, 0x30, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xf3, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x09, 0xc0, 0x19, 0x60, 0x40, 0x00, 0x63, 0x30,
-  0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf3, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0xc0, 0x27, 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xc0, 0x27, 0x03,
-  0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x0f, 0xc0, 0xde, 0x04, 0x0c, 0x06, 0x03, 0x80,
-  0xc1, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0xc0, 0x19, 0x00, 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f,
-  0x07, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x19, 0x00,
-  0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x07, 0x00, 0x18, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03,
-  0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1c, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x1f, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
-  0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, 0xf0, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x7f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
-  0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31,
-  0x04, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0xd9, 0x04,
-  0x00, 0x08, 0x00, 0x80, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x60, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0xd9, 0x04, 0x00, 0x08, 0x00, 0x80,
-  0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0xc0, 0x27, 0x00, 0x30, 0xc0, 0x60, 0xb0, 0xff, 0x7f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b,
-  0x8d, 0x01, 0x04, 0xc3, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0xf1, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x03, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, 0x8d, 0x01, 0x04, 0xc3,
-  0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf1, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0x39, 0x04, 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x39, 0x04,
-  0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xff, 0x07,
-  0xb0, 0x09, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x30, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff,
-  0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x08,
-  0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07,
-  0xb0, 0xc9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, 0xb0, 0xc9, 0xf8, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x0f, 0x00, 0xe7, 0xfb, 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xe7, 0xfb,
-  0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xfe, 0x1c, 0xb2, 0x0f, 0xe0, 0xff,
-  0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xf8, 0xe7, 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0,
-  0xb1, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xf8, 0xe7,
-  0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, 0xb1, 0x3f, 0x00, 0x00,
-  0xf8, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff,
-  0x01, 0x00, 0xe0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x98, 0x4f, 0x0e, 0x18, 0x00, 0xf8, 0xff, 0xff, 0xff,
-  0x07, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x01, 0x00, 0xe0, 0x03,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
-  0x4f, 0x0e, 0xf8, 0x1f, 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x1f,
-  0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
-  0x00, 0xce, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xe0, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xce, 0xff, 0x7f,
-  0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x1b, 0xb2, 0x31, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c,
-  0x00, 0xc0, 0xff, 0x73, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-  0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, 0x00, 0xc0, 0x7f, 0x1c,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x87, 0x31, 0x06, 0x7c, 0x1c, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x87,
-  0x31, 0x06, 0xfc, 0x0f, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x38,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0xe3, 0x0f,
-  0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xe0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff,
-  0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b,
-  0x4c, 0x00, 0x04, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x10,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x18, 0x80,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x78, 0xf3, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x08, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04,
-  0x02, 0x30, 0x60, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc0, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, 0x02, 0x30, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0x04, 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x04,
-  0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x67, 0x00, 0x06, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x06, 0x04, 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04,
-  0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08,
-  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1c, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x02, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c,
-  0x0c, 0x06, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
-  0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xe0,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, 0x0c, 0x06, 0xfb, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x68, 0x7c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf8, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x18, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b,
-  0x81, 0x01, 0x60, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80,
-  0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, 0x81, 0x01, 0x00, 0x00,
-  0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x38, 0x78, 0x0c, 0x30, 0x04, 0x00, 0xf6, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78,
-  0x0c, 0x30, 0x04, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8,
-  0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0x1c, 0x00,
-  0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x58, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-  0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0,
-  0x01, 0x36, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38,
-  0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
-  0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x36, 0xfc, 0x1f,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc6, 0x87, 0x0f, 0x00, 0xff, 0x1f, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xcf, 0x03, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x40, 0xc0, 0xff, 0x7f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x03, 0x00, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0xc0, 0xff, 0x7f,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff,
-  0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x7f,
-  0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0x07, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x4c, 0x00, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x1f,
-  0x00, 0xff, 0xff, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x0f, 0x00, 0xff, 0xff, 0x03,
-  0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
-  0x41, 0x00, 0xe0, 0x0f, 0x00, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x38,
-  0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x41, 0x00, 0x00, 0x80,
-  0xc9, 0xf9, 0xff, 0x3d, 0xff, 0x03, 0x00, 0x78, 0xc0, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0x32, 0x08, 0x00, 0x80, 0xc9, 0xf9, 0xff, 0x3d,
-  0xff, 0x03, 0x00, 0xf8, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x32, 0x08, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0xf8,
-  0x81, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0xf8, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0x38, 0x03, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff,
-  0x3f, 0x00, 0x00, 0x38, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38,
-  0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, 0xfc, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x38, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-  0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x78,
-  0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff,
-  0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0xc1, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x60, 0xf8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x67,
-  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xff,
-  0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf0, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x0f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x98,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x00, 0xc0, 0xff, 0x67, 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf8,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0xff, 0x67,
-  0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c,
-  0x37, 0x80, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
-  0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-  0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, 0x37, 0x80, 0x0c, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0xc0, 0xfe, 0x03,
-  0x8c, 0x09, 0xe3, 0x73, 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xfe, 0x03, 0x8c, 0x09, 0xe3, 0x73,
-  0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0xc0, 0x27, 0xe7, 0x31, 0x36, 0x04, 0x8c, 0x01, 0x60, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18,
-  0x42, 0xc0, 0x98, 0x30, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, 0x42, 0xc0, 0x98, 0x30,
-  0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0xc0, 0x27, 0x63, 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x27, 0x63,
-  0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0,
-  0x31, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff,
-  0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, 0x31, 0x19, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0xc0, 0x1e, 0x63,
-  0x00, 0x30, 0x04, 0x03, 0xc8, 0x60, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x0e, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0,
-  0x01, 0xe7, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0f, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, 0x01, 0xe7, 0xf3, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0xc0, 0x1e, 0x03,
-  0x02, 0x08, 0x04, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xd8, 0x0f, 0xc0, 0x1e, 0x03, 0x02, 0x08, 0x04, 0x00,
-  0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xc0, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x0b, 0x00, 0x21, 0x64, 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfb, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x21, 0x64,
-  0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfd, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00,
-  0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xf9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf,
-  0x01, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0e, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf0, 0x03, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0b, 0xc0, 0xc0, 0x84,
-  0x31, 0xc0, 0x00, 0x4c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x83, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0f, 0x0e, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80,
-  0x09, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0xc3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0c, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, 0x09, 0xff, 0xff, 0x3f,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8,
-  0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xc0, 0xc1, 0x03,
-  0x4c, 0x00, 0x00, 0x30, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x90, 0x13, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0xc0, 0xc1, 0x03, 0x4c, 0x00, 0x00, 0x30,
-  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x00, 0xc0, 0x3f, 0x98, 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
-  0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x98,
-  0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xc6, 0x03, 0x40, 0x00, 0x00, 0x80,
-  0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
-  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
-  0x00, 0x00, 0x3f, 0x18, 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xef, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3f, 0x18,
-  0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xc7, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30,
-  0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
-  0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, 0x30, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04,
-  0x02, 0x00, 0x00, 0x83, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x38, 0x04, 0x02, 0x00, 0x00, 0x83,
-  0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
-  0x03, 0x00, 0xe0, 0x1b, 0x0c, 0x08, 0x18, 0x40, 0x30, 0xfe, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84,
-  0x81, 0x01, 0x03, 0x0c, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, 0x81, 0x01, 0x03, 0x0c,
-  0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-  0x0e, 0x00, 0x00, 0x1b, 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x1b,
-  0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40,
-  0x00, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, 0x00, 0xe1, 0xff, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-  0x30, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x9c,
-  0x01, 0x08, 0x60, 0x0c, 0x06, 0x86, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
-  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbf, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00,
-  0xc0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xf0, 0x9f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-  0x07, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0xff,
-  0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xe0,
-  0x01, 0x06, 0x00, 0x30, 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
-  0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x06, 0x00, 0x30,
-  0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
-  0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff,
-  0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-  0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x0f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00,
-  0x00, 0x06, 0x83, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, 0x00, 0x06, 0x83, 0xff,
-  0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x00, 0xc0, 0x00, 0x8c, 0xc9, 0x60, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-  0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00,
-  0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-  0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0f, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
-  0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc6,
-  0x03, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xef, 0x07, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xd8, 0xef, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3,
-  0x0f, 0x00, 0x00, 0x00, 0x80, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x88, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13,
-  0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00,
-  0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x88, 0xf3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3,
-  0x0f, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xe1, 0x1f, 0x00, 0x00, 0x00,
-  0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0xf0, 0xc1, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc0, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  };
diff --git a/arch/m68knommu/platform/68EZ328/config.c b/arch/m68knommu/platform/68EZ328/config.c
deleted file mode 100644 (file)
index 1be1a16..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/68EZ328/config.c
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68EZ328.h>
-#ifdef CONFIG_UCSIMM
-#include <asm/bootstd.h>
-#endif
-
-/***************************************************************************/
-
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
-
-/***************************************************************************/
-
-void m68ez328_reset(void)
-{
-  local_irq_disable();
-  asm volatile (
-    "moveal #0x10c00000, %a0;\n"
-    "moveb #0, 0xFFFFF300;\n"
-    "moveal 0(%a0), %sp;\n"
-    "moveal 4(%a0), %a0;\n"
-    "jmp (%a0);\n"
-    );
-}
-
-/***************************************************************************/
-
-unsigned char *cs8900a_hwaddr;
-static int errno;
-
-#ifdef CONFIG_UCSIMM
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-#endif
-
-void config_BSP(char *command, int len)
-{
-  unsigned char *p;
-
-  printk(KERN_INFO "\n68EZ328 DragonBallEZ support (C) 1999 Rt-Control, Inc\n");
-
-#ifdef CONFIG_UCSIMM
-  printk(KERN_INFO "uCsimm serial string [%s]\n",getserialnum());
-  p = cs8900a_hwaddr = gethwaddr(0);
-  printk(KERN_INFO "uCsimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-         p[0], p[1], p[2], p[3], p[4], p[5]);
-
-  p = getbenv("APPEND");
-  if (p) strcpy(p,command);
-  else command[0] = 0;
-#endif
-  mach_gettod = m68328_timer_gettod;
-  mach_reset = m68ez328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/68VZ328/Makefile b/arch/m68knommu/platform/68VZ328/Makefile
deleted file mode 100644 (file)
index 447ffa0..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Makefile for arch/m68knommu/platform/68VZ328.
-#
-
-obj-y          := config.o
-logo-$(UCDIMM) := bootlogo.rh
-logo-$(DRAGEN2)        := screen.h
-extra-y                := $(logo-y)
-
-$(obj)/bootlogo.rh: $(src)/../68EZ328/bootlogo.h
-       perl $(src)/bootlogo.pl < $(src)/../68328/bootlogo.h > $(obj)/bootlogo.rh
-
-$(obj)/screen.h: $(src)/screen.xbm $(src)/xbm2lcd.pl
-       perl $(src)/xbm2lcd.pl < $(src)/screen.xbm > $(obj)/screen.h
-
-clean-files := $(obj)/screen.h $(obj)/bootlogo.rh
diff --git a/arch/m68knommu/platform/68VZ328/config.c b/arch/m68knommu/platform/68VZ328/config.c
deleted file mode 100644 (file)
index eabaabe..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************/
-
-/*
- *  linux/arch/m68knommu/platform/68VZ328/config.c
- *
- *  Copyright (C) 1993 Hamish Macdonald
- *  Copyright (C) 1999 D. Jeff Dionne
- *  Copyright (C) 2001 Georges Menie, Ken Desmet
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-/***************************************************************************/
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/kd.h>
-#include <linux/netdevice.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/MC68VZ328.h>
-#include <asm/bootstd.h>
-
-#ifdef CONFIG_INIT_LCD
-#include "bootlogo.h"
-#endif
-
-/***************************************************************************/
-
-void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec);
-
-/***************************************************************************/
-/*                        Init Drangon Engine hardware                     */
-/***************************************************************************/
-#if defined(CONFIG_DRAGEN2)
-
-static void m68vz328_reset(void)
-{
-       local_irq_disable();
-
-#ifdef CONFIG_INIT_LCD
-       PBDATA |= 0x20;                         /* disable CCFL light */
-       PKDATA |= 0x4;                          /* disable LCD controller */
-       LCKCON = 0;
-#endif
-
-       __asm__ __volatile__(
-               "reset\n\t"
-               "moveal #0x04000000, %a0\n\t"
-               "moveal 0(%a0), %sp\n\t"
-               "moveal 4(%a0), %a0\n\t"
-               "jmp (%a0)"
-       );
-}
-
-static void init_hardware(char *command, int size)
-{
-#ifdef CONFIG_DIRECT_IO_ACCESS
-       SCR = 0x10;                                     /* allow user access to internal registers */
-#endif
-
-       /* CSGB Init */
-       CSGBB = 0x4000;
-       CSB = 0x1a1;
-
-       /* CS8900 init */
-       /* PK3: hardware sleep function pin, active low */
-       PKSEL |= PK(3);                         /* select pin as I/O */
-       PKDIR |= PK(3);                         /* select pin as output */
-       PKDATA |= PK(3);                        /* set pin high */
-
-       /* PF5: hardware reset function pin, active high */
-       PFSEL |= PF(5);                         /* select pin as I/O */
-       PFDIR |= PF(5);                         /* select pin as output */
-       PFDATA &= ~PF(5);                       /* set pin low */
-
-       /* cs8900 hardware reset */
-       PFDATA |= PF(5);
-       { int i; for (i = 0; i < 32000; ++i); }
-       PFDATA &= ~PF(5);
-
-       /* INT1 enable (cs8900 IRQ) */
-       PDPOL &= ~PD(1);                        /* active high signal */
-       PDIQEG &= ~PD(1);
-       PDIRQEN |= PD(1);                       /* IRQ enabled */
-
-#ifdef CONFIG_INIT_LCD
-       /* initialize LCD controller */
-       LSSA = (long) screen_bits;
-       LVPW = 0x14;
-       LXMAX = 0x140;
-       LYMAX = 0xef;
-       LRRA = 0;
-       LPXCD = 3;
-       LPICF = 0x08;
-       LPOLCF = 0;
-       LCKCON = 0x80;
-       PCPDEN = 0xff;
-       PCSEL = 0;
-
-       /* Enable LCD controller */
-       PKDIR |= 0x4;
-       PKSEL |= 0x4;
-       PKDATA &= ~0x4;
-
-       /* Enable CCFL backlighting circuit */
-       PBDIR |= 0x20;
-       PBSEL |= 0x20;
-       PBDATA &= ~0x20;
-
-       /* contrast control register */
-       PFDIR |= 0x1;
-       PFSEL &= ~0x1;
-       PWMR = 0x037F;
-#endif
-}
-
-/***************************************************************************/
-/*                      Init RT-Control uCdimm hardware                    */
-/***************************************************************************/
-#elif defined(CONFIG_UCDIMM)
-
-static void m68vz328_reset(void)
-{
-       local_irq_disable();
-       asm volatile (
-               "moveal #0x10c00000, %a0;\n\t"
-               "moveb #0, 0xFFFFF300;\n\t"
-               "moveal 0(%a0), %sp;\n\t"
-               "moveal 4(%a0), %a0;\n\t"
-               "jmp (%a0);\n"
-       );
-}
-
-unsigned char *cs8900a_hwaddr;
-static int errno;
-
-_bsc0(char *, getserialnum)
-_bsc1(unsigned char *, gethwaddr, int, a)
-_bsc1(char *, getbenv, char *, a)
-
-static void init_hardware(char *command, int size)
-{
-       char *p;
-
-       printk(KERN_INFO "uCdimm serial string [%s]\n", getserialnum());
-       p = cs8900a_hwaddr = gethwaddr(0);
-       printk(KERN_INFO "uCdimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-               p[0], p[1], p[2], p[3], p[4], p[5]);
-       p = getbenv("APPEND");
-       if (p)
-               strcpy(p, command);
-       else
-               command[0] = 0;
-}
-
-/***************************************************************************/
-#else
-
-static void m68vz328_reset(void)
-{
-}
-
-static void init_hardware(char *command, int size)
-{
-}
-
-/***************************************************************************/
-#endif
-/***************************************************************************/
-
-void config_BSP(char *command, int size)
-{
-       printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
-
-       init_hardware(command, size);
-
-       mach_gettod = m68328_timer_gettod;
-       mach_reset = m68vz328_reset;
-}
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/Makefile b/arch/m68knommu/platform/Makefile
deleted file mode 100644 (file)
index fc932bf..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#
-# Makefile for the arch/m68knommu/platform.
-#
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
deleted file mode 100644 (file)
index a8967ba..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Makefile for the m68knommu kernel.
-#
-
-#
-# If you want to play with the HW breakpoints then you will
-# need to add define this,  which will give you a stack backtrace
-# on the console port whenever a DBG interrupt occurs. You have to
-# set up you HW breakpoints to trigger a DBG interrupt:
-#
-# ccflags-y := -DTRAP_DBG_INTERRUPT
-# asflags-y := -DTRAP_DBG_INTERRUPT
-#
-
-asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-
-obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206)    += timers.o intc.o
-obj-$(CONFIG_M5206e)   += timers.o intc.o
-obj-$(CONFIG_M520x)    += pit.o intc-simr.o
-obj-$(CONFIG_M523x)    += pit.o dma_timer.o intc-2.o
-obj-$(CONFIG_M5249)    += timers.o intc.o
-obj-$(CONFIG_M527x)    += pit.o intc-2.o
-obj-$(CONFIG_M5272)    += timers.o
-obj-$(CONFIG_M528x)    += pit.o intc-2.o
-obj-$(CONFIG_M5307)    += timers.o intc.o
-obj-$(CONFIG_M532x)    += timers.o intc-simr.o
-obj-$(CONFIG_M5407)    += timers.o intc.o
-obj-$(CONFIG_M54xx)    += sltimers.o intc-2.o
-
-obj-y                  += pinmux.o gpio.o
-extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/cache.c b/arch/m68knommu/platform/coldfire/cache.c
deleted file mode 100644 (file)
index 235d3c4..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/***************************************************************************/
-
-/*
- *     cache.c -- general ColdFire Cache maintainence code
- *
- *     Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-#ifdef CACHE_PUSH
-/***************************************************************************/
-
-/*
- *     Use cpushl to push all dirty cache lines back to memory.
- *     Older versions of GAS don't seem to know how to generate the
- *     ColdFire cpushl instruction... Oh well, bit stuff it for now.
- */
-
-void mcf_cache_push(void)
-{
-       __asm__ __volatile__ (
-               "clrl   %%d0\n\t"
-               "1:\n\t"
-               "movel  %%d0,%%a0\n\t"
-               "2:\n\t"
-               ".word  0xf468\n\t"
-               "addl   %0,%%a0\n\t"
-               "cmpl   %1,%%a0\n\t"
-               "blt    2b\n\t"
-               "addql  #1,%%d0\n\t"
-               "cmpil  %2,%%d0\n\t"
-               "bne    1b\n\t"
-               : /* No output */
-               : "i" (CACHE_LINE_SIZE),
-                 "i" (DCACHE_SIZE / CACHE_WAYS),
-                 "i" (CACHE_WAYS)
-               : "d0", "a0" );
-}
-
-/***************************************************************************/
-#endif /* CACHE_PUSH */
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/clk.c b/arch/m68knommu/platform/coldfire/clk.c
deleted file mode 100644 (file)
index 9f1260c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/***************************************************************************/
-
-/*
- *     clk.c -- general ColdFire CPU kernel clk handling
- *
- *     Copyright (C) 2009, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <asm/coldfire.h>
-
-/***************************************************************************/
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       return NULL;
-}
-EXPORT_SYMBOL(clk_get);
-
-int clk_enable(struct clk *clk)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       return MCF_CLK;
-}
-EXPORT_SYMBOL(clk_get_rate);
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/dma.c b/arch/m68knommu/platform/coldfire/dma.c
deleted file mode 100644 (file)
index e88b95e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/***************************************************************************/
-
-/*
- *     dma.c -- Freescale ColdFire DMA support
- *
- *     Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <asm/dma.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
-
-/***************************************************************************/
-
-/*
- *      DMA channel base address table.
- */
-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-#ifdef MCFDMA_BASE0
-       MCFDMA_BASE0,
-#endif
-#ifdef MCFDMA_BASE1
-       MCFDMA_BASE1,
-#endif
-#ifdef MCFDMA_BASE2
-       MCFDMA_BASE2,
-#endif
-#ifdef MCFDMA_BASE3
-       MCFDMA_BASE3,
-#endif
-};
-
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/dma_timer.c b/arch/m68knommu/platform/coldfire/dma_timer.c
deleted file mode 100644 (file)
index a5f5628..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * dma_timer.c -- Freescale ColdFire DMA Timer.
- *
- * Copyright (C) 2007, Benedikt Spranger <b.spranger@linutronix.de>
- * Copyright (C) 2008. Sebastian Siewior, Linutronix
- *
- */
-
-#include <linux/clocksource.h>
-#include <linux/io.h>
-
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfpit.h>
-#include <asm/mcfsim.h>
-
-#define DMA_TIMER_0    (0x00)
-#define DMA_TIMER_1    (0x40)
-#define DMA_TIMER_2    (0x80)
-#define DMA_TIMER_3    (0xc0)
-
-#define DTMR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x400)
-#define DTXMR0 (MCF_IPSBAR + DMA_TIMER_0 + 0x402)
-#define DTER0  (MCF_IPSBAR + DMA_TIMER_0 + 0x403)
-#define DTRR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x404)
-#define DTCR0  (MCF_IPSBAR + DMA_TIMER_0 + 0x408)
-#define DTCN0  (MCF_IPSBAR + DMA_TIMER_0 + 0x40c)
-
-#define DMA_FREQ    ((MCF_CLK / 2) / 16)
-
-/* DTMR */
-#define DMA_DTMR_RESTART       (1 << 3)
-#define DMA_DTMR_CLK_DIV_1     (1 << 1)
-#define DMA_DTMR_CLK_DIV_16    (2 << 1)
-#define DMA_DTMR_ENABLE                (1 << 0)
-
-static cycle_t cf_dt_get_cycles(struct clocksource *cs)
-{
-       return __raw_readl(DTCN0);
-}
-
-static struct clocksource clocksource_cf_dt = {
-       .name           = "coldfire_dma_timer",
-       .rating         = 200,
-       .read           = cf_dt_get_cycles,
-       .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 20,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init  init_cf_dt_clocksource(void)
-{
-       /*
-        * We setup DMA timer 0 in free run mode. This incrementing counter is
-        * used as a highly precious clock source. With MCF_CLOCK = 150 MHz we
-        * get a ~213 ns resolution and the 32bit register will overflow almost
-        * every 15 minutes.
-        */
-       __raw_writeb(0x00, DTXMR0);
-       __raw_writeb(0x00, DTER0);
-       __raw_writel(0x00000000, DTRR0);
-       __raw_writew(DMA_DTMR_CLK_DIV_16 | DMA_DTMR_ENABLE, DTMR0);
-       clocksource_cf_dt.mult = clocksource_hz2mult(DMA_FREQ,
-                                                    clocksource_cf_dt.shift);
-       return clocksource_register(&clocksource_cf_dt);
-}
-
-arch_initcall(init_cf_dt_clocksource);
-
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-#define CYC2NS_SCALE   ((1000000 << CYC2NS_SCALE_FACTOR) / (DMA_FREQ / 1000))
-
-static unsigned long long cycles2ns(unsigned long cycl)
-{
-       return (unsigned long long) ((unsigned long long)cycl *
-                       CYC2NS_SCALE) >> CYC2NS_SCALE_FACTOR;
-}
-
-unsigned long long sched_clock(void)
-{
-       unsigned long cycl = __raw_readl(DTCN0);
-
-       return cycles2ns(cycl);
-}
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
deleted file mode 100644 (file)
index 5837cf0..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- *  linux/arch/m68knommu/platform/5307/entry.S
- *
- *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
- *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                      Kenneth Albanowski <kjahds@kjahds.com>,
- *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
- *  Copyright (C) 2004-2006  Macq Electronique SA. (www.macqel.com)
- *
- * Based on:
- *
- *  linux/arch/m68k/kernel/entry.S
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- *
- * Linux/m68k support by Hamish Macdonald
- *
- * 68060 fixes by Jesper Skov
- * ColdFire support by Greg Ungerer (gerg@snapgear.com)
- * 5307 fixes by David W. Miller
- * linux 2.4 support David McCullough <davidm@snapgear.com>
- * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/unistd.h>
-#include <asm/thread_info.h>
-#include <asm/errno.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/asm-offsets.h>
-#include <asm/entry.h>
-
-#ifdef CONFIG_COLDFIRE_SW_A7
-/*
- *     Define software copies of the supervisor and user stack pointers.
- */
-.bss
-sw_ksp:
-.long  0
-sw_usp:
-.long  0
-#endif /* CONFIG_COLDFIRE_SW_A7 */
-
-.text
-
-.globl system_call
-.globl resume
-.globl ret_from_exception
-.globl ret_from_signal
-.globl sys_call_table
-.globl inthandler
-.globl fasthandler
-
-enosys:
-       mov.l   #sys_ni_syscall,%d3
-       bra     1f
-
-ENTRY(system_call)
-       SAVE_ALL
-       move    #0x2000,%sr             /* enable intrs again */
-
-       cmpl    #NR_syscalls,%d0
-       jcc     enosys
-       lea     sys_call_table,%a0
-       lsll    #2,%d0                  /* movel %a0@(%d0:l:4),%d3 */
-       movel   %a0@(%d0),%d3
-       jeq     enosys
-
-1:
-       movel   %sp,%d2                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d2       /* at start of kernel stack */
-       movel   %d2,%a0
-       movel   %a0@,%a1                /* save top of frame */
-       movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
-       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
-       bnes    1f
-
-       movel   %d3,%a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
-       jra     ret_from_exception
-1:
-       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_OFF_D0 */
-       movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
-       subql   #4,%sp
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_enter
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       movel   %d3,%a0
-       jbsr    %a0@
-       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       jbsr    syscall_trace_leave
-
-ret_from_signal:
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-
-ret_from_exception:
-       move    #0x2700,%sr             /* disable intrs */
-       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
-       jeq     Luser_return            /* if so, skip resched, signals */
-
-#ifdef CONFIG_PREEMPT
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
-       movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
-       andl    #(1<<TIF_NEED_RESCHED),%d1
-       jeq     Lkernel_return
-
-       movel   %a0@(TI_PREEMPTCOUNT),%d1
-       cmpl    #0,%d1
-       jne     Lkernel_return
-
-       pea     Lkernel_return
-       jmp     preempt_schedule_irq    /* preempt the kernel */
-#endif
-
-Lkernel_return:
-       moveml  %sp@,%d1-%d5/%a0-%a2
-       lea     %sp@(32),%sp            /* space for 8 regs */
-       movel   %sp@+,%d0
-       addql   #4,%sp                  /* orig d0 */
-       addl    %sp@+,%sp               /* stk adj */
-       rte
-
-Luser_return:
-       movel   %sp,%d1                 /* get thread_info pointer */
-       andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
-       movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
-       jne     Lwork_to_do             /* still work to do */
-
-Lreturn:
-       RESTORE_USER
-
-Lwork_to_do:
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
-       move    #0x2000,%sr             /* enable intrs again */
-       btst    #TIF_NEED_RESCHED,%d1
-       jne     reschedule
-
-       /* GERG: do we need something here for TRACEing?? */
-
-Lsignal_return:
-       subql   #4,%sp                  /* dummy return address */
-       SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jsr     do_signal
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
-       addql   #4,%sp
-       jmp     Luser_return
-
-/*
- * This is the generic interrupt handler (for all hardware interrupt
- * sources). Calls upto high level code to do all the work.
- */
-ENTRY(inthandler)
-       SAVE_ALL
-       moveq   #-1,%d0
-       movel   %d0,%sp@(PT_OFF_ORIG_D0)
-
-       movew   %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
-       andl    #0x03fc,%d0             /* mask out vector only */
-
-       movel   %sp,%sp@-               /* push regs arg */
-       lsrl    #2,%d0                  /* calculate real vector # */
-       movel   %d0,%sp@-               /* push vector number */
-       jbsr    do_IRQ                  /* call high level irq handler */
-       lea     %sp@(8),%sp             /* pop args off stack */
-
-       bra     ret_from_exception
-
-/*
- * Beware - when entering resume, prev (the current task) is
- * in a0, next (the new task) is in a1,so don't change these
- * registers until their contents are no longer needed.
- * This is always called in supervisor mode, so don't bother to save
- * and restore sr; user's process sr is actually in the stack.
- */
-ENTRY(resume)
-       movel   %a0, %d1                        /* get prev thread in d1 */
-       RDUSP
-       movel   %a2,%a0@(TASK_THREAD+THREAD_USP)
-
-       SAVE_SWITCH_STACK
-       movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
-       movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
-       RESTORE_SWITCH_STACK
-
-       movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
-       WRUSP
-       rts
diff --git a/arch/m68knommu/platform/coldfire/gpio.c b/arch/m68knommu/platform/coldfire/gpio.c
deleted file mode 100644 (file)
index ff00457..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Coldfire generic GPIO support.
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sysdev.h>
-
-#include <asm/gpio.h>
-#include <asm/pinmux.h>
-#include <asm/mcfgpio.h>
-
-#define MCF_CHIP(chip) container_of(chip, struct mcf_gpio_chip, gpio_chip)
-
-int mcf_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       unsigned long flags;
-       MCFGPIO_PORTTYPE dir;
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       local_irq_save(flags);
-       dir = mcfgpio_read(mcf_chip->pddr);
-       dir &= ~mcfgpio_bit(chip->base + offset);
-       mcfgpio_write(dir, mcf_chip->pddr);
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-int mcf_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       return mcfgpio_read(mcf_chip->ppdr) & mcfgpio_bit(chip->base + offset);
-}
-
-int mcf_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-               int value)
-{
-       unsigned long flags;
-       MCFGPIO_PORTTYPE data;
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       local_irq_save(flags);
-       /* write the value to the output latch */
-       data = mcfgpio_read(mcf_chip->podr);
-       if (value)
-               data |= mcfgpio_bit(chip->base + offset);
-       else
-               data &= ~mcfgpio_bit(chip->base + offset);
-       mcfgpio_write(data, mcf_chip->podr);
-
-       /* now set the direction to output */
-       data = mcfgpio_read(mcf_chip->pddr);
-       data |= mcfgpio_bit(chip->base + offset);
-       mcfgpio_write(data, mcf_chip->pddr);
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-void mcf_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       unsigned long flags;
-       MCFGPIO_PORTTYPE data;
-
-       local_irq_save(flags);
-       data = mcfgpio_read(mcf_chip->podr);
-       if (value)
-               data |= mcfgpio_bit(chip->base + offset);
-       else
-               data &= ~mcfgpio_bit(chip->base + offset);
-       mcfgpio_write(data, mcf_chip->podr);
-       local_irq_restore(flags);
-}
-
-void mcf_gpio_set_value_fast(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       if (value)
-               mcfgpio_write(mcfgpio_bit(chip->base + offset), mcf_chip->setr);
-       else
-               mcfgpio_write(~mcfgpio_bit(chip->base + offset), mcf_chip->clrr);
-}
-
-int mcf_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       return mcf_chip->gpio_to_pinmux ?
-               mcf_pinmux_request(mcf_chip->gpio_to_pinmux[offset], 0) : 0;
-}
-
-void mcf_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       struct mcf_gpio_chip *mcf_chip = MCF_CHIP(chip);
-
-       mcf_gpio_direction_input(chip, offset);
-
-       if (mcf_chip->gpio_to_pinmux)
-               mcf_pinmux_release(mcf_chip->gpio_to_pinmux[offset], 0);
-}
-
-struct sysdev_class mcf_gpio_sysclass = {
-       .name   = "gpio",
-};
-
-static int __init mcf_gpio_sysinit(void)
-{
-       return sysdev_class_register(&mcf_gpio_sysclass);
-}
-
-core_initcall(mcf_gpio_sysinit);
diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68knommu/platform/coldfire/head.S
deleted file mode 100644 (file)
index 129bff4..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     head.S -- common startup code for ColdFire CPUs.
- *
- *     (C) Copyright 1999-2010, Greg Ungerer <gerg@snapgear.com>.
- */
-
-/*****************************************************************************/
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/thread_info.h>
-
-/*****************************************************************************/
-
-/*
- *     If we don't have a fixed memory size, then lets build in code
- *     to auto detect the DRAM size. Obviously this is the prefered
- *     method, and should work for most boards. It won't work for those
- *     that do not have their RAM starting at address 0, and it only
- *     works on SDRAM (not boards fitted with SRAM).
- */
-#if CONFIG_RAMSIZE != 0
-.macro GET_MEM_SIZE
-       movel   #CONFIG_RAMSIZE,%d0     /* hard coded memory size */
-.endm
-
-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
-      defined(CONFIG_M5249) || defined(CONFIG_M527x) || \
-      defined(CONFIG_M528x) || defined(CONFIG_M5307) || \
-      defined(CONFIG_M5407)
-/*
- *     Not all these devices have exactly the same DRAM controller,
- *     but the DCMR register is virtually identical - give or take
- *     a couple of bits. The only exception is the 5272 devices, their
- *     DRAM controller is quite different.
- */
-.macro GET_MEM_SIZE
-       movel   MCFSIM_DMR0,%d0         /* get mask for 1st bank */
-       btst    #0,%d0                  /* check if region enabled */
-       beq     1f
-       andl    #0xfffc0000,%d0
-       beq     1f
-       addl    #0x00040000,%d0         /* convert mask to size */
-1:
-       movel   MCFSIM_DMR1,%d1         /* get mask for 2nd bank */
-       btst    #0,%d1                  /* check if region enabled */
-       beq     2f
-       andl    #0xfffc0000,%d1
-       beq     2f
-       addl    #0x00040000,%d1
-       addl    %d1,%d0                 /* total mem size in d0 */
-2:
-.endm
-
-#elif defined(CONFIG_M5272)
-.macro GET_MEM_SIZE
-       movel   MCF_MBAR+MCFSIM_CSOR7,%d0 /* get SDRAM address mask */
-       andil   #0xfffff000,%d0         /* mask out chip select options */
-       negl    %d0                     /* negate bits */
-.endm
-
-#elif defined(CONFIG_M520x)
-.macro GET_MEM_SIZE
-       clrl    %d0
-       movel   MCFSIM_SDCS0, %d2       /* Get SDRAM chip select 0 config */
-       andl    #0x1f, %d2              /* Get only the chip select size */
-       beq     3f                      /* Check if it is enabled */
-       addql   #1, %d2                 /* Form exponent */
-       moveql  #1, %d0
-       lsll    %d2, %d0                /* 2 ^ exponent */
-3:
-       movel   MCFSIM_SDCS1, %d2       /* Get SDRAM chip select 1 config */
-       andl    #0x1f, %d2              /* Get only the chip select size */
-       beq     4f                      /* Check if it is enabled */
-       addql   #1, %d2                 /* Form exponent */
-       moveql  #1, %d1
-       lsll    %d2, %d1                /* 2 ^ exponent */
-       addl    %d1, %d0                /* Total size of SDRAM in d0 */
-4:
-.endm
-
-#else
-#error "ERROR: I don't know how to probe your boards memory size?"
-#endif
-
-/*****************************************************************************/
-
-/*
- *     Boards and platforms can do specific early hardware setup if
- *     they need to. Most don't need this, define away if not required.
- */
-#ifndef PLATFORM_SETUP
-#define        PLATFORM_SETUP
-#endif
-
-/*****************************************************************************/
-
-.global        _start
-.global _rambase
-.global _ramvec
-.global        _ramstart
-.global        _ramend
-#if defined(CONFIG_UBOOT)
-.global        _init_sp
-#endif
-
-/*****************************************************************************/
-
-.data
-
-/*
- *     During startup we store away the RAM setup. These are not in the
- *     bss, since their values are determined and written before the bss
- *     has been cleared.
- */
-_rambase:
-.long  0
-_ramvec:
-.long  0
-_ramstart:
-.long  0
-_ramend:
-.long  0
-#if defined(CONFIG_UBOOT)
-_init_sp:
-.long  0
-#endif
-
-/*****************************************************************************/
-
-__HEAD
-
-/*
- *     This is the codes first entry point. This is where it all
- *     begins...
- */
-
-_start:
-       nop                                     /* filler */
-       movew   #0x2700, %sr                    /* no interrupts */
-#if defined(CONFIG_UBOOT)
-       movel   %sp,_init_sp                    /* save initial stack pointer */
-#endif
-
-       /*
-        *      Do any platform or board specific setup now. Most boards
-        *      don't need anything. Those exceptions are define this in
-        *      their board specific includes.
-        */
-       PLATFORM_SETUP
-
-       /*
-        *      Create basic memory configuration. Set VBR accordingly,
-        *      and size memory.
-        */
-       movel   #CONFIG_VECTORBASE,%a7
-       movec   %a7,%VBR                        /* set vectors addr */
-       movel   %a7,_ramvec
-
-       movel   #CONFIG_RAMBASE,%a7             /* mark the base of RAM */
-       movel   %a7,_rambase
-
-       GET_MEM_SIZE                            /* macro code determines size */
-       addl    %a7,%d0
-       movel   %d0,_ramend                     /* set end ram addr */
-
-       /*
-        *      Now that we know what the memory is, lets enable cache
-        *      and get things moving. This is Coldfire CPU specific. Not
-        *      all version cores have identical cache register setup. But
-        *      it is very similar. Define the exact settings in the headers
-        *      then the code here is the same for all.
-        */
-       movel   #CACHE_INIT,%d0                 /* invalidate whole cache */
-       movec   %d0,%CACR
-       nop
-       movel   #ACR0_MODE,%d0                  /* set RAM region for caching */
-       movec   %d0,%ACR0
-       movel   #ACR1_MODE,%d0                  /* anything else to cache? */
-       movec   %d0,%ACR1
-#ifdef ACR2_MODE
-       movel   #ACR2_MODE,%d0
-       movec   %d0,%ACR2
-       movel   #ACR3_MODE,%d0
-       movec   %d0,%ACR3
-#endif
-       movel   #CACHE_MODE,%d0                 /* enable cache */
-       movec   %d0,%CACR
-       nop
-
-#ifdef CONFIG_ROMFS_FS
-       /*
-        *      Move ROM filesystem above bss :-)
-        */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* set up destination  */
-       movel   %a0,%a2                         /* copy of bss start */
-
-       movel   8(%a0),%d0                      /* get size of ROMFS */
-       addql   #8,%d0                          /* allow for rounding */
-       andl    #0xfffffffc, %d0                /* whole words */
-
-       addl    %d0,%a0                         /* copy from end */
-       addl    %d0,%a1                         /* copy from end */
-       movel   %a1,_ramstart                   /* set start of ram */
-
-_copy_romfs:
-       movel   -(%a0),%d0                      /* copy dword */
-       movel   %d0,-(%a1)
-       cmpl    %a0,%a2                         /* check if at end */
-       bne     _copy_romfs
-
-#else /* CONFIG_ROMFS_FS */
-       lea     _ebss,%a1
-       movel   %a1,_ramstart
-#endif /* CONFIG_ROMFS_FS */
-
-
-       /*
-        *      Zero out the bss region.
-        */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* get end of bss */
-       clrl    %d0                             /* set value */
-_clear_bss:
-       movel   %d0,(%a0)+                      /* clear each word */
-       cmpl    %a0,%a1                         /* check if at end */
-       bne     _clear_bss
-
-       /*
-        *      Load the current task pointer and stack.
-        */
-       lea     init_thread_union,%a0
-       lea     THREAD_SIZE(%a0),%sp
-
-       /*
-        *      Assember start up done, start code proper.
-        */
-       jsr     start_kernel                    /* start Linux kernel */
-
-_exit:
-       jmp     _exit                           /* should never get here */
-
-/*****************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68knommu/platform/coldfire/intc-2.c
deleted file mode 100644 (file)
index 2cbfbf0..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * intc-2.c
- *
- * General interrupt controller code for the many ColdFire cores that use
- * interrupt controllers with 63 interrupt sources, organized as 56 fully-
- * programmable + 7 fixed-level interrupt sources. This includes the 523x
- * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
- * controllers, and the 547x and 548x families which have only one of them.
- *
- * The external 7 fixed interrupts are part the the Edge Port unit of these
- * ColdFire parts. They can be configured as level or edge triggered.
- *
- * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- * Bit definitions for the ICR family of registers.
- */
-#define MCFSIM_ICR_LEVEL(l)    ((l)<<3)        /* Level l intr */
-#define MCFSIM_ICR_PRI(p)      (p)             /* Priority p intr */
-
-/*
- *     The EDGE Port interrupts are the fixed 7 external interrupts.
- *     They need some special treatment, for example they need to be acked.
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT7   71      /* EDGE Port interrupt 7 */
-
-#ifdef MCFICM_INTC1
-#define NR_VECS        128
-#else
-#define NR_VECS        64
-#endif
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long imraddr;
-       u32 val, imrbit;
-
-#ifdef MCFICM_INTC1
-       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       imraddr = MCFICM_INTC0;
-#endif
-       imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
-       imrbit = 0x1 << (irq & 0x1f);
-
-       val = __raw_readl(imraddr);
-       __raw_writel(val | imrbit, imraddr);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long imraddr;
-       u32 val, imrbit;
-
-#ifdef MCFICM_INTC1
-       imraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       imraddr = MCFICM_INTC0;
-#endif
-       imraddr += ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
-       imrbit = 0x1 << (irq & 0x1f);
-
-       /* Don't set the "maskall" bit! */
-       if ((irq & 0x20) == 0)
-               imrbit |= 0x1;
-
-       val = __raw_readl(imraddr);
-       __raw_writel(val & ~imrbit, imraddr);
-}
-
-/*
- *     Only the external (or EDGE Port) interrupts need to be acknowledged
- *     here, as part of the IRQ handler. They only really need to be ack'ed
- *     if they are in edge triggered mode, but there is no harm in doing it
- *     for all types.
- */
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR);
-}
-
-/*
- *     Each vector needs a unique priority and level associated with it.
- *     We don't really care so much what they are, we don't rely on the
- *     traditional priority interrupt scheme of the m68k/ColdFire. This
- *     only needs to be set once for an interrupt, and we will never change
- *     these values once we have set them.
- */
-static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
-
-static unsigned int intc_irq_startup(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-       unsigned long icraddr;
-
-#ifdef MCFICM_INTC1
-       icraddr = (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
-#else
-       icraddr = MCFICM_INTC0;
-#endif
-       icraddr += MCFINTC_ICR0 + (irq & 0x3f);
-       if (__raw_readb(icraddr) == 0)
-               __raw_writeb(intc_intpri--, icraddr);
-
-       irq = d->irq;
-       if ((irq >= EINT1) && (irq <= EINT7)) {
-               u8 v;
-
-               irq -= EINT0;
-
-               /* Set EPORT line as input */
-               v = __raw_readb(MCFEPORT_EPDDR);
-               __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR);
-
-               /* Set EPORT line as interrupt source */
-               v = __raw_readb(MCFEPORT_EPIER);
-               __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER);
-       }
-
-       intc_irq_unmask(d);
-       return 0;
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int irq = d->irq;
-       u16 pa, tb;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               tb = 0x1;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               tb = 0x2;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               tb = 0x3;
-               break;
-       default:
-               /* Level triggered */
-               tb = 0;
-               break;
-       }
-
-       if (tb)
-               set_irq_handler(irq, handle_edge_irq);
-
-       irq -= EINT0;
-       pa = __raw_readw(MCFEPORT_EPPAR);
-       pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2));
-       __raw_writew(pa, MCFEPORT_EPPAR);
-       
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-static struct irq_chip intc_irq_chip_edge_port = {
-       .name           = "CF-INTC-EP",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq;
-
-       init_vectors();
-
-       /* Mask all interrupt sources */
-       __raw_writel(0x1, MCFICM_INTC0 + MCFINTC_IMRL);
-#ifdef MCFICM_INTC1
-       __raw_writel(0x1, MCFICM_INTC1 + MCFINTC_IMRL);
-#endif
-
-       for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) {
-               if ((irq >= EINT1) && (irq <=EINT7))
-                       set_irq_chip(irq, &intc_irq_chip_edge_port);
-               else
-                       set_irq_chip(irq, &intc_irq_chip);
-               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               set_irq_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68knommu/platform/coldfire/intc-simr.c
deleted file mode 100644 (file)
index e642b24..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * intc-simr.c
- *
- * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
- *
- * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/traps.h>
-
-/*
- *     The EDGE Port interrupts are the fixed 7 external interrupts.
- *     They need some special treatment, for example they need to be acked.
- */
-#ifdef CONFIG_M520x
-/*
- *     The 520x parts only support a limited range of these external
- *     interrupts, only 1, 4 and 7 (as interrupts 65, 66 and 67).
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT4   66      /* EDGE Port interrupt 4 */
-#define        EINT7   67      /* EDGE Port interrupt 7 */
-
-static unsigned int irqebitmap[] = { 0, 1, 4, 7 };
-static unsigned int inline irq2ebit(unsigned int irq)
-{
-       return irqebitmap[irq - EINT0];
-}
-
-#else
-
-/*
- *     Most of the ColdFire parts with the EDGE Port module just have
- *     a strait direct mapping of the 7 external interrupts. Although
- *     there is a bit reserved for 0, it is not used.
- */
-#define        EINT0   64      /* Is not actually used, but spot reserved for it */
-#define        EINT1   65      /* EDGE Port interrupt 1 */
-#define        EINT7   71      /* EDGE Port interrupt 7 */
-
-static unsigned int inline irq2ebit(unsigned int irq)
-{
-       return irq - EINT0;
-}
-
-#endif
-
-/*
- *     There maybe one or two interrupt control units, each has 64
- *     interrupts. If there is no second unit then MCFINTC1_* defines
- *     will be 0 (and code for them optimized away).
- */
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-
-       if (MCFINTC1_SIMR && (irq > 64))
-               __raw_writeb(irq - 64, MCFINTC1_SIMR);
-       else
-               __raw_writeb(irq, MCFINTC0_SIMR);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       unsigned int irq = d->irq - MCFINT_VECBASE;
-
-       if (MCFINTC1_CIMR && (irq > 64))
-               __raw_writeb(irq - 64, MCFINTC1_CIMR);
-       else
-               __raw_writeb(irq, MCFINTC0_CIMR);
-}
-
-static void intc_irq_ack(struct irq_data *d)
-{
-       unsigned int ebit = irq2ebit(d->irq);
-
-       __raw_writeb(0x1 << ebit, MCFEPORT_EPFR);
-}
-
-static unsigned int intc_irq_startup(struct irq_data *d)
-{
-       unsigned int irq = d->irq;
-
-       if ((irq >= EINT1) && (irq <= EINT7)) {
-               unsigned int ebit = irq2ebit(irq);
-               u8 v;
-
-               /* Set EPORT line as input */
-               v = __raw_readb(MCFEPORT_EPDDR);
-               __raw_writeb(v & ~(0x1 << ebit), MCFEPORT_EPDDR);
-
-               /* Set EPORT line as interrupt source */
-               v = __raw_readb(MCFEPORT_EPIER);
-               __raw_writeb(v | (0x1 << ebit), MCFEPORT_EPIER);
-       }
-
-       irq -= MCFINT_VECBASE;
-       if (MCFINTC1_ICR0 && (irq > 64))
-               __raw_writeb(5, MCFINTC1_ICR0 + irq - 64);
-       else
-               __raw_writeb(5, MCFINTC0_ICR0 + irq);
-
-
-       intc_irq_unmask(d);
-       return 0;
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       unsigned int ebit, irq = d->irq;
-       u16 pa, tb;
-
-       switch (type) {
-       case IRQ_TYPE_EDGE_RISING:
-               tb = 0x1;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               tb = 0x2;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               tb = 0x3;
-               break;
-       default:
-               /* Level triggered */
-               tb = 0;
-               break;
-       }
-
-       if (tb)
-               set_irq_handler(irq, handle_edge_irq);
-
-       ebit = irq2ebit(irq) * 2;
-       pa = __raw_readw(MCFEPORT_EPPAR);
-       pa = (pa & ~(0x3 << ebit)) | (tb << ebit);
-       __raw_writew(pa, MCFEPORT_EPPAR);
-       
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-};
-
-static struct irq_chip intc_irq_chip_edge_port = {
-       .name           = "CF-INTC-EP",
-       .irq_startup    = intc_irq_startup,
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_ack        = intc_irq_ack,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq, eirq;
-
-       init_vectors();
-
-       /* Mask all interrupt sources */
-       __raw_writeb(0xff, MCFINTC0_SIMR);
-       if (MCFINTC1_SIMR)
-               __raw_writeb(0xff, MCFINTC1_SIMR);
-
-       eirq = MCFINT_VECBASE + 64 + (MCFINTC1_ICR0 ? 64 : 0);
-       for (irq = MCFINT_VECBASE; (irq < eirq); irq++) {
-               if ((irq >= EINT1) && (irq <= EINT7))
-                       set_irq_chip(irq, &intc_irq_chip_edge_port);
-               else
-                       set_irq_chip(irq, &intc_irq_chip);
-               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               set_irq_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68knommu/platform/coldfire/intc.c
deleted file mode 100644 (file)
index d648081..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * intc.c  -- support for the old ColdFire interrupt controller
- *
- * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <asm/traps.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-
-/*
- * The mapping of irq number to a mask register bit is not one-to-one.
- * The irq numbers are either based on "level" of interrupt or fixed
- * for an autovector-able interrupt. So we keep a local data structure
- * that maps from irq to mask register. Not all interrupts will have
- * an IMR bit.
- */
-unsigned char mcf_irq2imr[NR_IRQS];
-
-/*
- * Define the miniumun and maximum external interrupt numbers.
- * This is also used as the "level" interrupt numbers.
- */
-#define        EIRQ1   25
-#define        EIRQ7   31
-
-/*
- * In the early version 2 core ColdFire parts the IMR register was 16 bits
- * in size. Version 3 (and later version 2) core parts have a 32 bit
- * sized IMR register. Provide some size independant methods to access the
- * IMR register.
- */
-#ifdef MCFSIM_IMR_IS_16BITS
-
-void mcf_setimr(int index)
-{
-       u16 imr;
-       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
-       __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
-}
-
-void mcf_clrimr(int index)
-{
-       u16 imr;
-       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
-       __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
-}
-
-void mcf_maskimr(unsigned int mask)
-{
-       u16 imr;
-       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
-       imr |= mask;
-       __raw_writew(imr, MCF_MBAR + MCFSIM_IMR);
-}
-
-#else
-
-void mcf_setimr(int index)
-{
-       u32 imr;
-       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
-       __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
-}
-
-void mcf_clrimr(int index)
-{
-       u32 imr;
-       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
-       __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
-}
-
-void mcf_maskimr(unsigned int mask)
-{
-       u32 imr;
-       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
-       imr |= mask;
-       __raw_writel(imr, MCF_MBAR + MCFSIM_IMR);
-}
-
-#endif
-
-/*
- * Interrupts can be "vectored" on the ColdFire cores that support this old
- * interrupt controller. That is, the device raising the interrupt can also
- * supply the vector number to interrupt through. The AVR register of the
- * interrupt controller enables or disables this for each external interrupt,
- * so provide generic support for this. Setting this up is out-of-band for
- * the interrupt system API's, and needs to be done by the driver that
- * supports this device. Very few devices actually use this.
- */
-void mcf_autovector(int irq)
-{
-#ifdef MCFSIM_AVR
-       if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
-               u8 avec;
-               avec = __raw_readb(MCF_MBAR + MCFSIM_AVR);
-               avec |= (0x1 << (irq - EIRQ1 + 1));
-               __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR);
-       }
-#endif
-}
-
-static void intc_irq_mask(struct irq_data *d)
-{
-       if (mcf_irq2imr[d->irq])
-               mcf_setimr(mcf_irq2imr[d->irq]);
-}
-
-static void intc_irq_unmask(struct irq_data *d)
-{
-       if (mcf_irq2imr[d->irq])
-               mcf_clrimr(mcf_irq2imr[d->irq]);
-}
-
-static int intc_irq_set_type(struct irq_data *d, unsigned int type)
-{
-       return 0;
-}
-
-static struct irq_chip intc_irq_chip = {
-       .name           = "CF-INTC",
-       .irq_mask       = intc_irq_mask,
-       .irq_unmask     = intc_irq_unmask,
-       .irq_set_type   = intc_irq_set_type,
-};
-
-void __init init_IRQ(void)
-{
-       int irq;
-
-       init_vectors();
-       mcf_maskimr(0xffffffff);
-
-       for (irq = 0; (irq < NR_IRQS); irq++) {
-               set_irq_chip(irq, &intc_irq_chip);
-               set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
-               set_irq_handler(irq, handle_level_irq);
-       }
-}
-
diff --git a/arch/m68knommu/platform/coldfire/pinmux.c b/arch/m68knommu/platform/coldfire/pinmux.c
deleted file mode 100644 (file)
index 8c62b82..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Coldfire generic GPIO pinmux support.
- *
- * (C) Copyright 2009, Steven King <sfking@fdwdc.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; 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.
- *
- */
-
-#include <linux/kernel.h>
-
-#include <asm/pinmux.h>
-
-int mcf_pinmux_request(unsigned pinmux, unsigned func)
-{
-       return 0;
-}
-
-void mcf_pinmux_release(unsigned pinmux, unsigned func)
-{
-}
diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c
deleted file mode 100644 (file)
index c2b9809..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/***************************************************************************/
-
-/*
- *     pit.c -- Freescale ColdFire PIT timer. Currently this type of
- *              hardware timer only exists in the Freescale ColdFire
- *              5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
- *              family members will probably use it too.
- *
- *     Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
- *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/param.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/clockchips.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/coldfire.h>
-#include <asm/mcfpit.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     By default use timer1 as the system clock timer.
- */
-#define        FREQ    ((MCF_CLK / 2) / 64)
-#define        TA(a)   (MCFPIT_BASE1 + (a))
-#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
-
-static u32 pit_cnt;
-
-/*
- * Initialize the PIT timer.
- *
- * This is also called after resume to bring the PIT into operation again.
- */
-
-static void init_cf_pit_timer(enum clock_event_mode mode,
-                             struct clock_event_device *evt)
-{
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
-               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
-                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
-                               MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_UNUSED:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_ONESHOT:
-
-               __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-               __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
-                               MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
-                               TA(MCFPIT_PCSR));
-               break;
-
-       case CLOCK_EVT_MODE_RESUME:
-               /* Nothing to do here */
-               break;
-       }
-}
-
-/*
- * Program the next event in oneshot mode
- *
- * Delta is given in PIT ticks
- */
-static int cf_pit_next_event(unsigned long delta,
-               struct clock_event_device *evt)
-{
-       __raw_writew(delta, TA(MCFPIT_PMR));
-       return 0;
-}
-
-struct clock_event_device cf_pit_clockevent = {
-       .name           = "pit",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = init_cf_pit_timer,
-       .set_next_event = cf_pit_next_event,
-       .shift          = 32,
-       .irq            = MCFINT_VECBASE + MCFINT_PIT1,
-};
-
-
-
-/***************************************************************************/
-
-static irqreturn_t pit_tick(int irq, void *dummy)
-{
-       struct clock_event_device *evt = &cf_pit_clockevent;
-       u16 pcsr;
-
-       /* Reset the ColdFire timer */
-       pcsr = __raw_readw(TA(MCFPIT_PCSR));
-       __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
-
-       pit_cnt += PIT_CYCLES_PER_JIFFY;
-       evt->event_handler(evt);
-       return IRQ_HANDLED;
-}
-
-/***************************************************************************/
-
-static struct irqaction pit_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = pit_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t pit_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-       u16 pcntr;
-
-       local_irq_save(flags);
-       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
-       cycles = pit_cnt;
-       local_irq_restore(flags);
-
-       return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
-}
-
-/***************************************************************************/
-
-static struct clocksource pit_clk = {
-       .name   = "pit",
-       .rating = 100,
-       .read   = pit_read_clk,
-       .shift  = 20,
-       .mask   = CLOCKSOURCE_MASK(32),
-};
-
-/***************************************************************************/
-
-void hw_timer_init(void)
-{
-       cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
-       cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
-       cf_pit_clockevent.max_delta_ns =
-               clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
-       cf_pit_clockevent.min_delta_ns =
-               clockevent_delta2ns(0x3f, &cf_pit_clockevent);
-       clockevents_register_device(&cf_pit_clockevent);
-
-       setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
-
-       pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
-       clocksource_register(&pit_clk);
-}
-
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68knommu/platform/coldfire/sltimers.c
deleted file mode 100644 (file)
index 0a1b937..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/***************************************************************************/
-
-/*
- *     sltimers.c -- generic ColdFire slice timer support.
- *
- *     Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
- *     based on
- *     timers.c -- generic ColdFire hardware timer support.
- *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/profile.h>
-#include <linux/clocksource.h>
-#include <asm/io.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfslt.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-#ifdef CONFIG_HIGHPROFILE
-
-/*
- *     By default use Slice Timer 1 as the profiler clock timer.
- */
-#define        PA(a)   (MCF_MBAR + MCFSLT_TIMER1 + (a))
-
-/*
- *     Choose a reasonably fast profile timer. Make it an odd value to
- *     try and get good coverage of kernel operations.
- */
-#define        PROFILEHZ       1013
-
-irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
-{
-       /* Reset Slice Timer 1 */
-       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-       return IRQ_HANDLED;
-}
-
-static struct irqaction mcfslt_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = mcfslt_profile_tick,
-};
-
-void mcfslt_profile_init(void)
-{
-       printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
-              PROFILEHZ);
-
-       setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
-
-       /* Set up TIMER 2 as high speed profile clock */
-       __raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
-       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
-                                                               PA(MCFSLT_SCR));
-
-}
-
-#endif /* CONFIG_HIGHPROFILE */
-
-/***************************************************************************/
-
-/*
- *     By default use Slice Timer 0 as the system clock timer.
- */
-#define        TA(a)   (MCF_MBAR + MCFSLT_TIMER0 + (a))
-
-static u32 mcfslt_cycles_per_jiffy;
-static u32 mcfslt_cnt;
-
-static irqreturn_t mcfslt_tick(int irq, void *dummy)
-{
-       /* Reset Slice Timer 0 */
-       __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
-       mcfslt_cnt += mcfslt_cycles_per_jiffy;
-       return arch_timer_interrupt(irq, dummy);
-}
-
-static struct irqaction mcfslt_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = mcfslt_tick,
-};
-
-static cycle_t mcfslt_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-       u16 scnt;
-
-       local_irq_save(flags);
-       scnt = __raw_readl(TA(MCFSLT_SCNT));
-       cycles = mcfslt_cnt;
-       local_irq_restore(flags);
-
-       /* substract because slice timers count down */
-       return cycles - scnt;
-}
-
-static struct clocksource mcfslt_clk = {
-       .name   = "slt",
-       .rating = 250,
-       .read   = mcfslt_read_clk,
-       .shift  = 20,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-void hw_timer_init(void)
-{
-       mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
-       /*
-        *      The coldfire slice timer (SLT) runs from STCNT to 0 included,
-        *      then STCNT again and so on.  It counts thus actually
-        *      STCNT + 1 steps for 1 tick, not STCNT.  So if you want
-        *      n cycles, initialize STCNT with n - 1.
-        */
-       __raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
-       __raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
-                                                               TA(MCFSLT_SCR));
-       /* initialize mcfslt_cnt knowing that slice timers count down */
-       mcfslt_cnt = mcfslt_cycles_per_jiffy;
-
-       setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
-
-       mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
-       clocksource_register(&mcfslt_clk);
-
-#ifdef CONFIG_HIGHPROFILE
-       mcfslt_profile_init();
-#endif
-}
diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c
deleted file mode 100644 (file)
index 60242f6..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/***************************************************************************/
-
-/*
- *     timers.c -- generic ColdFire hardware timer support.
- *
- *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/profile.h>
-#include <linux/clocksource.h>
-#include <asm/io.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcftimer.h>
-#include <asm/mcfsim.h>
-
-/***************************************************************************/
-
-/*
- *     By default use timer1 as the system clock timer.
- */
-#define        FREQ    (MCF_BUSCLK / 16)
-#define        TA(a)   (MCFTIMER_BASE1 + (a))
-
-/*
- *     These provide the underlying interrupt vector support.
- *     Unfortunately it is a little different on each ColdFire.
- */
-void coldfire_profile_init(void);
-
-#if defined(CONFIG_M532x)
-#define        __raw_readtrr   __raw_readl
-#define        __raw_writetrr  __raw_writel
-#else
-#define        __raw_readtrr   __raw_readw
-#define        __raw_writetrr  __raw_writew
-#endif
-
-static u32 mcftmr_cycles_per_jiffy;
-static u32 mcftmr_cnt;
-
-/***************************************************************************/
-
-static irqreturn_t mcftmr_tick(int irq, void *dummy)
-{
-       /* Reset the ColdFire timer */
-       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
-
-       mcftmr_cnt += mcftmr_cycles_per_jiffy;
-       return arch_timer_interrupt(irq, dummy);
-}
-
-/***************************************************************************/
-
-static struct irqaction mcftmr_timer_irq = {
-       .name    = "timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = mcftmr_tick,
-};
-
-/***************************************************************************/
-
-static cycle_t mcftmr_read_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 cycles;
-       u16 tcn;
-
-       local_irq_save(flags);
-       tcn = __raw_readw(TA(MCFTIMER_TCN));
-       cycles = mcftmr_cnt;
-       local_irq_restore(flags);
-
-       return cycles + tcn;
-}
-
-/***************************************************************************/
-
-static struct clocksource mcftmr_clk = {
-       .name   = "tmr",
-       .rating = 250,
-       .read   = mcftmr_read_clk,
-       .shift  = 20,
-       .mask   = CLOCKSOURCE_MASK(32),
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/***************************************************************************/
-
-void hw_timer_init(void)
-{
-       __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
-       mcftmr_cycles_per_jiffy = FREQ / HZ;
-       /*
-        *      The coldfire timer runs from 0 to TRR included, then 0
-        *      again and so on.  It counts thus actually TRR + 1 steps
-        *      for 1 tick, not TRR.  So if you want n cycles,
-        *      initialize TRR with n - 1.
-        */
-       __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR));
-       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
-
-       mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);
-       clocksource_register(&mcftmr_clk);
-
-       setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
-
-#ifdef CONFIG_HIGHPROFILE
-       coldfire_profile_init();
-#endif
-}
-
-/***************************************************************************/
-#ifdef CONFIG_HIGHPROFILE
-/***************************************************************************/
-
-/*
- *     By default use timer2 as the profiler clock timer.
- */
-#define        PA(a)   (MCFTIMER_BASE2 + (a))
-
-/*
- *     Choose a reasonably fast profile timer. Make it an odd value to
- *     try and get good coverage of kernel operations.
- */
-#define        PROFILEHZ       1013
-
-/*
- *     Use the other timer to provide high accuracy profiling info.
- */
-irqreturn_t coldfire_profile_tick(int irq, void *dummy)
-{
-       /* Reset ColdFire timer2 */
-       __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER));
-       if (current->pid)
-               profile_tick(CPU_PROFILING);
-       return IRQ_HANDLED;
-}
-
-/***************************************************************************/
-
-static struct irqaction coldfire_profile_irq = {
-       .name    = "profile timer",
-       .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = coldfire_profile_tick,
-};
-
-void coldfire_profile_init(void)
-{
-       printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n",
-              PROFILEHZ);
-
-       /* Set up TIMER 2 as high speed profile clock */
-       __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR));
-
-       __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR));
-       __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
-               MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR));
-
-       setup_irq(MCF_IRQ_PROFILER, &coldfire_profile_irq);
-}
-
-/***************************************************************************/
-#endif /* CONFIG_HIGHPROFILE */
-/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/vectors.c b/arch/m68knommu/platform/coldfire/vectors.c
deleted file mode 100644 (file)
index a21d3f8..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/***************************************************************************/
-
-/*
- *     linux/arch/m68knommu/platform/coldfire/vectors.c
- *
- *     Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
- */
-
-/***************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/traps.h>
-#include <asm/machdep.h>
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#include <asm/mcfwdebug.h>
-
-/***************************************************************************/
-
-#ifdef TRAP_DBG_INTERRUPT
-
-asmlinkage void dbginterrupt_c(struct frame *fp)
-{
-       extern void dump(struct pt_regs *fp);
-       printk(KERN_DEBUG "%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__);
-       dump((struct pt_regs *) fp);
-       asm("halt");
-}
-
-#endif
-
-/***************************************************************************/
-
-extern e_vector        *_ramvec;
-
-void set_evector(int vecnum, void (*handler)(void))
-{
-       if (vecnum >= 0 && vecnum <= 255)
-               _ramvec[vecnum] = handler;
-}
-
-/***************************************************************************/
-
-/* Assembler routines */
-asmlinkage void buserr(void);
-asmlinkage void trap(void);
-asmlinkage void system_call(void);
-asmlinkage void inthandler(void);
-
-void __init init_vectors(void)
-{
-       int i;
-
-       /*
-        *      There is a common trap handler and common interrupt
-        *      handler that handle almost every vector. We treat
-        *      the system call and bus error special, they get their
-        *      own first level handlers.
-        */
-       for (i = 3; (i <= 23); i++)
-               _ramvec[i] = trap;
-       for (i = 33; (i <= 63); i++)
-               _ramvec[i] = trap;
-       for (i = 24; (i <= 31); i++)
-               _ramvec[i] = inthandler;
-       for (i = 64; (i < 255); i++)
-               _ramvec[i] = inthandler;
-       _ramvec[255] = 0;
-
-       _ramvec[2] = buserr;
-       _ramvec[32] = system_call;
-
-#ifdef TRAP_DBG_INTERRUPT
-       _ramvec[12] = dbginterrupt;
-#endif
-}
-
-/***************************************************************************/
index 922c4194c7bb909c493716d1d48a4bceb8b714f9..5f0cf0e32653e30931b5039134ca339287f5c586 100644 (file)
@@ -37,6 +37,9 @@ config ARCH_HAS_ILOG2_U64
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
+config GENERIC_FIND_BIT_LE
+       def_bool y
+
 config GENERIC_HWEIGHT
        def_bool y
 
index 59cc7bceaf8c493d35ef426e9bafaad914dbf3ab..fceed4edea41966a4de1502b52d745b452966bbf 100644 (file)
@@ -6,7 +6,7 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_cache.o = -pg
 endif
 
-EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
+ccflags-y := -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
                -DCPU_REV=$(CPU_REV)
 
 obj-y += cache.o cpuinfo.o cpuinfo-pvr-full.o cpuinfo-static.o mb.o pvr.o
index d88983516e26118bff775f8d9c87f58e8163a88f..83aa5fb8e8f147e8f956ef462b22c79964ce0bd2 100644 (file)
@@ -22,6 +22,7 @@ config MIPS
        select HAVE_DMA_API_DEBUG
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
+       select GENERIC_IRQ_SHOW
        select HAVE_ARCH_JUMP_LABEL
 
 menu "Machine selection"
@@ -777,6 +778,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_HWEIGHT
        bool
        default y
@@ -858,6 +863,9 @@ config GPIO_TXX9
 config CFE
        bool
 
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool (HIGHMEM && 64BIT_PHYS_ADDR) || 64BIT
+
 config DMA_COHERENT
        bool
 
@@ -2340,6 +2348,16 @@ source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
 
+config RAPIDIO
+       bool "RapidIO support"
+       depends on PCI
+       default n
+       help
+         If you say Y here, the kernel will include drivers and
+         infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rapidio/Kconfig"
+
 endmenu
 
 menu "Executable file formats"
index 7c1102e41fe25b917dcce6566c0bf494ceef867e..ac1d5b611a27d2ea08d34cf983bbef5f94f1776e 100644 (file)
@@ -286,11 +286,11 @@ CLEAN_FILES += vmlinux.32 vmlinux.64
 archprepare:
 ifdef CONFIG_MIPS32_N32
        @echo '  Checking missing-syscalls for N32'
-       $(Q)$(MAKE) $(build)=. missing-syscalls EXTRA_CFLAGS="-mabi=n32"
+       $(Q)$(MAKE) $(build)=. missing-syscalls ccflags-y="-mabi=n32"
 endif
 ifdef CONFIG_MIPS32_O32
        @echo '  Checking missing-syscalls for O32'
-       $(Q)$(MAKE) $(build)=. missing-syscalls EXTRA_CFLAGS="-mabi=32"
+       $(Q)$(MAKE) $(build)=. missing-syscalls ccflags-y="-mabi=32"
 endif
 
 install:
index 9f78ada83b3cd4a00c2d61bdbf1de058429ad337..55dd7c8885175b6df9464dc5f8cd6792b2f38aab 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/mach-pb1x00/pb1000.h>
 #endif
 
-static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);
+static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
 
 /* NOTE on interrupt priorities: The original writers of this code said:
  *
@@ -218,17 +218,17 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = {
 };
 
 
-static void au1x_ic0_unmask(unsigned int irq_nr)
+static void au1x_ic0_unmask(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
        au_writel(1 << bit, IC0_MASKSET);
        au_writel(1 << bit, IC0_WAKESET);
        au_sync();
 }
 
-static void au1x_ic1_unmask(unsigned int irq_nr)
+static void au1x_ic1_unmask(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
        au_writel(1 << bit, IC1_MASKSET);
        au_writel(1 << bit, IC1_WAKESET);
 
@@ -236,31 +236,31 @@ static void au1x_ic1_unmask(unsigned int irq_nr)
  * nowhere in the current kernel sources is it disabled.       --mlau
  */
 #if defined(CONFIG_MIPS_PB1000)
-       if (irq_nr == AU1000_GPIO15_INT)
+       if (d->irq == AU1000_GPIO15_INT)
                au_writel(0x4000, PB1000_MDR); /* enable int */
 #endif
        au_sync();
 }
 
-static void au1x_ic0_mask(unsigned int irq_nr)
+static void au1x_ic0_mask(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
        au_writel(1 << bit, IC0_MASKCLR);
        au_writel(1 << bit, IC0_WAKECLR);
        au_sync();
 }
 
-static void au1x_ic1_mask(unsigned int irq_nr)
+static void au1x_ic1_mask(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
        au_writel(1 << bit, IC1_MASKCLR);
        au_writel(1 << bit, IC1_WAKECLR);
        au_sync();
 }
 
-static void au1x_ic0_ack(unsigned int irq_nr)
+static void au1x_ic0_ack(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
 
        /*
         * This may assume that we don't get interrupts from
@@ -271,9 +271,9 @@ static void au1x_ic0_ack(unsigned int irq_nr)
        au_sync();
 }
 
-static void au1x_ic1_ack(unsigned int irq_nr)
+static void au1x_ic1_ack(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
 
        /*
         * This may assume that we don't get interrupts from
@@ -284,9 +284,9 @@ static void au1x_ic1_ack(unsigned int irq_nr)
        au_sync();
 }
 
-static void au1x_ic0_maskack(unsigned int irq_nr)
+static void au1x_ic0_maskack(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
 
        au_writel(1 << bit, IC0_WAKECLR);
        au_writel(1 << bit, IC0_MASKCLR);
@@ -295,9 +295,9 @@ static void au1x_ic0_maskack(unsigned int irq_nr)
        au_sync();
 }
 
-static void au1x_ic1_maskack(unsigned int irq_nr)
+static void au1x_ic1_maskack(struct irq_data *d)
 {
-       unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE;
+       unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
 
        au_writel(1 << bit, IC1_WAKECLR);
        au_writel(1 << bit, IC1_MASKCLR);
@@ -306,9 +306,9 @@ static void au1x_ic1_maskack(unsigned int irq_nr)
        au_sync();
 }
 
-static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
+static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)
 {
-       int bit = irq - AU1000_INTC1_INT_BASE;
+       int bit = d->irq - AU1000_INTC1_INT_BASE;
        unsigned long wakemsk, flags;
 
        /* only GPIO 0-7 can act as wakeup source.  Fortunately these
@@ -336,28 +336,30 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
  */
 static struct irq_chip au1x_ic0_chip = {
        .name           = "Alchemy-IC0",
-       .ack            = au1x_ic0_ack,
-       .mask           = au1x_ic0_mask,
-       .mask_ack       = au1x_ic0_maskack,
-       .unmask         = au1x_ic0_unmask,
-       .set_type       = au1x_ic_settype,
+       .irq_ack        = au1x_ic0_ack,
+       .irq_mask       = au1x_ic0_mask,
+       .irq_mask_ack   = au1x_ic0_maskack,
+       .irq_unmask     = au1x_ic0_unmask,
+       .irq_set_type   = au1x_ic_settype,
 };
 
 static struct irq_chip au1x_ic1_chip = {
        .name           = "Alchemy-IC1",
-       .ack            = au1x_ic1_ack,
-       .mask           = au1x_ic1_mask,
-       .mask_ack       = au1x_ic1_maskack,
-       .unmask         = au1x_ic1_unmask,
-       .set_type       = au1x_ic_settype,
-       .set_wake       = au1x_ic1_setwake,
+       .irq_ack        = au1x_ic1_ack,
+       .irq_mask       = au1x_ic1_mask,
+       .irq_mask_ack   = au1x_ic1_maskack,
+       .irq_unmask     = au1x_ic1_unmask,
+       .irq_set_type   = au1x_ic_settype,
+       .irq_set_wake   = au1x_ic1_setwake,
 };
 
-static int au1x_ic_settype(unsigned int irq, unsigned int flow_type)
+static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)
 {
        struct irq_chip *chip;
        unsigned long icr[6];
-       unsigned int bit, ic;
+       unsigned int bit, ic, irq = d->irq;
+       irq_flow_handler_t handler = NULL;
+       unsigned char *name = NULL;
        int ret;
 
        if (irq >= AU1000_INTC1_INT_BASE) {
@@ -387,47 +389,47 @@ static int au1x_ic_settype(unsigned int irq, unsigned int flow_type)
                au_writel(1 << bit, icr[5]);
                au_writel(1 << bit, icr[4]);
                au_writel(1 << bit, icr[0]);
-               set_irq_chip_and_handler_name(irq, chip,
-                               handle_edge_irq, "riseedge");
+               handler = handle_edge_irq;
+               name = "riseedge";
                break;
        case IRQ_TYPE_EDGE_FALLING:     /* 0:1:0 */
                au_writel(1 << bit, icr[5]);
                au_writel(1 << bit, icr[1]);
                au_writel(1 << bit, icr[3]);
-               set_irq_chip_and_handler_name(irq, chip,
-                               handle_edge_irq, "falledge");
+               handler = handle_edge_irq;
+               name = "falledge";
                break;
        case IRQ_TYPE_EDGE_BOTH:        /* 0:1:1 */
                au_writel(1 << bit, icr[5]);
                au_writel(1 << bit, icr[1]);
                au_writel(1 << bit, icr[0]);
-               set_irq_chip_and_handler_name(irq, chip,
-                               handle_edge_irq, "bothedge");
+               handler = handle_edge_irq;
+               name = "bothedge";
                break;
        case IRQ_TYPE_LEVEL_HIGH:       /* 1:0:1 */
                au_writel(1 << bit, icr[2]);
                au_writel(1 << bit, icr[4]);
                au_writel(1 << bit, icr[0]);
-               set_irq_chip_and_handler_name(irq, chip,
-                               handle_level_irq, "hilevel");
+               handler = handle_level_irq;
+               name = "hilevel";
                break;
        case IRQ_TYPE_LEVEL_LOW:        /* 1:1:0 */
                au_writel(1 << bit, icr[2]);
                au_writel(1 << bit, icr[1]);
                au_writel(1 << bit, icr[3]);
-               set_irq_chip_and_handler_name(irq, chip,
-                               handle_level_irq, "lowlevel");
+               handler = handle_level_irq;
+               name = "lowlevel";
                break;
        case IRQ_TYPE_NONE:             /* 0:0:0 */
                au_writel(1 << bit, icr[5]);
                au_writel(1 << bit, icr[4]);
                au_writel(1 << bit, icr[3]);
-               /* set at least chip so we can call set_irq_type() on it */
-               set_irq_chip(irq, chip);
                break;
        default:
                ret = -EINVAL;
        }
+       __irq_set_chip_handler_name_locked(d->irq, chip, handler, name);
+
        au_sync();
 
        return ret;
@@ -504,11 +506,11 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
         */
        for (i = AU1000_INTC0_INT_BASE;
             (i < AU1000_INTC0_INT_BASE + 32); i++)
-               au1x_ic_settype(i, IRQ_TYPE_NONE);
+               au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
 
        for (i = AU1000_INTC1_INT_BASE;
             (i < AU1000_INTC1_INT_BASE + 32); i++)
-               au1x_ic_settype(i, IRQ_TYPE_NONE);
+               au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
 
        /*
         * Initialize IC0, which is fixed per processor.
@@ -526,7 +528,7 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
                                au_writel(1 << bit, IC0_ASSIGNSET);
                }
 
-               au1x_ic_settype(irq_nr, map->im_type);
+               au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type);
                ++map;
        }
 
index c52af8821da071f5fe49117ddb6f7f2652756c00..f91c43a7d5dc1ecf6d9a220704c9c0852d8c43b2 100644 (file)
@@ -97,26 +97,26 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
  * CPLD generates tons of spurious interrupts (at least on my DB1200).
  *     -- mlau
  */
-static void bcsr_irq_mask(unsigned int irq_nr)
+static void bcsr_irq_mask(struct irq_data *d)
 {
-       unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+       unsigned short v = 1 << (d->irq - bcsr_csc_base);
        __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
        wmb();
 }
 
-static void bcsr_irq_maskack(unsigned int irq_nr)
+static void bcsr_irq_maskack(struct irq_data *d)
 {
-       unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+       unsigned short v = 1 << (d->irq - bcsr_csc_base);
        __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
        __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);  /* ack */
        wmb();
 }
 
-static void bcsr_irq_unmask(unsigned int irq_nr)
+static void bcsr_irq_unmask(struct irq_data *d)
 {
-       unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+       unsigned short v = 1 << (d->irq - bcsr_csc_base);
        __raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
        __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
        wmb();
@@ -124,9 +124,9 @@ static void bcsr_irq_unmask(unsigned int irq_nr)
 
 static struct irq_chip bcsr_irq_type = {
        .name           = "CPLD",
-       .mask           = bcsr_irq_mask,
-       .mask_ack       = bcsr_irq_maskack,
-       .unmask         = bcsr_irq_unmask,
+       .irq_mask       = bcsr_irq_mask,
+       .irq_mask_ack   = bcsr_irq_maskack,
+       .irq_unmask     = bcsr_irq_unmask,
 };
 
 void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
index 4ec2642c568fb18ce58c6eb277f58b7fb55772d9..a6484b60642fc071465a0fe614220bc1808c654c 100644 (file)
 
 static int ar7_irq_base;
 
-static void ar7_unmask_irq(unsigned int irq)
+static void ar7_unmask_irq(struct irq_data *d)
 {
-       writel(1 << ((irq - ar7_irq_base) % 32),
-              REG(ESR_OFFSET(irq - ar7_irq_base)));
+       writel(1 << ((d->irq - ar7_irq_base) % 32),
+              REG(ESR_OFFSET(d->irq - ar7_irq_base)));
 }
 
-static void ar7_mask_irq(unsigned int irq)
+static void ar7_mask_irq(struct irq_data *d)
 {
-       writel(1 << ((irq - ar7_irq_base) % 32),
-              REG(ECR_OFFSET(irq - ar7_irq_base)));
+       writel(1 << ((d->irq - ar7_irq_base) % 32),
+              REG(ECR_OFFSET(d->irq - ar7_irq_base)));
 }
 
-static void ar7_ack_irq(unsigned int irq)
+static void ar7_ack_irq(struct irq_data *d)
 {
-       writel(1 << ((irq - ar7_irq_base) % 32),
-              REG(CR_OFFSET(irq - ar7_irq_base)));
+       writel(1 << ((d->irq - ar7_irq_base) % 32),
+              REG(CR_OFFSET(d->irq - ar7_irq_base)));
 }
 
-static void ar7_unmask_sec_irq(unsigned int irq)
+static void ar7_unmask_sec_irq(struct irq_data *d)
 {
-       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
+       writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
 }
 
-static void ar7_mask_sec_irq(unsigned int irq)
+static void ar7_mask_sec_irq(struct irq_data *d)
 {
-       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
+       writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
 }
 
-static void ar7_ack_sec_irq(unsigned int irq)
+static void ar7_ack_sec_irq(struct irq_data *d)
 {
-       writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
+       writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
 }
 
 static struct irq_chip ar7_irq_type = {
        .name = "AR7",
-       .unmask = ar7_unmask_irq,
-       .mask = ar7_mask_irq,
-       .ack = ar7_ack_irq
+       .irq_unmask = ar7_unmask_irq,
+       .irq_mask = ar7_mask_irq,
+       .irq_ack = ar7_ack_irq
 };
 
 static struct irq_chip ar7_sec_irq_type = {
        .name = "AR7",
-       .unmask = ar7_unmask_sec_irq,
-       .mask = ar7_mask_sec_irq,
-       .ack = ar7_ack_sec_irq,
+       .irq_unmask = ar7_unmask_sec_irq,
+       .irq_mask = ar7_mask_sec_irq,
+       .irq_ack = ar7_ack_sec_irq,
 };
 
 static struct irqaction ar7_cascade_action = {
index 1bf7f719ba532e4d5e1cb4d345c290afb334b049..7c02bc948a313077aac8fd354a0b2302c8f57169 100644 (file)
@@ -62,13 +62,12 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
                spurious_interrupt();
 }
 
-static void ar71xx_misc_irq_unmask(unsigned int irq)
+static void ar71xx_misc_irq_unmask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
        void __iomem *base = ath79_reset_base;
        u32 t;
 
-       irq -= ATH79_MISC_IRQ_BASE;
-
        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
        __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 
@@ -76,13 +75,12 @@ static void ar71xx_misc_irq_unmask(unsigned int irq)
        __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 }
 
-static void ar71xx_misc_irq_mask(unsigned int irq)
+static void ar71xx_misc_irq_mask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
        void __iomem *base = ath79_reset_base;
        u32 t;
 
-       irq -= ATH79_MISC_IRQ_BASE;
-
        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
        __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 
@@ -90,13 +88,12 @@ static void ar71xx_misc_irq_mask(unsigned int irq)
        __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
 }
 
-static void ar724x_misc_irq_ack(unsigned int irq)
+static void ar724x_misc_irq_ack(struct irq_data *d)
 {
+       unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE;
        void __iomem *base = ath79_reset_base;
        u32 t;
 
-       irq -= ATH79_MISC_IRQ_BASE;
-
        t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
        __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
 
@@ -106,8 +103,8 @@ static void ar724x_misc_irq_ack(unsigned int irq)
 
 static struct irq_chip ath79_misc_irq_chip = {
        .name           = "MISC",
-       .unmask         = ar71xx_misc_irq_unmask,
-       .mask           = ar71xx_misc_irq_mask,
+       .irq_unmask     = ar71xx_misc_irq_unmask,
+       .irq_mask       = ar71xx_misc_irq_mask,
 };
 
 static void __init ath79_misc_irq_init(void)
@@ -119,15 +116,14 @@ static void __init ath79_misc_irq_init(void)
        __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
 
        if (soc_is_ar71xx() || soc_is_ar913x())
-               ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
+               ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
        else if (soc_is_ar724x())
-               ath79_misc_irq_chip.ack = ar724x_misc_irq_ack;
+               ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
        else
                BUG();
 
        for (i = ATH79_MISC_IRQ_BASE;
             i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
                set_irq_chip_and_handler(i, &ath79_misc_irq_chip,
                                         handle_level_irq);
        }
index e5cc86dc1da83de4d2b09f6d134a81f1089bb1df..9f64fb41407743358f55a36377617613fb9a0383 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_BOARD_BCM963XX)           += board_bcm963xx.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index 3be87f2422f0357ddd16411c4fa0d406dc21cbe1..1691531aa34d405d166b946a8739637cf312ec7d 100644 (file)
@@ -76,88 +76,80 @@ asmlinkage void plat_irq_dispatch(void)
  * internal IRQs operations: only mask/unmask on PERF irq mask
  * register.
  */
-static inline void bcm63xx_internal_irq_mask(unsigned int irq)
+static inline void bcm63xx_internal_irq_mask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
        u32 mask;
 
-       irq -= IRQ_INTERNAL_BASE;
        mask = bcm_perf_readl(PERF_IRQMASK_REG);
        mask &= ~(1 << irq);
        bcm_perf_writel(mask, PERF_IRQMASK_REG);
 }
 
-static void bcm63xx_internal_irq_unmask(unsigned int irq)
+static void bcm63xx_internal_irq_unmask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - IRQ_INTERNAL_BASE;
        u32 mask;
 
-       irq -= IRQ_INTERNAL_BASE;
        mask = bcm_perf_readl(PERF_IRQMASK_REG);
        mask |= (1 << irq);
        bcm_perf_writel(mask, PERF_IRQMASK_REG);
 }
 
-static unsigned int bcm63xx_internal_irq_startup(unsigned int irq)
-{
-       bcm63xx_internal_irq_unmask(irq);
-       return 0;
-}
-
 /*
  * external IRQs operations: mask/unmask and clear on PERF external
  * irq control register.
  */
-static void bcm63xx_external_irq_mask(unsigned int irq)
+static void bcm63xx_external_irq_mask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - IRQ_EXT_BASE;
        u32 reg;
 
-       irq -= IRQ_EXT_BASE;
        reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
        reg &= ~EXTIRQ_CFG_MASK(irq);
        bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
 }
 
-static void bcm63xx_external_irq_unmask(unsigned int irq)
+static void bcm63xx_external_irq_unmask(struct irq_data *d)
 {
+       unsigned int irq = d->irq - IRQ_EXT_BASE;
        u32 reg;
 
-       irq -= IRQ_EXT_BASE;
        reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
        reg |= EXTIRQ_CFG_MASK(irq);
        bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
 }
 
-static void bcm63xx_external_irq_clear(unsigned int irq)
+static void bcm63xx_external_irq_clear(struct irq_data *d)
 {
+       unsigned int irq = d->irq - IRQ_EXT_BASE;
        u32 reg;
 
-       irq -= IRQ_EXT_BASE;
        reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
        reg |= EXTIRQ_CFG_CLEAR(irq);
        bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
 }
 
-static unsigned int bcm63xx_external_irq_startup(unsigned int irq)
+static unsigned int bcm63xx_external_irq_startup(struct irq_data *d)
 {
-       set_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
+       set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
        irq_enable_hazard();
-       bcm63xx_external_irq_unmask(irq);
+       bcm63xx_external_irq_unmask(d);
        return 0;
 }
 
-static void bcm63xx_external_irq_shutdown(unsigned int irq)
+static void bcm63xx_external_irq_shutdown(struct irq_data *d)
 {
-       bcm63xx_external_irq_mask(irq);
-       clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
+       bcm63xx_external_irq_mask(d);
+       clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE));
        irq_disable_hazard();
 }
 
-static int bcm63xx_external_irq_set_type(unsigned int irq,
+static int bcm63xx_external_irq_set_type(struct irq_data *d,
                                         unsigned int flow_type)
 {
+       unsigned int irq = d->irq - IRQ_EXT_BASE;
        u32 reg;
-       struct irq_desc *desc = irq_desc + irq;
-
-       irq -= IRQ_EXT_BASE;
 
        flow_type &= IRQ_TYPE_SENSE_MASK;
 
@@ -199,37 +191,32 @@ static int bcm63xx_external_irq_set_type(unsigned int irq,
        }
        bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
 
-       if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))  {
-               desc->status |= IRQ_LEVEL;
-               desc->handle_irq = handle_level_irq;
-       } else {
-               desc->handle_irq = handle_edge_irq;
-       }
+       irqd_set_trigger_type(d, flow_type);
+       if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+       else
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
 static struct irq_chip bcm63xx_internal_irq_chip = {
        .name           = "bcm63xx_ipic",
-       .startup        = bcm63xx_internal_irq_startup,
-       .shutdown       = bcm63xx_internal_irq_mask,
-
-       .mask           = bcm63xx_internal_irq_mask,
-       .mask_ack       = bcm63xx_internal_irq_mask,
-       .unmask         = bcm63xx_internal_irq_unmask,
+       .irq_mask       = bcm63xx_internal_irq_mask,
+       .irq_unmask     = bcm63xx_internal_irq_unmask,
 };
 
 static struct irq_chip bcm63xx_external_irq_chip = {
        .name           = "bcm63xx_epic",
-       .startup        = bcm63xx_external_irq_startup,
-       .shutdown       = bcm63xx_external_irq_shutdown,
+       .irq_startup    = bcm63xx_external_irq_startup,
+       .irq_shutdown   = bcm63xx_external_irq_shutdown,
 
-       .ack            = bcm63xx_external_irq_clear,
+       .irq_ack        = bcm63xx_external_irq_clear,
 
-       .mask           = bcm63xx_external_irq_mask,
-       .unmask         = bcm63xx_external_irq_unmask,
+       .irq_mask       = bcm63xx_external_irq_mask,
+       .irq_unmask     = bcm63xx_external_irq_unmask,
 
-       .set_type       = bcm63xx_external_irq_set_type,
+       .irq_set_type   = bcm63xx_external_irq_set_type,
 };
 
 static struct irqaction cpu_ip2_cascade_action = {
index cb41954fc321db609af7408922717588605be809..8d9a5fc607e48573f50efcd3eb9e9f2af0358756 100644 (file)
 #include <asm/dec/ioasic_addrs.h>
 #include <asm/dec/ioasic_ints.h>
 
-
 static int ioasic_irq_base;
 
-
-static inline void unmask_ioasic_irq(unsigned int irq)
+static void unmask_ioasic_irq(struct irq_data *d)
 {
        u32 simr;
 
        simr = ioasic_read(IO_REG_SIMR);
-       simr |= (1 << (irq - ioasic_irq_base));
+       simr |= (1 << (d->irq - ioasic_irq_base));
        ioasic_write(IO_REG_SIMR, simr);
 }
 
-static inline void mask_ioasic_irq(unsigned int irq)
+static void mask_ioasic_irq(struct irq_data *d)
 {
        u32 simr;
 
        simr = ioasic_read(IO_REG_SIMR);
-       simr &= ~(1 << (irq - ioasic_irq_base));
+       simr &= ~(1 << (d->irq - ioasic_irq_base));
        ioasic_write(IO_REG_SIMR, simr);
 }
 
-static inline void clear_ioasic_irq(unsigned int irq)
+static void ack_ioasic_irq(struct irq_data *d)
 {
-       u32 sir;
-
-       sir = ~(1 << (irq - ioasic_irq_base));
-       ioasic_write(IO_REG_SIR, sir);
-}
-
-static inline void ack_ioasic_irq(unsigned int irq)
-{
-       mask_ioasic_irq(irq);
+       mask_ioasic_irq(d);
        fast_iob();
 }
 
-static inline void end_ioasic_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               unmask_ioasic_irq(irq);
-}
-
 static struct irq_chip ioasic_irq_type = {
        .name = "IO-ASIC",
-       .ack = ack_ioasic_irq,
-       .mask = mask_ioasic_irq,
-       .mask_ack = ack_ioasic_irq,
-       .unmask = unmask_ioasic_irq,
+       .irq_ack = ack_ioasic_irq,
+       .irq_mask = mask_ioasic_irq,
+       .irq_mask_ack = ack_ioasic_irq,
+       .irq_unmask = unmask_ioasic_irq,
 };
 
-
-#define unmask_ioasic_dma_irq unmask_ioasic_irq
-
-#define mask_ioasic_dma_irq mask_ioasic_irq
-
-#define ack_ioasic_dma_irq ack_ioasic_irq
-
-static inline void end_ioasic_dma_irq(unsigned int irq)
-{
-       clear_ioasic_irq(irq);
-       fast_iob();
-       end_ioasic_irq(irq);
-}
-
 static struct irq_chip ioasic_dma_irq_type = {
        .name = "IO-ASIC-DMA",
-       .ack = ack_ioasic_dma_irq,
-       .mask = mask_ioasic_dma_irq,
-       .mask_ack = ack_ioasic_dma_irq,
-       .unmask = unmask_ioasic_dma_irq,
-       .end = end_ioasic_dma_irq,
+       .irq_ack = ack_ioasic_irq,
+       .irq_mask = mask_ioasic_irq,
+       .irq_mask_ack = ack_ioasic_irq,
+       .irq_unmask = unmask_ioasic_irq,
 };
 
-
 void __init init_ioasic_irqs(int base)
 {
        int i;
index ed90a8deabccf78d57c23eb956354fd2b205c262..ef31d98c4fb8dd01622505345b0fec9ced62b009 100644 (file)
  */
 u32 cached_kn02_csr;
 
-
 static int kn02_irq_base;
 
-
-static inline void unmask_kn02_irq(unsigned int irq)
+static void unmask_kn02_irq(struct irq_data *d)
 {
        volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
                                                       KN02_CSR);
 
-       cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16));
+       cached_kn02_csr |= (1 << (d->irq - kn02_irq_base + 16));
        *csr = cached_kn02_csr;
 }
 
-static inline void mask_kn02_irq(unsigned int irq)
+static void mask_kn02_irq(struct irq_data *d)
 {
        volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
                                                       KN02_CSR);
 
-       cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16));
+       cached_kn02_csr &= ~(1 << (d->irq - kn02_irq_base + 16));
        *csr = cached_kn02_csr;
 }
 
-static void ack_kn02_irq(unsigned int irq)
+static void ack_kn02_irq(struct irq_data *d)
 {
-       mask_kn02_irq(irq);
+       mask_kn02_irq(d);
        iob();
 }
 
 static struct irq_chip kn02_irq_type = {
        .name = "KN02-CSR",
-       .ack = ack_kn02_irq,
-       .mask = mask_kn02_irq,
-       .mask_ack = ack_kn02_irq,
-       .unmask = unmask_kn02_irq,
+       .irq_ack = ack_kn02_irq,
+       .irq_mask = mask_kn02_irq,
+       .irq_mask_ack = ack_kn02_irq,
+       .irq_unmask = unmask_kn02_irq,
 };
 
-
 void __init init_kn02_irqs(int base)
 {
        volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE +
index 3a96799eb65fec6b25b87e53fbf13b74c12464de..9b1207ae22560380a9f1837f02c1069cf8103a64 100644 (file)
 
 #include <asm/emma/emma2rh.h>
 
-static void emma2rh_irq_enable(unsigned int irq)
+static void emma2rh_irq_enable(struct irq_data *d)
 {
-       u32 reg_value;
-       u32 reg_bitmask;
-       u32 reg_index;
-
-       irq -= EMMA2RH_IRQ_BASE;
+       unsigned int irq = d->irq - EMMA2RH_IRQ_BASE;
+       u32 reg_value, reg_bitmask, reg_index;
 
        reg_index = EMMA2RH_BHIF_INT_EN_0 +
                    (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32);
@@ -49,13 +46,10 @@ static void emma2rh_irq_enable(unsigned int irq)
        emma2rh_out32(reg_index, reg_value | reg_bitmask);
 }
 
-static void emma2rh_irq_disable(unsigned int irq)
+static void emma2rh_irq_disable(struct irq_data *d)
 {
-       u32 reg_value;
-       u32 reg_bitmask;
-       u32 reg_index;
-
-       irq -= EMMA2RH_IRQ_BASE;
+       unsigned int irq = d->irq - EMMA2RH_IRQ_BASE;
+       u32 reg_value, reg_bitmask, reg_index;
 
        reg_index = EMMA2RH_BHIF_INT_EN_0 +
                    (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32);
@@ -66,10 +60,8 @@ static void emma2rh_irq_disable(unsigned int irq)
 
 struct irq_chip emma2rh_irq_controller = {
        .name = "emma2rh_irq",
-       .ack = emma2rh_irq_disable,
-       .mask = emma2rh_irq_disable,
-       .mask_ack = emma2rh_irq_disable,
-       .unmask = emma2rh_irq_enable,
+       .irq_mask = emma2rh_irq_disable,
+       .irq_unmask = emma2rh_irq_enable,
 };
 
 void emma2rh_irq_init(void)
@@ -82,23 +74,21 @@ void emma2rh_irq_init(void)
                                              handle_level_irq, "level");
 }
 
-static void emma2rh_sw_irq_enable(unsigned int irq)
+static void emma2rh_sw_irq_enable(struct irq_data *d)
 {
+       unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE;
        u32 reg;
 
-       irq -= EMMA2RH_SW_IRQ_BASE;
-
        reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN);
        reg |= 1 << irq;
        emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg);
 }
 
-static void emma2rh_sw_irq_disable(unsigned int irq)
+static void emma2rh_sw_irq_disable(struct irq_data *d)
 {
+       unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE;
        u32 reg;
 
-       irq -= EMMA2RH_SW_IRQ_BASE;
-
        reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN);
        reg &= ~(1 << irq);
        emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg);
@@ -106,10 +96,8 @@ static void emma2rh_sw_irq_disable(unsigned int irq)
 
 struct irq_chip emma2rh_sw_irq_controller = {
        .name = "emma2rh_sw_irq",
-       .ack = emma2rh_sw_irq_disable,
-       .mask = emma2rh_sw_irq_disable,
-       .mask_ack = emma2rh_sw_irq_disable,
-       .unmask = emma2rh_sw_irq_enable,
+       .irq_mask = emma2rh_sw_irq_disable,
+       .irq_unmask = emma2rh_sw_irq_enable,
 };
 
 void emma2rh_sw_irq_init(void)
@@ -122,39 +110,38 @@ void emma2rh_sw_irq_init(void)
                                              handle_level_irq, "level");
 }
 
-static void emma2rh_gpio_irq_enable(unsigned int irq)
+static void emma2rh_gpio_irq_enable(struct irq_data *d)
 {
+       unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE;
        u32 reg;
 
-       irq -= EMMA2RH_GPIO_IRQ_BASE;
-
        reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
        reg |= 1 << irq;
        emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg);
 }
 
-static void emma2rh_gpio_irq_disable(unsigned int irq)
+static void emma2rh_gpio_irq_disable(struct irq_data *d)
 {
+       unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE;
        u32 reg;
 
-       irq -= EMMA2RH_GPIO_IRQ_BASE;
-
        reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
        reg &= ~(1 << irq);
        emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg);
 }
 
-static void emma2rh_gpio_irq_ack(unsigned int irq)
+static void emma2rh_gpio_irq_ack(struct irq_data *d)
 {
-       irq -= EMMA2RH_GPIO_IRQ_BASE;
+       unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE;
+
        emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq));
 }
 
-static void emma2rh_gpio_irq_mask_ack(unsigned int irq)
+static void emma2rh_gpio_irq_mask_ack(struct irq_data *d)
 {
+       unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE;
        u32 reg;
 
-       irq -= EMMA2RH_GPIO_IRQ_BASE;
        emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq));
 
        reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
@@ -164,10 +151,10 @@ static void emma2rh_gpio_irq_mask_ack(unsigned int irq)
 
 struct irq_chip emma2rh_gpio_irq_controller = {
        .name = "emma2rh_gpio_irq",
-       .ack = emma2rh_gpio_irq_ack,
-       .mask = emma2rh_gpio_irq_disable,
-       .mask_ack = emma2rh_gpio_irq_mask_ack,
-       .unmask = emma2rh_gpio_irq_enable,
+       .irq_ack = emma2rh_gpio_irq_ack,
+       .irq_mask = emma2rh_gpio_irq_disable,
+       .irq_mask_ack = emma2rh_gpio_irq_mask_ack,
+       .irq_unmask = emma2rh_gpio_irq_enable,
 };
 
 void emma2rh_gpio_irq_init(void)
index e0aaad482b0ebc806e971101a4f701ff30d2848e..5314b37aff2c493a736eb438a47f03d33cba509f 100644 (file)
@@ -9,4 +9,4 @@ lib-$(CONFIG_ARC_MEMORY)        += memory.o
 lib-$(CONFIG_ARC_CONSOLE)      += arc_con.o
 lib-$(CONFIG_ARC_PROMLIB)      += promlib.o
 
-EXTRA_CFLAGS                   += -Werror
+ccflags-y                      := -Werror
index 50b4ef288c53f0be1a78d9de79e40e2337a3f76d..2e1ad4c652b72cf9042524870a19631f9e0566e0 100644 (file)
@@ -676,9 +676,8 @@ static inline int ffs(int word)
 #include <asm/arch_hweight.h>
 #include <asm-generic/bitops/const_hweight.h>
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
index b003ed52ed1725221ca6ac510251f46e7cb7d443..0ec01294b063c0cc323e49d45e4d4a46b6fc2a86 100644 (file)
@@ -55,9 +55,9 @@ static inline void smtc_im_ack_irq(unsigned int irq)
 #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
 #include <linux/cpumask.h>
 
-extern int plat_set_irq_affinity(unsigned int irq,
-                                 const struct cpumask *affinity);
-extern void smtc_forward_irq(unsigned int irq);
+extern int plat_set_irq_affinity(struct irq_data *d,
+                                const struct cpumask *affinity, bool force);
+extern void smtc_forward_irq(struct irq_data *d);
 
 /*
  * IRQ affinity hook invoked at the beginning of interrupt dispatch
@@ -70,51 +70,53 @@ extern void smtc_forward_irq(unsigned int irq);
  * cpumask implementations, this version is optimistically assuming
  * that cpumask.h macro overhead is reasonable during interrupt dispatch.
  */
-#define IRQ_AFFINITY_HOOK(irq)                                         \
-do {                                                                   \
-    if (!cpumask_test_cpu(smp_processor_id(), irq_desc[irq].affinity)) {\
-       smtc_forward_irq(irq);                                          \
-       irq_exit();                                                     \
-       return;                                                         \
-    }                                                                  \
-} while (0)
+static inline int handle_on_other_cpu(unsigned int irq)
+{
+       struct irq_data *d = irq_get_irq_data(irq);
+
+       if (cpumask_test_cpu(smp_processor_id(), d->affinity))
+               return 0;
+       smtc_forward_irq(d);
+       return 1;
+}
 
 #else /* Not doing SMTC affinity */
 
-#define IRQ_AFFINITY_HOOK(irq) do { } while (0)
+static inline int handle_on_other_cpu(unsigned int irq) { return 0; }
 
 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
 
 #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
 
+static inline void smtc_im_backstop(unsigned int irq)
+{
+       if (irq_hwmask[irq] & 0x0000ff00)
+               write_c0_tccontext(read_c0_tccontext() &
+                                  ~(irq_hwmask[irq] & 0x0000ff00));
+}
+
 /*
  * Clear interrupt mask handling "backstop" if irq_hwmask
  * entry so indicates. This implies that the ack() or end()
  * functions will take over re-enabling the low-level mask.
  * Otherwise it will be done on return from exception.
  */
-#define __DO_IRQ_SMTC_HOOK(irq)                                                \
-do {                                                                   \
-       IRQ_AFFINITY_HOOK(irq);                                         \
-       if (irq_hwmask[irq] & 0x0000ff00)                               \
-               write_c0_tccontext(read_c0_tccontext() &                \
-                                  ~(irq_hwmask[irq] & 0x0000ff00));    \
-} while (0)
-
-#define __NO_AFFINITY_IRQ_SMTC_HOOK(irq)                               \
-do {                                                                   \
-       if (irq_hwmask[irq] & 0x0000ff00)                               \
-               write_c0_tccontext(read_c0_tccontext() &                \
-                                  ~(irq_hwmask[irq] & 0x0000ff00));    \
-} while (0)
+static inline int smtc_handle_on_other_cpu(unsigned int irq)
+{
+       int ret = handle_on_other_cpu(irq);
+
+       if (!ret)
+               smtc_im_backstop(irq);
+       return ret;
+}
 
 #else
 
-#define __DO_IRQ_SMTC_HOOK(irq)                                                \
-do {                                                                   \
-       IRQ_AFFINITY_HOOK(irq);                                         \
-} while (0)
-#define __NO_AFFINITY_IRQ_SMTC_HOOK(irq) do { } while (0)
+static inline void smtc_im_backstop(unsigned int irq) { }
+static inline int smtc_handle_on_other_cpu(unsigned int irq)
+{
+       return handle_on_other_cpu(irq);
+}
 
 #endif
 
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h b/arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..a80801b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
+ */
+#ifndef __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_mips16         1
+#define cpu_has_dsp            1
+#define cpu_has_mipsmt         1
+#define cpu_has_fpu            0
+
+#define cpu_has_mips32r1       0
+#define cpu_has_mips32r2       1
+#define cpu_has_mips64r1       0
+#define cpu_has_mips64r2       0
+
+#endif /* __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h
new file mode 100644 (file)
index 0000000..156f320
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *
+ * Macros for external SMP-safe access to the PMC MSP71xx reference
+ * board GPIO pins
+ *
+ * Copyright 2010 PMC-Sierra, 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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT 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.
+ *
+ *  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 __MSP_GPIO_MACROS_H__
+#define __MSP_GPIO_MACROS_H__
+
+#include <msp_regops.h>
+#include <msp_regs.h>
+
+#ifdef CONFIG_PMC_MSP7120_GW
+#define MSP_NUM_GPIOS          20
+#else
+#define MSP_NUM_GPIOS          28
+#endif
+
+/* -- GPIO Enumerations -- */
+enum msp_gpio_data {
+       MSP_GPIO_LO = 0,
+       MSP_GPIO_HI = 1,
+       MSP_GPIO_NONE,          /* Special - Means pin is out of range */
+       MSP_GPIO_TOGGLE,        /* Special - Sets pin to opposite */
+};
+
+enum msp_gpio_mode {
+       MSP_GPIO_INPUT          = 0x0,
+       /* MSP_GPIO_ INTERRUPT  = 0x1,  Not supported yet */
+       MSP_GPIO_UART_INPUT     = 0x2,  /* Only GPIO 4 or 5 */
+       MSP_GPIO_OUTPUT         = 0x8,
+       MSP_GPIO_UART_OUTPUT    = 0x9,  /* Only GPIO 2 or 3 */
+       MSP_GPIO_PERIF_TIMERA   = 0x9,  /* Only GPIO 0 or 1 */
+       MSP_GPIO_PERIF_TIMERB   = 0xa,  /* Only GPIO 0 or 1 */
+       MSP_GPIO_UNKNOWN        = 0xb,  /* No such GPIO or mode */
+};
+
+/* -- Static Tables -- */
+
+/* Maps pins to data register */
+static volatile u32 * const MSP_GPIO_DATA_REGISTER[] = {
+       /* GPIO 0 and 1 on the first register */
+       GPIO_DATA1_REG, GPIO_DATA1_REG,
+       /* GPIO 2, 3, 4, and 5 on the second register */
+       GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG,
+       /* GPIO 6, 7, 8, and 9 on the third register */
+       GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG,
+       /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+       GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG,
+       GPIO_DATA4_REG, GPIO_DATA4_REG,
+       /* GPIO 16 - 23 on the first strange EXTENDED register */
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       /* GPIO 24 - 27 on the second strange EXTENDED register */
+       EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG,
+       EXTENDED_GPIO2_REG,
+};
+
+/* Maps pins to mode register */
+static volatile u32 * const MSP_GPIO_MODE_REGISTER[] = {
+       /* GPIO 0 and 1 on the first register */
+       GPIO_CFG1_REG, GPIO_CFG1_REG,
+       /* GPIO 2, 3, 4, and 5 on the second register */
+       GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG,
+       /* GPIO 6, 7, 8, and 9 on the third register */
+       GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG,
+       /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+       GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG,
+       GPIO_CFG4_REG, GPIO_CFG4_REG,
+       /* GPIO 16 - 23 on the first strange EXTENDED register */
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG,
+       /* GPIO 24 - 27 on the second strange EXTENDED register */
+       EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG,
+       EXTENDED_GPIO2_REG,
+};
+
+/* Maps 'basic' pins to relative offset from 0 per register */
+static int MSP_GPIO_OFFSET[] = {
+       /* GPIO 0 and 1 on the first register */
+       0, 0,
+       /* GPIO 2, 3, 4, and 5 on the second register */
+       2, 2, 2, 2,
+       /* GPIO 6, 7, 8, and 9 on the third register */
+       6, 6, 6, 6,
+       /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */
+       10, 10, 10, 10, 10, 10,
+};
+
+/* Maps MODE to allowed pin mask */
+static unsigned int MSP_GPIO_MODE_ALLOWED[] = {
+       0xffffffff,     /* Mode 0 - INPUT */
+       0x00000,        /* Mode 1 - INTERRUPT */
+       0x00030,        /* Mode 2 - UART_INPUT (GPIO 4, 5)*/
+       0, 0, 0, 0, 0,  /* Modes 3, 4, 5, 6, and 7 are reserved */
+       0xffffffff,     /* Mode 8 - OUTPUT */
+       0x0000f,        /* Mode 9 - UART_OUTPUT/
+                               PERF_TIMERA (GPIO 0, 1, 2, 3) */
+       0x00003,        /* Mode a - PERF_TIMERB (GPIO 0, 1) */
+       0x00000,        /* Mode b - Not really a mode! */
+};
+
+/* -- Bit masks -- */
+
+/* This gives you the 'register relative offset gpio' number */
+#define OFFSET_GPIO_NUMBER(gpio)       (gpio - MSP_GPIO_OFFSET[gpio])
+
+/* These take the 'register relative offset gpio' number */
+#define BASIC_DATA_REG_MASK(ogpio)             (1 << ogpio)
+#define BASIC_MODE_REG_VALUE(mode, ogpio)      \
+       (mode << BASIC_MODE_REG_SHIFT(ogpio))
+#define BASIC_MODE_REG_MASK(ogpio)             \
+       BASIC_MODE_REG_VALUE(0xf, ogpio)
+#define BASIC_MODE_REG_SHIFT(ogpio)            (ogpio * 4)
+#define BASIC_MODE_REG_FROM_REG(data, ogpio)   \
+       ((data & BASIC_MODE_REG_MASK(ogpio)) >> BASIC_MODE_REG_SHIFT(ogpio))
+
+/* These take the actual GPIO number (0 through 15) */
+#define BASIC_DATA_MASK(gpio)  \
+       BASIC_DATA_REG_MASK(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_MASK(gpio)  \
+       BASIC_MODE_REG_MASK(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE(mode, gpio) \
+       BASIC_MODE_REG_VALUE(mode, OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_SHIFT(gpio) \
+       BASIC_MODE_REG_SHIFT(OFFSET_GPIO_NUMBER(gpio))
+#define BASIC_MODE_FROM_REG(data, gpio)        \
+       BASIC_MODE_REG_FROM_REG(data, OFFSET_GPIO_NUMBER(gpio))
+
+/*
+ * Each extended GPIO register is 32 bits long and is responsible for up to
+ * eight GPIOs. The least significant 16 bits contain the set and clear bit
+ * pair for each of the GPIOs. The most significant 16 bits contain the
+ * disable and enable bit pair for each of the GPIOs. For example, the
+ * extended GPIO reg for GPIOs 16-23 is as follows:
+ *
+ *     31: GPIO23_DISABLE
+ *     ...
+ *     19: GPIO17_DISABLE
+ *     18: GPIO17_ENABLE
+ *     17: GPIO16_DISABLE
+ *     16: GPIO16_ENABLE
+ *     ...
+ *     3:  GPIO17_SET
+ *     2:  GPIO17_CLEAR
+ *     1:  GPIO16_SET
+ *     0:  GPIO16_CLEAR
+ */
+
+/* This gives the 'register relative offset gpio' number */
+#define EXTENDED_OFFSET_GPIO(gpio)     (gpio < 24 ? gpio - 16 : gpio - 24)
+
+/* These take the 'register relative offset gpio' number */
+#define EXTENDED_REG_DISABLE(ogpio)    (0x2 << ((ogpio * 2) + 16))
+#define EXTENDED_REG_ENABLE(ogpio)     (0x1 << ((ogpio * 2) + 16))
+#define EXTENDED_REG_SET(ogpio)                (0x2 << (ogpio * 2))
+#define EXTENDED_REG_CLR(ogpio)                (0x1 << (ogpio * 2))
+
+/* These take the actual GPIO number (16 through 27) */
+#define EXTENDED_DISABLE(gpio) \
+       EXTENDED_REG_DISABLE(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_ENABLE(gpio)  \
+       EXTENDED_REG_ENABLE(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_SET(gpio)     \
+       EXTENDED_REG_SET(EXTENDED_OFFSET_GPIO(gpio))
+#define EXTENDED_CLR(gpio)     \
+       EXTENDED_REG_CLR(EXTENDED_OFFSET_GPIO(gpio))
+
+#define EXTENDED_FULL_MASK             (0xffffffff)
+
+/* -- API inline-functions -- */
+
+/*
+ * Gets the current value of the specified pin
+ */
+static inline enum msp_gpio_data msp_gpio_pin_get(unsigned int gpio)
+{
+       u32 pinhi_mask = 0, pinhi_mask2 = 0;
+
+       if (gpio >= MSP_NUM_GPIOS)
+               return MSP_GPIO_NONE;
+
+       if (gpio < 16) {
+               pinhi_mask = BASIC_DATA_MASK(gpio);
+       } else {
+               /*
+                * Two cases are possible with the EXTENDED register:
+                *  - In output mode (ENABLED flag set), check the CLR bit
+                *  - In input mode (ENABLED flag not set), check the SET bit
+                */
+               pinhi_mask = EXTENDED_ENABLE(gpio) | EXTENDED_CLR(gpio);
+               pinhi_mask2 = EXTENDED_SET(gpio);
+       }
+       if (((*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask) == pinhi_mask) ||
+           (*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask2))
+               return MSP_GPIO_HI;
+       else
+               return MSP_GPIO_LO;
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_set(enum msp_gpio_data data, unsigned int gpio)
+{
+       if (gpio >= MSP_NUM_GPIOS)
+               return;
+
+       if (gpio < 16) {
+               if (data == MSP_GPIO_TOGGLE)
+                       toggle_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                       BASIC_DATA_MASK(gpio));
+               else if (data == MSP_GPIO_HI)
+                       set_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                       BASIC_DATA_MASK(gpio));
+               else
+                       clear_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                       BASIC_DATA_MASK(gpio));
+       } else {
+               if (data == MSP_GPIO_TOGGLE) {
+                       /* Special ugly case:
+                        *   We have to read the CLR bit.
+                        *   If set, we write the CLR bit.
+                        *   If not, we write the SET bit.
+                        */
+                       u32 tmpdata;
+
+                       custom_read_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                                               tmpdata);
+                       if (tmpdata & EXTENDED_CLR(gpio))
+                               tmpdata = EXTENDED_CLR(gpio);
+                       else
+                               tmpdata = EXTENDED_SET(gpio);
+                       custom_write_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                                               tmpdata);
+               } else {
+                       u32 newdata;
+
+                       if (data == MSP_GPIO_HI)
+                               newdata = EXTENDED_SET(gpio);
+                       else
+                               newdata = EXTENDED_CLR(gpio);
+                       set_value_reg32(MSP_GPIO_DATA_REGISTER[gpio],
+                                               EXTENDED_FULL_MASK, newdata);
+               }
+       }
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_hi(unsigned int gpio)
+{
+       msp_gpio_pin_set(MSP_GPIO_HI, gpio);
+}
+
+/* Sets the specified pin to the specified value */
+static inline void msp_gpio_pin_lo(unsigned int gpio)
+{
+       msp_gpio_pin_set(MSP_GPIO_LO, gpio);
+}
+
+/* Sets the specified pin to the opposite value */
+static inline void msp_gpio_pin_toggle(unsigned int gpio)
+{
+       msp_gpio_pin_set(MSP_GPIO_TOGGLE, gpio);
+}
+
+/* Gets the mode of the specified pin */
+static inline enum msp_gpio_mode msp_gpio_pin_get_mode(unsigned int gpio)
+{
+       enum msp_gpio_mode retval = MSP_GPIO_UNKNOWN;
+       uint32_t data;
+
+       if (gpio >= MSP_NUM_GPIOS)
+               return retval;
+
+       data = *MSP_GPIO_MODE_REGISTER[gpio];
+
+       if (gpio < 16) {
+               retval = BASIC_MODE_FROM_REG(data, gpio);
+       } else {
+               /* Extended pins can only be either INPUT or OUTPUT */
+               if (data & EXTENDED_ENABLE(gpio))
+                       retval = MSP_GPIO_OUTPUT;
+               else
+                       retval = MSP_GPIO_INPUT;
+       }
+
+       return retval;
+}
+
+/*
+ * Sets the specified mode on the requested pin
+ * Returns 0 on success, or -1 if that mode is not allowed on this pin
+ */
+static inline int msp_gpio_pin_mode(enum msp_gpio_mode mode, unsigned int gpio)
+{
+       u32 modemask, newmode;
+
+       if ((1 << gpio) & ~MSP_GPIO_MODE_ALLOWED[mode])
+               return -1;
+
+       if (gpio >= MSP_NUM_GPIOS)
+               return -1;
+
+       if (gpio < 16) {
+               modemask = BASIC_MODE_MASK(gpio);
+               newmode =  BASIC_MODE(mode, gpio);
+       } else {
+               modemask = EXTENDED_FULL_MASK;
+               if (mode == MSP_GPIO_INPUT)
+                       newmode = EXTENDED_DISABLE(gpio);
+               else
+                       newmode = EXTENDED_ENABLE(gpio);
+       }
+       /* Do the set atomically */
+       set_value_reg32(MSP_GPIO_MODE_REGISTER[gpio], modemask, newmode);
+
+       return 0;
+}
+
+#endif /* __MSP_GPIO_MACROS_H__ */
index 603eb737b4a8fecf63a58b73537b181c751eb398..692c1b658b92b0a7ea8e24c0329d074d9f2da447 100644 (file)
                                        /* MAC C device registers       */
 #define MSP_ADSL2_BASE         (MSP_MSB_BASE + 0xA80000)
                                        /* ADSL2 device registers       */
-#define MSP_USB_BASE           (MSP_MSB_BASE + 0xB40000)
-                                       /* USB device registers         */
-#define MSP_USB_BASE_START     (MSP_MSB_BASE + 0xB40100)
-                                       /* USB device registers         */
-#define MSP_USB_BASE_END       (MSP_MSB_BASE + 0xB401FF)
-                                       /* USB device registers         */
+#define MSP_USB0_BASE          (MSP_MSB_BASE + 0xB00000)
+                                       /* USB0 device registers        */
+#define MSP_USB1_BASE          (MSP_MSB_BASE + 0x300000)
+                                       /* USB1 device registers        */
 #define MSP_CPUIF_BASE         (MSP_MSB_BASE + 0xC00000)
                                        /* CPU interface registers      */
 
 #define CPU_ERR2_REG           regptr(MSP_SLP_BASE + 0x184)
                                        /* CPU/SLP Error status 1       */
 
-#define EXTENDED_GPIO_REG      regptr(MSP_SLP_BASE + 0x188)
-                                       /* Extended GPIO register       */
+/* Extended GPIO registers       */
+#define EXTENDED_GPIO1_REG     regptr(MSP_SLP_BASE + 0x188)
+#define EXTENDED_GPIO2_REG     regptr(MSP_SLP_BASE + 0x18c)
+#define EXTENDED_GPIO_REG      EXTENDED_GPIO1_REG
+                                       /* Backward-compatibility       */
 
 /* System Error registers */
 #define SLP_ERR_STS_REG                regptr(MSP_SLP_BASE + 0x190)
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h
new file mode 100644 (file)
index 0000000..4c9348d
--- /dev/null
@@ -0,0 +1,144 @@
+/******************************************************************
+ * Copyright (c) 2000-2007 PMC-Sierra 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.
+ *
+ *     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.
+ *
+ * PMC-SIERRA INC. DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS
+ * SOFTWARE.
+ */
+#ifndef MSP_USB_H_
+#define MSP_USB_H_
+
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+#define NUM_USB_DEVS   2
+#else
+#define NUM_USB_DEVS   1
+#endif
+
+/* Register spaces for USB host 0 */
+#define MSP_USB0_MAB_START     (MSP_USB0_BASE + 0x0)
+#define MSP_USB0_MAB_END       (MSP_USB0_BASE + 0x17)
+#define MSP_USB0_ID_START      (MSP_USB0_BASE + 0x40000)
+#define MSP_USB0_ID_END                (MSP_USB0_BASE + 0x4008f)
+#define MSP_USB0_HS_START      (MSP_USB0_BASE + 0x40100)
+#define MSP_USB0_HS_END                (MSP_USB0_BASE + 0x401FF)
+
+/* Register spaces for USB host 1 */
+#define        MSP_USB1_MAB_START      (MSP_USB1_BASE + 0x0)
+#define MSP_USB1_MAB_END       (MSP_USB1_BASE + 0x17)
+#define MSP_USB1_ID_START      (MSP_USB1_BASE + 0x40000)
+#define MSP_USB1_ID_END                (MSP_USB1_BASE + 0x4008f)
+#define MSP_USB1_HS_START      (MSP_USB1_BASE + 0x40100)
+#define MSP_USB1_HS_END                (MSP_USB1_BASE + 0x401ff)
+
+/* USB Identification registers */
+struct msp_usbid_regs {
+       u32 id;         /* 0x0: Identification register */
+       u32 hwgen;      /* 0x4: General HW params */
+       u32 hwhost;     /* 0x8: Host HW params */
+       u32 hwdev;      /* 0xc: Device HW params */
+       u32 hwtxbuf;    /* 0x10: Tx buffer HW params */
+       u32 hwrxbuf;    /* 0x14: Rx buffer HW params */
+       u32 reserved[26];
+       u32 timer0_load; /* 0x80: General-purpose timer 0 load*/
+       u32 timer0_ctrl; /* 0x84: General-purpose timer 0 control */
+       u32 timer1_load; /* 0x88: General-purpose timer 1 load*/
+       u32 timer1_ctrl; /* 0x8c: General-purpose timer 1 control */
+};
+
+/* MSBus to AMBA registers */
+struct msp_mab_regs {
+       u32 isr;        /* 0x0: Interrupt status */
+       u32 imr;        /* 0x4: Interrupt mask */
+       u32 thcr0;      /* 0x8: Transaction header capture 0 */
+       u32 thcr1;      /* 0xc: Transaction header capture 1 */
+       u32 int_stat;   /* 0x10: Interrupt status summary */
+       u32 phy_cfg;    /* 0x14: USB phy config */
+};
+
+/* EHCI registers */
+struct msp_usbhs_regs {
+       u32 hciver;     /* 0x0: Version and offset to operational regs */
+       u32 hcsparams;  /* 0x4: Host control structural parameters */
+       u32 hccparams;  /* 0x8: Host control capability parameters */
+       u32 reserved0[5];
+       u32 dciver;     /* 0x20: Device interface version */
+       u32 dccparams;  /* 0x24: Device control capability parameters */
+       u32 reserved1[6];
+       u32 cmd;        /* 0x40: USB command */
+       u32 sts;        /* 0x44: USB status */
+       u32 int_ena;    /* 0x48: USB interrupt enable */
+       u32 frindex;    /* 0x4c: Frame index */
+       u32 reserved3;
+       union {
+               struct {
+                       u32 flb_addr; /* 0x54: Frame list base address */
+                       u32 next_async_addr; /* 0x58: next asynchronous addr */
+                       u32 ttctrl; /* 0x5c: embedded transaction translator
+                                                       async buffer status */
+                       u32 burst_size; /* 0x60: Controller burst size */
+                       u32 tx_fifo_ctrl; /* 0x64: Tx latency FIFO tuning */
+                       u32 reserved0[4];
+                       u32 endpt_nak; /* 0x78: Endpoint NAK */
+                       u32 endpt_nak_ena; /* 0x7c: Endpoint NAK enable */
+                       u32 cfg_flag; /* 0x80: Config flag */
+                       u32 port_sc1; /* 0x84: Port status & control 1 */
+                       u32 reserved1[7];
+                       u32 otgsc;      /* 0xa4: OTG status & control */
+                       u32 mode;       /* 0xa8: USB controller mode */
+               } host;
+
+               struct {
+                       u32 dev_addr; /* 0x54: Device address */
+                       u32 endpt_list_addr; /* 0x58: Endpoint list address */
+                       u32 reserved0[7];
+                       u32 endpt_nak;  /* 0x74 */
+                       u32 endpt_nak_ctrl; /* 0x78 */
+                       u32 cfg_flag; /* 0x80 */
+                       u32 port_sc1; /* 0x84: Port status & control 1 */
+                       u32 reserved[7];
+                       u32 otgsc;      /* 0xa4: OTG status & control */
+                       u32 mode;       /* 0xa8: USB controller mode */
+                       u32 endpt_setup_stat; /* 0xac */
+                       u32 endpt_prime; /* 0xb0 */
+                       u32 endpt_flush; /* 0xb4 */
+                       u32 endpt_stat; /* 0xb8 */
+                       u32 endpt_complete; /* 0xbc */
+                       u32 endpt_ctrl0; /* 0xc0 */
+                       u32 endpt_ctrl1; /* 0xc4 */
+                       u32 endpt_ctrl2; /* 0xc8 */
+                       u32 endpt_ctrl3; /* 0xcc */
+               } device;
+       } u;
+};
+/*
+ * Container for the more-generic platform_device.
+ * This exists mainly as a way to map the non-standard register
+ * spaces and make them accessible to the USB ISR.
+ */
+struct mspusb_device {
+       struct msp_mab_regs   __iomem *mab_regs;
+       struct msp_usbid_regs __iomem *usbid_regs;
+       struct msp_usbhs_regs __iomem *usbhs_regs;
+       struct platform_device dev;
+};
+
+#define to_mspusb_device(x) container_of((x), struct mspusb_device, dev)
+#define TO_HOST_ID(x) ((x) & 0x3)
+#endif /*MSP_USB_H_*/
index 396e402fbe2c2915c4313fcd92e70881bfc8c985..ca61e846ab0f479406531a0996e14c623505705e 100644 (file)
@@ -245,16 +245,16 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # arch_read_lock        \n"
                "1:     ll      %1, %2                                  \n"
-               "       bltz    %1, 2f                                  \n"
+               "       bltz    %1, 3f                                  \n"
                "        addu   %1, 1                                   \n"
-               "       sc      %1, %0                                  \n"
+               "2:     sc      %1, %0                                  \n"
                "       beqz    %1, 1b                                  \n"
                "        nop                                            \n"
                "       .subsection 2                                   \n"
-               "2:     ll      %1, %2                                  \n"
-               "       bltz    %1, 2b                                  \n"
+               "3:     ll      %1, %2                                  \n"
+               "       bltz    %1, 3b                                  \n"
                "        addu   %1, 1                                   \n"
-               "       b       1b                                      \n"
+               "       b       2b                                      \n"
                "        nop                                            \n"
                "       .previous                                       \n"
                "       .set    reorder                                 \n"
@@ -324,16 +324,16 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # arch_write_lock       \n"
                "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 2f                                  \n"
+               "       bnez    %1, 3f                                  \n"
                "        lui    %1, 0x8000                              \n"
-               "       sc      %1, %0                                  \n"
-               "       beqz    %1, 2f                                  \n"
+               "2:     sc      %1, %0                                  \n"
+               "       beqz    %1, 3f                                  \n"
                "        nop                                            \n"
                "       .subsection 2                                   \n"
-               "2:     ll      %1, %2                                  \n"
-               "       bnez    %1, 2b                                  \n"
+               "3:     ll      %1, %2                                  \n"
+               "       bnez    %1, 3b                                  \n"
                "        lui    %1, 0x8000                              \n"
-               "       b       1b                                      \n"
+               "       b       2b                                      \n"
                "        nop                                            \n"
                "       .previous                                       \n"
                "       .set    reorder                                 \n"
index d309556cacf8ac9348f8068b99197673f570b772..d71160de4d10f19fc73e54d0a0a18dd442ecb44f 100644 (file)
@@ -88,9 +88,11 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) kzalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node) \
+               kzalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node) \
+               kmalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #endif
 
 #define free_thread_info(info) kfree(info)
index 544a2854598f0d6558269beb298fe839e161ea08..533812b6188181ecea4503450e8eae5677ae920d 100644 (file)
@@ -33,14 +33,6 @@ typedef unsigned short umode_t;
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-#if (defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) \
-    || defined(CONFIG_64BIT)
-typedef u64 dma_addr_t;
-#else
-typedef u32 dma_addr_t;
-#endif
-typedef u64 dma64_addr_t;
-
 /*
  * Don't use phys_t.  You've been warned.
  */
index 550725b881d5edec666a5b32bbe1200164ac7fd8..dae22c1d2c8287f2ce2b4ed24f8a0c98eaad0f15 100644 (file)
 #define __NR_fanotify_init             (__NR_Linux + 336)
 #define __NR_fanotify_mark             (__NR_Linux + 337)
 #define __NR_prlimit64                 (__NR_Linux + 338)
+#define __NR_name_to_handle_at         (__NR_Linux + 339)
+#define __NR_open_by_handle_at         (__NR_Linux + 340)
+#define __NR_clock_adjtime             (__NR_Linux + 341)
+#define __NR_syncfs                    (__NR_Linux + 342)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            338
+#define __NR_Linux_syscalls            342
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                338
+#define __NR_O32_Linux_syscalls                342
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_fanotify_init             (__NR_Linux + 295)
 #define __NR_fanotify_mark             (__NR_Linux + 296)
 #define __NR_prlimit64                 (__NR_Linux + 297)
+#define __NR_name_to_handle_at         (__NR_Linux + 298)
+#define __NR_open_by_handle_at         (__NR_Linux + 299)
+#define __NR_clock_adjtime             (__NR_Linux + 300)
+#define __NR_syncfs                    (__NR_Linux + 301)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            297
+#define __NR_Linux_syscalls            301
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         297
+#define __NR_64_Linux_syscalls         301
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_fanotify_init             (__NR_Linux + 300)
 #define __NR_fanotify_mark             (__NR_Linux + 301)
 #define __NR_prlimit64                 (__NR_Linux + 302)
+#define __NR_name_to_handle_at         (__NR_Linux + 303)
+#define __NR_open_by_handle_at         (__NR_Linux + 304)
+#define __NR_clock_adjtime             (__NR_Linux + 305)
+#define __NR_clock_adjtime             (__NR_Linux + 306)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            302
+#define __NR_Linux_syscalls            306
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                302
+#define __NR_N32_Linux_syscalls                306
 
 #ifdef __KERNEL__
 
index 35b3e2f0af04899ee159d59129203e445cfb6e49..40f7c6b1e26030d1a1a886f9c763c2b442410e01 100644 (file)
@@ -23,9 +23,9 @@
 
 static DEFINE_RAW_SPINLOCK(r4030_lock);
 
-static void enable_r4030_irq(unsigned int irq)
+static void enable_r4030_irq(struct irq_data *d)
 {
-       unsigned int mask = 1 << (irq - JAZZ_IRQ_START);
+       unsigned int mask = 1 << (d->irq - JAZZ_IRQ_START);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&r4030_lock, flags);
@@ -34,9 +34,9 @@ static void enable_r4030_irq(unsigned int irq)
        raw_spin_unlock_irqrestore(&r4030_lock, flags);
 }
 
-void disable_r4030_irq(unsigned int irq)
+void disable_r4030_irq(struct irq_data *d)
 {
-       unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START));
+       unsigned int mask = ~(1 << (d->irq - JAZZ_IRQ_START));
        unsigned long flags;
 
        raw_spin_lock_irqsave(&r4030_lock, flags);
@@ -47,10 +47,8 @@ void disable_r4030_irq(unsigned int irq)
 
 static struct irq_chip r4030_irq_type = {
        .name = "R4030",
-       .ack = disable_r4030_irq,
-       .mask = disable_r4030_irq,
-       .mask_ack = disable_r4030_irq,
-       .unmask = enable_r4030_irq,
+       .irq_mask = disable_r4030_irq,
+       .irq_unmask = enable_r4030_irq,
 };
 
 void __init init_r4030_ints(void)
index a604eaeb6c08533616839485b6f8fc89a032ed2b..a9dff33212518d752b8620a969a79da3935543d1 100644 (file)
@@ -17,4 +17,4 @@ obj-$(CONFIG_JZ4740_QI_LB60)  += board-qi_lb60.o
 
 obj-$(CONFIG_PM) += pm.o
 
-EXTRA_CFLAGS += -Werror -Wall
+ccflags-y := -Werror -Wall
index 2c0e107966ad944d6a936bc96b1a27a5c26f29f1..bc18daaa8f84ea092257fa893328c75a8d08bc80 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/spi/spi_gpio.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
+#include <linux/power/gpio-charger.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
 #include <asm/mach-jz4740/jz4740_mmc.h>
@@ -49,14 +50,14 @@ static bool is_avt2;
 
 /* NAND */
 static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
-/*     .eccbytes = 36,
+       .eccbytes = 36,
        .eccpos = {
                6,  7,  8,  9,  10, 11, 12, 13,
                14, 15, 16, 17, 18, 19, 20, 21,
                22, 23, 24, 25, 26, 27, 28, 29,
                30, 31, 32, 33, 34, 35, 36, 37,
                38, 39, 40, 41
-       },*/
+       },
        .oobfree = {
                { .offset = 2, .length = 4 },
                { .offset = 42, .length = 22 }
@@ -85,7 +86,7 @@ static struct mtd_partition qi_lb60_partitions_1gb[] = {
 };
 
 static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
-/*     .eccbytes = 72,
+       .eccbytes = 72,
        .eccpos = {
                12, 13, 14, 15, 16, 17, 18, 19,
                20, 21, 22, 23, 24, 25, 26, 27,
@@ -96,7 +97,7 @@ static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
                60, 61, 62, 63, 64, 65, 66, 67,
                68, 69, 70, 71, 72, 73, 74, 75,
                76, 77, 78, 79, 80, 81, 82, 83
-       },*/
+       },
        .oobfree = {
                { .offset = 2, .length = 10 },
                { .offset = 84, .length = 44 },
@@ -396,6 +397,28 @@ static struct platform_device qi_lb60_pwm_beeper = {
        },
 };
 
+/* charger */
+static char *qi_lb60_batteries[] = {
+       "battery",
+};
+
+static struct gpio_charger_platform_data qi_lb60_charger_pdata = {
+       .name = "usb",
+       .type = POWER_SUPPLY_TYPE_USB,
+       .gpio = JZ_GPIO_PORTD(28),
+       .gpio_active_low = 1,
+       .supplied_to = qi_lb60_batteries,
+       .num_supplicants = ARRAY_SIZE(qi_lb60_batteries),
+};
+
+static struct platform_device qi_lb60_charger_device = {
+       .name = "gpio-charger",
+       .dev = {
+               .platform_data = &qi_lb60_charger_pdata,
+       },
+};
+
+
 static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_udc_device,
        &jz4740_mmc_device,
@@ -410,6 +433,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_adc_device,
        &qi_lb60_gpio_keys,
        &qi_lb60_pwm_beeper,
+       &qi_lb60_charger_device,
 };
 
 static void __init board_gpio_setup(void)
index 88e6aeda5bf1ebac3ffdc99176e7e51bde0a6478..bd2fc29b95e0920ed73e34d1f1de0b1ca09f236f 100644 (file)
@@ -86,7 +86,6 @@ struct jz_gpio_chip {
        spinlock_t lock;
 
        struct gpio_chip gpio_chip;
-       struct irq_chip irq_chip;
        struct sys_device sysdev;
 };
 
@@ -102,9 +101,9 @@ static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *g
        return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip);
 }
 
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(unsigned int irq)
+static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
 {
-       return get_irq_chip_data(irq);
+       return irq_data_get_irq_chip_data(data);
 }
 
 static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
@@ -325,62 +324,52 @@ static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
        generic_handle_irq(gpio_irq);
 };
 
-static inline void jz_gpio_set_irq_bit(unsigned int irq, unsigned int reg)
+static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
 {
-       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
-       writel(IRQ_TO_BIT(irq), chip->base + reg);
+       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
+       writel(IRQ_TO_BIT(data->irq), chip->base + reg);
 }
 
-static void jz_gpio_irq_mask(unsigned int irq)
+static void jz_gpio_irq_mask(struct irq_data *data)
 {
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_SET);
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_SET);
 };
 
-static void jz_gpio_irq_unmask(unsigned int irq)
+static void jz_gpio_irq_unmask(struct irq_data *data)
 {
-       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
 
-       jz_gpio_check_trigger_both(chip, irq);
+       jz_gpio_check_trigger_both(chip, data->irq);
 
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_CLEAR);
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_CLEAR);
 };
 
 /* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(unsigned int irq)
+static unsigned int jz_gpio_irq_startup(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_SET);
-
-       desc->status &= ~IRQ_MASKED;
-       jz_gpio_irq_unmask(irq);
-
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
+       jz_gpio_irq_unmask(data);
        return 0;
 }
 
-static void jz_gpio_irq_shutdown(unsigned int irq)
+static void jz_gpio_irq_shutdown(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       jz_gpio_irq_mask(irq);
-       desc->status |= IRQ_MASKED;
+       jz_gpio_irq_mask(data);
 
        /* Set direction to input */
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_CLEAR);
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
 }
 
-static void jz_gpio_irq_ack(unsigned int irq)
+static void jz_gpio_irq_ack(struct irq_data *data)
 {
-       jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_FLAG_CLEAR);
+       jz_gpio_set_irq_bit(data, JZ_REG_GPIO_FLAG_CLEAR);
 };
 
-static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
 {
-       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       jz_gpio_irq_mask(irq);
+       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
+       unsigned int irq = data->irq;
 
        if (flow_type == IRQ_TYPE_EDGE_BOTH) {
                uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
@@ -395,45 +384,54 @@ static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
 
        switch (flow_type) {
        case IRQ_TYPE_EDGE_RISING:
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
                break;
        case IRQ_TYPE_LEVEL_HIGH:
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
-               jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
+               jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
                break;
        default:
                return -EINVAL;
        }
 
-       if (!(desc->status & IRQ_MASKED))
-               jz_gpio_irq_unmask(irq);
-
        return 0;
 }
 
-static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
 {
-       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
+       struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
        spin_lock(&chip->lock);
        if (on)
-               chip->wakeup |= IRQ_TO_BIT(irq);
+               chip->wakeup |= IRQ_TO_BIT(data->irq);
        else
-               chip->wakeup &= ~IRQ_TO_BIT(irq);
+               chip->wakeup &= ~IRQ_TO_BIT(data->irq);
        spin_unlock(&chip->lock);
 
        set_irq_wake(chip->irq, on);
        return 0;
 }
 
+static struct irq_chip jz_gpio_irq_chip = {
+       .name = "GPIO",
+       .irq_mask = jz_gpio_irq_mask,
+       .irq_unmask = jz_gpio_irq_unmask,
+       .irq_ack = jz_gpio_irq_ack,
+       .irq_startup = jz_gpio_irq_startup,
+       .irq_shutdown = jz_gpio_irq_shutdown,
+       .irq_set_type = jz_gpio_irq_set_type,
+       .irq_set_wake = jz_gpio_irq_set_wake,
+       .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
 /*
  * This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
@@ -452,16 +450,6 @@ static struct lock_class_key gpio_lock_class;
                .base = JZ4740_GPIO_BASE_ ## _bank, \
                .ngpio = JZ4740_GPIO_NUM_ ## _bank, \
        }, \
-       .irq_chip =  { \
-               .name = "GPIO Bank " # _bank, \
-               .mask = jz_gpio_irq_mask, \
-               .unmask = jz_gpio_irq_unmask, \
-               .ack = jz_gpio_irq_ack, \
-               .startup = jz_gpio_irq_startup, \
-               .shutdown = jz_gpio_irq_shutdown, \
-               .set_type = jz_gpio_irq_set_type, \
-               .set_wake = jz_gpio_irq_set_wake, \
-       }, \
 }
 
 static struct jz_gpio_chip jz4740_gpio_chips[] = {
@@ -526,9 +514,10 @@ static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
        set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
 
        for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) {
-               lockdep_set_class(&irq_desc[irq].lock, &gpio_lock_class);
+               irq_set_lockdep_class(irq, &gpio_lock_class);
                set_irq_chip_data(irq, chip);
-               set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
+               set_irq_chip_and_handler(irq, &jz_gpio_irq_chip,
+                       handle_level_irq);
        }
 
        return 0;
index 7d33ff83580f17efb307a46b4169b4ab663e2c32..dcc5593a9389ba7552c5de926cabf3cd74221145 100644 (file)
@@ -43,32 +43,37 @@ static uint32_t jz_intc_saved;
 
 #define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE)
 
-static void intc_irq_unmask(unsigned int irq)
+static inline unsigned long intc_irq_bit(struct irq_data *data)
 {
-       writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
+       return (unsigned long)irq_data_get_irq_chip_data(data);
 }
 
-static void intc_irq_mask(unsigned int irq)
+static void intc_irq_unmask(struct irq_data *data)
 {
-       writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK);
+       writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
 }
 
-static int intc_irq_set_wake(unsigned int irq, unsigned int on)
+static void intc_irq_mask(struct irq_data *data)
+{
+       writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_SET_MASK);
+}
+
+static int intc_irq_set_wake(struct irq_data *data, unsigned int on)
 {
        if (on)
-               jz_intc_wakeup |= IRQ_BIT(irq);
+               jz_intc_wakeup |= intc_irq_bit(data);
        else
-               jz_intc_wakeup &= ~IRQ_BIT(irq);
+               jz_intc_wakeup &= ~intc_irq_bit(data);
 
        return 0;
 }
 
 static struct irq_chip intc_irq_type = {
        .name =         "INTC",
-       .mask =         intc_irq_mask,
-       .mask_ack =     intc_irq_mask,
-       .unmask =       intc_irq_unmask,
-       .set_wake =     intc_irq_set_wake,
+       .irq_mask =     intc_irq_mask,
+       .irq_mask_ack = intc_irq_mask,
+       .irq_unmask =   intc_irq_unmask,
+       .irq_set_wake = intc_irq_set_wake,
 };
 
 static irqreturn_t jz4740_cascade(int irq, void *data)
@@ -95,8 +100,11 @@ void __init arch_init_irq(void)
 
        jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
 
+       /* Mask all irqs */
+       writel(0xffffffff, jz_intc_base + JZ_REG_INTC_SET_MASK);
+
        for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) {
-               intc_irq_mask(i);
+               set_irq_chip_data(i, (void *)IRQ_BIT(i));
                set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
        }
 
index c58176cc796baa0c03d6d86597ab5252478f4e65..e221662bb80cc1def1c5f35df77b93d2f2ea8b13 100644 (file)
 
 static int i8259A_auto_eoi = -1;
 DEFINE_RAW_SPINLOCK(i8259A_lock);
-static void disable_8259A_irq(unsigned int irq);
-static void enable_8259A_irq(unsigned int irq);
-static void mask_and_ack_8259A(unsigned int irq);
+static void disable_8259A_irq(struct irq_data *d);
+static void enable_8259A_irq(struct irq_data *d);
+static void mask_and_ack_8259A(struct irq_data *d);
 static void init_8259A(int auto_eoi);
 
 static struct irq_chip i8259A_chip = {
-       .name           = "XT-PIC",
-       .mask           = disable_8259A_irq,
-       .disable        = disable_8259A_irq,
-       .unmask         = enable_8259A_irq,
-       .mask_ack       = mask_and_ack_8259A,
+       .name                   = "XT-PIC",
+       .irq_mask               = disable_8259A_irq,
+       .irq_disable            = disable_8259A_irq,
+       .irq_unmask             = enable_8259A_irq,
+       .irq_mask_ack           = mask_and_ack_8259A,
 #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
-       .set_affinity   = plat_set_irq_affinity,
+       .irq_set_affinity       = plat_set_irq_affinity,
 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
 };
 
@@ -59,12 +59,11 @@ static unsigned int cached_irq_mask = 0xffff;
 #define cached_master_mask     (cached_irq_mask)
 #define cached_slave_mask      (cached_irq_mask >> 8)
 
-static void disable_8259A_irq(unsigned int irq)
+static void disable_8259A_irq(struct irq_data *d)
 {
-       unsigned int mask;
+       unsigned int mask, irq = d->irq - I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= I8259A_IRQ_BASE;
        mask = 1 << irq;
        raw_spin_lock_irqsave(&i8259A_lock, flags);
        cached_irq_mask |= mask;
@@ -75,12 +74,11 @@ static void disable_8259A_irq(unsigned int irq)
        raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
-static void enable_8259A_irq(unsigned int irq)
+static void enable_8259A_irq(struct irq_data *d)
 {
-       unsigned int mask;
+       unsigned int mask, irq = d->irq - I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= I8259A_IRQ_BASE;
        mask = ~(1 << irq);
        raw_spin_lock_irqsave(&i8259A_lock, flags);
        cached_irq_mask &= mask;
@@ -145,12 +143,11 @@ static inline int i8259A_irq_real(unsigned int irq)
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-static void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(struct irq_data *d)
 {
-       unsigned int irqmask;
+       unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= I8259A_IRQ_BASE;
        irqmask = 1 << irq;
        raw_spin_lock_irqsave(&i8259A_lock, flags);
        /*
@@ -290,9 +287,9 @@ static void init_8259A(int auto_eoi)
                 * In AEOI mode we just have to mask the interrupt
                 * when acking.
                 */
-               i8259A_chip.mask_ack = disable_8259A_irq;
+               i8259A_chip.irq_mask_ack = disable_8259A_irq;
        else
-               i8259A_chip.mask_ack = mask_and_ack_8259A;
+               i8259A_chip.irq_mask_ack = mask_and_ack_8259A;
 
        udelay(100);            /* wait for 8259A to initialize */
 
index 1774271af848b7cca4dc2ab2da0578c7f38a6e13..43cd9628251a5e3c4d74fabb1607dee24f619c8e 100644 (file)
@@ -87,17 +87,10 @@ unsigned int gic_get_int(void)
        return i;
 }
 
-static unsigned int gic_irq_startup(unsigned int irq)
+static void gic_irq_ack(struct irq_data *d)
 {
-       irq -= _irqbase;
-       pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
-       GIC_SET_INTR_MASK(irq);
-       return 0;
-}
+       unsigned int irq = d->irq - _irqbase;
 
-static void gic_irq_ack(unsigned int irq)
-{
-       irq -= _irqbase;
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        GIC_CLR_INTR_MASK(irq);
 
@@ -105,16 +98,16 @@ static void gic_irq_ack(unsigned int irq)
                GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
 }
 
-static void gic_mask_irq(unsigned int irq)
+static void gic_mask_irq(struct irq_data *d)
 {
-       irq -= _irqbase;
+       unsigned int irq = d->irq - _irqbase;
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        GIC_CLR_INTR_MASK(irq);
 }
 
-static void gic_unmask_irq(unsigned int irq)
+static void gic_unmask_irq(struct irq_data *d)
 {
-       irq -= _irqbase;
+       unsigned int irq = d->irq - _irqbase;
        pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
        GIC_SET_INTR_MASK(irq);
 }
@@ -123,13 +116,14 @@ static void gic_unmask_irq(unsigned int irq)
 
 static DEFINE_SPINLOCK(gic_lock);
 
-static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
+                           bool force)
 {
+       unsigned int irq = d->irq - _irqbase;
        cpumask_t       tmp = CPU_MASK_NONE;
        unsigned long   flags;
        int             i;
 
-       irq -= _irqbase;
        pr_debug("%s(%d) called\n", __func__, irq);
        cpumask_and(&tmp, cpumask, cpu_online_mask);
        if (cpus_empty(tmp))
@@ -147,23 +141,22 @@ static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
                set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
 
        }
-       cpumask_copy(irq_desc[irq].affinity, cpumask);
+       cpumask_copy(d->affinity, cpumask);
        spin_unlock_irqrestore(&gic_lock, flags);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 #endif
 
 static struct irq_chip gic_irq_controller = {
-       .name           =       "MIPS GIC",
-       .startup        =       gic_irq_startup,
-       .ack            =       gic_irq_ack,
-       .mask           =       gic_mask_irq,
-       .mask_ack       =       gic_mask_irq,
-       .unmask         =       gic_unmask_irq,
-       .eoi            =       gic_unmask_irq,
+       .name                   =       "MIPS GIC",
+       .irq_ack                =       gic_irq_ack,
+       .irq_mask               =       gic_mask_irq,
+       .irq_mask_ack           =       gic_mask_irq,
+       .irq_unmask             =       gic_unmask_irq,
+       .irq_eoi                =       gic_unmask_irq,
 #ifdef CONFIG_SMP
-       .set_affinity   =       gic_set_affinity,
+       .irq_set_affinity       =       gic_set_affinity,
 #endif
 };
 
index 42ef81461bfc2ee5c7354b4858fdcff005de7d61..7fd176fa367ac32cee4ead24da2aaffd50689290 100644 (file)
 
 static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock);
 
-static void ack_gt641xx_irq(unsigned int irq)
+static void ack_gt641xx_irq(struct irq_data *d)
 {
        unsigned long flags;
        u32 cause;
 
        raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
        cause = GT_READ(GT_INTRCAUSE_OFS);
-       cause &= ~GT641XX_IRQ_TO_BIT(irq);
+       cause &= ~GT641XX_IRQ_TO_BIT(d->irq);
        GT_WRITE(GT_INTRCAUSE_OFS, cause);
        raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
 }
 
-static void mask_gt641xx_irq(unsigned int irq)
+static void mask_gt641xx_irq(struct irq_data *d)
 {
        unsigned long flags;
        u32 mask;
 
        raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
        mask = GT_READ(GT_INTRMASK_OFS);
-       mask &= ~GT641XX_IRQ_TO_BIT(irq);
+       mask &= ~GT641XX_IRQ_TO_BIT(d->irq);
        GT_WRITE(GT_INTRMASK_OFS, mask);
        raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
 }
 
-static void mask_ack_gt641xx_irq(unsigned int irq)
+static void mask_ack_gt641xx_irq(struct irq_data *d)
 {
        unsigned long flags;
        u32 cause, mask;
 
        raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
        mask = GT_READ(GT_INTRMASK_OFS);
-       mask &= ~GT641XX_IRQ_TO_BIT(irq);
+       mask &= ~GT641XX_IRQ_TO_BIT(d->irq);
        GT_WRITE(GT_INTRMASK_OFS, mask);
 
        cause = GT_READ(GT_INTRCAUSE_OFS);
-       cause &= ~GT641XX_IRQ_TO_BIT(irq);
+       cause &= ~GT641XX_IRQ_TO_BIT(d->irq);
        GT_WRITE(GT_INTRCAUSE_OFS, cause);
        raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
 }
 
-static void unmask_gt641xx_irq(unsigned int irq)
+static void unmask_gt641xx_irq(struct irq_data *d)
 {
        unsigned long flags;
        u32 mask;
 
        raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
        mask = GT_READ(GT_INTRMASK_OFS);
-       mask |= GT641XX_IRQ_TO_BIT(irq);
+       mask |= GT641XX_IRQ_TO_BIT(d->irq);
        GT_WRITE(GT_INTRMASK_OFS, mask);
        raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
 }
 
 static struct irq_chip gt641xx_irq_chip = {
        .name           = "GT641xx",
-       .ack            = ack_gt641xx_irq,
-       .mask           = mask_gt641xx_irq,
-       .mask_ack       = mask_ack_gt641xx_irq,
-       .unmask         = unmask_gt641xx_irq,
+       .irq_ack        = ack_gt641xx_irq,
+       .irq_mask       = mask_gt641xx_irq,
+       .irq_mask_ack   = mask_ack_gt641xx_irq,
+       .irq_unmask     = unmask_gt641xx_irq,
 };
 
 void gt641xx_irq_dispatch(void)
index 6a8cd28133d5cf02727102199232a8f7e71134ae..fc800cd9947e648e996ec1a93bbbe4424ba2688a 100644 (file)
@@ -28,8 +28,10 @@ static unsigned long _icctrl_msc;
 static unsigned int irq_base;
 
 /* mask off an interrupt */
-static inline void mask_msc_irq(unsigned int irq)
+static inline void mask_msc_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < (irq_base + 32))
                MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base));
        else
@@ -37,8 +39,10 @@ static inline void mask_msc_irq(unsigned int irq)
 }
 
 /* unmask an interrupt */
-static inline void unmask_msc_irq(unsigned int irq)
+static inline void unmask_msc_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < (irq_base + 32))
                MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base));
        else
@@ -48,9 +52,11 @@ static inline void unmask_msc_irq(unsigned int irq)
 /*
  * Masks and ACKs an IRQ
  */
-static void level_mask_and_ack_msc_irq(unsigned int irq)
+static void level_mask_and_ack_msc_irq(struct irq_data *d)
 {
-       mask_msc_irq(irq);
+       unsigned int irq = d->irq;
+
+       mask_msc_irq(d);
        if (!cpu_has_veic)
                MSCIC_WRITE(MSC01_IC_EOI, 0);
        /* This actually needs to be a call into platform code */
@@ -60,9 +66,11 @@ static void level_mask_and_ack_msc_irq(unsigned int irq)
 /*
  * Masks and ACKs an IRQ
  */
-static void edge_mask_and_ack_msc_irq(unsigned int irq)
+static void edge_mask_and_ack_msc_irq(struct irq_data *d)
 {
-       mask_msc_irq(irq);
+       unsigned int irq = d->irq;
+
+       mask_msc_irq(d);
        if (!cpu_has_veic)
                MSCIC_WRITE(MSC01_IC_EOI, 0);
        else {
@@ -74,15 +82,6 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq)
        smtc_im_ack_irq(irq);
 }
 
-/*
- * End IRQ processing
- */
-static void end_msc_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               unmask_msc_irq(irq);
-}
-
 /*
  * Interrupt handler for interrupts coming from SOC-it.
  */
@@ -107,22 +106,20 @@ static void msc_bind_eic_interrupt(int irq, int set)
 
 static struct irq_chip msc_levelirq_type = {
        .name = "SOC-it-Level",
-       .ack = level_mask_and_ack_msc_irq,
-       .mask = mask_msc_irq,
-       .mask_ack = level_mask_and_ack_msc_irq,
-       .unmask = unmask_msc_irq,
-       .eoi = unmask_msc_irq,
-       .end = end_msc_irq,
+       .irq_ack = level_mask_and_ack_msc_irq,
+       .irq_mask = mask_msc_irq,
+       .irq_mask_ack = level_mask_and_ack_msc_irq,
+       .irq_unmask = unmask_msc_irq,
+       .irq_eoi = unmask_msc_irq,
 };
 
 static struct irq_chip msc_edgeirq_type = {
        .name = "SOC-it-Edge",
-       .ack = edge_mask_and_ack_msc_irq,
-       .mask = mask_msc_irq,
-       .mask_ack = edge_mask_and_ack_msc_irq,
-       .unmask = unmask_msc_irq,
-       .eoi = unmask_msc_irq,
-       .end = end_msc_irq,
+       .irq_ack = edge_mask_and_ack_msc_irq,
+       .irq_mask = mask_msc_irq,
+       .irq_mask_ack = edge_mask_and_ack_msc_irq,
+       .irq_unmask = unmask_msc_irq,
+       .irq_eoi = unmask_msc_irq,
 };
 
 
index 9731e8b47862f221124b8ed84df2a66a8c704cd5..fd24fd98b0410f70a83abe77a766014a4d963b87 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static inline void unmask_rm7k_irq(unsigned int irq)
+static inline void unmask_rm7k_irq(struct irq_data *d)
 {
-       set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
+       set_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE));
 }
 
-static inline void mask_rm7k_irq(unsigned int irq)
+static inline void mask_rm7k_irq(struct irq_data *d)
 {
-       clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
+       clear_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE));
 }
 
 static struct irq_chip rm7k_irq_controller = {
        .name = "RM7000",
-       .ack = mask_rm7k_irq,
-       .mask = mask_rm7k_irq,
-       .mask_ack = mask_rm7k_irq,
-       .unmask = unmask_rm7k_irq,
-       .eoi    = unmask_rm7k_irq
+       .irq_ack = mask_rm7k_irq,
+       .irq_mask = mask_rm7k_irq,
+       .irq_mask_ack = mask_rm7k_irq,
+       .irq_unmask = unmask_rm7k_irq,
+       .irq_eoi = unmask_rm7k_irq
 };
 
 void __init rm7k_cpu_irq_init(void)
index b7e4025b58a83d940080154b3edb76f3807c9e09..ca463ec9bad522260b6613626c33dbcab7aaff22 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static inline void unmask_rm9k_irq(unsigned int irq)
+static inline void unmask_rm9k_irq(struct irq_data *d)
 {
-       set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
+       set_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE));
 }
 
-static inline void mask_rm9k_irq(unsigned int irq)
+static inline void mask_rm9k_irq(struct irq_data *d)
 {
-       clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
+       clear_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE));
 }
 
-static inline void rm9k_cpu_irq_enable(unsigned int irq)
+static inline void rm9k_cpu_irq_enable(struct irq_data *d)
 {
        unsigned long flags;
 
        local_irq_save(flags);
-       unmask_rm9k_irq(irq);
+       unmask_rm9k_irq(d);
        local_irq_restore(flags);
 }
 
@@ -43,50 +43,47 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq)
  */
 static void local_rm9k_perfcounter_irq_startup(void *args)
 {
-       unsigned int irq = (unsigned int) args;
-
-       rm9k_cpu_irq_enable(irq);
+       rm9k_cpu_irq_enable(args);
 }
 
-static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq)
+static unsigned int rm9k_perfcounter_irq_startup(struct irq_data *d)
 {
-       on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 1);
+       on_each_cpu(local_rm9k_perfcounter_irq_startup, d, 1);
 
        return 0;
 }
 
 static void local_rm9k_perfcounter_irq_shutdown(void *args)
 {
-       unsigned int irq = (unsigned int) args;
        unsigned long flags;
 
        local_irq_save(flags);
-       mask_rm9k_irq(irq);
+       mask_rm9k_irq(args);
        local_irq_restore(flags);
 }
 
-static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
+static void rm9k_perfcounter_irq_shutdown(struct irq_data *d)
 {
-       on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 1);
+       on_each_cpu(local_rm9k_perfcounter_irq_shutdown, d, 1);
 }
 
 static struct irq_chip rm9k_irq_controller = {
        .name = "RM9000",
-       .ack = mask_rm9k_irq,
-       .mask = mask_rm9k_irq,
-       .mask_ack = mask_rm9k_irq,
-       .unmask = unmask_rm9k_irq,
-       .eoi    = unmask_rm9k_irq
+       .irq_ack = mask_rm9k_irq,
+       .irq_mask = mask_rm9k_irq,
+       .irq_mask_ack = mask_rm9k_irq,
+       .irq_unmask = unmask_rm9k_irq,
+       .irq_eoi = unmask_rm9k_irq
 };
 
 static struct irq_chip rm9k_perfcounter_irq = {
        .name = "RM9000",
-       .startup = rm9k_perfcounter_irq_startup,
-       .shutdown = rm9k_perfcounter_irq_shutdown,
-       .ack = mask_rm9k_irq,
-       .mask = mask_rm9k_irq,
-       .mask_ack = mask_rm9k_irq,
-       .unmask = unmask_rm9k_irq,
+       .irq_startup = rm9k_perfcounter_irq_startup,
+       .irq_shutdown = rm9k_perfcounter_irq_shutdown,
+       .irq_ack = mask_rm9k_irq,
+       .irq_mask = mask_rm9k_irq,
+       .irq_mask_ack = mask_rm9k_irq,
+       .irq_unmask = unmask_rm9k_irq,
 };
 
 unsigned int rm9000_perfcount_irq;
index 4f93db58a79ed9bdbecb1ba53c0c3eed9261d2e6..1b68ebe1b4583f42052d470626cc4250262219b8 100644 (file)
@@ -81,48 +81,9 @@ void ack_bad_irq(unsigned int irq)
 
 atomic_t irq_err_count;
 
-/*
- * Generic, controller-independent functions:
- */
-
-int show_interrupts(struct seq_file *p, void *v)
+int arch_show_interrupts(struct seq_file *p, int prec)
 {
-       int i = *(loff_t *) v, j;
-       struct irqaction * action;
-       unsigned long flags;
-
-       if (i == 0) {
-               seq_printf(p, "           ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ", j);
-               seq_putc(p, '\n');
-       }
-
-       if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
-               if (!action)
-                       goto skip;
-               seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
-               seq_printf(p, "  %s", action->name);
-
-               for (action=action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-
-               seq_putc(p, '\n');
-skip:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-       } else if (i == NR_IRQS) {
-               seq_putc(p, '\n');
-               seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-       }
+       seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
        return 0;
 }
 
@@ -183,8 +144,8 @@ void __irq_entry do_IRQ(unsigned int irq)
 {
        irq_enter();
        check_stack_overflow();
-       __DO_IRQ_SMTC_HOOK(irq);
-       generic_handle_irq(irq);
+       if (!smtc_handle_on_other_cpu(irq))
+               generic_handle_irq(irq);
        irq_exit();
 }
 
@@ -197,7 +158,7 @@ void __irq_entry do_IRQ(unsigned int irq)
 void __irq_entry do_IRQ_no_affinity(unsigned int irq)
 {
        irq_enter();
-       __NO_AFFINITY_IRQ_SMTC_HOOK(irq);
+       smtc_im_backstop(irq);
        generic_handle_irq(irq);
        irq_exit();
 }
index 0262abe09121954b47e40a2b0b4c6f21ff1feb37..fd945c56bc33edd5aae2b1e04cb1b2064c1b1d0f 100644 (file)
 #include <asm/mipsmtregs.h>
 #include <asm/system.h>
 
-static inline void unmask_mips_irq(unsigned int irq)
+static inline void unmask_mips_irq(struct irq_data *d)
 {
-       set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
+       set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
        irq_enable_hazard();
 }
 
-static inline void mask_mips_irq(unsigned int irq)
+static inline void mask_mips_irq(struct irq_data *d)
 {
-       clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
+       clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
        irq_disable_hazard();
 }
 
 static struct irq_chip mips_cpu_irq_controller = {
        .name           = "MIPS",
-       .ack            = mask_mips_irq,
-       .mask           = mask_mips_irq,
-       .mask_ack       = mask_mips_irq,
-       .unmask         = unmask_mips_irq,
-       .eoi            = unmask_mips_irq,
+       .irq_ack        = mask_mips_irq,
+       .irq_mask       = mask_mips_irq,
+       .irq_mask_ack   = mask_mips_irq,
+       .irq_unmask     = unmask_mips_irq,
+       .irq_eoi        = unmask_mips_irq,
 };
 
 /*
  * Basically the same as above but taking care of all the MT stuff
  */
 
-#define unmask_mips_mt_irq     unmask_mips_irq
-#define mask_mips_mt_irq       mask_mips_irq
-
-static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
+static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d)
 {
        unsigned int vpflags = dvpe();
 
-       clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
+       clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
        evpe(vpflags);
-       unmask_mips_mt_irq(irq);
-
+       unmask_mips_irq(d);
        return 0;
 }
 
@@ -80,22 +76,22 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
  * While we ack the interrupt interrupts are disabled and thus we don't need
  * to deal with concurrency issues.  Same for mips_cpu_irq_end.
  */
-static void mips_mt_cpu_irq_ack(unsigned int irq)
+static void mips_mt_cpu_irq_ack(struct irq_data *d)
 {
        unsigned int vpflags = dvpe();
-       clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
+       clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE));
        evpe(vpflags);
-       mask_mips_mt_irq(irq);
+       mask_mips_irq(d);
 }
 
 static struct irq_chip mips_mt_cpu_irq_controller = {
        .name           = "MIPS",
-       .startup        = mips_mt_cpu_irq_startup,
-       .ack            = mips_mt_cpu_irq_ack,
-       .mask           = mask_mips_mt_irq,
-       .mask_ack       = mips_mt_cpu_irq_ack,
-       .unmask         = unmask_mips_mt_irq,
-       .eoi            = unmask_mips_mt_irq,
+       .irq_startup    = mips_mt_cpu_irq_startup,
+       .irq_ack        = mips_mt_cpu_irq_ack,
+       .irq_mask       = mask_mips_irq,
+       .irq_mask_ack   = mips_mt_cpu_irq_ack,
+       .irq_unmask     = unmask_mips_irq,
+       .irq_eoi        = unmask_mips_irq,
 };
 
 void __init mips_cpu_irq_init(void)
index 95a96f69172d6d111a492e120c2af18adc364196..526e1581549a53c2216bca5445e8f3602cb5fb81 100644 (file)
@@ -63,9 +63,9 @@ static struct {
        unsigned char mode;
 } txx9irq[TXx9_MAX_IR] __read_mostly;
 
-static void txx9_irq_unmask(unsigned int irq)
+static void txx9_irq_unmask(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2];
        int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
 
@@ -79,9 +79,9 @@ static void txx9_irq_unmask(unsigned int irq)
 #endif
 }
 
-static inline void txx9_irq_mask(unsigned int irq)
+static inline void txx9_irq_mask(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2];
        int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8;
 
@@ -99,19 +99,19 @@ static inline void txx9_irq_mask(unsigned int irq)
 #endif
 }
 
-static void txx9_irq_mask_ack(unsigned int irq)
+static void txx9_irq_mask_ack(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
 
-       txx9_irq_mask(irq);
+       txx9_irq_mask(d);
        /* clear edge detection */
        if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode)))
                __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr);
 }
 
-static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int txx9_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 cr;
        u32 __iomem *crp;
        int ofs;
@@ -139,11 +139,11 @@ static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type)
 
 static struct irq_chip txx9_irq_chip = {
        .name           = "TXX9",
-       .ack            = txx9_irq_mask_ack,
-       .mask           = txx9_irq_mask,
-       .mask_ack       = txx9_irq_mask_ack,
-       .unmask         = txx9_irq_unmask,
-       .set_type       = txx9_irq_set_type,
+       .irq_ack        = txx9_irq_mask_ack,
+       .irq_mask       = txx9_irq_mask,
+       .irq_mask_ack   = txx9_irq_mask_ack,
+       .irq_unmask     = txx9_irq_unmask,
+       .irq_set_type   = txx9_irq_set_type,
 };
 
 void __init txx9_irq_init(unsigned long baseaddr)
index fbaabad0e6e28466aa1098d4f50c516d520b0c7d..7f5468b38d4cb08e3b1b6abf7bce6b8733003b41 100644 (file)
@@ -586,6 +586,10 @@ einval:    li      v0, -ENOSYS
        sys     sys_fanotify_init       2
        sys     sys_fanotify_mark       6
        sys     sys_prlimit64           4
+       sys     sys_name_to_handle_at   5
+       sys     sys_open_by_handle_at   3       /* 4340 */
+       sys     sys_clock_adjtime       2
+       sys     sys_syncfs              1
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 3f4179283207b1cc21e7fc14d9fea4da0c38bb28..a2e1fcbc41dce87add7a456301548fb1f38aaba6 100644 (file)
@@ -425,4 +425,8 @@ sys_call_table:
        PTR     sys_fanotify_init               /* 5295 */
        PTR     sys_fanotify_mark
        PTR     sys_prlimit64
+       PTR     sys_name_to_handle_at
+       PTR     sys_open_by_handle_at
+       PTR     sys_clock_adjtime               /* 5300 */
+       PTR     sys_syncfs
        .size   sys_call_table,.-sys_call_table
index f08ece6d8acc7f3aa78ecbca23f801ae76727f6a..b2c7624995b8068e3d8ae21b7faa56c016225ec9 100644 (file)
@@ -425,4 +425,8 @@ EXPORT(sysn32_call_table)
        PTR     sys_fanotify_init               /* 6300 */
        PTR     sys_fanotify_mark
        PTR     sys_prlimit64
+       PTR     sys_name_to_handle_at
+       PTR     sys_open_by_handle_at
+       PTR     compat_sys_clock_adjtime        /* 6305 */
+       PTR     sys_syncfs
        .size   sysn32_call_table,.-sysn32_call_table
index 78d768a3e19da78fc986e9170f73b240ee98c1c2..049a9c8c49a0fbf2f12055d4d98ad4e87d5ca8d0 100644 (file)
@@ -543,4 +543,8 @@ sys_call_table:
        PTR     sys_fanotify_init
        PTR     sys_32_fanotify_mark
        PTR     sys_prlimit64
+       PTR     sys_name_to_handle_at
+       PTR     compat_sys_open_by_handle_at    /* 4340 */
+       PTR     compat_sys_clock_adjtime
+       PTR     sys_syncfs
        .size   sys_call_table,.-sys_call_table
index 39c08254b0f16f7d36e1b73344cb75c52ed9619f..f7e2c7807d7ba8932e8ae136e5dce79b83846f51 100644 (file)
@@ -677,8 +677,9 @@ void smtc_set_irq_affinity(unsigned int irq, cpumask_t affinity)
         */
 }
 
-void smtc_forward_irq(unsigned int irq)
+void smtc_forward_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        int target;
 
        /*
@@ -692,7 +693,7 @@ void smtc_forward_irq(unsigned int irq)
         * and efficiency, we just pick the easiest one to find.
         */
 
-       target = cpumask_first(irq_desc[irq].affinity);
+       target = cpumask_first(d->affinity);
 
        /*
         * We depend on the platform code to have correctly processed
@@ -707,12 +708,10 @@ void smtc_forward_irq(unsigned int irq)
         */
 
        /* If no one is eligible, service locally */
-       if (target >= NR_CPUS) {
+       if (target >= NR_CPUS)
                do_IRQ_no_affinity(irq);
-               return;
-       }
-
-       smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq);
+       else
+               smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq);
 }
 
 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
index 1353fb135ed370969d9b2b7628a13cd041470542..670e3e70d1983f7bcb11b4b822718f7f3908eb6d 100644 (file)
@@ -32,24 +32,24 @@ static volatile int *lasat_int_status;
 static volatile int *lasat_int_mask;
 static volatile int lasat_int_mask_shift;
 
-void disable_lasat_irq(unsigned int irq_nr)
+void disable_lasat_irq(struct irq_data *d)
 {
-       irq_nr -= LASAT_IRQ_BASE;
+       unsigned int irq_nr = d->irq - LASAT_IRQ_BASE;
+
        *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift;
 }
 
-void enable_lasat_irq(unsigned int irq_nr)
+void enable_lasat_irq(struct irq_data *d)
 {
-       irq_nr -= LASAT_IRQ_BASE;
+       unsigned int irq_nr = d->irq - LASAT_IRQ_BASE;
+
        *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift;
 }
 
 static struct irq_chip lasat_irq_type = {
        .name = "Lasat",
-       .ack = disable_lasat_irq,
-       .mask = disable_lasat_irq,
-       .mask_ack = disable_lasat_irq,
-       .unmask = enable_lasat_irq,
+       .irq_mask = disable_lasat_irq,
+       .irq_unmask = enable_lasat_irq,
 };
 
 static inline int ls1bit32(unsigned int x)
index 2dc2a4cc632a72817aaa64617246d5845c7465ac..1549361696ad01bb94c0093bf5bcd8e9b35f6770 100644 (file)
 
 #include <loongson.h>
 
-static inline void bonito_irq_enable(unsigned int irq)
+static inline void bonito_irq_enable(struct irq_data *d)
 {
-       LOONGSON_INTENSET = (1 << (irq - LOONGSON_IRQ_BASE));
+       LOONGSON_INTENSET = (1 << (d->irq - LOONGSON_IRQ_BASE));
        mmiowb();
 }
 
-static inline void bonito_irq_disable(unsigned int irq)
+static inline void bonito_irq_disable(struct irq_data *d)
 {
-       LOONGSON_INTENCLR = (1 << (irq - LOONGSON_IRQ_BASE));
+       LOONGSON_INTENCLR = (1 << (d->irq - LOONGSON_IRQ_BASE));
        mmiowb();
 }
 
 static struct irq_chip bonito_irq_type = {
-       .name   = "bonito_irq",
-       .ack    = bonito_irq_disable,
-       .mask   = bonito_irq_disable,
-       .mask_ack = bonito_irq_disable,
-       .unmask = bonito_irq_enable,
+       .name           = "bonito_irq",
+       .irq_mask       = bonito_irq_disable,
+       .irq_unmask     = bonito_irq_enable,
 };
 
 static struct irqaction __maybe_unused dma_timeout_irqaction = {
index 5da30b6a65b77c1b7dff68465c3a7b906dbf0216..30df47258c2c4f0cd55cd79e52064798587834e1 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/atomic.h>
 #include <asm/cpu.h>
 #include <asm/processor.h>
+#include <asm/smtc.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/smtc_ipi.h>
@@ -57,8 +58,6 @@ static inline void ssmtc_send_ipi_mask(const struct cpumask *mask,
  */
 static void __cpuinit ssmtc_init_secondary(void)
 {
-       void smtc_init_secondary(void);
-
        smtc_init_secondary();
 }
 
index 192cfd2a539c5a7e8910b53cc54ecbfa2bf1548c..e67891521ac1ffe801a17dfc57485f4fd900a586 100644 (file)
@@ -34,7 +34,6 @@ static void msmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action)
  */
 static void __cpuinit msmtc_init_secondary(void)
 {
-       void smtc_init_secondary(void);
        int myvpe;
 
        /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
@@ -114,7 +113,8 @@ struct plat_smp_ops msmtc_smp_ops = {
  */
 
 
-int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
+int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
+                         bool force)
 {
        cpumask_t tmask;
        int cpu = 0;
@@ -144,7 +144,7 @@ int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
                if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu))
                        cpu_clear(cpu, tmask);
        }
-       cpumask_copy(irq_desc[irq].affinity, &tmask);
+       cpumask_copy(d->affinity, &tmask);
 
        if (cpus_empty(tmask))
                /*
@@ -155,8 +155,8 @@ int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
                        "IRQ affinity leaves no legal CPU for IRQ %d\n", irq);
 
        /* Do any generic SMTC IRQ affinity setup */
-       smtc_set_irq_affinity(irq, tmask);
+       smtc_set_irq_affinity(d->irq, tmask);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
index 02cc65e52d11b47574b2940e5859a733f7d0fd85..4b9d7044e26c236b87f3f4497cacd5acd1cc7e4b 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS := -Werror
+ccflags-y := -Werror
 
 obj-$(CONFIG_OPROFILE) += oprofile.o
 
index 8d798497c614fa0e79070f3be0a3981eb3e094d9..bbd76082fa8c497454193557b56ec195a514b317 100644 (file)
@@ -23,6 +23,8 @@ config PMC_MSP7120_GW
        select SYS_SUPPORTS_MULTITHREADING
        select IRQ_MSP_CIC
        select HW_HAS_PCI
+       select MSP_HAS_USB
+       select MSP_ETH
 
 config PMC_MSP7120_FPGA
        bool "PMC-Sierra MSP7120 FPGA"
@@ -35,3 +37,16 @@ endchoice
 config HYPERTRANSPORT
        bool "Hypertransport Support for PMC-Sierra Yosemite"
        depends on PMC_YOSEMITE
+
+config MSP_HAS_USB
+       boolean
+       depends on PMC_MSP
+
+config MSP_ETH
+       boolean
+       select MSP_HAS_MAC
+       depends on PMC_MSP
+
+config MSP_HAS_MAC
+       boolean
+       depends on PMC_MSP
index e107f79b149131a1b22d74dd88aaed8e827fa3e0..cefba7733b733100526ab450e3e34208b1e58584 100644 (file)
@@ -6,7 +6,9 @@ obj-y += msp_prom.o msp_setup.o msp_irq.o \
 obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o
 obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
 obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
-obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o
+obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o
 obj-$(CONFIG_PCI) += msp_pci.o
-obj-$(CONFIG_MSPETH) += msp_eth.o
-obj-$(CONFIG_USB_MSP71XX) += msp_usb.o
+obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o
+obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o
+obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o
+obj-$(CONFIG_MIPS_MT_SMTC) += msp_smtc.o
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_eth.c b/arch/mips/pmc-sierra/msp71xx/msp_eth.c
new file mode 100644 (file)
index 0000000..c584df3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * The setup file for ethernet related hardware on PMC-Sierra MSP processors.
+ *
+ * Copyright 2010 PMC-Sierra, 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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT 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.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <msp_regs.h>
+#include <msp_int.h>
+#include <msp_gpio_macros.h>
+
+
+#define MSP_ETHERNET_GPIO0     14
+#define MSP_ETHERNET_GPIO1     15
+#define MSP_ETHERNET_GPIO2     16
+
+#ifdef CONFIG_MSP_HAS_TSMAC
+#define MSP_TSMAC_SIZE 0x10020
+#define MSP_TSMAC_ID   "pmc_tsmac"
+
+static struct resource msp_tsmac0_resources[] = {
+       [0] = {
+               .start  = MSP_MAC0_BASE,
+               .end    = MSP_MAC0_BASE + MSP_TSMAC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_MAC0,
+               .end    = MSP_INT_MAC0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msp_tsmac1_resources[] = {
+       [0] = {
+               .start  = MSP_MAC1_BASE,
+               .end    = MSP_MAC1_BASE + MSP_TSMAC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_MAC1,
+               .end    = MSP_INT_MAC1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+static struct resource msp_tsmac2_resources[] = {
+       [0] = {
+               .start  = MSP_MAC2_BASE,
+               .end    = MSP_MAC2_BASE + MSP_TSMAC_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_SAR,
+               .end    = MSP_INT_SAR,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+
+static struct platform_device tsmac_device[] = {
+       [0] = {
+               .name   = MSP_TSMAC_ID,
+               .id     = 0,
+               .num_resources = ARRAY_SIZE(msp_tsmac0_resources),
+               .resource = msp_tsmac0_resources,
+       },
+       [1] = {
+               .name   = MSP_TSMAC_ID,
+               .id     = 1,
+               .num_resources = ARRAY_SIZE(msp_tsmac1_resources),
+               .resource = msp_tsmac1_resources,
+       },
+       [2] = {
+               .name   = MSP_TSMAC_ID,
+               .id     = 2,
+               .num_resources = ARRAY_SIZE(msp_tsmac2_resources),
+               .resource = msp_tsmac2_resources,
+       },
+};
+#define msp_eth_devs   tsmac_device
+
+#else
+/* If it is not TSMAC assume MSP_ETH (100Mbps) */
+#define MSP_ETH_ID     "pmc_mspeth"
+#define MSP_ETH_SIZE   0xE0
+static struct resource msp_eth0_resources[] = {
+       [0] = {
+               .start  = MSP_MAC0_BASE,
+               .end    = MSP_MAC0_BASE + MSP_ETH_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_MAC0,
+               .end    = MSP_INT_MAC0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msp_eth1_resources[] = {
+       [0] = {
+               .start  = MSP_MAC1_BASE,
+               .end    = MSP_MAC1_BASE + MSP_ETH_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_MAC1,
+               .end    = MSP_INT_MAC1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+
+
+static struct platform_device mspeth_device[] = {
+       [0] = {
+               .name   = MSP_ETH_ID,
+               .id     = 0,
+               .num_resources = ARRAY_SIZE(msp_eth0_resources),
+               .resource = msp_eth0_resources,
+       },
+       [1] = {
+               .name   = MSP_ETH_ID,
+               .id     = 1,
+               .num_resources = ARRAY_SIZE(msp_eth1_resources),
+               .resource = msp_eth1_resources,
+       },
+
+};
+#define msp_eth_devs   mspeth_device
+
+#endif
+int __init msp_eth_setup(void)
+{
+       int i, ret = 0;
+
+       /* Configure the GPIO and take the ethernet PHY out of reset */
+       msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO0);
+       msp_gpio_pin_hi(MSP_ETHERNET_GPIO0);
+
+#ifdef CONFIG_MSP_HAS_TSMAC
+       /* 3 phys on boards with TSMAC */
+       msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO1);
+       msp_gpio_pin_hi(MSP_ETHERNET_GPIO1);
+
+       msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO2);
+       msp_gpio_pin_hi(MSP_ETHERNET_GPIO2);
+#endif
+       for (i = 0; i < ARRAY_SIZE(msp_eth_devs); i++) {
+               ret = platform_device_register(&msp_eth_devs[i]);
+               printk(KERN_INFO "device: %d, return value = %d\n", i, ret);
+               if (ret) {
+                       platform_device_unregister(&msp_eth_devs[i]);
+                       break;
+               }
+       }
+
+       if (ret)
+               printk(KERN_WARNING "Could not initialize "
+                                               "MSPETH device structures.\n");
+
+       return ret;
+}
+subsys_initcall(msp_eth_setup);
index 734d598a2e3a0bcf370c6d9aeffd5d00fafc11d6..4531c4a514bc499b2dedfbe9bf497149a39947df 100644 (file)
@@ -19,8 +19,6 @@
 
 #include <msp_int.h>
 
-extern void msp_int_handle(void);
-
 /* SLP bases systems */
 extern void msp_slp_irq_init(void);
 extern void msp_slp_irq_dispatch(void);
@@ -29,6 +27,18 @@ extern void msp_slp_irq_dispatch(void);
 extern void msp_cic_irq_init(void);
 extern void msp_cic_irq_dispatch(void);
 
+/* VSMP support init */
+extern void msp_vsmp_int_init(void);
+
+/* vectored interrupt implementation */
+
+/* SW0/1 interrupts are used for SMP/SMTC */
+static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); }
+static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); }
+static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); }
+static inline void usb_int_dispatch(void)  { do_IRQ(MSP_INT_USB);  }
+static inline void sec_int_dispatch(void)  { do_IRQ(MSP_INT_SEC);  }
+
 /*
  * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
  * hierarchical system.  The first level are the direct MIPS interrupts
@@ -96,29 +106,57 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
                do_IRQ(MSP_INT_SW1);
 }
 
-static struct irqaction cascade_msp = {
+static struct irqaction cic_cascade_msp = {
        .handler = no_action,
-       .name    = "MSP cascade"
+       .name    = "MSP CIC cascade"
 };
 
+static struct irqaction per_cascade_msp = {
+       .handler = no_action,
+       .name    = "MSP PER cascade"
+};
 
 void __init arch_init_irq(void)
 {
+       /* assume we'll be using vectored interrupt mode except in UP mode*/
+#ifdef CONFIG_MIPS_MT
+       BUG_ON(!cpu_has_vint);
+#endif
        /* initialize the 1st-level CPU based interrupt controller */
        mips_cpu_irq_init();
 
 #ifdef CONFIG_IRQ_MSP_CIC
        msp_cic_irq_init();
-
+#ifdef CONFIG_MIPS_MT
+       set_vi_handler(MSP_INT_CIC, msp_cic_irq_dispatch);
+       set_vi_handler(MSP_INT_MAC0, mac0_int_dispatch);
+       set_vi_handler(MSP_INT_MAC1, mac1_int_dispatch);
+       set_vi_handler(MSP_INT_SAR, mac2_int_dispatch);
+       set_vi_handler(MSP_INT_USB, usb_int_dispatch);
+       set_vi_handler(MSP_INT_SEC, sec_int_dispatch);
+#ifdef CONFIG_MIPS_MT_SMP
+       msp_vsmp_int_init();
+#elif defined CONFIG_MIPS_MT_SMTC
+       /*Set hwmask for all platform devices */
+       irq_hwmask[MSP_INT_MAC0] = C_IRQ0;
+       irq_hwmask[MSP_INT_MAC1] = C_IRQ1;
+       irq_hwmask[MSP_INT_USB] = C_IRQ2;
+       irq_hwmask[MSP_INT_SAR] = C_IRQ3;
+       irq_hwmask[MSP_INT_SEC] = C_IRQ5;
+
+#endif /* CONFIG_MIPS_MT_SMP */
+#endif /* CONFIG_MIPS_MT */
        /* setup the cascaded interrupts */
-       setup_irq(MSP_INT_CIC, &cascade_msp);
-       setup_irq(MSP_INT_PER, &cascade_msp);
+       setup_irq(MSP_INT_CIC, &cic_cascade_msp);
+       setup_irq(MSP_INT_PER, &per_cascade_msp);
+
 #else
        /* setup the 2nd-level SLP register based interrupt controller */
+       /* VSMP /SMTC support support is not enabled for SLP */
        msp_slp_irq_init();
 
        /* setup the cascaded SLP/PER interrupts */
-       setup_irq(MSP_INT_SLP, &cascade_msp);
-       setup_irq(MSP_INT_PER, &cascade_msp);
+       setup_irq(MSP_INT_SLP, &cic_cascade_msp);
+       setup_irq(MSP_INT_PER, &per_cascade_msp);
 #endif
 }
index 07e71ff2433f642428462d405c0f843d3928fd6b..352f29d9226f01b5eff4377233862db55cba6817 100644 (file)
@@ -1,8 +1,7 @@
 /*
- * This file define the irq handler for MSP SLM subsystem interrupts.
+ * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c
  *
- * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
- * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
+ * This file define the irq handler for MSP CIC subsystem interrupts.
  *
  * 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
 #include <linux/bitops.h>
 #include <linux/irq.h>
 
+#include <asm/mipsregs.h>
 #include <asm/system.h>
 
 #include <msp_cic_int.h>
 #include <msp_regs.h>
 
 /*
- * NOTE: We are only enabling support for VPE0 right now.
+ * External API
  */
+extern void msp_per_irq_init(void);
+extern void msp_per_irq_dispatch(void);
 
-static inline void unmask_msp_cic_irq(unsigned int irq)
+
+/*
+ * Convenience Macro.  Should be somewhere generic.
+ */
+#define get_current_vpe()   \
+       ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
+
+#ifdef CONFIG_SMP
+
+#define LOCK_VPE(flags, mtflags) \
+do {                           \
+       local_irq_save(flags);  \
+       mtflags = dmt();        \
+} while (0)
+
+#define UNLOCK_VPE(flags, mtflags) \
+do {                           \
+       emt(mtflags);           \
+       local_irq_restore(flags);\
+} while (0)
+
+#define LOCK_CORE(flags, mtflags) \
+do {                           \
+       local_irq_save(flags);  \
+       mtflags = dvpe();       \
+} while (0)
+
+#define UNLOCK_CORE(flags, mtflags)            \
+do {                           \
+       evpe(mtflags);          \
+       local_irq_restore(flags);\
+} while (0)
+
+#else
+
+#define LOCK_VPE(flags, mtflags)
+#define UNLOCK_VPE(flags, mtflags)
+#endif
+
+/* ensure writes to cic are completed */
+static inline void cic_wmb(void)
 {
+       const volatile void __iomem *cic_mem = CIC_VPE0_MSK_REG;
+       volatile u32 dummy_read;
 
-       /* check for PER interrupt range */
-       if (irq < MSP_PER_INTBASE)
-               *CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
-       else
-               *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
+       wmb();
+       dummy_read = __raw_readl(cic_mem);
+       dummy_read++;
 }
 
-static inline void mask_msp_cic_irq(unsigned int irq)
+static void unmask_cic_irq(struct irq_data *d)
 {
-       /* check for PER interrupt range */
-       if (irq < MSP_PER_INTBASE)
-               *CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
-       else
-               *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
+       volatile u32   *cic_msk_reg = CIC_VPE0_MSK_REG;
+       int vpe;
+#ifdef CONFIG_SMP
+       unsigned int mtflags;
+       unsigned long  flags;
+
+       /*
+       * Make sure we have IRQ affinity.  It may have changed while
+       * we were processing the IRQ.
+       */
+       if (!cpumask_test_cpu(smp_processor_id(), d->affinity))
+               return;
+#endif
+
+       vpe = get_current_vpe();
+       LOCK_VPE(flags, mtflags);
+       cic_msk_reg[vpe] |= (1 << (d->irq - MSP_CIC_INTBASE));
+       UNLOCK_VPE(flags, mtflags);
+       cic_wmb();
 }
 
-/*
- * While we ack the interrupt interrupts are disabled and thus we don't need
- * to deal with concurrency issues.  Same for msp_cic_irq_end.
- */
-static inline void ack_msp_cic_irq(unsigned int irq)
+static void mask_cic_irq(struct irq_data *d)
 {
-       mask_msp_cic_irq(irq);
-
+       volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG;
+       int     vpe = get_current_vpe();
+#ifdef CONFIG_SMP
+       unsigned long flags, mtflags;
+#endif
+       LOCK_VPE(flags, mtflags);
+       cic_msk_reg[vpe] &= ~(1 << (d->irq - MSP_CIC_INTBASE));
+       UNLOCK_VPE(flags, mtflags);
+       cic_wmb();
+}
+static void msp_cic_irq_ack(struct irq_data *d)
+{
+       mask_cic_irq(d);
        /*
-        * only really necessary for 18, 16-14 and sometimes 3:0 (since
-        * these can be edge sensitive) but it doesn't hurt for the others.
-        */
-
-       /* check for PER interrupt range */
-       if (irq < MSP_PER_INTBASE)
-               *CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
-       else
-               *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
+       * Only really necessary for 18, 16-14 and sometimes 3:0
+       * (since these can be edge sensitive) but it doesn't
+       * hurt for the others
+       */
+       *CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE));
+       smtc_im_ack_irq(d->irq);
 }
 
+/*Note: Limiting to VSMP . Not tested in SMTC */
+
+#ifdef CONFIG_MIPS_MT_SMP
+static int msp_cic_irq_set_affinity(struct irq_data *d,
+                                   const struct cpumask *cpumask, bool force)
+{
+       int cpu;
+       unsigned long flags;
+       unsigned int  mtflags;
+       unsigned long imask = (1 << (irq - MSP_CIC_INTBASE));
+       volatile u32 *cic_mask = (volatile u32 *)CIC_VPE0_MSK_REG;
+
+       /* timer balancing should be disabled in kernel code */
+       BUG_ON(irq == MSP_INT_VPE0_TIMER || irq == MSP_INT_VPE1_TIMER);
+
+       LOCK_CORE(flags, mtflags);
+       /* enable if any of each VPE's TCs require this IRQ */
+       for_each_online_cpu(cpu) {
+               if (cpumask_test_cpu(cpu, cpumask))
+                       cic_mask[cpu] |= imask;
+               else
+                       cic_mask[cpu] &= ~imask;
+
+       }
+
+       UNLOCK_CORE(flags, mtflags);
+       return 0;
+
+}
+#endif
+
 static struct irq_chip msp_cic_irq_controller = {
        .name = "MSP_CIC",
-       .ack = ack_msp_cic_irq,
-       .mask = ack_msp_cic_irq,
-       .mask_ack = ack_msp_cic_irq,
-       .unmask = unmask_msp_cic_irq,
+       .irq_mask = mask_cic_irq,
+       .irq_mask_ack = msp_cic_irq_ack,
+       .irq_unmask = unmask_cic_irq,
+       .irq_ack = msp_cic_irq_ack,
+#ifdef CONFIG_MIPS_MT_SMP
+       .irq_set_affinity = msp_cic_irq_set_affinity,
+#endif
 };
 
-
 void __init msp_cic_irq_init(void)
 {
        int i;
-
        /* Mask/clear interrupts. */
        *CIC_VPE0_MSK_REG = 0x00000000;
-       *PER_INT_MSK_REG  = 0x00000000;
+       *CIC_VPE1_MSK_REG = 0x00000000;
        *CIC_STS_REG      = 0xFFFFFFFF;
-       *PER_INT_STS_REG  = 0xFFFFFFFF;
-
-#if defined(CONFIG_PMC_MSP7120_GW) || \
-    defined(CONFIG_PMC_MSP7120_EVAL)
        /*
-        * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
-        * These inputs map to EXT_INT_POL[6:4] inside the CIC.
-        * They are to be active low, level sensitive.
-        */
+       * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
+       * These inputs map to EXT_INT_POL[6:4] inside the CIC.
+       * They are to be active low, level sensitive.
+       */
        *CIC_EXT_CFG_REG &= 0xFFFF8F8F;
-#endif
 
        /* initialize all the IRQ descriptors */
-       for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
+       for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) {
                set_irq_chip_and_handler(i, &msp_cic_irq_controller,
                                         handle_level_irq);
+#ifdef CONFIG_MIPS_MT_SMTC
+               /* Mask of CIC interrupt */
+               irq_hwmask[i] = C_IRQ4;
+#endif
+       }
+
+       /* Initialize the PER interrupt sub-system */
+        msp_per_irq_init();
 }
 
+/* CIC masked by CIC vector processing before dispatch called */
 void msp_cic_irq_dispatch(void)
 {
-       u32 pending;
-       int intbase;
-
-       intbase = MSP_CIC_INTBASE;
-       pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
-
-       /* check for PER interrupt */
-       if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
-               intbase = MSP_PER_INTBASE;
-               pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
-       }
-
-       /* check for spurious interrupt */
-       if (pending == 0x00000000) {
-               printk(KERN_ERR
-                       "Spurious %s interrupt? status %08x, mask %08x\n",
-                       (intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
-                       (intbase == MSP_CIC_INTBASE) ?
-                               *CIC_STS_REG : *PER_INT_STS_REG,
-                       (intbase == MSP_CIC_INTBASE) ?
-                               *CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
-               return;
-       }
-
-       /* check for the timer and dispatch it first */
-       if ((intbase == MSP_CIC_INTBASE) &&
-           (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
+       volatile u32    *cic_msk_reg = (volatile u32 *)CIC_VPE0_MSK_REG;
+       u32     cic_mask;
+       u32      pending;
+       int     cic_status = *CIC_STS_REG;
+       cic_mask = cic_msk_reg[get_current_vpe()];
+       pending = cic_status & cic_mask;
+       if (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))) {
                do_IRQ(MSP_INT_VPE0_TIMER);
-       else
-               do_IRQ(ffs(pending) + intbase - 1);
+       } else if (pending & (1 << (MSP_INT_VPE1_TIMER - MSP_CIC_INTBASE))) {
+               do_IRQ(MSP_INT_VPE1_TIMER);
+       } else if (pending & (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
+               msp_per_irq_dispatch();
+       } else if (pending) {
+               do_IRQ(ffs(pending) + MSP_CIC_INTBASE - 1);
+       } else{
+               spurious_interrupt();
+       }
 }
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c
new file mode 100644 (file)
index 0000000..f9b9dcd
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c
+ *
+ * This file define the irq handler for MSP PER subsystem interrupts.
+ *
+ * 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/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+#include <msp_cic_int.h>
+#include <msp_regs.h>
+
+
+/*
+ * Convenience Macro.  Should be somewhere generic.
+ */
+#define get_current_vpe()      \
+       ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
+
+#ifdef CONFIG_SMP
+/*
+ * The PER registers must be protected from concurrent access.
+ */
+
+static DEFINE_SPINLOCK(per_lock);
+#endif
+
+/* ensure writes to per are completed */
+
+static inline void per_wmb(void)
+{
+       const volatile void __iomem *per_mem = PER_INT_MSK_REG;
+       volatile u32 dummy_read;
+
+       wmb();
+       dummy_read = __raw_readl(per_mem);
+       dummy_read++;
+}
+
+static inline void unmask_per_irq(struct irq_data *d)
+{
+#ifdef CONFIG_SMP
+       unsigned long flags;
+       spin_lock_irqsave(&per_lock, flags);
+       *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE));
+       spin_unlock_irqrestore(&per_lock, flags);
+#else
+       *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE));
+#endif
+       per_wmb();
+}
+
+static inline void mask_per_irq(struct irq_data *d)
+{
+#ifdef CONFIG_SMP
+       unsigned long flags;
+       spin_lock_irqsave(&per_lock, flags);
+       *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE));
+       spin_unlock_irqrestore(&per_lock, flags);
+#else
+       *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE));
+#endif
+       per_wmb();
+}
+
+static inline void msp_per_irq_ack(struct irq_data *d)
+{
+       mask_per_irq(d);
+       /*
+        * In the PER interrupt controller, only bits 11 and 10
+        * are write-to-clear, (SPI TX complete, SPI RX complete).
+        * It does nothing for any others.
+        */
+       *PER_INT_STS_REG = (1 << (d->irq - MSP_PER_INTBASE));
+}
+
+#ifdef CONFIG_SMP
+static int msp_per_irq_set_affinity(struct irq_data *d,
+                                   const struct cpumask *affinity, bool force)
+{
+       /* WTF is this doing ????? */
+       unmask_per_irq(d);
+       return 0;
+}
+#endif
+
+static struct irq_chip msp_per_irq_controller = {
+       .name = "MSP_PER",
+       .irq_enable = unmask_per_irq.
+       .irq_disable = mask_per_irq,
+       .irq_ack = msp_per_irq_ack,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = msp_per_irq_set_affinity,
+#endif
+};
+
+void __init msp_per_irq_init(void)
+{
+       int i;
+       /* Mask/clear interrupts. */
+       *PER_INT_MSK_REG  = 0x00000000;
+       *PER_INT_STS_REG  = 0xFFFFFFFF;
+       /* initialize all the IRQ descriptors */
+       for (i = MSP_PER_INTBASE; i < MSP_PER_INTBASE + 32; i++) {
+               irq_set_chip(i, &msp_per_irq_controller);
+#ifdef CONFIG_MIPS_MT_SMTC
+               irq_hwmask[i] = C_IRQ4;
+#endif
+       }
+}
+
+void msp_per_irq_dispatch(void)
+{
+       u32     per_mask = *PER_INT_MSK_REG;
+       u32     per_status = *PER_INT_STS_REG;
+       u32     pending;
+
+       pending = per_status & per_mask;
+       if (pending) {
+               do_IRQ(ffs(pending) + MSP_PER_INTBASE - 1);
+       } else {
+               spurious_interrupt();
+       }
+}
index 61f390232346509556862dce70afea4aa2662447..8f51e4adc4380391f34567cd504388a164ca30b4 100644 (file)
 #include <msp_slp_int.h>
 #include <msp_regs.h>
 
-static inline void unmask_msp_slp_irq(unsigned int irq)
+static inline void unmask_msp_slp_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        /* check for PER interrupt range */
        if (irq < MSP_PER_INTBASE)
                *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
@@ -30,8 +32,10 @@ static inline void unmask_msp_slp_irq(unsigned int irq)
                *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
 }
 
-static inline void mask_msp_slp_irq(unsigned int irq)
+static inline void mask_msp_slp_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        /* check for PER interrupt range */
        if (irq < MSP_PER_INTBASE)
                *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
@@ -43,8 +47,10 @@ static inline void mask_msp_slp_irq(unsigned int irq)
  * While we ack the interrupt interrupts are disabled and thus we don't need
  * to deal with concurrency issues.  Same for msp_slp_irq_end.
  */
-static inline void ack_msp_slp_irq(unsigned int irq)
+static inline void ack_msp_slp_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        /* check for PER interrupt range */
        if (irq < MSP_PER_INTBASE)
                *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
@@ -54,9 +60,9 @@ static inline void ack_msp_slp_irq(unsigned int irq)
 
 static struct irq_chip msp_slp_irq_controller = {
        .name = "MSP_SLP",
-       .ack = ack_msp_slp_irq,
-       .mask = mask_msp_slp_irq,
-       .unmask = unmask_msp_slp_irq,
+       .irq_ack = ack_msp_slp_irq,
+       .irq_mask = mask_msp_slp_irq,
+       .irq_unmask = unmask_msp_slp_irq,
 };
 
 void __init msp_slp_irq_init(void)
index a54e85b3cf29c10bbfb421aa7e2ddc7c111e460a..fb37a10e0309b033c32a260bcfedc2937c6568c5 100644 (file)
@@ -146,6 +146,8 @@ void __init plat_mem_setup(void)
        pm_power_off = msp_power_off;
 }
 
+extern struct plat_smp_ops msp_smtc_smp_ops;
+
 void __init prom_init(void)
 {
        unsigned long family;
@@ -226,6 +228,14 @@ void __init prom_init(void)
         */
        msp_serial_setup();
 
+#ifdef CONFIG_MIPS_MT_SMP
+       register_smp_ops(&vsmp_smp_ops);
+#endif
+
+#ifdef CONFIG_MIPS_MT_SMTC
+       register_smp_ops(&msp_smtc_smp_ops);
+#endif
+
 #ifdef CONFIG_PMCTWILED
        /*
         * Setup LED states before the subsys_initcall loads other
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_smp.c b/arch/mips/pmc-sierra/msp71xx/msp_smp.c
new file mode 100644 (file)
index 0000000..43a9e26
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
+ * Copyright (C) 2001 Ralf Baechle
+ * Copyright (C) 2010 PMC-Sierra, Inc.
+ *
+ *  VSMP support for MSP platforms . Derived from malta vsmp support.
+ *
+ *  This program is free software; you can distribute 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 it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_MIPS_MT_SMP
+#define MIPS_CPU_IPI_RESCHED_IRQ 0     /* SW int 0 for resched */
+#define MIPS_CPU_IPI_CALL_IRQ 1                /* SW int 1 for call */
+
+
+static void ipi_resched_dispatch(void)
+{
+       do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ);
+}
+
+static void ipi_call_dispatch(void)
+{
+       do_IRQ(MIPS_CPU_IPI_CALL_IRQ);
+}
+
+static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
+{
+       smp_call_function_interrupt();
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction irq_resched = {
+       .handler        = ipi_resched_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .name           = "IPI_resched"
+};
+
+static struct irqaction irq_call = {
+       .handler        = ipi_call_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_PERCPU,
+       .name           = "IPI_call"
+};
+
+void __init arch_init_ipiirq(int irq, struct irqaction *action)
+{
+       setup_irq(irq, action);
+       set_irq_handler(irq, handle_percpu_irq);
+}
+
+void __init msp_vsmp_int_init(void)
+{
+       set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
+       set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
+       arch_init_ipiirq(MIPS_CPU_IPI_RESCHED_IRQ, &irq_resched);
+       arch_init_ipiirq(MIPS_CPU_IPI_CALL_IRQ, &irq_call);
+}
+#endif /* CONFIG_MIPS_MT_SMP */
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_smtc.c b/arch/mips/pmc-sierra/msp71xx/msp_smtc.c
new file mode 100644 (file)
index 0000000..c8dcc1c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * MSP71xx Platform-specific hooks for SMP operation
+ */
+#include <linux/irq.h>
+#include <linux/init.h>
+
+#include <asm/mipsmtregs.h>
+#include <asm/mipsregs.h>
+#include <asm/smtc.h>
+#include <asm/smtc_ipi.h>
+
+/* VPE/SMP Prototype implements platform interfaces directly */
+
+/*
+ * Cause the specified action to be performed on a targeted "CPU"
+ */
+
+static void msp_smtc_send_ipi_single(int cpu, unsigned int action)
+{
+       /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
+       smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
+}
+
+static void msp_smtc_send_ipi_mask(const struct cpumask *mask,
+                                               unsigned int action)
+{
+       unsigned int i;
+
+       for_each_cpu(i, mask)
+               msp_smtc_send_ipi_single(i, action);
+}
+
+/*
+ * Post-config but pre-boot cleanup entry point
+ */
+static void __cpuinit msp_smtc_init_secondary(void)
+{
+       int myvpe;
+
+       /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
+       myvpe = read_c0_tcbind() & TCBIND_CURVPE;
+       if (myvpe > 0)
+               change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 |
+                               STATUSF_IP6 | STATUSF_IP7);
+       smtc_init_secondary();
+}
+
+/*
+ * Platform "CPU" startup hook
+ */
+static void __cpuinit msp_smtc_boot_secondary(int cpu,
+                                       struct task_struct *idle)
+{
+       smtc_boot_secondary(cpu, idle);
+}
+
+/*
+ * SMP initialization finalization entry point
+ */
+static void __cpuinit msp_smtc_smp_finish(void)
+{
+       smtc_smp_finish();
+}
+
+/*
+ * Hook for after all CPUs are online
+ */
+
+static void msp_smtc_cpus_done(void)
+{
+}
+
+/*
+ * Platform SMP pre-initialization
+ *
+ * As noted above, we can assume a single CPU for now
+ * but it may be multithreaded.
+ */
+
+static void __init msp_smtc_smp_setup(void)
+{
+       /*
+        * we won't get the definitive value until
+        * we've run smtc_prepare_cpus later, but
+        */
+
+       if (read_c0_config3() & (1 << 2))
+               smp_num_siblings = smtc_build_cpu_map(0);
+}
+
+static void __init msp_smtc_prepare_cpus(unsigned int max_cpus)
+{
+       smtc_prepare_cpus(max_cpus);
+}
+
+struct plat_smp_ops msp_smtc_smp_ops = {
+       .send_ipi_single        = msp_smtc_send_ipi_single,
+       .send_ipi_mask          = msp_smtc_send_ipi_mask,
+       .init_secondary         = msp_smtc_init_secondary,
+       .smp_finish             = msp_smtc_smp_finish,
+       .cpus_done              = msp_smtc_cpus_done,
+       .boot_secondary         = msp_smtc_boot_secondary,
+       .smp_setup              = msp_smtc_smp_setup,
+       .prepare_cpus           = msp_smtc_prepare_cpus,
+};
index 01df84ce31e209cd3d05e0e316b68ea78d74798e..8b42f307a7a7c10f0ea886cf1a28744cf895329a 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/ptrace.h>
 
+#include <asm/cevt-r4k.h>
 #include <asm/mipsregs.h>
 #include <asm/time.h>
 
 #include <msp_int.h>
 #include <msp_regs.h>
 
+#define get_current_vpe()   \
+       ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
+
+static struct irqaction timer_vpe1;
+static int tim_installed;
+
 void __init plat_time_init(void)
 {
        char    *endp, *s;
@@ -83,5 +90,12 @@ void __init plat_time_init(void)
 
 unsigned int __cpuinit get_c0_compare_int(void)
 {
-       return MSP_INT_VPE0_TIMER;
+       /* MIPS_MT modes may want timer for second VPE */
+       if ((get_current_vpe()) && !tim_installed) {
+               memcpy(&timer_vpe1, &c0_compare_irqaction, sizeof(timer_vpe1));
+               setup_irq(MSP_INT_VPE1_TIMER, &timer_vpe1);
+               tim_installed++;
+       }
+
+       return get_current_vpe() ? MSP_INT_VPE1_TIMER : MSP_INT_VPE0_TIMER;
 }
index 0ee01e359dd8aa4f0a1fcaa20d3fb0c05709cbde..9a1aef89bd4c827d3dc88e9a6b2c23561747e6ad 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * The setup file for USB related hardware on PMC-Sierra MSP processors.
  *
- * Copyright 2006-2007 PMC-Sierra, Inc.
+ * Copyright 2006 PMC-Sierra, 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
@@ -23,8 +23,8 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
 
-#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <msp_regs.h>
 #include <msp_int.h>
 #include <msp_prom.h>
+#include <msp_usb.h>
+
 
 #if defined(CONFIG_USB_EHCI_HCD)
-static struct resource msp_usbhost_resources [] = {
-       [0] = {
-               .start  = MSP_USB_BASE_START,
-               .end    = MSP_USB_BASE_END,
-               .flags  = IORESOURCE_MEM,
+static struct resource msp_usbhost0_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB0_HS_START,
+               .end    = MSP_USB0_HS_END,
+               .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = MSP_INT_USB,
-               .end    = MSP_INT_USB,
-               .flags  = IORESOURCE_IRQ,
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB0_MAB_START,
+               .end    = MSP_USB0_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB0_ID_START,
+               .end    = MSP_USB0_ID_END,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
-static u64 msp_usbhost_dma_mask = DMA_BIT_MASK(32);
+static u64 msp_usbhost0_dma_mask = 0xffffffffUL;
 
-static struct platform_device msp_usbhost_device = {
-       .name   = "pmcmsp-ehci",
-       .id     = 0,
+static struct mspusb_device msp_usbhost0_device = {
        .dev    = {
-               .dma_mask = &msp_usbhost_dma_mask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .name   = "pmcmsp-ehci",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbhost0_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbhost0_resources),
+               .resource       = msp_usbhost0_resources,
        },
-       .num_resources  = ARRAY_SIZE(msp_usbhost_resources),
-       .resource       = msp_usbhost_resources,
 };
-#endif /* CONFIG_USB_EHCI_HCD */
 
-#if defined(CONFIG_USB_GADGET)
-static struct resource msp_usbdev_resources [] = {
-       [0] = {
-               .start  = MSP_USB_BASE,
-               .end    = MSP_USB_BASE_END,
+/* MSP7140/MSP82XX has two USB2 hosts. */
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+static u64 msp_usbhost1_dma_mask = 0xffffffffUL;
+
+static struct resource msp_usbhost1_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB1_HS_START,
+               .end    = MSP_USB1_HS_END,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -75,76 +91,173 @@ static struct resource msp_usbdev_resources [] = {
                .end    = MSP_INT_USB,
                .flags  = IORESOURCE_IRQ,
        },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB1_MAB_START,
+               .end    = MSP_USB1_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB1_ID_START,
+               .end    = MSP_USB1_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct mspusb_device msp_usbhost1_device = {
+       .dev    = {
+               .name   = "pmcmsp-ehci",
+               .id     = 1,
+               .dev    = {
+                       .dma_mask = &msp_usbhost1_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbhost1_resources),
+               .resource       = msp_usbhost1_resources,
+       },
 };
+#endif /* CONFIG_MSP_HAS_DUAL_USB */
+#endif /* CONFIG_USB_EHCI_HCD */
 
-static u64 msp_usbdev_dma_mask = DMA_BIT_MASK(32);
+#if defined(CONFIG_USB_GADGET)
+static struct resource msp_usbdev0_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB0_HS_START,
+               .end    = MSP_USB0_HS_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB0_MAB_START,
+               .end    = MSP_USB0_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB0_ID_START,
+               .end    = MSP_USB0_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
 
-static struct platform_device msp_usbdev_device = {
-       .name   = "msp71xx_udc",
-       .id     = 0,
+static u64 msp_usbdev_dma_mask = 0xffffffffUL;
+
+/* This may need to be converted to a mspusb_device, too. */
+static struct mspusb_device msp_usbdev0_device = {
        .dev    = {
-               .dma_mask = &msp_usbdev_dma_mask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .name   = "msp71xx_udc",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbdev_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbdev0_resources),
+               .resource       = msp_usbdev0_resources,
        },
-       .num_resources  = ARRAY_SIZE(msp_usbdev_resources),
-       .resource       = msp_usbdev_resources,
 };
-#endif /* CONFIG_USB_GADGET */
 
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
-static struct platform_device *msp_devs[1];
-#endif
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+static struct resource msp_usbdev1_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB1_HS_START,
+               .end    = MSP_USB1_HS_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB1_MAB_START,
+               .end    = MSP_USB1_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB1_ID_START,
+               .end    = MSP_USB1_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
 
+/* This may need to be converted to a mspusb_device, too. */
+static struct mspusb_device msp_usbdev1_device = {
+       .dev    = {
+               .name   = "msp71xx_udc",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbdev_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbdev1_resources),
+               .resource       = msp_usbdev1_resources,
+       },
+};
+
+#endif /* CONFIG_MSP_HAS_DUAL_USB */
+#endif /* CONFIG_USB_GADGET */
 
 static int __init msp_usb_setup(void)
 {
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
-       char *strp;
-       char envstr[32];
-       unsigned int val = 0;
-       int result = 0;
+       char            *strp;
+       char            envstr[32];
+       struct platform_device *msp_devs[NUM_USB_DEVS];
+       unsigned int val;
 
+       /* construct environment name usbmode */
+       /* set usbmode <host/device> as pmon environment var */
        /*
-        * construct environment name usbmode
-        * set usbmode <host/device> as pmon environment var
+        * Could this perhaps be integrated into the "features" env var?
+        * Use the features key "U", and follow with "H" for host-mode,
+        * "D" for device-mode.  If it works for Ethernet, why not USB...
+        *  -- hammtrev, 2007/03/22
         */
        snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
 
-#if defined(CONFIG_USB_EHCI_HCD)
-       /* default to host mode */
+       /* set default host mode */
        val = 1;
-#endif
 
        /* get environment string */
        strp = prom_getenv((char *)&envstr[0]);
        if (strp) {
+               /* compare string */
                if (!strcmp(strp, "device"))
                        val = 0;
        }
 
        if (val) {
 #if defined(CONFIG_USB_EHCI_HCD)
-               /* get host mode device */
-               msp_devs[0] = &msp_usbhost_device;
-               ppfinit("platform add USB HOST done %s.\n",
-                           msp_devs[0]->name);
-
-               result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
-#endif /* CONFIG_USB_EHCI_HCD */
-       }
+               msp_devs[0] = &msp_usbhost0_device.dev;
+               ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+               msp_devs[1] = &msp_usbhost1_device.dev;
+               ppfinit("platform add USB HOST done %s.\n", msp_devs[1]->name);
+#endif
+#else
+               ppfinit("%s: echi_hcd not supported\n", __FILE__);
+#endif  /* CONFIG_USB_EHCI_HCD */
+       } else {
 #if defined(CONFIG_USB_GADGET)
-       else {
                /* get device mode structure */
-               msp_devs[0] = &msp_usbdev_device;
-               ppfinit("platform add USB DEVICE done %s.\n",
-                           msp_devs[0]->name);
-
-               result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
+               msp_devs[0] = &msp_usbdev0_device.dev;
+               ppfinit("platform add USB DEVICE done %s.\n"
+                                       , msp_devs[0]->name);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+               msp_devs[1] = &msp_usbdev1_device.dev;
+               ppfinit("platform add USB DEVICE done %s.\n"
+                                       , msp_devs[1]->name);
+#endif
+#else
+               ppfinit("%s: usb_gadget not supported\n", __FILE__);
+#endif  /* CONFIG_USB_GADGET */
        }
-#endif /* CONFIG_USB_GADGET */
-#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
+       /* add device */
+       platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
 
-       return result;
+       return 0;
 }
 
 subsys_initcall(msp_usb_setup);
+#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
index b16f95c3df654a089a33b7b9655228863421e865..02f5fb94ea2808a5bf580679421598e0659961d2 100644 (file)
@@ -6,4 +6,4 @@ obj-y    += irq.o prom.o py-console.o setup.o
 
 obj-$(CONFIG_SMP)              += smp.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
index 941916f8aaff03a0d9673e519ab72b2ed8e5e2f7..b226bcb0a2f4925969534213628bd7fd5238de5e 100644 (file)
@@ -152,10 +152,6 @@ static inline void pnx833x_hard_disable_pic_irq(unsigned int irq)
        PNX833X_PIC_INT_REG(irq) = 0;
 }
 
-static int irqflags[PNX833X_PIC_NUM_IRQ];      /* initialized by zeroes */
-#define IRQFLAG_STARTED                1
-#define IRQFLAG_DISABLED       2
-
 static DEFINE_RAW_SPINLOCK(pnx833x_irq_lock);
 
 static unsigned int pnx833x_startup_pic_irq(unsigned int irq)
@@ -164,108 +160,54 @@ static unsigned int pnx833x_startup_pic_irq(unsigned int irq)
        unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE;
 
        raw_spin_lock_irqsave(&pnx833x_irq_lock, flags);
-
-       irqflags[pic_irq] = IRQFLAG_STARTED;    /* started, not disabled */
        pnx833x_hard_enable_pic_irq(pic_irq);
-
        raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags);
        return 0;
 }
 
-static void pnx833x_shutdown_pic_irq(unsigned int irq)
-{
-       unsigned long flags;
-       unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE;
-
-       raw_spin_lock_irqsave(&pnx833x_irq_lock, flags);
-
-       irqflags[pic_irq] = 0;                  /* not started */
-       pnx833x_hard_disable_pic_irq(pic_irq);
-
-       raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags);
-}
-
-static void pnx833x_enable_pic_irq(unsigned int irq)
+static void pnx833x_enable_pic_irq(struct irq_data *d)
 {
        unsigned long flags;
-       unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE;
+       unsigned int pic_irq = d->irq - PNX833X_PIC_IRQ_BASE;
 
        raw_spin_lock_irqsave(&pnx833x_irq_lock, flags);
-
-       irqflags[pic_irq] &= ~IRQFLAG_DISABLED;
-       if (irqflags[pic_irq] == IRQFLAG_STARTED)
-               pnx833x_hard_enable_pic_irq(pic_irq);
-
+       pnx833x_hard_enable_pic_irq(pic_irq);
        raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags);
 }
 
-static void pnx833x_disable_pic_irq(unsigned int irq)
+static void pnx833x_disable_pic_irq(struct irq_data *d)
 {
        unsigned long flags;
-       unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE;
+       unsigned int pic_irq = d->irq - PNX833X_PIC_IRQ_BASE;
 
        raw_spin_lock_irqsave(&pnx833x_irq_lock, flags);
-
-       irqflags[pic_irq] |= IRQFLAG_DISABLED;
        pnx833x_hard_disable_pic_irq(pic_irq);
-
        raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags);
 }
 
-static void pnx833x_ack_pic_irq(unsigned int irq)
-{
-}
-
-static void pnx833x_end_pic_irq(unsigned int irq)
-{
-}
-
 static DEFINE_RAW_SPINLOCK(pnx833x_gpio_pnx833x_irq_lock);
 
-static unsigned int pnx833x_startup_gpio_irq(unsigned int irq)
-{
-       int pin = irq - PNX833X_GPIO_IRQ_BASE;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags);
-       pnx833x_gpio_enable_irq(pin);
-       raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags);
-       return 0;
-}
-
-static void pnx833x_enable_gpio_irq(unsigned int irq)
+static void pnx833x_enable_gpio_irq(struct irq_data *d)
 {
-       int pin = irq - PNX833X_GPIO_IRQ_BASE;
+       int pin = d->irq - PNX833X_GPIO_IRQ_BASE;
        unsigned long flags;
        raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags);
        pnx833x_gpio_enable_irq(pin);
        raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags);
 }
 
-static void pnx833x_disable_gpio_irq(unsigned int irq)
+static void pnx833x_disable_gpio_irq(struct irq_data *d)
 {
-       int pin = irq - PNX833X_GPIO_IRQ_BASE;
+       int pin = d->irq - PNX833X_GPIO_IRQ_BASE;
        unsigned long flags;
        raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags);
        pnx833x_gpio_disable_irq(pin);
        raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags);
 }
 
-static void pnx833x_ack_gpio_irq(unsigned int irq)
-{
-}
-
-static void pnx833x_end_gpio_irq(unsigned int irq)
-{
-       int pin = irq - PNX833X_GPIO_IRQ_BASE;
-       unsigned long flags;
-       raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags);
-       pnx833x_gpio_clear_irq(pin);
-       raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags);
-}
-
-static int pnx833x_set_type_gpio_irq(unsigned int irq, unsigned int flow_type)
+static int pnx833x_set_type_gpio_irq(struct irq_data *d, unsigned int flow_type)
 {
-       int pin = irq - PNX833X_GPIO_IRQ_BASE;
+       int pin = d->irq - PNX833X_GPIO_IRQ_BASE;
        int gpio_mode;
 
        switch (flow_type) {
@@ -296,23 +238,15 @@ static int pnx833x_set_type_gpio_irq(unsigned int irq, unsigned int flow_type)
 
 static struct irq_chip pnx833x_pic_irq_type = {
        .name = "PNX-PIC",
-       .startup = pnx833x_startup_pic_irq,
-       .shutdown = pnx833x_shutdown_pic_irq,
-       .enable = pnx833x_enable_pic_irq,
-       .disable = pnx833x_disable_pic_irq,
-       .ack = pnx833x_ack_pic_irq,
-       .end = pnx833x_end_pic_irq
+       .irq_enable = pnx833x_enable_pic_irq,
+       .irq_disable = pnx833x_disable_pic_irq,
 };
 
 static struct irq_chip pnx833x_gpio_irq_type = {
        .name = "PNX-GPIO",
-       .startup = pnx833x_startup_gpio_irq,
-       .shutdown = pnx833x_disable_gpio_irq,
-       .enable = pnx833x_enable_gpio_irq,
-       .disable = pnx833x_disable_gpio_irq,
-       .ack = pnx833x_ack_gpio_irq,
-       .end = pnx833x_end_gpio_irq,
-       .set_type = pnx833x_set_type_gpio_irq
+       .irq_enable = pnx833x_enable_gpio_irq,
+       .irq_disable = pnx833x_disable_gpio_irq,
+       .irq_set_type = pnx833x_set_type_gpio_irq,
 };
 
 void __init arch_init_irq(void)
index cfed5051dc6d6323e86ad8e90144e1006bb52b57..dbdc35c3531db15a8791783d50313479aa2a44b0 100644 (file)
@@ -114,8 +114,10 @@ static inline void unmask_gic_int(unsigned int irq_nr)
        PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr];
 }
 
-static inline void mask_irq(unsigned int irq_nr)
+static inline void mask_irq(struct irq_data *d)
 {
+       unsigned int irq_nr = d->irq;
+
        if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
                modify_cp0_intmask(1 << irq_nr, 0);
        } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
@@ -129,8 +131,10 @@ static inline void mask_irq(unsigned int irq_nr)
        }
 }
 
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void unmask_irq(struct irq_data *d)
 {
+       unsigned int irq_nr = d->irq;
+
        if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) {
                modify_cp0_intmask(0, 1 << irq_nr);
        } else if ((PNX8550_INT_GIC_MIN <= irq_nr) &&
@@ -157,10 +161,8 @@ int pnx8550_set_gic_priority(int irq, int priority)
 
 static struct irq_chip level_irq_type = {
        .name =         "PNX Level IRQ",
-       .ack =          mask_irq,
-       .mask =         mask_irq,
-       .mask_ack =     mask_irq,
-       .unmask =       unmask_irq,
+       .irq_mask =     mask_irq,
+       .irq_unmask =   unmask_irq,
 };
 
 static struct irqaction gic_action = {
@@ -180,10 +182,8 @@ void __init arch_init_irq(void)
        int i;
        int configPR;
 
-       for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
+       for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++)
                set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq);
-               mask_irq(i);    /* mask the irq just in case  */
-       }
 
        /* init of GIC/IPC interrupts */
        /* should be done before cp0 since cp0 init enables the GIC int */
index baf6e9092a9f84b941b37986dac89a289b5225a8..348d2e850ef5128d42a34fe761fe357fdb5fc5ff 100644 (file)
@@ -28,4 +28,4 @@ obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \
 
 obj-$(CONFIG_USB) += powertv-usb.o
 
-EXTRA_CFLAGS += -Wall
+ccflags-y := -Wall
index f0e95dc0ac97b4f63e924f3ae4387eb49e73199b..d810a33182a4a6b76a250e86532930b2f4d23f98 100644 (file)
@@ -20,4 +20,4 @@ obj-y += asic-calliope.o asic-cronus.o asic-gaia.o asic-zeus.o \
        asic_devices.o asic_int.o irq_asic.o prealloc-calliope.o \
        prealloc-cronus.o prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o
 
-EXTRA_CFLAGS += -Wall -Werror
+ccflags-y := -Wall -Werror
index e5538243415576d121b1400aceadc726c6a7fec8..6f1c8ef6a719bf3dfee9c9d9866a6ff7015df366 100644 (file)
 
 #include <asm/mach-powertv/asic_regs.h>
 
-static inline void unmask_asic_irq(unsigned int irq)
+static inline void unmask_asic_irq(struct irq_data *d)
 {
        unsigned long enable_bit;
+       unsigned int irq = d->irq;
 
        enable_bit = (1 << (irq & 0x1f));
 
@@ -45,9 +46,10 @@ static inline void unmask_asic_irq(unsigned int irq)
        }
 }
 
-static inline void mask_asic_irq(unsigned int irq)
+static inline void mask_asic_irq(struct irq_data *d)
 {
        unsigned long disable_mask;
+       unsigned int irq = d->irq;
 
        disable_mask = ~(1 << (irq & 0x1f));
 
@@ -71,11 +73,8 @@ static inline void mask_asic_irq(unsigned int irq)
 
 static struct irq_chip asic_irq_chip = {
        .name = "ASIC Level",
-       .ack = mask_asic_irq,
-       .mask = mask_asic_irq,
-       .mask_ack = mask_asic_irq,
-       .unmask = unmask_asic_irq,
-       .eoi = unmask_asic_irq,
+       .irq_mask = mask_asic_irq,
+       .irq_unmask = unmask_asic_irq,
 };
 
 void __init asic_irq_init(void)
index f5c62462fc9daf458b8248331dca8b6672a8bf7b..5783201cd2c81196659939f6ba495069118e6281 100644 (file)
@@ -18,4 +18,4 @@
 
 obj-$(CONFIG_PCI)      += fixup-powertv.o
 
-EXTRA_CFLAGS += -Wall -Werror
+ccflags-y := -Wall -Werror
index ea6cec3c1e0dbeecde2d7c3ceab11d26b216f18a..b32a768da894f53e627bae8a450bc2b1ff8b3f56 100644 (file)
@@ -111,10 +111,10 @@ static inline void ack_local_irq(unsigned int ip)
        clear_c0_cause(ipnum);
 }
 
-static void rb532_enable_irq(unsigned int irq_nr)
+static void rb532_enable_irq(struct irq_data *d)
 {
+       unsigned int group, intr_bit, irq_nr = d->irq;
        int ip = irq_nr - GROUP0_IRQ_BASE;
-       unsigned int group, intr_bit;
        volatile unsigned int *addr;
 
        if (ip < 0)
@@ -132,10 +132,10 @@ static void rb532_enable_irq(unsigned int irq_nr)
        }
 }
 
-static void rb532_disable_irq(unsigned int irq_nr)
+static void rb532_disable_irq(struct irq_data *d)
 {
+       unsigned int group, intr_bit, mask, irq_nr = d->irq;
        int ip = irq_nr - GROUP0_IRQ_BASE;
-       unsigned int group, intr_bit, mask;
        volatile unsigned int *addr;
 
        if (ip < 0) {
@@ -163,18 +163,18 @@ static void rb532_disable_irq(unsigned int irq_nr)
        }
 }
 
-static void rb532_mask_and_ack_irq(unsigned int irq_nr)
+static void rb532_mask_and_ack_irq(struct irq_data *d)
 {
-       rb532_disable_irq(irq_nr);
-       ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
+       rb532_disable_irq(d);
+       ack_local_irq(group_to_ip(irq_to_group(d->irq)));
 }
 
-static int rb532_set_type(unsigned int irq_nr, unsigned type)
+static int rb532_set_type(struct irq_data *d,  unsigned type)
 {
-       int gpio = irq_nr - GPIO_MAPPED_IRQ_BASE;
-       int group = irq_to_group(irq_nr);
+       int gpio = d->irq - GPIO_MAPPED_IRQ_BASE;
+       int group = irq_to_group(d->irq);
 
-       if (group != GPIO_MAPPED_IRQ_GROUP || irq_nr > (GROUP4_IRQ_BASE + 13))
+       if (group != GPIO_MAPPED_IRQ_GROUP || d->irq > (GROUP4_IRQ_BASE + 13))
                return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL;
 
        switch (type) {
@@ -193,11 +193,11 @@ static int rb532_set_type(unsigned int irq_nr, unsigned type)
 
 static struct irq_chip rc32434_irq_type = {
        .name           = "RB532",
-       .ack            = rb532_disable_irq,
-       .mask           = rb532_disable_irq,
-       .mask_ack       = rb532_mask_and_ack_irq,
-       .unmask         = rb532_enable_irq,
-       .set_type       = rb532_set_type,
+       .irq_ack        = rb532_disable_irq,
+       .irq_mask       = rb532_disable_irq,
+       .irq_mask_ack   = rb532_mask_and_ack_irq,
+       .irq_unmask     = rb532_enable_irq,
+       .irq_set_type   = rb532_set_type,
 };
 
 void __init arch_init_irq(void)
index 383f11d7f4424f99f31b20e9093283e939f390be..e6e64750e90a40d2932f4b2f64d6b16a2ea21179 100644 (file)
@@ -31,88 +31,80 @@ static char lc3msk_to_irqnr[256];
 
 extern int ip22_eisa_init(void);
 
-static void enable_local0_irq(unsigned int irq)
+static void enable_local0_irq(struct irq_data *d)
 {
        /* don't allow mappable interrupt to be enabled from setup_irq,
         * we have our own way to do so */
-       if (irq != SGI_MAP_0_IRQ)
-               sgint->imask0 |= (1 << (irq - SGINT_LOCAL0));
+       if (d->irq != SGI_MAP_0_IRQ)
+               sgint->imask0 |= (1 << (d->irq - SGINT_LOCAL0));
 }
 
-static void disable_local0_irq(unsigned int irq)
+static void disable_local0_irq(struct irq_data *d)
 {
-       sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0));
+       sgint->imask0 &= ~(1 << (d->irq - SGINT_LOCAL0));
 }
 
 static struct irq_chip ip22_local0_irq_type = {
        .name           = "IP22 local 0",
-       .ack            = disable_local0_irq,
-       .mask           = disable_local0_irq,
-       .mask_ack       = disable_local0_irq,
-       .unmask         = enable_local0_irq,
+       .irq_mask       = disable_local0_irq,
+       .irq_unmask     = enable_local0_irq,
 };
 
-static void enable_local1_irq(unsigned int irq)
+static void enable_local1_irq(struct irq_data *d)
 {
        /* don't allow mappable interrupt to be enabled from setup_irq,
         * we have our own way to do so */
-       if (irq != SGI_MAP_1_IRQ)
-               sgint->imask1 |= (1 << (irq - SGINT_LOCAL1));
+       if (d->irq != SGI_MAP_1_IRQ)
+               sgint->imask1 |= (1 << (d->irq - SGINT_LOCAL1));
 }
 
-static void disable_local1_irq(unsigned int irq)
+static void disable_local1_irq(struct irq_data *d)
 {
-       sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1));
+       sgint->imask1 &= ~(1 << (d->irq - SGINT_LOCAL1));
 }
 
 static struct irq_chip ip22_local1_irq_type = {
        .name           = "IP22 local 1",
-       .ack            = disable_local1_irq,
-       .mask           = disable_local1_irq,
-       .mask_ack       = disable_local1_irq,
-       .unmask         = enable_local1_irq,
+       .irq_mask       = disable_local1_irq,
+       .irq_unmask     = enable_local1_irq,
 };
 
-static void enable_local2_irq(unsigned int irq)
+static void enable_local2_irq(struct irq_data *d)
 {
        sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
-       sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2));
+       sgint->cmeimask0 |= (1 << (d->irq - SGINT_LOCAL2));
 }
 
-static void disable_local2_irq(unsigned int irq)
+static void disable_local2_irq(struct irq_data *d)
 {
-       sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2));
+       sgint->cmeimask0 &= ~(1 << (d->irq - SGINT_LOCAL2));
        if (!sgint->cmeimask0)
                sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
 }
 
 static struct irq_chip ip22_local2_irq_type = {
        .name           = "IP22 local 2",
-       .ack            = disable_local2_irq,
-       .mask           = disable_local2_irq,
-       .mask_ack       = disable_local2_irq,
-       .unmask         = enable_local2_irq,
+       .irq_mask       = disable_local2_irq,
+       .irq_unmask     = enable_local2_irq,
 };
 
-static void enable_local3_irq(unsigned int irq)
+static void enable_local3_irq(struct irq_data *d)
 {
        sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
-       sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3));
+       sgint->cmeimask1 |= (1 << (d->irq - SGINT_LOCAL3));
 }
 
-static void disable_local3_irq(unsigned int irq)
+static void disable_local3_irq(struct irq_data *d)
 {
-       sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3));
+       sgint->cmeimask1 &= ~(1 << (d->irq - SGINT_LOCAL3));
        if (!sgint->cmeimask1)
                sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
 }
 
 static struct irq_chip ip22_local3_irq_type = {
        .name           = "IP22 local 3",
-       .ack            = disable_local3_irq,
-       .mask           = disable_local3_irq,
-       .mask_ack       = disable_local3_irq,
-       .unmask         = enable_local3_irq,
+       .irq_mask       = disable_local3_irq,
+       .irq_unmask     = enable_local3_irq,
 };
 
 static void indy_local0_irqdispatch(void)
index 6a123ea72de54a42bfdc3e2d6b5d705731061e94..f2d09d7700dd75b4f3ae6c00cba9638974376d82 100644 (file)
@@ -240,7 +240,7 @@ static int intr_disconnect_level(int cpu, int bit)
 }
 
 /* Startup one of the (PCI ...) IRQs routes over a bridge.  */
-static unsigned int startup_bridge_irq(unsigned int irq)
+static unsigned int startup_bridge_irq(struct irq_data *d)
 {
        struct bridge_controller *bc;
        bridgereg_t device;
@@ -248,16 +248,16 @@ static unsigned int startup_bridge_irq(unsigned int irq)
        int pin, swlevel;
        cpuid_t cpu;
 
-       pin = SLOT_FROM_PCI_IRQ(irq);
-       bc = IRQ_TO_BRIDGE(irq);
+       pin = SLOT_FROM_PCI_IRQ(d->irq);
+       bc = IRQ_TO_BRIDGE(d->irq);
        bridge = bc->base;
 
-       pr_debug("bridge_startup(): irq= 0x%x  pin=%d\n", irq, pin);
+       pr_debug("bridge_startup(): irq= 0x%x  pin=%d\n", d->irq, pin);
        /*
         * "map" irq to a swlevel greater than 6 since the first 6 bits
         * of INT_PEND0 are taken
         */
-       swlevel = find_level(&cpu, irq);
+       swlevel = find_level(&cpu, d->irq);
        bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
        bridge->b_int_enable |= (1 << pin);
        bridge->b_int_enable |= 0x7ffffe00;     /* more stuff in int_enable */
@@ -288,53 +288,51 @@ static unsigned int startup_bridge_irq(unsigned int irq)
 }
 
 /* Shutdown one of the (PCI ...) IRQs routes over a bridge.  */
-static void shutdown_bridge_irq(unsigned int irq)
+static void shutdown_bridge_irq(struct irq_data *d)
 {
-       struct bridge_controller *bc = IRQ_TO_BRIDGE(irq);
+       struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
        bridge_t *bridge = bc->base;
        int pin, swlevel;
        cpuid_t cpu;
 
-       pr_debug("bridge_shutdown: irq 0x%x\n", irq);
-       pin = SLOT_FROM_PCI_IRQ(irq);
+       pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
+       pin = SLOT_FROM_PCI_IRQ(d->irq);
 
        /*
         * map irq to a swlevel greater than 6 since the first 6 bits
         * of INT_PEND0 are taken
         */
-       swlevel = find_level(&cpu, irq);
+       swlevel = find_level(&cpu, d->irq);
        intr_disconnect_level(cpu, swlevel);
 
        bridge->b_int_enable &= ~(1 << pin);
        bridge->b_wid_tflush;
 }
 
-static inline void enable_bridge_irq(unsigned int irq)
+static inline void enable_bridge_irq(struct irq_data *d)
 {
        cpuid_t cpu;
        int swlevel;
 
-       swlevel = find_level(&cpu, irq);        /* Criminal offence */
+       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
        intr_connect_level(cpu, swlevel);
 }
 
-static inline void disable_bridge_irq(unsigned int irq)
+static inline void disable_bridge_irq(struct irq_data *d)
 {
        cpuid_t cpu;
        int swlevel;
 
-       swlevel = find_level(&cpu, irq);        /* Criminal offence */
+       swlevel = find_level(&cpu, d->irq);     /* Criminal offence */
        intr_disconnect_level(cpu, swlevel);
 }
 
 static struct irq_chip bridge_irq_type = {
        .name           = "bridge",
-       .startup        = startup_bridge_irq,
-       .shutdown       = shutdown_bridge_irq,
-       .ack            = disable_bridge_irq,
-       .mask           = disable_bridge_irq,
-       .mask_ack       = disable_bridge_irq,
-       .unmask         = enable_bridge_irq,
+       .irq_startup    = startup_bridge_irq,
+       .irq_shutdown   = shutdown_bridge_irq,
+       .irq_mask       = disable_bridge_irq,
+       .irq_unmask     = enable_bridge_irq,
 };
 
 void __devinit register_bridge_irq(unsigned int irq)
index d6802d6d1f827a21b79cd0d8c4fb54b29cf7ae4d..c01f558a2a09142fb06c0ed4a64673b1fff461a3 100644 (file)
 #include <asm/sn/sn0/hubio.h>
 #include <asm/pci/bridge.h>
 
-static void enable_rt_irq(unsigned int irq)
+static void enable_rt_irq(struct irq_data *d)
 {
 }
 
-static void disable_rt_irq(unsigned int irq)
+static void disable_rt_irq(struct irq_data *d)
 {
 }
 
 static struct irq_chip rt_irq_type = {
        .name           = "SN HUB RT timer",
-       .ack            = disable_rt_irq,
-       .mask           = disable_rt_irq,
-       .mask_ack       = disable_rt_irq,
-       .unmask         = enable_rt_irq,
-       .eoi            = enable_rt_irq,
+       .irq_mask       = disable_rt_irq,
+       .irq_unmask     = enable_rt_irq,
 };
 
 static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
index eb40824b172ac1792c541036a5f6c5f8b8790ece..e0a3ce4a8d48a550b525b79b26b33b7cb81dbb65 100644 (file)
@@ -130,70 +130,48 @@ static struct irqaction cpuerr_irq = {
 
 static uint64_t crime_mask;
 
-static inline void crime_enable_irq(unsigned int irq)
+static inline void crime_enable_irq(struct irq_data *d)
 {
-       unsigned int bit = irq - CRIME_IRQ_BASE;
+       unsigned int bit = d->irq - CRIME_IRQ_BASE;
 
        crime_mask |= 1 << bit;
        crime->imask = crime_mask;
 }
 
-static inline void crime_disable_irq(unsigned int irq)
+static inline void crime_disable_irq(struct irq_data *d)
 {
-       unsigned int bit = irq - CRIME_IRQ_BASE;
+       unsigned int bit = d->irq - CRIME_IRQ_BASE;
 
        crime_mask &= ~(1 << bit);
        crime->imask = crime_mask;
        flush_crime_bus();
 }
 
-static void crime_level_mask_and_ack_irq(unsigned int irq)
-{
-       crime_disable_irq(irq);
-}
-
-static void crime_level_end_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               crime_enable_irq(irq);
-}
-
 static struct irq_chip crime_level_interrupt = {
        .name           = "IP32 CRIME",
-       .ack            = crime_level_mask_and_ack_irq,
-       .mask           = crime_disable_irq,
-       .mask_ack       = crime_level_mask_and_ack_irq,
-       .unmask         = crime_enable_irq,
-       .end            = crime_level_end_irq,
+       .irq_mask       = crime_disable_irq,
+       .irq_unmask     = crime_enable_irq,
 };
 
-static void crime_edge_mask_and_ack_irq(unsigned int irq)
+static void crime_edge_mask_and_ack_irq(struct irq_data *d)
 {
-       unsigned int bit = irq - CRIME_IRQ_BASE;
+       unsigned int bit = d->irq - CRIME_IRQ_BASE;
        uint64_t crime_int;
 
        /* Edge triggered interrupts must be cleared. */
-
        crime_int = crime->hard_int;
        crime_int &= ~(1 << bit);
        crime->hard_int = crime_int;
 
-       crime_disable_irq(irq);
-}
-
-static void crime_edge_end_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               crime_enable_irq(irq);
+       crime_disable_irq(d);
 }
 
 static struct irq_chip crime_edge_interrupt = {
        .name           = "IP32 CRIME",
-       .ack            = crime_edge_mask_and_ack_irq,
-       .mask           = crime_disable_irq,
-       .mask_ack       = crime_edge_mask_and_ack_irq,
-       .unmask         = crime_enable_irq,
-       .end            = crime_edge_end_irq,
+       .irq_ack        = crime_edge_mask_and_ack_irq,
+       .irq_mask       = crime_disable_irq,
+       .irq_mask_ack   = crime_edge_mask_and_ack_irq,
+       .irq_unmask     = crime_enable_irq,
 };
 
 /*
@@ -204,37 +182,28 @@ static struct irq_chip crime_edge_interrupt = {
 
 static unsigned long macepci_mask;
 
-static void enable_macepci_irq(unsigned int irq)
+static void enable_macepci_irq(struct irq_data *d)
 {
-       macepci_mask |= MACEPCI_CONTROL_INT(irq - MACEPCI_SCSI0_IRQ);
+       macepci_mask |= MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ);
        mace->pci.control = macepci_mask;
-       crime_mask |= 1 << (irq - CRIME_IRQ_BASE);
+       crime_mask |= 1 << (d->irq - CRIME_IRQ_BASE);
        crime->imask = crime_mask;
 }
 
-static void disable_macepci_irq(unsigned int irq)
+static void disable_macepci_irq(struct irq_data *d)
 {
-       crime_mask &= ~(1 << (irq - CRIME_IRQ_BASE));
+       crime_mask &= ~(1 << (d->irq - CRIME_IRQ_BASE));
        crime->imask = crime_mask;
        flush_crime_bus();
-       macepci_mask &= ~MACEPCI_CONTROL_INT(irq - MACEPCI_SCSI0_IRQ);
+       macepci_mask &= ~MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ);
        mace->pci.control = macepci_mask;
        flush_mace_bus();
 }
 
-static void end_macepci_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_macepci_irq(irq);
-}
-
 static struct irq_chip ip32_macepci_interrupt = {
        .name = "IP32 MACE PCI",
-       .ack = disable_macepci_irq,
-       .mask = disable_macepci_irq,
-       .mask_ack = disable_macepci_irq,
-       .unmask = enable_macepci_irq,
-       .end = end_macepci_irq,
+       .irq_mask = disable_macepci_irq,
+       .irq_unmask = enable_macepci_irq,
 };
 
 /* This is used for MACE ISA interrupts.  That means bits 4-6 in the
@@ -276,13 +245,13 @@ static struct irq_chip ip32_macepci_interrupt = {
 
 static unsigned long maceisa_mask;
 
-static void enable_maceisa_irq(unsigned int irq)
+static void enable_maceisa_irq(struct irq_data *d)
 {
        unsigned int crime_int = 0;
 
-       pr_debug("maceisa enable: %u\n", irq);
+       pr_debug("maceisa enable: %u\n", d->irq);
 
-       switch (irq) {
+       switch (d->irq) {
        case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
                crime_int = MACE_AUDIO_INT;
                break;
@@ -296,15 +265,15 @@ static void enable_maceisa_irq(unsigned int irq)
        pr_debug("crime_int %08x enabled\n", crime_int);
        crime_mask |= crime_int;
        crime->imask = crime_mask;
-       maceisa_mask |= 1 << (irq - MACEISA_AUDIO_SW_IRQ);
+       maceisa_mask |= 1 << (d->irq - MACEISA_AUDIO_SW_IRQ);
        mace->perif.ctrl.imask = maceisa_mask;
 }
 
-static void disable_maceisa_irq(unsigned int irq)
+static void disable_maceisa_irq(struct irq_data *d)
 {
        unsigned int crime_int = 0;
 
-       maceisa_mask &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ));
+       maceisa_mask &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ));
         if (!(maceisa_mask & MACEISA_AUDIO_INT))
                crime_int |= MACE_AUDIO_INT;
         if (!(maceisa_mask & MACEISA_MISC_INT))
@@ -318,76 +287,57 @@ static void disable_maceisa_irq(unsigned int irq)
        flush_mace_bus();
 }
 
-static void mask_and_ack_maceisa_irq(unsigned int irq)
+static void mask_and_ack_maceisa_irq(struct irq_data *d)
 {
        unsigned long mace_int;
 
        /* edge triggered */
        mace_int = mace->perif.ctrl.istat;
-       mace_int &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ));
+       mace_int &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ));
        mace->perif.ctrl.istat = mace_int;
 
-       disable_maceisa_irq(irq);
-}
-
-static void end_maceisa_irq(unsigned irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               enable_maceisa_irq(irq);
+       disable_maceisa_irq(d);
 }
 
 static struct irq_chip ip32_maceisa_level_interrupt = {
        .name           = "IP32 MACE ISA",
-       .ack            = disable_maceisa_irq,
-       .mask           = disable_maceisa_irq,
-       .mask_ack       = disable_maceisa_irq,
-       .unmask         = enable_maceisa_irq,
-       .end            = end_maceisa_irq,
+       .irq_mask       = disable_maceisa_irq,
+       .irq_unmask     = enable_maceisa_irq,
 };
 
 static struct irq_chip ip32_maceisa_edge_interrupt = {
        .name           = "IP32 MACE ISA",
-       .ack            = mask_and_ack_maceisa_irq,
-       .mask           = disable_maceisa_irq,
-       .mask_ack       = mask_and_ack_maceisa_irq,
-       .unmask         = enable_maceisa_irq,
-       .end            = end_maceisa_irq,
+       .irq_ack        = mask_and_ack_maceisa_irq,
+       .irq_mask       = disable_maceisa_irq,
+       .irq_mask_ack   = mask_and_ack_maceisa_irq,
+       .irq_unmask     = enable_maceisa_irq,
 };
 
 /* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
  * bits 0-3 and 7 in the CRIME register.
  */
 
-static void enable_mace_irq(unsigned int irq)
+static void enable_mace_irq(struct irq_data *d)
 {
-       unsigned int bit = irq - CRIME_IRQ_BASE;
+       unsigned int bit = d->irq - CRIME_IRQ_BASE;
 
        crime_mask |= (1 << bit);
        crime->imask = crime_mask;
 }
 
-static void disable_mace_irq(unsigned int irq)
+static void disable_mace_irq(struct irq_data *d)
 {
-       unsigned int bit = irq - CRIME_IRQ_BASE;
+       unsigned int bit = d->irq - CRIME_IRQ_BASE;
 
        crime_mask &= ~(1 << bit);
        crime->imask = crime_mask;
        flush_crime_bus();
 }
 
-static void end_mace_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_mace_irq(irq);
-}
-
 static struct irq_chip ip32_mace_interrupt = {
        .name = "IP32 MACE",
-       .ack = disable_mace_irq,
-       .mask = disable_mace_irq,
-       .mask_ack = disable_mace_irq,
-       .unmask = enable_mace_irq,
-       .end = end_mace_irq,
+       .irq_mask = disable_mace_irq,
+       .irq_unmask = enable_mace_irq,
 };
 
 static void ip32_unknown_interrupt(void)
index 044bbe462c2c85fc07f508143f0ec682efc28d79..89e8188a466522fdd5675fddcfac18ea5088c8d2 100644 (file)
  * for interrupt lines
  */
 
-
-static void end_bcm1480_irq(unsigned int irq);
-static void enable_bcm1480_irq(unsigned int irq);
-static void disable_bcm1480_irq(unsigned int irq);
-static void ack_bcm1480_irq(unsigned int irq);
-#ifdef CONFIG_SMP
-static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
-#endif
-
 #ifdef CONFIG_PCI
 extern unsigned long ht_eoi_space;
 #endif
 
-static struct irq_chip bcm1480_irq_type = {
-       .name = "BCM1480-IMR",
-       .ack = ack_bcm1480_irq,
-       .mask = disable_bcm1480_irq,
-       .mask_ack = ack_bcm1480_irq,
-       .unmask = enable_bcm1480_irq,
-       .end = end_bcm1480_irq,
-#ifdef CONFIG_SMP
-       .set_affinity = bcm1480_set_affinity
-#endif
-};
-
 /* Store the CPU id (not the logical number) */
 int bcm1480_irq_owner[BCM1480_NR_IRQS];
 
@@ -109,12 +88,13 @@ void bcm1480_unmask_irq(int cpu, int irq)
 }
 
 #ifdef CONFIG_SMP
-static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask,
+                               bool force)
 {
+       unsigned int irq_dirty, irq = d->irq;
        int i = 0, old_cpu, cpu, int_on, k;
        u64 cur_ints;
        unsigned long flags;
-       unsigned int irq_dirty;
 
        i = cpumask_first(mask);
 
@@ -156,21 +136,25 @@ static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
 
 /*****************************************************************************/
 
-static void disable_bcm1480_irq(unsigned int irq)
+static void disable_bcm1480_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
 }
 
-static void enable_bcm1480_irq(unsigned int irq)
+static void enable_bcm1480_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
 }
 
 
-static void ack_bcm1480_irq(unsigned int irq)
+static void ack_bcm1480_irq(struct irq_data *d)
 {
+       unsigned int irq_dirty, irq = d->irq;
        u64 pending;
-       unsigned int irq_dirty;
        int k;
 
        /*
@@ -217,14 +201,15 @@ static void ack_bcm1480_irq(unsigned int irq)
        bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
 }
 
-
-static void end_bcm1480_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-               bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
-       }
-}
-
+static struct irq_chip bcm1480_irq_type = {
+       .name = "BCM1480-IMR",
+       .irq_mask_ack = ack_bcm1480_irq,
+       .irq_mask = disable_bcm1480_irq,
+       .irq_unmask = enable_bcm1480_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = bcm1480_set_affinity
+#endif
+};
 
 void __init init_bcm1480_irqs(void)
 {
index 12ac04a658ee55e6e29d329f6bce0f2e1b328854..fd269ea8d8a85cbe71ca3b1e0c31e40ecf80f2d3 100644 (file)
  * for interrupt lines
  */
 
-
-static void end_sb1250_irq(unsigned int irq);
-static void enable_sb1250_irq(unsigned int irq);
-static void disable_sb1250_irq(unsigned int irq);
-static void ack_sb1250_irq(unsigned int irq);
-#ifdef CONFIG_SMP
-static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask);
-#endif
-
 #ifdef CONFIG_SIBYTE_HAS_LDT
 extern unsigned long ldt_eoi_space;
 #endif
 
-static struct irq_chip sb1250_irq_type = {
-       .name = "SB1250-IMR",
-       .ack = ack_sb1250_irq,
-       .mask = disable_sb1250_irq,
-       .mask_ack = ack_sb1250_irq,
-       .unmask = enable_sb1250_irq,
-       .end = end_sb1250_irq,
-#ifdef CONFIG_SMP
-       .set_affinity = sb1250_set_affinity
-#endif
-};
-
 /* Store the CPU id (not the logical number) */
 int sb1250_irq_owner[SB1250_NR_IRQS];
 
@@ -102,9 +81,11 @@ void sb1250_unmask_irq(int cpu, int irq)
 }
 
 #ifdef CONFIG_SMP
-static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask,
+                              bool force)
 {
        int i = 0, old_cpu, cpu, int_on;
+       unsigned int irq = d->irq;
        u64 cur_ints;
        unsigned long flags;
 
@@ -142,21 +123,17 @@ static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask)
 }
 #endif
 
-/*****************************************************************************/
-
-static void disable_sb1250_irq(unsigned int irq)
+static void enable_sb1250_irq(struct irq_data *d)
 {
-       sb1250_mask_irq(sb1250_irq_owner[irq], irq);
-}
+       unsigned int irq = d->irq;
 
-static void enable_sb1250_irq(unsigned int irq)
-{
        sb1250_unmask_irq(sb1250_irq_owner[irq], irq);
 }
 
 
-static void ack_sb1250_irq(unsigned int irq)
+static void ack_sb1250_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
 #ifdef CONFIG_SIBYTE_HAS_LDT
        u64 pending;
 
@@ -199,14 +176,14 @@ static void ack_sb1250_irq(unsigned int irq)
        sb1250_mask_irq(sb1250_irq_owner[irq], irq);
 }
 
-
-static void end_sb1250_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-               sb1250_unmask_irq(sb1250_irq_owner[irq], irq);
-       }
-}
-
+static struct irq_chip sb1250_irq_type = {
+       .name = "SB1250-IMR",
+       .irq_mask_ack = ack_sb1250_irq,
+       .irq_unmask = enable_sb1250_irq,
+#ifdef CONFIG_SMP
+       .irq_set_affinity = sb1250_set_affinity
+#endif
+};
 
 void __init init_sb1250_irqs(void)
 {
index bbe7187879fa9bb5c493f215ba1ef8f8f81cc695..72b94155778d51772b447c58e870cc00fc06a1a3 100644 (file)
@@ -168,33 +168,22 @@ static u32 a20r_ack_hwint(void)
        return status;
 }
 
-static inline void unmask_a20r_irq(unsigned int irq)
+static inline void unmask_a20r_irq(struct irq_data *d)
 {
-       set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
+       set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
        irq_enable_hazard();
 }
 
-static inline void mask_a20r_irq(unsigned int irq)
+static inline void mask_a20r_irq(struct irq_data *d)
 {
-       clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
+       clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE));
        irq_disable_hazard();
 }
 
-static void end_a20r_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-               a20r_ack_hwint();
-               unmask_a20r_irq(irq);
-       }
-}
-
 static struct irq_chip a20r_irq_type = {
        .name           = "A20R",
-       .ack            = mask_a20r_irq,
-       .mask           = mask_a20r_irq,
-       .mask_ack       = mask_a20r_irq,
-       .unmask         = unmask_a20r_irq,
-       .end            = end_a20r_irq,
+       .irq_mask       = mask_a20r_irq,
+       .irq_unmask     = unmask_a20r_irq,
 };
 
 /*
index 8c92c73bc717db178bcdbce74788f30fe1b193b5..cfcc68abc5b266dc3f6235f7160b2829cc8289cf 100644 (file)
@@ -194,33 +194,24 @@ static struct pci_controller sni_controller = {
        .io_map_base    = SNI_PORT_BASE
 };
 
-static void enable_pcimt_irq(unsigned int irq)
+static void enable_pcimt_irq(struct irq_data *d)
 {
-       unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
+       unsigned int mask = 1 << (d->irq - PCIMT_IRQ_INT2);
 
        *(volatile u8 *) PCIMT_IRQSEL |= mask;
 }
 
-void disable_pcimt_irq(unsigned int irq)
+void disable_pcimt_irq(struct irq_data *d)
 {
-       unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
+       unsigned int mask = ~(1 << (d->irq - PCIMT_IRQ_INT2));
 
        *(volatile u8 *) PCIMT_IRQSEL &= mask;
 }
 
-static void end_pcimt_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_pcimt_irq(irq);
-}
-
 static struct irq_chip pcimt_irq_type = {
        .name = "PCIMT",
-       .ack = disable_pcimt_irq,
-       .mask = disable_pcimt_irq,
-       .mask_ack = disable_pcimt_irq,
-       .unmask = enable_pcimt_irq,
-       .end = end_pcimt_irq,
+       .irq_mask = disable_pcimt_irq,
+       .irq_unmask = enable_pcimt_irq,
 };
 
 /*
index dc9874553becbf62abc5dce1135e9a7444f43d88..0846e99a6efee0f03e5040a28c430f96722a39db 100644 (file)
@@ -156,33 +156,24 @@ static struct pci_controller sni_pcit_controller = {
        .io_map_base    = SNI_PORT_BASE
 };
 
-static void enable_pcit_irq(unsigned int irq)
+static void enable_pcit_irq(struct irq_data *d)
 {
-       u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
+       u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24);
 
        *(volatile u32 *)SNI_PCIT_INT_REG |= mask;
 }
 
-void disable_pcit_irq(unsigned int irq)
+void disable_pcit_irq(struct irq_data *d)
 {
-       u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
+       u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24);
 
        *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
 }
 
-void end_pcit_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_pcit_irq(irq);
-}
-
 static struct irq_chip pcit_irq_type = {
        .name = "PCIT",
-       .ack = disable_pcit_irq,
-       .mask = disable_pcit_irq,
-       .mask_ack = disable_pcit_irq,
-       .unmask = enable_pcit_irq,
-       .end = end_pcit_irq,
+       .irq_mask = disable_pcit_irq,
+       .irq_unmask = enable_pcit_irq,
 };
 
 static void pcit_hwint1(void)
index 0e6f42c2bbc86c69117bd90bef5c22456f8c01ac..f05d8e593300736afbb096ee4090b775fe6f0a9a 100644 (file)
@@ -155,12 +155,11 @@ static __iomem u8 *rm200_pic_slave;
 #define cached_master_mask     (rm200_cached_irq_mask)
 #define cached_slave_mask      (rm200_cached_irq_mask >> 8)
 
-static void sni_rm200_disable_8259A_irq(unsigned int irq)
+static void sni_rm200_disable_8259A_irq(struct irq_data *d)
 {
-       unsigned int mask;
+       unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= RM200_I8259A_IRQ_BASE;
        mask = 1 << irq;
        raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
        rm200_cached_irq_mask |= mask;
@@ -171,12 +170,11 @@ static void sni_rm200_disable_8259A_irq(unsigned int irq)
        raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
 }
 
-static void sni_rm200_enable_8259A_irq(unsigned int irq)
+static void sni_rm200_enable_8259A_irq(struct irq_data *d)
 {
-       unsigned int mask;
+       unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= RM200_I8259A_IRQ_BASE;
        mask = ~(1 << irq);
        raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
        rm200_cached_irq_mask &= mask;
@@ -210,12 +208,11 @@ static inline int sni_rm200_i8259A_irq_real(unsigned int irq)
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-void sni_rm200_mask_and_ack_8259A(unsigned int irq)
+void sni_rm200_mask_and_ack_8259A(struct irq_data *d)
 {
-       unsigned int irqmask;
+       unsigned int irqmask, irq = d->irq - RM200_I8259A_IRQ_BASE;
        unsigned long flags;
 
-       irq -= RM200_I8259A_IRQ_BASE;
        irqmask = 1 << irq;
        raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
        /*
@@ -285,9 +282,9 @@ spurious_8259A_irq:
 
 static struct irq_chip sni_rm200_i8259A_chip = {
        .name           = "RM200-XT-PIC",
-       .mask           = sni_rm200_disable_8259A_irq,
-       .unmask         = sni_rm200_enable_8259A_irq,
-       .mask_ack       = sni_rm200_mask_and_ack_8259A,
+       .irq_mask       = sni_rm200_disable_8259A_irq,
+       .irq_unmask     = sni_rm200_enable_8259A_irq,
+       .irq_mask_ack   = sni_rm200_mask_and_ack_8259A,
 };
 
 /*
@@ -429,33 +426,24 @@ void __init sni_rm200_i8259_irqs(void)
 #define SNI_RM200_INT_START  24
 #define SNI_RM200_INT_END    28
 
-static void enable_rm200_irq(unsigned int irq)
+static void enable_rm200_irq(struct irq_data *d)
 {
-       unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
+       unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START);
 
        *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
 }
 
-void disable_rm200_irq(unsigned int irq)
+void disable_rm200_irq(struct irq_data *d)
 {
-       unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
+       unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START);
 
        *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
 }
 
-void end_rm200_irq(unsigned int irq)
-{
-       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-               enable_rm200_irq(irq);
-}
-
 static struct irq_chip rm200_irq_type = {
        .name = "RM200",
-       .ack = disable_rm200_irq,
-       .mask = disable_rm200_irq,
-       .mask_ack = disable_rm200_irq,
-       .unmask = enable_rm200_irq,
-       .end = end_rm200_irq,
+       .irq_mask = disable_rm200_irq,
+       .irq_unmask = enable_rm200_irq,
 };
 
 static void sni_rm200_hwint(void)
index 3886ad77cbadd21a1ed1a97ffea7482ea083d88a..93b6edbedd64bd7645c5ad7c9a390f6d350d434d 100644 (file)
@@ -50,9 +50,9 @@ static struct {
        unsigned char mode;
 } tx4939irq[TX4939_NUM_IR] __read_mostly;
 
-static void tx4939_irq_unmask(unsigned int irq)
+static void tx4939_irq_unmask(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 __iomem *lvlp;
        int ofs;
        if (irq_nr < 32) {
@@ -68,9 +68,9 @@ static void tx4939_irq_unmask(unsigned int irq)
                     lvlp);
 }
 
-static inline void tx4939_irq_mask(unsigned int irq)
+static inline void tx4939_irq_mask(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 __iomem *lvlp;
        int ofs;
        if (irq_nr < 32) {
@@ -87,11 +87,11 @@ static inline void tx4939_irq_mask(unsigned int irq)
        mmiowb();
 }
 
-static void tx4939_irq_mask_ack(unsigned int irq)
+static void tx4939_irq_mask_ack(struct irq_data *d)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
 
-       tx4939_irq_mask(irq);
+       tx4939_irq_mask(d);
        if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) {
                irq_nr--;
                /* clear edge detection */
@@ -101,9 +101,9 @@ static void tx4939_irq_mask_ack(unsigned int irq)
        }
 }
 
-static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int tx4939_irq_set_type(struct irq_data *d, unsigned int flow_type)
 {
-       unsigned int irq_nr = irq - TXX9_IRQ_BASE;
+       unsigned int irq_nr = d->irq - TXX9_IRQ_BASE;
        u32 cr;
        u32 __iomem *crp;
        int ofs;
@@ -145,11 +145,11 @@ static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type)
 
 static struct irq_chip tx4939_irq_chip = {
        .name           = "TX4939",
-       .ack            = tx4939_irq_mask_ack,
-       .mask           = tx4939_irq_mask,
-       .mask_ack       = tx4939_irq_mask_ack,
-       .unmask         = tx4939_irq_unmask,
-       .set_type       = tx4939_irq_set_type,
+       .irq_ack        = tx4939_irq_mask_ack,
+       .irq_mask       = tx4939_irq_mask,
+       .irq_mask_ack   = tx4939_irq_mask_ack,
+       .irq_unmask     = tx4939_irq_unmask,
+       .irq_set_type   = tx4939_irq_set_type,
 };
 
 static int tx4939_irq_set_pri(int irc_irq, int new_pri)
index 0a7f8e3b9fd796b7fe384d39772aef124231f40e..92a5c1b400f061d6dcc4a7917c2cead1ceb494e8 100644 (file)
  * CP0_STATUS is a thread's resource (saved/restored on context switch).
  * So disable_irq/enable_irq MUST handle IOC/IRC registers.
  */
-static void mask_irq_ioc(unsigned int irq)
+static void mask_irq_ioc(struct irq_data *d)
 {
        /* 0: mask */
-       unsigned int irq_nr = irq - JMR3927_IRQ_IOC;
+       unsigned int irq_nr = d->irq - JMR3927_IRQ_IOC;
        unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR);
        unsigned int bit = 1 << irq_nr;
        jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR);
        /* flush write buffer */
        (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR);
 }
-static void unmask_irq_ioc(unsigned int irq)
+static void unmask_irq_ioc(struct irq_data *d)
 {
        /* 0: mask */
-       unsigned int irq_nr = irq - JMR3927_IRQ_IOC;
+       unsigned int irq_nr = d->irq - JMR3927_IRQ_IOC;
        unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR);
        unsigned int bit = 1 << irq_nr;
        jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR);
@@ -95,10 +95,8 @@ static int jmr3927_irq_dispatch(int pending)
 
 static struct irq_chip jmr3927_irq_ioc = {
        .name = "jmr3927_ioc",
-       .ack = mask_irq_ioc,
-       .mask = mask_irq_ioc,
-       .mask_ack = mask_irq_ioc,
-       .unmask = unmask_irq_ioc,
+       .irq_mask = mask_irq_ioc,
+       .irq_unmask = unmask_irq_ioc,
 };
 
 void __init jmr3927_irq_setup(void)
index c4b54d20efd3c67fc279ef8d6cfbe2099bc0b62a..7c0a048b307ca15f3cabd83207e7d8cf95fcea79 100644 (file)
 #include <asm/txx9/generic.h>
 #include <asm/txx9/rbtx4927.h>
 
-static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq);
-static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq);
-
-#define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC"
-static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
-       .name = TOSHIBA_RBTX4927_IOC_NAME,
-       .ack = toshiba_rbtx4927_irq_ioc_disable,
-       .mask = toshiba_rbtx4927_irq_ioc_disable,
-       .mask_ack = toshiba_rbtx4927_irq_ioc_disable,
-       .unmask = toshiba_rbtx4927_irq_ioc_enable,
-};
-
 static int toshiba_rbtx4927_irq_nested(int sw_irq)
 {
        u8 level3;
@@ -139,41 +127,47 @@ static int toshiba_rbtx4927_irq_nested(int sw_irq)
        return RBTX4927_IRQ_IOC + __fls8(level3);
 }
 
-static void __init toshiba_rbtx4927_irq_ioc_init(void)
-{
-       int i;
-
-       /* mask all IOC interrupts */
-       writeb(0, rbtx4927_imask_addr);
-       /* clear SoftInt interrupts */
-       writeb(0, rbtx4927_softint_addr);
-
-       for (i = RBTX4927_IRQ_IOC;
-            i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++)
-               set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type,
-                                        handle_level_irq);
-       set_irq_chained_handler(RBTX4927_IRQ_IOCINT, handle_simple_irq);
-}
-
-static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq)
+static void toshiba_rbtx4927_irq_ioc_enable(struct irq_data *d)
 {
        unsigned char v;
 
        v = readb(rbtx4927_imask_addr);
-       v |= (1 << (irq - RBTX4927_IRQ_IOC));
+       v |= (1 << (d->irq - RBTX4927_IRQ_IOC));
        writeb(v, rbtx4927_imask_addr);
 }
 
-static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq)
+static void toshiba_rbtx4927_irq_ioc_disable(struct irq_data *d)
 {
        unsigned char v;
 
        v = readb(rbtx4927_imask_addr);
-       v &= ~(1 << (irq - RBTX4927_IRQ_IOC));
+       v &= ~(1 << (d->irq - RBTX4927_IRQ_IOC));
        writeb(v, rbtx4927_imask_addr);
        mmiowb();
 }
 
+#define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC"
+static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
+       .name = TOSHIBA_RBTX4927_IOC_NAME,
+       .irq_mask = toshiba_rbtx4927_irq_ioc_disable,
+       .irq_unmask = toshiba_rbtx4927_irq_ioc_enable,
+};
+
+static void __init toshiba_rbtx4927_irq_ioc_init(void)
+{
+       int i;
+
+       /* mask all IOC interrupts */
+       writeb(0, rbtx4927_imask_addr);
+       /* clear SoftInt interrupts */
+       writeb(0, rbtx4927_softint_addr);
+
+       for (i = RBTX4927_IRQ_IOC;
+            i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++)
+               set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type,
+                                        handle_level_irq);
+       set_irq_chained_handler(RBTX4927_IRQ_IOCINT, handle_simple_irq);
+}
 
 static int rbtx4927_irq_dispatch(int pending)
 {
index 67a73a8065ec800e00ebb753f612195434f5189b..2ec4fe1b167071d3e5c8eca38616ce68b1b66768 100644 (file)
 #include <asm/txx9/generic.h>
 #include <asm/txx9/rbtx4938.h>
 
-static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq);
-static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq);
-
-#define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
-static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
-       .name = TOSHIBA_RBTX4938_IOC_NAME,
-       .ack = toshiba_rbtx4938_irq_ioc_disable,
-       .mask = toshiba_rbtx4938_irq_ioc_disable,
-       .mask_ack = toshiba_rbtx4938_irq_ioc_disable,
-       .unmask = toshiba_rbtx4938_irq_ioc_enable,
-};
-
 static int toshiba_rbtx4938_irq_nested(int sw_irq)
 {
        u8 level3;
@@ -92,41 +80,33 @@ static int toshiba_rbtx4938_irq_nested(int sw_irq)
        return RBTX4938_IRQ_IOC + __fls8(level3);
 }
 
-static void __init
-toshiba_rbtx4938_irq_ioc_init(void)
-{
-       int i;
-
-       for (i = RBTX4938_IRQ_IOC;
-            i < RBTX4938_IRQ_IOC + RBTX4938_NR_IRQ_IOC; i++)
-               set_irq_chip_and_handler(i, &toshiba_rbtx4938_irq_ioc_type,
-                                        handle_level_irq);
-
-       set_irq_chained_handler(RBTX4938_IRQ_IOCINT, handle_simple_irq);
-}
-
-static void
-toshiba_rbtx4938_irq_ioc_enable(unsigned int irq)
+static void toshiba_rbtx4938_irq_ioc_enable(struct irq_data *d)
 {
        unsigned char v;
 
        v = readb(rbtx4938_imask_addr);
-       v |= (1 << (irq - RBTX4938_IRQ_IOC));
+       v |= (1 << (d->irq - RBTX4938_IRQ_IOC));
        writeb(v, rbtx4938_imask_addr);
        mmiowb();
 }
 
-static void
-toshiba_rbtx4938_irq_ioc_disable(unsigned int irq)
+static void toshiba_rbtx4938_irq_ioc_disable(struct irq_data *d)
 {
        unsigned char v;
 
        v = readb(rbtx4938_imask_addr);
-       v &= ~(1 << (irq - RBTX4938_IRQ_IOC));
+       v &= ~(1 << (d->irq - RBTX4938_IRQ_IOC));
        writeb(v, rbtx4938_imask_addr);
        mmiowb();
 }
 
+#define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
+static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
+       .name = TOSHIBA_RBTX4938_IOC_NAME,
+       .irq_mask = toshiba_rbtx4938_irq_ioc_disable,
+       .irq_unmask = toshiba_rbtx4938_irq_ioc_enable,
+};
+
 static int rbtx4938_irq_dispatch(int pending)
 {
        int irq;
@@ -146,6 +126,18 @@ static int rbtx4938_irq_dispatch(int pending)
        return irq;
 }
 
+static void __init toshiba_rbtx4938_irq_ioc_init(void)
+{
+       int i;
+
+       for (i = RBTX4938_IRQ_IOC;
+            i < RBTX4938_IRQ_IOC + RBTX4938_NR_IRQ_IOC; i++)
+               set_irq_chip_and_handler(i, &toshiba_rbtx4938_irq_ioc_type,
+                                        handle_level_irq);
+
+       set_irq_chained_handler(RBTX4938_IRQ_IOCINT, handle_simple_irq);
+}
+
 void __init rbtx4938_irq_setup(void)
 {
        txx9_irq_dispatch = rbtx4938_irq_dispatch;
index 57fa740a72056b65ecd0f08e55fb23fe434083e7..70074632fb990f6a6a6f7f133afdebdbd04517ef 100644 (file)
  * RBTX4939 IOC controller definition
  */
 
-static void rbtx4939_ioc_irq_unmask(unsigned int irq)
+static void rbtx4939_ioc_irq_unmask(struct irq_data *d)
 {
-       int ioc_nr = irq - RBTX4939_IRQ_IOC;
+       int ioc_nr = d->irq - RBTX4939_IRQ_IOC;
 
        writeb(readb(rbtx4939_ien_addr) | (1 << ioc_nr), rbtx4939_ien_addr);
 }
 
-static void rbtx4939_ioc_irq_mask(unsigned int irq)
+static void rbtx4939_ioc_irq_mask(struct irq_data *d)
 {
-       int ioc_nr = irq - RBTX4939_IRQ_IOC;
+       int ioc_nr = d->irq - RBTX4939_IRQ_IOC;
 
        writeb(readb(rbtx4939_ien_addr) & ~(1 << ioc_nr), rbtx4939_ien_addr);
        mmiowb();
@@ -36,10 +36,8 @@ static void rbtx4939_ioc_irq_mask(unsigned int irq)
 
 static struct irq_chip rbtx4939_ioc_irq_chip = {
        .name           = "IOC",
-       .ack            = rbtx4939_ioc_irq_mask,
-       .mask           = rbtx4939_ioc_irq_mask,
-       .mask_ack       = rbtx4939_ioc_irq_mask,
-       .unmask         = rbtx4939_ioc_irq_unmask,
+       .irq_mask       = rbtx4939_ioc_irq_mask,
+       .irq_unmask     = rbtx4939_ioc_irq_unmask,
 };
 
 
index 6153b6a05ccfd176a894e2ebfe74a8011469cc08..f53156bb9aa8c5815432d779e15fdfe28a9c2225 100644 (file)
@@ -154,7 +154,7 @@ static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear)
 
 void vr41xx_enable_piuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + PIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(PIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -169,7 +169,7 @@ EXPORT_SYMBOL(vr41xx_enable_piuint);
 
 void vr41xx_disable_piuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + PIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(PIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(vr41xx_disable_piuint);
 
 void vr41xx_enable_aiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + AIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(AIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(vr41xx_enable_aiuint);
 
 void vr41xx_disable_aiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + AIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(AIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(vr41xx_disable_aiuint);
 
 void vr41xx_enable_kiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + KIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(KIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -229,7 +229,7 @@ EXPORT_SYMBOL(vr41xx_enable_kiuint);
 
 void vr41xx_disable_kiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + KIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(KIU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4111 ||
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(vr41xx_disable_kiuint);
 
 void vr41xx_enable_macint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+       struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -256,7 +256,7 @@ EXPORT_SYMBOL(vr41xx_enable_macint);
 
 void vr41xx_disable_macint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+       struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -268,7 +268,7 @@ EXPORT_SYMBOL(vr41xx_disable_macint);
 
 void vr41xx_enable_dsiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + DSIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(DSIU_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(vr41xx_enable_dsiuint);
 
 void vr41xx_disable_dsiuint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + DSIU_IRQ;
+       struct irq_desc *desc = irq_to_desc(DSIU_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -292,7 +292,7 @@ EXPORT_SYMBOL(vr41xx_disable_dsiuint);
 
 void vr41xx_enable_firint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + FIR_IRQ;
+       struct irq_desc *desc = irq_to_desc(FIR_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -304,7 +304,7 @@ EXPORT_SYMBOL(vr41xx_enable_firint);
 
 void vr41xx_disable_firint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + FIR_IRQ;
+       struct irq_desc *desc = irq_to_desc(FIR_IRQ);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
@@ -316,7 +316,7 @@ EXPORT_SYMBOL(vr41xx_disable_firint);
 
 void vr41xx_enable_pciint(void)
 {
-       struct irq_desc *desc = irq_desc + PCI_IRQ;
+       struct irq_desc *desc = irq_to_desc(PCI_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -332,7 +332,7 @@ EXPORT_SYMBOL(vr41xx_enable_pciint);
 
 void vr41xx_disable_pciint(void)
 {
-       struct irq_desc *desc = irq_desc + PCI_IRQ;
+       struct irq_desc *desc = irq_to_desc(PCI_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -348,7 +348,7 @@ EXPORT_SYMBOL(vr41xx_disable_pciint);
 
 void vr41xx_enable_scuint(void)
 {
-       struct irq_desc *desc = irq_desc + SCU_IRQ;
+       struct irq_desc *desc = irq_to_desc(SCU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -364,7 +364,7 @@ EXPORT_SYMBOL(vr41xx_enable_scuint);
 
 void vr41xx_disable_scuint(void)
 {
-       struct irq_desc *desc = irq_desc + SCU_IRQ;
+       struct irq_desc *desc = irq_to_desc(SCU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -380,7 +380,7 @@ EXPORT_SYMBOL(vr41xx_disable_scuint);
 
 void vr41xx_enable_csiint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + CSI_IRQ;
+       struct irq_desc *desc = irq_to_desc(CSI_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -396,7 +396,7 @@ EXPORT_SYMBOL(vr41xx_enable_csiint);
 
 void vr41xx_disable_csiint(uint16_t mask)
 {
-       struct irq_desc *desc = irq_desc + CSI_IRQ;
+       struct irq_desc *desc = irq_to_desc(CSI_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -412,7 +412,7 @@ EXPORT_SYMBOL(vr41xx_disable_csiint);
 
 void vr41xx_enable_bcuint(void)
 {
-       struct irq_desc *desc = irq_desc + BCU_IRQ;
+       struct irq_desc *desc = irq_to_desc(BCU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -428,7 +428,7 @@ EXPORT_SYMBOL(vr41xx_enable_bcuint);
 
 void vr41xx_disable_bcuint(void)
 {
-       struct irq_desc *desc = irq_desc + BCU_IRQ;
+       struct irq_desc *desc = irq_to_desc(BCU_IRQ);
        unsigned long flags;
 
        if (current_cpu_type() == CPU_VR4122 ||
@@ -442,45 +442,41 @@ void vr41xx_disable_bcuint(void)
 
 EXPORT_SYMBOL(vr41xx_disable_bcuint);
 
-static void disable_sysint1_irq(unsigned int irq)
+static void disable_sysint1_irq(struct irq_data *d)
 {
-       icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
+       icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq));
 }
 
-static void enable_sysint1_irq(unsigned int irq)
+static void enable_sysint1_irq(struct irq_data *d)
 {
-       icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
+       icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq));
 }
 
 static struct irq_chip sysint1_irq_type = {
        .name           = "SYSINT1",
-       .ack            = disable_sysint1_irq,
-       .mask           = disable_sysint1_irq,
-       .mask_ack       = disable_sysint1_irq,
-       .unmask         = enable_sysint1_irq,
+       .irq_mask       = disable_sysint1_irq,
+       .irq_unmask     = enable_sysint1_irq,
 };
 
-static void disable_sysint2_irq(unsigned int irq)
+static void disable_sysint2_irq(struct irq_data *d)
 {
-       icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
+       icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq));
 }
 
-static void enable_sysint2_irq(unsigned int irq)
+static void enable_sysint2_irq(struct irq_data *d)
 {
-       icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
+       icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq));
 }
 
 static struct irq_chip sysint2_irq_type = {
        .name           = "SYSINT2",
-       .ack            = disable_sysint2_irq,
-       .mask           = disable_sysint2_irq,
-       .mask_ack       = disable_sysint2_irq,
-       .unmask         = enable_sysint2_irq,
+       .irq_mask       = disable_sysint2_irq,
+       .irq_unmask     = enable_sysint2_irq,
 };
 
 static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        uint16_t intassign0, intassign1;
        unsigned int pin;
 
@@ -540,7 +536,7 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
 
 static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        uint16_t intassign2, intassign3;
        unsigned int pin;
 
index 0975eb72d385e189af3f26895eeb689ab3d950c3..9ff7f397c0e14ed7520d266e5ad77dbad78bde91 100644 (file)
@@ -62,7 +62,6 @@ EXPORT_SYMBOL_GPL(cascade_irq);
 static void irq_dispatch(unsigned int irq)
 {
        irq_cascade_t *cascade;
-       struct irq_desc *desc;
 
        if (irq >= NR_IRQS) {
                atomic_inc(&irq_err_count);
@@ -71,14 +70,16 @@ static void irq_dispatch(unsigned int irq)
 
        cascade = irq_cascade + irq;
        if (cascade->get_irq != NULL) {
-               unsigned int source_irq = irq;
+               struct irq_desc *desc = irq_to_desc(irq);
+               struct irq_data *idata = irq_desc_get_irq_data(desc);
+               struct irq_chip *chip = irq_desc_get_chip(desc);
                int ret;
-               desc = irq_desc + source_irq;
-               if (desc->chip->mask_ack)
-                       desc->chip->mask_ack(source_irq);
+
+               if (chip->irq_mask_ack)
+                       chip->irq_mask_ack(idata);
                else {
-                       desc->chip->mask(source_irq);
-                       desc->chip->ack(source_irq);
+                       chip->irq_mask(idata);
+                       chip->irq_ack(idata);
                }
                ret = cascade->get_irq(irq);
                irq = ret;
@@ -86,8 +87,8 @@ static void irq_dispatch(unsigned int irq)
                        atomic_inc(&irq_err_count);
                else
                        irq_dispatch(irq);
-               if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
-                       desc->chip->unmask(source_irq);
+               if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
+                       chip->irq_unmask(idata);
        } else
                do_IRQ(irq);
 }
index 243bfa23fd5863c0d8198d61352b2c0a8db9812a..d8ab97a73db288db6b601fd13fd2baaa278f6809 100644 (file)
@@ -1,7 +1,10 @@
 config MN10300
        def_bool y
        select HAVE_OPROFILE
-       select GENERIC_HARDIRQS
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
+       select HAVE_ARCH_TRACEHOOK
+       select HAVE_ARCH_KGDB
 
 config AM33_2
        def_bool n
@@ -53,21 +56,6 @@ config GENERIC_TIME
 config GENERIC_CLOCKEVENTS
        def_bool y
 
-config GENERIC_CLOCKEVENTS_BUILD
-       def_bool y
-       depends on GENERIC_CLOCKEVENTS
-
-config GENERIC_CLOCKEVENTS_BROADCAST
-       bool
-
-config CEVT_MN10300
-       def_bool y
-       depends on GENERIC_CLOCKEVENTS
-
-config CSRC_MN10300
-       def_bool y
-       depends on GENERIC_TIME
-
 config GENERIC_BUG
        def_bool y
 
@@ -415,9 +403,9 @@ comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highes
 comment "____Non-maskable interrupt levels____"
 comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial"
 
-config GDBSTUB_IRQ_LEVEL
-       int "GDBSTUB interrupt priority"
-       depends on GDBSTUB
+config DEBUGGER_IRQ_LEVEL
+       int "DEBUGGER interrupt priority"
+       depends on KERNEL_DEBUGGER
        range 0 1 if LINUX_CLI_LEVEL = 2
        range 0 2 if LINUX_CLI_LEVEL = 3
        range 0 3 if LINUX_CLI_LEVEL = 4
@@ -451,7 +439,7 @@ config LINUX_CLI_LEVEL
          EPSW.IM from 7.  Any interrupt is permitted for which the level is
          lower than EPSW.IM.
 
-         Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip
+         Certain interrupts, such as DEBUGGER and virtual MN10300 on-chip
          serial DMA interrupts are allowed to interrupt normal disabled
          sections.
 
index ce83c74b3fd714abf68fca4a4d2beef024545c83..bdbfd444a9ff9cf5569baa685a906e5f8800801d 100644 (file)
@@ -36,7 +36,7 @@ config KPROBES
 
 config GDBSTUB
        bool "Remote GDB kernel debugging"
-       depends on DEBUG_KERNEL
+       depends on DEBUG_KERNEL && DEPRECATED
        select DEBUG_INFO
        select FRAME_POINTER
        help
@@ -46,6 +46,9 @@ config GDBSTUB
          RAM to avoid excessive linking time. This is only useful for kernel
          hackers. If unsure, say N.
 
+         This is deprecated in favour of KGDB and will be removed in a later
+         version.
+
 config GDBSTUB_IMMEDIATE
        bool "Break into GDB stub immediately"
        depends on GDBSTUB
@@ -54,6 +57,14 @@ config GDBSTUB_IMMEDIATE
          possible, leaving the program counter at the beginning of
          start_kernel() in init/main.c.
 
+config GDBSTUB_ALLOW_SINGLE_STEP
+       bool "Allow software single-stepping in GDB stub"
+       depends on GDBSTUB && !SMP && !PREEMPT
+       help
+         Allow GDB stub to perform software single-stepping through the
+         kernel.  This doesn't work very well on SMP or preemptible kernels as
+         it uses temporary breakpoints to emulate single-stepping.
+
 config GDB_CONSOLE
        bool "Console output to GDB"
        depends on GDBSTUB
@@ -142,3 +153,7 @@ config GDBSTUB_ON_TTYSx
        default y
 
 endmenu
+
+config KERNEL_DEBUGGER
+       def_bool y
+       depends on GDBSTUB || KGDB
index 3b8a868188f59e88f2926d48298b54c188f318f2..0939462967e35d37a33aaf6ab3f86cf5f3bb36e3 100644 (file)
@@ -233,8 +233,7 @@ int ffs(int x)
 #define ext2_clear_bit_atomic(lock, nr, addr) \
        test_and_clear_bit((nr), (addr))
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
-#include <asm-generic/bitops/minix-le.h>
+#include <asm-generic/bitops/le.h>
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_BITOPS_H */
diff --git a/arch/mn10300/include/asm/debugger.h b/arch/mn10300/include/asm/debugger.h
new file mode 100644 (file)
index 0000000..e1d3b08
--- /dev/null
@@ -0,0 +1,43 @@
+/* Kernel debugger for MN10300
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_DEBUGGER_H
+#define _ASM_DEBUGGER_H
+
+#if defined(CONFIG_KERNEL_DEBUGGER)
+
+extern int debugger_intercept(enum exception_code, int, int, struct pt_regs *);
+extern int at_debugger_breakpoint(struct pt_regs *);
+
+#ifndef CONFIG_MN10300_DEBUGGER_CACHE_NO_FLUSH
+extern void debugger_local_cache_flushinv(void);
+extern void debugger_local_cache_flushinv_one(u8 *);
+#else
+static inline void debugger_local_cache_flushinv(void) {}
+static inline void debugger_local_cache_flushinv_one(u8 *addr) {}
+#endif
+
+#else /* CONFIG_KERNEL_DEBUGGER */
+
+static inline int debugger_intercept(enum exception_code excep,
+                                    int signo, int si_code,
+                                    struct pt_regs *regs)
+{
+       return 0;
+}
+
+static inline int at_debugger_breakpoint(struct pt_regs *regs)
+{
+       return 0;
+}
+
+#endif /* CONFIG_KERNEL_DEBUGGER */
+#endif /* _ASM_DEBUGGER_H */
index 34dcb8e68309e0331b12d5ce2051a05da04e4c3f..503efab2a516988bbb024666227cb6c279c0b9f7 100644 (file)
 
 extern void ____unhandled_size_in_do_div___(void);
 
+/*
+ * Beginning with gcc 4.6, the MDR register is represented explicitly.  We
+ * must, therefore, at least explicitly clobber the register when we make
+ * changes to it.  The following assembly fragments *could* be rearranged in
+ * order to leave the moves to/from the MDR register to the compiler, but the
+ * gains would be minimal at best.
+ */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+# define CLOBBER_MDR_CC                "mdr", "cc"
+#else
+# define CLOBBER_MDR_CC                "cc"
+#endif
+
 /*
  * divide n by base, leaving the result in n and returning the remainder
  * - we can do this quite efficiently on the MN10300 by cascading the divides
@@ -29,7 +42,7 @@ extern void ____unhandled_size_in_do_div___(void);
                    "mov        mdr,%1  \n"                             \
                    : "+r"(n), "=d"(__rem)                              \
                    : "r"(base), "1"(__rem)                             \
-                   : "cc"                                              \
+                   : CLOBBER_MDR_CC                                    \
                    );                                                  \
        } else if (sizeof(n) <= 8) {                                    \
                union {                                                 \
@@ -48,7 +61,7 @@ extern void ____unhandled_size_in_do_div___(void);
                    : "=d"(__rem), "=r"(__quot.w[1]), "=r"(__quot.w[0]) \
                    : "r"(base), "0"(__rem), "1"(__quot.w[1]),          \
                      "2"(__quot.w[0])                                  \
-                   : "cc"                                              \
+                   : CLOBBER_MDR_CC                                    \
                    );                                                  \
                n = __quot.l;                                           \
        } else {                                                        \
@@ -72,7 +85,7 @@ unsigned __muldiv64u(unsigned val, unsigned mult, unsigned div)
                                         * MDR = MDR:val%div */
            : "=r"(result)
            : "0"(val), "ir"(mult), "r"(div)
-           : "cc"
+           : CLOBBER_MDR_CC
            );
 
        return result;
@@ -93,7 +106,7 @@ signed __muldiv64s(signed val, signed mult, signed div)
                                         * MDR = MDR:val%div */
            : "=r"(result)
            : "0"(val), "ir"(mult), "r"(div)
-           : "cc"
+           : CLOBBER_MDR_CC
            );
 
        return result;
index b7625de8eade6754edf14f5de0340d9a0aa76e57..738ff72659d52307cdbc6195f768db79843c4c19 100644 (file)
@@ -55,7 +55,6 @@ static inline void clear_using_fpu(struct task_struct *tsk)
 
 extern asmlinkage void fpu_kill_state(struct task_struct *);
 extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
-extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code);
 extern asmlinkage void fpu_init_state(void);
 extern asmlinkage void fpu_save(struct fpu_state_struct *);
 extern int fpu_setup_sigcontext(struct fpucontext *buf);
@@ -113,7 +112,6 @@ static inline void flush_fpu(void)
 
 extern asmlinkage
 void unexpected_fpu_exception(struct pt_regs *, enum exception_code);
-#define fpu_invalid_op unexpected_fpu_exception
 #define fpu_exception unexpected_fpu_exception
 
 struct task_struct;
index 585b708c2bc0620fb37b56df22a33df91e8ad5a1..d65bbeebe50a6253fcc76f96367a444d12a89c4f 100644 (file)
 
 #ifndef __ASSEMBLY__
 extern void set_intr_level(int irq, u16 level);
-extern void mn10300_intc_set_level(unsigned int irq, unsigned int level);
-extern void mn10300_intc_clear(unsigned int irq);
-extern void mn10300_intc_set(unsigned int irq);
-extern void mn10300_intc_enable(unsigned int irq);
-extern void mn10300_intc_disable(unsigned int irq);
 extern void mn10300_set_lateack_irq_type(int irq);
 #endif
 
index 7a7ae12c7119e42f9c83943dec0ad14ab9dfa7a7..678f68d5f37bb7ef819ab900302ff9e14c61705d 100644 (file)
@@ -20,7 +20,7 @@
 /*
  * interrupt control
  * - "disabled": run in IM1/2
- *   - level 0 - GDB stub
+ *   - level 0 - kernel debugger
  *   - level 1 - virtual serial DMA (if present)
  *   - level 5 - normal interrupt priority
  *   - level 6 - timer interrupt
diff --git a/arch/mn10300/include/asm/kgdb.h b/arch/mn10300/include/asm/kgdb.h
new file mode 100644 (file)
index 0000000..eb245f1
--- /dev/null
@@ -0,0 +1,81 @@
+/* Kernel debugger for MN10300
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_KGDB_H
+#define _ASM_KGDB_H
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound
+ * buffers at least NUMREGBYTES*2 are needed for register packets
+ * Longer buffer is needed to list all threads
+ */
+#define BUFMAX                 1024
+
+/*
+ * Note that this register image is in a different order than the register
+ * image that Linux produces at interrupt time.
+ */
+enum regnames {
+       GDB_FR_D0               = 0,
+       GDB_FR_D1               = 1,
+       GDB_FR_D2               = 2,
+       GDB_FR_D3               = 3,
+       GDB_FR_A0               = 4,
+       GDB_FR_A1               = 5,
+       GDB_FR_A2               = 6,
+       GDB_FR_A3               = 7,
+
+       GDB_FR_SP               = 8,
+       GDB_FR_PC               = 9,
+       GDB_FR_MDR              = 10,
+       GDB_FR_EPSW             = 11,
+       GDB_FR_LIR              = 12,
+       GDB_FR_LAR              = 13,
+       GDB_FR_MDRQ             = 14,
+
+       GDB_FR_E0               = 15,
+       GDB_FR_E1               = 16,
+       GDB_FR_E2               = 17,
+       GDB_FR_E3               = 18,
+       GDB_FR_E4               = 19,
+       GDB_FR_E5               = 20,
+       GDB_FR_E6               = 21,
+       GDB_FR_E7               = 22,
+
+       GDB_FR_SSP              = 23,
+       GDB_FR_MSP              = 24,
+       GDB_FR_USP              = 25,
+       GDB_FR_MCRH             = 26,
+       GDB_FR_MCRL             = 27,
+       GDB_FR_MCVF             = 28,
+
+       GDB_FR_FPCR             = 29,
+       GDB_FR_DUMMY0           = 30,
+       GDB_FR_DUMMY1           = 31,
+
+       GDB_FR_FS0              = 32,
+
+       GDB_FR_SIZE             = 64,
+};
+
+#define GDB_ORIG_D0            41
+#define NUMREGBYTES            (GDB_FR_SIZE*4)
+
+static inline void arch_kgdb_breakpoint(void)
+{
+       asm(".globl __arch_kgdb_breakpoint; __arch_kgdb_breakpoint: break");
+}
+extern u8 __arch_kgdb_breakpoint;
+
+#define BREAK_INSTR_SIZE       1
+#define CACHE_FLUSH_IS_SAFE    1
+
+#endif /* _ASM_KGDB_H */
index a3930e43a958d1e4077c028afd94b122963032cb..6745dbe649441d906cc76de00df7c496961ba1d7 100644 (file)
@@ -34,7 +34,7 @@
 #define LOCAL_TIMER_IPI                193
 #define FLUSH_CACHE_IPI                194
 #define CALL_FUNCTION_NMI_IPI  195
-#define GDB_NMI_IPI            196
+#define DEBUGGER_NMI_IPI       196
 
 #define SMP_BOOT_IRQ           195
 
@@ -43,6 +43,7 @@
 #define LOCAL_TIMER_GxICR_LV   GxICR_LEVEL_4
 #define FLUSH_CACHE_GxICR_LV   GxICR_LEVEL_0
 #define SMP_BOOT_GxICR_LV      GxICR_LEVEL_0
+#define DEBUGGER_GxICR_LV      CONFIG_DEBUGGER_IRQ_LEVEL
 
 #define TIME_OUT_COUNT_BOOT_IPI        100
 #define DELAY_TIME_BOOT_IPI    75000
@@ -61,8 +62,9 @@
  * An alternate way of dealing with this could be to use the EPSW.S bits to
  * cache this information for systems with up to four CPUs.
  */
+#define arch_smp_processor_id()        (CPUID)
 #if 0
-#define raw_smp_processor_id() (CPUID)
+#define raw_smp_processor_id() (arch_smp_processor_id())
 #else
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 #endif
index aa07a4a5d7949406550ba001f7a8faaa631633ec..87c213002d4c9b30834b88aff215262160193541 100644 (file)
@@ -124,12 +124,18 @@ static inline unsigned long current_stack_pointer(void)
 
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) kzalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node)                      \
+               kzalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node)                      \
+               kmalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #endif
 
+#ifndef CONFIG_KGDB
 #define free_thread_info(ti)   kfree((ti))
+#else
+extern void free_thread_info(struct thread_info *);
+#endif
 #define get_thread_info(ti)    get_task_struct((ti)->task)
 #define put_thread_info(ti)    put_task_struct((ti)->task)
 
index 7b9f01042fd4e6da98f59a1fbc91e586470a4ea6..c1833eb192e3f2fb2e83c91c0e71b52b108ed0df 100644 (file)
@@ -26,13 +26,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide.  */
-typedef u32 dma_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TYPES_H */
index 8f5f1e81baf5c1527a2a82d1380f88918dd38d07..47ed30fe8178c45c5d99f3ec490feb41770e7c5c 100644 (file)
@@ -8,7 +8,8 @@ fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o
 
 obj-y   := process.o signal.o entry.o traps.o irq.o \
           ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
-          switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y)
+          switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) \
+          csrc-mn10300.o cevt-mn10300.o
 
 obj-$(CONFIG_SMP) += smp.o smp-low.o
 
@@ -20,13 +21,8 @@ obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o
 obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o
 obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o
 
-ifeq ($(CONFIG_MN10300_CACHE_ENABLED),y)
-obj-$(CONFIG_GDBSTUB) += gdb-cache.o
-endif
-
 obj-$(CONFIG_MN10300_RTC) += rtc.o
 obj-$(CONFIG_PROFILE) += profile.o profile-low.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_CSRC_MN10300) += csrc-mn10300.o
-obj-$(CONFIG_CEVT_MN10300) += cevt-mn10300.o
+obj-$(CONFIG_KGDB) += kgdb.o
index d4cb535bf7863750768090ed049d7702a9649e04..69cae0260786207d0c3b62fde6255f6b2f442995 100644 (file)
@@ -89,9 +89,10 @@ int __init init_clockevents(void)
        cd->name                = "Timestamp";
        cd->features            = CLOCK_EVT_FEAT_ONESHOT;
 
-       /* Calculate the min / max delta */
-       clockevent_set_clock(cd, MN10300_JCCLK);
+       /* Calculate shift/mult. We want to spawn at least 1 second */
+       clockevents_calc_mult_shift(cd, MN10300_JCCLK, 1);
 
+       /* Calculate the min / max delta */
        cd->max_delta_ns        = clockevent_delta2ns(TMJCBR_MAX, cd);
        cd->min_delta_ns        = clockevent_delta2ns(100, cd);
 
@@ -110,9 +111,9 @@ int __init init_clockevents(void)
 #if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
        /* setup timer irq affinity so it only runs on this cpu */
        {
-               struct irq_desc *desc;
-               desc = irq_to_desc(cd->irq);
-               cpumask_copy(desc->affinity, cpumask_of(cpu));
+               struct irq_data *data;
+               data = irq_get_irq_data(cd->irq);
+               cpumask_copy(data->affinity, cpumask_of(cpu));
                iact->flags |= IRQF_NOBALANCING;
        }
 #endif
index ba2f0c4d6e01c708309b5178c479c98eb152a5e2..45644cf18c41245904722c405d7faeff4861838a 100644 (file)
@@ -29,7 +29,6 @@ static struct clocksource clocksource_mn10300 = {
 int __init init_clocksource(void)
 {
        startup_timestamp_counter();
-       clocksource_set_clock(&clocksource_mn10300, MN10300_TSCCLK);
-       clocksource_register(&clocksource_mn10300);
+       clocksource_register_hz(&clocksource_mn10300, MN10300_TSCCLK);
        return 0;
 }
index f00b9bafcd3ebb7aa8d53e0e8db61aedf15652e2..fb93ad720b82665cb5abbf1add396fdfd2e53ec4 100644 (file)
@@ -266,7 +266,11 @@ ENTRY(raw_bus_error)
 
 ###############################################################################
 #
-# Miscellaneous exception entry points
+# NMI exception entry points
+#
+# This is used by ordinary interrupt channels that have the GxICR_NMI bit set
+# in addition to the main NMI and Watchdog channels.  SMP NMI IPIs use this
+# facility.
 #
 ###############################################################################
 ENTRY(nmi_handler)
@@ -281,7 +285,7 @@ ENTRY(nmi_handler)
        and     NMIAGR_GN,d0
        lsr     0x2,d0
        cmp     CALL_FUNCTION_NMI_IPI,d0
-       bne     5f                      # if not call function, jump
+       bne     nmi_not_smp_callfunc    # if not call function, jump
 
        # function call nmi ipi
        add     4,sp                    # no need to store TBR
@@ -295,59 +299,38 @@ ENTRY(nmi_handler)
        call    smp_nmi_call_function_interrupt[],0
        RESTORE_ALL
 
-5:
-#ifdef CONFIG_GDBSTUB
-       cmp     GDB_NMI_IPI,d0
-       bne     3f                      # if not gdb nmi ipi, jump
+nmi_not_smp_callfunc:
+#ifdef CONFIG_KERNEL_DEBUGGER
+       cmp     DEBUGGER_NMI_IPI,d0
+       bne     nmi_not_debugger        # if not kernel debugger NMI IPI, jump
 
-       # gdb nmi ipi
+       # kernel debugger NMI IPI
        add     4,sp                    # no need to store TBR
        mov     GxICR_DETECT,d0         # clear NMI
-       movbu   d0,(GxICR(GDB_NMI_IPI))
-       movhu   (GxICR(GDB_NMI_IPI)),d0
+       movbu   d0,(GxICR(DEBUGGER_NMI_IPI))
+       movhu   (GxICR(DEBUGGER_NMI_IPI)),d0
        and     ~EPSW_NMID,epsw         # enable NMI
-#ifdef CONFIG_MN10300_CACHE_ENABLED
-       mov     (gdbstub_nmi_opr_type),d0
-       cmp     GDBSTUB_NMI_CACHE_PURGE,d0
-       bne     4f                      # if not gdb cache purge, jump
-
-       # gdb cache purge nmi ipi
-       add     -20,sp
-       mov     d1,(4,sp)
-       mov     a0,(8,sp)
-       mov     a1,(12,sp)
-       mov     mdr,d0
-       mov     d0,(16,sp)
-       call    gdbstub_local_purge_cache[],0
-       mov     0x1,d0
-       mov     (CPUID),d1
-       asl     d1,d0
-       mov     gdbstub_nmi_cpumask,a0
-       bclr    d0,(a0)
-       mov     (4,sp),d1
-       mov     (8,sp),a0
-       mov     (12,sp),a1
-       mov     (16,sp),d0
-       mov     d0,mdr
-       add     20,sp
-       mov     (sp),d0
-       add     4,sp
-       rti
-4:
-#endif /* CONFIG_MN10300_CACHE_ENABLED */
-       # gdb wait nmi ipi
+
        mov     (sp),d0
        SAVE_ALL
-       call    gdbstub_nmi_wait[],0
+       mov     fp,d0                   # arg 0: stacked register file
+       mov     a2,d1                   # arg 1: exception number
+       call    debugger_nmi_interrupt[],0
        RESTORE_ALL
-3:
-#endif /* CONFIG_GDBSTUB */
+
+nmi_not_debugger:
+#endif /* CONFIG_KERNEL_DEBUGGER */
        mov     (sp),d0                 # restore TBR to d0
        add     4,sp
 #endif /* CONFIG_SMP */
 
        bra     __common_exception_nonmi
 
+###############################################################################
+#
+# General exception entry point
+#
+###############################################################################
 ENTRY(__common_exception)
        add     -4,sp
        mov     d0,(sp)
index 5f9c3fa19a85fb4459987789229387352cf1a809..bb5fa7df6c4425f5ea856fb5625dd8d785f78493 100644 (file)
@@ -69,24 +69,6 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
        force_sig_info(SIGFPE, &info, tsk);
 }
 
-/*
- * handle an FPU invalid_op exception
- * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c
- */
-asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code)
-{
-       siginfo_t info;
-
-       if (!user_mode(regs))
-               die_if_no_fixup("FPU invalid opcode", regs, code);
-
-       info.si_signo = SIGILL;
-       info.si_errno = 0;
-       info.si_code = ILL_COPROC;
-       info.si_addr = (void *) regs->pc;
-       force_sig_info(info.si_signo, &info, current);
-}
-
 /*
  * save the FPU state to a signal context
  */
diff --git a/arch/mn10300/kernel/gdb-cache.S b/arch/mn10300/kernel/gdb-cache.S
deleted file mode 100644 (file)
index 1108bad..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-###############################################################################
-#
-# MN10300 Low-level cache purging routines for gdbstub
-#
-# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
-# Written by David Howells (dhowells@redhat.com)
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public Licence
-# as published by the Free Software Foundation; either version
-# 2 of the Licence, or (at your option) any later version.
-#
-###############################################################################
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/smp.h>
-#include <asm/cache.h>
-#include <asm/cpu-regs.h>
-#include <asm/exceptions.h>
-#include <asm/frame.inc>
-#include <asm/serial-regs.h>
-
-       .text
-
-###############################################################################
-#
-# GDB stub cache purge
-#
-###############################################################################
-       .type   gdbstub_purge_cache,@function
-ENTRY(gdbstub_purge_cache)
-       #######################################################################
-       # read the addresses tagged in the cache's tag RAM and attempt to flush
-       # those addresses specifically
-       # - we rely on the hardware to filter out invalid tag entry addresses
-       mov     DCACHE_TAG(0,0),a0              # dcache tag RAM access address
-       mov     DCACHE_PURGE(0,0),a1            # dcache purge request address
-       mov     L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
-
-mn10300_dcache_flush_loop:
-       mov     (a0),d0
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
-       or      L1_CACHE_TAG_VALID,d0           # retain valid entries in the
-                                               # cache
-       mov     d0,(a1)                         # conditional purge
-
-mn10300_dcache_flush_skip:
-       add     L1_CACHE_BYTES,a0
-       add     L1_CACHE_BYTES,a1
-       add     -1,d1
-       bne     mn10300_dcache_flush_loop
-
-;;     # unconditionally flush and invalidate the dcache
-;;     mov     DCACHE_PURGE(0,0),a1            # dcache purge request address
-;;     mov     L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1     # total number of
-;;                                                     # entries
-;;
-;; gdbstub_purge_cache__dcache_loop:
-;;     mov     (a1),d0                         # unconditional purge
-;;
-;;     add     L1_CACHE_BYTES,a1
-;;     add     -1,d1
-;;     bne     gdbstub_purge_cache__dcache_loop
-
-       #######################################################################
-       # now invalidate the icache
-       mov     CHCTR,a0
-       movhu   (a0),a1
-
-       mov     epsw,d1
-       and     ~EPSW_IE,epsw
-       nop
-       nop
-
-       # disable the icache
-       and     ~CHCTR_ICEN,d0
-       movhu   d0,(a0)
-
-       # and wait for it to calm down
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-
-       # wait for the cache to finish
-       mov     CHCTR,a0
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # and reenable it
-       movhu   a1,(a0)
-       movhu   (a0),d0                 # read back to flush
-                                       # (SIGILLs all over without this)
-
-       mov     d1,epsw
-
-       ret     [],0
-
-       .size   gdbstub_purge_cache,.-gdbstub_purge_cache
index abdeea153c89643184df8f7b1c13805a504b0b7a..c859cacbb9c3bfc94008f251430b038c3744ffac 100644 (file)
@@ -59,10 +59,10 @@ void __init gdbstub_io_init(void)
 
        /* we want to get serial receive interrupts */
        set_intr_level(gdbstub_port->rx_irq,
-               NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
+               NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
        set_intr_level(gdbstub_port->tx_irq,
-               NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
-       set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
+               NUM2GxICR_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL));
+       set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_DEBUGGER_IRQ_LEVEL),
                gdbstub_io_rx_handler);
 
        *gdbstub_port->rx_icr |= GxICR_ENABLE;
@@ -88,7 +88,7 @@ void __init gdbstub_io_init(void)
 
        /* permit level 0 IRQs only */
        arch_local_change_intr_mask_level(
-               NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
+               NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
 }
 
 /*
index b169d99d9f20e8fd4b5da5ea353b70f02819844b..538266b2c9bc6cd0d87e9886d4f2509e61847664 100644 (file)
 #include <asm/system.h>
 #include <asm/gdb-stub.h>
 #include <asm/exceptions.h>
-#include <asm/cacheflush.h>
+#include <asm/debugger.h>
 #include <asm/serial-regs.h>
 #include <asm/busctl-regs.h>
 #include <unit/leds.h>
@@ -405,6 +405,7 @@ static int hexToInt(char **ptr, int *intValue)
        return (numChars);
 }
 
+#ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
 /*
  * We single-step by setting breakpoints. When an exception
  * is handled, we need to restore the instructions hoisted
@@ -729,6 +730,7 @@ static int gdbstub_single_step(struct pt_regs *regs)
        __gdbstub_restore_bp();
        return -EFAULT;
 }
+#endif /* CONFIG_GDBSTUB_ALLOW_SINGLE_STEP */
 
 #ifdef CONFIG_GDBSTUB_CONSOLE
 
@@ -1171,7 +1173,7 @@ int gdbstub_clear_breakpoint(u8 *addr, int len)
 
 /*
  * This function does all command processing for interfacing to gdb
- * - returns 1 if the exception should be skipped, 0 otherwise.
+ * - returns 0 if the exception should be skipped, -ERROR otherwise.
  */
 static int gdbstub(struct pt_regs *regs, enum exception_code excep)
 {
@@ -1186,7 +1188,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
        int loop;
 
        if (excep == EXCEP_FPU_DISABLED)
-               return 0;
+               return -ENOTSUPP;
 
        gdbstub_flush_caches = 0;
 
@@ -1195,7 +1197,7 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
        asm volatile("mov mdr,%0" : "=d"(mdr));
        local_save_flags(epsw);
        arch_local_change_intr_mask_level(
-               NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
+               NUM2EPSW_IM(CONFIG_DEBUGGER_IRQ_LEVEL + 1));
 
        gdbstub_store_fpu();
 
@@ -1208,11 +1210,13 @@ static int gdbstub(struct pt_regs *regs, enum exception_code excep)
        /* if we were single stepping, restore the opcodes hoisted for the
         * breakpoint[s] */
        broke = 0;
+#ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
        if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) ||
            (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc))
                broke = 1;
 
        __gdbstub_restore_bp();
+#endif
 
        if (gdbstub_rx_unget) {
                sigval = SIGINT;
@@ -1548,17 +1552,21 @@ packet_waiting:
                         * Step to next instruction
                         */
                case 's':
-                       /*
-                        * using the T flag doesn't seem to perform single
+                       /* Using the T flag doesn't seem to perform single
                         * stepping (it seems to wind up being caught by the
                         * JTAG unit), so we have to use breakpoints and
                         * continue instead.
                         */
+#ifdef CONFIG_GDBSTUB_ALLOW_SINGLE_STEP
                        if (gdbstub_single_step(regs) < 0)
                                /* ignore any fault error for now */
                                gdbstub_printk("unable to set single-step"
                                               " bp\n");
                        goto done;
+#else
+                       gdbstub_strcpy(output_buffer, "E01");
+                       break;
+#endif
 
                        /*
                         * Set baud rate (bBB)
@@ -1657,7 +1665,7 @@ done:
         * NB: We flush both caches, just to be sure...
         */
        if (gdbstub_flush_caches)
-               gdbstub_purge_cache();
+               debugger_local_cache_flushinv();
 
        gdbstub_load_fpu();
        mn10300_set_gdbleds(0);
@@ -1667,14 +1675,23 @@ done:
        touch_softlockup_watchdog();
 
        local_irq_restore(epsw);
-       return 1;
+       return 0;
+}
+
+/*
+ * Determine if we hit a debugger special breakpoint that needs skipping over
+ * automatically.
+ */
+int at_debugger_breakpoint(struct pt_regs *regs)
+{
+       return 0;
 }
 
 /*
  * handle event interception
  */
-asmlinkage int gdbstub_intercept(struct pt_regs *regs,
-                                enum exception_code excep)
+asmlinkage int debugger_intercept(enum exception_code excep,
+                                 int signo, int si_code, struct pt_regs *regs)
 {
        static u8 notfirst = 1;
        int ret;
@@ -1688,7 +1705,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
                asm("mov mdr,%0" : "=d"(mdr));
 
                gdbstub_entry(
-                       "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
+                       "--> debugger_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
                        regs, excep, mdr, regs->pc);
 
                gdbstub_entry(
@@ -1722,7 +1739,7 @@ asmlinkage int gdbstub_intercept(struct pt_regs *regs,
 
        ret = gdbstub(regs, excep);
 
-       gdbstub_entry("<-- gdbstub_intercept()\n");
+       gdbstub_entry("<-- debugger_intercept()\n");
        gdbstub_busy = 0;
        return ret;
 }
index 6a064ab5af0774b15887d9432209a9e2f9abe208..a5ac755dd69f4acbc8c6d213c47c285b8af41098 100644 (file)
@@ -30,16 +30,13 @@ extern void mn10300_low_ipi_handler(void);
 #endif
 
 /*
- * time.c
+ * smp.c
  */
-extern irqreturn_t local_timer_interrupt(void);
+#ifdef CONFIG_SMP
+extern void smp_jump_to_debugger(void);
+#endif
 
 /*
  * time.c
  */
-#ifdef CONFIG_CEVT_MN10300
-extern void clockevent_set_clock(struct clock_event_device *, unsigned int);
-#endif
-#ifdef CONFIG_CSRC_MN10300
-extern void clocksource_set_clock(struct clocksource *, unsigned int);
-#endif
+extern irqreturn_t local_timer_interrupt(void);
index ac11754ecec544c965c196f9dc857b2b398b22e0..5f7fc3eb45e60807c58a4888fce1bc5ca24e83ce 100644 (file)
@@ -37,8 +37,9 @@ atomic_t irq_err_count;
 /*
  * MN10300 interrupt controller operations
  */
-static void mn10300_cpupic_ack(unsigned int irq)
+static void mn10300_cpupic_ack(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long flags;
        u16 tmp;
 
@@ -61,13 +62,14 @@ static void __mask_and_set_icr(unsigned int irq,
        arch_local_irq_restore(flags);
 }
 
-static void mn10300_cpupic_mask(unsigned int irq)
+static void mn10300_cpupic_mask(struct irq_data *d)
 {
-       __mask_and_set_icr(irq, GxICR_LEVEL, 0);
+       __mask_and_set_icr(d->irq, GxICR_LEVEL, 0);
 }
 
-static void mn10300_cpupic_mask_ack(unsigned int irq)
+static void mn10300_cpupic_mask_ack(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
 #ifdef CONFIG_SMP
        unsigned long flags;
        u16 tmp;
@@ -85,7 +87,7 @@ static void mn10300_cpupic_mask_ack(unsigned int irq)
                tmp2 = GxICR(irq);
 
                irq_affinity_online[irq] =
-                       any_online_cpu(*irq_desc[irq].affinity);
+                       any_online_cpu(*d->affinity);
                CROSS_GxICR(irq, irq_affinity_online[irq]) =
                        (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@@ -97,13 +99,14 @@ static void mn10300_cpupic_mask_ack(unsigned int irq)
 #endif /* CONFIG_SMP */
 }
 
-static void mn10300_cpupic_unmask(unsigned int irq)
+static void mn10300_cpupic_unmask(struct irq_data *d)
 {
-       __mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE);
+       __mask_and_set_icr(d->irq, GxICR_LEVEL, GxICR_ENABLE);
 }
 
-static void mn10300_cpupic_unmask_clear(unsigned int irq)
+static void mn10300_cpupic_unmask_clear(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        /* the MN10300 PIC latches its interrupt request bit, even after the
         * device has ceased to assert its interrupt line and the interrupt
         * channel has been disabled in the PIC, so for level-triggered
@@ -121,7 +124,7 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq)
        } else {
                tmp = GxICR(irq);
 
-               irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity);
+               irq_affinity_online[irq] = any_online_cpu(*d->affinity);
                CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
        }
@@ -134,7 +137,8 @@ static void mn10300_cpupic_unmask_clear(unsigned int irq)
 
 #ifdef CONFIG_SMP
 static int
-mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
+mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
+                          bool force)
 {
        unsigned long flags;
        int err;
@@ -142,14 +146,14 @@ mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
        flags = arch_local_cli_save();
 
        /* check irq no */
-       switch (irq) {
+       switch (d->irq) {
        case TMJCIRQ:
        case RESCHEDULE_IPI:
        case CALL_FUNC_SINGLE_IPI:
        case LOCAL_TIMER_IPI:
        case FLUSH_CACHE_IPI:
        case CALL_FUNCTION_NMI_IPI:
-       case GDB_NMI_IPI:
+       case DEBUGGER_NMI_IPI:
 #ifdef CONFIG_MN10300_TTYSM0
        case SC0RXIRQ:
        case SC0TXIRQ:
@@ -181,7 +185,7 @@ mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
                break;
 
        default:
-               set_bit(irq, irq_affinity_request);
+               set_bit(d->irq, irq_affinity_request);
                err = 0;
                break;
        }
@@ -202,15 +206,15 @@ mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
  * mask_ack() is provided), and mask_ack() just masks.
  */
 static struct irq_chip mn10300_cpu_pic_level = {
-       .name           = "cpu_l",
-       .disable        = mn10300_cpupic_mask,
-       .enable         = mn10300_cpupic_unmask_clear,
-       .ack            = NULL,
-       .mask           = mn10300_cpupic_mask,
-       .mask_ack       = mn10300_cpupic_mask,
-       .unmask         = mn10300_cpupic_unmask_clear,
+       .name                   = "cpu_l",
+       .irq_disable            = mn10300_cpupic_mask,
+       .irq_enable             = mn10300_cpupic_unmask_clear,
+       .irq_ack                = NULL,
+       .irq_mask               = mn10300_cpupic_mask,
+       .irq_mask_ack           = mn10300_cpupic_mask,
+       .irq_unmask             = mn10300_cpupic_unmask_clear,
 #ifdef CONFIG_SMP
-       .set_affinity   = mn10300_cpupic_setaffinity,
+       .irq_set_affinity       = mn10300_cpupic_setaffinity,
 #endif
 };
 
@@ -220,15 +224,15 @@ static struct irq_chip mn10300_cpu_pic_level = {
  * We use the latch clearing function of the PIC as the 'ACK' function.
  */
 static struct irq_chip mn10300_cpu_pic_edge = {
-       .name           = "cpu_e",
-       .disable        = mn10300_cpupic_mask,
-       .enable         = mn10300_cpupic_unmask,
-       .ack            = mn10300_cpupic_ack,
-       .mask           = mn10300_cpupic_mask,
-       .mask_ack       = mn10300_cpupic_mask_ack,
-       .unmask         = mn10300_cpupic_unmask,
+       .name                   = "cpu_e",
+       .irq_disable            = mn10300_cpupic_mask,
+       .irq_enable             = mn10300_cpupic_unmask,
+       .irq_ack                = mn10300_cpupic_ack,
+       .irq_mask               = mn10300_cpupic_mask,
+       .irq_mask_ack           = mn10300_cpupic_mask_ack,
+       .irq_unmask             = mn10300_cpupic_unmask,
 #ifdef CONFIG_SMP
-       .set_affinity   = mn10300_cpupic_setaffinity,
+       .irq_set_affinity       = mn10300_cpupic_setaffinity,
 #endif
 };
 
@@ -252,31 +256,6 @@ void set_intr_level(int irq, u16 level)
        __mask_and_set_icr(irq, GxICR_ENABLE, level);
 }
 
-void mn10300_intc_set_level(unsigned int irq, unsigned int level)
-{
-       set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL);
-}
-
-void mn10300_intc_clear(unsigned int irq)
-{
-       __mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT);
-}
-
-void mn10300_intc_set(unsigned int irq)
-{
-       __mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT);
-}
-
-void mn10300_intc_enable(unsigned int irq)
-{
-       mn10300_cpupic_unmask(irq);
-}
-
-void mn10300_intc_disable(unsigned int irq)
-{
-       mn10300_cpupic_mask(irq);
-}
-
 /*
  * mark an interrupt to be ACK'd after interrupt handlers have been run rather
  * than before
@@ -296,7 +275,7 @@ void __init init_IRQ(void)
        int irq;
 
        for (irq = 0; irq < NR_IRQS; irq++)
-               if (irq_desc[irq].chip == &no_irq_chip)
+               if (get_irq_chip(irq) == &no_irq_chip)
                        /* due to the PIC latching interrupt requests, even
                         * when the IRQ is disabled, IRQ_PENDING is superfluous
                         * and we can use handle_level_irq() for edge-triggered
@@ -384,12 +363,12 @@ int show_interrupts(struct seq_file *p, void *v)
 
                        if (i < NR_CPU_IRQS)
                                seq_printf(p, " %14s.%u",
-                                          irq_desc[i].chip->name,
+                                          irq_desc[i].irq_data.chip->name,
                                           (GxICR(i) & GxICR_LEVEL) >>
                                           GxICR_LEVEL_SHIFT);
                        else
                                seq_printf(p, " %14s",
-                                          irq_desc[i].chip->name);
+                                          irq_desc[i].irq_data.chip->name);
 
                        seq_printf(p, "  %s", action->name);
 
diff --git a/arch/mn10300/kernel/kgdb.c b/arch/mn10300/kernel/kgdb.c
new file mode 100644 (file)
index 0000000..f6c981d
--- /dev/null
@@ -0,0 +1,502 @@
+/* kgdb support for MN10300
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/kgdb.h>
+#include <linux/uaccess.h>
+#include <unit/leds.h>
+#include <unit/serial.h>
+#include <asm/debugger.h>
+#include <asm/serial-regs.h>
+#include "internal.h"
+
+/*
+ * Software single-stepping breakpoint save (used by __switch_to())
+ */
+static struct thread_info *kgdb_sstep_thread;
+u8 *kgdb_sstep_bp_addr[2];
+u8 kgdb_sstep_bp[2];
+
+/*
+ * Copy kernel exception frame registers to the GDB register file
+ */
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       unsigned long ssp = (unsigned long) (regs + 1);
+
+       gdb_regs[GDB_FR_D0]     = regs->d0;
+       gdb_regs[GDB_FR_D1]     = regs->d1;
+       gdb_regs[GDB_FR_D2]     = regs->d2;
+       gdb_regs[GDB_FR_D3]     = regs->d3;
+       gdb_regs[GDB_FR_A0]     = regs->a0;
+       gdb_regs[GDB_FR_A1]     = regs->a1;
+       gdb_regs[GDB_FR_A2]     = regs->a2;
+       gdb_regs[GDB_FR_A3]     = regs->a3;
+       gdb_regs[GDB_FR_SP]     = (regs->epsw & EPSW_nSL) ? regs->sp : ssp;
+       gdb_regs[GDB_FR_PC]     = regs->pc;
+       gdb_regs[GDB_FR_MDR]    = regs->mdr;
+       gdb_regs[GDB_FR_EPSW]   = regs->epsw;
+       gdb_regs[GDB_FR_LIR]    = regs->lir;
+       gdb_regs[GDB_FR_LAR]    = regs->lar;
+       gdb_regs[GDB_FR_MDRQ]   = regs->mdrq;
+       gdb_regs[GDB_FR_E0]     = regs->e0;
+       gdb_regs[GDB_FR_E1]     = regs->e1;
+       gdb_regs[GDB_FR_E2]     = regs->e2;
+       gdb_regs[GDB_FR_E3]     = regs->e3;
+       gdb_regs[GDB_FR_E4]     = regs->e4;
+       gdb_regs[GDB_FR_E5]     = regs->e5;
+       gdb_regs[GDB_FR_E6]     = regs->e6;
+       gdb_regs[GDB_FR_E7]     = regs->e7;
+       gdb_regs[GDB_FR_SSP]    = ssp;
+       gdb_regs[GDB_FR_MSP]    = 0;
+       gdb_regs[GDB_FR_USP]    = regs->sp;
+       gdb_regs[GDB_FR_MCRH]   = regs->mcrh;
+       gdb_regs[GDB_FR_MCRL]   = regs->mcrl;
+       gdb_regs[GDB_FR_MCVF]   = regs->mcvf;
+       gdb_regs[GDB_FR_DUMMY0] = 0;
+       gdb_regs[GDB_FR_DUMMY1] = 0;
+       gdb_regs[GDB_FR_FS0]    = 0;
+}
+
+/*
+ * Extracts kernel SP/PC values understandable by gdb from the values
+ * saved by switch_to().
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+       gdb_regs[GDB_FR_SSP]    = p->thread.sp;
+       gdb_regs[GDB_FR_PC]     = p->thread.pc;
+       gdb_regs[GDB_FR_A3]     = p->thread.a3;
+       gdb_regs[GDB_FR_USP]    = p->thread.usp;
+       gdb_regs[GDB_FR_FPCR]   = p->thread.fpu_state.fpcr;
+}
+
+/*
+ * Fill kernel exception frame registers from the GDB register file
+ */
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       regs->d0        = gdb_regs[GDB_FR_D0];
+       regs->d1        = gdb_regs[GDB_FR_D1];
+       regs->d2        = gdb_regs[GDB_FR_D2];
+       regs->d3        = gdb_regs[GDB_FR_D3];
+       regs->a0        = gdb_regs[GDB_FR_A0];
+       regs->a1        = gdb_regs[GDB_FR_A1];
+       regs->a2        = gdb_regs[GDB_FR_A2];
+       regs->a3        = gdb_regs[GDB_FR_A3];
+       regs->sp        = gdb_regs[GDB_FR_SP];
+       regs->pc        = gdb_regs[GDB_FR_PC];
+       regs->mdr       = gdb_regs[GDB_FR_MDR];
+       regs->epsw      = gdb_regs[GDB_FR_EPSW];
+       regs->lir       = gdb_regs[GDB_FR_LIR];
+       regs->lar       = gdb_regs[GDB_FR_LAR];
+       regs->mdrq      = gdb_regs[GDB_FR_MDRQ];
+       regs->e0        = gdb_regs[GDB_FR_E0];
+       regs->e1        = gdb_regs[GDB_FR_E1];
+       regs->e2        = gdb_regs[GDB_FR_E2];
+       regs->e3        = gdb_regs[GDB_FR_E3];
+       regs->e4        = gdb_regs[GDB_FR_E4];
+       regs->e5        = gdb_regs[GDB_FR_E5];
+       regs->e6        = gdb_regs[GDB_FR_E6];
+       regs->e7        = gdb_regs[GDB_FR_E7];
+       regs->sp        = gdb_regs[GDB_FR_SSP];
+       /* gdb_regs[GDB_FR_MSP]; */
+       // regs->usp    = gdb_regs[GDB_FR_USP];
+       regs->mcrh      = gdb_regs[GDB_FR_MCRH];
+       regs->mcrl      = gdb_regs[GDB_FR_MCRL];
+       regs->mcvf      = gdb_regs[GDB_FR_MCVF];
+       /* gdb_regs[GDB_FR_DUMMY0]; */
+       /* gdb_regs[GDB_FR_DUMMY1]; */
+
+       // regs->fpcr   = gdb_regs[GDB_FR_FPCR];
+       // regs->fs0    = gdb_regs[GDB_FR_FS0];
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+       .gdb_bpt_instr  = { 0xff },
+       .flags          = KGDB_HW_BREAKPOINT,
+};
+
+static const unsigned char mn10300_kgdb_insn_sizes[256] =
+{
+       /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
+       1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
+       2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */
+       1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */
+       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */
+       2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
+       0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1  /* f */
+};
+
+/*
+ * Attempt to emulate single stepping by means of breakpoint instructions.
+ * Although there is a single-step trace flag in EPSW, its use is not
+ * sufficiently documented and is only intended for use with the JTAG debugger.
+ */
+static int kgdb_arch_do_singlestep(struct pt_regs *regs)
+{
+       unsigned long arg;
+       unsigned size;
+       u8 *pc = (u8 *)regs->pc, *sp = (u8 *)(regs + 1), cur;
+       u8 *x = NULL, *y = NULL;
+       int ret;
+
+       ret = probe_kernel_read(&cur, pc, 1);
+       if (ret < 0)
+               return ret;
+
+       size = mn10300_kgdb_insn_sizes[cur];
+       if (size > 0) {
+               x = pc + size;
+               goto set_x;
+       }
+
+       switch (cur) {
+               /* Bxx (d8,PC) */
+       case 0xc0 ... 0xca:
+               ret = probe_kernel_read(&arg, pc + 1, 1);
+               if (ret < 0)
+                       return ret;
+               x = pc + 2;
+               if (arg >= 0 && arg <= 2)
+                       goto set_x;
+               y = pc + (s8)arg;
+               goto set_x_and_y;
+
+               /* LXX (d8,PC) */
+       case 0xd0 ... 0xda:
+               x = pc + 1;
+               if (regs->pc == regs->lar)
+                       goto set_x;
+               y = (u8 *)regs->lar;
+               goto set_x_and_y;
+
+               /* SETLB - loads the next four bytes into the LIR register
+                * (which mustn't include a breakpoint instruction) */
+       case 0xdb:
+               x = pc + 5;
+               goto set_x;
+
+               /* JMP (d16,PC) or CALL (d16,PC) */
+       case 0xcc:
+       case 0xcd:
+               ret = probe_kernel_read(&arg, pc + 1, 2);
+               if (ret < 0)
+                       return ret;
+               x = pc + (s16)arg;
+               goto set_x;
+
+               /* JMP (d32,PC) or CALL (d32,PC) */
+       case 0xdc:
+       case 0xdd:
+               ret = probe_kernel_read(&arg, pc + 1, 4);
+               if (ret < 0)
+                       return ret;
+               x = pc + (s32)arg;
+               goto set_x;
+
+               /* RETF */
+       case 0xde:
+               x = (u8 *)regs->mdr;
+               goto set_x;
+
+               /* RET */
+       case 0xdf:
+               ret = probe_kernel_read(&arg, pc + 2, 1);
+               if (ret < 0)
+                       return ret;
+               ret = probe_kernel_read(&x, sp + (s8)arg, 4);
+               if (ret < 0)
+                       return ret;
+               goto set_x;
+
+       case 0xf0:
+               ret = probe_kernel_read(&cur, pc + 1, 1);
+               if (ret < 0)
+                       return ret;
+
+               if (cur >= 0xf0 && cur <= 0xf7) {
+                       /* JMP (An) / CALLS (An) */
+                       switch (cur & 3) {
+                       case 0: x = (u8 *)regs->a0; break;
+                       case 1: x = (u8 *)regs->a1; break;
+                       case 2: x = (u8 *)regs->a2; break;
+                       case 3: x = (u8 *)regs->a3; break;
+                       }
+                       goto set_x;
+               } else if (cur == 0xfc) {
+                       /* RETS */
+                       ret = probe_kernel_read(&x, sp, 4);
+                       if (ret < 0)
+                               return ret;
+                       goto set_x;
+               } else if (cur == 0xfd) {
+                       /* RTI */
+                       ret = probe_kernel_read(&x, sp + 4, 4);
+                       if (ret < 0)
+                               return ret;
+                       goto set_x;
+               } else {
+                       x = pc + 2;
+                       goto set_x;
+               }
+               break;
+
+               /* potential 3-byte conditional branches */
+       case 0xf8:
+               ret = probe_kernel_read(&cur, pc + 1, 1);
+               if (ret < 0)
+                       return ret;
+               x = pc + 3;
+
+               if (cur >= 0xe8 && cur <= 0xeb) {
+                       ret = probe_kernel_read(&arg, pc + 2, 1);
+                       if (ret < 0)
+                               return ret;
+                       if (arg >= 0 && arg <= 3)
+                               goto set_x;
+                       y = pc + (s8)arg;
+                       goto set_x_and_y;
+               }
+               goto set_x;
+
+       case 0xfa:
+               ret = probe_kernel_read(&cur, pc + 1, 1);
+               if (ret < 0)
+                       return ret;
+
+               if (cur == 0xff) {
+                       /* CALLS (d16,PC) */
+                       ret = probe_kernel_read(&arg, pc + 2, 2);
+                       if (ret < 0)
+                               return ret;
+                       x = pc + (s16)arg;
+                       goto set_x;
+               }
+
+               x = pc + 4;
+               goto set_x;
+
+       case 0xfc:
+               ret = probe_kernel_read(&cur, pc + 1, 1);
+               if (ret < 0)
+                       return ret;
+
+               if (cur == 0xff) {
+                       /* CALLS (d32,PC) */
+                       ret = probe_kernel_read(&arg, pc + 2, 4);
+                       if (ret < 0)
+                               return ret;
+                       x = pc + (s32)arg;
+                       goto set_x;
+               }
+
+               x = pc + 6;
+               goto set_x;
+       }
+
+       return 0;
+
+set_x:
+       kgdb_sstep_bp_addr[0] = x;
+       kgdb_sstep_bp_addr[1] = NULL;
+       ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1);
+       if (ret < 0)
+               return ret;
+       ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1);
+       if (ret < 0)
+               return ret;
+       kgdb_sstep_thread = current_thread_info();
+       debugger_local_cache_flushinv_one(x);
+       return ret;
+
+set_x_and_y:
+       kgdb_sstep_bp_addr[0] = x;
+       kgdb_sstep_bp_addr[1] = y;
+       ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1);
+       if (ret < 0)
+               return ret;
+       ret = probe_kernel_read(&kgdb_sstep_bp[1], y, 1);
+       if (ret < 0)
+               return ret;
+       ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1);
+       if (ret < 0)
+               return ret;
+       ret = probe_kernel_write(y, &arch_kgdb_ops.gdb_bpt_instr, 1);
+       if (ret < 0) {
+               probe_kernel_write(kgdb_sstep_bp_addr[0],
+                                  &kgdb_sstep_bp[0], 1);
+       } else {
+               kgdb_sstep_thread = current_thread_info();
+       }
+       debugger_local_cache_flushinv_one(x);
+       debugger_local_cache_flushinv_one(y);
+       return ret;
+}
+
+/*
+ * Remove emplaced single-step breakpoints, returning true if we hit one of
+ * them.
+ */
+static bool kgdb_arch_undo_singlestep(struct pt_regs *regs)
+{
+       bool hit = false;
+       u8 *x = kgdb_sstep_bp_addr[0], *y = kgdb_sstep_bp_addr[1];
+       u8 opcode;
+
+       if (kgdb_sstep_thread == current_thread_info()) {
+               if (x) {
+                       if (x == (u8 *)regs->pc)
+                               hit = true;
+                       if (probe_kernel_read(&opcode, x,
+                                             1) < 0 ||
+                           opcode != 0xff)
+                               BUG();
+                       probe_kernel_write(x, &kgdb_sstep_bp[0], 1);
+                       debugger_local_cache_flushinv_one(x);
+               }
+               if (y) {
+                       if (y == (u8 *)regs->pc)
+                               hit = true;
+                       if (probe_kernel_read(&opcode, y,
+                                             1) < 0 ||
+                           opcode != 0xff)
+                               BUG();
+                       probe_kernel_write(y, &kgdb_sstep_bp[1], 1);
+                       debugger_local_cache_flushinv_one(y);
+               }
+       }
+
+       kgdb_sstep_bp_addr[0] = NULL;
+       kgdb_sstep_bp_addr[1] = NULL;
+       kgdb_sstep_thread = NULL;
+       return hit;
+}
+
+/*
+ * Catch a single-step-pending thread being deleted and make sure the global
+ * single-step state is cleared.  At this point the breakpoints should have
+ * been removed by __switch_to().
+ */
+void free_thread_info(struct thread_info *ti)
+{
+       if (kgdb_sstep_thread == ti) {
+               kgdb_sstep_thread = NULL;
+
+               /* However, we may now be running in degraded mode, with most
+                * of the CPUs disabled until such a time as KGDB is reentered,
+                * so force immediate reentry */
+               kgdb_breakpoint();
+       }
+       kfree(ti);
+}
+
+/*
+ * Handle unknown packets and [CcsDk] packets
+ * - at this point breakpoints have been installed
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+                              char *remcom_in_buffer, char *remcom_out_buffer,
+                              struct pt_regs *regs)
+{
+       long addr;
+       char *ptr;
+
+       switch (remcom_in_buffer[0]) {
+       case 'c':
+       case 's':
+               /* try to read optional parameter, pc unchanged if no parm */
+               ptr = &remcom_in_buffer[1];
+               if (kgdb_hex2long(&ptr, &addr))
+                       regs->pc = addr;
+       case 'D':
+       case 'k':
+               atomic_set(&kgdb_cpu_doing_single_step, -1);
+
+               if (remcom_in_buffer[0] == 's') {
+                       kgdb_arch_do_singlestep(regs);
+                       kgdb_single_step = 1;
+                       atomic_set(&kgdb_cpu_doing_single_step,
+                                  raw_smp_processor_id());
+               }
+               return 0;
+       }
+       return -1; /* this means that we do not want to exit from the handler */
+}
+
+/*
+ * Handle event interception
+ * - returns 0 if the exception should be skipped, -ERROR otherwise.
+ */
+int debugger_intercept(enum exception_code excep, int signo, int si_code,
+                      struct pt_regs *regs)
+{
+       int ret;
+
+       if (kgdb_arch_undo_singlestep(regs)) {
+               excep = EXCEP_TRAP;
+               signo = SIGTRAP;
+               si_code = TRAP_TRACE;
+       }
+
+       ret = kgdb_handle_exception(excep, signo, si_code, regs);
+
+       debugger_local_cache_flushinv();
+
+       return ret;
+}
+
+/*
+ * Determine if we've hit a debugger special breakpoint
+ */
+int at_debugger_breakpoint(struct pt_regs *regs)
+{
+       return regs->pc == (unsigned long)&__arch_kgdb_breakpoint;
+}
+
+/*
+ * Initialise kgdb
+ */
+int kgdb_arch_init(void)
+{
+       return 0;
+}
+
+/*
+ * Do something, perhaps, but don't know what.
+ */
+void kgdb_arch_exit(void)
+{
+}
+
+#ifdef CONFIG_SMP
+void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code)
+{
+       kgdb_nmicallback(arch_smp_processor_id(), regs);
+       debugger_local_cache_flushinv();
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       smp_jump_to_debugger();
+}
+#endif
index 996384dba45da8dabca666d78328a00811aa4931..efca426a2ed4e7241e4a8a74d7b29a49c29a2973 100644 (file)
@@ -119,6 +119,10 @@ static int mn10300_serial_request_port(struct uart_port *);
 static void mn10300_serial_config_port(struct uart_port *, int);
 static int mn10300_serial_verify_port(struct uart_port *,
                                        struct serial_struct *);
+#ifdef CONFIG_CONSOLE_POLL
+static void mn10300_serial_poll_put_char(struct uart_port *, unsigned char);
+static int mn10300_serial_poll_get_char(struct uart_port *);
+#endif
 
 static const struct uart_ops mn10300_serial_ops = {
        .tx_empty       = mn10300_serial_tx_empty,
@@ -138,6 +142,10 @@ static const struct uart_ops mn10300_serial_ops = {
        .request_port   = mn10300_serial_request_port,
        .config_port    = mn10300_serial_config_port,
        .verify_port    = mn10300_serial_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_put_char  = mn10300_serial_poll_put_char,
+       .poll_get_char  = mn10300_serial_poll_get_char,
+#endif
 };
 
 static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id);
@@ -384,17 +392,21 @@ static void mn10300_serial_mask_ack(unsigned int irq)
        arch_local_irq_restore(flags);
 }
 
-static void mn10300_serial_nop(unsigned int irq)
+static void mn10300_serial_chip_mask_ack(struct irq_data *d)
+{
+       mn10300_serial_mask_ack(d->irq);
+}
+
+static void mn10300_serial_nop(struct irq_data *d)
 {
 }
 
 static struct irq_chip mn10300_serial_pic = {
        .name           = "mnserial",
-       .ack            = mn10300_serial_mask_ack,
-       .mask           = mn10300_serial_mask_ack,
-       .mask_ack       = mn10300_serial_mask_ack,
-       .unmask         = mn10300_serial_nop,
-       .end            = mn10300_serial_nop,
+       .irq_ack        = mn10300_serial_chip_mask_ack,
+       .irq_mask       = mn10300_serial_chip_mask_ack,
+       .irq_mask_ack   = mn10300_serial_chip_mask_ack,
+       .irq_unmask     = mn10300_serial_nop,
 };
 
 
@@ -1630,3 +1642,70 @@ static int __init mn10300_serial_console_init(void)
 
 console_initcall(mn10300_serial_console_init);
 #endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Polled character reception for the kernel debugger
+ */
+static int mn10300_serial_poll_get_char(struct uart_port *_port)
+{
+       struct mn10300_serial_port *port =
+               container_of(_port, struct mn10300_serial_port, uart);
+       unsigned ix;
+       u8 st, ch;
+
+       _enter("%s", port->name);
+
+       do {
+               /* pull chars out of the hat */
+               ix = port->rx_outp;
+               if (ix == port->rx_inp)
+                       return NO_POLL_CHAR;
+
+               ch = port->rx_buffer[ix++];
+               st = port->rx_buffer[ix++];
+               smp_rmb();
+               port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1);
+
+       } while (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF));
+
+       return ch;
+}
+
+
+/*
+ * Polled character transmission for the kernel debugger
+ */
+static void mn10300_serial_poll_put_char(struct uart_port *_port,
+                                        unsigned char ch)
+{
+       struct mn10300_serial_port *port =
+               container_of(_port, struct mn10300_serial_port, uart);
+       u8 intr, tmp;
+
+       /* wait for the transmitter to finish anything it might be doing (and
+        * this includes the virtual DMA handler, so it might take a while) */
+       while (*port->_status & (SC01STR_TBF | SC01STR_TXF))
+               continue;
+
+       /* disable the Tx ready interrupt */
+       intr = *port->_intr;
+       *port->_intr = intr & ~SC01ICR_TI;
+       tmp = *port->_intr;
+
+       if (ch == 0x0a) {
+               *(u8 *) port->_txb = 0x0d;
+               while (*port->_status & SC01STR_TBF)
+                       continue;
+       }
+
+       *(u8 *) port->_txb = ch;
+       while (*port->_status & SC01STR_TBF)
+               continue;
+
+       /* restore the Tx interrupt flag */
+       *port->_intr = intr;
+       tmp = *port->_intr;
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
index e1b14a6ed544675bf7929dc7861876a1a3bf2cc8..28eec3102535c86c91649b336aeb0b9f5677b75c 100644 (file)
@@ -135,7 +135,7 @@ void release_segments(struct mm_struct *mm)
 
 void machine_restart(char *cmd)
 {
-#ifdef CONFIG_GDBSTUB
+#ifdef CONFIG_KERNEL_DEBUGGER
        gdbstub_exit(0);
 #endif
 
@@ -148,14 +148,14 @@ void machine_restart(char *cmd)
 
 void machine_halt(void)
 {
-#ifdef CONFIG_GDBSTUB
+#ifdef CONFIG_KERNEL_DEBUGGER
        gdbstub_exit(0);
 #endif
 }
 
 void machine_power_off(void)
 {
-#ifdef CONFIG_GDBSTUB
+#ifdef CONFIG_KERNEL_DEBUGGER
        gdbstub_exit(0);
 #endif
 }
index 0dcd1c686ba8e2c7126c1a478a034f3c7ad6e68e..51c02f97dceaa924aaba64383efcbb93032ad313 100644 (file)
@@ -113,15 +113,17 @@ static void init_ipi(void);
  */
 static void mn10300_ipi_disable(unsigned int irq);
 static void mn10300_ipi_enable(unsigned int irq);
-static void mn10300_ipi_ack(unsigned int irq);
-static void mn10300_ipi_nop(unsigned int irq);
+static void mn10300_ipi_chip_disable(struct irq_data *d);
+static void mn10300_ipi_chip_enable(struct irq_data *d);
+static void mn10300_ipi_ack(struct irq_data *d);
+static void mn10300_ipi_nop(struct irq_data *d);
 
 static struct irq_chip mn10300_ipi_type = {
        .name           = "cpu_ipi",
-       .disable        = mn10300_ipi_disable,
-       .enable         = mn10300_ipi_enable,
-       .ack            = mn10300_ipi_ack,
-       .eoi            = mn10300_ipi_nop
+       .irq_disable    = mn10300_ipi_chip_disable,
+       .irq_enable     = mn10300_ipi_chip_enable,
+       .irq_ack        = mn10300_ipi_ack,
+       .irq_eoi        = mn10300_ipi_nop
 };
 
 static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id);
@@ -236,6 +238,11 @@ static void mn10300_ipi_enable(unsigned int irq)
        arch_local_irq_restore(flags);
 }
 
+static void mn10300_ipi_chip_enable(struct irq_data *d)
+{
+       mn10300_ipi_enable(d->irq);
+}
+
 /**
  * mn10300_ipi_disable - Disable an IPI
  * @irq: The IPI to be disabled.
@@ -254,6 +261,12 @@ static void mn10300_ipi_disable(unsigned int irq)
        arch_local_irq_restore(flags);
 }
 
+static void mn10300_ipi_chip_disable(struct irq_data *d)
+{
+       mn10300_ipi_disable(d->irq);
+}
+
+
 /**
  * mn10300_ipi_ack - Acknowledge an IPI interrupt in the PIC
  * @irq: The IPI to be acknowledged.
@@ -261,8 +274,9 @@ static void mn10300_ipi_disable(unsigned int irq)
  * Clear the interrupt detection flag for the IPI on the appropriate interrupt
  * channel in the PIC.
  */
-static void mn10300_ipi_ack(unsigned int irq)
+static void mn10300_ipi_ack(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long flags;
        u16 tmp;
 
@@ -276,7 +290,7 @@ static void mn10300_ipi_ack(unsigned int irq)
  * mn10300_ipi_nop - Dummy IPI action
  * @irq: The IPI to be acted upon.
  */
-static void mn10300_ipi_nop(unsigned int irq)
+static void mn10300_ipi_nop(struct irq_data *d)
 {
 }
 
@@ -425,6 +439,22 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
        return ret;
 }
 
+/**
+ * smp_jump_to_debugger - Make other CPUs enter the debugger by sending an IPI
+ *
+ * Send a non-maskable request to all other CPUs in the system, instructing
+ * them to jump into the debugger.  The caller is responsible for checking that
+ * the other CPUs responded to the instruction.
+ *
+ * The caller should make sure that this CPU's debugger IPI is disabled.
+ */
+void smp_jump_to_debugger(void)
+{
+       if (num_online_cpus() > 1)
+               /* Send a message to all other CPUs */
+               send_IPI_allbutself(DEBUGGER_NMI_IPI);
+}
+
 /**
  * stop_this_cpu - Callback to stop a CPU.
  * @unused: Callback context (ignored).
@@ -589,7 +619,7 @@ static void __init smp_cpu_init(void)
 /**
  * smp_prepare_cpu_init - Initialise CPU in startup_secondary
  *
- * Set interrupt level 0-6 setting and init ICR of gdbstub.
+ * Set interrupt level 0-6 setting and init ICR of the kernel debugger.
  */
 void smp_prepare_cpu_init(void)
 {
@@ -608,15 +638,15 @@ void smp_prepare_cpu_init(void)
        for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
                GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
 
-#ifdef CONFIG_GDBSTUB
-       /* initialise GDB-stub */
+#ifdef CONFIG_KERNEL_DEBUGGER
+       /* initialise the kernel debugger interrupt */
        do {
                unsigned long flags;
                u16 tmp16;
 
                flags = arch_local_cli_save();
-               GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
-               tmp16 = GxICR(GDB_NMI_IPI);
+               GxICR(DEBUGGER_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+               tmp16 = GxICR(DEBUGGER_NMI_IPI);
                arch_local_irq_restore(flags);
        } while (0);
 #endif
index 9074d0fb8788fbc5187d6d77b026a271c91050f5..de3e74fc9ea04980099b6a6c68546e311e7cb565 100644 (file)
@@ -39,11 +39,17 @@ ENTRY(__switch_to)
 
        # save prev context
        mov     __switch_back,d0
-       mov     d0,(THREAD_PC,a0)
        mov     sp,a2
        mov     a2,(THREAD_SP,a0)
        mov     a3,(THREAD_A3,a0)
 
+#ifdef CONFIG_KGDB
+       btst    0xff,(kgdb_single_step)
+       bne     __switch_to__lift_sstep_bp
+__switch_to__continue:
+#endif
+       mov     d0,(THREAD_PC,a0)
+
        mov     (THREAD_A3,a1),a3
        mov     (THREAD_SP,a1),a2
 
@@ -68,3 +74,106 @@ ENTRY(__switch_to)
 __switch_back:
        and     ~EPSW_NMID,epsw
        ret     [d2,d3,a2,a3,exreg1],32
+
+#ifdef CONFIG_KGDB
+###############################################################################
+#
+# Lift the single-step breakpoints when the task being traced is switched out
+# A0 = prev
+# A1 = next
+#
+###############################################################################
+__switch_to__lift_sstep_bp:
+       add     -12,sp
+       mov     a0,e4
+       mov     a1,e5
+
+       # Clear the single-step flag to prevent us coming this way until we get
+       # switched back in
+       bclr    0xff,(kgdb_single_step)
+
+       # Remove first breakpoint
+       mov     (kgdb_sstep_bp_addr),a2
+       cmp     0,a2
+       beq     1f
+       movbu   (kgdb_sstep_bp),d0
+       movbu   d0,(a2)
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+       mov     a2,d0
+       mov     a2,d1
+       add     1,d1
+       calls   flush_icache_range
+#endif
+1:
+
+       # Remove second breakpoint
+       mov     (kgdb_sstep_bp_addr+4),a2
+       cmp     0,a2
+       beq     2f
+       movbu   (kgdb_sstep_bp+1),d0
+       movbu   d0,(a2)
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+       mov     a2,d0
+       mov     a2,d1
+       add     1,d1
+       calls   flush_icache_range
+#endif
+2:
+
+       # Change the resumption address and return
+       mov     __switch_back__reinstall_sstep_bp,d0
+       mov     e4,a0
+       mov     e5,a1
+       add     12,sp
+       bra     __switch_to__continue
+
+###############################################################################
+#
+# Reinstall the single-step breakpoints when the task being traced is switched
+# back in (A1 points to the new thread_struct).
+#
+###############################################################################
+__switch_back__reinstall_sstep_bp:
+       add     -12,sp
+       mov     a0,e4                   # save the return value
+       mov     0xff,d3
+
+       # Reinstall first breakpoint
+       mov     (kgdb_sstep_bp_addr),a2
+       cmp     0,a2
+       beq     1f
+       movbu   (a2),d0
+       movbu   d0,(kgdb_sstep_bp)
+       movbu   d3,(a2)
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+       mov     a2,d0
+       mov     a2,d1
+       add     1,d1
+       calls   flush_icache_range
+#endif
+1:
+
+       # Reinstall second breakpoint
+       mov     (kgdb_sstep_bp_addr+4),a2
+       cmp     0,a2
+       beq     2f
+       movbu   (a2),d0
+       movbu   d0,(kgdb_sstep_bp+1)
+       movbu   d3,(a2)
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE) || defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+       mov     a2,d0
+       mov     a2,d1
+       add     1,d1
+       calls   flush_icache_range
+#endif
+2:
+
+       mov     d3,(kgdb_single_step)
+
+       # Restore the return value (the previous thread_struct pointer)
+       mov     e4,a0
+       mov     a0,d0
+       add     12,sp
+       bra     __switch_back
+
+#endif /* CONFIG_KGDB */
index 5b955000626d9f79fc3abe126dcc117c0076bc1e..67c6416a58f8304cae8a6eb3c5f4307185afb903 100644 (file)
@@ -93,79 +93,6 @@ irqreturn_t local_timer_interrupt(void)
        return IRQ_HANDLED;
 }
 
-#ifndef CONFIG_GENERIC_TIME
-/*
- * advance the kernel's time keeping clocks (xtime and jiffies)
- * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time
- *   there's a need to update
- */
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-       unsigned tsc, elapse;
-       irqreturn_t ret;
-
-       while (tsc = get_cycles(),
-              elapse = tsc - mn10300_last_tsc, /* time elapsed since last
-                                                * tick */
-              elapse > MN10300_TSC_PER_HZ
-              ) {
-               mn10300_last_tsc += MN10300_TSC_PER_HZ;
-
-               /* advance the kernel's time tracking system */
-               xtime_update(1);
-       }
-
-       ret = local_timer_interrupt();
-#ifdef CONFIG_SMP
-       send_IPI_allbutself(LOCAL_TIMER_IPI);
-#endif
-       return ret;
-}
-
-static struct irqaction timer_irq = {
-       .handler        = timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
-       .name           = "timer",
-};
-#endif /* CONFIG_GENERIC_TIME */
-
-#ifdef CONFIG_CSRC_MN10300
-void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
-{
-       u64 temp;
-       u32 shift;
-
-       /* Find a shift value */
-       for (shift = 32; shift > 0; shift--) {
-               temp = (u64) NSEC_PER_SEC << shift;
-               do_div(temp, clock);
-               if ((temp >> 32) == 0)
-                       break;
-       }
-       cs->shift = shift;
-       cs->mult = (u32) temp;
-}
-#endif
-
-#if CONFIG_CEVT_MN10300
-void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
-                                   unsigned int clock)
-{
-       u64 temp;
-       u32 shift;
-
-       /* Find a shift value */
-       for (shift = 32; shift > 0; shift--) {
-               temp = (u64) clock << shift;
-               do_div(temp, NSEC_PER_SEC);
-               if ((temp >> 32) == 0)
-                       break;
-       }
-       cd->shift = shift;
-       cd->mult = (u32) temp;
-}
-#endif
-
 /*
  * initialise the various timers used by the main part of the kernel
  */
@@ -177,11 +104,7 @@ void __init time_init(void)
         */
        TMPSCNT |= TMPSCNT_ENABLE;
 
-#ifdef CONFIG_GENERIC_TIME
        init_clocksource();
-#else
-       startup_timestamp_counter();
-#endif
 
        printk(KERN_INFO
               "timestamp counter I/O clock running at %lu.%02lu"
@@ -190,12 +113,7 @@ void __init time_init(void)
 
        mn10300_last_tsc = read_timestamp_counter();
 
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
        init_clockevents();
-#else
-       reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
-       setup_jiffies_interrupt(TMJCIRQ, &timer_irq, CONFIG_TIMER_IRQ_LEVEL);
-#endif
 
 #ifdef CONFIG_MN10300_WD_TIMER
        /* start the watchdog timer */
index b90c3f160c77b0e598fe90578d9362de54e4a1f1..f03cb278828f400c1e66580be491c30da507e9b3 100644 (file)
@@ -38,8 +38,9 @@
 #include <asm/busctl-regs.h>
 #include <unit/leds.h>
 #include <asm/fpu.h>
-#include <asm/gdb-stub.h>
 #include <asm/sections.h>
+#include <asm/debugger.h>
+#include "internal.h"
 
 #if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff)
 #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
@@ -49,63 +50,169 @@ int kstack_depth_to_print = 24;
 
 spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock);
 
-ATOMIC_NOTIFIER_HEAD(mn10300_die_chain);
+struct exception_to_signal_map {
+       u8      signo;
+       u32     si_code;
+};
+
+static const struct exception_to_signal_map exception_to_signal_map[256] = {
+       /* MMU exceptions */
+       [EXCEP_ITLBMISS >> 3]   = { 0, 0 },
+       [EXCEP_DTLBMISS >> 3]   = { 0, 0 },
+       [EXCEP_IAERROR >> 3]    = { 0, 0 },
+       [EXCEP_DAERROR >> 3]    = { 0, 0 },
+
+       /* system exceptions */
+       [EXCEP_TRAP >> 3]       = { SIGTRAP,    TRAP_BRKPT },
+       [EXCEP_ISTEP >> 3]      = { SIGTRAP,    TRAP_TRACE },   /* Monitor */
+       [EXCEP_IBREAK >> 3]     = { SIGTRAP,    TRAP_HWBKPT },  /* Monitor */
+       [EXCEP_OBREAK >> 3]     = { SIGTRAP,    TRAP_HWBKPT },  /* Monitor */
+       [EXCEP_PRIVINS >> 3]    = { SIGILL,     ILL_PRVOPC },
+       [EXCEP_UNIMPINS >> 3]   = { SIGILL,     ILL_ILLOPC },
+       [EXCEP_UNIMPEXINS >> 3] = { SIGILL,     ILL_ILLOPC },
+       [EXCEP_MEMERR >> 3]     = { SIGSEGV,    SEGV_ACCERR },
+       [EXCEP_MISALIGN >> 3]   = { SIGBUS,     BUS_ADRALN },
+       [EXCEP_BUSERROR >> 3]   = { SIGBUS,     BUS_ADRERR },
+       [EXCEP_ILLINSACC >> 3]  = { SIGSEGV,    SEGV_ACCERR },
+       [EXCEP_ILLDATACC >> 3]  = { SIGSEGV,    SEGV_ACCERR },
+       [EXCEP_IOINSACC >> 3]   = { SIGSEGV,    SEGV_ACCERR },
+       [EXCEP_PRIVINSACC >> 3] = { SIGSEGV,    SEGV_ACCERR }, /* userspace */
+       [EXCEP_PRIVDATACC >> 3] = { SIGSEGV,    SEGV_ACCERR }, /* userspace */
+       [EXCEP_DATINSACC >> 3]  = { SIGSEGV,    SEGV_ACCERR },
+       [EXCEP_DOUBLE_FAULT >> 3] = { SIGILL,   ILL_BADSTK },
+
+       /* FPU exceptions */
+       [EXCEP_FPU_DISABLED >> 3] = { SIGILL,   ILL_COPROC },
+       [EXCEP_FPU_UNIMPINS >> 3] = { SIGILL,   ILL_COPROC },
+       [EXCEP_FPU_OPERATION >> 3] = { SIGFPE,  FPE_INTDIV },
+
+       /* interrupts */
+       [EXCEP_WDT >> 3]        = { SIGALRM,    0 },
+       [EXCEP_NMI >> 3]        = { SIGQUIT,    0 },
+       [EXCEP_IRQ_LEVEL0 >> 3] = { SIGINT,     0 },
+       [EXCEP_IRQ_LEVEL1 >> 3] = { 0, 0 },
+       [EXCEP_IRQ_LEVEL2 >> 3] = { 0, 0 },
+       [EXCEP_IRQ_LEVEL3 >> 3] = { 0, 0 },
+       [EXCEP_IRQ_LEVEL4 >> 3] = { 0, 0 },
+       [EXCEP_IRQ_LEVEL5 >> 3] = { 0, 0 },
+       [EXCEP_IRQ_LEVEL6 >> 3] = { 0, 0 },
+
+       /* system calls */
+       [EXCEP_SYSCALL0 >> 3]   = { 0, 0 },
+       [EXCEP_SYSCALL1 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL2 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL3 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL4 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL5 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL6 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL7 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL8 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL9 >> 3]   = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL10 >> 3]  = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL11 >> 3]  = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL12 >> 3]  = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL13 >> 3]  = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL14 >> 3]  = { SIGILL,     ILL_ILLTRP },
+       [EXCEP_SYSCALL15 >> 3]  = { SIGABRT,    0 },
+};
 
 /*
- * These constants are for searching for possible module text
- * segments. MODULE_RANGE is a guess of how much space is likely
- * to be vmalloced.
+ * Handle kernel exceptions.
+ *
+ * See if there's a fixup handler we can force a jump to when an exception
+ * happens due to something kernel code did
  */
-#define MODULE_RANGE (8 * 1024 * 1024)
-
-#define DO_ERROR(signr, prologue, str, name)                   \
-asmlinkage void name(struct pt_regs *regs, u32 intcode)                \
-{                                                              \
-       prologue;                                               \
-       if (die_if_no_fixup(str, regs, intcode))                \
-               return;                                         \
-       force_sig(signr, current);                              \
-}
+int die_if_no_fixup(const char *str, struct pt_regs *regs,
+                   enum exception_code code)
+{
+       u8 opcode;
+       int signo, si_code;
+
+       if (user_mode(regs))
+               return 0;
+
+       peripheral_leds_display_exception(code);
+
+       signo = exception_to_signal_map[code >> 3].signo;
+       si_code = exception_to_signal_map[code >> 3].si_code;
+
+       switch (code) {
+               /* see if we can fixup the kernel accessing memory */
+       case EXCEP_ITLBMISS:
+       case EXCEP_DTLBMISS:
+       case EXCEP_IAERROR:
+       case EXCEP_DAERROR:
+       case EXCEP_MEMERR:
+       case EXCEP_MISALIGN:
+       case EXCEP_BUSERROR:
+       case EXCEP_ILLDATACC:
+       case EXCEP_IOINSACC:
+       case EXCEP_PRIVINSACC:
+       case EXCEP_PRIVDATACC:
+       case EXCEP_DATINSACC:
+               if (fixup_exception(regs))
+                       return 1;
+               break;
 
-#define DO_EINFO(signr, prologue, str, name, sicode)                   \
-asmlinkage void name(struct pt_regs *regs, u32 intcode)                        \
-{                                                                      \
-       siginfo_t info;                                                 \
-       prologue;                                                       \
-       if (die_if_no_fixup(str, regs, intcode))                        \
-               return;                                                 \
-       info.si_signo = signr;                                          \
-       if (signr == SIGILL && sicode == ILL_ILLOPC) {                  \
-               uint8_t opcode;                                         \
-               if (get_user(opcode, (uint8_t __user *)regs->pc) == 0)  \
-                       if (opcode == 0xff)                             \
-                               info.si_signo = SIGTRAP;                \
-       }                                                               \
-       info.si_errno = 0;                                              \
-       info.si_code = sicode;                                          \
-       info.si_addr = (void *) regs->pc;                               \
-       force_sig_info(info.si_signo, &info, current);                  \
+       case EXCEP_TRAP:
+       case EXCEP_UNIMPINS:
+               if (get_user(opcode, (uint8_t __user *)regs->pc) != 0)
+                       break;
+               if (opcode == 0xff) {
+                       if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
+                               return 1;
+                       if (at_debugger_breakpoint(regs))
+                               regs->pc++;
+                       signo = SIGTRAP;
+                       si_code = TRAP_BRKPT;
+               }
+               break;
+
+       case EXCEP_SYSCALL1 ... EXCEP_SYSCALL14:
+               /* syscall return addr is _after_ the instruction */
+               regs->pc -= 2;
+               break;
+
+       case EXCEP_SYSCALL15:
+               if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_WARN)
+                       return 1;
+
+               /* syscall return addr is _after_ the instruction */
+               regs->pc -= 2;
+               break;
+
+       default:
+               break;
+       }
+
+       if (debugger_intercept(code, signo, si_code, regs) == 0)
+               return 1;
+
+       if (notify_die(DIE_GPF, str, regs, code, 0, 0))
+               return 1;
+
+       /* make the process die as the last resort */
+       die(str, regs, code);
 }
 
-DO_ERROR(SIGTRAP, {}, "trap",                  trap);
-DO_ERROR(SIGSEGV, {}, "ibreak",                        ibreak);
-DO_ERROR(SIGSEGV, {}, "obreak",                        obreak);
-DO_EINFO(SIGSEGV, {}, "access error",          access_error,   SEGV_ACCERR);
-DO_EINFO(SIGSEGV, {}, "insn access error",     insn_acc_error, SEGV_ACCERR);
-DO_EINFO(SIGSEGV, {}, "data access error",     data_acc_error, SEGV_ACCERR);
-DO_EINFO(SIGILL,  {}, "privileged opcode",     priv_op,        ILL_PRVOPC);
-DO_EINFO(SIGILL,  {}, "invalid opcode",                invalid_op,     ILL_ILLOPC);
-DO_EINFO(SIGILL,  {}, "invalid ex opcode",     invalid_exop,   ILL_ILLOPC);
-DO_EINFO(SIGBUS,  {}, "invalid address",       mem_error,      BUS_ADRERR);
-DO_EINFO(SIGBUS,  {}, "bus error",             bus_error,      BUS_ADRERR);
-
-DO_ERROR(SIGTRAP,
-#ifndef CONFIG_MN10300_USING_JTAG
-        DCR &= ~0x0001,
-#else
-        {},
-#endif
-        "single step", istep);
+/*
+ * General exception handler
+ */
+asmlinkage void handle_exception(struct pt_regs *regs, u32 intcode)
+{
+       siginfo_t info;
+
+       /* deal with kernel exceptions here */
+       if (die_if_no_fixup(NULL, regs, intcode))
+               return;
+
+       /* otherwise it's a userspace exception */
+       info.si_signo = exception_to_signal_map[intcode >> 3].signo;
+       info.si_code = exception_to_signal_map[intcode >> 3].si_code;
+       info.si_errno = 0;
+       info.si_addr = (void *) regs->pc;
+       force_sig_info(info.si_signo, &info, current);
+}
 
 /*
  * handle NMI
@@ -113,10 +220,8 @@ DO_ERROR(SIGTRAP,
 asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
 {
        /* see if gdbstub wants to deal with it */
-#ifdef CONFIG_GDBSTUB
-       if (gdbstub_intercept(regs, code))
+       if (debugger_intercept(code, SIGQUIT, 0, regs))
                return;
-#endif
 
        printk(KERN_WARNING "--- Register Dump ---\n");
        show_registers(regs);
@@ -128,29 +233,36 @@ asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
  */
 void show_trace(unsigned long *sp)
 {
-       unsigned long *stack, addr, module_start, module_end;
-       int i;
-
-       printk(KERN_EMERG "\nCall Trace:");
-
-       stack = sp;
-       i = 0;
-       module_start = VMALLOC_START;
-       module_end = VMALLOC_END;
+       unsigned long bottom, stack, addr, fp, raslot;
+
+       printk(KERN_EMERG "\nCall Trace:\n");
+
+       //stack = (unsigned long)sp;
+       asm("mov sp,%0" : "=a"(stack));
+       asm("mov a3,%0" : "=r"(fp));
+
+       raslot = ULONG_MAX;
+       bottom = (stack + THREAD_SIZE) & ~(THREAD_SIZE - 1);
+       for (; stack < bottom; stack += sizeof(addr)) {
+               addr = *(unsigned long *)stack;
+               if (stack == fp) {
+                       if (addr > stack && addr < bottom) {
+                               fp = addr;
+                               raslot = stack + sizeof(addr);
+                               continue;
+                       }
+                       fp = 0;
+                       raslot = ULONG_MAX;
+               }
 
-       while (((long) stack & (THREAD_SIZE - 1)) != 0) {
-               addr = *stack++;
                if (__kernel_text_address(addr)) {
-#if 1
                        printk(" [<%08lx>]", addr);
+                       if (stack >= raslot)
+                               raslot = ULONG_MAX;
+                       else
+                               printk(" ?");
                        print_symbol(" %s", addr);
                        printk("\n");
-#else
-                       if ((i % 6) == 0)
-                               printk(KERN_EMERG "  ");
-                       printk("[<%08lx>] ", addr);
-                       i++;
-#endif
                }
        }
 
@@ -322,86 +434,6 @@ void die(const char *str, struct pt_regs *regs, enum exception_code code)
        do_exit(SIGSEGV);
 }
 
-/*
- * see if there's a fixup handler we can force a jump to when an exception
- * happens due to something kernel code did
- */
-int die_if_no_fixup(const char *str, struct pt_regs *regs,
-                   enum exception_code code)
-{
-       if (user_mode(regs))
-               return 0;
-
-       peripheral_leds_display_exception(code);
-
-       switch (code) {
-               /* see if we can fixup the kernel accessing memory */
-       case EXCEP_ITLBMISS:
-       case EXCEP_DTLBMISS:
-       case EXCEP_IAERROR:
-       case EXCEP_DAERROR:
-       case EXCEP_MEMERR:
-       case EXCEP_MISALIGN:
-       case EXCEP_BUSERROR:
-       case EXCEP_ILLDATACC:
-       case EXCEP_IOINSACC:
-       case EXCEP_PRIVINSACC:
-       case EXCEP_PRIVDATACC:
-       case EXCEP_DATINSACC:
-               if (fixup_exception(regs))
-                       return 1;
-       case EXCEP_UNIMPINS:
-               if (regs->pc && *(uint8_t *)regs->pc == 0xff)
-                       if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
-                               return 1;
-               break;
-       default:
-               break;
-       }
-
-       /* see if gdbstub wants to deal with it */
-#ifdef CONFIG_GDBSTUB
-       if (gdbstub_intercept(regs, code))
-               return 1;
-#endif
-
-       if (notify_die(DIE_GPF, str, regs, code, 0, 0))
-               return 1;
-
-       /* make the process die as the last resort */
-       die(str, regs, code);
-}
-
-/*
- * handle unsupported syscall instructions (syscall 1-15)
- */
-static asmlinkage void unsupported_syscall(struct pt_regs *regs,
-                                          enum exception_code code)
-{
-       struct task_struct *tsk = current;
-       siginfo_t info;
-
-       /* catch a kernel BUG() */
-       if (code == EXCEP_SYSCALL15 && !user_mode(regs)) {
-               if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_BUG) {
-#ifdef CONFIG_GDBSTUB
-                       gdbstub_intercept(regs, code);
-#endif
-               }
-       }
-
-       regs->pc -= 2; /* syscall return addr is _after_ the instruction */
-
-       die_if_no_fixup("An unsupported syscall insn was used by the kernel\n",
-                       regs, code);
-
-       info.si_signo   = SIGILL;
-       info.si_errno   = ENOSYS;
-       info.si_code    = ILL_ILLTRP;
-       info.si_addr    = (void *) regs->pc;
-       force_sig_info(SIGILL, &info, tsk);
-}
-
 /*
  * display the register file when the stack pointer gets clobbered
  */
@@ -481,10 +513,8 @@ asmlinkage void uninitialised_exception(struct pt_regs *regs,
 {
 
        /* see if gdbstub wants to deal with it */
-#ifdef CONFIG_GDBSTUB
-       if (gdbstub_intercept(regs, code))
+       if (debugger_intercept(code, SIGSYS, 0, regs) == 0)
                return;
-#endif
 
        peripheral_leds_display_exception(code);
        printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF);
@@ -549,43 +579,43 @@ void __init set_intr_stub(enum exception_code code, void *handler)
  */
 void __init trap_init(void)
 {
-       set_excp_vector(EXCEP_TRAP,             trap);
-       set_excp_vector(EXCEP_ISTEP,            istep);
-       set_excp_vector(EXCEP_IBREAK,           ibreak);
-       set_excp_vector(EXCEP_OBREAK,           obreak);
-
-       set_excp_vector(EXCEP_PRIVINS,          priv_op);
-       set_excp_vector(EXCEP_UNIMPINS,         invalid_op);
-       set_excp_vector(EXCEP_UNIMPEXINS,       invalid_exop);
-       set_excp_vector(EXCEP_MEMERR,           mem_error);
+       set_excp_vector(EXCEP_TRAP,             handle_exception);
+       set_excp_vector(EXCEP_ISTEP,            handle_exception);
+       set_excp_vector(EXCEP_IBREAK,           handle_exception);
+       set_excp_vector(EXCEP_OBREAK,           handle_exception);
+
+       set_excp_vector(EXCEP_PRIVINS,          handle_exception);
+       set_excp_vector(EXCEP_UNIMPINS,         handle_exception);
+       set_excp_vector(EXCEP_UNIMPEXINS,       handle_exception);
+       set_excp_vector(EXCEP_MEMERR,           handle_exception);
        set_excp_vector(EXCEP_MISALIGN,         misalignment);
-       set_excp_vector(EXCEP_BUSERROR,         bus_error);
-       set_excp_vector(EXCEP_ILLINSACC,        insn_acc_error);
-       set_excp_vector(EXCEP_ILLDATACC,        data_acc_error);
-       set_excp_vector(EXCEP_IOINSACC,         insn_acc_error);
-       set_excp_vector(EXCEP_PRIVINSACC,       insn_acc_error);
-       set_excp_vector(EXCEP_PRIVDATACC,       data_acc_error);
-       set_excp_vector(EXCEP_DATINSACC,        insn_acc_error);
-       set_excp_vector(EXCEP_FPU_UNIMPINS,     fpu_invalid_op);
+       set_excp_vector(EXCEP_BUSERROR,         handle_exception);
+       set_excp_vector(EXCEP_ILLINSACC,        handle_exception);
+       set_excp_vector(EXCEP_ILLDATACC,        handle_exception);
+       set_excp_vector(EXCEP_IOINSACC,         handle_exception);
+       set_excp_vector(EXCEP_PRIVINSACC,       handle_exception);
+       set_excp_vector(EXCEP_PRIVDATACC,       handle_exception);
+       set_excp_vector(EXCEP_DATINSACC,        handle_exception);
+       set_excp_vector(EXCEP_FPU_UNIMPINS,     handle_exception);
        set_excp_vector(EXCEP_FPU_OPERATION,    fpu_exception);
 
        set_excp_vector(EXCEP_NMI,              nmi);
 
-       set_excp_vector(EXCEP_SYSCALL1,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL2,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL3,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL4,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL5,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL6,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL7,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL8,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL9,         unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL10,        unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL11,        unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL12,        unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL13,        unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL14,        unsupported_syscall);
-       set_excp_vector(EXCEP_SYSCALL15,        unsupported_syscall);
+       set_excp_vector(EXCEP_SYSCALL1,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL2,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL3,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL4,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL5,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL6,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL7,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL8,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL9,         handle_exception);
+       set_excp_vector(EXCEP_SYSCALL10,        handle_exception);
+       set_excp_vector(EXCEP_SYSCALL11,        handle_exception);
+       set_excp_vector(EXCEP_SYSCALL12,        handle_exception);
+       set_excp_vector(EXCEP_SYSCALL13,        handle_exception);
+       set_excp_vector(EXCEP_SYSCALL14,        handle_exception);
+       set_excp_vector(EXCEP_SYSCALL15,        handle_exception);
 }
 
 /*
index c4fd923a55a09803b0c06f13485598968345c0d9..bfbe52691f2c8feb474be5af3d9eccaea1e4e287 100644 (file)
@@ -99,3 +99,49 @@ config MN10300_CACHE_INV_ICACHE
        help
          Set if we need the icache to be invalidated, even if the dcache is in
          write-through mode and doesn't need flushing.
+
+#
+# The kernel debugger gets its own separate cache flushing functions
+#
+config MN10300_DEBUGGER_CACHE_FLUSH_BY_TAG
+       def_bool y if KERNEL_DEBUGGER && \
+                       MN10300_CACHE_WBACK && \
+                       !MN10300_CACHE_SNOOP && \
+                       MN10300_CACHE_MANAGE_BY_TAG
+       help
+         Set if the debugger needs to flush the dcache and invalidate the
+         icache using the cache tag registers to make breakpoints work.
+
+config MN10300_DEBUGGER_CACHE_FLUSH_BY_REG
+       def_bool y if KERNEL_DEBUGGER && \
+                       MN10300_CACHE_WBACK && \
+                       !MN10300_CACHE_SNOOP && \
+                       MN10300_CACHE_MANAGE_BY_REG
+       help
+         Set if the debugger needs to flush the dcache and invalidate the
+         icache using automatic purge registers to make breakpoints work.
+
+config MN10300_DEBUGGER_CACHE_INV_BY_TAG
+       def_bool y if KERNEL_DEBUGGER && \
+                       MN10300_CACHE_WTHRU && \
+                       !MN10300_CACHE_SNOOP && \
+                       MN10300_CACHE_MANAGE_BY_TAG
+       help
+         Set if the debugger needs to invalidate the icache using the cache
+         tag registers to make breakpoints work.
+
+config MN10300_DEBUGGER_CACHE_INV_BY_REG
+       def_bool y if KERNEL_DEBUGGER && \
+                       MN10300_CACHE_WTHRU && \
+                       !MN10300_CACHE_SNOOP && \
+                       MN10300_CACHE_MANAGE_BY_REG
+       help
+         Set if the debugger needs to invalidate the icache using automatic
+         purge registers to make breakpoints work.
+
+config MN10300_DEBUGGER_CACHE_NO_FLUSH
+       def_bool y if KERNEL_DEBUGGER && \
+                       (MN10300_CACHE_DISABLED || MN10300_CACHE_SNOOP)
+       help
+         Set if the debugger does not need to flush the dcache and/or
+         invalidate the icache to make breakpoints work.
index 203fee23f7d70efebe0b6c11eb1bfdb6dc3cae6c..11f38466ac28e17a7e3c2518a5a9679a1ad35d3b 100644 (file)
@@ -13,6 +13,15 @@ cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_REG) += cache-inv-by-reg.o
 cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o
 cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o
 
+cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_FLUSH_BY_TAG) += \
+       cache-dbg-flush-by-tag.o cache-dbg-inv-by-tag.o
+cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_FLUSH_BY_REG) += \
+       cache-dbg-flush-by-reg.o
+cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_TAG) += \
+       cache-dbg-inv-by-tag.o cache-dbg-inv.o
+cacheflush-$(CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_REG) += \
+       cache-dbg-inv-by-reg.o cache-dbg-inv.o
+
 cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o
 
 obj-y := \
diff --git a/arch/mn10300/mm/cache-dbg-flush-by-reg.S b/arch/mn10300/mm/cache-dbg-flush-by-reg.S
new file mode 100644 (file)
index 0000000..665919f
--- /dev/null
@@ -0,0 +1,160 @@
+/* MN10300 CPU cache invalidation routines, using automatic purge registers
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+#include "cache.inc"
+
+       .am33_2
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv(void)
+# Flush the entire data cache back to RAM and invalidate the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv
+        .type  debugger_local_cache_flushinv,@function
+debugger_local_cache_flushinv:
+       #
+       # firstly flush the dcache
+       #
+       movhu   (CHCTR),d0
+       btst    CHCTR_DCEN|CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_end
+
+       mov     DCPGCR,a0
+
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       or      EPSW_NMID,epsw
+       nop
+
+       btst    CHCTR_DCEN,d0
+       beq     debugger_local_cache_flushinv_no_dcache
+
+       # wait for busy bit of area purge
+       setlb
+       mov     (a0),d0
+       btst    DCPGCR_DCPGBSY,d0
+       lne
+
+       # set mask
+       clr     d0
+       mov     d0,(DCPGMR)
+
+       # area purge
+       #
+       # DCPGCR = DCPGCR_DCP
+       #
+       mov     DCPGCR_DCP,d0
+       mov     d0,(a0)
+
+       # wait for busy bit of area purge
+       setlb
+       mov     (a0),d0
+       btst    DCPGCR_DCPGBSY,d0
+       lne
+
+debugger_local_cache_flushinv_no_dcache:
+       #
+       # secondly, invalidate the icache if it is enabled
+       #
+       mov     CHCTR,a0
+       movhu   (a0),d0
+       btst    CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_done
+
+       invalidate_icache 0
+
+debugger_local_cache_flushinv_done:
+       mov     d1,epsw
+
+debugger_local_cache_flushinv_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv,.-debugger_local_cache_flushinv
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv_one(u8 *addr)
+#
+# Invalidate one particular cacheline if it's in the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv_one
+       .type   debugger_local_cache_flushinv_one,@function
+debugger_local_cache_flushinv_one:
+       movhu   (CHCTR),d1
+       btst    CHCTR_DCEN|CHCTR_ICEN,d1
+       beq     debugger_local_cache_flushinv_one_end
+       btst    CHCTR_DCEN,d1
+       beq     debugger_local_cache_flushinv_one_no_dcache
+
+       # round cacheline addr down
+       and     L1_CACHE_TAG_MASK,d0
+       mov     d0,a1
+       mov     d0,d1
+
+       # determine the dcache purge control reg address
+       mov     DCACHE_PURGE(0,0),a0
+       and     L1_CACHE_TAG_ENTRY,d0
+       add     d0,a0
+
+       # retain valid entries in the cache
+       or      L1_CACHE_TAG_VALID,d1
+
+       # conditionally purge this line in all ways
+       mov     d1,(L1_CACHE_WAYDISP*0,a0)
+
+debugger_local_cache_flushinv_no_dcache:
+       #
+       # now try to flush the icache
+       #
+       mov     CHCTR,a0
+       movhu   (a0),d0
+       btst    CHCTR_ICEN,d0
+       beq     mn10300_local_icache_inv_range_reg_end
+
+       LOCAL_CLI_SAVE(d1)
+
+       mov     ICIVCR,a0
+
+       # wait for the invalidator to quiesce
+       setlb
+       mov     (a0),d0
+       btst    ICIVCR_ICIVBSY,d0
+       lne
+
+       # set the mask
+       mov     L1_CACHE_TAG_MASK,d0
+       mov     d0,(ICIVMR)
+
+       # invalidate the cache line at the given address
+       or      ICIVCR_ICI,a1
+       mov     a1,(a0)
+
+       # wait for the invalidator to quiesce again
+       setlb
+       mov     (a0),d0
+       btst    ICIVCR_ICIVBSY,d0
+       lne
+
+       LOCAL_IRQ_RESTORE(d1)
+
+debugger_local_cache_flushinv_one_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one
diff --git a/arch/mn10300/mm/cache-dbg-flush-by-tag.S b/arch/mn10300/mm/cache-dbg-flush-by-tag.S
new file mode 100644 (file)
index 0000000..bf56930
--- /dev/null
@@ -0,0 +1,114 @@
+/* MN10300 CPU cache invalidation routines, using direct tag flushing
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+#include "cache.inc"
+
+       .am33_2
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv(void)
+#
+# Flush the entire data cache back to RAM and invalidate the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv
+        .type  debugger_local_cache_flushinv,@function
+debugger_local_cache_flushinv:
+       #
+       # firstly flush the dcache
+       #
+       movhu   (CHCTR),d0
+       btst    CHCTR_DCEN|CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_end
+
+       btst    CHCTR_DCEN,d0
+       beq     debugger_local_cache_flushinv_no_dcache
+
+       # read the addresses tagged in the cache's tag RAM and attempt to flush
+       # those addresses specifically
+       # - we rely on the hardware to filter out invalid tag entry addresses
+       mov     DCACHE_TAG(0,0),a0              # dcache tag RAM access address
+       mov     DCACHE_PURGE(0,0),a1            # dcache purge request address
+       mov     L1_CACHE_NWAYS*L1_CACHE_NENTRIES,e0  # total number of entries
+
+mn10300_local_dcache_flush_loop:
+       mov     (a0),d0
+       and     L1_CACHE_TAG_MASK,d0
+       or      L1_CACHE_TAG_VALID,d0           # retain valid entries in the
+                                               # cache
+       mov     d0,(a1)                         # conditional purge
+
+       add     L1_CACHE_BYTES,a0
+       add     L1_CACHE_BYTES,a1
+       add     -1,e0
+       bne     mn10300_local_dcache_flush_loop
+
+debugger_local_cache_flushinv_no_dcache:
+       #
+       # secondly, invalidate the icache if it is enabled
+       #
+       mov     CHCTR,a0
+       movhu   (a0),d0
+       btst    CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_end
+
+       invalidate_icache 1
+
+debugger_local_cache_flushinv_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv,.-debugger_local_cache_flushinv
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv_one(u8 *addr)
+#
+# Invalidate one particular cacheline if it's in the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv_one
+       .type   debugger_local_cache_flushinv_one,@function
+debugger_local_cache_flushinv_one:
+       movhu   (CHCTR),d1
+       btst    CHCTR_DCEN|CHCTR_ICEN,d1
+       beq     debugger_local_cache_flushinv_one_end
+       btst    CHCTR_DCEN,d1
+       beq     debugger_local_cache_flushinv_one_icache
+
+       # round cacheline addr down
+       and     L1_CACHE_TAG_MASK,d0
+       mov     d0,a1
+
+       # determine the dcache purge control reg address
+       mov     DCACHE_PURGE(0,0),a0
+       and     L1_CACHE_TAG_ENTRY,d0
+       add     d0,a0
+
+       # retain valid entries in the cache
+       or      L1_CACHE_TAG_VALID,a1
+
+       # conditionally purge this line in all ways
+       mov     a1,(L1_CACHE_WAYDISP*0,a0)
+
+       # now go and do the icache
+       bra     debugger_local_cache_flushinv_one_icache
+
+debugger_local_cache_flushinv_one_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one
diff --git a/arch/mn10300/mm/cache-dbg-inv-by-reg.S b/arch/mn10300/mm/cache-dbg-inv-by-reg.S
new file mode 100644 (file)
index 0000000..c4e6252
--- /dev/null
@@ -0,0 +1,69 @@
+/* MN10300 CPU cache invalidation routines, using automatic purge registers
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+#include "cache.inc"
+
+       .am33_2
+
+       .globl  debugger_local_cache_flushinv_one
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv_one(u8 *addr)
+#
+# Invalidate one particular cacheline if it's in the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv_one
+       .type   debugger_local_cache_flushinv_one,@function
+debugger_local_cache_flushinv_one:
+       mov     d0,a1
+
+       mov     CHCTR,a0
+       movhu   (a0),d0
+       btst    CHCTR_ICEN,d0
+       beq     mn10300_local_icache_inv_range_reg_end
+
+       LOCAL_CLI_SAVE(d1)
+
+       mov     ICIVCR,a0
+
+       # wait for the invalidator to quiesce
+       setlb
+       mov     (a0),d0
+       btst    ICIVCR_ICIVBSY,d0
+       lne
+
+       # set the mask
+       mov     ~L1_CACHE_TAG_MASK,d0
+       mov     d0,(ICIVMR)
+
+       # invalidate the cache line at the given address
+       and     ~L1_CACHE_TAG_MASK,a1
+       or      ICIVCR_ICI,a1
+       mov     a1,(a0)
+
+       # wait for the invalidator to quiesce again
+       setlb
+       mov     (a0),d0
+       btst    ICIVCR_ICIVBSY,d0
+       lne
+
+       LOCAL_IRQ_RESTORE(d1)
+
+mn10300_local_icache_inv_range_reg_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv_one,.-debugger_local_cache_flushinv_one
diff --git a/arch/mn10300/mm/cache-dbg-inv-by-tag.S b/arch/mn10300/mm/cache-dbg-inv-by-tag.S
new file mode 100644 (file)
index 0000000..d8ec821
--- /dev/null
@@ -0,0 +1,120 @@
+/* MN10300 CPU cache invalidation routines, using direct tag flushing
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+#include "cache.inc"
+
+       .am33_2
+
+       .globl  debugger_local_cache_flushinv_one_icache
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv_one(u8 *addr)
+#
+# Invalidate one particular cacheline if it's in the icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv_one_icache
+       .type   debugger_local_cache_flushinv_one_icache,@function
+debugger_local_cache_flushinv_one_icache:
+       movm    [d3,a2],(sp)
+
+       mov     CHCTR,a2
+       movhu   (a2),d0
+       btst    CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_one_icache_end
+
+       mov     d0,a1
+       and     L1_CACHE_TAG_MASK,a1
+
+       # read the tags from the tag RAM, and if they indicate a matching valid
+       # cache line then we invalidate that line
+       mov     ICACHE_TAG(0,0),a0
+       mov     a1,d0
+       and     L1_CACHE_TAG_ENTRY,d0
+       add     d0,a0                           # starting icache tag RAM
+                                               # access address
+
+       and     ~(L1_CACHE_DISPARITY-1),a1      # determine comparator base
+       or      L1_CACHE_TAG_VALID,a1
+       mov     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_VALID,d1
+
+       LOCAL_CLI_SAVE(d3)
+
+       # disable the icache
+       movhu   (a2),d0
+       and     ~CHCTR_ICEN,d0
+       movhu   d0,(a2)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a2),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # check all the way tags for this cache entry
+       mov     (a0),d0                         # read the tag in the way 0 slot
+       xor     a1,d0
+       and     d1,d0
+       beq     debugger_local_icache_kill      # jump if matched
+
+       add     L1_CACHE_WAYDISP,a0
+       mov     (a0),d0                         # read the tag in the way 1 slot
+       xor     a1,d0
+       and     d1,d0
+       beq     debugger_local_icache_kill      # jump if matched
+
+       add     L1_CACHE_WAYDISP,a0
+       mov     (a0),d0                         # read the tag in the way 2 slot
+       xor     a1,d0
+       and     d1,d0
+       beq     debugger_local_icache_kill      # jump if matched
+
+       add     L1_CACHE_WAYDISP,a0
+       mov     (a0),d0                         # read the tag in the way 3 slot
+       xor     a1,d0
+       and     d1,d0
+       bne     debugger_local_icache_finish    # jump if not matched
+
+debugger_local_icache_kill:
+       mov     d0,(a0)                         # kill the tag (D0 is 0 at this point)
+
+debugger_local_icache_finish:
+       # wait for the cache to finish what it's doing
+       setlb
+       movhu   (a2),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # and reenable it
+       or      CHCTR_ICEN,d0
+       movhu   d0,(a2)
+       movhu   (a2),d0
+
+       # re-enable interrupts
+       LOCAL_IRQ_RESTORE(d3)
+
+debugger_local_cache_flushinv_one_icache_end:
+       ret     [d3,a2],8
+       .size   debugger_local_cache_flushinv_one_icache,.-debugger_local_cache_flushinv_one_icache
+
+#ifdef CONFIG_MN10300_DEBUGGER_CACHE_INV_BY_TAG
+       .globl  debugger_local_cache_flushinv_one
+       .type   debugger_local_cache_flushinv_one,@function
+debugger_local_cache_flushinv_one = debugger_local_cache_flushinv_one_icache
+#endif
diff --git a/arch/mn10300/mm/cache-dbg-inv.S b/arch/mn10300/mm/cache-dbg-inv.S
new file mode 100644 (file)
index 0000000..eba2d6d
--- /dev/null
@@ -0,0 +1,47 @@
+/* MN10300 CPU cache invalidation routines
+ *
+ * Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+#include "cache.inc"
+
+       .am33_2
+
+       .globl  debugger_local_cache_flushinv
+
+###############################################################################
+#
+# void debugger_local_cache_flushinv(void)
+#
+# Invalidate the entire icache
+#
+###############################################################################
+       ALIGN
+       .globl  debugger_local_cache_flushinv
+        .type  debugger_local_cache_flushinv,@function
+debugger_local_cache_flushinv:
+       #
+       # we only need to invalidate the icache in this cache mode
+       #
+       mov     CHCTR,a0
+       movhu   (a0),d0
+       btst    CHCTR_ICEN,d0
+       beq     debugger_local_cache_flushinv_end
+
+       invalidate_icache 1
+
+debugger_local_cache_flushinv_end:
+       ret     [],0
+       .size   debugger_local_cache_flushinv,.-debugger_local_cache_flushinv
index 5cd6a27dd63e04448bde98836e8eff937824240b..1ddc068492429fc5903f0f776d42c6798d7eb76f 100644 (file)
@@ -62,7 +62,7 @@ mn10300_local_dcache_flush:
 
 mn10300_local_dcache_flush_loop:
        mov     (a0),d0
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+       and     L1_CACHE_TAG_MASK,d0
        or      L1_CACHE_TAG_VALID,d0           # retain valid entries in the
                                                # cache
        mov     d0,(a1)                         # conditional purge
@@ -112,11 +112,11 @@ mn10300_local_dcache_flush_range:
 1:
 
        # round start addr down
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+       and     L1_CACHE_TAG_MASK,d0
        mov     d0,a1
 
        add     L1_CACHE_BYTES,d1                       # round end addr up
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+       and     L1_CACHE_TAG_MASK,d1
 
        # write a request to flush all instances of an address from the cache
        mov     DCACHE_PURGE(0,0),a0
@@ -215,12 +215,11 @@ mn10300_local_dcache_flush_inv_range:
        bra     mn10300_local_dcache_flush_inv
 1:
 
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0      # round start
-                                                               # addr down
+       and     L1_CACHE_TAG_MASK,d0            # round start addr down
        mov     d0,a1
 
-       add     L1_CACHE_BYTES,d1                       # round end addr up
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+       add     L1_CACHE_BYTES,d1               # round end addr up
+       and     L1_CACHE_TAG_MASK,d1
 
        # write a request to flush and invalidate all instances of an address
        # from the cache
index c8950861ed779c5da127fbc562bc03ee58a72d55..a60825b91e7724fc0a7e6e54f17bd1059995a7fb 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/cache.h>
 #include <asm/irqflags.h>
 #include <asm/cacheflush.h>
+#include "cache.inc"
 
 #define mn10300_local_dcache_inv_range_intr_interval \
        +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
@@ -62,10 +63,7 @@ mn10300_local_icache_inv:
        btst    CHCTR_ICEN,d0
        beq     mn10300_local_icache_inv_end
 
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
+       invalidate_icache 1
 
 mn10300_local_icache_inv_end:
        ret     [],0
@@ -87,11 +85,8 @@ mn10300_local_dcache_inv:
        btst    CHCTR_DCEN,d0
        beq     mn10300_local_dcache_inv_end
 
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
+       invalidate_dcache 1
+       
 mn10300_local_dcache_inv_end:
        ret     [],0
        .size   mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
@@ -121,9 +116,9 @@ mn10300_local_dcache_inv_range:
        # and if they're not cacheline-aligned, we must flush any bits outside
        # the range that share cachelines with stuff inside the range
 #ifdef CONFIG_MN10300_CACHE_WBACK
-       btst    ~(L1_CACHE_BYTES-1),d0
+       btst    ~L1_CACHE_TAG_MASK,d0
        bne     1f
-       btst    ~(L1_CACHE_BYTES-1),d1
+       btst    ~L1_CACHE_TAG_MASK,d1
        beq     2f
 1:
        bra     mn10300_local_dcache_flush_inv_range
@@ -141,12 +136,11 @@ mn10300_local_dcache_inv_range:
        # writeback mode, in which case we would be in flush and invalidate by
        # now
 #ifndef CONFIG_MN10300_CACHE_WBACK
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0      # round start
-                                                               # addr down
+       and     L1_CACHE_TAG_MASK,d0    # round start addr down
 
        mov     L1_CACHE_BYTES-1,d2
        add     d2,d1
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1      # round end addr up
+       and     L1_CACHE_TAG_MASK,d1    # round end addr up
 #endif /* !CONFIG_MN10300_CACHE_WBACK */
 
        sub     d0,d1,d2                # calculate the total size
index e9713b40c0ff4823ead75d4e81b09a71138e9531..ccedce9c144d30459b8d092959247d4713ee03f0 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/cache.h>
 #include <asm/irqflags.h>
 #include <asm/cacheflush.h>
+#include "cache.inc"
 
 #define mn10300_local_dcache_inv_range_intr_interval \
        +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
@@ -70,43 +71,7 @@ mn10300_local_icache_inv:
        btst    CHCTR_ICEN,d0
        beq     mn10300_local_icache_inv_end
 
-#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
-       LOCAL_CLI_SAVE(d1)
-
-       # disable the icache
-       and     ~CHCTR_ICEN,d0
-       movhu   d0,(a0)
-
-       # and wait for it to calm down
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-
-       # wait for the cache to finish
-       mov     CHCTR,a0
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_ICBUSY,d0
-       lne
-
-       # and reenable it
-       and     ~CHCTR_ICINV,d0
-       or      CHCTR_ICEN,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
-       LOCAL_IRQ_RESTORE(d1)
-#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
-       # invalidate
-       or      CHCTR_ICINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       invalidate_icache 1
 
 mn10300_local_icache_inv_end:
        ret     [],0
@@ -128,43 +93,7 @@ mn10300_local_dcache_inv:
        btst    CHCTR_DCEN,d0
        beq     mn10300_local_dcache_inv_end
 
-#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
-       LOCAL_CLI_SAVE(d1)
-
-       # disable the dcache
-       and     ~CHCTR_DCEN,d0
-       movhu   d0,(a0)
-
-       # and wait for it to calm down
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_DCBUSY,d0
-       lne
-
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-
-       # wait for the cache to finish
-       mov     CHCTR,a0
-       setlb
-       movhu   (a0),d0
-       btst    CHCTR_DCBUSY,d0
-       lne
-
-       # and reenable it
-       and     ~CHCTR_DCINV,d0
-       or      CHCTR_DCEN,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-
-       LOCAL_IRQ_RESTORE(d1)
-#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
-       # invalidate
-       or      CHCTR_DCINV,d0
-       movhu   d0,(a0)
-       movhu   (a0),d0
-#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       invalidate_dcache 1
 
 mn10300_local_dcache_inv_end:
        ret     [],0
@@ -195,9 +124,9 @@ mn10300_local_dcache_inv_range:
        # and if they're not cacheline-aligned, we must flush any bits outside
        # the range that share cachelines with stuff inside the range
 #ifdef CONFIG_MN10300_CACHE_WBACK
-       btst    ~(L1_CACHE_BYTES-1),d0
+       btst    ~L1_CACHE_TAG_MASK,d0
        bne     1f
-       btst    ~(L1_CACHE_BYTES-1),d1
+       btst    ~L1_CACHE_TAG_MASK,d1
        beq     2f
 1:
        bra     mn10300_local_dcache_flush_inv_range
@@ -212,11 +141,10 @@ mn10300_local_dcache_inv_range:
        beq     mn10300_local_dcache_inv_range_end
 
 #ifndef CONFIG_MN10300_CACHE_WBACK
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0      # round start
-                                                               # addr down
+       and     L1_CACHE_TAG_MASK,d0            # round start addr down
 
        add     L1_CACHE_BYTES,d1               # round end addr up
-       and     L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+       and     L1_CACHE_TAG_MASK,d1
 #endif /* !CONFIG_MN10300_CACHE_WBACK */
        mov     d0,a1
 
diff --git a/arch/mn10300/mm/cache.inc b/arch/mn10300/mm/cache.inc
new file mode 100644 (file)
index 0000000..394a119
--- /dev/null
@@ -0,0 +1,133 @@
+/* MN10300 CPU core caching macros -*- asm -*-
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+
+###############################################################################
+#
+# Invalidate the instruction cache.
+#      A0: Should hold CHCTR
+#      D0: Should have been read from CHCTR
+#      D1: Will be clobbered
+#
+# On some cores it is necessary to disable the icache whilst we do this.
+#
+###############################################################################
+       .macro invalidate_icache,disable_irq
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+       .if \disable_irq
+       # don't want an interrupt routine seeing a disabled cache
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       or      EPSW_NMID,epsw
+       nop
+       nop
+       .endif
+
+       # disable the icache
+       and     ~CHCTR_ICEN,d0
+       movhu   d0,(a0)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # invalidate
+       or      CHCTR_ICINV,d0
+       movhu   d0,(a0)
+
+       # wait for the cache to finish
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_ICBUSY,d0
+       lne
+
+       # and reenable it
+       or      CHCTR_ICEN,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+       .if \disable_irq
+       LOCAL_IRQ_RESTORE(d1)
+       .endif
+
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+       # invalidate
+       or      CHCTR_ICINV,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       .endm
+
+###############################################################################
+#
+# Invalidate the data cache.
+#      A0: Should hold CHCTR
+#      D0: Should have been read from CHCTR
+#      D1: Will be clobbered
+#
+# On some cores it is necessary to disable the dcache whilst we do this.
+#
+###############################################################################
+       .macro invalidate_dcache,disable_irq
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+       .if \disable_irq
+       # don't want an interrupt routine seeing a disabled cache
+       mov     epsw,d1
+       and     ~EPSW_IE,epsw
+       or      EPSW_NMID,epsw
+       nop
+       nop
+       .endif
+       
+       # disable the dcache
+       and     ~CHCTR_DCEN,d0
+       movhu   d0,(a0)
+
+       # and wait for it to calm down
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_DCBUSY,d0
+       lne
+
+       # invalidate
+       or      CHCTR_DCINV,d0
+       movhu   d0,(a0)
+
+       # wait for the cache to finish
+       setlb
+       movhu   (a0),d0
+       btst    CHCTR_DCBUSY,d0
+       lne
+
+       # and reenable it
+       or      CHCTR_DCEN,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+       .if \disable_irq
+       LOCAL_IRQ_RESTORE(d1)
+       .endif
+
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+       # invalidate
+       or      CHCTR_DCINV,d0
+       movhu   d0,(a0)
+       movhu   (a0),d0
+
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+       .endm
index 59c3da49d9d9e4ad08108bf2f1eebe8182f46e0c..0945409a802219cb8b1d7f09ef5410941a4756c0 100644 (file)
@@ -28,8 +28,9 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/hardirq.h>
-#include <asm/gdb-stub.h>
 #include <asm/cpu-regs.h>
+#include <asm/debugger.h>
+#include <asm/gdb-stub.h>
 
 /*
  * Unlock any spinlocks which will prevent us from getting the
@@ -306,10 +307,8 @@ no_context:
        printk(" printing pc:\n");
        printk(KERN_ALERT "%08lx\n", regs->pc);
 
-#ifdef CONFIG_GDBSTUB
-       gdbstub_intercept(
-               regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR);
-#endif
+       debugger_intercept(fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR,
+                          SIGSEGV, SEGV_ACCERR, regs);
 
        page = PTBR;
        page = ((unsigned long *) __va(page))[address >> 22];
index c1528004163ce8fe54418368ce3aea757e31104f..967d144f307e5572d24b06e78ff50298366ce331 100644 (file)
@@ -23,6 +23,7 @@
 #define L1_CACHE_TAG_DIRTY     0x00000008      /* data cache tag dirty bit */
 #define L1_CACHE_TAG_ENTRY     0x00000ff0      /* cache tag entry address mask */
 #define L1_CACHE_TAG_ADDRESS   0xfffff000      /* cache tag line address mask */
+#define L1_CACHE_TAG_MASK      +(L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY)
 
 /*
  * specification of the interval between interrupt checking intervals whilst
index cafd7b5b55b444836a7714793eb9725c3e4f5740..bcb5df2d892f99c76012c491707a64223fa61784 100644 (file)
@@ -29,6 +29,7 @@
 #define L1_CACHE_TAG_DIRTY     0x00000008      /* data cache tag dirty bit */
 #define L1_CACHE_TAG_ENTRY     0x00000fe0      /* cache tag entry address mask */
 #define L1_CACHE_TAG_ADDRESS   0xfffff000      /* cache tag line address mask */
+#define L1_CACHE_TAG_MASK      +(L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY)
 
 /*
  * specification of the interval between interrupt checking intervals whilst
index 7cf12054db65da40b87d3cffe4f48ec13a322daa..33f100f9b468ecb75a942673aab6169ed700a46b 100644 (file)
@@ -14,7 +14,7 @@
 #define ASB2364_FPGA_REG_RESET_USB     __SYSREG(0xa900130c, u16)
 #define ASB2364_FPGA_REG_RESET_AV      __SYSREG(0xa9001310, u16)
 
-#define ASB2364_FPGA_REG_IRQ(X)                __SYSREG(0xa9001590+((X)*4), u16)
+#define ASB2364_FPGA_REG_IRQ(X)                __SYSREG(0xa9001510+((X)*4), u16)
 #define ASB2364_FPGA_REG_IRQ_LAN       ASB2364_FPGA_REG_IRQ(0)
 #define ASB2364_FPGA_REG_IRQ_UART      ASB2364_FPGA_REG_IRQ(1)
 #define ASB2364_FPGA_REG_IRQ_I2C       ASB2364_FPGA_REG_IRQ(2)
index 7f048bbfdfd7f0edc8833261ca751a4a5b17f85e..92f224a97efcc612ba8fa2610d335d04e9cd788c 100644 (file)
@@ -59,18 +59,18 @@ static inline void __debug_to_serial(const char *p, int n)
 #define SERIAL_PORT_DFNS /* stolen by gdb-stub */
 
 #if defined(CONFIG_GDBSTUB_ON_TTYS0)
-#define GDBPORT_SERIAL_RX      __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX  * 4, u8)
-#define GDBPORT_SERIAL_TX      __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX  * 4, u8)
-#define GDBPORT_SERIAL_DLL     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 4, u8)
-#define GDBPORT_SERIAL_DLM     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 4, u8)
-#define GDBPORT_SERIAL_IER     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 4, u8)
-#define GDBPORT_SERIAL_IIR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 4, u8)
-#define GDBPORT_SERIAL_FCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 4, u8)
-#define GDBPORT_SERIAL_LCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 4, u8)
-#define GDBPORT_SERIAL_MCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 4, u8)
-#define GDBPORT_SERIAL_LSR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 4, u8)
-#define GDBPORT_SERIAL_MSR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 4, u8)
-#define GDBPORT_SERIAL_SCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 4, u8)
+#define GDBPORT_SERIAL_RX      __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX  * 2, u8)
+#define GDBPORT_SERIAL_TX      __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX  * 2, u8)
+#define GDBPORT_SERIAL_DLL     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 2, u8)
+#define GDBPORT_SERIAL_DLM     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 2, u8)
+#define GDBPORT_SERIAL_IER     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 2, u8)
+#define GDBPORT_SERIAL_IIR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 2, u8)
+#define GDBPORT_SERIAL_FCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 2, u8)
+#define GDBPORT_SERIAL_LCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 2, u8)
+#define GDBPORT_SERIAL_MCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 2, u8)
+#define GDBPORT_SERIAL_LSR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 2, u8)
+#define GDBPORT_SERIAL_MSR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 2, u8)
+#define GDBPORT_SERIAL_SCR     __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 2, u8)
 #define GDBPORT_SERIAL_IRQ     SERIAL_IRQ
 
 #elif defined(CONFIG_GDBSTUB_ON_TTYS1)
index fcf29754e4d1770b4f1d1867ccad8d4e4325b1a2..ee84e62b16ede6e40d93592e3e6bd9342575cdd4 100644 (file)
 /*
  * FPGA PIC operations
  */
-static void asb2364_fpga_mask(unsigned int irq)
+static void asb2364_fpga_mask(struct irq_data *d)
 {
-       ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+       ASB2364_FPGA_REG_MASK(d->irq - NR_CPU_IRQS) = 0x0001;
        SyncExBus();
 }
 
-static void asb2364_fpga_ack(unsigned int irq)
+static void asb2364_fpga_ack(struct irq_data *d)
 {
-       ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+       ASB2364_FPGA_REG_IRQ(d->irq - NR_CPU_IRQS) = 0x0001;
        SyncExBus();
 }
 
-static void asb2364_fpga_mask_ack(unsigned int irq)
+static void asb2364_fpga_mask_ack(struct irq_data *d)
 {
-       ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+       ASB2364_FPGA_REG_MASK(d->irq - NR_CPU_IRQS) = 0x0001;
        SyncExBus();
-       ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+       ASB2364_FPGA_REG_IRQ(d->irq - NR_CPU_IRQS) = 0x0001;
        SyncExBus();
 }
 
-static void asb2364_fpga_unmask(unsigned int irq)
+static void asb2364_fpga_unmask(struct irq_data *d)
 {
-       ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0000;
+       ASB2364_FPGA_REG_MASK(d->irq - NR_CPU_IRQS) = 0x0000;
        SyncExBus();
 }
 
 static struct irq_chip asb2364_fpga_pic = {
        .name           = "fpga",
-       .ack            = asb2364_fpga_ack,
-       .mask           = asb2364_fpga_mask,
-       .mask_ack       = asb2364_fpga_mask_ack,
-       .unmask         = asb2364_fpga_unmask,
+       .irq_ack        = asb2364_fpga_ack,
+       .irq_mask       = asb2364_fpga_mask,
+       .irq_mask_ack   = asb2364_fpga_mask_ack,
+       .irq_unmask     = asb2364_fpga_unmask,
 };
 
 /*
@@ -88,6 +88,17 @@ void __init irq_fpga_init(void)
 {
        int irq;
 
+       ASB2364_FPGA_REG_MASK_LAN  = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_MASK_UART = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_MASK_I2C  = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_MASK_USB  = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_MASK_FPGA = 0x0001;
+       SyncExBus();
+
        for (irq = NR_CPU_IRQS; irq < NR_IRQS; irq++)
                set_irq_chip_and_handler(irq, &asb2364_fpga_pic, handle_level_irq);
 
index 11440803db10f97a8adfdb320541850939f7535e..6359b41ce7e970ce0bc8f7d71919487b366b3d8e 100644 (file)
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/intctl-regs.h>
+#include <asm/serial-regs.h>
 #include <unit/fpga-regs.h>
+#include <unit/serial.h>
+#include <unit/smsc911x.h>
+
+#define TTYS0_SERIAL_IER       __SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 2, u8)
+#define LAN_IRQ_CFG            __SYSREG(SMSC911X_BASE + 0x54, u32)
+#define LAN_INT_EN             __SYSREG(SMSC911X_BASE + 0x5c, u32)
 
 /*
  * initialise some of the unit hardware before gdbstub is set up
  */
 asmlinkage void __init unit_init(void)
 {
+       /* Make sure we aren't going to get unexpected interrupts */
+       TTYS0_SERIAL_IER = 0;
+       SC0RXICR = 0;
+       SC0TXICR = 0;
+       SC1RXICR = 0;
+       SC1TXICR = 0;
+       SC2RXICR = 0;
+       SC2TXICR = 0;
+
+       /* Attempt to reset the FPGA attached peripherals */
+       ASB2364_FPGA_REG_RESET_LAN = 0x0000;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_UART = 0x0000;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_I2C = 0x0000;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_USB = 0x0000;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_AV = 0x0000;
+       SyncExBus();
+
        /* set up the external interrupts */
 
        /* XIRQ[0]: NAND RXBY */
@@ -56,7 +84,23 @@ asmlinkage void __init unit_init(void)
  */
 asmlinkage void __init unit_setup(void)
 {
+       /* Release the reset on the SMSC911X so that it is ready by the time we
+        * need it */
+       ASB2364_FPGA_REG_RESET_LAN = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_UART = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_I2C = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_USB = 0x0001;
+       SyncExBus();
+       ASB2364_FPGA_REG_RESET_AV = 0x0001;
+       SyncExBus();
 
+       /* Make sure the ethernet chipset isn't going to give us an interrupt
+        * storm from stuff it was doing pre-reset */
+       LAN_IRQ_CFG = 0;
+       LAN_INT_EN = 0;
 }
 
 /*
index fed2946f73352489e15a5c0448bf6bdc717a00cc..9b1f427cdc3762b928aa6675f584b023eb82aea9 100644 (file)
@@ -15,6 +15,7 @@ config PARISC
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select IRQ_PER_CPU
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
@@ -51,6 +52,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_BUG
        bool
        default y
index 7a6ea10bd231a051217ddd00b0f9318a604b1878..43c516fa17ff2d47876fa74994c93705bfd3a530 100644 (file)
@@ -222,7 +222,7 @@ static __inline__ int fls(int x)
 
 #ifdef __KERNEL__
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 /* '3' is bits per byte */
 #define LE_BYTE_ADDR ((sizeof(unsigned long) - 1) << 3)
@@ -234,6 +234,4 @@ static __inline__ int fls(int x)
 
 #endif /* __KERNEL__ */
 
-#include <asm-generic/bitops/minix-le.h>
-
 #endif /* _PARISC_BITOPS_H */
index f388a85bba113c7c6f050202e494ad0d71731a43..d18328b3f9386c0477e61340f44e995888a1c47e 100644 (file)
@@ -26,8 +26,6 @@ void flush_user_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_page_asm(void *);
 void flush_kernel_icache_page(void *);
-void flush_user_dcache_page(unsigned long);
-void flush_user_icache_page(unsigned long);
 void flush_user_dcache_range(unsigned long, unsigned long);
 void flush_user_icache_range(unsigned long, unsigned long);
 
@@ -37,6 +35,13 @@ void flush_cache_all_local(void);
 void flush_cache_all(void);
 void flush_cache_mm(struct mm_struct *mm);
 
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page_addr(void *addr);
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+       flush_kernel_dcache_page_addr(page_address(page));
+}
+
 #define flush_kernel_dcache_range(start,size) \
        flush_kernel_dcache_range_asm((start), (start)+(size));
 /* vmap range flushes and invalidates.  Architecturally, we don't need
@@ -50,6 +55,16 @@ static inline void flush_kernel_vmap_range(void *vaddr, int size)
 }
 static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
 {
+       unsigned long start = (unsigned long)vaddr;
+       void *cursor = vaddr;
+
+       for ( ; cursor < vaddr + size; cursor += PAGE_SIZE) {
+               struct page *page = vmalloc_to_page(cursor);
+
+               if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+                       flush_kernel_dcache_page(page);
+       }
+       flush_kernel_dcache_range_asm(start, start + size);
 }
 
 #define flush_cache_vmap(start, end)           flush_cache_all()
@@ -90,19 +105,15 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end);
 
+/* defined in pacache.S exported in cache.c used by flush_anon_page */
+void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+
 #define ARCH_HAS_FLUSH_ANON_PAGE
 static inline void
 flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
 {
        if (PageAnon(page))
-               flush_user_dcache_page(vmaddr);
-}
-
-#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
-void flush_kernel_dcache_page_addr(void *addr);
-static inline void flush_kernel_dcache_page(struct page *page)
-{
-       flush_kernel_dcache_page_addr(page_address(page));
+               flush_dcache_page_asm(page_to_phys(page), vmaddr);
 }
 
 #ifdef CONFIG_DEBUG_RODATA
index c67dccf2e31f801860a7392598e951560921f3ce..1073599a7be93e6fa2de4e40d88793e5fd62b531 100644 (file)
@@ -32,15 +32,10 @@ static __inline__ int irq_canonicalize(int irq)
 }
 
 struct irq_chip;
+struct irq_data;
 
-/*
- * Some useful "we don't have to do anything here" handlers.  Should
- * probably be provided by the generic code.
- */
-void no_ack_irq(unsigned int irq);
-void no_end_irq(unsigned int irq);
-void cpu_ack_irq(unsigned int irq);
-void cpu_eoi_irq(unsigned int irq);
+void cpu_ack_irq(struct irq_data *d);
+void cpu_eoi_irq(struct irq_data *d);
 
 extern int txn_alloc_irq(unsigned int nbits);
 extern int txn_claim_irq(int);
@@ -49,7 +44,7 @@ extern unsigned long txn_alloc_addr(unsigned int);
 extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
 
 extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
-extern int cpu_check_affinity(unsigned int irq, const struct cpumask *dest);
+extern int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest);
 
 /* soft power switch support (power.c) */
 extern struct tasklet_struct power_tasklet;
index 6f1f65d3c0efb06bccbddb49612c4a3a1b01321e..5d7b8ce9fdf36507c8c541d76f4e176f9db01d94 100644 (file)
@@ -138,8 +138,7 @@ struct vm_area_struct;
 #define _PAGE_NO_CACHE_BIT 24   /* (0x080) Uncached Page (U bit) */
 #define _PAGE_ACCESSED_BIT 23   /* (0x100) Software: Page Accessed */
 #define _PAGE_PRESENT_BIT  22   /* (0x200) Software: translation valid */
-#define _PAGE_FLUSH_BIT    21   /* (0x400) Software: translation valid */
-                               /*             for cache flushing only */
+/* bit 21 was formerly the FLUSH bit but is now unused */
 #define _PAGE_USER_BIT     20   /* (0x800) Software: User accessible page */
 
 /* N.B. The bits are defined in terms of a 32 bit word above, so the */
@@ -173,7 +172,6 @@ struct vm_area_struct;
 #define _PAGE_NO_CACHE (1 << xlate_pabit(_PAGE_NO_CACHE_BIT))
 #define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT))
 #define _PAGE_PRESENT  (1 << xlate_pabit(_PAGE_PRESENT_BIT))
-#define _PAGE_FLUSH    (1 << xlate_pabit(_PAGE_FLUSH_BIT))
 #define _PAGE_USER     (1 << xlate_pabit(_PAGE_USER_BIT))
 #define _PAGE_FILE     (1 << xlate_pabit(_PAGE_FILE_BIT))
 
@@ -213,7 +211,6 @@ struct vm_area_struct;
 #define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
 #define PAGE_KERNEL_UNC        __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
 #define PAGE_GATEWAY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
-#define PAGE_FLUSH      __pgprot(_PAGE_FLUSH)
 
 
 /*
@@ -261,7 +258,7 @@ extern unsigned long *empty_zero_page;
 
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
-#define pte_none(x)     ((pte_val(x) == 0) || (pte_val(x) & _PAGE_FLUSH))
+#define pte_none(x)     (pte_val(x) == 0)
 #define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
 #define pte_clear(mm,addr,xp)  do { pte_val(*(xp)) = 0; } while (0)
 
@@ -444,13 +441,10 @@ struct mm_struct;
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_t old_pte;
-       pte_t pte;
 
        spin_lock(&pa_dbit_lock);
-       pte = old_pte = *ptep;
-       pte_val(pte) &= ~_PAGE_PRESENT;
-       pte_val(pte) |= _PAGE_FLUSH;
-       set_pte_at(mm,addr,ptep,pte);
+       old_pte = *ptep;
+       pte_clear(mm,addr,ptep);
        spin_unlock(&pa_dbit_lock);
 
        return old_pte;
index 20135cc8003924dc688d1abd52e064fbbf317fd5..80e415c9936d05312bfb96c4980254540b5f6bd5 100644 (file)
@@ -9,20 +9,4 @@ typedef unsigned short umode_t;
 
 #endif /* __ASSEMBLY__ */
 
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-
-#ifndef __ASSEMBLY__
-
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-typedef u64 dma64_addr_t;
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
 #endif
index d054f3da3ff512fa07c0a5b5b818a8e53adfcada..3f11331c27755f835a228cfdc91e5f05cf808042 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
+#include <asm/shmparam.h>
 
 int split_tlb __read_mostly;
 int dcache_stride __read_mostly;
 int icache_stride __read_mostly;
 EXPORT_SYMBOL(dcache_stride);
 
+void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+EXPORT_SYMBOL(flush_dcache_page_asm);
+void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+
 
 /* On some machines (e.g. ones with the Merced bus), there can be
  * only a single PxTLB broadcast at a time; this must be guaranteed
@@ -259,81 +264,13 @@ void disable_sr_hashing(void)
                panic("SpaceID hashing is still on!\n");
 }
 
-/* Simple function to work out if we have an existing address translation
- * for a user space vma. */
-static inline int translation_exists(struct vm_area_struct *vma,
-                               unsigned long addr, unsigned long pfn)
-{
-       pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
-       pmd_t *pmd;
-       pte_t pte;
-
-       if(pgd_none(*pgd))
-               return 0;
-
-       pmd = pmd_offset(pgd, addr);
-       if(pmd_none(*pmd) || pmd_bad(*pmd))
-               return 0;
-
-       /* We cannot take the pte lock here: flush_cache_page is usually
-        * called with pte lock already held.  Whereas flush_dcache_page
-        * takes flush_dcache_mmap_lock, which is lower in the hierarchy:
-        * the vma itself is secure, but the pte might come or go racily.
-        */
-       pte = *pte_offset_map(pmd, addr);
-       /* But pte_unmap() does nothing on this architecture */
-
-       /* Filter out coincidental file entries and swap entries */
-       if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT)))
-               return 0;
-
-       return pte_pfn(pte) == pfn;
-}
-
-/* Private function to flush a page from the cache of a non-current
- * process.  cr25 contains the Page Directory of the current user
- * process; we're going to hijack both it and the user space %sr3 to
- * temporarily make the non-current process current.  We have to do
- * this because cache flushing may cause a non-access tlb miss which
- * the handlers have to fill in from the pgd of the non-current
- * process. */
 static inline void
-flush_user_cache_page_non_current(struct vm_area_struct *vma,
-                                 unsigned long vmaddr)
+__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+                  unsigned long physaddr)
 {
-       /* save the current process space and pgd */
-       unsigned long space = mfsp(3), pgd = mfctl(25);
-
-       /* we don't mind taking interrupts since they may not
-        * do anything with user space, but we can't
-        * be preempted here */
-       preempt_disable();
-
-       /* make us current */
-       mtctl(__pa(vma->vm_mm->pgd), 25);
-       mtsp(vma->vm_mm->context, 3);
-
-       flush_user_dcache_page(vmaddr);
-       if(vma->vm_flags & VM_EXEC)
-               flush_user_icache_page(vmaddr);
-
-       /* put the old current process back */
-       mtsp(space, 3);
-       mtctl(pgd, 25);
-       preempt_enable();
-}
-
-
-static inline void
-__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-       if (likely(vma->vm_mm->context == mfsp(3))) {
-               flush_user_dcache_page(vmaddr);
-               if (vma->vm_flags & VM_EXEC)
-                       flush_user_icache_page(vmaddr);
-       } else {
-               flush_user_cache_page_non_current(vma, vmaddr);
-       }
+       flush_dcache_page_asm(physaddr, vmaddr);
+       if (vma->vm_flags & VM_EXEC)
+               flush_icache_page_asm(physaddr, vmaddr);
 }
 
 void flush_dcache_page(struct page *page)
@@ -342,10 +279,8 @@ void flush_dcache_page(struct page *page)
        struct vm_area_struct *mpnt;
        struct prio_tree_iter iter;
        unsigned long offset;
-       unsigned long addr;
+       unsigned long addr, old_addr = 0;
        pgoff_t pgoff;
-       unsigned long pfn = page_to_pfn(page);
-
 
        if (mapping && !mapping_mapped(mapping)) {
                set_bit(PG_dcache_dirty, &page->flags);
@@ -369,20 +304,11 @@ void flush_dcache_page(struct page *page)
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
                addr = mpnt->vm_start + offset;
 
-               /* Flush instructions produce non access tlb misses.
-                * On PA, we nullify these instructions rather than
-                * taking a page fault if the pte doesn't exist.
-                * This is just for speed.  If the page translation
-                * isn't there, there's no point exciting the
-                * nadtlb handler into a nullification frenzy.
-                *
-                * Make sure we really have this page: the private
-                * mappings may cover this area but have COW'd this
-                * particular page.
-                */
-               if (translation_exists(mpnt, addr, pfn)) {
-                       __flush_cache_page(mpnt, addr);
-                       break;
+               if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+                       __flush_cache_page(mpnt, addr, page_to_phys(page));
+                       if (old_addr)
+                               printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+                       old_addr = addr;
                }
        }
        flush_dcache_mmap_unlock(mapping);
@@ -573,7 +499,6 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 {
        BUG_ON(!vma->vm_mm->context);
 
-       if (likely(translation_exists(vma, vmaddr, pfn)))
-               __flush_cache_page(vma, vmaddr);
+       __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
 
 }
index 6337adef30f64f158086d6ff322dd20ed7ec6361..e5477092a5d4cde2cde30c2b11c79a6ffd58b18e 100644 (file)
 #ifndef CONFIG_64BIT
        /*
         * naitlb miss interruption handler (parisc 1.1 - 32 bit)
-        *
-        * Note: naitlb misses will be treated
-        * as an ordinary itlb miss for now.
-        * However, note that naitlb misses
-        * have the faulting address in the
-        * IOR/ISR.
         */
 
        .macro  naitlb_11 code
 
        mfctl   %isr,spc
-       b       itlb_miss_11
+       b       naitlb_miss_11
        mfctl   %ior,va
-       /* FIXME: If user causes a naitlb miss, the priv level may not be in
-        * lower bits of va, where the itlb miss handler is expecting them
-        */
 
        .align          32
        .endm
        
        /*
         * naitlb miss interruption handler (parisc 2.0)
-        *
-        * Note: naitlb misses will be treated
-        * as an ordinary itlb miss for now.
-        * However, note that naitlb misses
-        * have the faulting address in the
-        * IOR/ISR.
         */
 
        .macro  naitlb_20 code
 
        mfctl   %isr,spc
 #ifdef CONFIG_64BIT
-       b       itlb_miss_20w
+       b       naitlb_miss_20w
 #else
-       b       itlb_miss_20
+       b       naitlb_miss_20
 #endif
        mfctl   %ior,va
-       /* FIXME: If user causes a naitlb miss, the priv level may not be in
-        * lower bits of va, where the itlb miss handler is expecting them
-        */
 
        .align          32
        .endm
        copy            \va,\tmp1
        depi            0,31,23,\tmp1
        cmpb,COND(<>),n \tmp,\tmp1,\fault
-       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),\prot
+       mfctl           %cr19,\tmp      /* iir */
+       /* get the opcode (first six bits) into \tmp */
+       extrw,u         \tmp,5,6,\tmp
+       /*
+        * Only setting the T bit prevents data cache movein
+        * Setting access rights to zero prevents instruction cache movein
+        *
+        * Note subtlety here: _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE go
+        * to type field and _PAGE_READ goes to top bit of PL1
+        */
+       ldi             (_PAGE_REFTRAP|_PAGE_READ|_PAGE_WRITE),\prot
+       /*
+        * so if the opcode is one (i.e. this is a memory management
+        * instruction) nullify the next load so \prot is only T.
+        * Otherwise this is a normal data operation
+        */
+       cmpiclr,=       0x01,\tmp,%r0
+       ldi             (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
        depd,z          \prot,8,7,\prot
        /*
         * OK, it is in the temp alias region, check whether "from" or "to".
@@ -631,11 +630,7 @@ ENTRY(fault_vector_20)
        def             13
        def             14
        dtlb_20         15
-#if 0
        naitlb_20       16
-#else
-       def             16
-#endif
        nadtlb_20       17
        def             18
        def             19
@@ -678,11 +673,7 @@ ENTRY(fault_vector_11)
        def             13
        def             14
        dtlb_11         15
-#if 0
        naitlb_11       16
-#else
-       def             16
-#endif
        nadtlb_11       17
        def             18
        def             19
@@ -1203,7 +1194,7 @@ nadtlb_miss_20w:
        get_pgd         spc,ptp
        space_check     spc,t0,nadtlb_fault
 
-       L3_ptep         ptp,pte,t0,va,nadtlb_check_flush_20w
+       L3_ptep         ptp,pte,t0,va,nadtlb_check_alias_20w
 
        update_ptep     ptp,pte,t0,t1
 
@@ -1214,16 +1205,8 @@ nadtlb_miss_20w:
        rfir
        nop
 
-nadtlb_check_flush_20w:
-       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
-
-       /* Insert a "flush only" translation */
-
-       depdi,z         7,7,3,prot
-       depdi           1,10,1,prot
-
-       /* Drop prot bits from pte and convert to page addr for idtlbt */
-       convert_for_tlb_insert20 pte
+nadtlb_check_alias_20w:
+       do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 
        idtlbt          pte,prot
 
@@ -1255,25 +1238,7 @@ dtlb_miss_11:
        nop
 
 dtlb_check_alias_11:
-
-       /* Check to see if fault is in the temporary alias region */
-
-       cmpib,<>,n      0,spc,dtlb_fault /* forward */
-       ldil            L%(TMPALIAS_MAP_START),t0
-       copy            va,t1
-       depwi           0,31,23,t1
-       cmpb,<>,n       t0,t1,dtlb_fault /* forward */
-       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
-       depw,z          prot,8,7,prot
-
-       /*
-        * OK, it is in the temp alias region, check whether "from" or "to".
-        * Check "subtle" note in pacache.S re: r23/r26.
-        */
-
-       extrw,u,=       va,9,1,r0
-       or,tr           %r23,%r0,pte    /* If "from" use "from" page */
-       or              %r26,%r0,pte    /* else "to", use "to" page  */
+       do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
 
        idtlba          pte,(va)
        idtlbp          prot,(va)
@@ -1286,7 +1251,7 @@ nadtlb_miss_11:
 
        space_check     spc,t0,nadtlb_fault
 
-       L2_ptep         ptp,pte,t0,va,nadtlb_check_flush_11
+       L2_ptep         ptp,pte,t0,va,nadtlb_check_alias_11
 
        update_ptep     ptp,pte,t0,t1
 
@@ -1304,26 +1269,11 @@ nadtlb_miss_11:
        rfir
        nop
 
-nadtlb_check_flush_11:
-       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
-
-       /* Insert a "flush only" translation */
-
-       zdepi           7,7,3,prot
-       depi            1,10,1,prot
+nadtlb_check_alias_11:
+       do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 
-       /* Get rid of prot bits and convert to page addr for idtlba */
-
-       depi            0,31,ASM_PFN_PTE_SHIFT,pte
-       SHRREG          pte,(ASM_PFN_PTE_SHIFT-(31-26)),pte
-
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
-       mtsp            spc,%sr1
-
-       idtlba          pte,(%sr1,va)
-       idtlbp          prot,(%sr1,va)
-
-       mtsp            t0, %sr1        /* Restore sr1 */
+       idtlba          pte,(va)
+       idtlbp          prot,(va)
 
        rfir
        nop
@@ -1359,7 +1309,7 @@ nadtlb_miss_20:
 
        space_check     spc,t0,nadtlb_fault
 
-       L2_ptep         ptp,pte,t0,va,nadtlb_check_flush_20
+       L2_ptep         ptp,pte,t0,va,nadtlb_check_alias_20
 
        update_ptep     ptp,pte,t0,t1
 
@@ -1372,21 +1322,14 @@ nadtlb_miss_20:
        rfir
        nop
 
-nadtlb_check_flush_20:
-       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
-
-       /* Insert a "flush only" translation */
-
-       depdi,z         7,7,3,prot
-       depdi           1,10,1,prot
-
-       /* Drop prot bits from pte and convert to page addr for idtlbt */
-       convert_for_tlb_insert20 pte
+nadtlb_check_alias_20:
+       do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 
        idtlbt          pte,prot
 
        rfir
        nop
+
 #endif
 
 nadtlb_emulate:
@@ -1484,6 +1427,36 @@ itlb_miss_20w:
        rfir
        nop
 
+naitlb_miss_20w:
+
+       /*
+        * I miss is a little different, since we allow users to fault
+        * on the gateway page which is in the kernel address space.
+        */
+
+       space_adjust    spc,va,t0
+       get_pgd         spc,ptp
+       space_check     spc,t0,naitlb_fault
+
+       L3_ptep         ptp,pte,t0,va,naitlb_check_alias_20w
+
+       update_ptep     ptp,pte,t0,t1
+
+       make_insert_tlb spc,pte,prot
+
+       iitlbt          pte,prot
+
+       rfir
+       nop
+
+naitlb_check_alias_20w:
+       do_alias        spc,t0,t1,va,pte,prot,naitlb_fault
+
+       iitlbt          pte,prot
+
+       rfir
+       nop
+
 #else
 
 itlb_miss_11:
@@ -1508,6 +1481,38 @@ itlb_miss_11:
        rfir
        nop
 
+naitlb_miss_11:
+       get_pgd         spc,ptp
+
+       space_check     spc,t0,naitlb_fault
+
+       L2_ptep         ptp,pte,t0,va,naitlb_check_alias_11
+
+       update_ptep     ptp,pte,t0,t1
+
+       make_insert_tlb_11      spc,pte,prot
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       iitlba          pte,(%sr1,va)
+       iitlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1        /* Restore sr1 */
+
+       rfir
+       nop
+
+naitlb_check_alias_11:
+       do_alias        spc,t0,t1,va,pte,prot,itlb_fault
+
+       iitlba          pte,(%sr0, va)
+       iitlbp          prot,(%sr0, va)
+
+       rfir
+       nop
+
+
 itlb_miss_20:
        get_pgd         spc,ptp
 
@@ -1526,6 +1531,32 @@ itlb_miss_20:
        rfir
        nop
 
+naitlb_miss_20:
+       get_pgd         spc,ptp
+
+       space_check     spc,t0,naitlb_fault
+
+       L2_ptep         ptp,pte,t0,va,naitlb_check_alias_20
+
+       update_ptep     ptp,pte,t0,t1
+
+       make_insert_tlb spc,pte,prot
+
+       f_extend        pte,t0
+
+       iitlbt          pte,prot
+
+       rfir
+       nop
+
+naitlb_check_alias_20:
+       do_alias        spc,t0,t1,va,pte,prot,naitlb_fault
+
+       iitlbt          pte,prot
+
+       rfir
+       nop
+
 #endif
 
 #ifdef CONFIG_64BIT
@@ -1662,6 +1693,10 @@ nadtlb_fault:
        b               intr_save
        ldi             17,%r8
 
+naitlb_fault:
+       b               intr_save
+       ldi             16,%r8
+
 dtlb_fault:
        b               intr_save
        ldi             15,%r8
index d7d94b845dc2c8bb08ece9d5e420f8cae5b7abe2..cb450e1e79b322e074277aa9d56f8802476bd5c6 100644 (file)
@@ -52,9 +52,9 @@ static volatile unsigned long cpu_eiem = 0;
 */
 static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
 
-static void cpu_mask_irq(unsigned int irq)
+static void cpu_mask_irq(struct irq_data *d)
 {
-       unsigned long eirr_bit = EIEM_MASK(irq);
+       unsigned long eirr_bit = EIEM_MASK(d->irq);
 
        cpu_eiem &= ~eirr_bit;
        /* Do nothing on the other CPUs.  If they get this interrupt,
@@ -63,7 +63,7 @@ static void cpu_mask_irq(unsigned int irq)
         * then gets disabled */
 }
 
-static void cpu_unmask_irq(unsigned int irq)
+static void __cpu_unmask_irq(unsigned int irq)
 {
        unsigned long eirr_bit = EIEM_MASK(irq);
 
@@ -75,9 +75,14 @@ static void cpu_unmask_irq(unsigned int irq)
        smp_send_all_nop();
 }
 
-void cpu_ack_irq(unsigned int irq)
+static void cpu_unmask_irq(struct irq_data *d)
+{
+       __cpu_unmask_irq(d->irq);
+}
+
+void cpu_ack_irq(struct irq_data *d)
 {
-       unsigned long mask = EIEM_MASK(irq);
+       unsigned long mask = EIEM_MASK(d->irq);
        int cpu = smp_processor_id();
 
        /* Clear in EIEM so we can no longer process */
@@ -90,9 +95,9 @@ void cpu_ack_irq(unsigned int irq)
        mtctl(mask, 23);
 }
 
-void cpu_eoi_irq(unsigned int irq)
+void cpu_eoi_irq(struct irq_data *d)
 {
-       unsigned long mask = EIEM_MASK(irq);
+       unsigned long mask = EIEM_MASK(d->irq);
        int cpu = smp_processor_id();
 
        /* set it in the eiems---it's no longer in process */
@@ -103,15 +108,16 @@ void cpu_eoi_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_SMP
-int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
+int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
 {
        int cpu_dest;
 
        /* timer and ipi have to always be received on all CPUs */
-       if (CHECK_IRQ_PER_CPU(irq)) {
+       if (CHECK_IRQ_PER_CPU(irq_to_desc(d->irq)->status)) {
                /* Bad linux design decision.  The mask has already
-                * been set; we must reset it */
-               cpumask_setall(irq_desc[irq].affinity);
+                * been set; we must reset it. Will fix - tglx
+                */
+               cpumask_setall(d->affinity);
                return -EINVAL;
        }
 
@@ -121,33 +127,34 @@ int cpu_check_affinity(unsigned int irq, const struct cpumask *dest)
        return cpu_dest;
 }
 
-static int cpu_set_affinity_irq(unsigned int irq, const struct cpumask *dest)
+static int cpu_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+                               bool force)
 {
        int cpu_dest;
 
-       cpu_dest = cpu_check_affinity(irq, dest);
+       cpu_dest = cpu_check_affinity(d, dest);
        if (cpu_dest < 0)
                return -1;
 
-       cpumask_copy(irq_desc[irq].affinity, dest);
+       cpumask_copy(d->affinity, dest);
 
        return 0;
 }
 #endif
 
 static struct irq_chip cpu_interrupt_type = {
-       .name           = "CPU",
-       .mask           = cpu_mask_irq,
-       .unmask         = cpu_unmask_irq,
-       .ack            = cpu_ack_irq,
-       .eoi            = cpu_eoi_irq,
+       .name                   = "CPU",
+       .irq_mask               = cpu_mask_irq,
+       .irq_unmask             = cpu_unmask_irq,
+       .irq_ack                = cpu_ack_irq,
+       .irq_eoi                = cpu_eoi_irq,
 #ifdef CONFIG_SMP
-       .set_affinity   = cpu_set_affinity_irq,
+       .irq_set_affinity       = cpu_set_affinity_irq,
 #endif
        /* XXX: Needs to be written.  We managed without it so far, but
         * we really ought to write it.
         */
-       .retrigger      = NULL,
+       .irq_retrigger  = NULL,
 };
 
 int show_interrupts(struct seq_file *p, void *v)
@@ -181,7 +188,7 @@ int show_interrupts(struct seq_file *p, void *v)
                seq_printf(p, "%10u ", kstat_irqs(i));
 #endif
 
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
+               seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
 #ifndef PARISC_IRQ_CR16_COUNTS
                seq_printf(p, "  %s", action->name);
 
@@ -233,14 +240,14 @@ int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
 {
        if (irq_desc[irq].action)
                return -EBUSY;
-       if (irq_desc[irq].chip != &cpu_interrupt_type)
+       if (get_irq_chip(irq) != &cpu_interrupt_type)
                return -EBUSY;
 
        /* for iosapic interrupts */
        if (type) {
                set_irq_chip_and_handler(irq, type, handle_percpu_irq);
                set_irq_chip_data(irq, data);
-               cpu_unmask_irq(irq);
+               __cpu_unmask_irq(irq);
        }
        return 0;
 }
@@ -289,7 +296,8 @@ int txn_alloc_irq(unsigned int bits_wide)
 unsigned long txn_affinity_addr(unsigned int irq, int cpu)
 {
 #ifdef CONFIG_SMP
-       cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
+       struct irq_data *d = irq_get_irq_data(irq);
+       cpumask_copy(d->affinity, cpumask_of(cpu));
 #endif
 
        return per_cpu(cpu_data, cpu).txn_addr;
@@ -333,6 +341,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
        unsigned long eirr_val;
        int irq, cpu = smp_processor_id();
 #ifdef CONFIG_SMP
+       struct irq_desc *desc;
        cpumask_t dest;
 #endif
 
@@ -346,8 +355,9 @@ void do_cpu_irq_mask(struct pt_regs *regs)
        irq = eirr_to_irq(eirr_val);
 
 #ifdef CONFIG_SMP
-       cpumask_copy(&dest, irq_desc[irq].affinity);
-       if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
+       desc = irq_to_desc(irq);
+       cpumask_copy(&dest, desc->irq_data.affinity);
+       if (CHECK_IRQ_PER_CPU(desc->status) &&
            !cpu_isset(smp_processor_id(), dest)) {
                int cpu = first_cpu(dest);
 
index 09b77b2553c6bf67c1fe36b4d502eda41cc56de5..a85823668cba041708285555e4cc31f2475f131f 100644 (file)
@@ -608,93 +608,131 @@ ENTRY(__clear_user_page_asm)
        .procend
 ENDPROC(__clear_user_page_asm)
 
-ENTRY(flush_kernel_dcache_page_asm)
+ENTRY(flush_dcache_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
 
+       ldil            L%(TMPALIAS_MAP_START), %r28
+#ifdef CONFIG_64BIT
+#if (TMPALIAS_MAP_START >= 0x80000000)
+       depdi           0, 31,32, %r28          /* clear any sign extension */
+       /* FIXME: page size dependend */
+#endif
+       extrd,u         %r26, 56,32, %r26       /* convert phys addr to tlb insert format */
+       depd            %r25, 63,22, %r28       /* Form aliased virtual address 'to' */
+       depdi           0, 63,12, %r28          /* Clear any offset bits */
+#else
+       extrw,u         %r26, 24,25, %r26       /* convert phys addr to tlb insert format */
+       depw            %r25, 31,22, %r28       /* Form aliased virtual address 'to' */
+       depwi           0, 31,12, %r28          /* Clear any offset bits */
+#endif
+
+       /* Purge any old translation */
+
+       pdtlb           0(%r28)
+
        ldil            L%dcache_stride, %r1
-       ldw             R%dcache_stride(%r1), %r23
+       ldw             R%dcache_stride(%r1), %r1
 
 #ifdef CONFIG_64BIT
        depdi,z         1, 63-PAGE_SHIFT,1, %r25
 #else
        depwi,z         1, 31-PAGE_SHIFT,1, %r25
 #endif
-       add             %r26, %r25, %r25
-       sub             %r25, %r23, %r25
-
-
-1:      fdc,m          %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       fdc,m           %r23(%r26)
-       cmpb,COND(<<)           %r26, %r25,1b
-       fdc,m           %r23(%r26)
+       add             %r28, %r25, %r25
+       sub             %r25, %r1, %r25
+
+
+1:      fdc,m          %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       fdc,m           %r1(%r28)
+       cmpb,COND(<<)           %r28, %r25,1b
+       fdc,m           %r1(%r28)
 
        sync
        bv              %r0(%r2)
-       nop
+       pdtlb           (%r25)
        .exit
 
        .procend
-ENDPROC(flush_kernel_dcache_page_asm)
-       
-ENTRY(flush_user_dcache_page)
+ENDPROC(flush_dcache_page_asm)
+
+ENTRY(flush_icache_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
 
-       ldil            L%dcache_stride, %r1
-       ldw             R%dcache_stride(%r1), %r23
-
+       ldil            L%(TMPALIAS_MAP_START), %r28
 #ifdef CONFIG_64BIT
-       depdi,z         1,63-PAGE_SHIFT,1, %r25
+#if (TMPALIAS_MAP_START >= 0x80000000)
+       depdi           0, 31,32, %r28          /* clear any sign extension */
+       /* FIXME: page size dependend */
+#endif
+       extrd,u         %r26, 56,32, %r26       /* convert phys addr to tlb insert format */
+       depd            %r25, 63,22, %r28       /* Form aliased virtual address 'to' */
+       depdi           0, 63,12, %r28          /* Clear any offset bits */
 #else
-       depwi,z         1,31-PAGE_SHIFT,1, %r25
+       extrw,u         %r26, 24,25, %r26       /* convert phys addr to tlb insert format */
+       depw            %r25, 31,22, %r28       /* Form aliased virtual address 'to' */
+       depwi           0, 31,12, %r28          /* Clear any offset bits */
 #endif
-       add             %r26, %r25, %r25
-       sub             %r25, %r23, %r25
 
+       /* Purge any old translation */
 
-1:      fdc,m          %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       fdc,m           %r23(%sr3, %r26)
-       cmpb,COND(<<)           %r26, %r25,1b
-       fdc,m           %r23(%sr3, %r26)
+       pitlb           (%sr0,%r28)
+
+       ldil            L%icache_stride, %r1
+       ldw             R%icache_stride(%r1), %r1
+
+#ifdef CONFIG_64BIT
+       depdi,z         1, 63-PAGE_SHIFT,1, %r25
+#else
+       depwi,z         1, 31-PAGE_SHIFT,1, %r25
+#endif
+       add             %r28, %r25, %r25
+       sub             %r25, %r1, %r25
+
+
+1:      fic,m          %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       fic,m           %r1(%r28)
+       cmpb,COND(<<)           %r28, %r25,1b
+       fic,m           %r1(%r28)
 
        sync
        bv              %r0(%r2)
-       nop
+       pitlb           (%sr0,%r25)
        .exit
 
        .procend
-ENDPROC(flush_user_dcache_page)
+ENDPROC(flush_icache_page_asm)
 
-ENTRY(flush_user_icache_page)
+ENTRY(flush_kernel_dcache_page_asm)
        .proc
        .callinfo NO_CALLS
        .entry
@@ -711,23 +749,23 @@ ENTRY(flush_user_icache_page)
        sub             %r25, %r23, %r25
 
 
-1:      fic,m          %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
-       fic,m           %r23(%sr3, %r26)
+1:      fdc,m          %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
+       fdc,m           %r23(%r26)
        cmpb,COND(<<)           %r26, %r25,1b
-       fic,m           %r23(%sr3, %r26)
+       fdc,m           %r23(%r26)
 
        sync
        bv              %r0(%r2)
@@ -735,8 +773,7 @@ ENTRY(flush_user_icache_page)
        .exit
 
        .procend
-ENDPROC(flush_user_icache_page)
-
+ENDPROC(flush_kernel_dcache_page_asm)
 
 ENTRY(purge_kernel_dcache_page)
        .proc
@@ -780,69 +817,6 @@ ENTRY(purge_kernel_dcache_page)
        .procend
 ENDPROC(purge_kernel_dcache_page)
 
-#if 0
-       /* Currently not used, but it still is a possible alternate
-        * solution.
-        */
-
-ENTRY(flush_alias_page)
-       .proc
-       .callinfo NO_CALLS
-       .entry
-
-       tophys_r1               %r26
-
-       ldil            L%(TMPALIAS_MAP_START), %r28
-#ifdef CONFIG_64BIT
-       extrd,u         %r26, 56,32, %r26       /* convert phys addr to tlb insert format */
-       depd            %r25, 63,22, %r28       /* Form aliased virtual address 'to' */
-       depdi           0, 63,12, %r28          /* Clear any offset bits */
-#else
-       extrw,u         %r26, 24,25, %r26       /* convert phys addr to tlb insert format */
-       depw            %r25, 31,22, %r28       /* Form aliased virtual address 'to' */
-       depwi           0, 31,12, %r28          /* Clear any offset bits */
-#endif
-
-       /* Purge any old translation */
-
-       pdtlb           0(%r28)
-
-       ldil            L%dcache_stride, %r1
-       ldw             R%dcache_stride(%r1), %r23
-
-#ifdef CONFIG_64BIT
-       depdi,z         1, 63-PAGE_SHIFT,1, %r29
-#else
-       depwi,z         1, 31-PAGE_SHIFT,1, %r29
-#endif
-       add             %r28, %r29, %r29
-       sub             %r29, %r23, %r29
-
-1:      fdc,m          %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       fdc,m           %r23(%r28)
-       cmpb,COND(<<)           %r28, %r29, 1b
-       fdc,m           %r23(%r28)
-
-       sync
-       bv              %r0(%r2)
-       nop
-       .exit
-
-       .procend
-#endif
 
        .export flush_user_dcache_range_asm
 
@@ -865,7 +839,6 @@ flush_user_dcache_range_asm:
        .exit
 
        .procend
-ENDPROC(flush_alias_page)
 
 ENTRY(flush_kernel_dcache_range_asm)
        .proc
index f4f4d700833affc00d9953871b441eae12227831..b7ed8d7a9b33a10e784722a3fa5b8a55f7eabbcb 100644 (file)
@@ -544,7 +544,7 @@ void __init mem_init(void)
 unsigned long *empty_zero_page __read_mostly;
 EXPORT_SYMBOL(empty_zero_page);
 
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        int i,free = 0,total = 0,reserved = 0;
        int shared = 0, cached = 0;
index 71ba04721bebadb58132125da79b605c13a09d4f..3584e4d4a4ad5f0f0409e5fc77e2fa6869b8dc67 100644 (file)
@@ -95,6 +95,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_GPIO
        bool
        help
@@ -768,11 +772,19 @@ config HAS_RAPIDIO
 
 config RAPIDIO
        bool "RapidIO support"
-       depends on HAS_RAPIDIO
+       depends on HAS_RAPIDIO || PCI
        help
          If you say Y here, the kernel will include drivers and
          infrastructure code to support RapidIO interconnect devices.
 
+config FSL_RIO
+       bool "Freescale Embedded SRIO Controller support"
+       depends on RAPIDIO && HAS_RAPIDIO
+       default "n"
+       ---help---
+         Include support for RapidIO controller on Freescale embedded
+         processors (MPC8548, MPC8641, etc).
+
 source "drivers/rapidio/Kconfig"
 
 endmenu
index 8a7e9314c68a3b404713d3c282743d098fffb60f..2e561876fc899166d0c411cb77ae2f7f899eb096 100644 (file)
@@ -281,68 +281,56 @@ unsigned long __arch_hweight64(__u64 w);
 
 /* Little-endian versions */
 
-static __inline__ int test_le_bit(unsigned long nr,
-                                 __const__ unsigned long *addr)
+static __inline__ int test_bit_le(unsigned long nr,
+                                 __const__ void *addr)
 {
        __const__ unsigned char *tmp = (__const__ unsigned char *) addr;
        return (tmp[nr >> 3] >> (nr & 7)) & 1;
 }
 
-#define __set_le_bit(nr, addr) \
-       __set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define __clear_le_bit(nr, addr) \
-       __clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+static inline void __set_bit_le(int nr, void *addr)
+{
+       __set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline void __clear_bit_le(int nr, void *addr)
+{
+       __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int test_and_set_bit_le(int nr, void *addr)
+{
+       return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
 
-#define test_and_set_le_bit(nr, addr) \
-       test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define test_and_clear_le_bit(nr, addr) \
-       test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+static inline int test_and_clear_bit_le(int nr, void *addr)
+{
+       return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int __test_and_set_bit_le(int nr, void *addr)
+{
+       return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
 
-#define __test_and_set_le_bit(nr, addr) \
-       __test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define __test_and_clear_le_bit(nr, addr) \
-       __test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+static inline int __test_and_clear_bit_le(int nr, void *addr)
+{
+       return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
 
-#define find_first_zero_le_bit(addr, size) generic_find_next_zero_le_bit((addr), (size), 0)
-unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
+#define find_first_zero_bit_le(addr, size) \
+       find_next_zero_bit_le((addr), (size), 0)
+unsigned long find_next_zero_bit_le(const void *addr,
                                    unsigned long size, unsigned long offset);
 
-unsigned long generic_find_next_le_bit(const unsigned long *addr,
+unsigned long find_next_bit_le(const void *addr,
                                    unsigned long size, unsigned long offset);
 /* Bitmap functions for the ext2 filesystem */
 
-#define ext2_set_bit(nr,addr) \
-       __test_and_set_le_bit((nr), (unsigned long*)addr)
-#define ext2_clear_bit(nr, addr) \
-       __test_and_clear_le_bit((nr), (unsigned long*)addr)
-
 #define ext2_set_bit_atomic(lock, nr, addr) \
-       test_and_set_le_bit((nr), (unsigned long*)addr)
+       test_and_set_bit_le((nr), (unsigned long*)addr)
 #define ext2_clear_bit_atomic(lock, nr, addr) \
-       test_and_clear_le_bit((nr), (unsigned long*)addr)
-
-#define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
-
-#define ext2_find_first_zero_bit(addr, size) \
-       find_first_zero_le_bit((unsigned long*)addr, size)
-#define ext2_find_next_zero_bit(addr, size, off) \
-       generic_find_next_zero_le_bit((unsigned long*)addr, size, off)
-
-#define ext2_find_next_bit(addr, size, off) \
-       generic_find_next_le_bit((unsigned long *)addr, size, off)
-/* Bitmap functions for the minix filesystem.  */
-
-#define minix_test_and_set_bit(nr,addr) \
-       __test_and_set_le_bit(nr, (unsigned long *)addr)
-#define minix_set_bit(nr,addr) \
-       __set_le_bit(nr, (unsigned long *)addr)
-#define minix_test_and_clear_bit(nr,addr) \
-       __test_and_clear_le_bit(nr, (unsigned long *)addr)
-#define minix_test_bit(nr,addr) \
-       test_le_bit(nr, (unsigned long *)addr)
-
-#define minix_find_first_zero_bit(addr,size) \
-       find_first_zero_le_bit((unsigned long *)addr, size)
+       test_and_clear_bit_le((nr), (unsigned long*)addr)
 
 #include <asm-generic/bitops/sched.h>
 
index 946ec4947da282e90589a3012c8fb92653ecc5f2..7005ee0b074d744e6905fd8e0c6dfc144a3a4cb3 100644 (file)
@@ -367,6 +367,10 @@ struct mpic
 #define MPIC_SINGLE_DEST_CPU           0x00001000
 /* Enable CoreInt delivery of interrupts */
 #define MPIC_ENABLE_COREINT            0x00002000
+/* Disable resetting of the MPIC.
+ * NOTE: This flag trumps MPIC_WANTS_RESET.
+ */
+#define MPIC_NO_RESET                  0x00004000
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK               0xf0000000
index 0175a676b34b5e577c4e52107bfd1f3e99c6e8d2..48223f9b8728d5e1433c6d13ab9c1c583780d2cb 100644 (file)
@@ -125,8 +125,10 @@ extern int ptrace_put_reg(struct task_struct *task, int regno,
 #endif /* ! __powerpc64__ */
 #define TRAP(regs)             ((regs)->trap & ~0xF)
 #ifdef __powerpc64__
+#define NV_REG_POISON          0xdeadbeefdeadbeefUL
 #define CHECK_FULL_REGS(regs)  BUG_ON(regs->trap & 1)
 #else
+#define NV_REG_POISON          0xdeadbeef
 #define CHECK_FULL_REGS(regs)                                                \
 do {                                                                         \
        if ((regs)->trap & 1)                                                 \
index 65eb85976a03a9199e3316f5e59424d3105822c7..d8529ef13b2329352a6b85a92adb2574ed768607 100644 (file)
@@ -72,7 +72,7 @@ struct thread_info {
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
-extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
+extern struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node);
 extern void free_thread_info(struct thread_info *ti);
 
 #endif /* THREAD_SHIFT < PAGE_SHIFT */
index a5aea0ca34e9a3dc98fdf4b504cc56e472baad87..8947b9827bc40d8d03fba298554d0c0f449aa31c 100644 (file)
@@ -44,13 +44,6 @@ typedef struct {
 
 typedef __vector128 vector128;
 
-#if defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)
-typedef u64 dma_addr_t;
-#else
-typedef u32 dma_addr_t;
-#endif
-typedef u64 dma64_addr_t;
-
 typedef struct {
        unsigned long entry;
        unsigned long toc;
index 5c518ad3445c4a6e642d61a1ac24f35ee5846781..913611105c1f5154baf6a9d9ff473cd7444338c9 100644 (file)
@@ -64,7 +64,7 @@ _GLOBAL(__setup_cpu_e500v2)
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
        bl      __setup_e500_ivors
-#ifdef CONFIG_RAPIDIO
+#ifdef CONFIG_FSL_RIO
        /* Ensure that RFXE is set */
        mfspr   r3,SPRN_HID1
        oris    r3,r3,HID1_RFXE@h
index 0a2af50243cb04f060e23ba250ea888be41700a1..424afb6b8fbaef07f9db351eb4429783b9baa83c 100644 (file)
@@ -28,9 +28,6 @@
 #define DBG(fmt...)
 #endif
 
-/* Stores the physical address of elf header of crash image. */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
 #ifndef CONFIG_RELOCATABLE
 void __init reserve_kdump_trampoline(void)
 {
@@ -72,20 +69,6 @@ void __init setup_kdump_trampoline(void)
 }
 #endif /* CONFIG_RELOCATABLE */
 
-/*
- * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
- * is_kdump_kernel() to determine if we are booting after a panic. Hence
- * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
- */
-static int __init parse_elfcorehdr(char *p)
-{
-       if (p)
-               elfcorehdr_addr = memparse(p, &p);
-
-       return 1;
-}
-__setup("elfcorehdr=", parse_elfcorehdr);
-
 static int __init parse_savemaxmem(char *p)
 {
        if (p)
index 29852688ceaaae7f6f9c09cbc7e3f6350ee8170f..d225d99fe39d8f076ee637377a43692024c39232 100644 (file)
@@ -176,11 +176,14 @@ static void *is_devfn_node(struct device_node *dn, void *data)
  */
 struct device_node *fetch_dev_dn(struct pci_dev *dev)
 {
-       struct device_node *orig_dn = dev->dev.of_node;
+       struct pci_controller *phb = dev->sysdata;
        struct device_node *dn;
        unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
 
-       dn = traverse_pci_devices(orig_dn, is_devfn_node, (void *)searchval);
+       if (WARN_ON(!phb))
+               return NULL;
+
+       dn = traverse_pci_devices(phb->dn, is_devfn_node, (void *)searchval);
        if (dn)
                dev->dev.of_node = dn;
        return dn;
index 8303a6c65ef7e85f230bac363bb722c49e460211..f74f355a9617a97ea05e174efaa9f67f4db3e275 100644 (file)
@@ -1218,11 +1218,11 @@ void __ppc64_runlatch_off(void)
 
 static struct kmem_cache *thread_info_cache;
 
-struct thread_info *alloc_thread_info(struct task_struct *tsk)
+struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node)
 {
        struct thread_info *ti;
 
-       ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
+       ti = kmem_cache_alloc_node(thread_info_cache, GFP_KERNEL, node);
        if (unlikely(ti == NULL))
                return NULL;
 #ifdef CONFIG_DEBUG_STACK_USAGE
index 9065369982911f19eab7ee34fa88209597cfbdeb..895b082f1e48bafe5c7826de6950edf14cff6d23 100644 (file)
@@ -229,12 +229,16 @@ static int gpr_get(struct task_struct *target, const struct user_regset *regset,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
 {
-       int ret;
+       int i, ret;
 
        if (target->thread.regs == NULL)
                return -EIO;
 
-       CHECK_FULL_REGS(target->thread.regs);
+       if (!FULL_REGS(target->thread.regs)) {
+               /* We have a partial register set.  Fill 14-31 with bogus values */
+               for (i = 14; i < 32; i++)
+                       target->thread.regs->gpr[i] = NV_REG_POISON;
+       }
 
        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                  target->thread.regs,
@@ -641,11 +645,16 @@ static int gpr32_get(struct task_struct *target,
        compat_ulong_t *k = kbuf;
        compat_ulong_t __user *u = ubuf;
        compat_ulong_t reg;
+       int i;
 
        if (target->thread.regs == NULL)
                return -EIO;
 
-       CHECK_FULL_REGS(target->thread.regs);
+       if (!FULL_REGS(target->thread.regs)) {
+               /* We have a partial register set.  Fill 14-31 with bogus values */
+               for (i = 14; i < 32; i++)
+                       target->thread.regs->gpr[i] = NV_REG_POISON; 
+       }
 
        pos /= sizeof(reg);
        count /= sizeof(reg);
index fd8728729abc9cb671d65bd8cb625fbaf22de12c..142ab1008c3bd63aff1b99f6e0bb1726351c3212 100644 (file)
@@ -820,17 +820,17 @@ static int __init vdso_init(void)
 }
 arch_initcall(vdso_init);
 
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
        return 0;
 }
 
-int in_gate_area(struct task_struct *task, unsigned long addr)
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
 {
        return 0;
 }
 
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
        return NULL;
 }
index 9c2973479142125333e953e1a99f462c3350494a..1e0c933ef772d6aa2d120dc6abb7ee8d63b18a5c 100644 (file)
@@ -20,7 +20,7 @@ obj-$(CONFIG_FSL_GTM)         += fsl_gtm.o
 obj-$(CONFIG_MPC8xxx_GPIO)     += mpc8xxx_gpio.o
 obj-$(CONFIG_FSL_85XX_CACHE_SRAM)      += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)      += simple_gpio.o
-obj-$(CONFIG_RAPIDIO)          += fsl_rio.o
+obj-$(CONFIG_FSL_RIO)          += fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)     += qe_lib/
 obj-$(CONFIG_PPC_BESTCOMM)     += bestcomm/
index 3eff2c3a9ad56877d9e159ffa8ce460917d6bf5e..14232d57369c4de4f373f76e095ec95bb559345e 100644 (file)
@@ -482,7 +482,7 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
 }
 
 /**
- * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue
+ * fsl_add_outb_message - Add message to the MPC85xx outbound message queue
  * @mport: Master port with outbound message queue
  * @rdev: Target of outbound message
  * @mbox: Outbound mailbox
@@ -492,8 +492,8 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
  * Adds the @buffer message to the MPC85xx outbound message queue. Returns
  * %0 on success or %-EINVAL on failure.
  */
-int
-rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
+static int
+fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
                        void *buffer, size_t len)
 {
        struct rio_priv *priv = mport->priv;
@@ -502,9 +502,8 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
                                        + priv->msg_tx_ring.tx_slot;
        int ret = 0;
 
-       pr_debug
-           ("RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n",
-            rdev->destid, mbox, (int)buffer, len);
+       pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
+                "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
 
        if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
                ret = -EINVAL;
@@ -554,8 +553,6 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
        return ret;
 }
 
-EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
-
 /**
  * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
  * @irq: Linux interrupt number
@@ -600,7 +597,7 @@ fsl_rio_tx_handler(int irq, void *dev_instance)
 }
 
 /**
- * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox
  * @mport: Master port implementing the outbound message unit
  * @dev_id: Device specific pointer to pass on event
  * @mbox: Mailbox to open
@@ -610,7 +607,8 @@ fsl_rio_tx_handler(int irq, void *dev_instance)
  * and enables the outbound message unit. Returns %0 on success and
  * %-EINVAL or %-ENOMEM on failure.
  */
-int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+static int
+fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
 {
        int i, j, rc = 0;
        struct rio_priv *priv = mport->priv;
@@ -706,14 +704,14 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
 }
 
 /**
- * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox
  * @mport: Master port implementing the outbound message unit
  * @mbox: Mailbox to close
  *
  * Disables the outbound message unit, free all buffers, and
  * frees the outbound message interrupt.
  */
-void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
 {
        struct rio_priv *priv = mport->priv;
        /* Disable inbound message unit */
@@ -770,7 +768,7 @@ fsl_rio_rx_handler(int irq, void *dev_instance)
 }
 
 /**
- * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox
  * @mport: Master port implementing the inbound message unit
  * @dev_id: Device specific pointer to pass on event
  * @mbox: Mailbox to open
@@ -780,7 +778,8 @@ fsl_rio_rx_handler(int irq, void *dev_instance)
  * and enables the inbound message unit. Returns %0 on success
  * and %-EINVAL or %-ENOMEM on failure.
  */
-int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+static int
+fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
 {
        int i, rc = 0;
        struct rio_priv *priv = mport->priv;
@@ -844,14 +843,14 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
 }
 
 /**
- * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox
  * @mport: Master port implementing the inbound message unit
  * @mbox: Mailbox to close
  *
  * Disables the inbound message unit, free all buffers, and
  * frees the inbound message interrupt.
  */
-void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
 {
        struct rio_priv *priv = mport->priv;
        /* Disable inbound message unit */
@@ -866,7 +865,7 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
 }
 
 /**
- * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
+ * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
  * @mport: Master port implementing the inbound message unit
  * @mbox: Inbound mailbox number
  * @buf: Buffer to add to inbound queue
@@ -874,12 +873,12 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
  * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
  * %0 on success or %-EINVAL on failure.
  */
-int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
 {
        int rc = 0;
        struct rio_priv *priv = mport->priv;
 
-       pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+       pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
                 priv->msg_rx_ring.rx_slot);
 
        if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) {
@@ -898,17 +897,15 @@ int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
        return rc;
 }
 
-EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
-
 /**
- * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit
+ * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit
  * @mport: Master port implementing the inbound message unit
  * @mbox: Inbound mailbox number
  *
  * Gets the next available inbound message from the inbound message queue.
  * A pointer to the message is returned on success or NULL on failure.
  */
-void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+static void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
 {
        struct rio_priv *priv = mport->priv;
        u32 phys_buf, virt_buf;
@@ -945,8 +942,6 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
        return buf;
 }
 
-EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
-
 /**
  * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
  * @irq: Linux interrupt number
@@ -1293,28 +1288,6 @@ err_out:
        return rc;
 }
 
-static char *cmdline = NULL;
-
-static int fsl_rio_get_hdid(int index)
-{
-       /* XXX Need to parse multiple entries in some format */
-       if (!cmdline)
-               return -1;
-
-       return simple_strtol(cmdline, NULL, 0);
-}
-
-static int fsl_rio_get_cmdline(char *s)
-{
-       if (!s)
-               return 0;
-
-       cmdline = s;
-       return 1;
-}
-
-__setup("riohdid=", fsl_rio_get_cmdline);
-
 static inline void fsl_rio_info(struct device *dev, u32 ccsr)
 {
        const char *str;
@@ -1431,13 +1404,19 @@ int fsl_rio_setup(struct platform_device *dev)
        ops->cwrite = fsl_rio_config_write;
        ops->dsend = fsl_rio_doorbell_send;
        ops->pwenable = fsl_rio_pw_enable;
+       ops->open_outb_mbox = fsl_open_outb_mbox;
+       ops->open_inb_mbox = fsl_open_inb_mbox;
+       ops->close_outb_mbox = fsl_close_outb_mbox;
+       ops->close_inb_mbox = fsl_close_inb_mbox;
+       ops->add_outb_message = fsl_add_outb_message;
+       ops->add_inb_buffer = fsl_add_inb_buffer;
+       ops->get_inb_message = fsl_get_inb_message;
 
        port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
        if (!port) {
                rc = -ENOMEM;
                goto err_port;
        }
-       port->id = 0;
        port->index = 0;
 
        priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL);
@@ -1453,6 +1432,14 @@ int fsl_rio_setup(struct platform_device *dev)
        port->iores.flags = IORESOURCE_MEM;
        port->iores.name = "rio_io_win";
 
+       if (request_resource(&iomem_resource, &port->iores) < 0) {
+               dev_err(&dev->dev, "RIO: Error requesting master port region"
+                       " 0x%016llx-0x%016llx\n",
+                       (u64)port->iores.start, (u64)port->iores.end);
+                       rc = -ENOMEM;
+                       goto err_res;
+       }
+
        priv->pwirq   = irq_of_parse_and_map(dev->dev.of_node, 0);
        priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
        priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
@@ -1468,8 +1455,6 @@ int fsl_rio_setup(struct platform_device *dev)
        priv->dev = &dev->dev;
 
        port->ops = ops;
-       port->host_deviceid = fsl_rio_get_hdid(port->id);
-
        port->priv = priv;
        port->phys_efptr = 0x100;
        rio_register_mport(port);
@@ -1559,6 +1544,7 @@ int fsl_rio_setup(struct platform_device *dev)
        return 0;
 err:
        iounmap(priv->regs_win);
+err_res:
        kfree(priv);
 err_priv:
        kfree(port);
@@ -1572,18 +1558,10 @@ err_ops:
  */
 static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev)
 {
-       int rc;
        printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n",
                        dev->dev.of_node->full_name);
 
-       rc = fsl_rio_setup(dev);
-       if (rc)
-               goto out;
-
-       /* Enumerate all registered ports */
-       rc = rio_init_mports();
-out:
-       return rc;
+       return fsl_rio_setup(dev);
 };
 
 static const struct of_device_id fsl_of_rio_rpn_ids[] = {
index eb7021815e2da0c28e6bdc85be746e7135acd415..0f7c6718d26107c37e819be52d9794bbe7b9e883 100644 (file)
@@ -147,6 +147,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = {
 
 #endif /* CONFIG_MPIC_WEIRD */
 
+static inline unsigned int mpic_processor_id(struct mpic *mpic)
+{
+       unsigned int cpu = 0;
+
+       if (mpic->flags & MPIC_PRIMARY)
+               cpu = hard_smp_processor_id();
+
+       return cpu;
+}
+
 /*
  * Register accessor functions
  */
@@ -210,19 +220,14 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
 
 static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
 {
-       unsigned int cpu = 0;
+       unsigned int cpu = mpic_processor_id(mpic);
 
-       if (mpic->flags & MPIC_PRIMARY)
-               cpu = hard_smp_processor_id();
        return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
 }
 
 static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
 {
-       unsigned int cpu = 0;
-
-       if (mpic->flags & MPIC_PRIMARY)
-               cpu = hard_smp_processor_id();
+       unsigned int cpu = mpic_processor_id(mpic);
 
        _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
 }
@@ -913,6 +918,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
        mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
 }
 
+void mpic_set_destination(unsigned int virq, unsigned int cpuid)
+{
+       struct mpic *mpic = mpic_from_irq(virq);
+       unsigned int src = mpic_irq_to_hw(virq);
+
+       DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
+           mpic, virq, src, cpuid);
+
+       if (src >= mpic->irq_count)
+               return;
+
+       mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
+}
+
 static struct irq_chip mpic_irq_chip = {
        .irq_mask       = mpic_mask_irq,
        .irq_unmask     = mpic_unmask_irq,
@@ -993,6 +1012,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
        /* Set default irq type */
        set_irq_type(virq, IRQ_TYPE_NONE);
 
+       /* If the MPIC was reset, then all vectors have already been
+        * initialized.  Otherwise, a per source lazy initialization
+        * is done here.
+        */
+       if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) {
+               mpic_set_vector(virq, hw);
+               mpic_set_destination(virq, mpic_processor_id(mpic));
+               mpic_irq_set_priority(virq, 8);
+       }
+
        return 0;
 }
 
@@ -1040,6 +1069,11 @@ static struct irq_host_ops mpic_host_ops = {
        .xlate = mpic_host_xlate,
 };
 
+static int mpic_reset_prohibited(struct device_node *node)
+{
+       return node && of_get_property(node, "pic-no-reset", NULL);
+}
+
 /*
  * Exported functions
  */
@@ -1160,7 +1194,15 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
        /* Reset */
-       if (flags & MPIC_WANTS_RESET) {
+
+       /* When using a device-node, reset requests are only honored if the MPIC
+        * is allowed to reset.
+        */
+       if (mpic_reset_prohibited(node))
+               mpic->flags |= MPIC_NO_RESET;
+
+       if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+               printk(KERN_DEBUG "mpic: Resetting\n");
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
                           | MPIC_GREG_GCONF_RESET);
@@ -1320,22 +1362,21 @@ void __init mpic_init(struct mpic *mpic)
 
        mpic_pasemi_msi_init(mpic);
 
-       if (mpic->flags & MPIC_PRIMARY)
-               cpu = hard_smp_processor_id();
-       else
-               cpu = 0;
+       cpu = mpic_processor_id(mpic);
 
-       for (i = 0; i < mpic->num_sources; i++) {
-               /* start with vector = source number, and masked */
-               u32 vecpri = MPIC_VECPRI_MASK | i |
-                       (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+       if (!(mpic->flags & MPIC_NO_RESET)) {
+               for (i = 0; i < mpic->num_sources; i++) {
+                       /* start with vector = source number, and masked */
+                       u32 vecpri = MPIC_VECPRI_MASK | i |
+                               (8 << MPIC_VECPRI_PRIORITY_SHIFT);
                
-               /* check if protected */
-               if (mpic->protected && test_bit(i, mpic->protected))
-                       continue;
-               /* init hw */
-               mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
-               mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
+                       /* check if protected */
+                       if (mpic->protected && test_bit(i, mpic->protected))
+                               continue;
+                       /* init hw */
+                       mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+                       mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
+               }
        }
        
        /* Init spurious vector */
index d17d04cfb2cd4095c77adb306fcb690161c09fbf..33794c1d92c349b24589694d9fd0d5c321ccf522 100644 (file)
@@ -821,7 +821,7 @@ cmds(struct pt_regs *excp)
                                memzcan();
                                break;
                        case 'i':
-                               show_mem();
+                               show_mem(0);
                                break;
                        default:
                                termch = cmd;
index 8800cf090694766b87b6a881f28a93d77346aec2..635d677d3281e31eedf36a240b2a886e2d2f50cc 100644 (file)
@@ -6,7 +6,7 @@ COMPILE_VERSION := __linux_compile_version_id__`hostname |  \
                        tr -c '[0-9A-Za-z]' '_'`__`date | \
                        tr -c '[0-9A-Za-z]' '_'`_t
 
-EXTRA_CFLAGS  := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I.
+ccflags-y  := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I.
 
 targets := image
 targets += bzImage
index 2e05972c5085cec285a0653b9b314fb2dbf6d40c..e1c8f3a49884bcf73f5a04ad2e6fe613bc13cd45 100644 (file)
@@ -742,18 +742,42 @@ static inline int sched_find_first_bit(unsigned long *b)
  *    23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
  */
 
-#define ext2_set_bit(nr, addr)       \
-       __test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_set_bit_atomic(lock, nr, addr)       \
-       test_and_set_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_clear_bit(nr, addr)     \
-       __test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_clear_bit_atomic(lock, nr, addr)     \
-       test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_test_bit(nr, addr)      \
-       test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-
-static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size)
+static inline void __set_bit_le(unsigned long nr, void *addr)
+{
+       __set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline void __clear_bit_le(unsigned long nr, void *addr)
+{
+       __clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int __test_and_set_bit_le(unsigned long nr, void *addr)
+{
+       return __test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int test_and_set_bit_le(unsigned long nr, void *addr)
+{
+       return test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int __test_and_clear_bit_le(unsigned long nr, void *addr)
+{
+       return __test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int test_and_clear_bit_le(unsigned long nr, void *addr)
+{
+       return test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int test_bit_le(unsigned long nr, const void *addr)
+{
+       return test_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
+}
+
+static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
 {
        unsigned long bytes, bits;
 
@@ -764,7 +788,7 @@ static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size)
        return (bits < size) ? bits : size;
 }
 
-static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size,
+static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
                                          unsigned long offset)
 {
         unsigned long *addr = vaddr, *p;
@@ -790,11 +814,10 @@ static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size,
                size -= __BITOPS_WORDSIZE;
                p++;
         }
-       return offset + ext2_find_first_zero_bit(p, size);
+       return offset + find_first_zero_bit_le(p, size);
 }
 
-static inline unsigned long ext2_find_first_bit(void *vaddr,
-                                               unsigned long size)
+static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
 {
        unsigned long bytes, bits;
 
@@ -805,7 +828,7 @@ static inline unsigned long ext2_find_first_bit(void *vaddr,
        return (bits < size) ? bits : size;
 }
 
-static inline int ext2_find_next_bit(void *vaddr, unsigned long size,
+static inline int find_next_bit_le(void *vaddr, unsigned long size,
                                     unsigned long offset)
 {
        unsigned long *addr = vaddr, *p;
@@ -831,10 +854,14 @@ static inline int ext2_find_next_bit(void *vaddr, unsigned long size,
                size -= __BITOPS_WORDSIZE;
                p++;
        }
-       return offset + ext2_find_first_bit(p, size);
+       return offset + find_first_bit_le(p, size);
 }
 
-#include <asm-generic/bitops/minix.h>
+#define ext2_set_bit_atomic(lock, nr, addr)    \
+       test_and_set_bit_le(nr, addr)
+#define ext2_clear_bit_atomic(lock, nr, addr)  \
+       test_and_clear_bit_le(nr, addr)
+
 
 #endif /* __KERNEL__ */
 
index ff6f62e0ec3e01fcb3736a2dc55e06da267a4ced..623f2fb71774af7a352df0075f8253e776c15839 100644 (file)
@@ -112,7 +112,6 @@ enum uc_todo {
 
 /**
  * struct ccw driver - device driver for channel attached devices
- * @owner: owning module
  * @ids: ids supported by this driver
  * @probe: function called on probe
  * @remove: function called on remove
@@ -128,10 +127,8 @@ enum uc_todo {
  * @restore: callback for restoring after hibernation
  * @uc_handler: callback for unit check handler
  * @driver: embedded device driver structure
- * @name: device driver name
  */
 struct ccw_driver {
-       struct module *owner;
        struct ccw_device_id *ids;
        int (*probe) (struct ccw_device *);
        void (*remove) (struct ccw_device *);
@@ -147,7 +144,6 @@ struct ccw_driver {
        int (*restore)(struct ccw_device *);
        enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
        struct device_driver driver;
-       char *name;
 };
 
 extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
index c79c1e787b86fc67903c0823d9637b94a784ac93..f2ea2c56a7e18866d2775513df1e2f3f48d5b0e7 100644 (file)
@@ -29,8 +29,6 @@ struct ccwgroup_device {
 
 /**
  * struct ccwgroup_driver - driver for ccw group devices
- * @owner: driver owner
- * @name: driver name
  * @max_slaves: maximum number of slave devices
  * @driver_id: unique id
  * @probe: function called on probe
@@ -46,8 +44,6 @@ struct ccwgroup_device {
  * @driver: embedded driver structure
  */
 struct ccwgroup_driver {
-       struct module *owner;
-       char *name;
        int max_slaves;
        unsigned long driver_id;
 
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h
new file mode 100644 (file)
index 0000000..7488e52
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright IBM Corp. 1999, 2011
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ */
+
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <linux/types.h>
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static inline unsigned long __xchg(unsigned long x, void *ptr, int size)
+{
+       unsigned long addr, old;
+       int shift;
+
+       switch (size) {
+       case 1:
+               addr = (unsigned long) ptr;
+               shift = (3 ^ (addr & 3)) << 3;
+               addr ^= addr & 3;
+               asm volatile(
+                       "       l       %0,%4\n"
+                       "0:     lr      0,%0\n"
+                       "       nr      0,%3\n"
+                       "       or      0,%2\n"
+                       "       cs      %0,0,%4\n"
+                       "       jl      0b\n"
+                       : "=&d" (old), "=Q" (*(int *) addr)
+                       : "d" (x << shift), "d" (~(255 << shift)),
+                         "Q" (*(int *) addr) : "memory", "cc", "0");
+               return old >> shift;
+       case 2:
+               addr = (unsigned long) ptr;
+               shift = (2 ^ (addr & 2)) << 3;
+               addr ^= addr & 2;
+               asm volatile(
+                       "       l       %0,%4\n"
+                       "0:     lr      0,%0\n"
+                       "       nr      0,%3\n"
+                       "       or      0,%2\n"
+                       "       cs      %0,0,%4\n"
+                       "       jl      0b\n"
+                       : "=&d" (old), "=Q" (*(int *) addr)
+                       : "d" (x << shift), "d" (~(65535 << shift)),
+                         "Q" (*(int *) addr) : "memory", "cc", "0");
+               return old >> shift;
+       case 4:
+               asm volatile(
+                       "       l       %0,%3\n"
+                       "0:     cs      %0,%2,%3\n"
+                       "       jl      0b\n"
+                       : "=&d" (old), "=Q" (*(int *) ptr)
+                       : "d" (x), "Q" (*(int *) ptr)
+                       : "memory", "cc");
+               return old;
+#ifdef CONFIG_64BIT
+       case 8:
+               asm volatile(
+                       "       lg      %0,%3\n"
+                       "0:     csg     %0,%2,%3\n"
+                       "       jl      0b\n"
+                       : "=&d" (old), "=m" (*(long *) ptr)
+                       : "d" (x), "Q" (*(long *) ptr)
+                       : "memory", "cc");
+               return old;
+#endif /* CONFIG_64BIT */
+       }
+       __xchg_called_with_bad_pointer();
+       return x;
+}
+
+#define xchg(ptr, x)                                                     \
+({                                                                       \
+       __typeof__(*(ptr)) __ret;                                         \
+       __ret = (__typeof__(*(ptr)))                                      \
+               __xchg((unsigned long)(x), (void *)(ptr), sizeof(*(ptr)));\
+       __ret;                                                            \
+})
+
+/*
+ * Atomic compare and exchange.         Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG
+
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static inline unsigned long __cmpxchg(void *ptr, unsigned long old,
+                                     unsigned long new, int size)
+{
+       unsigned long addr, prev, tmp;
+       int shift;
+
+       switch (size) {
+       case 1:
+               addr = (unsigned long) ptr;
+               shift = (3 ^ (addr & 3)) << 3;
+               addr ^= addr & 3;
+               asm volatile(
+                       "       l       %0,%2\n"
+                       "0:     nr      %0,%5\n"
+                       "       lr      %1,%0\n"
+                       "       or      %0,%3\n"
+                       "       or      %1,%4\n"
+                       "       cs      %0,%1,%2\n"
+                       "       jnl     1f\n"
+                       "       xr      %1,%0\n"
+                       "       nr      %1,%5\n"
+                       "       jnz     0b\n"
+                       "1:"
+                       : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
+                       : "d" (old << shift), "d" (new << shift),
+                         "d" (~(255 << shift)), "Q" (*(int *) ptr)
+                       : "memory", "cc");
+               return prev >> shift;
+       case 2:
+               addr = (unsigned long) ptr;
+               shift = (2 ^ (addr & 2)) << 3;
+               addr ^= addr & 2;
+               asm volatile(
+                       "       l       %0,%2\n"
+                       "0:     nr      %0,%5\n"
+                       "       lr      %1,%0\n"
+                       "       or      %0,%3\n"
+                       "       or      %1,%4\n"
+                       "       cs      %0,%1,%2\n"
+                       "       jnl     1f\n"
+                       "       xr      %1,%0\n"
+                       "       nr      %1,%5\n"
+                       "       jnz     0b\n"
+                       "1:"
+                       : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
+                       : "d" (old << shift), "d" (new << shift),
+                         "d" (~(65535 << shift)), "Q" (*(int *) ptr)
+                       : "memory", "cc");
+               return prev >> shift;
+       case 4:
+               asm volatile(
+                       "       cs      %0,%3,%1\n"
+                       : "=&d" (prev), "=Q" (*(int *) ptr)
+                       : "0" (old), "d" (new), "Q" (*(int *) ptr)
+                       : "memory", "cc");
+               return prev;
+#ifdef CONFIG_64BIT
+       case 8:
+               asm volatile(
+                       "       csg     %0,%3,%1\n"
+                       : "=&d" (prev), "=Q" (*(long *) ptr)
+                       : "0" (old), "d" (new), "Q" (*(long *) ptr)
+                       : "memory", "cc");
+               return prev;
+#endif /* CONFIG_64BIT */
+       }
+       __cmpxchg_called_with_bad_pointer();
+       return old;
+}
+
+#define cmpxchg(ptr, o, n)                                             \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
+                                      (unsigned long)(n), sizeof(*(ptr))))
+
+#ifdef CONFIG_64BIT
+#define cmpxchg64(ptr, o, n)                                           \
+({                                                                     \
+       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
+       cmpxchg((ptr), (o), (n));                                       \
+})
+#else /* CONFIG_64BIT */
+static inline unsigned long long __cmpxchg64(void *ptr,
+                                            unsigned long long old,
+                                            unsigned long long new)
+{
+       register_pair rp_old = {.pair = old};
+       register_pair rp_new = {.pair = new};
+
+       asm volatile(
+               "       cds     %0,%2,%1"
+               : "+&d" (rp_old), "=Q" (ptr)
+               : "d" (rp_new), "Q" (ptr)
+               : "cc");
+       return rp_old.pair;
+}
+#define cmpxchg64(ptr, o, n)                                           \
+       ((__typeof__(*(ptr)))__cmpxchg64((ptr),                         \
+                                        (unsigned long long)(o),       \
+                                        (unsigned long long)(n)))
+#endif /* CONFIG_64BIT */
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(void *ptr,
+                                           unsigned long old,
+                                           unsigned long new, int size)
+{
+       switch (size) {
+       case 1:
+       case 2:
+       case 4:
+#ifdef CONFIG_64BIT
+       case 8:
+#endif
+               return __cmpxchg(ptr, old, new, size);
+       default:
+               return __cmpxchg_local_generic(ptr, old, new, size);
+       }
+
+       return old;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+                       (unsigned long)(n), sizeof(*(ptr))))
+
+#define cmpxchg64_local(ptr, o, n)     cmpxchg64((ptr), (o), (n))
+
+#endif /* __ASM_CMPXCHG_H */
index 8f8d759f6a7b696327955c2643312a52fd900c90..d382629a01728de29a1ceb396a637c26ed4f94c1 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/lowcore.h>
+#include <asm/cmpxchg.h>
 
 #ifdef __KERNEL__
 
@@ -120,161 +121,6 @@ extern int memcpy_real(void *, void *, size_t);
 
 #define nop() asm volatile("nop")
 
-#define xchg(ptr,x)                                                      \
-({                                                                       \
-       __typeof__(*(ptr)) __ret;                                         \
-       __ret = (__typeof__(*(ptr)))                                      \
-               __xchg((unsigned long)(x), (void *)(ptr),sizeof(*(ptr))); \
-       __ret;                                                            \
-})
-
-extern void __xchg_called_with_bad_pointer(void);
-
-static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
-{
-       unsigned long addr, old;
-       int shift;
-
-        switch (size) {
-       case 1:
-               addr = (unsigned long) ptr;
-               shift = (3 ^ (addr & 3)) << 3;
-               addr ^= addr & 3;
-               asm volatile(
-                       "       l       %0,%4\n"
-                       "0:     lr      0,%0\n"
-                       "       nr      0,%3\n"
-                       "       or      0,%2\n"
-                       "       cs      %0,0,%4\n"
-                       "       jl      0b\n"
-                       : "=&d" (old), "=Q" (*(int *) addr)
-                       : "d" (x << shift), "d" (~(255 << shift)),
-                         "Q" (*(int *) addr) : "memory", "cc", "0");
-               return old >> shift;
-       case 2:
-               addr = (unsigned long) ptr;
-               shift = (2 ^ (addr & 2)) << 3;
-               addr ^= addr & 2;
-               asm volatile(
-                       "       l       %0,%4\n"
-                       "0:     lr      0,%0\n"
-                       "       nr      0,%3\n"
-                       "       or      0,%2\n"
-                       "       cs      %0,0,%4\n"
-                       "       jl      0b\n"
-                       : "=&d" (old), "=Q" (*(int *) addr)
-                       : "d" (x << shift), "d" (~(65535 << shift)),
-                         "Q" (*(int *) addr) : "memory", "cc", "0");
-               return old >> shift;
-       case 4:
-               asm volatile(
-                       "       l       %0,%3\n"
-                       "0:     cs      %0,%2,%3\n"
-                       "       jl      0b\n"
-                       : "=&d" (old), "=Q" (*(int *) ptr)
-                       : "d" (x), "Q" (*(int *) ptr)
-                       : "memory", "cc");
-               return old;
-#ifdef __s390x__
-       case 8:
-               asm volatile(
-                       "       lg      %0,%3\n"
-                       "0:     csg     %0,%2,%3\n"
-                       "       jl      0b\n"
-                       : "=&d" (old), "=m" (*(long *) ptr)
-                       : "d" (x), "Q" (*(long *) ptr)
-                       : "memory", "cc");
-               return old;
-#endif /* __s390x__ */
-       }
-       __xchg_called_with_bad_pointer();
-       return x;
-}
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-#define cmpxchg(ptr, o, n)                                             \
-       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),       \
-                                       (unsigned long)(n), sizeof(*(ptr))))
-
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static inline unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
-       unsigned long addr, prev, tmp;
-       int shift;
-
-        switch (size) {
-       case 1:
-               addr = (unsigned long) ptr;
-               shift = (3 ^ (addr & 3)) << 3;
-               addr ^= addr & 3;
-               asm volatile(
-                       "       l       %0,%2\n"
-                       "0:     nr      %0,%5\n"
-                       "       lr      %1,%0\n"
-                       "       or      %0,%3\n"
-                       "       or      %1,%4\n"
-                       "       cs      %0,%1,%2\n"
-                       "       jnl     1f\n"
-                       "       xr      %1,%0\n"
-                       "       nr      %1,%5\n"
-                       "       jnz     0b\n"
-                       "1:"
-                       : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
-                       : "d" (old << shift), "d" (new << shift),
-                         "d" (~(255 << shift)), "Q" (*(int *) ptr)
-                       : "memory", "cc");
-               return prev >> shift;
-       case 2:
-               addr = (unsigned long) ptr;
-               shift = (2 ^ (addr & 2)) << 3;
-               addr ^= addr & 2;
-               asm volatile(
-                       "       l       %0,%2\n"
-                       "0:     nr      %0,%5\n"
-                       "       lr      %1,%0\n"
-                       "       or      %0,%3\n"
-                       "       or      %1,%4\n"
-                       "       cs      %0,%1,%2\n"
-                       "       jnl     1f\n"
-                       "       xr      %1,%0\n"
-                       "       nr      %1,%5\n"
-                       "       jnz     0b\n"
-                       "1:"
-                       : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
-                       : "d" (old << shift), "d" (new << shift),
-                         "d" (~(65535 << shift)), "Q" (*(int *) ptr)
-                       : "memory", "cc");
-               return prev >> shift;
-       case 4:
-               asm volatile(
-                       "       cs      %0,%3,%1\n"
-                       : "=&d" (prev), "=Q" (*(int *) ptr)
-                       : "0" (old), "d" (new), "Q" (*(int *) ptr)
-                       : "memory", "cc");
-               return prev;
-#ifdef __s390x__
-       case 8:
-               asm volatile(
-                       "       csg     %0,%3,%1\n"
-                       : "=&d" (prev), "=Q" (*(long *) ptr)
-                       : "0" (old), "d" (new), "Q" (*(long *) ptr)
-                       : "memory", "cc");
-               return prev;
-#endif /* __s390x__ */
-        }
-       __cmpxchg_called_with_bad_pointer();
-       return old;
-}
-
 /*
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
@@ -353,46 +199,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
        __ctl_load(__dummy, cr, cr);    \
 })
 
-#include <linux/irqflags.h>
-
-#include <asm-generic/cmpxchg-local.h>
-
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-                                     unsigned long old,
-                                     unsigned long new, int size)
-{
-       switch (size) {
-       case 1:
-       case 2:
-       case 4:
-#ifdef __s390x__
-       case 8:
-#endif
-               return __cmpxchg(ptr, old, new, size);
-       default:
-               return __cmpxchg_local_generic(ptr, old, new, size);
-       }
-
-       return old;
-}
-
-/*
- * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
- * them available.
- */
-#define cmpxchg_local(ptr, o, n)                                       \
-       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
-                       (unsigned long)(n), sizeof(*(ptr))))
-#ifdef __s390x__
-#define cmpxchg64_local(ptr, o, n)                                     \
-  ({                                                                   \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
-       cmpxchg_local((ptr), (o), (n));                                 \
-  })
-#else
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-#endif
-
 /*
  * Use to set psw mask except for the first byte which
  * won't be changed by this function.
index 04d6b95a89c6b4ce1c5454341d378ea45700e286..eeb52ccf499f5cc46c02baf926aa5804bfad24eb 100644 (file)
@@ -30,14 +30,6 @@ typedef __signed__ long saddr_t;
 
 #ifndef __ASSEMBLY__
 
-typedef u64 dma64_addr_t;
-#ifdef __s390x__
-/* DMA addresses come in 32-bit and 64-bit flavours. */
-typedef u64 dma_addr_t;
-#else
-typedef u32 dma_addr_t;
-#endif
-
 #ifndef __s390x__
 typedef union {
        unsigned long long pair;
index 1049ef27c15e83bb30092efc67c3517433e2bfe4..e821525723775c8f2ca745daffddd21f91f62d41 100644 (file)
 #define __NR_fanotify_init     332
 #define __NR_fanotify_mark     333
 #define __NR_prlimit64         334
-#define NR_syscalls 335
+#define __NR_name_to_handle_at 335
+#define __NR_open_by_handle_at 336
+#define __NR_clock_adjtime     337
+#define __NR_syncfs            338
+#define NR_syscalls 339
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 8e60fb23b90da9d61587c72938b785881683de93..1dc96ea08fa89283c12e4c2240af06efa9d0239a 100644 (file)
@@ -1877,3 +1877,30 @@ sys_prlimit64_wrapper:
        llgtr   %r4,%r4                 # const struct rlimit64 __user *
        llgtr   %r5,%r5                 # struct rlimit64 __user *
        jg      sys_prlimit64           # branch to system call
+
+       .globl  sys_name_to_handle_at_wrapper
+sys_name_to_handle_at_wrapper:
+       lgfr    %r2,%r2                 # int
+       llgtr   %r3,%r3                 # const char __user *
+       llgtr   %r4,%r4                 # struct file_handle __user *
+       llgtr   %r5,%r5                 # int __user *
+       lgfr    %r6,%r6                 # int
+       jg      sys_name_to_handle_at
+
+       .globl  compat_sys_open_by_handle_at_wrapper
+compat_sys_open_by_handle_at_wrapper:
+       lgfr    %r2,%r2                 # int
+       llgtr   %r3,%r3                 # struct file_handle __user *
+       lgfr    %r4,%r4                 # int
+       jg      compat_sys_open_by_handle_at
+
+       .globl  compat_sys_clock_adjtime_wrapper
+compat_sys_clock_adjtime_wrapper:
+       lgfr    %r2,%r2                 # clockid_t (int)
+       llgtr   %r3,%r3                 # struct compat_timex __user *
+       jg      compat_sys_clock_adjtime
+
+       .globl  sys_syncfs_wrapper
+sys_syncfs_wrapper:
+       lgfr    %r2,%r2                 # int
+       jg      sys_syncfs
index 3b7e7dddc324a6985a09758ce9636da5e6cae8c6..068f8465c4ee07c0156978517f9efe88dcc5e96a 100644 (file)
@@ -94,6 +94,7 @@ static noinline __init void create_kernel_nss(void)
        unsigned int sinitrd_pfn, einitrd_pfn;
 #endif
        int response;
+       int hlen;
        size_t len;
        char *savesys_ptr;
        char defsys_cmd[DEFSYS_CMD_SIZE];
@@ -124,24 +125,27 @@ static noinline __init void create_kernel_nss(void)
        end_pfn = PFN_UP(__pa(&_end));
        min_size = end_pfn << 2;
 
-       sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
-               kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
-               eshared_pfn, end_pfn);
+       hlen = snprintf(defsys_cmd, DEFSYS_CMD_SIZE,
+                       "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+                       kernel_nss_name, stext_pfn - 1, stext_pfn,
+                       eshared_pfn - 1, eshared_pfn, end_pfn);
 
 #ifdef CONFIG_BLK_DEV_INITRD
        if (INITRD_START && INITRD_SIZE) {
                sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
                einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
                min_size = einitrd_pfn << 2;
-               sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
-               sinitrd_pfn, einitrd_pfn);
+               hlen += snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen,
+                                " EW %.5X-%.5X", sinitrd_pfn, einitrd_pfn);
        }
 #endif
 
-       sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
-               defsys_cmd, min_size);
-       sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
-               kernel_nss_name, kernel_nss_name);
+       snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen,
+                " EW MINSIZE=%.7iK PARMREGS=0-13", min_size);
+       defsys_cmd[DEFSYS_CMD_SIZE - 1] = '\0';
+       snprintf(savesys_cmd, SAVESYS_CMD_SIZE, "SAVESYS %s \n IPL %s",
+                kernel_nss_name, kernel_nss_name);
+       savesys_cmd[SAVESYS_CMD_SIZE - 1] = '\0';
 
        __cpcmd(defsys_cmd, NULL, 0, &response);
 
index 6f6350826c81c1f7a1d81071ac0b4ed2df360e17..ed183c2c6168aa8414dfa6fbd60092bbe3be0e66 100644 (file)
@@ -102,16 +102,6 @@ EXPORT_SYMBOL(lowcore_ptr);
 
 #include <asm/setup.h>
 
-static struct resource code_resource = {
-       .name  = "Kernel code",
-       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
-};
-
-static struct resource data_resource = {
-       .name = "Kernel data",
-       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
-};
-
 /*
  * condev= and conmode= setup parameter.
  */
@@ -436,21 +426,43 @@ setup_lowcore(void)
        lowcore_ptr[0] = lc;
 }
 
-static void __init
-setup_resources(void)
+static struct resource code_resource = {
+       .name  = "Kernel code",
+       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource data_resource = {
+       .name = "Kernel data",
+       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource bss_resource = {
+       .name = "Kernel bss",
+       .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource __initdata *standard_resources[] = {
+       &code_resource,
+       &data_resource,
+       &bss_resource,
+};
+
+static void __init setup_resources(void)
 {
-       struct resource *res, *sub_res;
-       int i;
+       struct resource *res, *std_res, *sub_res;
+       int i, j;
 
        code_resource.start = (unsigned long) &_text;
        code_resource.end = (unsigned long) &_etext - 1;
        data_resource.start = (unsigned long) &_etext;
        data_resource.end = (unsigned long) &_edata - 1;
+       bss_resource.start = (unsigned long) &__bss_start;
+       bss_resource.end = (unsigned long) &__bss_stop - 1;
 
        for (i = 0; i < MEMORY_CHUNKS; i++) {
                if (!memory_chunk[i].size)
                        continue;
-               res = alloc_bootmem_low(sizeof(struct resource));
+               res = alloc_bootmem_low(sizeof(*res));
                res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
                switch (memory_chunk[i].type) {
                case CHUNK_READ_WRITE:
@@ -464,40 +476,24 @@ setup_resources(void)
                        res->name = "reserved";
                }
                res->start = memory_chunk[i].addr;
-               res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
+               res->end = res->start + memory_chunk[i].size - 1;
                request_resource(&iomem_resource, res);
 
-               if (code_resource.start >= res->start  &&
-                       code_resource.start <= res->end &&
-                       code_resource.end > res->end) {
-                       sub_res = alloc_bootmem_low(sizeof(struct resource));
-                       memcpy(sub_res, &code_resource,
-                               sizeof(struct resource));
-                       sub_res->end = res->end;
-                       code_resource.start = res->end + 1;
-                       request_resource(res, sub_res);
-               }
-
-               if (code_resource.start >= res->start &&
-                       code_resource.start <= res->end &&
-                       code_resource.end <= res->end)
-                       request_resource(res, &code_resource);
-
-               if (data_resource.start >= res->start &&
-                       data_resource.start <= res->end &&
-                       data_resource.end > res->end) {
-                       sub_res = alloc_bootmem_low(sizeof(struct resource));
-                       memcpy(sub_res, &data_resource,
-                               sizeof(struct resource));
-                       sub_res->end = res->end;
-                       data_resource.start = res->end + 1;
-                       request_resource(res, sub_res);
+               for (j = 0; j < ARRAY_SIZE(standard_resources); j++) {
+                       std_res = standard_resources[j];
+                       if (std_res->start < res->start ||
+                           std_res->start > res->end)
+                               continue;
+                       if (std_res->end > res->end) {
+                               sub_res = alloc_bootmem_low(sizeof(*sub_res));
+                               *sub_res = *std_res;
+                               sub_res->end = res->end;
+                               std_res->start = res->end + 1;
+                               request_resource(res, sub_res);
+                       } else {
+                               request_resource(res, std_res);
+                       }
                }
-
-               if (data_resource.start >= res->start &&
-                       data_resource.start <= res->end &&
-                       data_resource.end <= res->end)
-                       request_resource(res, &data_resource);
        }
 }
 
index a8fee1b14395a1472a5d8fa2f34f1ed34eafb4c8..9c65fd4ddce0b56e4cffa97ecef4730ed42f78e4 100644 (file)
@@ -343,3 +343,7 @@ SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
 SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
 SYSCALL(sys_fanotify_mark,sys_fanotify_mark,sys_fanotify_mark_wrapper)
 SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper)
+SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */
+SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at_wrapper)
+SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper)
+SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper)
index f438d74dedbd171fa151f234a96e4f173358403a..d73630b4fe1dbe87f9d492dd5f1e465749a5a0dc 100644 (file)
@@ -337,17 +337,17 @@ static int __init vdso_init(void)
 }
 arch_initcall(vdso_init);
 
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
        return 0;
 }
 
-int in_gate_area(struct task_struct *task, unsigned long addr)
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
 {
        return 0;
 }
 
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
        return NULL;
 }
index e5221ec0b8e3eeb5b008aefb891841e795d98221..860d26514c08dce870a8810dee1ff1e2a676b719 100644 (file)
@@ -8,7 +8,7 @@
 
 common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o)
 
-EXTRA_CFLAGS += -Ivirt/kvm -Iarch/s390/kvm
+ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
 kvm-objs := $(common-objs) kvm-s390.o sie64a.o intercept.o interrupt.o priv.o sigp.o diag.o
 obj-$(CONFIG_KVM) += kvm.o
index c84890341052ce7377fbcf9eb75e11436157dea6..51d399549f604cc2632c329ec1a9776862cc3623 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_MATHEMU) := math.o
 
-EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
+ccflags-y := -I$(src) -Iinclude/math-emu -w
index d698cddcfbdd9db4d60a39c1c84acf6989afd2ca..524c4b615821acaf6139c9a8f7c8646a4d88e49d 100644 (file)
@@ -6,4 +6,5 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprofilefs.o oprofile_stats.o  \
                timer_int.o )
 
-oprofile-y :=  $(DRIVER_OBJS) init.o backtrace.o hwsampler.o
+oprofile-y :=  $(DRIVER_OBJS) init.o backtrace.o
+oprofile-$(CONFIG_64BIT)       += hwsampler.o
index 16c76def4a9da5818f8cb557c43ec46f1fbe85da..c63d7e58352bb343db50a47bb0ea857fc5952f9b 100644 (file)
 #include <linux/fs.h>
 
 #include "../../../drivers/oprofile/oprof.h"
+
+extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+#ifdef CONFIG_64BIT
+
 #include "hwsampler.h"
 
 #define DEFAULT_INTERVAL       4096
@@ -37,8 +42,6 @@ static int hwsampler_running; /* start_mutex must be held to change */
 
 static struct oprofile_operations timer_ops;
 
-extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
-
 static int oprofile_hwsampler_start(void)
 {
        int retval;
@@ -172,14 +175,22 @@ static void oprofile_hwsampler_exit(void)
        hwsampler_shutdown();
 }
 
+#endif /* CONFIG_64BIT */
+
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
        ops->backtrace = s390_backtrace;
 
+#ifdef CONFIG_64BIT
        return oprofile_hwsampler_init(ops);
+#else
+       return -ENODEV;
+#endif
 }
 
 void oprofile_arch_exit(void)
 {
+#ifdef CONFIG_64BIT
        oprofile_hwsampler_exit();
+#endif
 }
index 8570d08f58c1f25cc8194d85cbe987133153526c..2205c62284dba93c87e9726465abc29ccd272e72 100644 (file)
@@ -71,7 +71,7 @@ struct thread_info {
 register struct thread_info *__current_thread_info __asm__("r28");
 #define current_thread_info()  __current_thread_info
 
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info_node(tsk, node) kmalloc_node(THREAD_SIZE, GFP_KERNEL, node)
 #define free_thread_info(info) kfree(info)
 
 #endif /* !__ASSEMBLY__ */
index 2d264fa84959dde3488b79c8d0fd111b5df63a7e..9af3c8d0776bba6308c4565ded06db43077972c9 100644 (file)
@@ -23,8 +23,7 @@ config SUPERH
        select HAVE_SPARSE_IRQ
        select RTC_LIB
        select GENERIC_ATOMIC64
-       # Support the deprecated APIs until MFD and GPIOLIB catch up.
-       select GENERIC_HARDIRQS_NO_DEPRECATED if !MFD_SUPPORT && !GPIOLIB
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        select GENERIC_IRQ_SHOW
        help
          The SuperH is a RISC processor targeted for use in embedded systems
@@ -75,6 +74,9 @@ config GENERIC_CSUM
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
+config GENERIC_FIND_BIT_LE
+       def_bool y
+
 config GENERIC_HWEIGHT
        def_bool y
 
index f47ac82da87636d4993b65d4adc66acded83257c..e9656a2cc4cc0396fa6dd9689620514a3a454472 100644 (file)
@@ -56,7 +56,7 @@ static struct mtd_partition edosk7760_nor_flash_partitions[] = {
        }, {
                .name = "fs",
                .offset = MTDPART_OFS_APPEND,
-               .size = SZ_26M,
+               .size = (26 << 20),
        }, {
                .name = "other",
                .offset = MTDPART_OFS_APPEND,
index c84e7831018dc12023a1f5a316b7ac9444be3598..16b122510c84f430d48f7257788205ab825bcfba 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/boot.h>
 #include <mach/romimage.h>
 
 #define MMCIF_BASE      (void __iomem *)0xa4ca0000
@@ -29,7 +30,7 @@
  */
 asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
 {
-       mmcif_update_progress(MMCIF_PROGRESS_ENTER);
+       mmcif_update_progress(MMC_PROGRESS_ENTER);
 
        /* enable clock to the MMCIF hardware block */
        __raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2);
@@ -52,12 +53,12 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
        /* high drive capability for MMC pins */
        __raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA);
 
-       mmcif_update_progress(MMCIF_PROGRESS_INIT);
+       mmcif_update_progress(MMC_PROGRESS_INIT);
 
        /* setup MMCIF hardware */
        sh_mmcif_boot_init(MMCIF_BASE);
 
-       mmcif_update_progress(MMCIF_PROGRESS_LOAD);
+       mmcif_update_progress(MMC_PROGRESS_LOAD);
 
        /* load kernel via MMCIF interface */
        sh_mmcif_boot_do_read(MMCIF_BASE, 512,
@@ -67,5 +68,5 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
        /* disable clock to the MMCIF hardware block */
        __raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2);
 
-       mmcif_update_progress(MMCIF_PROGRESS_DONE);
+       mmcif_update_progress(MMC_PROGRESS_DONE);
 }
index 98511e4d28cbe54c1c43f466eed1edba870a8361..90fa3e48b4d60816baf66acfc3eb71105752639e 100644 (file)
@@ -94,9 +94,8 @@ static inline unsigned long ffz(unsigned long word)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
 #include <asm-generic/bitops/fls64.h>
index 0b9fe2d5c36d9d4ac05621d50b8e6725ce6f3d13..dd248c2e1085250486a532996be028106648c8d4 100644 (file)
@@ -1,62 +1 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * 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
- */
-/* DO NOT EDIT!! - this file automatically generated
- *                 from .s file by awk -f s2h.awk
- */
-/*  Size definitions
- *  Copyright (C) ARM Limited 1998. All rights reserved.
- */
-
-#ifndef __sizes_h
-#define __sizes_h                       1
-
-/* handy sizes */
-#define SZ_16                          0x00000010
-#define SZ_32                          0x00000020
-#define SZ_64                          0x00000040
-#define SZ_128                         0x00000080
-#define SZ_256                         0x00000100
-#define SZ_512                         0x00000200
-
-#define SZ_1K                           0x00000400
-#define SZ_2K                           0x00000800
-#define SZ_4K                           0x00001000
-#define SZ_8K                           0x00002000
-#define SZ_16K                          0x00004000
-#define SZ_32K                         0x00008000
-#define SZ_64K                          0x00010000
-#define SZ_128K                         0x00020000
-#define SZ_256K                         0x00040000
-#define SZ_512K                         0x00080000
-
-#define SZ_1M                           0x00100000
-#define SZ_2M                           0x00200000
-#define SZ_4M                           0x00400000
-#define SZ_8M                           0x00800000
-#define SZ_16M                          0x01000000
-#define SZ_26M                         0x01a00000
-#define SZ_32M                          0x02000000
-#define SZ_64M                          0x04000000
-#define SZ_128M                         0x08000000
-#define SZ_256M                         0x10000000
-#define SZ_512M                         0x20000000
-
-#define SZ_1G                           0x40000000
-#define SZ_2G                           0x80000000
-
-#endif
-
-/*         END */
+#include <asm-generic/sizes.h>
index c228946926edba4025a52cf379a335050059ed29..ea2d5089de1ed27492c5fca9aefd195a2f787831 100644 (file)
@@ -95,7 +95,7 @@ static inline struct thread_info *current_thread_info(void)
 
 #endif
 
-extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
+extern struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node);
 extern void free_thread_info(struct thread_info *ti);
 extern void arch_task_cache_init(void);
 #define arch_task_cache_init arch_task_cache_init
index b5a74e88028dbfc5caa2e072030413fb26b31f4c..ca7765e5f9679db8b136d314574d09fc29d80853 100644 (file)
 #define __NR_name_to_handle_at 359
 #define __NR_open_by_handle_at 360
 #define __NR_clock_adjtime     361
+#define __NR_syncfs            362
 
-#define NR_syscalls 362
+#define NR_syscalls 363
 
 #ifdef __KERNEL__
 
index 953da4a521995517c9ee4f87a3e123389357fa49..a694009bb8169e3d01373109d075c7643be66858 100644 (file)
 #define __NR_name_to_handle_at 370
 #define __NR_open_by_handle_at 371
 #define __NR_clock_adjtime     372
+#define __NR_syncfs            373
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 373
+#define NR_syscalls 374
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 37c97d444576133c9d2dc186aafc555bc57296ce..569e7b171c01656e646001cc88acb7ec0cc91328 100644 (file)
@@ -9,28 +9,6 @@
 #include <linux/io.h>
 #include <asm/uaccess.h>
 
-/* Stores the physical address of elf header of crash image. */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
-/*
- * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
- * is_kdump_kernel() to determine if we are booting after a panic. Hence
- * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
- *
- * elfcorehdr= specifies the location of elf core header
- * stored by the crashed kernel.
- */
-static int __init parse_elfcorehdr(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       elfcorehdr_addr = memparse(arg, &arg);
-
-       return 0;
-}
-early_param("elfcorehdr", parse_elfcorehdr);
-
 /**
  * copy_oldmem_page - copy one page from "oldmem"
  * @pfn: page frame number to be copied
index dcb126dc76fd7b72102f4d5624e7a07a9664a82f..325f98b1736d4a1ab8fdc93f54bcd7cb3674d298 100644 (file)
@@ -32,16 +32,16 @@ void free_thread_xstate(struct task_struct *tsk)
 #if THREAD_SHIFT < PAGE_SHIFT
 static struct kmem_cache *thread_info_cache;
 
-struct thread_info *alloc_thread_info(struct task_struct *tsk)
+struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node)
 {
        struct thread_info *ti;
-
-       ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
-       if (unlikely(ti == NULL))
-               return NULL;
 #ifdef CONFIG_DEBUG_STACK_USAGE
-       memset(ti, 0, THREAD_SIZE);
+       gfp_t mask = GFP_KERNEL | __GFP_ZERO;
+#else
+       gfp_t mask = GFP_KERNEL;
 #endif
+
+       ti = kmem_cache_alloc_node(thread_info_cache, mask, node);
        return ti;
 }
 
@@ -57,14 +57,16 @@ void thread_info_cache_init(void)
                                              THREAD_SIZE, SLAB_PANIC, NULL);
 }
 #else
-struct thread_info *alloc_thread_info(struct task_struct *tsk)
+struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node)
 {
 #ifdef CONFIG_DEBUG_STACK_USAGE
        gfp_t mask = GFP_KERNEL | __GFP_ZERO;
 #else
        gfp_t mask = GFP_KERNEL;
 #endif
-       return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
+       struct page *page = alloc_pages_node(node, mask, THREAD_SIZE_ORDER);
+
+       return page ? page_address(page) : NULL;
 }
 
 void free_thread_info(struct thread_info *ti)
index 90a15d29feebdceb4aa019bc7cc8e4f649f08721..2130ca674e9bdd1674a22d339011a7f364bf0ec5 100644 (file)
@@ -101,6 +101,8 @@ static int set_single_step(struct task_struct *tsk, unsigned long addr)
 
                attr = bp->attr;
                attr.bp_addr = addr;
+               /* reenable breakpoint */
+               attr.disabled = false;
                err = modify_user_hw_breakpoint(bp, &attr);
                if (unlikely(err))
                        return err;
@@ -392,6 +394,9 @@ long arch_ptrace(struct task_struct *child, long request,
                                        tmp = 0;
                        } else {
                                unsigned long index;
+                               ret = init_fpu(child);
+                               if (ret)
+                                       break;
                                index = addr - offsetof(struct user, fpu);
                                tmp = ((unsigned long *)child->thread.xstate)
                                        [index >> 2];
@@ -423,6 +428,9 @@ long arch_ptrace(struct task_struct *child, long request,
                else if (addr >= offsetof(struct user, fpu) &&
                         addr < offsetof(struct user, u_fpvalid)) {
                        unsigned long index;
+                       ret = init_fpu(child);
+                       if (ret)
+                               break;
                        index = addr - offsetof(struct user, fpu);
                        set_stopped_child_used_math(child);
                        ((unsigned long *)child->thread.xstate)
index 4436eacddb1536e6aaf5a00299a659dc12a210c6..c8f97649f354b5f4b80366b79a95c9a9a0f4d4bb 100644 (file)
@@ -403,6 +403,9 @@ long arch_ptrace(struct task_struct *child, long request,
                else if ((addr >= offsetof(struct user, fpu)) &&
                         (addr <  offsetof(struct user, u_fpvalid))) {
                        unsigned long index;
+                       ret = init_fpu(child);
+                       if (ret)
+                               break;
                        index = addr - offsetof(struct user, fpu);
                        tmp = get_fpu_long(child, index);
                } else if (addr == offsetof(struct user, u_fpvalid)) {
@@ -442,6 +445,9 @@ long arch_ptrace(struct task_struct *child, long request,
                else if ((addr >= offsetof(struct user, fpu)) &&
                         (addr <  offsetof(struct user, u_fpvalid))) {
                        unsigned long index;
+                       ret = init_fpu(child);
+                       if (ret)
+                               break;
                        index = addr - offsetof(struct user, fpu);
                        ret = put_fpu_long(child, index, data);
                }
index 768fb33fdd35f3aa0f730498bd9cbfa75c77972e..030966a9305cf5202b94e516f5ffdbbbd71f5179 100644 (file)
@@ -379,3 +379,4 @@ ENTRY(sys_call_table)
        .long sys_name_to_handle_at
        .long sys_open_by_handle_at     /* 360 */
        .long sys_clock_adjtime
+       .long sys_syncfs
index 44e7b00c80675da76e26ee3a612f0c666bf52d90..ca0a6142ab632ff957b5d91605175b20438d3798 100644 (file)
@@ -399,3 +399,4 @@ sys_call_table:
        .long sys_name_to_handle_at     /* 370 */
        .long sys_open_by_handle_at
        .long sys_clock_adjtime
+       .long sys_syncfs
index 242117cbad67bfa5f936911dbd70024905a68c2b..1d6d51a1ce7955bb055cc2169b3e22d7c997d3b2 100644 (file)
@@ -94,17 +94,17 @@ const char *arch_vma_name(struct vm_area_struct *vma)
        return NULL;
 }
 
-struct vm_area_struct *get_gate_vma(struct task_struct *task)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
        return NULL;
 }
 
-int in_gate_area(struct task_struct *task, unsigned long address)
+int in_gate_area(struct mm_struct *mm, unsigned long address)
 {
        return 0;
 }
 
-int in_gate_area_no_task(unsigned long address)
+int in_gate_area_no_mm(unsigned long address)
 {
        return 0;
 }
index b20b1b3eee4b267778102e0420f9119a88cf959e..fad52f1f6812a7515b663ad7795184d7319ad416 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Privileged Space Mapping Buffer (PMB) Support.
  *
- * Copyright (C) 2005 - 2010  Paul Mundt
+ * Copyright (C) 2005 - 2011  Paul Mundt
  * Copyright (C) 2010  Matt Fleming
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -12,7 +12,7 @@
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
@@ -874,46 +874,31 @@ static int __init pmb_debugfs_init(void)
 subsys_initcall(pmb_debugfs_init);
 
 #ifdef CONFIG_PM
-static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+static void pmb_syscore_resume(void)
 {
-       static pm_message_t prev_state;
+       struct pmb_entry *pmbe;
        int i;
 
-       /* Restore the PMB after a resume from hibernation */
-       if (state.event == PM_EVENT_ON &&
-           prev_state.event == PM_EVENT_FREEZE) {
-               struct pmb_entry *pmbe;
-
-               read_lock(&pmb_rwlock);
+       read_lock(&pmb_rwlock);
 
-               for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
-                       if (test_bit(i, pmb_map)) {
-                               pmbe = &pmb_entry_list[i];
-                               set_pmb_entry(pmbe);
-                       }
+       for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) {
+               if (test_bit(i, pmb_map)) {
+                       pmbe = &pmb_entry_list[i];
+                       set_pmb_entry(pmbe);
                }
-
-               read_unlock(&pmb_rwlock);
        }
 
-       prev_state = state;
-
-       return 0;
-}
-
-static int pmb_sysdev_resume(struct sys_device *dev)
-{
-       return pmb_sysdev_suspend(dev, PMSG_ON);
+       read_unlock(&pmb_rwlock);
 }
 
-static struct sysdev_driver pmb_sysdev_driver = {
-       .suspend = pmb_sysdev_suspend,
-       .resume = pmb_sysdev_resume,
+static struct syscore_ops pmb_syscore_ops = {
+       .resume = pmb_syscore_resume,
 };
 
 static int __init pmb_sysdev_init(void)
 {
-       return sysdev_driver_register(&cpu_sysdev_class, &pmb_sysdev_driver);
+       register_syscore_ops(&pmb_syscore_ops);
+       return 0;
 }
 subsys_initcall(pmb_sysdev_init);
 #endif
index e48f471be547109b04e4d2124ff8b4c9498a3fad..f766e6bf370ebb2e8972a0cbdfd28b54f752d97c 100644 (file)
@@ -192,6 +192,10 @@ config GENERIC_FIND_NEXT_BIT
        bool
        default y
 
+config GENERIC_FIND_BIT_LE
+       bool
+       default y
+
 config GENERIC_HWEIGHT
        bool
        default y if !ULTRA_HAS_POPULATION_COUNT
index 9cf4ae0cd7ba7b2a173c5c30039365a06f0a1db1..25a676653d45d2ecb6ba01da2d0a76e82649d7e6 100644 (file)
@@ -103,9 +103,8 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/find.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
index 766121a67a24a1de821325352c1b3a5bc738a799..38e9aa1b2cea390528c7b75a06927b8938e597ce 100644 (file)
@@ -89,15 +89,13 @@ static inline unsigned int __arch_hweight8(unsigned int w)
 
 #ifdef __KERNEL__
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(lock,nr,addr) \
        test_and_set_bit((nr) ^ 0x38,(unsigned long *)(addr))
 #define ext2_clear_bit_atomic(lock,nr,addr) \
        test_and_clear_bit((nr) ^ 0x38,(unsigned long *)(addr))
 
-#include <asm-generic/bitops/minix.h>
-
 #endif /* __KERNEL__ */
 
 #endif /* defined(_SPARC64_BITOPS_H) */
index cbf4801deaafc9c9bbb3cb11a3383c5e209a240d..eced3e3ebd30f5603b6a236d0bd7886e67d1ddf2 100644 (file)
@@ -13,4 +13,7 @@
 #define irq_canonicalize(irq)  (irq)
 
 extern void __init init_IRQ(void);
+
+#define NO_IRQ         0xffffffff
+
 #endif
index 4f09666f07984022543c39742231b499a5d085de..16dcae6d56e7a777b1c833bb8f6f16d57279271a 100644 (file)
@@ -97,4 +97,6 @@ extern void *softirq_stack[NR_CPUS];
 #define __ARCH_HAS_DO_SOFTIRQ
 #define ARCH_HAS_NMI_WATCHDOG
 
+#define NO_IRQ         0xffffffff
+
 #endif
index 9dd0318d3ddfe5313eb6317f7c41965c93aece46..fa5753233410baaf9c489fe7968675b418fcdde1 100644 (file)
@@ -82,8 +82,8 @@ register struct thread_info *current_thread_info_reg asm("g6");
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
-BTFIXUPDEF_CALL(struct thread_info *, alloc_thread_info, void)
-#define alloc_thread_info(tsk) BTFIXUP_CALL(alloc_thread_info)()
+BTFIXUPDEF_CALL(struct thread_info *, alloc_thread_info_node, int)
+#define alloc_thread_info_node(tsk, node) BTFIXUP_CALL(alloc_thread_info_node)(node)
 
 BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
 #define free_thread_info(ti) BTFIXUP_CALL(free_thread_info)(ti)
@@ -92,7 +92,7 @@ BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *)
 
 /*
  * Size of kernel stack for each process.
- * Observe the order of get_free_pages() in alloc_thread_info().
+ * Observe the order of get_free_pages() in alloc_thread_info_node().
  * The sun4 has 8K stack too, because it's short on memory, and 16K is a waste.
  */
 #define THREAD_SIZE            8192
index fb2ea7705a46fc228d5d985d30d7686f0135b3ea..60d86be1a53381bd0fd09c3b133c0c0c80e60bd1 100644 (file)
@@ -146,21 +146,21 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk)                                 \
-({                                                             \
-       struct thread_info *ret;                                \
-                                                               \
-       ret = (struct thread_info *)                            \
-         __get_free_pages(GFP_KERNEL, __THREAD_INFO_ORDER);    \
-       if (ret)                                                \
-               memset(ret, 0, PAGE_SIZE<<__THREAD_INFO_ORDER); \
-       ret;                                                    \
-})
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO)
 #else
-#define alloc_thread_info(tsk) \
-       ((struct thread_info *)__get_free_pages(GFP_KERNEL, __THREAD_INFO_ORDER))
+#define THREAD_FLAGS (GFP_KERNEL)
 #endif
 
+#define alloc_thread_info_node(tsk, node)                              \
+({                                                                     \
+       struct page *page = alloc_pages_node(node, THREAD_FLAGS,        \
+                                            __THREAD_INFO_ORDER);      \
+       struct thread_info *ret;                                        \
+                                                                       \
+       ret = page ? page_address(page) : NULL;                         \
+       ret;                                                            \
+})
+
 #define free_thread_info(ti) \
        free_pages((unsigned long)(ti),__THREAD_INFO_ORDER)
 
index 09c79a9c85166a0c11fd5d45e38035b8611b13dd..91e5a034f987eea0f7c677ee13b9a1a57ff3fcb0 100644 (file)
@@ -18,28 +18,6 @@ typedef unsigned short umode_t;
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef __KERNEL__
-
-#ifndef __ASSEMBLY__
-
-/* Dma addresses come in generic and 64-bit flavours.  */
-
-typedef u32 dma_addr_t;
-
-#if defined(__arch64__)
-
-/*** SPARC 64 bit ***/
-typedef u64 dma64_addr_t;
-#else
-/*** SPARC 32 bit ***/
-typedef u32 dma64_addr_t;
-
-#endif /* defined(__arch64__) */
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
 #endif /* defined(__sparc__) */
 
 #endif /* defined(_SPARC_TYPES_H) */
index 03eb5a8f6f9363ccc55410e011328f843aa05474..2f475d7c0b53f7f127f5345a7bb1af7e81d9e8bc 100644 (file)
 #define __NR_fanotify_init     329
 #define __NR_fanotify_mark     330
 #define __NR_prlimit64         331
+#define __NR_name_to_handle_at 332
+#define __NR_open_by_handle_at 333
+#define __NR_clock_adjtime     334
 
-#define NR_syscalls            332
+#define NR_syscalls            335
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index 49ddff56cb04130ce1a84ccb0ed152ebf6516e9a..cb15bbf8a201478608672f85f55dc53f7b62247b 100644 (file)
@@ -22,6 +22,33 @@ unsigned int irq_of_parse_and_map(struct device_node *node, int index)
 }
 EXPORT_SYMBOL(irq_of_parse_and_map);
 
+int of_address_to_resource(struct device_node *node, int index,
+                          struct resource *r)
+{
+       struct platform_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_resources)
+               return -EINVAL;
+
+       memcpy(r, &op->archdata.resource[index], sizeof(*r));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_address_to_resource);
+
+void __iomem *of_iomap(struct device_node *node, int index)
+{
+       struct platform_device *op = of_find_device_by_node(node);
+       struct resource *r;
+
+       if (!op || index >= op->num_resources)
+               return NULL;
+
+       r = &op->archdata.resource[index];
+
+       return of_ioremap(r, 0, resource_size(r), (char *) r->name);
+}
+EXPORT_SYMBOL(of_iomap);
+
 /* Take the archdata values for IOMMU, STC, and HOSTDATA found in
  * BUS and propagate to all child platform_device objects.
  */
index ec396e1916b92e4560505175bcdee3b59b3fef49..4b86eaf04fe57ef4ed1aa632462325a0f3372c95 100644 (file)
@@ -83,5 +83,5 @@ sys_call_table:
 /*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
 /*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
-/*330*/        .long sys_fanotify_mark, sys_prlimit64
+/*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
 
index 8cfcaa54958054535dcd376296c1f71f780cc147..0331bafdf3a30c9d33f8d4c45228c7407eb2828f 100644 (file)
@@ -84,7 +84,7 @@ sys_call_table32:
        .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
-/*330*/        .word sys32_fanotify_mark, sys_prlimit64
+/*330*/        .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
 
 #endif /* CONFIG_COMPAT */
 
@@ -160,4 +160,4 @@ sys_call_table:
        .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
 /*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
-/*330*/        .word sys_fanotify_mark, sys_prlimit64
+/*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
index 8237dd4dfeb40d55e3b35947d3f41cd3d3f43372..4e236391b6359ab59223034c61892c6b3fce7a28 100644 (file)
@@ -145,6 +145,10 @@ static int __devinit clock_probe(struct platform_device *op)
        if (!model)
                return -ENODEV;
 
+       /* Only the primary RTC has an address property */
+       if (!of_find_property(dp, "address", NULL))
+               return -ENODEV;
+
        m48t59_rtc.resource = &op->resource[0];
        if (!strcmp(model, "mk48t02")) {
                /* Map the clock register io area read-only */
index 6d0e02c4fe09cdc318d6da849668495546d21897..4c31e2b6e71b8bd49451ab2d6f4381e82bfbd9ae 100644 (file)
@@ -75,7 +75,7 @@ void __init kmap_init(void)
        kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE);
 }
 
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        printk("Mem-info:\n");
        show_free_areas();
index 92319aa8b66212c35b6ee377db990057d05ee0df..fe09fd8be6956e5f00fe0fddc5c9bbf6a11882c5 100644 (file)
@@ -650,7 +650,7 @@ static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len)
  * mappings on the kernel stack without any special code as we did
  * need on the sun4c.
  */
-static struct thread_info *srmmu_alloc_thread_info(void)
+static struct thread_info *srmmu_alloc_thread_info_node(int node)
 {
        struct thread_info *ret;
 
@@ -2271,7 +2271,7 @@ void __init ld_mmu_srmmu(void)
 
        BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(alloc_thread_info, srmmu_alloc_thread_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(alloc_thread_info_node, srmmu_alloc_thread_info_node, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(free_thread_info, srmmu_free_thread_info, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(pte_to_pgoff, srmmu_pte_to_pgoff, BTFIXUPCALL_NORM);
index b5137cc2aba310ad5b0c877d58edabf01cc46010..a2350b5e68aa66c237999dca7790a7e7e0282c48 100644 (file)
@@ -922,7 +922,7 @@ static inline void garbage_collect(int entry)
        free_locked_segment(BUCKET_ADDR(entry));
 }
 
-static struct thread_info *sun4c_alloc_thread_info(void)
+static struct thread_info *sun4c_alloc_thread_info_node(int node)
 {
        unsigned long addr, pages;
        int entry;
@@ -2155,7 +2155,7 @@ void __init ld_mmu_sun4c(void)
        BTFIXUPSET_CALL(__swp_offset, sun4c_swp_offset, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(__swp_entry, sun4c_swp_entry, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(alloc_thread_info, sun4c_alloc_thread_info, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(alloc_thread_info_node, sun4c_alloc_thread_info_node, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(free_thread_info, sun4c_free_thread_info, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM);
index 6d4f0ff2c68cad734d9cb59df5c74e799e47a5ce..132e6bbd07e911e02f6abba5586db0c6d7d9456a 100644 (file)
@@ -122,7 +122,6 @@ static inline unsigned long __arch_hweight64(__u64 w)
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
-#include <asm-generic/bitops/minix.h>
+#include <asm-generic/bitops/le.h>
 
 #endif /* _ASM_TILE_BITOPS_H */
index 9e8e9c4dfa2af284a62bcc430af5e845ee03fb80..3405b52853b869ba7bae0fcd7e091051fdaa30a7 100644 (file)
@@ -84,7 +84,7 @@ register unsigned long stack_pointer __asm__("sp");
   ((struct thread_info *)(stack_pointer & -THREAD_SIZE))
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
-extern struct thread_info *alloc_thread_info(struct task_struct *task);
+extern struct thread_info *alloc_thread_info_node(struct task_struct *task, int node);
 extern void free_thread_info(struct thread_info *info);
 
 /* Sit on a nap instruction until interrupted. */
index b9cd962e1d307c45af9b342f36941d8cc67e9e04..d0065103eb7bd48e98003e2d594c7c8b2572f0c4 100644 (file)
@@ -109,7 +109,7 @@ void cpu_idle(void)
        }
 }
 
-struct thread_info *alloc_thread_info(struct task_struct *task)
+struct thread_info *alloc_thread_info_node(struct task_struct *task, int node)
 {
        struct page *page;
        gfp_t flags = GFP_KERNEL;
@@ -118,7 +118,7 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
        flags |= __GFP_ZERO;
 #endif
 
-       page = alloc_pages(flags, THREAD_SIZE_ORDER);
+       page = alloc_pages_node(node, flags, THREAD_SIZE_ORDER);
        if (!page)
                return NULL;
 
index f02040d3614e25d06330ed5413b26aa87bcc53e7..46570211df5275766bdf8ef9284ab3edbb802f95 100644 (file)
@@ -202,32 +202,32 @@ static inline int *__futex_setup(int __user *v)
        return __atomic_hashed_lock((int __force *)v);
 }
 
-struct __get_user futex_set(int __user *v, int i)
+struct __get_user futex_set(u32 __user *v, int i)
 {
        return __atomic_xchg((int __force *)v, __futex_setup(v), i);
 }
 
-struct __get_user futex_add(int __user *v, int n)
+struct __get_user futex_add(u32 __user *v, int n)
 {
        return __atomic_xchg_add((int __force *)v, __futex_setup(v), n);
 }
 
-struct __get_user futex_or(int __user *v, int n)
+struct __get_user futex_or(u32 __user *v, int n)
 {
        return __atomic_or((int __force *)v, __futex_setup(v), n);
 }
 
-struct __get_user futex_andn(int __user *v, int n)
+struct __get_user futex_andn(u32 __user *v, int n)
 {
        return __atomic_andn((int __force *)v, __futex_setup(v), n);
 }
 
-struct __get_user futex_xor(int __user *v, int n)
+struct __get_user futex_xor(u32 __user *v, int n)
 {
        return __atomic_xor((int __force *)v, __futex_setup(v), n);
 }
 
-struct __get_user futex_cmpxchg(int __user *v, int o, int n)
+struct __get_user futex_cmpxchg(u32 __user *v, int o, int n)
 {
        return __atomic_cmpxchg((int __force *)v, __futex_setup(v), o, n);
 }
index 1a2b36f8866d88b7708722ff81b9026e5445f22e..de7d8e21e01d8980009de9840ccbd2c30690b2f1 100644 (file)
@@ -41,7 +41,7 @@
  * The normal show_free_areas() is too verbose on Tile, with dozens
  * of processors and often four NUMA zones each with high and lowmem.
  */
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        struct zone *zone;
 
index 1e78940218c0f82767c16c72080d3d36dcd97c0f..109ddc0071c6ae214b762b848506b49bf846258c 100644 (file)
@@ -8,6 +8,7 @@ config UML
        default y
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_HARDIRQS_NO_DEPRECATED
+       select GENERIC_IRQ_SHOW
 
 config MMU
        bool
index 050e4ddbbb6516a20416cad7107695862f93f8cd..35dd0b86401a833624af552c5043585f8a1b5825 100644 (file)
@@ -255,8 +255,8 @@ static const struct {
        { KDSIGACCEPT, KERN_INFO,  "KDSIGACCEPT" },
 };
 
-int line_ioctl(struct tty_struct *tty, struct file * file,
-              unsigned int cmd, unsigned long arg)
+int line_ioctl(struct tty_struct *tty, unsigned int cmd,
+                               unsigned long arg)
 {
        int ret;
        int i;
index bed668824b5f94529c8d28e7209078d181f87d4b..d1d1b0d8a0cd9c66d754243f636425e4c942ee46 100644 (file)
@@ -66,7 +66,7 @@ struct thread_struct {
        .request                = { 0 } \
 }
 
-extern struct task_struct *alloc_task_struct(void);
+extern struct task_struct *alloc_task_struct_node(int node);
 
 static inline void release_thread(struct task_struct *task)
 {
index 311a0d3d93af2302224e9b9d6b76614643a23a67..72f4f25af2478e5c4d14d0a3072a45d10f21a211 100644 (file)
@@ -77,8 +77,8 @@ extern int line_chars_in_buffer(struct tty_struct *tty);
 extern void line_flush_buffer(struct tty_struct *tty);
 extern void line_flush_chars(struct tty_struct *tty);
 extern int line_write_room(struct tty_struct *tty);
-extern int line_ioctl(struct tty_struct *tty, struct file * file,
-                     unsigned int cmd, unsigned long arg);
+extern int line_ioctl(struct tty_struct *tty, unsigned int cmd,
+                               unsigned long arg);
 extern void line_throttle(struct tty_struct *tty);
 extern void line_unthrottle(struct tty_struct *tty);
 
index 64cfea80cfe2345937e0070779444b06accbfec7..9e485c770308d21fe7148f5ed5004f8f93b5d70d 100644 (file)
 #include "kern_util.h"
 #include "os.h"
 
-/*
- * Generic, controller-independent functions:
- */
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       int i = *(loff_t *) v, j;
-       struct irqaction * action;
-       unsigned long flags;
-
-       if (i == 0) {
-               seq_printf(p, "           ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ",j);
-               seq_putc(p, '\n');
-       }
-
-       if (i < NR_IRQS) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               raw_spin_lock_irqsave(&desc->lock, flags);
-               action = desc->action;
-               if (!action)
-                       goto skip;
-               seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
-               seq_printf(p, " %14s", get_irq_desc_chip(desc)->name);
-               seq_printf(p, "  %s", action->name);
-
-               for (action=action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-
-               seq_putc(p, '\n');
-skip:
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-       } else if (i == NR_IRQS)
-               seq_putc(p, '\n');
-
-       return 0;
-}
-
 /*
  * This list is accessed under irq_lock, except in sigio_handler,
  * where it is safe from being modified.  IRQ handlers won't change it -
@@ -390,11 +344,10 @@ void __init init_IRQ(void)
 {
        int i;
 
-       set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
+       irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
 
-       for (i = 1; i < NR_IRQS; i++) {
-               set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
-       }
+       for (i = 1; i < NR_IRQS; i++)
+               irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
 }
 
 /*
index a979a22a8d9f0567aca79521318f711025b5d1c8..d964a4111ac6fddb130204a72c95e7545b756a88 100644 (file)
@@ -75,6 +75,8 @@ typedef struct user_i387_struct elf_fpregset_t;
        pr_reg[16] = PT_REGS_SS(regs);          \
 } while (0);
 
+#define task_pt_regs(t) (&(t)->thread.regs)
+
 struct task_struct;
 
 extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
index b8bc844fd2c46d8d9316890068d6927622aaab46..20d363bd70041d1022dd57a8f40a5405655efa90 100644 (file)
@@ -6,7 +6,7 @@ OBJ = built-in.o
 OBJS = ptrace.o sigcontext.o checksum.o miscthings.o misc.o \
        ptrace_user.o sysrq.o
 
-EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel
+asflags-y := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel
 
 all: $(OBJ)
 
@@ -15,10 +15,10 @@ $(OBJ): $(OBJS)
        $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
 
 ptrace_user.o: ptrace_user.c
-       $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+       $(CC) -D__KERNEL__ $(USER_CFLAGS) $(ccflags-y) -c -o $@ $<
 
 sigcontext.o: sigcontext.c
-       $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+       $(CC) $(USER_CFLAGS) $(ccflags-y) -c -o $@ $<
 
 checksum.S:
        rm -f $@
@@ -53,13 +53,13 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
 checksum.o: checksum.S
        rm -f asm
        ln -s $(srctree)/include/asm-ppc asm
-       $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+       $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
        rm -f asm
 
 misc.o: misc.S ppc_defs.h
        rm -f asm
        ln -s $(srctree)/include/asm-ppc asm
-       $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+       $(CC) $(asflags-y) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
        rm -f asm
 
 clean-files := $(OBJS) ppc_defs.h checksum.S mk_defs.c
index d760967f33a7e029afd8792ded750e31911488fb..d6d5af376251e494f626491787b4a4c7178f662d 100644 (file)
@@ -95,6 +95,8 @@ typedef struct user_i387_struct elf_fpregset_t;
        (pr_reg)[25] = 0;                                       \
        (pr_reg)[26] = 0;
 
+#define task_pt_regs(t) (&(t)->thread.regs)
+
 struct task_struct;
 
 extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
index 3dbe3709b69d0ce0fe556c4f400e2d4d07a5bce9..1fc02633f700a18af47db8e61a85cd55c0210d80 100644 (file)
@@ -55,7 +55,7 @@ early_param("initrd", early_initrd);
  */
 struct meminfo meminfo;
 
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        int free = 0, total = 0, reserved = 0;
        int shared = 0, cached = 0, slab = 0, i;
index e1f65c46bc93e15af6d055b3220087fa8817ce40..140e254fe546e195c125915392d0f1ece1d38d8f 100644 (file)
@@ -123,7 +123,7 @@ config NEED_SG_DMA_LENGTH
        def_bool y
 
 config GENERIC_ISA_DMA
-       def_bool y
+       def_bool ISA_DMA_API
 
 config GENERIC_IOMAP
        def_bool y
@@ -143,7 +143,7 @@ config GENERIC_GPIO
        bool
 
 config ARCH_MAY_HAVE_PC_FDC
-       def_bool y
+       def_bool ISA_DMA_API
 
 config RWSEM_GENERIC_SPINLOCK
        def_bool !X86_XADD
@@ -2002,9 +2002,13 @@ source "drivers/pci/pcie/Kconfig"
 
 source "drivers/pci/Kconfig"
 
-# x86_64 have no ISA slots, but do have ISA-style DMA.
+# x86_64 have no ISA slots, but can have ISA-style DMA.
 config ISA_DMA_API
-       def_bool y
+       bool "ISA-style DMA support" if (X86_64 && EXPERT)
+       default y
+       help
+         Enables ISA-style DMA support for devices requiring such controllers.
+         If unsure, say Y.
 
 if X86_32
 
@@ -2092,6 +2096,16 @@ source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
 
+config RAPIDIO
+       bool "RapidIO support"
+       depends on PCI
+       default n
+       help
+         If you say Y here, the kernel will include drivers and
+         infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rapidio/Kconfig"
+
 endmenu
 
 
index 2d93bdbc9ac026f2c0ef1e3fcd9c9a208b609787..fd843877e84152d87d437fca5173b858336a104a 100644 (file)
@@ -298,6 +298,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        /* OK, This is the point of no return */
        set_personality(PER_LINUX);
        set_thread_flag(TIF_IA32);
+       current->mm->context.ia32_compat = 1;
 
        setup_new_exec(bprm);
 
index 430312ba6e3f3b0b9cee93427feb69b18c9a5ab2..849a9d23c71d5c11080d92edbb705343879aa15e 100644 (file)
@@ -847,4 +847,5 @@ ia32_sys_call_table:
        .quad sys_name_to_handle_at
        .quad compat_sys_open_by_handle_at
        .quad compat_sys_clock_adjtime
+       .quad sys_syncfs
 ia32_syscall_end:
index 448d73a371ba59c08be71c8a6658b4cb703348bb..12e0e7dd869c6f966efd4415c740db2f39bd0eb7 100644 (file)
@@ -114,9 +114,8 @@ static inline void acpi_disable_pci(void)
        acpi_noirq_set();
 }
 
-/* routines for saving/restoring kernel state */
-extern int acpi_save_state_mem(void);
-extern void acpi_restore_state_mem(void);
+/* Low-level suspend routine. */
+extern int acpi_suspend_lowlevel(void);
 
 extern const unsigned char acpi_wakeup_code[];
 #define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code)))
index 903683b07e423fde4189c8340bfa4fcf0725b206..69d58131bc8e185c5be704288e971e0757bc8eab 100644 (file)
@@ -456,14 +456,12 @@ static inline int fls(int x)
 
 #ifdef __KERNEL__
 
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #define ext2_set_bit_atomic(lock, nr, addr)                    \
        test_and_set_bit((nr), (unsigned long *)(addr))
 #define ext2_clear_bit_atomic(lock, nr, addr)                  \
        test_and_clear_bit((nr), (unsigned long *)(addr))
 
-#include <asm-generic/bitops/minix.h>
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_BITOPS_H */
index ca1098a7e58057eebe268c059a682990c6ebb7e6..97b6d8114a439e410bc7107e07492f5ff52cf14c 100644 (file)
 #define DMA_AUTOINIT           0x10
 
 
+#ifdef CONFIG_ISA_DMA_API
 extern spinlock_t  dma_spin_lock;
 
 static inline unsigned long claim_dma_lock(void)
@@ -164,6 +165,7 @@ static inline void release_dma_lock(unsigned long flags)
 {
        spin_unlock_irqrestore(&dma_spin_lock, flags);
 }
+#endif /* CONFIG_ISA_DMA_API */
 
 /* enable/disable a specific DMA channel */
 static inline void enable_dma(unsigned int dmanr)
@@ -303,9 +305,11 @@ static inline int get_dma_residue(unsigned int dmanr)
 }
 
 
-/* These are in kernel/dma.c: */
+/* These are in kernel/dma.c because x86 uses CONFIG_GENERIC_ISA_DMA */
+#ifdef CONFIG_ISA_DMA_API
 extern int request_dma(unsigned int dmanr, const char *device_id);
 extern void free_dma(unsigned int dmanr);
+#endif
 
 /* From PCI */
 
index 80a1dee5bea5ec67bb77adf6db286f471d8006e8..aeff3e89b222edc08d31f122dc7008a0cc8466a9 100644 (file)
@@ -13,6 +13,12 @@ typedef struct {
        int size;
        struct mutex lock;
        void *vdso;
+
+#ifdef CONFIG_X86_64
+       /* True if mm supports a task running in 32 bit compatibility mode. */
+       unsigned short ia32_compat;
+#endif
+
 } mm_context_t;
 
 #ifdef CONFIG_SMP
index f0b6e5dbc5a03b97f821cb71a6d4b95c2bc51b77..1f2e61e28981b7a32d8f9f6f409475460a2ca73d 100644 (file)
@@ -161,8 +161,14 @@ struct thread_info {
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
-#define alloc_thread_info(tsk)                                         \
-       ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
+#define alloc_thread_info_node(tsk, node)                              \
+({                                                                     \
+       struct page *page = alloc_pages_node(node, THREAD_FLAGS,        \
+                                            THREAD_ORDER);             \
+       struct thread_info *ret = page ? page_address(page) : NULL;     \
+                                                                       \
+       ret;                                                            \
+})
 
 #ifdef CONFIG_X86_32
 
index df1da20f453476635f8dd244cd690451c39b4c13..8e8c23fef08cee476a41a88c367e937385cb642c 100644 (file)
@@ -1,22 +1,6 @@
 #ifndef _ASM_X86_TYPES_H
 #define _ASM_X86_TYPES_H
 
-#define dma_addr_t     dma_addr_t
-
 #include <asm-generic/types.h>
 
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-
-typedef u64 dma64_addr_t;
-#if defined(CONFIG_X86_64) || defined(CONFIG_HIGHMEM64G)
-/* DMA addresses come in 32-bit and 64-bit flavours. */
-typedef u64 dma_addr_t;
-#else
-typedef u32 dma_addr_t;
-#endif
-
-#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_X86_TYPES_H */
index ffaf183c619a21f30c24384f8aa9e106e496dfa2..a755ef5e5977540cd52b63e85374e8c4d03e7b8c 100644 (file)
 #define __NR_name_to_handle_at 341
 #define __NR_open_by_handle_at  342
 #define __NR_clock_adjtime     343
+#define __NR_syncfs             344
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 344
+#define NR_syscalls 345
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 5466bea670e7e3c14774c998fb0f90d089cb3d8a..160fa76bd5786e680da555ad96d8101a71edc99e 100644 (file)
@@ -675,6 +675,8 @@ __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
 __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
 #define __NR_clock_adjtime                     305
 __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+#define __NR_syncfs                             306
+__SYSCALL(__NR_syncfs, sys_syncfs)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 743642f1a36c4aa611653e505afbe99ea88f5453..7338ef2218bc0687f6bfc392ecfeca8a48ca0b56 100644 (file)
@@ -41,7 +41,7 @@ obj-$(CONFIG_X86_32)  += sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)   += sys_x86_64.o x8664_ksyms_64.o
 obj-$(CONFIG_X86_64)   += syscall_64.o vsyscall_64.o
 obj-y                  += bootflag.o e820.o
-obj-y                  += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
+obj-y                  += pci-dma.o quirks.o topology.o kdebugfs.o
 obj-y                  += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
 obj-y                  += tsc.o io_delay.o rtc.o
 obj-y                  += pci-iommu_table.o
@@ -55,6 +55,7 @@ obj-$(CONFIG_X86_32)          += tls.o
 obj-$(CONFIG_IA32_EMULATION)   += tls.o
 obj-y                          += step.o
 obj-$(CONFIG_INTEL_TXT)                += tboot.o
+obj-$(CONFIG_ISA_DMA_API)      += i8237.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-y                          += cpu/
 obj-y                          += acpi/
index 4572c58e66d5d911df2b7994ab13dd87b1df047b..ff93bc1b09c3aedd1a83a9e2e94952b56aef4fff 100644 (file)
@@ -25,12 +25,12 @@ static char temp_stack[4096];
 #endif
 
 /**
- * acpi_save_state_mem - save kernel state
+ * acpi_suspend_lowlevel - save kernel state
  *
  * Create an identity mapped page table and copy the wakeup routine to
  * low memory.
  */
-int acpi_save_state_mem(void)
+int acpi_suspend_lowlevel(void)
 {
        struct wakeup_header *header;
        /* address in low memory of the wakeup routine. */
@@ -96,16 +96,10 @@ int acpi_save_state_mem(void)
        saved_magic = 0x123456789abcdef0L;
 #endif /* CONFIG_64BIT */
 
+       do_suspend_lowlevel();
        return 0;
 }
 
-/*
- * acpi_restore_state - undo effects of acpi_save_state_mem
- */
-void acpi_restore_state_mem(void)
-{
-}
-
 static int __init acpi_sleep_setup(char *str)
 {
        while ((str != NULL) && (*str != '\0')) {
index 86ba1c87165bea41d035a2019a50e9862ebf0e34..416d4be13fef6d16cc96936ae3f222a91040ccf0 100644 (file)
@@ -11,3 +11,5 @@ extern int wakeup_pmode_return;
 
 extern unsigned long acpi_copy_wakeup_routine(unsigned long);
 extern void wakeup_long64(void);
+
+extern void do_suspend_lowlevel(void);
index 8209472b27a5ef2e91b88c02841ee702a5a906ee..83930deec3c6e2628cfd1ba2da5cecf4528d4232 100644 (file)
@@ -106,24 +106,34 @@ int apei_write_mce(struct mce *m)
 ssize_t apei_read_mce(struct mce *m, u64 *record_id)
 {
        struct cper_mce_record rcd;
-       ssize_t len;
-
-       len = erst_read_next(&rcd.hdr, sizeof(rcd));
-       if (len <= 0)
-               return len;
-       /* Can not skip other records in storage via ERST unless clear them */
-       else if (len != sizeof(rcd) ||
-                uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
-               if (printk_ratelimit())
-                       pr_warning(
-                       "MCE-APEI: Can not skip the unknown record in ERST");
-               return -EIO;
-       }
-
+       int rc, pos;
+
+       rc = erst_get_record_id_begin(&pos);
+       if (rc)
+               return rc;
+retry:
+       rc = erst_get_record_id_next(&pos, record_id);
+       if (rc)
+               goto out;
+       /* no more record */
+       if (*record_id == APEI_ERST_INVALID_RECORD_ID)
+               goto out;
+       rc = erst_read(*record_id, &rcd.hdr, sizeof(rcd));
+       /* someone else has cleared the record, try next one */
+       if (rc == -ENOENT)
+               goto retry;
+       else if (rc < 0)
+               goto out;
+       /* try to skip other type records in storage */
+       else if (rc != sizeof(rcd) ||
+                uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE))
+               goto retry;
        memcpy(m, &rcd.mce, sizeof(*m));
-       *record_id = rcd.hdr.record_id;
+       rc = sizeof(*m);
+out:
+       erst_get_record_id_end();
 
-       return sizeof(*m);
+       return rc;
 }
 
 /* Check whether there is record in ERST */
index 87eab4a27dfccc0ad75d17338d6a8be5c5a1a1e0..eed3673a8656f5688d54f6b4d72fd9774c831fcb 100644 (file)
@@ -500,12 +500,17 @@ static bool check_hw_exists(void)
        return true;
 
 bios_fail:
-       printk(KERN_CONT "Broken BIOS detected, using software events only.\n");
+       /*
+        * We still allow the PMU driver to operate:
+        */
+       printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n");
        printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg, val);
-       return false;
+
+       return true;
 
 msr_fail:
        printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
+
        return false;
 }
 
@@ -912,7 +917,7 @@ static inline void x86_assign_hw_event(struct perf_event *event,
                hwc->event_base = 0;
        } else if (hwc->idx >= X86_PMC_IDX_FIXED) {
                hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
-               hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0;
+               hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - X86_PMC_IDX_FIXED);
        } else {
                hwc->config_base = x86_pmu_config_addr(hwc->idx);
                hwc->event_base  = x86_pmu_event_addr(hwc->idx);
index 0811f5ebfba6643083b50d81c5710292db12b4b6..c2520e178d32147fd9e2acd954d59e4217115add 100644 (file)
@@ -777,6 +777,7 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
         * the counter has reached zero value and continued counting before
         * real NMI signal was received:
         */
+       rdmsrl(hwc->event_base, v);
        if (!(v & ARCH_P4_UNFLAGGED_BIT))
                return 1;
 
index d5cd13945d5a48a30cc0c61c26824aa2dad38b5b..642f75a68cd56653896dda18d2f26c3be9b22fe0 100644 (file)
@@ -14,9 +14,6 @@
 
 static void *kdump_buf_page;
 
-/* Stores the physical address of elf header of crash image. */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
 static inline bool is_crashed_pfn_valid(unsigned long pfn)
 {
 #ifndef CONFIG_X86_PAE
index 994828899e098350d12ca73217235af843b0d497..afa64adb75eeb2bf830fbef1ef5a66960b14663e 100644 (file)
@@ -10,9 +10,6 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-/* Stores the physical address of elf header of crash image. */
-unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
-
 /**
  * copy_oldmem_page - copy one page from "oldmem"
  * @pfn: page frame number to be copied
index 7a8cebc9ff298ce0a788cc269e83efcd57a607d2..706a9fb46a58785edef3632d2dcfc5d02ac6404f 100644 (file)
@@ -65,12 +65,10 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
                return 0;
        ret = ih->xlate(ih, intspec, intsize, &virq, &type);
        if (ret)
-               return ret;
+               return 0;
        if (type == IRQ_TYPE_NONE)
                return virq;
-       /* set the mask if it is different from current */
-       if (type == (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK))
-               set_irq_type(virq, type);
+       irq_set_irq_type(virq, type);
        return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index 999e2793590b2275fe36d1c81d3bb74e69143a9d..e2a3f0606da4fa487d6d071ff0e964a16f44452c 100644 (file)
@@ -27,7 +27,7 @@ static int die_counter;
 
 void printk_address(unsigned long address, int reliable)
 {
-       printk(" [<%p>] %s%pS\n", (void *) address,
+       printk(" [<%p>] %s%pB\n", (void *) address,
                        reliable ? "" : "? ", (void *) address);
 }
 
@@ -322,16 +322,6 @@ void die(const char *str, struct pt_regs *regs, long err)
        oops_end(flags, regs, sig);
 }
 
-static int __init oops_setup(char *s)
-{
-       if (!s)
-               return -EINVAL;
-       if (!strcmp(s, "panic"))
-               panic_on_oops = 1;
-       return 0;
-}
-early_param("oops", oops_setup);
-
 static int __init kstack_setup(char *s)
 {
        if (!s)
index cdf5bfd9d4d50d8eb2503fd15c38b7d013e90f4a..3e2ef842531649de082d64298c6cb1044446c1bf 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/crash_dump.h>
 #include <linux/bootmem.h>
 #include <linux/pfn.h>
 #include <linux/suspend.h>
index 2d2673c28aff2754af1e6e8848e9068ab1a6cca5..5655c2272adb86244f1927127a40c705c5a4d447 100644 (file)
@@ -77,9 +77,6 @@ void __init x86_64_start_kernel(char * real_mode_data)
        /* Make NULL pointers segfault */
        zap_identity_mappings();
 
-       /* Cleanup the over mapped high alias */
-       cleanup_highmap();
-
        max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
 
        for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) {
index 6f789a887c0677cb8b4f753530bd623c46164e9e..5a532ce646bf5c08988e108c9e859fc77e8a0b57 100644 (file)
@@ -714,10 +714,6 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
                *nr_m_spare += 1;
        }
 }
-#else /* CONFIG_X86_IO_APIC */
-static
-inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {}
-#endif /* CONFIG_X86_IO_APIC */
 
 static int
 check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
@@ -731,6 +727,10 @@ check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
 
        return ret;
 }
+#else /* CONFIG_X86_IO_APIC */
+static
+inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {}
+#endif /* CONFIG_X86_IO_APIC */
 
 static int  __init replace_intsrc_all(struct mpc_table *mpc,
                                        unsigned long mpc_new_phys,
index bd387e8f73b473fe587715c8e4760c891c775d09..6c9dd922ac0d8b34ff9cac883ef86bf8843cb912 100644 (file)
@@ -501,6 +501,10 @@ void set_personality_64bit(void)
        /* Make sure to be in 64bit mode */
        clear_thread_flag(TIF_IA32);
 
+       /* Ensure the corresponding mm is not marked. */
+       if (current->mm)
+               current->mm->context.ia32_compat = 0;
+
        /* TBD: overwrites user setup. Should have two bits.
           But 64bit processes have always behaved this way,
           so it's not too bad. The main problem is just that
@@ -516,6 +520,10 @@ void set_personality_ia32(void)
        set_thread_flag(TIF_IA32);
        current->personality |= force_personality32;
 
+       /* Mark the associated mm as containing 32-bit tasks. */
+       if (current->mm)
+               current->mm->context.ia32_compat = 1;
+
        /* Prepare the first "return" to user space */
        current_thread_info()->status |= TS_COMPAT;
 }
index 9d43b28e07282c5d4cc658858a4103418ade4faf..5a0484a95ad6b99ad1824058efdcb238170a9f93 100644 (file)
@@ -294,30 +294,11 @@ static void __init init_gbpages(void)
        else
                direct_gbpages = 0;
 }
-
-static void __init cleanup_highmap_brk_end(void)
-{
-       pud_t *pud;
-       pmd_t *pmd;
-
-       mmu_cr4_features = read_cr4();
-
-       /*
-        * _brk_end cannot change anymore, but it and _end may be
-        * located on different 2M pages. cleanup_highmap(), however,
-        * can only consider _end when it runs, so destroy any
-        * mappings beyond _brk_end here.
-        */
-       pud = pud_offset(pgd_offset_k(_brk_end), _brk_end);
-       pmd = pmd_offset(pud, _brk_end - 1);
-       while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1))
-               pmd_clear(pmd);
-}
 #else
 static inline void init_gbpages(void)
 {
 }
-static inline void cleanup_highmap_brk_end(void)
+static void __init cleanup_highmap(void)
 {
 }
 #endif
@@ -330,8 +311,6 @@ static void __init reserve_brk(void)
        /* Mark brk area as locked down and no longer taking any
           new allocations */
        _brk_start = 0;
-
-       cleanup_highmap_brk_end();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -640,28 +619,6 @@ void __init reserve_standard_io_resources(void)
 
 }
 
-/*
- * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
- * is_kdump_kernel() to determine if we are booting after a panic. Hence
- * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
- */
-
-#ifdef CONFIG_CRASH_DUMP
-/* elfcorehdr= specifies the location of elf core header
- * stored by the crashed kernel. This option will be passed
- * by kexec loader to the capture kernel.
- */
-static int __init setup_elfcorehdr(char *arg)
-{
-       char *end;
-       if (!arg)
-               return -EINVAL;
-       elfcorehdr_addr = memparse(arg, &end);
-       return end > arg ? 0 : -EINVAL;
-}
-early_param("elfcorehdr", setup_elfcorehdr);
-#endif
-
 static __init void reserve_ibft_region(void)
 {
        unsigned long addr, size = 0;
@@ -950,6 +907,8 @@ void __init setup_arch(char **cmdline_p)
         */
        reserve_brk();
 
+       cleanup_highmap();
+
        memblock.current_limit = get_max_mapped();
        memblock_x86_fill();
 
index 5f181742e8f91c9510fbac2e0fd0ec7e12daf34d..abce34d5c79de0ce7e6275640a3470ccca9e1805 100644 (file)
@@ -343,3 +343,4 @@ ENTRY(sys_call_table)
        .long sys_name_to_handle_at
        .long sys_open_by_handle_at
        .long sys_clock_adjtime
+       .long sys_syncfs
index 0aa34669ed3f945400c46c737f63f5e01b6145dd..7942335872874c35a213fd6a45c1af326eb7c01c 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/cacheflush.h>
 #include <asm/init.h>
 #include <asm/uv/uv.h>
+#include <asm/setup.h>
 
 static int __init parse_direct_gbpages_off(char *arg)
 {
@@ -294,18 +295,18 @@ void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)
  * to the compile time generated pmds. This results in invalid pmds up
  * to the point where we hit the physaddr 0 mapping.
  *
- * We limit the mappings to the region from _text to _end.  _end is
- * rounded up to the 2MB boundary. This catches the invalid pmds as
+ * We limit the mappings to the region from _text to _brk_end.  _brk_end
+ * is rounded up to the 2MB boundary. This catches the invalid pmds as
  * well, as they are located before _text:
  */
 void __init cleanup_highmap(void)
 {
        unsigned long vaddr = __START_KERNEL_map;
-       unsigned long end = roundup((unsigned long)_end, PMD_SIZE) - 1;
+       unsigned long vaddr_end = __START_KERNEL_map + (max_pfn_mapped << PAGE_SHIFT);
+       unsigned long end = roundup((unsigned long)_brk_end, PMD_SIZE) - 1;
        pmd_t *pmd = level2_kernel_pgt;
-       pmd_t *last_pmd = pmd + PTRS_PER_PMD;
 
-       for (; pmd < last_pmd; pmd++, vaddr += PMD_SIZE) {
+       for (; vaddr + PMD_SIZE - 1 < vaddr_end; pmd++, vaddr += PMD_SIZE) {
                if (pmd_none(*pmd))
                        continue;
                if (vaddr < (unsigned long) _text || vaddr > end)
@@ -861,18 +862,18 @@ static struct vm_area_struct gate_vma = {
        .vm_flags       = VM_READ | VM_EXEC
 };
 
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
 #ifdef CONFIG_IA32_EMULATION
-       if (test_tsk_thread_flag(tsk, TIF_IA32))
+       if (!mm || mm->context.ia32_compat)
                return NULL;
 #endif
        return &gate_vma;
 }
 
-int in_gate_area(struct task_struct *task, unsigned long addr)
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
 {
-       struct vm_area_struct *vma = get_gate_vma(task);
+       struct vm_area_struct *vma = get_gate_vma(mm);
 
        if (!vma)
                return 0;
@@ -881,11 +882,11 @@ int in_gate_area(struct task_struct *task, unsigned long addr)
 }
 
 /*
- * Use this when you have no reliable task/vma, typically from interrupt
- * context. It is less reliable than using the task's vma and may give
- * false positives:
+ * Use this when you have no reliable mm, typically from interrupt
+ * context. It is less reliable than using a task's mm and may give
+ * false positives.
  */
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
        return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
index 127775696d6c34c254c3390d3180e929314fc3b3..99513642a0e6b324bc7b148fd7160222d043c87e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/mfd/core.h>
 
 #include <asm/io.h>
 #include <asm/olpc.h>
@@ -56,25 +57,24 @@ static void xo1_power_off(void)
 static int __devinit olpc_xo1_probe(struct platform_device *pdev)
 {
        struct resource *res;
+       int err;
 
        /* don't run on non-XOs */
        if (!machine_is_olpc())
                return -ENODEV;
 
+       err = mfd_cell_enable(pdev);
+       if (err)
+               return err;
+
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!res) {
                dev_err(&pdev->dev, "can't fetch device resource info\n");
                return -EIO;
        }
-
-       if (!request_region(res->start, resource_size(res), DRV_NAME)) {
-               dev_err(&pdev->dev, "can't request region\n");
-               return -EIO;
-       }
-
-       if (strcmp(pdev->name, "cs5535-pms") == 0)
+       if (strcmp(pdev->name, "olpc-xo1-pms") == 0)
                pms_base = res->start;
-       else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+       else if (strcmp(pdev->name, "olpc-xo1-ac-acpi") == 0)
                acpi_base = res->start;
 
        /* If we have both addresses, we can override the poweroff hook */
@@ -88,14 +88,11 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev)
 
 static int __devexit olpc_xo1_remove(struct platform_device *pdev)
 {
-       struct resource *r;
-
-       r = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       release_region(r->start, resource_size(r));
+       mfd_cell_disable(pdev);
 
-       if (strcmp(pdev->name, "cs5535-pms") == 0)
+       if (strcmp(pdev->name, "olpc-xo1-pms") == 0)
                pms_base = 0;
-       else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+       else if (strcmp(pdev->name, "olpc-xo1-acpi") == 0)
                acpi_base = 0;
 
        pm_power_off = NULL;
@@ -104,7 +101,7 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev)
 
 static struct platform_driver cs5535_pms_drv = {
        .driver = {
-               .name = "cs5535-pms",
+               .name = "olpc-xo1-pms",
                .owner = THIS_MODULE,
        },
        .probe = olpc_xo1_probe,
@@ -113,7 +110,7 @@ static struct platform_driver cs5535_pms_drv = {
 
 static struct platform_driver cs5535_acpi_drv = {
        .driver = {
-               .name = "cs5535-acpi",
+               .name = "olpc-xo1-acpi",
                .owner = THIS_MODULE,
        },
        .probe = olpc_xo1_probe,
@@ -124,26 +121,27 @@ static int __init olpc_xo1_init(void)
 {
        int r;
 
-       r = platform_driver_register(&cs5535_pms_drv);
+       r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms");
        if (r)
                return r;
 
-       r = platform_driver_register(&cs5535_acpi_drv);
+       r = mfd_shared_platform_driver_register(&cs5535_acpi_drv,
+                       "cs5535-acpi");
        if (r)
-               platform_driver_unregister(&cs5535_pms_drv);
+               mfd_shared_platform_driver_unregister(&cs5535_pms_drv);
 
        return r;
 }
 
 static void __exit olpc_xo1_exit(void)
 {
-       platform_driver_unregister(&cs5535_acpi_drv);
-       platform_driver_unregister(&cs5535_pms_drv);
+       mfd_shared_platform_driver_unregister(&cs5535_acpi_drv);
+       mfd_shared_platform_driver_unregister(&cs5535_pms_drv);
 }
 
 MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:olpc-xo1");
+MODULE_ALIAS("platform:cs5535-pms");
 
 module_init(olpc_xo1_init);
 module_exit(olpc_xo1_exit);
index 36df991985b2356188cee6c5e1409bcf28ed649e..468d591dde3159eaeeab46d09c04805354b95882 100644 (file)
@@ -417,24 +417,25 @@ const char *arch_vma_name(struct vm_area_struct *vma)
        return NULL;
 }
 
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
-       struct mm_struct *mm = tsk->mm;
-
-       /* Check to see if this task was created in compat vdso mode */
+       /*
+        * Check to see if the corresponding task was created in compat vdso
+        * mode.
+        */
        if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
                return &gate_vma;
        return NULL;
 }
 
-int in_gate_area(struct task_struct *task, unsigned long addr)
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
 {
-       const struct vm_area_struct *vma = get_gate_vma(task);
+       const struct vm_area_struct *vma = get_gate_vma(mm);
 
        return vma && addr >= vma->vm_start && addr < vma->vm_end;
 }
 
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
        return 0;
 }
index 39ee7182fd18a148569c7d7faf2c31a4a90bbb94..c82df6c9c0f0a4a1bbc61f1ea881ebdd37fecdef 100644 (file)
@@ -1487,10 +1487,12 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
        /*
         * If the new pfn is within the range of the newly allocated
         * kernel pagetable, and it isn't being mapped into an
-        * early_ioremap fixmap slot, make sure it is RO.
+        * early_ioremap fixmap slot as a freshly allocated page, make sure
+        * it is RO.
         */
-       if (!is_early_ioremap_ptep(ptep) &&
-           pfn >= pgt_buf_start && pfn < pgt_buf_end)
+       if (((!is_early_ioremap_ptep(ptep) &&
+                       pfn >= pgt_buf_start && pfn < pgt_buf_end)) ||
+                       (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1)))
                pte = pte_wrprotect(pte);
 
        return pte;
@@ -1700,9 +1702,6 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
                for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) {
                        pte_t pte;
 
-                       if (pfn > max_pfn_mapped)
-                               max_pfn_mapped = pfn;
-
                        if (!pte_none(pte_page[pteidx]))
                                continue;
 
@@ -1760,6 +1759,12 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
        pud_t *l3;
        pmd_t *l2;
 
+       /* max_pfn_mapped is the last pfn mapped in the initial memory
+        * mappings. Considering that on Xen after the kernel mappings we
+        * have the mappings of some pages that don't exist in pfn space, we
+        * set max_pfn_mapped to the last real pfn mapped. */
+       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
+
        /* Zap identity mapping */
        init_level4_pgt[0] = __pgd(0);
 
@@ -1864,9 +1869,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
        initial_kernel_pmd =
                extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
 
-       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
-                                 xen_start_info->nr_pt_frames * PAGE_SIZE +
-                                 512*1024);
+       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
 
        kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
        memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
index d373d159e75e408eef28e722cc8401885e9ffd0a..1d730b5579a0d051ba12c10979d385736b767d11 100644 (file)
@@ -7,6 +7,9 @@ config ZONE_DMA
 config XTENSA
        def_bool y
        select HAVE_IDE
+       select HAVE_GENERIC_HARDIRQS
+       select GENERIC_IRQ_SHOW
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -21,10 +24,10 @@ config RWSEM_XCHGADD_ALGORITHM
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
-config GENERIC_HWEIGHT
+config GENERIC_FIND_BIT_LE
        def_bool y
 
-config GENERIC_HARDIRQS
+config GENERIC_HWEIGHT
        def_bool y
 
 config GENERIC_GPIO
index 40aa55b485be91747ebc401f5d5d4047ce71aa11..70fd1453e172abcd48c54e11b8fd0af278f3fe45 100644 (file)
@@ -14,7 +14,7 @@ HOSTFLAGS     += -Iarch/$(ARCH)/boot/include
 
 BIG_ENDIAN     := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
 
-export EXTRA_CFLAGS
+export ccflags-y
 export BIG_ENDIAN
 
 subdir-y       := lib
index d3d2aa2d883aa6e4d9abfc7571b7e3e5eadbc30f..ad8952e8a07f6d369192416d831917cd642f9075 100644 (file)
@@ -6,7 +6,7 @@ zlib    := inffast.c inflate.c inftrees.c
 
 lib-y  += $(zlib:.c=.o) zmem.o
 
-EXTRA_CFLAGS   += -Ilib/zlib_inflate
+ccflags-y      := -Ilib/zlib_inflate
 
 quiet_cmd_copy_zlib = COPY    $@
       cmd_copy_zlib = cat $< > $@
index 6c3930397bd32539716f51c0cd23a290efa74cdd..c8fac8d8190dfaeafcf9a27f96122d0fe468b4ad 100644 (file)
@@ -106,7 +106,7 @@ static inline unsigned long __fls(unsigned long word)
 
 #include <asm-generic/bitops/fls64.h>
 #include <asm-generic/bitops/find.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 
 #ifdef __XTENSA_EL__
 # define ext2_set_bit_atomic(lock,nr,addr)                             \
@@ -125,7 +125,6 @@ static inline unsigned long __fls(unsigned long word)
 #include <asm-generic/bitops/hweight.h>
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/sched.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
 
index c89569a8da0cec6f2c664d073aa0010d265825ea..b1c981e39b52b1544a1dac3b0e4cc22f2510c36e 100644 (file)
@@ -32,10 +32,6 @@ typedef unsigned short umode_t;
 
 #define BITS_PER_LONG 32
 
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-
 #endif /* __KERNEL__ */
 #endif
 
index 87508886cbbdadb28d2843047cdbbb90e7656b77..d77089df412e156fb4784f7d3913af0b21d68980 100644 (file)
@@ -35,7 +35,6 @@ atomic_t irq_err_count;
 asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       struct irq_desc *desc = irq_desc + irq;
 
        if (irq >= NR_IRQS) {
                printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -57,104 +56,69 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
                               sp - sizeof(struct thread_info));
        }
 #endif
-       desc->handle_irq(irq, desc);
+       generic_handle_irq(irq);
 
        irq_exit();
        set_irq_regs(old_regs);
 }
 
-/*
- * Generic, controller-independent functions:
- */
-
-int show_interrupts(struct seq_file *p, void *v)
+int arch_show_interrupts(struct seq_file *p, int prec)
 {
-       int i = *(loff_t *) v, j;
-       struct irqaction * action;
-       unsigned long flags;
-
-       if (i == 0) {
-               seq_printf(p, "           ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ",j);
-               seq_putc(p, '\n');
-       }
-
-       if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
-               if (!action)
-                       goto skip;
-               seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
-               seq_printf(p, "  %s", action->name);
-
-               for (action=action->next; action; action = action->next)
-                       seq_printf(p, ", %s", action->name);
-
-               seq_putc(p, '\n');
-skip:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
-       } else if (i == NR_IRQS) {
-               seq_printf(p, "NMI: ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", nmi_count(j));
-               seq_putc(p, '\n');
-               seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-       }
+       int j;
+
+       seq_printf(p, "%*s: ", prec, "NMI");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", nmi_count(j));
+       seq_putc(p, '\n');
+       seq_printf(p, "%*s: ", prec, "ERR");
+       seq_printf(p, "%10u\n", atomic_read(&irq_err_count));
        return 0;
 }
 
-static void xtensa_irq_mask(unsigned int irq)
+static void xtensa_irq_mask(struct irq_chip *d)
 {
-       cached_irq_mask &= ~(1 << irq);
+       cached_irq_mask &= ~(1 << d->irq);
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static void xtensa_irq_unmask(unsigned int irq)
+static void xtensa_irq_unmask(struct irq_chip *d)
 {
-       cached_irq_mask |= 1 << irq;
+       cached_irq_mask |= 1 << d->irq;
        set_sr (cached_irq_mask, INTENABLE);
 }
 
-static void xtensa_irq_enable(unsigned int irq)
+static void xtensa_irq_enable(struct irq_chip *d)
 {
-       variant_irq_enable(irq);
-       xtensa_irq_unmask(irq);
+       variant_irq_enable(d->irq);
+       xtensa_irq_unmask(d->irq);
 }
 
-static void xtensa_irq_disable(unsigned int irq)
+static void xtensa_irq_disable(struct irq_chip *d)
 {
-       xtensa_irq_mask(irq);
-       variant_irq_disable(irq);
+       xtensa_irq_mask(d->irq);
+       variant_irq_disable(d->irq);
 }
 
-static void xtensa_irq_ack(unsigned int irq)
+static void xtensa_irq_ack(struct irq_chip *d)
 {
-       set_sr(1 << irq, INTCLEAR);
+       set_sr(1 << d->irq, INTCLEAR);
 }
 
-static int xtensa_irq_retrigger(unsigned int irq)
+static int xtensa_irq_retrigger(struct irq_chip *d)
 {
-       set_sr (1 << irq, INTSET);
+       set_sr (1 << d->irq, INTSET);
        return 1;
 }
 
 
 static struct irq_chip xtensa_irq_chip = {
        .name           = "xtensa",
-       .enable         = xtensa_irq_enable,
-       .disable        = xtensa_irq_disable,
-       .mask           = xtensa_irq_mask,
-       .unmask         = xtensa_irq_unmask,
-       .ack            = xtensa_irq_ack,
-       .retrigger      = xtensa_irq_retrigger,
+       .irq_enable     = xtensa_irq_enable,
+       .irq_disable    = xtensa_irq_disable,
+       .irq_mask       = xtensa_irq_mask,
+       .irq_unmask     = xtensa_irq_unmask,
+       .irq_ack        = xtensa_irq_ack,
+       .irq_retrigger  = xtensa_irq_retrigger,
 };
 
 void __init init_IRQ(void)
@@ -165,25 +129,25 @@ void __init init_IRQ(void)
                int mask = 1 << index;
 
                if (mask & XCHAL_INTTYPE_MASK_SOFTWARE)
-                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
                                                 handle_simple_irq);
 
                else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE)
-                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
                                                 handle_edge_irq);
 
                else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL)
-                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
                                                 handle_level_irq);
 
                else if (mask & XCHAL_INTTYPE_MASK_TIMER)
-                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
                                                 handle_edge_irq);
 
                else    /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
                        /* XCHAL_INTTYPE_MASK_NMI */
 
-                       set_irq_chip_and_handler(index, &xtensa_irq_chip,
+                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
                                                 handle_level_irq);
        }
 
index 65333ffefb079431451c4fc5aa9f3dc011ce3d69..4f4fc971042fb0992c73b4c2b1d1750e564c1c23 100644 (file)
@@ -120,7 +120,7 @@ static int __init prepare_phy_irq(int pin)
        irq = gpio_to_irq(pin);
        if (irq < 0)
                goto free;
-       if (set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0)
+       if (irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0)
                goto free;
        return irq;
 free:
index 380a70fff756b3e561200126bb9b5a87b671c866..7af0757e001b066e26164406f6e8b0725e44f13f 100644 (file)
@@ -85,30 +85,29 @@ int s6_gpio_init(u32 afsel)
        return gpiochip_add(&gpiochip);
 }
 
-static void ack(unsigned int irq)
+static void ack(struct irq_data *d)
 {
-       writeb(1 << (irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC);
+       writeb(1 << (d->irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC);
 }
 
-static void mask(unsigned int irq)
+static void mask(struct irq_data *d)
 {
        u8 r = readb(S6_REG_GPIO + S6_GPIO_IE);
-       r &= ~(1 << (irq - IRQ_BASE));
+       r &= ~(1 << (d->irq - IRQ_BASE));
        writeb(r, S6_REG_GPIO + S6_GPIO_IE);
 }
 
-static void unmask(unsigned int irq)
+static void unmask(struct irq_data *d)
 {
        u8 m = readb(S6_REG_GPIO + S6_GPIO_IE);
-       m |= 1 << (irq - IRQ_BASE);
+       m |= 1 << (d->irq - IRQ_BASE);
        writeb(m, S6_REG_GPIO + S6_GPIO_IE);
 }
 
-static int set_type(unsigned int irq, unsigned int type)
+static int set_type(struct irq_data *d, unsigned int type)
 {
-       const u8 m = 1 << (irq - IRQ_BASE);
+       const u8 m = 1 << (d->irq - IRQ_BASE);
        irq_flow_handler_t handler;
-       struct irq_desc *desc;
        u8 reg;
 
        if (type == IRQ_TYPE_PROBE) {
@@ -129,8 +128,7 @@ static int set_type(unsigned int irq, unsigned int type)
                handler = handle_edge_irq;
        }
        writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS);
-       desc = irq_to_desc(irq);
-       desc->handle_irq = handler;
+       __irq_set_handler_locked(irq, handler);
 
        reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV);
        if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING))
@@ -150,22 +148,23 @@ static int set_type(unsigned int irq, unsigned int type)
 
 static struct irq_chip gpioirqs = {
        .name = "GPIO",
-       .ack = ack,
-       .mask = mask,
-       .unmask = unmask,
-       .set_type = set_type,
+       .irq_ack = ack,
+       .irq_mask = mask,
+       .irq_unmask = unmask,
+       .irq_set_type = set_type,
 };
 
 static u8 demux_masks[4];
 
 static void demux_irqs(unsigned int irq, struct irq_desc *desc)
 {
-       u8 *mask = get_irq_desc_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       u8 *mask = irq_desc_get_handler_data(desc);
        u8 pending;
        int cirq;
 
-       desc->chip->mask(irq);
-       desc->chip->ack(irq);
+       chip->irq_mask(&desc->irq_data);
+       chip->irq_ack(&desc->irq_data));
        pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask;
        cirq = IRQ_BASE - 1;
        while (pending) {
@@ -174,7 +173,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc)
                pending >>= n;
                generic_handle_irq(cirq);
        }
-       desc->chip->unmask(irq);
+       chip->irq_unmask(&desc->irq_data));
 }
 
 extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS];
@@ -219,11 +218,11 @@ void __init variant_init_irq(void)
                                i = ffs(mask);
                                cirq += i;
                                mask >>= i;
-                               set_irq_chip(cirq, &gpioirqs);
-                               set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+                               irq_set_chip(cirq, &gpioirqs);
+                               irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
                        } while (mask);
-                       set_irq_data(irq, demux_masks + n);
-                       set_irq_chained_handler(irq, demux_irqs);
+                       irq_set_handler_data(irq, demux_masks + n);
+                       irq_set_chained_handler(irq, demux_irqs);
                        if (++n == ARRAY_SIZE(demux_masks))
                                break;
                }
index 455768a3eb9e8c916747024bc6cdfba101ab9919..2bef5705ce249d474a5d51dbab84b5c516383095 100644 (file)
@@ -371,12 +371,14 @@ void blkiocg_update_io_remove_stats(struct blkio_group *blkg,
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_io_remove_stats);
 
-void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time)
+void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time,
+                               unsigned long unaccounted_time)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&blkg->stats_lock, flags);
        blkg->stats.time += time;
+       blkg->stats.unaccounted_time += unaccounted_time;
        spin_unlock_irqrestore(&blkg->stats_lock, flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
@@ -604,6 +606,9 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
                return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
                                        blkg->stats.sectors, cb, dev);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
+       if (type == BLKIO_STAT_UNACCOUNTED_TIME)
+               return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
+                                       blkg->stats.unaccounted_time, cb, dev);
        if (type == BLKIO_STAT_AVG_QUEUE_SIZE) {
                uint64_t sum = blkg->stats.avg_queue_size_sum;
                uint64_t samples = blkg->stats.avg_queue_size_samples;
@@ -1125,6 +1130,9 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                        return blkio_read_blkg_stats(blkcg, cft, cb,
                                                BLKIO_STAT_QUEUED, 1);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
+               case BLKIO_PROP_unaccounted_time:
+                       return blkio_read_blkg_stats(blkcg, cft, cb,
+                                               BLKIO_STAT_UNACCOUNTED_TIME, 0);
                case BLKIO_PROP_dequeue:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
                                                BLKIO_STAT_DEQUEUE, 0);
@@ -1382,6 +1390,12 @@ struct cftype blkio_files[] = {
                                BLKIO_PROP_dequeue),
                .read_map = blkiocg_file_read_map,
        },
+       {
+               .name = "unaccounted_time",
+               .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+                               BLKIO_PROP_unaccounted_time),
+               .read_map = blkiocg_file_read_map,
+       },
 #endif
 };
 
index ea4861bdd549a58fb3884eab94c1c2395bae243a..10919fae2d3aa2e6ebc1e3cdc2d1636939c997ad 100644 (file)
@@ -49,6 +49,8 @@ enum stat_type {
        /* All the single valued stats go below this */
        BLKIO_STAT_TIME,
        BLKIO_STAT_SECTORS,
+       /* Time not charged to this cgroup */
+       BLKIO_STAT_UNACCOUNTED_TIME,
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        BLKIO_STAT_AVG_QUEUE_SIZE,
        BLKIO_STAT_IDLE_TIME,
@@ -81,6 +83,7 @@ enum blkcg_file_name_prop {
        BLKIO_PROP_io_serviced,
        BLKIO_PROP_time,
        BLKIO_PROP_sectors,
+       BLKIO_PROP_unaccounted_time,
        BLKIO_PROP_io_service_time,
        BLKIO_PROP_io_wait_time,
        BLKIO_PROP_io_merged,
@@ -114,6 +117,8 @@ struct blkio_group_stats {
        /* total disk time and nr sectors dispatched by this group */
        uint64_t time;
        uint64_t sectors;
+       /* Time not charged to this cgroup */
+       uint64_t unaccounted_time;
        uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        /* Sum of number of IOs queued across all samples */
@@ -240,7 +245,7 @@ static inline char *blkg_path(struct blkio_group *blkg) { return NULL; }
 
 #endif
 
-#define BLKIO_WEIGHT_MIN       100
+#define BLKIO_WEIGHT_MIN       10
 #define BLKIO_WEIGHT_MAX       1000
 #define BLKIO_WEIGHT_DEFAULT   500
 
@@ -293,7 +298,8 @@ extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
 extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
                                                void *key);
 void blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                                       unsigned long time);
+                                       unsigned long time,
+                                       unsigned long unaccounted_time);
 void blkiocg_update_dispatch_stats(struct blkio_group *blkg, uint64_t bytes,
                                                bool direction, bool sync);
 void blkiocg_update_completion_stats(struct blkio_group *blkg,
@@ -319,7 +325,9 @@ blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
 static inline struct blkio_group *
 blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key) { return NULL; }
 static inline void blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                                               unsigned long time) {}
+                                               unsigned long time,
+                                               unsigned long unaccounted_time)
+{}
 static inline void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
                                uint64_t bytes, bool direction, bool sync) {}
 static inline void blkiocg_update_completion_stats(struct blkio_group *blkg,
index a63336d49f3004919fda91d13e4f7087789fd184..e0a062363937291e2a9b82602b296bd8e6e2602a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/writeback.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/fault-inject.h>
+#include <linux/list_sort.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/block.h>
@@ -149,39 +150,29 @@ EXPORT_SYMBOL(blk_rq_init);
 static void req_bio_endio(struct request *rq, struct bio *bio,
                          unsigned int nbytes, int error)
 {
-       struct request_queue *q = rq->q;
-
-       if (&q->flush_rq != rq) {
-               if (error)
-                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
-               else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-                       error = -EIO;
+       if (error)
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+               error = -EIO;
 
-               if (unlikely(nbytes > bio->bi_size)) {
-                       printk(KERN_ERR "%s: want %u bytes done, %u left\n",
-                              __func__, nbytes, bio->bi_size);
-                       nbytes = bio->bi_size;
-               }
+       if (unlikely(nbytes > bio->bi_size)) {
+               printk(KERN_ERR "%s: want %u bytes done, %u left\n",
+                      __func__, nbytes, bio->bi_size);
+               nbytes = bio->bi_size;
+       }
 
-               if (unlikely(rq->cmd_flags & REQ_QUIET))
-                       set_bit(BIO_QUIET, &bio->bi_flags);
+       if (unlikely(rq->cmd_flags & REQ_QUIET))
+               set_bit(BIO_QUIET, &bio->bi_flags);
 
-               bio->bi_size -= nbytes;
-               bio->bi_sector += (nbytes >> 9);
+       bio->bi_size -= nbytes;
+       bio->bi_sector += (nbytes >> 9);
 
-               if (bio_integrity(bio))
-                       bio_integrity_advance(bio, nbytes);
+       if (bio_integrity(bio))
+               bio_integrity_advance(bio, nbytes);
 
-               if (bio->bi_size == 0)
-                       bio_endio(bio, error);
-       } else {
-               /*
-                * Okay, this is the sequenced flush request in
-                * progress, just record the error;
-                */
-               if (error && !q->flush_err)
-                       q->flush_err = error;
-       }
+       /* don't actually finish bio if it's part of flush sequence */
+       if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
+               bio_endio(bio, error);
 }
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
@@ -208,135 +199,43 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
 EXPORT_SYMBOL(blk_dump_rq_flags);
 
 /*
- * "plug" the device if there are no outstanding requests: this will
- * force the transfer to start only after we have put all the requests
- * on the list.
- *
- * This is called with interrupts off and no requests on the queue and
- * with the queue lock held.
- */
-void blk_plug_device(struct request_queue *q)
+ * Make sure that plugs that were pending when this function was entered,
+ * are now complete and requests pushed to the queue.
+*/
+static inline void queue_sync_plugs(struct request_queue *q)
 {
-       WARN_ON(!irqs_disabled());
-
        /*
-        * don't plug a stopped queue, it must be paired with blk_start_queue()
-        * which will restart the queueing
+        * If the current process is plugged and has barriers submitted,
+        * we will livelock if we don't unplug first.
         */
-       if (blk_queue_stopped(q))
-               return;
-
-       if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) {
-               mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
-               trace_block_plug(q);
-       }
-}
-EXPORT_SYMBOL(blk_plug_device);
-
-/**
- * blk_plug_device_unlocked - plug a device without queue lock held
- * @q:    The &struct request_queue to plug
- *
- * Description:
- *   Like @blk_plug_device(), but grabs the queue lock and disables
- *   interrupts.
- **/
-void blk_plug_device_unlocked(struct request_queue *q)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-       blk_plug_device(q);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-}
-EXPORT_SYMBOL(blk_plug_device_unlocked);
-
-/*
- * remove the queue from the plugged list, if present. called with
- * queue lock held and interrupts disabled.
- */
-int blk_remove_plug(struct request_queue *q)
-{
-       WARN_ON(!irqs_disabled());
-
-       if (!queue_flag_test_and_clear(QUEUE_FLAG_PLUGGED, q))
-               return 0;
-
-       del_timer(&q->unplug_timer);
-       return 1;
+       blk_flush_plug(current);
 }
-EXPORT_SYMBOL(blk_remove_plug);
 
-/*
- * remove the plug and let it rip..
- */
-void __generic_unplug_device(struct request_queue *q)
+static void blk_delay_work(struct work_struct *work)
 {
-       if (unlikely(blk_queue_stopped(q)))
-               return;
-       if (!blk_remove_plug(q) && !blk_queue_nonrot(q))
-               return;
+       struct request_queue *q;
 
-       q->request_fn(q);
+       q = container_of(work, struct request_queue, delay_work.work);
+       spin_lock_irq(q->queue_lock);
+       __blk_run_queue(q, false);
+       spin_unlock_irq(q->queue_lock);
 }
 
 /**
- * generic_unplug_device - fire a request queue
- * @q:    The &struct request_queue in question
+ * blk_delay_queue - restart queueing after defined interval
+ * @q:         The &struct request_queue in question
+ * @msecs:     Delay in msecs
  *
  * Description:
- *   Linux uses plugging to build bigger requests queues before letting
- *   the device have at them. If a queue is plugged, the I/O scheduler
- *   is still adding and merging requests on the queue. Once the queue
- *   gets unplugged, the request_fn defined for the queue is invoked and
- *   transfers started.
- **/
-void generic_unplug_device(struct request_queue *q)
-{
-       if (blk_queue_plugged(q)) {
-               spin_lock_irq(q->queue_lock);
-               __generic_unplug_device(q);
-               spin_unlock_irq(q->queue_lock);
-       }
-}
-EXPORT_SYMBOL(generic_unplug_device);
-
-static void blk_backing_dev_unplug(struct backing_dev_info *bdi,
-                                  struct page *page)
-{
-       struct request_queue *q = bdi->unplug_io_data;
-
-       blk_unplug(q);
-}
-
-void blk_unplug_work(struct work_struct *work)
-{
-       struct request_queue *q =
-               container_of(work, struct request_queue, unplug_work);
-
-       trace_block_unplug_io(q);
-       q->unplug_fn(q);
-}
-
-void blk_unplug_timeout(unsigned long data)
-{
-       struct request_queue *q = (struct request_queue *)data;
-
-       trace_block_unplug_timer(q);
-       kblockd_schedule_work(q, &q->unplug_work);
-}
-
-void blk_unplug(struct request_queue *q)
+ *   Sometimes queueing needs to be postponed for a little while, to allow
+ *   resources to come back. This function will make sure that queueing is
+ *   restarted around the specified time.
+ */
+void blk_delay_queue(struct request_queue *q, unsigned long msecs)
 {
-       /*
-        * devices don't necessarily have an ->unplug_fn defined
-        */
-       if (q->unplug_fn) {
-               trace_block_unplug_io(q);
-               q->unplug_fn(q);
-       }
+       schedule_delayed_work(&q->delay_work, msecs_to_jiffies(msecs));
 }
-EXPORT_SYMBOL(blk_unplug);
+EXPORT_SYMBOL(blk_delay_queue);
 
 /**
  * blk_start_queue - restart a previously stopped queue
@@ -372,7 +271,7 @@ EXPORT_SYMBOL(blk_start_queue);
  **/
 void blk_stop_queue(struct request_queue *q)
 {
-       blk_remove_plug(q);
+       __cancel_delayed_work(&q->delay_work);
        queue_flag_set(QUEUE_FLAG_STOPPED, q);
 }
 EXPORT_SYMBOL(blk_stop_queue);
@@ -390,13 +289,16 @@ EXPORT_SYMBOL(blk_stop_queue);
  *     that its ->make_request_fn will not re-add plugging prior to calling
  *     this function.
  *
+ *     This function does not cancel any asynchronous activity arising
+ *     out of elevator or throttling code. That would require elevaotor_exit()
+ *     and blk_throtl_exit() to be called with queue lock initialized.
+ *
  */
 void blk_sync_queue(struct request_queue *q)
 {
-       del_timer_sync(&q->unplug_timer);
        del_timer_sync(&q->timeout);
-       cancel_work_sync(&q->unplug_work);
-       throtl_shutdown_timer_wq(q);
+       cancel_delayed_work_sync(&q->delay_work);
+       queue_sync_plugs(q);
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -412,14 +314,9 @@ EXPORT_SYMBOL(blk_sync_queue);
  */
 void __blk_run_queue(struct request_queue *q, bool force_kblockd)
 {
-       blk_remove_plug(q);
-
        if (unlikely(blk_queue_stopped(q)))
                return;
 
-       if (elv_queue_empty(q))
-               return;
-
        /*
         * Only recurse once to avoid overrunning the stack, let the unplug
         * handling reinvoke the handler shortly if we already got there.
@@ -427,10 +324,8 @@ void __blk_run_queue(struct request_queue *q, bool force_kblockd)
        if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
                q->request_fn(q);
                queue_flag_clear(QUEUE_FLAG_REENTER, q);
-       } else {
-               queue_flag_set(QUEUE_FLAG_PLUGGED, q);
-               kblockd_schedule_work(q, &q->unplug_work);
-       }
+       } else
+               queue_delayed_work(kblockd_workqueue, &q->delay_work, 0);
 }
 EXPORT_SYMBOL(__blk_run_queue);
 
@@ -457,6 +352,11 @@ void blk_put_queue(struct request_queue *q)
        kobject_put(&q->kobj);
 }
 
+/*
+ * Note: If a driver supplied the queue lock, it should not zap that lock
+ * unexpectedly as some queue cleanup components like elevator_exit() and
+ * blk_throtl_exit() need queue lock.
+ */
 void blk_cleanup_queue(struct request_queue *q)
 {
        /*
@@ -475,6 +375,8 @@ void blk_cleanup_queue(struct request_queue *q)
        if (q->elevator)
                elevator_exit(q->elevator);
 
+       blk_throtl_exit(q);
+
        blk_put_queue(q);
 }
 EXPORT_SYMBOL(blk_cleanup_queue);
@@ -517,8 +419,6 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        if (!q)
                return NULL;
 
-       q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug;
-       q->backing_dev_info.unplug_io_data = q;
        q->backing_dev_info.ra_pages =
                        (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
        q->backing_dev_info.state = 0;
@@ -538,17 +438,24 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
                    laptop_mode_timer_fn, (unsigned long) q);
-       init_timer(&q->unplug_timer);
        setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
        INIT_LIST_HEAD(&q->timeout_list);
-       INIT_LIST_HEAD(&q->pending_flushes);
-       INIT_WORK(&q->unplug_work, blk_unplug_work);
+       INIT_LIST_HEAD(&q->flush_queue[0]);
+       INIT_LIST_HEAD(&q->flush_queue[1]);
+       INIT_LIST_HEAD(&q->flush_data_in_flight);
+       INIT_DELAYED_WORK(&q->delay_work, blk_delay_work);
 
        kobject_init(&q->kobj, &blk_queue_ktype);
 
        mutex_init(&q->sysfs_lock);
        spin_lock_init(&q->__queue_lock);
 
+       /*
+        * By default initialize queue_lock to internal lock and driver can
+        * override it later if need be.
+        */
+       q->queue_lock = &q->__queue_lock;
+
        return q;
 }
 EXPORT_SYMBOL(blk_alloc_queue_node);
@@ -631,9 +538,11 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
        q->request_fn           = rfn;
        q->prep_rq_fn           = NULL;
        q->unprep_rq_fn         = NULL;
-       q->unplug_fn            = generic_unplug_device;
        q->queue_flags          = QUEUE_FLAG_DEFAULT;
-       q->queue_lock           = lock;
+
+       /* Override internal queue lock with supplied lock pointer */
+       if (lock)
+               q->queue_lock           = lock;
 
        /*
         * This also sets hw/phys segments, boundary and size
@@ -666,6 +575,8 @@ int blk_get_queue(struct request_queue *q)
 
 static inline void blk_free_request(struct request_queue *q, struct request *rq)
 {
+       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
+
        if (rq->cmd_flags & REQ_ELVPRIV)
                elv_put_request(q, rq);
        mempool_free(rq, q->rq.rq_pool);
@@ -761,6 +672,25 @@ static void freed_request(struct request_queue *q, int sync, int priv)
                __freed_request(q, sync ^ 1);
 }
 
+/*
+ * Determine if elevator data should be initialized when allocating the
+ * request associated with @bio.
+ */
+static bool blk_rq_should_init_elevator(struct bio *bio)
+{
+       if (!bio)
+               return true;
+
+       /*
+        * Flush requests do not use the elevator so skip initialization.
+        * This allows a request to share the flush and elevator data.
+        */
+       if (bio->bi_rw & (REQ_FLUSH | REQ_FUA))
+               return false;
+
+       return true;
+}
+
 /*
  * Get a free request, queue_lock must be held.
  * Returns NULL on failure, with queue_lock held.
@@ -773,7 +703,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
        struct request_list *rl = &q->rq;
        struct io_context *ioc = NULL;
        const bool is_sync = rw_is_sync(rw_flags) != 0;
-       int may_queue, priv;
+       int may_queue, priv = 0;
 
        may_queue = elv_may_queue(q, rw_flags);
        if (may_queue == ELV_MQUEUE_NO)
@@ -817,9 +747,11 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
        rl->count[is_sync]++;
        rl->starved[is_sync] = 0;
 
-       priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
-       if (priv)
-               rl->elvpriv++;
+       if (blk_rq_should_init_elevator(bio)) {
+               priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+               if (priv)
+                       rl->elvpriv++;
+       }
 
        if (blk_queue_io_stat(q))
                rw_flags |= REQ_IO_STAT;
@@ -866,8 +798,8 @@ out:
 }
 
 /*
- * No available requests for this queue, unplug the device and wait for some
- * requests to become available.
+ * No available requests for this queue, wait for some requests to become
+ * available.
  *
  * Called with q->queue_lock held, and returns with it unlocked.
  */
@@ -888,7 +820,6 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags,
 
                trace_block_sleeprq(q, bio, rw_flags & 1);
 
-               __generic_unplug_device(q);
                spin_unlock_irq(q->queue_lock);
                io_schedule();
 
@@ -1010,6 +941,13 @@ void blk_requeue_request(struct request_queue *q, struct request *rq)
 }
 EXPORT_SYMBOL(blk_requeue_request);
 
+static void add_acct_request(struct request_queue *q, struct request *rq,
+                            int where)
+{
+       drive_stat_acct(rq, 1);
+       __elv_add_request(q, rq, where);
+}
+
 /**
  * blk_insert_request - insert a special request into a request queue
  * @q:         request queue where request should be inserted
@@ -1052,8 +990,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
        if (blk_rq_tagged(rq))
                blk_queue_end_tag(q, rq);
 
-       drive_stat_acct(rq, 1);
-       __elv_add_request(q, rq, where, 0);
+       add_acct_request(q, rq, where);
        __blk_run_queue(q, false);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
@@ -1174,6 +1111,113 @@ void blk_add_request_payload(struct request *rq, struct page *page,
 }
 EXPORT_SYMBOL_GPL(blk_add_request_payload);
 
+static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
+                                  struct bio *bio)
+{
+       const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
+
+       /*
+        * Debug stuff, kill later
+        */
+       if (!rq_mergeable(req)) {
+               blk_dump_rq_flags(req, "back");
+               return false;
+       }
+
+       if (!ll_back_merge_fn(q, req, bio))
+               return false;
+
+       trace_block_bio_backmerge(q, bio);
+
+       if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
+               blk_rq_set_mixed_merge(req);
+
+       req->biotail->bi_next = bio;
+       req->biotail = bio;
+       req->__data_len += bio->bi_size;
+       req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
+
+       drive_stat_acct(req, 0);
+       return true;
+}
+
+static bool bio_attempt_front_merge(struct request_queue *q,
+                                   struct request *req, struct bio *bio)
+{
+       const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
+       sector_t sector;
+
+       /*
+        * Debug stuff, kill later
+        */
+       if (!rq_mergeable(req)) {
+               blk_dump_rq_flags(req, "front");
+               return false;
+       }
+
+       if (!ll_front_merge_fn(q, req, bio))
+               return false;
+
+       trace_block_bio_frontmerge(q, bio);
+
+       if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
+               blk_rq_set_mixed_merge(req);
+
+       sector = bio->bi_sector;
+
+       bio->bi_next = req->bio;
+       req->bio = bio;
+
+       /*
+        * may not be valid. if the low level driver said
+        * it didn't need a bounce buffer then it better
+        * not touch req->buffer either...
+        */
+       req->buffer = bio_data(bio);
+       req->__sector = bio->bi_sector;
+       req->__data_len += bio->bi_size;
+       req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
+
+       drive_stat_acct(req, 0);
+       return true;
+}
+
+/*
+ * Attempts to merge with the plugged list in the current process. Returns
+ * true if merge was succesful, otherwise false.
+ */
+static bool attempt_plug_merge(struct task_struct *tsk, struct request_queue *q,
+                              struct bio *bio)
+{
+       struct blk_plug *plug;
+       struct request *rq;
+       bool ret = false;
+
+       plug = tsk->plug;
+       if (!plug)
+               goto out;
+
+       list_for_each_entry_reverse(rq, &plug->list, queuelist) {
+               int el_ret;
+
+               if (rq->q != q)
+                       continue;
+
+               el_ret = elv_try_merge(rq, bio);
+               if (el_ret == ELEVATOR_BACK_MERGE) {
+                       ret = bio_attempt_back_merge(q, rq, bio);
+                       if (ret)
+                               break;
+               } else if (el_ret == ELEVATOR_FRONT_MERGE) {
+                       ret = bio_attempt_front_merge(q, rq, bio);
+                       if (ret)
+                               break;
+               }
+       }
+out:
+       return ret;
+}
+
 void init_request_from_bio(struct request *req, struct bio *bio)
 {
        req->cpu = bio->bi_comp_cpu;
@@ -1189,26 +1233,12 @@ void init_request_from_bio(struct request *req, struct bio *bio)
        blk_rq_bio_prep(req->q, req, bio);
 }
 
-/*
- * Only disabling plugging for non-rotational devices if it does tagging
- * as well, otherwise we do need the proper merging
- */
-static inline bool queue_should_plug(struct request_queue *q)
-{
-       return !(blk_queue_nonrot(q) && blk_queue_tagged(q));
-}
-
 static int __make_request(struct request_queue *q, struct bio *bio)
 {
-       struct request *req;
-       int el_ret;
-       unsigned int bytes = bio->bi_size;
-       const unsigned short prio = bio_prio(bio);
        const bool sync = !!(bio->bi_rw & REQ_SYNC);
-       const bool unplug = !!(bio->bi_rw & REQ_UNPLUG);
-       const unsigned long ff = bio->bi_rw & REQ_FAILFAST_MASK;
-       int where = ELEVATOR_INSERT_SORT;
-       int rw_flags;
+       struct blk_plug *plug;
+       int el_ret, rw_flags, where = ELEVATOR_INSERT_SORT;
+       struct request *req;
 
        /*
         * low level driver can indicate that it wants pages above a
@@ -1217,78 +1247,36 @@ static int __make_request(struct request_queue *q, struct bio *bio)
         */
        blk_queue_bounce(q, &bio);
 
-       spin_lock_irq(q->queue_lock);
-
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
-               where = ELEVATOR_INSERT_FRONT;
+               spin_lock_irq(q->queue_lock);
+               where = ELEVATOR_INSERT_FLUSH;
                goto get_rq;
        }
 
-       if (elv_queue_empty(q))
-               goto get_rq;
-
-       el_ret = elv_merge(q, &req, bio);
-       switch (el_ret) {
-       case ELEVATOR_BACK_MERGE:
-               BUG_ON(!rq_mergeable(req));
-
-               if (!ll_back_merge_fn(q, req, bio))
-                       break;
-
-               trace_block_bio_backmerge(q, bio);
-
-               if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
-                       blk_rq_set_mixed_merge(req);
-
-               req->biotail->bi_next = bio;
-               req->biotail = bio;
-               req->__data_len += bytes;
-               req->ioprio = ioprio_best(req->ioprio, prio);
-               if (!blk_rq_cpu_valid(req))
-                       req->cpu = bio->bi_comp_cpu;
-               drive_stat_acct(req, 0);
-               elv_bio_merged(q, req, bio);
-               if (!attempt_back_merge(q, req))
-                       elv_merged_request(q, req, el_ret);
+       /*
+        * Check if we can merge with the plugged list before grabbing
+        * any locks.
+        */
+       if (attempt_plug_merge(current, q, bio))
                goto out;
 
-       case ELEVATOR_FRONT_MERGE:
-               BUG_ON(!rq_mergeable(req));
-
-               if (!ll_front_merge_fn(q, req, bio))
-                       break;
-
-               trace_block_bio_frontmerge(q, bio);
+       spin_lock_irq(q->queue_lock);
 
-               if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) {
-                       blk_rq_set_mixed_merge(req);
-                       req->cmd_flags &= ~REQ_FAILFAST_MASK;
-                       req->cmd_flags |= ff;
+       el_ret = elv_merge(q, &req, bio);
+       if (el_ret == ELEVATOR_BACK_MERGE) {
+               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
+               if (bio_attempt_back_merge(q, req, bio)) {
+                       if (!attempt_back_merge(q, req))
+                               elv_merged_request(q, req, el_ret);
+                       goto out_unlock;
+               }
+       } else if (el_ret == ELEVATOR_FRONT_MERGE) {
+               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
+               if (bio_attempt_front_merge(q, req, bio)) {
+                       if (!attempt_front_merge(q, req))
+                               elv_merged_request(q, req, el_ret);
+                       goto out_unlock;
                }
-
-               bio->bi_next = req->bio;
-               req->bio = bio;
-
-               /*
-                * may not be valid. if the low level driver said
-                * it didn't need a bounce buffer then it better
-                * not touch req->buffer either...
-                */
-               req->buffer = bio_data(bio);
-               req->__sector = bio->bi_sector;
-               req->__data_len += bytes;
-               req->ioprio = ioprio_best(req->ioprio, prio);
-               if (!blk_rq_cpu_valid(req))
-                       req->cpu = bio->bi_comp_cpu;
-               drive_stat_acct(req, 0);
-               elv_bio_merged(q, req, bio);
-               if (!attempt_front_merge(q, req))
-                       elv_merged_request(q, req, el_ret);
-               goto out;
-
-       /* ELV_NO_MERGE: elevator says don't/can't merge. */
-       default:
-               ;
        }
 
 get_rq:
@@ -1315,20 +1303,35 @@ get_rq:
         */
        init_request_from_bio(req, bio);
 
-       spin_lock_irq(q->queue_lock);
        if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) ||
-           bio_flagged(bio, BIO_CPU_AFFINE))
-               req->cpu = blk_cpu_to_group(smp_processor_id());
-       if (queue_should_plug(q) && elv_queue_empty(q))
-               blk_plug_device(q);
-
-       /* insert the request into the elevator */
-       drive_stat_acct(req, 1);
-       __elv_add_request(q, req, where, 0);
+           bio_flagged(bio, BIO_CPU_AFFINE)) {
+               req->cpu = blk_cpu_to_group(get_cpu());
+               put_cpu();
+       }
+
+       plug = current->plug;
+       if (plug) {
+               if (!plug->should_sort && !list_empty(&plug->list)) {
+                       struct request *__rq;
+
+                       __rq = list_entry_rq(plug->list.prev);
+                       if (__rq->q != q)
+                               plug->should_sort = 1;
+               }
+               /*
+                * Debug flag, kill later
+                */
+               req->cmd_flags |= REQ_ON_PLUG;
+               list_add_tail(&req->queuelist, &plug->list);
+               drive_stat_acct(req, 1);
+       } else {
+               spin_lock_irq(q->queue_lock);
+               add_acct_request(q, req, where);
+               __blk_run_queue(q, false);
+out_unlock:
+               spin_unlock_irq(q->queue_lock);
+       }
 out:
-       if (unplug || !queue_should_plug(q))
-               __generic_unplug_device(q);
-       spin_unlock_irq(q->queue_lock);
        return 0;
 }
 
@@ -1731,9 +1734,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
         */
        BUG_ON(blk_queued_rq(rq));
 
-       drive_stat_acct(rq, 1);
-       __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0);
-
+       add_acct_request(q, rq, ELEVATOR_INSERT_BACK);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        return 0;
@@ -1805,7 +1806,7 @@ static void blk_account_io_done(struct request *req)
         * normal IO on queueing nor completion.  Accounting the
         * containing request is enough.
         */
-       if (blk_do_io_stat(req) && req != &req->q->flush_rq) {
+       if (blk_do_io_stat(req) && !(req->cmd_flags & REQ_FLUSH_SEQ)) {
                unsigned long duration = jiffies - req->start_time;
                const int rw = rq_data_dir(req);
                struct hd_struct *part;
@@ -2628,6 +2629,116 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
+int kblockd_schedule_delayed_work(struct request_queue *q,
+                       struct delayed_work *dwork, unsigned long delay)
+{
+       return queue_delayed_work(kblockd_workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(kblockd_schedule_delayed_work);
+
+#define PLUG_MAGIC     0x91827364
+
+void blk_start_plug(struct blk_plug *plug)
+{
+       struct task_struct *tsk = current;
+
+       plug->magic = PLUG_MAGIC;
+       INIT_LIST_HEAD(&plug->list);
+       plug->should_sort = 0;
+
+       /*
+        * If this is a nested plug, don't actually assign it. It will be
+        * flushed on its own.
+        */
+       if (!tsk->plug) {
+               /*
+                * Store ordering should not be needed here, since a potential
+                * preempt will imply a full memory barrier
+                */
+               tsk->plug = plug;
+       }
+}
+EXPORT_SYMBOL(blk_start_plug);
+
+static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+       struct request *rqa = container_of(a, struct request, queuelist);
+       struct request *rqb = container_of(b, struct request, queuelist);
+
+       return !(rqa->q == rqb->q);
+}
+
+static void flush_plug_list(struct blk_plug *plug)
+{
+       struct request_queue *q;
+       unsigned long flags;
+       struct request *rq;
+
+       BUG_ON(plug->magic != PLUG_MAGIC);
+
+       if (list_empty(&plug->list))
+               return;
+
+       if (plug->should_sort)
+               list_sort(NULL, &plug->list, plug_rq_cmp);
+
+       q = NULL;
+       local_irq_save(flags);
+       while (!list_empty(&plug->list)) {
+               rq = list_entry_rq(plug->list.next);
+               list_del_init(&rq->queuelist);
+               BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
+               BUG_ON(!rq->q);
+               if (rq->q != q) {
+                       if (q) {
+                               __blk_run_queue(q, false);
+                               spin_unlock(q->queue_lock);
+                       }
+                       q = rq->q;
+                       spin_lock(q->queue_lock);
+               }
+               rq->cmd_flags &= ~REQ_ON_PLUG;
+
+               /*
+                * rq is already accounted, so use raw insert
+                */
+               if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA))
+                       __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH);
+               else
+                       __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE);
+       }
+
+       if (q) {
+               __blk_run_queue(q, false);
+               spin_unlock(q->queue_lock);
+       }
+
+       BUG_ON(!list_empty(&plug->list));
+       local_irq_restore(flags);
+}
+
+static void __blk_finish_plug(struct task_struct *tsk, struct blk_plug *plug)
+{
+       flush_plug_list(plug);
+
+       if (plug == tsk->plug)
+               tsk->plug = NULL;
+}
+
+void blk_finish_plug(struct blk_plug *plug)
+{
+       if (plug)
+               __blk_finish_plug(current, plug);
+}
+EXPORT_SYMBOL(blk_finish_plug);
+
+void __blk_flush_plug(struct task_struct *tsk, struct blk_plug *plug)
+{
+       __blk_finish_plug(tsk, plug);
+       tsk->plug = plug;
+}
+EXPORT_SYMBOL(__blk_flush_plug);
+
 int __init blk_dev_init(void)
 {
        BUILD_BUG_ON(__REQ_NR_BITS > 8 *
index cf1456a02acdf7f4fc7fb924ff1153dcb4620c06..7482b7fa863ba10b337d7547fb7040767e02b2da 100644 (file)
@@ -54,8 +54,8 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        rq->end_io = done;
        WARN_ON(irqs_disabled());
        spin_lock_irq(q->queue_lock);
-       __elv_add_request(q, rq, where, 1);
-       __generic_unplug_device(q);
+       __elv_add_request(q, rq, where);
+       __blk_run_queue(q, false);
        /* the queue is stopped so it won't be plugged+unplugged */
        if (rq->cmd_type == REQ_TYPE_PM_RESUME)
                q->request_fn(q);
index b27d0208611b4d904e7fda9e4e66bd9a4c7411b4..93d5fd8e51ebfe1126746321af3a9f143831ac83 100644 (file)
@@ -1,6 +1,69 @@
 /*
  * Functions to sequence FLUSH and FUA writes.
+ *
+ * Copyright (C) 2011          Max Planck Institute for Gravitational Physics
+ * Copyright (C) 2011          Tejun Heo <tj@kernel.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ * REQ_{FLUSH|FUA} requests are decomposed to sequences consisted of three
+ * optional steps - PREFLUSH, DATA and POSTFLUSH - according to the request
+ * properties and hardware capability.
+ *
+ * If a request doesn't have data, only REQ_FLUSH makes sense, which
+ * indicates a simple flush request.  If there is data, REQ_FLUSH indicates
+ * that the device cache should be flushed before the data is executed, and
+ * REQ_FUA means that the data must be on non-volatile media on request
+ * completion.
+ *
+ * If the device doesn't have writeback cache, FLUSH and FUA don't make any
+ * difference.  The requests are either completed immediately if there's no
+ * data or executed as normal requests otherwise.
+ *
+ * If the device has writeback cache and supports FUA, REQ_FLUSH is
+ * translated to PREFLUSH but REQ_FUA is passed down directly with DATA.
+ *
+ * If the device has writeback cache and doesn't support FUA, REQ_FLUSH is
+ * translated to PREFLUSH and REQ_FUA to POSTFLUSH.
+ *
+ * The actual execution of flush is double buffered.  Whenever a request
+ * needs to execute PRE or POSTFLUSH, it queues at
+ * q->flush_queue[q->flush_pending_idx].  Once certain criteria are met, a
+ * flush is issued and the pending_idx is toggled.  When the flush
+ * completes, all the requests which were pending are proceeded to the next
+ * step.  This allows arbitrary merging of different types of FLUSH/FUA
+ * requests.
+ *
+ * Currently, the following conditions are used to determine when to issue
+ * flush.
+ *
+ * C1. At any given time, only one flush shall be in progress.  This makes
+ *     double buffering sufficient.
+ *
+ * C2. Flush is deferred if any request is executing DATA of its sequence.
+ *     This avoids issuing separate POSTFLUSHes for requests which shared
+ *     PREFLUSH.
+ *
+ * C3. The second condition is ignored if there is a request which has
+ *     waited longer than FLUSH_PENDING_TIMEOUT.  This is to avoid
+ *     starvation in the unlikely case where there are continuous stream of
+ *     FUA (without FLUSH) requests.
+ *
+ * For devices which support FUA, it isn't clear whether C2 (and thus C3)
+ * is beneficial.
+ *
+ * Note that a sequenced FLUSH/FUA request with DATA is completed twice.
+ * Once while executing DATA and again after the whole sequence is
+ * complete.  The first completion updates the contained bio but doesn't
+ * finish it so that the bio submitter is notified only after the whole
+ * sequence is complete.  This is implemented by testing REQ_FLUSH_SEQ in
+ * req_bio_endio().
+ *
+ * The above peculiarity requires that each FLUSH/FUA request has only one
+ * bio attached to it, which is guaranteed as they aren't allowed to be
+ * merged in the usual way.
  */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/bio.h>
 
 /* FLUSH/FUA sequences */
 enum {
-       QUEUE_FSEQ_STARTED      = (1 << 0), /* flushing in progress */
-       QUEUE_FSEQ_PREFLUSH     = (1 << 1), /* pre-flushing in progress */
-       QUEUE_FSEQ_DATA         = (1 << 2), /* data write in progress */
-       QUEUE_FSEQ_POSTFLUSH    = (1 << 3), /* post-flushing in progress */
-       QUEUE_FSEQ_DONE         = (1 << 4),
+       REQ_FSEQ_PREFLUSH       = (1 << 0), /* pre-flushing in progress */
+       REQ_FSEQ_DATA           = (1 << 1), /* data write in progress */
+       REQ_FSEQ_POSTFLUSH      = (1 << 2), /* post-flushing in progress */
+       REQ_FSEQ_DONE           = (1 << 3),
+
+       REQ_FSEQ_ACTIONS        = REQ_FSEQ_PREFLUSH | REQ_FSEQ_DATA |
+                                 REQ_FSEQ_POSTFLUSH,
+
+       /*
+        * If flush has been pending longer than the following timeout,
+        * it's issued even if flush_data requests are still in flight.
+        */
+       FLUSH_PENDING_TIMEOUT   = 5 * HZ,
 };
 
-static struct request *queue_next_fseq(struct request_queue *q);
+static bool blk_kick_flush(struct request_queue *q);
 
-unsigned blk_flush_cur_seq(struct request_queue *q)
+static unsigned int blk_flush_policy(unsigned int fflags, struct request *rq)
 {
-       if (!q->flush_seq)
-               return 0;
-       return 1 << ffz(q->flush_seq);
+       unsigned int policy = 0;
+
+       if (fflags & REQ_FLUSH) {
+               if (rq->cmd_flags & REQ_FLUSH)
+                       policy |= REQ_FSEQ_PREFLUSH;
+               if (blk_rq_sectors(rq))
+                       policy |= REQ_FSEQ_DATA;
+               if (!(fflags & REQ_FUA) && (rq->cmd_flags & REQ_FUA))
+                       policy |= REQ_FSEQ_POSTFLUSH;
+       }
+       return policy;
 }
 
-static struct request *blk_flush_complete_seq(struct request_queue *q,
-                                             unsigned seq, int error)
+static unsigned int blk_flush_cur_seq(struct request *rq)
 {
-       struct request *next_rq = NULL;
-
-       if (error && !q->flush_err)
-               q->flush_err = error;
-
-       BUG_ON(q->flush_seq & seq);
-       q->flush_seq |= seq;
-
-       if (blk_flush_cur_seq(q) != QUEUE_FSEQ_DONE) {
-               /* not complete yet, queue the next flush sequence */
-               next_rq = queue_next_fseq(q);
-       } else {
-               /* complete this flush request */
-               __blk_end_request_all(q->orig_flush_rq, q->flush_err);
-               q->orig_flush_rq = NULL;
-               q->flush_seq = 0;
-
-               /* dispatch the next flush if there's one */
-               if (!list_empty(&q->pending_flushes)) {
-                       next_rq = list_entry_rq(q->pending_flushes.next);
-                       list_move(&next_rq->queuelist, &q->queue_head);
-               }
+       return 1 << ffz(rq->flush.seq);
+}
+
+static void blk_flush_restore_request(struct request *rq)
+{
+       /*
+        * After flush data completion, @rq->bio is %NULL but we need to
+        * complete the bio again.  @rq->biotail is guaranteed to equal the
+        * original @rq->bio.  Restore it.
+        */
+       rq->bio = rq->biotail;
+
+       /* make @rq a normal request */
+       rq->cmd_flags &= ~REQ_FLUSH_SEQ;
+       rq->end_io = NULL;
+}
+
+/**
+ * blk_flush_complete_seq - complete flush sequence
+ * @rq: FLUSH/FUA request being sequenced
+ * @seq: sequences to complete (mask of %REQ_FSEQ_*, can be zero)
+ * @error: whether an error occurred
+ *
+ * @rq just completed @seq part of its flush sequence, record the
+ * completion and trigger the next step.
+ *
+ * CONTEXT:
+ * spin_lock_irq(q->queue_lock)
+ *
+ * RETURNS:
+ * %true if requests were added to the dispatch queue, %false otherwise.
+ */
+static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
+                                  int error)
+{
+       struct request_queue *q = rq->q;
+       struct list_head *pending = &q->flush_queue[q->flush_pending_idx];
+       bool queued = false;
+
+       BUG_ON(rq->flush.seq & seq);
+       rq->flush.seq |= seq;
+
+       if (likely(!error))
+               seq = blk_flush_cur_seq(rq);
+       else
+               seq = REQ_FSEQ_DONE;
+
+       switch (seq) {
+       case REQ_FSEQ_PREFLUSH:
+       case REQ_FSEQ_POSTFLUSH:
+               /* queue for flush */
+               if (list_empty(pending))
+                       q->flush_pending_since = jiffies;
+               list_move_tail(&rq->flush.list, pending);
+               break;
+
+       case REQ_FSEQ_DATA:
+               list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
+               list_add(&rq->queuelist, &q->queue_head);
+               queued = true;
+               break;
+
+       case REQ_FSEQ_DONE:
+               /*
+                * @rq was previously adjusted by blk_flush_issue() for
+                * flush sequencing and may already have gone through the
+                * flush data request completion path.  Restore @rq for
+                * normal completion and end it.
+                */
+               BUG_ON(!list_empty(&rq->queuelist));
+               list_del_init(&rq->flush.list);
+               blk_flush_restore_request(rq);
+               __blk_end_request_all(rq, error);
+               break;
+
+       default:
+               BUG();
        }
-       return next_rq;
+
+       return blk_kick_flush(q) | queued;
 }
 
-static void blk_flush_complete_seq_end_io(struct request_queue *q,
-                                         unsigned seq, int error)
+static void flush_end_io(struct request *flush_rq, int error)
 {
-       bool was_empty = elv_queue_empty(q);
-       struct request *next_rq;
+       struct request_queue *q = flush_rq->q;
+       struct list_head *running = &q->flush_queue[q->flush_running_idx];
+       bool queued = false;
+       struct request *rq, *n;
 
-       next_rq = blk_flush_complete_seq(q, seq, error);
+       BUG_ON(q->flush_pending_idx == q->flush_running_idx);
+
+       /* account completion of the flush request */
+       q->flush_running_idx ^= 1;
+       elv_completed_request(q, flush_rq);
+
+       /* and push the waiting requests to the next stage */
+       list_for_each_entry_safe(rq, n, running, flush.list) {
+               unsigned int seq = blk_flush_cur_seq(rq);
+
+               BUG_ON(seq != REQ_FSEQ_PREFLUSH && seq != REQ_FSEQ_POSTFLUSH);
+               queued |= blk_flush_complete_seq(rq, seq, error);
+       }
 
        /*
         * Moving a request silently to empty queue_head may stall the
@@ -70,127 +217,153 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q,
         * from request completion path and calling directly into
         * request_fn may confuse the driver.  Always use kblockd.
         */
-       if (was_empty && next_rq)
+       if (queued)
                __blk_run_queue(q, true);
 }
 
-static void pre_flush_end_io(struct request *rq, int error)
+/**
+ * blk_kick_flush - consider issuing flush request
+ * @q: request_queue being kicked
+ *
+ * Flush related states of @q have changed, consider issuing flush request.
+ * Please read the comment at the top of this file for more info.
+ *
+ * CONTEXT:
+ * spin_lock_irq(q->queue_lock)
+ *
+ * RETURNS:
+ * %true if flush was issued, %false otherwise.
+ */
+static bool blk_kick_flush(struct request_queue *q)
 {
-       elv_completed_request(rq->q, rq);
-       blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_PREFLUSH, error);
+       struct list_head *pending = &q->flush_queue[q->flush_pending_idx];
+       struct request *first_rq =
+               list_first_entry(pending, struct request, flush.list);
+
+       /* C1 described at the top of this file */
+       if (q->flush_pending_idx != q->flush_running_idx || list_empty(pending))
+               return false;
+
+       /* C2 and C3 */
+       if (!list_empty(&q->flush_data_in_flight) &&
+           time_before(jiffies,
+                       q->flush_pending_since + FLUSH_PENDING_TIMEOUT))
+               return false;
+
+       /*
+        * Issue flush and toggle pending_idx.  This makes pending_idx
+        * different from running_idx, which means flush is in flight.
+        */
+       blk_rq_init(q, &q->flush_rq);
+       q->flush_rq.cmd_type = REQ_TYPE_FS;
+       q->flush_rq.cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
+       q->flush_rq.rq_disk = first_rq->rq_disk;
+       q->flush_rq.end_io = flush_end_io;
+
+       q->flush_pending_idx ^= 1;
+       elv_insert(q, &q->flush_rq, ELEVATOR_INSERT_REQUEUE);
+       return true;
 }
 
 static void flush_data_end_io(struct request *rq, int error)
 {
-       elv_completed_request(rq->q, rq);
-       blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_DATA, error);
-}
+       struct request_queue *q = rq->q;
 
-static void post_flush_end_io(struct request *rq, int error)
-{
-       elv_completed_request(rq->q, rq);
-       blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_POSTFLUSH, error);
+       /*
+        * After populating an empty queue, kick it to avoid stall.  Read
+        * the comment in flush_end_io().
+        */
+       if (blk_flush_complete_seq(rq, REQ_FSEQ_DATA, error))
+               __blk_run_queue(q, true);
 }
 
-static void init_flush_request(struct request *rq, struct gendisk *disk)
+/**
+ * blk_insert_flush - insert a new FLUSH/FUA request
+ * @rq: request to insert
+ *
+ * To be called from elv_insert() for %ELEVATOR_INSERT_FLUSH insertions.
+ * @rq is being submitted.  Analyze what needs to be done and put it on the
+ * right queue.
+ *
+ * CONTEXT:
+ * spin_lock_irq(q->queue_lock)
+ */
+void blk_insert_flush(struct request *rq)
 {
-       rq->cmd_type = REQ_TYPE_FS;
-       rq->cmd_flags = WRITE_FLUSH;
-       rq->rq_disk = disk;
-}
+       struct request_queue *q = rq->q;
+       unsigned int fflags = q->flush_flags;   /* may change, cache */
+       unsigned int policy = blk_flush_policy(fflags, rq);
 
-static struct request *queue_next_fseq(struct request_queue *q)
-{
-       struct request *orig_rq = q->orig_flush_rq;
-       struct request *rq = &q->flush_rq;
+       BUG_ON(rq->end_io);
+       BUG_ON(!rq->bio || rq->bio != rq->biotail);
 
-       blk_rq_init(q, rq);
+       /*
+        * @policy now records what operations need to be done.  Adjust
+        * REQ_FLUSH and FUA for the driver.
+        */
+       rq->cmd_flags &= ~REQ_FLUSH;
+       if (!(fflags & REQ_FUA))
+               rq->cmd_flags &= ~REQ_FUA;
 
-       switch (blk_flush_cur_seq(q)) {
-       case QUEUE_FSEQ_PREFLUSH:
-               init_flush_request(rq, orig_rq->rq_disk);
-               rq->end_io = pre_flush_end_io;
-               break;
-       case QUEUE_FSEQ_DATA:
-               init_request_from_bio(rq, orig_rq->bio);
-               /*
-                * orig_rq->rq_disk may be different from
-                * bio->bi_bdev->bd_disk if orig_rq got here through
-                * remapping drivers.  Make sure rq->rq_disk points
-                * to the same one as orig_rq.
-                */
-               rq->rq_disk = orig_rq->rq_disk;
-               rq->cmd_flags &= ~(REQ_FLUSH | REQ_FUA);
-               rq->cmd_flags |= orig_rq->cmd_flags & (REQ_FLUSH | REQ_FUA);
-               rq->end_io = flush_data_end_io;
-               break;
-       case QUEUE_FSEQ_POSTFLUSH:
-               init_flush_request(rq, orig_rq->rq_disk);
-               rq->end_io = post_flush_end_io;
-               break;
-       default:
-               BUG();
+       /*
+        * If there's data but flush is not necessary, the request can be
+        * processed directly without going through flush machinery.  Queue
+        * for normal execution.
+        */
+       if ((policy & REQ_FSEQ_DATA) &&
+           !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
+               list_add(&rq->queuelist, &q->queue_head);
+               return;
        }
 
-       elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
-       return rq;
+       /*
+        * @rq should go through flush machinery.  Mark it part of flush
+        * sequence and submit for further processing.
+        */
+       memset(&rq->flush, 0, sizeof(rq->flush));
+       INIT_LIST_HEAD(&rq->flush.list);
+       rq->cmd_flags |= REQ_FLUSH_SEQ;
+       rq->end_io = flush_data_end_io;
+
+       blk_flush_complete_seq(rq, REQ_FSEQ_ACTIONS & ~policy, 0);
 }
 
-struct request *blk_do_flush(struct request_queue *q, struct request *rq)
+/**
+ * blk_abort_flushes - @q is being aborted, abort flush requests
+ * @q: request_queue being aborted
+ *
+ * To be called from elv_abort_queue().  @q is being aborted.  Prepare all
+ * FLUSH/FUA requests for abortion.
+ *
+ * CONTEXT:
+ * spin_lock_irq(q->queue_lock)
+ */
+void blk_abort_flushes(struct request_queue *q)
 {
-       unsigned int fflags = q->flush_flags; /* may change, cache it */
-       bool has_flush = fflags & REQ_FLUSH, has_fua = fflags & REQ_FUA;
-       bool do_preflush = has_flush && (rq->cmd_flags & REQ_FLUSH);
-       bool do_postflush = has_flush && !has_fua && (rq->cmd_flags & REQ_FUA);
-       unsigned skip = 0;
+       struct request *rq, *n;
+       int i;
 
        /*
-        * Special case.  If there's data but flush is not necessary,
-        * the request can be issued directly.
-        *
-        * Flush w/o data should be able to be issued directly too but
-        * currently some drivers assume that rq->bio contains
-        * non-zero data if it isn't NULL and empty FLUSH requests
-        * getting here usually have bio's without data.
+        * Requests in flight for data are already owned by the dispatch
+        * queue or the device driver.  Just restore for normal completion.
         */
-       if (blk_rq_sectors(rq) && !do_preflush && !do_postflush) {
-               rq->cmd_flags &= ~REQ_FLUSH;
-               if (!has_fua)
-                       rq->cmd_flags &= ~REQ_FUA;
-               return rq;
+       list_for_each_entry_safe(rq, n, &q->flush_data_in_flight, flush.list) {
+               list_del_init(&rq->flush.list);
+               blk_flush_restore_request(rq);
        }
 
        /*
-        * Sequenced flushes can't be processed in parallel.  If
-        * another one is already in progress, queue for later
-        * processing.
+        * We need to give away requests on flush queues.  Restore for
+        * normal completion and put them on the dispatch queue.
         */
-       if (q->flush_seq) {
-               list_move_tail(&rq->queuelist, &q->pending_flushes);
-               return NULL;
+       for (i = 0; i < ARRAY_SIZE(q->flush_queue); i++) {
+               list_for_each_entry_safe(rq, n, &q->flush_queue[i],
+                                        flush.list) {
+                       list_del_init(&rq->flush.list);
+                       blk_flush_restore_request(rq);
+                       list_add_tail(&rq->queuelist, &q->queue_head);
+               }
        }
-
-       /*
-        * Start a new flush sequence
-        */
-       q->flush_err = 0;
-       q->flush_seq |= QUEUE_FSEQ_STARTED;
-
-       /* adjust FLUSH/FUA of the original request and stash it away */
-       rq->cmd_flags &= ~REQ_FLUSH;
-       if (!has_fua)
-               rq->cmd_flags &= ~REQ_FUA;
-       blk_dequeue_request(rq);
-       q->orig_flush_rq = rq;
-
-       /* skip unneded sequences and return the first one */
-       if (!do_preflush)
-               skip |= QUEUE_FSEQ_PREFLUSH;
-       if (!blk_rq_sectors(rq))
-               skip |= QUEUE_FSEQ_DATA;
-       if (!do_postflush)
-               skip |= QUEUE_FSEQ_POSTFLUSH;
-       return blk_flush_complete_seq(q, skip, 0);
 }
 
 static void bio_end_flush(struct bio *bio, int err)
index bd3e8df4d5e2b45a0ae89d90de025cfbaa12eed9..25de73e4759b82d624c2a89b545baf6ea859f624 100644 (file)
@@ -136,8 +136,6 @@ static void bio_batch_end_io(struct bio *bio, int err)
  *
  * Description:
  *  Generate and issue number of bios with zerofiled pages.
- *  Send barrier at the beginning and at the end if requested. This guarantie
- *  correct request ordering. Empty barrier allow us to avoid post queue flush.
  */
 
 int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
index ea85e20d5e9462be965f3f117bd7c3efcf51aa57..cfcc37cb222b63722bc048814c0f392205d1a898 100644 (file)
@@ -465,3 +465,9 @@ int attempt_front_merge(struct request_queue *q, struct request *rq)
 
        return 0;
 }
+
+int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
+                         struct request *next)
+{
+       return attempt_merge(q, rq, next);
+}
index 36c8c1f2af18088fb5fa34f4889d2fead2556600..1fa7692935976f4e60393e8d7289acf1c56c74c3 100644 (file)
@@ -164,24 +164,9 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        blk_queue_congestion_threshold(q);
        q->nr_batching = BLK_BATCH_REQ;
 
-       q->unplug_thresh = 4;           /* hmm */
-       q->unplug_delay = msecs_to_jiffies(3);  /* 3 milliseconds */
-       if (q->unplug_delay == 0)
-               q->unplug_delay = 1;
-
-       q->unplug_timer.function = blk_unplug_timeout;
-       q->unplug_timer.data = (unsigned long)q;
-
        blk_set_default_limits(&q->limits);
        blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
 
-       /*
-        * If the caller didn't supply a lock, fall back to our embedded
-        * per-queue locks
-        */
-       if (!q->queue_lock)
-               q->queue_lock = &q->__queue_lock;
-
        /*
         * by default assume old behaviour and bounce for any highmem page
         */
index 41fb69150b4d3c6758b0f5da6ff2005d4d7a0a3f..261c75c665ae381a4c12dd444f7ed3b847c155a0 100644 (file)
@@ -471,8 +471,6 @@ static void blk_release_queue(struct kobject *kobj)
 
        blk_sync_queue(q);
 
-       blk_throtl_exit(q);
-
        if (rl->rq_pool)
                mempool_destroy(rl->rq_pool);
 
index e36cc10a346c83bfd233a0b71421486180518e2f..5352bdafbcf0fe6dcf761e6c1f4f36b12492f64e 100644 (file)
@@ -102,7 +102,7 @@ struct throtl_data
        /* Work for dispatching throttled bios */
        struct delayed_work throtl_work;
 
-       atomic_t limits_changed;
+       bool limits_changed;
 };
 
 enum tg_state_flags {
@@ -201,6 +201,7 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
        RB_CLEAR_NODE(&tg->rb_node);
        bio_list_init(&tg->bio_lists[0]);
        bio_list_init(&tg->bio_lists[1]);
+       td->limits_changed = false;
 
        /*
         * Take the initial reference that will be released on destroy
@@ -737,34 +738,36 @@ static void throtl_process_limit_change(struct throtl_data *td)
        struct throtl_grp *tg;
        struct hlist_node *pos, *n;
 
-       if (!atomic_read(&td->limits_changed))
+       if (!td->limits_changed)
                return;
 
-       throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed));
+       xchg(&td->limits_changed, false);
 
-       /*
-        * Make sure updates from throtl_update_blkio_group_read_bps() group
-        * of functions to tg->limits_changed are visible. We do not
-        * want update td->limits_changed to be visible but update to
-        * tg->limits_changed not being visible yet on this cpu. Hence
-        * the read barrier.
-        */
-       smp_rmb();
+       throtl_log(td, "limits changed");
 
        hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
-               if (throtl_tg_on_rr(tg) && tg->limits_changed) {
-                       throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
-                               " riops=%u wiops=%u", tg->bps[READ],
-                               tg->bps[WRITE], tg->iops[READ],
-                               tg->iops[WRITE]);
+               if (!tg->limits_changed)
+                       continue;
+
+               if (!xchg(&tg->limits_changed, false))
+                       continue;
+
+               throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
+                       " riops=%u wiops=%u", tg->bps[READ], tg->bps[WRITE],
+                       tg->iops[READ], tg->iops[WRITE]);
+
+               /*
+                * Restart the slices for both READ and WRITES. It
+                * might happen that a group's limit are dropped
+                * suddenly and we don't want to account recently
+                * dispatched IO with new low rate
+                */
+               throtl_start_new_slice(td, tg, 0);
+               throtl_start_new_slice(td, tg, 1);
+
+               if (throtl_tg_on_rr(tg))
                        tg_update_disptime(td, tg);
-                       tg->limits_changed = false;
-               }
        }
-
-       smp_mb__before_atomic_dec();
-       atomic_dec(&td->limits_changed);
-       smp_mb__after_atomic_dec();
 }
 
 /* Dispatch throttled bios. Should be called without queue lock held. */
@@ -774,6 +777,7 @@ static int throtl_dispatch(struct request_queue *q)
        unsigned int nr_disp = 0;
        struct bio_list bio_list_on_stack;
        struct bio *bio;
+       struct blk_plug plug;
 
        spin_lock_irq(q->queue_lock);
 
@@ -802,9 +806,10 @@ out:
         * immediate dispatch
         */
        if (nr_disp) {
+               blk_start_plug(&plug);
                while((bio = bio_list_pop(&bio_list_on_stack)))
                        generic_make_request(bio);
-               blk_unplug(q);
+               blk_finish_plug(&plug);
        }
        return nr_disp;
 }
@@ -825,7 +830,8 @@ throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay)
 
        struct delayed_work *dwork = &td->throtl_work;
 
-       if (total_nr_queued(td) > 0) {
+       /* schedule work if limits changed even if no bio is queued */
+       if (total_nr_queued(td) > 0 || td->limits_changed) {
                /*
                 * We might have a work scheduled to be executed in future.
                 * Cancel that and schedule a new one.
@@ -898,6 +904,15 @@ void throtl_unlink_blkio_group(void *key, struct blkio_group *blkg)
        spin_unlock_irqrestore(td->queue->queue_lock, flags);
 }
 
+static void throtl_update_blkio_group_common(struct throtl_data *td,
+                               struct throtl_grp *tg)
+{
+       xchg(&tg->limits_changed, true);
+       xchg(&td->limits_changed, true);
+       /* Schedule a work now to process the limit change */
+       throtl_schedule_delayed_work(td, 0);
+}
+
 /*
  * For all update functions, key should be a valid pointer because these
  * update functions are called under blkcg_lock, that means, blkg is
@@ -911,64 +926,43 @@ static void throtl_update_blkio_group_read_bps(void *key,
                                struct blkio_group *blkg, u64 read_bps)
 {
        struct throtl_data *td = key;
+       struct throtl_grp *tg = tg_of_blkg(blkg);
 
-       tg_of_blkg(blkg)->bps[READ] = read_bps;
-       /* Make sure read_bps is updated before setting limits_changed */
-       smp_wmb();
-       tg_of_blkg(blkg)->limits_changed = true;
-
-       /* Make sure tg->limits_changed is updated before td->limits_changed */
-       smp_mb__before_atomic_inc();
-       atomic_inc(&td->limits_changed);
-       smp_mb__after_atomic_inc();
-
-       /* Schedule a work now to process the limit change */
-       throtl_schedule_delayed_work(td, 0);
+       tg->bps[READ] = read_bps;
+       throtl_update_blkio_group_common(td, tg);
 }
 
 static void throtl_update_blkio_group_write_bps(void *key,
                                struct blkio_group *blkg, u64 write_bps)
 {
        struct throtl_data *td = key;
+       struct throtl_grp *tg = tg_of_blkg(blkg);
 
-       tg_of_blkg(blkg)->bps[WRITE] = write_bps;
-       smp_wmb();
-       tg_of_blkg(blkg)->limits_changed = true;
-       smp_mb__before_atomic_inc();
-       atomic_inc(&td->limits_changed);
-       smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td, 0);
+       tg->bps[WRITE] = write_bps;
+       throtl_update_blkio_group_common(td, tg);
 }
 
 static void throtl_update_blkio_group_read_iops(void *key,
                        struct blkio_group *blkg, unsigned int read_iops)
 {
        struct throtl_data *td = key;
+       struct throtl_grp *tg = tg_of_blkg(blkg);
 
-       tg_of_blkg(blkg)->iops[READ] = read_iops;
-       smp_wmb();
-       tg_of_blkg(blkg)->limits_changed = true;
-       smp_mb__before_atomic_inc();
-       atomic_inc(&td->limits_changed);
-       smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td, 0);
+       tg->iops[READ] = read_iops;
+       throtl_update_blkio_group_common(td, tg);
 }
 
 static void throtl_update_blkio_group_write_iops(void *key,
                        struct blkio_group *blkg, unsigned int write_iops)
 {
        struct throtl_data *td = key;
+       struct throtl_grp *tg = tg_of_blkg(blkg);
 
-       tg_of_blkg(blkg)->iops[WRITE] = write_iops;
-       smp_wmb();
-       tg_of_blkg(blkg)->limits_changed = true;
-       smp_mb__before_atomic_inc();
-       atomic_inc(&td->limits_changed);
-       smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td, 0);
+       tg->iops[WRITE] = write_iops;
+       throtl_update_blkio_group_common(td, tg);
 }
 
-void throtl_shutdown_timer_wq(struct request_queue *q)
+static void throtl_shutdown_wq(struct request_queue *q)
 {
        struct throtl_data *td = q->td;
 
@@ -1009,20 +1003,28 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
                /*
                 * There is already another bio queued in same dir. No
                 * need to update dispatch time.
-                * Still update the disptime if rate limits on this group
-                * were changed.
                 */
-               if (!tg->limits_changed)
-                       update_disptime = false;
-               else
-                       tg->limits_changed = false;
-
+               update_disptime = false;
                goto queue_bio;
+
        }
 
        /* Bio is with-in rate limit of group */
        if (tg_may_dispatch(td, tg, bio, NULL)) {
                throtl_charge_bio(tg, bio);
+
+               /*
+                * We need to trim slice even when bios are not being queued
+                * otherwise it might happen that a bio is not queued for
+                * a long time and slice keeps on extending and trim is not
+                * called for a long time. Now if limits are reduced suddenly
+                * we take into account all the IO dispatched so far at new
+                * low rate and * newly queued IO gets a really long dispatch
+                * time.
+                *
+                * So keep on trimming slice even if bio is not queued.
+                */
+               throtl_trim_slice(td, tg, rw);
                goto out;
        }
 
@@ -1058,7 +1060,7 @@ int blk_throtl_init(struct request_queue *q)
 
        INIT_HLIST_HEAD(&td->tg_list);
        td->tg_service_tree = THROTL_RB_ROOT;
-       atomic_set(&td->limits_changed, 0);
+       td->limits_changed = false;
 
        /* Init root group */
        tg = &td->root_tg;
@@ -1070,6 +1072,7 @@ int blk_throtl_init(struct request_queue *q)
        /* Practically unlimited BW */
        tg->bps[0] = tg->bps[1] = -1;
        tg->iops[0] = tg->iops[1] = -1;
+       td->limits_changed = false;
 
        /*
         * Set root group reference to 2. One reference will be dropped when
@@ -1102,7 +1105,7 @@ void blk_throtl_exit(struct request_queue *q)
 
        BUG_ON(!td);
 
-       throtl_shutdown_timer_wq(q);
+       throtl_shutdown_wq(q);
 
        spin_lock_irq(q->queue_lock);
        throtl_release_tgs(td);
@@ -1132,7 +1135,7 @@ void blk_throtl_exit(struct request_queue *q)
         * update limits through cgroup and another work got queued, cancel
         * it.
         */
-       throtl_shutdown_timer_wq(q);
+       throtl_shutdown_wq(q);
        throtl_td_free(td);
 }
 
index 2db8f32838e7336d1a53bbddc8a4c01ec0c3489f..c8db371a921d55760e2d9494c25a0f52c16bd659 100644 (file)
@@ -18,8 +18,6 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
 void blk_dequeue_request(struct request *rq);
 void __blk_queue_free_tags(struct request_queue *q);
 
-void blk_unplug_work(struct work_struct *work);
-void blk_unplug_timeout(unsigned long data);
 void blk_rq_timed_out_timer(unsigned long data);
 void blk_delete_timer(struct request *);
 void blk_add_timer(struct request *);
@@ -51,21 +49,17 @@ static inline void blk_clear_rq_complete(struct request *rq)
  */
 #define ELV_ON_HASH(rq)                (!hlist_unhashed(&(rq)->hash))
 
-struct request *blk_do_flush(struct request_queue *q, struct request *rq);
+void blk_insert_flush(struct request *rq);
+void blk_abort_flushes(struct request_queue *q);
 
 static inline struct request *__elv_next_request(struct request_queue *q)
 {
        struct request *rq;
 
        while (1) {
-               while (!list_empty(&q->queue_head)) {
+               if (!list_empty(&q->queue_head)) {
                        rq = list_entry_rq(q->queue_head.next);
-                       if (!(rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) ||
-                           rq == &q->flush_rq)
-                               return rq;
-                       rq = blk_do_flush(q, rq);
-                       if (rq)
-                               return rq;
+                       return rq;
                }
 
                if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
@@ -109,6 +103,8 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
                      struct bio *bio);
 int attempt_back_merge(struct request_queue *q, struct request *rq);
 int attempt_front_merge(struct request_queue *q, struct request *rq);
+int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
+                               struct request *next);
 void blk_recalc_rq_segments(struct request *rq);
 void blk_rq_set_mixed_merge(struct request *rq);
 
index ea83a4f0c27dfda658ee41d87979a2d57c58450d..7785169f3c8f86df03887fe98d9af988b260e8ea 100644 (file)
@@ -54,9 +54,9 @@ static const int cfq_hist_divisor = 4;
 #define CFQQ_SEEKY(cfqq)       (hweight32(cfqq->seek_history) > 32/8)
 
 #define RQ_CIC(rq)             \
-       ((struct cfq_io_context *) (rq)->elevator_private)
-#define RQ_CFQQ(rq)            (struct cfq_queue *) ((rq)->elevator_private2)
-#define RQ_CFQG(rq)            (struct cfq_group *) ((rq)->elevator_private3)
+       ((struct cfq_io_context *) (rq)->elevator_private[0])
+#define RQ_CFQQ(rq)            (struct cfq_queue *) ((rq)->elevator_private[1])
+#define RQ_CFQG(rq)            (struct cfq_group *) ((rq)->elevator_private[2])
 
 static struct kmem_cache *cfq_pool;
 static struct kmem_cache *cfq_ioc_pool;
@@ -146,7 +146,6 @@ struct cfq_queue {
        struct cfq_rb_root *service_tree;
        struct cfq_queue *new_cfqq;
        struct cfq_group *cfqg;
-       struct cfq_group *orig_cfqg;
        /* Number of sectors dispatched from queue in single dispatch round */
        unsigned long nr_sectors;
 };
@@ -179,6 +178,8 @@ struct cfq_group {
        /* group service_tree key */
        u64 vdisktime;
        unsigned int weight;
+       unsigned int new_weight;
+       bool needs_update;
 
        /* number of cfqq currently on this group */
        int nr_cfqq;
@@ -238,6 +239,7 @@ struct cfq_data {
        struct rb_root prio_trees[CFQ_PRIO_LISTS];
 
        unsigned int busy_queues;
+       unsigned int busy_sync_queues;
 
        int rq_in_driver;
        int rq_in_flight[2];
@@ -285,7 +287,6 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
        unsigned int cfq_group_idle;
        unsigned int cfq_latency;
-       unsigned int cfq_group_isolation;
 
        unsigned int cic_index;
        struct list_head cic_list;
@@ -501,13 +502,6 @@ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
        }
 }
 
-static int cfq_queue_empty(struct request_queue *q)
-{
-       struct cfq_data *cfqd = q->elevator->elevator_data;
-
-       return !cfqd->rq_queued;
-}
-
 /*
  * Scale schedule slice based on io priority. Use the sync time slice only
  * if a queue is marked sync and has sync io queued. A sync queue with async
@@ -558,15 +552,13 @@ static inline u64 min_vdisktime(u64 min_vdisktime, u64 vdisktime)
 
 static void update_min_vdisktime(struct cfq_rb_root *st)
 {
-       u64 vdisktime = st->min_vdisktime;
        struct cfq_group *cfqg;
 
        if (st->left) {
                cfqg = rb_entry_cfqg(st->left);
-               vdisktime = min_vdisktime(vdisktime, cfqg->vdisktime);
+               st->min_vdisktime = max_vdisktime(st->min_vdisktime,
+                                                 cfqg->vdisktime);
        }
-
-       st->min_vdisktime = max_vdisktime(st->min_vdisktime, vdisktime);
 }
 
 /*
@@ -863,7 +855,27 @@ __cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
 }
 
 static void
-cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
+cfq_update_group_weight(struct cfq_group *cfqg)
+{
+       BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
+       if (cfqg->needs_update) {
+               cfqg->weight = cfqg->new_weight;
+               cfqg->needs_update = false;
+       }
+}
+
+static void
+cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
+{
+       BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
+
+       cfq_update_group_weight(cfqg);
+       __cfq_group_service_tree_add(st, cfqg);
+       st->total_weight += cfqg->weight;
+}
+
+static void
+cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
 {
        struct cfq_rb_root *st = &cfqd->grp_service_tree;
        struct cfq_group *__cfqg;
@@ -884,13 +896,19 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
                cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
        } else
                cfqg->vdisktime = st->min_vdisktime;
+       cfq_group_service_tree_add(st, cfqg);
+}
 
-       __cfq_group_service_tree_add(st, cfqg);
-       st->total_weight += cfqg->weight;
+static void
+cfq_group_service_tree_del(struct cfq_rb_root *st, struct cfq_group *cfqg)
+{
+       st->total_weight -= cfqg->weight;
+       if (!RB_EMPTY_NODE(&cfqg->rb_node))
+               cfq_rb_erase(&cfqg->rb_node, st);
 }
 
 static void
-cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
+cfq_group_notify_queue_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
 {
        struct cfq_rb_root *st = &cfqd->grp_service_tree;
 
@@ -902,14 +920,13 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
                return;
 
        cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
-       st->total_weight -= cfqg->weight;
-       if (!RB_EMPTY_NODE(&cfqg->rb_node))
-               cfq_rb_erase(&cfqg->rb_node, st);
+       cfq_group_service_tree_del(st, cfqg);
        cfqg->saved_workload_slice = 0;
        cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1);
 }
 
-static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
+static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq,
+                                               unsigned int *unaccounted_time)
 {
        unsigned int slice_used;
 
@@ -928,8 +945,13 @@ static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
                                        1);
        } else {
                slice_used = jiffies - cfqq->slice_start;
-               if (slice_used > cfqq->allocated_slice)
+               if (slice_used > cfqq->allocated_slice) {
+                       *unaccounted_time = slice_used - cfqq->allocated_slice;
                        slice_used = cfqq->allocated_slice;
+               }
+               if (time_after(cfqq->slice_start, cfqq->dispatch_start))
+                       *unaccounted_time += cfqq->slice_start -
+                                       cfqq->dispatch_start;
        }
 
        return slice_used;
@@ -939,12 +961,12 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
                                struct cfq_queue *cfqq)
 {
        struct cfq_rb_root *st = &cfqd->grp_service_tree;
-       unsigned int used_sl, charge;
+       unsigned int used_sl, charge, unaccounted_sl = 0;
        int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg)
                        - cfqg->service_tree_idle.count;
 
        BUG_ON(nr_sync < 0);
-       used_sl = charge = cfq_cfqq_slice_usage(cfqq);
+       used_sl = charge = cfq_cfqq_slice_usage(cfqq, &unaccounted_sl);
 
        if (iops_mode(cfqd))
                charge = cfqq->slice_dispatch;
@@ -952,9 +974,10 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
                charge = cfqq->allocated_slice;
 
        /* Can't update vdisktime while group is on service tree */
-       cfq_rb_erase(&cfqg->rb_node, st);
+       cfq_group_service_tree_del(st, cfqg);
        cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
-       __cfq_group_service_tree_add(st, cfqg);
+       /* If a new weight was requested, update now, off tree */
+       cfq_group_service_tree_add(st, cfqg);
 
        /* This group is being expired. Save the context */
        if (time_after(cfqd->workload_expires, jiffies)) {
@@ -970,7 +993,8 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
        cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u"
                        " sect=%u", used_sl, cfqq->slice_dispatch, charge,
                        iops_mode(cfqd), cfqq->nr_sectors);
-       cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl);
+       cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl,
+                                         unaccounted_sl);
        cfq_blkiocg_set_start_empty_time(&cfqg->blkg);
 }
 
@@ -985,7 +1009,9 @@ static inline struct cfq_group *cfqg_of_blkg(struct blkio_group *blkg)
 void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
                                        unsigned int weight)
 {
-       cfqg_of_blkg(blkg)->weight = weight;
+       struct cfq_group *cfqg = cfqg_of_blkg(blkg);
+       cfqg->new_weight = weight;
+       cfqg->needs_update = true;
 }
 
 static struct cfq_group *
@@ -1187,32 +1213,6 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        int new_cfqq = 1;
        int group_changed = 0;
 
-#ifdef CONFIG_CFQ_GROUP_IOSCHED
-       if (!cfqd->cfq_group_isolation
-           && cfqq_type(cfqq) == SYNC_NOIDLE_WORKLOAD
-           && cfqq->cfqg && cfqq->cfqg != &cfqd->root_group) {
-               /* Move this cfq to root group */
-               cfq_log_cfqq(cfqd, cfqq, "moving to root group");
-               if (!RB_EMPTY_NODE(&cfqq->rb_node))
-                       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
-               cfqq->orig_cfqg = cfqq->cfqg;
-               cfqq->cfqg = &cfqd->root_group;
-               cfqd->root_group.ref++;
-               group_changed = 1;
-       } else if (!cfqd->cfq_group_isolation
-                  && cfqq_type(cfqq) == SYNC_WORKLOAD && cfqq->orig_cfqg) {
-               /* cfqq is sequential now needs to go to its original group */
-               BUG_ON(cfqq->cfqg != &cfqd->root_group);
-               if (!RB_EMPTY_NODE(&cfqq->rb_node))
-                       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
-               cfq_put_cfqg(cfqq->cfqg);
-               cfqq->cfqg = cfqq->orig_cfqg;
-               cfqq->orig_cfqg = NULL;
-               group_changed = 1;
-               cfq_log_cfqq(cfqd, cfqq, "moved to origin group");
-       }
-#endif
-
        service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
                                                cfqq_type(cfqq));
        if (cfq_class_idle(cfqq)) {
@@ -1284,7 +1284,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        service_tree->count++;
        if ((add_front || !new_cfqq) && !group_changed)
                return;
-       cfq_group_service_tree_add(cfqd, cfqq->cfqg);
+       cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
 }
 
 static struct cfq_queue *
@@ -1372,6 +1372,8 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
        BUG_ON(cfq_cfqq_on_rr(cfqq));
        cfq_mark_cfqq_on_rr(cfqq);
        cfqd->busy_queues++;
+       if (cfq_cfqq_sync(cfqq))
+               cfqd->busy_sync_queues++;
 
        cfq_resort_rr_list(cfqd, cfqq);
 }
@@ -1395,9 +1397,11 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
                cfqq->p_root = NULL;
        }
 
-       cfq_group_service_tree_del(cfqd, cfqq->cfqg);
+       cfq_group_notify_queue_del(cfqd, cfqq->cfqg);
        BUG_ON(!cfqd->busy_queues);
        cfqd->busy_queues--;
+       if (cfq_cfqq_sync(cfqq))
+               cfqd->busy_sync_queues--;
 }
 
 /*
@@ -2405,22 +2409,34 @@ static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
         * Does this cfqq already have too much IO in flight?
         */
        if (cfqq->dispatched >= max_dispatch) {
+               bool promote_sync = false;
                /*
                 * idle queue must always only have a single IO in flight
                 */
                if (cfq_class_idle(cfqq))
                        return false;
 
+               /*
+                * If there is only one sync queue
+                * we can ignore async queue here and give the sync
+                * queue no dispatch limit. The reason is a sync queue can
+                * preempt async queue, limiting the sync queue doesn't make
+                * sense. This is useful for aiostress test.
+                */
+               if (cfq_cfqq_sync(cfqq) && cfqd->busy_sync_queues == 1)
+                       promote_sync = true;
+
                /*
                 * We have other queues, don't allow more IO from this one
                 */
-               if (cfqd->busy_queues > 1 && cfq_slice_used_soon(cfqd, cfqq))
+               if (cfqd->busy_queues > 1 && cfq_slice_used_soon(cfqd, cfqq) &&
+                               !promote_sync)
                        return false;
 
                /*
                 * Sole queue user, no limit
                 */
-               if (cfqd->busy_queues == 1)
+               if (cfqd->busy_queues == 1 || promote_sync)
                        max_dispatch = -1;
                else
                        /*
@@ -2542,7 +2558,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
 static void cfq_put_queue(struct cfq_queue *cfqq)
 {
        struct cfq_data *cfqd = cfqq->cfqd;
-       struct cfq_group *cfqg, *orig_cfqg;
+       struct cfq_group *cfqg;
 
        BUG_ON(cfqq->ref <= 0);
 
@@ -2554,7 +2570,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        BUG_ON(rb_first(&cfqq->sort_list));
        BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
        cfqg = cfqq->cfqg;
-       orig_cfqg = cfqq->orig_cfqg;
 
        if (unlikely(cfqd->active_queue == cfqq)) {
                __cfq_slice_expired(cfqd, cfqq, 0);
@@ -2564,8 +2579,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
        BUG_ON(cfq_cfqq_on_rr(cfqq));
        kmem_cache_free(cfq_pool, cfqq);
        cfq_put_cfqg(cfqg);
-       if (orig_cfqg)
-               cfq_put_cfqg(orig_cfqg);
 }
 
 /*
@@ -3613,12 +3626,12 @@ static void cfq_put_request(struct request *rq)
 
                put_io_context(RQ_CIC(rq)->ioc);
 
-               rq->elevator_private = NULL;
-               rq->elevator_private2 = NULL;
+               rq->elevator_private[0] = NULL;
+               rq->elevator_private[1] = NULL;
 
                /* Put down rq reference on cfqg */
                cfq_put_cfqg(RQ_CFQG(rq));
-               rq->elevator_private3 = NULL;
+               rq->elevator_private[2] = NULL;
 
                cfq_put_queue(cfqq);
        }
@@ -3705,13 +3718,12 @@ new_queue:
        }
 
        cfqq->allocated[rw]++;
-       cfqq->ref++;
-       rq->elevator_private = cic;
-       rq->elevator_private2 = cfqq;
-       rq->elevator_private3 = cfq_ref_get_cfqg(cfqq->cfqg);
 
+       cfqq->ref++;
+       rq->elevator_private[0] = cic;
+       rq->elevator_private[1] = cfqq;
+       rq->elevator_private[2] = cfq_ref_get_cfqg(cfqq->cfqg);
        spin_unlock_irqrestore(q->queue_lock, flags);
-
        return 0;
 
 queue_fail:
@@ -3953,7 +3965,6 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->cfq_slice_idle = cfq_slice_idle;
        cfqd->cfq_group_idle = cfq_group_idle;
        cfqd->cfq_latency = 1;
-       cfqd->cfq_group_isolation = 0;
        cfqd->hw_tag = -1;
        /*
         * we optimistically start assuming sync ops weren't delayed in last
@@ -4029,7 +4040,6 @@ SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
 SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0);
-SHOW_FUNCTION(cfq_group_isolation_show, cfqd->cfq_group_isolation, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
@@ -4063,7 +4073,6 @@ STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
                UINT_MAX, 0);
 STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0);
-STORE_FUNCTION(cfq_group_isolation_store, &cfqd->cfq_group_isolation, 0, 1, 0);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
@@ -4081,7 +4090,6 @@ static struct elv_fs_entry cfq_attrs[] = {
        CFQ_ATTR(slice_idle),
        CFQ_ATTR(group_idle),
        CFQ_ATTR(low_latency),
-       CFQ_ATTR(group_isolation),
        __ATTR_NULL
 };
 
@@ -4096,7 +4104,6 @@ static struct elevator_type iosched_cfq = {
                .elevator_add_req_fn =          cfq_insert_request,
                .elevator_activate_req_fn =     cfq_activate_request,
                .elevator_deactivate_req_fn =   cfq_deactivate_request,
-               .elevator_queue_empty_fn =      cfq_queue_empty,
                .elevator_completed_req_fn =    cfq_completed_request,
                .elevator_former_req_fn =       elv_rb_former_request,
                .elevator_latter_req_fn =       elv_rb_latter_request,
index 54a6d90f8e8c914564546c1e3f699a298e8cc0e9..2a155927e37ce50a936019cecab31805945c4e45 100644 (file)
@@ -16,9 +16,9 @@ static inline void cfq_blkiocg_update_dequeue_stats(struct blkio_group *blkg,
 }
 
 static inline void cfq_blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                       unsigned long time)
+                       unsigned long time, unsigned long unaccounted_time)
 {
-       blkiocg_update_timeslice_used(blkg, time);
+       blkiocg_update_timeslice_used(blkg, time, unaccounted_time);
 }
 
 static inline void cfq_blkiocg_set_start_empty_time(struct blkio_group *blkg)
@@ -85,7 +85,7 @@ static inline void cfq_blkiocg_update_dequeue_stats(struct blkio_group *blkg,
                        unsigned long dequeue) {}
 
 static inline void cfq_blkiocg_update_timeslice_used(struct blkio_group *blkg,
-                       unsigned long time) {}
+                       unsigned long time, unsigned long unaccounted_time) {}
 static inline void cfq_blkiocg_set_start_empty_time(struct blkio_group *blkg) {}
 static inline void cfq_blkiocg_update_io_remove_stats(struct blkio_group *blkg,
                                bool direction, bool sync) {}
index b547cbca7b23a55dd9d1f0b444bed07d297fc646..5139c0ea1864a858b6072febcf636a71e9bc6f13 100644 (file)
@@ -326,14 +326,6 @@ dispatch_request:
        return 1;
 }
 
-static int deadline_queue_empty(struct request_queue *q)
-{
-       struct deadline_data *dd = q->elevator->elevator_data;
-
-       return list_empty(&dd->fifo_list[WRITE])
-               && list_empty(&dd->fifo_list[READ]);
-}
-
 static void deadline_exit_queue(struct elevator_queue *e)
 {
        struct deadline_data *dd = e->elevator_data;
@@ -445,7 +437,6 @@ static struct elevator_type iosched_deadline = {
                .elevator_merge_req_fn =        deadline_merged_requests,
                .elevator_dispatch_fn =         deadline_dispatch_requests,
                .elevator_add_req_fn =          deadline_add_request,
-               .elevator_queue_empty_fn =      deadline_queue_empty,
                .elevator_former_req_fn =       elv_rb_former_request,
                .elevator_latter_req_fn =       elv_rb_latter_request,
                .elevator_init_fn =             deadline_init_queue,
index 236e93c1f46ce54d0f2ac40c48a85289f1d568fb..c387d3168734c21d74336b536819d35dc77719a5 100644 (file)
@@ -113,7 +113,7 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
 }
 EXPORT_SYMBOL(elv_rq_merge_ok);
 
-static inline int elv_try_merge(struct request *__rq, struct bio *bio)
+int elv_try_merge(struct request *__rq, struct bio *bio)
 {
        int ret = ELEVATOR_NO_MERGE;
 
@@ -421,6 +421,8 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
        struct list_head *entry;
        int stop_flags;
 
+       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
+
        if (q->last_merge == rq)
                q->last_merge = NULL;
 
@@ -519,6 +521,40 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
        return ELEVATOR_NO_MERGE;
 }
 
+/*
+ * Attempt to do an insertion back merge. Only check for the case where
+ * we can append 'rq' to an existing request, so we can throw 'rq' away
+ * afterwards.
+ *
+ * Returns true if we merged, false otherwise
+ */
+static bool elv_attempt_insert_merge(struct request_queue *q,
+                                    struct request *rq)
+{
+       struct request *__rq;
+
+       if (blk_queue_nomerges(q))
+               return false;
+
+       /*
+        * First try one-hit cache.
+        */
+       if (q->last_merge && blk_attempt_req_merge(q, q->last_merge, rq))
+               return true;
+
+       if (blk_queue_noxmerges(q))
+               return false;
+
+       /*
+        * See if our hash lookup can find a potential backmerge.
+        */
+       __rq = elv_rqhash_find(q, blk_rq_pos(rq));
+       if (__rq && blk_attempt_req_merge(q, __rq, rq))
+               return true;
+
+       return false;
+}
+
 void elv_merged_request(struct request_queue *q, struct request *rq, int type)
 {
        struct elevator_queue *e = q->elevator;
@@ -536,14 +572,18 @@ void elv_merge_requests(struct request_queue *q, struct request *rq,
                             struct request *next)
 {
        struct elevator_queue *e = q->elevator;
+       const int next_sorted = next->cmd_flags & REQ_SORTED;
 
-       if (e->ops->elevator_merge_req_fn)
+       if (next_sorted && e->ops->elevator_merge_req_fn)
                e->ops->elevator_merge_req_fn(q, rq, next);
 
        elv_rqhash_reposition(q, rq);
-       elv_rqhash_del(q, next);
 
-       q->nr_sorted--;
+       if (next_sorted) {
+               elv_rqhash_del(q, next);
+               q->nr_sorted--;
+       }
+
        q->last_merge = rq;
 }
 
@@ -617,21 +657,12 @@ void elv_quiesce_end(struct request_queue *q)
 
 void elv_insert(struct request_queue *q, struct request *rq, int where)
 {
-       int unplug_it = 1;
-
        trace_block_rq_insert(q, rq);
 
        rq->q = q;
 
        switch (where) {
        case ELEVATOR_INSERT_REQUEUE:
-               /*
-                * Most requeues happen because of a busy condition,
-                * don't force unplug of the queue for that case.
-                * Clear unplug_it and fall through.
-                */
-               unplug_it = 0;
-
        case ELEVATOR_INSERT_FRONT:
                rq->cmd_flags |= REQ_SOFTBARRIER;
                list_add(&rq->queuelist, &q->queue_head);
@@ -654,6 +685,14 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
                __blk_run_queue(q, false);
                break;
 
+       case ELEVATOR_INSERT_SORT_MERGE:
+               /*
+                * If we succeed in merging this request with one in the
+                * queue already, we are done - rq has now been freed,
+                * so no need to do anything further.
+                */
+               if (elv_attempt_insert_merge(q, rq))
+                       break;
        case ELEVATOR_INSERT_SORT:
                BUG_ON(rq->cmd_type != REQ_TYPE_FS &&
                       !(rq->cmd_flags & REQ_DISCARD));
@@ -673,24 +712,21 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
                q->elevator->ops->elevator_add_req_fn(q, rq);
                break;
 
+       case ELEVATOR_INSERT_FLUSH:
+               rq->cmd_flags |= REQ_SOFTBARRIER;
+               blk_insert_flush(rq);
+               break;
        default:
                printk(KERN_ERR "%s: bad insertion point %d\n",
                       __func__, where);
                BUG();
        }
-
-       if (unplug_it && blk_queue_plugged(q)) {
-               int nrq = q->rq.count[BLK_RW_SYNC] + q->rq.count[BLK_RW_ASYNC]
-                               - queue_in_flight(q);
-
-               if (nrq >= q->unplug_thresh)
-                       __generic_unplug_device(q);
-       }
 }
 
-void __elv_add_request(struct request_queue *q, struct request *rq, int where,
-                      int plug)
+void __elv_add_request(struct request_queue *q, struct request *rq, int where)
 {
+       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
+
        if (rq->cmd_flags & REQ_SOFTBARRIER) {
                /* barriers are scheduling boundary, update end_sector */
                if (rq->cmd_type == REQ_TYPE_FS ||
@@ -702,38 +738,20 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
                    where == ELEVATOR_INSERT_SORT)
                where = ELEVATOR_INSERT_BACK;
 
-       if (plug)
-               blk_plug_device(q);
-
        elv_insert(q, rq, where);
 }
 EXPORT_SYMBOL(__elv_add_request);
 
-void elv_add_request(struct request_queue *q, struct request *rq, int where,
-                    int plug)
+void elv_add_request(struct request_queue *q, struct request *rq, int where)
 {
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __elv_add_request(q, rq, where, plug);
+       __elv_add_request(q, rq, where);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(elv_add_request);
 
-int elv_queue_empty(struct request_queue *q)
-{
-       struct elevator_queue *e = q->elevator;
-
-       if (!list_empty(&q->queue_head))
-               return 0;
-
-       if (e->ops->elevator_queue_empty_fn)
-               return e->ops->elevator_queue_empty_fn(q);
-
-       return 1;
-}
-EXPORT_SYMBOL(elv_queue_empty);
-
 struct request *elv_latter_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
@@ -759,7 +777,7 @@ int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
        if (e->ops->elevator_set_req_fn)
                return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
 
-       rq->elevator_private = NULL;
+       rq->elevator_private[0] = NULL;
        return 0;
 }
 
@@ -785,6 +803,8 @@ void elv_abort_queue(struct request_queue *q)
 {
        struct request *rq;
 
+       blk_abort_flushes(q);
+
        while (!list_empty(&q->queue_head)) {
                rq = list_entry_rq(q->queue_head.next);
                rq->cmd_flags |= REQ_QUIET;
index cbf1112a885c0c715e4d38a3dfad91f74cd1f1fa..c91a2dac6b6b282f5104c781b8f9509dda42f38d 100644 (file)
@@ -1158,14 +1158,14 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                           "%u %lu %lu %llu %u %u %u %u\n",
                           MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
                           disk_name(gp, hd->partno, buf),
-                          part_stat_read(hd, ios[0]),
-                          part_stat_read(hd, merges[0]),
-                          (unsigned long long)part_stat_read(hd, sectors[0]),
-                          jiffies_to_msecs(part_stat_read(hd, ticks[0])),
-                          part_stat_read(hd, ios[1]),
-                          part_stat_read(hd, merges[1]),
-                          (unsigned long long)part_stat_read(hd, sectors[1]),
-                          jiffies_to_msecs(part_stat_read(hd, ticks[1])),
+                          part_stat_read(hd, ios[READ]),
+                          part_stat_read(hd, merges[READ]),
+                          (unsigned long long)part_stat_read(hd, sectors[READ]),
+                          jiffies_to_msecs(part_stat_read(hd, ticks[READ])),
+                          part_stat_read(hd, ios[WRITE]),
+                          part_stat_read(hd, merges[WRITE]),
+                          (unsigned long long)part_stat_read(hd, sectors[WRITE]),
+                          jiffies_to_msecs(part_stat_read(hd, ticks[WRITE])),
                           part_in_flight(hd),
                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
                           jiffies_to_msecs(part_stat_read(hd, time_in_queue))
@@ -1494,7 +1494,7 @@ void disk_block_events(struct gendisk *disk)
 void disk_unblock_events(struct gendisk *disk)
 {
        if (disk->ev)
-               __disk_unblock_events(disk, true);
+               __disk_unblock_events(disk, false);
 }
 
 /**
index 232c4b38cd3769d31e0c79700a49f42915c683a6..06389e9ef96d552836a1509ddf86745d82c09762 100644 (file)
@@ -39,13 +39,6 @@ static void noop_add_request(struct request_queue *q, struct request *rq)
        list_add_tail(&rq->queuelist, &nd->queue);
 }
 
-static int noop_queue_empty(struct request_queue *q)
-{
-       struct noop_data *nd = q->elevator->elevator_data;
-
-       return list_empty(&nd->queue);
-}
-
 static struct request *
 noop_former_request(struct request_queue *q, struct request *rq)
 {
@@ -90,7 +83,6 @@ static struct elevator_type elevator_noop = {
                .elevator_merge_req_fn          = noop_merged_requests,
                .elevator_dispatch_fn           = noop_dispatch,
                .elevator_add_req_fn            = noop_add_request,
-               .elevator_queue_empty_fn        = noop_queue_empty,
                .elevator_former_req_fn         = noop_former_request,
                .elevator_latter_req_fn         = noop_latter_request,
                .elevator_init_fn               = noop_init_queue,
index cbc7a33a9600c2b1cb9e9bdc161f3586229b85d1..b5ccae29be7491571301b81beae5b135fa064628 100644 (file)
@@ -48,7 +48,8 @@ static int deflate_comp_init(struct deflate_ctx *ctx)
        int ret = 0;
        struct z_stream_s *stream = &ctx->comp_stream;
 
-       stream->workspace = vzalloc(zlib_deflate_workspacesize());
+       stream->workspace = vzalloc(zlib_deflate_workspacesize(
+                               -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL));
        if (!stream->workspace) {
                ret = -ENOMEM;
                goto out;
index 739b8fca4cea518777f569372ded2e0b751dcd49..d11d761a5e418191c29a987f923ac3e2be0f20a6 100644 (file)
@@ -85,6 +85,7 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
        struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
        struct z_stream_s *stream = &ctx->comp_stream;
        struct nlattr *tb[ZLIB_COMP_MAX + 1];
+       int window_bits, mem_level;
        size_t workspacesize;
        int ret;
 
@@ -94,7 +95,14 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
 
        zlib_comp_exit(ctx);
 
-       workspacesize = zlib_deflate_workspacesize();
+       window_bits = tb[ZLIB_COMP_WINDOWBITS]
+                                       ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
+                                       : MAX_WBITS;
+       mem_level = tb[ZLIB_COMP_MEMLEVEL]
+                                       ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
+                                       : DEF_MEM_LEVEL;
+
+       workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
        stream->workspace = vzalloc(workspacesize);
        if (!stream->workspace)
                return -ENOMEM;
@@ -106,12 +114,8 @@ static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
                                tb[ZLIB_COMP_METHOD]
                                        ? nla_get_u32(tb[ZLIB_COMP_METHOD])
                                        : Z_DEFLATED,
-                               tb[ZLIB_COMP_WINDOWBITS]
-                                       ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
-                                       : MAX_WBITS,
-                               tb[ZLIB_COMP_MEMLEVEL]
-                                       ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
-                                       : DEF_MEM_LEVEL,
+                               window_bits,
+                               mem_level,
                                tb[ZLIB_COMP_STRATEGY]
                                        ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
                                        : Z_DEFAULT_STRATEGY);
index 6afceb3d4034edef3a868722e41af82873057e74..a43fa1a57d57f45616c9d70c362df15d3b71c8e5 100644 (file)
@@ -298,7 +298,7 @@ static ssize_t acpi_pad_rrtime_store(struct device *dev,
 static ssize_t acpi_pad_rrtime_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       return scnprintf(buf, PAGE_SIZE, "%d", round_robin_time);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", round_robin_time);
 }
 static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR,
        acpi_pad_rrtime_show,
@@ -321,7 +321,7 @@ static ssize_t acpi_pad_idlepct_store(struct device *dev,
 static ssize_t acpi_pad_idlepct_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       return scnprintf(buf, PAGE_SIZE, "%d", idle_pct);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", idle_pct);
 }
 static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR,
        acpi_pad_idlepct_show,
@@ -342,8 +342,11 @@ static ssize_t acpi_pad_idlecpus_store(struct device *dev,
 static ssize_t acpi_pad_idlecpus_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       return cpumask_scnprintf(buf, PAGE_SIZE,
-               to_cpumask(pad_busy_cpus_bits));
+       int n = 0;
+       n = cpumask_scnprintf(buf, PAGE_SIZE-2, to_cpumask(pad_busy_cpus_bits));
+       buf[n++] = '\n';
+       buf[n] = '\0';
+       return n;
 }
 static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR,
        acpi_pad_idlecpus_show,
@@ -453,7 +456,7 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
                        dev_name(&device->dev), event, 0);
                break;
        default:
-               printk(KERN_WARNING"Unsupported event [0x%x]\n", event);
+               printk(KERN_WARNING "Unsupported event [0x%x]\n", event);
                break;
        }
 }
index eec2eadd24310d7742ddc2f26847cc390d382abe..a1224712fd0c1abaab12a70e8f97237252380090 100644 (file)
@@ -10,7 +10,7 @@ obj-y += acpi.o
 
 acpi-y := dsfield.o   dsmthdat.o  dsopcode.o  dswexec.o  dswscope.o \
         dsmethod.o  dsobject.o  dsutils.o   dswload.o  dswstate.o \
-        dsinit.o
+        dsinit.o dsargs.o dscontrol.o dswload2.o
 
 acpi-y += evevent.o  evregion.o  evsci.o    evxfevnt.o \
         evmisc.o   evrgnini.o  evxface.o  evxfregn.o \
@@ -45,4 +45,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
 acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
                utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
                utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \
-               utosi.o utxferror.o
+               utosi.o utxferror.o utdecode.o
index 666271b65418b4d0be228a3009e8c4913043b54e..2d1b7ffa377a030d9e30490bcdcfef225bdb1d89 100644 (file)
@@ -48,7 +48,7 @@
 #define NAMEOF_ARG_NTE      "__A0"
 
 /*
- * dsopcode - support for late evaluation
+ * dsargs - execution of dynamic arguments for static objects
  */
 acpi_status
 acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc);
@@ -62,6 +62,20 @@ acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc);
 
 acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc);
 
+/*
+ * dscontrol - support for execution control opcodes
+ */
+acpi_status
+acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
+                             union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
+                           union acpi_parse_object *op);
+
+/*
+ * dsopcode - support for late operand evaluation
+ */
 acpi_status
 acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
                                   union acpi_parse_object *op);
@@ -85,17 +99,6 @@ acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
 
 acpi_status acpi_ds_initialize_region(acpi_handle obj_handle);
 
-/*
- * dsctrl - Parser/Interpreter interface, control stack routines
- */
-acpi_status
-acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
-                             union acpi_parse_object *op);
-
-acpi_status
-acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
-                           union acpi_parse_object *op);
-
 /*
  * dsexec - Parser/Interpreter interface, method execution callbacks
  */
@@ -136,23 +139,26 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
                           struct acpi_walk_state *walk_state);
 
 /*
- * dsload - Parser/Interpreter interface, namespace load callbacks
+ * dsload - Parser/Interpreter interface, pass 1 namespace load callbacks
  */
+acpi_status
+acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number);
+
 acpi_status
 acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state,
                       union acpi_parse_object **out_op);
 
 acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state);
 
+/*
+ * dsload - Parser/Interpreter interface, pass 2 namespace load callbacks
+ */
 acpi_status
 acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
                       union acpi_parse_object **out_op);
 
 acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state);
 
-acpi_status
-acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number);
-
 /*
  * dsmthdat - method data (locals/args)
  */
index 82a1bd283db84208080aeb657ebe22ec869e78c7..d69750b83b365a236567815f723102b53a57ac80 100644 (file)
@@ -273,6 +273,10 @@ ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
 ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
 ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
 
+/* Initialization sequencing */
+
+ACPI_EXTERN u8 acpi_gbl_reg_methods_executed;
+
 /* Misc */
 
 ACPI_EXTERN u32 acpi_gbl_original_mode;
index edc25867ad9d92ca4a23ef6fc7aa9c5f66c5862a..c7f743ca395bbcaf91d4b046cee29b804b871c3a 100644 (file)
@@ -89,25 +89,6 @@ union acpi_parse_object;
 #define ACPI_MAX_MUTEX                  7
 #define ACPI_NUM_MUTEX                  ACPI_MAX_MUTEX+1
 
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
-#ifdef DEFINE_ACPI_GLOBALS
-
-/* Debug names for the mutexes above */
-
-static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
-       "ACPI_MTX_Interpreter",
-       "ACPI_MTX_Namespace",
-       "ACPI_MTX_Tables",
-       "ACPI_MTX_Events",
-       "ACPI_MTX_Caches",
-       "ACPI_MTX_Memory",
-       "ACPI_MTX_CommandComplete",
-       "ACPI_MTX_CommandReady"
-};
-
-#endif
-#endif
-
 /* Lock structure for reader/writer interfaces */
 
 struct acpi_rw_lock {
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
new file mode 100644 (file)
index 0000000..8c7b997
--- /dev/null
@@ -0,0 +1,391 @@
+/******************************************************************************
+ *
+ * Module Name: dsargs - Support for execution of dynamic arguments for static
+ *                       objects (regions, fields, buffer fields, etc.)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsargs")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_execute_arguments(struct acpi_namespace_node *node,
+                         struct acpi_namespace_node *scope_node,
+                         u32 aml_length, u8 *aml_start);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_execute_arguments
+ *
+ * PARAMETERS:  Node                - Object NS node
+ *              scope_node          - Parent NS node
+ *              aml_length          - Length of executable AML
+ *              aml_start           - Pointer to the AML
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Late (deferred) execution of region or field arguments
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_execute_arguments(struct acpi_namespace_node *node,
+                         struct acpi_namespace_node *scope_node,
+                         u32 aml_length, u8 *aml_start)
+{
+       acpi_status status;
+       union acpi_parse_object *op;
+       struct acpi_walk_state *walk_state;
+
+       ACPI_FUNCTION_TRACE(ds_execute_arguments);
+
+       /* Allocate a new parser op to be the root of the parsed tree */
+
+       op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
+       if (!op) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Save the Node for use in acpi_ps_parse_aml */
+
+       op->common.node = scope_node;
+
+       /* Create and initialize a new parser state */
+
+       walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+       if (!walk_state) {
+               status = AE_NO_MEMORY;
+               goto cleanup;
+       }
+
+       status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
+                                      aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
+       if (ACPI_FAILURE(status)) {
+               acpi_ds_delete_walk_state(walk_state);
+               goto cleanup;
+       }
+
+       /* Mark this parse as a deferred opcode */
+
+       walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP;
+       walk_state->deferred_node = node;
+
+       /* Pass1: Parse the entire declaration */
+
+       status = acpi_ps_parse_aml(walk_state);
+       if (ACPI_FAILURE(status)) {
+               goto cleanup;
+       }
+
+       /* Get and init the Op created above */
+
+       op->common.node = node;
+       acpi_ps_delete_parse_tree(op);
+
+       /* Evaluate the deferred arguments */
+
+       op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
+       if (!op) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       op->common.node = scope_node;
+
+       /* Create and initialize a new parser state */
+
+       walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+       if (!walk_state) {
+               status = AE_NO_MEMORY;
+               goto cleanup;
+       }
+
+       /* Execute the opcode and arguments */
+
+       status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
+                                      aml_length, NULL, ACPI_IMODE_EXECUTE);
+       if (ACPI_FAILURE(status)) {
+               acpi_ds_delete_walk_state(walk_state);
+               goto cleanup;
+       }
+
+       /* Mark this execution as a deferred opcode */
+
+       walk_state->deferred_node = node;
+       status = acpi_ps_parse_aml(walk_state);
+
+      cleanup:
+       acpi_ps_delete_parse_tree(op);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_get_buffer_field_arguments
+ *
+ * PARAMETERS:  obj_desc        - A valid buffer_field object
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late
+ *              evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
+{
+       union acpi_operand_object *extra_desc;
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc);
+
+       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Get the AML pointer (method object) and buffer_field node */
+
+       extra_desc = acpi_ns_get_secondary_object(obj_desc);
+       node = obj_desc->buffer_field.node;
+
+       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_BUFFER_FIELD,
+                                                     node, NULL));
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n",
+                         acpi_ut_get_node_name(node)));
+
+       /* Execute the AML code for the term_arg arguments */
+
+       status = acpi_ds_execute_arguments(node, node->parent,
+                                          extra_desc->extra.aml_length,
+                                          extra_desc->extra.aml_start);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_get_bank_field_arguments
+ *
+ * PARAMETERS:  obj_desc        - A valid bank_field object
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get bank_field bank_value. This implements the late
+ *              evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
+{
+       union acpi_operand_object *extra_desc;
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
+
+       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Get the AML pointer (method object) and bank_field node */
+
+       extra_desc = acpi_ns_get_secondary_object(obj_desc);
+       node = obj_desc->bank_field.node;
+
+       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+                       (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
+                         acpi_ut_get_node_name(node)));
+
+       /* Execute the AML code for the term_arg arguments */
+
+       status = acpi_ds_execute_arguments(node, node->parent,
+                                          extra_desc->extra.aml_length,
+                                          extra_desc->extra.aml_start);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_get_buffer_arguments
+ *
+ * PARAMETERS:  obj_desc        - A valid Buffer object
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get Buffer length and initializer byte list. This implements
+ *              the late evaluation of these attributes.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc);
+
+       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Get the Buffer node */
+
+       node = obj_desc->buffer.node;
+       if (!node) {
+               ACPI_ERROR((AE_INFO,
+                           "No pointer back to namespace node in buffer object %p",
+                           obj_desc));
+               return_ACPI_STATUS(AE_AML_INTERNAL);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n"));
+
+       /* Execute the AML code for the term_arg arguments */
+
+       status = acpi_ds_execute_arguments(node, node,
+                                          obj_desc->buffer.aml_length,
+                                          obj_desc->buffer.aml_start);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_get_package_arguments
+ *
+ * PARAMETERS:  obj_desc        - A valid Package object
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get Package length and initializer byte list. This implements
+ *              the late evaluation of these attributes.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc);
+
+       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Get the Package node */
+
+       node = obj_desc->package.node;
+       if (!node) {
+               ACPI_ERROR((AE_INFO,
+                           "No pointer back to namespace node in package %p",
+                           obj_desc));
+               return_ACPI_STATUS(AE_AML_INTERNAL);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n"));
+
+       /* Execute the AML code for the term_arg arguments */
+
+       status = acpi_ds_execute_arguments(node, node,
+                                          obj_desc->package.aml_length,
+                                          obj_desc->package.aml_start);
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_get_region_arguments
+ *
+ * PARAMETERS:  obj_desc        - A valid region object
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get region address and length. This implements the late
+ *              evaluation of these region attributes.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
+{
+       struct acpi_namespace_node *node;
+       acpi_status status;
+       union acpi_operand_object *extra_desc;
+
+       ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc);
+
+       if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       extra_desc = acpi_ns_get_secondary_object(obj_desc);
+       if (!extra_desc) {
+               return_ACPI_STATUS(AE_NOT_EXIST);
+       }
+
+       /* Get the Region node */
+
+       node = obj_desc->region.node;
+
+       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+                       (ACPI_TYPE_REGION, node, NULL));
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n",
+                         acpi_ut_get_node_name(node),
+                         extra_desc->extra.aml_start));
+
+       /* Execute the argument AML */
+
+       status = acpi_ds_execute_arguments(node, node->parent,
+                                          extra_desc->extra.aml_length,
+                                          extra_desc->extra.aml_start);
+       return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
new file mode 100644 (file)
index 0000000..26c49ff
--- /dev/null
@@ -0,0 +1,410 @@
+/******************************************************************************
+ *
+ * Module Name: dscontrol - Support for execution control opcodes -
+ *                          if/else/while/return
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+
+#define _COMPONENT          ACPI_DISPATCHER
+ACPI_MODULE_NAME("dscontrol")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_exec_begin_control_op
+ *
+ * PARAMETERS:  walk_list       - The list that owns the walk stack
+ *              Op              - The control Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ *              execution.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
+                             union acpi_parse_object *op)
+{
+       acpi_status status = AE_OK;
+       union acpi_generic_state *control_state;
+
+       ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
+
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",
+                         op, op->common.aml_opcode, walk_state));
+
+       switch (op->common.aml_opcode) {
+       case AML_WHILE_OP:
+
+               /*
+                * If this is an additional iteration of a while loop, continue.
+                * There is no need to allocate a new control state.
+                */
+               if (walk_state->control_state) {
+                       if (walk_state->control_state->control.
+                           aml_predicate_start ==
+                           (walk_state->parser_state.aml - 1)) {
+
+                               /* Reset the state to start-of-loop */
+
+                               walk_state->control_state->common.state =
+                                   ACPI_CONTROL_CONDITIONAL_EXECUTING;
+                               break;
+                       }
+               }
+
+               /*lint -fallthrough */
+
+       case AML_IF_OP:
+
+               /*
+                * IF/WHILE: Create a new control state to manage these
+                * constructs. We need to manage these as a stack, in order
+                * to handle nesting.
+                */
+               control_state = acpi_ut_create_control_state();
+               if (!control_state) {
+                       status = AE_NO_MEMORY;
+                       break;
+               }
+               /*
+                * Save a pointer to the predicate for multiple executions
+                * of a loop
+                */
+               control_state->control.aml_predicate_start =
+                   walk_state->parser_state.aml - 1;
+               control_state->control.package_end =
+                   walk_state->parser_state.pkg_end;
+               control_state->control.opcode = op->common.aml_opcode;
+
+               /* Push the control state on this walk's control stack */
+
+               acpi_ut_push_generic_state(&walk_state->control_state,
+                                          control_state);
+               break;
+
+       case AML_ELSE_OP:
+
+               /* Predicate is in the state object */
+               /* If predicate is true, the IF was executed, ignore ELSE part */
+
+               if (walk_state->last_predicate) {
+                       status = AE_CTRL_TRUE;
+               }
+
+               break;
+
+       case AML_RETURN_OP:
+
+               break;
+
+       default:
+               break;
+       }
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_exec_end_control_op
+ *
+ * PARAMETERS:  walk_list       - The list that owns the walk stack
+ *              Op              - The control Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ *              execution.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
+                           union acpi_parse_object * op)
+{
+       acpi_status status = AE_OK;
+       union acpi_generic_state *control_state;
+
+       ACPI_FUNCTION_NAME(ds_exec_end_control_op);
+
+       switch (op->common.aml_opcode) {
+       case AML_IF_OP:
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
+
+               /*
+                * Save the result of the predicate in case there is an
+                * ELSE to come
+                */
+               walk_state->last_predicate =
+                   (u8)walk_state->control_state->common.value;
+
+               /*
+                * Pop the control state that was created at the start
+                * of the IF and free it
+                */
+               control_state =
+                   acpi_ut_pop_generic_state(&walk_state->control_state);
+               acpi_ut_delete_generic_state(control_state);
+               break;
+
+       case AML_ELSE_OP:
+
+               break;
+
+       case AML_WHILE_OP:
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
+
+               control_state = walk_state->control_state;
+               if (control_state->common.value) {
+
+                       /* Predicate was true, the body of the loop was just executed */
+
+                       /*
+                        * This loop counter mechanism allows the interpreter to escape
+                        * possibly infinite loops. This can occur in poorly written AML
+                        * when the hardware does not respond within a while loop and the
+                        * loop does not implement a timeout.
+                        */
+                       control_state->control.loop_count++;
+                       if (control_state->control.loop_count >
+                           ACPI_MAX_LOOP_ITERATIONS) {
+                               status = AE_AML_INFINITE_LOOP;
+                               break;
+                       }
+
+                       /*
+                        * Go back and evaluate the predicate and maybe execute the loop
+                        * another time
+                        */
+                       status = AE_CTRL_PENDING;
+                       walk_state->aml_last_while =
+                           control_state->control.aml_predicate_start;
+                       break;
+               }
+
+               /* Predicate was false, terminate this while loop */
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "[WHILE_OP] termination! Op=%p\n", op));
+
+               /* Pop this control state and free it */
+
+               control_state =
+                   acpi_ut_pop_generic_state(&walk_state->control_state);
+               acpi_ut_delete_generic_state(control_state);
+               break;
+
+       case AML_RETURN_OP:
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "[RETURN_OP] Op=%p Arg=%p\n", op,
+                                 op->common.value.arg));
+
+               /*
+                * One optional operand -- the return value
+                * It can be either an immediate operand or a result that
+                * has been bubbled up the tree
+                */
+               if (op->common.value.arg) {
+
+                       /* Since we have a real Return(), delete any implicit return */
+
+                       acpi_ds_clear_implicit_return(walk_state);
+
+                       /* Return statement has an immediate operand */
+
+                       status =
+                           acpi_ds_create_operands(walk_state,
+                                                   op->common.value.arg);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       /*
+                        * If value being returned is a Reference (such as
+                        * an arg or local), resolve it now because it may
+                        * cease to exist at the end of the method.
+                        */
+                       status =
+                           acpi_ex_resolve_to_value(&walk_state->operands[0],
+                                                    walk_state);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       /*
+                        * Get the return value and save as the last result
+                        * value.  This is the only place where walk_state->return_desc
+                        * is set to anything other than zero!
+                        */
+                       walk_state->return_desc = walk_state->operands[0];
+               } else if (walk_state->result_count) {
+
+                       /* Since we have a real Return(), delete any implicit return */
+
+                       acpi_ds_clear_implicit_return(walk_state);
+
+                       /*
+                        * The return value has come from a previous calculation.
+                        *
+                        * If value being returned is a Reference (such as
+                        * an arg or local), resolve it now because it may
+                        * cease to exist at the end of the method.
+                        *
+                        * Allow references created by the Index operator to return
+                        * unchanged.
+                        */
+                       if ((ACPI_GET_DESCRIPTOR_TYPE
+                            (walk_state->results->results.obj_desc[0]) ==
+                            ACPI_DESC_TYPE_OPERAND)
+                           && ((walk_state->results->results.obj_desc[0])->
+                               common.type == ACPI_TYPE_LOCAL_REFERENCE)
+                           && ((walk_state->results->results.obj_desc[0])->
+                               reference.class != ACPI_REFCLASS_INDEX)) {
+                               status =
+                                   acpi_ex_resolve_to_value(&walk_state->
+                                                            results->results.
+                                                            obj_desc[0],
+                                                            walk_state);
+                               if (ACPI_FAILURE(status)) {
+                                       return (status);
+                               }
+                       }
+
+                       walk_state->return_desc =
+                           walk_state->results->results.obj_desc[0];
+               } else {
+                       /* No return operand */
+
+                       if (walk_state->num_operands) {
+                               acpi_ut_remove_reference(walk_state->
+                                                        operands[0]);
+                       }
+
+                       walk_state->operands[0] = NULL;
+                       walk_state->num_operands = 0;
+                       walk_state->return_desc = NULL;
+               }
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "Completed RETURN_OP State=%p, RetVal=%p\n",
+                                 walk_state, walk_state->return_desc));
+
+               /* End the control method execution right now */
+
+               status = AE_CTRL_TERMINATE;
+               break;
+
+       case AML_NOOP_OP:
+
+               /* Just do nothing! */
+               break;
+
+       case AML_BREAK_POINT_OP:
+
+               /*
+                * Set the single-step flag. This will cause the debugger (if present)
+                * to break to the console within the AML debugger at the start of the
+                * next AML instruction.
+                */
+               ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
+               ACPI_DEBUGGER_EXEC(acpi_os_printf
+                                  ("**break** Executed AML BreakPoint opcode\n"));
+
+               /* Call to the OSL in case OS wants a piece of the action */
+
+               status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
+                                       "Executed AML Breakpoint opcode");
+               break;
+
+       case AML_BREAK_OP:
+       case AML_CONTINUE_OP:   /* ACPI 2.0 */
+
+               /* Pop and delete control states until we find a while */
+
+               while (walk_state->control_state &&
+                      (walk_state->control_state->control.opcode !=
+                       AML_WHILE_OP)) {
+                       control_state =
+                           acpi_ut_pop_generic_state(&walk_state->
+                                                     control_state);
+                       acpi_ut_delete_generic_state(control_state);
+               }
+
+               /* No while found? */
+
+               if (!walk_state->control_state) {
+                       return (AE_AML_NO_WHILE);
+               }
+
+               /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
+
+               walk_state->aml_last_while =
+                   walk_state->control_state->control.package_end;
+
+               /* Return status depending on opcode */
+
+               if (op->common.aml_opcode == AML_BREAK_OP) {
+                       status = AE_CTRL_BREAK;
+               } else {
+                       status = AE_CTRL_CONTINUE;
+               }
+               break;
+
+       default:
+
+               ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
+                           op->common.aml_opcode, op));
+
+               status = AE_AML_BAD_OPCODE;
+               break;
+       }
+
+       return (status);
+}
index bbecf293aeebfcd8729a2d9b43404e187af7c17b..c627a288e027644d5ef537eb1776098085811ed4 100644 (file)
@@ -1,7 +1,6 @@
 /******************************************************************************
  *
- * Module Name: dsopcode - Dispatcher Op Region support and handling of
- *                         "control" opcodes
+ * Module Name: dsopcode - Dispatcher suport for regions and fields
  *
  *****************************************************************************/
 
 ACPI_MODULE_NAME("dsopcode")
 
 /* Local prototypes */
-static acpi_status
-acpi_ds_execute_arguments(struct acpi_namespace_node *node,
-                         struct acpi_namespace_node *scope_node,
-                         u32 aml_length, u8 * aml_start);
-
 static acpi_status
 acpi_ds_init_buffer_field(u16 aml_opcode,
                          union acpi_operand_object *obj_desc,
@@ -69,361 +63,6 @@ acpi_ds_init_buffer_field(u16 aml_opcode,
                          union acpi_operand_object *length_desc,
                          union acpi_operand_object *result_desc);
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_execute_arguments
- *
- * PARAMETERS:  Node                - Object NS node
- *              scope_node          - Parent NS node
- *              aml_length          - Length of executable AML
- *              aml_start           - Pointer to the AML
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Late (deferred) execution of region or field arguments
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ds_execute_arguments(struct acpi_namespace_node *node,
-                         struct acpi_namespace_node *scope_node,
-                         u32 aml_length, u8 * aml_start)
-{
-       acpi_status status;
-       union acpi_parse_object *op;
-       struct acpi_walk_state *walk_state;
-
-       ACPI_FUNCTION_TRACE(ds_execute_arguments);
-
-       /*
-        * Allocate a new parser op to be the root of the parsed tree
-        */
-       op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
-       if (!op) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
-       }
-
-       /* Save the Node for use in acpi_ps_parse_aml */
-
-       op->common.node = scope_node;
-
-       /* Create and initialize a new parser state */
-
-       walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
-       if (!walk_state) {
-               status = AE_NO_MEMORY;
-               goto cleanup;
-       }
-
-       status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-                                      aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
-       if (ACPI_FAILURE(status)) {
-               acpi_ds_delete_walk_state(walk_state);
-               goto cleanup;
-       }
-
-       /* Mark this parse as a deferred opcode */
-
-       walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP;
-       walk_state->deferred_node = node;
-
-       /* Pass1: Parse the entire declaration */
-
-       status = acpi_ps_parse_aml(walk_state);
-       if (ACPI_FAILURE(status)) {
-               goto cleanup;
-       }
-
-       /* Get and init the Op created above */
-
-       op->common.node = node;
-       acpi_ps_delete_parse_tree(op);
-
-       /* Evaluate the deferred arguments */
-
-       op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
-       if (!op) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
-       }
-
-       op->common.node = scope_node;
-
-       /* Create and initialize a new parser state */
-
-       walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
-       if (!walk_state) {
-               status = AE_NO_MEMORY;
-               goto cleanup;
-       }
-
-       /* Execute the opcode and arguments */
-
-       status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-                                      aml_length, NULL, ACPI_IMODE_EXECUTE);
-       if (ACPI_FAILURE(status)) {
-               acpi_ds_delete_walk_state(walk_state);
-               goto cleanup;
-       }
-
-       /* Mark this execution as a deferred opcode */
-
-       walk_state->deferred_node = node;
-       status = acpi_ps_parse_aml(walk_state);
-
-      cleanup:
-       acpi_ps_delete_parse_tree(op);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_get_buffer_field_arguments
- *
- * PARAMETERS:  obj_desc        - A valid buffer_field object
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late
- *              evaluation of these field attributes.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
-{
-       union acpi_operand_object *extra_desc;
-       struct acpi_namespace_node *node;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc);
-
-       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Get the AML pointer (method object) and buffer_field node */
-
-       extra_desc = acpi_ns_get_secondary_object(obj_desc);
-       node = obj_desc->buffer_field.node;
-
-       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
-                       (ACPI_TYPE_BUFFER_FIELD, node, NULL));
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n",
-                         acpi_ut_get_node_name(node)));
-
-       /* Execute the AML code for the term_arg arguments */
-
-       status = acpi_ds_execute_arguments(node, node->parent,
-                                          extra_desc->extra.aml_length,
-                                          extra_desc->extra.aml_start);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_get_bank_field_arguments
- *
- * PARAMETERS:  obj_desc        - A valid bank_field object
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Get bank_field bank_value. This implements the late
- *              evaluation of these field attributes.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
-{
-       union acpi_operand_object *extra_desc;
-       struct acpi_namespace_node *node;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
-
-       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Get the AML pointer (method object) and bank_field node */
-
-       extra_desc = acpi_ns_get_secondary_object(obj_desc);
-       node = obj_desc->bank_field.node;
-
-       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
-                       (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
-                         acpi_ut_get_node_name(node)));
-
-       /* Execute the AML code for the term_arg arguments */
-
-       status = acpi_ds_execute_arguments(node, node->parent,
-                                          extra_desc->extra.aml_length,
-                                          extra_desc->extra.aml_start);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_get_buffer_arguments
- *
- * PARAMETERS:  obj_desc        - A valid Buffer object
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Get Buffer length and initializer byte list.  This implements
- *              the late evaluation of these attributes.
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc)
-{
-       struct acpi_namespace_node *node;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc);
-
-       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Get the Buffer node */
-
-       node = obj_desc->buffer.node;
-       if (!node) {
-               ACPI_ERROR((AE_INFO,
-                           "No pointer back to namespace node in buffer object %p",
-                           obj_desc));
-               return_ACPI_STATUS(AE_AML_INTERNAL);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n"));
-
-       /* Execute the AML code for the term_arg arguments */
-
-       status = acpi_ds_execute_arguments(node, node,
-                                          obj_desc->buffer.aml_length,
-                                          obj_desc->buffer.aml_start);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_get_package_arguments
- *
- * PARAMETERS:  obj_desc        - A valid Package object
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Get Package length and initializer byte list.  This implements
- *              the late evaluation of these attributes.
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc)
-{
-       struct acpi_namespace_node *node;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc);
-
-       if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Get the Package node */
-
-       node = obj_desc->package.node;
-       if (!node) {
-               ACPI_ERROR((AE_INFO,
-                           "No pointer back to namespace node in package %p",
-                           obj_desc));
-               return_ACPI_STATUS(AE_AML_INTERNAL);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n"));
-
-       /* Execute the AML code for the term_arg arguments */
-
-       status = acpi_ds_execute_arguments(node, node,
-                                          obj_desc->package.aml_length,
-                                          obj_desc->package.aml_start);
-       return_ACPI_STATUS(status);
-}
-
-/*****************************************************************************
- *
- * FUNCTION:    acpi_ds_get_region_arguments
- *
- * PARAMETERS:  obj_desc        - A valid region object
- *
- * RETURN:      Status.
- *
- * DESCRIPTION: Get region address and length.  This implements the late
- *              evaluation of these region attributes.
- *
- ****************************************************************************/
-
-acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
-{
-       struct acpi_namespace_node *node;
-       acpi_status status;
-       union acpi_operand_object *extra_desc;
-
-       ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc);
-
-       if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       extra_desc = acpi_ns_get_secondary_object(obj_desc);
-       if (!extra_desc) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
-       }
-
-       /* Get the Region node */
-
-       node = obj_desc->region.node;
-
-       ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
-                       (ACPI_TYPE_REGION, node, NULL));
-
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n",
-                         acpi_ut_get_node_name(node),
-                         extra_desc->extra.aml_start));
-
-       /* Execute the argument AML */
-
-       status = acpi_ds_execute_arguments(node, node->parent,
-                                          extra_desc->extra.aml_length,
-                                          extra_desc->extra.aml_start);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Validate the region address/length via the host OS */
-
-       status = acpi_os_validate_address(obj_desc->region.space_id,
-                                         obj_desc->region.address,
-                                         (acpi_size) obj_desc->region.length,
-                                         acpi_ut_get_node_name(node));
-
-       if (ACPI_FAILURE(status)) {
-               /*
-                * Invalid address/length. We will emit an error message and mark
-                * the region as invalid, so that it will cause an additional error if
-                * it is ever used. Then return AE_OK.
-                */
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "During address validation of OpRegion [%4.4s]",
-                               node->name.ascii));
-               obj_desc->common.flags |= AOPOBJ_INVALID;
-               status = AE_OK;
-       }
-
-       return_ACPI_STATUS(status);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_initialize_region
@@ -826,8 +465,9 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Get region address and length
- *              Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ * DESCRIPTION: Get region address and length.
+ *              Called from acpi_ds_exec_end_op during data_table_region parse
+ *              tree walk.
  *
  ******************************************************************************/
 
@@ -1114,360 +754,3 @@ acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
        acpi_ut_remove_reference(operand_desc);
        return_ACPI_STATUS(status);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_exec_begin_control_op
- *
- * PARAMETERS:  walk_list       - The list that owns the walk stack
- *              Op              - The control Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Handles all control ops encountered during control method
- *              execution.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
-                             union acpi_parse_object *op)
-{
-       acpi_status status = AE_OK;
-       union acpi_generic_state *control_state;
-
-       ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op,
-                         op->common.aml_opcode, walk_state));
-
-       switch (op->common.aml_opcode) {
-       case AML_WHILE_OP:
-
-               /*
-                * If this is an additional iteration of a while loop, continue.
-                * There is no need to allocate a new control state.
-                */
-               if (walk_state->control_state) {
-                       if (walk_state->control_state->control.aml_predicate_start
-                               == (walk_state->parser_state.aml - 1)) {
-
-                               /* Reset the state to start-of-loop */
-
-                               walk_state->control_state->common.state =
-                                   ACPI_CONTROL_CONDITIONAL_EXECUTING;
-                               break;
-                       }
-               }
-
-               /*lint -fallthrough */
-
-       case AML_IF_OP:
-
-               /*
-                * IF/WHILE: Create a new control state to manage these
-                * constructs. We need to manage these as a stack, in order
-                * to handle nesting.
-                */
-               control_state = acpi_ut_create_control_state();
-               if (!control_state) {
-                       status = AE_NO_MEMORY;
-                       break;
-               }
-               /*
-                * Save a pointer to the predicate for multiple executions
-                * of a loop
-                */
-               control_state->control.aml_predicate_start =
-                   walk_state->parser_state.aml - 1;
-               control_state->control.package_end =
-                   walk_state->parser_state.pkg_end;
-               control_state->control.opcode = op->common.aml_opcode;
-
-               /* Push the control state on this walk's control stack */
-
-               acpi_ut_push_generic_state(&walk_state->control_state,
-                                          control_state);
-               break;
-
-       case AML_ELSE_OP:
-
-               /* Predicate is in the state object */
-               /* If predicate is true, the IF was executed, ignore ELSE part */
-
-               if (walk_state->last_predicate) {
-                       status = AE_CTRL_TRUE;
-               }
-
-               break;
-
-       case AML_RETURN_OP:
-
-               break;
-
-       default:
-               break;
-       }
-
-       return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_exec_end_control_op
- *
- * PARAMETERS:  walk_list       - The list that owns the walk stack
- *              Op              - The control Op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Handles all control ops encountered during control method
- *              execution.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
-                           union acpi_parse_object * op)
-{
-       acpi_status status = AE_OK;
-       union acpi_generic_state *control_state;
-
-       ACPI_FUNCTION_NAME(ds_exec_end_control_op);
-
-       switch (op->common.aml_opcode) {
-       case AML_IF_OP:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
-
-               /*
-                * Save the result of the predicate in case there is an
-                * ELSE to come
-                */
-               walk_state->last_predicate =
-                   (u8) walk_state->control_state->common.value;
-
-               /*
-                * Pop the control state that was created at the start
-                * of the IF and free it
-                */
-               control_state =
-                   acpi_ut_pop_generic_state(&walk_state->control_state);
-               acpi_ut_delete_generic_state(control_state);
-               break;
-
-       case AML_ELSE_OP:
-
-               break;
-
-       case AML_WHILE_OP:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
-
-               control_state = walk_state->control_state;
-               if (control_state->common.value) {
-
-                       /* Predicate was true, the body of the loop was just executed */
-
-                       /*
-                        * This loop counter mechanism allows the interpreter to escape
-                        * possibly infinite loops. This can occur in poorly written AML
-                        * when the hardware does not respond within a while loop and the
-                        * loop does not implement a timeout.
-                        */
-                       control_state->control.loop_count++;
-                       if (control_state->control.loop_count >
-                               ACPI_MAX_LOOP_ITERATIONS) {
-                               status = AE_AML_INFINITE_LOOP;
-                               break;
-                       }
-
-                       /*
-                        * Go back and evaluate the predicate and maybe execute the loop
-                        * another time
-                        */
-                       status = AE_CTRL_PENDING;
-                       walk_state->aml_last_while =
-                           control_state->control.aml_predicate_start;
-                       break;
-               }
-
-               /* Predicate was false, terminate this while loop */
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "[WHILE_OP] termination! Op=%p\n", op));
-
-               /* Pop this control state and free it */
-
-               control_state =
-                   acpi_ut_pop_generic_state(&walk_state->control_state);
-               acpi_ut_delete_generic_state(control_state);
-               break;
-
-       case AML_RETURN_OP:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "[RETURN_OP] Op=%p Arg=%p\n", op,
-                                 op->common.value.arg));
-
-               /*
-                * One optional operand -- the return value
-                * It can be either an immediate operand or a result that
-                * has been bubbled up the tree
-                */
-               if (op->common.value.arg) {
-
-                       /* Since we have a real Return(), delete any implicit return */
-
-                       acpi_ds_clear_implicit_return(walk_state);
-
-                       /* Return statement has an immediate operand */
-
-                       status =
-                           acpi_ds_create_operands(walk_state,
-                                                   op->common.value.arg);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-
-                       /*
-                        * If value being returned is a Reference (such as
-                        * an arg or local), resolve it now because it may
-                        * cease to exist at the end of the method.
-                        */
-                       status =
-                           acpi_ex_resolve_to_value(&walk_state->operands[0],
-                                                    walk_state);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-
-                       /*
-                        * Get the return value and save as the last result
-                        * value.  This is the only place where walk_state->return_desc
-                        * is set to anything other than zero!
-                        */
-                       walk_state->return_desc = walk_state->operands[0];
-               } else if (walk_state->result_count) {
-
-                       /* Since we have a real Return(), delete any implicit return */
-
-                       acpi_ds_clear_implicit_return(walk_state);
-
-                       /*
-                        * The return value has come from a previous calculation.
-                        *
-                        * If value being returned is a Reference (such as
-                        * an arg or local), resolve it now because it may
-                        * cease to exist at the end of the method.
-                        *
-                        * Allow references created by the Index operator to return unchanged.
-                        */
-                       if ((ACPI_GET_DESCRIPTOR_TYPE
-                            (walk_state->results->results.obj_desc[0]) ==
-                            ACPI_DESC_TYPE_OPERAND)
-                           && ((walk_state->results->results.obj_desc[0])->
-                               common.type == ACPI_TYPE_LOCAL_REFERENCE)
-                           && ((walk_state->results->results.obj_desc[0])->
-                               reference.class != ACPI_REFCLASS_INDEX)) {
-                               status =
-                                   acpi_ex_resolve_to_value(&walk_state->
-                                                            results->results.
-                                                            obj_desc[0],
-                                                            walk_state);
-                               if (ACPI_FAILURE(status)) {
-                                       return (status);
-                               }
-                       }
-
-                       walk_state->return_desc =
-                           walk_state->results->results.obj_desc[0];
-               } else {
-                       /* No return operand */
-
-                       if (walk_state->num_operands) {
-                               acpi_ut_remove_reference(walk_state->
-                                                        operands[0]);
-                       }
-
-                       walk_state->operands[0] = NULL;
-                       walk_state->num_operands = 0;
-                       walk_state->return_desc = NULL;
-               }
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "Completed RETURN_OP State=%p, RetVal=%p\n",
-                                 walk_state, walk_state->return_desc));
-
-               /* End the control method execution right now */
-
-               status = AE_CTRL_TERMINATE;
-               break;
-
-       case AML_NOOP_OP:
-
-               /* Just do nothing! */
-               break;
-
-       case AML_BREAK_POINT_OP:
-
-               /*
-                * Set the single-step flag. This will cause the debugger (if present)
-                * to break to the console within the AML debugger at the start of the
-                * next AML instruction.
-                */
-               ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
-               ACPI_DEBUGGER_EXEC(acpi_os_printf
-                                  ("**break** Executed AML BreakPoint opcode\n"));
-
-               /* Call to the OSL in case OS wants a piece of the action */
-
-               status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
-                                       "Executed AML Breakpoint opcode");
-               break;
-
-       case AML_BREAK_OP:
-       case AML_CONTINUE_OP:   /* ACPI 2.0 */
-
-               /* Pop and delete control states until we find a while */
-
-               while (walk_state->control_state &&
-                      (walk_state->control_state->control.opcode !=
-                       AML_WHILE_OP)) {
-                       control_state =
-                           acpi_ut_pop_generic_state(&walk_state->
-                                                     control_state);
-                       acpi_ut_delete_generic_state(control_state);
-               }
-
-               /* No while found? */
-
-               if (!walk_state->control_state) {
-                       return (AE_AML_NO_WHILE);
-               }
-
-               /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
-
-               walk_state->aml_last_while =
-                   walk_state->control_state->control.package_end;
-
-               /* Return status depending on opcode */
-
-               if (op->common.aml_opcode == AML_BREAK_OP) {
-                       status = AE_CTRL_BREAK;
-               } else {
-                       status = AE_CTRL_CONTINUE;
-               }
-               break;
-
-       default:
-
-               ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
-                           op->common.aml_opcode, op));
-
-               status = AE_AML_BAD_OPCODE;
-               break;
-       }
-
-       return (status);
-}
index 52566ff5e9034bfbb91e06c9132bea52ec91ef8c..23a3b1ab20c1c0ec0cc62cdbc5419c77da6fcb8f 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Module Name: dswload - Dispatcher namespace load callbacks
+ * Module Name: dswload - Dispatcher first pass namespace load callbacks
  *
  *****************************************************************************/
 
@@ -48,7 +48,6 @@
 #include "acdispat.h"
 #include "acinterp.h"
 #include "acnamesp.h"
-#include "acevents.h"
 
 #ifdef ACPI_ASL_COMPILER
 #include <acpi/acdisasm.h>
@@ -537,670 +536,3 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
 
        return_ACPI_STATUS(status);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_load2_begin_op
- *
- * PARAMETERS:  walk_state      - Current state of the parse tree walk
- *              out_op          - Wher to return op if a new one is created
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Descending callback used during the loading of ACPI tables.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
-                      union acpi_parse_object **out_op)
-{
-       union acpi_parse_object *op;
-       struct acpi_namespace_node *node;
-       acpi_status status;
-       acpi_object_type object_type;
-       char *buffer_ptr;
-       u32 flags;
-
-       ACPI_FUNCTION_TRACE(ds_load2_begin_op);
-
-       op = walk_state->op;
-       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
-                         walk_state));
-
-       if (op) {
-               if ((walk_state->control_state) &&
-                   (walk_state->control_state->common.state ==
-                    ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
-
-                       /* We are executing a while loop outside of a method */
-
-                       status = acpi_ds_exec_begin_op(walk_state, out_op);
-                       return_ACPI_STATUS(status);
-               }
-
-               /* We only care about Namespace opcodes here */
-
-               if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
-                    (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
-                   (!(walk_state->op_info->flags & AML_NAMED))) {
-                       return_ACPI_STATUS(AE_OK);
-               }
-
-               /* Get the name we are going to enter or lookup in the namespace */
-
-               if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
-
-                       /* For Namepath op, get the path string */
-
-                       buffer_ptr = op->common.value.string;
-                       if (!buffer_ptr) {
-
-                               /* No name, just exit */
-
-                               return_ACPI_STATUS(AE_OK);
-                       }
-               } else {
-                       /* Get name from the op */
-
-                       buffer_ptr = ACPI_CAST_PTR(char, &op->named.name);
-               }
-       } else {
-               /* Get the namestring from the raw AML */
-
-               buffer_ptr =
-                   acpi_ps_get_next_namestring(&walk_state->parser_state);
-       }
-
-       /* Map the opcode into an internal object type */
-
-       object_type = walk_state->op_info->object_type;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                         "State=%p Op=%p Type=%X\n", walk_state, op,
-                         object_type));
-
-       switch (walk_state->opcode) {
-       case AML_FIELD_OP:
-       case AML_BANK_FIELD_OP:
-       case AML_INDEX_FIELD_OP:
-
-               node = NULL;
-               status = AE_OK;
-               break;
-
-       case AML_INT_NAMEPATH_OP:
-               /*
-                * The name_path is an object reference to an existing object.
-                * Don't enter the name into the namespace, but look it up
-                * for use later.
-                */
-               status =
-                   acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
-                                  object_type, ACPI_IMODE_EXECUTE,
-                                  ACPI_NS_SEARCH_PARENT, walk_state, &(node));
-               break;
-
-       case AML_SCOPE_OP:
-
-               /* Special case for Scope(\) -> refers to the Root node */
-
-               if (op && (op->named.node == acpi_gbl_root_node)) {
-                       node = op->named.node;
-
-                       status =
-                           acpi_ds_scope_stack_push(node, object_type,
-                                                    walk_state);
-                       if (ACPI_FAILURE(status)) {
-                               return_ACPI_STATUS(status);
-                       }
-               } else {
-                       /*
-                        * The Path is an object reference to an existing object.
-                        * Don't enter the name into the namespace, but look it up
-                        * for use later.
-                        */
-                       status =
-                           acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
-                                          object_type, ACPI_IMODE_EXECUTE,
-                                          ACPI_NS_SEARCH_PARENT, walk_state,
-                                          &(node));
-                       if (ACPI_FAILURE(status)) {
-#ifdef ACPI_ASL_COMPILER
-                               if (status == AE_NOT_FOUND) {
-                                       status = AE_OK;
-                               } else {
-                                       ACPI_ERROR_NAMESPACE(buffer_ptr,
-                                                            status);
-                               }
-#else
-                               ACPI_ERROR_NAMESPACE(buffer_ptr, status);
-#endif
-                               return_ACPI_STATUS(status);
-                       }
-               }
-
-               /*
-                * We must check to make sure that the target is
-                * one of the opcodes that actually opens a scope
-                */
-               switch (node->type) {
-               case ACPI_TYPE_ANY:
-               case ACPI_TYPE_LOCAL_SCOPE:     /* Scope */
-               case ACPI_TYPE_DEVICE:
-               case ACPI_TYPE_POWER:
-               case ACPI_TYPE_PROCESSOR:
-               case ACPI_TYPE_THERMAL:
-
-                       /* These are acceptable types */
-                       break;
-
-               case ACPI_TYPE_INTEGER:
-               case ACPI_TYPE_STRING:
-               case ACPI_TYPE_BUFFER:
-
-                       /*
-                        * These types we will allow, but we will change the type.
-                        * This enables some existing code of the form:
-                        *
-                        *  Name (DEB, 0)
-                        *  Scope (DEB) { ... }
-                        */
-                       ACPI_WARNING((AE_INFO,
-                                     "Type override - [%4.4s] had invalid type (%s) "
-                                     "for Scope operator, changed to type ANY\n",
-                                     acpi_ut_get_node_name(node),
-                                     acpi_ut_get_type_name(node->type)));
-
-                       node->type = ACPI_TYPE_ANY;
-                       walk_state->scope_info->common.value = ACPI_TYPE_ANY;
-                       break;
-
-               default:
-
-                       /* All other types are an error */
-
-                       ACPI_ERROR((AE_INFO,
-                                   "Invalid type (%s) for target of "
-                                   "Scope operator [%4.4s] (Cannot override)",
-                                   acpi_ut_get_type_name(node->type),
-                                   acpi_ut_get_node_name(node)));
-
-                       return (AE_AML_OPERAND_TYPE);
-               }
-               break;
-
-       default:
-
-               /* All other opcodes */
-
-               if (op && op->common.node) {
-
-                       /* This op/node was previously entered into the namespace */
-
-                       node = op->common.node;
-
-                       if (acpi_ns_opens_scope(object_type)) {
-                               status =
-                                   acpi_ds_scope_stack_push(node, object_type,
-                                                            walk_state);
-                               if (ACPI_FAILURE(status)) {
-                                       return_ACPI_STATUS(status);
-                               }
-                       }
-
-                       return_ACPI_STATUS(AE_OK);
-               }
-
-               /*
-                * Enter the named type into the internal namespace. We enter the name
-                * as we go downward in the parse tree. Any necessary subobjects that
-                * involve arguments to the opcode must be created as we go back up the
-                * parse tree later.
-                *
-                * Note: Name may already exist if we are executing a deferred opcode.
-                */
-               if (walk_state->deferred_node) {
-
-                       /* This name is already in the namespace, get the node */
-
-                       node = walk_state->deferred_node;
-                       status = AE_OK;
-                       break;
-               }
-
-               flags = ACPI_NS_NO_UPSEARCH;
-               if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
-
-                       /* Execution mode, node cannot already exist, node is temporary */
-
-                       flags |= ACPI_NS_ERROR_IF_FOUND;
-
-                       if (!
-                           (walk_state->
-                            parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
-                               flags |= ACPI_NS_TEMPORARY;
-                       }
-               }
-
-               /* Add new entry or lookup existing entry */
-
-               status =
-                   acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
-                                  object_type, ACPI_IMODE_LOAD_PASS2, flags,
-                                  walk_state, &node);
-
-               if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                         "***New Node [%4.4s] %p is temporary\n",
-                                         acpi_ut_get_node_name(node), node));
-               }
-               break;
-       }
-
-       if (ACPI_FAILURE(status)) {
-               ACPI_ERROR_NAMESPACE(buffer_ptr, status);
-               return_ACPI_STATUS(status);
-       }
-
-       if (!op) {
-
-               /* Create a new op */
-
-               op = acpi_ps_alloc_op(walk_state->opcode);
-               if (!op) {
-                       return_ACPI_STATUS(AE_NO_MEMORY);
-               }
-
-               /* Initialize the new op */
-
-               if (node) {
-                       op->named.name = node->name.integer;
-               }
-               *out_op = op;
-       }
-
-       /*
-        * Put the Node in the "op" object that the parser uses, so we
-        * can get it again quickly when this scope is closed
-        */
-       op->common.node = node;
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ds_load2_end_op
- *
- * PARAMETERS:  walk_state      - Current state of the parse tree walk
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Ascending callback used during the loading of the namespace,
- *              both control methods and everything else.
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
-{
-       union acpi_parse_object *op;
-       acpi_status status = AE_OK;
-       acpi_object_type object_type;
-       struct acpi_namespace_node *node;
-       union acpi_parse_object *arg;
-       struct acpi_namespace_node *new_node;
-#ifndef ACPI_NO_METHOD_EXECUTION
-       u32 i;
-       u8 region_space;
-#endif
-
-       ACPI_FUNCTION_TRACE(ds_load2_end_op);
-
-       op = walk_state->op;
-       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
-                         walk_state->op_info->name, op, walk_state));
-
-       /* Check if opcode had an associated namespace object */
-
-       if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       if (op->common.aml_opcode == AML_SCOPE_OP) {
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "Ending scope Op=%p State=%p\n", op,
-                                 walk_state));
-       }
-
-       object_type = walk_state->op_info->object_type;
-
-       /*
-        * Get the Node/name from the earlier lookup
-        * (It was saved in the *op structure)
-        */
-       node = op->common.node;
-
-       /*
-        * Put the Node on the object stack (Contains the ACPI Name of
-        * this object)
-        */
-       walk_state->operands[0] = (void *)node;
-       walk_state->num_operands = 1;
-
-       /* Pop the scope stack */
-
-       if (acpi_ns_opens_scope(object_type) &&
-           (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "(%s) Popping scope for Op %p\n",
-                                 acpi_ut_get_type_name(object_type), op));
-
-               status = acpi_ds_scope_stack_pop(walk_state);
-               if (ACPI_FAILURE(status)) {
-                       goto cleanup;
-               }
-       }
-
-       /*
-        * Named operations are as follows:
-        *
-        * AML_ALIAS
-        * AML_BANKFIELD
-        * AML_CREATEBITFIELD
-        * AML_CREATEBYTEFIELD
-        * AML_CREATEDWORDFIELD
-        * AML_CREATEFIELD
-        * AML_CREATEQWORDFIELD
-        * AML_CREATEWORDFIELD
-        * AML_DATA_REGION
-        * AML_DEVICE
-        * AML_EVENT
-        * AML_FIELD
-        * AML_INDEXFIELD
-        * AML_METHOD
-        * AML_METHODCALL
-        * AML_MUTEX
-        * AML_NAME
-        * AML_NAMEDFIELD
-        * AML_OPREGION
-        * AML_POWERRES
-        * AML_PROCESSOR
-        * AML_SCOPE
-        * AML_THERMALZONE
-        */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                         "Create-Load [%s] State=%p Op=%p NamedObj=%p\n",
-                         acpi_ps_get_opcode_name(op->common.aml_opcode),
-                         walk_state, op, node));
-
-       /* Decode the opcode */
-
-       arg = op->common.value.arg;
-
-       switch (walk_state->op_info->type) {
-#ifndef ACPI_NO_METHOD_EXECUTION
-
-       case AML_TYPE_CREATE_FIELD:
-               /*
-                * Create the field object, but the field buffer and index must
-                * be evaluated later during the execution phase
-                */
-               status = acpi_ds_create_buffer_field(op, walk_state);
-               break;
-
-       case AML_TYPE_NAMED_FIELD:
-               /*
-                * If we are executing a method, initialize the field
-                */
-               if (walk_state->method_node) {
-                       status = acpi_ds_init_field_objects(op, walk_state);
-               }
-
-               switch (op->common.aml_opcode) {
-               case AML_INDEX_FIELD_OP:
-
-                       status =
-                           acpi_ds_create_index_field(op,
-                                                      (acpi_handle) arg->
-                                                      common.node, walk_state);
-                       break;
-
-               case AML_BANK_FIELD_OP:
-
-                       status =
-                           acpi_ds_create_bank_field(op, arg->common.node,
-                                                     walk_state);
-                       break;
-
-               case AML_FIELD_OP:
-
-                       status =
-                           acpi_ds_create_field(op, arg->common.node,
-                                                walk_state);
-                       break;
-
-               default:
-                       /* All NAMED_FIELD opcodes must be handled above */
-                       break;
-               }
-               break;
-
-       case AML_TYPE_NAMED_SIMPLE:
-
-               status = acpi_ds_create_operands(walk_state, arg);
-               if (ACPI_FAILURE(status)) {
-                       goto cleanup;
-               }
-
-               switch (op->common.aml_opcode) {
-               case AML_PROCESSOR_OP:
-
-                       status = acpi_ex_create_processor(walk_state);
-                       break;
-
-               case AML_POWER_RES_OP:
-
-                       status = acpi_ex_create_power_resource(walk_state);
-                       break;
-
-               case AML_MUTEX_OP:
-
-                       status = acpi_ex_create_mutex(walk_state);
-                       break;
-
-               case AML_EVENT_OP:
-
-                       status = acpi_ex_create_event(walk_state);
-                       break;
-
-               case AML_ALIAS_OP:
-
-                       status = acpi_ex_create_alias(walk_state);
-                       break;
-
-               default:
-                       /* Unknown opcode */
-
-                       status = AE_OK;
-                       goto cleanup;
-               }
-
-               /* Delete operands */
-
-               for (i = 1; i < walk_state->num_operands; i++) {
-                       acpi_ut_remove_reference(walk_state->operands[i]);
-                       walk_state->operands[i] = NULL;
-               }
-
-               break;
-#endif                         /* ACPI_NO_METHOD_EXECUTION */
-
-       case AML_TYPE_NAMED_COMPLEX:
-
-               switch (op->common.aml_opcode) {
-#ifndef ACPI_NO_METHOD_EXECUTION
-               case AML_REGION_OP:
-               case AML_DATA_REGION_OP:
-
-                       if (op->common.aml_opcode == AML_REGION_OP) {
-                               region_space = (acpi_adr_space_type)
-                                   ((op->common.value.arg)->common.value.
-                                    integer);
-                       } else {
-                               region_space = REGION_DATA_TABLE;
-                       }
-
-                       /*
-                        * The op_region is not fully parsed at this time. The only valid
-                        * argument is the space_id. (We must save the address of the
-                        * AML of the address and length operands)
-                        *
-                        * If we have a valid region, initialize it. The namespace is
-                        * unlocked at this point.
-                        *
-                        * Need to unlock interpreter if it is locked (if we are running
-                        * a control method), in order to allow _REG methods to be run
-                        * during acpi_ev_initialize_region.
-                        */
-                       if (walk_state->method_node) {
-                               /*
-                                * Executing a method: initialize the region and unlock
-                                * the interpreter
-                                */
-                               status =
-                                   acpi_ex_create_region(op->named.data,
-                                                         op->named.length,
-                                                         region_space,
-                                                         walk_state);
-                               if (ACPI_FAILURE(status)) {
-                                       return (status);
-                               }
-
-                               acpi_ex_exit_interpreter();
-                       }
-
-                       status =
-                           acpi_ev_initialize_region
-                           (acpi_ns_get_attached_object(node), FALSE);
-                       if (walk_state->method_node) {
-                               acpi_ex_enter_interpreter();
-                       }
-
-                       if (ACPI_FAILURE(status)) {
-                               /*
-                                *  If AE_NOT_EXIST is returned, it is not fatal
-                                *  because many regions get created before a handler
-                                *  is installed for said region.
-                                */
-                               if (AE_NOT_EXIST == status) {
-                                       status = AE_OK;
-                               }
-                       }
-                       break;
-
-               case AML_NAME_OP:
-
-                       status = acpi_ds_create_node(walk_state, node, op);
-                       break;
-
-               case AML_METHOD_OP:
-                       /*
-                        * method_op pkg_length name_string method_flags term_list
-                        *
-                        * Note: We must create the method node/object pair as soon as we
-                        * see the method declaration. This allows later pass1 parsing
-                        * of invocations of the method (need to know the number of
-                        * arguments.)
-                        */
-                       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                         "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
-                                         walk_state, op, op->named.node));
-
-                       if (!acpi_ns_get_attached_object(op->named.node)) {
-                               walk_state->operands[0] =
-                                   ACPI_CAST_PTR(void, op->named.node);
-                               walk_state->num_operands = 1;
-
-                               status =
-                                   acpi_ds_create_operands(walk_state,
-                                                           op->common.value.
-                                                           arg);
-                               if (ACPI_SUCCESS(status)) {
-                                       status =
-                                           acpi_ex_create_method(op->named.
-                                                                 data,
-                                                                 op->named.
-                                                                 length,
-                                                                 walk_state);
-                               }
-                               walk_state->operands[0] = NULL;
-                               walk_state->num_operands = 0;
-
-                               if (ACPI_FAILURE(status)) {
-                                       return_ACPI_STATUS(status);
-                               }
-                       }
-                       break;
-
-#endif                         /* ACPI_NO_METHOD_EXECUTION */
-
-               default:
-                       /* All NAMED_COMPLEX opcodes must be handled above */
-                       break;
-               }
-               break;
-
-       case AML_CLASS_INTERNAL:
-
-               /* case AML_INT_NAMEPATH_OP: */
-               break;
-
-       case AML_CLASS_METHOD_CALL:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                                 "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n",
-                                 walk_state, op, node));
-
-               /*
-                * Lookup the method name and save the Node
-                */
-               status =
-                   acpi_ns_lookup(walk_state->scope_info,
-                                  arg->common.value.string, ACPI_TYPE_ANY,
-                                  ACPI_IMODE_LOAD_PASS2,
-                                  ACPI_NS_SEARCH_PARENT |
-                                  ACPI_NS_DONT_OPEN_SCOPE, walk_state,
-                                  &(new_node));
-               if (ACPI_SUCCESS(status)) {
-                       /*
-                        * Make sure that what we found is indeed a method
-                        * We didn't search for a method on purpose, to see if the name
-                        * would resolve
-                        */
-                       if (new_node->type != ACPI_TYPE_METHOD) {
-                               status = AE_AML_OPERAND_TYPE;
-                       }
-
-                       /* We could put the returned object (Node) on the object stack for
-                        * later, but for now, we will put it in the "op" object that the
-                        * parser uses, so we can get it again at the end of this scope
-                        */
-                       op->common.node = new_node;
-               } else {
-                       ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
-               }
-               break;
-
-       default:
-               break;
-       }
-
-      cleanup:
-
-       /* Remove the Node pushed at the very beginning */
-
-       walk_state->operands[0] = NULL;
-       walk_state->num_operands = 0;
-       return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
new file mode 100644 (file)
index 0000000..4be4e92
--- /dev/null
@@ -0,0 +1,720 @@
+/******************************************************************************
+ *
+ * Module Name: dswload2 - Dispatcher second pass namespace load callbacks
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
+
+#define _COMPONENT          ACPI_DISPATCHER
+ACPI_MODULE_NAME("dswload2")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_load2_begin_op
+ *
+ * PARAMETERS:  walk_state      - Current state of the parse tree walk
+ *              out_op          - Wher to return op if a new one is created
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
+                      union acpi_parse_object **out_op)
+{
+       union acpi_parse_object *op;
+       struct acpi_namespace_node *node;
+       acpi_status status;
+       acpi_object_type object_type;
+       char *buffer_ptr;
+       u32 flags;
+
+       ACPI_FUNCTION_TRACE(ds_load2_begin_op);
+
+       op = walk_state->op;
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
+                         walk_state));
+
+       if (op) {
+               if ((walk_state->control_state) &&
+                   (walk_state->control_state->common.state ==
+                    ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+
+                       /* We are executing a while loop outside of a method */
+
+                       status = acpi_ds_exec_begin_op(walk_state, out_op);
+                       return_ACPI_STATUS(status);
+               }
+
+               /* We only care about Namespace opcodes here */
+
+               if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
+                    (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
+                   (!(walk_state->op_info->flags & AML_NAMED))) {
+                       return_ACPI_STATUS(AE_OK);
+               }
+
+               /* Get the name we are going to enter or lookup in the namespace */
+
+               if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+
+                       /* For Namepath op, get the path string */
+
+                       buffer_ptr = op->common.value.string;
+                       if (!buffer_ptr) {
+
+                               /* No name, just exit */
+
+                               return_ACPI_STATUS(AE_OK);
+                       }
+               } else {
+                       /* Get name from the op */
+
+                       buffer_ptr = ACPI_CAST_PTR(char, &op->named.name);
+               }
+       } else {
+               /* Get the namestring from the raw AML */
+
+               buffer_ptr =
+                   acpi_ps_get_next_namestring(&walk_state->parser_state);
+       }
+
+       /* Map the opcode into an internal object type */
+
+       object_type = walk_state->op_info->object_type;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "State=%p Op=%p Type=%X\n", walk_state, op,
+                         object_type));
+
+       switch (walk_state->opcode) {
+       case AML_FIELD_OP:
+       case AML_BANK_FIELD_OP:
+       case AML_INDEX_FIELD_OP:
+
+               node = NULL;
+               status = AE_OK;
+               break;
+
+       case AML_INT_NAMEPATH_OP:
+               /*
+                * The name_path is an object reference to an existing object.
+                * Don't enter the name into the namespace, but look it up
+                * for use later.
+                */
+               status =
+                   acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+                                  object_type, ACPI_IMODE_EXECUTE,
+                                  ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+               break;
+
+       case AML_SCOPE_OP:
+
+               /* Special case for Scope(\) -> refers to the Root node */
+
+               if (op && (op->named.node == acpi_gbl_root_node)) {
+                       node = op->named.node;
+
+                       status =
+                           acpi_ds_scope_stack_push(node, object_type,
+                                                    walk_state);
+                       if (ACPI_FAILURE(status)) {
+                               return_ACPI_STATUS(status);
+                       }
+               } else {
+                       /*
+                        * The Path is an object reference to an existing object.
+                        * Don't enter the name into the namespace, but look it up
+                        * for use later.
+                        */
+                       status =
+                           acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+                                          object_type, ACPI_IMODE_EXECUTE,
+                                          ACPI_NS_SEARCH_PARENT, walk_state,
+                                          &(node));
+                       if (ACPI_FAILURE(status)) {
+#ifdef ACPI_ASL_COMPILER
+                               if (status == AE_NOT_FOUND) {
+                                       status = AE_OK;
+                               } else {
+                                       ACPI_ERROR_NAMESPACE(buffer_ptr,
+                                                            status);
+                               }
+#else
+                               ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+#endif
+                               return_ACPI_STATUS(status);
+                       }
+               }
+
+               /*
+                * We must check to make sure that the target is
+                * one of the opcodes that actually opens a scope
+                */
+               switch (node->type) {
+               case ACPI_TYPE_ANY:
+               case ACPI_TYPE_LOCAL_SCOPE:     /* Scope */
+               case ACPI_TYPE_DEVICE:
+               case ACPI_TYPE_POWER:
+               case ACPI_TYPE_PROCESSOR:
+               case ACPI_TYPE_THERMAL:
+
+                       /* These are acceptable types */
+                       break;
+
+               case ACPI_TYPE_INTEGER:
+               case ACPI_TYPE_STRING:
+               case ACPI_TYPE_BUFFER:
+
+                       /*
+                        * These types we will allow, but we will change the type.
+                        * This enables some existing code of the form:
+                        *
+                        *  Name (DEB, 0)
+                        *  Scope (DEB) { ... }
+                        */
+                       ACPI_WARNING((AE_INFO,
+                                     "Type override - [%4.4s] had invalid type (%s) "
+                                     "for Scope operator, changed to type ANY\n",
+                                     acpi_ut_get_node_name(node),
+                                     acpi_ut_get_type_name(node->type)));
+
+                       node->type = ACPI_TYPE_ANY;
+                       walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+                       break;
+
+               default:
+
+                       /* All other types are an error */
+
+                       ACPI_ERROR((AE_INFO,
+                                   "Invalid type (%s) for target of "
+                                   "Scope operator [%4.4s] (Cannot override)",
+                                   acpi_ut_get_type_name(node->type),
+                                   acpi_ut_get_node_name(node)));
+
+                       return (AE_AML_OPERAND_TYPE);
+               }
+               break;
+
+       default:
+
+               /* All other opcodes */
+
+               if (op && op->common.node) {
+
+                       /* This op/node was previously entered into the namespace */
+
+                       node = op->common.node;
+
+                       if (acpi_ns_opens_scope(object_type)) {
+                               status =
+                                   acpi_ds_scope_stack_push(node, object_type,
+                                                            walk_state);
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
+
+                       return_ACPI_STATUS(AE_OK);
+               }
+
+               /*
+                * Enter the named type into the internal namespace. We enter the name
+                * as we go downward in the parse tree. Any necessary subobjects that
+                * involve arguments to the opcode must be created as we go back up the
+                * parse tree later.
+                *
+                * Note: Name may already exist if we are executing a deferred opcode.
+                */
+               if (walk_state->deferred_node) {
+
+                       /* This name is already in the namespace, get the node */
+
+                       node = walk_state->deferred_node;
+                       status = AE_OK;
+                       break;
+               }
+
+               flags = ACPI_NS_NO_UPSEARCH;
+               if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+                       /* Execution mode, node cannot already exist, node is temporary */
+
+                       flags |= ACPI_NS_ERROR_IF_FOUND;
+
+                       if (!
+                           (walk_state->
+                            parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
+                               flags |= ACPI_NS_TEMPORARY;
+                       }
+               }
+
+               /* Add new entry or lookup existing entry */
+
+               status =
+                   acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+                                  object_type, ACPI_IMODE_LOAD_PASS2, flags,
+                                  walk_state, &node);
+
+               if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                         "***New Node [%4.4s] %p is temporary\n",
+                                         acpi_ut_get_node_name(node), node));
+               }
+               break;
+       }
+
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+               return_ACPI_STATUS(status);
+       }
+
+       if (!op) {
+
+               /* Create a new op */
+
+               op = acpi_ps_alloc_op(walk_state->opcode);
+               if (!op) {
+                       return_ACPI_STATUS(AE_NO_MEMORY);
+               }
+
+               /* Initialize the new op */
+
+               if (node) {
+                       op->named.name = node->name.integer;
+               }
+               *out_op = op;
+       }
+
+       /*
+        * Put the Node in the "op" object that the parser uses, so we
+        * can get it again quickly when this scope is closed
+        */
+       op->common.node = node;
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_load2_end_op
+ *
+ * PARAMETERS:  walk_state      - Current state of the parse tree walk
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ *              both control methods and everything else.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
+{
+       union acpi_parse_object *op;
+       acpi_status status = AE_OK;
+       acpi_object_type object_type;
+       struct acpi_namespace_node *node;
+       union acpi_parse_object *arg;
+       struct acpi_namespace_node *new_node;
+#ifndef ACPI_NO_METHOD_EXECUTION
+       u32 i;
+       u8 region_space;
+#endif
+
+       ACPI_FUNCTION_TRACE(ds_load2_end_op);
+
+       op = walk_state->op;
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
+                         walk_state->op_info->name, op, walk_state));
+
+       /* Check if opcode had an associated namespace object */
+
+       if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       if (op->common.aml_opcode == AML_SCOPE_OP) {
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "Ending scope Op=%p State=%p\n", op,
+                                 walk_state));
+       }
+
+       object_type = walk_state->op_info->object_type;
+
+       /*
+        * Get the Node/name from the earlier lookup
+        * (It was saved in the *op structure)
+        */
+       node = op->common.node;
+
+       /*
+        * Put the Node on the object stack (Contains the ACPI Name of
+        * this object)
+        */
+       walk_state->operands[0] = (void *)node;
+       walk_state->num_operands = 1;
+
+       /* Pop the scope stack */
+
+       if (acpi_ns_opens_scope(object_type) &&
+           (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "(%s) Popping scope for Op %p\n",
+                                 acpi_ut_get_type_name(object_type), op));
+
+               status = acpi_ds_scope_stack_pop(walk_state);
+               if (ACPI_FAILURE(status)) {
+                       goto cleanup;
+               }
+       }
+
+       /*
+        * Named operations are as follows:
+        *
+        * AML_ALIAS
+        * AML_BANKFIELD
+        * AML_CREATEBITFIELD
+        * AML_CREATEBYTEFIELD
+        * AML_CREATEDWORDFIELD
+        * AML_CREATEFIELD
+        * AML_CREATEQWORDFIELD
+        * AML_CREATEWORDFIELD
+        * AML_DATA_REGION
+        * AML_DEVICE
+        * AML_EVENT
+        * AML_FIELD
+        * AML_INDEXFIELD
+        * AML_METHOD
+        * AML_METHODCALL
+        * AML_MUTEX
+        * AML_NAME
+        * AML_NAMEDFIELD
+        * AML_OPREGION
+        * AML_POWERRES
+        * AML_PROCESSOR
+        * AML_SCOPE
+        * AML_THERMALZONE
+        */
+
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "Create-Load [%s] State=%p Op=%p NamedObj=%p\n",
+                         acpi_ps_get_opcode_name(op->common.aml_opcode),
+                         walk_state, op, node));
+
+       /* Decode the opcode */
+
+       arg = op->common.value.arg;
+
+       switch (walk_state->op_info->type) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+       case AML_TYPE_CREATE_FIELD:
+               /*
+                * Create the field object, but the field buffer and index must
+                * be evaluated later during the execution phase
+                */
+               status = acpi_ds_create_buffer_field(op, walk_state);
+               break;
+
+       case AML_TYPE_NAMED_FIELD:
+               /*
+                * If we are executing a method, initialize the field
+                */
+               if (walk_state->method_node) {
+                       status = acpi_ds_init_field_objects(op, walk_state);
+               }
+
+               switch (op->common.aml_opcode) {
+               case AML_INDEX_FIELD_OP:
+
+                       status =
+                           acpi_ds_create_index_field(op,
+                                                      (acpi_handle) arg->
+                                                      common.node, walk_state);
+                       break;
+
+               case AML_BANK_FIELD_OP:
+
+                       status =
+                           acpi_ds_create_bank_field(op, arg->common.node,
+                                                     walk_state);
+                       break;
+
+               case AML_FIELD_OP:
+
+                       status =
+                           acpi_ds_create_field(op, arg->common.node,
+                                                walk_state);
+                       break;
+
+               default:
+                       /* All NAMED_FIELD opcodes must be handled above */
+                       break;
+               }
+               break;
+
+       case AML_TYPE_NAMED_SIMPLE:
+
+               status = acpi_ds_create_operands(walk_state, arg);
+               if (ACPI_FAILURE(status)) {
+                       goto cleanup;
+               }
+
+               switch (op->common.aml_opcode) {
+               case AML_PROCESSOR_OP:
+
+                       status = acpi_ex_create_processor(walk_state);
+                       break;
+
+               case AML_POWER_RES_OP:
+
+                       status = acpi_ex_create_power_resource(walk_state);
+                       break;
+
+               case AML_MUTEX_OP:
+
+                       status = acpi_ex_create_mutex(walk_state);
+                       break;
+
+               case AML_EVENT_OP:
+
+                       status = acpi_ex_create_event(walk_state);
+                       break;
+
+               case AML_ALIAS_OP:
+
+                       status = acpi_ex_create_alias(walk_state);
+                       break;
+
+               default:
+                       /* Unknown opcode */
+
+                       status = AE_OK;
+                       goto cleanup;
+               }
+
+               /* Delete operands */
+
+               for (i = 1; i < walk_state->num_operands; i++) {
+                       acpi_ut_remove_reference(walk_state->operands[i]);
+                       walk_state->operands[i] = NULL;
+               }
+
+               break;
+#endif                         /* ACPI_NO_METHOD_EXECUTION */
+
+       case AML_TYPE_NAMED_COMPLEX:
+
+               switch (op->common.aml_opcode) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+               case AML_REGION_OP:
+               case AML_DATA_REGION_OP:
+
+                       if (op->common.aml_opcode == AML_REGION_OP) {
+                               region_space = (acpi_adr_space_type)
+                                   ((op->common.value.arg)->common.value.
+                                    integer);
+                       } else {
+                               region_space = REGION_DATA_TABLE;
+                       }
+
+                       /*
+                        * The op_region is not fully parsed at this time. The only valid
+                        * argument is the space_id. (We must save the address of the
+                        * AML of the address and length operands)
+                        *
+                        * If we have a valid region, initialize it. The namespace is
+                        * unlocked at this point.
+                        *
+                        * Need to unlock interpreter if it is locked (if we are running
+                        * a control method), in order to allow _REG methods to be run
+                        * during acpi_ev_initialize_region.
+                        */
+                       if (walk_state->method_node) {
+                               /*
+                                * Executing a method: initialize the region and unlock
+                                * the interpreter
+                                */
+                               status =
+                                   acpi_ex_create_region(op->named.data,
+                                                         op->named.length,
+                                                         region_space,
+                                                         walk_state);
+                               if (ACPI_FAILURE(status)) {
+                                       return (status);
+                               }
+
+                               acpi_ex_exit_interpreter();
+                       }
+
+                       status =
+                           acpi_ev_initialize_region
+                           (acpi_ns_get_attached_object(node), FALSE);
+                       if (walk_state->method_node) {
+                               acpi_ex_enter_interpreter();
+                       }
+
+                       if (ACPI_FAILURE(status)) {
+                               /*
+                                *  If AE_NOT_EXIST is returned, it is not fatal
+                                *  because many regions get created before a handler
+                                *  is installed for said region.
+                                */
+                               if (AE_NOT_EXIST == status) {
+                                       status = AE_OK;
+                               }
+                       }
+                       break;
+
+               case AML_NAME_OP:
+
+                       status = acpi_ds_create_node(walk_state, node, op);
+                       break;
+
+               case AML_METHOD_OP:
+                       /*
+                        * method_op pkg_length name_string method_flags term_list
+                        *
+                        * Note: We must create the method node/object pair as soon as we
+                        * see the method declaration. This allows later pass1 parsing
+                        * of invocations of the method (need to know the number of
+                        * arguments.)
+                        */
+                       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                         "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
+                                         walk_state, op, op->named.node));
+
+                       if (!acpi_ns_get_attached_object(op->named.node)) {
+                               walk_state->operands[0] =
+                                   ACPI_CAST_PTR(void, op->named.node);
+                               walk_state->num_operands = 1;
+
+                               status =
+                                   acpi_ds_create_operands(walk_state,
+                                                           op->common.value.
+                                                           arg);
+                               if (ACPI_SUCCESS(status)) {
+                                       status =
+                                           acpi_ex_create_method(op->named.
+                                                                 data,
+                                                                 op->named.
+                                                                 length,
+                                                                 walk_state);
+                               }
+                               walk_state->operands[0] = NULL;
+                               walk_state->num_operands = 0;
+
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
+                       break;
+
+#endif                         /* ACPI_NO_METHOD_EXECUTION */
+
+               default:
+                       /* All NAMED_COMPLEX opcodes must be handled above */
+                       break;
+               }
+               break;
+
+       case AML_CLASS_INTERNAL:
+
+               /* case AML_INT_NAMEPATH_OP: */
+               break;
+
+       case AML_CLASS_METHOD_CALL:
+
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n",
+                                 walk_state, op, node));
+
+               /*
+                * Lookup the method name and save the Node
+                */
+               status =
+                   acpi_ns_lookup(walk_state->scope_info,
+                                  arg->common.value.string, ACPI_TYPE_ANY,
+                                  ACPI_IMODE_LOAD_PASS2,
+                                  ACPI_NS_SEARCH_PARENT |
+                                  ACPI_NS_DONT_OPEN_SCOPE, walk_state,
+                                  &(new_node));
+               if (ACPI_SUCCESS(status)) {
+                       /*
+                        * Make sure that what we found is indeed a method
+                        * We didn't search for a method on purpose, to see if the name
+                        * would resolve
+                        */
+                       if (new_node->type != ACPI_TYPE_METHOD) {
+                               status = AE_AML_OPERAND_TYPE;
+                       }
+
+                       /* We could put the returned object (Node) on the object stack for
+                        * later, but for now, we will put it in the "op" object that the
+                        * parser uses, so we can get it again at the end of this scope
+                        */
+                       op->common.node = new_node;
+               } else {
+                       ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+      cleanup:
+
+       /* Remove the Node pushed at the very beginning */
+
+       walk_state->operands[0] = NULL;
+       walk_state->num_operands = 0;
+       return_ACPI_STATUS(status);
+}
index f4725212eb488fd1b37a3c2cc21735dbeb2282ad..65c79add3b1982ae3432a830c4c94f37be60f39d 100644 (file)
@@ -373,6 +373,15 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 
                        gpe_register_info = &gpe_block->register_info[i];
 
+                       /*
+                        * Optimization: If there are no GPEs enabled within this
+                        * register, we can safely ignore the entire register.
+                        */
+                       if (!(gpe_register_info->enable_for_run |
+                             gpe_register_info->enable_for_wake)) {
+                               continue;
+                       }
+
                        /* Read the Status Register */
 
                        status =
index 785a5ee64585eaad3c6a7f7101e475452d42467d..bea7223d7a710558d40a1c774a1760bd38670940 100644 (file)
@@ -231,6 +231,8 @@ acpi_status acpi_ev_initialize_op_regions(void)
                }
        }
 
+       acpi_gbl_reg_methods_executed = TRUE;
+
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
 }
index eb7386763712367d1814cecf1151f4acbd6e983b..c85c8c45599d9242134503cdcde2998e39492f2e 100644 (file)
@@ -110,9 +110,39 @@ acpi_install_address_space_handler(acpi_handle device,
                goto unlock_and_exit;
        }
 
-       /* Run all _REG methods for this address space */
+       /*
+        * For the default space_iDs, (the IDs for which there are default region handlers
+        * installed) Only execute the _REG methods if the global initialization _REG
+        * methods have already been run (via acpi_initialize_objects). In other words,
+        * we will defer the execution of the _REG methods for these space_iDs until
+        * execution of acpi_initialize_objects. This is done because we need the handlers
+        * for the default spaces (mem/io/pci/table) to be installed before we can run
+        * any control methods (or _REG methods). There is known BIOS code that depends
+        * on this.
+        *
+        * For all other space_iDs, we can safely execute the _REG methods immediately.
+        * This means that for IDs like embedded_controller, this function should be called
+        * only after acpi_enable_subsystem has been called.
+        */
+       switch (space_id) {
+       case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+       case ACPI_ADR_SPACE_SYSTEM_IO:
+       case ACPI_ADR_SPACE_PCI_CONFIG:
+       case ACPI_ADR_SPACE_DATA_TABLE:
+
+               if (acpi_gbl_reg_methods_executed) {
+
+                       /* Run all _REG methods for this address space */
+
+                       status = acpi_ev_execute_reg_methods(node, space_id);
+               }
+               break;
+
+       default:
 
-       status = acpi_ev_execute_reg_methods(node, space_id);
+               status = acpi_ev_execute_reg_methods(node, space_id);
+               break;
+       }
 
       unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
index 6c79c29f082df60156a83560de03a04f3bacbc60..f915a7f3f921ea6fd43d195425cb9783946cae60 100644 (file)
@@ -280,13 +280,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
        if (ACPI_FAILURE(status)) {
                if (status == AE_NOT_IMPLEMENTED) {
                        ACPI_ERROR((AE_INFO,
-                                   "Region %s(0x%X) not implemented",
+                                   "Region %s (ID=%u) not implemented",
                                    acpi_ut_get_region_name(rgn_desc->region.
                                                            space_id),
                                    rgn_desc->region.space_id));
                } else if (status == AE_NOT_EXIST) {
                        ACPI_ERROR((AE_INFO,
-                                   "Region %s(0x%X) has no handler",
+                                   "Region %s (ID=%u) has no handler",
                                    acpi_ut_get_region_name(rgn_desc->region.
                                                            space_id),
                                    rgn_desc->region.space_id));
index 6f98d210e71c4f23ae4b3ccd01b84cc2574b2221..f75f81ad15c962a20c0cbc1afa7ba035e9ccca8c 100644 (file)
@@ -80,14 +80,14 @@ acpi_status acpi_reset(void)
 
        if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                /*
-                * For I/O space, write directly to the OSL. This bypasses the port
-                * validation mechanism, which may block a valid write to the reset
-                * register.
+                * For I/O space, write directly to the OSL. This
+                * bypasses the port validation mechanism, which may
+                * block a valid write to the reset register. Spec
+                * section 4.7.3.6 requires register width to be 8.
                 */
                status =
                    acpi_os_write_port((acpi_io_address) reset_reg->address,
-                                      acpi_gbl_FADT.reset_value,
-                                      reset_reg->bit_width);
+                                      acpi_gbl_FADT.reset_value, 8);
        } else {
                /* Write the reset value to the reset register */
 
index 428d44e2d162402d8f9d5bb3c9c6542e40e193b2..6f5588e62c0ac24d396288f661fa3a959b52f734 100644 (file)
@@ -384,8 +384,11 @@ static void acpi_tb_convert_fadt(void)
         *
         * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
         * offset 45, 55, 95, and the word located at offset 109, 110.
+        *
+        * Note: The FADT revision value is unreliable. Only the length can be
+        * trusted.
         */
-       if (acpi_gbl_FADT.header.revision < FADT2_REVISION_ID) {
+       if (acpi_gbl_FADT.header.length <= ACPI_FADT_V2_SIZE) {
                acpi_gbl_FADT.preferred_profile = 0;
                acpi_gbl_FADT.pstate_control = 0;
                acpi_gbl_FADT.cst_control = 0;
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
new file mode 100644 (file)
index 0000000..136a814
--- /dev/null
@@ -0,0 +1,548 @@
+/******************************************************************************
+ *
+ * Module Name: utdecode - Utility decoding routines (value-to-string)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utdecode")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_format_exception
+ *
+ * PARAMETERS:  Status       - The acpi_status code to be formatted
+ *
+ * RETURN:      A string containing the exception text. A valid pointer is
+ *              always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ *              It is here instead of utxface.c so it is always present.
+ *
+ ******************************************************************************/
+const char *acpi_format_exception(acpi_status status)
+{
+       const char *exception = NULL;
+
+       ACPI_FUNCTION_ENTRY();
+
+       exception = acpi_ut_validate_exception(status);
+       if (!exception) {
+
+               /* Exception code was not recognized */
+
+               ACPI_ERROR((AE_INFO,
+                           "Unknown exception code: 0x%8.8X", status));
+
+               exception = "UNKNOWN_STATUS_CODE";
+       }
+
+       return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*
+ * Properties of the ACPI Object Types, both internal and external.
+ * The table is indexed by values of acpi_object_type
+ */
+const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES] = {
+       ACPI_NS_NORMAL,         /* 00 Any              */
+       ACPI_NS_NORMAL,         /* 01 Number           */
+       ACPI_NS_NORMAL,         /* 02 String           */
+       ACPI_NS_NORMAL,         /* 03 Buffer           */
+       ACPI_NS_NORMAL,         /* 04 Package          */
+       ACPI_NS_NORMAL,         /* 05 field_unit       */
+       ACPI_NS_NEWSCOPE,       /* 06 Device           */
+       ACPI_NS_NORMAL,         /* 07 Event            */
+       ACPI_NS_NEWSCOPE,       /* 08 Method           */
+       ACPI_NS_NORMAL,         /* 09 Mutex            */
+       ACPI_NS_NORMAL,         /* 10 Region           */
+       ACPI_NS_NEWSCOPE,       /* 11 Power            */
+       ACPI_NS_NEWSCOPE,       /* 12 Processor        */
+       ACPI_NS_NEWSCOPE,       /* 13 Thermal          */
+       ACPI_NS_NORMAL,         /* 14 buffer_field     */
+       ACPI_NS_NORMAL,         /* 15 ddb_handle       */
+       ACPI_NS_NORMAL,         /* 16 Debug Object     */
+       ACPI_NS_NORMAL,         /* 17 def_field        */
+       ACPI_NS_NORMAL,         /* 18 bank_field       */
+       ACPI_NS_NORMAL,         /* 19 index_field      */
+       ACPI_NS_NORMAL,         /* 20 Reference        */
+       ACPI_NS_NORMAL,         /* 21 Alias            */
+       ACPI_NS_NORMAL,         /* 22 method_alias     */
+       ACPI_NS_NORMAL,         /* 23 Notify           */
+       ACPI_NS_NORMAL,         /* 24 Address Handler  */
+       ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,       /* 25 Resource Desc    */
+       ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,       /* 26 Resource Field   */
+       ACPI_NS_NEWSCOPE,       /* 27 Scope            */
+       ACPI_NS_NORMAL,         /* 28 Extra            */
+       ACPI_NS_NORMAL,         /* 29 Data             */
+       ACPI_NS_NORMAL          /* 30 Invalid          */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_hex_to_ascii_char
+ *
+ * PARAMETERS:  Integer             - Contains the hex digit
+ *              Position            - bit position of the digit within the
+ *                                    integer (multiple of 4)
+ *
+ * RETURN:      The converted Ascii character
+ *
+ * DESCRIPTION: Convert a hex digit to an Ascii character
+ *
+ ******************************************************************************/
+
+/* Hex to ASCII conversion table */
+
+static const char acpi_gbl_hex_to_ascii[] = {
+       '0', '1', '2', '3', '4', '5', '6', '7',
+       '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
+{
+
+       return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_region_name
+ *
+ * PARAMETERS:  Space ID            - ID for the region
+ *
+ * RETURN:      Decoded region space_id name
+ *
+ * DESCRIPTION: Translate a Space ID into a name string (Debug only)
+ *
+ ******************************************************************************/
+
+/* Region type decoding */
+
+const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
+       "SystemMemory",
+       "SystemIO",
+       "PCI_Config",
+       "EmbeddedControl",
+       "SMBus",
+       "SystemCMOS",
+       "PCIBARTarget",
+       "IPMI",
+       "DataTable"
+};
+
+char *acpi_ut_get_region_name(u8 space_id)
+{
+
+       if (space_id >= ACPI_USER_REGION_BEGIN) {
+               return ("UserDefinedRegion");
+       } else if (space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+               return ("FunctionalFixedHW");
+       } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) {
+               return ("InvalidSpaceId");
+       }
+
+       return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id]));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_event_name
+ *
+ * PARAMETERS:  event_id            - Fixed event ID
+ *
+ * RETURN:      Decoded event ID name
+ *
+ * DESCRIPTION: Translate a Event ID into a name string (Debug only)
+ *
+ ******************************************************************************/
+
+/* Event type decoding */
+
+static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = {
+       "PM_Timer",
+       "GlobalLock",
+       "PowerButton",
+       "SleepButton",
+       "RealTimeClock",
+};
+
+char *acpi_ut_get_event_name(u32 event_id)
+{
+
+       if (event_id > ACPI_EVENT_MAX) {
+               return ("InvalidEventID");
+       }
+
+       return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id]));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_type_name
+ *
+ * PARAMETERS:  Type                - An ACPI object type
+ *
+ * RETURN:      Decoded ACPI object type name
+ *
+ * DESCRIPTION: Translate a Type ID into a name string (Debug only)
+ *
+ ******************************************************************************/
+
+/*
+ * Elements of acpi_gbl_ns_type_names below must match
+ * one-to-one with values of acpi_object_type
+ *
+ * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching;
+ * when stored in a table it really means that we have thus far seen no
+ * evidence to indicate what type is actually going to be stored for this entry.
+ */
+static const char acpi_gbl_bad_type[] = "UNDEFINED";
+
+/* Printable names of the ACPI object types */
+
+static const char *acpi_gbl_ns_type_names[] = {
+       /* 00 */ "Untyped",
+       /* 01 */ "Integer",
+       /* 02 */ "String",
+       /* 03 */ "Buffer",
+       /* 04 */ "Package",
+       /* 05 */ "FieldUnit",
+       /* 06 */ "Device",
+       /* 07 */ "Event",
+       /* 08 */ "Method",
+       /* 09 */ "Mutex",
+       /* 10 */ "Region",
+       /* 11 */ "Power",
+       /* 12 */ "Processor",
+       /* 13 */ "Thermal",
+       /* 14 */ "BufferField",
+       /* 15 */ "DdbHandle",
+       /* 16 */ "DebugObject",
+       /* 17 */ "RegionField",
+       /* 18 */ "BankField",
+       /* 19 */ "IndexField",
+       /* 20 */ "Reference",
+       /* 21 */ "Alias",
+       /* 22 */ "MethodAlias",
+       /* 23 */ "Notify",
+       /* 24 */ "AddrHandler",
+       /* 25 */ "ResourceDesc",
+       /* 26 */ "ResourceFld",
+       /* 27 */ "Scope",
+       /* 28 */ "Extra",
+       /* 29 */ "Data",
+       /* 30 */ "Invalid"
+};
+
+char *acpi_ut_get_type_name(acpi_object_type type)
+{
+
+       if (type > ACPI_TYPE_INVALID) {
+               return (ACPI_CAST_PTR(char, acpi_gbl_bad_type));
+       }
+
+       return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type]));
+}
+
+char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
+{
+
+       if (!obj_desc) {
+               return ("[NULL Object Descriptor]");
+       }
+
+       return (acpi_ut_get_type_name(obj_desc->common.type));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_node_name
+ *
+ * PARAMETERS:  Object               - A namespace node
+ *
+ * RETURN:      ASCII name of the node
+ *
+ * DESCRIPTION: Validate the node and return the node's ACPI name.
+ *
+ ******************************************************************************/
+
+char *acpi_ut_get_node_name(void *object)
+{
+       struct acpi_namespace_node *node = (struct acpi_namespace_node *)object;
+
+       /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */
+
+       if (!object) {
+               return ("NULL");
+       }
+
+       /* Check for Root node */
+
+       if ((object == ACPI_ROOT_OBJECT) || (object == acpi_gbl_root_node)) {
+               return ("\"\\\" ");
+       }
+
+       /* Descriptor must be a namespace node */
+
+       if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
+               return ("####");
+       }
+
+       /*
+        * Ensure name is valid. The name was validated/repaired when the node
+        * was created, but make sure it has not been corrupted.
+        */
+       acpi_ut_repair_name(node->name.ascii);
+
+       /* Return the name */
+
+       return (node->name.ascii);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_descriptor_name
+ *
+ * PARAMETERS:  Object               - An ACPI object
+ *
+ * RETURN:      Decoded name of the descriptor type
+ *
+ * DESCRIPTION: Validate object and return the descriptor type
+ *
+ ******************************************************************************/
+
+/* Printable names of object descriptor types */
+
+static const char *acpi_gbl_desc_type_names[] = {
+       /* 00 */ "Not a Descriptor",
+       /* 01 */ "Cached",
+       /* 02 */ "State-Generic",
+       /* 03 */ "State-Update",
+       /* 04 */ "State-Package",
+       /* 05 */ "State-Control",
+       /* 06 */ "State-RootParseScope",
+       /* 07 */ "State-ParseScope",
+       /* 08 */ "State-WalkScope",
+       /* 09 */ "State-Result",
+       /* 10 */ "State-Notify",
+       /* 11 */ "State-Thread",
+       /* 12 */ "Walk",
+       /* 13 */ "Parser",
+       /* 14 */ "Operand",
+       /* 15 */ "Node"
+};
+
+char *acpi_ut_get_descriptor_name(void *object)
+{
+
+       if (!object) {
+               return ("NULL OBJECT");
+       }
+
+       if (ACPI_GET_DESCRIPTOR_TYPE(object) > ACPI_DESC_TYPE_MAX) {
+               return ("Not a Descriptor");
+       }
+
+       return (ACPI_CAST_PTR(char,
+                             acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE
+                                                      (object)]));
+
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_reference_name
+ *
+ * PARAMETERS:  Object               - An ACPI reference object
+ *
+ * RETURN:      Decoded name of the type of reference
+ *
+ * DESCRIPTION: Decode a reference object sub-type to a string.
+ *
+ ******************************************************************************/
+
+/* Printable names of reference object sub-types */
+
+static const char *acpi_gbl_ref_class_names[] = {
+       /* 00 */ "Local",
+       /* 01 */ "Argument",
+       /* 02 */ "RefOf",
+       /* 03 */ "Index",
+       /* 04 */ "DdbHandle",
+       /* 05 */ "Named Object",
+       /* 06 */ "Debug"
+};
+
+const char *acpi_ut_get_reference_name(union acpi_operand_object *object)
+{
+
+       if (!object) {
+               return ("NULL Object");
+       }
+
+       if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
+               return ("Not an Operand object");
+       }
+
+       if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
+               return ("Not a Reference object");
+       }
+
+       if (object->reference.class > ACPI_REFCLASS_MAX) {
+               return ("Unknown Reference class");
+       }
+
+       return (acpi_gbl_ref_class_names[object->reference.class]);
+}
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+/*
+ * Strings and procedures used for debug only
+ */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_mutex_name
+ *
+ * PARAMETERS:  mutex_id        - The predefined ID for this mutex.
+ *
+ * RETURN:      Decoded name of the internal mutex
+ *
+ * DESCRIPTION: Translate a mutex ID into a name string (Debug only)
+ *
+ ******************************************************************************/
+
+/* Names for internal mutex objects, used for debug output */
+
+static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
+       "ACPI_MTX_Interpreter",
+       "ACPI_MTX_Namespace",
+       "ACPI_MTX_Tables",
+       "ACPI_MTX_Events",
+       "ACPI_MTX_Caches",
+       "ACPI_MTX_Memory",
+       "ACPI_MTX_CommandComplete",
+       "ACPI_MTX_CommandReady"
+};
+
+char *acpi_ut_get_mutex_name(u32 mutex_id)
+{
+
+       if (mutex_id > ACPI_MAX_MUTEX) {
+               return ("Invalid Mutex ID");
+       }
+
+       return (acpi_gbl_mutex_names[mutex_id]);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_notify_name
+ *
+ * PARAMETERS:  notify_value    - Value from the Notify() request
+ *
+ * RETURN:      Decoded name for the notify value
+ *
+ * DESCRIPTION: Translate a Notify Value to a notify namestring.
+ *
+ ******************************************************************************/
+
+/* Names for Notify() values, used for debug output */
+
+static const char *acpi_gbl_notify_value_names[] = {
+       "Bus Check",
+       "Device Check",
+       "Device Wake",
+       "Eject Request",
+       "Device Check Light",
+       "Frequency Mismatch",
+       "Bus Mode Mismatch",
+       "Power Fault",
+       "Capabilities Check",
+       "Device PLD Check",
+       "Reserved",
+       "System Locality Update"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value)
+{
+
+       if (notify_value <= ACPI_NOTIFY_MAX) {
+               return (acpi_gbl_notify_value_names[notify_value]);
+       } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+               return ("Reserved");
+       } else {                /* Greater or equal to 0x80 */
+
+               return ("**Device Specific**");
+       }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_valid_object_type
+ *
+ * PARAMETERS:  Type            - Object type to be validated
+ *
+ * RETURN:      TRUE if valid object type, FALSE otherwise
+ *
+ * DESCRIPTION: Validate an object type
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_valid_object_type(acpi_object_type type)
+{
+
+       if (type > ACPI_TYPE_LOCAL_MAX) {
+
+               /* Note: Assumes all TYPEs are contiguous (external/local) */
+
+               return (FALSE);
+       }
+
+       return (TRUE);
+}
index 97dd9bbf055ace4b895b0a84bfb2b2b695a55679..833a38a9c90524c9b099b14d7d40761b660c1b75 100644 (file)
@@ -45,7 +45,6 @@
 
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acnamesp.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utglobal")
@@ -105,43 +104,6 @@ const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = {
        "_S4D"
 };
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_format_exception
- *
- * PARAMETERS:  Status       - The acpi_status code to be formatted
- *
- * RETURN:      A string containing the exception text. A valid pointer is
- *              always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string
- *              It is here instead of utxface.c so it is always present.
- *
- ******************************************************************************/
-
-const char *acpi_format_exception(acpi_status status)
-{
-       const char *exception = NULL;
-
-       ACPI_FUNCTION_ENTRY();
-
-       exception = acpi_ut_validate_exception(status);
-       if (!exception) {
-
-               /* Exception code was not recognized */
-
-               ACPI_ERROR((AE_INFO,
-                           "Unknown exception code: 0x%8.8X", status));
-
-               exception = "UNKNOWN_STATUS_CODE";
-               dump_stack();
-       }
-
-       return (ACPI_CAST_PTR(const char, exception));
-}
-
-ACPI_EXPORT_SYMBOL(acpi_format_exception)
-
 /*******************************************************************************
  *
  * Namespace globals
@@ -177,71 +139,6 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
        {NULL, ACPI_TYPE_ANY, NULL}
 };
 
-/*
- * Properties of the ACPI Object Types, both internal and external.
- * The table is indexed by values of acpi_object_type
- */
-const u8 acpi_gbl_ns_properties[] = {
-       ACPI_NS_NORMAL,         /* 00 Any              */
-       ACPI_NS_NORMAL,         /* 01 Number           */
-       ACPI_NS_NORMAL,         /* 02 String           */
-       ACPI_NS_NORMAL,         /* 03 Buffer           */
-       ACPI_NS_NORMAL,         /* 04 Package          */
-       ACPI_NS_NORMAL,         /* 05 field_unit       */
-       ACPI_NS_NEWSCOPE,       /* 06 Device           */
-       ACPI_NS_NORMAL,         /* 07 Event            */
-       ACPI_NS_NEWSCOPE,       /* 08 Method           */
-       ACPI_NS_NORMAL,         /* 09 Mutex            */
-       ACPI_NS_NORMAL,         /* 10 Region           */
-       ACPI_NS_NEWSCOPE,       /* 11 Power            */
-       ACPI_NS_NEWSCOPE,       /* 12 Processor        */
-       ACPI_NS_NEWSCOPE,       /* 13 Thermal          */
-       ACPI_NS_NORMAL,         /* 14 buffer_field     */
-       ACPI_NS_NORMAL,         /* 15 ddb_handle       */
-       ACPI_NS_NORMAL,         /* 16 Debug Object     */
-       ACPI_NS_NORMAL,         /* 17 def_field        */
-       ACPI_NS_NORMAL,         /* 18 bank_field       */
-       ACPI_NS_NORMAL,         /* 19 index_field      */
-       ACPI_NS_NORMAL,         /* 20 Reference        */
-       ACPI_NS_NORMAL,         /* 21 Alias            */
-       ACPI_NS_NORMAL,         /* 22 method_alias     */
-       ACPI_NS_NORMAL,         /* 23 Notify           */
-       ACPI_NS_NORMAL,         /* 24 Address Handler  */
-       ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,       /* 25 Resource Desc    */
-       ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,       /* 26 Resource Field   */
-       ACPI_NS_NEWSCOPE,       /* 27 Scope            */
-       ACPI_NS_NORMAL,         /* 28 Extra            */
-       ACPI_NS_NORMAL,         /* 29 Data             */
-       ACPI_NS_NORMAL          /* 30 Invalid          */
-};
-
-/* Hex to ASCII conversion table */
-
-static const char acpi_gbl_hex_to_ascii[] = {
-       '0', '1', '2', '3', '4', '5', '6', '7',
-       '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-};
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_hex_to_ascii_char
- *
- * PARAMETERS:  Integer             - Contains the hex digit
- *              Position            - bit position of the digit within the
- *                                    integer (multiple of 4)
- *
- * RETURN:      The converted Ascii character
- *
- * DESCRIPTION: Convert a hex digit to an Ascii character
- *
- ******************************************************************************/
-
-char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
-{
-
-       return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
-}
-
 /******************************************************************************
  *
  * Event and Hardware globals
@@ -339,386 +236,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] =
                                        ACPI_BITMASK_RT_CLOCK_ENABLE},
 };
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_region_name
- *
- * PARAMETERS:  None.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Translate a Space ID into a name string (Debug only)
- *
- ******************************************************************************/
-
-/* Region type decoding */
-
-const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
-       "SystemMemory",
-       "SystemIO",
-       "PCI_Config",
-       "EmbeddedControl",
-       "SMBus",
-       "SystemCMOS",
-       "PCIBARTarget",
-       "IPMI",
-       "DataTable"
-};
-
-char *acpi_ut_get_region_name(u8 space_id)
-{
-
-       if (space_id >= ACPI_USER_REGION_BEGIN) {
-               return ("UserDefinedRegion");
-       } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) {
-               return ("InvalidSpaceId");
-       }
-
-       return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id]));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_event_name
- *
- * PARAMETERS:  None.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Translate a Event ID into a name string (Debug only)
- *
- ******************************************************************************/
-
-/* Event type decoding */
-
-static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = {
-       "PM_Timer",
-       "GlobalLock",
-       "PowerButton",
-       "SleepButton",
-       "RealTimeClock",
-};
-
-char *acpi_ut_get_event_name(u32 event_id)
-{
-
-       if (event_id > ACPI_EVENT_MAX) {
-               return ("InvalidEventID");
-       }
-
-       return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id]));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_type_name
- *
- * PARAMETERS:  None.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Translate a Type ID into a name string (Debug only)
- *
- ******************************************************************************/
-
-/*
- * Elements of acpi_gbl_ns_type_names below must match
- * one-to-one with values of acpi_object_type
- *
- * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching;
- * when stored in a table it really means that we have thus far seen no
- * evidence to indicate what type is actually going to be stored for this entry.
- */
-static const char acpi_gbl_bad_type[] = "UNDEFINED";
-
-/* Printable names of the ACPI object types */
-
-static const char *acpi_gbl_ns_type_names[] = {
-       /* 00 */ "Untyped",
-       /* 01 */ "Integer",
-       /* 02 */ "String",
-       /* 03 */ "Buffer",
-       /* 04 */ "Package",
-       /* 05 */ "FieldUnit",
-       /* 06 */ "Device",
-       /* 07 */ "Event",
-       /* 08 */ "Method",
-       /* 09 */ "Mutex",
-       /* 10 */ "Region",
-       /* 11 */ "Power",
-       /* 12 */ "Processor",
-       /* 13 */ "Thermal",
-       /* 14 */ "BufferField",
-       /* 15 */ "DdbHandle",
-       /* 16 */ "DebugObject",
-       /* 17 */ "RegionField",
-       /* 18 */ "BankField",
-       /* 19 */ "IndexField",
-       /* 20 */ "Reference",
-       /* 21 */ "Alias",
-       /* 22 */ "MethodAlias",
-       /* 23 */ "Notify",
-       /* 24 */ "AddrHandler",
-       /* 25 */ "ResourceDesc",
-       /* 26 */ "ResourceFld",
-       /* 27 */ "Scope",
-       /* 28 */ "Extra",
-       /* 29 */ "Data",
-       /* 30 */ "Invalid"
-};
-
-char *acpi_ut_get_type_name(acpi_object_type type)
-{
-
-       if (type > ACPI_TYPE_INVALID) {
-               return (ACPI_CAST_PTR(char, acpi_gbl_bad_type));
-       }
-
-       return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type]));
-}
-
-char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
-{
-
-       if (!obj_desc) {
-               return ("[NULL Object Descriptor]");
-       }
-
-       return (acpi_ut_get_type_name(obj_desc->common.type));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_node_name
- *
- * PARAMETERS:  Object               - A namespace node
- *
- * RETURN:      Pointer to a string
- *
- * DESCRIPTION: Validate the node and return the node's ACPI name.
- *
- ******************************************************************************/
-
-char *acpi_ut_get_node_name(void *object)
-{
-       struct acpi_namespace_node *node = (struct acpi_namespace_node *)object;
-
-       /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */
-
-       if (!object) {
-               return ("NULL");
-       }
-
-       /* Check for Root node */
-
-       if ((object == ACPI_ROOT_OBJECT) || (object == acpi_gbl_root_node)) {
-               return ("\"\\\" ");
-       }
-
-       /* Descriptor must be a namespace node */
-
-       if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
-               return ("####");
-       }
-
-       /* Name must be a valid ACPI name */
-
-       if (!acpi_ut_valid_acpi_name(node->name.integer)) {
-               node->name.integer = acpi_ut_repair_name(node->name.ascii);
-       }
-
-       /* Return the name */
-
-       return (node->name.ascii);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_descriptor_name
- *
- * PARAMETERS:  Object               - An ACPI object
- *
- * RETURN:      Pointer to a string
- *
- * DESCRIPTION: Validate object and return the descriptor type
- *
- ******************************************************************************/
-
-/* Printable names of object descriptor types */
-
-static const char *acpi_gbl_desc_type_names[] = {
-       /* 00 */ "Invalid",
-       /* 01 */ "Cached",
-       /* 02 */ "State-Generic",
-       /* 03 */ "State-Update",
-       /* 04 */ "State-Package",
-       /* 05 */ "State-Control",
-       /* 06 */ "State-RootParseScope",
-       /* 07 */ "State-ParseScope",
-       /* 08 */ "State-WalkScope",
-       /* 09 */ "State-Result",
-       /* 10 */ "State-Notify",
-       /* 11 */ "State-Thread",
-       /* 12 */ "Walk",
-       /* 13 */ "Parser",
-       /* 14 */ "Operand",
-       /* 15 */ "Node"
-};
-
-char *acpi_ut_get_descriptor_name(void *object)
-{
-
-       if (!object) {
-               return ("NULL OBJECT");
-       }
-
-       if (ACPI_GET_DESCRIPTOR_TYPE(object) > ACPI_DESC_TYPE_MAX) {
-               return (ACPI_CAST_PTR(char, acpi_gbl_bad_type));
-       }
-
-       return (ACPI_CAST_PTR(char,
-                             acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE
-                                                      (object)]));
-
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_reference_name
- *
- * PARAMETERS:  Object               - An ACPI reference object
- *
- * RETURN:      Pointer to a string
- *
- * DESCRIPTION: Decode a reference object sub-type to a string.
- *
- ******************************************************************************/
-
-/* Printable names of reference object sub-types */
-
-static const char *acpi_gbl_ref_class_names[] = {
-       /* 00 */ "Local",
-       /* 01 */ "Argument",
-       /* 02 */ "RefOf",
-       /* 03 */ "Index",
-       /* 04 */ "DdbHandle",
-       /* 05 */ "Named Object",
-       /* 06 */ "Debug"
-};
-
-const char *acpi_ut_get_reference_name(union acpi_operand_object *object)
-{
-       if (!object)
-               return "NULL Object";
-
-       if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND)
-               return "Not an Operand object";
-
-       if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE)
-               return "Not a Reference object";
-
-       if (object->reference.class > ACPI_REFCLASS_MAX)
-               return "Unknown Reference class";
-
-       return acpi_gbl_ref_class_names[object->reference.class];
-}
-
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
-/*
- * Strings and procedures used for debug only
- */
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_mutex_name
- *
- * PARAMETERS:  mutex_id        - The predefined ID for this mutex.
- *
- * RETURN:      String containing the name of the mutex. Always returns a valid
- *              pointer.
- *
- * DESCRIPTION: Translate a mutex ID into a name string (Debug only)
- *
- ******************************************************************************/
-
-char *acpi_ut_get_mutex_name(u32 mutex_id)
-{
-
-       if (mutex_id > ACPI_MAX_MUTEX) {
-               return ("Invalid Mutex ID");
-       }
-
-       return (acpi_gbl_mutex_names[mutex_id]);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_get_notify_name
- *
- * PARAMETERS:  notify_value    - Value from the Notify() request
- *
- * RETURN:      String corresponding to the Notify Value.
- *
- * DESCRIPTION: Translate a Notify Value to a notify namestring.
- *
- ******************************************************************************/
-
-/* Names for Notify() values, used for debug output */
-
-static const char *acpi_gbl_notify_value_names[] = {
-       "Bus Check",
-       "Device Check",
-       "Device Wake",
-       "Eject Request",
-       "Device Check Light",
-       "Frequency Mismatch",
-       "Bus Mode Mismatch",
-       "Power Fault",
-       "Capabilities Check",
-       "Device PLD Check",
-       "Reserved",
-       "System Locality Update"
-};
-
-const char *acpi_ut_get_notify_name(u32 notify_value)
-{
-
-       if (notify_value <= ACPI_NOTIFY_MAX) {
-               return (acpi_gbl_notify_value_names[notify_value]);
-       } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
-               return ("Reserved");
-       } else {                /* Greater or equal to 0x80 */
-
-               return ("**Device Specific**");
-       }
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_valid_object_type
- *
- * PARAMETERS:  Type            - Object type to be validated
- *
- * RETURN:      TRUE if valid object type, FALSE otherwise
- *
- * DESCRIPTION: Validate an object type
- *
- ******************************************************************************/
-
-u8 acpi_ut_valid_object_type(acpi_object_type type)
-{
-
-       if (type > ACPI_TYPE_LOCAL_MAX) {
-
-               /* Note: Assumes all TYPEs are contiguous (external/local) */
-
-               return (FALSE);
-       }
-
-       return (TRUE);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_init_globals
@@ -806,6 +323,7 @@ acpi_status acpi_ut_init_globals(void)
        acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
        acpi_gbl_osi_data = 0;
        acpi_gbl_osi_mutex = NULL;
+       acpi_gbl_reg_methods_executed = FALSE;
 
        /* Hardware oriented */
 
index e91680c7e04788b05a6a33fdbeee2a8cd313c92a..66a03caa2ad92093cf68ce5ddcbc215ea8ef7b3d 100644 (file)
@@ -22,6 +22,13 @@ config ACPI_APEI_GHES
          by firmware to produce more valuable hardware error
          information for Linux.
 
+config ACPI_APEI_PCIEAER
+       bool "APEI PCIe AER logging/recovering support"
+       depends on ACPI_APEI && PCIEAER
+       help
+         PCIe AER errors may be reported via APEI firmware first mode.
+         Turn on this option to enable the corresponding support.
+
 config ACPI_APEI_EINJ
        tristate "APEI Error INJection (EINJ)"
        depends on ACPI_APEI && DEBUG_FS
index 31464a006d7612f9ceedd214ec172056793a9632..5d4189464d63155a300c4f7c66f9abb9d0cb11ec 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/time.h>
 #include <linux/cper.h>
 #include <linux/acpi.h>
+#include <linux/aer.h>
 
 /*
  * CPER record ID need to be unique even after reboot, because record
@@ -70,8 +71,8 @@ static const char *cper_severity_str(unsigned int severity)
  * If the output length is longer than 80, multiple line will be
  * printed, with @pfx is printed at the beginning of each line.
  */
-static void cper_print_bits(const char *pfx, unsigned int bits,
-                           const char *strs[], unsigned int strs_size)
+void cper_print_bits(const char *pfx, unsigned int bits,
+                    const char *strs[], unsigned int strs_size)
 {
        int i, len = 0;
        const char *str;
@@ -81,6 +82,8 @@ static void cper_print_bits(const char *pfx, unsigned int bits,
                if (!(bits & (1U << i)))
                        continue;
                str = strs[i];
+               if (!str)
+                       continue;
                if (len && len + strlen(str) + 2 > 80) {
                        printk("%s\n", buf);
                        len = 0;
@@ -243,7 +246,8 @@ static const char *cper_pcie_port_type_strs[] = {
        "root complex event collector",
 };
 
-static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
+static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
+                           const struct acpi_hest_generic_data *gdata)
 {
        if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
                printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
@@ -276,6 +280,12 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
                printk(
        "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
        pfx, pcie->bridge.secondary_status, pcie->bridge.control);
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+       if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
+               struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
+               cper_print_aer(pfx, gdata->error_severity, aer_regs);
+       }
+#endif
 }
 
 static const char *apei_estatus_section_flag_strs[] = {
@@ -322,7 +332,7 @@ static void apei_estatus_print_section(
                struct cper_sec_pcie *pcie = (void *)(gdata + 1);
                printk("%s""section_type: PCIe error\n", pfx);
                if (gdata->error_data_length >= sizeof(*pcie))
-                       cper_print_pcie(pfx, pcie);
+                       cper_print_pcie(pfx, pcie, gdata);
                else
                        goto err_section_too_small;
        } else
index de73caf3cebc8955e1502de7eac4eee0218c3fe6..a4cfb64c86a157bcf8ae22730d6a7943e31af7e0 100644 (file)
@@ -43,12 +43,27 @@ static DEFINE_MUTEX(erst_dbg_mutex);
 
 static int erst_dbg_open(struct inode *inode, struct file *file)
 {
+       int rc, *pos;
+
        if (erst_disable)
                return -ENODEV;
 
+       pos = (int *)&file->private_data;
+
+       rc = erst_get_record_id_begin(pos);
+       if (rc)
+               return rc;
+
        return nonseekable_open(inode, file);
 }
 
+static int erst_dbg_release(struct inode *inode, struct file *file)
+{
+       erst_get_record_id_end();
+
+       return 0;
+}
+
 static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
        int rc;
@@ -79,18 +94,20 @@ static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf,
                             size_t usize, loff_t *off)
 {
-       int rc;
+       int rc, *pos;
        ssize_t len = 0;
        u64 id;
 
-       if (*off != 0)
+       if (*off)
                return -EINVAL;
 
        if (mutex_lock_interruptible(&erst_dbg_mutex) != 0)
                return -EINTR;
 
+       pos = (int *)&filp->private_data;
+
 retry_next:
-       rc = erst_get_next_record_id(&id);
+       rc = erst_get_record_id_next(pos, &id);
        if (rc)
                goto out;
        /* no more record */
@@ -181,6 +198,7 @@ out:
 static const struct file_operations erst_dbg_ops = {
        .owner          = THIS_MODULE,
        .open           = erst_dbg_open,
+       .release        = erst_dbg_release,
        .read           = erst_dbg_read,
        .write          = erst_dbg_write,
        .unlocked_ioctl = erst_dbg_ioctl,
index c02005abce43dc12d9c805a80fcb325d9eaeeb97..d6cb0ff6988e2797455e15e98426d021dd4fc005 100644 (file)
@@ -430,6 +430,22 @@ ssize_t erst_get_record_count(void)
 }
 EXPORT_SYMBOL_GPL(erst_get_record_count);
 
+#define ERST_RECORD_ID_CACHE_SIZE_MIN  16
+#define ERST_RECORD_ID_CACHE_SIZE_MAX  1024
+
+struct erst_record_id_cache {
+       struct mutex lock;
+       u64 *entries;
+       int len;
+       int size;
+       int refcount;
+};
+
+static struct erst_record_id_cache erst_record_id_cache = {
+       .lock = __MUTEX_INITIALIZER(erst_record_id_cache.lock),
+       .refcount = 0,
+};
+
 static int __erst_get_next_record_id(u64 *record_id)
 {
        struct apei_exec_context ctx;
@@ -444,26 +460,179 @@ static int __erst_get_next_record_id(u64 *record_id)
        return 0;
 }
 
+int erst_get_record_id_begin(int *pos)
+{
+       int rc;
+
+       if (erst_disable)
+               return -ENODEV;
+
+       rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
+       if (rc)
+               return rc;
+       erst_record_id_cache.refcount++;
+       mutex_unlock(&erst_record_id_cache.lock);
+
+       *pos = 0;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(erst_get_record_id_begin);
+
+/* erst_record_id_cache.lock must be held by caller */
+static int __erst_record_id_cache_add_one(void)
+{
+       u64 id, prev_id, first_id;
+       int i, rc;
+       u64 *entries;
+       unsigned long flags;
+
+       id = prev_id = first_id = APEI_ERST_INVALID_RECORD_ID;
+retry:
+       raw_spin_lock_irqsave(&erst_lock, flags);
+       rc = __erst_get_next_record_id(&id);
+       raw_spin_unlock_irqrestore(&erst_lock, flags);
+       if (rc == -ENOENT)
+               return 0;
+       if (rc)
+               return rc;
+       if (id == APEI_ERST_INVALID_RECORD_ID)
+               return 0;
+       /* can not skip current ID, or loop back to first ID */
+       if (id == prev_id || id == first_id)
+               return 0;
+       if (first_id == APEI_ERST_INVALID_RECORD_ID)
+               first_id = id;
+       prev_id = id;
+
+       entries = erst_record_id_cache.entries;
+       for (i = 0; i < erst_record_id_cache.len; i++) {
+               if (entries[i] == id)
+                       break;
+       }
+       /* record id already in cache, try next */
+       if (i < erst_record_id_cache.len)
+               goto retry;
+       if (erst_record_id_cache.len >= erst_record_id_cache.size) {
+               int new_size, alloc_size;
+               u64 *new_entries;
+
+               new_size = erst_record_id_cache.size * 2;
+               new_size = clamp_val(new_size, ERST_RECORD_ID_CACHE_SIZE_MIN,
+                                    ERST_RECORD_ID_CACHE_SIZE_MAX);
+               if (new_size <= erst_record_id_cache.size) {
+                       if (printk_ratelimit())
+                               pr_warning(FW_WARN ERST_PFX
+                                          "too many record ID!\n");
+                       return 0;
+               }
+               alloc_size = new_size * sizeof(entries[0]);
+               if (alloc_size < PAGE_SIZE)
+                       new_entries = kmalloc(alloc_size, GFP_KERNEL);
+               else
+                       new_entries = vmalloc(alloc_size);
+               if (!new_entries)
+                       return -ENOMEM;
+               memcpy(new_entries, entries,
+                      erst_record_id_cache.len * sizeof(entries[0]));
+               if (erst_record_id_cache.size < PAGE_SIZE)
+                       kfree(entries);
+               else
+                       vfree(entries);
+               erst_record_id_cache.entries = entries = new_entries;
+               erst_record_id_cache.size = new_size;
+       }
+       entries[i] = id;
+       erst_record_id_cache.len++;
+
+       return 1;
+}
+
 /*
  * Get the record ID of an existing error record on the persistent
  * storage. If there is no error record on the persistent storage, the
  * returned record_id is APEI_ERST_INVALID_RECORD_ID.
  */
-int erst_get_next_record_id(u64 *record_id)
+int erst_get_record_id_next(int *pos, u64 *record_id)
 {
-       int rc;
-       unsigned long flags;
+       int rc = 0;
+       u64 *entries;
 
        if (erst_disable)
                return -ENODEV;
 
-       raw_spin_lock_irqsave(&erst_lock, flags);
-       rc = __erst_get_next_record_id(record_id);
-       raw_spin_unlock_irqrestore(&erst_lock, flags);
+       /* must be enclosed by erst_get_record_id_begin/end */
+       BUG_ON(!erst_record_id_cache.refcount);
+       BUG_ON(*pos < 0 || *pos > erst_record_id_cache.len);
+
+       mutex_lock(&erst_record_id_cache.lock);
+       entries = erst_record_id_cache.entries;
+       for (; *pos < erst_record_id_cache.len; (*pos)++)
+               if (entries[*pos] != APEI_ERST_INVALID_RECORD_ID)
+                       break;
+       /* found next record id in cache */
+       if (*pos < erst_record_id_cache.len) {
+               *record_id = entries[*pos];
+               (*pos)++;
+               goto out_unlock;
+       }
+
+       /* Try to add one more record ID to cache */
+       rc = __erst_record_id_cache_add_one();
+       if (rc < 0)
+               goto out_unlock;
+       /* successfully add one new ID */
+       if (rc == 1) {
+               *record_id = erst_record_id_cache.entries[*pos];
+               (*pos)++;
+               rc = 0;
+       } else {
+               *pos = -1;
+               *record_id = APEI_ERST_INVALID_RECORD_ID;
+       }
+out_unlock:
+       mutex_unlock(&erst_record_id_cache.lock);
 
        return rc;
 }
-EXPORT_SYMBOL_GPL(erst_get_next_record_id);
+EXPORT_SYMBOL_GPL(erst_get_record_id_next);
+
+/* erst_record_id_cache.lock must be held by caller */
+static void __erst_record_id_cache_compact(void)
+{
+       int i, wpos = 0;
+       u64 *entries;
+
+       if (erst_record_id_cache.refcount)
+               return;
+
+       entries = erst_record_id_cache.entries;
+       for (i = 0; i < erst_record_id_cache.len; i++) {
+               if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
+                       continue;
+               if (wpos != i)
+                       memcpy(&entries[wpos], &entries[i], sizeof(entries[i]));
+               wpos++;
+       }
+       erst_record_id_cache.len = wpos;
+}
+
+void erst_get_record_id_end(void)
+{
+       /*
+        * erst_disable != 0 should be detected by invoker via the
+        * return value of erst_get_record_id_begin/next, so this
+        * function should not be called for erst_disable != 0.
+        */
+       BUG_ON(erst_disable);
+
+       mutex_lock(&erst_record_id_cache.lock);
+       erst_record_id_cache.refcount--;
+       BUG_ON(erst_record_id_cache.refcount < 0);
+       __erst_record_id_cache_compact();
+       mutex_unlock(&erst_record_id_cache.lock);
+}
+EXPORT_SYMBOL_GPL(erst_get_record_id_end);
 
 static int __erst_write_to_storage(u64 offset)
 {
@@ -704,56 +873,34 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record,
 }
 EXPORT_SYMBOL_GPL(erst_read);
 
-/*
- * If return value > buflen, the buffer size is not big enough,
- * else if return value = 0, there is no more record to read,
- * else if return value < 0, something goes wrong,
- * else everything is OK, and return value is record length
- */
-ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
-{
-       int rc;
-       ssize_t len;
-       unsigned long flags;
-       u64 record_id;
-
-       if (erst_disable)
-               return -ENODEV;
-
-       raw_spin_lock_irqsave(&erst_lock, flags);
-       rc = __erst_get_next_record_id(&record_id);
-       if (rc) {
-               raw_spin_unlock_irqrestore(&erst_lock, flags);
-               return rc;
-       }
-       /* no more record */
-       if (record_id == APEI_ERST_INVALID_RECORD_ID) {
-               raw_spin_unlock_irqrestore(&erst_lock, flags);
-               return 0;
-       }
-
-       len = __erst_read(record_id, record, buflen);
-       raw_spin_unlock_irqrestore(&erst_lock, flags);
-
-       return len;
-}
-EXPORT_SYMBOL_GPL(erst_read_next);
-
 int erst_clear(u64 record_id)
 {
-       int rc;
+       int rc, i;
        unsigned long flags;
+       u64 *entries;
 
        if (erst_disable)
                return -ENODEV;
 
+       rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
+       if (rc)
+               return rc;
        raw_spin_lock_irqsave(&erst_lock, flags);
        if (erst_erange.attr & ERST_RANGE_NVRAM)
                rc = __erst_clear_from_nvram(record_id);
        else
                rc = __erst_clear_from_storage(record_id);
        raw_spin_unlock_irqrestore(&erst_lock, flags);
-
+       if (rc)
+               goto out;
+       entries = erst_record_id_cache.entries;
+       for (i = 0; i < erst_record_id_cache.len; i++) {
+               if (entries[i] == record_id)
+                       entries[i] = APEI_ERST_INVALID_RECORD_ID;
+       }
+       __erst_record_id_cache_compact();
+out:
+       mutex_unlock(&erst_record_id_cache.lock);
        return rc;
 }
 EXPORT_SYMBOL_GPL(erst_clear);
index ac1a599f5147640cc58135391260f0f202a411b1..fcc13ac0aa1870009ad0fd9dc41712795e582aab 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/async.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/suspend.h>
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 #include <linux/proc_fs.h>
@@ -102,6 +103,7 @@ struct acpi_battery {
        struct mutex lock;
        struct power_supply bat;
        struct acpi_device *device;
+       struct notifier_block pm_nb;
        unsigned long update_time;
        int rate_now;
        int capacity_now;
@@ -940,6 +942,21 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
                power_supply_changed(&battery->bat);
 }
 
+static int battery_notify(struct notifier_block *nb,
+                              unsigned long mode, void *_unused)
+{
+       struct acpi_battery *battery = container_of(nb, struct acpi_battery,
+                                                   pm_nb);
+       switch (mode) {
+       case PM_POST_SUSPEND:
+               sysfs_remove_battery(battery);
+               sysfs_add_battery(battery);
+               break;
+       }
+
+       return 0;
+}
+
 static int acpi_battery_add(struct acpi_device *device)
 {
        int result = 0;
@@ -972,6 +989,10 @@ static int acpi_battery_add(struct acpi_device *device)
 #endif
                kfree(battery);
        }
+
+       battery->pm_nb.notifier_call = battery_notify;
+       register_pm_notifier(&battery->pm_nb);
+
        return result;
 }
 
@@ -982,6 +1003,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
        battery = acpi_driver_data(device);
+       unregister_pm_notifier(&battery->pm_nb);
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_remove_fs(device);
 #endif
index 76bbb78a5ad957525c066b90ec2457ae533934e6..d27d072472f9a638fac8da78d507438b0bb3bf5e 100644 (file)
@@ -78,8 +78,6 @@ static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device, int type);
 static int acpi_button_resume(struct acpi_device *device);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
-static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
-static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
 
 static struct acpi_driver acpi_button_driver = {
        .name = "button",
@@ -98,22 +96,7 @@ struct acpi_button {
        struct input_dev *input;
        char phys[32];                  /* for input device */
        unsigned long pushed;
-};
-
-static const struct file_operations acpi_button_info_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_button_info_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-};
-
-static const struct file_operations acpi_button_state_fops = {
-       .owner = THIS_MODULE,
-       .open = acpi_button_state_open_fs,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
+       bool wakeup_enabled;
 };
 
 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
@@ -124,20 +107,7 @@ static struct acpi_device *lid_device;
    -------------------------------------------------------------------------- */
 
 static struct proc_dir_entry *acpi_button_dir;
-
-static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
-{
-       struct acpi_device *device = seq->private;
-
-       seq_printf(seq, "type:                    %s\n",
-                  acpi_device_name(device));
-       return 0;
-}
-
-static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
-{
-       return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
-}
+static struct proc_dir_entry *acpi_lid_dir;
 
 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
 {
@@ -157,77 +127,85 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
        return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
 }
 
-static struct proc_dir_entry *acpi_power_dir;
-static struct proc_dir_entry *acpi_sleep_dir;
-static struct proc_dir_entry *acpi_lid_dir;
+static const struct file_operations acpi_button_state_fops = {
+       .owner = THIS_MODULE,
+       .open = acpi_button_state_open_fs,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
 
 static int acpi_button_add_fs(struct acpi_device *device)
 {
        struct acpi_button *button = acpi_driver_data(device);
        struct proc_dir_entry *entry = NULL;
+       int ret = 0;
 
-       switch (button->type) {
-       case ACPI_BUTTON_TYPE_POWER:
-               if (!acpi_power_dir)
-                       acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
-                                                   acpi_button_dir);
-               entry = acpi_power_dir;
-               break;
-       case ACPI_BUTTON_TYPE_SLEEP:
-               if (!acpi_sleep_dir)
-                       acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
-                                                   acpi_button_dir);
-               entry = acpi_sleep_dir;
-               break;
-       case ACPI_BUTTON_TYPE_LID:
-               if (!acpi_lid_dir)
-                       acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
-                                                 acpi_button_dir);
-               entry = acpi_lid_dir;
-               break;
+       /* procfs I/F for ACPI lid device only */
+       if (button->type != ACPI_BUTTON_TYPE_LID)
+               return 0;
+
+       if (acpi_button_dir || acpi_lid_dir) {
+               printk(KERN_ERR PREFIX "More than one Lid device found!\n");
+               return -EEXIST;
        }
 
-       if (!entry)
+       /* create /proc/acpi/button */
+       acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
+       if (!acpi_button_dir)
                return -ENODEV;
 
-       acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
-       if (!acpi_device_dir(device))
-               return -ENODEV;
+       /* create /proc/acpi/button/lid */
+       acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+       if (!acpi_lid_dir) {
+               ret = -ENODEV;
+               goto remove_button_dir;
+       }
 
-       /* 'info' [R] */
-       entry = proc_create_data(ACPI_BUTTON_FILE_INFO,
-                                S_IRUGO, acpi_device_dir(device),
-                                &acpi_button_info_fops, device);
-       if (!entry)
-               return -ENODEV;
+       /* create /proc/acpi/button/lid/LID/ */
+       acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir);
+       if (!acpi_device_dir(device)) {
+               ret = -ENODEV;
+               goto remove_lid_dir;
+       }
 
-       /* show lid state [R] */
-       if (button->type == ACPI_BUTTON_TYPE_LID) {
-               entry = proc_create_data(ACPI_BUTTON_FILE_STATE,
-                                        S_IRUGO, acpi_device_dir(device),
-                                        &acpi_button_state_fops, device);
-               if (!entry)
-                       return -ENODEV;
+       /* create /proc/acpi/button/lid/LID/state */
+       entry = proc_create_data(ACPI_BUTTON_FILE_STATE,
+                                S_IRUGO, acpi_device_dir(device),
+                                &acpi_button_state_fops, device);
+       if (!entry) {
+               ret = -ENODEV;
+               goto remove_dev_dir;
        }
 
-       return 0;
+done:
+       return ret;
+
+remove_dev_dir:
+       remove_proc_entry(acpi_device_bid(device),
+                         acpi_lid_dir);
+       acpi_device_dir(device) = NULL;
+remove_lid_dir:
+       remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+remove_button_dir:
+       remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+       goto done;
 }
 
 static int acpi_button_remove_fs(struct acpi_device *device)
 {
        struct acpi_button *button = acpi_driver_data(device);
 
-       if (acpi_device_dir(device)) {
-               if (button->type == ACPI_BUTTON_TYPE_LID)
-                       remove_proc_entry(ACPI_BUTTON_FILE_STATE,
-                                         acpi_device_dir(device));
-               remove_proc_entry(ACPI_BUTTON_FILE_INFO,
-                                 acpi_device_dir(device));
+       if (button->type != ACPI_BUTTON_TYPE_LID)
+               return 0;
 
-               remove_proc_entry(acpi_device_bid(device),
-                                 acpi_device_dir(device)->parent);
-               acpi_device_dir(device) = NULL;
-       }
+       remove_proc_entry(ACPI_BUTTON_FILE_STATE,
+                         acpi_device_dir(device));
+       remove_proc_entry(acpi_device_bid(device),
+                         acpi_lid_dir);
+       acpi_device_dir(device) = NULL;
+       remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+       remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 
        return 0;
 }
@@ -430,8 +408,10 @@ static int acpi_button_add(struct acpi_device *device)
                /* Button's GPE is run-wake GPE */
                acpi_enable_gpe(device->wakeup.gpe_device,
                                device->wakeup.gpe_number);
-               device->wakeup.run_wake_count++;
-               device_set_wakeup_enable(&device->dev, true);
+               if (!device_may_wakeup(&device->dev)) {
+                       device_set_wakeup_enable(&device->dev, true);
+                       button->wakeup_enabled = true;
+               }
        }
 
        printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
@@ -453,8 +433,8 @@ static int acpi_button_remove(struct acpi_device *device, int type)
        if (device->wakeup.flags.valid) {
                acpi_disable_gpe(device->wakeup.gpe_device,
                                device->wakeup.gpe_number);
-               device->wakeup.run_wake_count--;
-               device_set_wakeup_enable(&device->dev, false);
+               if (button->wakeup_enabled)
+                       device_set_wakeup_enable(&device->dev, false);
        }
 
        acpi_button_remove_fs(device);
@@ -465,32 +445,12 @@ static int acpi_button_remove(struct acpi_device *device, int type)
 
 static int __init acpi_button_init(void)
 {
-       int result;
-
-       acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
-       if (!acpi_button_dir)
-               return -ENODEV;
-
-       result = acpi_bus_register_driver(&acpi_button_driver);
-       if (result < 0) {
-               remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
-               return -ENODEV;
-       }
-
-       return 0;
+       return acpi_bus_register_driver(&acpi_button_driver);
 }
 
 static void __exit acpi_button_exit(void)
 {
        acpi_bus_unregister_driver(&acpi_button_driver);
-
-       if (acpi_power_dir)
-               remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir);
-       if (acpi_sleep_dir)
-               remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir);
-       if (acpi_lid_dir)
-               remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
-       remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 }
 
 module_init(acpi_button_init);
index 411620ef84c2e83811adc73c8cd255f58a99549b..05b44201a61476988475fce1fea5d6b817e0565d 100644 (file)
@@ -24,10 +24,6 @@ MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
 
 #define EC_SPACE_SIZE 256
 
-struct sysdev_class acpi_ec_sysdev_class = {
-       .name = "ec",
-};
-
 static struct dentry *acpi_ec_debugfs_dir;
 
 static int acpi_ec_open_io(struct inode *i, struct file *f)
index b1cc81a0431b600653011a284228424b50ac5e83..4bfb759deb104e6febcf837a84d52c3cb39916a3 100644 (file)
@@ -21,8 +21,6 @@
 #ifndef _ACPI_INTERNAL_H_
 #define _ACPI_INTERNAL_H_
 
-#include <linux/sysdev.h>
-
 #define PREFIX "ACPI: "
 
 int init_acpi_device_notify(void);
@@ -64,7 +62,6 @@ struct acpi_ec {
        struct list_head list;
        struct transaction *curr;
        spinlock_t curr_lock;
-       struct sys_device sysdev;
 };
 
 extern struct acpi_ec *first_ec;
index fa5a1df42b79a40a817d27f036789d7bcd3a3c38..096787b43c960a71afd971ed8f312ba39e7787a9 100644 (file)
@@ -26,6 +26,7 @@ struct nvs_page {
        unsigned int size;
        void *kaddr;
        void *data;
+       bool unmap;
        struct list_head node;
 };
 
@@ -44,6 +45,9 @@ int suspend_nvs_register(unsigned long start, unsigned long size)
 {
        struct nvs_page *entry, *next;
 
+       pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n",
+               start, size);
+
        while (size > 0) {
                unsigned int nr_bytes;
 
@@ -81,7 +85,13 @@ void suspend_nvs_free(void)
                        free_page((unsigned long)entry->data);
                        entry->data = NULL;
                        if (entry->kaddr) {
-                               iounmap(entry->kaddr);
+                               if (entry->unmap) {
+                                       iounmap(entry->kaddr);
+                                       entry->unmap = false;
+                               } else {
+                                       acpi_os_unmap_memory(entry->kaddr,
+                                                            entry->size);
+                               }
                                entry->kaddr = NULL;
                        }
                }
@@ -115,8 +125,14 @@ int suspend_nvs_save(void)
 
        list_for_each_entry(entry, &nvs_list, node)
                if (entry->data) {
-                       entry->kaddr = acpi_os_ioremap(entry->phys_start,
-                                                   entry->size);
+                       unsigned long phys = entry->phys_start;
+                       unsigned int size = entry->size;
+
+                       entry->kaddr = acpi_os_get_iomem(phys, size);
+                       if (!entry->kaddr) {
+                               entry->kaddr = acpi_os_ioremap(phys, size);
+                               entry->unmap = !!entry->kaddr;
+                       }
                        if (!entry->kaddr) {
                                suspend_nvs_free();
                                return -ENOMEM;
index 4a6753009d790130bed6a9fcfa5f5cc765b0e4c6..45ad4ffef5334ba692e7883515399f863fe22e24 100644 (file)
@@ -76,7 +76,6 @@ EXPORT_SYMBOL(acpi_in_debugger);
 extern char line_buf[80];
 #endif                         /*ENABLE_DEBUGGER */
 
-static unsigned int acpi_irq_irq;
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
@@ -105,11 +104,11 @@ struct acpi_ioremap {
        void __iomem *virt;
        acpi_physical_address phys;
        acpi_size size;
-       struct kref ref;
+       unsigned long refcount;
 };
 
 static LIST_HEAD(acpi_ioremaps);
-static DEFINE_SPINLOCK(acpi_ioremap_lock);
+static DEFINE_MUTEX(acpi_ioremap_lock);
 
 static void __init acpi_osi_setup_late(void);
 
@@ -285,6 +284,22 @@ acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
        return NULL;
 }
 
+void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size)
+{
+       struct acpi_ioremap *map;
+       void __iomem *virt = NULL;
+
+       mutex_lock(&acpi_ioremap_lock);
+       map = acpi_map_lookup(phys, size);
+       if (map) {
+               virt = map->virt + (phys - map->phys);
+               map->refcount++;
+       }
+       mutex_unlock(&acpi_ioremap_lock);
+       return virt;
+}
+EXPORT_SYMBOL_GPL(acpi_os_get_iomem);
+
 /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
 static struct acpi_ioremap *
 acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
@@ -302,8 +317,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
 void __iomem *__init_refok
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
-       struct acpi_ioremap *map, *tmp_map;
-       unsigned long flags;
+       struct acpi_ioremap *map;
        void __iomem *virt;
        acpi_physical_address pg_off;
        acpi_size pg_sz;
@@ -316,14 +330,25 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
        if (!acpi_gbl_permanent_mmap)
                return __acpi_map_table((unsigned long)phys, size);
 
+       mutex_lock(&acpi_ioremap_lock);
+       /* Check if there's a suitable mapping already. */
+       map = acpi_map_lookup(phys, size);
+       if (map) {
+               map->refcount++;
+               goto out;
+       }
+
        map = kzalloc(sizeof(*map), GFP_KERNEL);
-       if (!map)
+       if (!map) {
+               mutex_unlock(&acpi_ioremap_lock);
                return NULL;
+       }
 
        pg_off = round_down(phys, PAGE_SIZE);
        pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
        virt = acpi_os_ioremap(pg_off, pg_sz);
        if (!virt) {
+               mutex_unlock(&acpi_ioremap_lock);
                kfree(map);
                return NULL;
        }
@@ -332,62 +357,51 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
        map->virt = virt;
        map->phys = pg_off;
        map->size = pg_sz;
-       kref_init(&map->ref);
-
-       spin_lock_irqsave(&acpi_ioremap_lock, flags);
-       /* Check if page has already been mapped. */
-       tmp_map = acpi_map_lookup(phys, size);
-       if (tmp_map) {
-               kref_get(&tmp_map->ref);
-               spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
-               iounmap(map->virt);
-               kfree(map);
-               return tmp_map->virt + (phys - tmp_map->phys);
-       }
+       map->refcount = 1;
+
        list_add_tail_rcu(&map->list, &acpi_ioremaps);
-       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
 
+ out:
+       mutex_unlock(&acpi_ioremap_lock);
        return map->virt + (phys - map->phys);
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
-static void acpi_kref_del_iomap(struct kref *ref)
+static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
 {
-       struct acpi_ioremap *map;
+       if (!--map->refcount)
+               list_del_rcu(&map->list);
+}
 
-       map = container_of(ref, struct acpi_ioremap, ref);
-       list_del_rcu(&map->list);
+static void acpi_os_map_cleanup(struct acpi_ioremap *map)
+{
+       if (!map->refcount) {
+               synchronize_rcu();
+               iounmap(map->virt);
+               kfree(map);
+       }
 }
 
 void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
 {
        struct acpi_ioremap *map;
-       unsigned long flags;
-       int del;
 
        if (!acpi_gbl_permanent_mmap) {
                __acpi_unmap_table(virt, size);
                return;
        }
 
-       spin_lock_irqsave(&acpi_ioremap_lock, flags);
+       mutex_lock(&acpi_ioremap_lock);
        map = acpi_map_lookup_virt(virt, size);
        if (!map) {
-               spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
-               printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
-               dump_stack();
+               mutex_unlock(&acpi_ioremap_lock);
+               WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
                return;
        }
+       acpi_os_drop_map_ref(map);
+       mutex_unlock(&acpi_ioremap_lock);
 
-       del = kref_put(&map->ref, acpi_kref_del_iomap);
-       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
-
-       if (!del)
-               return;
-
-       synchronize_rcu();
-       iounmap(map->virt);
-       kfree(map);
+       acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
@@ -397,7 +411,7 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
                __acpi_unmap_table(virt, size);
 }
 
-int acpi_os_map_generic_address(struct acpi_generic_address *addr)
+static int acpi_os_map_generic_address(struct acpi_generic_address *addr)
 {
        void __iomem *virt;
 
@@ -413,13 +427,10 @@ int acpi_os_map_generic_address(struct acpi_generic_address *addr)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
 
-void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
+static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
 {
-       void __iomem *virt;
-       unsigned long flags;
-       acpi_size size = addr->bit_width / 8;
+       struct acpi_ioremap *map;
 
        if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
                return;
@@ -427,13 +438,17 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
        if (!addr->address || !addr->bit_width)
                return;
 
-       spin_lock_irqsave(&acpi_ioremap_lock, flags);
-       virt = acpi_map_vaddr_lookup(addr->address, size);
-       spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+       mutex_lock(&acpi_ioremap_lock);
+       map = acpi_map_lookup(addr->address, addr->bit_width / 8);
+       if (!map) {
+               mutex_unlock(&acpi_ioremap_lock);
+               return;
+       }
+       acpi_os_drop_map_ref(map);
+       mutex_unlock(&acpi_ioremap_lock);
 
-       acpi_os_unmap_memory(virt, size);
+       acpi_os_map_cleanup(map);
 }
-EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
 
 #ifdef ACPI_FUTURE_USAGE
 acpi_status
@@ -516,11 +531,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
        acpi_irq_stats_init();
 
        /*
-        * Ignore the GSI from the core, and use the value in our copy of the
-        * FADT. It may not be the same if an interrupt source override exists
-        * for the SCI.
+        * ACPI interrupts different from the SCI in our copy of the FADT are
+        * not supported.
         */
-       gsi = acpi_gbl_FADT.sci_interrupt;
+       if (gsi != acpi_gbl_FADT.sci_interrupt)
+               return AE_BAD_PARAMETER;
+
+       if (acpi_irq_handler)
+               return AE_ALREADY_ACQUIRED;
+
        if (acpi_gsi_to_irq(gsi, &irq) < 0) {
                printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
                       gsi);
@@ -531,20 +550,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
        acpi_irq_context = context;
        if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
                printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
+               acpi_irq_handler = NULL;
                return AE_NOT_ACQUIRED;
        }
-       acpi_irq_irq = irq;
 
        return AE_OK;
 }
 
 acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
 {
-       if (irq) {
-               free_irq(irq, acpi_irq);
-               acpi_irq_handler = NULL;
-               acpi_irq_irq = 0;
-       }
+       if (irq != acpi_gbl_FADT.sci_interrupt)
+               return AE_BAD_PARAMETER;
+
+       free_irq(irq, acpi_irq);
+       acpi_irq_handler = NULL;
 
        return AE_OK;
 }
@@ -1603,7 +1622,7 @@ acpi_status __init acpi_os_initialize1(void)
 acpi_status acpi_os_terminate(void)
 {
        if (acpi_irq_handler) {
-               acpi_os_remove_interrupt_handler(acpi_irq_irq,
+               acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt,
                                                 acpi_irq_handler);
        }
 
index 9ff80a7e9f6ada0aef1c57bea5e3f6b142037de5..4a29763b8eb454b28c59c9257c893ac0fadc5599 100644 (file)
@@ -29,7 +29,7 @@
  *        for IRQ management (e.g. start()->_SRS).
  */
 
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -757,14 +757,13 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link)
        return 0;
 }
 
-static int irqrouter_resume(struct sys_device *dev)
+static void irqrouter_resume(void)
 {
        struct acpi_pci_link *link;
 
        list_for_each_entry(link, &acpi_link_list, list) {
                acpi_pci_link_resume(link);
        }
-       return 0;
 }
 
 static int acpi_pci_link_remove(struct acpi_device *device, int type)
@@ -871,32 +870,19 @@ static int __init acpi_irq_balance_set(char *str)
 
 __setup("acpi_irq_balance", acpi_irq_balance_set);
 
-/* FIXME: we will remove this interface after all drivers call pci_disable_device */
-static struct sysdev_class irqrouter_sysdev_class = {
-       .name = "irqrouter",
+static struct syscore_ops irqrouter_syscore_ops = {
        .resume = irqrouter_resume,
 };
 
-static struct sys_device device_irqrouter = {
-       .id = 0,
-       .cls = &irqrouter_sysdev_class,
-};
-
-static int __init irqrouter_init_sysfs(void)
+static int __init irqrouter_init_ops(void)
 {
-       int error;
+       if (!acpi_disabled && !acpi_noirq)
+               register_syscore_ops(&irqrouter_syscore_ops);
 
-       if (acpi_disabled || acpi_noirq)
-               return 0;
-
-       error = sysdev_class_register(&irqrouter_sysdev_class);
-       if (!error)
-               error = sysdev_register(&device_irqrouter);
-
-       return error;
+       return 0;
 }
 
-device_initcall(irqrouter_init_sysfs);
+device_initcall(irqrouter_init_ops);
 
 static int __init acpi_pci_link_init(void)
 {
index 85249395623baa32b556fbddeb77e4c71e6dfeac..f911a2f8cc346f40f7575db6eab96cf6acf2339a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/pci-acpi.h>
+#include <linux/pci-aspm.h>
 #include <linux/acpi.h>
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
@@ -564,7 +565,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
        /* Indicate support for various _OSC capabilities. */
        if (pci_ext_cfg_avail(root->bus->self))
                flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
-       if (pcie_aspm_enabled())
+       if (pcie_aspm_support_enabled())
                flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
                        OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
        if (pci_msi_enabled())
@@ -591,12 +592,16 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
 
                status = acpi_pci_osc_control_set(device->handle, &flags,
                                        OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
-               if (ACPI_SUCCESS(status))
+               if (ACPI_SUCCESS(status)) {
                        dev_info(root->bus->bridge,
                                "ACPI _OSC control (0x%02x) granted\n", flags);
-               else
+               } else {
                        dev_dbg(root->bus->bridge,
                                "ACPI _OSC request failed (code %d)\n", status);
+                       printk(KERN_INFO "Unable to assume _OSC PCIe control. "
+                               "Disabling ASPM\n");
+                       pcie_no_aspm();
+               }
        }
 
        pci_acpi_add_bus_pm_notifier(device, root->bus);
index 3c1a2fec8cda7533d7bd1be0346f3ee9383da7f7..25bf17da69fd8a298d1bb875a5942fe253720168 100644 (file)
@@ -19,7 +19,7 @@
 #define _COMPONENT             ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_core");
 
-static int set_no_mwait(const struct dmi_system_id *id)
+static int __init set_no_mwait(const struct dmi_system_id *id)
 {
        printk(KERN_NOTICE PREFIX "%s detected - "
                "disabling mwait for CPU C-states\n", id->ident);
@@ -27,7 +27,7 @@ static int set_no_mwait(const struct dmi_system_id *id)
        return 0;
 }
 
-static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
+static struct dmi_system_id __initdata processor_idle_dmi_table[] = {
        {
        set_no_mwait, "Extensa 5220", {
        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
@@ -183,7 +183,7 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 EXPORT_SYMBOL_GPL(acpi_get_cpuid);
 #endif
 
-static bool processor_physically_present(acpi_handle handle)
+static bool __init processor_physically_present(acpi_handle handle)
 {
        int cpuid, type;
        u32 acpi_id;
@@ -223,7 +223,7 @@ static bool processor_physically_present(acpi_handle handle)
        return true;
 }
 
-static void acpi_set_pdc_bits(u32 *buf)
+static void __cpuinit acpi_set_pdc_bits(u32 *buf)
 {
        buf[0] = ACPI_PDC_REVISION_ID;
        buf[1] = 1;
@@ -235,7 +235,7 @@ static void acpi_set_pdc_bits(u32 *buf)
        arch_acpi_set_pdc_bits(buf);
 }
 
-static struct acpi_object_list *acpi_processor_alloc_pdc(void)
+static struct acpi_object_list *__cpuinit acpi_processor_alloc_pdc(void)
 {
        struct acpi_object_list *obj_list;
        union acpi_object *obj;
@@ -278,7 +278,7 @@ static struct acpi_object_list *acpi_processor_alloc_pdc(void)
  * _PDC is required for a BIOS-OS handshake for most of the newer
  * ACPI processor features.
  */
-static int
+static int __cpuinit
 acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
 {
        acpi_status status = AE_OK;
@@ -306,7 +306,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
        return status;
 }
 
-void acpi_processor_set_pdc(acpi_handle handle)
+void __cpuinit acpi_processor_set_pdc(acpi_handle handle)
 {
        struct acpi_object_list *obj_list;
 
@@ -323,9 +323,8 @@ void acpi_processor_set_pdc(acpi_handle handle)
        kfree(obj_list->pointer);
        kfree(obj_list);
 }
-EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
 
-static acpi_status
+static acpi_status __init
 early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        if (processor_physically_present(handle) == false)
index 360a74e6add035e5da570f5c89d8d64c4aec82b3..a4e0f1ba6040c7f398f08f8816090ec5524ea629 100644 (file)
@@ -635,8 +635,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
        return 0;
 }
 
-static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
-                                               u32 event, void *data)
+static void acpi_processor_hotplug_notify(acpi_handle handle,
+                                         u32 event, void *data)
 {
        struct acpi_processor *pr;
        struct acpi_device *device = NULL;
index 93f91142d7ad5ca01fc62b8dc16569660cfa0434..a6c77e8b37bde54c266cae17d620c441a896e3b9 100644 (file)
@@ -15,9 +15,15 @@ void acpi_reboot(void)
 
        rr = &acpi_gbl_FADT.reset_register;
 
-       /* Is the reset register supported? */
-       if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
-           rr->bit_width != 8 || rr->bit_offset != 0)
+       /* ACPI reset register was only introduced with v2 of the FADT */
+
+       if (acpi_gbl_FADT.header.revision < 2)
+               return;
+
+       /* Is the reset register supported? The spec says we should be
+        * checking the bit width and bit offset, but Windows ignores
+        * these fields */
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER))
                return;
 
        reset_value = acpi_gbl_FADT.reset_value;
@@ -45,6 +51,4 @@ void acpi_reboot(void)
                acpi_reset();
                break;
        }
-       /* Wait ten seconds */
-       acpi_os_stall(10000000);
 }
index b99e624946074143a28f6c0a236b0d002426117a..b136c9c1e531954dc27cc4bed422e1618e7681ee 100644 (file)
@@ -797,7 +797,6 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
        acpi_status status;
        acpi_event_status event_status;
 
-       device->wakeup.run_wake_count = 0;
        device->wakeup.flags.notifier_present = 0;
 
        /* Power button, Lid switch always enable wakeup */
index 1850dac8f45c229576a1aafb29e3da4e284515ce..6c949602cbd111d18753217ea0ee4784054ec008 100644 (file)
@@ -200,8 +200,6 @@ static void acpi_pm_end(void)
 #endif /* CONFIG_ACPI_SLEEP */
 
 #ifdef CONFIG_SUSPEND
-extern void do_suspend_lowlevel(void);
-
 static u32 acpi_suspend_states[] = {
        [PM_SUSPEND_ON] = ACPI_STATE_S0,
        [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
@@ -244,20 +242,11 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
 static int acpi_suspend_enter(suspend_state_t pm_state)
 {
        acpi_status status = AE_OK;
-       unsigned long flags = 0;
        u32 acpi_state = acpi_target_sleep_state;
+       int error;
 
        ACPI_FLUSH_CPU_CACHE();
 
-       /* Do arch specific saving of state. */
-       if (acpi_state == ACPI_STATE_S3) {
-               int error = acpi_save_state_mem();
-
-               if (error)
-                       return error;
-       }
-
-       local_irq_save(flags);
        switch (acpi_state) {
        case ACPI_STATE_S1:
                barrier();
@@ -265,7 +254,10 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
 
        case ACPI_STATE_S3:
-               do_suspend_lowlevel();
+               error = acpi_suspend_lowlevel();
+               if (error)
+                       return error;
+               pr_info(PREFIX "Low-level resume complete\n");
                break;
        }
 
@@ -291,13 +283,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        /* Allow EC transactions to happen. */
        acpi_ec_unblock_transactions_early();
 
-       local_irq_restore(flags);
-       printk(KERN_DEBUG "Back to C!\n");
-
-       /* restore processor state */
-       if (acpi_state == ACPI_STATE_S3)
-               acpi_restore_state_mem();
-
        suspend_nvs_restore();
 
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -473,16 +458,13 @@ static int acpi_hibernation_begin(void)
 static int acpi_hibernation_enter(void)
 {
        acpi_status status = AE_OK;
-       unsigned long flags = 0;
 
        ACPI_FLUSH_CPU_CACHE();
 
-       local_irq_save(flags);
        /* This shouldn't return.  If it returns, we have a problem */
        status = acpi_enter_sleep_state(ACPI_STATE_S4);
        /* Reprogram control registers and execute _BFS */
        acpi_leave_sleep_state_prep(ACPI_STATE_S4);
-       local_irq_restore(flags);
 
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
index 90f8f7676d1faeb346ef02791ab919987e95c08e..a18e497f1c3ca92722fd5f8bc8e36bb774d7b982 100644 (file)
@@ -782,6 +782,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
        if (acpi_video_backlight_support()) {
                struct backlight_properties props;
+               struct pci_dev *pdev;
+               acpi_handle acpi_parent;
+               struct device *parent = NULL;
                int result;
                static int count = 0;
                char *name;
@@ -794,9 +797,20 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                        return;
                count++;
 
+               acpi_get_parent(device->dev->handle, &acpi_parent);
+
+               pdev = acpi_get_pci_dev(acpi_parent);
+               if (pdev) {
+                       parent = &pdev->dev;
+                       pci_dev_put(pdev);
+               }
+
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_FIRMWARE;
                props.max_brightness = device->brightness->count - 3;
-               device->backlight = backlight_device_register(name, NULL, device,
+               device->backlight = backlight_device_register(name,
+                                                             parent,
+                                                             device,
                                                              &acpi_backlight_ops,
                                                              &props);
                kfree(name);
index 1f286ab461d3d62471dbaa5323cd468b1080a842..79882104e431a283235b3e1cdee24343429366eb 100644 (file)
@@ -140,13 +140,14 @@ static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static int DAC960_media_changed(struct gendisk *disk)
+static unsigned int DAC960_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        DAC960_Controller_T *p = disk->queue->queuedata;
        int drive_nr = (long)disk->private_data;
 
        if (!p->LogicalDriveInitiallyAccessible[drive_nr])
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        return 0;
 }
 
@@ -163,7 +164,7 @@ static const struct block_device_operations DAC960_BlockDeviceOperations = {
        .owner                  = THIS_MODULE,
        .open                   = DAC960_open,
        .getgeo                 = DAC960_getgeo,
-       .media_changed          = DAC960_media_changed,
+       .check_events           = DAC960_check_events,
        .revalidate_disk        = DAC960_revalidate_disk,
 };
 
@@ -2546,6 +2547,7 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
        disk->major = MajorNumber;
        disk->first_minor = n << DAC960_MaxPartitionsBits;
        disk->fops = &DAC960_BlockDeviceOperations;
+       disk->events = DISK_EVENT_MEDIA_CHANGE;
    }
   /*
     Indicate the Block Device Registration completed successfully,
index 363855ca376e6792f9684e44a4eea3b1c2abcb2d..456c0cc90dcfd58d87de3d34ace5dda354795112 100644 (file)
@@ -1658,12 +1658,12 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
 }
 
 /*
- * floppy-change is never called from an interrupt, so we can relax a bit
+ * check_events is never called from an interrupt, so we can relax a bit
  * here, sleep etc. Note that floppy-on tries to set current_DOR to point
  * to the desired drive, but it will probably not survive the sleep if
  * several floppies are used at the same time: thus the loop.
  */
-static int amiga_floppy_change(struct gendisk *disk)
+static unsigned amiga_check_events(struct gendisk *disk, unsigned int clearing)
 {
        struct amiga_floppy_struct *p = disk->private_data;
        int drive = p - unit;
@@ -1686,7 +1686,7 @@ static int amiga_floppy_change(struct gendisk *disk)
                p->dirty = 0;
                writepending = 0; /* if this was true before, too bad! */
                writefromint = 0;
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
        return 0;
 }
@@ -1697,7 +1697,7 @@ static const struct block_device_operations floppy_fops = {
        .release        = floppy_release,
        .ioctl          = fd_ioctl,
        .getgeo         = fd_getgeo,
-       .media_changed  = amiga_floppy_change,
+       .check_events   = amiga_check_events,
 };
 
 static int __init fd_probe_drives(void)
@@ -1736,6 +1736,7 @@ static int __init fd_probe_drives(void)
                disk->major = FLOPPY_MAJOR;
                disk->first_minor = drive;
                disk->fops = &floppy_fops;
+               disk->events = DISK_EVENT_MEDIA_CHANGE;
                sprintf(disk->disk_name, "fd%d", drive);
                disk->private_data = &unit[drive];
                set_capacity(disk, 880*2);
index 605a67e40bbfc902609233ebc52d22f8bc008e23..c871eae14120423f2cd618742730a6f6b51edeb3 100644 (file)
@@ -1324,23 +1324,24 @@ static void finish_fdc_done( int dummy )
  * due to unrecognised disk changes.
  */
 
-static int check_floppy_change(struct gendisk *disk)
+static unsigned int floppy_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        struct atari_floppy_struct *p = disk->private_data;
        unsigned int drive = p - unit;
        if (test_bit (drive, &fake_change)) {
                /* simulated change (e.g. after formatting) */
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
        if (test_bit (drive, &changed_floppies)) {
                /* surely changed (the WP signal changed at least once) */
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
        if (UD.wpstat) {
                /* WP is on -> could be changed: to be sure, buffers should be
                 * invalidated...
                 */
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
 
        return 0;
@@ -1570,7 +1571,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
                 * or the next access will revalidate - and clear UDT :-(
                 */
 
-               if (check_floppy_change(disk))
+               if (floppy_check_events(disk, 0))
                        floppy_revalidate(disk);
 
                if (UD.flags & FTD_MSG)
@@ -1904,7 +1905,7 @@ static const struct block_device_operations floppy_fops = {
        .open           = floppy_unlocked_open,
        .release        = floppy_release,
        .ioctl          = fd_ioctl,
-       .media_changed  = check_floppy_change,
+       .check_events   = floppy_check_events,
        .revalidate_disk= floppy_revalidate,
 };
 
@@ -1963,6 +1964,7 @@ static int __init atari_floppy_init (void)
                unit[i].disk->first_minor = i;
                sprintf(unit[i].disk->disk_name, "fd%d", i);
                unit[i].disk->fops = &floppy_fops;
+               unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE;
                unit[i].disk->private_data = &unit[i];
                unit[i].disk->queue = blk_init_queue(do_fd_request,
                                        &ataflop_lock);
index 9279272b3732719c9b660e6abc6146dd6dfee960..35658f445fca4a494071438ad0f4788bab936231 100644 (file)
@@ -3170,12 +3170,6 @@ static void do_cciss_request(struct request_queue *q)
        int sg_index = 0;
        int chained = 0;
 
-       /* We call start_io here in case there is a command waiting on the
-        * queue that has not been sent.
-        */
-       if (blk_queue_plugged(q))
-               goto startio;
-
       queue:
        creq = blk_peek_request(q);
        if (!creq)
index 946dad4caef37c63615d151fecabc8a7ac5e0d4e..b2fceb53e8092bd28355f7678ea4e92351952299 100644 (file)
@@ -911,9 +911,6 @@ static void do_ida_request(struct request_queue *q)
        struct scatterlist tmp_sg[SG_MAX];
        int i, dir, seg;
 
-       if (blk_queue_plugged(q))
-               goto startio;
-
 queue_next:
        creq = blk_peek_request(q);
        if (!creq)
index ba95cba192be8d1d00f7b7e9b47f1cb05d460470..aca302492ff20a25e65ac645a601dbf51ada2f33 100644 (file)
@@ -80,7 +80,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
 
        if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
                rw |= REQ_FUA;
-       rw |= REQ_UNPLUG | REQ_SYNC;
+       rw |= REQ_SYNC;
 
        bio = bio_alloc(GFP_NOIO, 1);
        bio->bi_bdev = bdev->md_bdev;
@@ -689,8 +689,6 @@ void drbd_al_to_on_disk_bm(struct drbd_conf *mdev)
                }
        }
 
-       drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
-
        /* always (try to) flush bitmap to stable storage */
        drbd_md_flush(mdev);
 
index fd42832f785b86a6056e3c4efceccaeab37f04bd..0645ca829a94163c57f4ee5ac43e96aaa344870d 100644 (file)
@@ -840,7 +840,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local)
        for (i = 0; i < num_pages; i++)
                bm_page_io_async(mdev, b, i, rw);
 
-       drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev));
        wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0);
 
        if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) {
index 3803a03489372911290cd539988da5e779ac85d2..b0bd27dfc1e8a88deab0c49705b3ed201da7309c 100644 (file)
@@ -377,7 +377,7 @@ union p_header {
 #define DP_HARDBARRIER       1 /* depricated */
 #define DP_RW_SYNC           2 /* equals REQ_SYNC    */
 #define DP_MAY_SET_IN_SYNC    4
-#define DP_UNPLUG             8 /* equals REQ_UNPLUG  */
+#define DP_UNPLUG             8 /* not used anymore   */
 #define DP_FUA               16 /* equals REQ_FUA     */
 #define DP_FLUSH             32 /* equals REQ_FLUSH   */
 #define DP_DISCARD           64 /* equals REQ_DISCARD */
@@ -2382,20 +2382,6 @@ static inline int drbd_queue_order_type(struct drbd_conf *mdev)
        return QUEUE_ORDERED_NONE;
 }
 
-static inline void drbd_blk_run_queue(struct request_queue *q)
-{
-       if (q && q->unplug_fn)
-               q->unplug_fn(q);
-}
-
-static inline void drbd_kick_lo(struct drbd_conf *mdev)
-{
-       if (get_ldev(mdev)) {
-               drbd_blk_run_queue(bdev_get_queue(mdev->ldev->backing_bdev));
-               put_ldev(mdev);
-       }
-}
-
 static inline void drbd_md_flush(struct drbd_conf *mdev)
 {
        int r;
index 29cd0dc9fe4f8c9fe6731aaaf6f85220b7bf5db0..8a43ce0edeed12f1007cfeb9474ed857fc8f39cd 100644 (file)
@@ -2477,12 +2477,11 @@ static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
 {
        if (mdev->agreed_pro_version >= 95)
                return  (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
-                       (bi_rw & REQ_UNPLUG ? DP_UNPLUG : 0) |
                        (bi_rw & REQ_FUA ? DP_FUA : 0) |
                        (bi_rw & REQ_FLUSH ? DP_FLUSH : 0) |
                        (bi_rw & REQ_DISCARD ? DP_DISCARD : 0);
        else
-               return bi_rw & (REQ_SYNC | REQ_UNPLUG) ? DP_RW_SYNC : 0;
+               return bi_rw & REQ_SYNC ? DP_RW_SYNC : 0;
 }
 
 /* Used to send write requests
@@ -2719,35 +2718,6 @@ static int drbd_release(struct gendisk *gd, fmode_t mode)
        return 0;
 }
 
-static void drbd_unplug_fn(struct request_queue *q)
-{
-       struct drbd_conf *mdev = q->queuedata;
-
-       /* unplug FIRST */
-       spin_lock_irq(q->queue_lock);
-       blk_remove_plug(q);
-       spin_unlock_irq(q->queue_lock);
-
-       /* only if connected */
-       spin_lock_irq(&mdev->req_lock);
-       if (mdev->state.pdsk >= D_INCONSISTENT && mdev->state.conn >= C_CONNECTED) {
-               D_ASSERT(mdev->state.role == R_PRIMARY);
-               if (test_and_clear_bit(UNPLUG_REMOTE, &mdev->flags)) {
-                       /* add to the data.work queue,
-                        * unless already queued.
-                        * XXX this might be a good addition to drbd_queue_work
-                        * anyways, to detect "double queuing" ... */
-                       if (list_empty(&mdev->unplug_work.list))
-                               drbd_queue_work(&mdev->data.work,
-                                               &mdev->unplug_work);
-               }
-       }
-       spin_unlock_irq(&mdev->req_lock);
-
-       if (mdev->state.disk >= D_INCONSISTENT)
-               drbd_kick_lo(mdev);
-}
-
 static void drbd_set_defaults(struct drbd_conf *mdev)
 {
        /* This way we get a compile error when sync_conf grows,
@@ -3222,9 +3192,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
        blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE);
        blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
        blk_queue_merge_bvec(q, drbd_merge_bvec);
-       q->queue_lock = &mdev->req_lock; /* needed since we use */
-               /* plugging on a queue, that actually has no requests! */
-       q->unplug_fn = drbd_unplug_fn;
+       q->queue_lock = &mdev->req_lock;
 
        mdev->md_io_page = alloc_page(GFP_KERNEL);
        if (!mdev->md_io_page)
index 24487d4fb20297e6676a91e60c9525f26092e315..8e68be939debefb6e5960ed38c2dd42d67c3a18d 100644 (file)
@@ -187,15 +187,6 @@ static struct page *drbd_pp_first_pages_or_try_alloc(struct drbd_conf *mdev, int
        return NULL;
 }
 
-/* kick lower level device, if we have more than (arbitrary number)
- * reference counts on it, which typically are locally submitted io
- * requests.  don't use unacked_cnt, so we speed up proto A and B, too. */
-static void maybe_kick_lo(struct drbd_conf *mdev)
-{
-       if (atomic_read(&mdev->local_cnt) >= mdev->net_conf->unplug_watermark)
-               drbd_kick_lo(mdev);
-}
-
 static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed)
 {
        struct drbd_epoch_entry *e;
@@ -219,7 +210,6 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev)
        LIST_HEAD(reclaimed);
        struct drbd_epoch_entry *e, *t;
 
-       maybe_kick_lo(mdev);
        spin_lock_irq(&mdev->req_lock);
        reclaim_net_ee(mdev, &reclaimed);
        spin_unlock_irq(&mdev->req_lock);
@@ -436,8 +426,7 @@ void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head)
        while (!list_empty(head)) {
                prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE);
                spin_unlock_irq(&mdev->req_lock);
-               drbd_kick_lo(mdev);
-               schedule();
+               io_schedule();
                finish_wait(&mdev->ee_wait, &wait);
                spin_lock_irq(&mdev->req_lock);
        }
@@ -1111,8 +1100,6 @@ next_bio:
        /* > e->sector, unless this is the first bio */
        bio->bi_sector = sector;
        bio->bi_bdev = mdev->ldev->backing_bdev;
-       /* we special case some flags in the multi-bio case, see below
-        * (REQ_UNPLUG) */
        bio->bi_rw = rw;
        bio->bi_private = e;
        bio->bi_end_io = drbd_endio_sec;
@@ -1141,13 +1128,8 @@ next_bio:
                bios = bios->bi_next;
                bio->bi_next = NULL;
 
-               /* strip off REQ_UNPLUG unless it is the last bio */
-               if (bios)
-                       bio->bi_rw &= ~REQ_UNPLUG;
-
                drbd_generic_make_request(mdev, fault_type, bio);
        } while (bios);
-       maybe_kick_lo(mdev);
        return 0;
 
 fail:
@@ -1167,9 +1149,6 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign
 
        inc_unacked(mdev);
 
-       if (mdev->net_conf->wire_protocol != DRBD_PROT_C)
-               drbd_kick_lo(mdev);
-
        mdev->current_epoch->barrier_nr = p->barrier;
        rv = drbd_may_finish_epoch(mdev, mdev->current_epoch, EV_GOT_BARRIER_NR);
 
@@ -1636,12 +1615,11 @@ static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
 {
        if (mdev->agreed_pro_version >= 95)
                return  (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
-                       (dpf & DP_UNPLUG ? REQ_UNPLUG : 0) |
                        (dpf & DP_FUA ? REQ_FUA : 0) |
                        (dpf & DP_FLUSH ? REQ_FUA : 0) |
                        (dpf & DP_DISCARD ? REQ_DISCARD : 0);
        else
-               return dpf & DP_RW_SYNC ? (REQ_SYNC | REQ_UNPLUG) : 0;
+               return dpf & DP_RW_SYNC ? REQ_SYNC : 0;
 }
 
 /* mirrored write */
@@ -3556,9 +3534,6 @@ static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 
 static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-       if (mdev->state.disk >= D_INCONSISTENT)
-               drbd_kick_lo(mdev);
-
        /* Make sure we've acked all the TCP data associated
         * with the data requests being unplugged */
        drbd_tcp_quickack(mdev->data.socket);
index 11a75d32a2e27f0d78c26b511921780f4d336264..ad3fc6228f27924d3523976fd3a5a4486c3a5b4a 100644 (file)
@@ -960,10 +960,6 @@ allocate_barrier:
                        bio_endio(req->private_bio, -EIO);
        }
 
-       /* we need to plug ALWAYS since we possibly need to kick lo_dev.
-        * we plug after submit, so we won't miss an unplug event */
-       drbd_plug_device(mdev);
-
        return 0;
 
 fail_conflicting:
index 34f224b018b37b1e1781134fedf67179799ab20e..e027446590d3752d63d2301c7d65e17d749f7b13 100644 (file)
@@ -792,7 +792,6 @@ int drbd_resync_finished(struct drbd_conf *mdev)
                 * queue (or even the read operations for those packets
                 * is not finished by now).   Retry in 100ms. */
 
-               drbd_kick_lo(mdev);
                __set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(HZ / 10);
                w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC);
index defdb5013ea3444f272e83084d378964eca621ba..53586fa5ae1b098686e6171ea821fa21dc1bdb1f 100644 (file)
@@ -45,24 +45,6 @@ static inline void drbd_generic_make_request(struct drbd_conf *mdev,
                generic_make_request(bio);
 }
 
-static inline void drbd_plug_device(struct drbd_conf *mdev)
-{
-       struct request_queue *q;
-       q = bdev_get_queue(mdev->this_bdev);
-
-       spin_lock_irq(q->queue_lock);
-
-/* XXX the check on !blk_queue_plugged is redundant,
- * implicitly checked in blk_plug_device */
-
-       if (!blk_queue_plugged(q)) {
-               blk_plug_device(q);
-               del_timer(&q->unplug_timer);
-               /* unplugging should not happen automatically... */
-       }
-       spin_unlock_irq(q->queue_lock);
-}
-
 static inline int drbd_crypto_is_hash(struct crypto_tfm *tfm)
 {
         return (crypto_tfm_alg_type(tfm) & CRYPTO_ALG_TYPE_HASH_MASK)
index 77fc76f8aea91b79be3f8cfc6c640e3e23748de0..301d7a9a41a6b51be0ae02f6ca92b2fb063316a7 100644 (file)
@@ -3770,13 +3770,14 @@ out2:
 /*
  * Check if the disk has been changed or if a change has been faked.
  */
-static int check_floppy_change(struct gendisk *disk)
+static unsigned int floppy_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        int drive = (long)disk->private_data;
 
        if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
            test_bit(FD_VERIFY_BIT, &UDRS->flags))
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
 
        if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
                lock_fdc(drive, false);
@@ -3788,7 +3789,7 @@ static int check_floppy_change(struct gendisk *disk)
            test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
            test_bit(drive, &fake_change) ||
            drive_no_geom(drive))
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        return 0;
 }
 
@@ -3837,7 +3838,6 @@ static int __floppy_read_block_0(struct block_device *bdev)
        bio.bi_end_io = floppy_rb0_complete;
 
        submit_bio(READ, &bio);
-       generic_unplug_device(bdev_get_queue(bdev));
        process_fd_request();
        wait_for_completion(&complete);
 
@@ -3898,7 +3898,7 @@ static const struct block_device_operations floppy_fops = {
        .release                = floppy_release,
        .ioctl                  = fd_ioctl,
        .getgeo                 = fd_getgeo,
-       .media_changed          = check_floppy_change,
+       .check_events           = floppy_check_events,
        .revalidate_disk        = floppy_revalidate,
 };
 
@@ -4205,6 +4205,7 @@ static int __init floppy_init(void)
                disks[dr]->major = FLOPPY_MAJOR;
                disks[dr]->first_minor = TOMINOR(dr);
                disks[dr]->fops = &floppy_fops;
+               disks[dr]->events = DISK_EVENT_MEDIA_CHANGE;
                sprintf(disks[dr]->disk_name, "fd%d", dr);
 
                init_timer(&motor_off_timer[dr]);
index dbf31ec9114db6a23c270be8d49e3836cbc2684a..a076a14ca72d848fbf144042a7272038eab22390 100644 (file)
@@ -540,17 +540,6 @@ out:
        return 0;
 }
 
-/*
- * kick off io on the underlying address space
- */
-static void loop_unplug(struct request_queue *q)
-{
-       struct loop_device *lo = q->queuedata;
-
-       queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q);
-       blk_run_address_space(lo->lo_backing_file->f_mapping);
-}
-
 struct switch_request {
        struct file *file;
        struct completion wait;
@@ -917,7 +906,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
         */
        blk_queue_make_request(lo->lo_queue, loop_make_request);
        lo->lo_queue->queuedata = lo;
-       lo->lo_queue->unplug_fn = loop_unplug;
 
        if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
                blk_queue_flush(lo->lo_queue, REQ_FLUSH);
@@ -1019,7 +1007,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
 
        kthread_stop(lo->lo_thread);
 
-       lo->lo_queue->unplug_fn = NULL;
        lo->lo_backing_file = NULL;
 
        loop_release_xfer(lo);
@@ -1636,9 +1623,6 @@ out:
 
 static void loop_free(struct loop_device *lo)
 {
-       if (!lo->lo_queue->queue_lock)
-               lo->lo_queue->queue_lock = &lo->lo_queue->__queue_lock;
-
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
        list_del(&lo->lo_list);
index 62cec6afd7adf560f6792c68949f71fcc8e6f9ea..2f2ccf6862519c4bb44493ccab140cbbdab37a93 100644 (file)
@@ -172,7 +172,8 @@ module_param_array(drive3, int, NULL, 0);
 static int pcd_open(struct cdrom_device_info *cdi, int purpose);
 static void pcd_release(struct cdrom_device_info *cdi);
 static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
-static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr);
+static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
+                                    unsigned int clearing, int slot_nr);
 static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
 static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
 static int pcd_drive_reset(struct cdrom_device_info *cdi);
@@ -257,10 +258,11 @@ static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
        return ret;
 }
 
-static int pcd_block_media_changed(struct gendisk *disk)
+static unsigned int pcd_block_check_events(struct gendisk *disk,
+                                          unsigned int clearing)
 {
        struct pcd_unit *cd = disk->private_data;
-       return cdrom_media_changed(&cd->info);
+       return cdrom_check_events(&cd->info, clearing);
 }
 
 static const struct block_device_operations pcd_bdops = {
@@ -268,14 +270,14 @@ static const struct block_device_operations pcd_bdops = {
        .open           = pcd_block_open,
        .release        = pcd_block_release,
        .ioctl          = pcd_block_ioctl,
-       .media_changed  = pcd_block_media_changed,
+       .check_events   = pcd_block_check_events,
 };
 
 static struct cdrom_device_ops pcd_dops = {
        .open           = pcd_open,
        .release        = pcd_release,
        .drive_status   = pcd_drive_status,
-       .media_changed  = pcd_media_changed,
+       .check_events   = pcd_check_events,
        .tray_move      = pcd_tray_move,
        .lock_door      = pcd_lock_door,
        .get_mcn        = pcd_get_mcn,
@@ -318,6 +320,7 @@ static void pcd_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, cd->name);      /* umm... */
                disk->fops = &pcd_bdops;
+               disk->events = DISK_EVENT_MEDIA_CHANGE;
        }
 }
 
@@ -502,13 +505,14 @@ static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
 
 #define DBMSG(msg)     ((verbose>1)?(msg):NULL)
 
-static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
+static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
+                                    unsigned int clearing, int slot_nr)
 {
        struct pcd_unit *cd = cdi->handle;
        int res = cd->changed;
        if (res)
                cd->changed = 0;
-       return res;
+       return res ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
index c0ee1558b9bba105859f29f288bb4310e8ad4f3d..21dfdb7768695cfe8d9517dc59f4cf7a5b1df279 100644 (file)
@@ -794,7 +794,7 @@ static int pd_release(struct gendisk *p, fmode_t mode)
        return 0;
 }
 
-static int pd_check_media(struct gendisk *p)
+static unsigned int pd_check_events(struct gendisk *p, unsigned int clearing)
 {
        struct pd_unit *disk = p->private_data;
        int r;
@@ -803,7 +803,7 @@ static int pd_check_media(struct gendisk *p)
        pd_special_command(disk, pd_media_check);
        r = disk->changed;
        disk->changed = 0;
-       return r;
+       return r ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int pd_revalidate(struct gendisk *p)
@@ -822,7 +822,7 @@ static const struct block_device_operations pd_fops = {
        .release        = pd_release,
        .ioctl          = pd_ioctl,
        .getgeo         = pd_getgeo,
-       .media_changed  = pd_check_media,
+       .check_events   = pd_check_events,
        .revalidate_disk= pd_revalidate
 };
 
@@ -837,6 +837,7 @@ static void pd_probe_drive(struct pd_unit *disk)
        p->fops = &pd_fops;
        p->major = major;
        p->first_minor = (disk - pd) << PD_BITS;
+       p->events = DISK_EVENT_MEDIA_CHANGE;
        disk->gd = p;
        p->private_data = disk;
        p->queue = pd_queue;
index 635f25dd9e1082c9d1099c0ccca8142436e8f38d..7adeb1edbf43faf02b5f68f79d93f6d839baa9e4 100644 (file)
@@ -243,7 +243,8 @@ static struct pf_unit units[PF_UNITS];
 static int pf_identify(struct pf_unit *pf);
 static void pf_lock(struct pf_unit *pf, int func);
 static void pf_eject(struct pf_unit *pf);
-static int pf_check_media(struct gendisk *disk);
+static unsigned int pf_check_events(struct gendisk *disk,
+                                   unsigned int clearing);
 
 static char pf_scratch[512];   /* scratch block buffer */
 
@@ -270,7 +271,7 @@ static const struct block_device_operations pf_fops = {
        .release        = pf_release,
        .ioctl          = pf_ioctl,
        .getgeo         = pf_getgeo,
-       .media_changed  = pf_check_media,
+       .check_events   = pf_check_events,
 };
 
 static void __init pf_init_units(void)
@@ -293,6 +294,7 @@ static void __init pf_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, pf->name);
                disk->fops = &pf_fops;
+               disk->events = DISK_EVENT_MEDIA_CHANGE;
                if (!(*drives[unit])[D_PRT])
                        pf_drive_count++;
        }
@@ -377,9 +379,9 @@ static int pf_release(struct gendisk *disk, fmode_t mode)
 
 }
 
-static int pf_check_media(struct gendisk *disk)
+static unsigned int pf_check_events(struct gendisk *disk, unsigned int clearing)
 {
-       return 1;
+       return DISK_EVENT_MEDIA_CHANGE;
 }
 
 static inline int status_reg(struct pf_unit *pf)
index 77d70eebb6b2121e49b94b7626383b31552a2a35..07a382eaf0a86b8b0a8f9f30a57dfe3e3e68f6a9 100644 (file)
@@ -1606,8 +1606,6 @@ static int kcdrwd(void *foobar)
                                        min_sleep_time = pkt->sleep_time;
                        }
 
-                       generic_unplug_device(bdev_get_queue(pd->bdev));
-
                        VPRINTK("kcdrwd: sleeping\n");
                        residue = schedule_timeout(min_sleep_time);
                        VPRINTK("kcdrwd: wake up\n");
@@ -2796,7 +2794,8 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
        return ret;
 }
 
-static int pkt_media_changed(struct gendisk *disk)
+static unsigned int pkt_check_events(struct gendisk *disk,
+                                    unsigned int clearing)
 {
        struct pktcdvd_device *pd = disk->private_data;
        struct gendisk *attached_disk;
@@ -2806,9 +2805,9 @@ static int pkt_media_changed(struct gendisk *disk)
        if (!pd->bdev)
                return 0;
        attached_disk = pd->bdev->bd_disk;
-       if (!attached_disk)
+       if (!attached_disk || !attached_disk->fops->check_events)
                return 0;
-       return attached_disk->fops->media_changed(attached_disk);
+       return attached_disk->fops->check_events(attached_disk, clearing);
 }
 
 static const struct block_device_operations pktcdvd_ops = {
@@ -2816,7 +2815,7 @@ static const struct block_device_operations pktcdvd_ops = {
        .open =                 pkt_open,
        .release =              pkt_close,
        .ioctl =                pkt_ioctl,
-       .media_changed =        pkt_media_changed,
+       .check_events =         pkt_check_events,
 };
 
 static char *pktcdvd_devnode(struct gendisk *gd, mode_t *mode)
@@ -2889,6 +2888,10 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        if (ret)
                goto out_new_dev;
 
+       /* inherit events of the host device */
+       disk->events = pd->bdev->bd_disk->events;
+       disk->async_events = pd->bdev->bd_disk->async_events;
+
        add_disk(disk);
 
        pkt_sysfs_dev_new(pd);
index e1e38b11f48ae3b60f15a27f0242b4b9c100dde5..16dc3645291cd7bbb3eab203b83dde68939b61d7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ceph/osd_client.h>
 #include <linux/ceph/mon_client.h>
 #include <linux/ceph/decode.h>
+#include <linux/parser.h>
 
 #include <linux/kernel.h>
 #include <linux/device.h>
@@ -54,6 +55,8 @@
 
 #define DEV_NAME_LEN           32
 
+#define RBD_NOTIFY_TIMEOUT_DEFAULT 10
+
 /*
  * block device image metadata (in-memory version)
  */
@@ -71,6 +74,12 @@ struct rbd_image_header {
 
        char *snap_names;
        u64 *snap_sizes;
+
+       u64 obj_version;
+};
+
+struct rbd_options {
+       int     notify_timeout;
 };
 
 /*
@@ -78,6 +87,7 @@ struct rbd_image_header {
  */
 struct rbd_client {
        struct ceph_client      *client;
+       struct rbd_options      *rbd_opts;
        struct kref             kref;
        struct list_head        node;
 };
@@ -124,6 +134,9 @@ struct rbd_device {
        char                    pool_name[RBD_MAX_POOL_NAME_LEN];
        int                     poolid;
 
+       struct ceph_osd_event   *watch_event;
+       struct ceph_osd_request *watch_request;
+
        char                    snap_name[RBD_MAX_SNAP_NAME_LEN];
        u32 cur_snap;   /* index+1 of current snapshot within snap context
                           0 - for the head */
@@ -177,6 +190,8 @@ static void rbd_put_dev(struct rbd_device *rbd_dev)
        put_device(&rbd_dev->dev);
 }
 
+static int __rbd_update_snaps(struct rbd_device *rbd_dev);
+
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
        struct gendisk *disk = bdev->bd_disk;
@@ -211,7 +226,8 @@ static const struct block_device_operations rbd_bd_ops = {
  * Initialize an rbd client instance.
  * We own *opt.
  */
-static struct rbd_client *rbd_client_create(struct ceph_options *opt)
+static struct rbd_client *rbd_client_create(struct ceph_options *opt,
+                                           struct rbd_options *rbd_opts)
 {
        struct rbd_client *rbdc;
        int ret = -ENOMEM;
@@ -233,6 +249,8 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt)
        if (ret < 0)
                goto out_err;
 
+       rbdc->rbd_opts = rbd_opts;
+
        spin_lock(&node_lock);
        list_add_tail(&rbdc->node, &rbd_client_list);
        spin_unlock(&node_lock);
@@ -266,6 +284,59 @@ static struct rbd_client *__rbd_client_find(struct ceph_options *opt)
        return NULL;
 }
 
+/*
+ * mount options
+ */
+enum {
+       Opt_notify_timeout,
+       Opt_last_int,
+       /* int args above */
+       Opt_last_string,
+       /* string args above */
+};
+
+static match_table_t rbdopt_tokens = {
+       {Opt_notify_timeout, "notify_timeout=%d"},
+       /* int args above */
+       /* string args above */
+       {-1, NULL}
+};
+
+static int parse_rbd_opts_token(char *c, void *private)
+{
+       struct rbd_options *rbdopt = private;
+       substring_t argstr[MAX_OPT_ARGS];
+       int token, intval, ret;
+
+       token = match_token((char *)c, rbdopt_tokens, argstr);
+       if (token < 0)
+               return -EINVAL;
+
+       if (token < Opt_last_int) {
+               ret = match_int(&argstr[0], &intval);
+               if (ret < 0) {
+                       pr_err("bad mount option arg (not int) "
+                              "at '%s'\n", c);
+                       return ret;
+               }
+               dout("got int token %d val %d\n", token, intval);
+       } else if (token > Opt_last_int && token < Opt_last_string) {
+               dout("got string token %d val %s\n", token,
+                    argstr[0].from);
+       } else {
+               dout("got token %d\n", token);
+       }
+
+       switch (token) {
+       case Opt_notify_timeout:
+               rbdopt->notify_timeout = intval;
+               break;
+       default:
+               BUG_ON(token);
+       }
+       return 0;
+}
+
 /*
  * Get a ceph client with specific addr and configuration, if one does
  * not exist create it.
@@ -276,11 +347,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
        struct rbd_client *rbdc;
        struct ceph_options *opt;
        int ret;
+       struct rbd_options *rbd_opts;
+
+       rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL);
+       if (!rbd_opts)
+               return -ENOMEM;
+
+       rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT;
 
        ret = ceph_parse_options(&opt, options, mon_addr,
-                                mon_addr + strlen(mon_addr), NULL, NULL);
+                                mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts);
        if (ret < 0)
-               return ret;
+               goto done_err;
 
        spin_lock(&node_lock);
        rbdc = __rbd_client_find(opt);
@@ -296,13 +374,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
        }
        spin_unlock(&node_lock);
 
-       rbdc = rbd_client_create(opt);
-       if (IS_ERR(rbdc))
-               return PTR_ERR(rbdc);
+       rbdc = rbd_client_create(opt, rbd_opts);
+       if (IS_ERR(rbdc)) {
+               ret = PTR_ERR(rbdc);
+               goto done_err;
+       }
 
        rbd_dev->rbd_client = rbdc;
        rbd_dev->client = rbdc->client;
        return 0;
+done_err:
+       kfree(rbd_opts);
+       return ret;
 }
 
 /*
@@ -318,6 +401,7 @@ static void rbd_client_release(struct kref *kref)
        spin_unlock(&node_lock);
 
        ceph_destroy_client(rbdc->client);
+       kfree(rbdc->rbd_opts);
        kfree(rbdc);
 }
 
@@ -666,7 +750,9 @@ static int rbd_do_request(struct request *rq,
                          struct ceph_osd_req_op *ops,
                          int num_reply,
                          void (*rbd_cb)(struct ceph_osd_request *req,
-                                        struct ceph_msg *msg))
+                                        struct ceph_msg *msg),
+                         struct ceph_osd_request **linger_req,
+                         u64 *ver)
 {
        struct ceph_osd_request *req;
        struct ceph_file_layout *layout;
@@ -729,12 +815,20 @@ static int rbd_do_request(struct request *rq,
                                req->r_oid, req->r_oid_len);
        up_read(&header->snap_rwsem);
 
+       if (linger_req) {
+               ceph_osdc_set_request_linger(&dev->client->osdc, req);
+               *linger_req = req;
+       }
+
        ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
        if (ret < 0)
                goto done_err;
 
        if (!rbd_cb) {
                ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+               if (ver)
+                       *ver = le64_to_cpu(req->r_reassert_version.version);
+               dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version));
                ceph_osdc_put_request(req);
        }
        return ret;
@@ -789,6 +883,11 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
        kfree(req_data);
 }
 
+static void rbd_simple_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
+{
+       ceph_osdc_put_request(req);
+}
+
 /*
  * Do a synchronous ceph osd operation
  */
@@ -801,7 +900,9 @@ static int rbd_req_sync_op(struct rbd_device *dev,
                           int num_reply,
                           const char *obj,
                           u64 ofs, u64 len,
-                          char *buf)
+                          char *buf,
+                          struct ceph_osd_request **linger_req,
+                          u64 *ver)
 {
        int ret;
        struct page **pages;
@@ -833,7 +934,8 @@ static int rbd_req_sync_op(struct rbd_device *dev,
                          flags,
                          ops,
                          2,
-                         NULL);
+                         NULL,
+                         linger_req, ver);
        if (ret < 0)
                goto done_ops;
 
@@ -893,7 +995,7 @@ static int rbd_do_op(struct request *rq,
                             flags,
                             ops,
                             num_reply,
-                            rbd_req_cb);
+                            rbd_req_cb, 0, NULL);
 done:
        kfree(seg_name);
        return ret;
@@ -940,18 +1042,174 @@ static int rbd_req_sync_read(struct rbd_device *dev,
                          u64 snapid,
                          const char *obj,
                          u64 ofs, u64 len,
-                         char *buf)
+                         char *buf,
+                         u64 *ver)
 {
        return rbd_req_sync_op(dev, NULL,
                               (snapid ? snapid : CEPH_NOSNAP),
                               CEPH_OSD_OP_READ,
                               CEPH_OSD_FLAG_READ,
                               NULL,
-                              1, obj, ofs, len, buf);
+                              1, obj, ofs, len, buf, NULL, ver);
 }
 
 /*
- * Request sync osd read
+ * Request sync osd watch
+ */
+static int rbd_req_sync_notify_ack(struct rbd_device *dev,
+                                  u64 ver,
+                                  u64 notify_id,
+                                  const char *obj)
+{
+       struct ceph_osd_req_op *ops;
+       struct page **pages = NULL;
+       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0);
+       if (ret < 0)
+               return ret;
+
+       ops[0].watch.ver = cpu_to_le64(dev->header.obj_version);
+       ops[0].watch.cookie = notify_id;
+       ops[0].watch.flag = 0;
+
+       ret = rbd_do_request(NULL, dev, NULL, CEPH_NOSNAP,
+                         obj, 0, 0, NULL,
+                         pages, 0,
+                         CEPH_OSD_FLAG_READ,
+                         ops,
+                         1,
+                         rbd_simple_req_cb, 0, NULL);
+
+       rbd_destroy_ops(ops);
+       return ret;
+}
+
+static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
+{
+       struct rbd_device *dev = (struct rbd_device *)data;
+       if (!dev)
+               return;
+
+       dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
+               notify_id, (int)opcode);
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       __rbd_update_snaps(dev);
+       mutex_unlock(&ctl_mutex);
+
+       rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
+}
+
+/*
+ * Request sync osd watch
+ */
+static int rbd_req_sync_watch(struct rbd_device *dev,
+                             const char *obj,
+                             u64 ver)
+{
+       struct ceph_osd_req_op *ops;
+       struct ceph_osd_client *osdc = &dev->client->osdc;
+
+       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = ceph_osdc_create_event(osdc, rbd_watch_cb, 0,
+                                    (void *)dev, &dev->watch_event);
+       if (ret < 0)
+               goto fail;
+
+       ops[0].watch.ver = cpu_to_le64(ver);
+       ops[0].watch.cookie = cpu_to_le64(dev->watch_event->cookie);
+       ops[0].watch.flag = 1;
+
+       ret = rbd_req_sync_op(dev, NULL,
+                             CEPH_NOSNAP,
+                             0,
+                             CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+                             ops,
+                             1, obj, 0, 0, NULL,
+                             &dev->watch_request, NULL);
+
+       if (ret < 0)
+               goto fail_event;
+
+       rbd_destroy_ops(ops);
+       return 0;
+
+fail_event:
+       ceph_osdc_cancel_event(dev->watch_event);
+       dev->watch_event = NULL;
+fail:
+       rbd_destroy_ops(ops);
+       return ret;
+}
+
+struct rbd_notify_info {
+       struct rbd_device *dev;
+};
+
+static void rbd_notify_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
+{
+       struct rbd_device *dev = (struct rbd_device *)data;
+       if (!dev)
+               return;
+
+       dout("rbd_notify_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
+               notify_id, (int)opcode);
+}
+
+/*
+ * Request sync osd notify
+ */
+static int rbd_req_sync_notify(struct rbd_device *dev,
+                         const char *obj)
+{
+       struct ceph_osd_req_op *ops;
+       struct ceph_osd_client *osdc = &dev->client->osdc;
+       struct ceph_osd_event *event;
+       struct rbd_notify_info info;
+       int payload_len = sizeof(u32) + sizeof(u32);
+       int ret;
+
+       ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY, payload_len);
+       if (ret < 0)
+               return ret;
+
+       info.dev = dev;
+
+       ret = ceph_osdc_create_event(osdc, rbd_notify_cb, 1,
+                                    (void *)&info, &event);
+       if (ret < 0)
+               goto fail;
+
+       ops[0].watch.ver = 1;
+       ops[0].watch.flag = 1;
+       ops[0].watch.cookie = event->cookie;
+       ops[0].watch.prot_ver = RADOS_NOTIFY_VER;
+       ops[0].watch.timeout = 12;
+
+       ret = rbd_req_sync_op(dev, NULL,
+                              CEPH_NOSNAP,
+                              0,
+                              CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+                              ops,
+                              1, obj, 0, 0, NULL, NULL, NULL);
+       if (ret < 0)
+               goto fail_event;
+
+       ret = ceph_osdc_wait_event(event, CEPH_OSD_TIMEOUT_DEFAULT);
+       dout("ceph_osdc_wait_event returned %d\n", ret);
+       rbd_destroy_ops(ops);
+       return 0;
+
+fail_event:
+       ceph_osdc_cancel_event(event);
+fail:
+       rbd_destroy_ops(ops);
+       return ret;
+}
+
+/*
+ * Request sync osd rollback
  */
 static int rbd_req_sync_rollback_obj(struct rbd_device *dev,
                                     u64 snapid,
@@ -969,13 +1227,10 @@ static int rbd_req_sync_rollback_obj(struct rbd_device *dev,
                               0,
                               CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                               ops,
-                              1, obj, 0, 0, NULL);
+                              1, obj, 0, 0, NULL, NULL, NULL);
 
        rbd_destroy_ops(ops);
 
-       if (ret < 0)
-               return ret;
-
        return ret;
 }
 
@@ -987,7 +1242,8 @@ static int rbd_req_sync_exec(struct rbd_device *dev,
                             const char *cls,
                             const char *method,
                             const char *data,
-                            int len)
+                            int len,
+                            u64 *ver)
 {
        struct ceph_osd_req_op *ops;
        int cls_len = strlen(cls);
@@ -1010,7 +1266,7 @@ static int rbd_req_sync_exec(struct rbd_device *dev,
                               0,
                               CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
                               ops,
-                              1, obj, 0, 0, NULL);
+                              1, obj, 0, 0, NULL, NULL, ver);
 
        rbd_destroy_ops(ops);
 
@@ -1156,6 +1412,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
        struct rbd_image_header_ondisk *dh;
        int snap_count = 0;
        u64 snap_names_len = 0;
+       u64 ver;
 
        while (1) {
                int len = sizeof(*dh) +
@@ -1171,7 +1428,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
                                       NULL, CEPH_NOSNAP,
                                       rbd_dev->obj_md_name,
                                       0, len,
-                                      (char *)dh);
+                                      (char *)dh, &ver);
                if (rc < 0)
                        goto out_dh;
 
@@ -1188,6 +1445,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
                }
                break;
        }
+       header->obj_version = ver;
 
 out_dh:
        kfree(dh);
@@ -1205,6 +1463,7 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        u64 new_snapid;
        int ret;
        void *data, *data_start, *data_end;
+       u64 ver;
 
        /* we should create a snapshot only if we're pointing at the head */
        if (dev->cur_snap)
@@ -1227,7 +1486,7 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        ceph_encode_64_safe(&data, data_end, new_snapid, bad);
 
        ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
-                               data_start, data - data_start);
+                               data_start, data - data_start, &ver);
 
        kfree(data_start);
 
@@ -1259,6 +1518,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
        int ret;
        struct rbd_image_header h;
        u64 snap_seq;
+       int follow_seq = 0;
 
        ret = rbd_read_header(rbd_dev, &h);
        if (ret < 0)
@@ -1267,6 +1527,11 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
        down_write(&rbd_dev->header.snap_rwsem);
 
        snap_seq = rbd_dev->header.snapc->seq;
+       if (rbd_dev->header.total_snaps &&
+           rbd_dev->header.snapc->snaps[0] == snap_seq)
+               /* pointing at the head, will need to follow that
+                  if head moves */
+               follow_seq = 1;
 
        kfree(rbd_dev->header.snapc);
        kfree(rbd_dev->header.snap_names);
@@ -1277,7 +1542,10 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
        rbd_dev->header.snap_names = h.snap_names;
        rbd_dev->header.snap_names_len = h.snap_names_len;
        rbd_dev->header.snap_sizes = h.snap_sizes;
-       rbd_dev->header.snapc->seq = snap_seq;
+       if (follow_seq)
+               rbd_dev->header.snapc->seq = rbd_dev->header.snapc->snaps[0];
+       else
+               rbd_dev->header.snapc->seq = snap_seq;
 
        ret = __rbd_init_snaps_header(rbd_dev);
 
@@ -1699,7 +1967,28 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
        device_unregister(&rbd_dev->dev);
 }
 
-static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count)
+static int rbd_init_watch_dev(struct rbd_device *rbd_dev)
+{
+       int ret, rc;
+
+       do {
+               ret = rbd_req_sync_watch(rbd_dev, rbd_dev->obj_md_name,
+                                        rbd_dev->header.obj_version);
+               if (ret == -ERANGE) {
+                       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+                       rc = __rbd_update_snaps(rbd_dev);
+                       mutex_unlock(&ctl_mutex);
+                       if (rc < 0)
+                               return rc;
+               }
+       } while (ret == -ERANGE);
+
+       return ret;
+}
+
+static ssize_t rbd_add(struct bus_type *bus,
+                      const char *buf,
+                      size_t count)
 {
        struct ceph_osd_client *osdc;
        struct rbd_device *rbd_dev;
@@ -1797,6 +2086,10 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count)
        if (rc)
                goto err_out_bus;
 
+       rc = rbd_init_watch_dev(rbd_dev);
+       if (rc)
+               goto err_out_bus;
+
        return count;
 
 err_out_bus:
@@ -1849,6 +2142,12 @@ static void rbd_dev_release(struct device *dev)
        struct rbd_device *rbd_dev =
                        container_of(dev, struct rbd_device, dev);
 
+       if (rbd_dev->watch_request)
+               ceph_osdc_unregister_linger_request(&rbd_dev->client->osdc,
+                                                   rbd_dev->watch_request);
+       if (rbd_dev->watch_event)
+               ceph_osdc_cancel_event(rbd_dev->watch_event);
+
        rbd_put_client(rbd_dev);
 
        /* clean up and free blkdev */
@@ -1914,14 +2213,24 @@ static ssize_t rbd_snap_add(struct device *dev,
        ret = rbd_header_add_snap(rbd_dev,
                                  name, GFP_KERNEL);
        if (ret < 0)
-               goto done_unlock;
+               goto err_unlock;
 
        ret = __rbd_update_snaps(rbd_dev);
        if (ret < 0)
-               goto done_unlock;
+               goto err_unlock;
+
+       /* shouldn't hold ctl_mutex when notifying.. notify might
+          trigger a watch callback that would need to get that mutex */
+       mutex_unlock(&ctl_mutex);
+
+       /* make a best effort, don't error if failed */
+       rbd_req_sync_notify(rbd_dev, rbd_dev->obj_md_name);
 
        ret = count;
-done_unlock:
+       kfree(name);
+       return ret;
+
+err_unlock:
        mutex_unlock(&ctl_mutex);
        kfree(name);
        return ret;
index 75333d0a3327de785f520cdeddbb4a45b83f1a90..24a482f2fbd60fcfd0917374bd6197a76d6ddf85 100644 (file)
@@ -741,11 +741,12 @@ static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static int floppy_check_change(struct gendisk *disk)
+static unsigned int floppy_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        struct floppy_state *fs = disk->private_data;
 
-       return fs->ejected;
+       return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int floppy_revalidate(struct gendisk *disk)
@@ -772,7 +773,7 @@ static const struct block_device_operations floppy_fops = {
        .release         = floppy_release,
        .ioctl           = floppy_ioctl,
        .getgeo          = floppy_getgeo,
-       .media_changed   = floppy_check_change,
+       .check_events    = floppy_check_events,
        .revalidate_disk = floppy_revalidate,
 };
 
@@ -857,6 +858,7 @@ static int __devinit swim_floppy_init(struct swim_priv *swd)
                swd->unit[drive].disk->first_minor = drive;
                sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive);
                swd->unit[drive].disk->fops = &floppy_fops;
+               swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE;
                swd->unit[drive].disk->private_data = &swd->unit[drive];
                swd->unit[drive].disk->queue = swd->queue;
                set_capacity(swd->unit[drive].disk, 2880);
index bf3a5b8592990ccf640b4221973ff84114b893df..4c10f56facbff8b5c0e56615c0ebc79a1179903f 100644 (file)
@@ -250,7 +250,8 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long param);
 static int floppy_open(struct block_device *bdev, fmode_t mode);
 static int floppy_release(struct gendisk *disk, fmode_t mode);
-static int floppy_check_change(struct gendisk *disk);
+static unsigned int floppy_check_events(struct gendisk *disk,
+                                       unsigned int clearing);
 static int floppy_revalidate(struct gendisk *disk);
 
 static bool swim3_end_request(int err, unsigned int nr_bytes)
@@ -975,10 +976,11 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
        return 0;
 }
 
-static int floppy_check_change(struct gendisk *disk)
+static unsigned int floppy_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        struct floppy_state *fs = disk->private_data;
-       return fs->ejected;
+       return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int floppy_revalidate(struct gendisk *disk)
@@ -1025,7 +1027,7 @@ static const struct block_device_operations floppy_fops = {
        .open           = floppy_unlocked_open,
        .release        = floppy_release,
        .ioctl          = floppy_ioctl,
-       .media_changed  = floppy_check_change,
+       .check_events   = floppy_check_events,
        .revalidate_disk= floppy_revalidate,
 };
 
@@ -1161,6 +1163,7 @@ static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device
        disk->major = FLOPPY_MAJOR;
        disk->first_minor = i;
        disk->fops = &floppy_fops;
+       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = &floppy_states[i];
        disk->queue = swim3_queue;
        disk->flags |= GENHD_FL_REMOVABLE;
index 9ae3bb713286f0d0d3a959a81f7f4b4db5cde1db..68b9430c7cfe56f7f23330cb152b103aef3098b9 100644 (file)
@@ -1788,7 +1788,8 @@ static int ub_bd_revalidate(struct gendisk *disk)
  *
  * The return code is bool!
  */
-static int ub_bd_media_changed(struct gendisk *disk)
+static unsigned int ub_bd_check_events(struct gendisk *disk,
+                                      unsigned int clearing)
 {
        struct ub_lun *lun = disk->private_data;
 
@@ -1806,10 +1807,10 @@ static int ub_bd_media_changed(struct gendisk *disk)
         */
        if (ub_sync_tur(lun->udev, lun) != 0) {
                lun->changed = 1;
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
 
-       return lun->changed;
+       return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static const struct block_device_operations ub_bd_fops = {
@@ -1817,7 +1818,7 @@ static const struct block_device_operations ub_bd_fops = {
        .open           = ub_bd_unlocked_open,
        .release        = ub_bd_release,
        .ioctl          = ub_bd_ioctl,
-       .media_changed  = ub_bd_media_changed,
+       .check_events   = ub_bd_check_events,
        .revalidate_disk = ub_bd_revalidate,
 };
 
@@ -2333,6 +2334,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        disk->major = UB_MAJOR;
        disk->first_minor = lun->id * UB_PARTS_PER_LUN;
        disk->fops = &ub_bd_fops;
+       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = lun;
        disk->driverfs_dev = &sc->intf->dev;
 
index 8be57151f5d6570cd9b9c9a629618bc23ae3466b..031ca720d926623e810368399359e6a4dcf1b02d 100644 (file)
@@ -241,8 +241,7 @@ static void dump_dmastat(struct cardinfo *card, unsigned int dmastat)
  *
  * Whenever IO on the active page completes, the Ready page is activated
  * and the ex-Active page is clean out and made Ready.
- * Otherwise the Ready page is only activated when it becomes full, or
- * when mm_unplug_device is called via the unplug_io_fn.
+ * Otherwise the Ready page is only activated when it becomes full.
  *
  * If a request arrives while both pages a full, it is queued, and b_rdev is
  * overloaded to record whether it was a read or a write.
@@ -333,17 +332,6 @@ static inline void reset_page(struct mm_page *page)
        page->biotail = &page->bio;
 }
 
-static void mm_unplug_device(struct request_queue *q)
-{
-       struct cardinfo *card = q->queuedata;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       if (blk_remove_plug(q))
-               activate(card);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
 /*
  * If there is room on Ready page, take
  * one bh off list and add it.
@@ -535,7 +523,6 @@ static int mm_make_request(struct request_queue *q, struct bio *bio)
        *card->biotail = bio;
        bio->bi_next = NULL;
        card->biotail = &bio->bi_next;
-       blk_plug_device(q);
        spin_unlock_irq(&card->lock);
 
        return 0;
@@ -779,20 +766,10 @@ static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-/*
- * Future support for removable devices
- */
-static int mm_check_change(struct gendisk *disk)
-{
-/*  struct cardinfo *dev = disk->private_data; */
-       return 0;
-}
-
 static const struct block_device_operations mm_fops = {
        .owner          = THIS_MODULE,
        .getgeo         = mm_getgeo,
        .revalidate_disk = mm_revalidate,
-       .media_changed  = mm_check_change,
 };
 
 static int __devinit mm_pci_probe(struct pci_dev *dev,
@@ -907,7 +884,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev,
        blk_queue_make_request(card->queue, mm_make_request);
        card->queue->queue_lock = &card->lock;
        card->queue->queuedata = card;
-       card->queue->unplug_fn = mm_unplug_device;
 
        tasklet_init(&card->tasklet, process_page, (unsigned long)card);
 
index 2c590a796aa1480bb24f2ce4e54814d971c56b76..73354b081ed3e8a629c849f3aaac865c1e1649e1 100644 (file)
@@ -867,12 +867,12 @@ static void ace_request(struct request_queue * q)
        }
 }
 
-static int ace_media_changed(struct gendisk *gd)
+static unsigned int ace_check_events(struct gendisk *gd, unsigned int clearing)
 {
        struct ace_device *ace = gd->private_data;
-       dev_dbg(ace->dev, "ace_media_changed(): %i\n", ace->media_change);
+       dev_dbg(ace->dev, "ace_check_events(): %i\n", ace->media_change);
 
-       return ace->media_change;
+       return ace->media_change ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int ace_revalidate_disk(struct gendisk *gd)
@@ -953,7 +953,7 @@ static const struct block_device_operations ace_fops = {
        .owner = THIS_MODULE,
        .open = ace_open,
        .release = ace_release,
-       .media_changed = ace_media_changed,
+       .check_events = ace_check_events,
        .revalidate_disk = ace_revalidate_disk,
        .getgeo = ace_getgeo,
 };
@@ -1005,6 +1005,7 @@ static int __devinit ace_setup(struct ace_device *ace)
        ace->gd->major = ace_major;
        ace->gd->first_minor = ace->id * ACE_NUM_MINORS;
        ace->gd->fops = &ace_fops;
+       ace->gd->events = DISK_EVENT_MEDIA_CHANGE;
        ace->gd->queue = ace->queue;
        ace->gd->private_data = ace;
        snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
index 64a21461c408f9853d6c6199bc1ed9e38fb842ca..b2b034fea34e6b8eabf7054928e34bc4d6fc0e17 100644 (file)
@@ -395,10 +395,12 @@ static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
        return CDS_NO_INFO;
 }
 
-static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
+static unsigned int gdrom_check_events(struct cdrom_device_info *cd_info,
+                                      unsigned int clearing, int ignore)
 {
        /* check the sense key */
-       return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60;
+       return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60 ?
+               DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 /* reset the G1 bus */
@@ -483,7 +485,7 @@ static struct cdrom_device_ops gdrom_ops = {
        .open                   = gdrom_open,
        .release                = gdrom_release,
        .drive_status           = gdrom_drivestatus,
-       .media_changed          = gdrom_mediachanged,
+       .check_events           = gdrom_check_events,
        .get_last_session       = gdrom_get_last_session,
        .reset                  = gdrom_hardreset,
        .audio_ioctl            = gdrom_audio_ioctl,
@@ -509,9 +511,10 @@ static int gdrom_bdops_release(struct gendisk *disk, fmode_t mode)
        return 0;
 }
 
-static int gdrom_bdops_mediachanged(struct gendisk *disk)
+static unsigned int gdrom_bdops_check_events(struct gendisk *disk,
+                                            unsigned int clearing)
 {
-       return cdrom_media_changed(gd.cd_info);
+       return cdrom_check_events(gd.cd_info, clearing);
 }
 
 static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode,
@@ -530,7 +533,7 @@ static const struct block_device_operations gdrom_bdops = {
        .owner                  = THIS_MODULE,
        .open                   = gdrom_bdops_open,
        .release                = gdrom_bdops_release,
-       .media_changed          = gdrom_bdops_mediachanged,
+       .check_events           = gdrom_bdops_check_events,
        .ioctl                  = gdrom_bdops_ioctl,
 };
 
@@ -800,6 +803,7 @@ static int __devinit probe_gdrom(struct platform_device *devptr)
                goto probe_fail_cdrom_register;
        }
        gd.disk->fops = &gdrom_bdops;
+       gd.disk->events = DISK_EVENT_MEDIA_CHANGE;
        /* latch on to the interrupt */
        err = gdrom_set_interrupt_handlers();
        if (err)
index be73a9b493a69970135663ffd4ed7a83cb568cb9..4e874c5fa60595036a7e10b26257384715b06b56 100644 (file)
@@ -186,10 +186,11 @@ static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode,
        return ret;
 }
 
-static int viocd_blk_media_changed(struct gendisk *disk)
+static unsigned int viocd_blk_check_events(struct gendisk *disk,
+                                          unsigned int clearing)
 {
        struct disk_info *di = disk->private_data;
-       return cdrom_media_changed(&di->viocd_info);
+       return cdrom_check_events(&di->viocd_info, clearing);
 }
 
 static const struct block_device_operations viocd_fops = {
@@ -197,7 +198,7 @@ static const struct block_device_operations viocd_fops = {
        .open =                 viocd_blk_open,
        .release =              viocd_blk_release,
        .ioctl =                viocd_blk_ioctl,
-       .media_changed =        viocd_blk_media_changed,
+       .check_events =         viocd_blk_check_events,
 };
 
 static int viocd_open(struct cdrom_device_info *cdi, int purpose)
@@ -320,7 +321,8 @@ static void do_viocd_request(struct request_queue *q)
        }
 }
 
-static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+static unsigned int viocd_check_events(struct cdrom_device_info *cdi,
+                                      unsigned int clearing, int disc_nr)
 {
        struct viocd_waitevent we;
        HvLpEvent_Rc hvrc;
@@ -340,7 +342,7 @@ static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
        if (hvrc != 0) {
                pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
                           (int)hvrc);
-               return -EIO;
+               return 0;
        }
 
        wait_for_completion(&we.com);
@@ -354,7 +356,7 @@ static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
                return 0;
        }
 
-       return we.changed;
+       return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static int viocd_lock_door(struct cdrom_device_info *cdi, int locking)
@@ -550,7 +552,7 @@ static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
 static struct cdrom_device_ops viocd_dops = {
        .open = viocd_open,
        .release = viocd_release,
-       .media_changed = viocd_media_changed,
+       .check_events = viocd_check_events,
        .lock_door = viocd_lock_door,
        .generic_packet = viocd_packet,
        .audio_ioctl = viocd_audio_ioctl,
@@ -624,6 +626,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        gendisk->queue = q;
        gendisk->fops = &viocd_fops;
        gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
+       gendisk->events = DISK_EVENT_MEDIA_CHANGE;
        set_capacity(gendisk, 0);
        gendisk->private_data = d;
        d->viocd_disk = gendisk;
index 04f8b2d083c61d166dd0b705ee576c0f80c40004..ad59b4e0a9b50500b372af7291836f44573c3d79 100644 (file)
@@ -608,5 +608,13 @@ config RAMOOPS
          This enables panic and oops messages to be logged to a circular
          buffer in RAM where it can be read back at some later point.
 
+config MSM_SMD_PKT
+       bool "Enable device interface for some SMD packet ports"
+       default n
+       depends on MSM_SMD
+       help
+         Enables userspace clients to read and write to some packet SMD
+         ports via device interface for MSM chipset.
+
 endmenu
 
index 057f65452e7ba67e6fe6863c9ac5aebaa6e59e48..7a00672bd85de7b7256855653bce7d3c04b0b33b 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_ATARI_DSP56K)      += dsp56k.o
 obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
+obj-$(CONFIG_MSM_SMD_PKT)      += msm_smd_pkt.o
 obj-$(CONFIG_MSPEC)            += mspec.o
 obj-$(CONFIG_MMTIMER)          += mmtimer.o
 obj-$(CONFIG_UV_MMTIMER)       += uv_mmtimer.o
index c86d43b88e1ec54f59a0a0aa2864d1b4a09c7f72..d28b484aee45bf8d012dcc4a03904bbd81c4af85 100644 (file)
@@ -3521,7 +3521,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
        kfree(to_clean);
 }
 
-static void __exit cleanup_ipmi_si(void)
+static void cleanup_ipmi_si(void)
 {
        struct smi_info *e, *tmp_e;
 
index 1256454b2d4364f7fa6ad95b661d30ad62b673b4..436a990179988a06fb10e18884cb9db56371fdb5 100644 (file)
@@ -47,10 +47,7 @@ static inline unsigned long size_inside_page(unsigned long start,
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t count)
 {
-       if (addr + count > __pa(high_memory))
-               return 0;
-
-       return 1;
+       return addr + count <= __pa(high_memory);
 }
 
 static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c
new file mode 100644 (file)
index 0000000..b6f8a65
--- /dev/null
@@ -0,0 +1,466 @@
+/* Copyright (c) 2008-2010, Code Aurora Forum. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+/*
+ * SMD Packet Driver -- Provides userspace interface to SMD packet ports.
+ */
+
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+
+#include <mach/msm_smd.h>
+
+#define NUM_SMD_PKT_PORTS 9
+#define DEVICE_NAME "smdpkt"
+#define MAX_BUF_SIZE 2048
+
+struct smd_pkt_dev {
+       struct cdev cdev;
+       struct device *devicep;
+
+       struct smd_channel *ch;
+       int open_count;
+       struct mutex ch_lock;
+       struct mutex rx_lock;
+       struct mutex tx_lock;
+       wait_queue_head_t ch_read_wait_queue;
+       wait_queue_head_t ch_opened_wait_queue;
+
+       int i;
+
+       unsigned char tx_buf[MAX_BUF_SIZE];
+       unsigned char rx_buf[MAX_BUF_SIZE];
+       int remote_open;
+
+} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
+
+struct class *smd_pkt_classp;
+static dev_t smd_pkt_number;
+
+static int msm_smd_pkt_debug_enable;
+module_param_named(debug_enable, msm_smd_pkt_debug_enable,
+                  int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#ifdef DEBUG
+#define D_DUMP_BUFFER(prestr, cnt, buf) do {                   \
+               int i;                                          \
+               if (msm_smd_pkt_debug_enable) {                 \
+                       pr_debug("%s", prestr);                 \
+                       for (i = 0; i < cnt; i++)               \
+                               pr_debug("%.2x", buf[i]);       \
+                       pr_debug("\n");                         \
+               }                                               \
+       } while (0)
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#endif
+
+#ifdef DEBUG
+#define DBG(x...) do {                 \
+       if (msm_smd_pkt_debug_enable)   \
+               pr_debug(x);            \
+       } while (0)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
+{
+       int sz;
+
+       if (!smd_pkt_devp || !smd_pkt_devp->ch)
+               return;
+
+       sz = smd_cur_packet_size(smd_pkt_devp->ch);
+       if (sz == 0) {
+               DBG("no packet\n");
+               return;
+       }
+       if (sz > smd_read_avail(smd_pkt_devp->ch)) {
+               DBG("incomplete packet\n");
+               return;
+       }
+
+       DBG("waking up reader\n");
+       wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue);
+}
+
+static int smd_pkt_read(struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       int r, bytes_read;
+       struct smd_pkt_dev *smd_pkt_devp;
+       struct smd_channel *chl;
+
+       DBG("read %d bytes\n", count);
+       if (count > MAX_BUF_SIZE)
+               return -EINVAL;
+
+       smd_pkt_devp = file->private_data;
+       if (!smd_pkt_devp || !smd_pkt_devp->ch)
+               return -EINVAL;
+
+       chl = smd_pkt_devp->ch;
+wait_for_packet:
+       r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
+                                    (smd_cur_packet_size(chl) > 0 &&
+                                     smd_read_avail(chl) >=
+                                     smd_cur_packet_size(chl)));
+
+       if (r < 0) {
+               if (r != -ERESTARTSYS)
+                       pr_err("wait returned %d\n", r);
+               return r;
+       }
+
+       mutex_lock(&smd_pkt_devp->rx_lock);
+
+       bytes_read = smd_cur_packet_size(smd_pkt_devp->ch);
+       if (bytes_read == 0 ||
+           bytes_read < smd_read_avail(smd_pkt_devp->ch)) {
+               mutex_unlock(&smd_pkt_devp->rx_lock);
+               DBG("Nothing to read\n");
+               goto wait_for_packet;
+       }
+
+       if (bytes_read > count) {
+               mutex_unlock(&smd_pkt_devp->rx_lock);
+               pr_info("packet size %d > buffer size %d", bytes_read, count);
+               return -EINVAL;
+       }
+
+       r = smd_read(smd_pkt_devp->ch, smd_pkt_devp->rx_buf, bytes_read);
+       if (r != bytes_read) {
+               mutex_unlock(&smd_pkt_devp->rx_lock);
+               pr_err("smd_read failed to read %d bytes: %d\n", bytes_read, r);
+               return -EIO;
+       }
+
+       D_DUMP_BUFFER("read: ", bytes_read, smd_pkt_devp->rx_buf);
+       r = copy_to_user(buf, smd_pkt_devp->rx_buf, bytes_read);
+       mutex_unlock(&smd_pkt_devp->rx_lock);
+       if (r) {
+               pr_err("copy_to_user failed %d\n", r);
+               return -EFAULT;
+       }
+
+       DBG("read complete %d bytes\n", bytes_read);
+       check_and_wakeup_reader(smd_pkt_devp);
+
+       return bytes_read;
+}
+
+static int smd_pkt_write(struct file *file, const char __user *buf,
+                        size_t count, loff_t *ppos)
+{
+       int r;
+       struct smd_pkt_dev *smd_pkt_devp;
+
+       if (count > MAX_BUF_SIZE)
+               return -EINVAL;
+
+       DBG("writting %d bytes\n", count);
+
+       smd_pkt_devp = file->private_data;
+       if (!smd_pkt_devp || !smd_pkt_devp->ch)
+               return -EINVAL;
+
+       mutex_lock(&smd_pkt_devp->tx_lock);
+       if (smd_write_avail(smd_pkt_devp->ch) < count) {
+               mutex_unlock(&smd_pkt_devp->tx_lock);
+               DBG("Not enough space to write\n");
+               return -ENOMEM;
+       }
+
+       D_DUMP_BUFFER("write: ", count, buf);
+       r = copy_from_user(smd_pkt_devp->tx_buf, buf, count);
+       if (r) {
+               mutex_unlock(&smd_pkt_devp->tx_lock);
+               pr_err("copy_from_user failed %d\n", r);
+               return -EFAULT;
+       }
+
+       r = smd_write(smd_pkt_devp->ch, smd_pkt_devp->tx_buf, count);
+       if (r != count) {
+               mutex_unlock(&smd_pkt_devp->tx_lock);
+               pr_err("smd_write failed to write %d bytes: %d.\n", count, r);
+               return -EIO;
+       }
+       mutex_unlock(&smd_pkt_devp->tx_lock);
+
+       DBG("wrote %d bytes\n", count);
+       return count;
+}
+
+static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
+{
+       struct smd_pkt_dev *smd_pkt_devp;
+       unsigned int mask = 0;
+
+       smd_pkt_devp = file->private_data;
+       if (!smd_pkt_devp)
+               return POLLERR;
+
+       DBG("poll waiting\n");
+       poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
+       if (smd_read_avail(smd_pkt_devp->ch))
+               mask |= POLLIN | POLLRDNORM;
+
+       DBG("poll return\n");
+       return mask;
+}
+
+static void smd_pkt_ch_notify(void *priv, unsigned event)
+{
+       struct smd_pkt_dev *smd_pkt_devp = priv;
+
+       if (smd_pkt_devp->ch == 0)
+               return;
+
+       switch (event) {
+       case SMD_EVENT_DATA:
+               DBG("data\n");
+               check_and_wakeup_reader(smd_pkt_devp);
+               break;
+
+       case SMD_EVENT_OPEN:
+               DBG("remote open\n");
+               smd_pkt_devp->remote_open = 1;
+               wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
+               break;
+
+       case SMD_EVENT_CLOSE:
+               smd_pkt_devp->remote_open = 0;
+               pr_info("remote closed\n");
+               break;
+
+       default:
+               pr_err("unknown event %d\n", event);
+               break;
+       }
+}
+
+static char *smd_pkt_dev_name[] = {
+       "smdcntl0",
+       "smdcntl1",
+       "smdcntl2",
+       "smdcntl3",
+       "smdcntl4",
+       "smdcntl5",
+       "smdcntl6",
+       "smdcntl7",
+       "smd22",
+};
+
+static char *smd_ch_name[] = {
+       "DATA5_CNTL",
+       "DATA6_CNTL",
+       "DATA7_CNTL",
+       "DATA8_CNTL",
+       "DATA9_CNTL",
+       "DATA12_CNTL",
+       "DATA13_CNTL",
+       "DATA14_CNTL",
+       "DATA22",
+};
+
+static int smd_pkt_open(struct inode *inode, struct file *file)
+{
+       int r = 0;
+       struct smd_pkt_dev *smd_pkt_devp;
+
+       smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
+       if (!smd_pkt_devp)
+               return -EINVAL;
+
+       file->private_data = smd_pkt_devp;
+
+       mutex_lock(&smd_pkt_devp->ch_lock);
+       if (smd_pkt_devp->open_count == 0) {
+               r = smd_open(smd_ch_name[smd_pkt_devp->i],
+                            &smd_pkt_devp->ch, smd_pkt_devp,
+                            smd_pkt_ch_notify);
+               if (r < 0) {
+                       pr_err("smd_open failed for %s, %d\n",
+                              smd_ch_name[smd_pkt_devp->i], r);
+                       goto out;
+               }
+
+               r = wait_event_interruptible_timeout(
+                               smd_pkt_devp->ch_opened_wait_queue,
+                               smd_pkt_devp->remote_open,
+                               msecs_to_jiffies(2 * HZ));
+               if (r == 0)
+                       r = -ETIMEDOUT;
+
+               if (r < 0) {
+                       pr_err("wait returned %d\n", r);
+                       smd_close(smd_pkt_devp->ch);
+                       smd_pkt_devp->ch = 0;
+               } else {
+                       smd_pkt_devp->open_count++;
+                       r = 0;
+               }
+       }
+out:
+       mutex_unlock(&smd_pkt_devp->ch_lock);
+       return r;
+}
+
+static int smd_pkt_release(struct inode *inode, struct file *file)
+{
+       int r = 0;
+       struct smd_pkt_dev *smd_pkt_devp = file->private_data;
+
+       if (!smd_pkt_devp)
+               return -EINVAL;
+
+       mutex_lock(&smd_pkt_devp->ch_lock);
+       if (--smd_pkt_devp->open_count == 0) {
+               r = smd_close(smd_pkt_devp->ch);
+               smd_pkt_devp->ch = 0;
+       }
+       mutex_unlock(&smd_pkt_devp->ch_lock);
+
+       return r;
+}
+
+static const struct file_operations smd_pkt_fops = {
+       .owner = THIS_MODULE,
+       .open = smd_pkt_open,
+       .release = smd_pkt_release,
+       .read = smd_pkt_read,
+       .write = smd_pkt_write,
+       .poll = smd_pkt_poll,
+};
+
+static int __init smd_pkt_init(void)
+{
+       int i;
+       int r;
+
+       r = alloc_chrdev_region(&smd_pkt_number, 0,
+                               NUM_SMD_PKT_PORTS, DEVICE_NAME);
+       if (r) {
+               pr_err("alloc_chrdev_region() failed %d\n", r);
+               return r;
+       }
+
+       smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
+       if (IS_ERR(smd_pkt_classp)) {
+               r = PTR_ERR(smd_pkt_classp);
+               pr_err("class_create() failed %d\n", r);
+               goto unreg_chardev;
+       }
+
+       for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+               smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
+                                         GFP_KERNEL);
+               if (IS_ERR(smd_pkt_devp[i])) {
+                       r = PTR_ERR(smd_pkt_devp[i]);
+                       pr_err("kmalloc() failed %d\n", r);
+                       goto clean_cdevs;
+               }
+
+               smd_pkt_devp[i]->i = i;
+
+               init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
+               smd_pkt_devp[i]->remote_open = 0;
+               init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
+
+               mutex_init(&smd_pkt_devp[i]->ch_lock);
+               mutex_init(&smd_pkt_devp[i]->rx_lock);
+               mutex_init(&smd_pkt_devp[i]->tx_lock);
+
+               cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
+               smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
+
+               r = cdev_add(&smd_pkt_devp[i]->cdev,
+                            (smd_pkt_number + i), 1);
+               if (r) {
+                       pr_err("cdev_add() failed %d\n", r);
+                       kfree(smd_pkt_devp[i]);
+                       goto clean_cdevs;
+               }
+
+               smd_pkt_devp[i]->devicep =
+                       device_create(smd_pkt_classp, NULL,
+                                     (smd_pkt_number + i), NULL,
+                                     smd_pkt_dev_name[i]);
+               if (IS_ERR(smd_pkt_devp[i]->devicep)) {
+                       r = PTR_ERR(smd_pkt_devp[i]->devicep);
+                       pr_err("device_create() failed %d\n", r);
+                       cdev_del(&smd_pkt_devp[i]->cdev);
+                       kfree(smd_pkt_devp[i]);
+                       goto clean_cdevs;
+               }
+
+       }
+
+       pr_info("SMD Packet Port Driver Initialized.\n");
+       return 0;
+
+clean_cdevs:
+       if (i > 0) {
+               while (--i >= 0) {
+                       mutex_destroy(&smd_pkt_devp[i]->ch_lock);
+                       mutex_destroy(&smd_pkt_devp[i]->rx_lock);
+                       mutex_destroy(&smd_pkt_devp[i]->tx_lock);
+                       cdev_del(&smd_pkt_devp[i]->cdev);
+                       kfree(smd_pkt_devp[i]);
+                       device_destroy(smd_pkt_classp,
+                                      MKDEV(MAJOR(smd_pkt_number), i));
+               }
+       }
+
+       class_destroy(smd_pkt_classp);
+unreg_chardev:
+       unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
+       return r;
+}
+module_init(smd_pkt_init);
+
+static void __exit smd_pkt_cleanup(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
+               mutex_destroy(&smd_pkt_devp[i]->ch_lock);
+               mutex_destroy(&smd_pkt_devp[i]->rx_lock);
+               mutex_destroy(&smd_pkt_devp[i]->tx_lock);
+               cdev_del(&smd_pkt_devp[i]->cdev);
+               kfree(smd_pkt_devp[i]);
+               device_destroy(smd_pkt_classp,
+                              MKDEV(MAJOR(smd_pkt_number), i));
+       }
+
+       class_destroy(smd_pkt_classp);
+       unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
+}
+module_exit(smd_pkt_cleanup);
+
+MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
+MODULE_LICENSE("GPL v2");
index 26b4fce217b6475ecb3e8a696cb82e4f9f0cccb6..efa6a82e543dc70aab8be26359e73fc46e5cd589 100644 (file)
@@ -9,7 +9,7 @@ obj-$(CONFIG_MWAVE) += mwave.o
 mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o
 
 # To have the mwave driver disable other uarts if necessary
-# EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES
+# ccflags-y := -DMWAVE_FUTZ_WITH_OTHER_DEVICES
 
 # To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
-ccflags-y := -DMW_TRACE
+ccflags-y += -DMW_TRACE
index 480251fc78e2865dd3d387e59074fcefbce77b12..c2a58f428bc84778c0ca3f09d372cbecc8b24191 100644 (file)
@@ -11,7 +11,7 @@ are not saved by the BIOS and so do not persist after unload and reload.
        0x0008 tp3780i tracing
 
         Tracing only occurs if the driver has been compiled with the
-        MW_TRACE macro #defined  (i.e. let EXTRA_CFLAGS += -DMW_TRACE
+        MW_TRACE macro #defined  (i.e. let ccflags-y := -DMW_TRACE
         in the Makefile).
 
   mwave_3780i_irq=5/7/10/11/15
index c461eda6241159ac52ee279bf681778d2f6a7390..4abd089a094fe43ce20f04d6cd5b958e58b969e9 100644 (file)
@@ -111,10 +111,8 @@ static void unregister_dca_providers(void)
        /* at this point only one domain in the list is expected */
        domain = list_first_entry(&dca_domains, struct dca_domain, node);
 
-       list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) {
-               list_del(&dca->node);
-               list_add(&dca->node, &unregistered_providers);
-       }
+       list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node)
+               list_move(&dca->node, &unregistered_providers);
 
        dca_free_domain(domain);
 
index 1c28816152fa3169254681cbe76f758f99192e59..a572600e44eb3e28d10b3b52b748eac5419661fd 100644 (file)
@@ -82,7 +82,7 @@ config INTEL_IOP_ADMA
 
 config DW_DMAC
        tristate "Synopsys DesignWare AHB DMA support"
-       depends on AVR32
+       depends on HAVE_CLK
        select DMA_ENGINE
        default y if CPU_AT32AP7000
        help
@@ -221,12 +221,20 @@ config IMX_SDMA
 
 config IMX_DMA
        tristate "i.MX DMA support"
-       depends on ARCH_MX1 || ARCH_MX21 || MACH_MX27
+       depends on IMX_HAVE_DMA_V1
        select DMA_ENGINE
        help
          Support the i.MX DMA engine. This engine is integrated into
          Freescale i.MX1/21/27 chips.
 
+config MXS_DMA
+       bool "MXS DMA support"
+       depends on SOC_IMX23 || SOC_IMX28
+       select DMA_ENGINE
+       help
+         Support the MXS DMA engine. This engine including APBH-DMA
+         and APBX-DMA is integrated into Freescale i.MX23/28 chips.
+
 config DMA_ENGINE
        bool
 
index 64b21f5cd740fc5dfa1d5f09b1a944ed1f661440..836095ab3c5c7db30307cc1e3946346a882b0aad 100644 (file)
@@ -1,9 +1,5 @@
-ifeq ($(CONFIG_DMADEVICES_DEBUG),y)
-       ccflags-y       += -DDEBUG
-endif
-ifeq ($(CONFIG_DMADEVICES_VDEBUG),y)
-       ccflags-y       += -DVERBOSE_DEBUG
-endif
+ccflags-$(CONFIG_DMADEVICES_DEBUG)  := -DDEBUG
+ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG
 
 obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
 obj-$(CONFIG_NET_DMA) += iovlock.o
@@ -23,6 +19,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
 obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
 obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
 obj-$(CONFIG_IMX_DMA) += imx-dma.o
+obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
index 5589358b684d7ab3e19cefe0bb83aa775ac59fda..e0888cb538d4b0ffa65f733065cde71684a11039 100644 (file)
@@ -54,6 +54,11 @@ module_param(pq_sources, uint, S_IRUGO);
 MODULE_PARM_DESC(pq_sources,
                "Number of p+q source buffers (default: 3)");
 
+static int timeout = 3000;
+module_param(timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), \
+               Pass -1 for infinite timeout");
+
 /*
  * Initialization patterns. All bytes in the source buffer has bit 7
  * set, all bytes in the destination buffer has bit 7 cleared.
@@ -285,7 +290,12 @@ static int dmatest_func(void *data)
 
        set_user_nice(current, 10);
 
-       flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
+       /*
+        * src buffers are freed by the DMAEngine code with dma_unmap_single()
+        * dst buffers are freed by ourselves below
+        */
+       flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT
+             | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE;
 
        while (!kthread_should_stop()
               && !(iterations && total_tests >= iterations)) {
@@ -294,7 +304,7 @@ static int dmatest_func(void *data)
                dma_addr_t dma_srcs[src_cnt];
                dma_addr_t dma_dsts[dst_cnt];
                struct completion cmp;
-               unsigned long tmo = msecs_to_jiffies(3000);
+               unsigned long tmo = msecs_to_jiffies(timeout);
                u8 align = 0;
 
                total_tests++;
index a3991ab0d67e06cf6e99d41d9a1a923109dc1a06..9c25c7d099e494be5ddee2bed8276932c9a2e7eb 100644 (file)
  * which does not support descriptor writeback.
  */
 
-/* NOTE:  DMS+SMS is system-specific. We should get this information
- * from the platform code somehow.
- */
-#define DWC_DEFAULT_CTLLO      (DWC_CTLL_DST_MSIZE(0)          \
-                               | DWC_CTLL_SRC_MSIZE(0)         \
-                               | DWC_CTLL_DMS(0)               \
-                               | DWC_CTLL_SMS(1)               \
-                               | DWC_CTLL_LLP_D_EN             \
-                               | DWC_CTLL_LLP_S_EN)
+#define DWC_DEFAULT_CTLLO(private) ({                          \
+               struct dw_dma_slave *__slave = (private);       \
+               int dms = __slave ? __slave->dst_master : 0;    \
+               int sms = __slave ? __slave->src_master : 1;    \
+               u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \
+               u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \
+                                                               \
+               (DWC_CTLL_DST_MSIZE(dmsize)                     \
+                | DWC_CTLL_SRC_MSIZE(smsize)                   \
+                | DWC_CTLL_LLP_D_EN                            \
+                | DWC_CTLL_LLP_S_EN                            \
+                | DWC_CTLL_DMS(dms)                            \
+                | DWC_CTLL_SMS(sms));                          \
+       })
 
 /*
  * This is configuration-dependent and usually a funny size like 4095.
- * Let's round it down to the nearest power of two.
  *
  * Note that this is a transfer count, i.e. if we transfer 32-bit
- * words, we can do 8192 bytes per descriptor.
+ * words, we can do 16380 bytes per descriptor.
  *
  * This parameter is also system-specific.
  */
-#define DWC_MAX_COUNT  2048U
+#define DWC_MAX_COUNT  4095U
 
 /*
  * Number of descriptors to allocate for each channel. This should be
@@ -84,11 +88,6 @@ static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
        return list_entry(dwc->active_list.next, struct dw_desc, desc_node);
 }
 
-static struct dw_desc *dwc_first_queued(struct dw_dma_chan *dwc)
-{
-       return list_entry(dwc->queue.next, struct dw_desc, desc_node);
-}
-
 static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
 {
        struct dw_desc *desc, *_desc;
@@ -201,6 +200,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
        dma_async_tx_callback           callback;
        void                            *param;
        struct dma_async_tx_descriptor  *txd = &desc->txd;
+       struct dw_desc                  *child;
 
        dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
 
@@ -209,6 +209,12 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
        param = txd->callback_param;
 
        dwc_sync_desc_for_cpu(dwc, desc);
+
+       /* async_tx_ack */
+       list_for_each_entry(child, &desc->tx_list, desc_node)
+               async_tx_ack(&child->txd);
+       async_tx_ack(&desc->txd);
+
        list_splice_init(&desc->tx_list, &dwc->free_list);
        list_move(&desc->desc_node, &dwc->free_list);
 
@@ -259,10 +265,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
         * Submit queued descriptors ASAP, i.e. before we go through
         * the completed ones.
         */
-       if (!list_empty(&dwc->queue))
-               dwc_dostart(dwc, dwc_first_queued(dwc));
        list_splice_init(&dwc->active_list, &list);
-       list_splice_init(&dwc->queue, &dwc->active_list);
+       if (!list_empty(&dwc->queue)) {
+               list_move(dwc->queue.next, &dwc->active_list);
+               dwc_dostart(dwc, dwc_first_active(dwc));
+       }
 
        list_for_each_entry_safe(desc, _desc, &list, desc_node)
                dwc_descriptor_complete(dwc, desc);
@@ -291,6 +298,9 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
                return;
        }
 
+       if (list_empty(&dwc->active_list))
+               return;
+
        dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
 
        list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
@@ -319,8 +329,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
                cpu_relax();
 
        if (!list_empty(&dwc->queue)) {
-               dwc_dostart(dwc, dwc_first_queued(dwc));
-               list_splice_init(&dwc->queue, &dwc->active_list);
+               list_move(dwc->queue.next, &dwc->active_list);
+               dwc_dostart(dwc, dwc_first_active(dwc));
        }
 }
 
@@ -346,7 +356,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
         */
        bad_desc = dwc_first_active(dwc);
        list_del_init(&bad_desc->desc_node);
-       list_splice_init(&dwc->queue, dwc->active_list.prev);
+       list_move(dwc->queue.next, dwc->active_list.prev);
 
        /* Clear the error flag and try to restart the controller */
        dma_writel(dw, CLEAR.ERROR, dwc->mask);
@@ -541,8 +551,8 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
        if (list_empty(&dwc->active_list)) {
                dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
                                desc->txd.cookie);
-               dwc_dostart(dwc, desc);
                list_add_tail(&desc->desc_node, &dwc->active_list);
+               dwc_dostart(dwc, dwc_first_active(dwc));
        } else {
                dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
                                desc->txd.cookie);
@@ -581,14 +591,16 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
         * We can be a lot more clever here, but this should take care
         * of the most common optimization.
         */
-       if (!((src | dest  | len) & 3))
+       if (!((src | dest  | len) & 7))
+               src_width = dst_width = 3;
+       else if (!((src | dest  | len) & 3))
                src_width = dst_width = 2;
        else if (!((src | dest | len) & 1))
                src_width = dst_width = 1;
        else
                src_width = dst_width = 0;
 
-       ctllo = DWC_DEFAULT_CTLLO
+       ctllo = DWC_DEFAULT_CTLLO(chan->private)
                        | DWC_CTLL_DST_WIDTH(dst_width)
                        | DWC_CTLL_SRC_WIDTH(src_width)
                        | DWC_CTLL_DST_INC
@@ -669,11 +681,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
        switch (direction) {
        case DMA_TO_DEVICE:
-               ctllo = (DWC_DEFAULT_CTLLO
+               ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                | DWC_CTLL_DST_WIDTH(reg_width)
                                | DWC_CTLL_DST_FIX
                                | DWC_CTLL_SRC_INC
-                               | DWC_CTLL_FC_M2P);
+                               | DWC_CTLL_FC(dws->fc));
                reg = dws->tx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
@@ -714,11 +726,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                }
                break;
        case DMA_FROM_DEVICE:
-               ctllo = (DWC_DEFAULT_CTLLO
+               ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                | DWC_CTLL_SRC_WIDTH(reg_width)
                                | DWC_CTLL_DST_INC
                                | DWC_CTLL_SRC_FIX
-                               | DWC_CTLL_FC_P2M);
+                               | DWC_CTLL_FC(dws->fc));
 
                reg = dws->rx_reg;
                for_each_sg(sgl, sg, sg_len, i) {
@@ -834,7 +846,9 @@ dwc_tx_status(struct dma_chan *chan,
 
        ret = dma_async_is_complete(cookie, last_complete, last_used);
        if (ret != DMA_SUCCESS) {
+               spin_lock_bh(&dwc->lock);
                dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
+               spin_unlock_bh(&dwc->lock);
 
                last_complete = dwc->completed;
                last_used = chan->cookie;
@@ -889,8 +903,11 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
                BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
 
                cfghi = dws->cfg_hi;
-               cfglo = dws->cfg_lo;
+               cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK;
        }
+
+       cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority);
+
        channel_writel(dwc, CFG_LO, cfglo);
        channel_writel(dwc, CFG_HI, cfghi);
 
@@ -1126,23 +1143,23 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
                case DMA_TO_DEVICE:
                        desc->lli.dar = dws->tx_reg;
                        desc->lli.sar = buf_addr + (period_len * i);
-                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO
+                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                        | DWC_CTLL_DST_WIDTH(reg_width)
                                        | DWC_CTLL_SRC_WIDTH(reg_width)
                                        | DWC_CTLL_DST_FIX
                                        | DWC_CTLL_SRC_INC
-                                       | DWC_CTLL_FC_M2P
+                                       | DWC_CTLL_FC(dws->fc)
                                        | DWC_CTLL_INT_EN);
                        break;
                case DMA_FROM_DEVICE:
                        desc->lli.dar = buf_addr + (period_len * i);
                        desc->lli.sar = dws->rx_reg;
-                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO
+                       desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private)
                                        | DWC_CTLL_SRC_WIDTH(reg_width)
                                        | DWC_CTLL_DST_WIDTH(reg_width)
                                        | DWC_CTLL_DST_INC
                                        | DWC_CTLL_SRC_FIX
-                                       | DWC_CTLL_FC_P2M
+                                       | DWC_CTLL_FC(dws->fc)
                                        | DWC_CTLL_INT_EN);
                        break;
                default:
@@ -1307,7 +1324,17 @@ static int __init dw_probe(struct platform_device *pdev)
                dwc->chan.device = &dw->dma;
                dwc->chan.cookie = dwc->completed = 1;
                dwc->chan.chan_id = i;
-               list_add_tail(&dwc->chan.device_node, &dw->dma.channels);
+               if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING)
+                       list_add_tail(&dwc->chan.device_node,
+                                       &dw->dma.channels);
+               else
+                       list_add(&dwc->chan.device_node, &dw->dma.channels);
+
+               /* 7 is highest priority & 0 is lowest. */
+               if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
+                       dwc->priority = 7 - i;
+               else
+                       dwc->priority = i;
 
                dwc->ch_regs = &__dw_regs(dw)->CHAN[i];
                spin_lock_init(&dwc->lock);
@@ -1335,6 +1362,8 @@ static int __init dw_probe(struct platform_device *pdev)
 
        dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask);
        dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
+       if (pdata->is_private)
+               dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask);
        dw->dma.dev = &pdev->dev;
        dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources;
        dw->dma.device_free_chan_resources = dwc_free_chan_resources;
@@ -1447,7 +1476,7 @@ static int __init dw_init(void)
 {
        return platform_driver_probe(&dw_driver, dw_probe);
 }
-module_init(dw_init);
+subsys_initcall(dw_init);
 
 static void __exit dw_exit(void)
 {
index d9a939f67f461ffa7b5deffd0f21d35bd7678864..720f821527f8aeebd8738c34f1f5c87a5a34f867 100644 (file)
@@ -86,6 +86,7 @@ struct dw_dma_regs {
 #define DWC_CTLL_SRC_MSIZE(n)  ((n)<<14)
 #define DWC_CTLL_S_GATH_EN     (1 << 17)       /* src gather, !FIX */
 #define DWC_CTLL_D_SCAT_EN     (1 << 18)       /* dst scatter, !FIX */
+#define DWC_CTLL_FC(n)         ((n) << 20)
 #define DWC_CTLL_FC_M2M                (0 << 20)       /* mem-to-mem */
 #define DWC_CTLL_FC_M2P                (1 << 20)       /* mem-to-periph */
 #define DWC_CTLL_FC_P2M                (2 << 20)       /* periph-to-mem */
@@ -101,6 +102,8 @@ struct dw_dma_regs {
 #define DWC_CTLH_BLOCK_TS_MASK 0x00000fff
 
 /* Bitfields in CFG_LO. Platform-configurable bits are in <linux/dw_dmac.h> */
+#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5)      /* priority mask */
+#define DWC_CFGL_CH_PRIOR(x)   ((x) << 5)      /* priority */
 #define DWC_CFGL_CH_SUSP       (1 << 8)        /* pause xfer */
 #define DWC_CFGL_FIFO_EMPTY    (1 << 9)        /* pause xfer */
 #define DWC_CFGL_HS_DST                (1 << 10)       /* handshake w/dst */
@@ -134,6 +137,7 @@ struct dw_dma_chan {
        struct dma_chan         chan;
        void __iomem            *ch_regs;
        u8                      mask;
+       u8                      priority;
 
        spinlock_t              lock;
 
@@ -155,9 +159,9 @@ __dwc_regs(struct dw_dma_chan *dwc)
 }
 
 #define channel_readl(dwc, name) \
-       __raw_readl(&(__dwc_regs(dwc)->name))
+       readl(&(__dwc_regs(dwc)->name))
 #define channel_writel(dwc, name, val) \
-       __raw_writel((val), &(__dwc_regs(dwc)->name))
+       writel((val), &(__dwc_regs(dwc)->name))
 
 static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
 {
@@ -181,9 +185,9 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
 }
 
 #define dma_readl(dw, name) \
-       __raw_readl(&(__dw_regs(dw)->name))
+       readl(&(__dw_regs(dw)->name))
 #define dma_writel(dw, name, val) \
-       __raw_writel((val), &(__dw_regs(dw)->name))
+       writel((val), &(__dw_regs(dw)->name))
 
 #define channel_set_bit(dw, reg, mask) \
        dma_writel(dw, reg, ((mask) << 8) | (mask))
index e3854a8f0de02224ef24ba2e572fc4cad7e9e13e..6b396759e7f596f54eab9d9bd28c06ae13fe6887 100644 (file)
 
 #include "fsldma.h"
 
-static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+#define chan_dbg(chan, fmt, arg...)                                    \
+       dev_dbg(chan->dev, "%s: " fmt, chan->name, ##arg)
+#define chan_err(chan, fmt, arg...)                                    \
+       dev_err(chan->dev, "%s: " fmt, chan->name, ##arg)
 
-static void dma_init(struct fsldma_chan *chan)
-{
-       /* Reset the channel */
-       DMA_OUT(chan, &chan->regs->mr, 0, 32);
+static const char msg_ld_oom[] = "No free memory for link descriptor";
 
-       switch (chan->feature & FSL_DMA_IP_MASK) {
-       case FSL_DMA_IP_85XX:
-               /* Set the channel to below modes:
-                * EIE - Error interrupt enable
-                * EOSIE - End of segments interrupt enable (basic mode)
-                * EOLNIE - End of links interrupt enable
-                * BWC - Bandwidth sharing among channels
-                */
-               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-                               | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
-                               | FSL_DMA_MR_EOSIE, 32);
-               break;
-       case FSL_DMA_IP_83XX:
-               /* Set the channel to below modes:
-                * EOTIE - End-of-transfer interrupt enable
-                * PRC_RM - PCI read multiple
-                */
-               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
-                               | FSL_DMA_MR_PRC_RM, 32);
-               break;
-       }
-}
+/*
+ * Register Helpers
+ */
 
 static void set_sr(struct fsldma_chan *chan, u32 val)
 {
@@ -77,14 +58,38 @@ static u32 get_sr(struct fsldma_chan *chan)
        return DMA_IN(chan, &chan->regs->sr, 32);
 }
 
+static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+{
+       DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
+}
+
+static dma_addr_t get_cdar(struct fsldma_chan *chan)
+{
+       return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
+}
+
+static u32 get_bcr(struct fsldma_chan *chan)
+{
+       return DMA_IN(chan, &chan->regs->bcr, 32);
+}
+
+/*
+ * Descriptor Helpers
+ */
+
 static void set_desc_cnt(struct fsldma_chan *chan,
                                struct fsl_dma_ld_hw *hw, u32 count)
 {
        hw->count = CPU_TO_DMA(chan, count, 32);
 }
 
+static u32 get_desc_cnt(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
+{
+       return DMA_TO_CPU(chan, desc->hw.count, 32);
+}
+
 static void set_desc_src(struct fsldma_chan *chan,
-                               struct fsl_dma_ld_hw *hw, dma_addr_t src)
+                        struct fsl_dma_ld_hw *hw, dma_addr_t src)
 {
        u64 snoop_bits;
 
@@ -93,8 +98,18 @@ static void set_desc_src(struct fsldma_chan *chan,
        hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64);
 }
 
+static dma_addr_t get_desc_src(struct fsldma_chan *chan,
+                              struct fsl_desc_sw *desc)
+{
+       u64 snoop_bits;
+
+       snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+               ? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
+       return DMA_TO_CPU(chan, desc->hw.src_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_dst(struct fsldma_chan *chan,
-                               struct fsl_dma_ld_hw *hw, dma_addr_t dst)
+                        struct fsl_dma_ld_hw *hw, dma_addr_t dst)
 {
        u64 snoop_bits;
 
@@ -103,8 +118,18 @@ static void set_desc_dst(struct fsldma_chan *chan,
        hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64);
 }
 
+static dma_addr_t get_desc_dst(struct fsldma_chan *chan,
+                              struct fsl_desc_sw *desc)
+{
+       u64 snoop_bits;
+
+       snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+               ? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
+       return DMA_TO_CPU(chan, desc->hw.dst_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_next(struct fsldma_chan *chan,
-                               struct fsl_dma_ld_hw *hw, dma_addr_t next)
+                         struct fsl_dma_ld_hw *hw, dma_addr_t next)
 {
        u64 snoop_bits;
 
@@ -113,24 +138,46 @@ static void set_desc_next(struct fsldma_chan *chan,
        hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
 }
 
-static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
-       DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
-}
+       u64 snoop_bits;
 
-static dma_addr_t get_cdar(struct fsldma_chan *chan)
-{
-       return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
-}
+       snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+               ? FSL_DMA_SNEN : 0;
 
-static dma_addr_t get_ndar(struct fsldma_chan *chan)
-{
-       return DMA_IN(chan, &chan->regs->ndar, 64);
+       desc->hw.next_ln_addr = CPU_TO_DMA(chan,
+               DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
+                       | snoop_bits, 64);
 }
 
-static u32 get_bcr(struct fsldma_chan *chan)
+/*
+ * DMA Engine Hardware Control Helpers
+ */
+
+static void dma_init(struct fsldma_chan *chan)
 {
-       return DMA_IN(chan, &chan->regs->bcr, 32);
+       /* Reset the channel */
+       DMA_OUT(chan, &chan->regs->mr, 0, 32);
+
+       switch (chan->feature & FSL_DMA_IP_MASK) {
+       case FSL_DMA_IP_85XX:
+               /* Set the channel to below modes:
+                * EIE - Error interrupt enable
+                * EOLNIE - End of links interrupt enable
+                * BWC - Bandwidth sharing among channels
+                */
+               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+                               | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32);
+               break;
+       case FSL_DMA_IP_83XX:
+               /* Set the channel to below modes:
+                * EOTIE - End-of-transfer interrupt enable
+                * PRC_RM - PCI read multiple
+                */
+               DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
+                               | FSL_DMA_MR_PRC_RM, 32);
+               break;
+       }
 }
 
 static int dma_is_idle(struct fsldma_chan *chan)
@@ -139,25 +186,32 @@ static int dma_is_idle(struct fsldma_chan *chan)
        return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH);
 }
 
+/*
+ * Start the DMA controller
+ *
+ * Preconditions:
+ * - the CDAR register must point to the start descriptor
+ * - the MRn[CS] bit must be cleared
+ */
 static void dma_start(struct fsldma_chan *chan)
 {
        u32 mode;
 
        mode = DMA_IN(chan, &chan->regs->mr, 32);
 
-       if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
-               if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
-                       DMA_OUT(chan, &chan->regs->bcr, 0, 32);
-                       mode |= FSL_DMA_MR_EMP_EN;
-               } else {
-                       mode &= ~FSL_DMA_MR_EMP_EN;
-               }
+       if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) {
+               DMA_OUT(chan, &chan->regs->bcr, 0, 32);
+               mode |= FSL_DMA_MR_EMP_EN;
+       } else {
+               mode &= ~FSL_DMA_MR_EMP_EN;
        }
 
-       if (chan->feature & FSL_DMA_CHAN_START_EXT)
+       if (chan->feature & FSL_DMA_CHAN_START_EXT) {
                mode |= FSL_DMA_MR_EMS_EN;
-       else
+       } else {
+               mode &= ~FSL_DMA_MR_EMS_EN;
                mode |= FSL_DMA_MR_CS;
+       }
 
        DMA_OUT(chan, &chan->regs->mr, mode, 32);
 }
@@ -167,13 +221,26 @@ static void dma_halt(struct fsldma_chan *chan)
        u32 mode;
        int i;
 
+       /* read the mode register */
        mode = DMA_IN(chan, &chan->regs->mr, 32);
-       mode |= FSL_DMA_MR_CA;
-       DMA_OUT(chan, &chan->regs->mr, mode, 32);
 
-       mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA);
+       /*
+        * The 85xx controller supports channel abort, which will stop
+        * the current transfer. On 83xx, this bit is the transfer error
+        * mask bit, which should not be changed.
+        */
+       if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+               mode |= FSL_DMA_MR_CA;
+               DMA_OUT(chan, &chan->regs->mr, mode, 32);
+
+               mode &= ~FSL_DMA_MR_CA;
+       }
+
+       /* stop the DMA controller */
+       mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN);
        DMA_OUT(chan, &chan->regs->mr, mode, 32);
 
+       /* wait for the DMA controller to become idle */
        for (i = 0; i < 100; i++) {
                if (dma_is_idle(chan))
                        return;
@@ -182,20 +249,7 @@ static void dma_halt(struct fsldma_chan *chan)
        }
 
        if (!dma_is_idle(chan))
-               dev_err(chan->dev, "DMA halt timeout!\n");
-}
-
-static void set_ld_eol(struct fsldma_chan *chan,
-                       struct fsl_desc_sw *desc)
-{
-       u64 snoop_bits;
-
-       snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
-               ? FSL_DMA_SNEN : 0;
-
-       desc->hw.next_ln_addr = CPU_TO_DMA(chan,
-               DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
-                       | snoop_bits, 64);
+               chan_err(chan, "DMA halt timeout!\n");
 }
 
 /**
@@ -321,8 +375,7 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable)
                chan->feature &= ~FSL_DMA_CHAN_START_EXT;
 }
 
-static void append_ld_queue(struct fsldma_chan *chan,
-                           struct fsl_desc_sw *desc)
+static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
        struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev);
 
@@ -363,8 +416,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
        cookie = chan->common.cookie;
        list_for_each_entry(child, &desc->tx_list, node) {
                cookie++;
-               if (cookie < 0)
-                       cookie = 1;
+               if (cookie < DMA_MIN_COOKIE)
+                       cookie = DMA_MIN_COOKIE;
 
                child->async_tx.cookie = cookie;
        }
@@ -385,15 +438,14 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
  *
  * Return - The descriptor allocated. NULL for failed.
  */
-static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
-                                       struct fsldma_chan *chan)
+static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan)
 {
        struct fsl_desc_sw *desc;
        dma_addr_t pdesc;
 
        desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc);
        if (!desc) {
-               dev_dbg(chan->dev, "out of memory for link desc\n");
+               chan_dbg(chan, "out of memory for link descriptor\n");
                return NULL;
        }
 
@@ -403,10 +455,13 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
        desc->async_tx.tx_submit = fsl_dma_tx_submit;
        desc->async_tx.phys = pdesc;
 
+#ifdef FSL_DMA_LD_DEBUG
+       chan_dbg(chan, "LD %p allocated\n", desc);
+#endif
+
        return desc;
 }
 
-
 /**
  * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
  * @chan : Freescale DMA channel
@@ -427,13 +482,11 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan)
         * We need the descriptor to be aligned to 32bytes
         * for meeting FSL DMA specification requirement.
         */
-       chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
-                                         chan->dev,
+       chan->desc_pool = dma_pool_create(chan->name, chan->dev,
                                          sizeof(struct fsl_desc_sw),
                                          __alignof__(struct fsl_desc_sw), 0);
        if (!chan->desc_pool) {
-               dev_err(chan->dev, "unable to allocate channel %d "
-                                  "descriptor pool\n", chan->id);
+               chan_err(chan, "unable to allocate descriptor pool\n");
                return -ENOMEM;
        }
 
@@ -455,6 +508,9 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan,
 
        list_for_each_entry_safe(desc, _desc, list, node) {
                list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+               chan_dbg(chan, "LD %p free\n", desc);
+#endif
                dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
        }
 }
@@ -466,6 +522,9 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
 
        list_for_each_entry_safe_reverse(desc, _desc, list, node) {
                list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+               chan_dbg(chan, "LD %p free\n", desc);
+#endif
                dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
        }
 }
@@ -479,7 +538,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
        struct fsldma_chan *chan = to_fsl_chan(dchan);
        unsigned long flags;
 
-       dev_dbg(chan->dev, "Free all channel resources.\n");
+       chan_dbg(chan, "free all channel resources\n");
        spin_lock_irqsave(&chan->desc_lock, flags);
        fsldma_free_desc_list(chan, &chan->ld_pending);
        fsldma_free_desc_list(chan, &chan->ld_running);
@@ -502,7 +561,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
 
        new = fsl_dma_alloc_descriptor(chan);
        if (!new) {
-               dev_err(chan->dev, msg_ld_oom);
+               chan_err(chan, "%s\n", msg_ld_oom);
                return NULL;
        }
 
@@ -512,14 +571,15 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
        /* Insert the link descriptor to the LD ring */
        list_add_tail(&new->node, &new->tx_list);
 
-       /* Set End-of-link to the last link descriptor of new list*/
+       /* Set End-of-link to the last link descriptor of new list */
        set_ld_eol(chan, new);
 
        return &new->async_tx;
 }
 
-static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
-       struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src,
+static struct dma_async_tx_descriptor *
+fsl_dma_prep_memcpy(struct dma_chan *dchan,
+       dma_addr_t dma_dst, dma_addr_t dma_src,
        size_t len, unsigned long flags)
 {
        struct fsldma_chan *chan;
@@ -539,12 +599,9 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
                /* Allocate the link descriptor from DMA pool */
                new = fsl_dma_alloc_descriptor(chan);
                if (!new) {
-                       dev_err(chan->dev, msg_ld_oom);
+                       chan_err(chan, "%s\n", msg_ld_oom);
                        goto fail;
                }
-#ifdef FSL_DMA_LD_DEBUG
-               dev_dbg(chan->dev, "new link desc alloc %p\n", new);
-#endif
 
                copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
 
@@ -572,7 +629,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
        new->async_tx.flags = flags; /* client is in control of this ack */
        new->async_tx.cookie = -EBUSY;
 
-       /* Set End-of-link to the last link descriptor of new list*/
+       /* Set End-of-link to the last link descriptor of new list */
        set_ld_eol(chan, new);
 
        return &first->async_tx;
@@ -627,12 +684,9 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
                /* allocate and populate the descriptor */
                new = fsl_dma_alloc_descriptor(chan);
                if (!new) {
-                       dev_err(chan->dev, msg_ld_oom);
+                       chan_err(chan, "%s\n", msg_ld_oom);
                        goto fail;
                }
-#ifdef FSL_DMA_LD_DEBUG
-               dev_dbg(chan->dev, "new link desc alloc %p\n", new);
-#endif
 
                set_desc_cnt(chan, &new->hw, len);
                set_desc_src(chan, &new->hw, src);
@@ -744,14 +798,15 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 
        switch (cmd) {
        case DMA_TERMINATE_ALL:
+               spin_lock_irqsave(&chan->desc_lock, flags);
+
                /* Halt the DMA engine */
                dma_halt(chan);
 
-               spin_lock_irqsave(&chan->desc_lock, flags);
-
                /* Remove and free all of the descriptors in the LD queue */
                fsldma_free_desc_list(chan, &chan->ld_pending);
                fsldma_free_desc_list(chan, &chan->ld_running);
+               chan->idle = true;
 
                spin_unlock_irqrestore(&chan->desc_lock, flags);
                return 0;
@@ -789,139 +844,86 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 }
 
 /**
- * fsl_dma_update_completed_cookie - Update the completed cookie.
- * @chan : Freescale DMA channel
- *
- * CONTEXT: hardirq
- */
-static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
-{
-       struct fsl_desc_sw *desc;
-       unsigned long flags;
-       dma_cookie_t cookie;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-
-       if (list_empty(&chan->ld_running)) {
-               dev_dbg(chan->dev, "no running descriptors\n");
-               goto out_unlock;
-       }
-
-       /* Get the last descriptor, update the cookie to that */
-       desc = to_fsl_desc(chan->ld_running.prev);
-       if (dma_is_idle(chan))
-               cookie = desc->async_tx.cookie;
-       else {
-               cookie = desc->async_tx.cookie - 1;
-               if (unlikely(cookie < DMA_MIN_COOKIE))
-                       cookie = DMA_MAX_COOKIE;
-       }
-
-       chan->completed_cookie = cookie;
-
-out_unlock:
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
-}
-
-/**
- * fsldma_desc_status - Check the status of a descriptor
+ * fsldma_cleanup_descriptor - cleanup and free a single link descriptor
  * @chan: Freescale DMA channel
- * @desc: DMA SW descriptor
- *
- * This function will return the status of the given descriptor
- */
-static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
-                                         struct fsl_desc_sw *desc)
-{
-       return dma_async_is_complete(desc->async_tx.cookie,
-                                    chan->completed_cookie,
-                                    chan->common.cookie);
-}
-
-/**
- * fsl_chan_ld_cleanup - Clean up link descriptors
- * @chan : Freescale DMA channel
+ * @desc: descriptor to cleanup and free
  *
- * This function clean up the ld_queue of DMA channel.
+ * This function is used on a descriptor which has been executed by the DMA
+ * controller. It will run any callbacks, submit any dependencies, and then
+ * free the descriptor.
  */
-static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
+static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
+                                     struct fsl_desc_sw *desc)
 {
-       struct fsl_desc_sw *desc, *_desc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-
-       dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie);
-       list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
-               dma_async_tx_callback callback;
-               void *callback_param;
-
-               if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS)
-                       break;
+       struct dma_async_tx_descriptor *txd = &desc->async_tx;
+       struct device *dev = chan->common.device->dev;
+       dma_addr_t src = get_desc_src(chan, desc);
+       dma_addr_t dst = get_desc_dst(chan, desc);
+       u32 len = get_desc_cnt(chan, desc);
+
+       /* Run the link descriptor callback function */
+       if (txd->callback) {
+#ifdef FSL_DMA_LD_DEBUG
+               chan_dbg(chan, "LD %p callback\n", desc);
+#endif
+               txd->callback(txd->callback_param);
+       }
 
-               /* Remove from the list of running transactions */
-               list_del(&desc->node);
+       /* Run any dependencies */
+       dma_run_dependencies(txd);
 
-               /* Run the link descriptor callback function */
-               callback = desc->async_tx.callback;
-               callback_param = desc->async_tx.callback_param;
-               if (callback) {
-                       spin_unlock_irqrestore(&chan->desc_lock, flags);
-                       dev_dbg(chan->dev, "LD %p callback\n", desc);
-                       callback(callback_param);
-                       spin_lock_irqsave(&chan->desc_lock, flags);
-               }
+       /* Unmap the dst buffer, if requested */
+       if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+               if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+                       dma_unmap_single(dev, dst, len, DMA_FROM_DEVICE);
+               else
+                       dma_unmap_page(dev, dst, len, DMA_FROM_DEVICE);
+       }
 
-               /* Run any dependencies, then free the descriptor */
-               dma_run_dependencies(&desc->async_tx);
-               dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+       /* Unmap the src buffer, if requested */
+       if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+               if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+                       dma_unmap_single(dev, src, len, DMA_TO_DEVICE);
+               else
+                       dma_unmap_page(dev, src, len, DMA_TO_DEVICE);
        }
 
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
+#ifdef FSL_DMA_LD_DEBUG
+       chan_dbg(chan, "LD %p free\n", desc);
+#endif
+       dma_pool_free(chan->desc_pool, desc, txd->phys);
 }
 
 /**
  * fsl_chan_xfer_ld_queue - transfer any pending transactions
  * @chan : Freescale DMA channel
  *
- * This will make sure that any pending transactions will be run.
- * If the DMA controller is idle, it will be started. Otherwise,
- * the DMA controller's interrupt handler will start any pending
- * transactions when it becomes idle.
+ * HARDWARE STATE: idle
+ * LOCKING: must hold chan->desc_lock
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
        struct fsl_desc_sw *desc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
 
        /*
         * If the list of pending descriptors is empty, then we
         * don't need to do any work at all
         */
        if (list_empty(&chan->ld_pending)) {
-               dev_dbg(chan->dev, "no pending LDs\n");
-               goto out_unlock;
+               chan_dbg(chan, "no pending LDs\n");
+               return;
        }
 
        /*
-        * The DMA controller is not idle, which means the interrupt
-        * handler will start any queued transactions when it runs
-        * at the end of the current transaction
+        * The DMA controller is not idle, which means that the interrupt
+        * handler will start any queued transactions when it runs after
+        * this transaction finishes
         */
-       if (!dma_is_idle(chan)) {
-               dev_dbg(chan->dev, "DMA controller still busy\n");
-               goto out_unlock;
+       if (!chan->idle) {
+               chan_dbg(chan, "DMA controller still busy\n");
+               return;
        }
 
-       /*
-        * TODO:
-        * make sure the dma_halt() function really un-wedges the
-        * controller as much as possible
-        */
-       dma_halt(chan);
-
        /*
         * If there are some link descriptors which have not been
         * transferred, we need to start the controller
@@ -931,18 +933,32 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
         * Move all elements from the queue of pending transactions
         * onto the list of running transactions
         */
+       chan_dbg(chan, "idle, starting controller\n");
        desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
        list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
 
+       /*
+        * The 85xx DMA controller doesn't clear the channel start bit
+        * automatically at the end of a transfer. Therefore we must clear
+        * it in software before starting the transfer.
+        */
+       if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+               u32 mode;
+
+               mode = DMA_IN(chan, &chan->regs->mr, 32);
+               mode &= ~FSL_DMA_MR_CS;
+               DMA_OUT(chan, &chan->regs->mr, mode, 32);
+       }
+
        /*
         * Program the descriptor's address into the DMA controller,
         * then start the DMA transaction
         */
        set_cdar(chan, desc->async_tx.phys);
-       dma_start(chan);
+       get_cdar(chan);
 
-out_unlock:
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
+       dma_start(chan);
+       chan->idle = false;
 }
 
 /**
@@ -952,7 +968,11 @@ out_unlock:
 static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
 {
        struct fsldma_chan *chan = to_fsl_chan(dchan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chan->desc_lock, flags);
        fsl_chan_xfer_ld_queue(chan);
+       spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
@@ -964,16 +984,18 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
                                        struct dma_tx_state *txstate)
 {
        struct fsldma_chan *chan = to_fsl_chan(dchan);
-       dma_cookie_t last_used;
        dma_cookie_t last_complete;
+       dma_cookie_t last_used;
+       unsigned long flags;
 
-       fsl_chan_ld_cleanup(chan);
+       spin_lock_irqsave(&chan->desc_lock, flags);
 
-       last_used = dchan->cookie;
        last_complete = chan->completed_cookie;
+       last_used = dchan->cookie;
 
-       dma_set_tx_state(txstate, last_complete, last_used, 0);
+       spin_unlock_irqrestore(&chan->desc_lock, flags);
 
+       dma_set_tx_state(txstate, last_complete, last_used, 0);
        return dma_async_is_complete(cookie, last_complete, last_used);
 }
 
@@ -984,21 +1006,20 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
 static irqreturn_t fsldma_chan_irq(int irq, void *data)
 {
        struct fsldma_chan *chan = data;
-       int update_cookie = 0;
-       int xfer_ld_q = 0;
        u32 stat;
 
        /* save and clear the status register */
        stat = get_sr(chan);
        set_sr(chan, stat);
-       dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat);
+       chan_dbg(chan, "irq: stat = 0x%x\n", stat);
 
+       /* check that this was really our device */
        stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
        if (!stat)
                return IRQ_NONE;
 
        if (stat & FSL_DMA_SR_TE)
-               dev_err(chan->dev, "Transfer Error!\n");
+               chan_err(chan, "Transfer Error!\n");
 
        /*
         * Programming Error
@@ -1006,29 +1027,10 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
         * triger a PE interrupt.
         */
        if (stat & FSL_DMA_SR_PE) {
-               dev_dbg(chan->dev, "irq: Programming Error INT\n");
-               if (get_bcr(chan) == 0) {
-                       /* BCR register is 0, this is a DMA_INTERRUPT async_tx.
-                        * Now, update the completed cookie, and continue the
-                        * next uncompleted transfer.
-                        */
-                       update_cookie = 1;
-                       xfer_ld_q = 1;
-               }
+               chan_dbg(chan, "irq: Programming Error INT\n");
                stat &= ~FSL_DMA_SR_PE;
-       }
-
-       /*
-        * If the link descriptor segment transfer finishes,
-        * we will recycle the used descriptor.
-        */
-       if (stat & FSL_DMA_SR_EOSI) {
-               dev_dbg(chan->dev, "irq: End-of-segments INT\n");
-               dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n",
-                       (unsigned long long)get_cdar(chan),
-                       (unsigned long long)get_ndar(chan));
-               stat &= ~FSL_DMA_SR_EOSI;
-               update_cookie = 1;
+               if (get_bcr(chan) != 0)
+                       chan_err(chan, "Programming Error!\n");
        }
 
        /*
@@ -1036,10 +1038,8 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
         * and start the next transfer if it exist.
         */
        if (stat & FSL_DMA_SR_EOCDI) {
-               dev_dbg(chan->dev, "irq: End-of-Chain link INT\n");
+               chan_dbg(chan, "irq: End-of-Chain link INT\n");
                stat &= ~FSL_DMA_SR_EOCDI;
-               update_cookie = 1;
-               xfer_ld_q = 1;
        }
 
        /*
@@ -1048,27 +1048,79 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
         * prepare next transfer.
         */
        if (stat & FSL_DMA_SR_EOLNI) {
-               dev_dbg(chan->dev, "irq: End-of-link INT\n");
+               chan_dbg(chan, "irq: End-of-link INT\n");
                stat &= ~FSL_DMA_SR_EOLNI;
-               xfer_ld_q = 1;
        }
 
-       if (update_cookie)
-               fsl_dma_update_completed_cookie(chan);
-       if (xfer_ld_q)
-               fsl_chan_xfer_ld_queue(chan);
+       /* check that the DMA controller is really idle */
+       if (!dma_is_idle(chan))
+               chan_err(chan, "irq: controller not idle!\n");
+
+       /* check that we handled all of the bits */
        if (stat)
-               dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat);
+               chan_err(chan, "irq: unhandled sr 0x%08x\n", stat);
 
-       dev_dbg(chan->dev, "irq: Exit\n");
+       /*
+        * Schedule the tasklet to handle all cleanup of the current
+        * transaction. It will start a new transaction if there is
+        * one pending.
+        */
        tasklet_schedule(&chan->tasklet);
+       chan_dbg(chan, "irq: Exit\n");
        return IRQ_HANDLED;
 }
 
 static void dma_do_tasklet(unsigned long data)
 {
        struct fsldma_chan *chan = (struct fsldma_chan *)data;
-       fsl_chan_ld_cleanup(chan);
+       struct fsl_desc_sw *desc, *_desc;
+       LIST_HEAD(ld_cleanup);
+       unsigned long flags;
+
+       chan_dbg(chan, "tasklet entry\n");
+
+       spin_lock_irqsave(&chan->desc_lock, flags);
+
+       /* update the cookie if we have some descriptors to cleanup */
+       if (!list_empty(&chan->ld_running)) {
+               dma_cookie_t cookie;
+
+               desc = to_fsl_desc(chan->ld_running.prev);
+               cookie = desc->async_tx.cookie;
+
+               chan->completed_cookie = cookie;
+               chan_dbg(chan, "completed_cookie=%d\n", cookie);
+       }
+
+       /*
+        * move the descriptors to a temporary list so we can drop the lock
+        * during the entire cleanup operation
+        */
+       list_splice_tail_init(&chan->ld_running, &ld_cleanup);
+
+       /* the hardware is now idle and ready for more */
+       chan->idle = true;
+
+       /*
+        * Start any pending transactions automatically
+        *
+        * In the ideal case, we keep the DMA controller busy while we go
+        * ahead and free the descriptors below.
+        */
+       fsl_chan_xfer_ld_queue(chan);
+       spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+       /* Run the callback for each descriptor, in order */
+       list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
+
+               /* Remove from the list of transactions */
+               list_del(&desc->node);
+
+               /* Run all cleanup for this descriptor */
+               fsldma_cleanup_descriptor(chan, desc);
+       }
+
+       chan_dbg(chan, "tasklet exit\n");
 }
 
 static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
@@ -1116,7 +1168,7 @@ static void fsldma_free_irqs(struct fsldma_device *fdev)
        for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
                chan = fdev->chan[i];
                if (chan && chan->irq != NO_IRQ) {
-                       dev_dbg(fdev->dev, "free channel %d IRQ\n", chan->id);
+                       chan_dbg(chan, "free per-channel IRQ\n");
                        free_irq(chan->irq, chan);
                }
        }
@@ -1143,19 +1195,16 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
                        continue;
 
                if (chan->irq == NO_IRQ) {
-                       dev_err(fdev->dev, "no interrupts property defined for "
-                                          "DMA channel %d. Please fix your "
-                                          "device tree\n", chan->id);
+                       chan_err(chan, "interrupts property missing in device tree\n");
                        ret = -ENODEV;
                        goto out_unwind;
                }
 
-               dev_dbg(fdev->dev, "request channel %d IRQ\n", chan->id);
+               chan_dbg(chan, "request per-channel IRQ\n");
                ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED,
                                  "fsldma-chan", chan);
                if (ret) {
-                       dev_err(fdev->dev, "unable to request IRQ for DMA "
-                                          "channel %d\n", chan->id);
+                       chan_err(chan, "unable to request per-channel IRQ\n");
                        goto out_unwind;
                }
        }
@@ -1230,6 +1279,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
 
        fdev->chan[chan->id] = chan;
        tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan);
+       snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id);
 
        /* Initialize the channel */
        dma_init(chan);
@@ -1250,6 +1300,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
        spin_lock_init(&chan->desc_lock);
        INIT_LIST_HEAD(&chan->ld_pending);
        INIT_LIST_HEAD(&chan->ld_running);
+       chan->idle = true;
 
        chan->common.device = &fdev->common;
 
index ba9f403c0fbe9127441e7b92bf70c59c71cbde28..9cb5aa57c677ea982339a87bc21df0a8e4d679e0 100644 (file)
@@ -102,8 +102,8 @@ struct fsl_desc_sw {
 } __attribute__((aligned(32)));
 
 struct fsldma_chan_regs {
-       u32 mr; /* 0x00 - Mode Register */
-       u32 sr; /* 0x04 - Status Register */
+       u32 mr;         /* 0x00 - Mode Register */
+       u32 sr;         /* 0x04 - Status Register */
        u64 cdar;       /* 0x08 - Current descriptor address register */
        u64 sar;        /* 0x10 - Source Address Register */
        u64 dar;        /* 0x18 - Destination Address Register */
@@ -135,6 +135,7 @@ struct fsldma_device {
 #define FSL_DMA_CHAN_START_EXT 0x00002000
 
 struct fsldma_chan {
+       char name[8];                   /* Channel name */
        struct fsldma_chan_regs __iomem *regs;
        dma_cookie_t completed_cookie;  /* The maximum cookie completed */
        spinlock_t desc_lock;           /* Descriptor operation lock */
@@ -147,6 +148,7 @@ struct fsldma_chan {
        int id;                         /* Raw id of this channel */
        struct tasklet_struct tasklet;
        u32 feature;
+       bool idle;                      /* DMA controller is idle */
 
        void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
        void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
new file mode 100644 (file)
index 0000000..88aad4f
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Refer to drivers/dma/imx-sdma.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <mach/mxs.h>
+#include <mach/dma.h>
+#include <mach/common.h>
+
+/*
+ * NOTE: The term "PIO" throughout the mxs-dma implementation means
+ * PIO mode of mxs apbh-dma and apbx-dma.  With this working mode,
+ * dma can program the controller registers of peripheral devices.
+ */
+
+#define MXS_DMA_APBH           0
+#define MXS_DMA_APBX           1
+#define dma_is_apbh()          (mxs_dma->dev_id == MXS_DMA_APBH)
+
+#define APBH_VERSION_LATEST    3
+#define apbh_is_old()          (mxs_dma->version < APBH_VERSION_LATEST)
+
+#define HW_APBHX_CTRL0                         0x000
+#define BM_APBH_CTRL0_APB_BURST8_EN            (1 << 29)
+#define BM_APBH_CTRL0_APB_BURST_EN             (1 << 28)
+#define BP_APBH_CTRL0_CLKGATE_CHANNEL          8
+#define BP_APBH_CTRL0_RESET_CHANNEL            16
+#define HW_APBHX_CTRL1                         0x010
+#define HW_APBHX_CTRL2                         0x020
+#define HW_APBHX_CHANNEL_CTRL                  0x030
+#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL    16
+#define HW_APBH_VERSION                                (cpu_is_mx23() ? 0x3f0 : 0x800)
+#define HW_APBX_VERSION                                0x800
+#define BP_APBHX_VERSION_MAJOR                 24
+#define HW_APBHX_CHn_NXTCMDAR(n) \
+       (((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70)
+#define HW_APBHX_CHn_SEMA(n) \
+       (((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70)
+
+/*
+ * ccw bits definitions
+ *
+ * COMMAND:            0..1    (2)
+ * CHAIN:              2       (1)
+ * IRQ:                        3       (1)
+ * NAND_LOCK:          4       (1) - not implemented
+ * NAND_WAIT4READY:    5       (1) - not implemented
+ * DEC_SEM:            6       (1)
+ * WAIT4END:           7       (1)
+ * HALT_ON_TERMINATE:  8       (1)
+ * TERMINATE_FLUSH:    9       (1)
+ * RESERVED:           10..11  (2)
+ * PIO_NUM:            12..15  (4)
+ */
+#define BP_CCW_COMMAND         0
+#define BM_CCW_COMMAND         (3 << 0)
+#define CCW_CHAIN              (1 << 2)
+#define CCW_IRQ                        (1 << 3)
+#define CCW_DEC_SEM            (1 << 6)
+#define CCW_WAIT4END           (1 << 7)
+#define CCW_HALT_ON_TERM       (1 << 8)
+#define CCW_TERM_FLUSH         (1 << 9)
+#define BP_CCW_PIO_NUM         12
+#define BM_CCW_PIO_NUM         (0xf << 12)
+
+#define BF_CCW(value, field)   (((value) << BP_CCW_##field) & BM_CCW_##field)
+
+#define MXS_DMA_CMD_NO_XFER    0
+#define MXS_DMA_CMD_WRITE      1
+#define MXS_DMA_CMD_READ       2
+#define MXS_DMA_CMD_DMA_SENSE  3       /* not implemented */
+
+struct mxs_dma_ccw {
+       u32             next;
+       u16             bits;
+       u16             xfer_bytes;
+#define MAX_XFER_BYTES 0xff00
+       u32             bufaddr;
+#define MXS_PIO_WORDS  16
+       u32             pio_words[MXS_PIO_WORDS];
+};
+
+#define NUM_CCW        (int)(PAGE_SIZE / sizeof(struct mxs_dma_ccw))
+
+struct mxs_dma_chan {
+       struct mxs_dma_engine           *mxs_dma;
+       struct dma_chan                 chan;
+       struct dma_async_tx_descriptor  desc;
+       struct tasklet_struct           tasklet;
+       int                             chan_irq;
+       struct mxs_dma_ccw              *ccw;
+       dma_addr_t                      ccw_phys;
+       dma_cookie_t                    last_completed;
+       enum dma_status                 status;
+       unsigned int                    flags;
+#define MXS_DMA_SG_LOOP                        (1 << 0)
+};
+
+#define MXS_DMA_CHANNELS               16
+#define MXS_DMA_CHANNELS_MASK          0xffff
+
+struct mxs_dma_engine {
+       int                             dev_id;
+       unsigned int                    version;
+       void __iomem                    *base;
+       struct clk                      *clk;
+       struct dma_device               dma_device;
+       struct device_dma_parameters    dma_parms;
+       struct mxs_dma_chan             mxs_chans[MXS_DMA_CHANNELS];
+};
+
+static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
+{
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int chan_id = mxs_chan->chan.chan_id;
+
+       if (dma_is_apbh() && apbh_is_old())
+               writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL),
+                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+       else
+               writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL),
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+}
+
+static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
+{
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int chan_id = mxs_chan->chan.chan_id;
+
+       /* set cmd_addr up */
+       writel(mxs_chan->ccw_phys,
+               mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
+
+       /* enable apbh channel clock */
+       if (dma_is_apbh()) {
+               if (apbh_is_old())
+                       writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+                               mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+               else
+                       writel(1 << chan_id,
+                               mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+       }
+
+       /* write 1 to SEMA to kick off the channel */
+       writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id));
+}
+
+static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
+{
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int chan_id = mxs_chan->chan.chan_id;
+
+       /* disable apbh channel clock */
+       if (dma_is_apbh()) {
+               if (apbh_is_old())
+                       writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+                               mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+               else
+                       writel(1 << chan_id,
+                               mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+       }
+
+       mxs_chan->status = DMA_SUCCESS;
+}
+
+static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
+{
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int chan_id = mxs_chan->chan.chan_id;
+
+       /* freeze the channel */
+       if (dma_is_apbh() && apbh_is_old())
+               writel(1 << chan_id,
+                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+       else
+               writel(1 << chan_id,
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+
+       mxs_chan->status = DMA_PAUSED;
+}
+
+static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
+{
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int chan_id = mxs_chan->chan.chan_id;
+
+       /* unfreeze the channel */
+       if (dma_is_apbh() && apbh_is_old())
+               writel(1 << chan_id,
+                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+       else
+               writel(1 << chan_id,
+                       mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR);
+
+       mxs_chan->status = DMA_IN_PROGRESS;
+}
+
+static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
+{
+       dma_cookie_t cookie = mxs_chan->chan.cookie;
+
+       if (++cookie < 0)
+               cookie = 1;
+
+       mxs_chan->chan.cookie = cookie;
+       mxs_chan->desc.cookie = cookie;
+
+       return cookie;
+}
+
+static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct mxs_dma_chan, chan);
+}
+
+static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(tx->chan);
+
+       mxs_dma_enable_chan(mxs_chan);
+
+       return mxs_dma_assign_cookie(mxs_chan);
+}
+
+static void mxs_dma_tasklet(unsigned long data)
+{
+       struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data;
+
+       if (mxs_chan->desc.callback)
+               mxs_chan->desc.callback(mxs_chan->desc.callback_param);
+}
+
+static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
+{
+       struct mxs_dma_engine *mxs_dma = dev_id;
+       u32 stat1, stat2;
+
+       /* completion status */
+       stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1);
+       stat1 &= MXS_DMA_CHANNELS_MASK;
+       writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR);
+
+       /* error status */
+       stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2);
+       writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR);
+
+       /*
+        * When both completion and error of termination bits set at the
+        * same time, we do not take it as an error.  IOW, it only becomes
+        * an error we need to handler here in case of ether it's (1) an bus
+        * error or (2) a termination error with no completion.
+        */
+       stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */
+               (~(stat2 >> MXS_DMA_CHANNELS) & stat2 & ~stat1); /* (2) */
+
+       /* combine error and completion status for checking */
+       stat1 = (stat2 << MXS_DMA_CHANNELS) | stat1;
+       while (stat1) {
+               int channel = fls(stat1) - 1;
+               struct mxs_dma_chan *mxs_chan =
+                       &mxs_dma->mxs_chans[channel % MXS_DMA_CHANNELS];
+
+               if (channel >= MXS_DMA_CHANNELS) {
+                       dev_dbg(mxs_dma->dma_device.dev,
+                               "%s: error in channel %d\n", __func__,
+                               channel - MXS_DMA_CHANNELS);
+                       mxs_chan->status = DMA_ERROR;
+                       mxs_dma_reset_chan(mxs_chan);
+               } else {
+                       if (mxs_chan->flags & MXS_DMA_SG_LOOP)
+                               mxs_chan->status = DMA_IN_PROGRESS;
+                       else
+                               mxs_chan->status = DMA_SUCCESS;
+               }
+
+               stat1 &= ~(1 << channel);
+
+               if (mxs_chan->status == DMA_SUCCESS)
+                       mxs_chan->last_completed = mxs_chan->desc.cookie;
+
+               /* schedule tasklet on this channel */
+               tasklet_schedule(&mxs_chan->tasklet);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_data *data = chan->private;
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int ret;
+
+       if (!data)
+               return -EINVAL;
+
+       mxs_chan->chan_irq = data->chan_irq;
+
+       mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+                               &mxs_chan->ccw_phys, GFP_KERNEL);
+       if (!mxs_chan->ccw) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       memset(mxs_chan->ccw, 0, PAGE_SIZE);
+
+       ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
+                               0, "mxs-dma", mxs_dma);
+       if (ret)
+               goto err_irq;
+
+       ret = clk_enable(mxs_dma->clk);
+       if (ret)
+               goto err_clk;
+
+       mxs_dma_reset_chan(mxs_chan);
+
+       dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
+       mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
+
+       /* the descriptor is ready */
+       async_tx_ack(&mxs_chan->desc);
+
+       return 0;
+
+err_clk:
+       free_irq(mxs_chan->chan_irq, mxs_dma);
+err_irq:
+       dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+                       mxs_chan->ccw, mxs_chan->ccw_phys);
+err_alloc:
+       return ret;
+}
+
+static void mxs_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+
+       mxs_dma_disable_chan(mxs_chan);
+
+       free_irq(mxs_chan->chan_irq, mxs_dma);
+
+       dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+                       mxs_chan->ccw, mxs_chan->ccw_phys);
+
+       clk_disable(mxs_dma->clk);
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned long append)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       struct mxs_dma_ccw *ccw;
+       struct scatterlist *sg;
+       int i, j;
+       u32 *pio;
+       static int idx;
+
+       if (mxs_chan->status == DMA_IN_PROGRESS && !append)
+               return NULL;
+
+       if (sg_len + (append ? idx : 0) > NUM_CCW) {
+               dev_err(mxs_dma->dma_device.dev,
+                               "maximum number of sg exceeded: %d > %d\n",
+                               sg_len, NUM_CCW);
+               goto err_out;
+       }
+
+       mxs_chan->status = DMA_IN_PROGRESS;
+       mxs_chan->flags = 0;
+
+       /*
+        * If the sg is prepared with append flag set, the sg
+        * will be appended to the last prepared sg.
+        */
+       if (append) {
+               BUG_ON(idx < 1);
+               ccw = &mxs_chan->ccw[idx - 1];
+               ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+               ccw->bits |= CCW_CHAIN;
+               ccw->bits &= ~CCW_IRQ;
+               ccw->bits &= ~CCW_DEC_SEM;
+               ccw->bits &= ~CCW_WAIT4END;
+       } else {
+               idx = 0;
+       }
+
+       if (direction == DMA_NONE) {
+               ccw = &mxs_chan->ccw[idx++];
+               pio = (u32 *) sgl;
+
+               for (j = 0; j < sg_len;)
+                       ccw->pio_words[j++] = *pio++;
+
+               ccw->bits = 0;
+               ccw->bits |= CCW_IRQ;
+               ccw->bits |= CCW_DEC_SEM;
+               ccw->bits |= CCW_WAIT4END;
+               ccw->bits |= CCW_HALT_ON_TERM;
+               ccw->bits |= CCW_TERM_FLUSH;
+               ccw->bits |= BF_CCW(sg_len, PIO_NUM);
+               ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND);
+       } else {
+               for_each_sg(sgl, sg, sg_len, i) {
+                       if (sg->length > MAX_XFER_BYTES) {
+                               dev_err(mxs_dma->dma_device.dev, "maximum bytes for sg entry exceeded: %d > %d\n",
+                                               sg->length, MAX_XFER_BYTES);
+                               goto err_out;
+                       }
+
+                       ccw = &mxs_chan->ccw[idx++];
+
+                       ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+                       ccw->bufaddr = sg->dma_address;
+                       ccw->xfer_bytes = sg->length;
+
+                       ccw->bits = 0;
+                       ccw->bits |= CCW_CHAIN;
+                       ccw->bits |= CCW_HALT_ON_TERM;
+                       ccw->bits |= CCW_TERM_FLUSH;
+                       ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+                                       MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ,
+                                       COMMAND);
+
+                       if (i + 1 == sg_len) {
+                               ccw->bits &= ~CCW_CHAIN;
+                               ccw->bits |= CCW_IRQ;
+                               ccw->bits |= CCW_DEC_SEM;
+                               ccw->bits |= CCW_WAIT4END;
+                       }
+               }
+       }
+
+       return &mxs_chan->desc;
+
+err_out:
+       mxs_chan->status = DMA_ERROR;
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+               size_t period_len, enum dma_data_direction direction)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+       int num_periods = buf_len / period_len;
+       int i = 0, buf = 0;
+
+       if (mxs_chan->status == DMA_IN_PROGRESS)
+               return NULL;
+
+       mxs_chan->status = DMA_IN_PROGRESS;
+       mxs_chan->flags |= MXS_DMA_SG_LOOP;
+
+       if (num_periods > NUM_CCW) {
+               dev_err(mxs_dma->dma_device.dev,
+                               "maximum number of sg exceeded: %d > %d\n",
+                               num_periods, NUM_CCW);
+               goto err_out;
+       }
+
+       if (period_len > MAX_XFER_BYTES) {
+               dev_err(mxs_dma->dma_device.dev,
+                               "maximum period size exceeded: %d > %d\n",
+                               period_len, MAX_XFER_BYTES);
+               goto err_out;
+       }
+
+       while (buf < buf_len) {
+               struct mxs_dma_ccw *ccw = &mxs_chan->ccw[i];
+
+               if (i + 1 == num_periods)
+                       ccw->next = mxs_chan->ccw_phys;
+               else
+                       ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * (i + 1);
+
+               ccw->bufaddr = dma_addr;
+               ccw->xfer_bytes = period_len;
+
+               ccw->bits = 0;
+               ccw->bits |= CCW_CHAIN;
+               ccw->bits |= CCW_IRQ;
+               ccw->bits |= CCW_HALT_ON_TERM;
+               ccw->bits |= CCW_TERM_FLUSH;
+               ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+                               MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND);
+
+               dma_addr += period_len;
+               buf += period_len;
+
+               i++;
+       }
+
+       return &mxs_chan->desc;
+
+err_out:
+       mxs_chan->status = DMA_ERROR;
+       return NULL;
+}
+
+static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+               unsigned long arg)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       int ret = 0;
+
+       switch (cmd) {
+       case DMA_TERMINATE_ALL:
+               mxs_dma_disable_chan(mxs_chan);
+               break;
+       case DMA_PAUSE:
+               mxs_dma_pause_chan(mxs_chan);
+               break;
+       case DMA_RESUME:
+               mxs_dma_resume_chan(mxs_chan);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       return ret;
+}
+
+static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
+                       dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+       dma_cookie_t last_used;
+
+       last_used = chan->cookie;
+       dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0);
+
+       return mxs_chan->status;
+}
+
+static void mxs_dma_issue_pending(struct dma_chan *chan)
+{
+       /*
+        * Nothing to do. We only have a single descriptor.
+        */
+}
+
+static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
+{
+       int ret;
+
+       ret = clk_enable(mxs_dma->clk);
+       if (ret)
+               goto err_out;
+
+       ret = mxs_reset_block(mxs_dma->base);
+       if (ret)
+               goto err_out;
+
+       /* only major version matters */
+       mxs_dma->version = readl(mxs_dma->base +
+                               ((mxs_dma->dev_id == MXS_DMA_APBX) ?
+                               HW_APBX_VERSION : HW_APBH_VERSION)) >>
+                               BP_APBHX_VERSION_MAJOR;
+
+       /* enable apbh burst */
+       if (dma_is_apbh()) {
+               writel(BM_APBH_CTRL0_APB_BURST_EN,
+                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+               writel(BM_APBH_CTRL0_APB_BURST8_EN,
+                       mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+       }
+
+       /* enable irq for all the channels */
+       writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
+               mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
+
+       clk_disable(mxs_dma->clk);
+
+       return 0;
+
+err_out:
+       return ret;
+}
+
+static int __init mxs_dma_probe(struct platform_device *pdev)
+{
+       const struct platform_device_id *id_entry =
+                               platform_get_device_id(pdev);
+       struct mxs_dma_engine *mxs_dma;
+       struct resource *iores;
+       int ret, i;
+
+       mxs_dma = kzalloc(sizeof(*mxs_dma), GFP_KERNEL);
+       if (!mxs_dma)
+               return -ENOMEM;
+
+       mxs_dma->dev_id = id_entry->driver_data;
+
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!request_mem_region(iores->start, resource_size(iores),
+                               pdev->name)) {
+               ret = -EBUSY;
+               goto err_request_region;
+       }
+
+       mxs_dma->base = ioremap(iores->start, resource_size(iores));
+       if (!mxs_dma->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       mxs_dma->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mxs_dma->clk)) {
+               ret = PTR_ERR(mxs_dma->clk);
+               goto err_clk;
+       }
+
+       dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask);
+
+       INIT_LIST_HEAD(&mxs_dma->dma_device.channels);
+
+       /* Initialize channel parameters */
+       for (i = 0; i < MXS_DMA_CHANNELS; i++) {
+               struct mxs_dma_chan *mxs_chan = &mxs_dma->mxs_chans[i];
+
+               mxs_chan->mxs_dma = mxs_dma;
+               mxs_chan->chan.device = &mxs_dma->dma_device;
+
+               tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet,
+                            (unsigned long) mxs_chan);
+
+
+               /* Add the channel to mxs_chan list */
+               list_add_tail(&mxs_chan->chan.device_node,
+                       &mxs_dma->dma_device.channels);
+       }
+
+       ret = mxs_dma_init(mxs_dma);
+       if (ret)
+               goto err_init;
+
+       mxs_dma->dma_device.dev = &pdev->dev;
+
+       /* mxs_dma gets 65535 bytes maximum sg size */
+       mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms;
+       dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES);
+
+       mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources;
+       mxs_dma->dma_device.device_free_chan_resources = mxs_dma_free_chan_resources;
+       mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status;
+       mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg;
+       mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic;
+       mxs_dma->dma_device.device_control = mxs_dma_control;
+       mxs_dma->dma_device.device_issue_pending = mxs_dma_issue_pending;
+
+       ret = dma_async_device_register(&mxs_dma->dma_device);
+       if (ret) {
+               dev_err(mxs_dma->dma_device.dev, "unable to register\n");
+               goto err_init;
+       }
+
+       dev_info(mxs_dma->dma_device.dev, "initialized\n");
+
+       return 0;
+
+err_init:
+       clk_put(mxs_dma->clk);
+err_clk:
+       iounmap(mxs_dma->base);
+err_ioremap:
+       release_mem_region(iores->start, resource_size(iores));
+err_request_region:
+       kfree(mxs_dma);
+       return ret;
+}
+
+static struct platform_device_id mxs_dma_type[] = {
+       {
+               .name = "mxs-dma-apbh",
+               .driver_data = MXS_DMA_APBH,
+       }, {
+               .name = "mxs-dma-apbx",
+               .driver_data = MXS_DMA_APBX,
+       }
+};
+
+static struct platform_driver mxs_dma_driver = {
+       .driver         = {
+               .name   = "mxs-dma",
+       },
+       .id_table       = mxs_dma_type,
+};
+
+static int __init mxs_dma_module_init(void)
+{
+       return platform_driver_probe(&mxs_dma_driver, mxs_dma_probe);
+}
+subsys_initcall(mxs_dma_module_init);
index 1c38418ae61f03f4da6585d6505faadec339843f..8d8fef1480a93115ab17c51f6c97d0130b44b21d 100644 (file)
@@ -82,7 +82,7 @@ struct pch_dma_regs {
        u32     dma_sts1;
        u32     reserved2;
        u32     reserved3;
-       struct pch_dma_desc_regs desc[0];
+       struct pch_dma_desc_regs desc[MAX_CHAN_NR];
 };
 
 struct pch_dma_desc {
@@ -124,7 +124,7 @@ struct pch_dma {
        struct pci_pool         *pool;
        struct pch_dma_regs     regs;
        struct pch_dma_desc_regs ch_regs[MAX_CHAN_NR];
-       struct pch_dma_chan     channels[0];
+       struct pch_dma_chan     channels[MAX_CHAN_NR];
 };
 
 #define PCH_DMA_CTL0   0x00
@@ -366,7 +366,7 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd)
        struct pch_dma_chan *pd_chan = to_pd_chan(txd->chan);
        dma_cookie_t cookie;
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock(&pd_chan->lock);
        cookie = pdc_assign_cookie(pd_chan, desc);
 
        if (list_empty(&pd_chan->active_list)) {
@@ -376,7 +376,7 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd)
                list_add_tail(&desc->desc_node, &pd_chan->queue);
        }
 
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock(&pd_chan->lock);
        return 0;
 }
 
@@ -386,7 +386,7 @@ static struct pch_dma_desc *pdc_alloc_desc(struct dma_chan *chan, gfp_t flags)
        struct pch_dma *pd = to_pd(chan->device);
        dma_addr_t addr;
 
-       desc = pci_pool_alloc(pd->pool, GFP_KERNEL, &addr);
+       desc = pci_pool_alloc(pd->pool, flags, &addr);
        if (desc) {
                memset(desc, 0, sizeof(struct pch_dma_desc));
                INIT_LIST_HEAD(&desc->tx_list);
@@ -405,7 +405,7 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan)
        struct pch_dma_desc *ret = NULL;
        int i;
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock(&pd_chan->lock);
        list_for_each_entry_safe(desc, _d, &pd_chan->free_list, desc_node) {
                i++;
                if (async_tx_test_ack(&desc->txd)) {
@@ -415,15 +415,15 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan)
                }
                dev_dbg(chan2dev(&pd_chan->chan), "desc %p not ACKed\n", desc);
        }
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock(&pd_chan->lock);
        dev_dbg(chan2dev(&pd_chan->chan), "scanned %d descriptors\n", i);
 
        if (!ret) {
                ret = pdc_alloc_desc(&pd_chan->chan, GFP_NOIO);
                if (ret) {
-                       spin_lock_bh(&pd_chan->lock);
+                       spin_lock(&pd_chan->lock);
                        pd_chan->descs_allocated++;
-                       spin_unlock_bh(&pd_chan->lock);
+                       spin_unlock(&pd_chan->lock);
                } else {
                        dev_err(chan2dev(&pd_chan->chan),
                                "failed to alloc desc\n");
@@ -437,10 +437,10 @@ static void pdc_desc_put(struct pch_dma_chan *pd_chan,
                         struct pch_dma_desc *desc)
 {
        if (desc) {
-               spin_lock_bh(&pd_chan->lock);
+               spin_lock(&pd_chan->lock);
                list_splice_init(&desc->tx_list, &pd_chan->free_list);
                list_add(&desc->desc_node, &pd_chan->free_list);
-               spin_unlock_bh(&pd_chan->lock);
+               spin_unlock(&pd_chan->lock);
        }
 }
 
@@ -530,9 +530,9 @@ static void pd_issue_pending(struct dma_chan *chan)
        struct pch_dma_chan *pd_chan = to_pd_chan(chan);
 
        if (pdc_is_idle(pd_chan)) {
-               spin_lock_bh(&pd_chan->lock);
+               spin_lock(&pd_chan->lock);
                pdc_advance_work(pd_chan);
-               spin_unlock_bh(&pd_chan->lock);
+               spin_unlock(&pd_chan->lock);
        }
 }
 
@@ -592,7 +592,6 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan,
                        goto err_desc_get;
                }
 
-
                if (!first) {
                        first = desc;
                } else {
@@ -641,13 +640,13 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 
        spin_unlock_bh(&pd_chan->lock);
 
-
        return 0;
 }
 
 static void pdc_tasklet(unsigned long data)
 {
        struct pch_dma_chan *pd_chan = (struct pch_dma_chan *)data;
+       unsigned long flags;
 
        if (!pdc_is_idle(pd_chan)) {
                dev_err(chan2dev(&pd_chan->chan),
@@ -655,12 +654,12 @@ static void pdc_tasklet(unsigned long data)
                return;
        }
 
-       spin_lock_bh(&pd_chan->lock);
+       spin_lock_irqsave(&pd_chan->lock, flags);
        if (test_and_clear_bit(0, &pd_chan->err_status))
                pdc_handle_error(pd_chan);
        else
                pdc_advance_work(pd_chan);
-       spin_unlock_bh(&pd_chan->lock);
+       spin_unlock_irqrestore(&pd_chan->lock, flags);
 }
 
 static irqreturn_t pd_irq(int irq, void *devid)
@@ -694,6 +693,7 @@ static irqreturn_t pd_irq(int irq, void *devid)
        return ret;
 }
 
+#ifdef CONFIG_PM
 static void pch_dma_save_regs(struct pch_dma *pd)
 {
        struct pch_dma_chan *pd_chan;
@@ -771,6 +771,7 @@ static int pch_dma_resume(struct pci_dev *pdev)
 
        return 0;
 }
+#endif
 
 static int __devinit pch_dma_probe(struct pci_dev *pdev,
                                   const struct pci_device_id *id)
index 6e1d46a65d0eec5cbcd1e3d5dee89a57931effd5..af955de035f42dd4d6a96ea97c11f16295b44e7b 100644 (file)
@@ -68,6 +68,7 @@ enum d40_command {
  * @base: Pointer to memory area when the pre_alloc_lli's are not large
  * enough, IE bigger than the most common case, 1 dst and 1 src. NULL if
  * pre_alloc_lli is used.
+ * @dma_addr: DMA address, if mapped
  * @size: The size in bytes of the memory at base or the size of pre_alloc_lli.
  * @pre_alloc_lli: Pre allocated area for the most common case of transfers,
  * one buffer to one buffer.
@@ -75,6 +76,7 @@ enum d40_command {
 struct d40_lli_pool {
        void    *base;
        int      size;
+       dma_addr_t      dma_addr;
        /* Space for dst and src, plus an extra for padding */
        u8       pre_alloc_lli[3 * sizeof(struct d40_phy_lli)];
 };
@@ -94,7 +96,6 @@ struct d40_lli_pool {
  * during a transfer.
  * @node: List entry.
  * @is_in_client_list: true if the client owns this descriptor.
- * @is_hw_linked: true if this job will automatically be continued for
  * the previous one.
  *
  * This descriptor is used for both logical and physical transfers.
@@ -114,7 +115,7 @@ struct d40_desc {
        struct list_head                 node;
 
        bool                             is_in_client_list;
-       bool                             is_hw_linked;
+       bool                             cyclic;
 };
 
 /**
@@ -130,6 +131,7 @@ struct d40_desc {
  */
 struct d40_lcla_pool {
        void            *base;
+       dma_addr_t      dma_addr;
        void            *base_unaligned;
        int              pages;
        spinlock_t       lock;
@@ -303,9 +305,37 @@ struct d40_reg_val {
        unsigned int val;
 };
 
-static int d40_pool_lli_alloc(struct d40_desc *d40d,
-                             int lli_len, bool is_log)
+static struct device *chan2dev(struct d40_chan *d40c)
 {
+       return &d40c->chan.dev->device;
+}
+
+static bool chan_is_physical(struct d40_chan *chan)
+{
+       return chan->log_num == D40_PHY_CHAN;
+}
+
+static bool chan_is_logical(struct d40_chan *chan)
+{
+       return !chan_is_physical(chan);
+}
+
+static void __iomem *chan_base(struct d40_chan *chan)
+{
+       return chan->base->virtbase + D40_DREG_PCBASE +
+              chan->phy_chan->num * D40_DREG_PCDELTA;
+}
+
+#define d40_err(dev, format, arg...)           \
+       dev_err(dev, "[%s] " format, __func__, ## arg)
+
+#define chan_err(d40c, format, arg...)         \
+       d40_err(chan2dev(d40c), format, ## arg)
+
+static int d40_pool_lli_alloc(struct d40_chan *d40c, struct d40_desc *d40d,
+                             int lli_len)
+{
+       bool is_log = chan_is_logical(d40c);
        u32 align;
        void *base;
 
@@ -319,7 +349,7 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d,
                d40d->lli_pool.size = sizeof(d40d->lli_pool.pre_alloc_lli);
                d40d->lli_pool.base = NULL;
        } else {
-               d40d->lli_pool.size = ALIGN(lli_len * 2 * align, align);
+               d40d->lli_pool.size = lli_len * 2 * align;
 
                base = kmalloc(d40d->lli_pool.size + align, GFP_NOWAIT);
                d40d->lli_pool.base = base;
@@ -329,22 +359,37 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d,
        }
 
        if (is_log) {
-               d40d->lli_log.src = PTR_ALIGN((struct d40_log_lli *) base,
-                                             align);
-               d40d->lli_log.dst = PTR_ALIGN(d40d->lli_log.src + lli_len,
-                                             align);
+               d40d->lli_log.src = PTR_ALIGN(base, align);
+               d40d->lli_log.dst = d40d->lli_log.src + lli_len;
+
+               d40d->lli_pool.dma_addr = 0;
        } else {
-               d40d->lli_phy.src = PTR_ALIGN((struct d40_phy_lli *)base,
-                                             align);
-               d40d->lli_phy.dst = PTR_ALIGN(d40d->lli_phy.src + lli_len,
-                                             align);
+               d40d->lli_phy.src = PTR_ALIGN(base, align);
+               d40d->lli_phy.dst = d40d->lli_phy.src + lli_len;
+
+               d40d->lli_pool.dma_addr = dma_map_single(d40c->base->dev,
+                                                        d40d->lli_phy.src,
+                                                        d40d->lli_pool.size,
+                                                        DMA_TO_DEVICE);
+
+               if (dma_mapping_error(d40c->base->dev,
+                                     d40d->lli_pool.dma_addr)) {
+                       kfree(d40d->lli_pool.base);
+                       d40d->lli_pool.base = NULL;
+                       d40d->lli_pool.dma_addr = 0;
+                       return -ENOMEM;
+               }
        }
 
        return 0;
 }
 
-static void d40_pool_lli_free(struct d40_desc *d40d)
+static void d40_pool_lli_free(struct d40_chan *d40c, struct d40_desc *d40d)
 {
+       if (d40d->lli_pool.dma_addr)
+               dma_unmap_single(d40c->base->dev, d40d->lli_pool.dma_addr,
+                                d40d->lli_pool.size, DMA_TO_DEVICE);
+
        kfree(d40d->lli_pool.base);
        d40d->lli_pool.base = NULL;
        d40d->lli_pool.size = 0;
@@ -391,7 +436,7 @@ static int d40_lcla_free_all(struct d40_chan *d40c,
        int i;
        int ret = -EINVAL;
 
-       if (d40c->log_num == D40_PHY_CHAN)
+       if (chan_is_physical(d40c))
                return 0;
 
        spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
@@ -430,7 +475,7 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
 
                list_for_each_entry_safe(d, _d, &d40c->client, node)
                        if (async_tx_test_ack(&d->txd)) {
-                               d40_pool_lli_free(d);
+                               d40_pool_lli_free(d40c, d);
                                d40_desc_remove(d);
                                desc = d;
                                memset(desc, 0, sizeof(*desc));
@@ -450,6 +495,7 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
 static void d40_desc_free(struct d40_chan *d40c, struct d40_desc *d40d)
 {
 
+       d40_pool_lli_free(d40c, d40d);
        d40_lcla_free_all(d40c, d40d);
        kmem_cache_free(d40c->base->desc_slab, d40d);
 }
@@ -459,57 +505,128 @@ static void d40_desc_submit(struct d40_chan *d40c, struct d40_desc *desc)
        list_add_tail(&desc->node, &d40c->active);
 }
 
-static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+static void d40_phy_lli_load(struct d40_chan *chan, struct d40_desc *desc)
 {
-       int curr_lcla = -EINVAL, next_lcla;
+       struct d40_phy_lli *lli_dst = desc->lli_phy.dst;
+       struct d40_phy_lli *lli_src = desc->lli_phy.src;
+       void __iomem *base = chan_base(chan);
+
+       writel(lli_src->reg_cfg, base + D40_CHAN_REG_SSCFG);
+       writel(lli_src->reg_elt, base + D40_CHAN_REG_SSELT);
+       writel(lli_src->reg_ptr, base + D40_CHAN_REG_SSPTR);
+       writel(lli_src->reg_lnk, base + D40_CHAN_REG_SSLNK);
+
+       writel(lli_dst->reg_cfg, base + D40_CHAN_REG_SDCFG);
+       writel(lli_dst->reg_elt, base + D40_CHAN_REG_SDELT);
+       writel(lli_dst->reg_ptr, base + D40_CHAN_REG_SDPTR);
+       writel(lli_dst->reg_lnk, base + D40_CHAN_REG_SDLNK);
+}
 
-       if (d40c->log_num == D40_PHY_CHAN) {
-               d40_phy_lli_write(d40c->base->virtbase,
-                                 d40c->phy_chan->num,
-                                 d40d->lli_phy.dst,
-                                 d40d->lli_phy.src);
-               d40d->lli_current = d40d->lli_len;
-       } else {
+static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc)
+{
+       struct d40_lcla_pool *pool = &chan->base->lcla_pool;
+       struct d40_log_lli_bidir *lli = &desc->lli_log;
+       int lli_current = desc->lli_current;
+       int lli_len = desc->lli_len;
+       bool cyclic = desc->cyclic;
+       int curr_lcla = -EINVAL;
+       int first_lcla = 0;
+       bool linkback;
 
-               if ((d40d->lli_len - d40d->lli_current) > 1)
-                       curr_lcla = d40_lcla_alloc_one(d40c, d40d);
+       /*
+        * We may have partially running cyclic transfers, in case we did't get
+        * enough LCLA entries.
+        */
+       linkback = cyclic && lli_current == 0;
 
-               d40_log_lli_lcpa_write(d40c->lcpa,
-                                      &d40d->lli_log.dst[d40d->lli_current],
-                                      &d40d->lli_log.src[d40d->lli_current],
-                                      curr_lcla);
+       /*
+        * For linkback, we need one LCLA even with only one link, because we
+        * can't link back to the one in LCPA space
+        */
+       if (linkback || (lli_len - lli_current > 1)) {
+               curr_lcla = d40_lcla_alloc_one(chan, desc);
+               first_lcla = curr_lcla;
+       }
 
-               d40d->lli_current++;
-               for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) {
-                       struct d40_log_lli *lcla;
+       /*
+        * For linkback, we normally load the LCPA in the loop since we need to
+        * link it to the second LCLA and not the first.  However, if we
+        * couldn't even get a first LCLA, then we have to run in LCPA and
+        * reload manually.
+        */
+       if (!linkback || curr_lcla == -EINVAL) {
+               unsigned int flags = 0;
 
-                       if (d40d->lli_current + 1 < d40d->lli_len)
-                               next_lcla = d40_lcla_alloc_one(d40c, d40d);
-                       else
-                               next_lcla = -EINVAL;
+               if (curr_lcla == -EINVAL)
+                       flags |= LLI_TERM_INT;
 
-                       lcla = d40c->base->lcla_pool.base +
-                               d40c->phy_chan->num * 1024 +
-                               8 * curr_lcla * 2;
+               d40_log_lli_lcpa_write(chan->lcpa,
+                                      &lli->dst[lli_current],
+                                      &lli->src[lli_current],
+                                      curr_lcla,
+                                      flags);
+               lli_current++;
+       }
 
-                       d40_log_lli_lcla_write(lcla,
-                                              &d40d->lli_log.dst[d40d->lli_current],
-                                              &d40d->lli_log.src[d40d->lli_current],
-                                              next_lcla);
+       if (curr_lcla < 0)
+               goto out;
 
-                       (void) dma_map_single(d40c->base->dev, lcla,
-                                             2 * sizeof(struct d40_log_lli),
-                                             DMA_TO_DEVICE);
+       for (; lli_current < lli_len; lli_current++) {
+               unsigned int lcla_offset = chan->phy_chan->num * 1024 +
+                                          8 * curr_lcla * 2;
+               struct d40_log_lli *lcla = pool->base + lcla_offset;
+               unsigned int flags = 0;
+               int next_lcla;
 
-                       curr_lcla = next_lcla;
+               if (lli_current + 1 < lli_len)
+                       next_lcla = d40_lcla_alloc_one(chan, desc);
+               else
+                       next_lcla = linkback ? first_lcla : -EINVAL;
 
-                       if (curr_lcla == -EINVAL) {
-                               d40d->lli_current++;
-                               break;
-                       }
+               if (cyclic || next_lcla == -EINVAL)
+                       flags |= LLI_TERM_INT;
+
+               if (linkback && curr_lcla == first_lcla) {
+                       /* First link goes in both LCPA and LCLA */
+                       d40_log_lli_lcpa_write(chan->lcpa,
+                                              &lli->dst[lli_current],
+                                              &lli->src[lli_current],
+                                              next_lcla, flags);
+               }
+
+               /*
+                * One unused LCLA in the cyclic case if the very first
+                * next_lcla fails...
+                */
+               d40_log_lli_lcla_write(lcla,
+                                      &lli->dst[lli_current],
+                                      &lli->src[lli_current],
+                                      next_lcla, flags);
+
+               dma_sync_single_range_for_device(chan->base->dev,
+                                       pool->dma_addr, lcla_offset,
+                                       2 * sizeof(struct d40_log_lli),
+                                       DMA_TO_DEVICE);
 
+               curr_lcla = next_lcla;
+
+               if (curr_lcla == -EINVAL || curr_lcla == first_lcla) {
+                       lli_current++;
+                       break;
                }
        }
+
+out:
+       desc->lli_current = lli_current;
+}
+
+static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+       if (chan_is_physical(d40c)) {
+               d40_phy_lli_load(d40c, d40d);
+               d40d->lli_current = d40d->lli_len;
+       } else
+               d40_log_lli_to_lcxa(d40c, d40d);
 }
 
 static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
@@ -543,18 +660,6 @@ static struct d40_desc *d40_first_queued(struct d40_chan *d40c)
        return d;
 }
 
-static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
-{
-       struct d40_desc *d;
-
-       if (list_empty(&d40c->queue))
-               return NULL;
-       list_for_each_entry(d, &d40c->queue, node)
-               if (list_is_last(&d->node, &d40c->queue))
-                       break;
-       return d;
-}
-
 static int d40_psize_2_burst_size(bool is_log, int psize)
 {
        if (is_log) {
@@ -666,9 +771,9 @@ static int d40_channel_execute_command(struct d40_chan *d40c,
                }
 
                if (i == D40_SUSPEND_MAX_IT) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s]: unable to suspend the chl %d (log: %d) status %x\n",
-                               __func__, d40c->phy_chan->num, d40c->log_num,
+                       chan_err(d40c,
+                               "unable to suspend the chl %d (log: %d) status %x\n",
+                               d40c->phy_chan->num, d40c->log_num,
                                status);
                        dump_stack();
                        ret = -EBUSY;
@@ -701,17 +806,45 @@ static void d40_term_all(struct d40_chan *d40c)
        d40c->busy = false;
 }
 
+static void __d40_config_set_event(struct d40_chan *d40c, bool enable,
+                                  u32 event, int reg)
+{
+       void __iomem *addr = chan_base(d40c) + reg;
+       int tries;
+
+       if (!enable) {
+               writel((D40_DEACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event))
+                      | ~D40_EVENTLINE_MASK(event), addr);
+               return;
+       }
+
+       /*
+        * The hardware sometimes doesn't register the enable when src and dst
+        * event lines are active on the same logical channel.  Retry to ensure
+        * it does.  Usually only one retry is sufficient.
+        */
+       tries = 100;
+       while (--tries) {
+               writel((D40_ACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event))
+                      | ~D40_EVENTLINE_MASK(event), addr);
+
+               if (readl(addr) & D40_EVENTLINE_MASK(event))
+                       break;
+       }
+
+       if (tries != 99)
+               dev_dbg(chan2dev(d40c),
+                       "[%s] workaround enable S%cLNK (%d tries)\n",
+                       __func__, reg == D40_CHAN_REG_SSLNK ? 'S' : 'D',
+                       100 - tries);
+
+       WARN_ON(!tries);
+}
+
 static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
 {
-       u32 val;
        unsigned long flags;
 
-       /* Notice, that disable requires the physical channel to be stopped */
-       if (do_enable)
-               val = D40_ACTIVATE_EVENTLINE;
-       else
-               val = D40_DEACTIVATE_EVENTLINE;
-
        spin_lock_irqsave(&d40c->phy_chan->lock, flags);
 
        /* Enable event line connected to device (or memcpy) */
@@ -719,20 +852,15 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
            (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) {
                u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
 
-               writel((val << D40_EVENTLINE_POS(event)) |
-                      ~D40_EVENTLINE_MASK(event),
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SSLNK);
+               __d40_config_set_event(d40c, do_enable, event,
+                                      D40_CHAN_REG_SSLNK);
        }
+
        if (d40c->dma_cfg.dir !=  STEDMA40_PERIPH_TO_MEM) {
                u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
 
-               writel((val << D40_EVENTLINE_POS(event)) |
-                      ~D40_EVENTLINE_MASK(event),
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SDLNK);
+               __d40_config_set_event(d40c, do_enable, event,
+                                      D40_CHAN_REG_SDLNK);
        }
 
        spin_unlock_irqrestore(&d40c->phy_chan->lock, flags);
@@ -740,15 +868,12 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable)
 
 static u32 d40_chan_has_events(struct d40_chan *d40c)
 {
+       void __iomem *chanbase = chan_base(d40c);
        u32 val;
 
-       val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                   d40c->phy_chan->num * D40_DREG_PCDELTA +
-                   D40_CHAN_REG_SSLNK);
+       val = readl(chanbase + D40_CHAN_REG_SSLNK);
+       val |= readl(chanbase + D40_CHAN_REG_SDLNK);
 
-       val |= readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                    d40c->phy_chan->num * D40_DREG_PCDELTA +
-                    D40_CHAN_REG_SDLNK);
        return val;
 }
 
@@ -771,7 +896,7 @@ static u32 d40_get_prmo(struct d40_chan *d40c)
                        = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG,
        };
 
-       if (d40c->log_num == D40_PHY_CHAN)
+       if (chan_is_physical(d40c))
                return phy_map[d40c->dma_cfg.mode_opt];
        else
                return log_map[d40c->dma_cfg.mode_opt];
@@ -785,7 +910,7 @@ static void d40_config_write(struct d40_chan *d40c)
        /* Odd addresses are even addresses + 4 */
        addr_base = (d40c->phy_chan->num % 2) * 4;
        /* Setup channel mode to logical or physical */
-       var = ((u32)(d40c->log_num != D40_PHY_CHAN) + 1) <<
+       var = ((u32)(chan_is_logical(d40c)) + 1) <<
                D40_CHAN_POS(d40c->phy_chan->num);
        writel(var, d40c->base->virtbase + D40_DREG_PRMSE + addr_base);
 
@@ -794,30 +919,18 @@ static void d40_config_write(struct d40_chan *d40c)
 
        writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base);
 
-       if (d40c->log_num != D40_PHY_CHAN) {
+       if (chan_is_logical(d40c)) {
+               int lidx = (d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS)
+                          & D40_SREG_ELEM_LOG_LIDX_MASK;
+               void __iomem *chanbase = chan_base(d40c);
+
                /* Set default config for CFG reg */
-               writel(d40c->src_def_cfg,
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SSCFG);
-               writel(d40c->dst_def_cfg,
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SDCFG);
+               writel(d40c->src_def_cfg, chanbase + D40_CHAN_REG_SSCFG);
+               writel(d40c->dst_def_cfg, chanbase + D40_CHAN_REG_SDCFG);
 
                /* Set LIDX for lcla */
-               writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
-                      D40_SREG_ELEM_LOG_LIDX_MASK,
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SDELT);
-
-               writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
-                      D40_SREG_ELEM_LOG_LIDX_MASK,
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SSELT);
-
+               writel(lidx, chanbase + D40_CHAN_REG_SSELT);
+               writel(lidx, chanbase + D40_CHAN_REG_SDELT);
        }
 }
 
@@ -825,15 +938,15 @@ static u32 d40_residue(struct d40_chan *d40c)
 {
        u32 num_elt;
 
-       if (d40c->log_num != D40_PHY_CHAN)
+       if (chan_is_logical(d40c))
                num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
                        >> D40_MEM_LCSP2_ECNT_POS;
-       else
-               num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                                d40c->phy_chan->num * D40_DREG_PCDELTA +
-                                D40_CHAN_REG_SDELT) &
-                          D40_SREG_ELEM_PHY_ECNT_MASK) >>
-                       D40_SREG_ELEM_PHY_ECNT_POS;
+       else {
+               u32 val = readl(chan_base(d40c) + D40_CHAN_REG_SDELT);
+               num_elt = (val & D40_SREG_ELEM_PHY_ECNT_MASK)
+                         >> D40_SREG_ELEM_PHY_ECNT_POS;
+       }
+
        return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
 }
 
@@ -841,20 +954,17 @@ static bool d40_tx_is_linked(struct d40_chan *d40c)
 {
        bool is_link;
 
-       if (d40c->log_num != D40_PHY_CHAN)
+       if (chan_is_logical(d40c))
                is_link = readl(&d40c->lcpa->lcsp3) &  D40_MEM_LCSP3_DLOS_MASK;
        else
-               is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                               d40c->phy_chan->num * D40_DREG_PCDELTA +
-                               D40_CHAN_REG_SDLNK) &
-                       D40_SREG_LNK_PHYS_LNK_MASK;
+               is_link = readl(chan_base(d40c) + D40_CHAN_REG_SDLNK)
+                         & D40_SREG_LNK_PHYS_LNK_MASK;
+
        return is_link;
 }
 
-static int d40_pause(struct dma_chan *chan)
+static int d40_pause(struct d40_chan *d40c)
 {
-       struct d40_chan *d40c =
-               container_of(chan, struct d40_chan, chan);
        int res = 0;
        unsigned long flags;
 
@@ -865,7 +975,7 @@ static int d40_pause(struct dma_chan *chan)
 
        res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
        if (res == 0) {
-               if (d40c->log_num != D40_PHY_CHAN) {
+               if (chan_is_logical(d40c)) {
                        d40_config_set_event(d40c, false);
                        /* Resume the other logical channels if any */
                        if (d40_chan_has_events(d40c))
@@ -878,10 +988,8 @@ static int d40_pause(struct dma_chan *chan)
        return res;
 }
 
-static int d40_resume(struct dma_chan *chan)
+static int d40_resume(struct d40_chan *d40c)
 {
-       struct d40_chan *d40c =
-               container_of(chan, struct d40_chan, chan);
        int res = 0;
        unsigned long flags;
 
@@ -891,7 +999,7 @@ static int d40_resume(struct dma_chan *chan)
        spin_lock_irqsave(&d40c->lock, flags);
 
        if (d40c->base->rev == 0)
-               if (d40c->log_num != D40_PHY_CHAN) {
+               if (chan_is_logical(d40c)) {
                        res = d40_channel_execute_command(d40c,
                                                          D40_DMA_SUSPEND_REQ);
                        goto no_suspend;
@@ -900,7 +1008,7 @@ static int d40_resume(struct dma_chan *chan)
        /* If bytes left to transfer or linked tx resume job */
        if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
 
-               if (d40c->log_num != D40_PHY_CHAN)
+               if (chan_is_logical(d40c))
                        d40_config_set_event(d40c, true);
 
                res = d40_channel_execute_command(d40c, D40_DMA_RUN);
@@ -911,75 +1019,20 @@ no_suspend:
        return res;
 }
 
-static void d40_tx_submit_log(struct d40_chan *d40c, struct d40_desc *d40d)
+static int d40_terminate_all(struct d40_chan *chan)
 {
-       /* TODO: Write */
-}
-
-static void d40_tx_submit_phy(struct d40_chan *d40c, struct d40_desc *d40d)
-{
-       struct d40_desc *d40d_prev = NULL;
-       int i;
-       u32 val;
-
-       if (!list_empty(&d40c->queue))
-               d40d_prev = d40_last_queued(d40c);
-       else if (!list_empty(&d40c->active))
-               d40d_prev = d40_first_active_get(d40c);
-
-       if (!d40d_prev)
-               return;
-
-       /* Here we try to join this job with previous jobs */
-       val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                   d40c->phy_chan->num * D40_DREG_PCDELTA +
-                   D40_CHAN_REG_SSLNK);
-
-       /* Figure out which link we're currently transmitting */
-       for (i = 0; i < d40d_prev->lli_len; i++)
-               if (val == d40d_prev->lli_phy.src[i].reg_lnk)
-                       break;
-
-       val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                   d40c->phy_chan->num * D40_DREG_PCDELTA +
-                   D40_CHAN_REG_SSELT) >> D40_SREG_ELEM_LOG_ECNT_POS;
-
-       if (i == (d40d_prev->lli_len - 1) && val > 0) {
-               /* Change the current one */
-               writel(virt_to_phys(d40d->lli_phy.src),
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SSLNK);
-               writel(virt_to_phys(d40d->lli_phy.dst),
-                      d40c->base->virtbase + D40_DREG_PCBASE +
-                      d40c->phy_chan->num * D40_DREG_PCDELTA +
-                      D40_CHAN_REG_SDLNK);
-
-               d40d->is_hw_linked = true;
-
-       } else if (i < d40d_prev->lli_len) {
-               (void) dma_unmap_single(d40c->base->dev,
-                                       virt_to_phys(d40d_prev->lli_phy.src),
-                                       d40d_prev->lli_pool.size,
-                                       DMA_TO_DEVICE);
+       unsigned long flags;
+       int ret = 0;
 
-               /* Keep the settings */
-               val = d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk &
-                       ~D40_SREG_LNK_PHYS_LNK_MASK;
-               d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk =
-                       val | virt_to_phys(d40d->lli_phy.src);
+       ret = d40_pause(chan);
+       if (!ret && chan_is_physical(chan))
+               ret = d40_channel_execute_command(chan, D40_DMA_STOP);
 
-               val = d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk &
-                       ~D40_SREG_LNK_PHYS_LNK_MASK;
-               d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk =
-                       val | virt_to_phys(d40d->lli_phy.dst);
+       spin_lock_irqsave(&chan->lock, flags);
+       d40_term_all(chan);
+       spin_unlock_irqrestore(&chan->lock, flags);
 
-               (void) dma_map_single(d40c->base->dev,
-                                     d40d_prev->lli_phy.src,
-                                     d40d_prev->lli_pool.size,
-                                     DMA_TO_DEVICE);
-               d40d->is_hw_linked = true;
-       }
+       return ret;
 }
 
 static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -990,8 +1043,6 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
        struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
        unsigned long flags;
 
-       (void) d40_pause(&d40c->chan);
-
        spin_lock_irqsave(&d40c->lock, flags);
 
        d40c->chan.cookie++;
@@ -1001,17 +1052,10 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
 
        d40d->txd.cookie = d40c->chan.cookie;
 
-       if (d40c->log_num == D40_PHY_CHAN)
-               d40_tx_submit_phy(d40c, d40d);
-       else
-               d40_tx_submit_log(d40c, d40d);
-
        d40_desc_queue(d40c, d40d);
 
        spin_unlock_irqrestore(&d40c->lock, flags);
 
-       (void) d40_resume(&d40c->chan);
-
        return tx->cookie;
 }
 
@@ -1020,7 +1064,7 @@ static int d40_start(struct d40_chan *d40c)
        if (d40c->base->rev == 0) {
                int err;
 
-               if (d40c->log_num != D40_PHY_CHAN) {
+               if (chan_is_logical(d40c)) {
                        err = d40_channel_execute_command(d40c,
                                                          D40_DMA_SUSPEND_REQ);
                        if (err)
@@ -1028,7 +1072,7 @@ static int d40_start(struct d40_chan *d40c)
                }
        }
 
-       if (d40c->log_num != D40_PHY_CHAN)
+       if (chan_is_logical(d40c))
                d40_config_set_event(d40c, true);
 
        return d40_channel_execute_command(d40c, D40_DMA_RUN);
@@ -1051,21 +1095,14 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
                /* Add to active queue */
                d40_desc_submit(d40c, d40d);
 
-               /*
-                * If this job is already linked in hw,
-                * do not submit it.
-                */
-
-               if (!d40d->is_hw_linked) {
-                       /* Initiate DMA job */
-                       d40_desc_load(d40c, d40d);
+               /* Initiate DMA job */
+               d40_desc_load(d40c, d40d);
 
-                       /* Start dma job */
-                       err = d40_start(d40c);
+               /* Start dma job */
+               err = d40_start(d40c);
 
-                       if (err)
-                               return NULL;
-               }
+               if (err)
+                       return NULL;
        }
 
        return d40d;
@@ -1082,17 +1119,36 @@ static void dma_tc_handle(struct d40_chan *d40c)
        if (d40d == NULL)
                return;
 
-       d40_lcla_free_all(d40c, d40d);
+       if (d40d->cyclic) {
+               /*
+                * If this was a paritially loaded list, we need to reloaded
+                * it, and only when the list is completed.  We need to check
+                * for done because the interrupt will hit for every link, and
+                * not just the last one.
+                */
+               if (d40d->lli_current < d40d->lli_len
+                   && !d40_tx_is_linked(d40c)
+                   && !d40_residue(d40c)) {
+                       d40_lcla_free_all(d40c, d40d);
+                       d40_desc_load(d40c, d40d);
+                       (void) d40_start(d40c);
 
-       if (d40d->lli_current < d40d->lli_len) {
-               d40_desc_load(d40c, d40d);
-               /* Start dma job */
-               (void) d40_start(d40c);
-               return;
-       }
+                       if (d40d->lli_current == d40d->lli_len)
+                               d40d->lli_current = 0;
+               }
+       } else {
+               d40_lcla_free_all(d40c, d40d);
 
-       if (d40_queue_start(d40c) == NULL)
-               d40c->busy = false;
+               if (d40d->lli_current < d40d->lli_len) {
+                       d40_desc_load(d40c, d40d);
+                       /* Start dma job */
+                       (void) d40_start(d40c);
+                       return;
+               }
+
+               if (d40_queue_start(d40c) == NULL)
+                       d40c->busy = false;
+       }
 
        d40c->pending_tx++;
        tasklet_schedule(&d40c->tasklet);
@@ -1111,11 +1167,11 @@ static void dma_tasklet(unsigned long data)
 
        /* Get first active entry from list */
        d40d = d40_first_active_get(d40c);
-
        if (d40d == NULL)
                goto err;
 
-       d40c->completed = d40d->txd.cookie;
+       if (!d40d->cyclic)
+               d40c->completed = d40d->txd.cookie;
 
        /*
         * If terminating a channel pending_tx is set to zero.
@@ -1130,16 +1186,18 @@ static void dma_tasklet(unsigned long data)
        callback = d40d->txd.callback;
        callback_param = d40d->txd.callback_param;
 
-       if (async_tx_test_ack(&d40d->txd)) {
-               d40_pool_lli_free(d40d);
-               d40_desc_remove(d40d);
-               d40_desc_free(d40c, d40d);
-       } else {
-               if (!d40d->is_in_client_list) {
+       if (!d40d->cyclic) {
+               if (async_tx_test_ack(&d40d->txd)) {
+                       d40_pool_lli_free(d40c, d40d);
                        d40_desc_remove(d40d);
-                       d40_lcla_free_all(d40c, d40d);
-                       list_add_tail(&d40d->node, &d40c->client);
-                       d40d->is_in_client_list = true;
+                       d40_desc_free(d40c, d40d);
+               } else {
+                       if (!d40d->is_in_client_list) {
+                               d40_desc_remove(d40d);
+                               d40_lcla_free_all(d40c, d40d);
+                               list_add_tail(&d40d->node, &d40c->client);
+                               d40d->is_in_client_list = true;
+                       }
                }
        }
 
@@ -1216,9 +1274,8 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data)
                if (!il[row].is_error)
                        dma_tc_handle(d40c);
                else
-                       dev_err(base->dev,
-                               "[%s] IRQ chan: %ld offset %d idx %d\n",
-                               __func__, chan, il[row].offset, idx);
+                       d40_err(base->dev, "IRQ chan: %ld offset %d idx %d\n",
+                               chan, il[row].offset, idx);
 
                spin_unlock(&d40c->lock);
        }
@@ -1237,8 +1294,7 @@ static int d40_validate_conf(struct d40_chan *d40c,
        bool is_log = conf->mode == STEDMA40_MODE_LOGICAL;
 
        if (!conf->dir) {
-               dev_err(&d40c->chan.dev->device, "[%s] Invalid direction.\n",
-                       __func__);
+               chan_err(d40c, "Invalid direction.\n");
                res = -EINVAL;
        }
 
@@ -1246,46 +1302,40 @@ static int d40_validate_conf(struct d40_chan *d40c,
            d40c->base->plat_data->dev_tx[conf->dst_dev_type] == 0 &&
            d40c->runtime_addr == 0) {
 
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Invalid TX channel address (%d)\n",
-                       __func__, conf->dst_dev_type);
+               chan_err(d40c, "Invalid TX channel address (%d)\n",
+                        conf->dst_dev_type);
                res = -EINVAL;
        }
 
        if (conf->src_dev_type != STEDMA40_DEV_SRC_MEMORY &&
            d40c->base->plat_data->dev_rx[conf->src_dev_type] == 0 &&
            d40c->runtime_addr == 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Invalid RX channel address (%d)\n",
-                       __func__, conf->src_dev_type);
+               chan_err(d40c, "Invalid RX channel address (%d)\n",
+                       conf->src_dev_type);
                res = -EINVAL;
        }
 
        if (conf->dir == STEDMA40_MEM_TO_PERIPH &&
            dst_event_group == STEDMA40_DEV_DST_MEMORY) {
-               dev_err(&d40c->chan.dev->device, "[%s] Invalid dst\n",
-                       __func__);
+               chan_err(d40c, "Invalid dst\n");
                res = -EINVAL;
        }
 
        if (conf->dir == STEDMA40_PERIPH_TO_MEM &&
            src_event_group == STEDMA40_DEV_SRC_MEMORY) {
-               dev_err(&d40c->chan.dev->device, "[%s] Invalid src\n",
-                       __func__);
+               chan_err(d40c, "Invalid src\n");
                res = -EINVAL;
        }
 
        if (src_event_group == STEDMA40_DEV_SRC_MEMORY &&
            dst_event_group == STEDMA40_DEV_DST_MEMORY && is_log) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] No event line\n", __func__);
+               chan_err(d40c, "No event line\n");
                res = -EINVAL;
        }
 
        if (conf->dir == STEDMA40_PERIPH_TO_PERIPH &&
            (src_event_group != dst_event_group)) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Invalid event group\n", __func__);
+               chan_err(d40c, "Invalid event group\n");
                res = -EINVAL;
        }
 
@@ -1294,9 +1344,7 @@ static int d40_validate_conf(struct d40_chan *d40c,
                 * DMAC HW supports it. Will be added to this driver,
                 * in case any dma client requires it.
                 */
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] periph to periph not supported\n",
-                       __func__);
+               chan_err(d40c, "periph to periph not supported\n");
                res = -EINVAL;
        }
 
@@ -1309,9 +1357,7 @@ static int d40_validate_conf(struct d40_chan *d40c,
                 * src (burst x width) == dst (burst x width)
                 */
 
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] src (burst x width) != dst (burst x width)\n",
-                       __func__);
+               chan_err(d40c, "src (burst x width) != dst (burst x width)\n");
                res = -EINVAL;
        }
 
@@ -1514,8 +1560,7 @@ static int d40_config_memcpy(struct d40_chan *d40c)
                   dma_has_cap(DMA_SLAVE, cap)) {
                d40c->dma_cfg = *d40c->base->plat_data->memcpy_conf_phy;
        } else {
-               dev_err(&d40c->chan.dev->device, "[%s] No memcpy\n",
-                       __func__);
+               chan_err(d40c, "No memcpy\n");
                return -EINVAL;
        }
 
@@ -1540,21 +1585,19 @@ static int d40_free_dma(struct d40_chan *d40c)
        /* Release client owned descriptors */
        if (!list_empty(&d40c->client))
                list_for_each_entry_safe(d, _d, &d40c->client, node) {
-                       d40_pool_lli_free(d);
+                       d40_pool_lli_free(d40c, d);
                        d40_desc_remove(d);
                        d40_desc_free(d40c, d);
                }
 
        if (phy == NULL) {
-               dev_err(&d40c->chan.dev->device, "[%s] phy == null\n",
-                       __func__);
+               chan_err(d40c, "phy == null\n");
                return -EINVAL;
        }
 
        if (phy->allocated_src == D40_ALLOC_FREE &&
            phy->allocated_dst == D40_ALLOC_FREE) {
-               dev_err(&d40c->chan.dev->device, "[%s] channel already free\n",
-                       __func__);
+               chan_err(d40c, "channel already free\n");
                return -EINVAL;
        }
 
@@ -1566,19 +1609,17 @@ static int d40_free_dma(struct d40_chan *d40c)
                event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
                is_src = true;
        } else {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unknown direction\n", __func__);
+               chan_err(d40c, "Unknown direction\n");
                return -EINVAL;
        }
 
        res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
        if (res) {
-               dev_err(&d40c->chan.dev->device, "[%s] suspend failed\n",
-                       __func__);
+               chan_err(d40c, "suspend failed\n");
                return res;
        }
 
-       if (d40c->log_num != D40_PHY_CHAN) {
+       if (chan_is_logical(d40c)) {
                /* Release logical channel, deactivate the event line */
 
                d40_config_set_event(d40c, false);
@@ -1594,9 +1635,8 @@ static int d40_free_dma(struct d40_chan *d40c)
                                res = d40_channel_execute_command(d40c,
                                                                  D40_DMA_RUN);
                                if (res) {
-                                       dev_err(&d40c->chan.dev->device,
-                                               "[%s] Executing RUN command\n",
-                                               __func__);
+                                       chan_err(d40c,
+                                               "Executing RUN command\n");
                                        return res;
                                }
                        }
@@ -1609,8 +1649,7 @@ static int d40_free_dma(struct d40_chan *d40c)
        /* Release physical channel */
        res = d40_channel_execute_command(d40c, D40_DMA_STOP);
        if (res) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Failed to stop channel\n", __func__);
+               chan_err(d40c, "Failed to stop channel\n");
                return res;
        }
        d40c->phy_chan = NULL;
@@ -1622,6 +1661,7 @@ static int d40_free_dma(struct d40_chan *d40c)
 
 static bool d40_is_paused(struct d40_chan *d40c)
 {
+       void __iomem *chanbase = chan_base(d40c);
        bool is_paused = false;
        unsigned long flags;
        void __iomem *active_reg;
@@ -1630,7 +1670,7 @@ static bool d40_is_paused(struct d40_chan *d40c)
 
        spin_lock_irqsave(&d40c->lock, flags);
 
-       if (d40c->log_num == D40_PHY_CHAN) {
+       if (chan_is_physical(d40c)) {
                if (d40c->phy_chan->num % 2 == 0)
                        active_reg = d40c->base->virtbase + D40_DREG_ACTIVE;
                else
@@ -1648,17 +1688,12 @@ static bool d40_is_paused(struct d40_chan *d40c)
        if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH ||
            d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) {
                event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
-               status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                              d40c->phy_chan->num * D40_DREG_PCDELTA +
-                              D40_CHAN_REG_SDLNK);
+               status = readl(chanbase + D40_CHAN_REG_SDLNK);
        } else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) {
                event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
-               status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-                              d40c->phy_chan->num * D40_DREG_PCDELTA +
-                              D40_CHAN_REG_SSLNK);
+               status = readl(chanbase + D40_CHAN_REG_SSLNK);
        } else {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unknown direction\n", __func__);
+               chan_err(d40c, "Unknown direction\n");
                goto _exit;
        }
 
@@ -1688,114 +1723,184 @@ static u32 stedma40_residue(struct dma_chan *chan)
        return bytes_left;
 }
 
-struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
-                                                  struct scatterlist *sgl_dst,
-                                                  struct scatterlist *sgl_src,
-                                                  unsigned int sgl_len,
-                                                  unsigned long dma_flags)
+static int
+d40_prep_sg_log(struct d40_chan *chan, struct d40_desc *desc,
+               struct scatterlist *sg_src, struct scatterlist *sg_dst,
+               unsigned int sg_len, dma_addr_t src_dev_addr,
+               dma_addr_t dst_dev_addr)
 {
-       int res;
-       struct d40_desc *d40d;
-       struct d40_chan *d40c = container_of(chan, struct d40_chan,
-                                            chan);
-       unsigned long flags;
+       struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
+       struct stedma40_half_channel_info *src_info = &cfg->src_info;
+       struct stedma40_half_channel_info *dst_info = &cfg->dst_info;
+       int ret;
 
-       if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unallocated channel.\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       ret = d40_log_sg_to_lli(sg_src, sg_len,
+                               src_dev_addr,
+                               desc->lli_log.src,
+                               chan->log_def.lcsp1,
+                               src_info->data_width,
+                               dst_info->data_width);
 
-       spin_lock_irqsave(&d40c->lock, flags);
-       d40d = d40_desc_get(d40c);
+       ret = d40_log_sg_to_lli(sg_dst, sg_len,
+                               dst_dev_addr,
+                               desc->lli_log.dst,
+                               chan->log_def.lcsp3,
+                               dst_info->data_width,
+                               src_info->data_width);
 
-       if (d40d == NULL)
+       return ret < 0 ? ret : 0;
+}
+
+static int
+d40_prep_sg_phy(struct d40_chan *chan, struct d40_desc *desc,
+               struct scatterlist *sg_src, struct scatterlist *sg_dst,
+               unsigned int sg_len, dma_addr_t src_dev_addr,
+               dma_addr_t dst_dev_addr)
+{
+       struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
+       struct stedma40_half_channel_info *src_info = &cfg->src_info;
+       struct stedma40_half_channel_info *dst_info = &cfg->dst_info;
+       unsigned long flags = 0;
+       int ret;
+
+       if (desc->cyclic)
+               flags |= LLI_CYCLIC | LLI_TERM_INT;
+
+       ret = d40_phy_sg_to_lli(sg_src, sg_len, src_dev_addr,
+                               desc->lli_phy.src,
+                               virt_to_phys(desc->lli_phy.src),
+                               chan->src_def_cfg,
+                               src_info, dst_info, flags);
+
+       ret = d40_phy_sg_to_lli(sg_dst, sg_len, dst_dev_addr,
+                               desc->lli_phy.dst,
+                               virt_to_phys(desc->lli_phy.dst),
+                               chan->dst_def_cfg,
+                               dst_info, src_info, flags);
+
+       dma_sync_single_for_device(chan->base->dev, desc->lli_pool.dma_addr,
+                                  desc->lli_pool.size, DMA_TO_DEVICE);
+
+       return ret < 0 ? ret : 0;
+}
+
+
+static struct d40_desc *
+d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg,
+             unsigned int sg_len, unsigned long dma_flags)
+{
+       struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
+       struct d40_desc *desc;
+       int ret;
+
+       desc = d40_desc_get(chan);
+       if (!desc)
+               return NULL;
+
+       desc->lli_len = d40_sg_2_dmalen(sg, sg_len, cfg->src_info.data_width,
+                                       cfg->dst_info.data_width);
+       if (desc->lli_len < 0) {
+               chan_err(chan, "Unaligned size\n");
                goto err;
+       }
 
-       d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len,
-                                       d40c->dma_cfg.src_info.data_width,
-                                       d40c->dma_cfg.dst_info.data_width);
-       if (d40d->lli_len < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unaligned size\n", __func__);
+       ret = d40_pool_lli_alloc(chan, desc, desc->lli_len);
+       if (ret < 0) {
+               chan_err(chan, "Could not allocate lli\n");
                goto err;
        }
 
-       d40d->lli_current = 0;
-       d40d->txd.flags = dma_flags;
 
-       if (d40c->log_num != D40_PHY_CHAN) {
+       desc->lli_current = 0;
+       desc->txd.flags = dma_flags;
+       desc->txd.tx_submit = d40_tx_submit;
 
-               if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s] Out of memory\n", __func__);
-                       goto err;
-               }
+       dma_async_tx_descriptor_init(&desc->txd, &chan->chan);
 
-               (void) d40_log_sg_to_lli(sgl_src,
-                                        sgl_len,
-                                        d40d->lli_log.src,
-                                        d40c->log_def.lcsp1,
-                                        d40c->dma_cfg.src_info.data_width,
-                                        d40c->dma_cfg.dst_info.data_width);
-
-               (void) d40_log_sg_to_lli(sgl_dst,
-                                        sgl_len,
-                                        d40d->lli_log.dst,
-                                        d40c->log_def.lcsp3,
-                                        d40c->dma_cfg.dst_info.data_width,
-                                        d40c->dma_cfg.src_info.data_width);
-       } else {
-               if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s] Out of memory\n", __func__);
-                       goto err;
-               }
+       return desc;
+
+err:
+       d40_desc_free(chan, desc);
+       return NULL;
+}
+
+static dma_addr_t
+d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction)
+{
+       struct stedma40_platform_data *plat = chan->base->plat_data;
+       struct stedma40_chan_cfg *cfg = &chan->dma_cfg;
+       dma_addr_t addr;
 
-               res = d40_phy_sg_to_lli(sgl_src,
-                                       sgl_len,
-                                       0,
-                                       d40d->lli_phy.src,
-                                       virt_to_phys(d40d->lli_phy.src),
-                                       d40c->src_def_cfg,
-                                       d40c->dma_cfg.src_info.data_width,
-                                       d40c->dma_cfg.dst_info.data_width,
-                                       d40c->dma_cfg.src_info.psize);
+       if (chan->runtime_addr)
+               return chan->runtime_addr;
 
-               if (res < 0)
-                       goto err;
+       if (direction == DMA_FROM_DEVICE)
+               addr = plat->dev_rx[cfg->src_dev_type];
+       else if (direction == DMA_TO_DEVICE)
+               addr = plat->dev_tx[cfg->dst_dev_type];
 
-               res = d40_phy_sg_to_lli(sgl_dst,
-                                       sgl_len,
-                                       0,
-                                       d40d->lli_phy.dst,
-                                       virt_to_phys(d40d->lli_phy.dst),
-                                       d40c->dst_def_cfg,
-                                       d40c->dma_cfg.dst_info.data_width,
-                                       d40c->dma_cfg.src_info.data_width,
-                                       d40c->dma_cfg.dst_info.psize);
+       return addr;
+}
 
-               if (res < 0)
-                       goto err;
+static struct dma_async_tx_descriptor *
+d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src,
+           struct scatterlist *sg_dst, unsigned int sg_len,
+           enum dma_data_direction direction, unsigned long dma_flags)
+{
+       struct d40_chan *chan = container_of(dchan, struct d40_chan, chan);
+       dma_addr_t src_dev_addr = 0;
+       dma_addr_t dst_dev_addr = 0;
+       struct d40_desc *desc;
+       unsigned long flags;
+       int ret;
 
-               (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
-                                     d40d->lli_pool.size, DMA_TO_DEVICE);
+       if (!chan->phy_chan) {
+               chan_err(chan, "Cannot prepare unallocated channel\n");
+               return NULL;
        }
 
-       dma_async_tx_descriptor_init(&d40d->txd, chan);
 
-       d40d->txd.tx_submit = d40_tx_submit;
+       spin_lock_irqsave(&chan->lock, flags);
 
-       spin_unlock_irqrestore(&d40c->lock, flags);
+       desc = d40_prep_desc(chan, sg_src, sg_len, dma_flags);
+       if (desc == NULL)
+               goto err;
+
+       if (sg_next(&sg_src[sg_len - 1]) == sg_src)
+               desc->cyclic = true;
+
+       if (direction != DMA_NONE) {
+               dma_addr_t dev_addr = d40_get_dev_addr(chan, direction);
+
+               if (direction == DMA_FROM_DEVICE)
+                       src_dev_addr = dev_addr;
+               else if (direction == DMA_TO_DEVICE)
+                       dst_dev_addr = dev_addr;
+       }
+
+       if (chan_is_logical(chan))
+               ret = d40_prep_sg_log(chan, desc, sg_src, sg_dst,
+                                     sg_len, src_dev_addr, dst_dev_addr);
+       else
+               ret = d40_prep_sg_phy(chan, desc, sg_src, sg_dst,
+                                     sg_len, src_dev_addr, dst_dev_addr);
+
+       if (ret) {
+               chan_err(chan, "Failed to prepare %s sg job: %d\n",
+                        chan_is_logical(chan) ? "log" : "phy", ret);
+               goto err;
+       }
+
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return &desc->txd;
 
-       return &d40d->txd;
 err:
-       if (d40d)
-               d40_desc_free(d40c, d40d);
-       spin_unlock_irqrestore(&d40c->lock, flags);
+       if (desc)
+               d40_desc_free(chan, desc);
+       spin_unlock_irqrestore(&chan->lock, flags);
        return NULL;
 }
-EXPORT_SYMBOL(stedma40_memcpy_sg);
 
 bool stedma40_filter(struct dma_chan *chan, void *data)
 {
@@ -1818,6 +1923,38 @@ bool stedma40_filter(struct dma_chan *chan, void *data)
 }
 EXPORT_SYMBOL(stedma40_filter);
 
+static void __d40_set_prio_rt(struct d40_chan *d40c, int dev_type, bool src)
+{
+       bool realtime = d40c->dma_cfg.realtime;
+       bool highprio = d40c->dma_cfg.high_priority;
+       u32 prioreg = highprio ? D40_DREG_PSEG1 : D40_DREG_PCEG1;
+       u32 rtreg = realtime ? D40_DREG_RSEG1 : D40_DREG_RCEG1;
+       u32 event = D40_TYPE_TO_EVENT(dev_type);
+       u32 group = D40_TYPE_TO_GROUP(dev_type);
+       u32 bit = 1 << event;
+
+       /* Destination event lines are stored in the upper halfword */
+       if (!src)
+               bit <<= 16;
+
+       writel(bit, d40c->base->virtbase + prioreg + group * 4);
+       writel(bit, d40c->base->virtbase + rtreg + group * 4);
+}
+
+static void d40_set_prio_realtime(struct d40_chan *d40c)
+{
+       if (d40c->base->rev < 3)
+               return;
+
+       if ((d40c->dma_cfg.dir ==  STEDMA40_PERIPH_TO_MEM) ||
+           (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
+               __d40_set_prio_rt(d40c, d40c->dma_cfg.src_dev_type, true);
+
+       if ((d40c->dma_cfg.dir ==  STEDMA40_MEM_TO_PERIPH) ||
+           (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
+               __d40_set_prio_rt(d40c, d40c->dma_cfg.dst_dev_type, false);
+}
+
 /* DMA ENGINE functions */
 static int d40_alloc_chan_resources(struct dma_chan *chan)
 {
@@ -1834,9 +1971,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
        if (!d40c->configured) {
                err = d40_config_memcpy(d40c);
                if (err) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s] Failed to configure memcpy channel\n",
-                               __func__);
+                       chan_err(d40c, "Failed to configure memcpy channel\n");
                        goto fail;
                }
        }
@@ -1844,16 +1979,17 @@ static int d40_alloc_chan_resources(struct dma_chan *chan)
 
        err = d40_allocate_channel(d40c);
        if (err) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Failed to allocate channel\n", __func__);
+               chan_err(d40c, "Failed to allocate channel\n");
                goto fail;
        }
 
        /* Fill in basic CFG register values */
        d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg,
-                   &d40c->dst_def_cfg, d40c->log_num != D40_PHY_CHAN);
+                   &d40c->dst_def_cfg, chan_is_logical(d40c));
 
-       if (d40c->log_num != D40_PHY_CHAN) {
+       d40_set_prio_realtime(d40c);
+
+       if (chan_is_logical(d40c)) {
                d40_log_cfg(&d40c->dma_cfg,
                            &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
 
@@ -1886,8 +2022,7 @@ static void d40_free_chan_resources(struct dma_chan *chan)
        unsigned long flags;
 
        if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Cannot free unallocated channel\n", __func__);
+               chan_err(d40c, "Cannot free unallocated channel\n");
                return;
        }
 
@@ -1897,8 +2032,7 @@ static void d40_free_chan_resources(struct dma_chan *chan)
        err = d40_free_dma(d40c);
 
        if (err)
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Failed to free channel\n", __func__);
+               chan_err(d40c, "Failed to free channel\n");
        spin_unlock_irqrestore(&d40c->lock, flags);
 }
 
@@ -1908,251 +2042,31 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
                                                       size_t size,
                                                       unsigned long dma_flags)
 {
-       struct d40_desc *d40d;
-       struct d40_chan *d40c = container_of(chan, struct d40_chan,
-                                            chan);
-       unsigned long flags;
-
-       if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Channel is not allocated.\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
-
-       spin_lock_irqsave(&d40c->lock, flags);
-       d40d = d40_desc_get(d40c);
-
-       if (d40d == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Descriptor is NULL\n", __func__);
-               goto err;
-       }
+       struct scatterlist dst_sg;
+       struct scatterlist src_sg;
 
-       d40d->txd.flags = dma_flags;
-       d40d->lli_len = d40_size_2_dmalen(size,
-                                         d40c->dma_cfg.src_info.data_width,
-                                         d40c->dma_cfg.dst_info.data_width);
-       if (d40d->lli_len < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unaligned size\n", __func__);
-               goto err;
-       }
+       sg_init_table(&dst_sg, 1);
+       sg_init_table(&src_sg, 1);
 
+       sg_dma_address(&dst_sg) = dst;
+       sg_dma_address(&src_sg) = src;
 
-       dma_async_tx_descriptor_init(&d40d->txd, chan);
+       sg_dma_len(&dst_sg) = size;
+       sg_dma_len(&src_sg) = size;
 
-       d40d->txd.tx_submit = d40_tx_submit;
-
-       if (d40c->log_num != D40_PHY_CHAN) {
-
-               if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s] Out of memory\n", __func__);
-                       goto err;
-               }
-               d40d->lli_current = 0;
-
-               if (d40_log_buf_to_lli(d40d->lli_log.src,
-                                      src,
-                                      size,
-                                      d40c->log_def.lcsp1,
-                                      d40c->dma_cfg.src_info.data_width,
-                                      d40c->dma_cfg.dst_info.data_width,
-                                      true) == NULL)
-                       goto err;
-
-               if (d40_log_buf_to_lli(d40d->lli_log.dst,
-                                      dst,
-                                      size,
-                                      d40c->log_def.lcsp3,
-                                      d40c->dma_cfg.dst_info.data_width,
-                                      d40c->dma_cfg.src_info.data_width,
-                                      true) == NULL)
-                       goto err;
-
-       } else {
-
-               if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
-                       dev_err(&d40c->chan.dev->device,
-                               "[%s] Out of memory\n", __func__);
-                       goto err;
-               }
-
-               if (d40_phy_buf_to_lli(d40d->lli_phy.src,
-                                      src,
-                                      size,
-                                      d40c->dma_cfg.src_info.psize,
-                                      0,
-                                      d40c->src_def_cfg,
-                                      true,
-                                      d40c->dma_cfg.src_info.data_width,
-                                      d40c->dma_cfg.dst_info.data_width,
-                                      false) == NULL)
-                       goto err;
-
-               if (d40_phy_buf_to_lli(d40d->lli_phy.dst,
-                                      dst,
-                                      size,
-                                      d40c->dma_cfg.dst_info.psize,
-                                      0,
-                                      d40c->dst_def_cfg,
-                                      true,
-                                      d40c->dma_cfg.dst_info.data_width,
-                                      d40c->dma_cfg.src_info.data_width,
-                                      false) == NULL)
-                       goto err;
-
-               (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
-                                     d40d->lli_pool.size, DMA_TO_DEVICE);
-       }
-
-       spin_unlock_irqrestore(&d40c->lock, flags);
-       return &d40d->txd;
-
-err:
-       if (d40d)
-               d40_desc_free(d40c, d40d);
-       spin_unlock_irqrestore(&d40c->lock, flags);
-       return NULL;
+       return d40_prep_sg(chan, &src_sg, &dst_sg, 1, DMA_NONE, dma_flags);
 }
 
 static struct dma_async_tx_descriptor *
-d40_prep_sg(struct dma_chan *chan,
-           struct scatterlist *dst_sg, unsigned int dst_nents,
-           struct scatterlist *src_sg, unsigned int src_nents,
-           unsigned long dma_flags)
+d40_prep_memcpy_sg(struct dma_chan *chan,
+                  struct scatterlist *dst_sg, unsigned int dst_nents,
+                  struct scatterlist *src_sg, unsigned int src_nents,
+                  unsigned long dma_flags)
 {
        if (dst_nents != src_nents)
                return NULL;
 
-       return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags);
-}
-
-static int d40_prep_slave_sg_log(struct d40_desc *d40d,
-                                struct d40_chan *d40c,
-                                struct scatterlist *sgl,
-                                unsigned int sg_len,
-                                enum dma_data_direction direction,
-                                unsigned long dma_flags)
-{
-       dma_addr_t dev_addr = 0;
-       int total_size;
-
-       d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len,
-                                       d40c->dma_cfg.src_info.data_width,
-                                       d40c->dma_cfg.dst_info.data_width);
-       if (d40d->lli_len < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unaligned size\n", __func__);
-               return -EINVAL;
-       }
-
-       if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Out of memory\n", __func__);
-               return -ENOMEM;
-       }
-
-       d40d->lli_current = 0;
-
-       if (direction == DMA_FROM_DEVICE)
-               if (d40c->runtime_addr)
-                       dev_addr = d40c->runtime_addr;
-               else
-                       dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
-       else if (direction == DMA_TO_DEVICE)
-               if (d40c->runtime_addr)
-                       dev_addr = d40c->runtime_addr;
-               else
-                       dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
-
-       else
-               return -EINVAL;
-
-       total_size = d40_log_sg_to_dev(sgl, sg_len,
-                                      &d40d->lli_log,
-                                      &d40c->log_def,
-                                      d40c->dma_cfg.src_info.data_width,
-                                      d40c->dma_cfg.dst_info.data_width,
-                                      direction,
-                                      dev_addr);
-
-       if (total_size < 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
-                                struct d40_chan *d40c,
-                                struct scatterlist *sgl,
-                                unsigned int sgl_len,
-                                enum dma_data_direction direction,
-                                unsigned long dma_flags)
-{
-       dma_addr_t src_dev_addr;
-       dma_addr_t dst_dev_addr;
-       int res;
-
-       d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len,
-                                       d40c->dma_cfg.src_info.data_width,
-                                       d40c->dma_cfg.dst_info.data_width);
-       if (d40d->lli_len < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Unaligned size\n", __func__);
-               return -EINVAL;
-       }
-
-       if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Out of memory\n", __func__);
-               return -ENOMEM;
-       }
-
-       d40d->lli_current = 0;
-
-       if (direction == DMA_FROM_DEVICE) {
-               dst_dev_addr = 0;
-               if (d40c->runtime_addr)
-                       src_dev_addr = d40c->runtime_addr;
-               else
-                       src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
-       } else if (direction == DMA_TO_DEVICE) {
-               if (d40c->runtime_addr)
-                       dst_dev_addr = d40c->runtime_addr;
-               else
-                       dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
-               src_dev_addr = 0;
-       } else
-               return -EINVAL;
-
-       res = d40_phy_sg_to_lli(sgl,
-                               sgl_len,
-                               src_dev_addr,
-                               d40d->lli_phy.src,
-                               virt_to_phys(d40d->lli_phy.src),
-                               d40c->src_def_cfg,
-                               d40c->dma_cfg.src_info.data_width,
-                               d40c->dma_cfg.dst_info.data_width,
-                               d40c->dma_cfg.src_info.psize);
-       if (res < 0)
-               return res;
-
-       res = d40_phy_sg_to_lli(sgl,
-                               sgl_len,
-                               dst_dev_addr,
-                               d40d->lli_phy.dst,
-                               virt_to_phys(d40d->lli_phy.dst),
-                               d40c->dst_def_cfg,
-                               d40c->dma_cfg.dst_info.data_width,
-                               d40c->dma_cfg.src_info.data_width,
-                               d40c->dma_cfg.dst_info.psize);
-       if (res < 0)
-               return res;
-
-       (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
-                             d40d->lli_pool.size, DMA_TO_DEVICE);
-       return 0;
+       return d40_prep_sg(chan, src_sg, dst_sg, src_nents, DMA_NONE, dma_flags);
 }
 
 static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
@@ -2161,52 +2075,40 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
                                                         enum dma_data_direction direction,
                                                         unsigned long dma_flags)
 {
-       struct d40_desc *d40d;
-       struct d40_chan *d40c = container_of(chan, struct d40_chan,
-                                            chan);
-       unsigned long flags;
-       int err;
-
-       if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Cannot prepare unallocated channel\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE)
+               return NULL;
 
-       spin_lock_irqsave(&d40c->lock, flags);
-       d40d = d40_desc_get(d40c);
+       return d40_prep_sg(chan, sgl, sgl, sg_len, direction, dma_flags);
+}
 
-       if (d40d == NULL)
-               goto err;
+static struct dma_async_tx_descriptor *
+dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
+                    size_t buf_len, size_t period_len,
+                    enum dma_data_direction direction)
+{
+       unsigned int periods = buf_len / period_len;
+       struct dma_async_tx_descriptor *txd;
+       struct scatterlist *sg;
+       int i;
 
-       if (d40c->log_num != D40_PHY_CHAN)
-               err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len,
-                                           direction, dma_flags);
-       else
-               err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len,
-                                           direction, dma_flags);
-       if (err) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Failed to prepare %s slave sg job: %d\n",
-                       __func__,
-                       d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err);
-               goto err;
+       sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL);
+       for (i = 0; i < periods; i++) {
+               sg_dma_address(&sg[i]) = dma_addr;
+               sg_dma_len(&sg[i]) = period_len;
+               dma_addr += period_len;
        }
 
-       d40d->txd.flags = dma_flags;
+       sg[periods].offset = 0;
+       sg[periods].length = 0;
+       sg[periods].page_link =
+               ((unsigned long)sg | 0x01) & ~0x02;
 
-       dma_async_tx_descriptor_init(&d40d->txd, chan);
+       txd = d40_prep_sg(chan, sg, sg, periods, direction,
+                         DMA_PREP_INTERRUPT);
 
-       d40d->txd.tx_submit = d40_tx_submit;
+       kfree(sg);
 
-       spin_unlock_irqrestore(&d40c->lock, flags);
-       return &d40d->txd;
-
-err:
-       if (d40d)
-               d40_desc_free(d40c, d40d);
-       spin_unlock_irqrestore(&d40c->lock, flags);
-       return NULL;
+       return txd;
 }
 
 static enum dma_status d40_tx_status(struct dma_chan *chan,
@@ -2219,9 +2121,7 @@ static enum dma_status d40_tx_status(struct dma_chan *chan,
        int ret;
 
        if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Cannot read status of unallocated channel\n",
-                       __func__);
+               chan_err(d40c, "Cannot read status of unallocated channel\n");
                return -EINVAL;
        }
 
@@ -2245,8 +2145,7 @@ static void d40_issue_pending(struct dma_chan *chan)
        unsigned long flags;
 
        if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Channel is not allocated!\n", __func__);
+               chan_err(d40c, "Channel is not allocated!\n");
                return;
        }
 
@@ -2339,7 +2238,7 @@ static void d40_set_runtime_config(struct dma_chan *chan,
                return;
        }
 
-       if (d40c->log_num != D40_PHY_CHAN) {
+       if (chan_is_logical(d40c)) {
                if (config_maxburst >= 16)
                        psize = STEDMA40_PSIZE_LOG_16;
                else if (config_maxburst >= 8)
@@ -2372,7 +2271,7 @@ static void d40_set_runtime_config(struct dma_chan *chan,
        cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
 
        /* Fill in register values */
-       if (d40c->log_num != D40_PHY_CHAN)
+       if (chan_is_logical(d40c))
                d40_log_cfg(cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
        else
                d40_phy_cfg(cfg, &d40c->src_def_cfg,
@@ -2393,25 +2292,20 @@ static void d40_set_runtime_config(struct dma_chan *chan,
 static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                       unsigned long arg)
 {
-       unsigned long flags;
        struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
 
        if (d40c->phy_chan == NULL) {
-               dev_err(&d40c->chan.dev->device,
-                       "[%s] Channel is not allocated!\n", __func__);
+               chan_err(d40c, "Channel is not allocated!\n");
                return -EINVAL;
        }
 
        switch (cmd) {
        case DMA_TERMINATE_ALL:
-               spin_lock_irqsave(&d40c->lock, flags);
-               d40_term_all(d40c);
-               spin_unlock_irqrestore(&d40c->lock, flags);
-               return 0;
+               return d40_terminate_all(d40c);
        case DMA_PAUSE:
-               return d40_pause(chan);
+               return d40_pause(d40c);
        case DMA_RESUME:
-               return d40_resume(chan);
+               return d40_resume(d40c);
        case DMA_SLAVE_CONFIG:
                d40_set_runtime_config(chan,
                        (struct dma_slave_config *) arg);
@@ -2456,6 +2350,35 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
        }
 }
 
+static void d40_ops_init(struct d40_base *base, struct dma_device *dev)
+{
+       if (dma_has_cap(DMA_SLAVE, dev->cap_mask))
+               dev->device_prep_slave_sg = d40_prep_slave_sg;
+
+       if (dma_has_cap(DMA_MEMCPY, dev->cap_mask)) {
+               dev->device_prep_dma_memcpy = d40_prep_memcpy;
+
+               /*
+                * This controller can only access address at even
+                * 32bit boundaries, i.e. 2^2
+                */
+               dev->copy_align = 2;
+       }
+
+       if (dma_has_cap(DMA_SG, dev->cap_mask))
+               dev->device_prep_dma_sg = d40_prep_memcpy_sg;
+
+       if (dma_has_cap(DMA_CYCLIC, dev->cap_mask))
+               dev->device_prep_dma_cyclic = dma40_prep_dma_cyclic;
+
+       dev->device_alloc_chan_resources = d40_alloc_chan_resources;
+       dev->device_free_chan_resources = d40_free_chan_resources;
+       dev->device_issue_pending = d40_issue_pending;
+       dev->device_tx_status = d40_tx_status;
+       dev->device_control = d40_control;
+       dev->dev = base->dev;
+}
+
 static int __init d40_dmaengine_init(struct d40_base *base,
                                     int num_reserved_chans)
 {
@@ -2466,23 +2389,14 @@ static int __init d40_dmaengine_init(struct d40_base *base,
 
        dma_cap_zero(base->dma_slave.cap_mask);
        dma_cap_set(DMA_SLAVE, base->dma_slave.cap_mask);
+       dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask);
 
-       base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources;
-       base->dma_slave.device_free_chan_resources = d40_free_chan_resources;
-       base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
-       base->dma_slave.device_prep_dma_sg = d40_prep_sg;
-       base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
-       base->dma_slave.device_tx_status = d40_tx_status;
-       base->dma_slave.device_issue_pending = d40_issue_pending;
-       base->dma_slave.device_control = d40_control;
-       base->dma_slave.dev = base->dev;
+       d40_ops_init(base, &base->dma_slave);
 
        err = dma_async_device_register(&base->dma_slave);
 
        if (err) {
-               dev_err(base->dev,
-                       "[%s] Failed to register slave channels\n",
-                       __func__);
+               d40_err(base->dev, "Failed to register slave channels\n");
                goto failure1;
        }
 
@@ -2491,29 +2405,15 @@ static int __init d40_dmaengine_init(struct d40_base *base,
 
        dma_cap_zero(base->dma_memcpy.cap_mask);
        dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask);
-       dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
-
-       base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources;
-       base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources;
-       base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
-       base->dma_slave.device_prep_dma_sg = d40_prep_sg;
-       base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
-       base->dma_memcpy.device_tx_status = d40_tx_status;
-       base->dma_memcpy.device_issue_pending = d40_issue_pending;
-       base->dma_memcpy.device_control = d40_control;
-       base->dma_memcpy.dev = base->dev;
-       /*
-        * This controller can only access address at even
-        * 32bit boundaries, i.e. 2^2
-        */
-       base->dma_memcpy.copy_align = 2;
+       dma_cap_set(DMA_SG, base->dma_memcpy.cap_mask);
+
+       d40_ops_init(base, &base->dma_memcpy);
 
        err = dma_async_device_register(&base->dma_memcpy);
 
        if (err) {
-               dev_err(base->dev,
-                       "[%s] Failed to regsiter memcpy only channels\n",
-                       __func__);
+               d40_err(base->dev,
+                       "Failed to regsiter memcpy only channels\n");
                goto failure2;
        }
 
@@ -2523,24 +2423,15 @@ static int __init d40_dmaengine_init(struct d40_base *base,
        dma_cap_zero(base->dma_both.cap_mask);
        dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask);
        dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask);
-       dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
-
-       base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources;
-       base->dma_both.device_free_chan_resources = d40_free_chan_resources;
-       base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
-       base->dma_slave.device_prep_dma_sg = d40_prep_sg;
-       base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
-       base->dma_both.device_tx_status = d40_tx_status;
-       base->dma_both.device_issue_pending = d40_issue_pending;
-       base->dma_both.device_control = d40_control;
-       base->dma_both.dev = base->dev;
-       base->dma_both.copy_align = 2;
+       dma_cap_set(DMA_SG, base->dma_both.cap_mask);
+       dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask);
+
+       d40_ops_init(base, &base->dma_both);
        err = dma_async_device_register(&base->dma_both);
 
        if (err) {
-               dev_err(base->dev,
-                       "[%s] Failed to register logical and physical capable channels\n",
-                       __func__);
+               d40_err(base->dev,
+                       "Failed to register logical and physical capable channels\n");
                goto failure3;
        }
        return 0;
@@ -2616,9 +2507,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
                { .reg = D40_DREG_PERIPHID1, .val = 0x0000},
                /*
                 * D40_DREG_PERIPHID2 Depends on HW revision:
-                *  MOP500/HREF ED has 0x0008,
+                *  DB8500ed has 0x0008,
                 *  ? has 0x0018,
-                *  HREF V1 has 0x0028
+                *  DB8500v1 has 0x0028
+                *  DB8500v2 has 0x0038
                 */
                { .reg = D40_DREG_PERIPHID3, .val = 0x0000},
 
@@ -2642,8 +2534,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
        clk = clk_get(&pdev->dev, NULL);
 
        if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "[%s] No matching clock found\n",
-                       __func__);
+               d40_err(&pdev->dev, "No matching clock found\n");
                goto failure;
        }
 
@@ -2666,9 +2557,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) {
                if (dma_id_regs[i].val !=
                    readl(virtbase + dma_id_regs[i].reg)) {
-                       dev_err(&pdev->dev,
-                               "[%s] Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n",
-                               __func__,
+                       d40_err(&pdev->dev,
+                               "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n",
                                dma_id_regs[i].val,
                                dma_id_regs[i].reg,
                                readl(virtbase + dma_id_regs[i].reg));
@@ -2681,9 +2571,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
 
        if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) !=
            D40_HW_DESIGNER) {
-               dev_err(&pdev->dev,
-                       "[%s] Unknown designer! Got %x wanted %x\n",
-                       __func__, val & D40_DREG_PERIPHID2_DESIGNER_MASK,
+               d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n",
+                       val & D40_DREG_PERIPHID2_DESIGNER_MASK,
                        D40_HW_DESIGNER);
                goto failure;
        }
@@ -2713,7 +2602,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
                       sizeof(struct d40_chan), GFP_KERNEL);
 
        if (base == NULL) {
-               dev_err(&pdev->dev, "[%s] Out of memory\n", __func__);
+               d40_err(&pdev->dev, "Out of memory\n");
                goto failure;
        }
 
@@ -2860,6 +2749,7 @@ static void __init d40_hw_init(struct d40_base *base)
 
 static int __init d40_lcla_allocate(struct d40_base *base)
 {
+       struct d40_lcla_pool *pool = &base->lcla_pool;
        unsigned long *page_list;
        int i, j;
        int ret = 0;
@@ -2885,9 +2775,8 @@ static int __init d40_lcla_allocate(struct d40_base *base)
                                                base->lcla_pool.pages);
                if (!page_list[i]) {
 
-                       dev_err(base->dev,
-                               "[%s] Failed to allocate %d pages.\n",
-                               __func__, base->lcla_pool.pages);
+                       d40_err(base->dev, "Failed to allocate %d pages.\n",
+                               base->lcla_pool.pages);
 
                        for (j = 0; j < i; j++)
                                free_pages(page_list[j], base->lcla_pool.pages);
@@ -2925,6 +2814,15 @@ static int __init d40_lcla_allocate(struct d40_base *base)
                                                 LCLA_ALIGNMENT);
        }
 
+       pool->dma_addr = dma_map_single(base->dev, pool->base,
+                                       SZ_1K * base->num_phy_chans,
+                                       DMA_TO_DEVICE);
+       if (dma_mapping_error(base->dev, pool->dma_addr)) {
+               pool->dma_addr = 0;
+               ret = -ENOMEM;
+               goto failure;
+       }
+
        writel(virt_to_phys(base->lcla_pool.base),
               base->virtbase + D40_DREG_LCLA);
 failure:
@@ -2957,9 +2855,7 @@ static int __init d40_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcpa");
        if (!res) {
                ret = -ENOENT;
-               dev_err(&pdev->dev,
-                       "[%s] No \"lcpa\" memory resource\n",
-                       __func__);
+               d40_err(&pdev->dev, "No \"lcpa\" memory resource\n");
                goto failure;
        }
        base->lcpa_size = resource_size(res);
@@ -2968,9 +2864,9 @@ static int __init d40_probe(struct platform_device *pdev)
        if (request_mem_region(res->start, resource_size(res),
                               D40_NAME " I/O lcpa") == NULL) {
                ret = -EBUSY;
-               dev_err(&pdev->dev,
-                       "[%s] Failed to request LCPA region 0x%x-0x%x\n",
-                       __func__, res->start, res->end);
+               d40_err(&pdev->dev,
+                       "Failed to request LCPA region 0x%x-0x%x\n",
+                       res->start, res->end);
                goto failure;
        }
 
@@ -2986,16 +2882,13 @@ static int __init d40_probe(struct platform_device *pdev)
        base->lcpa_base = ioremap(res->start, resource_size(res));
        if (!base->lcpa_base) {
                ret = -ENOMEM;
-               dev_err(&pdev->dev,
-                       "[%s] Failed to ioremap LCPA region\n",
-                       __func__);
+               d40_err(&pdev->dev, "Failed to ioremap LCPA region\n");
                goto failure;
        }
 
        ret = d40_lcla_allocate(base);
        if (ret) {
-               dev_err(&pdev->dev, "[%s] Failed to allocate LCLA area\n",
-                       __func__);
+               d40_err(&pdev->dev, "Failed to allocate LCLA area\n");
                goto failure;
        }
 
@@ -3004,9 +2897,8 @@ static int __init d40_probe(struct platform_device *pdev)
        base->irq = platform_get_irq(pdev, 0);
 
        ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
-
        if (ret) {
-               dev_err(&pdev->dev, "[%s] No IRQ defined\n", __func__);
+               d40_err(&pdev->dev, "No IRQ defined\n");
                goto failure;
        }
 
@@ -3025,6 +2917,12 @@ failure:
                        kmem_cache_destroy(base->desc_slab);
                if (base->virtbase)
                        iounmap(base->virtbase);
+
+               if (base->lcla_pool.dma_addr)
+                       dma_unmap_single(base->dev, base->lcla_pool.dma_addr,
+                                        SZ_1K * base->num_phy_chans,
+                                        DMA_TO_DEVICE);
+
                if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
                        free_pages((unsigned long)base->lcla_pool.base,
                                   base->lcla_pool.pages);
@@ -3049,7 +2947,7 @@ failure:
                kfree(base);
        }
 
-       dev_err(&pdev->dev, "[%s] probe failed\n", __func__);
+       d40_err(&pdev->dev, "probe failed\n");
        return ret;
 }
 
@@ -3060,7 +2958,7 @@ static struct platform_driver d40_driver = {
        },
 };
 
-int __init stedma40_init(void)
+static int __init stedma40_init(void)
 {
        return platform_driver_probe(&d40_driver, d40_probe);
 }
index 0b096a38322dd39d74e26df6c31cfc6cc9aed848..cad9e1daedff4ec30aa6e304c2527073674fe020 100644 (file)
@@ -125,13 +125,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
 static int d40_phy_fill_lli(struct d40_phy_lli *lli,
                            dma_addr_t data,
                            u32 data_size,
-                           int psize,
                            dma_addr_t next_lli,
                            u32 reg_cfg,
-                           bool term_int,
-                           u32 data_width,
-                           bool is_device)
+                           struct stedma40_half_channel_info *info,
+                           unsigned int flags)
 {
+       bool addr_inc = flags & LLI_ADDR_INC;
+       bool term_int = flags & LLI_TERM_INT;
+       unsigned int data_width = info->data_width;
+       int psize = info->psize;
        int num_elems;
 
        if (psize == STEDMA40_PSIZE_PHY_1)
@@ -154,7 +156,7 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli,
         * Distance to next element sized entry.
         * Usually the size of the element unless you want gaps.
         */
-       if (!is_device)
+       if (addr_inc)
                lli->reg_elt |= (0x1 << data_width) <<
                        D40_SREG_ELEM_PHY_EIDX_POS;
 
@@ -198,47 +200,51 @@ static int d40_seg_size(int size, int data_width1, int data_width2)
        return seg_max;
 }
 
-struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
-                                      dma_addr_t addr,
-                                      u32 size,
-                                      int psize,
-                                      dma_addr_t lli_phys,
-                                      u32 reg_cfg,
-                                      bool term_int,
-                                      u32 data_width1,
-                                      u32 data_width2,
-                                      bool is_device)
+static struct d40_phy_lli *
+d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size,
+                  dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg,
+                  struct stedma40_half_channel_info *info,
+                  struct stedma40_half_channel_info *otherinfo,
+                  unsigned long flags)
 {
+       bool lastlink = flags & LLI_LAST_LINK;
+       bool addr_inc = flags & LLI_ADDR_INC;
+       bool term_int = flags & LLI_TERM_INT;
+       bool cyclic = flags & LLI_CYCLIC;
        int err;
        dma_addr_t next = lli_phys;
        int size_rest = size;
        int size_seg = 0;
 
+       /*
+        * This piece may be split up based on d40_seg_size(); we only want the
+        * term int on the last part.
+        */
+       if (term_int)
+               flags &= ~LLI_TERM_INT;
+
        do {
-               size_seg = d40_seg_size(size_rest, data_width1, data_width2);
+               size_seg = d40_seg_size(size_rest, info->data_width,
+                                       otherinfo->data_width);
                size_rest -= size_seg;
 
-               if (term_int && size_rest == 0)
-                       next = 0;
+               if (size_rest == 0 && term_int)
+                       flags |= LLI_TERM_INT;
+
+               if (size_rest == 0 && lastlink)
+                       next = cyclic ? first_phys : 0;
                else
                        next = ALIGN(next + sizeof(struct d40_phy_lli),
                                     D40_LLI_ALIGN);
 
-               err = d40_phy_fill_lli(lli,
-                                      addr,
-                                      size_seg,
-                                      psize,
-                                      next,
-                                      reg_cfg,
-                                      !next,
-                                      data_width1,
-                                      is_device);
+               err = d40_phy_fill_lli(lli, addr, size_seg, next,
+                                      reg_cfg, info, flags);
 
                if (err)
                        goto err;
 
                lli++;
-               if (!is_device)
+               if (addr_inc)
                        addr += size_seg;
        } while (size_rest);
 
@@ -254,39 +260,35 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
                      struct d40_phy_lli *lli_sg,
                      dma_addr_t lli_phys,
                      u32 reg_cfg,
-                     u32 data_width1,
-                     u32 data_width2,
-                     int psize)
+                     struct stedma40_half_channel_info *info,
+                     struct stedma40_half_channel_info *otherinfo,
+                     unsigned long flags)
 {
        int total_size = 0;
        int i;
        struct scatterlist *current_sg = sg;
-       dma_addr_t dst;
        struct d40_phy_lli *lli = lli_sg;
        dma_addr_t l_phys = lli_phys;
 
+       if (!target)
+               flags |= LLI_ADDR_INC;
+
        for_each_sg(sg, current_sg, sg_len, i) {
+               dma_addr_t sg_addr = sg_dma_address(current_sg);
+               unsigned int len = sg_dma_len(current_sg);
+               dma_addr_t dst = target ?: sg_addr;
 
                total_size += sg_dma_len(current_sg);
 
-               if (target)
-                       dst = target;
-               else
-                       dst = sg_phys(current_sg);
+               if (i == sg_len - 1)
+                       flags |= LLI_TERM_INT | LLI_LAST_LINK;
 
                l_phys = ALIGN(lli_phys + (lli - lli_sg) *
                               sizeof(struct d40_phy_lli), D40_LLI_ALIGN);
 
-               lli = d40_phy_buf_to_lli(lli,
-                                        dst,
-                                        sg_dma_len(current_sg),
-                                        psize,
-                                        l_phys,
-                                        reg_cfg,
-                                        sg_len - 1 == i,
-                                        data_width1,
-                                        data_width2,
-                                        target == dst);
+               lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys,
+                                        reg_cfg, info, otherinfo, flags);
+
                if (lli == NULL)
                        return -EINVAL;
        }
@@ -295,45 +297,22 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
 }
 
 
-void d40_phy_lli_write(void __iomem *virtbase,
-                      u32 phy_chan_num,
-                      struct d40_phy_lli *lli_dst,
-                      struct d40_phy_lli *lli_src)
-{
-
-       writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG);
-       writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
-       writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR);
-       writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK);
-
-       writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG);
-       writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
-       writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR);
-       writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE +
-              phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK);
-
-}
-
 /* DMA logical lli operations */
 
 static void d40_log_lli_link(struct d40_log_lli *lli_dst,
                             struct d40_log_lli *lli_src,
-                            int next)
+                            int next, unsigned int flags)
 {
+       bool interrupt = flags & LLI_TERM_INT;
        u32 slos = 0;
        u32 dlos = 0;
 
        if (next != -EINVAL) {
                slos = next * 2;
                dlos = next * 2 + 1;
-       } else {
+       }
+
+       if (interrupt) {
                lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
                lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
        }
@@ -348,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst,
 void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
                           struct d40_log_lli *lli_dst,
                           struct d40_log_lli *lli_src,
-                          int next)
+                          int next, unsigned int flags)
 {
-       d40_log_lli_link(lli_dst, lli_src, next);
+       d40_log_lli_link(lli_dst, lli_src, next, flags);
 
        writel(lli_src->lcsp02, &lcpa[0].lcsp0);
        writel(lli_src->lcsp13, &lcpa[0].lcsp1);
@@ -361,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
 void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
                           struct d40_log_lli *lli_dst,
                           struct d40_log_lli *lli_src,
-                          int next)
+                          int next, unsigned int flags)
 {
-       d40_log_lli_link(lli_dst, lli_src, next);
+       d40_log_lli_link(lli_dst, lli_src, next, flags);
 
        writel(lli_src->lcsp02, &lcla[0].lcsp02);
        writel(lli_src->lcsp13, &lcla[0].lcsp13);
@@ -375,8 +354,10 @@ static void d40_log_fill_lli(struct d40_log_lli *lli,
                             dma_addr_t data, u32 data_size,
                             u32 reg_cfg,
                             u32 data_width,
-                            bool addr_inc)
+                            unsigned int flags)
 {
+       bool addr_inc = flags & LLI_ADDR_INC;
+
        lli->lcsp13 = reg_cfg;
 
        /* The number of elements to transfer */
@@ -395,67 +376,15 @@ static void d40_log_fill_lli(struct d40_log_lli *lli,
 
 }
 
-int d40_log_sg_to_dev(struct scatterlist *sg,
-                     int sg_len,
-                     struct d40_log_lli_bidir *lli,
-                     struct d40_def_lcsp *lcsp,
-                     u32 src_data_width,
-                     u32 dst_data_width,
-                     enum dma_data_direction direction,
-                     dma_addr_t dev_addr)
-{
-       int total_size = 0;
-       struct scatterlist *current_sg = sg;
-       int i;
-       struct d40_log_lli *lli_src = lli->src;
-       struct d40_log_lli *lli_dst = lli->dst;
-
-       for_each_sg(sg, current_sg, sg_len, i) {
-               total_size += sg_dma_len(current_sg);
-
-               if (direction == DMA_TO_DEVICE) {
-                       lli_src =
-                               d40_log_buf_to_lli(lli_src,
-                                                  sg_phys(current_sg),
-                                                  sg_dma_len(current_sg),
-                                                  lcsp->lcsp1, src_data_width,
-                                                  dst_data_width,
-                                                  true);
-                       lli_dst =
-                               d40_log_buf_to_lli(lli_dst,
-                                                  dev_addr,
-                                                  sg_dma_len(current_sg),
-                                                  lcsp->lcsp3, dst_data_width,
-                                                  src_data_width,
-                                                  false);
-               } else {
-                       lli_dst =
-                               d40_log_buf_to_lli(lli_dst,
-                                                  sg_phys(current_sg),
-                                                  sg_dma_len(current_sg),
-                                                  lcsp->lcsp3, dst_data_width,
-                                                  src_data_width,
-                                                  true);
-                       lli_src =
-                               d40_log_buf_to_lli(lli_src,
-                                                  dev_addr,
-                                                  sg_dma_len(current_sg),
-                                                  lcsp->lcsp1, src_data_width,
-                                                  dst_data_width,
-                                                  false);
-               }
-       }
-       return total_size;
-}
-
-struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
+static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
                                       dma_addr_t addr,
                                       int size,
                                       u32 lcsp13, /* src or dst*/
                                       u32 data_width1,
                                       u32 data_width2,
-                                      bool addr_inc)
+                                      unsigned int flags)
 {
+       bool addr_inc = flags & LLI_ADDR_INC;
        struct d40_log_lli *lli = lli_sg;
        int size_rest = size;
        int size_seg = 0;
@@ -468,7 +397,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
                                 addr,
                                 size_seg,
                                 lcsp13, data_width1,
-                                addr_inc);
+                                flags);
                if (addr_inc)
                        addr += size_seg;
                lli++;
@@ -479,6 +408,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
 
 int d40_log_sg_to_lli(struct scatterlist *sg,
                      int sg_len,
+                     dma_addr_t dev_addr,
                      struct d40_log_lli *lli_sg,
                      u32 lcsp13, /* src or dst*/
                      u32 data_width1, u32 data_width2)
@@ -487,14 +417,24 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
        struct scatterlist *current_sg = sg;
        int i;
        struct d40_log_lli *lli = lli_sg;
+       unsigned long flags = 0;
+
+       if (!dev_addr)
+               flags |= LLI_ADDR_INC;
 
        for_each_sg(sg, current_sg, sg_len, i) {
+               dma_addr_t sg_addr = sg_dma_address(current_sg);
+               unsigned int len = sg_dma_len(current_sg);
+               dma_addr_t addr = dev_addr ?: sg_addr;
+
                total_size += sg_dma_len(current_sg);
-               lli = d40_log_buf_to_lli(lli,
-                                        sg_phys(current_sg),
-                                        sg_dma_len(current_sg),
+
+               lli = d40_log_buf_to_lli(lli, addr, len,
                                         lcsp13,
-                                        data_width1, data_width2, true);
+                                        data_width1,
+                                        data_width2,
+                                        flags);
        }
+
        return total_size;
 }
index 9cc43495bea2051292f1952b7cc0d683cbf7c915..195ee65ee7f3513111f212c3b51a69bd92d96a67 100644 (file)
 #define D40_DREG_LCEIS1                0x0B4
 #define D40_DREG_LCEIS2                0x0B8
 #define D40_DREG_LCEIS3                0x0BC
+#define D40_DREG_PSEG1         0x110
+#define D40_DREG_PSEG2         0x114
+#define D40_DREG_PSEG3         0x118
+#define D40_DREG_PSEG4         0x11C
+#define D40_DREG_PCEG1         0x120
+#define D40_DREG_PCEG2         0x124
+#define D40_DREG_PCEG3         0x128
+#define D40_DREG_PCEG4         0x12C
+#define D40_DREG_RSEG1         0x130
+#define D40_DREG_RSEG2         0x134
+#define D40_DREG_RSEG3         0x138
+#define D40_DREG_RSEG4         0x13C
+#define D40_DREG_RCEG1         0x140
+#define D40_DREG_RCEG2         0x144
+#define D40_DREG_RCEG3         0x148
+#define D40_DREG_RCEG4         0x14C
 #define D40_DREG_STFU          0xFC8
 #define D40_DREG_ICFG          0xFCC
 #define D40_DREG_PERIPHID0     0xFE0
@@ -277,6 +293,13 @@ struct d40_def_lcsp {
 
 /* Physical channels */
 
+enum d40_lli_flags {
+       LLI_ADDR_INC    = 1 << 0,
+       LLI_TERM_INT    = 1 << 1,
+       LLI_CYCLIC      = 1 << 2,
+       LLI_LAST_LINK   = 1 << 3,
+};
+
 void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
                 u32 *src_cfg,
                 u32 *dst_cfg,
@@ -292,46 +315,15 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
                      struct d40_phy_lli *lli,
                      dma_addr_t lli_phys,
                      u32 reg_cfg,
-                     u32 data_width1,
-                     u32 data_width2,
-                     int psize);
-
-struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
-                                      dma_addr_t data,
-                                      u32 data_size,
-                                      int psize,
-                                      dma_addr_t next_lli,
-                                      u32 reg_cfg,
-                                      bool term_int,
-                                      u32 data_width1,
-                                      u32 data_width2,
-                                      bool is_device);
-
-void d40_phy_lli_write(void __iomem *virtbase,
-                      u32 phy_chan_num,
-                      struct d40_phy_lli *lli_dst,
-                      struct d40_phy_lli *lli_src);
+                     struct stedma40_half_channel_info *info,
+                     struct stedma40_half_channel_info *otherinfo,
+                     unsigned long flags);
 
 /* Logical channels */
 
-struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
-                                      dma_addr_t addr,
-                                      int size,
-                                      u32 lcsp13, /* src or dst*/
-                                      u32 data_width1, u32 data_width2,
-                                      bool addr_inc);
-
-int d40_log_sg_to_dev(struct scatterlist *sg,
-                     int sg_len,
-                     struct d40_log_lli_bidir *lli,
-                     struct d40_def_lcsp *lcsp,
-                     u32 src_data_width,
-                     u32 dst_data_width,
-                     enum dma_data_direction direction,
-                     dma_addr_t dev_addr);
-
 int d40_log_sg_to_lli(struct scatterlist *sg,
                      int sg_len,
+                     dma_addr_t dev_addr,
                      struct d40_log_lli *lli_sg,
                      u32 lcsp13, /* src or dst*/
                      u32 data_width1, u32 data_width2);
@@ -339,11 +331,11 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
 void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
                            struct d40_log_lli *lli_dst,
                            struct d40_log_lli *lli_src,
-                           int next);
+                           int next, unsigned int flags);
 
 void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
                            struct d40_log_lli *lli_dst,
                            struct d40_log_lli *lli_src,
-                           int next);
+                           int next, unsigned int flags);
 
 #endif /* STE_DMA40_LLI_H */
index f69f90a61873819c7ff743f9afb93d80ed8c3116..d2c75feff7df32925bc668d01a41cc724a44c9d2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 #include <linux/timb_dma.h>
@@ -684,7 +685,7 @@ static irqreturn_t td_irq(int irq, void *devid)
 
 static int __devinit td_probe(struct platform_device *pdev)
 {
-       struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
+       struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
        struct timb_dma *td;
        struct resource *iomem;
        int irq;
index 0c56989cd9073b4d0770a5ad4d15d11a907605c1..2be6f452077257bcd7d085eea00bfda70de86e54 100644 (file)
@@ -75,7 +75,8 @@ config FIREWIRE_NOSY
          The following cards are known to be based on PCILynx or PCILynx-2:
          IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2
          (PCI card), Newer Technology FireWire 2 Go (CardBus card),
-         Apple Power Mac G3 blue & white (onboard controller).
+         Apple Power Mac G3 blue & white and G4 with PCI graphics
+         (onboard controller).
 
          To compile this driver as a module, say M here:  The module will be
          called nosy.  Source code of a userspace interface to nosy, called
index 24ff35511e2b1b6a890e7fc9f9499e75c74459d1..3c44fbc81acba5758a38b77169dfe566c9b1cfd5 100644 (file)
@@ -75,6 +75,13 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_IRMC               ((1) << 31)
 #define NODE_CAPABILITIES      0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
 
+/*
+ * IEEE-1394 specifies a default SPLIT_TIMEOUT value of 800 cycles (100 ms),
+ * but we have to make it longer because there are many devices whose firmware
+ * is just too slow for that.
+ */
+#define DEFAULT_SPLIT_TIMEOUT  (2 * 8000)
+
 #define CANON_OUI              0x000085
 
 static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
@@ -233,7 +240,7 @@ static void br_work(struct work_struct *work)
 
        /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
        if (card->reset_jiffies != 0 &&
-           time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) {
+           time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) {
                if (!schedule_delayed_work(&card->br_work, 2 * HZ))
                        fw_card_put(card);
                return;
@@ -316,7 +323,8 @@ static void bm_work(struct work_struct *work)
        irm_id   = card->irm_node->node_id;
        local_id = card->local_node->node_id;
 
-       grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8));
+       grace = time_after64(get_jiffies_64(),
+                            card->reset_jiffies + DIV_ROUND_UP(HZ, 8));
 
        if ((is_next_generation(generation, card->bm_generation) &&
             !card->bm_abdicate) ||
@@ -511,10 +519,11 @@ void fw_card_initialize(struct fw_card *card,
        card->device = device;
        card->current_tlabel = 0;
        card->tlabel_mask = 0;
-       card->split_timeout_hi = 0;
-       card->split_timeout_lo = 800 << 19;
-       card->split_timeout_cycles = 800;
-       card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10);
+       card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000;
+       card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19;
+       card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT;
+       card->split_timeout_jiffies =
+                       DIV_ROUND_UP(DEFAULT_SPLIT_TIMEOUT * HZ, 8000);
        card->color = 0;
        card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;
 
index 48ae712e21018e64cca840b3e146b728bda72f99..62ac111af2432d4f8f0c3216be5bf724343e4ea8 100644 (file)
@@ -64,6 +64,7 @@ struct client {
        struct idr resource_idr;
        struct list_head event_list;
        wait_queue_head_t wait;
+       wait_queue_head_t tx_flush_wait;
        u64 bus_reset_closure;
 
        struct fw_iso_context *iso_context;
@@ -251,6 +252,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        idr_init(&client->resource_idr);
        INIT_LIST_HEAD(&client->event_list);
        init_waitqueue_head(&client->wait);
+       init_waitqueue_head(&client->tx_flush_wait);
        INIT_LIST_HEAD(&client->phy_receiver_link);
        kref_init(&client->kref);
 
@@ -520,10 +522,6 @@ static int release_client_resource(struct client *client, u32 handle,
 static void release_transaction(struct client *client,
                                struct client_resource *resource)
 {
-       struct outbound_transaction_resource *r = container_of(resource,
-                       struct outbound_transaction_resource, resource);
-
-       fw_cancel_transaction(client->device->card, &r->transaction);
 }
 
 static void complete_transaction(struct fw_card *card, int rcode,
@@ -540,22 +538,9 @@ static void complete_transaction(struct fw_card *card, int rcode,
                memcpy(rsp->data, payload, rsp->length);
 
        spin_lock_irqsave(&client->lock, flags);
-       /*
-        * 1. If called while in shutdown, the idr tree must be left untouched.
-        *    The idr handle will be removed and the client reference will be
-        *    dropped later.
-        * 2. If the call chain was release_client_resource ->
-        *    release_transaction -> complete_transaction (instead of a normal
-        *    conclusion of the transaction), i.e. if this resource was already
-        *    unregistered from the idr, the client reference will be dropped
-        *    by release_client_resource and we must not drop it here.
-        */
-       if (!client->in_shutdown &&
-           idr_find(&client->resource_idr, e->r.resource.handle)) {
-               idr_remove(&client->resource_idr, e->r.resource.handle);
-               /* Drop the idr's reference */
-               client_put(client);
-       }
+       idr_remove(&client->resource_idr, e->r.resource.handle);
+       if (client->in_shutdown)
+               wake_up(&client->tx_flush_wait);
        spin_unlock_irqrestore(&client->lock, flags);
 
        rsp->type = FW_CDEV_EVENT_RESPONSE;
@@ -575,7 +560,7 @@ static void complete_transaction(struct fw_card *card, int rcode,
                queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
                            NULL, 0);
 
-       /* Drop the transaction callback's reference */
+       /* Drop the idr's reference */
        client_put(client);
 }
 
@@ -614,9 +599,6 @@ static int init_request(struct client *client,
        if (ret < 0)
                goto failed;
 
-       /* Get a reference for the transaction callback */
-       client_get(client);
-
        fw_send_request(client->device->card, &e->r.transaction,
                        request->tcode, destination_id, request->generation,
                        speed, request->offset, e->response.data,
@@ -1223,7 +1205,8 @@ static void iso_resource_work(struct work_struct *work)
        todo = r->todo;
        /* Allow 1000ms grace period for other reallocations. */
        if (todo == ISO_RES_ALLOC &&
-           time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
+           time_before64(get_jiffies_64(),
+                         client->device->card->reset_jiffies + HZ)) {
                schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
                skip = true;
        } else {
@@ -1678,6 +1661,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
        return ret;
 }
 
+static int is_outbound_transaction_resource(int id, void *p, void *data)
+{
+       struct client_resource *resource = p;
+
+       return resource->release == release_transaction;
+}
+
+static int has_outbound_transactions(struct client *client)
+{
+       int ret;
+
+       spin_lock_irq(&client->lock);
+       ret = idr_for_each(&client->resource_idr,
+                          is_outbound_transaction_resource, NULL);
+       spin_unlock_irq(&client->lock);
+
+       return ret;
+}
+
 static int shutdown_resource(int id, void *p, void *data)
 {
        struct client_resource *resource = p;
@@ -1713,6 +1715,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
        client->in_shutdown = true;
        spin_unlock_irq(&client->lock);
 
+       wait_event(client->tx_flush_wait, !has_outbound_transactions(client));
+
        idr_for_each(&client->resource_idr, shutdown_resource, client);
        idr_remove_all(&client->resource_idr);
        idr_destroy(&client->resource_idr);
index 6113b896e7901013d8564967e45edd5d8988c5d7..9a262439e3a7220aa8bd4712acb73dc99b63fb62 100644 (file)
@@ -747,7 +747,8 @@ static void fw_device_shutdown(struct work_struct *work)
                container_of(work, struct fw_device, work.work);
        int minor = MINOR(device->device.devt);
 
-       if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY)
+       if (time_before64(get_jiffies_64(),
+                         device->card->reset_jiffies + SHUTDOWN_DELAY)
            && !list_empty(&device->card->link)) {
                schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
                return;
@@ -954,8 +955,9 @@ static void fw_device_init(struct work_struct *work)
                        device->config_rom_retries++;
                        schedule_delayed_work(&device->work, RETRY_DELAY);
                } else {
-                       fw_notify("giving up on config rom for node id %x\n",
-                                 device->node_id);
+                       if (device->node->link_on)
+                               fw_notify("giving up on config rom for node id %x\n",
+                                         device->node_id);
                        if (device->node == device->card->root_node)
                                fw_schedule_bm_work(device->card, 0);
                        fw_device_release(&device->device);
@@ -1168,9 +1170,12 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 
        switch (event) {
        case FW_NODE_CREATED:
-       case FW_NODE_LINK_ON:
-               if (!node->link_on)
-                       break;
+               /*
+                * Attempt to scan the node, regardless whether its self ID has
+                * the L (link active) flag set or not.  Some broken devices
+                * send L=0 but have an up-and-running link; others send L=1
+                * without actually having a link.
+                */
  create:
                device = kzalloc(sizeof(*device), GFP_ATOMIC);
                if (device == NULL)
@@ -1213,6 +1218,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                break;
 
        case FW_NODE_INITIATED_RESET:
+       case FW_NODE_LINK_ON:
                device = node->data;
                if (device == NULL)
                        goto create;
@@ -1230,10 +1236,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                break;
 
        case FW_NODE_UPDATED:
-               if (!node->link_on || node->data == NULL)
+               device = node->data;
+               if (device == NULL)
                        break;
 
-               device = node->data;
                device->node_id = node->node_id;
                smp_wmb();  /* update node_id before generation */
                device->generation = card->generation;
index c8658888e67bac701df8cf603b52220f5d219009..481056df9268db5cb51979c83a337715c7c6fb42 100644 (file)
@@ -235,45 +235,45 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
 static int manage_channel(struct fw_card *card, int irm_id, int generation,
                u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
 {
-       __be32 c, all, old;
-       int i, ret = -EIO, retry = 5;
+       __be32 bit, all, old;
+       int channel, ret = -EIO, retry = 5;
 
        old = all = allocate ? cpu_to_be32(~0) : 0;
 
-       for (i = 0; i < 32; i++) {
-               if (!(channels_mask & 1 << i))
+       for (channel = 0; channel < 32; channel++) {
+               if (!(channels_mask & 1 << channel))
                        continue;
 
                ret = -EBUSY;
 
-               c = cpu_to_be32(1 << (31 - i));
-               if ((old & c) != (all & c))
+               bit = cpu_to_be32(1 << (31 - channel));
+               if ((old & bit) != (all & bit))
                        continue;
 
                data[0] = old;
-               data[1] = old ^ c;
+               data[1] = old ^ bit;
                switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
                                           irm_id, generation, SCODE_100,
                                           offset, data, 8)) {
                case RCODE_GENERATION:
                        /* A generation change frees all channels. */
-                       return allocate ? -EAGAIN : i;
+                       return allocate ? -EAGAIN : channel;
 
                case RCODE_COMPLETE:
                        if (data[0] == old)
-                               return i;
+                               return channel;
 
                        old = data[0];
 
                        /* Is the IRM 1394a-2000 compliant? */
-                       if ((data[0] & c) == (data[1] & c))
+                       if ((data[0] & bit) == (data[1] & bit))
                                continue;
 
                        /* 1394-1995 IRM, fall through to retry. */
                default:
                        if (retry) {
                                retry--;
-                               i--;
+                               channel--;
                        } else {
                                ret = -EIO;
                        }
index 09be1a635505c4737283f595ef8c5ab70fffb631..193ed9233144b458a486dfd13f7217037522efc9 100644 (file)
@@ -545,7 +545,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
         */
        smp_wmb();
        card->generation = generation;
-       card->reset_jiffies = jiffies;
+       card->reset_jiffies = get_jiffies_64();
        card->bm_node_id  = 0xffff;
        card->bm_abdicate = bm_abdicate;
        fw_schedule_bm_work(card, 0);
index bd3c61b6dd8d5a76cab9f6380fd4e4a08e959ed6..f903d7b6f34a92bca580b5ed01cf422c9a8caf7c 100644 (file)
@@ -208,9 +208,11 @@ struct fw_ohci {
        struct context at_request_ctx;
        struct context at_response_ctx;
 
+       u32 it_context_support;
        u32 it_context_mask;     /* unoccupied IT contexts */
        struct iso_context *it_context_list;
        u64 ir_context_channels; /* unoccupied channels */
+       u32 ir_context_support;
        u32 ir_context_mask;     /* unoccupied IR contexts */
        struct iso_context *ir_context_list;
        u64 mc_channels; /* channels in use by the multichannel IR context */
@@ -338,7 +340,7 @@ static void log_irqs(u32 evt)
            !(evt & OHCI1394_busReset))
                return;
 
-       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+       fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
            evt & OHCI1394_selfIDComplete       ? " selfID"             : "",
            evt & OHCI1394_RQPkt                ? " AR_req"             : "",
            evt & OHCI1394_RSPkt                ? " AR_resp"            : "",
@@ -351,6 +353,7 @@ static void log_irqs(u32 evt)
            evt & OHCI1394_cycle64Seconds       ? " cycle64Seconds"     : "",
            evt & OHCI1394_cycleInconsistent    ? " cycleInconsistent"  : "",
            evt & OHCI1394_regAccessFail        ? " regAccessFail"      : "",
+           evt & OHCI1394_unrecoverableError   ? " unrecoverableError" : "",
            evt & OHCI1394_busReset             ? " busReset"           : "",
            evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
                    OHCI1394_RSPkt | OHCI1394_reqTxComplete |
@@ -1326,21 +1329,8 @@ static int at_context_queue_packet(struct context *ctx,
                                     DESCRIPTOR_IRQ_ALWAYS |
                                     DESCRIPTOR_BRANCH_ALWAYS);
 
-       /*
-        * If the controller and packet generations don't match, we need to
-        * bail out and try again.  If IntEvent.busReset is set, the AT context
-        * is halted, so appending to the context and trying to run it is
-        * futile.  Most controllers do the right thing and just flush the AT
-        * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but
-        * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind
-        * up stalling out.  So we just bail out in software and try again
-        * later, and everyone is happy.
-        * FIXME: Test of IntEvent.busReset may no longer be necessary since we
-        *        flush AT queues in bus_reset_tasklet.
-        * FIXME: Document how the locking works.
-        */
-       if (ohci->generation != packet->generation ||
-           reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+       /* FIXME: Document how the locking works. */
+       if (ohci->generation != packet->generation) {
                if (packet->payload_mapped)
                        dma_unmap_single(ohci->card.device, payload_bus,
                                         packet->payload_length, DMA_TO_DEVICE);
@@ -1590,6 +1580,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet)
 
 }
 
+static void detect_dead_context(struct fw_ohci *ohci,
+                               const char *name, unsigned int regs)
+{
+       u32 ctl;
+
+       ctl = reg_read(ohci, CONTROL_SET(regs));
+       if (ctl & CONTEXT_DEAD) {
+#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
+               fw_error("DMA context %s has stopped, error code: %s\n",
+                        name, evts[ctl & 0x1f]);
+#else
+               fw_error("DMA context %s has stopped, error code: %#x\n",
+                        name, ctl & 0x1f);
+#endif
+       }
+}
+
+static void handle_dead_contexts(struct fw_ohci *ohci)
+{
+       unsigned int i;
+       char name[8];
+
+       detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase);
+       detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase);
+       detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase);
+       detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase);
+       for (i = 0; i < 32; ++i) {
+               if (!(ohci->it_context_support & (1 << i)))
+                       continue;
+               sprintf(name, "IT%u", i);
+               detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i));
+       }
+       for (i = 0; i < 32; ++i) {
+               if (!(ohci->ir_context_support & (1 << i)))
+                       continue;
+               sprintf(name, "IR%u", i);
+               detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i));
+       }
+       /* TODO: maybe try to flush and restart the dead contexts */
+}
+
 static u32 cycle_timer_ticks(u32 cycle_timer)
 {
        u32 ticks;
@@ -1904,6 +1935,9 @@ static irqreturn_t irq_handler(int irq, void *data)
                        fw_notify("isochronous cycle inconsistent\n");
        }
 
+       if (unlikely(event & OHCI1394_unrecoverableError))
+               handle_dead_contexts(ohci);
+
        if (event & OHCI1394_cycle64Seconds) {
                spin_lock(&ohci->lock);
                update_bus_time(ohci);
@@ -2141,7 +2175,9 @@ static int ohci_enable(struct fw_card *card,
                OHCI1394_selfIDComplete |
                OHCI1394_regAccessFail |
                OHCI1394_cycle64Seconds |
-               OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong |
+               OHCI1394_cycleInconsistent |
+               OHCI1394_unrecoverableError |
+               OHCI1394_cycleTooLong |
                OHCI1394_masterIntEnable;
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                irqs |= OHCI1394_busReset;
@@ -2657,6 +2693,10 @@ static int ohci_start_iso(struct fw_iso_context *base,
        u32 control = IR_CONTEXT_ISOCH_HEADER, match;
        int index;
 
+       /* the controller cannot start without any queued packets */
+       if (ctx->context.last->branch_address == 0)
+               return -ENODATA;
+
        switch (ctx->base.type) {
        case FW_ISO_CONTEXT_TRANSMIT:
                index = ctx - ohci->it_context_list;
@@ -2715,6 +2755,7 @@ static int ohci_stop_iso(struct fw_iso_context *base)
        }
        flush_writes(ohci);
        context_stop(&ctx->context);
+       tasklet_kill(&ctx->context.tasklet);
 
        return 0;
 }
@@ -3207,15 +3248,17 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
        ohci->ir_context_channels = ~0ULL;
-       ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+       ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
        reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
+       ohci->ir_context_mask = ohci->ir_context_support;
        ohci->n_ir = hweight32(ohci->ir_context_mask);
        size = sizeof(struct iso_context) * ohci->n_ir;
        ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
 
        reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
-       ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+       ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
        reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
+       ohci->it_context_mask = ohci->it_context_support;
        ohci->n_it = hweight32(ohci->it_context_mask);
        size = sizeof(struct iso_context) * ohci->n_it;
        ohci->it_context_list = kzalloc(size, GFP_KERNEL);
@@ -3266,7 +3309,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
  fail_disable:
        pci_disable_device(dev);
  fail_free:
-       kfree(&ohci->card);
+       kfree(ohci);
        pmac_ohci_off(dev);
  fail:
        if (err == -ENOMEM)
@@ -3310,7 +3353,7 @@ static void pci_remove(struct pci_dev *dev)
        pci_iounmap(dev, ohci->registers);
        pci_release_region(dev, 0);
        pci_disable_device(dev);
-       kfree(&ohci->card);
+       kfree(ohci);
        pmac_ohci_off(dev);
 
        fw_notify("Removed fw-ohci device.\n");
index afa576a75a8ed443273d4722c03edc2bb8c31720..77ed589b360d7dce2d7567685fa032f96f40ed54 100644 (file)
@@ -472,18 +472,12 @@ static void complete_transaction(struct fw_card *card, int rcode,
         * So this callback only sets the rcode if it hasn't already
         * been set and only does the cleanup if the transaction
         * failed and we didn't already get a status write.
-        *
-        * Here we treat RCODE_CANCELLED like RCODE_COMPLETE because some
-        * OXUF936QSE firmwares occasionally respond after Split_Timeout and
-        * complete the ORB just fine.  Note, we also get RCODE_CANCELLED
-        * from sbp2_cancel_orbs() if fw_cancel_transaction() == 0.
         */
        spin_lock_irqsave(&card->lock, flags);
 
        if (orb->rcode == -1)
                orb->rcode = rcode;
-
-       if (orb->rcode != RCODE_COMPLETE && orb->rcode != RCODE_CANCELLED) {
+       if (orb->rcode != RCODE_COMPLETE) {
                list_del(&orb->link);
                spin_unlock_irqrestore(&card->lock, flags);
 
@@ -532,7 +526,8 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
 
        list_for_each_entry_safe(orb, next, &list, link) {
                retval = 0;
-               fw_cancel_transaction(device->card, &orb->t);
+               if (fw_cancel_transaction(device->card, &orb->t) == 0)
+                       continue;
 
                orb->rcode = RCODE_CANCELLED;
                orb->callback(orb, NULL);
index 3c56afc5eb1bdbddd62a5dcb274cc1b589d9122a..b3a25a55ba231e1e422a085a323e287e88f967ac 100644 (file)
@@ -145,4 +145,16 @@ config ISCSI_IBFT
          detect iSCSI boot parameters dynamically during system boot, say Y.
          Otherwise, say N.
 
+config SIGMA
+       tristate "SigmaStudio firmware loader"
+       depends on I2C
+       select CRC32
+       default n
+       help
+         Enable helper functions for working with Analog Devices SigmaDSP
+         parts and binary firmwares produced by Analog Devices SigmaStudio.
+
+         If unsure, say N here.  Drivers that need these helpers will select
+         this option automatically.
+
 endmenu
index 20c17fca1232e7895fbd76e390583d30be32f62f..00bb0b80a79f9e8b5599568e5f750cd1c3769273 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_DMIID)           += dmi-id.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)  += iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)       += iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
+obj-$(CONFIG_SIGMA)            += sigma.o
diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c
new file mode 100644 (file)
index 0000000..c19cd2c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Load Analog Devices SigmaStudio firmware files
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/sigma.h>
+
+/* Return: 0==OK, <0==error, =1 ==no more actions */
+static int
+process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
+{
+       struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
+       size_t len = sigma_action_len(sa);
+       int ret = 0;
+
+       pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
+               sa->instr, sa->addr, len);
+
+       switch (sa->instr) {
+       case SIGMA_ACTION_WRITEXBYTES:
+       case SIGMA_ACTION_WRITESINGLE:
+       case SIGMA_ACTION_WRITESAFELOAD:
+               if (ssfw->fw->size < ssfw->pos + len)
+                       return -EINVAL;
+               ret = i2c_master_send(client, (void *)&sa->addr, len);
+               if (ret < 0)
+                       return -EINVAL;
+               break;
+
+       case SIGMA_ACTION_DELAY:
+               ret = 0;
+               udelay(len);
+               len = 0;
+               break;
+
+       case SIGMA_ACTION_END:
+               return 1;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* when arrive here ret=0 or sent data */
+       ssfw->pos += sigma_action_size(sa, len);
+       return ssfw->pos == ssfw->fw->size;
+}
+
+static int
+process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
+{
+       pr_debug("%s: processing %p\n", __func__, ssfw);
+
+       while (1) {
+               int ret = process_sigma_action(client, ssfw);
+               pr_debug("%s: action returned %i\n", __func__, ret);
+               if (ret == 1)
+                       return 0;
+               else if (ret)
+                       return ret;
+       }
+}
+
+int process_sigma_firmware(struct i2c_client *client, const char *name)
+{
+       int ret;
+       struct sigma_firmware_header *ssfw_head;
+       struct sigma_firmware ssfw;
+       const struct firmware *fw;
+       u32 crc;
+
+       pr_debug("%s: loading firmware %s\n", __func__, name);
+
+       /* first load the blob */
+       ret = request_firmware(&fw, name, &client->dev);
+       if (ret) {
+               pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
+               return ret;
+       }
+       ssfw.fw = fw;
+
+       /* then verify the header */
+       ret = -EINVAL;
+       if (fw->size < sizeof(*ssfw_head))
+               goto done;
+
+       ssfw_head = (void *)fw->data;
+       if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
+               goto done;
+
+       crc = crc32(0, fw->data, fw->size);
+       pr_debug("%s: crc=%x\n", __func__, crc);
+       if (crc != ssfw_head->crc)
+               goto done;
+
+       ssfw.pos = sizeof(*ssfw_head);
+
+       /* finally process all of the actions */
+       ret = process_sigma_actions(client, &ssfw);
+
+ done:
+       release_firmware(fw);
+
+       pr_debug("%s: loaded %s\n", __func__, name);
+
+       return ret;
+}
+EXPORT_SYMBOL(process_sigma_firmware);
index b46442d7d66e424d550630d0ace3d3c3eb821112..d8d0cda2641da2a9c1f43a20cf14d248588b9f6a 100644 (file)
@@ -100,18 +100,21 @@ config GPIO_VR41XX
          Say yes here to support the NEC VR4100 series General-purpose I/O Uint
 
 config GPIO_SCH
-       tristate "Intel SCH GPIO"
+       tristate "Intel SCH/TunnelCreek GPIO"
        depends on GPIOLIB && PCI && X86
        select MFD_CORE
        select LPC_SCH
        help
-         Say yes here to support GPIO interface on Intel Poulsbo SCH.
+         Say yes here to support GPIO interface on Intel Poulsbo SCH
+         or Intel Tunnel Creek processor.
          The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
          powered by the core power rail and are turned off during sleep
          modes (S3 and higher). The remaining four GPIOs are powered by
          the Intel SCH suspend power supply. These GPIOs remain
          active during S3. The suspend powered GPIOs can be used to wake the
          system from the Suspend-to-RAM state.
+         The Intel Tunnel Creek processor has 5 GPIOs powered by the
+         core power rail and 9 from suspend power supply.
 
          This driver can also be built as a module. If so, the module
          will be called sch-gpio.
index 33fc685cb3852bb311608b364717e5cb34fdb29f..3525ad91877162aefb6cacc5bcd0963f3156aee7 100644 (file)
@@ -289,10 +289,10 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev)
 
        for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) {
                int irq = gpio + dev->irq_base;
-               set_irq_chip_data(irq, dev);
-               set_irq_chip_and_handler(irq, &adp5588_irq_chip,
+               irq_set_chip_data(irq, dev);
+               irq_set_chip_and_handler(irq, &adp5588_irq_chip,
                                         handle_level_irq);
-               set_irq_nested_thread(irq, 1);
+               irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                /*
                 * ARM needs us to explicitly flag the IRQ as VALID,
@@ -300,7 +300,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev)
                 */
                set_irq_flags(irq, IRQF_VALID);
 #else
-               set_irq_noprobe(irq);
+               irq_set_noprobe(irq);
 #endif
        }
 
index 649550e2cae99947027df5f2887e77016f554b54..36a2974815b70d4bb0346c7b14b6d84c2ac7accc 100644 (file)
@@ -1656,51 +1656,6 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                        chip->get
                                ? (chip->get(chip, i) ? "hi" : "lo")
                                : "?  ");
-
-               if (!is_out) {
-                       int             irq = gpio_to_irq(gpio);
-                       struct irq_desc *desc = irq_to_desc(irq);
-
-                       /* This races with request_irq(), set_irq_type(),
-                        * and set_irq_wake() ... but those are "rare".
-                        *
-                        * More significantly, trigger type flags aren't
-                        * currently maintained by genirq.
-                        */
-                       if (irq >= 0 && desc->action) {
-                               char *trigger;
-
-                               switch (desc->status & IRQ_TYPE_SENSE_MASK) {
-                               case IRQ_TYPE_NONE:
-                                       trigger = "(default)";
-                                       break;
-                               case IRQ_TYPE_EDGE_FALLING:
-                                       trigger = "edge-falling";
-                                       break;
-                               case IRQ_TYPE_EDGE_RISING:
-                                       trigger = "edge-rising";
-                                       break;
-                               case IRQ_TYPE_EDGE_BOTH:
-                                       trigger = "edge-both";
-                                       break;
-                               case IRQ_TYPE_LEVEL_HIGH:
-                                       trigger = "level-high";
-                                       break;
-                               case IRQ_TYPE_LEVEL_LOW:
-                                       trigger = "level-low";
-                                       break;
-                               default:
-                                       trigger = "?trigger?";
-                                       break;
-                               }
-
-                               seq_printf(s, " irq-%d %s%s",
-                                       irq, trigger,
-                                       (desc->status & IRQ_WAKEUP)
-                                               ? " wakeup" : "");
-                       }
-               }
-
                seq_printf(s, "\n");
        }
 }
index 813ac077e5d7d5b0d25e465c53dcb10a023ef595..2514fb075f4afbdc1bb7a0ad62a9e3dff3bd9994 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
@@ -149,7 +150,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = mfd_get_data(pdev);
        if (!pdata) {
                dev_err(dev, "no platform data\n");
                ret = -ENXIO;
index 9e1d01f0071ac14374c693418b92e21278778b8c..ad6951edc16c49c468f810cf9c251e5509926c45 100644 (file)
@@ -470,14 +470,14 @@ static int max732x_irq_setup(struct max732x_chip *chip,
                        if (!(chip->dir_input & (1 << lvl)))
                                continue;
 
-                       set_irq_chip_data(irq, chip);
-                       set_irq_chip_and_handler(irq, &max732x_irq_chip,
+                       irq_set_chip_data(irq, chip);
+                       irq_set_chip_and_handler(irq, &max732x_irq_chip,
                                                 handle_edge_irq);
-                       set_irq_nested_thread(irq, 1);
+                       irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                        set_irq_flags(irq, IRQF_VALID);
 #else
-                       set_irq_noprobe(irq);
+                       irq_set_noprobe(irq);
 #endif
                }
 
index 2fc25dec7cf5371ccd1a405fae65d622af5352e8..583e92592073647481d52acf81cd1a520d0e9d85 100644 (file)
@@ -395,13 +395,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
                        int irq = lvl + chip->irq_base;
 
-                       set_irq_chip_data(irq, chip);
-                       set_irq_chip_and_handler(irq, &pca953x_irq_chip,
+                       irq_set_chip_data(irq, chip);
+                       irq_set_chip_and_handler(irq, &pca953x_irq_chip,
                                                 handle_edge_irq);
 #ifdef CONFIG_ARM
                        set_irq_flags(irq, IRQF_VALID);
 #else
-                       set_irq_noprobe(irq);
+                       irq_set_noprobe(irq);
 #endif
                }
 
index 838ddbdf90cc22fe0a69ec7b84153f52cdaf4baf..6fcb28cdd862af40527d79cb80b14393ae410d5d 100644 (file)
@@ -210,7 +210,7 @@ static struct irq_chip pl061_irqchip = {
 
 static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct list_head *chip_list = get_irq_data(irq);
+       struct list_head *chip_list = irq_get_handler_data(irq);
        struct list_head *ptr;
        struct pl061_gpio *chip;
 
@@ -294,7 +294,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                ret = -ENODEV;
                goto iounmap;
        }
-       set_irq_chained_handler(irq, pl061_irq_handler);
+       irq_set_chained_handler(irq, pl061_irq_handler);
        if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
                chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
                if (chip_list == NULL) {
@@ -303,9 +303,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                        goto iounmap;
                }
                INIT_LIST_HEAD(chip_list);
-               set_irq_data(irq, chip_list);
+               irq_set_handler_data(irq, chip_list);
        } else
-               chip_list = get_irq_data(irq);
+               chip_list = irq_get_handler_data(irq);
        list_add(&chip->list, chip_list);
 
        for (i = 0; i < PL061_GPIO_NR; i++) {
@@ -315,10 +315,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
                else
                        pl061_direction_input(&chip->gc, i);
 
-               set_irq_chip(i+chip->irq_base, &pl061_irqchip);
-               set_irq_handler(i+chip->irq_base, handle_simple_irq);
+               irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip,
+                                        handle_simple_irq);
                set_irq_flags(i+chip->irq_base, IRQF_VALID);
-               set_irq_chip_data(i+chip->irq_base, chip);
+               irq_set_chip_data(i + chip->irq_base, chip);
        }
 
        return 0;
index 897e0577e65e0fd425f18edb00512ee414566a64..a9bda881935a82907ff0c5c753efee59b924cdf5 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/gpio.h>
 #include <linux/mfd/rdc321x.h>
+#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 struct rdc321x_gpio {
@@ -135,7 +136,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
        struct rdc321x_gpio *rdc321x_gpio_dev;
        struct rdc321x_gpio_pdata *pdata;
 
-       pdata = platform_get_drvdata(pdev);
+       pdata = mfd_get_data(pdev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -ENODEV;
index 583521352c16d7a24e4d039e8218ccfde835e940..56060421cdff5f546873d4abb88d25bfc38d94a4 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
+#include <linux/pci_ids.h>
 
 #include <linux/gpio.h>
 
@@ -187,7 +188,11 @@ static struct gpio_chip sch_gpio_resume = {
 static int __devinit sch_gpio_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       int err;
+       int err, id;
+
+       id = pdev->id;
+       if (!id)
+               return -ENODEV;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!res)
@@ -198,12 +203,40 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
 
        gpio_ba = res->start;
 
-       sch_gpio_core.base = 0;
-       sch_gpio_core.ngpio = 10;
-       sch_gpio_core.dev = &pdev->dev;
+       switch (id) {
+               case PCI_DEVICE_ID_INTEL_SCH_LPC:
+                       sch_gpio_core.base = 0;
+                       sch_gpio_core.ngpio = 10;
+
+                       sch_gpio_resume.base = 10;
+                       sch_gpio_resume.ngpio = 4;
+
+                       /*
+                        * GPIO[6:0] enabled by default
+                        * GPIO7 is configured by the CMC as SLPIOVR
+                        * Enable GPIO[9:8] core powered gpios explicitly
+                        */
+                       outb(0x3, gpio_ba + CGEN + 1);
+                       /*
+                        * SUS_GPIO[2:0] enabled by default
+                        * Enable SUS_GPIO3 resume powered gpio explicitly
+                        */
+                       outb(0x8, gpio_ba + RGEN);
+                       break;
+
+               case PCI_DEVICE_ID_INTEL_ITC_LPC:
+                       sch_gpio_core.base = 0;
+                       sch_gpio_core.ngpio = 5;
+
+                       sch_gpio_resume.base = 5;
+                       sch_gpio_resume.ngpio = 9;
+                       break;
+
+               default:
+                       return -ENODEV;
+       }
 
-       sch_gpio_resume.base = 10;
-       sch_gpio_resume.ngpio = 4;
+       sch_gpio_core.dev = &pdev->dev;
        sch_gpio_resume.dev = &pdev->dev;
 
        err = gpiochip_add(&sch_gpio_core);
@@ -214,18 +247,6 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
        if (err < 0)
                goto err_sch_gpio_resume;
 
-       /*
-        * GPIO[6:0] enabled by default
-        * GPIO7 is configured by the CMC as SLPIOVR
-        * Enable GPIO[9:8] core powered gpios explicitly
-        */
-       outb(0x3, gpio_ba + CGEN + 1);
-       /*
-        * SUS_GPIO[2:0] enabled by default
-        * Enable SUS_GPIO3 resume powered gpio explicitly
-        */
-       outb(0x8, gpio_ba + RGEN);
-
        return 0;
 
 err_sch_gpio_resume:
index eb2901f8ab5ef6706d4705bb761cea30e129301b..4c980b573328eaeb4432504284ffe249fdb66a45 100644 (file)
@@ -254,14 +254,14 @@ static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
        int irq;
 
        for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
-               set_irq_chip_data(irq, stmpe_gpio);
-               set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip,
+               irq_set_chip_data(irq, stmpe_gpio);
+               irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
                                         handle_simple_irq);
-               set_irq_nested_thread(irq, 1);
+               irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                set_irq_flags(irq, IRQF_VALID);
 #else
-               set_irq_noprobe(irq);
+               irq_set_noprobe(irq);
 #endif
        }
 
@@ -277,8 +277,8 @@ static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
 #ifdef CONFIG_ARM
                set_irq_flags(irq, 0);
 #endif
-               set_irq_chip_and_handler(irq, NULL, NULL);
-               set_irq_chip_data(irq, NULL);
+               irq_set_chip_and_handler(irq, NULL, NULL);
+               irq_set_chip_data(irq, NULL);
        }
 }
 
index d2f874c3d3d59ff3f8c095ca5d93a33c769131fe..a4f73534394e4f37e13b6998e50c64dde43b7f3e 100644 (file)
@@ -551,12 +551,12 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
 
        for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
                irq = irq_base + n;
-               set_irq_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq);
-               set_irq_nested_thread(irq, 1);
+               irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq);
+               irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                set_irq_flags(irq, IRQF_VALID);
 #else
-               set_irq_noprobe(irq);
+               irq_set_noprobe(irq);
 #endif
        }
 
@@ -583,8 +583,7 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
 
        for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
                irq = chip->irq_base + n;
-               set_irq_handler(irq, NULL);
-               set_irq_chip(irq, NULL);
+               irq_set_chip_and_handler(irq, NULL, NULL);
        }
 }
 
index 27200af1a595d731d6dc7f2b4d1803660baff9ad..2a82e8999a4299553a4ebeec273a69b55663df61 100644 (file)
@@ -239,14 +239,14 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
        int irq;
 
        for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
-               set_irq_chip_data(irq, tc3589x_gpio);
-               set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
+               irq_set_chip_data(irq, tc3589x_gpio);
+               irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
                                         handle_simple_irq);
-               set_irq_nested_thread(irq, 1);
+               irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                set_irq_flags(irq, IRQF_VALID);
 #else
-               set_irq_noprobe(irq);
+               irq_set_noprobe(irq);
 #endif
        }
 
@@ -262,8 +262,8 @@ static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio)
 #ifdef CONFIG_ARM
                set_irq_flags(irq, 0);
 #endif
-               set_irq_chip_and_handler(irq, NULL, NULL);
-               set_irq_chip_data(irq, NULL);
+               irq_set_chip_and_handler(irq, NULL, NULL);
+               irq_set_chip_data(irq, NULL);
        }
 }
 
index 58c8f30352dddbd4eda7b3cd2ac45455b51d92a4..edbe1eae531fa6ad35394232af3de40f78425622 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/timb_gpio.h>
@@ -195,7 +196,7 @@ out:
 
 static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct timbgpio *tgpio = get_irq_data(irq);
+       struct timbgpio *tgpio = irq_get_handler_data(irq);
        unsigned long ipr;
        int offset;
 
@@ -228,7 +229,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
        struct gpio_chip *gc;
        struct timbgpio *tgpio;
        struct resource *iomem;
-       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+       struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
        int irq = platform_get_irq(pdev, 0);
 
        if (!pdata || pdata->nr_pins > 32) {
@@ -291,16 +292,16 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
                return 0;
 
        for (i = 0; i < pdata->nr_pins; i++) {
-               set_irq_chip_and_handler_name(tgpio->irq_base + i,
+               irq_set_chip_and_handler_name(tgpio->irq_base + i,
                        &timbgpio_irqchip, handle_simple_irq, "mux");
-               set_irq_chip_data(tgpio->irq_base + i, tgpio);
+               irq_set_chip_data(tgpio->irq_base + i, tgpio);
 #ifdef CONFIG_ARM
                set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE);
 #endif
        }
 
-       set_irq_data(irq, tgpio);
-       set_irq_chained_handler(irq, timbgpio_irq);
+       irq_set_handler_data(irq, tgpio);
+       irq_set_chained_handler(irq, timbgpio_irq);
 
        return 0;
 
@@ -319,20 +320,19 @@ err_mem:
 static int __devexit timbgpio_remove(struct platform_device *pdev)
 {
        int err;
-       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
        struct timbgpio *tgpio = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
 
        if (irq >= 0 && tgpio->irq_base > 0) {
                int i;
-               for (i = 0; i < pdata->nr_pins; i++) {
-                       set_irq_chip(tgpio->irq_base + i, NULL);
-                       set_irq_chip_data(tgpio->irq_base + i, NULL);
+               for (i = 0; i < tgpio->gpio.ngpio; i++) {
+                       irq_set_chip(tgpio->irq_base + i, NULL);
+                       irq_set_chip_data(tgpio->irq_base + i, NULL);
                }
 
-               set_irq_handler(irq, NULL);
-               set_irq_data(irq, NULL);
+               irq_set_handler(irq, NULL);
+               irq_set_handler_data(irq, NULL);
        }
 
        err = gpiochip_remove(&tgpio->gpio);
index cffa3bd7ad3bcb52fbc6328c5dcff3080a3c31ec..a365be040b3663be0f8eaf1baf4fac6b935bfcb6 100644 (file)
@@ -238,13 +238,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
                                        break;
                                }
                        }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                       irq_set_chip_and_handler(GIU_IRQ(pin),
                                                 &giuint_low_irq_chip,
                                                 handle_edge_irq);
                } else {
                        giu_clear(GIUINTTYPL, mask);
                        giu_clear(GIUINTHTSELL, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                       irq_set_chip_and_handler(GIU_IRQ(pin),
                                                 &giuint_low_irq_chip,
                                                 handle_level_irq);
                }
@@ -273,13 +273,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
                                        break;
                                }
                        }
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                       irq_set_chip_and_handler(GIU_IRQ(pin),
                                                 &giuint_high_irq_chip,
                                                 handle_edge_irq);
                } else {
                        giu_clear(GIUINTTYPH, mask);
                        giu_clear(GIUINTHTSELH, mask);
-                       set_irq_chip_and_handler(GIU_IRQ(pin),
+                       irq_set_chip_and_handler(GIU_IRQ(pin),
                                                 &giuint_high_irq_chip,
                                                 handle_level_irq);
                }
@@ -539,9 +539,9 @@ static int __devinit giu_probe(struct platform_device *pdev)
                        chip = &giuint_high_irq_chip;
 
                if (trigger & (1 << pin))
-                       set_irq_chip_and_handler(i, chip, handle_edge_irq);
+                       irq_set_chip_and_handler(i, chip, handle_edge_irq);
                else
-                       set_irq_chip_and_handler(i, chip, handle_level_irq);
+                       irq_set_chip_and_handler(i, chip, handle_level_irq);
 
        }
 
index 4c95b5fd9df32622d3116b7c4360794876b0407b..799e1490cf240964962650140bc1aca3631f3691 100644 (file)
@@ -1073,6 +1073,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        uint32_t __user *encoder_id;
        struct drm_mode_group *mode_group;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        /*
@@ -1244,6 +1247,9 @@ int drm_mode_getcrtc(struct drm_device *dev,
        struct drm_mode_object *obj;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
@@ -1312,6 +1318,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        uint64_t __user *prop_values;
        uint32_t __user *encoder_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
@@ -1431,6 +1440,9 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
        struct drm_encoder *encoder;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, enc_resp->encoder_id,
                                   DRM_MODE_OBJECT_ENCODER);
@@ -1486,6 +1498,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        int ret = 0;
        int i;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_req->crtc_id,
                                   DRM_MODE_OBJECT_CRTC);
@@ -1603,6 +1618,9 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
        struct drm_crtc *crtc;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        if (!req->flags) {
                DRM_ERROR("no operation set\n");
                return -EINVAL;
@@ -1667,6 +1685,9 @@ int drm_mode_addfb(struct drm_device *dev,
        struct drm_framebuffer *fb;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        if ((config->min_width > r->width) || (r->width > config->max_width)) {
                DRM_ERROR("mode new framebuffer width not within limits\n");
                return -EINVAL;
@@ -1724,6 +1745,9 @@ int drm_mode_rmfb(struct drm_device *dev,
        int ret = 0;
        int found = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
        /* TODO check that we realy get a framebuffer back. */
@@ -1780,6 +1804,9 @@ int drm_mode_getfb(struct drm_device *dev,
        struct drm_framebuffer *fb;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
        if (!obj) {
@@ -1813,6 +1840,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        int num_clips;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
        if (!obj) {
@@ -1996,6 +2026,9 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
        struct drm_mode_modeinfo *umode = &mode_cmd->mode;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2042,6 +2075,9 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
        struct drm_mode_modeinfo *umode = &mode_cmd->mode;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2211,6 +2247,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
        uint64_t __user *values_ptr;
        uint32_t __user *blob_length_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
        if (!obj) {
@@ -2333,6 +2372,9 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
        int ret = 0;
        void *blob_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
        if (!obj) {
@@ -2393,6 +2435,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
        int ret = -EINVAL;
        int i;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2509,6 +2554,9 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
        int size;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
@@ -2560,6 +2608,9 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
        int size;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
index 57ce27c9a747799dfb5065a056747d1b2d30bcab..74e4ff578017b90d3e0649219d71a87163fb5b19 100644 (file)
@@ -499,11 +499,12 @@ EXPORT_SYMBOL(drm_gem_vm_open);
 void drm_gem_vm_close(struct vm_area_struct *vma)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->dev;
 
-       mutex_lock(&obj->dev->struct_mutex);
+       mutex_lock(&dev->struct_mutex);
        drm_vm_close_locked(vma);
        drm_gem_object_unreference(obj);
-       mutex_unlock(&obj->dev->struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 }
 EXPORT_SYMBOL(drm_gem_vm_close);
 
index 7f6912a16761a12c360310fd60e45d375d17966e..904d7e9c8e4752ffa738ee33b0f884e305825a12 100644 (file)
@@ -280,6 +280,9 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
                if (dev->driver->dumb_create)
                        req->value = 1;
                break;
+       case DRM_CAP_VBLANK_HIGH_CRTC:
+               req->value = 1;
+               break;
        default:
                return -EINVAL;
        }
index a34ef97d3c817b33012f17d344e5d3f84df0db42..741457bd1c46ef1f54af12296e348a053430329e 100644 (file)
@@ -1125,7 +1125,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
 {
        union drm_wait_vblank *vblwait = data;
        int ret = 0;
-       unsigned int flags, seq, crtc;
+       unsigned int flags, seq, crtc, high_crtc;
 
        if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
                return -EINVAL;
@@ -1134,16 +1134,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                return -EINVAL;
 
        if (vblwait->request.type &
-           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+             _DRM_VBLANK_HIGH_CRTC_MASK)) {
                DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
                          vblwait->request.type,
-                         (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
+                         (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+                          _DRM_VBLANK_HIGH_CRTC_MASK));
                return -EINVAL;
        }
 
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
-       crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
-
+       high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
+       if (high_crtc)
+               crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+       else
+               crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
        if (crtc >= dev->num_crtcs)
                return -EINVAL;
 
index 09e0327fc6cee13288ba6950eb3cf765f6be1146..87c8e29465e30a7963afdd03c1aa0666ed89d55d 100644 (file)
@@ -892,7 +892,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                seq_printf(m, "Render p-state limit: %d\n",
                           rp_state_limits & 0xff);
                seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >>
-                                               GEN6_CAGF_SHIFT) * 100);
+                                               GEN6_CAGF_SHIFT) * 50);
                seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
                           GEN6_CURICONT_MASK);
                seq_printf(m, "RP CUR UP: %dus\n", rpcurup &
@@ -908,15 +908,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
 
                max_freq = (rp_state_cap & 0xff0000) >> 16;
                seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
-                          max_freq * 100);
+                          max_freq * 50);
 
                max_freq = (rp_state_cap & 0xff00) >> 8;
                seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
-                          max_freq * 100);
+                          max_freq * 50);
 
                max_freq = rp_state_cap & 0xff;
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
-                          max_freq * 100);
+                          max_freq * 50);
 
                __gen6_gt_force_wake_put(dev_priv);
        } else {
index 449650545bb4fa2456c39b01ba518ffd8ee6ddfc..5004724ea57e08aa808b85ec5612e4e9a8a97af8 100644 (file)
@@ -383,6 +383,7 @@ typedef struct drm_i915_private {
        u32 saveDSPACNTR;
        u32 saveDSPBCNTR;
        u32 saveDSPARB;
+       u32 saveHWS;
        u32 savePIPEACONF;
        u32 savePIPEBCONF;
        u32 savePIPEASRC;
index c4c2855d002d950beb6ecebf3eec0f8d7a8712a1..7ce3f353af33657e612f40887a89aefb9b936dda 100644 (file)
@@ -224,7 +224,7 @@ i915_gem_dumb_create(struct drm_file *file,
                     struct drm_mode_create_dumb *args)
 {
        /* have to work out size/pitch and return them */
-       args->pitch = ALIGN(args->width & ((args->bpp + 1) / 8), 64);
+       args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
        args->size = args->pitch * args->height;
        return i915_gem_create(file, dev,
                               args->size, &args->handle);
@@ -1356,9 +1356,10 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)
        if (!obj->fault_mappable)
                return;
 
-       unmap_mapping_range(obj->base.dev->dev_mapping,
-                           (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
-                           obj->base.size, 1);
+       if (obj->base.dev->dev_mapping)
+               unmap_mapping_range(obj->base.dev->dev_mapping,
+                                   (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
+                                   obj->base.size, 1);
 
        obj->fault_mappable = false;
 }
@@ -1796,8 +1797,10 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
                return;
 
        spin_lock(&file_priv->mm.lock);
-       list_del(&request->client_list);
-       request->file_priv = NULL;
+       if (request->file_priv) {
+               list_del(&request->client_list);
+               request->file_priv = NULL;
+       }
        spin_unlock(&file_priv->mm.lock);
 }
 
@@ -2217,13 +2220,18 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring,
 {
        int ret;
 
+       if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0)
+               return 0;
+
        trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains);
 
        ret = ring->flush(ring, invalidate_domains, flush_domains);
        if (ret)
                return ret;
 
-       i915_gem_process_flushing_list(ring, flush_domains);
+       if (flush_domains & I915_GEM_GPU_DOMAINS)
+               i915_gem_process_flushing_list(ring, flush_domains);
+
        return 0;
 }
 
@@ -2579,8 +2587,23 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
                reg = &dev_priv->fence_regs[obj->fence_reg];
                list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
 
-               if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
-                       pipelined = NULL;
+               if (obj->tiling_changed) {
+                       ret = i915_gem_object_flush_fence(obj, pipelined);
+                       if (ret)
+                               return ret;
+
+                       if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
+                               pipelined = NULL;
+
+                       if (pipelined) {
+                               reg->setup_seqno =
+                                       i915_gem_next_request_seqno(pipelined);
+                               obj->last_fenced_seqno = reg->setup_seqno;
+                               obj->last_fenced_ring = pipelined;
+                       }
+
+                       goto update;
+               }
 
                if (!pipelined) {
                        if (reg->setup_seqno) {
@@ -2599,31 +2622,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
                        ret = i915_gem_object_flush_fence(obj, pipelined);
                        if (ret)
                                return ret;
-               } else if (obj->tiling_changed) {
-                       if (obj->fenced_gpu_access) {
-                               if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
-                                       ret = i915_gem_flush_ring(obj->ring,
-                                                                 0, obj->base.write_domain);
-                                       if (ret)
-                                               return ret;
-                               }
-
-                               obj->fenced_gpu_access = false;
-                       }
-               }
-
-               if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
-                       pipelined = NULL;
-               BUG_ON(!pipelined && reg->setup_seqno);
-
-               if (obj->tiling_changed) {
-                       if (pipelined) {
-                               reg->setup_seqno =
-                                       i915_gem_next_request_seqno(pipelined);
-                               obj->last_fenced_seqno = reg->setup_seqno;
-                               obj->last_fenced_ring = pipelined;
-                       }
-                       goto update;
                }
 
                return 0;
@@ -3606,6 +3604,8 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
                return;
        }
 
+       trace_i915_gem_object_destroy(obj);
+
        if (obj->base.map_list.map)
                i915_gem_free_mmap_offset(obj);
 
@@ -3615,8 +3615,6 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
        kfree(obj->page_cpu_valid);
        kfree(obj->bit_17);
        kfree(obj);
-
-       trace_i915_gem_object_destroy(obj);
 }
 
 void i915_gem_free_object(struct drm_gem_object *gem_obj)
index 7ff7f933ddf17e1395ab7140be773bda10a7132b..20a4cc5b818f51632ad50a94bdfa4092c3f1a454 100644 (file)
@@ -367,6 +367,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                uint32_t __iomem *reloc_entry;
                void __iomem *reloc_page;
 
+               /* We can't wait for rendering with pagefaults disabled */
+               if (obj->active && in_atomic())
+                       return -EFAULT;
+
                ret = i915_gem_object_set_to_gtt_domain(obj, 1);
                if (ret)
                        return ret;
@@ -440,15 +444,24 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
                             struct list_head *objects)
 {
        struct drm_i915_gem_object *obj;
-       int ret;
-
+       int ret = 0;
+
+       /* This is the fast path and we cannot handle a pagefault whilst
+        * holding the struct mutex lest the user pass in the relocations
+        * contained within a mmaped bo. For in such a case we, the page
+        * fault handler would call i915_gem_fault() and we would try to
+        * acquire the struct mutex again. Obviously this is bad and so
+        * lockdep complains vehemently.
+        */
+       pagefault_disable();
        list_for_each_entry(obj, objects, exec_list) {
                ret = i915_gem_execbuffer_relocate_object(obj, eb);
                if (ret)
-                       return ret;
+                       break;
        }
+       pagefault_enable();
 
-       return 0;
+       return ret;
 }
 
 static int
index 7e992a8e90982929eb78ca03be42b5223439d1d4..da474153a0a228626cef23e08b5d3c9566642dee 100644 (file)
@@ -796,6 +796,9 @@ int i915_save_state(struct drm_device *dev)
 
        pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
 
+       /* Hardware status page */
+       dev_priv->saveHWS = I915_READ(HWS_PGA);
+
        i915_save_display(dev);
 
        /* Interrupt state */
@@ -842,6 +845,9 @@ int i915_restore_state(struct drm_device *dev)
 
        pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
 
+       /* Hardware status page */
+       I915_WRITE(HWS_PGA, dev_priv->saveHWS);
+
        i915_restore_display(dev);
 
        /* Interrupt state */
index 3106c0dc838959d8054e9fbd06a244fbf8154b7a..432fc04c6bffc1b58d8da1645a8a5687049a9bc2 100644 (file)
@@ -1516,9 +1516,10 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        reg = PIPECONF(pipe);
        val = I915_READ(reg);
-       val |= PIPECONF_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       if (val & PIPECONF_ENABLE)
+               return;
+
+       I915_WRITE(reg, val | PIPECONF_ENABLE);
        intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
@@ -1552,9 +1553,10 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
 
        reg = PIPECONF(pipe);
        val = I915_READ(reg);
-       val &= ~PIPECONF_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       if ((val & PIPECONF_ENABLE) == 0)
+               return;
+
+       I915_WRITE(reg, val & ~PIPECONF_ENABLE);
        intel_wait_for_pipe_off(dev_priv->dev, pipe);
 }
 
@@ -1577,9 +1579,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv,
 
        reg = DSPCNTR(plane);
        val = I915_READ(reg);
-       val |= DISPLAY_PLANE_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       if (val & DISPLAY_PLANE_ENABLE)
+               return;
+
+       I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
        intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
@@ -1610,9 +1613,10 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
 
        reg = DSPCNTR(plane);
        val = I915_READ(reg);
-       val &= ~DISPLAY_PLANE_ENABLE;
-       I915_WRITE(reg, val);
-       POSTING_READ(reg);
+       if ((val & DISPLAY_PLANE_ENABLE) == 0)
+               return;
+
+       I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
        intel_flush_display_plane(dev_priv, plane);
        intel_wait_for_vblank(dev_priv->dev, pipe);
 }
@@ -1769,7 +1773,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                        return;
 
                I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
-               POSTING_READ(DPFC_CONTROL);
                intel_wait_for_vblank(dev, intel_crtc->pipe);
        }
 
@@ -1861,7 +1864,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
                        return;
 
                I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
-               POSTING_READ(ILK_DPFC_CONTROL);
                intel_wait_for_vblank(dev, intel_crtc->pipe);
        }
 
@@ -3883,10 +3885,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
                              display, cursor);
 }
 
-static inline bool single_plane_enabled(unsigned int mask)
-{
-       return mask && (mask & -mask) == 0;
-}
+#define single_plane_enabled(mask) is_power_of_2(mask)
 
 static void g4x_update_wm(struct drm_device *dev)
 {
@@ -5777,7 +5776,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
 
                dpll &= ~DISPLAY_RATE_SELECT_FPA1;
                I915_WRITE(dpll_reg, dpll);
-               POSTING_READ(dpll_reg);
                intel_wait_for_vblank(dev, pipe);
 
                dpll = I915_READ(dpll_reg);
@@ -5821,7 +5819,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
 
                dpll |= DISPLAY_RATE_SELECT_FPA1;
                I915_WRITE(dpll_reg, dpll);
-               dpll = I915_READ(dpll_reg);
                intel_wait_for_vblank(dev, pipe);
                dpll = I915_READ(dpll_reg);
                if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
@@ -6933,7 +6930,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
        if (pcu_mbox & (1<<31)) { /* OC supported */
                max_freq = pcu_mbox & 0xff;
-               DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100);
+               DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
        }
 
        /* In units of 100MHz */
index d29e33f815d7ce8e4392e1c81704e2628c58fe51..0daefca5cbb83591ec83ffc391e3303b2f3ca50b 100644 (file)
@@ -1957,9 +1957,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                                        DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
                } else {
                        /* if this fails, presume the device is a ghost */
-                       DRM_ERROR("failed to retrieve link info\n");
-                       intel_dp_destroy(&intel_connector->base);
+                       DRM_INFO("failed to retrieve link info, disabling eDP\n");
                        intel_dp_encoder_destroy(&intel_dp->base.base);
+                       intel_dp_destroy(&intel_connector->base);
                        return;
                }
        }
index 789c47801ba89bf1cf7577b5c46e01cc1f3f0e32..e9e6f71418a43122c3545d712c2ea3268861c2c4 100644 (file)
@@ -65,62 +65,60 @@ render_ring_flush(struct intel_ring_buffer *ring,
        u32 cmd;
        int ret;
 
-       if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
+       /*
+        * read/write caches:
+        *
+        * I915_GEM_DOMAIN_RENDER is always invalidated, but is
+        * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
+        * also flushed at 2d versus 3d pipeline switches.
+        *
+        * read-only caches:
+        *
+        * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
+        * MI_READ_FLUSH is set, and is always flushed on 965.
+        *
+        * I915_GEM_DOMAIN_COMMAND may not exist?
+        *
+        * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
+        * invalidated when MI_EXE_FLUSH is set.
+        *
+        * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
+        * invalidated with every MI_FLUSH.
+        *
+        * TLBs:
+        *
+        * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
+        * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
+        * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
+        * are flushed at any MI_FLUSH.
+        */
+
+       cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+       if ((invalidate_domains|flush_domains) &
+           I915_GEM_DOMAIN_RENDER)
+               cmd &= ~MI_NO_WRITE_FLUSH;
+       if (INTEL_INFO(dev)->gen < 4) {
                /*
-                * read/write caches:
-                *
-                * I915_GEM_DOMAIN_RENDER is always invalidated, but is
-                * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
-                * also flushed at 2d versus 3d pipeline switches.
-                *
-                * read-only caches:
-                *
-                * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
-                * MI_READ_FLUSH is set, and is always flushed on 965.
-                *
-                * I915_GEM_DOMAIN_COMMAND may not exist?
-                *
-                * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
-                * invalidated when MI_EXE_FLUSH is set.
-                *
-                * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
-                * invalidated with every MI_FLUSH.
-                *
-                * TLBs:
-                *
-                * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
-                * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
-                * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
-                * are flushed at any MI_FLUSH.
+                * On the 965, the sampler cache always gets flushed
+                * and this bit is reserved.
                 */
+               if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+                       cmd |= MI_READ_FLUSH;
+       }
+       if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+               cmd |= MI_EXE_FLUSH;
 
-               cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
-               if ((invalidate_domains|flush_domains) &
-                   I915_GEM_DOMAIN_RENDER)
-                       cmd &= ~MI_NO_WRITE_FLUSH;
-               if (INTEL_INFO(dev)->gen < 4) {
-                       /*
-                        * On the 965, the sampler cache always gets flushed
-                        * and this bit is reserved.
-                        */
-                       if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
-                               cmd |= MI_READ_FLUSH;
-               }
-               if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
-                       cmd |= MI_EXE_FLUSH;
-
-               if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
-                   (IS_G4X(dev) || IS_GEN5(dev)))
-                       cmd |= MI_INVALIDATE_ISP;
+       if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
+           (IS_G4X(dev) || IS_GEN5(dev)))
+               cmd |= MI_INVALIDATE_ISP;
 
-               ret = intel_ring_begin(ring, 2);
-               if (ret)
-                       return ret;
+       ret = intel_ring_begin(ring, 2);
+       if (ret)
+               return ret;
 
-               intel_ring_emit(ring, cmd);
-               intel_ring_emit(ring, MI_NOOP);
-               intel_ring_advance(ring);
-       }
+       intel_ring_emit(ring, cmd);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return 0;
 }
@@ -568,9 +566,6 @@ bsd_ring_flush(struct intel_ring_buffer *ring,
 {
        int ret;
 
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
-               return 0;
-
        ret = intel_ring_begin(ring, 2);
        if (ret)
                return ret;
@@ -1056,9 +1051,6 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring,
        uint32_t cmd;
        int ret;
 
-       if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0)
-               return 0;
-
        ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
@@ -1230,9 +1222,6 @@ static int blt_ring_flush(struct intel_ring_buffer *ring,
        uint32_t cmd;
        int ret;
 
-       if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0)
-               return 0;
-
        ret = blt_ring_begin(ring, 4);
        if (ret)
                return ret;
index d3a9c6e024772343a8be94d04db52840cd2d6304..00a55dfdba82dc2d6a8a26ad91168774a71fc06c 100644 (file)
@@ -88,18 +88,20 @@ static const struct backlight_ops nv50_bl_ops = {
        .update_status = nv50_set_intensity,
 };
 
-static int nouveau_nv40_backlight_init(struct drm_device *dev)
+static int nouveau_nv40_backlight_init(struct drm_connector *connector)
 {
-       struct backlight_properties props;
+       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct backlight_properties props;
        struct backlight_device *bd;
 
        if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK))
                return 0;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 31;
-       bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
+       bd = backlight_device_register("nv_backlight", &connector->kdev, dev,
                                       &nv40_bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
@@ -111,18 +113,20 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev)
        return 0;
 }
 
-static int nouveau_nv50_backlight_init(struct drm_device *dev)
+static int nouveau_nv50_backlight_init(struct drm_connector *connector)
 {
-       struct backlight_properties props;
+       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct backlight_properties props;
        struct backlight_device *bd;
 
        if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT))
                return 0;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 1025;
-       bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev,
+       bd = backlight_device_register("nv_backlight", &connector->kdev, dev,
                                       &nv50_bl_ops, &props);
        if (IS_ERR(bd))
                return PTR_ERR(bd);
@@ -133,8 +137,9 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev)
        return 0;
 }
 
-int nouveau_backlight_init(struct drm_device *dev)
+int nouveau_backlight_init(struct drm_connector *connector)
 {
+       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
 #ifdef CONFIG_ACPI
@@ -147,9 +152,9 @@ int nouveau_backlight_init(struct drm_device *dev)
 
        switch (dev_priv->card_type) {
        case NV_40:
-               return nouveau_nv40_backlight_init(dev);
+               return nouveau_nv40_backlight_init(connector);
        case NV_50:
-               return nouveau_nv50_backlight_init(dev);
+               return nouveau_nv50_backlight_init(connector);
        default:
                break;
        }
@@ -157,8 +162,9 @@ int nouveau_backlight_init(struct drm_device *dev)
        return 0;
 }
 
-void nouveau_backlight_exit(struct drm_device *dev)
+void nouveau_backlight_exit(struct drm_connector *connector)
 {
+       struct drm_device *dev = connector->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
        if (dev_priv->backlight) {
index 390d82c3c4b04a8450c661090e0e680f5154a6ab..7ae151109a66f76eb467557f66f055c5ea7cb5c7 100644 (file)
@@ -116,6 +116,10 @@ nouveau_connector_destroy(struct drm_connector *connector)
                                      nouveau_connector_hotplug, connector);
        }
 
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+           connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               nouveau_backlight_exit(connector);
+
        kfree(nv_connector->edid);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
@@ -894,6 +898,11 @@ nouveau_connector_create(struct drm_device *dev, int index)
        }
 
        drm_sysfs_connector_add(connector);
+
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+           connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               nouveau_backlight_init(connector);
+
        dcb->drm = connector;
        return dcb->drm;
 
index 06111887b7895105008ccc7cdf1c80bbde0894a1..fff180a99867f43ca09d61fab78bcfba1468a631 100644 (file)
@@ -999,15 +999,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector
 
 /* nouveau_backlight.c */
 #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
-extern int nouveau_backlight_init(struct drm_device *);
-extern void nouveau_backlight_exit(struct drm_device *);
+extern int nouveau_backlight_init(struct drm_connector *);
+extern void nouveau_backlight_exit(struct drm_connector *);
 #else
-static inline int nouveau_backlight_init(struct drm_device *dev)
+static inline int nouveau_backlight_init(struct drm_connector *dev)
 {
        return 0;
 }
 
-static inline void nouveau_backlight_exit(struct drm_device *dev) { }
+static inline void nouveau_backlight_exit(struct drm_connector *dev) { }
 #endif
 
 /* nouveau_bios.c */
index 05294910e135630ca7516e34a4dfea4076883c22..4fcbd091a117caea61fb684374a4fe9f0e661886 100644 (file)
@@ -704,10 +704,6 @@ nouveau_card_init(struct drm_device *dev)
                        goto out_fence;
        }
 
-       ret = nouveau_backlight_init(dev);
-       if (ret)
-               NV_ERROR(dev, "Error %d registering backlight\n", ret);
-
        nouveau_fbcon_init(dev);
        drm_kms_helper_poll_init(dev);
        return 0;
@@ -759,8 +755,6 @@ static void nouveau_card_takedown(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
 
-       nouveau_backlight_exit(dev);
-
        if (!engine->graph.accel_blocked) {
                nouveau_fence_fini(dev);
                nouveau_channel_put_unlocked(&dev_priv->channel);
index 1c02d23f6fcca9f9a6030bba9ea309ef98838419..9746fee59f567856511b0eae1a2ed9310e3e52d0 100644 (file)
@@ -1,6 +1,7 @@
 config DRM_RADEON_KMS
        bool "Enable modesetting on radeon by default - NEW DRIVER"
        depends on DRM_RADEON
+       select BACKLIGHT_CLASS_DEVICE
        help
          Choose this option if you want kernel modesetting enabled by default.
 
index 3cd3234ba0af4abbe698a9e8ed02a33a2fe7eb84..10e41af6b0269d24210a945762ddead3e8a26786 100644 (file)
@@ -957,7 +957,11 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        /* adjust pixel clock as needed */
        adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
 
-       if (ASIC_IS_AVIVO(rdev))
+       if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+               /* TV seems to prefer the legacy algo on some boards */
+               radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                                         &ref_div, &post_div);
+       else if (ASIC_IS_AVIVO(rdev))
                radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
                                         &ref_div, &post_div);
        else
index cf7c8d5b4ec24a431a81c776c367a1a54e4f29f3..cf602e2d0718ed21539dafd566405c77b3d9a4ac 100644 (file)
@@ -448,7 +448,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
 
 bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
 {
-       int edid_info;
+       int edid_info, size;
        struct edid *edid;
        unsigned char *raw;
        edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
@@ -456,11 +456,12 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
                return false;
 
        raw = rdev->bios + edid_info;
-       edid = kmalloc(EDID_LENGTH * (raw[0x7e] + 1), GFP_KERNEL);
+       size = EDID_LENGTH * (raw[0x7e] + 1);
+       edid = kmalloc(size, GFP_KERNEL);
        if (edid == NULL)
                return false;
 
-       memcpy((unsigned char *)edid, raw, EDID_LENGTH * (raw[0x7e] + 1));
+       memcpy((unsigned char *)edid, raw, size);
 
        if (!drm_edid_is_valid(edid)) {
                kfree(edid);
@@ -468,6 +469,7 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
        }
 
        rdev->mode_info.bios_hardcoded_edid = edid;
+       rdev->mode_info.bios_hardcoded_edid_size = size;
        return true;
 }
 
@@ -475,8 +477,17 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
 struct edid *
 radeon_bios_get_hardcoded_edid(struct radeon_device *rdev)
 {
-       if (rdev->mode_info.bios_hardcoded_edid)
-               return rdev->mode_info.bios_hardcoded_edid;
+       struct edid *edid;
+
+       if (rdev->mode_info.bios_hardcoded_edid) {
+               edid = kmalloc(rdev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL);
+               if (edid) {
+                       memcpy((unsigned char *)edid,
+                              (unsigned char *)rdev->mode_info.bios_hardcoded_edid,
+                              rdev->mode_info.bios_hardcoded_edid_size);
+                       return edid;
+               }
+       }
        return NULL;
 }
 
index 3f3c9aac46ccfd4fb2ff4c58a13ecfbfca4f4501..2ef6d513506404075307c5f5865e091b8e4653ea 100644 (file)
@@ -40,6 +40,10 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
                                       struct drm_encoder *encoder,
                                       bool connected);
 
+extern void
+radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+                            struct drm_connector *drm_connector);
+
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
@@ -629,6 +633,8 @@ static int radeon_vga_mode_valid(struct drm_connector *connector,
 static enum drm_connector_status
 radeon_vga_detect(struct drm_connector *connector, bool force)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct drm_encoder *encoder;
        struct drm_encoder_helper_funcs *encoder_funcs;
@@ -679,6 +685,17 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
 
        if (ret == connector_status_connected)
                ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
+
+       /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
+        * vbios to deal with KVMs. If we have one and are not able to detect a monitor
+        * by other means, assume the CRT is connected and use that EDID.
+        */
+       if ((!rdev->is_atom_bios) &&
+           (ret == connector_status_disconnected) &&
+           rdev->mode_info.bios_hardcoded_edid_size) {
+               ret = connector_status_connected;
+       }
+
        radeon_connector_update_scratch_regs(connector, ret);
        return ret;
 }
@@ -790,6 +807,8 @@ static int radeon_dvi_get_modes(struct drm_connector *connector)
 static enum drm_connector_status
 radeon_dvi_detect(struct drm_connector *connector, bool force)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct drm_encoder *encoder = NULL;
        struct drm_encoder_helper_funcs *encoder_funcs;
@@ -829,8 +848,6 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                         * you don't really know what's connected to which port as both are digital.
                         */
                        if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
-                               struct drm_device *dev = connector->dev;
-                               struct radeon_device *rdev = dev->dev_private;
                                struct drm_connector *list_connector;
                                struct radeon_connector *list_radeon_connector;
                                list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
@@ -895,6 +912,19 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
        }
 
+       /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
+        * vbios to deal with KVMs. If we have one and are not able to detect a monitor
+        * by other means, assume the DFP is connected and use that EDID.  In most
+        * cases the DVI port is actually a virtual KVM port connected to the service
+        * processor.
+        */
+       if ((!rdev->is_atom_bios) &&
+           (ret == connector_status_disconnected) &&
+           rdev->mode_info.bios_hardcoded_edid_size) {
+               radeon_connector->use_digital = true;
+               ret = connector_status_connected;
+       }
+
 out:
        /* updated in get modes as well since we need to know if it's analog or digital */
        radeon_connector_update_scratch_regs(connector, ret);
@@ -1526,6 +1556,17 @@ radeon_add_legacy_connector(struct drm_device *dev,
                connector->polled = DRM_CONNECTOR_POLL_HPD;
        connector->display_info.subpixel_order = subpixel_order;
        drm_sysfs_connector_add(connector);
+       if (connector_type == DRM_MODE_CONNECTOR_LVDS) {
+               struct drm_encoder *drm_encoder;
+
+               list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) {
+                       struct radeon_encoder *radeon_encoder;
+
+                       radeon_encoder = to_radeon_encoder(drm_encoder);
+                       if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS)
+                               radeon_legacy_backlight_init(radeon_encoder, connector);
+               }
+       }
        return;
 
 failed:
index 66c9af1b3d9690a1a38d9b1a08f8b888ac276f17..41a5d48e657b61b7d511977b81ad1c6622e10554 100644 (file)
@@ -889,7 +889,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
                }
 
                if (rdev->flags & RADEON_IS_MOBILITY) {
-                       /* A temporal workaround for the occational blanking on certain laptop panels.
+                       /* A temporal workaround for the occasional blanking on certain laptop panels.
                           This appears to related to the PLL divider registers (fail to lock?).
                           It occurs even when all dividers are the same with their old settings.
                           In this case we really don't need to fiddle with PLL registers.
index 59f834ba283dd3fa15dde00b373c6a330d62decc..5b54268ed6b2c9e881b664e04ba05d421eea404d 100644 (file)
 #include "radeon_drm.h"
 #include "radeon.h"
 #include "atom.h"
+#include <linux/backlight.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 
 static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
 {
@@ -39,7 +43,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
        radeon_encoder->active_device = 0;
 }
 
-static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -47,15 +51,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
        uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
        int panel_pwr_delay = 2000;
        bool is_mac = false;
+       uint8_t backlight_level;
        DRM_DEBUG_KMS("\n");
 
+       lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+       backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
        if (radeon_encoder->enc_priv) {
                if (rdev->is_atom_bios) {
                        struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
                        panel_pwr_delay = lvds->panel_pwr_delay;
+                       if (lvds->bl_dev)
+                               backlight_level = lvds->backlight_level;
                } else {
                        struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
                        panel_pwr_delay = lvds->panel_pwr_delay;
+                       if (lvds->bl_dev)
+                               backlight_level = lvds->backlight_level;
                }
        }
 
@@ -82,11 +94,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
                lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
                WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
 
-               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
-               lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+               lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
+                                  RADEON_LVDS_BL_MOD_LEVEL_MASK);
+               lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
+                                 RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
+                                 (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
                if (is_mac)
                        lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
-               lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
                udelay(panel_pwr_delay * 1000);
                WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
                break;
@@ -95,7 +109,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
        case DRM_MODE_DPMS_OFF:
                pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
                WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
-               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
                lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
                if (is_mac) {
                        lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
@@ -119,6 +132,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
 
 }
 
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       DRM_DEBUG("\n");
+
+       if (radeon_encoder->enc_priv) {
+               if (rdev->is_atom_bios) {
+                       struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+                       lvds->dpms_mode = mode;
+               } else {
+                       struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+                       lvds->dpms_mode = mode;
+               }
+       }
+
+       radeon_legacy_lvds_update(encoder, mode);
+}
+
 static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
@@ -237,9 +269,222 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
        .disable = radeon_legacy_encoder_disable,
 };
 
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+
+#define MAX_RADEON_LEVEL 0xFF
+
+struct radeon_backlight_privdata {
+       struct radeon_encoder *encoder;
+       uint8_t negative;
+};
+
+static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
+{
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       uint8_t level;
+
+       /* Convert brightness to hardware level */
+       if (bd->props.brightness < 0)
+               level = 0;
+       else if (bd->props.brightness > MAX_RADEON_LEVEL)
+               level = MAX_RADEON_LEVEL;
+       else
+               level = bd->props.brightness;
+
+       if (pdata->negative)
+               level = MAX_RADEON_LEVEL - level;
+
+       return level;
+}
+
+static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
+{
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       struct radeon_encoder *radeon_encoder = pdata->encoder;
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int dpms_mode = DRM_MODE_DPMS_ON;
+
+       if (radeon_encoder->enc_priv) {
+               if (rdev->is_atom_bios) {
+                       struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+                       dpms_mode = lvds->dpms_mode;
+                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
+               } else {
+                       struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+                       dpms_mode = lvds->dpms_mode;
+                       lvds->backlight_level = radeon_legacy_lvds_level(bd);
+               }
+       }
+
+       if (bd->props.brightness > 0)
+               radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
+       else
+               radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF);
+
+       return 0;
+}
+
+static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
+{
+       struct radeon_backlight_privdata *pdata = bl_get_data(bd);
+       struct radeon_encoder *radeon_encoder = pdata->encoder;
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint8_t backlight_level;
+
+       backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+                          RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+       return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level;
+}
+
+static const struct backlight_ops radeon_backlight_ops = {
+       .get_brightness = radeon_legacy_backlight_get_brightness,
+       .update_status  = radeon_legacy_backlight_update_status,
+};
+
+void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
+                                 struct drm_connector *drm_connector)
+{
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct backlight_device *bd;
+       struct backlight_properties props;
+       struct radeon_backlight_privdata *pdata;
+       uint8_t backlight_level;
+
+       if (!radeon_encoder->enc_priv)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!pmac_has_backlight_type("ati") &&
+           !pmac_has_backlight_type("mnca"))
+               return;
+#endif
+
+       pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
+       if (!pdata) {
+               DRM_ERROR("Memory allocation failed\n");
+               goto error;
+       }
+
+       props.max_brightness = MAX_RADEON_LEVEL;
+       props.type = BACKLIGHT_RAW;
+       bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
+                                      pdata, &radeon_backlight_ops, &props);
+       if (IS_ERR(bd)) {
+               DRM_ERROR("Backlight registration failed\n");
+               goto error;
+       }
+
+       pdata->encoder = radeon_encoder;
+
+       backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
+                          RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
+
+       /* First, try to detect backlight level sense based on the assumption
+        * that firmware set it up at full brightness
+        */
+       if (backlight_level == 0)
+               pdata->negative = true;
+       else if (backlight_level == 0xff)
+               pdata->negative = false;
+       else {
+               /* XXX hack... maybe some day we can figure out in what direction
+                * backlight should work on a given panel?
+                */
+               pdata->negative = (rdev->family != CHIP_RV200 &&
+                                  rdev->family != CHIP_RV250 &&
+                                  rdev->family != CHIP_RV280 &&
+                                  rdev->family != CHIP_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+               pdata->negative = (pdata->negative ||
+                                  of_machine_is_compatible("PowerBook4,3") ||
+                                  of_machine_is_compatible("PowerBook6,3") ||
+                                  of_machine_is_compatible("PowerBook6,5"));
+#endif
+       }
+
+       if (rdev->is_atom_bios) {
+               struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+               lvds->bl_dev = bd;
+       } else {
+               struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+               lvds->bl_dev = bd;
+       }
+
+       bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
+       bd->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(bd);
+
+       DRM_INFO("radeon legacy LVDS backlight initialized\n");
+
+       return;
+
+error:
+       kfree(pdata);
+       return;
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
+{
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct backlight_device *bd = NULL;
+
+       if (!radeon_encoder->enc_priv)
+               return;
+
+       if (rdev->is_atom_bios) {
+               struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+               bd = lvds->bl_dev;
+               lvds->bl_dev = NULL;
+       } else {
+               struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+               bd = lvds->bl_dev;
+               lvds->bl_dev = NULL;
+       }
+
+       if (bd) {
+               struct radeon_legacy_backlight_privdata *pdata;
+
+               pdata = bl_get_data(bd);
+               backlight_device_unregister(bd);
+               kfree(pdata);
+
+               DRM_INFO("radeon legacy LVDS backlight unloaded\n");
+       }
+}
+
+#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+void radeon_legacy_backlight_init(struct radeon_encoder *encoder)
+{
+}
+
+static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder)
+{
+}
+
+#endif
+
+
+static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+       if (radeon_encoder->enc_priv) {
+               radeon_legacy_backlight_exit(radeon_encoder);
+               kfree(radeon_encoder->enc_priv);
+       }
+       drm_encoder_cleanup(encoder);
+       kfree(radeon_encoder);
+}
 
 static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
-       .destroy = radeon_enc_destroy,
+       .destroy = radeon_lvds_enc_destroy,
 };
 
 static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
index 5067d18d0009c2bff5c326e90ee7fcb3468bfd81..9c57538231d5f2c9b42c1516797472e149583f04 100644 (file)
@@ -239,6 +239,7 @@ struct radeon_mode_info {
        struct drm_property *underscan_vborder_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
+       int bios_hardcoded_edid_size;
 
        /* pointer to fbdev info structure */
        struct radeon_fbdev *rfbdev;
@@ -302,6 +303,9 @@ struct radeon_encoder_lvds {
        uint32_t lvds_gen_cntl;
        /* panel mode */
        struct drm_display_mode native_mode;
+       struct backlight_device *bl_dev;
+       int      dpms_mode;
+       uint8_t  backlight_level;
 };
 
 struct radeon_encoder_tv_dac {
@@ -355,6 +359,9 @@ struct radeon_encoder_atom_dig {
        uint32_t lcd_ss_id;
        /* panel mode */
        struct drm_display_mode native_mode;
+       struct backlight_device *bl_dev;
+       int dpms_mode;
+       uint8_t backlight_level;
 };
 
 struct radeon_encoder_atom_dac {
index 2aed03bde4b2ad3bf40963d7acc1f66afa843da2..08de669e025ab9bddf0bd118a457288bbb2b49e0 100644 (file)
@@ -365,12 +365,14 @@ static ssize_t radeon_set_pm_profile(struct device *dev,
                else if (strncmp("high", buf, strlen("high")) == 0)
                        rdev->pm.profile = PM_PROFILE_HIGH;
                else {
-                       DRM_ERROR("invalid power profile!\n");
+                       count = -EINVAL;
                        goto fail;
                }
                radeon_pm_update_profile(rdev);
                radeon_pm_set_clocks(rdev);
-       }
+       } else
+               count = -EINVAL;
+
 fail:
        mutex_unlock(&rdev->pm.mutex);
 
@@ -413,7 +415,7 @@ static ssize_t radeon_set_pm_method(struct device *dev,
                mutex_unlock(&rdev->pm.mutex);
                cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
        } else {
-               DRM_ERROR("invalid power method!\n");
+               count = -EINVAL;
                goto fail;
        }
        radeon_pm_compute_clocks(rdev);
index 61aa712333927815e5cb9d0d4777e8de3dacd1af..b85744fe846477221ad02221f78bb397c603f54d 100644 (file)
@@ -481,6 +481,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index c3d66269ed7d584bb655be926cef4b8e073699a9..e9687768a335d5461e1ed7785d0d8bd551af3724 100644 (file)
@@ -1333,6 +1333,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1840,6 +1843,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_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) },
        { }
index d485894ff4db877f2045db8c21934cbd2d41d547..65ac53d7aeccf86a9f3a0c1e7a6a9c00af0a470f 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
index cd74203c8178950408b95cb51dd69b01ccb1ceea..33dde8724e02faec04fe1388103343a4cf03eda2 100644 (file)
@@ -900,8 +900,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                        hid->ll_driver->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
-                               input_dev->setkeycode_new = hidinput_setkeycode;
-                               input_dev->getkeycode_new = hidinput_getkeycode;
+                               input_dev->setkeycode = hidinput_setkeycode;
+                               input_dev->getkeycode = hidinput_getkeycode;
 
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
index de9cf21b3494c39d7a105f75a90078ebfe8b145e..657da5a3d5c6213040dbea89f2de4339bf19dfd8 100644 (file)
@@ -944,6 +944,7 @@ static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *
        }
 
        memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 0xff;
        bdev = backlight_device_register(dev_name(dev), dev, data,
                        &picolcd_blops, &props);
index 1bfb4439e4e1cb34fa4cb31a71eaf9a7db024071..81131eda5544a6715a0d71e4e8902537a951b4fa 100644 (file)
@@ -521,7 +521,7 @@ config SENSORS_LM75
                - Dallas Semiconductor DS75 and DS1775
                - Maxim MAX6625 and MAX6626
                - Microchip MCP980x
-               - National Semiconductor LM75
+               - National Semiconductor LM75, LM75A
                - NXP's LM75A
                - ST Microelectronics STDS75
                - TelCom (now Microchip) TCN75
@@ -959,6 +959,25 @@ config SENSORS_SMSC47B397
          This driver can also be built as a module.  If so, the module
          will be called smsc47b397.
 
+config SENSORS_SCH5627
+       tristate "SMSC SCH5627"
+       help
+         If you say yes here you get support for the hardware monitoring
+         features of the SMSC SCH5627 Super-I/O chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called sch5627.
+
+config SENSORS_ADS1015
+       tristate "Texas Instruments ADS1015"
+       depends on I2C
+       help
+         If you say yes here you get support for Texas Instruments ADS1015
+         12-bit 4-input ADC device.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ads1015.
+
 config SENSORS_ADS7828
        tristate "Texas Instruments ADS7828"
        depends on I2C
@@ -1028,6 +1047,16 @@ config SENSORS_TMP421
          This driver can also be built as a module.  If so, the module
          will be called tmp421.
 
+config SENSORS_TWL4030_MADC
+       tristate "Texas Instruments TWL4030 MADC Hwmon"
+       depends on TWL4030_MADC
+       help
+       If you say yes here you get hwmon support for triton
+       TWL4030-MADC.
+
+       This driver can also be built as a module. If so it will be called
+       twl4030-madc-hwmon.
+
 config SENSORS_VIA_CPUTEMP
        tristate "VIA CPU temperature sensor"
        depends on X86
@@ -1215,40 +1244,6 @@ config SENSORS_ULTRA45
          This driver provides support for the Ultra45 workstation environmental
          sensors.
 
-config SENSORS_LIS3_SPI
-       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
-       depends on !ACPI && SPI_MASTER && INPUT
-       select INPUT_POLLDEV
-       default n
-       help
-         This driver provides support for the LIS3LV02Dx accelerometer connected
-         via SPI. The accelerometer data is readable via
-         /sys/devices/platform/lis3lv02d.
-
-         This driver also provides an absolute input class device, allowing
-         the laptop to act as a pinball machine-esque joystick.
-
-         This driver can also be built as modules.  If so, the core module
-         will be called lis3lv02d and a specific module for the SPI transport
-         is called lis3lv02d_spi.
-
-config SENSORS_LIS3_I2C
-       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
-       depends on I2C && INPUT
-       select INPUT_POLLDEV
-       default n
-       help
-         This driver provides support for the LIS3LV02Dx accelerometer connected
-         via I2C. The accelerometer data is readable via
-         /sys/devices/platform/lis3lv02d.
-
-         This driver also provides an absolute input class device, allowing
-         the device to act as a pinball machine-esque joystick.
-
-         This driver can also be built as modules.  If so, the core module
-         will be called lis3lv02d and a specific module for the I2C transport
-         is called lis3lv02d_i2c.
-
 config SENSORS_APPLESMC
        tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
        depends on INPUT && X86
@@ -1296,36 +1291,6 @@ config SENSORS_ATK0110
          This driver can also be built as a module. If so, the module
          will be called asus_atk0110.
 
-config SENSORS_LIS3LV02D
-       tristate "STMicroeletronics LIS3* three-axis digital accelerometer"
-       depends on INPUT
-       select INPUT_POLLDEV
-       select NEW_LEDS
-       select LEDS_CLASS
-       default n
-       help
-         This driver provides support for the LIS3* accelerometers, such as the
-         LIS3LV02DL or the LIS331DL. In particular, it can be found in a number
-         of HP laptops, which have the "Mobile Data Protection System 3D" or
-         "3D DriveGuard" feature. On such systems the driver should load
-         automatically (via ACPI alias). The accelerometer might also be found
-         in other systems, connected via SPI or I2C. The accelerometer data is
-         readable via /sys/devices/platform/lis3lv02d.
-
-         This driver also provides an absolute input class device, allowing
-         a laptop to act as a pinball machine-esque joystick. It provides also
-         a misc device which can be used to detect free-fall. On HP laptops,
-         if the led infrastructure is activated, support for a led indicating
-         disk protection will be provided as hp::hddprotect. For more
-         information on the feature, refer to Documentation/hwmon/lis3lv02d.
-
-         This driver can also be built as modules.  If so, the core module
-         will be called lis3lv02d and a specific module for HP laptops will be
-         called hp_accel.
-
-         Say Y here if you have an applicable laptop and want to experience
-         the awesome power of lis3lv02d.
-
 endif # ACPI
 
 endif # HWMON
index bd0410e4b44f2fdbf39769a305291362c120bb35..967d0ea9447feaab002f5ae8cc9e2a5423a324ef 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
 obj-$(CONFIG_SENSORS_ADM1029)  += adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)  += adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)  += adm9240.o
+obj-$(CONFIG_SENSORS_ADS1015)  += ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
 obj-$(CONFIG_SENSORS_ADT7411)  += adt7411.o
@@ -63,9 +64,6 @@ obj-$(CONFIG_SENSORS_JZ4740)  += jz4740-hwmon.o
 obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
 obj-$(CONFIG_SENSORS_K10TEMP)  += k10temp.o
 obj-$(CONFIG_SENSORS_LINEAGE)  += lineage-pem.o
-obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
-obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
-obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o
 obj-$(CONFIG_SENSORS_LM63)     += lm63.o
 obj-$(CONFIG_SENSORS_LM70)     += lm70.o
 obj-$(CONFIG_SENSORS_LM73)     += lm73.o
@@ -93,6 +91,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
 obj-$(CONFIG_SENSORS_S3C)      += s3c-hwmon.o
+obj-$(CONFIG_SENSORS_SCH5627)  += sch5627.o
 obj-$(CONFIG_SENSORS_SHT15)    += sht15.o
 obj-$(CONFIG_SENSORS_SHT21)    += sht21.o
 obj-$(CONFIG_SENSORS_SIS5595)  += sis5595.o
@@ -105,6 +104,7 @@ obj-$(CONFIG_SENSORS_THMC50)        += thmc50.o
 obj-$(CONFIG_SENSORS_TMP102)   += tmp102.o
 obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_TMP421)   += tmp421.o
+obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
 obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
 obj-$(CONFIG_SENSORS_VIA686A)  += via686a.o
 obj-$(CONFIG_SENSORS_VT1211)   += vt1211.o
@@ -122,7 +122,5 @@ obj-$(CONFIG_SENSORS_MAX16064)      += max16064.o
 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
 obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
 
-ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
 
index 8f07a9dda15216073df1cd937f68d33787e71306..0e05aa179eaa09c1c52763be60a84d1d41d3d3db 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.nl>
+    abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -1505,7 +1505,7 @@ static void __exit abituguru_exit(void)
        platform_driver_unregister(&abituguru_driver);
 }
 
-MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Abit uGuru Sensor device");
 MODULE_LICENSE("GPL");
 
index 48d21e22e9302a66e2d8b467ea5c42532875514e..034cebfcd273cec998779f3c50b5da473f696d1a 100644 (file)
@@ -1,7 +1,7 @@
 /*
     abituguru3.c
 
-    Copyright (c) 2006-2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+    Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
     Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
 
     This program is free software; you can redistribute it and/or modify
@@ -1266,7 +1266,7 @@ static void __exit abituguru3_exit(void)
        platform_driver_unregister(&abituguru3_driver);
 }
 
-MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
new file mode 100644 (file)
index 0000000..e9beeda
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
+ * (C) Copyright 2010
+ * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
+ *
+ * Based on the ads7828 driver by Steve Hardy.
+ *
+ * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+
+#include <linux/i2c/ads1015.h>
+
+/* ADS1015 registers */
+enum {
+       ADS1015_CONVERSION = 0,
+       ADS1015_CONFIG = 1,
+};
+
+/* PGA fullscale voltages in mV */
+static const unsigned int fullscale_table[8] = {
+       6144, 4096, 2048, 1024, 512, 256, 256, 256 };
+
+/* Data rates in samples per second */
+static const unsigned int data_rate_table[8] = {
+       128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+
+#define ADS1015_DEFAULT_CHANNELS 0xff
+#define ADS1015_DEFAULT_PGA 2
+#define ADS1015_DEFAULT_DATA_RATE 4
+
+struct ads1015_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock; /* mutex protect updates */
+       struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+};
+
+static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
+{
+       s32 data = i2c_smbus_read_word_data(client, reg);
+
+       return (data < 0) ? data : swab16(data);
+}
+
+static s32 ads1015_write_reg(struct i2c_client *client, unsigned int reg,
+                            u16 val)
+{
+       return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
+                             int *value)
+{
+       u16 config;
+       s16 conversion;
+       struct ads1015_data *data = i2c_get_clientdata(client);
+       unsigned int pga = data->channel_data[channel].pga;
+       int fullscale;
+       unsigned int data_rate = data->channel_data[channel].data_rate;
+       unsigned int conversion_time_ms;
+       int res;
+
+       mutex_lock(&data->update_lock);
+
+       /* get channel parameters */
+       res = ads1015_read_reg(client, ADS1015_CONFIG);
+       if (res < 0)
+               goto err_unlock;
+       config = res;
+       fullscale = fullscale_table[pga];
+       conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
+
+       /* setup and start single conversion */
+       config &= 0x001f;
+       config |= (1 << 15) | (1 << 8);
+       config |= (channel & 0x0007) << 12;
+       config |= (pga & 0x0007) << 9;
+       config |= (data_rate & 0x0007) << 5;
+
+       res = ads1015_write_reg(client, ADS1015_CONFIG, config);
+       if (res < 0)
+               goto err_unlock;
+
+       /* wait until conversion finished */
+       msleep(conversion_time_ms);
+       res = ads1015_read_reg(client, ADS1015_CONFIG);
+       if (res < 0)
+               goto err_unlock;
+       config = res;
+       if (!(config & (1 << 15))) {
+               /* conversion not finished in time */
+               res = -EIO;
+               goto err_unlock;
+       }
+
+       res = ads1015_read_reg(client, ADS1015_CONVERSION);
+       if (res < 0)
+               goto err_unlock;
+       conversion = res;
+
+       mutex_unlock(&data->update_lock);
+
+       *value = DIV_ROUND_CLOSEST(conversion * fullscale, 0x7ff0);
+
+       return 0;
+
+err_unlock:
+       mutex_unlock(&data->update_lock);
+       return res;
+}
+
+/* sysfs callback function */
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+       char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct i2c_client *client = to_i2c_client(dev);
+       int in;
+       int res;
+
+       res = ads1015_read_value(client, attr->index, &in);
+
+       return (res < 0) ? res : sprintf(buf, "%d\n", in);
+}
+
+static const struct sensor_device_attribute ads1015_in[] = {
+       SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+       SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+       SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+       SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+       SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+       SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+       SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+       SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+};
+
+/*
+ * Driver interface
+ */
+
+static int ads1015_remove(struct i2c_client *client)
+{
+       struct ads1015_data *data = i2c_get_clientdata(client);
+       int k;
+
+       hwmon_device_unregister(data->hwmon_dev);
+       for (k = 0; k < ADS1015_CHANNELS; ++k)
+               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
+       kfree(data);
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static int ads1015_get_channels_config_of(struct i2c_client *client)
+{
+       struct ads1015_data *data = i2c_get_clientdata(client);
+       struct device_node *node;
+
+       if (!client->dev.of_node
+           || !of_get_next_child(client->dev.of_node, NULL))
+               return -EINVAL;
+
+       for_each_child_of_node(client->dev.of_node, node) {
+               const __be32 *property;
+               int len;
+               unsigned int channel;
+               unsigned int pga = ADS1015_DEFAULT_PGA;
+               unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
+
+               property = of_get_property(node, "reg", &len);
+               if (!property || len != sizeof(int)) {
+                       dev_err(&client->dev, "invalid reg on %s\n",
+                               node->full_name);
+                       continue;
+               }
+
+               channel = be32_to_cpup(property);
+               if (channel > ADS1015_CHANNELS) {
+                       dev_err(&client->dev,
+                               "invalid channel index %d on %s\n",
+                               channel, node->full_name);
+                       continue;
+               }
+
+               property = of_get_property(node, "ti,gain", &len);
+               if (property && len == sizeof(int)) {
+                       pga = be32_to_cpup(property);
+                       if (pga > 6) {
+                               dev_err(&client->dev,
+                                       "invalid gain on %s\n",
+                                       node->full_name);
+                       }
+               }
+
+               property = of_get_property(node, "ti,datarate", &len);
+               if (property && len == sizeof(int)) {
+                       data_rate = be32_to_cpup(property);
+                       if (data_rate > 7) {
+                               dev_err(&client->dev,
+                                       "invalid data_rate on %s\n",
+                                       node->full_name);
+                       }
+               }
+
+               data->channel_data[channel].enabled = true;
+               data->channel_data[channel].pga = pga;
+               data->channel_data[channel].data_rate = data_rate;
+       }
+
+       return 0;
+}
+#endif
+
+static void ads1015_get_channels_config(struct i2c_client *client)
+{
+       unsigned int k;
+       struct ads1015_data *data = i2c_get_clientdata(client);
+       struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
+
+       /* prefer platform data */
+       if (pdata) {
+               memcpy(data->channel_data, pdata->channel_data,
+                      sizeof(data->channel_data));
+               return;
+       }
+
+#ifdef CONFIG_OF
+       if (!ads1015_get_channels_config_of(client))
+               return;
+#endif
+
+       /* fallback on default configuration */
+       for (k = 0; k < ADS1015_CHANNELS; ++k) {
+               data->channel_data[k].enabled = true;
+               data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
+               data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
+       }
+}
+
+static int ads1015_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct ads1015_data *data;
+       int err;
+       unsigned int k;
+
+       data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* build sysfs attribute group */
+       ads1015_get_channels_config(client);
+       for (k = 0; k < ADS1015_CHANNELS; ++k) {
+               if (!data->channel_data[k].enabled)
+                       continue;
+               err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
+               if (err)
+                       goto exit_free;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       for (k = 0; k < ADS1015_CHANNELS; ++k)
+               device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static const struct i2c_device_id ads1015_id[] = {
+       { "ads1015", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ads1015_id);
+
+static struct i2c_driver ads1015_driver = {
+       .driver = {
+               .name = "ads1015",
+       },
+       .probe = ads1015_probe,
+       .remove = ads1015_remove,
+       .id_table = ads1015_id,
+};
+
+static int __init sensors_ads1015_init(void)
+{
+       return i2c_add_driver(&ads1015_driver);
+}
+
+static void __exit sensors_ads1015_exit(void)
+{
+       i2c_del_driver(&ads1015_driver);
+}
+
+MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
+MODULE_DESCRIPTION("ADS1015 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_ads1015_init);
+module_exit(sensors_ads1015_exit);
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
deleted file mode 100644 (file)
index 3d21fa2..0000000
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- *  hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS
- *
- *  Copyright (C) 2007-2008 Yan Burman
- *  Copyright (C) 2008 Eric Piel
- *  Copyright (C) 2008-2009 Pavel Machek
- *
- *  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
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
-#include <linux/poll.h>
-#include <linux/freezer.h>
-#include <linux/uaccess.h>
-#include <linux/leds.h>
-#include <acpi/acpi_drivers.h>
-#include <asm/atomic.h>
-#include "lis3lv02d.h"
-
-#define DRIVER_NAME     "lis3lv02d"
-#define ACPI_MDPS_CLASS "accelerometer"
-
-/* Delayed LEDs infrastructure ------------------------------------ */
-
-/* Special LED class that can defer work */
-struct delayed_led_classdev {
-       struct led_classdev led_classdev;
-       struct work_struct work;
-       enum led_brightness new_brightness;
-
-       unsigned int led;               /* For driver */
-       void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value);
-};
-
-static inline void delayed_set_status_worker(struct work_struct *work)
-{
-       struct delayed_led_classdev *data =
-                       container_of(work, struct delayed_led_classdev, work);
-
-       data->set_brightness(data, data->new_brightness);
-}
-
-static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
-                             enum led_brightness brightness)
-{
-       struct delayed_led_classdev *data = container_of(led_cdev,
-                            struct delayed_led_classdev, led_classdev);
-       data->new_brightness = brightness;
-       schedule_work(&data->work);
-}
-
-/* HP-specific accelerometer driver ------------------------------------ */
-
-/* For automatic insertion of the module */
-static struct acpi_device_id lis3lv02d_device_ids[] = {
-       {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
-
-
-/**
- * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
- * @lis3: pointer to the device struct
- *
- * Returns 0 on success.
- */
-int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
-{
-       struct acpi_device *dev = lis3->bus_priv;
-       if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
-                                NULL, NULL) != AE_OK)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- * lis3lv02d_acpi_read - ACPI ALRD method: read a register
- * @lis3: pointer to the device struct
- * @reg:    the register to read
- * @ret:    result of the operation
- *
- * Returns 0 on success.
- */
-int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
-{
-       struct acpi_device *dev = lis3->bus_priv;
-       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list args = { 1, &arg0 };
-       unsigned long long lret;
-       acpi_status status;
-
-       arg0.integer.value = reg;
-
-       status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret);
-       *ret = lret;
-       return (status != AE_OK) ? -EINVAL : 0;
-}
-
-/**
- * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
- * @lis3: pointer to the device struct
- * @reg:    the register to write to
- * @val:    the value to write
- *
- * Returns 0 on success.
- */
-int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
-{
-       struct acpi_device *dev = lis3->bus_priv;
-       unsigned long long ret; /* Not used when writting */
-       union acpi_object in_obj[2];
-       struct acpi_object_list args = { 2, in_obj };
-
-       in_obj[0].type          = ACPI_TYPE_INTEGER;
-       in_obj[0].integer.value = reg;
-       in_obj[1].type          = ACPI_TYPE_INTEGER;
-       in_obj[1].integer.value = val;
-
-       if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
-{
-       lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
-       pr_info("hardware type %s found\n", dmi->ident);
-
-       return 1;
-}
-
-/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
- * If the value is negative, the opposite of the hw value is used. */
-#define DEFINE_CONV(name, x, y, z)                           \
-       static union axis_conversion lis3lv02d_axis_##name = \
-               { .as_array = { x, y, z } }
-DEFINE_CONV(normal, 1, 2, 3);
-DEFINE_CONV(y_inverted, 1, -2, 3);
-DEFINE_CONV(x_inverted, -1, 2, 3);
-DEFINE_CONV(z_inverted, 1, 2, -3);
-DEFINE_CONV(xy_swap, 2, 1, 3);
-DEFINE_CONV(xy_rotated_left, -2, 1, 3);
-DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
-DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
-DEFINE_CONV(xy_rotated_right, 2, -1, 3);
-DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
-
-#define AXIS_DMI_MATCH(_ident, _name, _axis) {         \
-       .ident = _ident,                                \
-       .callback = lis3lv02d_dmi_matched,              \
-       .matches = {                                    \
-               DMI_MATCH(DMI_PRODUCT_NAME, _name)      \
-       },                                              \
-       .driver_data = &lis3lv02d_axis_##_axis          \
-}
-
-#define AXIS_DMI_MATCH2(_ident, _class1, _name1,       \
-                               _class2, _name2,        \
-                               _axis) {                \
-       .ident = _ident,                                \
-       .callback = lis3lv02d_dmi_matched,              \
-       .matches = {                                    \
-               DMI_MATCH(DMI_##_class1, _name1),       \
-               DMI_MATCH(DMI_##_class2, _name2),       \
-       },                                              \
-       .driver_data = &lis3lv02d_axis_##_axis          \
-}
-static struct dmi_system_id lis3lv02d_dmi_ids[] = {
-       /* product names are truncated to match all kinds of a same model */
-       AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
-       AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
-       AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
-       AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
-       AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
-       AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
-       AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
-       AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
-       AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
-       AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
-       AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd),
-       AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap),
-       AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
-       AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
-       AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
-       AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
-       AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap),
-       /* Intel-based HP Pavilion dv5 */
-       AXIS_DMI_MATCH2("HPDV5_I",
-                       PRODUCT_NAME, "HP Pavilion dv5",
-                       BOARD_NAME, "3603",
-                       x_inverted),
-       /* AMD-based HP Pavilion dv5 */
-       AXIS_DMI_MATCH2("HPDV5_A",
-                       PRODUCT_NAME, "HP Pavilion dv5",
-                       BOARD_NAME, "3600",
-                       y_inverted),
-       AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted),
-       AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted),
-       AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
-       AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
-       AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
-       AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
-       AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
-       AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
-       AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
-       { NULL, }
-/* Laptop models without axis info (yet):
- * "NC6910" "HP Compaq 6910"
- * "NC2400" "HP Compaq nc2400"
- * "NX74x0" "HP Compaq nx74"
- * "NX6325" "HP Compaq nx6325"
- * "NC4400" "HP Compaq nc4400"
- */
-};
-
-static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
-{
-       struct acpi_device *dev = lis3_dev.bus_priv;
-       unsigned long long ret; /* Not used when writing */
-       union acpi_object in_obj[1];
-       struct acpi_object_list args = { 1, in_obj };
-
-       in_obj[0].type          = ACPI_TYPE_INTEGER;
-       in_obj[0].integer.value = !!value;
-
-       acpi_evaluate_integer(dev->handle, "ALED", &args, &ret);
-}
-
-static struct delayed_led_classdev hpled_led = {
-       .led_classdev = {
-               .name                   = "hp::hddprotect",
-               .default_trigger        = "none",
-               .brightness_set         = delayed_sysfs_set,
-               .flags                  = LED_CORE_SUSPENDRESUME,
-       },
-       .set_brightness = hpled_set,
-};
-
-static acpi_status
-lis3lv02d_get_resource(struct acpi_resource *resource, void *context)
-{
-       if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
-               struct acpi_resource_extended_irq *irq;
-               u32 *device_irq = context;
-
-               irq = &resource->data.extended_irq;
-               *device_irq = irq->interrupts[0];
-       }
-
-       return AE_OK;
-}
-
-static void lis3lv02d_enum_resources(struct acpi_device *device)
-{
-       acpi_status status;
-
-       status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                                       lis3lv02d_get_resource, &lis3_dev.irq);
-       if (ACPI_FAILURE(status))
-               printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
-}
-
-static int lis3lv02d_add(struct acpi_device *device)
-{
-       int ret;
-
-       if (!device)
-               return -EINVAL;
-
-       lis3_dev.bus_priv = device;
-       lis3_dev.init = lis3lv02d_acpi_init;
-       lis3_dev.read = lis3lv02d_acpi_read;
-       lis3_dev.write = lis3lv02d_acpi_write;
-       strcpy(acpi_device_name(device), DRIVER_NAME);
-       strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
-       device->driver_data = &lis3_dev;
-
-       /* obtain IRQ number of our device from ACPI */
-       lis3lv02d_enum_resources(device);
-
-       /* If possible use a "standard" axes order */
-       if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
-               pr_info("Using custom axes %d,%d,%d\n",
-                       lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
-       } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
-               pr_info("laptop model unknown, using default axes configuration\n");
-               lis3_dev.ac = lis3lv02d_axis_normal;
-       }
-
-       /* call the core layer do its init */
-       ret = lis3lv02d_init_device(&lis3_dev);
-       if (ret)
-               return ret;
-
-       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
-       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
-       if (ret) {
-               lis3lv02d_joystick_disable();
-               lis3lv02d_poweroff(&lis3_dev);
-               flush_work(&hpled_led.work);
-               return ret;
-       }
-
-       return ret;
-}
-
-static int lis3lv02d_remove(struct acpi_device *device, int type)
-{
-       if (!device)
-               return -EINVAL;
-
-       lis3lv02d_joystick_disable();
-       lis3lv02d_poweroff(&lis3_dev);
-
-       led_classdev_unregister(&hpled_led.led_classdev);
-       flush_work(&hpled_led.work);
-
-       return lis3lv02d_remove_fs(&lis3_dev);
-}
-
-
-#ifdef CONFIG_PM
-static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
-{
-       /* make sure the device is off when we suspend */
-       lis3lv02d_poweroff(&lis3_dev);
-       return 0;
-}
-
-static int lis3lv02d_resume(struct acpi_device *device)
-{
-       lis3lv02d_poweron(&lis3_dev);
-       return 0;
-}
-#else
-#define lis3lv02d_suspend NULL
-#define lis3lv02d_resume NULL
-#endif
-
-/* For the HP MDPS aka 3D Driveguard */
-static struct acpi_driver lis3lv02d_driver = {
-       .name  = DRIVER_NAME,
-       .class = ACPI_MDPS_CLASS,
-       .ids   = lis3lv02d_device_ids,
-       .ops = {
-               .add     = lis3lv02d_add,
-               .remove  = lis3lv02d_remove,
-               .suspend = lis3lv02d_suspend,
-               .resume  = lis3lv02d_resume,
-       }
-};
-
-static int __init lis3lv02d_init_module(void)
-{
-       int ret;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       ret = acpi_bus_register_driver(&lis3lv02d_driver);
-       if (ret < 0)
-               return ret;
-
-       pr_info("driver loaded\n");
-
-       return 0;
-}
-
-static void __exit lis3lv02d_exit_module(void)
-{
-       acpi_bus_unregister_driver(&lis3lv02d_driver);
-}
-
-MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED.");
-MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
-MODULE_LICENSE("GPL");
-
-module_init(lis3lv02d_init_module);
-module_exit(lis3lv02d_exit_module);
-
index 1c8b3d9e205186c4018fc040eeffd305513f725f..fea292d43407cecba6e75b70021617f871d6b1b8 100644 (file)
@@ -32,7 +32,7 @@ struct jz4740_hwmon {
 
        int irq;
 
-       struct mfd_cell *cell;
+       const struct mfd_cell *cell;
        struct device *hwmon;
 
        struct completion read_completion;
@@ -112,7 +112,7 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       hwmon->cell = pdev->dev.platform_data;
+       hwmon->cell = mfd_get_cell(pdev);
 
        hwmon->irq = platform_get_irq(pdev, 0);
        if (hwmon->irq < 0) {
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
deleted file mode 100644 (file)
index d805e8e..0000000
+++ /dev/null
@@ -1,1000 +0,0 @@
-/*
- *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver
- *
- *  Copyright (C) 2007-2008 Yan Burman
- *  Copyright (C) 2008 Eric Piel
- *  Copyright (C) 2008-2009 Pavel Machek
- *
- *  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
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/input-polldev.h>
-#include <linux/delay.h>
-#include <linux/wait.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/freezer.h>
-#include <linux/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pm_runtime.h>
-#include <asm/atomic.h>
-#include "lis3lv02d.h"
-
-#define DRIVER_NAME     "lis3lv02d"
-
-/* joystick device poll interval in milliseconds */
-#define MDPS_POLL_INTERVAL 50
-#define MDPS_POLL_MIN     0
-#define MDPS_POLL_MAX     2000
-
-#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
-
-#define SELFTEST_OK           0
-#define SELFTEST_FAIL         -1
-#define SELFTEST_IRQ          -2
-
-#define IRQ_LINE0             0
-#define IRQ_LINE1             1
-
-/*
- * The sensor can also generate interrupts (DRDY) but it's pretty pointless
- * because they are generated even if the data do not change. So it's better
- * to keep the interrupt for the free-fall event. The values are updated at
- * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
- * some low processor, we poll the sensor only at 20Hz... enough for the
- * joystick.
- */
-
-#define LIS3_PWRON_DELAY_WAI_12B       (5000)
-#define LIS3_PWRON_DELAY_WAI_8B                (3000)
-
-/*
- * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG
- * LIS302D spec says: 18 mG / digit
- * LIS3_ACCURACY is used to increase accuracy of the intermediate
- * calculation results.
- */
-#define LIS3_ACCURACY                  1024
-/* Sensitivity values for -2G +2G scale */
-#define LIS3_SENSITIVITY_12B           ((LIS3_ACCURACY * 1000) / 1024)
-#define LIS3_SENSITIVITY_8B            (18 * LIS3_ACCURACY)
-
-#define LIS3_DEFAULT_FUZZ_12B          3
-#define LIS3_DEFAULT_FLAT_12B          3
-#define LIS3_DEFAULT_FUZZ_8B           1
-#define LIS3_DEFAULT_FLAT_8B           1
-
-struct lis3lv02d lis3_dev = {
-       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
-};
-
-EXPORT_SYMBOL_GPL(lis3_dev);
-
-/* just like param_set_int() but does sanity-check so that it won't point
- * over the axis array size
- */
-static int param_set_axis(const char *val, const struct kernel_param *kp)
-{
-       int ret = param_set_int(val, kp);
-       if (!ret) {
-               int val = *(int *)kp->arg;
-               if (val < 0)
-                       val = -val;
-               if (!val || val > 3)
-                       return -EINVAL;
-       }
-       return ret;
-}
-
-static struct kernel_param_ops param_ops_axis = {
-       .set = param_set_axis,
-       .get = param_get_int,
-};
-
-module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
-MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
-
-static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
-{
-       s8 lo;
-       if (lis3->read(lis3, reg, &lo) < 0)
-               return 0;
-
-       return lo;
-}
-
-static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
-{
-       u8 lo, hi;
-
-       lis3->read(lis3, reg - 1, &lo);
-       lis3->read(lis3, reg, &hi);
-       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
-       return (s16)((hi << 8) | lo);
-}
-
-/**
- * lis3lv02d_get_axis - For the given axis, give the value converted
- * @axis:      1,2,3 - can also be negative
- * @hw_values: raw values returned by the hardware
- *
- * Returns the converted value.
- */
-static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
-{
-       if (axis > 0)
-               return hw_values[axis - 1];
-       else
-               return -hw_values[-axis - 1];
-}
-
-/**
- * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
- * @lis3: pointer to the device struct
- * @x:    where to store the X axis value
- * @y:    where to store the Y axis value
- * @z:    where to store the Z axis value
- *
- * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
- */
-static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
-{
-       int position[3];
-       int i;
-
-       if (lis3->blkread) {
-               if (lis3_dev.whoami == WAI_12B) {
-                       u16 data[3];
-                       lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
-                       for (i = 0; i < 3; i++)
-                               position[i] = (s16)le16_to_cpu(data[i]);
-               } else {
-                       u8 data[5];
-                       /* Data: x, dummy, y, dummy, z */
-                       lis3->blkread(lis3, OUTX, 5, data);
-                       for (i = 0; i < 3; i++)
-                               position[i] = (s8)data[i * 2];
-               }
-       } else {
-               position[0] = lis3->read_data(lis3, OUTX);
-               position[1] = lis3->read_data(lis3, OUTY);
-               position[2] = lis3->read_data(lis3, OUTZ);
-       }
-
-       for (i = 0; i < 3; i++)
-               position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
-
-       *x = lis3lv02d_get_axis(lis3->ac.x, position);
-       *y = lis3lv02d_get_axis(lis3->ac.y, position);
-       *z = lis3lv02d_get_axis(lis3->ac.z, position);
-}
-
-/* conversion btw sampling rate and the register values */
-static int lis3_12_rates[4] = {40, 160, 640, 2560};
-static int lis3_8_rates[2] = {100, 400};
-static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
-
-/* ODR is Output Data Rate */
-static int lis3lv02d_get_odr(void)
-{
-       u8 ctrl;
-       int shift;
-
-       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-       ctrl &= lis3_dev.odr_mask;
-       shift = ffs(lis3_dev.odr_mask) - 1;
-       return lis3_dev.odrs[(ctrl >> shift)];
-}
-
-static int lis3lv02d_set_odr(int rate)
-{
-       u8 ctrl;
-       int i, len, shift;
-
-       if (!rate)
-               return -EINVAL;
-
-       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-       ctrl &= ~lis3_dev.odr_mask;
-       len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
-       shift = ffs(lis3_dev.odr_mask) - 1;
-
-       for (i = 0; i < len; i++)
-               if (lis3_dev.odrs[i] == rate) {
-                       lis3_dev.write(&lis3_dev, CTRL_REG1,
-                                       ctrl | (i << shift));
-                       return 0;
-               }
-       return -EINVAL;
-}
-
-static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
-{
-       u8 ctlreg, reg;
-       s16 x, y, z;
-       u8 selftest;
-       int ret;
-       u8 ctrl_reg_data;
-       unsigned char irq_cfg;
-
-       mutex_lock(&lis3->mutex);
-
-       irq_cfg = lis3->irq_cfg;
-       if (lis3_dev.whoami == WAI_8B) {
-               lis3->data_ready_count[IRQ_LINE0] = 0;
-               lis3->data_ready_count[IRQ_LINE1] = 0;
-
-               /* Change interrupt cfg to data ready for selftest */
-               atomic_inc(&lis3_dev.wake_thread);
-               lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
-               lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
-               lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
-                               ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
-                               (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
-       }
-
-       if (lis3_dev.whoami == WAI_3DC) {
-               ctlreg = CTRL_REG4;
-               selftest = CTRL4_ST0;
-       } else {
-               ctlreg = CTRL_REG1;
-               if (lis3_dev.whoami == WAI_12B)
-                       selftest = CTRL1_ST;
-               else
-                       selftest = CTRL1_STP;
-       }
-
-       lis3->read(lis3, ctlreg, &reg);
-       lis3->write(lis3, ctlreg, (reg | selftest));
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
-       /* Read directly to avoid axis remap */
-       x = lis3->read_data(lis3, OUTX);
-       y = lis3->read_data(lis3, OUTY);
-       z = lis3->read_data(lis3, OUTZ);
-
-       /* back to normal settings */
-       lis3->write(lis3, ctlreg, reg);
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
-       results[0] = x - lis3->read_data(lis3, OUTX);
-       results[1] = y - lis3->read_data(lis3, OUTY);
-       results[2] = z - lis3->read_data(lis3, OUTZ);
-
-       ret = 0;
-
-       if (lis3_dev.whoami == WAI_8B) {
-               /* Restore original interrupt configuration */
-               atomic_dec(&lis3_dev.wake_thread);
-               lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
-               lis3->irq_cfg = irq_cfg;
-
-               if ((irq_cfg & LIS3_IRQ1_MASK) &&
-                       lis3->data_ready_count[IRQ_LINE0] < 2) {
-                       ret = SELFTEST_IRQ;
-                       goto fail;
-               }
-
-               if ((irq_cfg & LIS3_IRQ2_MASK) &&
-                       lis3->data_ready_count[IRQ_LINE1] < 2) {
-                       ret = SELFTEST_IRQ;
-                       goto fail;
-               }
-       }
-
-       if (lis3->pdata) {
-               int i;
-               for (i = 0; i < 3; i++) {
-                       /* Check against selftest acceptance limits */
-                       if ((results[i] < lis3->pdata->st_min_limits[i]) ||
-                           (results[i] > lis3->pdata->st_max_limits[i])) {
-                               ret = SELFTEST_FAIL;
-                               goto fail;
-                       }
-               }
-       }
-
-       /* test passed */
-fail:
-       mutex_unlock(&lis3->mutex);
-       return ret;
-}
-
-/*
- * Order of registers in the list affects to order of the restore process.
- * Perhaps it is a good idea to set interrupt enable register as a last one
- * after all other configurations
- */
-static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
-                              FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
-                              CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
-                              CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
-                              CTRL_REG1, CTRL_REG2, CTRL_REG3};
-
-static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
-                              FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
-                              DD_THSE_L, DD_THSE_H,
-                              CTRL_REG1, CTRL_REG3, CTRL_REG2};
-
-static inline void lis3_context_save(struct lis3lv02d *lis3)
-{
-       int i;
-       for (i = 0; i < lis3->regs_size; i++)
-               lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
-       lis3->regs_stored = true;
-}
-
-static inline void lis3_context_restore(struct lis3lv02d *lis3)
-{
-       int i;
-       if (lis3->regs_stored)
-               for (i = 0; i < lis3->regs_size; i++)
-                       lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
-}
-
-void lis3lv02d_poweroff(struct lis3lv02d *lis3)
-{
-       if (lis3->reg_ctrl)
-               lis3_context_save(lis3);
-       /* disable X,Y,Z axis and power down */
-       lis3->write(lis3, CTRL_REG1, 0x00);
-       if (lis3->reg_ctrl)
-               lis3->reg_ctrl(lis3, LIS3_REG_OFF);
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
-
-void lis3lv02d_poweron(struct lis3lv02d *lis3)
-{
-       u8 reg;
-
-       lis3->init(lis3);
-
-       /*
-        * Common configuration
-        * BDU: (12 bits sensors only) LSB and MSB values are not updated until
-        *      both have been read. So the value read will always be correct.
-        * Set BOOT bit to refresh factory tuning values.
-        */
-       lis3->read(lis3, CTRL_REG2, &reg);
-       if (lis3->whoami ==  WAI_12B)
-               reg |= CTRL2_BDU | CTRL2_BOOT;
-       else
-               reg |= CTRL2_BOOT_8B;
-       lis3->write(lis3, CTRL_REG2, reg);
-
-       /* LIS3 power on delay is quite long */
-       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
-       if (lis3->reg_ctrl)
-               lis3_context_restore(lis3);
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
-
-
-static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
-{
-       int x, y, z;
-
-       mutex_lock(&lis3_dev.mutex);
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       input_report_abs(pidev->input, ABS_X, x);
-       input_report_abs(pidev->input, ABS_Y, y);
-       input_report_abs(pidev->input, ABS_Z, z);
-       input_sync(pidev->input);
-       mutex_unlock(&lis3_dev.mutex);
-}
-
-static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
-{
-       if (lis3_dev.pm_dev)
-               pm_runtime_get_sync(lis3_dev.pm_dev);
-
-       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
-               atomic_set(&lis3_dev.wake_thread, 1);
-       /*
-        * Update coordinates for the case where poll interval is 0 and
-        * the chip in running purely under interrupt control
-        */
-       lis3lv02d_joystick_poll(pidev);
-}
-
-static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
-{
-       atomic_set(&lis3_dev.wake_thread, 0);
-       if (lis3_dev.pm_dev)
-               pm_runtime_put(lis3_dev.pm_dev);
-}
-
-static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
-{
-       if (!test_bit(0, &lis3_dev.misc_opened))
-               goto out;
-
-       /*
-        * Be careful: on some HP laptops the bios force DD when on battery and
-        * the lid is closed. This leads to interrupts as soon as a little move
-        * is done.
-        */
-       atomic_inc(&lis3_dev.count);
-
-       wake_up_interruptible(&lis3_dev.misc_wait);
-       kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
-out:
-       if (atomic_read(&lis3_dev.wake_thread))
-               return IRQ_WAKE_THREAD;
-       return IRQ_HANDLED;
-}
-
-static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
-{
-       struct input_dev *dev = lis3->idev->input;
-       u8 click_src;
-
-       mutex_lock(&lis3->mutex);
-       lis3->read(lis3, CLICK_SRC, &click_src);
-
-       if (click_src & CLICK_SINGLE_X) {
-               input_report_key(dev, lis3->mapped_btns[0], 1);
-               input_report_key(dev, lis3->mapped_btns[0], 0);
-       }
-
-       if (click_src & CLICK_SINGLE_Y) {
-               input_report_key(dev, lis3->mapped_btns[1], 1);
-               input_report_key(dev, lis3->mapped_btns[1], 0);
-       }
-
-       if (click_src & CLICK_SINGLE_Z) {
-               input_report_key(dev, lis3->mapped_btns[2], 1);
-               input_report_key(dev, lis3->mapped_btns[2], 0);
-       }
-       input_sync(dev);
-       mutex_unlock(&lis3->mutex);
-}
-
-static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
-{
-       int dummy;
-
-       /* Dummy read to ack interrupt */
-       lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
-       lis3->data_ready_count[index]++;
-}
-
-static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
-{
-       struct lis3lv02d *lis3 = data;
-       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
-
-       if (irq_cfg == LIS3_IRQ1_CLICK)
-               lis302dl_interrupt_handle_click(lis3);
-       else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
-               lis302dl_data_ready(lis3, IRQ_LINE0);
-       else
-               lis3lv02d_joystick_poll(lis3->idev);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
-{
-       struct lis3lv02d *lis3 = data;
-       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
-
-       if (irq_cfg == LIS3_IRQ2_CLICK)
-               lis302dl_interrupt_handle_click(lis3);
-       else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
-               lis302dl_data_ready(lis3, IRQ_LINE1);
-       else
-               lis3lv02d_joystick_poll(lis3->idev);
-
-       return IRQ_HANDLED;
-}
-
-static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(0, &lis3_dev.misc_opened))
-               return -EBUSY; /* already open */
-
-       if (lis3_dev.pm_dev)
-               pm_runtime_get_sync(lis3_dev.pm_dev);
-
-       atomic_set(&lis3_dev.count, 0);
-       return 0;
-}
-
-static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
-{
-       fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-       clear_bit(0, &lis3_dev.misc_opened); /* release the device */
-       if (lis3_dev.pm_dev)
-               pm_runtime_put(lis3_dev.pm_dev);
-       return 0;
-}
-
-static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
-                               size_t count, loff_t *pos)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       u32 data;
-       unsigned char byte_data;
-       ssize_t retval = 1;
-
-       if (count < 1)
-               return -EINVAL;
-
-       add_wait_queue(&lis3_dev.misc_wait, &wait);
-       while (true) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               data = atomic_xchg(&lis3_dev.count, 0);
-               if (data)
-                       break;
-
-               if (file->f_flags & O_NONBLOCK) {
-                       retval = -EAGAIN;
-                       goto out;
-               }
-
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       goto out;
-               }
-
-               schedule();
-       }
-
-       if (data < 255)
-               byte_data = data;
-       else
-               byte_data = 255;
-
-       /* make sure we are not going into copy_to_user() with
-        * TASK_INTERRUPTIBLE state */
-       set_current_state(TASK_RUNNING);
-       if (copy_to_user(buf, &byte_data, sizeof(byte_data)))
-               retval = -EFAULT;
-
-out:
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&lis3_dev.misc_wait, &wait);
-
-       return retval;
-}
-
-static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lis3_dev.misc_wait, wait);
-       if (atomic_read(&lis3_dev.count))
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
-{
-       return fasync_helper(fd, file, on, &lis3_dev.async_queue);
-}
-
-static const struct file_operations lis3lv02d_misc_fops = {
-       .owner   = THIS_MODULE,
-       .llseek  = no_llseek,
-       .read    = lis3lv02d_misc_read,
-       .open    = lis3lv02d_misc_open,
-       .release = lis3lv02d_misc_release,
-       .poll    = lis3lv02d_misc_poll,
-       .fasync  = lis3lv02d_misc_fasync,
-};
-
-static struct miscdevice lis3lv02d_misc_device = {
-       .minor   = MISC_DYNAMIC_MINOR,
-       .name    = "freefall",
-       .fops    = &lis3lv02d_misc_fops,
-};
-
-int lis3lv02d_joystick_enable(void)
-{
-       struct input_dev *input_dev;
-       int err;
-       int max_val, fuzz, flat;
-       int btns[] = {BTN_X, BTN_Y, BTN_Z};
-
-       if (lis3_dev.idev)
-               return -EINVAL;
-
-       lis3_dev.idev = input_allocate_polled_device();
-       if (!lis3_dev.idev)
-               return -ENOMEM;
-
-       lis3_dev.idev->poll = lis3lv02d_joystick_poll;
-       lis3_dev.idev->open = lis3lv02d_joystick_open;
-       lis3_dev.idev->close = lis3lv02d_joystick_close;
-       lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
-       lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
-       lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
-       input_dev = lis3_dev.idev->input;
-
-       input_dev->name       = "ST LIS3LV02DL Accelerometer";
-       input_dev->phys       = DRIVER_NAME "/input0";
-       input_dev->id.bustype = BUS_HOST;
-       input_dev->id.vendor  = 0;
-       input_dev->dev.parent = &lis3_dev.pdev->dev;
-
-       set_bit(EV_ABS, input_dev->evbit);
-       max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
-       if (lis3_dev.whoami == WAI_12B) {
-               fuzz = LIS3_DEFAULT_FUZZ_12B;
-               flat = LIS3_DEFAULT_FLAT_12B;
-       } else {
-               fuzz = LIS3_DEFAULT_FUZZ_8B;
-               flat = LIS3_DEFAULT_FLAT_8B;
-       }
-       fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
-       flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
-
-       input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
-       input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
-       input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
-
-       lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
-       lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
-       lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
-
-       err = input_register_polled_device(lis3_dev.idev);
-       if (err) {
-               input_free_polled_device(lis3_dev.idev);
-               lis3_dev.idev = NULL;
-       }
-
-       return err;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
-
-void lis3lv02d_joystick_disable(void)
-{
-       if (lis3_dev.irq)
-               free_irq(lis3_dev.irq, &lis3_dev);
-       if (lis3_dev.pdata && lis3_dev.pdata->irq2)
-               free_irq(lis3_dev.pdata->irq2, &lis3_dev);
-
-       if (!lis3_dev.idev)
-               return;
-
-       if (lis3_dev.irq)
-               misc_deregister(&lis3lv02d_misc_device);
-       input_unregister_polled_device(lis3_dev.idev);
-       input_free_polled_device(lis3_dev.idev);
-       lis3_dev.idev = NULL;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
-
-/* Sysfs stuff */
-static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
-{
-       /*
-        * SYSFS functions are fast visitors so put-call
-        * immediately after the get-call. However, keep
-        * chip running for a while and schedule delayed
-        * suspend. This way periodic sysfs calls doesn't
-        * suffer from relatively long power up time.
-        */
-
-       if (lis3->pm_dev) {
-               pm_runtime_get_sync(lis3->pm_dev);
-               pm_runtime_put_noidle(lis3->pm_dev);
-               pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
-       }
-}
-
-static ssize_t lis3lv02d_selftest_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       s16 values[3];
-
-       static const char ok[] = "OK";
-       static const char fail[] = "FAIL";
-       static const char irq[] = "FAIL_IRQ";
-       const char *res;
-
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       switch (lis3lv02d_selftest(&lis3_dev, values)) {
-       case SELFTEST_FAIL:
-               res = fail;
-               break;
-       case SELFTEST_IRQ:
-               res = irq;
-               break;
-       case SELFTEST_OK:
-       default:
-               res = ok;
-               break;
-       }
-       return sprintf(buf, "%s %d %d %d\n", res,
-               values[0], values[1], values[2]);
-}
-
-static ssize_t lis3lv02d_position_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       int x, y, z;
-
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       mutex_lock(&lis3_dev.mutex);
-       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       mutex_unlock(&lis3_dev.mutex);
-       return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
-}
-
-static ssize_t lis3lv02d_rate_show(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       return sprintf(buf, "%d\n", lis3lv02d_get_odr());
-}
-
-static ssize_t lis3lv02d_rate_set(struct device *dev,
-                               struct device_attribute *attr, const char *buf,
-                               size_t count)
-{
-       unsigned long rate;
-
-       if (strict_strtoul(buf, 0, &rate))
-               return -EINVAL;
-
-       lis3lv02d_sysfs_poweron(&lis3_dev);
-       if (lis3lv02d_set_odr(rate))
-               return -EINVAL;
-
-       return count;
-}
-
-static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
-static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
-static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
-                                           lis3lv02d_rate_set);
-
-static struct attribute *lis3lv02d_attributes[] = {
-       &dev_attr_selftest.attr,
-       &dev_attr_position.attr,
-       &dev_attr_rate.attr,
-       NULL
-};
-
-static struct attribute_group lis3lv02d_attribute_group = {
-       .attrs = lis3lv02d_attributes
-};
-
-
-static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
-{
-       lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(lis3->pdev))
-               return PTR_ERR(lis3->pdev);
-
-       return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
-}
-
-int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
-{
-       sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
-       platform_device_unregister(lis3->pdev);
-       if (lis3->pm_dev) {
-               /* Barrier after the sysfs remove */
-               pm_runtime_barrier(lis3->pm_dev);
-
-               /* SYSFS may have left chip running. Turn off if necessary */
-               if (!pm_runtime_suspended(lis3->pm_dev))
-                       lis3lv02d_poweroff(&lis3_dev);
-
-               pm_runtime_disable(lis3->pm_dev);
-               pm_runtime_set_suspended(lis3->pm_dev);
-       }
-       kfree(lis3->reg_cache);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
-
-static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
-                               struct lis3lv02d_platform_data *p)
-{
-       int err;
-       int ctrl2 = p->hipass_ctrl;
-
-       if (p->click_flags) {
-               dev->write(dev, CLICK_CFG, p->click_flags);
-               dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
-               dev->write(dev, CLICK_LATENCY, p->click_latency);
-               dev->write(dev, CLICK_WINDOW, p->click_window);
-               dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
-               dev->write(dev, CLICK_THSY_X,
-                       (p->click_thresh_x & 0xf) |
-                       (p->click_thresh_y << 4));
-
-               if (dev->idev) {
-                       struct input_dev *input_dev = lis3_dev.idev->input;
-                       input_set_capability(input_dev, EV_KEY, BTN_X);
-                       input_set_capability(input_dev, EV_KEY, BTN_Y);
-                       input_set_capability(input_dev, EV_KEY, BTN_Z);
-               }
-       }
-
-       if (p->wakeup_flags) {
-               dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
-               dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
-               /* pdata value + 1 to keep this backward compatible*/
-               dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
-               ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
-       }
-
-       if (p->wakeup_flags2) {
-               dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
-               dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
-               /* pdata value + 1 to keep this backward compatible*/
-               dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
-               ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
-       }
-       /* Configure hipass filters */
-       dev->write(dev, CTRL_REG2, ctrl2);
-
-       if (p->irq2) {
-               err = request_threaded_irq(p->irq2,
-                                       NULL,
-                                       lis302dl_interrupt_thread2_8b,
-                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT |
-                                       (p->irq_flags2 & IRQF_TRIGGER_MASK),
-                                       DRIVER_NAME, &lis3_dev);
-               if (err < 0)
-                       pr_err("No second IRQ. Limited functionality\n");
-       }
-}
-
-/*
- * Initialise the accelerometer and the various subsystems.
- * Should be rather independent of the bus system.
- */
-int lis3lv02d_init_device(struct lis3lv02d *dev)
-{
-       int err;
-       irq_handler_t thread_fn;
-       int irq_flags = 0;
-
-       dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
-
-       switch (dev->whoami) {
-       case WAI_12B:
-               pr_info("12 bits sensor found\n");
-               dev->read_data = lis3lv02d_read_12;
-               dev->mdps_max_val = 2048;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
-               dev->odrs = lis3_12_rates;
-               dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
-               dev->scale = LIS3_SENSITIVITY_12B;
-               dev->regs = lis3_wai12_regs;
-               dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
-               break;
-       case WAI_8B:
-               pr_info("8 bits sensor found\n");
-               dev->read_data = lis3lv02d_read_8;
-               dev->mdps_max_val = 128;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-               dev->odrs = lis3_8_rates;
-               dev->odr_mask = CTRL1_DR;
-               dev->scale = LIS3_SENSITIVITY_8B;
-               dev->regs = lis3_wai8_regs;
-               dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
-               break;
-       case WAI_3DC:
-               pr_info("8 bits 3DC sensor found\n");
-               dev->read_data = lis3lv02d_read_8;
-               dev->mdps_max_val = 128;
-               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-               dev->odrs = lis3_3dc_rates;
-               dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
-               dev->scale = LIS3_SENSITIVITY_8B;
-               break;
-       default:
-               pr_err("unknown sensor type 0x%X\n", dev->whoami);
-               return -EINVAL;
-       }
-
-       dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
-                                    sizeof(lis3_wai12_regs)), GFP_KERNEL);
-
-       if (dev->reg_cache == NULL) {
-               printk(KERN_ERR DRIVER_NAME "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->mutex);
-       atomic_set(&dev->wake_thread, 0);
-
-       lis3lv02d_add_fs(dev);
-       lis3lv02d_poweron(dev);
-
-       if (dev->pm_dev) {
-               pm_runtime_set_active(dev->pm_dev);
-               pm_runtime_enable(dev->pm_dev);
-       }
-
-       if (lis3lv02d_joystick_enable())
-               pr_err("joystick initialization failed\n");
-
-       /* passing in platform specific data is purely optional and only
-        * used by the SPI transport layer at the moment */
-       if (dev->pdata) {
-               struct lis3lv02d_platform_data *p = dev->pdata;
-
-               if (dev->whoami == WAI_8B)
-                       lis3lv02d_8b_configure(dev, p);
-
-               irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
-
-               dev->irq_cfg = p->irq_cfg;
-               if (p->irq_cfg)
-                       dev->write(dev, CTRL_REG3, p->irq_cfg);
-
-               if (p->default_rate)
-                       lis3lv02d_set_odr(p->default_rate);
-       }
-
-       /* bail if we did not get an IRQ from the bus layer */
-       if (!dev->irq) {
-               pr_debug("No IRQ. Disabling /dev/freefall\n");
-               goto out;
-       }
-
-       /*
-        * The sensor can generate interrupts for free-fall and direction
-        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
-        * the things simple and _fast_ we activate it only for free-fall, so
-        * no need to read register (very slow with ACPI). For the same reason,
-        * we forbid shared interrupts.
-        *
-        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
-        * io-apic is not configurable (and generates a warning) but I keep it
-        * in case of support for other hardware.
-        */
-       if (dev->pdata && dev->whoami == WAI_8B)
-               thread_fn = lis302dl_interrupt_thread1_8b;
-       else
-               thread_fn = NULL;
-
-       err = request_threaded_irq(dev->irq, lis302dl_interrupt,
-                               thread_fn,
-                               IRQF_TRIGGER_RISING | IRQF_ONESHOT |
-                               irq_flags,
-                               DRIVER_NAME, &lis3_dev);
-
-       if (err < 0) {
-               pr_err("Cannot get IRQ\n");
-               goto out;
-       }
-
-       if (misc_register(&lis3lv02d_misc_device))
-               pr_err("misc_register failed\n");
-out:
-       return 0;
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
-
-MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
-MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
deleted file mode 100644 (file)
index a193958..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- *  lis3lv02d.h - ST LIS3LV02DL accelerometer driver
- *
- *  Copyright (C) 2007-2008 Yan Burman
- *  Copyright (C) 2008-2009 Eric Piel
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/platform_device.h>
-#include <linux/input-polldev.h>
-#include <linux/regulator/consumer.h>
-
-/*
- * This driver tries to support the "digital" accelerometer chips from
- * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
- * LIS35DE, or LIS202DL. They are very similar in terms of programming, with
- * almost the same registers. In addition to differing on physical properties,
- * they differ on the number of axes (2/3), precision (8/12 bits), and special
- * features (freefall detection, click...). Unfortunately, not all the
- * differences can be probed via a register.
- * They can be connected either via IĀ²C or SPI.
- */
-
-#include <linux/lis3lv02d.h>
-
-enum lis3_reg {
-       WHO_AM_I        = 0x0F,
-       OFFSET_X        = 0x16,
-       OFFSET_Y        = 0x17,
-       OFFSET_Z        = 0x18,
-       GAIN_X          = 0x19,
-       GAIN_Y          = 0x1A,
-       GAIN_Z          = 0x1B,
-       CTRL_REG1       = 0x20,
-       CTRL_REG2       = 0x21,
-       CTRL_REG3       = 0x22,
-       CTRL_REG4       = 0x23,
-       HP_FILTER_RESET = 0x23,
-       STATUS_REG      = 0x27,
-       OUTX_L          = 0x28,
-       OUTX_H          = 0x29,
-       OUTX            = 0x29,
-       OUTY_L          = 0x2A,
-       OUTY_H          = 0x2B,
-       OUTY            = 0x2B,
-       OUTZ_L          = 0x2C,
-       OUTZ_H          = 0x2D,
-       OUTZ            = 0x2D,
-};
-
-enum lis302d_reg {
-       FF_WU_CFG_1     = 0x30,
-       FF_WU_SRC_1     = 0x31,
-       FF_WU_THS_1     = 0x32,
-       FF_WU_DURATION_1 = 0x33,
-       FF_WU_CFG_2     = 0x34,
-       FF_WU_SRC_2     = 0x35,
-       FF_WU_THS_2     = 0x36,
-       FF_WU_DURATION_2 = 0x37,
-       CLICK_CFG       = 0x38,
-       CLICK_SRC       = 0x39,
-       CLICK_THSY_X    = 0x3B,
-       CLICK_THSZ      = 0x3C,
-       CLICK_TIMELIMIT = 0x3D,
-       CLICK_LATENCY   = 0x3E,
-       CLICK_WINDOW    = 0x3F,
-};
-
-enum lis3lv02d_reg {
-       FF_WU_CFG       = 0x30,
-       FF_WU_SRC       = 0x31,
-       FF_WU_ACK       = 0x32,
-       FF_WU_THS_L     = 0x34,
-       FF_WU_THS_H     = 0x35,
-       FF_WU_DURATION  = 0x36,
-       DD_CFG          = 0x38,
-       DD_SRC          = 0x39,
-       DD_ACK          = 0x3A,
-       DD_THSI_L       = 0x3C,
-       DD_THSI_H       = 0x3D,
-       DD_THSE_L       = 0x3E,
-       DD_THSE_H       = 0x3F,
-};
-
-enum lis3_who_am_i {
-       WAI_3DC         = 0x33, /* 8 bits: LIS3DC, HP3DC */
-       WAI_12B         = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
-       WAI_8B          = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
-       WAI_6B          = 0x52, /* 6 bits: LIS331DLF - not supported */
-};
-
-enum lis3lv02d_ctrl1_12b {
-       CTRL1_Xen       = 0x01,
-       CTRL1_Yen       = 0x02,
-       CTRL1_Zen       = 0x04,
-       CTRL1_ST        = 0x08,
-       CTRL1_DF0       = 0x10,
-       CTRL1_DF1       = 0x20,
-       CTRL1_PD0       = 0x40,
-       CTRL1_PD1       = 0x80,
-};
-
-/* Delta to ctrl1_12b version */
-enum lis3lv02d_ctrl1_8b {
-       CTRL1_STM       = 0x08,
-       CTRL1_STP       = 0x10,
-       CTRL1_FS        = 0x20,
-       CTRL1_PD        = 0x40,
-       CTRL1_DR        = 0x80,
-};
-
-enum lis3lv02d_ctrl1_3dc {
-       CTRL1_ODR0      = 0x10,
-       CTRL1_ODR1      = 0x20,
-       CTRL1_ODR2      = 0x40,
-       CTRL1_ODR3      = 0x80,
-};
-
-enum lis3lv02d_ctrl2 {
-       CTRL2_DAS       = 0x01,
-       CTRL2_SIM       = 0x02,
-       CTRL2_DRDY      = 0x04,
-       CTRL2_IEN       = 0x08,
-       CTRL2_BOOT      = 0x10,
-       CTRL2_BLE       = 0x20,
-       CTRL2_BDU       = 0x40, /* Block Data Update */
-       CTRL2_FS        = 0x80, /* Full Scale selection */
-};
-
-enum lis3lv02d_ctrl4_3dc {
-       CTRL4_SIM       = 0x01,
-       CTRL4_ST0       = 0x02,
-       CTRL4_ST1       = 0x04,
-       CTRL4_FS0       = 0x10,
-       CTRL4_FS1       = 0x20,
-};
-
-enum lis302d_ctrl2 {
-       HP_FF_WU2       = 0x08,
-       HP_FF_WU1       = 0x04,
-       CTRL2_BOOT_8B   = 0x40,
-};
-
-enum lis3lv02d_ctrl3 {
-       CTRL3_CFS0      = 0x01,
-       CTRL3_CFS1      = 0x02,
-       CTRL3_FDS       = 0x10,
-       CTRL3_HPFF      = 0x20,
-       CTRL3_HPDD      = 0x40,
-       CTRL3_ECK       = 0x80,
-};
-
-enum lis3lv02d_status_reg {
-       STATUS_XDA      = 0x01,
-       STATUS_YDA      = 0x02,
-       STATUS_ZDA      = 0x04,
-       STATUS_XYZDA    = 0x08,
-       STATUS_XOR      = 0x10,
-       STATUS_YOR      = 0x20,
-       STATUS_ZOR      = 0x40,
-       STATUS_XYZOR    = 0x80,
-};
-
-enum lis3lv02d_ff_wu_cfg {
-       FF_WU_CFG_XLIE  = 0x01,
-       FF_WU_CFG_XHIE  = 0x02,
-       FF_WU_CFG_YLIE  = 0x04,
-       FF_WU_CFG_YHIE  = 0x08,
-       FF_WU_CFG_ZLIE  = 0x10,
-       FF_WU_CFG_ZHIE  = 0x20,
-       FF_WU_CFG_LIR   = 0x40,
-       FF_WU_CFG_AOI   = 0x80,
-};
-
-enum lis3lv02d_ff_wu_src {
-       FF_WU_SRC_XL    = 0x01,
-       FF_WU_SRC_XH    = 0x02,
-       FF_WU_SRC_YL    = 0x04,
-       FF_WU_SRC_YH    = 0x08,
-       FF_WU_SRC_ZL    = 0x10,
-       FF_WU_SRC_ZH    = 0x20,
-       FF_WU_SRC_IA    = 0x40,
-};
-
-enum lis3lv02d_dd_cfg {
-       DD_CFG_XLIE     = 0x01,
-       DD_CFG_XHIE     = 0x02,
-       DD_CFG_YLIE     = 0x04,
-       DD_CFG_YHIE     = 0x08,
-       DD_CFG_ZLIE     = 0x10,
-       DD_CFG_ZHIE     = 0x20,
-       DD_CFG_LIR      = 0x40,
-       DD_CFG_IEND     = 0x80,
-};
-
-enum lis3lv02d_dd_src {
-       DD_SRC_XL       = 0x01,
-       DD_SRC_XH       = 0x02,
-       DD_SRC_YL       = 0x04,
-       DD_SRC_YH       = 0x08,
-       DD_SRC_ZL       = 0x10,
-       DD_SRC_ZH       = 0x20,
-       DD_SRC_IA       = 0x40,
-};
-
-enum lis3lv02d_click_src_8b {
-       CLICK_SINGLE_X  = 0x01,
-       CLICK_DOUBLE_X  = 0x02,
-       CLICK_SINGLE_Y  = 0x04,
-       CLICK_DOUBLE_Y  = 0x08,
-       CLICK_SINGLE_Z  = 0x10,
-       CLICK_DOUBLE_Z  = 0x20,
-       CLICK_IA        = 0x40,
-};
-
-enum lis3lv02d_reg_state {
-       LIS3_REG_OFF    = 0x00,
-       LIS3_REG_ON     = 0x01,
-};
-
-union axis_conversion {
-       struct {
-               int x, y, z;
-       };
-       int as_array[3];
-
-};
-
-struct lis3lv02d {
-       void                    *bus_priv; /* used by the bus layer only */
-       struct device           *pm_dev; /* for pm_runtime purposes */
-       int (*init) (struct lis3lv02d *lis3);
-       int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
-       int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
-       int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
-       int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
-
-       int                     *odrs;     /* Supported output data rates */
-       u8                      *regs;     /* Regs to store / restore */
-       int                     regs_size;
-       u8                      *reg_cache;
-       bool                    regs_stored;
-       u8                      odr_mask;  /* ODR bit mask */
-       u8                      whoami;    /* indicates measurement precision */
-       s16 (*read_data) (struct lis3lv02d *lis3, int reg);
-       int                     mdps_max_val;
-       int                     pwron_delay;
-       int                     scale; /*
-                                       * relationship between 1 LBS and mG
-                                       * (1/1000th of earth gravity)
-                                       */
-
-       struct input_polled_dev *idev;     /* input device */
-       struct platform_device  *pdev;     /* platform device */
-       struct regulator_bulk_data regulators[2];
-       atomic_t                count;     /* interrupt count after last read */
-       union axis_conversion   ac;        /* hw -> logical axis */
-       int                     mapped_btns[3];
-
-       u32                     irq;       /* IRQ number */
-       struct fasync_struct    *async_queue; /* queue for the misc device */
-       wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
-       unsigned long           misc_opened; /* bit0: whether the device is open */
-       int                     data_ready_count[2];
-       atomic_t                wake_thread;
-       unsigned char           irq_cfg;
-
-       struct lis3lv02d_platform_data *pdata;  /* for passing board config */
-       struct mutex            mutex;     /* Serialize poll and selftest */
-};
-
-int lis3lv02d_init_device(struct lis3lv02d *lis3);
-int lis3lv02d_joystick_enable(void);
-void lis3lv02d_joystick_disable(void);
-void lis3lv02d_poweroff(struct lis3lv02d *lis3);
-void lis3lv02d_poweron(struct lis3lv02d *lis3);
-int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
-
-extern struct lis3lv02d lis3_dev;
diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c
deleted file mode 100644 (file)
index 8853afc..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * drivers/hwmon/lis3lv02d_i2c.c
- *
- * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer.
- * Driver is based on corresponding SPI driver written by Daniel Mack
- * (lis3lv02d_spi.c (C) 2009 Daniel Mack <daniel@caiaq.de> ).
- *
- * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
- *
- * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/pm_runtime.h>
-#include <linux/delay.h>
-#include "lis3lv02d.h"
-
-#define DRV_NAME       "lis3lv02d_i2c"
-
-static const char reg_vdd[]    = "Vdd";
-static const char reg_vdd_io[] = "Vdd_IO";
-
-static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
-{
-       int ret;
-       if (state == LIS3_REG_OFF) {
-               ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
-                                       lis3->regulators);
-       } else {
-               ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
-                                       lis3->regulators);
-               /* Chip needs time to wakeup. Not mentioned in datasheet */
-               usleep_range(10000, 20000);
-       }
-       return ret;
-}
-
-static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
-{
-       struct i2c_client *c = lis3->bus_priv;
-       return i2c_smbus_write_byte_data(c, reg, value);
-}
-
-static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
-{
-       struct i2c_client *c = lis3->bus_priv;
-       *v = i2c_smbus_read_byte_data(c, reg);
-       return 0;
-}
-
-static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
-                               u8 *v)
-{
-       struct i2c_client *c = lis3->bus_priv;
-       reg |= (1 << 7); /* 7th bit enables address auto incrementation */
-       return i2c_smbus_read_i2c_block_data(c, reg, len, v);
-}
-
-static int lis3_i2c_init(struct lis3lv02d *lis3)
-{
-       u8 reg;
-       int ret;
-
-       if (lis3->reg_ctrl)
-               lis3_reg_ctrl(lis3, LIS3_REG_ON);
-
-       lis3->read(lis3, WHO_AM_I, &reg);
-       if (reg != lis3->whoami)
-               printk(KERN_ERR "lis3: power on failure\n");
-
-       /* power up the device */
-       ret = lis3->read(lis3, CTRL_REG1, &reg);
-       if (ret < 0)
-               return ret;
-
-       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
-       return lis3->write(lis3, CTRL_REG1, reg);
-}
-
-/* Default axis mapping but it can be overwritten by platform data */
-static union axis_conversion lis3lv02d_axis_map =
-       { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
-
-static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
-{
-       int ret = 0;
-       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
-
-       if (pdata) {
-               /* Regulator control is optional */
-               if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
-                       lis3_dev.reg_ctrl = lis3_reg_ctrl;
-
-               if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
-                       (i2c_check_functionality(client->adapter,
-                                               I2C_FUNC_SMBUS_I2C_BLOCK)))
-                       lis3_dev.blkread  = lis3_i2c_blockread;
-
-               if (pdata->axis_x)
-                       lis3lv02d_axis_map.x = pdata->axis_x;
-
-               if (pdata->axis_y)
-                       lis3lv02d_axis_map.y = pdata->axis_y;
-
-               if (pdata->axis_z)
-                       lis3lv02d_axis_map.z = pdata->axis_z;
-
-               if (pdata->setup_resources)
-                       ret = pdata->setup_resources();
-
-               if (ret)
-                       goto fail;
-       }
-
-       if (lis3_dev.reg_ctrl) {
-               lis3_dev.regulators[0].supply = reg_vdd;
-               lis3_dev.regulators[1].supply = reg_vdd_io;
-               ret = regulator_bulk_get(&client->dev,
-                                       ARRAY_SIZE(lis3_dev.regulators),
-                                       lis3_dev.regulators);
-               if (ret < 0)
-                       goto fail;
-       }
-
-       lis3_dev.pdata    = pdata;
-       lis3_dev.bus_priv = client;
-       lis3_dev.init     = lis3_i2c_init;
-       lis3_dev.read     = lis3_i2c_read;
-       lis3_dev.write    = lis3_i2c_write;
-       lis3_dev.irq      = client->irq;
-       lis3_dev.ac       = lis3lv02d_axis_map;
-       lis3_dev.pm_dev   = &client->dev;
-
-       i2c_set_clientdata(client, &lis3_dev);
-
-       /* Provide power over the init call */
-       if (lis3_dev.reg_ctrl)
-               lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
-
-       ret = lis3lv02d_init_device(&lis3_dev);
-
-       if (lis3_dev.reg_ctrl)
-               lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
-
-       if (ret == 0)
-               return 0;
-fail:
-       if (pdata && pdata->release_resources)
-               pdata->release_resources();
-       return ret;
-}
-
-static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
-{
-       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
-       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
-
-       if (pdata && pdata->release_resources)
-               pdata->release_resources();
-
-       lis3lv02d_joystick_disable();
-       lis3lv02d_remove_fs(&lis3_dev);
-
-       if (lis3_dev.reg_ctrl)
-               regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
-                               lis3_dev.regulators);
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int lis3lv02d_i2c_suspend(struct device *dev)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
-
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
-               lis3lv02d_poweroff(lis3);
-       return 0;
-}
-
-static int lis3lv02d_i2c_resume(struct device *dev)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
-
-       /*
-        * pm_runtime documentation says that devices should always
-        * be powered on at resume. Pm_runtime turns them off after system
-        * wide resume is complete.
-        */
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
-               pm_runtime_suspended(dev))
-               lis3lv02d_poweron(lis3);
-
-       return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-#ifdef CONFIG_PM_RUNTIME
-static int lis3_i2c_runtime_suspend(struct device *dev)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
-
-       lis3lv02d_poweroff(lis3);
-       return 0;
-}
-
-static int lis3_i2c_runtime_resume(struct device *dev)
-{
-       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
-       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
-
-       lis3lv02d_poweron(lis3);
-       return 0;
-}
-#endif /* CONFIG_PM_RUNTIME */
-
-static const struct i2c_device_id lis3lv02d_id[] = {
-       {"lis3lv02d", 0 },
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
-
-static const struct dev_pm_ops lis3_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
-                               lis3lv02d_i2c_resume)
-       SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
-                          lis3_i2c_runtime_resume,
-                          NULL)
-};
-
-static struct i2c_driver lis3lv02d_i2c_driver = {
-       .driver  = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-               .pm     = &lis3_pm_ops,
-       },
-       .probe  = lis3lv02d_i2c_probe,
-       .remove = __devexit_p(lis3lv02d_i2c_remove),
-       .id_table = lis3lv02d_id,
-};
-
-static int __init lis3lv02d_init(void)
-{
-       return i2c_add_driver(&lis3lv02d_i2c_driver);
-}
-
-static void __exit lis3lv02d_exit(void)
-{
-       i2c_del_driver(&lis3lv02d_i2c_driver);
-}
-
-MODULE_AUTHOR("Nokia Corporation");
-MODULE_DESCRIPTION("lis3lv02d I2C interface");
-MODULE_LICENSE("GPL");
-
-module_init(lis3lv02d_init);
-module_exit(lis3lv02d_exit);
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
deleted file mode 100644 (file)
index c1f8a8f..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * lis3lv02d_spi - SPI glue layer for lis3lv02d
- *
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- *
- *  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
- *  publishhed by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/spi/spi.h>
-#include <linux/pm.h>
-
-#include "lis3lv02d.h"
-
-#define DRV_NAME       "lis3lv02d_spi"
-#define LIS3_SPI_READ  0x80
-
-static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v)
-{
-       struct spi_device *spi = lis3->bus_priv;
-       int ret = spi_w8r8(spi, reg | LIS3_SPI_READ);
-       if (ret < 0)
-               return -EINVAL;
-
-       *v = (u8) ret;
-       return 0;
-}
-
-static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val)
-{
-       u8 tmp[2] = { reg, val };
-       struct spi_device *spi = lis3->bus_priv;
-       return spi_write(spi, tmp, sizeof(tmp));
-}
-
-static int lis3_spi_init(struct lis3lv02d *lis3)
-{
-       u8 reg;
-       int ret;
-
-       /* power up the device */
-       ret = lis3->read(lis3, CTRL_REG1, &reg);
-       if (ret < 0)
-               return ret;
-
-       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
-       return lis3->write(lis3, CTRL_REG1, reg);
-}
-
-static union axis_conversion lis3lv02d_axis_normal =
-       { .as_array = { 1, 2, 3 } };
-
-static int __devinit lis302dl_spi_probe(struct spi_device *spi)
-{
-       int ret;
-
-       spi->bits_per_word = 8;
-       spi->mode = SPI_MODE_0;
-       ret = spi_setup(spi);
-       if (ret < 0)
-               return ret;
-
-       lis3_dev.bus_priv       = spi;
-       lis3_dev.init           = lis3_spi_init;
-       lis3_dev.read           = lis3_spi_read;
-       lis3_dev.write          = lis3_spi_write;
-       lis3_dev.irq            = spi->irq;
-       lis3_dev.ac             = lis3lv02d_axis_normal;
-       lis3_dev.pdata          = spi->dev.platform_data;
-       spi_set_drvdata(spi, &lis3_dev);
-
-       return lis3lv02d_init_device(&lis3_dev);
-}
-
-static int __devexit lis302dl_spi_remove(struct spi_device *spi)
-{
-       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
-       lis3lv02d_joystick_disable();
-       lis3lv02d_poweroff(lis3);
-
-       return lis3lv02d_remove_fs(&lis3_dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int lis3lv02d_spi_suspend(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
-
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
-               lis3lv02d_poweroff(&lis3_dev);
-
-       return 0;
-}
-
-static int lis3lv02d_spi_resume(struct device *dev)
-{
-       struct spi_device *spi = to_spi_device(dev);
-       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
-
-       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
-               lis3lv02d_poweron(lis3);
-
-       return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend,
-                        lis3lv02d_spi_resume);
-
-static struct spi_driver lis302dl_spi_driver = {
-       .driver  = {
-               .name   = DRV_NAME,
-               .owner  = THIS_MODULE,
-               .pm     = &lis3lv02d_spi_pm,
-       },
-       .probe  = lis302dl_spi_probe,
-       .remove = __devexit_p(lis302dl_spi_remove),
-};
-
-static int __init lis302dl_init(void)
-{
-       return spi_register_driver(&lis302dl_spi_driver);
-}
-
-static void __exit lis302dl_exit(void)
-{
-       spi_unregister_driver(&lis302dl_spi_driver);
-}
-
-module_init(lis302dl_init);
-module_exit(lis302dl_exit);
-
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("lis3lv02d SPI glue layer");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:" DRV_NAME);
index f36eb80d227fa27c2e5d2a547465ba7f25ecc132..ef902d5d06ab9f98e610f63ed0ee709eb0f66b87 100644 (file)
@@ -232,13 +232,16 @@ static const struct i2c_device_id lm75_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, lm75_ids);
 
+#define LM75A_ID 0xA1
+
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm75_detect(struct i2c_client *new_client,
                       struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = new_client->adapter;
        int i;
-       int cur, conf, hyst, os;
+       int conf, hyst, os;
+       bool is_lm75a = 0;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
                                     I2C_FUNC_SMBUS_WORD_DATA))
@@ -250,37 +253,58 @@ static int lm75_detect(struct i2c_client *new_client,
           addresses 0x04-0x07 returning the last read value.
           The cycling+unused addresses combination is not tested,
           since it would significantly slow the detection down and would
-          hardly add any value. */
+          hardly add any value.
 
-       /* Unused addresses */
-       cur = i2c_smbus_read_word_data(new_client, 0);
-       conf = i2c_smbus_read_byte_data(new_client, 1);
-       hyst = i2c_smbus_read_word_data(new_client, 2);
-       if (i2c_smbus_read_word_data(new_client, 4) != hyst
-        || i2c_smbus_read_word_data(new_client, 5) != hyst
-        || i2c_smbus_read_word_data(new_client, 6) != hyst
-        || i2c_smbus_read_word_data(new_client, 7) != hyst)
-               return -ENODEV;
-       os = i2c_smbus_read_word_data(new_client, 3);
-       if (i2c_smbus_read_word_data(new_client, 4) != os
-        || i2c_smbus_read_word_data(new_client, 5) != os
-        || i2c_smbus_read_word_data(new_client, 6) != os
-        || i2c_smbus_read_word_data(new_client, 7) != os)
-               return -ENODEV;
+          The National Semiconductor LM75A is different than earlier
+          LM75s.  It has an ID byte of 0xaX (where X is the chip
+          revision, with 1 being the only revision in existence) in
+          register 7, and unused registers return 0xff rather than the
+          last read value. */
 
        /* Unused bits */
+       conf = i2c_smbus_read_byte_data(new_client, 1);
        if (conf & 0xe0)
                return -ENODEV;
 
+       /* First check for LM75A */
+       if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) {
+               /* LM75A returns 0xff on unused registers so
+                  just to be sure we check for that too. */
+               if (i2c_smbus_read_byte_data(new_client, 4) != 0xff
+                || i2c_smbus_read_byte_data(new_client, 5) != 0xff
+                || i2c_smbus_read_byte_data(new_client, 6) != 0xff)
+                       return -ENODEV;
+               is_lm75a = 1;
+               hyst = i2c_smbus_read_byte_data(new_client, 2);
+               os = i2c_smbus_read_byte_data(new_client, 3);
+       } else { /* Traditional style LM75 detection */
+               /* Unused addresses */
+               hyst = i2c_smbus_read_byte_data(new_client, 2);
+               if (i2c_smbus_read_byte_data(new_client, 4) != hyst
+                || i2c_smbus_read_byte_data(new_client, 5) != hyst
+                || i2c_smbus_read_byte_data(new_client, 6) != hyst
+                || i2c_smbus_read_byte_data(new_client, 7) != hyst)
+                       return -ENODEV;
+               os = i2c_smbus_read_byte_data(new_client, 3);
+               if (i2c_smbus_read_byte_data(new_client, 4) != os
+                || i2c_smbus_read_byte_data(new_client, 5) != os
+                || i2c_smbus_read_byte_data(new_client, 6) != os
+                || i2c_smbus_read_byte_data(new_client, 7) != os)
+                       return -ENODEV;
+       }
+
        /* Addresses cycling */
-       for (i = 8; i < 0xff; i += 8) {
+       for (i = 8; i <= 248; i += 40) {
                if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
-                || i2c_smbus_read_word_data(new_client, i + 2) != hyst
-                || i2c_smbus_read_word_data(new_client, i + 3) != os)
+                || i2c_smbus_read_byte_data(new_client, i + 2) != hyst
+                || i2c_smbus_read_byte_data(new_client, i + 3) != os)
+                       return -ENODEV;
+               if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7)
+                               != LM75A_ID)
                        return -ENODEV;
        }
 
-       strlcpy(info->type, "lm75", I2C_NAME_SIZE);
+       strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE);
 
        return 0;
 }
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
new file mode 100644 (file)
index 0000000..9a51dcc
--- /dev/null
@@ -0,0 +1,858 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+
+#define DRVNAME "sch5627"
+#define DEVNAME DRVNAME /* We only support one model */
+
+#define SIO_SCH5627_EM_LD      0x0C    /* Embedded Microcontroller LD */
+#define SIO_UNLOCK_KEY         0x55    /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY           0xAA    /* Key to disable Super-I/O */
+
+#define SIO_REG_LDSEL          0x07    /* Logical device select */
+#define SIO_REG_DEVID          0x20    /* Device ID */
+#define SIO_REG_ENABLE         0x30    /* Logical device enable */
+#define SIO_REG_ADDR           0x66    /* Logical device address (2 bytes) */
+
+#define SIO_SCH5627_ID         0xC6    /* Chipset ID */
+
+#define REGION_LENGTH          9
+
+#define SCH5627_HWMON_ID               0xa5
+#define SCH5627_COMPANY_ID             0x5c
+#define SCH5627_PRIMARY_ID             0xa0
+
+#define SCH5627_REG_BUILD_CODE         0x39
+#define SCH5627_REG_BUILD_ID           0x3a
+#define SCH5627_REG_HWMON_ID           0x3c
+#define SCH5627_REG_HWMON_REV          0x3d
+#define SCH5627_REG_COMPANY_ID         0x3e
+#define SCH5627_REG_PRIMARY_ID         0x3f
+#define SCH5627_REG_CTRL               0x40
+
+#define SCH5627_NO_TEMPS               8
+#define SCH5627_NO_FANS                        4
+#define SCH5627_NO_IN                  5
+
+static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
+       0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
+static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
+       0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
+static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
+       0, 0, 1, 1, 0, 0, 0, 1 };
+static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
+       0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
+static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
+       0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
+
+static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
+       0x2C, 0x2E, 0x30, 0x32 };
+static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
+       0x62, 0x64, 0x66, 0x68 };
+
+static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
+       0x22, 0x23, 0x24, 0x25, 0x189 };
+static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
+       0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
+static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
+       1, 0, 1, 0, 1 };
+static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
+       10745, 3660, 9765, 10745, 3660 };
+static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
+       "VCC", "VTT", "VBAT", "VTR", "V_IN" };
+
+struct sch5627_data {
+       unsigned short addr;
+       struct device *hwmon_dev;
+       u8 temp_max[SCH5627_NO_TEMPS];
+       u8 temp_crit[SCH5627_NO_TEMPS];
+       u16 fan_min[SCH5627_NO_FANS];
+
+       struct mutex update_lock;
+       char valid;                     /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+       u16 temp[SCH5627_NO_TEMPS];
+       u16 fan[SCH5627_NO_FANS];
+       u16 in[SCH5627_NO_IN];
+};
+
+static struct platform_device *sch5627_pdev;
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+       outb(reg, base);
+       return inb(base + 1);
+}
+
+static inline int superio_enter(int base)
+{
+       /* Don't step on other drivers' I/O space by accident */
+       if (!request_muxed_region(base, 2, DRVNAME)) {
+               pr_err("I/O address 0x%04x already in use\n", base);
+               return -EBUSY;
+       }
+
+       outb(SIO_UNLOCK_KEY, base);
+
+       return 0;
+}
+
+static inline void superio_select(int base, int ld)
+{
+       outb(SIO_REG_LDSEL, base);
+       outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+       outb(SIO_LOCK_KEY, base);
+       release_region(base, 2);
+}
+
+static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+{
+       u8 val;
+       int i;
+       /*
+        * According to SMSC for the commands we use the maximum time for
+        * the EM to respond is 15 ms, but testing shows in practice it
+        * responds within 15-32 reads, so we first busy poll, and if
+        * that fails sleep a bit and try again until we are way past
+        * the 15 ms maximum response time.
+        */
+       const int max_busy_polls = 64;
+       const int max_lazy_polls = 32;
+
+       /* (Optional) Write-Clear the EC to Host Mailbox Register */
+       val = inb(data->addr + 1);
+       outb(val, data->addr + 1);
+
+       /* Set Mailbox Address Pointer to first location in Region 1 */
+       outb(0x00, data->addr + 2);
+       outb(0x80, data->addr + 3);
+
+       /* Write Request Packet Header */
+       outb(0x02, data->addr + 4); /* Access Type: VREG read */
+       outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */
+       outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */
+
+       /* Write Address field */
+       outb(reg & 0xff, data->addr + 6);
+       outb(reg >> 8, data->addr + 7);
+
+       /* Execute the Random Access Command */
+       outb(0x01, data->addr); /* Write 01h to the Host-to-EC register */
+
+       /* EM Interface Polling "Algorithm" */
+       for (i = 0; i < max_busy_polls + max_lazy_polls; i++) {
+               if (i >= max_busy_polls)
+                       msleep(1);
+               /* Read Interrupt source Register */
+               val = inb(data->addr + 8);
+               /* Write Clear the interrupt source bits */
+               if (val)
+                       outb(val, data->addr + 8);
+               /* Command Completed ? */
+               if (val & 0x01)
+                       break;
+       }
+       if (i == max_busy_polls + max_lazy_polls) {
+               pr_err("Max retries exceeded reading virtual "
+                      "register 0x%04hx (%d)\n", reg, 1);
+               return -EIO;
+       }
+
+       /*
+        * According to SMSC we may need to retry this, but sofar I've always
+        * seen this succeed in 1 try.
+        */
+       for (i = 0; i < max_busy_polls; i++) {
+               /* Read EC-to-Host Register */
+               val = inb(data->addr + 1);
+               /* Command Completed ? */
+               if (val == 0x01)
+                       break;
+
+               if (i == 0)
+                       pr_warn("EC reports: 0x%02x reading virtual register "
+                               "0x%04hx\n", (unsigned int)val, reg);
+       }
+       if (i == max_busy_polls) {
+               pr_err("Max retries exceeded reading virtual "
+                      "register 0x%04hx (%d)\n", reg, 2);
+               return -EIO;
+       }
+
+       /*
+        * According to the SMSC app note we should now do:
+        *
+        * Set Mailbox Address Pointer to first location in Region 1 *
+        * outb(0x00, data->addr + 2);
+        * outb(0x80, data->addr + 3);
+        *
+        * But if we do that things don't work, so let's not.
+        */
+
+       /* Read Data from Mailbox */
+       return inb(data->addr + 4);
+}
+
+static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg)
+{
+       int lsb, msb;
+
+       /* Read LSB first, this will cause the matching MSB to be latched */
+       lsb = sch5627_read_virtual_reg(data, reg);
+       if (lsb < 0)
+               return lsb;
+
+       msb = sch5627_read_virtual_reg(data, reg + 1);
+       if (msb < 0)
+               return msb;
+
+       return lsb | (msb << 8);
+}
+
+static int sch5627_read_virtual_reg12(struct sch5627_data *data, u16 msb_reg,
+                                     u16 lsn_reg, int high_nibble)
+{
+       int msb, lsn;
+
+       /* Read MSB first, this will cause the matching LSN to be latched */
+       msb = sch5627_read_virtual_reg(data, msb_reg);
+       if (msb < 0)
+               return msb;
+
+       lsn = sch5627_read_virtual_reg(data, lsn_reg);
+       if (lsn < 0)
+               return lsn;
+
+       if (high_nibble)
+               return (msb << 4) | (lsn >> 4);
+       else
+               return (msb << 4) | (lsn & 0x0f);
+}
+
+static struct sch5627_data *sch5627_update_device(struct device *dev)
+{
+       struct sch5627_data *data = dev_get_drvdata(dev);
+       struct sch5627_data *ret = data;
+       int i, val;
+
+       mutex_lock(&data->update_lock);
+
+       /* Cache the values for 1 second */
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               for (i = 0; i < SCH5627_NO_TEMPS; i++) {
+                       val = sch5627_read_virtual_reg12(data,
+                               SCH5627_REG_TEMP_MSB[i],
+                               SCH5627_REG_TEMP_LSN[i],
+                               SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
+                       if (unlikely(val < 0)) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->temp[i] = val;
+               }
+
+               for (i = 0; i < SCH5627_NO_FANS; i++) {
+                       val = sch5627_read_virtual_reg16(data,
+                                                        SCH5627_REG_FAN[i]);
+                       if (unlikely(val < 0)) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->fan[i] = val;
+               }
+
+               for (i = 0; i < SCH5627_NO_IN; i++) {
+                       val = sch5627_read_virtual_reg12(data,
+                               SCH5627_REG_IN_MSB[i],
+                               SCH5627_REG_IN_LSN[i],
+                               SCH5627_REG_IN_HIGH_NIBBLE[i]);
+                       if (unlikely(val < 0)) {
+                               ret = ERR_PTR(val);
+                               goto abort;
+                       }
+                       data->in[i] = val;
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static int __devinit sch5627_read_limits(struct sch5627_data *data)
+{
+       int i, val;
+
+       for (i = 0; i < SCH5627_NO_TEMPS; i++) {
+               /*
+                * Note what SMSC calls ABS, is what lm_sensors calls max
+                * (aka high), and HIGH is what lm_sensors calls crit.
+                */
+               val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_ABS[i]);
+               if (val < 0)
+                       return val;
+               data->temp_max[i] = val;
+
+               val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_HIGH[i]);
+               if (val < 0)
+                       return val;
+               data->temp_crit[i] = val;
+       }
+       for (i = 0; i < SCH5627_NO_FANS; i++) {
+               val = sch5627_read_virtual_reg16(data, SCH5627_REG_FAN_MIN[i]);
+               if (val < 0)
+                       return val;
+               data->fan_min[i] = val;
+       }
+
+       return 0;
+}
+
+static int reg_to_temp(u16 reg)
+{
+       return (reg * 625) / 10 - 64000;
+}
+
+static int reg_to_temp_limit(u8 reg)
+{
+       return (reg - 64) * 1000;
+}
+
+static int reg_to_rpm(u16 reg)
+{
+       if (reg == 0)
+               return -EIO;
+       if (reg == 0xffff)
+               return 0;
+
+       return 5400540 / reg;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = sch5627_update_device(dev);
+       int val;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       val = reg_to_temp(data->temp[attr->index]);
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = sch5627_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = dev_get_drvdata(dev);
+       int val;
+
+       val = reg_to_temp_limit(data->temp_max[attr->index]);
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = dev_get_drvdata(dev);
+       int val;
+
+       val = reg_to_temp_limit(data->temp_crit[attr->index]);
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = sch5627_update_device(dev);
+       int val;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       val = reg_to_rpm(data->fan[attr->index]);
+       if (val < 0)
+               return val;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = sch5627_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       data->fan[attr->index] == 0xffff);
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = dev_get_drvdata(dev);
+       int val = reg_to_rpm(data->fan_min[attr->index]);
+       if (val < 0)
+               return val;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct sch5627_data *data = sch5627_update_device(dev);
+       int val;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       val = DIV_ROUND_CLOSEST(
+               data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index],
+               10000);
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t show_in_label(struct device *dev, struct device_attribute
+       *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       SCH5627_IN_LABELS[attr->index]);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_temp_fault, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_temp_fault, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IRUGO, show_temp_max, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IRUGO, show_temp_max, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_crit, S_IRUGO, show_temp_crit, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_crit, S_IRUGO, show_temp_crit, NULL, 7);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan_min, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO, show_fan_min, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IRUGO, show_fan_min, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_in_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_in_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_in_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_in_label, NULL, 3);
+
+static struct attribute *sch5627_attributes[] = {
+       &dev_attr_name.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp6_input.dev_attr.attr,
+       &sensor_dev_attr_temp7_input.dev_attr.attr,
+       &sensor_dev_attr_temp8_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
+       &sensor_dev_attr_temp5_fault.dev_attr.attr,
+       &sensor_dev_attr_temp6_fault.dev_attr.attr,
+       &sensor_dev_attr_temp7_fault.dev_attr.attr,
+       &sensor_dev_attr_temp8_fault.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp6_max.dev_attr.attr,
+       &sensor_dev_attr_temp7_max.dev_attr.attr,
+       &sensor_dev_attr_temp8_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp3_crit.dev_attr.attr,
+       &sensor_dev_attr_temp4_crit.dev_attr.attr,
+       &sensor_dev_attr_temp5_crit.dev_attr.attr,
+       &sensor_dev_attr_temp6_crit.dev_attr.attr,
+       &sensor_dev_attr_temp7_crit.dev_attr.attr,
+       &sensor_dev_attr_temp8_crit.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_fault.dev_attr.attr,
+       &sensor_dev_attr_fan2_fault.dev_attr.attr,
+       &sensor_dev_attr_fan3_fault.dev_attr.attr,
+       &sensor_dev_attr_fan4_fault.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in0_label.dev_attr.attr,
+       &sensor_dev_attr_in1_label.dev_attr.attr,
+       &sensor_dev_attr_in2_label.dev_attr.attr,
+       &sensor_dev_attr_in3_label.dev_attr.attr,
+       /* No in4_label as in4 is a generic input pin */
+
+       NULL
+};
+
+static const struct attribute_group sch5627_group = {
+       .attrs = sch5627_attributes,
+};
+
+static int sch5627_remove(struct platform_device *pdev)
+{
+       struct sch5627_data *data = platform_get_drvdata(pdev);
+
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
+       platform_set_drvdata(pdev, NULL);
+       kfree(data);
+
+       return 0;
+}
+
+static int __devinit sch5627_probe(struct platform_device *pdev)
+{
+       struct sch5627_data *data;
+       int err, build_code, build_id, hwmon_rev, val;
+
+       data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+       mutex_init(&data->update_lock);
+       platform_set_drvdata(pdev, data);
+
+       val = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_ID);
+       if (val < 0) {
+               err = val;
+               goto error;
+       }
+       if (val != SCH5627_HWMON_ID) {
+               pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
+                      val, SCH5627_HWMON_ID);
+               err = -ENODEV;
+               goto error;
+       }
+
+       val = sch5627_read_virtual_reg(data, SCH5627_REG_COMPANY_ID);
+       if (val < 0) {
+               err = val;
+               goto error;
+       }
+       if (val != SCH5627_COMPANY_ID) {
+               pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
+                      val, SCH5627_COMPANY_ID);
+               err = -ENODEV;
+               goto error;
+       }
+
+       val = sch5627_read_virtual_reg(data, SCH5627_REG_PRIMARY_ID);
+       if (val < 0) {
+               err = val;
+               goto error;
+       }
+       if (val != SCH5627_PRIMARY_ID) {
+               pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
+                      val, SCH5627_PRIMARY_ID);
+               err = -ENODEV;
+               goto error;
+       }
+
+       build_code = sch5627_read_virtual_reg(data, SCH5627_REG_BUILD_CODE);
+       if (build_code < 0) {
+               err = build_code;
+               goto error;
+       }
+
+       build_id = sch5627_read_virtual_reg16(data, SCH5627_REG_BUILD_ID);
+       if (build_id < 0) {
+               err = build_id;
+               goto error;
+       }
+
+       hwmon_rev = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_REV);
+       if (hwmon_rev < 0) {
+               err = hwmon_rev;
+               goto error;
+       }
+
+       val = sch5627_read_virtual_reg(data, SCH5627_REG_CTRL);
+       if (val < 0) {
+               err = val;
+               goto error;
+       }
+       if (!(val & 0x01)) {
+               pr_err("hardware monitoring not enabled\n");
+               err = -ENODEV;
+               goto error;
+       }
+
+       /*
+        * Read limits, we do this only once as reading a register on
+        * the sch5627 is quite expensive (and they don't change).
+        */
+       err = sch5627_read_limits(data);
+       if (err)
+               goto error;
+
+       pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
+               build_code, build_id, hwmon_rev);
+
+       /* Register sysfs interface files */
+       err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group);
+       if (err)
+               goto error;
+
+       data->hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               data->hwmon_dev = NULL;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       sch5627_remove(pdev);
+       return err;
+}
+
+static int __init sch5627_find(int sioaddr, unsigned short *address)
+{
+       u8 devid;
+       int err = superio_enter(sioaddr);
+       if (err)
+               return err;
+
+       devid = superio_inb(sioaddr, SIO_REG_DEVID);
+       if (devid != SIO_SCH5627_ID) {
+               pr_debug("Unsupported device id: 0x%02x\n",
+                        (unsigned int)devid);
+               err = -ENODEV;
+               goto exit;
+       }
+
+       superio_select(sioaddr, SIO_SCH5627_EM_LD);
+
+       if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+               pr_warn("Device not activated\n");
+               err = -ENODEV;
+               goto exit;
+       }
+
+       /*
+        * Warning the order of the low / high byte is the other way around
+        * as on most other superio devices!!
+        */
+       *address = superio_inb(sioaddr, SIO_REG_ADDR) |
+                  superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
+       if (*address == 0) {
+               pr_warn("Base address not set\n");
+               err = -ENODEV;
+               goto exit;
+       }
+
+       pr_info("Found %s chip at %#hx\n", DEVNAME, *address);
+exit:
+       superio_exit(sioaddr);
+       return err;
+}
+
+static int __init sch5627_device_add(unsigned short address)
+{
+       struct resource res = {
+               .start  = address,
+               .end    = address + REGION_LENGTH - 1,
+               .flags  = IORESOURCE_IO,
+       };
+       int err;
+
+       sch5627_pdev = platform_device_alloc(DRVNAME, address);
+       if (!sch5627_pdev)
+               return -ENOMEM;
+
+       res.name = sch5627_pdev->name;
+       err = acpi_check_resource_conflict(&res);
+       if (err)
+               goto exit_device_put;
+
+       err = platform_device_add_resources(sch5627_pdev, &res, 1);
+       if (err) {
+               pr_err("Device resource addition failed\n");
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(sch5627_pdev);
+       if (err) {
+               pr_err("Device addition failed\n");
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(sch5627_pdev);
+
+       return err;
+}
+
+static struct platform_driver sch5627_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = DRVNAME,
+       },
+       .probe          = sch5627_probe,
+       .remove         = sch5627_remove,
+};
+
+static int __init sch5627_init(void)
+{
+       int err = -ENODEV;
+       unsigned short address;
+
+       if (sch5627_find(0x4e, &address) && sch5627_find(0x2e, &address))
+               goto exit;
+
+       err = platform_driver_register(&sch5627_driver);
+       if (err)
+               goto exit;
+
+       err = sch5627_device_add(address);
+       if (err)
+               goto exit_driver;
+
+       return 0;
+
+exit_driver:
+       platform_driver_unregister(&sch5627_driver);
+exit:
+       return err;
+}
+
+static void __exit sch5627_exit(void)
+{
+       platform_device_unregister(sch5627_pdev);
+       platform_driver_unregister(&sch5627_driver);
+}
+
+MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans de Goede (hdegoede@redhat.com)");
+MODULE_LICENSE("GPL");
+
+module_init(sch5627_init);
+module_exit(sch5627_exit);
index a610e7880fb3e5498b5d836d456ec4e25c58e278..1a9c32d6893a83b2c6603b70c0bfa1e0428488d7 100644 (file)
@@ -333,11 +333,11 @@ static inline int sht15_calc_humid(struct sht15_data *data)
 
        const int c1 = -4;
        const int c2 = 40500; /* x 10 ^ -6 */
-       const int c3 = -2800; /* x10 ^ -9 */
+       const int c3 = -28; /* x 10 ^ -7 */
 
        RHlinear = c1*1000
                + c2 * data->val_humid/1000
-               + (data->val_humid * data->val_humid * c3)/1000000;
+               + (data->val_humid * data->val_humid * c3) / 10000;
        return (temp - 25000) * (10000 + 80 * data->val_humid)
                / 1000000 + RHlinear;
 }
@@ -610,7 +610,7 @@ static int __devexit sht15_remove(struct platform_device *pdev)
        struct sht15_data *data = platform_get_drvdata(pdev);
 
        /* Make sure any reads from the device are done and
-        * prevent new ones beginnning */
+        * prevent new ones from beginning */
        mutex_lock(&data->read_lock);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c
new file mode 100644 (file)
index 0000000..97e22be
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *
+ * TWL4030 MADC Hwmon driver-This driver monitors the real time
+ * conversion of analog signals like battery temperature,
+ * battery type, battery level etc. User can ask for the conversion on a
+ * particular channel using the sysfs nodes.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c/twl.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/stddef.h>
+#include <linux/sysfs.h>
+#include <linux/err.h>
+#include <linux/types.h>
+
+/*
+ * sysfs hook function
+ */
+static ssize_t madc_read(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct twl4030_madc_request req;
+       long val;
+
+       req.channels = (1 << attr->index);
+       req.method = TWL4030_MADC_SW2;
+       req.func_cb = NULL;
+       val = twl4030_madc_conversion(&req);
+       if (val < 0)
+               return val;
+
+       return sprintf(buf, "%d\n", req.rbuf[attr->index]);
+}
+
+/* sysfs nodes to read individual channels from user side */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, madc_read, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, madc_read, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, madc_read, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, madc_read, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, madc_read, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, madc_read, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, madc_read, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, madc_read, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, madc_read, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, madc_read, NULL, 9);
+static SENSOR_DEVICE_ATTR(curr10_input, S_IRUGO, madc_read, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15);
+
+static struct attribute *twl4030_madc_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in6_input.dev_attr.attr,
+       &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in8_input.dev_attr.attr,
+       &sensor_dev_attr_in9_input.dev_attr.attr,
+       &sensor_dev_attr_curr10_input.dev_attr.attr,
+       &sensor_dev_attr_in11_input.dev_attr.attr,
+       &sensor_dev_attr_in12_input.dev_attr.attr,
+       &sensor_dev_attr_in15_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group twl4030_madc_group = {
+       .attrs = twl4030_madc_attributes,
+};
+
+static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev)
+{
+       int ret;
+       int status;
+       struct device *hwmon;
+
+       ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group);
+       if (ret)
+               goto err_sysfs;
+       hwmon = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(hwmon)) {
+               dev_err(&pdev->dev, "hwmon_device_register failed.\n");
+               status = PTR_ERR(hwmon);
+               goto err_reg;
+       }
+
+       return 0;
+
+err_reg:
+       sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
+err_sysfs:
+
+       return ret;
+}
+
+static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev)
+{
+       hwmon_device_unregister(&pdev->dev);
+       sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_madc_hwmon_driver = {
+       .probe = twl4030_madc_hwmon_probe,
+       .remove = __exit_p(twl4030_madc_hwmon_remove),
+       .driver = {
+                  .name = "twl4030_madc_hwmon",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+static int __init twl4030_madc_hwmon_init(void)
+{
+       return platform_driver_register(&twl4030_madc_hwmon_driver);
+}
+
+module_init(twl4030_madc_hwmon_init);
+
+static void __exit twl4030_madc_hwmon_exit(void)
+{
+       platform_driver_unregister(&twl4030_madc_hwmon_driver);
+}
+
+module_exit(twl4030_madc_hwmon_exit);
+
+MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("J Keerthy");
+MODULE_ALIAS("twl4030_madc_hwmon");
index 23ac61e2db398363ccb4bb742d8f07aff0aa7e60..beee6b2d361db458a1336a48bd13b5166d6d013c 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_I2C_MUX)         += i2c-mux.o
 obj-y                          += algos/ busses/ muxes/
 
 ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
+CFLAGS_i2c-core.o := -Wno-deprecated-declarations
index 230601e8853fff715a23465a507cdc054390d72b..326652f673f7e0fc1b709320204046290e6c7ae7 100644 (file)
@@ -98,8 +98,9 @@ config I2C_I801
            EP80579 (Tolapai)
            ICH10
            5/3400 Series (PCH)
-           Cougar Point (PCH)
+           6 Series (PCH)
            Patsburg (PCH)
+           DH89xxCC (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -546,15 +547,18 @@ config I2C_PUV3
 
 config I2C_PXA
        tristate "Intel PXA2XX I2C adapter"
-       depends on ARCH_PXA || ARCH_MMP
+       depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF)
        help
          If you have devices in the PXA I2C bus, say yes to this option.
          This driver can also be built as a module.  If so, the module
          will be called i2c-pxa.
 
+config I2C_PXA_PCI
+       def_bool I2C_PXA && X86_32 && PCI && OF
+
 config I2C_PXA_SLAVE
        bool "Intel PXA2XX I2C Slave comms support"
-       depends on I2C_PXA
+       depends on I2C_PXA && !X86_32
        help
          Support I2C slave mode communications on the PXA I2C bus.  This
          is necessary for systems where the PXA may be a target on the
@@ -667,15 +671,28 @@ config I2C_XILINX
          will be called xilinx_i2c.
 
 config I2C_EG20T
-        tristate "PCH I2C of Intel EG20T"
-        depends on PCI
-        help
-          This driver is for PCH(Platform controller Hub) I2C of EG20T which
-          is an IOH(Input/Output Hub) for x86 embedded processor.
-          This driver can access PCH I2C bus device.
+       tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+       depends on PCI
+       help
+         This driver is for PCH(Platform controller Hub) I2C of EG20T which
+         is an IOH(Input/Output Hub) for x86 embedded processor.
+         This driver can access PCH I2C bus device.
+
+         This driver also supports the ML7213, a companion chip for the
+         Atom E6xx series and compatible with the Intel EG20T PCH.
 
 comment "External I2C/SMBus adapter drivers"
 
+config I2C_DIOLAN_U2C
+       tristate "Diolan U2C-12 USB adapter"
+       depends on USB
+       help
+         If you say yes to this option, support will be included for Diolan
+         U2C-12, a USB to I2C interface.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-diolan-u2c.
+
 config I2C_PARPORT
        tristate "Parallel port adapter"
        depends on PARPORT
index 3878c959d4fa89356e894633f3d02b9e87e2f867..e6cf294d37293b75287c566353f0945a7d5203ee 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_I2C_PMCMSP)      += i2c-pmcmsp.o
 obj-$(CONFIG_I2C_PNX)          += i2c-pnx.o
 obj-$(CONFIG_I2C_PUV3)         += i2c-puv3.o
 obj-$(CONFIG_I2C_PXA)          += i2c-pxa.o
+obj-$(CONFIG_I2C_PXA_PCI)      += i2c-pxa-pci.o
 obj-$(CONFIG_I2C_S3C2410)      += i2c-s3c2410.o
 obj-$(CONFIG_I2C_S6000)                += i2c-s6000.o
 obj-$(CONFIG_I2C_SH7760)       += i2c-sh7760.o
@@ -67,6 +68,7 @@ obj-$(CONFIG_I2C_XILINX)      += i2c-xiic.o
 obj-$(CONFIG_I2C_EG20T)         += i2c-eg20t.o
 
 # External I2C/SMBus adapter drivers
+obj-$(CONFIG_I2C_DIOLAN_U2C)   += i2c-diolan-u2c.o
 obj-$(CONFIG_I2C_PARPORT)      += i2c-parport.o
 obj-$(CONFIG_I2C_PARPORT_LIGHT)        += i2c-parport-light.o
 obj-$(CONFIG_I2C_TAOS_EVM)     += i2c-taos-evm.o
diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c
new file mode 100644 (file)
index 0000000..7636671
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Driver for the Diolan u2c-12 USB-I2C adapter
+ *
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * Derived from:
+ *  i2c-tiny-usb.c
+ *  Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#define DRIVER_NAME            "i2c-diolan-u2c"
+
+#define USB_VENDOR_ID_DIOLAN           0x0abf
+#define USB_DEVICE_ID_DIOLAN_U2C       0x3370
+
+#define DIOLAN_OUT_EP          0x02
+#define DIOLAN_IN_EP           0x84
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_I2C_READ           0x01
+#define CMD_I2C_WRITE          0x02
+#define CMD_I2C_SCAN           0x03    /* Returns list of detected devices */
+#define CMD_I2C_RELEASE_SDA    0x04
+#define CMD_I2C_RELEASE_SCL    0x05
+#define CMD_I2C_DROP_SDA       0x06
+#define CMD_I2C_DROP_SCL       0x07
+#define CMD_I2C_READ_SDA       0x08
+#define CMD_I2C_READ_SCL       0x09
+#define CMD_GET_FW_VERSION     0x0a
+#define CMD_GET_SERIAL         0x0b
+#define CMD_I2C_START          0x0c
+#define CMD_I2C_STOP           0x0d
+#define CMD_I2C_REPEATED_START 0x0e
+#define CMD_I2C_PUT_BYTE       0x0f
+#define CMD_I2C_GET_BYTE       0x10
+#define CMD_I2C_PUT_ACK                0x11
+#define CMD_I2C_GET_ACK                0x12
+#define CMD_I2C_PUT_BYTE_ACK   0x13
+#define CMD_I2C_GET_BYTE_ACK   0x14
+#define CMD_I2C_SET_SPEED      0x1b
+#define CMD_I2C_GET_SPEED      0x1c
+#define CMD_I2C_SET_CLK_SYNC   0x24
+#define CMD_I2C_GET_CLK_SYNC   0x25
+#define CMD_I2C_SET_CLK_SYNC_TO        0x26
+#define CMD_I2C_GET_CLK_SYNC_TO        0x27
+
+#define RESP_OK                        0x00
+#define RESP_FAILED            0x01
+#define RESP_BAD_MEMADDR       0x04
+#define RESP_DATA_ERR          0x05
+#define RESP_NOT_IMPLEMENTED   0x06
+#define RESP_NACK              0x07
+#define RESP_TIMEOUT           0x09
+
+#define U2C_I2C_SPEED_FAST     0       /* 400 kHz */
+#define U2C_I2C_SPEED_STD      1       /* 100 kHz */
+#define U2C_I2C_SPEED_2KHZ     242     /* 2 kHz, minimum speed */
+#define U2C_I2C_SPEED(f)       ((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1)
+
+#define U2C_I2C_FREQ_FAST      400000
+#define U2C_I2C_FREQ_STD       100000
+#define U2C_I2C_FREQ(s)                (1000000 / (2 * (s - 1) + 10))
+
+#define DIOLAN_USB_TIMEOUT     100     /* in ms */
+#define DIOLAN_SYNC_TIMEOUT    20      /* in ms */
+
+#define DIOLAN_OUTBUF_LEN      128
+#define DIOLAN_FLUSH_LEN       (DIOLAN_OUTBUF_LEN - 4)
+#define DIOLAN_INBUF_LEN       256     /* Maximum supported receive length */
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_diolan_u2c {
+       u8 obuffer[DIOLAN_OUTBUF_LEN];  /* output buffer */
+       u8 ibuffer[DIOLAN_INBUF_LEN];   /* input buffer */
+       struct usb_device *usb_dev;     /* the usb device for this device */
+       struct usb_interface *interface;/* the interface for this device */
+       struct i2c_adapter adapter;     /* i2c related things */
+       int olen;                       /* Output buffer length */
+       int ocount;                     /* Number of enqueued messages */
+};
+
+static uint frequency = U2C_I2C_FREQ_STD;      /* I2C clock frequency in Hz */
+
+module_param(frequency, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
+
+/* usb layer */
+
+/* Send command to device, and get response. */
+static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
+{
+       int ret = 0;
+       int actual;
+       int i;
+
+       if (!dev->olen || !dev->ocount)
+               return -EINVAL;
+
+       ret = usb_bulk_msg(dev->usb_dev,
+                          usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP),
+                          dev->obuffer, dev->olen, &actual,
+                          DIOLAN_USB_TIMEOUT);
+       if (!ret) {
+               for (i = 0; i < dev->ocount; i++) {
+                       int tmpret;
+
+                       tmpret = usb_bulk_msg(dev->usb_dev,
+                                             usb_rcvbulkpipe(dev->usb_dev,
+                                                             DIOLAN_IN_EP),
+                                             dev->ibuffer,
+                                             sizeof(dev->ibuffer), &actual,
+                                             DIOLAN_USB_TIMEOUT);
+                       /*
+                        * Stop command processing if a previous command
+                        * returned an error.
+                        * Note that we still need to retrieve all messages.
+                        */
+                       if (ret < 0)
+                               continue;
+                       ret = tmpret;
+                       if (ret == 0 && actual > 0) {
+                               switch (dev->ibuffer[actual - 1]) {
+                               case RESP_NACK:
+                                       /*
+                                        * Return ENXIO if NACK was received as
+                                        * response to the address phase,
+                                        * EIO otherwise
+                                        */
+                                       ret = i == 1 ? -ENXIO : -EIO;
+                                       break;
+                               case RESP_TIMEOUT:
+                                       ret = -ETIMEDOUT;
+                                       break;
+                               case RESP_OK:
+                                       /* strip off return code */
+                                       ret = actual - 1;
+                                       break;
+                               default:
+                                       ret = -EIO;
+                                       break;
+                               }
+                       }
+               }
+       }
+       dev->olen = 0;
+       dev->ocount = 0;
+       return ret;
+}
+
+static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
+{
+       if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
+               return diolan_usb_transfer(dev);
+       return 0;
+}
+
+/* Send command (no data) */
+static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
+{
+       dev->obuffer[dev->olen++] = command;
+       dev->ocount++;
+       return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with one byte of data */
+static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data,
+                              bool flush)
+{
+       dev->obuffer[dev->olen++] = command;
+       dev->obuffer[dev->olen++] = data;
+       dev->ocount++;
+       return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with two bytes of data */
+static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1,
+                               u8 d2, bool flush)
+{
+       dev->obuffer[dev->olen++] = command;
+       dev->obuffer[dev->olen++] = d1;
+       dev->obuffer[dev->olen++] = d2;
+       dev->ocount++;
+       return diolan_write_cmd(dev, flush);
+}
+
+/*
+ * Flush input queue.
+ * If we don't do this at startup and the controller has queued up
+ * messages which were not retrieved, it will stop responding
+ * at some point.
+ */
+static void diolan_flush_input(struct i2c_diolan_u2c *dev)
+{
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               int actual = 0;
+               int ret;
+
+               ret = usb_bulk_msg(dev->usb_dev,
+                                  usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP),
+                                  dev->ibuffer, sizeof(dev->ibuffer), &actual,
+                                  DIOLAN_USB_TIMEOUT);
+               if (ret < 0 || actual == 0)
+                       break;
+       }
+       if (i == 10)
+               dev_err(&dev->interface->dev, "Failed to flush input buffer\n");
+}
+
+static int diolan_i2c_start(struct i2c_diolan_u2c *dev)
+{
+       return diolan_usb_cmd(dev, CMD_I2C_START, false);
+}
+
+static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev)
+{
+       return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false);
+}
+
+static int diolan_i2c_stop(struct i2c_diolan_u2c *dev)
+{
+       return diolan_usb_cmd(dev, CMD_I2C_STOP, true);
+}
+
+static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack,
+                                  u8 *byte)
+{
+       int ret;
+
+       ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true);
+       if (ret > 0)
+               *byte = dev->ibuffer[0];
+       else if (ret == 0)
+               ret = -EIO;
+
+       return ret;
+}
+
+static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte)
+{
+       return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false);
+}
+
+static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed)
+{
+       return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true);
+}
+
+/* Enable or disable clock synchronization (stretching) */
+static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable)
+{
+       return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true);
+}
+
+/* Set clock synchronization timeout in ms */
+static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms)
+{
+       int to_val = ms * 10;
+
+       return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO,
+                                   to_val & 0xff, (to_val >> 8) & 0xff, true);
+}
+
+static void diolan_fw_version(struct i2c_diolan_u2c *dev)
+{
+       int ret;
+
+       ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true);
+       if (ret >= 2)
+               dev_info(&dev->interface->dev,
+                        "Diolan U2C firmware version %u.%u\n",
+                        (unsigned int)dev->ibuffer[0],
+                        (unsigned int)dev->ibuffer[1]);
+}
+
+static void diolan_get_serial(struct i2c_diolan_u2c *dev)
+{
+       int ret;
+       u32 serial;
+
+       ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true);
+       if (ret >= 4) {
+               serial = le32_to_cpu(*(u32 *)dev->ibuffer);
+               dev_info(&dev->interface->dev,
+                        "Diolan U2C serial number %u\n", serial);
+       }
+}
+
+static int diolan_init(struct i2c_diolan_u2c *dev)
+{
+       int speed, ret;
+
+       if (frequency >= 200000) {
+               speed = U2C_I2C_SPEED_FAST;
+               frequency = U2C_I2C_FREQ_FAST;
+       } else if (frequency >= 100000 || frequency == 0) {
+               speed = U2C_I2C_SPEED_STD;
+               frequency = U2C_I2C_FREQ_STD;
+       } else {
+               speed = U2C_I2C_SPEED(frequency);
+               if (speed > U2C_I2C_SPEED_2KHZ)
+                       speed = U2C_I2C_SPEED_2KHZ;
+               frequency = U2C_I2C_FREQ(speed);
+       }
+
+       dev_info(&dev->interface->dev,
+                "Diolan U2C at USB bus %03d address %03d speed %d Hz\n",
+                dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency);
+
+       diolan_flush_input(dev);
+       diolan_fw_version(dev);
+       diolan_get_serial(dev);
+
+       /* Set I2C speed */
+       ret = diolan_set_speed(dev, speed);
+       if (ret < 0)
+               return ret;
+
+       /* Configure I2C clock synchronization */
+       ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST);
+       if (ret < 0)
+               return ret;
+
+       if (speed != U2C_I2C_SPEED_FAST)
+               ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT);
+
+       return ret;
+}
+
+/* i2c layer */
+
+static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+                          int num)
+{
+       struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter);
+       struct i2c_msg *pmsg;
+       int i, j;
+       int ret, sret;
+
+       ret = diolan_i2c_start(dev);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < num; i++) {
+               pmsg = &msgs[i];
+               if (i) {
+                       ret = diolan_i2c_repeated_start(dev);
+                       if (ret < 0)
+                               goto abort;
+               }
+               if (pmsg->flags & I2C_M_RD) {
+                       ret =
+                           diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
+                       if (ret < 0)
+                               goto abort;
+                       for (j = 0; j < pmsg->len; j++) {
+                               u8 byte;
+                               bool ack = j < pmsg->len - 1;
+
+                               /*
+                                * Don't send NACK if this is the first byte
+                                * of a SMBUS_BLOCK message.
+                                */
+                               if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN))
+                                       ack = true;
+
+                               ret = diolan_i2c_get_byte_ack(dev, ack, &byte);
+                               if (ret < 0)
+                                       goto abort;
+                               /*
+                                * Adjust count if first received byte is length
+                                */
+                               if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) {
+                                       if (byte == 0
+                                           || byte > I2C_SMBUS_BLOCK_MAX) {
+                                               ret = -EPROTO;
+                                               goto abort;
+                                       }
+                                       pmsg->len += byte;
+                               }
+                               pmsg->buf[j] = byte;
+                       }
+               } else {
+                       ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
+                       if (ret < 0)
+                               goto abort;
+                       for (j = 0; j < pmsg->len; j++) {
+                               ret = diolan_i2c_put_byte_ack(dev,
+                                                             pmsg->buf[j]);
+                               if (ret < 0)
+                                       goto abort;
+                       }
+               }
+       }
+abort:
+       sret = diolan_i2c_stop(dev);
+       if (sret < 0 && ret >= 0)
+               ret = sret;
+       return ret;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 diolan_usb_func(struct i2c_adapter *a)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+              I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm diolan_usb_algorithm = {
+       .master_xfer = diolan_usb_xfer,
+       .functionality = diolan_usb_func,
+};
+
+/* device layer */
+
+static const struct usb_device_id diolan_u2c_table[] = {
+       { USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
+
+static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
+{
+       usb_put_dev(dev->usb_dev);
+       kfree(dev);
+}
+
+static int diolan_u2c_probe(struct usb_interface *interface,
+                           const struct usb_device_id *id)
+{
+       struct i2c_diolan_u2c *dev;
+       int ret;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&interface->dev, "no memory for device state\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+       dev->interface = interface;
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       /* setup i2c adapter description */
+       dev->adapter.owner = THIS_MODULE;
+       dev->adapter.class = I2C_CLASS_HWMON;
+       dev->adapter.algo = &diolan_usb_algorithm;
+       i2c_set_adapdata(&dev->adapter, dev);
+       snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+                DRIVER_NAME " at bus %03d device %03d",
+                dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+       dev->adapter.dev.parent = &dev->interface->dev;
+
+       /* initialize diolan i2c interface */
+       ret = diolan_init(dev);
+       if (ret < 0) {
+               dev_err(&interface->dev, "failed to initialize adapter\n");
+               goto error_free;
+       }
+
+       /* and finally attach to i2c layer */
+       ret = i2c_add_adapter(&dev->adapter);
+       if (ret < 0) {
+               dev_err(&interface->dev, "failed to add I2C adapter\n");
+               goto error_free;
+       }
+
+       dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
+
+       return 0;
+
+error_free:
+       usb_set_intfdata(interface, NULL);
+       diolan_u2c_free(dev);
+error:
+       return ret;
+}
+
+static void diolan_u2c_disconnect(struct usb_interface *interface)
+{
+       struct i2c_diolan_u2c *dev = usb_get_intfdata(interface);
+
+       i2c_del_adapter(&dev->adapter);
+       usb_set_intfdata(interface, NULL);
+       diolan_u2c_free(dev);
+
+       dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver diolan_u2c_driver = {
+       .name = DRIVER_NAME,
+       .probe = diolan_u2c_probe,
+       .disconnect = diolan_u2c_disconnect,
+       .id_table = diolan_u2c_table,
+};
+
+static int __init diolan_u2c_init(void)
+{
+       /* register this driver with the USB subsystem */
+       return usb_register(&diolan_u2c_driver);
+}
+
+static void __exit diolan_u2c_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&diolan_u2c_driver);
+}
+
+module_init(diolan_u2c_init);
+module_exit(diolan_u2c_exit);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION(DRIVER_NAME " driver");
+MODULE_LICENSE("GPL");
index 50ea1f43bdc1ea6f11688c64e044fe573736dba4..878a12026af2e2fa1b89225563248fe597659c02 100644 (file)
 #define pch_pci_dbg(pdev, fmt, arg...)  \
        dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
 
+/*
+Set the number of I2C instance max
+Intel EG20T PCH :              1ch
+OKI SEMICONDUCTOR ML7213 IOH : 2ch
+*/
+#define PCH_I2C_MAX_DEV                        2
+
 /**
  * struct i2c_algo_pch_data - for I2C driver functionalities
  * @pch_adapter:               stores the reference to i2c_adapter structure
@@ -156,12 +163,14 @@ struct i2c_algo_pch_data {
  * @pch_data:          stores a list of i2c_algo_pch_data
  * @pch_i2c_suspended: specifies whether the system is suspended or not
  *                     perhaps with more lines and words.
+ * @ch_num:            specifies the number of i2c instance
  *
  * pch_data has as many elements as maximum I2C channels
  */
 struct adapter_info {
-       struct i2c_algo_pch_data pch_data;
+       struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
        bool pch_i2c_suspended;
+       int ch_num;
 };
 
 
@@ -170,8 +179,13 @@ static int pch_clk = 50000;        /* specifies I2C clock speed in KHz */
 static wait_queue_head_t pch_event;
 static DEFINE_MUTEX(pch_mutex);
 
+/* Definition for ML7213 by OKI SEMICONDUCTOR */
+#define PCI_VENDOR_ID_ROHM             0x10DB
+#define PCI_DEVICE_ID_ML7213_I2C       0x802D
+
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)},
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
        {0,}
 };
 
@@ -212,8 +226,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap)
        /* Initialize I2C registers */
        iowrite32(0x21, p + PCH_I2CNF);
 
-       pch_setbit(adap->pch_base_address, PCH_I2CCTL,
-                         PCH_I2CCTL_I2CMEN);
+       pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
 
        if (pch_i2c_speed != 400)
                pch_i2c_speed = 100;
@@ -255,7 +268,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
  * @timeout:   waiting time counter (us).
  */
 static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
-                                s32 timeout)
+                                    s32 timeout)
 {
        void __iomem *p = adap->pch_base_address;
 
@@ -475,8 +488,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
  * @last:      specifies whether last message or not.
  * @first:     specifies whether first message or not.
  */
-s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
-                 u32 last, u32 first)
+static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+                            u32 last, u32 first)
 {
        struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
 
@@ -569,10 +582,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
 }
 
 /**
- * pch_i2c_cb_ch0() - Interrupt handler Call back function
+ * pch_i2c_cb() - Interrupt handler Call back function
  * @adap:      Pointer to struct i2c_algo_pch_data.
  */
-static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
+static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
 {
        u32 sts;
        void __iomem *p = adap->pch_base_address;
@@ -600,24 +613,30 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
  */
 static irqreturn_t pch_i2c_handler(int irq, void *pData)
 {
-       s32 reg_val;
-
-       struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData;
-       void __iomem *p = adap_data->pch_base_address;
-       u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE);
-
-       if (mode != NORMAL_MODE) {
-               pch_err(adap_data, "I2C mode is not supported\n");
-               return IRQ_NONE;
+       u32 reg_val;
+       int flag;
+       int i;
+       struct adapter_info *adap_info = pData;
+       void __iomem *p;
+       u32 mode;
+
+       for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
+               p = adap_info->pch_data[i].pch_base_address;
+               mode = ioread32(p + PCH_I2CMOD);
+               mode &= BUFFER_MODE | EEPROM_SR_MODE;
+               if (mode != NORMAL_MODE) {
+                       pch_err(adap_info->pch_data,
+                               "I2C-%d mode(%d) is not supported\n", mode, i);
+                       continue;
+               }
+               reg_val = ioread32(p + PCH_I2CSR);
+               if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
+                       pch_i2c_cb(&adap_info->pch_data[i]);
+                       flag = 1;
+               }
        }
 
-       reg_val = ioread32(p + PCH_I2CSR);
-       if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT))
-               pch_i2c_cb_ch0(adap_data);
-       else
-               return IRQ_NONE;
-
-       return IRQ_HANDLED;
+       return flag ? IRQ_HANDLED : IRQ_NONE;
 }
 
 /**
@@ -627,7 +646,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData)
  * @num:       number of messages.
  */
 static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
-                   struct i2c_msg *msgs, s32 num)
+                       struct i2c_msg *msgs, s32 num)
 {
        struct i2c_msg *pmsg;
        u32 i = 0;
@@ -710,11 +729,13 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
 }
 
 static int __devinit pch_i2c_probe(struct pci_dev *pdev,
-                              const struct pci_device_id *id)
+                                  const struct pci_device_id *id)
 {
        void __iomem *base_addr;
-       s32 ret;
+       int ret;
+       int i, j;
        struct adapter_info *adap_info;
+       struct i2c_adapter *pch_adap;
 
        pch_pci_dbg(pdev, "Entered.\n");
 
@@ -744,44 +765,48 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
                goto err_pci_iomap;
        }
 
-       adap_info->pch_i2c_suspended = false;
+       /* Set the number of I2C channel instance */
+       adap_info->ch_num = id->driver_data;
 
-       adap_info->pch_data.p_adapter_info = adap_info;
+       for (i = 0; i < adap_info->ch_num; i++) {
+               pch_adap = &adap_info->pch_data[i].pch_adapter;
+               adap_info->pch_i2c_suspended = false;
 
-       adap_info->pch_data.pch_adapter.owner = THIS_MODULE;
-       adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON;
-       strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME);
-       adap_info->pch_data.pch_adapter.algo = &pch_algorithm;
-       adap_info->pch_data.pch_adapter.algo_data =
-                                               &adap_info->pch_data;
+               adap_info->pch_data[i].p_adapter_info = adap_info;
 
-       /* (i * 0x80) + base_addr; */
-       adap_info->pch_data.pch_base_address = base_addr;
+               pch_adap->owner = THIS_MODULE;
+               pch_adap->class = I2C_CLASS_HWMON;
+               strcpy(pch_adap->name, KBUILD_MODNAME);
+               pch_adap->algo = &pch_algorithm;
+               pch_adap->algo_data = &adap_info->pch_data[i];
 
-       adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev;
+               /* base_addr + offset; */
+               adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
 
-       ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter));
+               pch_adap->dev.parent = &pdev->dev;
 
-       if (ret) {
-               pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
-               goto err_i2c_add_adapter;
-       }
+               ret = i2c_add_adapter(pch_adap);
+               if (ret) {
+                       pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
+                       goto err_i2c_add_adapter;
+               }
 
-       pch_i2c_init(&adap_info->pch_data);
+               pch_i2c_init(&adap_info->pch_data[i]);
+       }
        ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
-                 KBUILD_MODNAME, &adap_info->pch_data);
+                 KBUILD_MODNAME, adap_info);
        if (ret) {
                pch_pci_err(pdev, "request_irq FAILED\n");
-               goto err_request_irq;
+               goto err_i2c_add_adapter;
        }
 
        pci_set_drvdata(pdev, adap_info);
        pch_pci_dbg(pdev, "returns %d.\n", ret);
        return 0;
 
-err_request_irq:
-       i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
 err_i2c_add_adapter:
+       for (j = 0; j < i; j++)
+               i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
        pci_iounmap(pdev, base_addr);
 err_pci_iomap:
        pci_release_regions(pdev);
@@ -794,17 +819,22 @@ err_pci_enable:
 
 static void __devexit pch_i2c_remove(struct pci_dev *pdev)
 {
+       int i;
        struct adapter_info *adap_info = pci_get_drvdata(pdev);
 
-       pch_i2c_disbl_int(&adap_info->pch_data);
-       free_irq(pdev->irq, &adap_info->pch_data);
-       i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
+       free_irq(pdev->irq, adap_info);
 
-       if (adap_info->pch_data.pch_base_address) {
-               pci_iounmap(pdev, adap_info->pch_data.pch_base_address);
-               adap_info->pch_data.pch_base_address = 0;
+       for (i = 0; i < adap_info->ch_num; i++) {
+               pch_i2c_disbl_int(&adap_info->pch_data[i]);
+               i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
        }
 
+       if (adap_info->pch_data[0].pch_base_address)
+               pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
+
+       for (i = 0; i < adap_info->ch_num; i++)
+               adap_info->pch_data[i].pch_base_address = 0;
+
        pci_set_drvdata(pdev, NULL);
 
        pci_release_regions(pdev);
@@ -817,17 +847,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev)
 static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        int ret;
+       int i;
        struct adapter_info *adap_info = pci_get_drvdata(pdev);
-       void __iomem *p = adap_info->pch_data.pch_base_address;
+       void __iomem *p = adap_info->pch_data[0].pch_base_address;
 
        adap_info->pch_i2c_suspended = true;
 
-       while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) {
-               /* Wait until all channel transfers are completed */
-               msleep(20);
+       for (i = 0; i < adap_info->ch_num; i++) {
+               while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
+                       /* Wait until all channel transfers are completed */
+                       msleep(20);
+               }
        }
+
        /* Disable the i2c interrupts */
-       pch_i2c_disbl_int(&adap_info->pch_data);
+       for (i = 0; i < adap_info->ch_num; i++)
+               pch_i2c_disbl_int(&adap_info->pch_data[i]);
 
        pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
                "invoked function pch_i2c_disbl_int successfully\n",
@@ -850,6 +885,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
 
 static int pch_i2c_resume(struct pci_dev *pdev)
 {
+       int i;
        struct adapter_info *adap_info = pci_get_drvdata(pdev);
 
        pci_set_power_state(pdev, PCI_D0);
@@ -862,7 +898,8 @@ static int pch_i2c_resume(struct pci_dev *pdev)
 
        pci_enable_wake(pdev, PCI_D3hot, 0);
 
-       pch_i2c_init(&adap_info->pch_data);
+       for (i = 0; i < adap_info->ch_num; i++)
+               pch_i2c_init(&adap_info->pch_data[i]);
 
        adap_info->pch_i2c_suspended = false;
 
@@ -894,7 +931,7 @@ static void __exit pch_pci_exit(void)
 }
 module_exit(pch_pci_exit);
 
-MODULE_DESCRIPTION("PCH I2C PCI Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>");
 module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
index 7979aef7ee7b2db822ca99937210c04346815006..ed2e0c5ea37c7b53ee1b67a20881caff26e7797d 100644 (file)
   ICH10                 0x3a30     32     hard     yes     yes     yes
   ICH10                 0x3a60     32     hard     yes     yes     yes
   5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes
-  Cougar Point (PCH)    0x1c22     32     hard     yes     yes     yes
+  6 Series (PCH)        0x1c22     32     hard     yes     yes     yes
   Patsburg (PCH)        0x1d22     32     hard     yes     yes     yes
   Patsburg (PCH) IDF    0x1d70     32     hard     yes     yes     yes
   Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
   Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
+  DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
@@ -621,6 +622,7 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
        { 0, }
 };
 
index 8022e2390a5a74d9c21ea67df4cf7c7600732581..caf96dc8ca1b9ba5aca46b4fcf7f7a91147d565b 100644 (file)
@@ -118,6 +118,8 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
 {
        mxs_reset_block(i2c->regs);
        writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+       writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+                       i2c->regs + MXS_I2C_QUEUECTRL_SET);
 }
 
 static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
@@ -347,8 +349,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
 
        /* Do reset to enforce correct startup after pinmuxing */
        mxs_i2c_reset(i2c);
-       writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
-                       i2c->regs + MXS_I2C_QUEUECTRL_SET);
 
        adap = &i2c->adapter;
        strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
index 1b46a9d9f907336fb70526ca93881ce3b3934950..fee1a2613861a8d1ea16d12b9e660dd0947df05c 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -305,7 +306,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
                return -EIO;
        }
 
-       pdata = pdev->dev.platform_data;
+       pdata = mfd_get_data(pdev);
        if (pdata) {
                i2c->regstep = pdata->regstep;
                i2c->clock_khz = pdata->clock_khz;
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
new file mode 100644 (file)
index 0000000..6659d26
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * The CE4100's I2C device is more or less the same one as found on PXA.
+ * It does not support slave mode, the register slightly moved. This PCI
+ * device provides three bars, every contains a single I2C controller.
+ */
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/pxa-i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#define CE4100_PCI_I2C_DEVS    3
+
+struct ce4100_devices {
+       struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
+};
+
+static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
+{
+       struct platform_device *pdev;
+       struct i2c_pxa_platform_data pdata;
+       struct resource res[2];
+       struct device_node *child;
+       static int devnum;
+       int ret;
+
+       memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
+       memset(&res, 0, sizeof(res));
+
+       res[0].flags = IORESOURCE_MEM;
+       res[0].start = pci_resource_start(dev, bar);
+       res[0].end = pci_resource_end(dev, bar);
+
+       res[1].flags = IORESOURCE_IRQ;
+       res[1].start = dev->irq;
+       res[1].end = dev->irq;
+
+       for_each_child_of_node(dev->dev.of_node, child) {
+               const void *prop;
+               struct resource r;
+               int ret;
+
+               ret = of_address_to_resource(child, 0, &r);
+               if (ret < 0)
+                       continue;
+               if (r.start != res[0].start)
+                       continue;
+               if (r.end != res[0].end)
+                       continue;
+               if (r.flags != res[0].flags)
+                       continue;
+
+               prop = of_get_property(child, "fast-mode", NULL);
+               if (prop)
+                       pdata.fast_mode = 1;
+
+               break;
+       }
+
+       if (!child) {
+               dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
+                               bar);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       pdev = platform_device_alloc("ce4100-i2c", devnum);
+       if (!pdev) {
+               of_node_put(child);
+               ret = -ENOMEM;
+               goto out;
+       }
+       pdev->dev.parent = &dev->dev;
+       pdev->dev.of_node = child;
+
+       ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+       if (ret)
+               goto err;
+
+       ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+       if (ret)
+               goto err;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto err;
+       devnum++;
+       return pdev;
+err:
+       platform_device_put(pdev);
+out:
+       return ERR_PTR(ret);
+}
+
+static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
+               const struct pci_device_id *ent)
+{
+       int ret;
+       int i;
+       struct ce4100_devices *sds;
+
+       ret = pci_enable_device_mem(dev);
+       if (ret)
+               return ret;
+
+       if (!dev->dev.of_node) {
+               dev_err(&dev->dev, "Missing device tree node.\n");
+               return -EINVAL;
+       }
+       sds = kzalloc(sizeof(*sds), GFP_KERNEL);
+       if (!sds)
+               goto err_mem;
+
+       for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
+               sds->pdev[i] = add_i2c_device(dev, i);
+               if (IS_ERR(sds->pdev[i])) {
+                       while (--i >= 0)
+                               platform_device_unregister(sds->pdev[i]);
+                       goto err_dev_add;
+               }
+       }
+       pci_set_drvdata(dev, sds);
+       return 0;
+
+err_dev_add:
+       pci_set_drvdata(dev, NULL);
+       kfree(sds);
+err_mem:
+       pci_disable_device(dev);
+       return ret;
+}
+
+static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
+{
+       struct ce4100_devices *sds;
+       unsigned int i;
+
+       sds = pci_get_drvdata(dev);
+       pci_set_drvdata(dev, NULL);
+
+       for (i = 0; i < ARRAY_SIZE(sds->pdev); i++)
+               platform_device_unregister(sds->pdev[i]);
+
+       pci_disable_device(dev);
+       kfree(sds);
+}
+
+static struct pci_device_id ce4100_i2c_devices[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
+       { },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices);
+
+static struct pci_driver ce4100_i2c_driver = {
+       .name           = "ce4100_i2c",
+       .id_table       = ce4100_i2c_devices,
+       .probe          = ce4100_i2c_probe,
+       .remove         = __devexit_p(ce4100_i2c_remove),
+};
+
+static int __init ce4100_i2c_init(void)
+{
+       return pci_register_driver(&ce4100_i2c_driver);
+}
+module_init(ce4100_i2c_init);
+
+static void __exit ce4100_i2c_exit(void)
+{
+       pci_unregister_driver(&ce4100_i2c_driver);
+}
+module_exit(ce4100_i2c_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
index f4c19a97e0b302d4339a9272f1b405bbf05d877a..f59224a5c76183374eaefd99ff072eb38231d80c 100644 (file)
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/i2c-pxa.h>
+#include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/i2c/pxa-i2c.h>
 
 #include <asm/irq.h>
-#include <plat/i2c.h>
+
+#ifndef CONFIG_HAVE_CLK
+#define clk_get(dev, id)       NULL
+#define clk_put(clk)           do { } while (0)
+#define clk_disable(clk)       do { } while (0)
+#define clk_enable(clk)                do { } while (0)
+#endif
+
+struct pxa_reg_layout {
+       u32 ibmr;
+       u32 idbr;
+       u32 icr;
+       u32 isr;
+       u32 isar;
+};
+
+enum pxa_i2c_types {
+       REGS_PXA2XX,
+       REGS_PXA3XX,
+       REGS_CE4100,
+};
 
 /*
- * I2C register offsets will be shifted 0 or 1 bit left, depending on
- * different SoCs
+ * I2C registers definitions
  */
-#define REG_SHIFT_0    (0 << 0)
-#define REG_SHIFT_1    (1 << 0)
-#define REG_SHIFT(d)   ((d) & 0x1)
+static struct pxa_reg_layout pxa_reg_layout[] = {
+       [REGS_PXA2XX] = {
+               .ibmr = 0x00,
+               .idbr = 0x08,
+               .icr =  0x10,
+               .isr =  0x18,
+               .isar = 0x20,
+       },
+       [REGS_PXA3XX] = {
+               .ibmr = 0x00,
+               .idbr = 0x04,
+               .icr =  0x08,
+               .isr =  0x0c,
+               .isar = 0x10,
+       },
+       [REGS_CE4100] = {
+               .ibmr = 0x14,
+               .idbr = 0x0c,
+               .icr =  0x00,
+               .isr =  0x04,
+               /* no isar register */
+       },
+};
 
 static const struct platform_device_id i2c_pxa_id_table[] = {
-       { "pxa2xx-i2c",         REG_SHIFT_1 },
-       { "pxa3xx-pwri2c",      REG_SHIFT_0 },
+       { "pxa2xx-i2c",         REGS_PXA2XX },
+       { "pxa3xx-pwri2c",      REGS_PXA3XX },
+       { "ce4100-i2c",         REGS_CE4100 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
 
 /*
- * I2C registers and bit definitions
+ * I2C bit definitions
  */
-#define IBMR           (0x00)
-#define IDBR           (0x08)
-#define ICR            (0x10)
-#define ISR            (0x18)
-#define ISAR           (0x20)
 
 #define ICR_START      (1 << 0)           /* start bit */
 #define ICR_STOP       (1 << 1)           /* stop bit */
@@ -111,7 +148,11 @@ struct pxa_i2c {
        u32                     icrlog[32];
 
        void __iomem            *reg_base;
-       unsigned int            reg_shift;
+       void __iomem            *reg_ibmr;
+       void __iomem            *reg_idbr;
+       void __iomem            *reg_icr;
+       void __iomem            *reg_isr;
+       void __iomem            *reg_isar;
 
        unsigned long           iobase;
        unsigned long           iosize;
@@ -121,11 +162,11 @@ struct pxa_i2c {
        unsigned int            fast_mode :1;
 };
 
-#define _IBMR(i2c)     ((i2c)->reg_base + (0x0 << (i2c)->reg_shift))
-#define _IDBR(i2c)     ((i2c)->reg_base + (0x4 << (i2c)->reg_shift))
-#define _ICR(i2c)      ((i2c)->reg_base + (0x8 << (i2c)->reg_shift))
-#define _ISR(i2c)      ((i2c)->reg_base + (0xc << (i2c)->reg_shift))
-#define _ISAR(i2c)     ((i2c)->reg_base + (0x10 << (i2c)->reg_shift))
+#define _IBMR(i2c)     ((i2c)->reg_ibmr)
+#define _IDBR(i2c)     ((i2c)->reg_idbr)
+#define _ICR(i2c)      ((i2c)->reg_icr)
+#define _ISR(i2c)      ((i2c)->reg_isr)
+#define _ISAR(i2c)     ((i2c)->reg_isar)
 
 /*
  * I2C Slave mode address
@@ -418,7 +459,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
        writel(I2C_ISR_INIT, _ISR(i2c));
        writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
 
-       writel(i2c->slave_addr, _ISAR(i2c));
+       if (i2c->reg_isar)
+               writel(i2c->slave_addr, _ISAR(i2c));
 
        /* set control register values */
        writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
@@ -729,8 +771,10 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
         */
        ret = i2c->msg_idx;
 
-       if (timeout == 0)
+       if (!timeout && i2c->msg_num) {
                i2c_pxa_scream_blue_murder(i2c, "timeout");
+               ret = I2C_RETRY;
+       }
 
  out:
        return ret;
@@ -915,11 +959,16 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
        writel(icr, _ICR(i2c));
 }
 
+#define VALID_INT_SOURCE       (ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \
+                               ISR_SAD | ISR_BED)
 static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
 {
        struct pxa_i2c *i2c = dev_id;
        u32 isr = readl(_ISR(i2c));
 
+       if (!(isr & VALID_INT_SOURCE))
+               return IRQ_NONE;
+
        if (i2c_debug > 2 && 0) {
                dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
                        __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
@@ -934,7 +983,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
        /*
         * Always clear all pending IRQs.
         */
-       writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c));
+       writel(isr & VALID_INT_SOURCE, _ISR(i2c));
 
        if (isr & ISR_SAD)
                i2c_pxa_slave_start(i2c, isr);
@@ -1001,6 +1050,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
        struct resource *res;
        struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
        const struct platform_device_id *id = platform_get_device_id(dev);
+       enum pxa_i2c_types i2c_type = id->driver_data;
        int ret;
        int irq;
 
@@ -1044,7 +1094,13 @@ static int i2c_pxa_probe(struct platform_device *dev)
                ret = -EIO;
                goto eremap;
        }
-       i2c->reg_shift = REG_SHIFT(id->driver_data);
+
+       i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+       i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+       i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+       i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+       if (i2c_type != REGS_CE4100)
+               i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
 
        i2c->iobase = res->start;
        i2c->iosize = resource_size(res);
@@ -1072,7 +1128,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
                i2c->adap.algo = &i2c_pxa_pio_algorithm;
        } else {
                i2c->adap.algo = &i2c_pxa_algorithm;
-               ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+               ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
                                  i2c->adap.name, i2c);
                if (ret)
                        goto ereqirq;
@@ -1082,12 +1138,19 @@ static int i2c_pxa_probe(struct platform_device *dev)
 
        i2c->adap.algo_data = i2c;
        i2c->adap.dev.parent = &dev->dev;
+#ifdef CONFIG_OF
+       i2c->adap.dev.of_node = dev->dev.of_node;
+#endif
 
-       ret = i2c_add_numbered_adapter(&i2c->adap);
+       if (i2c_type == REGS_CE4100)
+               ret = i2c_add_adapter(&i2c->adap);
+       else
+               ret = i2c_add_numbered_adapter(&i2c->adap);
        if (ret < 0) {
                printk(KERN_INFO "I2C: Failed to add bus\n");
                goto eadapt;
        }
+       of_i2c_register_devices(&i2c->adap);
 
        platform_set_drvdata(dev, i2c);
 
index a9c419e075a511589233147d1b229d0842933e4e..9fbd7e6fe32ececfee1c01928cf584ffc1f0bc65 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
@@ -704,7 +705,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
        if (irq < 0)
                goto resource_missing;
 
-       pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
+       pdata = mfd_get_data(pdev);
        if (!pdata)
                return -EINVAL;
 
index 7e6a63b571650b1f100c4707309f31de1af415bb..3ca2e012e78932ed8cf33339a3a0a0d404026c03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * i2c-boardinfo.h - collect pre-declarations of I2C devices
+ * i2c-boardinfo.c - collect pre-declarations of I2C devices
  *
  * 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
index 045ba6efea48fd24cbf651115e2d86a4f87781b4..e5f76a0372fd6f6e9d1fa063b60a07ffb08fb781 100644 (file)
@@ -797,6 +797,9 @@ static int i2c_do_add_adapter(struct i2c_driver *driver,
 
        /* Let legacy drivers scan this bus for matching devices */
        if (driver->attach_adapter) {
+               dev_warn(&adap->dev, "attach_adapter method is deprecated\n");
+               dev_warn(&adap->dev, "Please use another way to instantiate "
+                        "your i2c_client\n");
                /* We ignore the return code; if it fails, too bad */
                driver->attach_adapter(adap);
        }
@@ -981,6 +984,7 @@ static int i2c_do_del_adapter(struct i2c_driver *driver,
 
        if (!driver->detach_adapter)
                return 0;
+       dev_warn(&adapter->dev, "detach_adapter method is deprecated\n");
        res = driver->detach_adapter(adapter);
        if (res)
                dev_err(&adapter->dev, "detach_adapter failed (%d) "
@@ -1091,6 +1095,18 @@ EXPORT_SYMBOL(i2c_del_adapter);
 
 /* ------------------------------------------------------------------------- */
 
+int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
+{
+       int res;
+
+       mutex_lock(&core_lock);
+       res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
+       mutex_unlock(&core_lock);
+
+       return res;
+}
+EXPORT_SYMBOL_GPL(i2c_for_each_dev);
+
 static int __process_new_driver(struct device *dev, void *data)
 {
        if (dev->type != &i2c_adapter_type)
@@ -1134,9 +1150,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 
        INIT_LIST_HEAD(&driver->clients);
        /* Walk the adapters that are already present */
-       mutex_lock(&core_lock);
-       bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
-       mutex_unlock(&core_lock);
+       i2c_for_each_dev(driver, __process_new_driver);
 
        return 0;
 }
@@ -1156,9 +1170,7 @@ static int __process_removed_driver(struct device *dev, void *data)
  */
 void i2c_del_driver(struct i2c_driver *driver)
 {
-       mutex_lock(&core_lock);
-       bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver);
-       mutex_unlock(&core_lock);
+       i2c_for_each_dev(driver, __process_removed_driver);
 
        driver_unregister(&driver->driver);
        pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
@@ -1581,12 +1593,12 @@ i2c_new_probed_device(struct i2c_adapter *adap,
 }
 EXPORT_SYMBOL_GPL(i2c_new_probed_device);
 
-struct i2c_adapter *i2c_get_adapter(int id)
+struct i2c_adapter *i2c_get_adapter(int nr)
 {
        struct i2c_adapter *adapter;
 
        mutex_lock(&core_lock);
-       adapter = idr_find(&i2c_adapter_idr, id);
+       adapter = idr_find(&i2c_adapter_idr, nr);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
index cec0f3ba97f8b1a74d7134d3a86a61e4a79474df..c90ce50b619f7b483b85483a24457a8cab73f3c2 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/uaccess.h>
 
-static struct i2c_driver i2cdev_driver;
-
 /*
  * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
  * slave (i2c_client) with which messages will be exchanged.  It's coupled
  * with a character special file which is accessed by user mode drivers.
  *
  * The list of i2c_dev structures is parallel to the i2c_adapter lists
- * maintained by the driver model, and is updated using notifications
- * delivered to the i2cdev_driver.
+ * maintained by the driver model, and is updated using bus notifications.
  */
 struct i2c_dev {
        struct list_head list;
@@ -491,7 +490,6 @@ static int i2cdev_open(struct inode *inode, struct file *file)
                return -ENOMEM;
        }
        snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
-       client->driver = &i2cdev_driver;
 
        client->adapter = adap;
        file->private_data = client;
@@ -522,19 +520,18 @@ static const struct file_operations i2cdev_fops = {
 
 /* ------------------------------------------------------------------------- */
 
-/*
- * The legacy "i2cdev_driver" is used primarily to get notifications when
- * I2C adapters are added or removed, so that each one gets an i2c_dev
- * and is thus made available to userspace driver code.
- */
-
 static struct class *i2c_dev_class;
 
-static int i2cdev_attach_adapter(struct i2c_adapter *adap)
+static int i2cdev_attach_adapter(struct device *dev, void *dummy)
 {
+       struct i2c_adapter *adap;
        struct i2c_dev *i2c_dev;
        int res;
 
+       if (dev->type != &i2c_adapter_type)
+               return 0;
+       adap = to_i2c_adapter(dev);
+
        i2c_dev = get_free_i2c_dev(adap);
        if (IS_ERR(i2c_dev))
                return PTR_ERR(i2c_dev);
@@ -561,10 +558,15 @@ error:
        return res;
 }
 
-static int i2cdev_detach_adapter(struct i2c_adapter *adap)
+static int i2cdev_detach_adapter(struct device *dev, void *dummy)
 {
+       struct i2c_adapter *adap;
        struct i2c_dev *i2c_dev;
 
+       if (dev->type != &i2c_adapter_type)
+               return 0;
+       adap = to_i2c_adapter(dev);
+
        i2c_dev = i2c_dev_get_by_minor(adap->nr);
        if (!i2c_dev) /* attach_adapter must have failed */
                return 0;
@@ -577,12 +579,23 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
        return 0;
 }
 
-static struct i2c_driver i2cdev_driver = {
-       .driver = {
-               .name   = "dev_driver",
-       },
-       .attach_adapter = i2cdev_attach_adapter,
-       .detach_adapter = i2cdev_detach_adapter,
+int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
+                        void *data)
+{
+       struct device *dev = data;
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               return i2cdev_attach_adapter(dev, NULL);
+       case BUS_NOTIFY_DEL_DEVICE:
+               return i2cdev_detach_adapter(dev, NULL);
+       }
+
+       return 0;
+}
+
+static struct notifier_block i2cdev_notifier = {
+       .notifier_call = i2cdev_notifier_call,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -607,10 +620,14 @@ static int __init i2c_dev_init(void)
                goto out_unreg_chrdev;
        }
 
-       res = i2c_add_driver(&i2cdev_driver);
+       /* Keep track of adapters which will be added or removed later */
+       res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
        if (res)
                goto out_unreg_class;
 
+       /* Bind to already existing adapters right away */
+       i2c_for_each_dev(NULL, i2cdev_attach_adapter);
+
        return 0;
 
 out_unreg_class:
@@ -624,7 +641,8 @@ out:
 
 static void __exit i2c_dev_exit(void)
 {
-       i2c_del_driver(&i2cdev_driver);
+       bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
+       i2c_for_each_dev(NULL, i2cdev_detach_adapter);
        class_destroy(i2c_dev_class);
        unregister_chrdev(I2C_MAJOR, "i2c");
 }
index 81df925f0e8b932c3e821e29dbe2e94d636a2d08..7f879b2397b0e35a535449a3e0dcca8b36f48f10 100644 (file)
@@ -2,7 +2,7 @@
 # link order is important here
 #
 
-EXTRA_CFLAGS                           += -Idrivers/ide
+ccflags-y                              := -Idrivers/ide
 
 ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
              ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
index e88a2cf177110f37fdd6bfc6d1801184ec2b94f4..6f218e014e9940a4021533159dd72e9b64fac5f5 100644 (file)
@@ -233,8 +233,7 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special)
 
        drive->hwif->rq = NULL;
 
-       elv_add_request(drive->queue, &drive->sense_rq,
-                       ELEVATOR_INSERT_FRONT, 0);
+       elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
index 0c73fe39a236bb6d6e05f37814c646098a57b715..fd1e117991373853d5b51d8827f99157fabd3b55 100644 (file)
@@ -258,17 +258,10 @@ static int ide_cd_breathe(ide_drive_t *drive, struct request *rq)
        if (time_after(jiffies, info->write_timeout))
                return 0;
        else {
-               struct request_queue *q = drive->queue;
-               unsigned long flags;
-
                /*
-                * take a breather relying on the unplug timer to kick us again
+                * take a breather
                 */
-
-               spin_lock_irqsave(q->queue_lock, flags);
-               blk_plug_device(q);
-               spin_unlock_irqrestore(q->queue_lock, flags);
-
+               blk_delay_queue(drive->queue, 1);
                return 1;
        }
 }
@@ -1177,7 +1170,7 @@ static struct cdrom_device_ops ide_cdrom_dops = {
        .open                   = ide_cdrom_open_real,
        .release                = ide_cdrom_release_real,
        .drive_status           = ide_cdrom_drive_status,
-       .media_changed          = ide_cdrom_check_media_change_real,
+       .check_events           = ide_cdrom_check_events_real,
        .tray_move              = ide_cdrom_tray_move,
        .lock_door              = ide_cdrom_lock_door,
        .select_speed           = ide_cdrom_select_speed,
@@ -1514,8 +1507,6 @@ static int ide_cdrom_setup(ide_drive_t *drive)
        blk_queue_dma_alignment(q, 31);
        blk_queue_update_dma_pad(q, 15);
 
-       q->unplug_delay = max((1 * HZ) / 1000, 1);
-
        drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
        drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
 
@@ -1702,10 +1693,11 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
 }
 
 
-static int idecd_media_changed(struct gendisk *disk)
+static unsigned int idecd_check_events(struct gendisk *disk,
+                                      unsigned int clearing)
 {
        struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
-       return cdrom_media_changed(&info->devinfo);
+       return cdrom_check_events(&info->devinfo, clearing);
 }
 
 static int idecd_revalidate_disk(struct gendisk *disk)
@@ -1723,7 +1715,7 @@ static const struct block_device_operations idecd_ops = {
        .open                   = idecd_open,
        .release                = idecd_release,
        .ioctl                  = idecd_ioctl,
-       .media_changed          = idecd_media_changed,
+       .check_events           = idecd_check_events,
        .revalidate_disk        = idecd_revalidate_disk
 };
 
@@ -1790,6 +1782,7 @@ static int ide_cd_probe(ide_drive_t *drive)
        ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
        g->flags |= GENHD_FL_REMOVABLE;
+       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 93a3cf1b0f3f8c61b974b9b16a190502f5d4d038..1efc936f5b6672e268a38db439c63831fd59b71f 100644 (file)
@@ -111,7 +111,8 @@ int cdrom_check_status(ide_drive_t *, struct request_sense *);
 int ide_cdrom_open_real(struct cdrom_device_info *, int);
 void ide_cdrom_release_real(struct cdrom_device_info *);
 int ide_cdrom_drive_status(struct cdrom_device_info *, int);
-int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int);
+unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *,
+                                        unsigned int clearing, int slot_nr);
 int ide_cdrom_tray_move(struct cdrom_device_info *, int);
 int ide_cdrom_lock_door(struct cdrom_device_info *, int);
 int ide_cdrom_select_speed(struct cdrom_device_info *, int);
index 766b3deeb23c75f51eb5618a90e891d2fb220d90..2a6bc50e8a41e8918da5ad8aca49686d68da318c 100644 (file)
@@ -79,8 +79,8 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
        return CDS_DRIVE_NOT_READY;
 }
 
-int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
-                                      int slot_nr)
+unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi,
+                                        unsigned int clearing, int slot_nr)
 {
        ide_drive_t *drive = cdi->handle;
        int retval;
@@ -89,9 +89,9 @@ int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
                (void) cdrom_check_status(drive, NULL);
                retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0;
                drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
-               return retval;
+               return retval ? DISK_EVENT_MEDIA_CHANGE : 0;
        } else {
-               return -EINVAL;
+               return 0;
        }
 }
 
index 35c4b43585e3418ebb7ad1b74c94550d5fbcfb86..c4ffd4888939a7f4e67ee7f1191a08d485c85e44 100644 (file)
@@ -285,11 +285,12 @@ static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
-static int ide_gd_media_changed(struct gendisk *disk)
+static unsigned int ide_gd_check_events(struct gendisk *disk,
+                                       unsigned int clearing)
 {
        struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
        ide_drive_t *drive = idkp->drive;
-       int ret;
+       bool ret;
 
        /* do not scan partitions twice if this is a removable device */
        if (drive->dev_flags & IDE_DFLAG_ATTACH) {
@@ -297,10 +298,10 @@ static int ide_gd_media_changed(struct gendisk *disk)
                return 0;
        }
 
-       ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
+       ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED;
        drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
 
-       return ret;
+       return ret ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 static void ide_gd_unlock_native_capacity(struct gendisk *disk)
@@ -318,7 +319,7 @@ static int ide_gd_revalidate_disk(struct gendisk *disk)
        struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
        ide_drive_t *drive = idkp->drive;
 
-       if (ide_gd_media_changed(disk))
+       if (ide_gd_check_events(disk, 0))
                drive->disk_ops->get_capacity(drive);
 
        set_capacity(disk, ide_gd_capacity(drive));
@@ -340,7 +341,7 @@ static const struct block_device_operations ide_gd_ops = {
        .release                = ide_gd_release,
        .ioctl                  = ide_gd_ioctl,
        .getgeo                 = ide_gd_getgeo,
-       .media_changed          = ide_gd_media_changed,
+       .check_events           = ide_gd_check_events,
        .unlock_native_capacity = ide_gd_unlock_native_capacity,
        .revalidate_disk        = ide_gd_revalidate_disk
 };
@@ -412,6 +413,7 @@ static int ide_gd_probe(ide_drive_t *drive)
        if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
                g->flags = GENHD_FL_REMOVABLE;
        g->fops = &ide_gd_ops;
+       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 999dac054bccc708dee92756b2ec4eb361e590bd..f4077840d3abdbc027585617b8379304865dae81 100644 (file)
@@ -549,8 +549,6 @@ plug_device_2:
 
        if (rq)
                blk_requeue_request(q, rq);
-       if (!elv_queue_empty(q))
-               blk_plug_device(q);
 }
 
 void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
@@ -562,8 +560,6 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
 
        if (rq)
                blk_requeue_request(q, rq);
-       if (!elv_queue_empty(q))
-               blk_plug_device(q);
 
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
index 88a380c5a4708bd9f396a52da5dd47128137f74f..6ab9ab2a5081eba538b43abf738f549562cb166b 100644 (file)
@@ -52,7 +52,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
        rq->cmd[0] = REQ_UNPARK_HEADS;
        rq->cmd_len = 1;
        rq->cmd_type = REQ_TYPE_SPECIAL;
-       elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
+       elv_add_request(q, rq, ELEVATOR_INSERT_FRONT);
 
 out:
        return;
index 4a5c4a44ffb17a3ae0f44a489074ca99c33fa7ed..a46dddf6107884deb0852883f7d012d23e05b75e 100644 (file)
@@ -107,7 +107,7 @@ static unsigned long long auto_demotion_disable_flags;
 static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
        { /* MWAIT C0 */ },
        { /* MWAIT C1 */
-               .name = "NHM-C1",
+               .name = "C1-NHM",
                .desc = "MWAIT 0x00",
                .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
@@ -115,7 +115,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 6,
                .enter = &intel_idle },
        { /* MWAIT C2 */
-               .name = "NHM-C3",
+               .name = "C3-NHM",
                .desc = "MWAIT 0x10",
                .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -123,7 +123,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 80,
                .enter = &intel_idle },
        { /* MWAIT C3 */
-               .name = "NHM-C6",
+               .name = "C6-NHM",
                .desc = "MWAIT 0x20",
                .driver_data = (void *) 0x20,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -135,7 +135,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
 static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
        { /* MWAIT C0 */ },
        { /* MWAIT C1 */
-               .name = "SNB-C1",
+               .name = "C1-SNB",
                .desc = "MWAIT 0x00",
                .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
@@ -143,7 +143,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 1,
                .enter = &intel_idle },
        { /* MWAIT C2 */
-               .name = "SNB-C3",
+               .name = "C3-SNB",
                .desc = "MWAIT 0x10",
                .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -151,7 +151,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 211,
                .enter = &intel_idle },
        { /* MWAIT C3 */
-               .name = "SNB-C6",
+               .name = "C6-SNB",
                .desc = "MWAIT 0x20",
                .driver_data = (void *) 0x20,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -159,7 +159,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 345,
                .enter = &intel_idle },
        { /* MWAIT C4 */
-               .name = "SNB-C7",
+               .name = "C7-SNB",
                .desc = "MWAIT 0x30",
                .driver_data = (void *) 0x30,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -171,7 +171,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
 static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
        { /* MWAIT C0 */ },
        { /* MWAIT C1 */
-               .name = "ATM-C1",
+               .name = "C1-ATM",
                .desc = "MWAIT 0x00",
                .driver_data = (void *) 0x00,
                .flags = CPUIDLE_FLAG_TIME_VALID,
@@ -179,7 +179,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .target_residency = 4,
                .enter = &intel_idle },
        { /* MWAIT C2 */
-               .name = "ATM-C2",
+               .name = "C2-ATM",
                .desc = "MWAIT 0x10",
                .driver_data = (void *) 0x10,
                .flags = CPUIDLE_FLAG_TIME_VALID,
@@ -188,7 +188,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .enter = &intel_idle },
        { /* MWAIT C3 */ },
        { /* MWAIT C4 */
-               .name = "ATM-C4",
+               .name = "C4-ATM",
                .desc = "MWAIT 0x30",
                .driver_data = (void *) 0x30,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
@@ -197,7 +197,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .enter = &intel_idle },
        { /* MWAIT C5 */ },
        { /* MWAIT C6 */
-               .name = "ATM-C6",
+               .name = "C6-ATM",
                .desc = "MWAIT 0x52",
                .driver_data = (void *) 0x52,
                .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
index e0e8e1a184ffa3ff7c7c02682d6fb9eb8c982330..68999137dedfe24cb7044d6de38b6e4f6f8193c5 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 
-EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
+ccflags-y := -DDEBUG -DCONFIG_FFD
index e0ef5fdc361e6e02ffa1da2cd39f428244547a40..4ffc224faa7fa1961b30d282195379c8dc78501f 100644 (file)
@@ -204,7 +204,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 
        /* If the device does ARP internally, return 'done' */
        if (rt->dst.dev->flags & IFF_NOARP) {
-               rdma_copy_addr(addr, rt->dst.dev, NULL);
+               ret = rdma_copy_addr(addr, rt->dst.dev, NULL);
                goto put;
        }
 
index 91916a8d5de408b239050f614f86ed09d4717433..2bc7f5af64f4270b3f84d866822babaca34417dd 100644 (file)
@@ -101,7 +101,8 @@ void agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
        agent = port_priv->agent[qpn];
        ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
        if (IS_ERR(ah)) {
-               printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n");
+               printk(KERN_ERR SPFX "ib_create_ah_from_wc error %ld\n",
+                       PTR_ERR(ah));
                return;
        }
 
index 8a40cd539ab11f02855f8513ec8d98e86d59c199..f24b79b805f2b0463ae3383e1c62f0133d83c8ef 100644 (file)
@@ -1043,6 +1043,9 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
                }
        }
 
+       /* We can handle large RDMA requests, so allow larger segments. */
+       dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
+
        mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev);
        if (!mdev) {
                dev_err(&pdev->dev, "Device struct alloc failed, "
index 3d7f3664b67b9f301ec1fb80cb27df1cbcd3b11f..13de1192927cc50da063562fdc8a47e8a4336422 100644 (file)
@@ -694,7 +694,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
        nesdev->netdev_count++;
        nesdev->nesadapter->netdev_count++;
 
-       printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n",
+       printk(KERN_INFO PFX "%s: NetEffect RNIC driver successfully loaded.\n",
                        pci_name(pcidev));
        return 0;
 
index 83664ed2804f995ac2576e1b7c5c0e5d88b32ad6..376d640487d2ce942ff58d348a38a8a9737c5699 100644 (file)
@@ -59,25 +59,31 @@ MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator "
                   "v" DRV_VERSION " (" DRV_RELDATE ")");
 MODULE_LICENSE("Dual BSD/GPL");
 
-static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE;
-static int srp_max_iu_len;
+static unsigned int srp_sg_tablesize;
+static unsigned int cmd_sg_entries;
+static unsigned int indirect_sg_entries;
+static bool allow_ext_sg;
+static int topspin_workarounds = 1;
 
-module_param(srp_sg_tablesize, int, 0444);
-MODULE_PARM_DESC(srp_sg_tablesize,
-                "Max number of gather/scatter entries per I/O (default is 12, max 255)");
+module_param(srp_sg_tablesize, uint, 0444);
+MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries");
 
-static int topspin_workarounds = 1;
+module_param(cmd_sg_entries, uint, 0444);
+MODULE_PARM_DESC(cmd_sg_entries,
+                "Default number of gather/scatter entries in the SRP command (default is 12, max 255)");
+
+module_param(indirect_sg_entries, uint, 0444);
+MODULE_PARM_DESC(indirect_sg_entries,
+                "Default max number of gather/scatter entries (default is 12, max is " __stringify(SCSI_MAX_SG_CHAIN_SEGMENTS) ")");
+
+module_param(allow_ext_sg, bool, 0444);
+MODULE_PARM_DESC(allow_ext_sg,
+                 "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)");
 
 module_param(topspin_workarounds, int, 0444);
 MODULE_PARM_DESC(topspin_workarounds,
                 "Enable workarounds for Topspin/Cisco SRP target bugs if != 0");
 
-static int mellanox_workarounds = 1;
-
-module_param(mellanox_workarounds, int, 0444);
-MODULE_PARM_DESC(mellanox_workarounds,
-                "Enable workarounds for Mellanox SRP target bugs if != 0");
-
 static void srp_add_one(struct ib_device *device);
 static void srp_remove_one(struct ib_device *device);
 static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
@@ -114,14 +120,6 @@ static int srp_target_is_topspin(struct srp_target_port *target)
                 !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui));
 }
 
-static int srp_target_is_mellanox(struct srp_target_port *target)
-{
-       static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
-
-       return mellanox_workarounds &&
-               !memcmp(&target->ioc_guid, mellanox_oui, sizeof mellanox_oui);
-}
-
 static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
                                   gfp_t gfp_mask,
                                   enum dma_data_direction direction)
@@ -378,7 +376,7 @@ static int srp_send_req(struct srp_target_port *target)
 
        req->priv.opcode        = SRP_LOGIN_REQ;
        req->priv.tag           = 0;
-       req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len);
+       req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len);
        req->priv.req_buf_fmt   = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
                                              SRP_BUF_FORMAT_INDIRECT);
        /*
@@ -456,6 +454,24 @@ static bool srp_change_state(struct srp_target_port *target,
        return changed;
 }
 
+static void srp_free_req_data(struct srp_target_port *target)
+{
+       struct ib_device *ibdev = target->srp_host->srp_dev->dev;
+       struct srp_request *req;
+       int i;
+
+       for (i = 0, req = target->req_ring; i < SRP_CMD_SQ_SIZE; ++i, ++req) {
+               kfree(req->fmr_list);
+               kfree(req->map_page);
+               if (req->indirect_dma_addr) {
+                       ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
+                                           target->indirect_size,
+                                           DMA_TO_DEVICE);
+               }
+               kfree(req->indirect_desc);
+       }
+}
+
 static void srp_remove_work(struct work_struct *work)
 {
        struct srp_target_port *target =
@@ -472,6 +488,7 @@ static void srp_remove_work(struct work_struct *work)
        scsi_remove_host(target->scsi_host);
        ib_destroy_cm_id(target->cm_id);
        srp_free_target_ib(target);
+       srp_free_req_data(target);
        scsi_host_put(target->scsi_host);
 }
 
@@ -535,18 +552,20 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
                           struct srp_target_port *target,
                           struct srp_request *req)
 {
+       struct ib_device *ibdev = target->srp_host->srp_dev->dev;
+       struct ib_pool_fmr **pfmr;
+
        if (!scsi_sglist(scmnd) ||
            (scmnd->sc_data_direction != DMA_TO_DEVICE &&
             scmnd->sc_data_direction != DMA_FROM_DEVICE))
                return;
 
-       if (req->fmr) {
-               ib_fmr_pool_unmap(req->fmr);
-               req->fmr = NULL;
-       }
+       pfmr = req->fmr_list;
+       while (req->nfmr--)
+               ib_fmr_pool_unmap(*pfmr++);
 
-       ib_dma_unmap_sg(target->srp_host->srp_dev->dev, scsi_sglist(scmnd),
-                       scsi_sg_count(scmnd), scmnd->sc_data_direction);
+       ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd),
+                       scmnd->sc_data_direction);
 }
 
 static void srp_remove_req(struct srp_target_port *target,
@@ -645,96 +664,151 @@ err:
        return ret;
 }
 
-static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
-                      int sg_cnt, struct srp_request *req,
-                      struct srp_direct_buf *buf)
+static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr,
+                        unsigned int dma_len, u32 rkey)
 {
-       u64 io_addr = 0;
-       u64 *dma_pages;
-       u32 len;
-       int page_cnt;
-       int i, j;
-       int ret;
-       struct srp_device *dev = target->srp_host->srp_dev;
-       struct ib_device *ibdev = dev->dev;
-       struct scatterlist *sg;
+       struct srp_direct_buf *desc = state->desc;
 
-       if (!dev->fmr_pool)
-               return -ENODEV;
+       desc->va = cpu_to_be64(dma_addr);
+       desc->key = cpu_to_be32(rkey);
+       desc->len = cpu_to_be32(dma_len);
 
-       if (srp_target_is_mellanox(target) &&
-           (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask))
-               return -EINVAL;
+       state->total_len += dma_len;
+       state->desc++;
+       state->ndesc++;
+}
 
-       len = page_cnt = 0;
-       scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
-               unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
+static int srp_map_finish_fmr(struct srp_map_state *state,
+                             struct srp_target_port *target)
+{
+       struct srp_device *dev = target->srp_host->srp_dev;
+       struct ib_pool_fmr *fmr;
+       u64 io_addr = 0;
 
-               if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) {
-                       if (i > 0)
-                               return -EINVAL;
-                       else
-                               ++page_cnt;
-               }
-               if ((ib_sg_dma_address(ibdev, sg) + dma_len) &
-                   ~dev->fmr_page_mask) {
-                       if (i < sg_cnt - 1)
-                               return -EINVAL;
-                       else
-                               ++page_cnt;
-               }
+       if (!state->npages)
+               return 0;
 
-               len += dma_len;
+       if (state->npages == 1) {
+               srp_map_desc(state, state->base_dma_addr, state->fmr_len,
+                            target->rkey);
+               state->npages = state->fmr_len = 0;
+               return 0;
        }
 
-       page_cnt += len >> dev->fmr_page_shift;
-       if (page_cnt > SRP_FMR_SIZE)
-               return -ENOMEM;
+       fmr = ib_fmr_pool_map_phys(dev->fmr_pool, state->pages,
+                                  state->npages, io_addr);
+       if (IS_ERR(fmr))
+               return PTR_ERR(fmr);
 
-       dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC);
-       if (!dma_pages)
-               return -ENOMEM;
+       *state->next_fmr++ = fmr;
+       state->nfmr++;
 
-       page_cnt = 0;
-       scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
-               unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
+       srp_map_desc(state, 0, state->fmr_len, fmr->fmr->rkey);
+       state->npages = state->fmr_len = 0;
+       return 0;
+}
 
-               for (j = 0; j < dma_len; j += dev->fmr_page_size)
-                       dma_pages[page_cnt++] =
-                               (ib_sg_dma_address(ibdev, sg) &
-                                dev->fmr_page_mask) + j;
+static void srp_map_update_start(struct srp_map_state *state,
+                                struct scatterlist *sg, int sg_index,
+                                dma_addr_t dma_addr)
+{
+       state->unmapped_sg = sg;
+       state->unmapped_index = sg_index;
+       state->unmapped_addr = dma_addr;
+}
+
+static int srp_map_sg_entry(struct srp_map_state *state,
+                           struct srp_target_port *target,
+                           struct scatterlist *sg, int sg_index,
+                           int use_fmr)
+{
+       struct srp_device *dev = target->srp_host->srp_dev;
+       struct ib_device *ibdev = dev->dev;
+       dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg);
+       unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
+       unsigned int len;
+       int ret;
+
+       if (!dma_len)
+               return 0;
+
+       if (use_fmr == SRP_MAP_NO_FMR) {
+               /* Once we're in direct map mode for a request, we don't
+                * go back to FMR mode, so no need to update anything
+                * other than the descriptor.
+                */
+               srp_map_desc(state, dma_addr, dma_len, target->rkey);
+               return 0;
        }
 
-       req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
-                                       dma_pages, page_cnt, io_addr);
-       if (IS_ERR(req->fmr)) {
-               ret = PTR_ERR(req->fmr);
-               req->fmr = NULL;
-               goto out;
+       /* If we start at an offset into the FMR page, don't merge into
+        * the current FMR. Finish it out, and use the kernel's MR for this
+        * sg entry. This is to avoid potential bugs on some SRP targets
+        * that were never quite defined, but went away when the initiator
+        * avoided using FMR on such page fragments.
+        */
+       if (dma_addr & ~dev->fmr_page_mask || dma_len > dev->fmr_max_size) {
+               ret = srp_map_finish_fmr(state, target);
+               if (ret)
+                       return ret;
+
+               srp_map_desc(state, dma_addr, dma_len, target->rkey);
+               srp_map_update_start(state, NULL, 0, 0);
+               return 0;
        }
 
-       buf->va  = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) &
-                              ~dev->fmr_page_mask);
-       buf->key = cpu_to_be32(req->fmr->fmr->rkey);
-       buf->len = cpu_to_be32(len);
+       /* If this is the first sg to go into the FMR, save our position.
+        * We need to know the first unmapped entry, its index, and the
+        * first unmapped address within that entry to be able to restart
+        * mapping after an error.
+        */
+       if (!state->unmapped_sg)
+               srp_map_update_start(state, sg, sg_index, dma_addr);
 
-       ret = 0;
+       while (dma_len) {
+               if (state->npages == SRP_FMR_SIZE) {
+                       ret = srp_map_finish_fmr(state, target);
+                       if (ret)
+                               return ret;
 
-out:
-       kfree(dma_pages);
+                       srp_map_update_start(state, sg, sg_index, dma_addr);
+               }
+
+               len = min_t(unsigned int, dma_len, dev->fmr_page_size);
 
+               if (!state->npages)
+                       state->base_dma_addr = dma_addr;
+               state->pages[state->npages++] = dma_addr;
+               state->fmr_len += len;
+               dma_addr += len;
+               dma_len -= len;
+       }
+
+       /* If the last entry of the FMR wasn't a full page, then we need to
+        * close it out and start a new one -- we can only merge at page
+        * boundries.
+        */
+       ret = 0;
+       if (len != dev->fmr_page_size) {
+               ret = srp_map_finish_fmr(state, target);
+               if (!ret)
+                       srp_map_update_start(state, NULL, 0, 0);
+       }
        return ret;
 }
 
 static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                        struct srp_request *req)
 {
-       struct scatterlist *scat;
+       struct scatterlist *scat, *sg;
        struct srp_cmd *cmd = req->cmd->buf;
-       int len, nents, count;
-       u8 fmt = SRP_DATA_DESC_DIRECT;
+       int i, len, nents, count, use_fmr;
        struct srp_device *dev;
        struct ib_device *ibdev;
+       struct srp_map_state state;
+       struct srp_indirect_buf *indirect_hdr;
+       u32 table_len;
+       u8 fmt;
 
        if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
                return sizeof (struct srp_cmd);
@@ -754,6 +828,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
        ibdev = dev->dev;
 
        count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
+       if (unlikely(count == 0))
+               return -EIO;
 
        fmt = SRP_DATA_DESC_DIRECT;
        len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
@@ -770,49 +846,99 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                buf->va  = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
                buf->key = cpu_to_be32(target->rkey);
                buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
-       } else if (srp_map_fmr(target, scat, count, req,
-                              (void *) cmd->add_data)) {
-               /*
-                * FMR mapping failed, and the scatterlist has more
-                * than one entry.  Generate an indirect memory
-                * descriptor.
-                */
-               struct srp_indirect_buf *buf = (void *) cmd->add_data;
-               struct scatterlist *sg;
-               u32 datalen = 0;
-               int i;
-
-               fmt = SRP_DATA_DESC_INDIRECT;
-               len = sizeof (struct srp_cmd) +
-                       sizeof (struct srp_indirect_buf) +
-                       count * sizeof (struct srp_direct_buf);
-
-               scsi_for_each_sg(scmnd, sg, count, i) {
-                       unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
-
-                       buf->desc_list[i].va  =
-                               cpu_to_be64(ib_sg_dma_address(ibdev, sg));
-                       buf->desc_list[i].key =
-                               cpu_to_be32(target->rkey);
-                       buf->desc_list[i].len = cpu_to_be32(dma_len);
-                       datalen += dma_len;
+
+               req->nfmr = 0;
+               goto map_complete;
+       }
+
+       /* We have more than one scatter/gather entry, so build our indirect
+        * descriptor table, trying to merge as many entries with FMR as we
+        * can.
+        */
+       indirect_hdr = (void *) cmd->add_data;
+
+       ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr,
+                                  target->indirect_size, DMA_TO_DEVICE);
+
+       memset(&state, 0, sizeof(state));
+       state.desc      = req->indirect_desc;
+       state.pages     = req->map_page;
+       state.next_fmr  = req->fmr_list;
+
+       use_fmr = dev->fmr_pool ? SRP_MAP_ALLOW_FMR : SRP_MAP_NO_FMR;
+
+       for_each_sg(scat, sg, count, i) {
+               if (srp_map_sg_entry(&state, target, sg, i, use_fmr)) {
+                       /* FMR mapping failed, so backtrack to the first
+                        * unmapped entry and continue on without using FMR.
+                        */
+                       dma_addr_t dma_addr;
+                       unsigned int dma_len;
+
+backtrack:
+                       sg = state.unmapped_sg;
+                       i = state.unmapped_index;
+
+                       dma_addr = ib_sg_dma_address(ibdev, sg);
+                       dma_len = ib_sg_dma_len(ibdev, sg);
+                       dma_len -= (state.unmapped_addr - dma_addr);
+                       dma_addr = state.unmapped_addr;
+                       use_fmr = SRP_MAP_NO_FMR;
+                       srp_map_desc(&state, dma_addr, dma_len, target->rkey);
                }
+       }
 
-               if (scmnd->sc_data_direction == DMA_TO_DEVICE)
-                       cmd->data_out_desc_cnt = count;
-               else
-                       cmd->data_in_desc_cnt = count;
+       if (use_fmr == SRP_MAP_ALLOW_FMR && srp_map_finish_fmr(&state, target))
+               goto backtrack;
 
-               buf->table_desc.va  =
-                       cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf);
-               buf->table_desc.key =
-                       cpu_to_be32(target->rkey);
-               buf->table_desc.len =
-                       cpu_to_be32(count * sizeof (struct srp_direct_buf));
+       /* We've mapped the request, now pull as much of the indirect
+        * descriptor table as we can into the command buffer. If this
+        * target is not using an external indirect table, we are
+        * guaranteed to fit into the command, as the SCSI layer won't
+        * give us more S/G entries than we allow.
+        */
+       req->nfmr = state.nfmr;
+       if (state.ndesc == 1) {
+               /* FMR mapping was able to collapse this to one entry,
+                * so use a direct descriptor.
+                */
+               struct srp_direct_buf *buf = (void *) cmd->add_data;
 
-               buf->len = cpu_to_be32(datalen);
+               *buf = req->indirect_desc[0];
+               goto map_complete;
+       }
+
+       if (unlikely(target->cmd_sg_cnt < state.ndesc &&
+                                               !target->allow_ext_sg)) {
+               shost_printk(KERN_ERR, target->scsi_host,
+                            "Could not fit S/G list into SRP_CMD\n");
+               return -EIO;
        }
 
+       count = min(state.ndesc, target->cmd_sg_cnt);
+       table_len = state.ndesc * sizeof (struct srp_direct_buf);
+
+       fmt = SRP_DATA_DESC_INDIRECT;
+       len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf);
+       len += count * sizeof (struct srp_direct_buf);
+
+       memcpy(indirect_hdr->desc_list, req->indirect_desc,
+              count * sizeof (struct srp_direct_buf));
+
+       indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
+       indirect_hdr->table_desc.key = cpu_to_be32(target->rkey);
+       indirect_hdr->table_desc.len = cpu_to_be32(table_len);
+       indirect_hdr->len = cpu_to_be32(state.total_len);
+
+       if (scmnd->sc_data_direction == DMA_TO_DEVICE)
+               cmd->data_out_desc_cnt = count;
+       else
+               cmd->data_in_desc_cnt = count;
+
+       ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len,
+                                     DMA_TO_DEVICE);
+
+map_complete:
        if (scmnd->sc_data_direction == DMA_TO_DEVICE)
                cmd->buf_fmt = fmt << 4;
        else
@@ -1140,7 +1266,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
        spin_unlock_irqrestore(&target->lock, flags);
 
        dev = target->srp_host->srp_dev->dev;
-       ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
+       ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len,
                                   DMA_TO_DEVICE);
 
        scmnd->result        = 0;
@@ -1164,7 +1290,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
                goto err_iu;
        }
 
-       ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
+       ib_dma_sync_single_for_device(dev, iu->dma, target->max_iu_len,
                                      DMA_TO_DEVICE);
 
        if (srp_post_send(target, iu, len)) {
@@ -1204,7 +1330,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
 
        for (i = 0; i < SRP_SQ_SIZE; ++i) {
                target->tx_ring[i] = srp_alloc_iu(target->srp_host,
-                                                 srp_max_iu_len,
+                                                 target->max_iu_len,
                                                  GFP_KERNEL, DMA_TO_DEVICE);
                if (!target->tx_ring[i])
                        goto err;
@@ -1228,6 +1354,78 @@ err:
        return -ENOMEM;
 }
 
+static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
+                              struct srp_login_rsp *lrsp,
+                              struct srp_target_port *target)
+{
+       struct ib_qp_attr *qp_attr = NULL;
+       int attr_mask = 0;
+       int ret;
+       int i;
+
+       if (lrsp->opcode == SRP_LOGIN_RSP) {
+               target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
+               target->req_lim       = be32_to_cpu(lrsp->req_lim_delta);
+
+               /*
+                * Reserve credits for task management so we don't
+                * bounce requests back to the SCSI mid-layer.
+                */
+               target->scsi_host->can_queue
+                       = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
+                             target->scsi_host->can_queue);
+       } else {
+               shost_printk(KERN_WARNING, target->scsi_host,
+                            PFX "Unhandled RSP opcode %#x\n", lrsp->opcode);
+               ret = -ECONNRESET;
+               goto error;
+       }
+
+       if (!target->rx_ring[0]) {
+               ret = srp_alloc_iu_bufs(target);
+               if (ret)
+                       goto error;
+       }
+
+       ret = -ENOMEM;
+       qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
+       if (!qp_attr)
+               goto error;
+
+       qp_attr->qp_state = IB_QPS_RTR;
+       ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
+       if (ret)
+               goto error_free;
+
+       ret = ib_modify_qp(target->qp, qp_attr, attr_mask);
+       if (ret)
+               goto error_free;
+
+       for (i = 0; i < SRP_RQ_SIZE; i++) {
+               struct srp_iu *iu = target->rx_ring[i];
+               ret = srp_post_recv(target, iu);
+               if (ret)
+                       goto error_free;
+       }
+
+       qp_attr->qp_state = IB_QPS_RTS;
+       ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
+       if (ret)
+               goto error_free;
+
+       ret = ib_modify_qp(target->qp, qp_attr, attr_mask);
+       if (ret)
+               goto error_free;
+
+       ret = ib_send_cm_rtu(cm_id, NULL, 0);
+
+error_free:
+       kfree(qp_attr);
+
+error:
+       target->status = ret;
+}
+
 static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
                               struct ib_cm_event *event,
                               struct srp_target_port *target)
@@ -1311,11 +1509,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
 static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 {
        struct srp_target_port *target = cm_id->context;
-       struct ib_qp_attr *qp_attr = NULL;
-       int attr_mask = 0;
        int comp = 0;
-       int opcode = 0;
-       int i;
 
        switch (event->event) {
        case IB_CM_REQ_ERROR:
@@ -1327,71 +1521,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 
        case IB_CM_REP_RECEIVED:
                comp = 1;
-               opcode = *(u8 *) event->private_data;
-
-               if (opcode == SRP_LOGIN_RSP) {
-                       struct srp_login_rsp *rsp = event->private_data;
-
-                       target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
-                       target->req_lim       = be32_to_cpu(rsp->req_lim_delta);
-
-                       /*
-                        * Reserve credits for task management so we don't
-                        * bounce requests back to the SCSI mid-layer.
-                        */
-                       target->scsi_host->can_queue
-                               = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
-                                     target->scsi_host->can_queue);
-               } else {
-                       shost_printk(KERN_WARNING, target->scsi_host,
-                                   PFX "Unhandled RSP opcode %#x\n", opcode);
-                       target->status = -ECONNRESET;
-                       break;
-               }
-
-               if (!target->rx_ring[0]) {
-                       target->status = srp_alloc_iu_bufs(target);
-                       if (target->status)
-                               break;
-               }
-
-               qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
-               if (!qp_attr) {
-                       target->status = -ENOMEM;
-                       break;
-               }
-
-               qp_attr->qp_state = IB_QPS_RTR;
-               target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
-               if (target->status)
-                       break;
-
-               target->status = ib_modify_qp(target->qp, qp_attr, attr_mask);
-               if (target->status)
-                       break;
-
-               for (i = 0; i < SRP_RQ_SIZE; i++) {
-                       struct srp_iu *iu = target->rx_ring[i];
-                       target->status = srp_post_recv(target, iu);
-                       if (target->status)
-                               break;
-               }
-               if (target->status)
-                       break;
-
-               qp_attr->qp_state = IB_QPS_RTS;
-               target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
-               if (target->status)
-                       break;
-
-               target->status = ib_modify_qp(target->qp, qp_attr, attr_mask);
-               if (target->status)
-                       break;
-
-               target->status = ib_send_cm_rtu(cm_id, NULL, 0);
-               if (target->status)
-                       break;
-
+               srp_cm_rep_handler(cm_id, event->private_data, target);
                break;
 
        case IB_CM_REJ_RECEIVED:
@@ -1431,8 +1561,6 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
        if (comp)
                complete(&target->done);
 
-       kfree(qp_attr);
-
        return 0;
 }
 
@@ -1658,6 +1786,22 @@ static ssize_t show_local_ib_device(struct device *dev,
        return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
 }
 
+static ssize_t show_cmd_sg_entries(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+       return sprintf(buf, "%u\n", target->cmd_sg_cnt);
+}
+
+static ssize_t show_allow_ext_sg(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+       return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false");
+}
+
 static DEVICE_ATTR(id_ext,         S_IRUGO, show_id_ext,          NULL);
 static DEVICE_ATTR(ioc_guid,       S_IRUGO, show_ioc_guid,        NULL);
 static DEVICE_ATTR(service_id,     S_IRUGO, show_service_id,      NULL);
@@ -1668,6 +1812,8 @@ static DEVICE_ATTR(req_lim,         S_IRUGO, show_req_lim,         NULL);
 static DEVICE_ATTR(zero_req_lim,    S_IRUGO, show_zero_req_lim,           NULL);
 static DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,   NULL);
 static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
+static DEVICE_ATTR(cmd_sg_entries,  S_IRUGO, show_cmd_sg_entries,  NULL);
+static DEVICE_ATTR(allow_ext_sg,    S_IRUGO, show_allow_ext_sg,    NULL);
 
 static struct device_attribute *srp_host_attrs[] = {
        &dev_attr_id_ext,
@@ -1680,6 +1826,8 @@ static struct device_attribute *srp_host_attrs[] = {
        &dev_attr_zero_req_lim,
        &dev_attr_local_ib_port,
        &dev_attr_local_ib_device,
+       &dev_attr_cmd_sg_entries,
+       &dev_attr_allow_ext_sg,
        NULL
 };
 
@@ -1692,6 +1840,7 @@ static struct scsi_host_template srp_template = {
        .eh_abort_handler               = srp_abort,
        .eh_device_reset_handler        = srp_reset_device,
        .eh_host_reset_handler          = srp_reset_host,
+       .sg_tablesize                   = SRP_DEF_SG_TABLESIZE,
        .can_queue                      = SRP_CMD_SQ_SIZE,
        .this_id                        = -1,
        .cmd_per_lun                    = SRP_CMD_SQ_SIZE,
@@ -1763,6 +1912,9 @@ enum {
        SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
        SRP_OPT_IO_CLASS        = 1 << 7,
        SRP_OPT_INITIATOR_EXT   = 1 << 8,
+       SRP_OPT_CMD_SG_ENTRIES  = 1 << 9,
+       SRP_OPT_ALLOW_EXT_SG    = 1 << 10,
+       SRP_OPT_SG_TABLESIZE    = 1 << 11,
        SRP_OPT_ALL             = (SRP_OPT_ID_EXT       |
                                   SRP_OPT_IOC_GUID     |
                                   SRP_OPT_DGID         |
@@ -1780,6 +1932,9 @@ static const match_table_t srp_opt_tokens = {
        { SRP_OPT_MAX_CMD_PER_LUN,      "max_cmd_per_lun=%d"    },
        { SRP_OPT_IO_CLASS,             "io_class=%x"           },
        { SRP_OPT_INITIATOR_EXT,        "initiator_ext=%s"      },
+       { SRP_OPT_CMD_SG_ENTRIES,       "cmd_sg_entries=%u"     },
+       { SRP_OPT_ALLOW_EXT_SG,         "allow_ext_sg=%u"       },
+       { SRP_OPT_SG_TABLESIZE,         "sg_tablesize=%u"       },
        { SRP_OPT_ERR,                  NULL                    }
 };
 
@@ -1907,6 +2062,31 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                        kfree(p);
                        break;
 
+               case SRP_OPT_CMD_SG_ENTRIES:
+                       if (match_int(args, &token) || token < 1 || token > 255) {
+                               printk(KERN_WARNING PFX "bad max cmd_sg_entries parameter '%s'\n", p);
+                               goto out;
+                       }
+                       target->cmd_sg_cnt = token;
+                       break;
+
+               case SRP_OPT_ALLOW_EXT_SG:
+                       if (match_int(args, &token)) {
+                               printk(KERN_WARNING PFX "bad allow_ext_sg parameter '%s'\n", p);
+                               goto out;
+                       }
+                       target->allow_ext_sg = !!token;
+                       break;
+
+               case SRP_OPT_SG_TABLESIZE:
+                       if (match_int(args, &token) || token < 1 ||
+                                       token > SCSI_MAX_SG_CHAIN_SEGMENTS) {
+                               printk(KERN_WARNING PFX "bad max sg_tablesize parameter '%s'\n", p);
+                               goto out;
+                       }
+                       target->sg_tablesize = token;
+                       break;
+
                default:
                        printk(KERN_WARNING PFX "unknown parameter or missing value "
                               "'%s' in target creation request\n", p);
@@ -1937,39 +2117,73 @@ static ssize_t srp_create_target(struct device *dev,
                container_of(dev, struct srp_host, dev);
        struct Scsi_Host *target_host;
        struct srp_target_port *target;
-       int ret;
-       int i;
+       struct ib_device *ibdev = host->srp_dev->dev;
+       dma_addr_t dma_addr;
+       int i, ret;
 
        target_host = scsi_host_alloc(&srp_template,
                                      sizeof (struct srp_target_port));
        if (!target_host)
                return -ENOMEM;
 
-       target_host->transportt = ib_srp_transport_template;
+       target_host->transportt  = ib_srp_transport_template;
        target_host->max_lun     = SRP_MAX_LUN;
        target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
 
        target = host_to_target(target_host);
 
-       target->io_class   = SRP_REV16A_IB_IO_CLASS;
-       target->scsi_host  = target_host;
-       target->srp_host   = host;
-       target->lkey       = host->srp_dev->mr->lkey;
-       target->rkey       = host->srp_dev->mr->rkey;
+       target->io_class        = SRP_REV16A_IB_IO_CLASS;
+       target->scsi_host       = target_host;
+       target->srp_host        = host;
+       target->lkey            = host->srp_dev->mr->lkey;
+       target->rkey            = host->srp_dev->mr->rkey;
+       target->cmd_sg_cnt      = cmd_sg_entries;
+       target->sg_tablesize    = indirect_sg_entries ? : cmd_sg_entries;
+       target->allow_ext_sg    = allow_ext_sg;
+
+       ret = srp_parse_options(buf, target);
+       if (ret)
+               goto err;
+
+       if (!host->srp_dev->fmr_pool && !target->allow_ext_sg &&
+                               target->cmd_sg_cnt < target->sg_tablesize) {
+               printk(KERN_WARNING PFX "No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
+               target->sg_tablesize = target->cmd_sg_cnt;
+       }
+
+       target_host->sg_tablesize = target->sg_tablesize;
+       target->indirect_size = target->sg_tablesize *
+                               sizeof (struct srp_direct_buf);
+       target->max_iu_len = sizeof (struct srp_cmd) +
+                            sizeof (struct srp_indirect_buf) +
+                            target->cmd_sg_cnt * sizeof (struct srp_direct_buf);
 
        spin_lock_init(&target->lock);
        INIT_LIST_HEAD(&target->free_tx);
        INIT_LIST_HEAD(&target->free_reqs);
        for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
-               target->req_ring[i].index = i;
-               list_add_tail(&target->req_ring[i].list, &target->free_reqs);
-       }
+               struct srp_request *req = &target->req_ring[i];
 
-       ret = srp_parse_options(buf, target);
-       if (ret)
-               goto err;
+               req->fmr_list = kmalloc(target->cmd_sg_cnt * sizeof (void *),
+                                       GFP_KERNEL);
+               req->map_page = kmalloc(SRP_FMR_SIZE * sizeof (void *),
+                                       GFP_KERNEL);
+               req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
+               if (!req->fmr_list || !req->map_page || !req->indirect_desc)
+                       goto err_free_mem;
+
+               dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
+                                            target->indirect_size,
+                                            DMA_TO_DEVICE);
+               if (ib_dma_mapping_error(ibdev, dma_addr))
+                       goto err_free_mem;
+
+               req->indirect_dma_addr = dma_addr;
+               req->index = i;
+               list_add_tail(&req->list, &target->free_reqs);
+       }
 
-       ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid);
+       ib_query_gid(ibdev, host->port, 0, &target->path.sgid);
 
        shost_printk(KERN_DEBUG, target->scsi_host, PFX
                     "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
@@ -1982,11 +2196,11 @@ static ssize_t srp_create_target(struct device *dev,
 
        ret = srp_create_target_ib(target);
        if (ret)
-               goto err;
+               goto err_free_mem;
 
        ret = srp_new_cm_id(target);
        if (ret)
-               goto err_free;
+               goto err_free_ib;
 
        target->qp_in_error = 0;
        ret = srp_connect_target(target);
@@ -2008,9 +2222,12 @@ err_disconnect:
 err_cm_id:
        ib_destroy_cm_id(target->cm_id);
 
-err_free:
+err_free_ib:
        srp_free_target_ib(target);
 
+err_free_mem:
+       srp_free_req_data(target);
+
 err:
        scsi_host_put(target_host);
 
@@ -2083,7 +2300,7 @@ static void srp_add_one(struct ib_device *device)
        struct ib_device_attr *dev_attr;
        struct ib_fmr_pool_param fmr_param;
        struct srp_host *host;
-       int s, e, p;
+       int max_pages_per_fmr, fmr_page_shift, s, e, p;
 
        dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
        if (!dev_attr)
@@ -2101,12 +2318,13 @@ static void srp_add_one(struct ib_device *device)
 
        /*
         * Use the smallest page size supported by the HCA, down to a
-        * minimum of 512 bytes (which is the smallest sector that a
-        * SCSI command will ever carry).
+        * minimum of 4096 bytes. We're unlikely to build large sglists
+        * out of smaller entries.
         */
-       srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
-       srp_dev->fmr_page_size  = 1 << srp_dev->fmr_page_shift;
-       srp_dev->fmr_page_mask  = ~((u64) srp_dev->fmr_page_size - 1);
+       fmr_page_shift          = max(12, ffs(dev_attr->page_size_cap) - 1);
+       srp_dev->fmr_page_size  = 1 << fmr_page_shift;
+       srp_dev->fmr_page_mask  = ~((u64) srp_dev->fmr_page_size - 1);
+       srp_dev->fmr_max_size   = srp_dev->fmr_page_size * SRP_FMR_SIZE;
 
        INIT_LIST_HEAD(&srp_dev->dev_list);
 
@@ -2122,17 +2340,24 @@ static void srp_add_one(struct ib_device *device)
        if (IS_ERR(srp_dev->mr))
                goto err_pd;
 
-       memset(&fmr_param, 0, sizeof fmr_param);
-       fmr_param.pool_size         = SRP_FMR_POOL_SIZE;
-       fmr_param.dirty_watermark   = SRP_FMR_DIRTY_SIZE;
-       fmr_param.cache             = 1;
-       fmr_param.max_pages_per_fmr = SRP_FMR_SIZE;
-       fmr_param.page_shift        = srp_dev->fmr_page_shift;
-       fmr_param.access            = (IB_ACCESS_LOCAL_WRITE |
-                                      IB_ACCESS_REMOTE_WRITE |
-                                      IB_ACCESS_REMOTE_READ);
-
-       srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param);
+       for (max_pages_per_fmr = SRP_FMR_SIZE;
+                       max_pages_per_fmr >= SRP_FMR_MIN_SIZE;
+                       max_pages_per_fmr /= 2, srp_dev->fmr_max_size /= 2) {
+               memset(&fmr_param, 0, sizeof fmr_param);
+               fmr_param.pool_size         = SRP_FMR_POOL_SIZE;
+               fmr_param.dirty_watermark   = SRP_FMR_DIRTY_SIZE;
+               fmr_param.cache             = 1;
+               fmr_param.max_pages_per_fmr = max_pages_per_fmr;
+               fmr_param.page_shift        = fmr_page_shift;
+               fmr_param.access            = (IB_ACCESS_LOCAL_WRITE |
+                                              IB_ACCESS_REMOTE_WRITE |
+                                              IB_ACCESS_REMOTE_READ);
+
+               srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param);
+               if (!IS_ERR(srp_dev->fmr_pool))
+                       break;
+       }
+
        if (IS_ERR(srp_dev->fmr_pool))
                srp_dev->fmr_pool = NULL;
 
@@ -2207,6 +2432,7 @@ static void srp_remove_one(struct ib_device *device)
                        srp_disconnect_target(target);
                        ib_destroy_cm_id(target->cm_id);
                        srp_free_target_ib(target);
+                       srp_free_req_data(target);
                        scsi_host_put(target->scsi_host);
                }
 
@@ -2230,9 +2456,25 @@ static int __init srp_init_module(void)
 
        BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *));
 
-       if (srp_sg_tablesize > 255) {
-               printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n");
-               srp_sg_tablesize = 255;
+       if (srp_sg_tablesize) {
+               printk(KERN_WARNING PFX "srp_sg_tablesize is deprecated, please use cmd_sg_entries\n");
+               if (!cmd_sg_entries)
+                       cmd_sg_entries = srp_sg_tablesize;
+       }
+
+       if (!cmd_sg_entries)
+               cmd_sg_entries = SRP_DEF_SG_TABLESIZE;
+
+       if (cmd_sg_entries > 255) {
+               printk(KERN_WARNING PFX "Clamping cmd_sg_entries to 255\n");
+               cmd_sg_entries = 255;
+       }
+
+       if (!indirect_sg_entries)
+               indirect_sg_entries = cmd_sg_entries;
+       else if (indirect_sg_entries < cmd_sg_entries) {
+               printk(KERN_WARNING PFX "Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", cmd_sg_entries);
+               indirect_sg_entries = cmd_sg_entries;
        }
 
        ib_srp_transport_template =
@@ -2240,11 +2482,6 @@ static int __init srp_init_module(void)
        if (!ib_srp_transport_template)
                return -ENOMEM;
 
-       srp_template.sg_tablesize = srp_sg_tablesize;
-       srp_max_iu_len = (sizeof (struct srp_cmd) +
-                         sizeof (struct srp_indirect_buf) +
-                         srp_sg_tablesize * 16);
-
        ret = class_register(&srp_class);
        if (ret) {
                printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
index 9dc6fc3fd894f1fce02d60daf4a598193277dfa2..020caf0c3789ed0d6bd14fa95708132a3bdb8c94 100644 (file)
@@ -69,9 +69,13 @@ enum {
        SRP_TAG_NO_REQ          = ~0U,
        SRP_TAG_TSK_MGMT        = 1U << 31,
 
-       SRP_FMR_SIZE            = 256,
+       SRP_FMR_SIZE            = 512,
+       SRP_FMR_MIN_SIZE        = 128,
        SRP_FMR_POOL_SIZE       = 1024,
-       SRP_FMR_DIRTY_SIZE      = SRP_FMR_POOL_SIZE / 4
+       SRP_FMR_DIRTY_SIZE      = SRP_FMR_POOL_SIZE / 4,
+
+       SRP_MAP_ALLOW_FMR       = 0,
+       SRP_MAP_NO_FMR          = 1,
 };
 
 enum srp_target_state {
@@ -93,9 +97,9 @@ struct srp_device {
        struct ib_pd           *pd;
        struct ib_mr           *mr;
        struct ib_fmr_pool     *fmr_pool;
-       int                     fmr_page_shift;
-       int                     fmr_page_size;
        u64                     fmr_page_mask;
+       int                     fmr_page_size;
+       int                     fmr_max_size;
 };
 
 struct srp_host {
@@ -112,7 +116,11 @@ struct srp_request {
        struct list_head        list;
        struct scsi_cmnd       *scmnd;
        struct srp_iu          *cmd;
-       struct ib_pool_fmr     *fmr;
+       struct ib_pool_fmr    **fmr_list;
+       u64                    *map_page;
+       struct srp_direct_buf  *indirect_desc;
+       dma_addr_t              indirect_dma_addr;
+       short                   nfmr;
        short                   index;
 };
 
@@ -130,6 +138,10 @@ struct srp_target_port {
        u32                     lkey;
        u32                     rkey;
        enum srp_target_state   state;
+       unsigned int            max_iu_len;
+       unsigned int            cmd_sg_cnt;
+       unsigned int            indirect_size;
+       bool                    allow_ext_sg;
 
        /* Everything above this point is used in the hot path of
         * command processing. Try to keep them packed into cachelines.
@@ -144,6 +156,7 @@ struct srp_target_port {
        struct Scsi_Host       *scsi_host;
        char                    target_name[32];
        unsigned int            scsi_id;
+       unsigned int            sg_tablesize;
 
        struct ib_sa_path_rec   path;
        __be16                  orig_dgid[8];
@@ -179,4 +192,19 @@ struct srp_iu {
        enum dma_data_direction direction;
 };
 
+struct srp_map_state {
+       struct ib_pool_fmr    **next_fmr;
+       struct srp_direct_buf  *desc;
+       u64                    *pages;
+       dma_addr_t              base_dma_addr;
+       u32                     fmr_len;
+       u32                     total_len;
+       unsigned int            npages;
+       unsigned int            nfmr;
+       unsigned int            ndesc;
+       struct scatterlist     *unmapped_sg;
+       int                     unmapped_index;
+       dma_addr_t              unmapped_addr;
+};
+
 #endif /* IB_SRP_H */
index 1903c0f5b9257d2384cec4a8763cf116c2bb904e..23e82e46656dbe08236577dd0d5fdf04ca209f61 100644 (file)
@@ -161,16 +161,6 @@ config INPUT_APMPOWER
          To compile this driver as a module, choose M here: the
          module will be called apm-power.
 
-config XEN_KBDDEV_FRONTEND
-       tristate "Xen virtual keyboard and mouse support"
-       depends on XEN_FBDEV_FRONTEND
-       default y
-       select XEN_XENBUS_FRONTEND
-       help
-         This driver implements the front-end of the Xen virtual
-         keyboard and mouse device driver.  It communicates with a back-end
-         in another domain.
-
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
index 09614ce74961bccded0b02ecd29815f3947533a1..0c789490e0b359d60040fd82ed6c19dfb8784d04 100644 (file)
@@ -24,5 +24,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN)       += touchscreen/
 obj-$(CONFIG_INPUT_MISC)       += misc/
 
 obj-$(CONFIG_INPUT_APMPOWER)   += apm-power.o
-
-obj-$(CONFIG_XEN_KBDDEV_FRONTEND)      += xen-kbdfront.o
index c8471a2552e73ea28c7401e58e713b66bbc6cc33..7f42d3a454d2d6aaebdc41e0e5a8c6700d6a00df 100644 (file)
@@ -321,6 +321,9 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
        struct input_event event;
        int retval;
 
+       if (count < input_event_size())
+               return -EINVAL;
+
        retval = mutex_lock_interruptible(&evdev->mutex);
        if (retval)
                return retval;
@@ -330,17 +333,16 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
                goto out;
        }
 
-       while (retval < count) {
-
+       do {
                if (input_event_from_user(buffer + retval, &event)) {
                        retval = -EFAULT;
                        goto out;
                }
+               retval += input_event_size();
 
                input_inject_event(&evdev->handle,
                                   event.type, event.code, event.value);
-               retval += input_event_size();
-       }
+       } while (retval + input_event_size() <= count);
 
  out:
        mutex_unlock(&evdev->mutex);
index 0559e309bac9a443230e66d3f3cfff31e7963f0b..3037842a60d8a10e0533033b665aca490c10b030 100644 (file)
@@ -192,7 +192,7 @@ static struct attribute_group input_polldev_attribute_group = {
 };
 
 /**
- * input_allocate_polled_device - allocated memory polled device
+ * input_allocate_polled_device - allocate memory for polled device
  *
  * The function allocates memory for a polled device and also
  * for an input device associated with this polled device.
@@ -239,7 +239,7 @@ EXPORT_SYMBOL(input_free_polled_device);
  * with input layer. The device should be allocated with call to
  * input_allocate_polled_device(). Callers should also set up poll()
  * method and set up capabilities (id, name, phys, bits) of the
- * corresponing input_dev structure.
+ * corresponding input_dev structure.
  */
 int input_register_polled_device(struct input_polled_dev *dev)
 {
index 11905b6a30237c574825a178b16b8fde32d593dd..d6e8bd8a851c26d0e4718d10d30977451bb28009 100644 (file)
@@ -791,22 +791,9 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
        int retval;
 
        spin_lock_irqsave(&dev->event_lock, flags);
-
-       if (dev->getkeycode) {
-               /*
-                * Support for legacy drivers, that don't implement the new
-                * ioctls
-                */
-               u32 scancode = ke->index;
-
-               memcpy(ke->scancode, &scancode, sizeof(scancode));
-               ke->len = sizeof(scancode);
-               retval = dev->getkeycode(dev, scancode, &ke->keycode);
-       } else {
-               retval = dev->getkeycode_new(dev, ke);
-       }
-
+       retval = dev->getkeycode(dev, ke);
        spin_unlock_irqrestore(&dev->event_lock, flags);
+
        return retval;
 }
 EXPORT_SYMBOL(input_get_keycode);
@@ -831,35 +818,7 @@ int input_set_keycode(struct input_dev *dev,
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
-       if (dev->setkeycode) {
-               /*
-                * Support for legacy drivers, that don't implement the new
-                * ioctls
-                */
-               unsigned int scancode;
-
-               retval = input_scancode_to_scalar(ke, &scancode);
-               if (retval)
-                       goto out;
-
-               /*
-                * We need to know the old scancode, in order to generate a
-                * keyup effect, if the set operation happens successfully
-                */
-               if (!dev->getkeycode) {
-                       retval = -EINVAL;
-                       goto out;
-               }
-
-               retval = dev->getkeycode(dev, scancode, &old_keycode);
-               if (retval)
-                       goto out;
-
-               retval = dev->setkeycode(dev, scancode, ke->keycode);
-       } else {
-               retval = dev->setkeycode_new(dev, ke, &old_keycode);
-       }
-
+       retval = dev->setkeycode(dev, ke, &old_keycode);
        if (retval)
                goto out;
 
@@ -1846,11 +1805,11 @@ int input_register_device(struct input_dev *dev)
                dev->rep[REP_PERIOD] = 33;
        }
 
-       if (!dev->getkeycode && !dev->getkeycode_new)
-               dev->getkeycode_new = input_default_getkeycode;
+       if (!dev->getkeycode)
+               dev->getkeycode = input_default_getkeycode;
 
-       if (!dev->setkeycode && !dev->setkeycode_new)
-               dev->setkeycode_new = input_default_setkeycode;
+       if (!dev->setkeycode)
+               dev->setkeycode = input_default_setkeycode;
 
        dev_set_name(&dev->dev, "input%ld",
                     (unsigned long) atomic_inc_return(&input_no) - 1);
index c7a92028f450953b264ac6d8d950eeef9135c4a6..b16bed038f7245634aa3a6ffbbac45b40d168878 100644 (file)
@@ -112,6 +112,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
          right-hand column will be interpreted as the key shown in the
          left-hand column.
 
+config KEYBOARD_QT1070
+       tristate "Atmel AT42QT1070 Touch Sensor Chip"
+       depends on I2C
+       help
+         Say Y here if you want to use Atmel AT42QT1070 QTouch
+         Sensor chip as input device.
+
+         To compile this driver as a module, choose M here:
+         the module will be called qt1070
+
 config KEYBOARD_QT2160
        tristate "Atmel AT42QT2160 Touch Sensor Chip"
        depends on I2C && EXPERIMENTAL
index 468c627a28447efb78b9fb32b9a35351719d4f06..878e6c20deb0e1f231526e26846aedd1e1ce60d4 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_OMAP4)          += omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)       += opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
 obj-$(CONFIG_KEYBOARD_QT2160)          += qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)         += samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
index f7c2a166576b8cc161c1debb85639c8426906584..b732870ecc897a1465ad8645342b9ce60435beba 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/leds.h>
+#include <linux/pm.h>
 #include <linux/i2c/lm8323.h>
 #include <linux/slab.h>
 
@@ -802,8 +803,9 @@ static int __devexit lm8323_remove(struct i2c_client *client)
  * We don't need to explicitly suspend the chip, as it already switches off
  * when there's no activity.
  */
-static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
+static int lm8323_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct lm8323_chip *lm = i2c_get_clientdata(client);
        int i;
 
@@ -821,8 +823,9 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int lm8323_resume(struct i2c_client *client)
+static int lm8323_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct lm8323_chip *lm = i2c_get_clientdata(client);
        int i;
 
@@ -839,11 +842,10 @@ static int lm8323_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define lm8323_suspend NULL
-#define lm8323_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume);
+
 static const struct i2c_device_id lm8323_id[] = {
        { "lm8323", 0 },
        { }
@@ -852,11 +854,10 @@ static const struct i2c_device_id lm8323_id[] = {
 static struct i2c_driver lm8323_i2c_driver = {
        .driver = {
                .name   = "lm8323",
+               .pm     = &lm8323_pm_ops,
        },
        .probe          = lm8323_probe,
        .remove         = __devexit_p(lm8323_remove),
-       .suspend        = lm8323_suspend,
-       .resume         = lm8323_resume,
        .id_table       = lm8323_id,
 };
 MODULE_DEVICE_TABLE(i2c, lm8323_id);
index 9091ff5ea808b8829d7d9475f15f704532d10c5e..5afe35ad24d37b4ec3558cc5a07c20470e6f3ea8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 
@@ -271,8 +272,10 @@ static int __devexit max7359_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
+static int max7359_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        max7359_fall_deepsleep(client);
 
        if (device_may_wakeup(&client->dev))
@@ -281,8 +284,10 @@ static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int max7359_resume(struct i2c_client *client)
+static int max7359_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        if (device_may_wakeup(&client->dev))
                disable_irq_wake(client->irq);
 
@@ -291,11 +296,10 @@ static int max7359_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define max7359_suspend        NULL
-#define max7359_resume NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume);
+
 static const struct i2c_device_id max7359_ids[] = {
        { "max7359", 0 },
        { }
@@ -305,11 +309,10 @@ MODULE_DEVICE_TABLE(i2c, max7359_ids);
 static struct i2c_driver max7359_i2c_driver = {
        .driver = {
                .name = "max7359",
+               .pm   = &max7359_pm,
        },
        .probe          = max7359_probe,
        .remove         = __devexit_p(max7359_remove),
-       .suspend        = max7359_suspend,
-       .resume         = max7359_resume,
        .id_table       = max7359_ids,
 };
 
index 63b849d7e90b0fb9d2755ed6a1e9f0bf9975959f..af1aab324a4c58c0e011ea8660e483802db2ef41 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ * Touchkey driver for MELFAS MCS5000/5080 controller
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
  * Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -19,6 +19,7 @@
 #include <linux/input.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 
 /* MCS5000 Touchkey */
 #define MCS5000_TOUCHKEY_STATUS                0x04
@@ -45,6 +46,8 @@ struct mcs_touchkey_chip {
 };
 
 struct mcs_touchkey_data {
+       void (*poweron)(bool);
+
        struct i2c_client *client;
        struct input_dev *input_dev;
        struct mcs_touchkey_chip chip;
@@ -169,6 +172,11 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client,
        if (pdata->cfg_pin)
                pdata->cfg_pin();
 
+       if (pdata->poweron) {
+               data->poweron = pdata->poweron;
+               data->poweron(true);
+       }
+
        error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
                        IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
        if (error) {
@@ -196,12 +204,57 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client)
        struct mcs_touchkey_data *data = i2c_get_clientdata(client);
 
        free_irq(client->irq, data);
+       if (data->poweron)
+               data->poweron(false);
        input_unregister_device(data->input_dev);
        kfree(data);
 
        return 0;
 }
 
+static void mcs_touchkey_shutdown(struct i2c_client *client)
+{
+       struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+       if (data->poweron)
+               data->poweron(false);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mcs_touchkey_suspend(struct device *dev)
+{
+       struct mcs_touchkey_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       /* Disable the work */
+       disable_irq(client->irq);
+
+       /* Finally turn off the power */
+       if (data->poweron)
+               data->poweron(false);
+
+       return 0;
+}
+
+static int mcs_touchkey_resume(struct device *dev)
+{
+       struct mcs_touchkey_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       /* Enable the device first */
+       if (data->poweron)
+               data->poweron(true);
+
+       /* Enable irq again */
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops,
+                        mcs_touchkey_suspend, mcs_touchkey_resume);
+
 static const struct i2c_device_id mcs_touchkey_id[] = {
        { "mcs5000_touchkey", MCS5000_TOUCHKEY },
        { "mcs5080_touchkey", MCS5080_TOUCHKEY },
@@ -213,9 +266,11 @@ static struct i2c_driver mcs_touchkey_driver = {
        .driver = {
                .name   = "mcs_touchkey",
                .owner  = THIS_MODULE,
+               .pm     = &mcs_touchkey_pm_ops,
        },
        .probe          = mcs_touchkey_probe,
        .remove         = __devexit_p(mcs_touchkey_remove),
+       .shutdown       = mcs_touchkey_shutdown,
        .id_table       = mcs_touchkey_id,
 };
 
index 45bd0977d0066622d543a9d51cca96873536f8a9..c51a3c4a7feb52520246c332d93784a25fc70774 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/io.h>
 #include <linux/input.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/omap4-keypad.h>
 
@@ -80,20 +81,6 @@ struct omap4_keypad {
        unsigned short keymap[];
 };
 
-static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
-{
-       __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
-                       keypad_data->base + OMAP4_KBD_CTRL);
-       __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
-                       keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
-       __raw_writel(OMAP4_VAL_IRQDISABLE,
-                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
-       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
-                       keypad_data->base + OMAP4_KBD_IRQENABLE);
-       __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
-                       keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
-}
-
 /* Interrupt handler */
 static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
 {
@@ -144,6 +131,49 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int omap4_keypad_open(struct input_dev *input)
+{
+       struct omap4_keypad *keypad_data = input_get_drvdata(input);
+
+       pm_runtime_get_sync(input->dev.parent);
+
+       disable_irq(keypad_data->irq);
+
+       __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
+                       keypad_data->base + OMAP4_KBD_CTRL);
+       __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
+                       keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+                       keypad_data->base + OMAP4_KBD_IRQENABLE);
+       __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
+                       keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+
+       enable_irq(keypad_data->irq);
+
+       return 0;
+}
+
+static void omap4_keypad_close(struct input_dev *input)
+{
+       struct omap4_keypad *keypad_data = input_get_drvdata(input);
+
+       disable_irq(keypad_data->irq);
+
+       /* Disable interrupts */
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                    keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+       /* clear pending interrupts */
+       __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+
+       enable_irq(keypad_data->irq);
+
+       pm_runtime_put_sync(input->dev.parent);
+}
+
 static int __devinit omap4_keypad_probe(struct platform_device *pdev)
 {
        const struct omap4_keypad_platform_data *pdata;
@@ -225,6 +255,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
        input_dev->id.product = 0x0001;
        input_dev->id.version = 0x0001;
 
+       input_dev->open = omap4_keypad_open;
+       input_dev->close = omap4_keypad_close;
+
        input_dev->keycode      = keypad_data->keymap;
        input_dev->keycodesize  = sizeof(keypad_data->keymap[0]);
        input_dev->keycodemax   = max_keys;
@@ -239,8 +272,6 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
        matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
                        input_dev->keycode, input_dev->keybit);
 
-       omap4_keypad_config(keypad_data);
-
        error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
                             IRQF_TRIGGER_RISING,
                             "omap4-keypad", keypad_data);
@@ -249,17 +280,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
                goto err_free_input;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
        error = input_register_device(keypad_data->input);
        if (error < 0) {
                dev_err(&pdev->dev, "failed to register input device\n");
-               goto err_free_irq;
+               goto err_pm_disable;
        }
 
-
        platform_set_drvdata(pdev, keypad_data);
        return 0;
 
-err_free_irq:
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
        free_irq(keypad_data->irq, keypad_data);
 err_free_input:
        input_free_device(input_dev);
@@ -278,6 +311,9 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev)
        struct resource *res;
 
        free_irq(keypad_data->irq, keypad_data);
+
+       pm_runtime_disable(&pdev->dev);
+
        input_unregister_device(keypad_data->input);
 
        iounmap(keypad_data->base);
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
new file mode 100644 (file)
index 0000000..fba8404
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ *  Atmel AT42QT1070 QTouch Sensor Controller
+ *
+ *  Copyright (C) 2011 Atmel
+ *
+ *  Authors: Bo Shen <voice.shen@atmel.com>
+ *
+ *  Base on AT42QT2160 driver by:
+ *  Raphael Derosso Pereira <raphaelpereira@gmail.com>
+ *  Copyright (C) 2009
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+
+/* Address for each register */
+#define CHIP_ID            0x00
+#define QT1070_CHIP_ID     0x2E
+
+#define FW_VERSION         0x01
+#define QT1070_FW_VERSION  0x15
+
+#define DET_STATUS         0x02
+
+#define KEY_STATUS         0x03
+
+/* Calibrate */
+#define CALIBRATE_CMD      0x38
+#define QT1070_CAL_TIME    200
+
+/* Reset */
+#define RESET              0x39
+#define QT1070_RESET_TIME  255
+
+/* AT42QT1070 support up to 7 keys */
+static const unsigned short qt1070_key2code[] = {
+       KEY_0, KEY_1, KEY_2, KEY_3,
+       KEY_4, KEY_5, KEY_6,
+};
+
+struct qt1070_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+       unsigned int irq;
+       unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)];
+       u8 last_keys;
+};
+
+static int qt1070_read(struct i2c_client *client, u8 reg)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "can not read register, returned %d\n", ret);
+
+       return ret;
+}
+
+static int qt1070_write(struct i2c_client *client, u8 reg, u8 data)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, reg, data);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "can not write register, returned %d\n", ret);
+
+       return ret;
+}
+
+static bool __devinit qt1070_identify(struct i2c_client *client)
+{
+       int id, ver;
+
+       /* Read Chip ID */
+       id = qt1070_read(client, CHIP_ID);
+       if (id != QT1070_CHIP_ID) {
+               dev_err(&client->dev, "ID %d not supported\n", id);
+               return false;
+       }
+
+       /* Read firmware version */
+       ver = qt1070_read(client, FW_VERSION);
+       if (ver < 0) {
+               dev_err(&client->dev, "could not read the firmware version\n");
+               return false;
+       }
+
+       dev_info(&client->dev, "AT42QT1070 firmware version %x\n", ver);
+
+       return true;
+}
+
+static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
+{
+       struct qt1070_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       struct input_dev *input = data->input;
+       int i;
+       u8 new_keys, keyval, mask = 0x01;
+
+       /* Read the detected status register, thus clearing interrupt */
+       qt1070_read(client, DET_STATUS);
+
+       /* Read which key changed */
+       new_keys = qt1070_read(client, KEY_STATUS);
+
+       for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
+               keyval = new_keys & mask;
+               if ((data->last_keys & mask) != keyval)
+                       input_report_key(input, data->keycodes[i], keyval);
+               mask <<= 1;
+       }
+       input_sync(input);
+
+       data->last_keys = new_keys;
+       return IRQ_HANDLED;
+}
+
+static int __devinit qt1070_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct qt1070_data *data;
+       struct input_dev *input;
+       int i;
+       int err;
+
+       err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
+       if (!err) {
+               dev_err(&client->dev, "%s adapter not supported\n",
+                       dev_driver_string(&client->adapter->dev));
+               return -ENODEV;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "please assign the irq to this device\n");
+               return -EINVAL;
+       }
+
+       /* Identify the qt1070 chip */
+       if (!qt1070_identify(client))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!data || !input) {
+               dev_err(&client->dev, "insufficient memory\n");
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input = input;
+       data->irq = client->irq;
+
+       input->name = "AT42QT1070 QTouch Sensor";
+       input->dev.parent = &client->dev;
+       input->id.bustype = BUS_I2C;
+
+       /* Add the keycode */
+       input->keycode = data->keycodes;
+       input->keycodesize = sizeof(data->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(qt1070_key2code);
+
+       __set_bit(EV_KEY, input->evbit);
+
+       for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
+               data->keycodes[i] = qt1070_key2code[i];
+               __set_bit(qt1070_key2code[i], input->keybit);
+       }
+
+       /* Calibrate device */
+       qt1070_write(client, CALIBRATE_CMD, 1);
+       msleep(QT1070_CAL_TIME);
+
+       /* Soft reset */
+       qt1070_write(client, RESET, 1);
+       msleep(QT1070_RESET_TIME);
+
+       err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
+               IRQF_TRIGGER_NONE, client->dev.driver->name, data);
+       if (err) {
+               dev_err(&client->dev, "fail to request irq\n");
+               goto err_free_mem;
+       }
+
+       /* Register the input device */
+       err = input_register_device(data->input);
+       if (err) {
+               dev_err(&client->dev, "Failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       i2c_set_clientdata(client, data);
+
+       /* Read to clear the chang line */
+       qt1070_read(client, DET_STATUS);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input);
+       kfree(data);
+       return err;
+}
+
+static int __devexit qt1070_remove(struct i2c_client *client)
+{
+       struct qt1070_data *data = i2c_get_clientdata(client);
+
+       /* Release IRQ */
+       free_irq(client->irq, data);
+
+       input_unregister_device(data->input);
+       kfree(data);
+
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static const struct i2c_device_id qt1070_id[] = {
+       { "qt1070", 0 },
+       { },
+};
+
+static struct i2c_driver qt1070_driver = {
+       .driver = {
+               .name   = "qt1070",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = qt1070_id,
+       .probe          = qt1070_probe,
+       .remove         = __devexit_p(qt1070_remove),
+};
+
+static int __init qt1070_init(void)
+{
+       return i2c_add_driver(&qt1070_driver);
+}
+module_init(qt1070_init);
+
+static void __exit qt1070_exit(void)
+{
+       i2c_del_driver(&qt1070_driver);
+}
+module_exit(qt1070_exit);
+
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor");
+MODULE_LICENSE("GPL");
index dbbe761778d28e2815182ed023bf5d196f842b27..99122f59e98822d8620cec91c2ea4942e427269b 100644 (file)
@@ -402,7 +402,7 @@ static int __devexit tc3589x_keypad_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int tc3589x_keypad_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -439,19 +439,19 @@ static int tc3589x_keypad_resume(struct device *dev)
 
        return 0;
 }
-
-static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
-                              tc3589x_keypad_suspend, tc3589x_keypad_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
+                        tc3589x_keypad_suspend, tc3589x_keypad_resume);
+
 static struct platform_driver tc3589x_keypad_driver = {
-       .driver.name  = "tc3589x-keypad",
-       .driver.owner = THIS_MODULE,
-#ifdef CONFIG_PM
-       .driver.pm = &tc3589x_keypad_dev_pm_ops,
-#endif
-       .probe = tc3589x_keypad_probe,
-       .remove = __devexit_p(tc3589x_keypad_remove),
+       .driver = {
+               .name   = "tc3589x-keypad",
+               .owner  = THIS_MODULE,
+               .pm     = &tc3589x_keypad_dev_pm_ops,
+       },
+       .probe  = tc3589x_keypad_probe,
+       .remove = __devexit_p(tc3589x_keypad_remove),
 };
 
 static int __init tc3589x_keypad_init(void)
index 800fbccf1f0fb714017cefb47320829753b0f839..3afea3f897182adba5c1439dc38e7a34126fa440 100644 (file)
@@ -297,6 +297,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
        }
 
        i2c_set_clientdata(client, chip);
+       device_init_wakeup(&client->dev, 1);
 
        return 0;
 
@@ -326,10 +327,37 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tca6416_keypad_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(chip->irqnum);
+
+       return 0;
+}
+
+static int tca6416_keypad_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(chip->irqnum);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops,
+                        tca6416_keypad_suspend, tca6416_keypad_resume);
 
 static struct i2c_driver tca6416_keypad_driver = {
        .driver = {
                .name   = "tca6416-keypad",
+               .pm     = &tca6416_keypad_dev_pm_ops,
        },
        .probe          = tca6416_keypad_probe,
        .remove         = __devexit_p(tca6416_keypad_remove),
index 4cc82826ea6bc273168c3a34f100b28025fe3366..3dca3c14510e055be3925d9552cd79e181ef91cd 100644 (file)
@@ -74,7 +74,7 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
        info->chip = chip;
        info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
        info->dev = &pdev->dev;
-       info->irq = irq + chip->irq_base;
+       info->irq = irq;
 
        info->idev = input_allocate_device();
        if (!info->idev) {
index b0c6772851a99496727663941e092b46f81482e3..f9cf0881b0e3cf386a3e606d462aebf4bacd5575 100644 (file)
@@ -454,4 +454,17 @@ config INPUT_CMA3000_I2C
          To compile this driver as a module, choose M here: the
          module will be called cma3000_d0x_i2c.
 
+config INPUT_XEN_KBDDEV_FRONTEND
+       tristate "Xen virtual keyboard and mouse support"
+       depends on XEN_FBDEV_FRONTEND
+       default y
+       select XEN_XENBUS_FRONTEND
+       help
+         This driver implements the front-end of the Xen virtual
+         keyboard and mouse device driver.  It communicates with a back-end
+         in another domain.
+
+         To compile this driver as a module, choose M here: the
+         module will be called xen-kbdfront.
+
 endif
index 9b4797112c9ac14955ff7afb0b84ab616e613a89..e3f7984e627427ead449de2d6e6452d3aac1c915 100644 (file)
@@ -42,5 +42,6 @@ obj-$(CONFIG_INPUT_TWL4030_VIBRA)     += twl4030-vibra.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)          += wm831x-on.o
+obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 
index 2bef8fa56c948e0ba4305ea0f4f22450244f79d4..e21deb1baa8abfb193d46702023540e2d09a41ca 100644 (file)
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pm.h>
 #include "ad714x.h"
 
 #ifdef CONFIG_PM
-static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int ad714x_i2c_suspend(struct device *dev)
 {
-       return ad714x_disable(i2c_get_clientdata(client));
+       return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
 }
 
-static int ad714x_i2c_resume(struct i2c_client *client)
+static int ad714x_i2c_resume(struct device *dev)
 {
-       return ad714x_enable(i2c_get_clientdata(client));
+       return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev)));
 }
-#else
-# define ad714x_i2c_suspend NULL
-# define ad714x_i2c_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
+
 static int ad714x_i2c_write(struct device *dev, unsigned short reg,
                                unsigned short data)
 {
@@ -114,11 +114,10 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id);
 static struct i2c_driver ad714x_i2c_driver = {
        .driver = {
                .name = "ad714x_captouch",
+               .pm   = &ad714x_i2c_pm,
        },
        .probe    = ad714x_i2c_probe,
        .remove   = __devexit_p(ad714x_i2c_remove),
-       .suspend  = ad714x_i2c_suspend,
-       .resume   = ad714x_i2c_resume,
        .id_table = ad714x_id,
 };
 
index 7f8dedfd1bfeed3db41403e560dc55b16a32f907..4120dd5493059126b272256b47eba121044e396d 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/input.h>       /* BUS_I2C */
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/pm.h>
 #include <linux/types.h>
 #include "ad714x.h"
 
 #define AD714x_SPI_READ            BIT(10)
 
 #ifdef CONFIG_PM
-static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message)
+static int ad714x_spi_suspend(struct device *dev)
 {
-       return ad714x_disable(spi_get_drvdata(spi));
+       return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
 }
 
-static int ad714x_spi_resume(struct spi_device *spi)
+static int ad714x_spi_resume(struct device *dev)
 {
-       return ad714x_enable(spi_get_drvdata(spi));
+       return ad714x_enable(spi_get_drvdata(to_spi_device(dev)));
 }
-#else
-# define ad714x_spi_suspend NULL
-# define ad714x_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
+
 static int ad714x_spi_read(struct device *dev, unsigned short reg,
                unsigned short *data)
 {
@@ -79,11 +79,10 @@ static struct spi_driver ad714x_spi_driver = {
        .driver = {
                .name   = "ad714x_captouch",
                .owner  = THIS_MODULE,
+               .pm     = &ad714x_spi_pm,
        },
        .probe          = ad714x_spi_probe,
        .remove         = __devexit_p(ad714x_spi_remove),
-       .suspend        = ad714x_spi_suspend,
-       .resume         = ad714x_spi_resume,
 };
 
 static __init int ad714x_spi_init(void)
index 0779724af7e79b8f34d6857c15793f09d7080b60..ccacf2bb06a4e56c74624dab181ac6398ab56bcc 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pm.h>
 #include "adxl34x.h"
 
 static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
@@ -105,8 +106,9 @@ static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int adxl34x_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adxl34x *ac = i2c_get_clientdata(client);
 
        adxl34x_suspend(ac);
@@ -114,19 +116,20 @@ static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
        return 0;
 }
 
-static int adxl34x_i2c_resume(struct i2c_client *client)
+static int adxl34x_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adxl34x *ac = i2c_get_clientdata(client);
 
        adxl34x_resume(ac);
 
        return 0;
 }
-#else
-# define adxl34x_i2c_suspend NULL
-# define adxl34x_i2c_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
+                        adxl34x_i2c_resume);
+
 static const struct i2c_device_id adxl34x_id[] = {
        { "adxl34x", 0 },
        { }
@@ -138,11 +141,10 @@ static struct i2c_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .owner = THIS_MODULE,
+               .pm = &adxl34x_i2c_pm,
        },
        .probe    = adxl34x_i2c_probe,
        .remove   = __devexit_p(adxl34x_i2c_remove),
-       .suspend  = adxl34x_i2c_suspend,
-       .resume   = adxl34x_i2c_resume,
        .id_table = adxl34x_id,
 };
 
index 782de9e898287b4905291a26305eb049a04fcac1..f29de22fdda054b7fed385ea0abe957e2cda5570 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/input.h>       /* BUS_SPI */
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/pm.h>
 #include <linux/types.h>
 #include "adxl34x.h"
 
@@ -57,7 +58,7 @@ static int adxl34x_spi_read_block(struct device *dev,
        return (status < 0) ? status : 0;
 }
 
-static const struct adxl34x_bus_ops adx134x_spi_bops = {
+static const struct adxl34x_bus_ops adxl34x_spi_bops = {
        .bustype        = BUS_SPI,
        .write          = adxl34x_spi_write,
        .read           = adxl34x_spi_read,
@@ -76,7 +77,7 @@ static int __devinit adxl34x_spi_probe(struct spi_device *spi)
 
        ac = adxl34x_probe(&spi->dev, spi->irq,
                           spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
-                          &adx134x_spi_bops);
+                          &adxl34x_spi_bops);
 
        if (IS_ERR(ac))
                return PTR_ERR(ac);
@@ -94,8 +95,9 @@ static int __devexit adxl34x_spi_remove(struct spi_device *spi)
 }
 
 #ifdef CONFIG_PM
-static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+static int adxl34x_spi_suspend(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct adxl34x *ac = dev_get_drvdata(&spi->dev);
 
        adxl34x_suspend(ac);
@@ -103,29 +105,29 @@ static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int adxl34x_spi_resume(struct spi_device *spi)
+static int adxl34x_spi_resume(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct adxl34x *ac = dev_get_drvdata(&spi->dev);
 
        adxl34x_resume(ac);
 
        return 0;
 }
-#else
-# define adxl34x_spi_suspend NULL
-# define adxl34x_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
+                        adxl34x_spi_resume);
+
 static struct spi_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .bus = &spi_bus_type,
                .owner = THIS_MODULE,
+               .pm = &adxl34x_spi_pm,
        },
        .probe   = adxl34x_spi_probe,
        .remove  = __devexit_p(adxl34x_spi_remove),
-       .suspend = adxl34x_spi_suspend,
-       .resume  = adxl34x_spi_resume,
 };
 
 static int __init adxl34x_spi_init(void)
index 0b0e9be6354215319200a8a305c9db55e8b4c3dd..9ccdb82d869a09245c80bf125a99c5fcac5cffd7 100644 (file)
@@ -612,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
        idev->open = ati_remote2_open;
        idev->close = ati_remote2_close;
 
-       idev->getkeycode_new = ati_remote2_getkeycode;
-       idev->setkeycode_new = ati_remote2_setkeycode;
+       idev->getkeycode = ati_remote2_getkeycode;
+       idev->setkeycode = ati_remote2_setkeycode;
 
        idev->name = ar2->name;
        idev->phys = ar2->phys;
index 014dd4ad0d4fecede04221e5348fc78e023d76e2..6a11694e3fc7bb1274f59105e35f9d0b7c7d33c9 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/workqueue.h>
 #include <linux/i2c/twl.h>
 #include <linux/mfd/twl4030-codec.h>
+#include <linux/mfd/core.h>
 #include <linux/input.h>
 #include <linux/slab.h>
 
@@ -196,7 +197,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
 
 static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
+       struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
        struct vibra_info *info;
        int ret;
 
index 82542a1c1098fb00c3d33769a21088f3f7eccd05..364bdf43a381d8a052c730eb38eb005c0f006c0c 100644 (file)
@@ -347,8 +347,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
 {
        struct uinput_user_dev  *user_dev;
        struct input_dev        *dev;
-       char                    *name;
-       int                     i, size;
+       int                     i;
        int                     retval;
 
        if (count != sizeof(struct uinput_user_dev))
@@ -362,30 +361,25 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
 
        dev = udev->dev;
 
-       user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL);
-       if (!user_dev)
-               return -ENOMEM;
-
-       if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
-               retval = -EFAULT;
-               goto exit;
-       }
+       user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
+       if (IS_ERR(user_dev))
+               return PTR_ERR(user_dev);
 
        udev->ff_effects_max = user_dev->ff_effects_max;
 
-       size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-       if (!size) {
+       /* Ensure name is filled in */
+       if (!user_dev->name[0]) {
                retval = -EINVAL;
                goto exit;
        }
 
        kfree(dev->name);
-       dev->name = name = kmalloc(size, GFP_KERNEL);
-       if (!name) {
+       dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
+                            GFP_KERNEL);
+       if (!dev->name) {
                retval = -ENOMEM;
                goto exit;
        }
-       strlcpy(name, user_dev->name, size);
 
        dev->id.bustype = user_dev->id.bustype;
        dev->id.vendor  = user_dev->id.vendor;
@@ -622,7 +616,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
        struct uinput_ff_upload ff_up;
        struct uinput_ff_erase  ff_erase;
        struct uinput_request   *req;
-       int                     length;
        char                    *phys;
 
        retval = mutex_lock_interruptible(&udev->mutex);
@@ -689,24 +682,15 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
                                retval = -EINVAL;
                                goto out;
                        }
-                       length = strnlen_user(p, 1024);
-                       if (length <= 0) {
-                               retval = -EFAULT;
-                               break;
+
+                       phys = strndup_user(p, 1024);
+                       if (IS_ERR(phys)) {
+                               retval = PTR_ERR(phys);
+                               goto out;
                        }
+
                        kfree(udev->dev->phys);
-                       udev->dev->phys = phys = kmalloc(length, GFP_KERNEL);
-                       if (!phys) {
-                               retval = -ENOMEM;
-                               break;
-                       }
-                       if (copy_from_user(phys, p, length)) {
-                               udev->dev->phys = NULL;
-                               kfree(phys);
-                               retval = -EFAULT;
-                               break;
-                       }
-                       phys[length - 1] = '\0';
+                       udev->dev->phys = phys;
                        break;
 
                case UI_BEGIN_FF_UPLOAD:
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
new file mode 100644 (file)
index 0000000..7077f9b
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Xen para-virtual input device
+ *
+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
+ * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
+ *
+ *  Based on linux/drivers/input/mouse/sermouse.c
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/kbdif.h>
+#include <xen/xenbus.h>
+
+struct xenkbd_info {
+       struct input_dev *kbd;
+       struct input_dev *ptr;
+       struct xenkbd_page *page;
+       int gref;
+       int irq;
+       struct xenbus_device *xbdev;
+       char phys[32];
+};
+
+static int xenkbd_remove(struct xenbus_device *);
+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
+static void xenkbd_disconnect_backend(struct xenkbd_info *);
+
+/*
+ * Note: if you need to send out events, see xenfb_do_update() for how
+ * to do that.
+ */
+
+static irqreturn_t input_handler(int rq, void *dev_id)
+{
+       struct xenkbd_info *info = dev_id;
+       struct xenkbd_page *page = info->page;
+       __u32 cons, prod;
+
+       prod = page->in_prod;
+       if (prod == page->in_cons)
+               return IRQ_HANDLED;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = page->in_cons; cons != prod; cons++) {
+               union xenkbd_in_event *event;
+               struct input_dev *dev;
+               event = &XENKBD_IN_RING_REF(page, cons);
+
+               dev = info->ptr;
+               switch (event->type) {
+               case XENKBD_TYPE_MOTION:
+                       input_report_rel(dev, REL_X, event->motion.rel_x);
+                       input_report_rel(dev, REL_Y, event->motion.rel_y);
+                       if (event->motion.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->motion.rel_z);
+                       break;
+               case XENKBD_TYPE_KEY:
+                       dev = NULL;
+                       if (test_bit(event->key.keycode, info->kbd->keybit))
+                               dev = info->kbd;
+                       if (test_bit(event->key.keycode, info->ptr->keybit))
+                               dev = info->ptr;
+                       if (dev)
+                               input_report_key(dev, event->key.keycode,
+                                                event->key.pressed);
+                       else
+                               pr_warning("unhandled keycode 0x%x\n",
+                                          event->key.keycode);
+                       break;
+               case XENKBD_TYPE_POS:
+                       input_report_abs(dev, ABS_X, event->pos.abs_x);
+                       input_report_abs(dev, ABS_Y, event->pos.abs_y);
+                       if (event->pos.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->pos.rel_z);
+                       break;
+               }
+               if (dev)
+                       input_sync(dev);
+       }
+       mb();                   /* ensure we got ring contents */
+       page->in_cons = cons;
+       notify_remote_via_irq(info->irq);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit xenkbd_probe(struct xenbus_device *dev,
+                                 const struct xenbus_device_id *id)
+{
+       int ret, i, abs;
+       struct xenkbd_info *info;
+       struct input_dev *kbd, *ptr;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+       dev_set_drvdata(&dev->dev, info);
+       info->xbdev = dev;
+       info->irq = -1;
+       info->gref = -1;
+       snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
+
+       info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+       if (!info->page)
+               goto error_nomem;
+
+       if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0)
+               abs = 0;
+       if (abs)
+               xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1");
+
+       /* keyboard */
+       kbd = input_allocate_device();
+       if (!kbd)
+               goto error_nomem;
+       kbd->name = "Xen Virtual Keyboard";
+       kbd->phys = info->phys;
+       kbd->id.bustype = BUS_PCI;
+       kbd->id.vendor = 0x5853;
+       kbd->id.product = 0xffff;
+
+       __set_bit(EV_KEY, kbd->evbit);
+       for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
+               __set_bit(i, kbd->keybit);
+       for (i = KEY_OK; i < KEY_MAX; i++)
+               __set_bit(i, kbd->keybit);
+
+       ret = input_register_device(kbd);
+       if (ret) {
+               input_free_device(kbd);
+               xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
+               goto error;
+       }
+       info->kbd = kbd;
+
+       /* pointing device */
+       ptr = input_allocate_device();
+       if (!ptr)
+               goto error_nomem;
+       ptr->name = "Xen Virtual Pointer";
+       ptr->phys = info->phys;
+       ptr->id.bustype = BUS_PCI;
+       ptr->id.vendor = 0x5853;
+       ptr->id.product = 0xfffe;
+
+       if (abs) {
+               __set_bit(EV_ABS, ptr->evbit);
+               input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
+               input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
+       } else {
+               input_set_capability(ptr, EV_REL, REL_X);
+               input_set_capability(ptr, EV_REL, REL_Y);
+       }
+       input_set_capability(ptr, EV_REL, REL_WHEEL);
+
+       __set_bit(EV_KEY, ptr->evbit);
+       for (i = BTN_LEFT; i <= BTN_TASK; i++)
+               __set_bit(i, ptr->keybit);
+
+       ret = input_register_device(ptr);
+       if (ret) {
+               input_free_device(ptr);
+               xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
+               goto error;
+       }
+       info->ptr = ptr;
+
+       ret = xenkbd_connect_backend(dev, info);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+ error_nomem:
+       ret = -ENOMEM;
+       xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+       xenkbd_remove(dev);
+       return ret;
+}
+
+static int xenkbd_resume(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+       xenkbd_disconnect_backend(info);
+       memset(info->page, 0, PAGE_SIZE);
+       return xenkbd_connect_backend(dev, info);
+}
+
+static int xenkbd_remove(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+       xenkbd_disconnect_backend(info);
+       if (info->kbd)
+               input_unregister_device(info->kbd);
+       if (info->ptr)
+               input_unregister_device(info->ptr);
+       free_page((unsigned long)info->page);
+       kfree(info);
+       return 0;
+}
+
+static int xenkbd_connect_backend(struct xenbus_device *dev,
+                                 struct xenkbd_info *info)
+{
+       int ret, evtchn;
+       struct xenbus_transaction xbt;
+
+       ret = gnttab_grant_foreign_access(dev->otherend_id,
+                                         virt_to_mfn(info->page), 0);
+       if (ret < 0)
+               return ret;
+       info->gref = ret;
+
+       ret = xenbus_alloc_evtchn(dev, &evtchn);
+       if (ret)
+               goto error_grant;
+       ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
+                                       0, dev->devicetype, info);
+       if (ret < 0) {
+               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+               goto error_evtchan;
+       }
+       info->irq = ret;
+
+ again:
+       ret = xenbus_transaction_start(&xbt);
+       if (ret) {
+               xenbus_dev_fatal(dev, ret, "starting transaction");
+               goto error_irqh;
+       }
+       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+                           virt_to_mfn(info->page));
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           evtchn);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_transaction_end(xbt, 0);
+       if (ret) {
+               if (ret == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, ret, "completing transaction");
+               goto error_irqh;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+       return 0;
+
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, ret, "writing xenstore");
+ error_irqh:
+       unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+ error_evtchan:
+       xenbus_free_evtchn(dev, evtchn);
+ error_grant:
+       gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
+       return ret;
+}
+
+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
+{
+       if (info->irq >= 0)
+               unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+       if (info->gref >= 0)
+               gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
+}
+
+static void xenkbd_backend_changed(struct xenbus_device *dev,
+                                  enum xenbus_state backend_state)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+       int val;
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateReconfiguring:
+       case XenbusStateReconfigured:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+InitWait:
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateConnected:
+               /*
+                * Work around xenbus race condition: If backend goes
+                * through InitWait to Connected fast enough, we can
+                * get Connected twice here.
+                */
+               if (dev->state != XenbusStateConnected)
+                       goto InitWait; /* no InitWait seen yet, fudge it */
+
+               /* Set input abs params to match backend screen res */
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "width", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
+
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "height", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
+
+               break;
+
+       case XenbusStateClosing:
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static const struct xenbus_device_id xenkbd_ids[] = {
+       { "vkbd" },
+       { "" }
+};
+
+static struct xenbus_driver xenkbd_driver = {
+       .name = "vkbd",
+       .owner = THIS_MODULE,
+       .ids = xenkbd_ids,
+       .probe = xenkbd_probe,
+       .remove = xenkbd_remove,
+       .resume = xenkbd_resume,
+       .otherend_changed = xenkbd_backend_changed,
+};
+
+static int __init xenkbd_init(void)
+{
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       /* Nothing to do if running in dom0. */
+       if (xen_initial_domain())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&xenkbd_driver);
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+       xenbus_unregister_driver(&xenkbd_driver);
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vkbd");
index ee82851afe3ee9a660873b59d5fcb8cf39181ca7..3aead91bacc851d283458a2f48064ab36ec01320 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
+/* Macbook8 (unibody, March 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -96,6 +100,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
+       /* MacbookPro8 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
        /* Terminating entry */
        {}
 };
@@ -274,6 +282,18 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
                { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING5_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4415, 5050 },
+               { DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
+       },
        {}
 };
 
@@ -430,10 +450,6 @@ static int report_tp_state(struct bcm5974 *dev, int size)
                ptest = int2bound(&c->p, raw_p);
                origin = raw2int(f->origin);
 
-               /* set the integrated button if applicable */
-               if (c->tp_type == TYPE2)
-                       ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
-
                /* while tracking finger still valid, count all fingers */
                if (ptest > PRESSURE_LOW && origin) {
                        abs_p = ptest;
@@ -452,6 +468,10 @@ static int report_tp_state(struct bcm5974 *dev, int size)
                }
        }
 
+       /* set the integrated button if applicable */
+       if (c->tp_type == TYPE2)
+               ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+
        if (dev->fingers < nmin)
                dev->fingers = nmin;
        if (dev->fingers > nmax)
index 0ae62f0bcb3216ca32c494e3a807a75a8f6753bd..f6aa26d305edd4e4922517610fbd8437aab62367 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 
 #define DRIVER_NAME            "synaptics_i2c"
 /* maximum product id is 15 characters */
@@ -619,8 +620,9 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int synaptics_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
        cancel_delayed_work_sync(&touch->dwork);
@@ -631,9 +633,10 @@ static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int synaptics_i2c_resume(struct i2c_client *client)
+static int synaptics_i2c_resume(struct device *dev)
 {
        int ret;
+       struct i2c_client *client = to_i2c_client(dev);
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
        ret = synaptics_i2c_reset_config(client);
@@ -645,11 +648,11 @@ static int synaptics_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define synaptics_i2c_suspend  NULL
-#define synaptics_i2c_resume   NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
+                        synaptics_i2c_resume);
+
 static const struct i2c_device_id synaptics_i2c_id_table[] = {
        { "synaptics_i2c", 0 },
        { },
@@ -660,13 +663,12 @@ static struct i2c_driver synaptics_i2c_driver = {
        .driver = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .pm     = &synaptics_i2c_pm,
        },
 
        .probe          = synaptics_i2c_probe,
        .remove         = __devexit_p(synaptics_i2c_remove),
 
-       .suspend        = synaptics_i2c_suspend,
-       .resume         = synaptics_i2c_resume,
        .id_table       = synaptics_i2c_id_table,
 };
 
index 7729e547ba65d853581e115a4ce6428883549ecd..337bf51bc984253abf9a77b558eb36c8c10deb53 100644 (file)
@@ -210,8 +210,8 @@ int sparse_keymap_setup(struct input_dev *dev,
 
        dev->keycode = map;
        dev->keycodemax = map_size;
-       dev->getkeycode_new = sparse_keymap_getkeycode;
-       dev->setkeycode_new = sparse_keymap_setkeycode;
+       dev->getkeycode = sparse_keymap_getkeycode;
+       dev->setkeycode = sparse_keymap_setkeycode;
 
        return 0;
 
index cf8fb9f5d4a8282f9405736af668d5f8cd423a4b..449c0a46dbac51ba881ba49b8cfff1c3861dfee7 100644 (file)
@@ -193,16 +193,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        case HID_USAGE_X:
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
-                                               features->device_type = BTN_TOOL_DOUBLETAP;
+                                               features->device_type = BTN_TOOL_FINGER;
                                                if (features->type == TABLETPC2FG) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                }
                                                if (features->type == BAMBOO_PT) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_BBTOUCH;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->x_phy =
                                                                get_unaligned_le16(&report[i + 5]);
                                                        features->x_max =
@@ -241,11 +241,11 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        case HID_USAGE_Y:
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
-                                               features->device_type = BTN_TOOL_DOUBLETAP;
+                                               features->device_type = BTN_TOOL_FINGER;
                                                if (features->type == TABLETPC2FG) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->y_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_phy =
@@ -254,7 +254,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                                } else if (features->type == BAMBOO_PT) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_BBTOUCH;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_max =
index 367fa82a607e81ef8bf03d7b69c8bc231736fc65..5597637cfd41895181176f627f072ac3f0c39a77 100644 (file)
@@ -675,169 +675,87 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 1;
 }
 
-
-static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
+static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
-       int finger = idx + 1;
-       int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff;
-       int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff;
+       unsigned char *data = wacom->data;
+       int contact_with_no_pen_down_count = 0;
+       int i;
 
-       /*
-        * Work around input core suppressing "duplicate" events since
-        * we are abusing ABS_X/ABS_Y to transmit multi-finger data.
-        * This should go away once we switch to true multitouch
-        * protocol.
-        */
-       if (wacom->last_finger != finger) {
-               if (x == input_abs_get_val(input, ABS_X))
-                       x++;
+       for (i = 0; i < 2; i++) {
+               int p = data[1] & (1 << i);
+               bool touch = p && !wacom->shared->stylus_in_proximity;
+
+               input_mt_slot(input, i);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
+                       int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
 
-               if (y == input_abs_get_val(input, ABS_Y))
-                       y++;
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
+               }
        }
 
-       input_report_abs(input, ABS_X, x);
-       input_report_abs(input, ABS_Y, y);
-       input_report_abs(input, ABS_MISC, wacom->id[0]);
-       input_report_key(input, wacom->tool[finger], 1);
-       if (!idx)
-               input_report_key(input, BTN_TOUCH, 1);
-       input_event(input, EV_MSC, MSC_SERIAL, finger);
-       input_sync(input);
+       /* keep touch state for pen event */
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
-       wacom->last_finger = finger;
-}
+       input_mt_report_pointer_emulation(input, true);
 
-static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx)
-{
-       struct input_dev *input = wacom->input;
-       int finger = idx + 1;
-
-       input_report_abs(input, ABS_X, 0);
-       input_report_abs(input, ABS_Y, 0);
-       input_report_abs(input, ABS_MISC, 0);
-       input_report_key(input, wacom->tool[finger], 0);
-       if (!idx)
-               input_report_key(input, BTN_TOUCH, 0);
-       input_event(input, EV_MSC, MSC_SERIAL, finger);
-       input_sync(input);
+       return 1;
 }
 
-static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len)
+static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        char *data = wacom->data;
        struct input_dev *input = wacom->input;
+       bool prox;
+       int x = 0, y = 0;
 
-       wacom->tool[1] = BTN_TOOL_DOUBLETAP;
-       wacom->id[0] = TOUCH_DEVICE_ID;
-       wacom->tool[2] = BTN_TOOL_TRIPLETAP;
-
-       if (len != WACOM_PKGLEN_TPC1FG) {
-
-               switch (data[0]) {
+       if (!wacom->shared->stylus_in_proximity) {
+               if (len == WACOM_PKGLEN_TPC1FG) {
+                       prox = data[0] & 0x01;
+                       x = get_unaligned_le16(&data[1]);
+                       y = get_unaligned_le16(&data[3]);
+               } else { /* with capacity */
+                       prox = data[1] & 0x01;
+                       x = le16_to_cpup((__le16 *)&data[2]);
+                       y = le16_to_cpup((__le16 *)&data[4]);
+               }
+       } else
+               /* force touch out when pen is in prox */
+               prox = 0;
 
-               case WACOM_REPORT_TPC1FG:
-                       input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
-                       input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
-                       input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
-                       input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6]));
-                       input_report_abs(input, ABS_MISC, wacom->id[0]);
-                       input_report_key(input, wacom->tool[1], 1);
-                       input_sync(input);
-                       break;
+       if (prox) {
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+       }
+       input_report_key(input, BTN_TOUCH, prox);
 
-               case WACOM_REPORT_TPC2FG:
-                       if (data[1] & 0x01)
-                               wacom_tpc_finger_in(wacom, data, 0);
-                       else if (wacom->id[1] & 0x01)
-                               wacom_tpc_touch_out(wacom, 0);
+       /* keep touch state for pen events */
+       wacom->shared->touch_down = prox;
 
-                       if (data[1] & 0x02)
-                               wacom_tpc_finger_in(wacom, data, 1);
-                       else if (wacom->id[1] & 0x02)
-                               wacom_tpc_touch_out(wacom, 1);
-                       break;
-               }
-       } else {
-               input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
-               input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
-               input_report_key(input, BTN_TOUCH, 1);
-               input_report_abs(input, ABS_MISC, wacom->id[1]);
-               input_report_key(input, wacom->tool[1], 1);
-               input_sync(input);
-       }
+       return 1;
 }
 
-static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
+static int wacom_tpc_pen(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
        char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       int prox = 0, pressure;
-       int retval = 0;
+       int pressure;
+       bool prox = data[1] & 0x20;
 
-       dbg("wacom_tpc_irq: received report #%d", data[0]);
-
-       if (len == WACOM_PKGLEN_TPC1FG ||                /* single touch */
-           data[0] == WACOM_REPORT_TPC1FG ||            /* single touch */
-           data[0] == WACOM_REPORT_TPC2FG) {            /* 2FG touch */
-
-               if (wacom->shared->stylus_in_proximity) {
-                       if (wacom->id[1] & 0x01)
-                               wacom_tpc_touch_out(wacom, 0);
-
-                       if (wacom->id[1] & 0x02)
-                               wacom_tpc_touch_out(wacom, 1);
-
-                       wacom->id[1] = 0;
-                       return 0;
-               }
-
-               if (len == WACOM_PKGLEN_TPC1FG) {       /* with touch */
-                       prox = data[0] & 0x01;
-               } else {  /* with capacity */
-                       if (data[0] == WACOM_REPORT_TPC1FG)
-                               /* single touch */
-                               prox = data[1] & 0x01;
-                       else
-                               /* 2FG touch data */
-                               prox = data[1] & 0x03;
-               }
-
-               if (prox) {
-                       if (!wacom->id[1])
-                               wacom->last_finger = 1;
-                       wacom_tpc_touch_in(wacom, len);
-               } else {
-                       if (data[0] == WACOM_REPORT_TPC2FG) {
-                               /* 2FGT out-prox */
-                               if (wacom->id[1] & 0x01)
-                                       wacom_tpc_touch_out(wacom, 0);
+       if (!wacom->shared->stylus_in_proximity) /* first in prox */
+               /* Going into proximity select tool */
+               wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
 
-                               if (wacom->id[1] & 0x02)
-                                       wacom_tpc_touch_out(wacom, 1);
-                       } else
-                               /* one finger touch */
-                               wacom_tpc_touch_out(wacom, 0);
+       /* keep pen state for touch events */
+       wacom->shared->stylus_in_proximity = prox;
 
-                       wacom->id[0] = 0;
-               }
-               /* keep prox bit to send proper out-prox event */
-               wacom->id[1] = prox;
-       } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */
-               prox = data[1] & 0x20;
-
-               if (!wacom->shared->stylus_in_proximity) { /* first in prox */
-                       /* Going into proximity select tool */
-                       wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-                       if (wacom->tool[0] == BTN_TOOL_PEN)
-                               wacom->id[0] = STYLUS_DEVICE_ID;
-                       else
-                               wacom->id[0] = ERASER_DEVICE_ID;
-
-                       wacom->shared->stylus_in_proximity = true;
-               }
+       /* send pen events only when touch is up or forced out */
+       if (!wacom->shared->touch_down) {
                input_report_key(input, BTN_STYLUS, data[1] & 0x02);
                input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
@@ -847,15 +765,27 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
                        pressure = features->pressure_max + pressure + 1;
                input_report_abs(input, ABS_PRESSURE, pressure);
                input_report_key(input, BTN_TOUCH, data[1] & 0x05);
-               if (!prox) { /* out-prox */
-                       wacom->id[0] = 0;
-                       wacom->shared->stylus_in_proximity = false;
-               }
                input_report_key(input, wacom->tool[0], prox);
-               input_report_abs(input, ABS_MISC, wacom->id[0]);
-               retval = 1;
+               return 1;
        }
-       return retval;
+
+       return 0;
+}
+
+static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
+{
+       char *data = wacom->data;
+
+       dbg("wacom_tpc_irq: received report #%d", data[0]);
+
+       if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG)
+               return wacom_tpc_single_touch(wacom, len);
+       else if (data[0] == WACOM_REPORT_TPC2FG)
+               return wacom_tpc_mt_touch(wacom);
+       else if (data[0] == WACOM_REPORT_PENABLED)
+               return wacom_tpc_pen(wacom);
+
+       return 0;
 }
 
 static int wacom_bpt_touch(struct wacom_wac *wacom)
@@ -1078,7 +1008,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 {
 
        /* touch device found but size is not defined. use default */
-       if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+       if (features->device_type == BTN_TOOL_FINGER && !features->x_max) {
                features->x_max = 1023;
                features->y_max = 1023;
        }
@@ -1090,7 +1020,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 
        /* quirks for bamboo touch */
        if (features->type == BAMBOO_PT &&
-           features->device_type == BTN_TOOL_TRIPLETAP) {
+           features->device_type == BTN_TOOL_DOUBLETAP) {
                features->x_max <<= 5;
                features->y_max <<= 5;
                features->x_fuzz <<= 5;
@@ -1226,27 +1156,30 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                break;
 
        case TABLETPC2FG:
-               if (features->device_type == BTN_TOOL_TRIPLETAP) {
-                       __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-                       input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
+               if (features->device_type == BTN_TOOL_DOUBLETAP) {
+
+                       input_mt_init_slots(input_dev, 2);
+                       input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
+                                       0, MT_TOOL_MAX, 0, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                       0, features->x_max, 0, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                       0, features->y_max, 0, 0);
                }
                /* fall through */
 
        case TABLETPC:
-               if (features->device_type == BTN_TOOL_DOUBLETAP ||
-                   features->device_type == BTN_TOOL_TRIPLETAP) {
+               __clear_bit(ABS_MISC, input_dev->absbit);
+
+               if (features->device_type != BTN_TOOL_PEN) {
                        input_abs_set_res(input_dev, ABS_X,
                                wacom_calculate_touch_res(features->x_max,
                                                        features->x_phy));
                        input_abs_set_res(input_dev, ABS_Y,
                                wacom_calculate_touch_res(features->y_max,
                                                        features->y_phy));
-                       __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-               }
-
-               if (features->device_type != BTN_TOOL_PEN)
                        break;  /* no need to process stylus stuff */
-
+               }
                /* fall through */
 
        case PL:
@@ -1264,7 +1197,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case BAMBOO_PT:
                __clear_bit(ABS_MISC, input_dev->absbit);
 
-               if (features->device_type == BTN_TOOL_TRIPLETAP) {
+               if (features->device_type == BTN_TOOL_DOUBLETAP) {
                        __set_bit(BTN_LEFT, input_dev->keybit);
                        __set_bit(BTN_FORWARD, input_dev->keybit);
                        __set_bit(BTN_BACK, input_dev->keybit);
index b1310ec9720c0613ab6a219cbe421d6e6eb62241..835f756b150c193fb9b46b4cd3ae6cccefa0a851 100644 (file)
@@ -88,15 +88,15 @@ struct wacom_features {
 
 struct wacom_shared {
        bool stylus_in_proximity;
+       bool touch_down;
 };
 
 struct wacom_wac {
        char name[64];
        unsigned char *data;
-       int tool[3];
-       int id[3];
+       int tool[2];
+       int id[2];
        __u32 serial[2];
-       int last_finger;
        struct wacom_features features;
        struct wacom_shared *shared;
        struct input_dev *input;
index 61834ae282e13c72be5ea2fad3dca266debc91b3..434fd800cd24e7eb54adf896b8ec20e7f17e4dc5 100644 (file)
@@ -86,6 +86,18 @@ config TOUCHSCREEN_AD7879_SPI
          To compile this driver as a module, choose M here: the
          module will be called ad7879-spi.
 
+config TOUCHSCREEN_ATMEL_MXT
+       tristate "Atmel mXT I2C Touchscreen"
+       depends on I2C
+       help
+         Say Y here if you have Atmel mXT series I2C touchscreen,
+         such as AT42QT602240/ATMXT224, connected to your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called atmel_mxt_ts.
+
 config TOUCHSCREEN_BITSY
        tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
        depends on SA1100_BITSY
@@ -339,18 +351,6 @@ config TOUCHSCREEN_PENMOUNT
          To compile this driver as a module, choose M here: the
          module will be called penmount.
 
-config TOUCHSCREEN_QT602240
-       tristate "QT602240 I2C Touchscreen"
-       depends on I2C
-       help
-         Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
-         connected to your system.
-
-         If unsure, say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called qt602240_ts.
-
 config TOUCHSCREEN_MIGOR
        tristate "Renesas MIGO-R touchscreen"
        depends on SH_MIGOR && I2C
@@ -423,6 +423,16 @@ config TOUCHSCREEN_UCB1400
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_ts.
 
+config TOUCHSCREEN_WM831X
+       tristate "Support for WM831x touchscreen controllers"
+       depends on MFD_WM831X
+       help
+         This enables support for the touchscreen controller on the WM831x
+         series of PMICs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wm831x-ts.
+
 config TOUCHSCREEN_WM97XX
        tristate "Support for WM97xx AC97 touchscreen controllers"
        depends on AC97_BUS
@@ -629,6 +639,17 @@ config TOUCHSCREEN_TOUCHIT213
          To compile this driver as a module, choose M here: the
          module will be called touchit213.
 
+config TOUCHSCREEN_TSC2005
+        tristate "TSC2005 based touchscreens"
+        depends on SPI_MASTER && GENERIC_HARDIRQS
+        help
+          Say Y here if you have a TSC2005 based touchscreen.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2005.
+
 config TOUCHSCREEN_TSC2007
        tristate "TSC2007 based touchscreens"
        depends on I2C
index 718bcc814952cd38b82b3c2b086a05ec19ed983d..ca94098d4c92b8116815c17a9ac742e77aa622e3 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879)      += ad7879.o
 obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)   += ad7879-i2c.o
 obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)   += ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)      += ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)    += atmel_mxt_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)                += h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
@@ -37,7 +38,6 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN)      += htcpen.o
 obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)        += usbtouchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_PCAP)         += pcap_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)     += penmount.o
-obj-$(CONFIG_TOUCHSCREEN_QT602240)     += qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)       += st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
@@ -45,9 +45,11 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X)  += tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005)      += tsc2005.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2007)      += tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)  += wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WM831X)       += wm831x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
index a1952fcc083e14a68694b5f69c64359588818b2c..714d4e0f9f95f546affadbdbc677d87c27152bc0 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ad7877.h>
@@ -826,39 +827,37 @@ static int __devexit ad7877_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int ad7877_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ad7877_suspend(struct device *dev)
 {
-       struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        ad7877_disable(ts);
 
        return 0;
 }
 
-static int ad7877_resume(struct spi_device *spi)
+static int ad7877_resume(struct device *dev)
 {
-       struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        ad7877_enable(ts);
 
        return 0;
 }
-#else
-#define ad7877_suspend NULL
-#define ad7877_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
+
 static struct spi_driver ad7877_driver = {
        .driver = {
                .name   = "ad7877",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ad7877_pm,
        },
        .probe          = ad7877_probe,
        .remove         = __devexit_p(ad7877_remove),
-       .suspend        = ad7877_suspend,
-       .resume         = ad7877_resume,
 };
 
 static int __init ad7877_init(void)
index 59c6e68c432507a61392993b572541dc2c8693a4..ddf732f3cafcd3021c889f435d2d1c662f627663 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/input.h>       /* BUS_SPI */
+#include <linux/pm.h>
 #include <linux/spi/spi.h>
 
 #include "ad7879.h"
 #define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
 #define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
 
-#ifdef CONFIG_PM
-static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ad7879_spi_suspend(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct ad7879 *ts = spi_get_drvdata(spi);
 
        ad7879_suspend(ts);
@@ -30,19 +32,19 @@ static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int ad7879_spi_resume(struct spi_device *spi)
+static int ad7879_spi_resume(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct ad7879 *ts = spi_get_drvdata(spi);
 
        ad7879_resume(ts);
 
        return 0;
 }
-#else
-# define ad7879_spi_suspend NULL
-# define ad7879_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume);
+
 /*
  * ad7879_read/write are only used for initial setup and for sysfs controls.
  * The main traffic is done in ad7879_collect().
@@ -173,11 +175,10 @@ static struct spi_driver ad7879_spi_driver = {
                .name   = "ad7879",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ad7879_spi_pm,
        },
        .probe          = ad7879_spi_probe,
        .remove         = __devexit_p(ad7879_spi_remove),
-       .suspend        = ad7879_spi_suspend,
-       .resume         = ad7879_spi_resume,
 };
 
 static int __init ad7879_spi_init(void)
index 4bf2316e3284b8db426e6e11d2dfda72166b1278..c24946f512564e35925d0e6c090b7fd4a6c4eccd 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -892,9 +893,10 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
        return IRQ_HANDLED;
 }
 
-static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ads7846_suspend(struct device *dev)
 {
-       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
 
        mutex_lock(&ts->lock);
 
@@ -914,9 +916,9 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int ads7846_resume(struct spi_device *spi)
+static int ads7846_resume(struct device *dev)
 {
-       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
 
        mutex_lock(&ts->lock);
 
@@ -935,6 +937,9 @@ static int ads7846_resume(struct spi_device *spi)
 
        return 0;
 }
+#endif
+
+static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
 
 static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
 {
@@ -1408,11 +1413,10 @@ static struct spi_driver ads7846_driver = {
                .name   = "ads7846",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ads7846_pm,
        },
        .probe          = ads7846_probe,
        .remove         = __devexit_p(ads7846_remove),
-       .suspend        = ads7846_suspend,
-       .resume         = ads7846_resume,
 };
 
 static int __init ads7846_init(void)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
new file mode 100644 (file)
index 0000000..4012436
--- /dev/null
@@ -0,0 +1,1211 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Version */
+#define MXT_VER_20             20
+#define MXT_VER_21             21
+#define MXT_VER_22             22
+
+/* Slave addresses */
+#define MXT_APP_LOW            0x4a
+#define MXT_APP_HIGH           0x4b
+#define MXT_BOOT_LOW           0x24
+#define MXT_BOOT_HIGH          0x25
+
+/* Firmware */
+#define MXT_FW_NAME            "maxtouch.fw"
+
+/* Registers */
+#define MXT_FAMILY_ID          0x00
+#define MXT_VARIANT_ID         0x01
+#define MXT_VERSION            0x02
+#define MXT_BUILD              0x03
+#define MXT_MATRIX_X_SIZE      0x04
+#define MXT_MATRIX_Y_SIZE      0x05
+#define MXT_OBJECT_NUM         0x06
+#define MXT_OBJECT_START       0x07
+
+#define MXT_OBJECT_SIZE                6
+
+/* Object types */
+#define MXT_DEBUG_DIAGNOSTIC   37
+#define MXT_GEN_MESSAGE                5
+#define MXT_GEN_COMMAND                6
+#define MXT_GEN_POWER          7
+#define MXT_GEN_ACQUIRE                8
+#define MXT_TOUCH_MULTI                9
+#define MXT_TOUCH_KEYARRAY     15
+#define MXT_TOUCH_PROXIMITY    23
+#define MXT_PROCI_GRIPFACE     20
+#define MXT_PROCG_NOISE                22
+#define MXT_PROCI_ONETOUCH     24
+#define MXT_PROCI_TWOTOUCH     27
+#define MXT_PROCI_GRIP         40
+#define MXT_PROCI_PALM         41
+#define MXT_SPT_COMMSCONFIG    18
+#define MXT_SPT_GPIOPWM                19
+#define MXT_SPT_SELFTEST       25
+#define MXT_SPT_CTECONFIG      28
+#define MXT_SPT_USERDATA       38
+#define MXT_SPT_DIGITIZER      43
+#define MXT_SPT_MESSAGECOUNT   44
+
+/* MXT_GEN_COMMAND field */
+#define MXT_COMMAND_RESET      0
+#define MXT_COMMAND_BACKUPNV   1
+#define MXT_COMMAND_CALIBRATE  2
+#define MXT_COMMAND_REPORTALL  3
+#define MXT_COMMAND_DIAGNOSTIC 5
+
+/* MXT_GEN_POWER field */
+#define MXT_POWER_IDLEACQINT   0
+#define MXT_POWER_ACTVACQINT   1
+#define MXT_POWER_ACTV2IDLETO  2
+
+/* MXT_GEN_ACQUIRE field */
+#define MXT_ACQUIRE_CHRGTIME   0
+#define MXT_ACQUIRE_TCHDRIFT   2
+#define MXT_ACQUIRE_DRIFTST    3
+#define MXT_ACQUIRE_TCHAUTOCAL 4
+#define MXT_ACQUIRE_SYNC       5
+#define MXT_ACQUIRE_ATCHCALST  6
+#define MXT_ACQUIRE_ATCHCALSTHR        7
+
+/* MXT_TOUCH_MULTI field */
+#define MXT_TOUCH_CTRL         0
+#define MXT_TOUCH_XORIGIN      1
+#define MXT_TOUCH_YORIGIN      2
+#define MXT_TOUCH_XSIZE                3
+#define MXT_TOUCH_YSIZE                4
+#define MXT_TOUCH_BLEN         6
+#define MXT_TOUCH_TCHTHR       7
+#define MXT_TOUCH_TCHDI                8
+#define MXT_TOUCH_ORIENT       9
+#define MXT_TOUCH_MOVHYSTI     11
+#define MXT_TOUCH_MOVHYSTN     12
+#define MXT_TOUCH_NUMTOUCH     14
+#define MXT_TOUCH_MRGHYST      15
+#define MXT_TOUCH_MRGTHR       16
+#define MXT_TOUCH_AMPHYST      17
+#define MXT_TOUCH_XRANGE_LSB   18
+#define MXT_TOUCH_XRANGE_MSB   19
+#define MXT_TOUCH_YRANGE_LSB   20
+#define MXT_TOUCH_YRANGE_MSB   21
+#define MXT_TOUCH_XLOCLIP      22
+#define MXT_TOUCH_XHICLIP      23
+#define MXT_TOUCH_YLOCLIP      24
+#define MXT_TOUCH_YHICLIP      25
+#define MXT_TOUCH_XEDGECTRL    26
+#define MXT_TOUCH_XEDGEDIST    27
+#define MXT_TOUCH_YEDGECTRL    28
+#define MXT_TOUCH_YEDGEDIST    29
+#define MXT_TOUCH_JUMPLIMIT    30
+
+/* MXT_PROCI_GRIPFACE field */
+#define MXT_GRIPFACE_CTRL      0
+#define MXT_GRIPFACE_XLOGRIP   1
+#define MXT_GRIPFACE_XHIGRIP   2
+#define MXT_GRIPFACE_YLOGRIP   3
+#define MXT_GRIPFACE_YHIGRIP   4
+#define MXT_GRIPFACE_MAXTCHS   5
+#define MXT_GRIPFACE_SZTHR1    7
+#define MXT_GRIPFACE_SZTHR2    8
+#define MXT_GRIPFACE_SHPTHR1   9
+#define MXT_GRIPFACE_SHPTHR2   10
+#define MXT_GRIPFACE_SUPEXTTO  11
+
+/* MXT_PROCI_NOISE field */
+#define MXT_NOISE_CTRL         0
+#define MXT_NOISE_OUTFLEN      1
+#define MXT_NOISE_GCAFUL_LSB   3
+#define MXT_NOISE_GCAFUL_MSB   4
+#define MXT_NOISE_GCAFLL_LSB   5
+#define MXT_NOISE_GCAFLL_MSB   6
+#define MXT_NOISE_ACTVGCAFVALID        7
+#define MXT_NOISE_NOISETHR     8
+#define MXT_NOISE_FREQHOPSCALE 10
+#define MXT_NOISE_FREQ0                11
+#define MXT_NOISE_FREQ1                12
+#define MXT_NOISE_FREQ2                13
+#define MXT_NOISE_FREQ3                14
+#define MXT_NOISE_FREQ4                15
+#define MXT_NOISE_IDLEGCAFVALID        16
+
+/* MXT_SPT_COMMSCONFIG */
+#define MXT_COMMS_CTRL         0
+#define MXT_COMMS_CMD          1
+
+/* MXT_SPT_CTECONFIG field */
+#define MXT_CTE_CTRL           0
+#define MXT_CTE_CMD            1
+#define MXT_CTE_MODE           2
+#define MXT_CTE_IDLEGCAFDEPTH  3
+#define MXT_CTE_ACTVGCAFDEPTH  4
+#define MXT_CTE_VOLTAGE                5
+
+#define MXT_VOLTAGE_DEFAULT    2700000
+#define MXT_VOLTAGE_STEP       10000
+
+/* Define for MXT_GEN_COMMAND */
+#define MXT_BOOT_VALUE         0xa5
+#define MXT_BACKUP_VALUE       0x55
+#define MXT_BACKUP_TIME                25      /* msec */
+#define MXT_RESET_TIME         65      /* msec */
+
+#define MXT_FWRESET_TIME       175     /* msec */
+
+/* Command to unlock bootloader */
+#define MXT_UNLOCK_CMD_MSB     0xaa
+#define MXT_UNLOCK_CMD_LSB     0xdc
+
+/* Bootloader mode status */
+#define MXT_WAITING_BOOTLOAD_CMD       0xc0    /* valid 7 6 bit only */
+#define MXT_WAITING_FRAME_DATA 0x80    /* valid 7 6 bit only */
+#define MXT_FRAME_CRC_CHECK    0x02
+#define MXT_FRAME_CRC_FAIL     0x03
+#define MXT_FRAME_CRC_PASS     0x04
+#define MXT_APP_CRC_FAIL       0x40    /* valid 7 8 bit only */
+#define MXT_BOOT_STATUS_MASK   0x3f
+
+/* Touch status */
+#define MXT_SUPPRESS           (1 << 1)
+#define MXT_AMP                        (1 << 2)
+#define MXT_VECTOR             (1 << 3)
+#define MXT_MOVE               (1 << 4)
+#define MXT_RELEASE            (1 << 5)
+#define MXT_PRESS              (1 << 6)
+#define MXT_DETECT             (1 << 7)
+
+/* Touchscreen absolute values */
+#define MXT_MAX_XC             0x3ff
+#define MXT_MAX_YC             0x3ff
+#define MXT_MAX_AREA           0xff
+
+#define MXT_MAX_FINGER         10
+
+struct mxt_info {
+       u8 family_id;
+       u8 variant_id;
+       u8 version;
+       u8 build;
+       u8 matrix_xsize;
+       u8 matrix_ysize;
+       u8 object_num;
+};
+
+struct mxt_object {
+       u8 type;
+       u16 start_address;
+       u8 size;
+       u8 instances;
+       u8 num_report_ids;
+
+       /* to map object and message */
+       u8 max_reportid;
+};
+
+struct mxt_message {
+       u8 reportid;
+       u8 message[7];
+       u8 checksum;
+};
+
+struct mxt_finger {
+       int status;
+       int x;
+       int y;
+       int area;
+};
+
+/* Each client has this additional data */
+struct mxt_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       const struct mxt_platform_data *pdata;
+       struct mxt_object *object_table;
+       struct mxt_info info;
+       struct mxt_finger finger[MXT_MAX_FINGER];
+       unsigned int irq;
+};
+
+static bool mxt_object_readable(unsigned int type)
+{
+       switch (type) {
+       case MXT_GEN_MESSAGE:
+       case MXT_GEN_COMMAND:
+       case MXT_GEN_POWER:
+       case MXT_GEN_ACQUIRE:
+       case MXT_TOUCH_MULTI:
+       case MXT_TOUCH_KEYARRAY:
+       case MXT_TOUCH_PROXIMITY:
+       case MXT_PROCI_GRIPFACE:
+       case MXT_PROCG_NOISE:
+       case MXT_PROCI_ONETOUCH:
+       case MXT_PROCI_TWOTOUCH:
+       case MXT_PROCI_GRIP:
+       case MXT_PROCI_PALM:
+       case MXT_SPT_COMMSCONFIG:
+       case MXT_SPT_GPIOPWM:
+       case MXT_SPT_SELFTEST:
+       case MXT_SPT_CTECONFIG:
+       case MXT_SPT_USERDATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool mxt_object_writable(unsigned int type)
+{
+       switch (type) {
+       case MXT_GEN_COMMAND:
+       case MXT_GEN_POWER:
+       case MXT_GEN_ACQUIRE:
+       case MXT_TOUCH_MULTI:
+       case MXT_TOUCH_KEYARRAY:
+       case MXT_TOUCH_PROXIMITY:
+       case MXT_PROCI_GRIPFACE:
+       case MXT_PROCG_NOISE:
+       case MXT_PROCI_ONETOUCH:
+       case MXT_PROCI_TWOTOUCH:
+       case MXT_PROCI_GRIP:
+       case MXT_PROCI_PALM:
+       case MXT_SPT_GPIOPWM:
+       case MXT_SPT_SELFTEST:
+       case MXT_SPT_CTECONFIG:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static void mxt_dump_message(struct device *dev,
+                                 struct mxt_message *message)
+{
+       dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
+       dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
+       dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
+       dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
+       dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
+       dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
+       dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
+       dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
+       dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+}
+
+static int mxt_check_bootloader(struct i2c_client *client,
+                                    unsigned int state)
+{
+       u8 val;
+
+recheck:
+       if (i2c_master_recv(client, &val, 1) != 1) {
+               dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+               return -EIO;
+       }
+
+       switch (state) {
+       case MXT_WAITING_BOOTLOAD_CMD:
+       case MXT_WAITING_FRAME_DATA:
+               val &= ~MXT_BOOT_STATUS_MASK;
+               break;
+       case MXT_FRAME_CRC_PASS:
+               if (val == MXT_FRAME_CRC_CHECK)
+                       goto recheck;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (val != state) {
+               dev_err(&client->dev, "Unvalid bootloader mode state\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mxt_unlock_bootloader(struct i2c_client *client)
+{
+       u8 buf[2];
+
+       buf[0] = MXT_UNLOCK_CMD_LSB;
+       buf[1] = MXT_UNLOCK_CMD_MSB;
+
+       if (i2c_master_send(client, buf, 2) != 2) {
+               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int mxt_fw_write(struct i2c_client *client,
+                            const u8 *data, unsigned int frame_size)
+{
+       if (i2c_master_send(client, data, frame_size) != frame_size) {
+               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int __mxt_read_reg(struct i2c_client *client,
+                              u16 reg, u16 len, void *val)
+{
+       struct i2c_msg xfer[2];
+       u8 buf[2];
+
+       buf[0] = reg & 0xff;
+       buf[1] = (reg >> 8) & 0xff;
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 2;
+       xfer[0].buf = buf;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = len;
+       xfer[1].buf = val;
+
+       if (i2c_transfer(client->adapter, xfer, 2) != 2) {
+               dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
+{
+       return __mxt_read_reg(client, reg, 1, val);
+}
+
+static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+       u8 buf[3];
+
+       buf[0] = reg & 0xff;
+       buf[1] = (reg >> 8) & 0xff;
+       buf[2] = val;
+
+       if (i2c_master_send(client, buf, 3) != 3) {
+               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int mxt_read_object_table(struct i2c_client *client,
+                                     u16 reg, u8 *object_buf)
+{
+       return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE,
+                                  object_buf);
+}
+
+static struct mxt_object *
+mxt_get_object(struct mxt_data *data, u8 type)
+{
+       struct mxt_object *object;
+       int i;
+
+       for (i = 0; i < data->info.object_num; i++) {
+               object = data->object_table + i;
+               if (object->type == type)
+                       return object;
+       }
+
+       dev_err(&data->client->dev, "Invalid object type\n");
+       return NULL;
+}
+
+static int mxt_read_message(struct mxt_data *data,
+                                struct mxt_message *message)
+{
+       struct mxt_object *object;
+       u16 reg;
+
+       object = mxt_get_object(data, MXT_GEN_MESSAGE);
+       if (!object)
+               return -EINVAL;
+
+       reg = object->start_address;
+       return __mxt_read_reg(data->client, reg,
+                       sizeof(struct mxt_message), message);
+}
+
+static int mxt_read_object(struct mxt_data *data,
+                               u8 type, u8 offset, u8 *val)
+{
+       struct mxt_object *object;
+       u16 reg;
+
+       object = mxt_get_object(data, type);
+       if (!object)
+               return -EINVAL;
+
+       reg = object->start_address;
+       return __mxt_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int mxt_write_object(struct mxt_data *data,
+                                u8 type, u8 offset, u8 val)
+{
+       struct mxt_object *object;
+       u16 reg;
+
+       object = mxt_get_object(data, type);
+       if (!object)
+               return -EINVAL;
+
+       reg = object->start_address;
+       return mxt_write_reg(data->client, reg + offset, val);
+}
+
+static void mxt_input_report(struct mxt_data *data, int single_id)
+{
+       struct mxt_finger *finger = data->finger;
+       struct input_dev *input_dev = data->input_dev;
+       int status = finger[single_id].status;
+       int finger_num = 0;
+       int id;
+
+       for (id = 0; id < MXT_MAX_FINGER; id++) {
+               if (!finger[id].status)
+                       continue;
+
+               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+                               finger[id].status != MXT_RELEASE ?
+                               finger[id].area : 0);
+               input_report_abs(input_dev, ABS_MT_POSITION_X,
+                               finger[id].x);
+               input_report_abs(input_dev, ABS_MT_POSITION_Y,
+                               finger[id].y);
+               input_mt_sync(input_dev);
+
+               if (finger[id].status == MXT_RELEASE)
+                       finger[id].status = 0;
+               else
+                       finger_num++;
+       }
+
+       input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
+
+       if (status != MXT_RELEASE) {
+               input_report_abs(input_dev, ABS_X, finger[single_id].x);
+               input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+       }
+
+       input_sync(input_dev);
+}
+
+static void mxt_input_touchevent(struct mxt_data *data,
+                                     struct mxt_message *message, int id)
+{
+       struct mxt_finger *finger = data->finger;
+       struct device *dev = &data->client->dev;
+       u8 status = message->message[0];
+       int x;
+       int y;
+       int area;
+
+       /* Check the touch is present on the screen */
+       if (!(status & MXT_DETECT)) {
+               if (status & MXT_RELEASE) {
+                       dev_dbg(dev, "[%d] released\n", id);
+
+                       finger[id].status = MXT_RELEASE;
+                       mxt_input_report(data, id);
+               }
+               return;
+       }
+
+       /* Check only AMP detection */
+       if (!(status & (MXT_PRESS | MXT_MOVE)))
+               return;
+
+       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
+       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+       area = message->message[4];
+
+       dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
+               status & MXT_MOVE ? "moved" : "pressed",
+               x, y, area);
+
+       finger[id].status = status & MXT_MOVE ?
+                               MXT_MOVE : MXT_PRESS;
+       finger[id].x = x;
+       finger[id].y = y;
+       finger[id].area = area;
+
+       mxt_input_report(data, id);
+}
+
+static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+{
+       struct mxt_data *data = dev_id;
+       struct mxt_message message;
+       struct mxt_object *object;
+       struct device *dev = &data->client->dev;
+       int id;
+       u8 reportid;
+       u8 max_reportid;
+       u8 min_reportid;
+
+       do {
+               if (mxt_read_message(data, &message)) {
+                       dev_err(dev, "Failed to read message\n");
+                       goto end;
+               }
+
+               reportid = message.reportid;
+
+               /* whether reportid is thing of MXT_TOUCH_MULTI */
+               object = mxt_get_object(data, MXT_TOUCH_MULTI);
+               if (!object)
+                       goto end;
+
+               max_reportid = object->max_reportid;
+               min_reportid = max_reportid - object->num_report_ids + 1;
+               id = reportid - min_reportid;
+
+               if (reportid >= min_reportid && reportid <= max_reportid)
+                       mxt_input_touchevent(data, &message, id);
+               else
+                       mxt_dump_message(dev, &message);
+       } while (reportid != 0xff);
+
+end:
+       return IRQ_HANDLED;
+}
+
+static int mxt_check_reg_init(struct mxt_data *data)
+{
+       const struct mxt_platform_data *pdata = data->pdata;
+       struct mxt_object *object;
+       struct device *dev = &data->client->dev;
+       int index = 0;
+       int i, j, config_offset;
+
+       if (!pdata->config) {
+               dev_dbg(dev, "No cfg data defined, skipping reg init\n");
+               return 0;
+       }
+
+       for (i = 0; i < data->info.object_num; i++) {
+               object = data->object_table + i;
+
+               if (!mxt_object_writable(object->type))
+                       continue;
+
+               for (j = 0; j < object->size + 1; j++) {
+                       config_offset = index + j;
+                       if (config_offset > pdata->config_length) {
+                               dev_err(dev, "Not enough config data!\n");
+                               return -EINVAL;
+                       }
+                       mxt_write_object(data, object->type, j,
+                                        pdata->config[config_offset]);
+               }
+               index += object->size + 1;
+       }
+
+       return 0;
+}
+
+static int mxt_make_highchg(struct mxt_data *data)
+{
+       struct device *dev = &data->client->dev;
+       struct mxt_message message;
+       int count = 10;
+       int error;
+
+       /* Read dummy message to make high CHG pin */
+       do {
+               error = mxt_read_message(data, &message);
+               if (error)
+                       return error;
+       } while (message.reportid != 0xff && --count);
+
+       if (!count) {
+               dev_err(dev, "CHG pin isn't cleared\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void mxt_handle_pdata(struct mxt_data *data)
+{
+       const struct mxt_platform_data *pdata = data->pdata;
+       u8 voltage;
+
+       /* Set touchscreen lines */
+       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE,
+                       pdata->x_line);
+       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE,
+                       pdata->y_line);
+
+       /* Set touchscreen orient */
+       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT,
+                       pdata->orient);
+
+       /* Set touchscreen burst length */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_BLEN, pdata->blen);
+
+       /* Set touchscreen threshold */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_TCHTHR, pdata->threshold);
+
+       /* Set touchscreen resolution */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
+
+       /* Set touchscreen voltage */
+       if (pdata->voltage) {
+               if (pdata->voltage < MXT_VOLTAGE_DEFAULT) {
+                       voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) /
+                               MXT_VOLTAGE_STEP;
+                       voltage = 0xff - voltage + 1;
+               } else
+                       voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
+                               MXT_VOLTAGE_STEP;
+
+               mxt_write_object(data, MXT_SPT_CTECONFIG,
+                               MXT_CTE_VOLTAGE, voltage);
+       }
+}
+
+static int mxt_get_info(struct mxt_data *data)
+{
+       struct i2c_client *client = data->client;
+       struct mxt_info *info = &data->info;
+       int error;
+       u8 val;
+
+       error = mxt_read_reg(client, MXT_FAMILY_ID, &val);
+       if (error)
+               return error;
+       info->family_id = val;
+
+       error = mxt_read_reg(client, MXT_VARIANT_ID, &val);
+       if (error)
+               return error;
+       info->variant_id = val;
+
+       error = mxt_read_reg(client, MXT_VERSION, &val);
+       if (error)
+               return error;
+       info->version = val;
+
+       error = mxt_read_reg(client, MXT_BUILD, &val);
+       if (error)
+               return error;
+       info->build = val;
+
+       error = mxt_read_reg(client, MXT_OBJECT_NUM, &val);
+       if (error)
+               return error;
+       info->object_num = val;
+
+       return 0;
+}
+
+static int mxt_get_object_table(struct mxt_data *data)
+{
+       int error;
+       int i;
+       u16 reg;
+       u8 reportid = 0;
+       u8 buf[MXT_OBJECT_SIZE];
+
+       for (i = 0; i < data->info.object_num; i++) {
+               struct mxt_object *object = data->object_table + i;
+
+               reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i;
+               error = mxt_read_object_table(data->client, reg, buf);
+               if (error)
+                       return error;
+
+               object->type = buf[0];
+               object->start_address = (buf[2] << 8) | buf[1];
+               object->size = buf[3];
+               object->instances = buf[4];
+               object->num_report_ids = buf[5];
+
+               if (object->num_report_ids) {
+                       reportid += object->num_report_ids *
+                                       (object->instances + 1);
+                       object->max_reportid = reportid;
+               }
+       }
+
+       return 0;
+}
+
+static int mxt_initialize(struct mxt_data *data)
+{
+       struct i2c_client *client = data->client;
+       struct mxt_info *info = &data->info;
+       int error;
+       u8 val;
+
+       error = mxt_get_info(data);
+       if (error)
+               return error;
+
+       data->object_table = kcalloc(info->object_num,
+                                    sizeof(struct mxt_object),
+                                    GFP_KERNEL);
+       if (!data->object_table) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       /* Get object table information */
+       error = mxt_get_object_table(data);
+       if (error)
+               return error;
+
+       /* Check register init values */
+       error = mxt_check_reg_init(data);
+       if (error)
+               return error;
+
+       error = mxt_make_highchg(data);
+       if (error)
+               return error;
+
+       mxt_handle_pdata(data);
+
+       /* Backup to memory */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       MXT_COMMAND_BACKUPNV,
+                       MXT_BACKUP_VALUE);
+       msleep(MXT_BACKUP_TIME);
+
+       /* Soft reset */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       MXT_COMMAND_RESET, 1);
+       msleep(MXT_RESET_TIME);
+
+       /* Update matrix size at info struct */
+       error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
+       if (error)
+               return error;
+       info->matrix_xsize = val;
+
+       error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
+       if (error)
+               return error;
+       info->matrix_ysize = val;
+
+       dev_info(&client->dev,
+                       "Family ID: %d Variant ID: %d Version: %d Build: %d\n",
+                       info->family_id, info->variant_id, info->version,
+                       info->build);
+
+       dev_info(&client->dev,
+                       "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
+                       info->matrix_xsize, info->matrix_ysize,
+                       info->object_num);
+
+       return 0;
+}
+
+static ssize_t mxt_object_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct mxt_data *data = dev_get_drvdata(dev);
+       struct mxt_object *object;
+       int count = 0;
+       int i, j;
+       int error;
+       u8 val;
+
+       for (i = 0; i < data->info.object_num; i++) {
+               object = data->object_table + i;
+
+               count += sprintf(buf + count,
+                               "Object Table Element %d(Type %d)\n",
+                               i + 1, object->type);
+
+               if (!mxt_object_readable(object->type)) {
+                       count += sprintf(buf + count, "\n");
+                       continue;
+               }
+
+               for (j = 0; j < object->size + 1; j++) {
+                       error = mxt_read_object(data,
+                                               object->type, j, &val);
+                       if (error)
+                               return error;
+
+                       count += sprintf(buf + count,
+                                       "  Byte %d: 0x%x (%d)\n", j, val, val);
+               }
+
+               count += sprintf(buf + count, "\n");
+       }
+
+       return count;
+}
+
+static int mxt_load_fw(struct device *dev, const char *fn)
+{
+       struct mxt_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+       const struct firmware *fw = NULL;
+       unsigned int frame_size;
+       unsigned int pos = 0;
+       int ret;
+
+       ret = request_firmware(&fw, fn, dev);
+       if (ret) {
+               dev_err(dev, "Unable to open firmware %s\n", fn);
+               return ret;
+       }
+
+       /* Change to the bootloader mode */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+       msleep(MXT_RESET_TIME);
+
+       /* Change to slave address of bootloader */
+       if (client->addr == MXT_APP_LOW)
+               client->addr = MXT_BOOT_LOW;
+       else
+               client->addr = MXT_BOOT_HIGH;
+
+       ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
+       if (ret)
+               goto out;
+
+       /* Unlock bootloader */
+       mxt_unlock_bootloader(client);
+
+       while (pos < fw->size) {
+               ret = mxt_check_bootloader(client,
+                                               MXT_WAITING_FRAME_DATA);
+               if (ret)
+                       goto out;
+
+               frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+
+               /* We should add 2 at frame size as the the firmware data is not
+                * included the CRC bytes.
+                */
+               frame_size += 2;
+
+               /* Write one frame to device */
+               mxt_fw_write(client, fw->data + pos, frame_size);
+
+               ret = mxt_check_bootloader(client,
+                                               MXT_FRAME_CRC_PASS);
+               if (ret)
+                       goto out;
+
+               pos += frame_size;
+
+               dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+       }
+
+out:
+       release_firmware(fw);
+
+       /* Change to slave address of application */
+       if (client->addr == MXT_BOOT_LOW)
+               client->addr = MXT_APP_LOW;
+       else
+               client->addr = MXT_APP_HIGH;
+
+       return ret;
+}
+
+static ssize_t mxt_update_fw_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct mxt_data *data = dev_get_drvdata(dev);
+       int error;
+
+       disable_irq(data->irq);
+
+       error = mxt_load_fw(dev, MXT_FW_NAME);
+       if (error) {
+               dev_err(dev, "The firmware update failed(%d)\n", error);
+               count = error;
+       } else {
+               dev_dbg(dev, "The firmware update succeeded\n");
+
+               /* Wait for reset */
+               msleep(MXT_FWRESET_TIME);
+
+               kfree(data->object_table);
+               data->object_table = NULL;
+
+               mxt_initialize(data);
+       }
+
+       enable_irq(data->irq);
+
+       return count;
+}
+
+static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
+
+static struct attribute *mxt_attrs[] = {
+       &dev_attr_object.attr,
+       &dev_attr_update_fw.attr,
+       NULL
+};
+
+static const struct attribute_group mxt_attr_group = {
+       .attrs = mxt_attrs,
+};
+
+static void mxt_start(struct mxt_data *data)
+{
+       /* Touch enable */
+       mxt_write_object(data,
+                       MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83);
+}
+
+static void mxt_stop(struct mxt_data *data)
+{
+       /* Touch disable */
+       mxt_write_object(data,
+                       MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
+}
+
+static int mxt_input_open(struct input_dev *dev)
+{
+       struct mxt_data *data = input_get_drvdata(dev);
+
+       mxt_start(data);
+
+       return 0;
+}
+
+static void mxt_input_close(struct input_dev *dev)
+{
+       struct mxt_data *data = input_get_drvdata(dev);
+
+       mxt_stop(data);
+}
+
+static int __devinit mxt_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       const struct mxt_platform_data *pdata = client->dev.platform_data;
+       struct mxt_data *data;
+       struct input_dev *input_dev;
+       int error;
+
+       if (!pdata)
+               return -EINVAL;
+
+       data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       input_dev->name = "Atmel maXTouch Touchscreen";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+       input_dev->open = mxt_input_open;
+       input_dev->close = mxt_input_close;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+
+       /* For single touch */
+       input_set_abs_params(input_dev, ABS_X,
+                            0, MXT_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                            0, MXT_MAX_YC, 0, 0);
+
+       /* For multi touch */
+       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+                            0, MXT_MAX_AREA, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                            0, MXT_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                            0, MXT_MAX_YC, 0, 0);
+
+       input_set_drvdata(input_dev, data);
+
+       data->client = client;
+       data->input_dev = input_dev;
+       data->pdata = pdata;
+       data->irq = client->irq;
+
+       i2c_set_clientdata(client, data);
+
+       error = mxt_initialize(data);
+       if (error)
+               goto err_free_object;
+
+       error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
+                       pdata->irqflags, client->dev.driver->name, data);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_object;
+       }
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_free_irq;
+
+       error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
+       if (error)
+               goto err_unregister_device;
+
+       return 0;
+
+err_unregister_device:
+       input_unregister_device(input_dev);
+       input_dev = NULL;
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_object:
+       kfree(data->object_table);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return error;
+}
+
+static int __devexit mxt_remove(struct i2c_client *client)
+{
+       struct mxt_data *data = i2c_get_clientdata(client);
+
+       sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+       free_irq(data->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data->object_table);
+       kfree(data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxt_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mxt_data *data = i2c_get_clientdata(client);
+       struct input_dev *input_dev = data->input_dev;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               mxt_stop(data);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static int mxt_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mxt_data *data = i2c_get_clientdata(client);
+       struct input_dev *input_dev = data->input_dev;
+
+       /* Soft reset */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       MXT_COMMAND_RESET, 1);
+
+       msleep(MXT_RESET_TIME);
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               mxt_start(data);
+
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static const struct dev_pm_ops mxt_pm_ops = {
+       .suspend        = mxt_suspend,
+       .resume         = mxt_resume,
+};
+#endif
+
+static const struct i2c_device_id mxt_id[] = {
+       { "qt602240_ts", 0 },
+       { "atmel_mxt_ts", 0 },
+       { "mXT224", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mxt_id);
+
+static struct i2c_driver mxt_driver = {
+       .driver = {
+               .name   = "atmel_mxt_ts",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &mxt_pm_ops,
+#endif
+       },
+       .probe          = mxt_probe,
+       .remove         = __devexit_p(mxt_remove),
+       .id_table       = mxt_id,
+};
+
+static int __init mxt_init(void)
+{
+       return i2c_add_driver(&mxt_driver);
+}
+
+static void __exit mxt_exit(void)
+{
+       i2c_del_driver(&mxt_driver);
+}
+
+module_init(mxt_init);
+module_exit(mxt_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
deleted file mode 100644 (file)
index 4dcb0e8..0000000
+++ /dev/null
@@ -1,1406 +0,0 @@
-/*
- * AT42QT602240/ATMXT224 Touchscreen driver
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.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/init.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/i2c/qt602240_ts.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-/* Version */
-#define QT602240_VER_20                        20
-#define QT602240_VER_21                        21
-#define QT602240_VER_22                        22
-
-/* Slave addresses */
-#define QT602240_APP_LOW               0x4a
-#define QT602240_APP_HIGH              0x4b
-#define QT602240_BOOT_LOW              0x24
-#define QT602240_BOOT_HIGH             0x25
-
-/* Firmware */
-#define QT602240_FW_NAME               "qt602240.fw"
-
-/* Registers */
-#define QT602240_FAMILY_ID             0x00
-#define QT602240_VARIANT_ID            0x01
-#define QT602240_VERSION               0x02
-#define QT602240_BUILD                 0x03
-#define QT602240_MATRIX_X_SIZE         0x04
-#define QT602240_MATRIX_Y_SIZE         0x05
-#define QT602240_OBJECT_NUM            0x06
-#define QT602240_OBJECT_START          0x07
-
-#define QT602240_OBJECT_SIZE           6
-
-/* Object types */
-#define QT602240_DEBUG_DIAGNOSTIC      37
-#define QT602240_GEN_MESSAGE           5
-#define QT602240_GEN_COMMAND           6
-#define QT602240_GEN_POWER             7
-#define QT602240_GEN_ACQUIRE           8
-#define QT602240_TOUCH_MULTI           9
-#define QT602240_TOUCH_KEYARRAY                15
-#define QT602240_TOUCH_PROXIMITY       23
-#define QT602240_PROCI_GRIPFACE                20
-#define QT602240_PROCG_NOISE           22
-#define QT602240_PROCI_ONETOUCH                24
-#define QT602240_PROCI_TWOTOUCH                27
-#define QT602240_SPT_COMMSCONFIG       18      /* firmware ver 21 over */
-#define QT602240_SPT_GPIOPWM           19
-#define QT602240_SPT_SELFTEST          25
-#define QT602240_SPT_CTECONFIG         28
-#define QT602240_SPT_USERDATA          38      /* firmware ver 21 over */
-
-/* QT602240_GEN_COMMAND field */
-#define QT602240_COMMAND_RESET         0
-#define QT602240_COMMAND_BACKUPNV      1
-#define QT602240_COMMAND_CALIBRATE     2
-#define QT602240_COMMAND_REPORTALL     3
-#define QT602240_COMMAND_DIAGNOSTIC    5
-
-/* QT602240_GEN_POWER field */
-#define QT602240_POWER_IDLEACQINT      0
-#define QT602240_POWER_ACTVACQINT      1
-#define QT602240_POWER_ACTV2IDLETO     2
-
-/* QT602240_GEN_ACQUIRE field */
-#define QT602240_ACQUIRE_CHRGTIME      0
-#define QT602240_ACQUIRE_TCHDRIFT      2
-#define QT602240_ACQUIRE_DRIFTST       3
-#define QT602240_ACQUIRE_TCHAUTOCAL    4
-#define QT602240_ACQUIRE_SYNC          5
-#define QT602240_ACQUIRE_ATCHCALST     6
-#define QT602240_ACQUIRE_ATCHCALSTHR   7
-
-/* QT602240_TOUCH_MULTI field */
-#define QT602240_TOUCH_CTRL            0
-#define QT602240_TOUCH_XORIGIN         1
-#define QT602240_TOUCH_YORIGIN         2
-#define QT602240_TOUCH_XSIZE           3
-#define QT602240_TOUCH_YSIZE           4
-#define QT602240_TOUCH_BLEN            6
-#define QT602240_TOUCH_TCHTHR          7
-#define QT602240_TOUCH_TCHDI           8
-#define QT602240_TOUCH_ORIENT          9
-#define QT602240_TOUCH_MOVHYSTI                11
-#define QT602240_TOUCH_MOVHYSTN                12
-#define QT602240_TOUCH_NUMTOUCH                14
-#define QT602240_TOUCH_MRGHYST         15
-#define QT602240_TOUCH_MRGTHR          16
-#define QT602240_TOUCH_AMPHYST         17
-#define QT602240_TOUCH_XRANGE_LSB      18
-#define QT602240_TOUCH_XRANGE_MSB      19
-#define QT602240_TOUCH_YRANGE_LSB      20
-#define QT602240_TOUCH_YRANGE_MSB      21
-#define QT602240_TOUCH_XLOCLIP         22
-#define QT602240_TOUCH_XHICLIP         23
-#define QT602240_TOUCH_YLOCLIP         24
-#define QT602240_TOUCH_YHICLIP         25
-#define QT602240_TOUCH_XEDGECTRL       26
-#define QT602240_TOUCH_XEDGEDIST       27
-#define QT602240_TOUCH_YEDGECTRL       28
-#define QT602240_TOUCH_YEDGEDIST       29
-#define QT602240_TOUCH_JUMPLIMIT       30      /* firmware ver 22 over */
-
-/* QT602240_PROCI_GRIPFACE field */
-#define QT602240_GRIPFACE_CTRL         0
-#define QT602240_GRIPFACE_XLOGRIP      1
-#define QT602240_GRIPFACE_XHIGRIP      2
-#define QT602240_GRIPFACE_YLOGRIP      3
-#define QT602240_GRIPFACE_YHIGRIP      4
-#define QT602240_GRIPFACE_MAXTCHS      5
-#define QT602240_GRIPFACE_SZTHR1       7
-#define QT602240_GRIPFACE_SZTHR2       8
-#define QT602240_GRIPFACE_SHPTHR1      9
-#define QT602240_GRIPFACE_SHPTHR2      10
-#define QT602240_GRIPFACE_SUPEXTTO     11
-
-/* QT602240_PROCI_NOISE field */
-#define QT602240_NOISE_CTRL            0
-#define QT602240_NOISE_OUTFLEN         1
-#define QT602240_NOISE_GCAFUL_LSB      3
-#define QT602240_NOISE_GCAFUL_MSB      4
-#define QT602240_NOISE_GCAFLL_LSB      5
-#define QT602240_NOISE_GCAFLL_MSB      6
-#define QT602240_NOISE_ACTVGCAFVALID   7
-#define QT602240_NOISE_NOISETHR                8
-#define QT602240_NOISE_FREQHOPSCALE    10
-#define QT602240_NOISE_FREQ0           11
-#define QT602240_NOISE_FREQ1           12
-#define QT602240_NOISE_FREQ2           13
-#define QT602240_NOISE_FREQ3           14
-#define QT602240_NOISE_FREQ4           15
-#define QT602240_NOISE_IDLEGCAFVALID   16
-
-/* QT602240_SPT_COMMSCONFIG */
-#define QT602240_COMMS_CTRL            0
-#define QT602240_COMMS_CMD             1
-
-/* QT602240_SPT_CTECONFIG field */
-#define QT602240_CTE_CTRL              0
-#define QT602240_CTE_CMD               1
-#define QT602240_CTE_MODE              2
-#define QT602240_CTE_IDLEGCAFDEPTH     3
-#define QT602240_CTE_ACTVGCAFDEPTH     4
-#define QT602240_CTE_VOLTAGE           5       /* firmware ver 21 over */
-
-#define QT602240_VOLTAGE_DEFAULT       2700000
-#define QT602240_VOLTAGE_STEP          10000
-
-/* Define for QT602240_GEN_COMMAND */
-#define QT602240_BOOT_VALUE            0xa5
-#define QT602240_BACKUP_VALUE          0x55
-#define QT602240_BACKUP_TIME           25      /* msec */
-#define QT602240_RESET_TIME            65      /* msec */
-
-#define QT602240_FWRESET_TIME          175     /* msec */
-
-/* Command to unlock bootloader */
-#define QT602240_UNLOCK_CMD_MSB                0xaa
-#define QT602240_UNLOCK_CMD_LSB                0xdc
-
-/* Bootloader mode status */
-#define QT602240_WAITING_BOOTLOAD_CMD  0xc0    /* valid 7 6 bit only */
-#define QT602240_WAITING_FRAME_DATA    0x80    /* valid 7 6 bit only */
-#define QT602240_FRAME_CRC_CHECK       0x02
-#define QT602240_FRAME_CRC_FAIL                0x03
-#define QT602240_FRAME_CRC_PASS                0x04
-#define QT602240_APP_CRC_FAIL          0x40    /* valid 7 8 bit only */
-#define QT602240_BOOT_STATUS_MASK      0x3f
-
-/* Touch status */
-#define QT602240_SUPPRESS              (1 << 1)
-#define QT602240_AMP                   (1 << 2)
-#define QT602240_VECTOR                        (1 << 3)
-#define QT602240_MOVE                  (1 << 4)
-#define QT602240_RELEASE               (1 << 5)
-#define QT602240_PRESS                 (1 << 6)
-#define QT602240_DETECT                        (1 << 7)
-
-/* Touchscreen absolute values */
-#define QT602240_MAX_XC                        0x3ff
-#define QT602240_MAX_YC                        0x3ff
-#define QT602240_MAX_AREA              0xff
-
-#define QT602240_MAX_FINGER            10
-
-/* Initial register values recommended from chip vendor */
-static const u8 init_vals_ver_20[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04,
-       0x1e, 0x00,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00,
-       0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x04, 0x08,
-};
-
-static const u8 init_vals_ver_21[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
-       0x0f, 0x0a,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
-       0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
-};
-
-static const u8 init_vals_ver_22[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
-       0x0f, 0x0a,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
-       0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
-};
-
-struct qt602240_info {
-       u8 family_id;
-       u8 variant_id;
-       u8 version;
-       u8 build;
-       u8 matrix_xsize;
-       u8 matrix_ysize;
-       u8 object_num;
-};
-
-struct qt602240_object {
-       u8 type;
-       u16 start_address;
-       u8 size;
-       u8 instances;
-       u8 num_report_ids;
-
-       /* to map object and message */
-       u8 max_reportid;
-};
-
-struct qt602240_message {
-       u8 reportid;
-       u8 message[7];
-       u8 checksum;
-};
-
-struct qt602240_finger {
-       int status;
-       int x;
-       int y;
-       int area;
-};
-
-/* Each client has this additional data */
-struct qt602240_data {
-       struct i2c_client *client;
-       struct input_dev *input_dev;
-       const struct qt602240_platform_data *pdata;
-       struct qt602240_object *object_table;
-       struct qt602240_info info;
-       struct qt602240_finger finger[QT602240_MAX_FINGER];
-       unsigned int irq;
-};
-
-static bool qt602240_object_readable(unsigned int type)
-{
-       switch (type) {
-       case QT602240_GEN_MESSAGE:
-       case QT602240_GEN_COMMAND:
-       case QT602240_GEN_POWER:
-       case QT602240_GEN_ACQUIRE:
-       case QT602240_TOUCH_MULTI:
-       case QT602240_TOUCH_KEYARRAY:
-       case QT602240_TOUCH_PROXIMITY:
-       case QT602240_PROCI_GRIPFACE:
-       case QT602240_PROCG_NOISE:
-       case QT602240_PROCI_ONETOUCH:
-       case QT602240_PROCI_TWOTOUCH:
-       case QT602240_SPT_COMMSCONFIG:
-       case QT602240_SPT_GPIOPWM:
-       case QT602240_SPT_SELFTEST:
-       case QT602240_SPT_CTECONFIG:
-       case QT602240_SPT_USERDATA:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool qt602240_object_writable(unsigned int type)
-{
-       switch (type) {
-       case QT602240_GEN_COMMAND:
-       case QT602240_GEN_POWER:
-       case QT602240_GEN_ACQUIRE:
-       case QT602240_TOUCH_MULTI:
-       case QT602240_TOUCH_KEYARRAY:
-       case QT602240_TOUCH_PROXIMITY:
-       case QT602240_PROCI_GRIPFACE:
-       case QT602240_PROCG_NOISE:
-       case QT602240_PROCI_ONETOUCH:
-       case QT602240_PROCI_TWOTOUCH:
-       case QT602240_SPT_GPIOPWM:
-       case QT602240_SPT_SELFTEST:
-       case QT602240_SPT_CTECONFIG:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static void qt602240_dump_message(struct device *dev,
-                                 struct qt602240_message *message)
-{
-       dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
-       dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
-       dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
-       dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
-       dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
-       dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
-       dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
-       dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
-       dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
-}
-
-static int qt602240_check_bootloader(struct i2c_client *client,
-                                    unsigned int state)
-{
-       u8 val;
-
-recheck:
-       if (i2c_master_recv(client, &val, 1) != 1) {
-               dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
-               return -EIO;
-       }
-
-       switch (state) {
-       case QT602240_WAITING_BOOTLOAD_CMD:
-       case QT602240_WAITING_FRAME_DATA:
-               val &= ~QT602240_BOOT_STATUS_MASK;
-               break;
-       case QT602240_FRAME_CRC_PASS:
-               if (val == QT602240_FRAME_CRC_CHECK)
-                       goto recheck;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (val != state) {
-               dev_err(&client->dev, "Unvalid bootloader mode state\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int qt602240_unlock_bootloader(struct i2c_client *client)
-{
-       u8 buf[2];
-
-       buf[0] = QT602240_UNLOCK_CMD_LSB;
-       buf[1] = QT602240_UNLOCK_CMD_MSB;
-
-       if (i2c_master_send(client, buf, 2) != 2) {
-               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int qt602240_fw_write(struct i2c_client *client,
-                            const u8 *data, unsigned int frame_size)
-{
-       if (i2c_master_send(client, data, frame_size) != frame_size) {
-               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int __qt602240_read_reg(struct i2c_client *client,
-                              u16 reg, u16 len, void *val)
-{
-       struct i2c_msg xfer[2];
-       u8 buf[2];
-
-       buf[0] = reg & 0xff;
-       buf[1] = (reg >> 8) & 0xff;
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 2;
-       xfer[0].buf = buf;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = len;
-       xfer[1].buf = val;
-
-       if (i2c_transfer(client->adapter, xfer, 2) != 2) {
-               dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val)
-{
-       return __qt602240_read_reg(client, reg, 1, val);
-}
-
-static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val)
-{
-       u8 buf[3];
-
-       buf[0] = reg & 0xff;
-       buf[1] = (reg >> 8) & 0xff;
-       buf[2] = val;
-
-       if (i2c_master_send(client, buf, 3) != 3) {
-               dev_err(&client->dev, "%s: i2c send failed\n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int qt602240_read_object_table(struct i2c_client *client,
-                                     u16 reg, u8 *object_buf)
-{
-       return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE,
-                                  object_buf);
-}
-
-static struct qt602240_object *
-qt602240_get_object(struct qt602240_data *data, u8 type)
-{
-       struct qt602240_object *object;
-       int i;
-
-       for (i = 0; i < data->info.object_num; i++) {
-               object = data->object_table + i;
-               if (object->type == type)
-                       return object;
-       }
-
-       dev_err(&data->client->dev, "Invalid object type\n");
-       return NULL;
-}
-
-static int qt602240_read_message(struct qt602240_data *data,
-                                struct qt602240_message *message)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, QT602240_GEN_MESSAGE);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return __qt602240_read_reg(data->client, reg,
-                       sizeof(struct qt602240_message), message);
-}
-
-static int qt602240_read_object(struct qt602240_data *data,
-                               u8 type, u8 offset, u8 *val)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, type);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return __qt602240_read_reg(data->client, reg + offset, 1, val);
-}
-
-static int qt602240_write_object(struct qt602240_data *data,
-                                u8 type, u8 offset, u8 val)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, type);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return qt602240_write_reg(data->client, reg + offset, val);
-}
-
-static void qt602240_input_report(struct qt602240_data *data, int single_id)
-{
-       struct qt602240_finger *finger = data->finger;
-       struct input_dev *input_dev = data->input_dev;
-       int status = finger[single_id].status;
-       int finger_num = 0;
-       int id;
-
-       for (id = 0; id < QT602240_MAX_FINGER; id++) {
-               if (!finger[id].status)
-                       continue;
-
-               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
-                               finger[id].status != QT602240_RELEASE ?
-                               finger[id].area : 0);
-               input_report_abs(input_dev, ABS_MT_POSITION_X,
-                               finger[id].x);
-               input_report_abs(input_dev, ABS_MT_POSITION_Y,
-                               finger[id].y);
-               input_mt_sync(input_dev);
-
-               if (finger[id].status == QT602240_RELEASE)
-                       finger[id].status = 0;
-               else
-                       finger_num++;
-       }
-
-       input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
-
-       if (status != QT602240_RELEASE) {
-               input_report_abs(input_dev, ABS_X, finger[single_id].x);
-               input_report_abs(input_dev, ABS_Y, finger[single_id].y);
-       }
-
-       input_sync(input_dev);
-}
-
-static void qt602240_input_touchevent(struct qt602240_data *data,
-                                     struct qt602240_message *message, int id)
-{
-       struct qt602240_finger *finger = data->finger;
-       struct device *dev = &data->client->dev;
-       u8 status = message->message[0];
-       int x;
-       int y;
-       int area;
-
-       /* Check the touch is present on the screen */
-       if (!(status & QT602240_DETECT)) {
-               if (status & QT602240_RELEASE) {
-                       dev_dbg(dev, "[%d] released\n", id);
-
-                       finger[id].status = QT602240_RELEASE;
-                       qt602240_input_report(data, id);
-               }
-               return;
-       }
-
-       /* Check only AMP detection */
-       if (!(status & (QT602240_PRESS | QT602240_MOVE)))
-               return;
-
-       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
-       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
-       area = message->message[4];
-
-       dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
-               status & QT602240_MOVE ? "moved" : "pressed",
-               x, y, area);
-
-       finger[id].status = status & QT602240_MOVE ?
-                               QT602240_MOVE : QT602240_PRESS;
-       finger[id].x = x;
-       finger[id].y = y;
-       finger[id].area = area;
-
-       qt602240_input_report(data, id);
-}
-
-static irqreturn_t qt602240_interrupt(int irq, void *dev_id)
-{
-       struct qt602240_data *data = dev_id;
-       struct qt602240_message message;
-       struct qt602240_object *object;
-       struct device *dev = &data->client->dev;
-       int id;
-       u8 reportid;
-       u8 max_reportid;
-       u8 min_reportid;
-
-       do {
-               if (qt602240_read_message(data, &message)) {
-                       dev_err(dev, "Failed to read message\n");
-                       goto end;
-               }
-
-               reportid = message.reportid;
-
-               /* whether reportid is thing of QT602240_TOUCH_MULTI */
-               object = qt602240_get_object(data, QT602240_TOUCH_MULTI);
-               if (!object)
-                       goto end;
-
-               max_reportid = object->max_reportid;
-               min_reportid = max_reportid - object->num_report_ids + 1;
-               id = reportid - min_reportid;
-
-               if (reportid >= min_reportid && reportid <= max_reportid)
-                       qt602240_input_touchevent(data, &message, id);
-               else
-                       qt602240_dump_message(dev, &message);
-       } while (reportid != 0xff);
-
-end:
-       return IRQ_HANDLED;
-}
-
-static int qt602240_check_reg_init(struct qt602240_data *data)
-{
-       struct qt602240_object *object;
-       struct device *dev = &data->client->dev;
-       int index = 0;
-       int i, j;
-       u8 version = data->info.version;
-       u8 *init_vals;
-
-       switch (version) {
-       case QT602240_VER_20:
-               init_vals = (u8 *)init_vals_ver_20;
-               break;
-       case QT602240_VER_21:
-               init_vals = (u8 *)init_vals_ver_21;
-               break;
-       case QT602240_VER_22:
-               init_vals = (u8 *)init_vals_ver_22;
-               break;
-       default:
-               dev_err(dev, "Firmware version %d doesn't support\n", version);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < data->info.object_num; i++) {
-               object = data->object_table + i;
-
-               if (!qt602240_object_writable(object->type))
-                       continue;
-
-               for (j = 0; j < object->size + 1; j++)
-                       qt602240_write_object(data, object->type, j,
-                                       init_vals[index + j]);
-
-               index += object->size + 1;
-       }
-
-       return 0;
-}
-
-static int qt602240_check_matrix_size(struct qt602240_data *data)
-{
-       const struct qt602240_platform_data *pdata = data->pdata;
-       struct device *dev = &data->client->dev;
-       int mode = -1;
-       int error;
-       u8 val;
-
-       dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line);
-       dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line);
-
-       switch (pdata->x_line) {
-       case 0 ... 15:
-               if (pdata->y_line <= 14)
-                       mode = 0;
-               break;
-       case 16:
-               if (pdata->y_line <= 12)
-                       mode = 1;
-               if (pdata->y_line == 13 || pdata->y_line == 14)
-                       mode = 0;
-               break;
-       case 17:
-               if (pdata->y_line <= 11)
-                       mode = 2;
-               if (pdata->y_line == 12 || pdata->y_line == 13)
-                       mode = 1;
-               break;
-       case 18:
-               if (pdata->y_line <= 10)
-                       mode = 3;
-               if (pdata->y_line == 11 || pdata->y_line == 12)
-                       mode = 2;
-               break;
-       case 19:
-               if (pdata->y_line <= 9)
-                       mode = 4;
-               if (pdata->y_line == 10 || pdata->y_line == 11)
-                       mode = 3;
-               break;
-       case 20:
-               mode = 4;
-       }
-
-       if (mode < 0) {
-               dev_err(dev, "Invalid X/Y lines\n");
-               return -EINVAL;
-       }
-
-       error = qt602240_read_object(data, QT602240_SPT_CTECONFIG,
-                               QT602240_CTE_MODE, &val);
-       if (error)
-               return error;
-
-       if (mode == val)
-               return 0;
-
-       /* Change the CTE configuration */
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_CTRL, 1);
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_MODE, mode);
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_CTRL, 0);
-
-       return 0;
-}
-
-static int qt602240_make_highchg(struct qt602240_data *data)
-{
-       struct device *dev = &data->client->dev;
-       int count = 10;
-       int error;
-       u8 val;
-
-       /* Read dummy message to make high CHG pin */
-       do {
-               error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val);
-               if (error)
-                       return error;
-       } while ((val != 0xff) && --count);
-
-       if (!count) {
-               dev_err(dev, "CHG pin isn't cleared\n");
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void qt602240_handle_pdata(struct qt602240_data *data)
-{
-       const struct qt602240_platform_data *pdata = data->pdata;
-       u8 voltage;
-
-       /* Set touchscreen lines */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE,
-                       pdata->x_line);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE,
-                       pdata->y_line);
-
-       /* Set touchscreen orient */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT,
-                       pdata->orient);
-
-       /* Set touchscreen burst length */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_BLEN, pdata->blen);
-
-       /* Set touchscreen threshold */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_TCHTHR, pdata->threshold);
-
-       /* Set touchscreen resolution */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
-
-       /* Set touchscreen voltage */
-       if (data->info.version >= QT602240_VER_21 && pdata->voltage) {
-               if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) {
-                       voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) /
-                               QT602240_VOLTAGE_STEP;
-                       voltage = 0xff - voltage + 1;
-               } else
-                       voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) /
-                               QT602240_VOLTAGE_STEP;
-
-               qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                               QT602240_CTE_VOLTAGE, voltage);
-       }
-}
-
-static int qt602240_get_info(struct qt602240_data *data)
-{
-       struct i2c_client *client = data->client;
-       struct qt602240_info *info = &data->info;
-       int error;
-       u8 val;
-
-       error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val);
-       if (error)
-               return error;
-       info->family_id = val;
-
-       error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val);
-       if (error)
-               return error;
-       info->variant_id = val;
-
-       error = qt602240_read_reg(client, QT602240_VERSION, &val);
-       if (error)
-               return error;
-       info->version = val;
-
-       error = qt602240_read_reg(client, QT602240_BUILD, &val);
-       if (error)
-               return error;
-       info->build = val;
-
-       error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val);
-       if (error)
-               return error;
-       info->object_num = val;
-
-       return 0;
-}
-
-static int qt602240_get_object_table(struct qt602240_data *data)
-{
-       int error;
-       int i;
-       u16 reg;
-       u8 reportid = 0;
-       u8 buf[QT602240_OBJECT_SIZE];
-
-       for (i = 0; i < data->info.object_num; i++) {
-               struct qt602240_object *object = data->object_table + i;
-
-               reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i;
-               error = qt602240_read_object_table(data->client, reg, buf);
-               if (error)
-                       return error;
-
-               object->type = buf[0];
-               object->start_address = (buf[2] << 8) | buf[1];
-               object->size = buf[3];
-               object->instances = buf[4];
-               object->num_report_ids = buf[5];
-
-               if (object->num_report_ids) {
-                       reportid += object->num_report_ids *
-                                       (object->instances + 1);
-                       object->max_reportid = reportid;
-               }
-       }
-
-       return 0;
-}
-
-static int qt602240_initialize(struct qt602240_data *data)
-{
-       struct i2c_client *client = data->client;
-       struct qt602240_info *info = &data->info;
-       int error;
-       u8 val;
-
-       error = qt602240_get_info(data);
-       if (error)
-               return error;
-
-       data->object_table = kcalloc(info->object_num,
-                                    sizeof(struct qt602240_object),
-                                    GFP_KERNEL);
-       if (!data->object_table) {
-               dev_err(&client->dev, "Failed to allocate memory\n");
-               return -ENOMEM;
-       }
-
-       /* Get object table information */
-       error = qt602240_get_object_table(data);
-       if (error)
-               return error;
-
-       /* Check register init values */
-       error = qt602240_check_reg_init(data);
-       if (error)
-               return error;
-
-       /* Check X/Y matrix size */
-       error = qt602240_check_matrix_size(data);
-       if (error)
-               return error;
-
-       error = qt602240_make_highchg(data);
-       if (error)
-               return error;
-
-       qt602240_handle_pdata(data);
-
-       /* Backup to memory */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_BACKUPNV,
-                       QT602240_BACKUP_VALUE);
-       msleep(QT602240_BACKUP_TIME);
-
-       /* Soft reset */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, 1);
-       msleep(QT602240_RESET_TIME);
-
-       /* Update matrix size at info struct */
-       error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val);
-       if (error)
-               return error;
-       info->matrix_xsize = val;
-
-       error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val);
-       if (error)
-               return error;
-       info->matrix_ysize = val;
-
-       dev_info(&client->dev,
-                       "Family ID: %d Variant ID: %d Version: %d Build: %d\n",
-                       info->family_id, info->variant_id, info->version,
-                       info->build);
-
-       dev_info(&client->dev,
-                       "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
-                       info->matrix_xsize, info->matrix_ysize,
-                       info->object_num);
-
-       return 0;
-}
-
-static ssize_t qt602240_object_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct qt602240_data *data = dev_get_drvdata(dev);
-       struct qt602240_object *object;
-       int count = 0;
-       int i, j;
-       int error;
-       u8 val;
-
-       for (i = 0; i < data->info.object_num; i++) {
-               object = data->object_table + i;
-
-               count += sprintf(buf + count,
-                               "Object Table Element %d(Type %d)\n",
-                               i + 1, object->type);
-
-               if (!qt602240_object_readable(object->type)) {
-                       count += sprintf(buf + count, "\n");
-                       continue;
-               }
-
-               for (j = 0; j < object->size + 1; j++) {
-                       error = qt602240_read_object(data,
-                                               object->type, j, &val);
-                       if (error)
-                               return error;
-
-                       count += sprintf(buf + count,
-                                       "  Byte %d: 0x%x (%d)\n", j, val, val);
-               }
-
-               count += sprintf(buf + count, "\n");
-       }
-
-       return count;
-}
-
-static int qt602240_load_fw(struct device *dev, const char *fn)
-{
-       struct qt602240_data *data = dev_get_drvdata(dev);
-       struct i2c_client *client = data->client;
-       const struct firmware *fw = NULL;
-       unsigned int frame_size;
-       unsigned int pos = 0;
-       int ret;
-
-       ret = request_firmware(&fw, fn, dev);
-       if (ret) {
-               dev_err(dev, "Unable to open firmware %s\n", fn);
-               return ret;
-       }
-
-       /* Change to the bootloader mode */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, QT602240_BOOT_VALUE);
-       msleep(QT602240_RESET_TIME);
-
-       /* Change to slave address of bootloader */
-       if (client->addr == QT602240_APP_LOW)
-               client->addr = QT602240_BOOT_LOW;
-       else
-               client->addr = QT602240_BOOT_HIGH;
-
-       ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD);
-       if (ret)
-               goto out;
-
-       /* Unlock bootloader */
-       qt602240_unlock_bootloader(client);
-
-       while (pos < fw->size) {
-               ret = qt602240_check_bootloader(client,
-                                               QT602240_WAITING_FRAME_DATA);
-               if (ret)
-                       goto out;
-
-               frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
-
-               /* We should add 2 at frame size as the the firmware data is not
-                * included the CRC bytes.
-                */
-               frame_size += 2;
-
-               /* Write one frame to device */
-               qt602240_fw_write(client, fw->data + pos, frame_size);
-
-               ret = qt602240_check_bootloader(client,
-                                               QT602240_FRAME_CRC_PASS);
-               if (ret)
-                       goto out;
-
-               pos += frame_size;
-
-               dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
-       }
-
-out:
-       release_firmware(fw);
-
-       /* Change to slave address of application */
-       if (client->addr == QT602240_BOOT_LOW)
-               client->addr = QT602240_APP_LOW;
-       else
-               client->addr = QT602240_APP_HIGH;
-
-       return ret;
-}
-
-static ssize_t qt602240_update_fw_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       struct qt602240_data *data = dev_get_drvdata(dev);
-       unsigned int version;
-       int error;
-
-       if (sscanf(buf, "%u", &version) != 1) {
-               dev_err(dev, "Invalid values\n");
-               return -EINVAL;
-       }
-
-       if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) {
-               dev_err(dev, "FW update supported starting with version 21\n");
-               return -EINVAL;
-       }
-
-       disable_irq(data->irq);
-
-       error = qt602240_load_fw(dev, QT602240_FW_NAME);
-       if (error) {
-               dev_err(dev, "The firmware update failed(%d)\n", error);
-               count = error;
-       } else {
-               dev_dbg(dev, "The firmware update succeeded\n");
-
-               /* Wait for reset */
-               msleep(QT602240_FWRESET_TIME);
-
-               kfree(data->object_table);
-               data->object_table = NULL;
-
-               qt602240_initialize(data);
-       }
-
-       enable_irq(data->irq);
-
-       return count;
-}
-
-static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store);
-
-static struct attribute *qt602240_attrs[] = {
-       &dev_attr_object.attr,
-       &dev_attr_update_fw.attr,
-       NULL
-};
-
-static const struct attribute_group qt602240_attr_group = {
-       .attrs = qt602240_attrs,
-};
-
-static void qt602240_start(struct qt602240_data *data)
-{
-       /* Touch enable */
-       qt602240_write_object(data,
-                       QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83);
-}
-
-static void qt602240_stop(struct qt602240_data *data)
-{
-       /* Touch disable */
-       qt602240_write_object(data,
-                       QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0);
-}
-
-static int qt602240_input_open(struct input_dev *dev)
-{
-       struct qt602240_data *data = input_get_drvdata(dev);
-
-       qt602240_start(data);
-
-       return 0;
-}
-
-static void qt602240_input_close(struct input_dev *dev)
-{
-       struct qt602240_data *data = input_get_drvdata(dev);
-
-       qt602240_stop(data);
-}
-
-static int __devinit qt602240_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
-{
-       struct qt602240_data *data;
-       struct input_dev *input_dev;
-       int error;
-
-       if (!client->dev.platform_data)
-               return -EINVAL;
-
-       data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!data || !input_dev) {
-               dev_err(&client->dev, "Failed to allocate memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
-
-       input_dev->name = "AT42QT602240/ATMXT224 Touchscreen";
-       input_dev->id.bustype = BUS_I2C;
-       input_dev->dev.parent = &client->dev;
-       input_dev->open = qt602240_input_open;
-       input_dev->close = qt602240_input_close;
-
-       __set_bit(EV_ABS, input_dev->evbit);
-       __set_bit(EV_KEY, input_dev->evbit);
-       __set_bit(BTN_TOUCH, input_dev->keybit);
-
-       /* For single touch */
-       input_set_abs_params(input_dev, ABS_X,
-                            0, QT602240_MAX_XC, 0, 0);
-       input_set_abs_params(input_dev, ABS_Y,
-                            0, QT602240_MAX_YC, 0, 0);
-
-       /* For multi touch */
-       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
-                            0, QT602240_MAX_AREA, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, QT602240_MAX_XC, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, QT602240_MAX_YC, 0, 0);
-
-       input_set_drvdata(input_dev, data);
-
-       data->client = client;
-       data->input_dev = input_dev;
-       data->pdata = client->dev.platform_data;
-       data->irq = client->irq;
-
-       i2c_set_clientdata(client, data);
-
-       error = qt602240_initialize(data);
-       if (error)
-               goto err_free_object;
-
-       error = request_threaded_irq(client->irq, NULL, qt602240_interrupt,
-                       IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
-       if (error) {
-               dev_err(&client->dev, "Failed to register interrupt\n");
-               goto err_free_object;
-       }
-
-       error = input_register_device(input_dev);
-       if (error)
-               goto err_free_irq;
-
-       error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group);
-       if (error)
-               goto err_unregister_device;
-
-       return 0;
-
-err_unregister_device:
-       input_unregister_device(input_dev);
-       input_dev = NULL;
-err_free_irq:
-       free_irq(client->irq, data);
-err_free_object:
-       kfree(data->object_table);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(data);
-       return error;
-}
-
-static int __devexit qt602240_remove(struct i2c_client *client)
-{
-       struct qt602240_data *data = i2c_get_clientdata(client);
-
-       sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group);
-       free_irq(data->irq, data);
-       input_unregister_device(data->input_dev);
-       kfree(data->object_table);
-       kfree(data);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int qt602240_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct qt602240_data *data = i2c_get_clientdata(client);
-       struct input_dev *input_dev = data->input_dev;
-
-       mutex_lock(&input_dev->mutex);
-
-       if (input_dev->users)
-               qt602240_stop(data);
-
-       mutex_unlock(&input_dev->mutex);
-
-       return 0;
-}
-
-static int qt602240_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct qt602240_data *data = i2c_get_clientdata(client);
-       struct input_dev *input_dev = data->input_dev;
-
-       /* Soft reset */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, 1);
-
-       msleep(QT602240_RESET_TIME);
-
-       mutex_lock(&input_dev->mutex);
-
-       if (input_dev->users)
-               qt602240_start(data);
-
-       mutex_unlock(&input_dev->mutex);
-
-       return 0;
-}
-
-static const struct dev_pm_ops qt602240_pm_ops = {
-       .suspend        = qt602240_suspend,
-       .resume         = qt602240_resume,
-};
-#endif
-
-static const struct i2c_device_id qt602240_id[] = {
-       { "qt602240_ts", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, qt602240_id);
-
-static struct i2c_driver qt602240_driver = {
-       .driver = {
-               .name   = "qt602240_ts",
-               .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm     = &qt602240_pm_ops,
-#endif
-       },
-       .probe          = qt602240_probe,
-       .remove         = __devexit_p(qt602240_remove),
-       .id_table       = qt602240_id,
-};
-
-static int __init qt602240_init(void)
-{
-       return i2c_add_driver(&qt602240_driver);
-}
-
-static void __exit qt602240_exit(void)
-{
-       i2c_del_driver(&qt602240_driver);
-}
-
-module_init(qt602240_init);
-module_exit(qt602240_exit);
-
-/* Module information */
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
new file mode 100644 (file)
index 0000000..cbf0ff3
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2005.h>
+
+/*
+ * The touchscreen interface operates as follows:
+ *
+ * 1) Pen is pressed against the touchscreen.
+ * 2) TSC2005 performs AD conversion.
+ * 3) After the conversion is done TSC2005 drives DAV line down.
+ * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled.
+ * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2
+ *    values.
+ * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up
+ *    tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms).
+ * 7) When the penup timer expires, there have not been touch or DAV interrupts
+ *    during the last 40ms which means the pen has been lifted.
+ *
+ * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond
+ * after a configurable period (in ms) of activity. If esd_timeout is 0, the
+ * watchdog is disabled.
+ */
+
+/* control byte 1 */
+#define TSC2005_CMD                    0x80
+#define TSC2005_CMD_NORMAL             0x00
+#define TSC2005_CMD_STOP               0x01
+#define TSC2005_CMD_12BIT              0x04
+
+/* control byte 0 */
+#define TSC2005_REG_READ               0x0001
+#define TSC2005_REG_PND0               0x0002
+#define TSC2005_REG_X                  0x0000
+#define TSC2005_REG_Y                  0x0008
+#define TSC2005_REG_Z1                 0x0010
+#define TSC2005_REG_Z2                 0x0018
+#define TSC2005_REG_TEMP_HIGH          0x0050
+#define TSC2005_REG_CFR0               0x0060
+#define TSC2005_REG_CFR1               0x0068
+#define TSC2005_REG_CFR2               0x0070
+
+/* configuration register 0 */
+#define TSC2005_CFR0_PRECHARGE_276US   0x0040
+#define TSC2005_CFR0_STABTIME_1MS      0x0300
+#define TSC2005_CFR0_CLOCK_1MHZ                0x1000
+#define TSC2005_CFR0_RESOLUTION12      0x2000
+#define TSC2005_CFR0_PENMODE           0x8000
+#define TSC2005_CFR0_INITVALUE         (TSC2005_CFR0_STABTIME_1MS    | \
+                                        TSC2005_CFR0_CLOCK_1MHZ      | \
+                                        TSC2005_CFR0_RESOLUTION12    | \
+                                        TSC2005_CFR0_PRECHARGE_276US | \
+                                        TSC2005_CFR0_PENMODE)
+
+/* bits common to both read and write of configuration register 0 */
+#define        TSC2005_CFR0_RW_MASK            0x3fff
+
+/* configuration register 1 */
+#define TSC2005_CFR1_BATCHDELAY_4MS    0x0003
+#define TSC2005_CFR1_INITVALUE         TSC2005_CFR1_BATCHDELAY_4MS
+
+/* configuration register 2 */
+#define TSC2005_CFR2_MAVE_Z            0x0004
+#define TSC2005_CFR2_MAVE_Y            0x0008
+#define TSC2005_CFR2_MAVE_X            0x0010
+#define TSC2005_CFR2_AVG_7             0x0800
+#define TSC2005_CFR2_MEDIUM_15         0x3000
+#define TSC2005_CFR2_INITVALUE         (TSC2005_CFR2_MAVE_X    | \
+                                        TSC2005_CFR2_MAVE_Y    | \
+                                        TSC2005_CFR2_MAVE_Z    | \
+                                        TSC2005_CFR2_MEDIUM_15 | \
+                                        TSC2005_CFR2_AVG_7)
+
+#define MAX_12BIT                      0xfff
+#define TSC2005_SPI_MAX_SPEED_HZ       10000000
+#define TSC2005_PENUP_TIME_MS          40
+
+struct tsc2005_spi_rd {
+       struct spi_transfer     spi_xfer;
+       u32                     spi_tx;
+       u32                     spi_rx;
+};
+
+struct tsc2005 {
+       struct spi_device       *spi;
+
+       struct spi_message      spi_read_msg;
+       struct tsc2005_spi_rd   spi_x;
+       struct tsc2005_spi_rd   spi_y;
+       struct tsc2005_spi_rd   spi_z1;
+       struct tsc2005_spi_rd   spi_z2;
+
+       struct input_dev        *idev;
+       char                    phys[32];
+
+       struct mutex            mutex;
+
+       /* raw copy of previous x,y,z */
+       int                     in_x;
+       int                     in_y;
+       int                     in_z1;
+       int                     in_z2;
+
+       spinlock_t              lock;
+       struct timer_list       penup_timer;
+
+       unsigned int            esd_timeout;
+       struct delayed_work     esd_work;
+       unsigned long           last_valid_interrupt;
+
+       unsigned int            x_plate_ohm;
+
+       bool                    opened;
+       bool                    suspended;
+
+       bool                    pen_down;
+
+       void                    (*set_reset)(bool enable);
+};
+
+static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+{
+       u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+       struct spi_transfer xfer = {
+               .tx_buf         = &tx,
+               .len            = 1,
+               .bits_per_word  = 8,
+       };
+       struct spi_message msg;
+       int error;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       error = spi_sync(ts->spi, &msg);
+       if (error) {
+               dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n",
+                       __func__, cmd, error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
+{
+       u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value;
+       struct spi_transfer xfer = {
+               .tx_buf         = &tx,
+               .len            = 4,
+               .bits_per_word  = 24,
+       };
+       struct spi_message msg;
+       int error;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       error = spi_sync(ts->spi, &msg);
+       if (error) {
+               dev_err(&ts->spi->dev,
+                       "%s: failed, register: %x, value: %x, error: %d\n",
+                       __func__, reg, value, error);
+               return error;
+       }
+
+       return 0;
+}
+
+static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
+{
+       memset(rd, 0, sizeof(*rd));
+
+       rd->spi_tx                 = (reg | TSC2005_REG_READ) << 16;
+       rd->spi_xfer.tx_buf        = &rd->spi_tx;
+       rd->spi_xfer.rx_buf        = &rd->spi_rx;
+       rd->spi_xfer.len           = 4;
+       rd->spi_xfer.bits_per_word = 24;
+       rd->spi_xfer.cs_change     = !last;
+}
+
+static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value)
+{
+       struct tsc2005_spi_rd spi_rd;
+       struct spi_message msg;
+       int error;
+
+       tsc2005_setup_read(&spi_rd, reg, true);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&spi_rd.spi_xfer, &msg);
+
+       error = spi_sync(ts->spi, &msg);
+       if (error)
+               return error;
+
+       *value = spi_rd.spi_rx;
+       return 0;
+}
+
+static void tsc2005_update_pen_state(struct tsc2005 *ts,
+                                    int x, int y, int pressure)
+{
+       if (pressure) {
+               input_report_abs(ts->idev, ABS_X, x);
+               input_report_abs(ts->idev, ABS_Y, y);
+               input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+               if (!ts->pen_down) {
+                       input_report_key(ts->idev, BTN_TOUCH, !!pressure);
+                       ts->pen_down = true;
+               }
+       } else {
+               input_report_abs(ts->idev, ABS_PRESSURE, 0);
+               if (ts->pen_down) {
+                       input_report_key(ts->idev, BTN_TOUCH, 0);
+                       ts->pen_down = false;
+               }
+       }
+       input_sync(ts->idev);
+       dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
+               pressure);
+}
+
+static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
+{
+       struct tsc2005 *ts = _ts;
+       unsigned long flags;
+       unsigned int pressure;
+       u32 x, y;
+       u32 z1, z2;
+       int error;
+
+       /* read the coordinates */
+       error = spi_sync(ts->spi, &ts->spi_read_msg);
+       if (unlikely(error))
+               goto out;
+
+       x = ts->spi_x.spi_rx;
+       y = ts->spi_y.spi_rx;
+       z1 = ts->spi_z1.spi_rx;
+       z2 = ts->spi_z2.spi_rx;
+
+       /* validate position */
+       if (unlikely(x > MAX_12BIT || y > MAX_12BIT))
+               goto out;
+
+       /* Skip reading if the pressure components are out of range */
+       if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2))
+               goto out;
+
+       /*
+       * Skip point if this is a pen down with the exact same values as
+       * the value before pen-up - that implies SPI fed us stale data
+       */
+       if (!ts->pen_down &&
+           ts->in_x == x && ts->in_y == y &&
+           ts->in_z1 == z1 && ts->in_z2 == z2) {
+               goto out;
+       }
+
+       /*
+        * At this point we are happy we have a valid and useful reading.
+        * Remember it for later comparisons. We may now begin downsampling.
+        */
+       ts->in_x = x;
+       ts->in_y = y;
+       ts->in_z1 = z1;
+       ts->in_z2 = z2;
+
+       /* Compute touch pressure resistance using equation #1 */
+       pressure = x * (z2 - z1) / z1;
+       pressure = pressure * ts->x_plate_ohm / 4096;
+       if (unlikely(pressure > MAX_12BIT))
+               goto out;
+
+       spin_lock_irqsave(&ts->lock, flags);
+
+       tsc2005_update_pen_state(ts, x, y, pressure);
+       mod_timer(&ts->penup_timer,
+                 jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
+
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       ts->last_valid_interrupt = jiffies;
+out:
+       return IRQ_HANDLED;
+}
+
+static void tsc2005_penup_timer(unsigned long data)
+{
+       struct tsc2005 *ts = (struct tsc2005 *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       tsc2005_update_pen_state(ts, 0, 0, 0);
+       spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void tsc2005_start_scan(struct tsc2005 *ts)
+{
+       tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
+       tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
+       tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
+       tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
+}
+
+static void tsc2005_stop_scan(struct tsc2005 *ts)
+{
+       tsc2005_cmd(ts, TSC2005_CMD_STOP);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc2005_disable(struct tsc2005 *ts)
+{
+       tsc2005_stop_scan(ts);
+
+       disable_irq(ts->spi->irq);
+       del_timer_sync(&ts->penup_timer);
+
+       cancel_delayed_work_sync(&ts->esd_work);
+
+       enable_irq(ts->spi->irq);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc2005_enable(struct tsc2005 *ts)
+{
+       tsc2005_start_scan(ts);
+
+       if (ts->esd_timeout && ts->set_reset) {
+               ts->last_valid_interrupt = jiffies;
+               schedule_delayed_work(&ts->esd_work,
+                               round_jiffies_relative(
+                                       msecs_to_jiffies(ts->esd_timeout)));
+       }
+
+}
+
+static ssize_t tsc2005_selftest_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct tsc2005 *ts = spi_get_drvdata(spi);
+       u16 temp_high;
+       u16 temp_high_orig;
+       u16 temp_high_test;
+       bool success = true;
+       int error;
+
+       mutex_lock(&ts->mutex);
+
+       /*
+        * Test TSC2005 communications via temp high register.
+        */
+       __tsc2005_disable(ts);
+
+       error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
+       if (error) {
+               dev_warn(dev, "selftest failed: read error %d\n", error);
+               success = false;
+               goto out;
+       }
+
+       temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
+
+       error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test);
+       if (error) {
+               dev_warn(dev, "selftest failed: write error %d\n", error);
+               success = false;
+               goto out;
+       }
+
+       error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+       if (error) {
+               dev_warn(dev, "selftest failed: read error %d after write\n",
+                        error);
+               success = false;
+               goto out;
+       }
+
+       if (temp_high != temp_high_test) {
+               dev_warn(dev, "selftest failed: %d != %d\n",
+                        temp_high, temp_high_test);
+               success = false;
+       }
+
+       /* hardware reset */
+       ts->set_reset(false);
+       usleep_range(100, 500); /* only 10us required */
+       ts->set_reset(true);
+
+       if (!success)
+               goto out;
+
+       /* test that the reset really happened */
+       error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+       if (error) {
+               dev_warn(dev, "selftest failed: read error %d after reset\n",
+                        error);
+               success = false;
+               goto out;
+       }
+
+       if (temp_high != temp_high_orig) {
+               dev_warn(dev, "selftest failed after reset: %d != %d\n",
+                        temp_high, temp_high_orig);
+               success = false;
+       }
+
+out:
+       __tsc2005_enable(ts);
+       mutex_unlock(&ts->mutex);
+
+       return sprintf(buf, "%d\n", success);
+}
+
+static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL);
+
+static struct attribute *tsc2005_attrs[] = {
+       &dev_attr_selftest.attr,
+       NULL
+};
+
+static mode_t tsc2005_attr_is_visible(struct kobject *kobj,
+                                     struct attribute *attr, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct spi_device *spi = to_spi_device(dev);
+       struct tsc2005 *ts = spi_get_drvdata(spi);
+       mode_t mode = attr->mode;
+
+       if (attr == &dev_attr_selftest.attr) {
+               if (!ts->set_reset)
+                       mode = 0;
+       }
+
+       return mode;
+}
+
+static const struct attribute_group tsc2005_attr_group = {
+       .is_visible     = tsc2005_attr_is_visible,
+       .attrs          = tsc2005_attrs,
+};
+
+static void tsc2005_esd_work(struct work_struct *work)
+{
+       struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work);
+       int error;
+       u16 r;
+
+       if (!mutex_trylock(&ts->mutex)) {
+               /*
+                * If the mutex is taken, it means that disable or enable is in
+                * progress. In that case just reschedule the work. If the work
+                * is not needed, it will be canceled by disable.
+                */
+               goto reschedule;
+       }
+
+       if (time_is_after_jiffies(ts->last_valid_interrupt +
+                                 msecs_to_jiffies(ts->esd_timeout)))
+               goto out;
+
+       /* We should be able to read register without disabling interrupts. */
+       error = tsc2005_read(ts, TSC2005_REG_CFR0, &r);
+       if (!error &&
+           !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
+               goto out;
+       }
+
+       /*
+        * If we could not read our known value from configuration register 0
+        * then we should reset the controller as if from power-up and start
+        * scanning again.
+        */
+       dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n");
+
+       disable_irq(ts->spi->irq);
+       del_timer_sync(&ts->penup_timer);
+
+       tsc2005_update_pen_state(ts, 0, 0, 0);
+
+       ts->set_reset(false);
+       usleep_range(100, 500); /* only 10us required */
+       ts->set_reset(true);
+
+       enable_irq(ts->spi->irq);
+       tsc2005_start_scan(ts);
+
+out:
+       mutex_unlock(&ts->mutex);
+reschedule:
+       /* re-arm the watchdog */
+       schedule_delayed_work(&ts->esd_work,
+                             round_jiffies_relative(
+                                       msecs_to_jiffies(ts->esd_timeout)));
+}
+
+static int tsc2005_open(struct input_dev *input)
+{
+       struct tsc2005 *ts = input_get_drvdata(input);
+
+       mutex_lock(&ts->mutex);
+
+       if (!ts->suspended)
+               __tsc2005_enable(ts);
+
+       ts->opened = true;
+
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+
+static void tsc2005_close(struct input_dev *input)
+{
+       struct tsc2005 *ts = input_get_drvdata(input);
+
+       mutex_lock(&ts->mutex);
+
+       if (!ts->suspended)
+               __tsc2005_disable(ts);
+
+       ts->opened = false;
+
+       mutex_unlock(&ts->mutex);
+}
+
+static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
+{
+       tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false);
+       tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false);
+       tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false);
+       tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true);
+
+       spi_message_init(&ts->spi_read_msg);
+       spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg);
+       spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg);
+       spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg);
+       spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
+}
+
+static int __devinit tsc2005_probe(struct spi_device *spi)
+{
+       const struct tsc2005_platform_data *pdata = spi->dev.platform_data;
+       struct tsc2005 *ts;
+       struct input_dev *input_dev;
+       unsigned int max_x, max_y, max_p;
+       unsigned int fudge_x, fudge_y, fudge_p;
+       int error;
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data\n");
+               return -ENODEV;
+       }
+
+       fudge_x = pdata->ts_x_fudge        ? : 4;
+       fudge_y = pdata->ts_y_fudge        ? : 8;
+       fudge_p = pdata->ts_pressure_fudge ? : 2;
+       max_x   = pdata->ts_x_max          ? : MAX_12BIT;
+       max_y   = pdata->ts_y_max          ? : MAX_12BIT;
+       max_p   = pdata->ts_pressure_max   ? : MAX_12BIT;
+
+       if (spi->irq <= 0) {
+               dev_dbg(&spi->dev, "no irq\n");
+               return -ENODEV;
+       }
+
+       spi->mode = SPI_MODE_0;
+       spi->bits_per_word = 8;
+       if (!spi->max_speed_hz)
+               spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ;
+
+       error = spi_setup(spi);
+       if (error)
+               return error;
+
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !input_dev) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ts->spi = spi;
+       ts->idev = input_dev;
+
+       ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+       ts->esd_timeout = pdata->esd_timeout_ms;
+       ts->set_reset   = pdata->set_reset;
+
+       mutex_init(&ts->mutex);
+
+       spin_lock_init(&ts->lock);
+       setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
+
+       INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work);
+
+       tsc2005_setup_spi_xfer(ts);
+
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input-ts", dev_name(&spi->dev));
+
+       input_dev->name = "TSC2005 touchscreen";
+       input_dev->phys = ts->phys;
+       input_dev->id.bustype = BUS_SPI;
+       input_dev->dev.parent = &spi->dev;
+       input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+       input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
+
+       input_dev->open = tsc2005_open;
+       input_dev->close = tsc2005_close;
+
+       input_set_drvdata(input_dev, ts);
+
+       /* Ensure the touchscreen is off */
+       tsc2005_stop_scan(ts);
+
+       error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
+                                    IRQF_TRIGGER_RISING, "tsc2005", ts);
+       if (error) {
+               dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
+               goto err_free_mem;
+       }
+
+       spi_set_drvdata(spi, ts);
+       error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group);
+       if (error) {
+               dev_err(&spi->dev,
+                       "Failed to create sysfs attributes, err: %d\n", error);
+               goto err_clear_drvdata;
+       }
+
+       error = input_register_device(ts->idev);
+       if (error) {
+               dev_err(&spi->dev,
+                       "Failed to register input device, err: %d\n", error);
+               goto err_remove_sysfs;
+       }
+
+       irq_set_irq_wake(spi->irq, 1);
+       return 0;
+
+err_remove_sysfs:
+       sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
+err_clear_drvdata:
+       spi_set_drvdata(spi, NULL);
+       free_irq(spi->irq, ts);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(ts);
+       return error;
+}
+
+static int __devexit tsc2005_remove(struct spi_device *spi)
+{
+       struct tsc2005 *ts = spi_get_drvdata(spi);
+
+       sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
+
+       free_irq(ts->spi->irq, ts);
+       input_unregister_device(ts->idev);
+       kfree(ts);
+
+       spi_set_drvdata(spi, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tsc2005_suspend(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct tsc2005 *ts = spi_get_drvdata(spi);
+
+       mutex_lock(&ts->mutex);
+
+       if (!ts->suspended && ts->opened)
+               __tsc2005_disable(ts);
+
+       ts->suspended = true;
+
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+
+static int tsc2005_resume(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct tsc2005 *ts = spi_get_drvdata(spi);
+
+       mutex_lock(&ts->mutex);
+
+       if (ts->suspended && ts->opened)
+               __tsc2005_enable(ts);
+
+       ts->suspended = false;
+
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume);
+
+static struct spi_driver tsc2005_driver = {
+       .driver = {
+               .name   = "tsc2005",
+               .owner  = THIS_MODULE,
+               .pm     = &tsc2005_pm_ops,
+       },
+       .probe  = tsc2005_probe,
+       .remove = __devexit_p(tsc2005_remove),
+};
+
+static int __init tsc2005_init(void)
+{
+       return spi_register_driver(&tsc2005_driver);
+}
+module_init(tsc2005_init);
+
+static void __exit tsc2005_exit(void)
+{
+       spi_unregister_driver(&tsc2005_driver);
+}
+module_exit(tsc2005_exit);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
new file mode 100644 (file)
index 0000000..6ae054f
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Touchscreen driver for WM831x PMICs
+ *
+ * Copyright 2011 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/irq.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/*
+ * R16424 (0x4028) - Touch Control 1
+ */
+#define WM831X_TCH_ENA                          0x8000  /* TCH_ENA */
+#define WM831X_TCH_CVT_ENA                      0x4000  /* TCH_CVT_ENA */
+#define WM831X_TCH_SLPENA                       0x1000  /* TCH_SLPENA */
+#define WM831X_TCH_Z_ENA                        0x0400  /* TCH_Z_ENA */
+#define WM831X_TCH_Y_ENA                        0x0200  /* TCH_Y_ENA */
+#define WM831X_TCH_X_ENA                        0x0100  /* TCH_X_ENA */
+#define WM831X_TCH_DELAY_MASK                   0x00E0  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_DELAY_SHIFT                       5  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_DELAY_WIDTH                       3  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_RATE_MASK                    0x001F  /* TCH_RATE - [4:0] */
+#define WM831X_TCH_RATE_SHIFT                        0  /* TCH_RATE - [4:0] */
+#define WM831X_TCH_RATE_WIDTH                        5  /* TCH_RATE - [4:0] */
+
+/*
+ * R16425 (0x4029) - Touch Control 2
+ */
+#define WM831X_TCH_PD_WK                        0x2000  /* TCH_PD_WK */
+#define WM831X_TCH_5WIRE                        0x1000  /* TCH_5WIRE */
+#define WM831X_TCH_PDONLY                       0x0800  /* TCH_PDONLY */
+#define WM831X_TCH_ISEL                         0x0100  /* TCH_ISEL */
+#define WM831X_TCH_RPU_MASK                     0x000F  /* TCH_RPU - [3:0] */
+#define WM831X_TCH_RPU_SHIFT                         0  /* TCH_RPU - [3:0] */
+#define WM831X_TCH_RPU_WIDTH                         4  /* TCH_RPU - [3:0] */
+
+/*
+ * R16426-8 (0x402A-C) - Touch Data X/Y/X
+ */
+#define WM831X_TCH_PD                           0x8000  /* TCH_PD1 */
+#define WM831X_TCH_DATA_MASK                    0x0FFF  /* TCH_DATA - [11:0] */
+#define WM831X_TCH_DATA_SHIFT                        0  /* TCH_DATA - [11:0] */
+#define WM831X_TCH_DATA_WIDTH                       12  /* TCH_DATA - [11:0] */
+
+struct wm831x_ts {
+       struct input_dev *input_dev;
+       struct wm831x *wm831x;
+       unsigned int data_irq;
+       unsigned int pd_irq;
+       bool pressure;
+       bool pen_down;
+};
+
+static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
+{
+       struct wm831x_ts *wm831x_ts = irq_data;
+       struct wm831x *wm831x = wm831x_ts->wm831x;
+       static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE };
+       u16 data[3];
+       int count;
+       int i, ret;
+
+       if (wm831x_ts->pressure)
+               count = 3;
+       else
+               count = 2;
+
+       wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+                       WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);
+
+       ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count,
+                              data);
+       if (ret != 0) {
+               dev_err(wm831x->dev, "Failed to read touch data: %d\n",
+                       ret);
+               return IRQ_NONE;
+       }
+
+       /*
+        * We get a pen down reading on every reading, report pen up if any
+        * individual reading does so.
+        */
+       wm831x_ts->pen_down = true;
+       for (i = 0; i < count; i++) {
+               if (!(data[i] & WM831X_TCH_PD)) {
+                       wm831x_ts->pen_down = false;
+                       continue;
+               }
+               input_report_abs(wm831x_ts->input_dev, data_types[i],
+                                data[i] & WM831X_TCH_DATA_MASK);
+       }
+
+       if (!wm831x_ts->pen_down) {
+               disable_irq_nosync(wm831x_ts->data_irq);
+
+               /* Don't need data any more */
+               wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                               WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+                               WM831X_TCH_Z_ENA, 0);
+
+               /* Flush any final samples that arrived while reading */
+               wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+                               WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);
+
+               wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data);
+
+               if (wm831x_ts->pressure)
+                       input_report_abs(wm831x_ts->input_dev,
+                                        ABS_PRESSURE, 0);
+
+               input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0);
+       }
+
+       input_sync(wm831x_ts->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
+{
+       struct wm831x_ts *wm831x_ts = irq_data;
+       struct wm831x *wm831x = wm831x_ts->wm831x;
+       int ena = 0;
+
+       /* Start collecting data */
+       if (wm831x_ts->pressure)
+               ena |= WM831X_TCH_Z_ENA;
+
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                       WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA,
+                       WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena);
+
+       input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
+       input_sync(wm831x_ts->input_dev);
+
+       wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+                       WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
+
+       wm831x_ts->pen_down = true;
+       enable_irq(wm831x_ts->data_irq);
+
+       return IRQ_HANDLED;
+}
+
+static int wm831x_ts_input_open(struct input_dev *idev)
+{
+       struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
+       struct wm831x *wm831x = wm831x_ts->wm831x;
+
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                       WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
+                       WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+                       WM831X_TCH_Z_ENA, WM831X_TCH_ENA);
+
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                       WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA);
+
+       return 0;
+}
+
+static void wm831x_ts_input_close(struct input_dev *idev)
+{
+       struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
+       struct wm831x *wm831x = wm831x_ts->wm831x;
+
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                       WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
+                       WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+                       WM831X_TCH_Z_ENA, 0);
+
+       if (wm831x_ts->pen_down)
+               disable_irq(wm831x_ts->data_irq);
+}
+
+static __devinit int wm831x_ts_probe(struct platform_device *pdev)
+{
+       struct wm831x_ts *wm831x_ts;
+       struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent);
+       struct wm831x_touch_pdata *pdata = NULL;
+       struct input_dev *input_dev;
+       int error;
+
+       if (core_pdata)
+               pdata = core_pdata->touch;
+
+       wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!wm831x_ts || !input_dev) {
+               error = -ENOMEM;
+               goto err_alloc;
+       }
+
+       wm831x_ts->wm831x = wm831x;
+       wm831x_ts->input_dev = input_dev;
+
+       /*
+        * If we have a direct IRQ use it, otherwise use the interrupt
+        * from the WM831x IRQ controller.
+        */
+       if (pdata && pdata->data_irq)
+               wm831x_ts->data_irq = pdata->data_irq;
+       else
+               wm831x_ts->data_irq = platform_get_irq_byname(pdev, "TCHDATA");
+
+       if (pdata && pdata->pd_irq)
+               wm831x_ts->pd_irq = pdata->pd_irq;
+       else
+               wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD");
+
+       if (pdata)
+               wm831x_ts->pressure = pdata->pressure;
+       else
+               wm831x_ts->pressure = true;
+
+       /* Five wire touchscreens can't report pressure */
+       if (pdata && pdata->fivewire) {
+               wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+                               WM831X_TCH_5WIRE, WM831X_TCH_5WIRE);
+
+               /* Pressure measurements are not possible for five wire mode */
+               WARN_ON(pdata->pressure && pdata->fivewire);
+               wm831x_ts->pressure = false;
+       } else {
+               wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+                               WM831X_TCH_5WIRE, 0);
+       }
+
+       if (pdata) {
+               switch (pdata->isel) {
+               default:
+                       dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n",
+                               pdata->isel);
+                       /* Fall through */
+               case 200:
+               case 0:
+                       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+                                       WM831X_TCH_ISEL, 0);
+                       break;
+               case 400:
+                       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+                                       WM831X_TCH_ISEL, WM831X_TCH_ISEL);
+                       break;
+               }
+       }
+
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+                       WM831X_TCH_PDONLY, 0);
+
+       /* Default to 96 samples/sec */
+       wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+                       WM831X_TCH_RATE_MASK, 6);
+
+       error = request_threaded_irq(wm831x_ts->data_irq,
+                                    NULL, wm831x_ts_data_irq,
+                                    IRQF_ONESHOT,
+                                    "Touchscreen data", wm831x_ts);
+       if (error) {
+               dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n",
+                       wm831x_ts->data_irq, error);
+               goto err_alloc;
+       }
+       disable_irq(wm831x_ts->data_irq);
+
+       error = request_threaded_irq(wm831x_ts->pd_irq,
+                                    NULL, wm831x_ts_pen_down_irq,
+                                    IRQF_ONESHOT,
+                                    "Touchscreen pen down", wm831x_ts);
+       if (error) {
+               dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n",
+                       wm831x_ts->pd_irq, error);
+               goto err_data_irq;
+       }
+
+       /* set up touch configuration */
+       input_dev->name = "WM831x touchscreen";
+       input_dev->phys = "wm831x";
+       input_dev->open = wm831x_ts_input_open;
+       input_dev->close = wm831x_ts_input_close;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+
+       input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0);
+       if (wm831x_ts->pressure)
+               input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0);
+
+       input_set_drvdata(input_dev, wm831x_ts);
+       input_dev->dev.parent = &pdev->dev;
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_pd_irq;
+
+       platform_set_drvdata(pdev, wm831x_ts);
+       return 0;
+
+err_pd_irq:
+       free_irq(wm831x_ts->pd_irq, wm831x_ts);
+err_data_irq:
+       free_irq(wm831x_ts->data_irq, wm831x_ts);
+err_alloc:
+       input_free_device(input_dev);
+       kfree(wm831x_ts);
+
+       return error;
+}
+
+static __devexit int wm831x_ts_remove(struct platform_device *pdev)
+{
+       struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev);
+
+       free_irq(wm831x_ts->pd_irq, wm831x_ts);
+       free_irq(wm831x_ts->data_irq, wm831x_ts);
+       input_unregister_device(wm831x_ts->input_dev);
+       kfree(wm831x_ts);
+
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver wm831x_ts_driver = {
+       .driver = {
+               .name = "wm831x-touch",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm831x_ts_probe,
+       .remove = __devexit_p(wm831x_ts_remove),
+};
+
+static int __init wm831x_ts_init(void)
+{
+       return platform_driver_register(&wm831x_ts_driver);
+}
+module_init(wm831x_ts_init);
+
+static void __exit wm831x_ts_exit(void)
+{
+       platform_driver_unregister(&wm831x_ts_driver);
+}
+module_exit(wm831x_ts_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM831x PMIC touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-touch");
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
deleted file mode 100644 (file)
index 7f85a86..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Xen para-virtual input device
- *
- * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
- * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
- *
- *  Based on linux/drivers/input/mouse/sermouse.c
- *
- *  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.
- */
-
-/*
- * TODO:
- *
- * Switch to grant tables together with xen-fbfront.c.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-
-#include <asm/xen/hypervisor.h>
-
-#include <xen/xen.h>
-#include <xen/events.h>
-#include <xen/page.h>
-#include <xen/interface/io/fbif.h>
-#include <xen/interface/io/kbdif.h>
-#include <xen/xenbus.h>
-
-struct xenkbd_info {
-       struct input_dev *kbd;
-       struct input_dev *ptr;
-       struct xenkbd_page *page;
-       int irq;
-       struct xenbus_device *xbdev;
-       char phys[32];
-};
-
-static int xenkbd_remove(struct xenbus_device *);
-static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
-static void xenkbd_disconnect_backend(struct xenkbd_info *);
-
-/*
- * Note: if you need to send out events, see xenfb_do_update() for how
- * to do that.
- */
-
-static irqreturn_t input_handler(int rq, void *dev_id)
-{
-       struct xenkbd_info *info = dev_id;
-       struct xenkbd_page *page = info->page;
-       __u32 cons, prod;
-
-       prod = page->in_prod;
-       if (prod == page->in_cons)
-               return IRQ_HANDLED;
-       rmb();                  /* ensure we see ring contents up to prod */
-       for (cons = page->in_cons; cons != prod; cons++) {
-               union xenkbd_in_event *event;
-               struct input_dev *dev;
-               event = &XENKBD_IN_RING_REF(page, cons);
-
-               dev = info->ptr;
-               switch (event->type) {
-               case XENKBD_TYPE_MOTION:
-                       input_report_rel(dev, REL_X, event->motion.rel_x);
-                       input_report_rel(dev, REL_Y, event->motion.rel_y);
-                       if (event->motion.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->motion.rel_z);
-                       break;
-               case XENKBD_TYPE_KEY:
-                       dev = NULL;
-                       if (test_bit(event->key.keycode, info->kbd->keybit))
-                               dev = info->kbd;
-                       if (test_bit(event->key.keycode, info->ptr->keybit))
-                               dev = info->ptr;
-                       if (dev)
-                               input_report_key(dev, event->key.keycode,
-                                                event->key.pressed);
-                       else
-                               pr_warning("unhandled keycode 0x%x\n",
-                                          event->key.keycode);
-                       break;
-               case XENKBD_TYPE_POS:
-                       input_report_abs(dev, ABS_X, event->pos.abs_x);
-                       input_report_abs(dev, ABS_Y, event->pos.abs_y);
-                       if (event->pos.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->pos.rel_z);
-                       break;
-               }
-               if (dev)
-                       input_sync(dev);
-       }
-       mb();                   /* ensure we got ring contents */
-       page->in_cons = cons;
-       notify_remote_via_irq(info->irq);
-
-       return IRQ_HANDLED;
-}
-
-static int __devinit xenkbd_probe(struct xenbus_device *dev,
-                                 const struct xenbus_device_id *id)
-{
-       int ret, i;
-       struct xenkbd_info *info;
-       struct input_dev *kbd, *ptr;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
-               return -ENOMEM;
-       }
-       dev_set_drvdata(&dev->dev, info);
-       info->xbdev = dev;
-       info->irq = -1;
-       snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
-
-       info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
-       if (!info->page)
-               goto error_nomem;
-
-       /* keyboard */
-       kbd = input_allocate_device();
-       if (!kbd)
-               goto error_nomem;
-       kbd->name = "Xen Virtual Keyboard";
-       kbd->phys = info->phys;
-       kbd->id.bustype = BUS_PCI;
-       kbd->id.vendor = 0x5853;
-       kbd->id.product = 0xffff;
-       kbd->evbit[0] = BIT(EV_KEY);
-       for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
-               set_bit(i, kbd->keybit);
-       for (i = KEY_OK; i < KEY_MAX; i++)
-               set_bit(i, kbd->keybit);
-
-       ret = input_register_device(kbd);
-       if (ret) {
-               input_free_device(kbd);
-               xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
-               goto error;
-       }
-       info->kbd = kbd;
-
-       /* pointing device */
-       ptr = input_allocate_device();
-       if (!ptr)
-               goto error_nomem;
-       ptr->name = "Xen Virtual Pointer";
-       ptr->phys = info->phys;
-       ptr->id.bustype = BUS_PCI;
-       ptr->id.vendor = 0x5853;
-       ptr->id.product = 0xfffe;
-       ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
-       for (i = BTN_LEFT; i <= BTN_TASK; i++)
-               set_bit(i, ptr->keybit);
-       ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
-       input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
-       input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
-
-       ret = input_register_device(ptr);
-       if (ret) {
-               input_free_device(ptr);
-               xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
-               goto error;
-       }
-       info->ptr = ptr;
-
-       ret = xenkbd_connect_backend(dev, info);
-       if (ret < 0)
-               goto error;
-
-       return 0;
-
- error_nomem:
-       ret = -ENOMEM;
-       xenbus_dev_fatal(dev, ret, "allocating device memory");
- error:
-       xenkbd_remove(dev);
-       return ret;
-}
-
-static int xenkbd_resume(struct xenbus_device *dev)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-
-       xenkbd_disconnect_backend(info);
-       memset(info->page, 0, PAGE_SIZE);
-       return xenkbd_connect_backend(dev, info);
-}
-
-static int xenkbd_remove(struct xenbus_device *dev)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-
-       xenkbd_disconnect_backend(info);
-       if (info->kbd)
-               input_unregister_device(info->kbd);
-       if (info->ptr)
-               input_unregister_device(info->ptr);
-       free_page((unsigned long)info->page);
-       kfree(info);
-       return 0;
-}
-
-static int xenkbd_connect_backend(struct xenbus_device *dev,
-                                 struct xenkbd_info *info)
-{
-       int ret, evtchn;
-       struct xenbus_transaction xbt;
-
-       ret = xenbus_alloc_evtchn(dev, &evtchn);
-       if (ret)
-               return ret;
-       ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
-                                       0, dev->devicetype, info);
-       if (ret < 0) {
-               xenbus_free_evtchn(dev, evtchn);
-               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
-               return ret;
-       }
-       info->irq = ret;
-
- again:
-       ret = xenbus_transaction_start(&xbt);
-       if (ret) {
-               xenbus_dev_fatal(dev, ret, "starting transaction");
-               return ret;
-       }
-       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
-                           virt_to_mfn(info->page));
-       if (ret)
-               goto error_xenbus;
-       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
-                           evtchn);
-       if (ret)
-               goto error_xenbus;
-       ret = xenbus_transaction_end(xbt, 0);
-       if (ret) {
-               if (ret == -EAGAIN)
-                       goto again;
-               xenbus_dev_fatal(dev, ret, "completing transaction");
-               return ret;
-       }
-
-       xenbus_switch_state(dev, XenbusStateInitialised);
-       return 0;
-
- error_xenbus:
-       xenbus_transaction_end(xbt, 1);
-       xenbus_dev_fatal(dev, ret, "writing xenstore");
-       return ret;
-}
-
-static void xenkbd_disconnect_backend(struct xenkbd_info *info)
-{
-       if (info->irq >= 0)
-               unbind_from_irqhandler(info->irq, info);
-       info->irq = -1;
-}
-
-static void xenkbd_backend_changed(struct xenbus_device *dev,
-                                  enum xenbus_state backend_state)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-       int ret, val;
-
-       switch (backend_state) {
-       case XenbusStateInitialising:
-       case XenbusStateInitialised:
-       case XenbusStateReconfiguring:
-       case XenbusStateReconfigured:
-       case XenbusStateUnknown:
-       case XenbusStateClosed:
-               break;
-
-       case XenbusStateInitWait:
-InitWait:
-               ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                  "feature-abs-pointer", "%d", &val);
-               if (ret < 0)
-                       val = 0;
-               if (val) {
-                       ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
-                                           "request-abs-pointer", "1");
-                       if (ret)
-                               pr_warning("can't request abs-pointer\n");
-               }
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
-       case XenbusStateConnected:
-               /*
-                * Work around xenbus race condition: If backend goes
-                * through InitWait to Connected fast enough, we can
-                * get Connected twice here.
-                */
-               if (dev->state != XenbusStateConnected)
-                       goto InitWait; /* no InitWait seen yet, fudge it */
-
-               /* Set input abs params to match backend screen res */
-               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                "width", "%d", &val) > 0)
-                       input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
-
-               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                "height", "%d", &val) > 0)
-                       input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
-
-               break;
-
-       case XenbusStateClosing:
-               xenbus_frontend_closed(dev);
-               break;
-       }
-}
-
-static const struct xenbus_device_id xenkbd_ids[] = {
-       { "vkbd" },
-       { "" }
-};
-
-static struct xenbus_driver xenkbd_driver = {
-       .name = "vkbd",
-       .owner = THIS_MODULE,
-       .ids = xenkbd_ids,
-       .probe = xenkbd_probe,
-       .remove = xenkbd_remove,
-       .resume = xenkbd_resume,
-       .otherend_changed = xenkbd_backend_changed,
-};
-
-static int __init xenkbd_init(void)
-{
-       if (!xen_pv_domain())
-               return -ENODEV;
-
-       /* Nothing to do if running in dom0. */
-       if (xen_initial_domain())
-               return -ENODEV;
-
-       return xenbus_register_frontend(&xenkbd_driver);
-}
-
-static void __exit xenkbd_cleanup(void)
-{
-       xenbus_unregister_driver(&xenkbd_driver);
-}
-
-module_init(xenkbd_init);
-module_exit(xenkbd_cleanup);
-
-MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("xen:vkbd");
index ab638b083df9cfffb79071b7a313a5c2663eab4b..646368fe41c94a7a6444b3ce8023663c79cf0308 100644 (file)
@@ -4,7 +4,7 @@
 
 # Define maximum number of cards
 
-EXTRA_CFLAGS      += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
+ccflags-y      := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
 
 obj-$(CONFIG_ISDN_DRV_HISAX)           += hisax.o
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)       += sedlbauer_cs.o
index 6f190f4cdbc00e4917c457dcd004060c3b8976ba..9bec8699b8a327e107ddeb4fcfadb01e588c54e7 100644 (file)
@@ -34,6 +34,16 @@ config LEDS_ATMEL_PWM
          This option enables support for LEDs driven using outputs
          of the dedicated PWM controller found on newer Atmel SOCs.
 
+config LEDS_LM3530
+       tristate "LCD Backlight driver for LM3530"
+       depends on LEDS_CLASS
+       depends on I2C
+       help
+         This option enables support for the LCD backlight using
+         LM3530 ambient light sensor chip. This ALS chip can be
+         controlled manually or using PWM input or using ambient
+         light automatically.
+
 config LEDS_LOCOMO
        tristate "LED Support for Locomo device"
        depends on LEDS_CLASS
index aae6989ff6b63445e6b6c974df537f0f0784fe3f..39c80fca84d276e3327ec4a69a902a85ebc6ae44 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_LEDS_88PM860X)             += leds-88pm860x.o
 obj-$(CONFIG_LEDS_ATMEL_PWM)           += leds-atmel-pwm.o
 obj-$(CONFIG_LEDS_BD2802)              += leds-bd2802.o
 obj-$(CONFIG_LEDS_LOCOMO)              += leds-locomo.o
+obj-$(CONFIG_LEDS_LM3530)              += leds-lm3530.o
 obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
index c41eb6180c9c2eb2e88ce2dfbfc64d7ff90daf2a..4bebae733349b90f84230d1b4454942cc9744451 100644 (file)
@@ -231,6 +231,26 @@ void led_trigger_event(struct led_trigger *trigger,
 }
 EXPORT_SYMBOL_GPL(led_trigger_event);
 
+void led_trigger_blink(struct led_trigger *trigger,
+                      unsigned long *delay_on,
+                      unsigned long *delay_off)
+{
+       struct list_head *entry;
+
+       if (!trigger)
+               return;
+
+       read_lock(&trigger->leddev_list_lock);
+       list_for_each(entry, &trigger->led_cdevs) {
+               struct led_classdev *led_cdev;
+
+               led_cdev = list_entry(entry, struct led_classdev, trig_list);
+               led_blink_set(led_cdev, delay_on, delay_off);
+       }
+       read_unlock(&trigger->leddev_list_lock);
+}
+EXPORT_SYMBOL_GPL(led_trigger_blink);
+
 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 {
        struct led_trigger *trigger;
index e672b44ee1723491f3bdee869a69cb286f381bf7..416def84d0459e5a5c3a9708261d12fdf76280a6 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/leds.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 
 #define LED_PWM_SHIFT          (3)
@@ -118,7 +119,8 @@ static void pm860x_led_work(struct work_struct *work)
 
        struct pm860x_led *led;
        struct pm860x_chip *chip;
-       int mask;
+       unsigned char buf[3];
+       int mask, ret;
 
        led = container_of(work, struct pm860x_led, work);
        chip = led->chip;
@@ -128,16 +130,27 @@ static void pm860x_led_work(struct work_struct *work)
                        pm860x_set_bits(led->i2c, __led_off(led->port),
                                        LED_CURRENT_MASK, led->iset);
                }
+               pm860x_set_bits(led->i2c, __blink_off(led->port),
+                               LED_BLINK_MASK, LED_ON_CONTINUOUS);
                mask = __blink_ctl_mask(led->port);
                pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
-       } else if (led->brightness == 0) {
-               pm860x_set_bits(led->i2c, __led_off(led->port),
-                               LED_CURRENT_MASK, 0);
-               mask = __blink_ctl_mask(led->port);
-               pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
        }
        pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK,
                        led->brightness);
+
+       if (led->brightness == 0) {
+               pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf);
+               ret = buf[0] & LED_PWM_MASK;
+               ret |= buf[1] & LED_PWM_MASK;
+               ret |= buf[2] & LED_PWM_MASK;
+               if (ret == 0) {
+                       /* unset current since no led is lighting */
+                       pm860x_set_bits(led->i2c, __led_off(led->port),
+                                       LED_CURRENT_MASK, 0);
+                       mask = __blink_ctl_mask(led->port);
+                       pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+               }
+       }
        led->current_brightness = led->brightness;
        dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
                __led_off(led->port), led->brightness);
@@ -153,31 +166,12 @@ static void pm860x_led_set(struct led_classdev *cdev,
        schedule_work(&data->work);
 }
 
-static int __check_device(struct pm860x_led_pdata *pdata, char *name)
-{
-       struct pm860x_led_pdata *p = pdata;
-       int ret = -EINVAL;
-
-       while (p && p->id) {
-               if ((p->id != PM8606_ID_LED) || (p->flags < 0))
-                       break;
-
-               if (!strncmp(name, pm860x_led_name[p->flags],
-                       MFD_NAME_SIZE)) {
-                       ret = (int)p->flags;
-                       break;
-               }
-               p++;
-       }
-       return ret;
-}
-
 static int pm860x_led_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct pm860x_platform_data *pm860x_pdata;
        struct pm860x_led_pdata *pdata;
        struct pm860x_led *data;
+       struct mfd_cell *cell;
        struct resource *res;
        int ret;
 
@@ -187,10 +181,11 @@ static int pm860x_led_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (pdev->dev.parent->platform_data) {
-               pm860x_pdata = pdev->dev.parent->platform_data;
-               pdata = pm860x_pdata->led;
-       } else {
+       cell = pdev->dev.platform_data;
+       if (cell == NULL)
+               return -ENODEV;
+       pdata = cell->mfd_data;
+       if (pdata == NULL) {
                dev_err(&pdev->dev, "No platform data!\n");
                return -EINVAL;
        }
@@ -198,12 +193,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
        data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
-       strncpy(data->name, res->name, MFD_NAME_SIZE);
+       strncpy(data->name, res->name, MFD_NAME_SIZE - 1);
        dev_set_drvdata(&pdev->dev, data);
        data->chip = chip;
        data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
        data->iset = pdata->iset;
-       data->port = __check_device(pdata, data->name);
+       data->port = pdata->flags;
        if (data->port < 0) {
                dev_err(&pdev->dev, "check device failed\n");
                kfree(data);
@@ -221,6 +216,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
                goto out;
        }
+       pm860x_led_set(&data->cdev, 0);
        return 0;
 out:
        kfree(data);
index 19dc4b61a1055220b0308434c30f7028bdcfb2df..3ebe3824662d6d4da520d3172be1e0789efa0be2 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/leds.h>
 #include <linux/leds-bd2802.h>
 #include <linux/slab.h>
-
+#include <linux/pm.h>
 
 #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
 
@@ -319,20 +319,6 @@ static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
        bd2802_update_state(led, id, color, BD2802_OFF);
 }
 
-static void bd2802_restore_state(struct bd2802_led *led)
-{
-       int i;
-
-       for (i = 0; i < LED_NUM; i++) {
-               if (led->led[i].r)
-                       bd2802_turn_on(led, i, RED, led->led[i].r);
-               if (led->led[i].g)
-                       bd2802_turn_on(led, i, GREEN, led->led[i].g);
-               if (led->led[i].b)
-                       bd2802_turn_on(led, i, BLUE, led->led[i].b);
-       }
-}
-
 #define BD2802_SET_REGISTER(reg_addr, reg_name)                                \
 static ssize_t bd2802_store_reg##reg_addr(struct device *dev,          \
        struct device_attribute *attr, const char *buf, size_t count)   \
@@ -761,8 +747,25 @@ static int __exit bd2802_remove(struct i2c_client *client)
        return 0;
 }
 
-static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM
+
+static void bd2802_restore_state(struct bd2802_led *led)
 {
+       int i;
+
+       for (i = 0; i < LED_NUM; i++) {
+               if (led->led[i].r)
+                       bd2802_turn_on(led, i, RED, led->led[i].r);
+               if (led->led[i].g)
+                       bd2802_turn_on(led, i, GREEN, led->led[i].g);
+               if (led->led[i].b)
+                       bd2802_turn_on(led, i, BLUE, led->led[i].b);
+       }
+}
+
+static int bd2802_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
        struct bd2802_led *led = i2c_get_clientdata(client);
 
        gpio_set_value(led->pdata->reset_gpio, 0);
@@ -770,8 +773,9 @@ static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int bd2802_resume(struct i2c_client *client)
+static int bd2802_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct bd2802_led *led = i2c_get_clientdata(client);
 
        if (!bd2802_is_all_off(led) || led->adf_on) {
@@ -782,6 +786,12 @@ static int bd2802_resume(struct i2c_client *client)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
+#define BD2802_PM (&bd2802_pm)
+#else          /* CONFIG_PM */
+#define BD2802_PM NULL
+#endif
+
 static const struct i2c_device_id bd2802_id[] = {
        { "BD2802", 0 },
        { }
@@ -791,11 +801,10 @@ MODULE_DEVICE_TABLE(i2c, bd2802_id);
 static struct i2c_driver bd2802_i2c_driver = {
        .driver = {
                .name   = "BD2802",
+               .pm     = BD2802_PM,
        },
        .probe          = bd2802_probe,
        .remove         = __exit_p(bd2802_remove),
-       .suspend        = bd2802_suspend,
-       .resume         = bd2802_resume,
        .id_table       = bd2802_id,
 };
 
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
new file mode 100644 (file)
index 0000000..e7089a1
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2011 ST-Ericsson SA.
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Simple driver for National Semiconductor LM3530 Backlight driver chip
+ *
+ * Author: Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>
+ * based on leds-lm3530.c by Dan Murphy <D.Murphy@motorola.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/led-lm3530.h>
+#include <linux/types.h>
+
+#define LM3530_LED_DEV "lcd-backlight"
+#define LM3530_NAME "lm3530-led"
+
+#define LM3530_GEN_CONFIG              0x10
+#define LM3530_ALS_CONFIG              0x20
+#define LM3530_BRT_RAMP_RATE           0x30
+#define LM3530_ALS_ZONE_REG            0x40
+#define LM3530_ALS_IMP_SELECT          0x41
+#define LM3530_BRT_CTRL_REG            0xA0
+#define LM3530_ALS_ZB0_REG             0x60
+#define LM3530_ALS_ZB1_REG             0x61
+#define LM3530_ALS_ZB2_REG             0x62
+#define LM3530_ALS_ZB3_REG             0x63
+#define LM3530_ALS_Z0T_REG             0x70
+#define LM3530_ALS_Z1T_REG             0x71
+#define LM3530_ALS_Z2T_REG             0x72
+#define LM3530_ALS_Z3T_REG             0x73
+#define LM3530_ALS_Z4T_REG             0x74
+#define LM3530_REG_MAX                 15
+
+/* General Control Register */
+#define LM3530_EN_I2C_SHIFT            (0)
+#define LM3530_RAMP_LAW_SHIFT          (1)
+#define LM3530_MAX_CURR_SHIFT          (2)
+#define LM3530_EN_PWM_SHIFT            (5)
+#define LM3530_PWM_POL_SHIFT           (6)
+#define LM3530_EN_PWM_SIMPLE_SHIFT     (7)
+
+#define LM3530_ENABLE_I2C              (1 << LM3530_EN_I2C_SHIFT)
+#define LM3530_ENABLE_PWM              (1 << LM3530_EN_PWM_SHIFT)
+#define LM3530_POL_LOW                 (1 << LM3530_PWM_POL_SHIFT)
+#define LM3530_ENABLE_PWM_SIMPLE       (1 << LM3530_EN_PWM_SIMPLE_SHIFT)
+
+/* ALS Config Register Options */
+#define LM3530_ALS_AVG_TIME_SHIFT      (0)
+#define LM3530_EN_ALS_SHIFT            (3)
+#define LM3530_ALS_SEL_SHIFT           (5)
+
+#define LM3530_ENABLE_ALS              (3 << LM3530_EN_ALS_SHIFT)
+
+/* Brightness Ramp Rate Register */
+#define LM3530_BRT_RAMP_FALL_SHIFT     (0)
+#define LM3530_BRT_RAMP_RISE_SHIFT     (3)
+
+/* ALS Resistor Select */
+#define LM3530_ALS1_IMP_SHIFT          (0)
+#define LM3530_ALS2_IMP_SHIFT          (4)
+
+/* Zone Boundary Register defaults */
+#define LM3530_DEF_ZB_0                        (0x33)
+#define LM3530_DEF_ZB_1                        (0x66)
+#define LM3530_DEF_ZB_2                        (0x99)
+#define LM3530_DEF_ZB_3                        (0xCC)
+
+/* Zone Target Register defaults */
+#define LM3530_DEF_ZT_0                        (0x19)
+#define LM3530_DEF_ZT_1                        (0x33)
+#define LM3530_DEF_ZT_2                        (0x4C)
+#define LM3530_DEF_ZT_3                        (0x66)
+#define LM3530_DEF_ZT_4                        (0x7F)
+
+struct lm3530_mode_map {
+       const char *mode;
+       enum lm3530_mode mode_val;
+};
+
+static struct lm3530_mode_map mode_map[] = {
+       { "man", LM3530_BL_MODE_MANUAL },
+       { "als", LM3530_BL_MODE_ALS },
+       { "pwm", LM3530_BL_MODE_PWM },
+};
+
+/**
+ * struct lm3530_data
+ * @led_dev: led class device
+ * @client: i2c client
+ * @pdata: LM3530 platform data
+ * @mode: mode of operation - manual, ALS, PWM
+ */
+struct lm3530_data {
+       struct led_classdev led_dev;
+       struct i2c_client *client;
+       struct lm3530_platform_data *pdata;
+       enum lm3530_mode mode;
+};
+
+static const u8 lm3530_reg[LM3530_REG_MAX] = {
+       LM3530_GEN_CONFIG,
+       LM3530_ALS_CONFIG,
+       LM3530_BRT_RAMP_RATE,
+       LM3530_ALS_ZONE_REG,
+       LM3530_ALS_IMP_SELECT,
+       LM3530_BRT_CTRL_REG,
+       LM3530_ALS_ZB0_REG,
+       LM3530_ALS_ZB1_REG,
+       LM3530_ALS_ZB2_REG,
+       LM3530_ALS_ZB3_REG,
+       LM3530_ALS_Z0T_REG,
+       LM3530_ALS_Z1T_REG,
+       LM3530_ALS_Z2T_REG,
+       LM3530_ALS_Z3T_REG,
+       LM3530_ALS_Z4T_REG,
+};
+
+static int lm3530_get_mode_from_str(const char *str)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mode_map); i++)
+               if (sysfs_streq(str, mode_map[i].mode))
+                       return mode_map[i].mode_val;
+
+       return -1;
+}
+
+static int lm3530_init_registers(struct lm3530_data *drvdata)
+{
+       int ret = 0;
+       int i;
+       u8 gen_config;
+       u8 als_config = 0;
+       u8 brt_ramp;
+       u8 als_imp_sel = 0;
+       u8 brightness;
+       u8 reg_val[LM3530_REG_MAX];
+       struct lm3530_platform_data *pltfm = drvdata->pdata;
+       struct i2c_client *client = drvdata->client;
+
+       gen_config = (pltfm->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
+                       ((pltfm->max_current & 7) << LM3530_MAX_CURR_SHIFT);
+
+       if (drvdata->mode == LM3530_BL_MODE_MANUAL ||
+           drvdata->mode == LM3530_BL_MODE_ALS)
+               gen_config |= (LM3530_ENABLE_I2C);
+
+       if (drvdata->mode == LM3530_BL_MODE_ALS) {
+               als_config =
+                       (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
+                       (LM3530_ENABLE_ALS) |
+                       (pltfm->als_input_mode << LM3530_ALS_SEL_SHIFT);
+
+               als_imp_sel =
+                       (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
+                       (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
+       }
+
+       if (drvdata->mode == LM3530_BL_MODE_PWM)
+               gen_config |= (LM3530_ENABLE_PWM) |
+                               (pltfm->pwm_pol_hi << LM3530_PWM_POL_SHIFT) |
+                               (LM3530_ENABLE_PWM_SIMPLE);
+
+       brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
+                       (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
+
+       brightness = pltfm->brt_val;
+
+       reg_val[0] = gen_config;        /* LM3530_GEN_CONFIG */
+       reg_val[1] = als_config;        /* LM3530_ALS_CONFIG */
+       reg_val[2] = brt_ramp;          /* LM3530_BRT_RAMP_RATE */
+       reg_val[3] = 0x00;              /* LM3530_ALS_ZONE_REG */
+       reg_val[4] = als_imp_sel;       /* LM3530_ALS_IMP_SELECT */
+       reg_val[5] = brightness;        /* LM3530_BRT_CTRL_REG */
+       reg_val[6] = LM3530_DEF_ZB_0;   /* LM3530_ALS_ZB0_REG */
+       reg_val[7] = LM3530_DEF_ZB_1;   /* LM3530_ALS_ZB1_REG */
+       reg_val[8] = LM3530_DEF_ZB_2;   /* LM3530_ALS_ZB2_REG */
+       reg_val[9] = LM3530_DEF_ZB_3;   /* LM3530_ALS_ZB3_REG */
+       reg_val[10] = LM3530_DEF_ZT_0;  /* LM3530_ALS_Z0T_REG */
+       reg_val[11] = LM3530_DEF_ZT_1;  /* LM3530_ALS_Z1T_REG */
+       reg_val[12] = LM3530_DEF_ZT_2;  /* LM3530_ALS_Z2T_REG */
+       reg_val[13] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
+       reg_val[14] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
+
+       for (i = 0; i < LM3530_REG_MAX; i++) {
+               ret = i2c_smbus_write_byte_data(client,
+                               lm3530_reg[i], reg_val[i]);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static void lm3530_brightness_set(struct led_classdev *led_cdev,
+                                    enum led_brightness brt_val)
+{
+       int err;
+       struct lm3530_data *drvdata =
+           container_of(led_cdev, struct lm3530_data, led_dev);
+
+       switch (drvdata->mode) {
+       case LM3530_BL_MODE_MANUAL:
+
+               /* set the brightness in brightness control register*/
+               err = i2c_smbus_write_byte_data(drvdata->client,
+                               LM3530_BRT_CTRL_REG, brt_val / 2);
+               if (err)
+                       dev_err(&drvdata->client->dev,
+                               "Unable to set brightness: %d\n", err);
+               break;
+       case LM3530_BL_MODE_ALS:
+               break;
+       case LM3530_BL_MODE_PWM:
+               break;
+       default:
+               break;
+       }
+}
+
+
+static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
+                                  *attr, const char *buf, size_t size)
+{
+       int err;
+       struct i2c_client *client = container_of(
+                                       dev->parent, struct i2c_client, dev);
+       struct lm3530_data *drvdata = i2c_get_clientdata(client);
+       int mode;
+
+       mode = lm3530_get_mode_from_str(buf);
+       if (mode < 0) {
+               dev_err(dev, "Invalid mode\n");
+               return -EINVAL;
+       }
+
+       if (mode == LM3530_BL_MODE_MANUAL)
+               drvdata->mode = LM3530_BL_MODE_MANUAL;
+       else if (mode == LM3530_BL_MODE_ALS)
+               drvdata->mode = LM3530_BL_MODE_ALS;
+       else if (mode == LM3530_BL_MODE_PWM) {
+               dev_err(dev, "PWM mode not supported\n");
+               return -EINVAL;
+       }
+
+       err = lm3530_init_registers(drvdata);
+       if (err) {
+               dev_err(dev, "Setting %s Mode failed :%d\n", buf, err);
+               return err;
+       }
+
+       return sizeof(drvdata->mode);
+}
+
+static DEVICE_ATTR(mode, 0644, NULL, lm3530_mode_set);
+
+static int __devinit lm3530_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
+{
+       struct lm3530_platform_data *pdata = client->dev.platform_data;
+       struct lm3530_data *drvdata;
+       int err = 0;
+
+       if (pdata == NULL) {
+               dev_err(&client->dev, "platform data required\n");
+               err = -ENODEV;
+               goto err_out;
+       }
+
+       /* BL mode */
+       if (pdata->mode > LM3530_BL_MODE_PWM) {
+               dev_err(&client->dev, "Illegal Mode request\n");
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "I2C_FUNC_I2C not supported\n");
+               err = -EIO;
+               goto err_out;
+       }
+
+       drvdata = kzalloc(sizeof(struct lm3530_data), GFP_KERNEL);
+       if (drvdata == NULL) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       drvdata->mode = pdata->mode;
+       drvdata->client = client;
+       drvdata->pdata = pdata;
+       drvdata->led_dev.name = LM3530_LED_DEV;
+       drvdata->led_dev.brightness_set = lm3530_brightness_set;
+
+       i2c_set_clientdata(client, drvdata);
+
+       err = lm3530_init_registers(drvdata);
+       if (err < 0) {
+               dev_err(&client->dev, "Register Init failed: %d\n", err);
+               err = -ENODEV;
+               goto err_reg_init;
+       }
+
+       err = led_classdev_register((struct device *)
+                                     &client->dev, &drvdata->led_dev);
+       if (err < 0) {
+               dev_err(&client->dev, "Register led class failed: %d\n", err);
+               err = -ENODEV;
+               goto err_class_register;
+       }
+
+       err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode);
+       if (err < 0) {
+               dev_err(&client->dev, "File device creation failed: %d\n", err);
+               err = -ENODEV;
+               goto err_create_file;
+       }
+
+       return 0;
+
+err_create_file:
+       led_classdev_unregister(&drvdata->led_dev);
+err_class_register:
+err_reg_init:
+       kfree(drvdata);
+err_out:
+       return err;
+}
+
+static int __devexit lm3530_remove(struct i2c_client *client)
+{
+       struct lm3530_data *drvdata = i2c_get_clientdata(client);
+
+       device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
+       led_classdev_unregister(&drvdata->led_dev);
+       kfree(drvdata);
+       return 0;
+}
+
+static const struct i2c_device_id lm3530_id[] = {
+       {LM3530_NAME, 0},
+       {}
+};
+
+static struct i2c_driver lm3530_i2c_driver = {
+       .probe = lm3530_probe,
+       .remove = lm3530_remove,
+       .id_table = lm3530_id,
+       .driver = {
+               .name = LM3530_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init lm3530_init(void)
+{
+       return i2c_add_driver(&lm3530_i2c_driver);
+}
+
+static void __exit lm3530_exit(void)
+{
+       i2c_del_driver(&lm3530_i2c_driver);
+}
+
+module_init(lm3530_init);
+module_exit(lm3530_exit);
+
+MODULE_DESCRIPTION("Back Light driver for LM3530");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>");
index 80a3ae3c00b93de8c542f51ec739b3d8792c2eeb..c0cff64a1ae64240e76c06f2cba931a908435d8a 100644 (file)
@@ -534,7 +534,7 @@ static ssize_t lp5521_selftest(struct device *dev,
 }
 
 /* led class device attributes */
-static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
 
 static struct attribute *lp5521_led_attributes[] = {
@@ -548,15 +548,15 @@ static struct attribute_group lp5521_led_attribute_group = {
 };
 
 /* device attributes */
-static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
                   show_engine1_mode, store_engine1_mode);
-static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
                   show_engine2_mode, store_engine2_mode);
-static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
                   show_engine3_mode, store_engine3_mode);
-static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
-static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
-static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
 static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
 
 static struct attribute *lp5521_attributes[] = {
index d0c4068ecddd771a6c26f808d60c3cc85568bfe3..e19fed25f1376e2632995d71661df0e9d49dc091 100644 (file)
@@ -713,7 +713,7 @@ static ssize_t store_current(struct device *dev,
 }
 
 /* led class device attributes */
-static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
 
 static struct attribute *lp5523_led_attributes[] = {
@@ -727,21 +727,21 @@ static struct attribute_group lp5523_led_attribute_group = {
 };
 
 /* device attributes */
-static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR,
                   show_engine1_mode, store_engine1_mode);
-static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR,
                   show_engine2_mode, store_engine2_mode);
-static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR,
                   show_engine3_mode, store_engine3_mode);
-static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUSR,
                   show_engine1_leds, store_engine1_leds);
-static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUSR,
                   show_engine2_leds, store_engine2_leds);
-static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUSR,
                   show_engine3_leds, store_engine3_leds);
-static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
-static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
-static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
 static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
 
 static struct attribute *lp5523_attributes[] = {
index f05bb08d0f0968e49a51e7b96aeee392c48287d2..06a5bb484707b47dd005504140b1fb9e649aa7b1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/leds.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/mc13783.h>
+#include <linux/mfd/core.h>
 #include <linux/slab.h>
 
 struct mc13783_led {
@@ -183,7 +184,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
 
 static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
        struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
        int ret = 0;
        int reg = 0;
@@ -264,7 +265,7 @@ out:
 
 static int __devinit mc13783_led_probe(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
        struct mc13783_led_platform_data *led_cur;
        struct mc13783_led *led, *led_dat;
        int ret, i;
@@ -351,7 +352,7 @@ err_free:
 
 static int __devexit mc13783_led_remove(struct platform_device *pdev)
 {
-       struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
        struct mc13783_led *led = platform_get_drvdata(pdev);
        struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
        int i;
index 1739557a903881a246c14d5047cca5a454081894..7e764b8365e60c58e7357da121ae0abbacee1029 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <asm/geode.h>
 
-static struct gpio_led net5501_leds[] = {
+static const struct gpio_led net5501_leds[] = {
        {
                .name = "error",
                .gpio = 6,
index ade1e656bfb25b0ce7343af35f53638bfc778018..b1d91170ded00eeb13d93dbdbef3117d131b224b 100644 (file)
@@ -163,6 +163,7 @@ void __init pmu_backlight_init()
        snprintf(name, sizeof(name), "pmubl");
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
                                       &props);
index 98d9ec85e0eb1723a04b2218563a803213b52cd6..8420129fc5eed67693b99812ab565130b8ad1db7 100644 (file)
@@ -327,4 +327,10 @@ config DM_UEVENT
        ---help---
        Generate udev events for DM events.
 
+config DM_FLAKEY
+       tristate "Flakey target (EXPERIMENTAL)"
+       depends on BLK_DEV_DM && EXPERIMENTAL
+       ---help---
+         A target that intermittently fails I/O for debugging purposes.
+
 endif # MD
index d0138606c2e82b74067c0fc775052046c7f6bd8f..448838b1f92a492e30c0c8b86f2ffb014a5e27cf 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_BLK_DEV_MD)      += md-mod.o
 obj-$(CONFIG_BLK_DEV_DM)       += dm-mod.o
 obj-$(CONFIG_DM_CRYPT)         += dm-crypt.o
 obj-$(CONFIG_DM_DELAY)         += dm-delay.o
+obj-$(CONFIG_DM_FLAKEY)                += dm-flakey.o
 obj-$(CONFIG_DM_MULTIPATH)     += dm-multipath.o dm-round-robin.o
 obj-$(CONFIG_DM_MULTIPATH_QL)  += dm-queue-length.o
 obj-$(CONFIG_DM_MULTIPATH_ST)  += dm-service-time.o
index 9a35320fb59f774b0e840d934bd2a16422e99f22..5c9362792f1d928d71ded12a61b919c9ee25e7be 100644 (file)
@@ -347,7 +347,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
                        atomic_inc(&bitmap->pending_writes);
                        set_buffer_locked(bh);
                        set_buffer_mapped(bh);
-                       submit_bh(WRITE | REQ_UNPLUG | REQ_SYNC, bh);
+                       submit_bh(WRITE | REQ_SYNC, bh);
                        bh = bh->b_this_page;
                }
 
@@ -854,7 +854,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
                if (bitmap->flags & BITMAP_HOSTENDIAN)
                        set_bit(bit, kaddr);
                else
-                       ext2_set_bit(bit, kaddr);
+                       __test_and_set_bit_le(bit, kaddr);
                kunmap_atomic(kaddr, KM_USER0);
                PRINTK("set file bit %lu page %lu\n", bit, page->index);
        }
@@ -1050,7 +1050,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
                if (bitmap->flags & BITMAP_HOSTENDIAN)
                        b = test_bit(bit, paddr);
                else
-                       b = ext2_test_bit(bit, paddr);
+                       b = test_bit_le(bit, paddr);
                kunmap_atomic(paddr, KM_USER0);
                if (b) {
                        /* if the disk bit is set, set the memory bit */
@@ -1226,7 +1226,7 @@ void bitmap_daemon_work(mddev_t *mddev)
                                                clear_bit(file_page_offset(bitmap, j),
                                                          paddr);
                                        else
-                                               ext2_clear_bit(file_page_offset(bitmap, j),
+                                               __test_and_clear_bit_le(file_page_offset(bitmap, j),
                                                               paddr);
                                        kunmap_atomic(paddr, KM_USER0);
                                } else
@@ -1339,8 +1339,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
                        prepare_to_wait(&bitmap->overflow_wait, &__wait,
                                        TASK_UNINTERRUPTIBLE);
                        spin_unlock_irq(&bitmap->lock);
-                       md_unplug(bitmap->mddev);
-                       schedule();
+                       io_schedule();
                        finish_wait(&bitmap->overflow_wait, &__wait);
                        continue;
                }
index 4e054bd91664a8047968d51ec313958013b4a8af..c8827ffd85bb961b7e9cad4d54647ea0251fd716 100644 (file)
@@ -991,11 +991,6 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
        clone->bi_destructor = dm_crypt_bio_destructor;
 }
 
-static void kcryptd_unplug(struct crypt_config *cc)
-{
-       blk_unplug(bdev_get_queue(cc->dev->bdev));
-}
-
 static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
 {
        struct crypt_config *cc = io->target->private;
@@ -1008,10 +1003,8 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
         * one in order to decrypt the whole bio data *afterwards*.
         */
        clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs);
-       if (!clone) {
-               kcryptd_unplug(cc);
+       if (!clone)
                return 1;
-       }
 
        crypt_inc_pending(io);
 
@@ -1331,20 +1324,29 @@ static int crypt_setkey_allcpus(struct crypt_config *cc)
 
 static int crypt_set_key(struct crypt_config *cc, char *key)
 {
+       int r = -EINVAL;
+       int key_string_len = strlen(key);
+
        /* The key size may not be changed. */
-       if (cc->key_size != (strlen(key) >> 1))
-               return -EINVAL;
+       if (cc->key_size != (key_string_len >> 1))
+               goto out;
 
        /* Hyphen (which gives a key_size of zero) means there is no key. */
        if (!cc->key_size && strcmp(key, "-"))
-               return -EINVAL;
+               goto out;
 
        if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0)
-               return -EINVAL;
+               goto out;
 
        set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 
-       return crypt_setkey_allcpus(cc);
+       r = crypt_setkey_allcpus(cc);
+
+out:
+       /* Hex key string not needed after here, so wipe it. */
+       memset(key, '0', key_string_len);
+
+       return r;
 }
 
 static int crypt_wipe_key(struct crypt_config *cc)
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
new file mode 100644 (file)
index 0000000..ea79062
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2003 Sistina Software (UK) Limited.
+ * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/device-mapper.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+
+#define DM_MSG_PREFIX "flakey"
+
+/*
+ * Flakey: Used for testing only, simulates intermittent,
+ * catastrophic device failure.
+ */
+struct flakey_c {
+       struct dm_dev *dev;
+       unsigned long start_time;
+       sector_t start;
+       unsigned up_interval;
+       unsigned down_interval;
+};
+
+/*
+ * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval>
+ */
+static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+       struct flakey_c *fc;
+       unsigned long long tmp;
+
+       if (argc != 4) {
+               ti->error = "dm-flakey: Invalid argument count";
+               return -EINVAL;
+       }
+
+       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+       if (!fc) {
+               ti->error = "dm-flakey: Cannot allocate linear context";
+               return -ENOMEM;
+       }
+       fc->start_time = jiffies;
+
+       if (sscanf(argv[1], "%llu", &tmp) != 1) {
+               ti->error = "dm-flakey: Invalid device sector";
+               goto bad;
+       }
+       fc->start = tmp;
+
+       if (sscanf(argv[2], "%u", &fc->up_interval) != 1) {
+               ti->error = "dm-flakey: Invalid up interval";
+               goto bad;
+       }
+
+       if (sscanf(argv[3], "%u", &fc->down_interval) != 1) {
+               ti->error = "dm-flakey: Invalid down interval";
+               goto bad;
+       }
+
+       if (!(fc->up_interval + fc->down_interval)) {
+               ti->error = "dm-flakey: Total (up + down) interval is zero";
+               goto bad;
+       }
+
+       if (fc->up_interval + fc->down_interval < fc->up_interval) {
+               ti->error = "dm-flakey: Interval overflow";
+               goto bad;
+       }
+
+       if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) {
+               ti->error = "dm-flakey: Device lookup failed";
+               goto bad;
+       }
+
+       ti->num_flush_requests = 1;
+       ti->private = fc;
+       return 0;
+
+bad:
+       kfree(fc);
+       return -EINVAL;
+}
+
+static void flakey_dtr(struct dm_target *ti)
+{
+       struct flakey_c *fc = ti->private;
+
+       dm_put_device(ti, fc->dev);
+       kfree(fc);
+}
+
+static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector)
+{
+       struct flakey_c *fc = ti->private;
+
+       return fc->start + (bi_sector - ti->begin);
+}
+
+static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
+{
+       struct flakey_c *fc = ti->private;
+
+       bio->bi_bdev = fc->dev->bdev;
+       if (bio_sectors(bio))
+               bio->bi_sector = flakey_map_sector(ti, bio->bi_sector);
+}
+
+static int flakey_map(struct dm_target *ti, struct bio *bio,
+                     union map_info *map_context)
+{
+       struct flakey_c *fc = ti->private;
+       unsigned elapsed;
+
+       /* Are we alive ? */
+       elapsed = (jiffies - fc->start_time) / HZ;
+       if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval)
+               return -EIO;
+
+       flakey_map_bio(ti, bio);
+
+       return DM_MAPIO_REMAPPED;
+}
+
+static int flakey_status(struct dm_target *ti, status_type_t type,
+                        char *result, unsigned int maxlen)
+{
+       struct flakey_c *fc = ti->private;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               result[0] = '\0';
+               break;
+
+       case STATUSTYPE_TABLE:
+               snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name,
+                        (unsigned long long)fc->start, fc->up_interval,
+                        fc->down_interval);
+               break;
+       }
+       return 0;
+}
+
+static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
+{
+       struct flakey_c *fc = ti->private;
+
+       return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg);
+}
+
+static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+                       struct bio_vec *biovec, int max_size)
+{
+       struct flakey_c *fc = ti->private;
+       struct request_queue *q = bdev_get_queue(fc->dev->bdev);
+
+       if (!q->merge_bvec_fn)
+               return max_size;
+
+       bvm->bi_bdev = fc->dev->bdev;
+       bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector);
+
+       return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
+static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
+{
+       struct flakey_c *fc = ti->private;
+
+       return fn(ti, fc->dev, fc->start, ti->len, data);
+}
+
+static struct target_type flakey_target = {
+       .name   = "flakey",
+       .version = {1, 1, 0},
+       .module = THIS_MODULE,
+       .ctr    = flakey_ctr,
+       .dtr    = flakey_dtr,
+       .map    = flakey_map,
+       .status = flakey_status,
+       .ioctl  = flakey_ioctl,
+       .merge  = flakey_merge,
+       .iterate_devices = flakey_iterate_devices,
+};
+
+static int __init dm_flakey_init(void)
+{
+       int r = dm_register_target(&flakey_target);
+
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       return r;
+}
+
+static void __exit dm_flakey_exit(void)
+{
+       dm_unregister_target(&flakey_target);
+}
+
+/* Module hooks */
+module_init(dm_flakey_init);
+module_exit(dm_flakey_exit);
+
+MODULE_DESCRIPTION(DM_NAME " flakey target");
+MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
index 136d4f71a1162509abc40cd10b96ed6085c75186..76a5af00a26b5b52ce45a72bc0e58d6744d33468 100644 (file)
@@ -352,7 +352,7 @@ static void dispatch_io(int rw, unsigned int num_regions,
        BUG_ON(num_regions > DM_IO_MAX_REGIONS);
 
        if (sync)
-               rw |= REQ_SYNC | REQ_UNPLUG;
+               rw |= REQ_SYNC;
 
        /*
         * For multiple regions we need to be careful to rewind
index 6d12775a1061059e483fdbeab3bf7b6ccbe53011..4cacdad2270a345e1ef8455eddf5c2a2838a22e1 100644 (file)
@@ -1501,14 +1501,10 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user)
        return r;
 }
 
-static void free_params(struct dm_ioctl *param)
-{
-       vfree(param);
-}
-
 static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
 {
        struct dm_ioctl tmp, *dmi;
+       int secure_data;
 
        if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data)))
                return -EFAULT;
@@ -1516,17 +1512,30 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
        if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data)))
                return -EINVAL;
 
+       secure_data = tmp.flags & DM_SECURE_DATA_FLAG;
+
        dmi = vmalloc(tmp.data_size);
-       if (!dmi)
+       if (!dmi) {
+               if (secure_data && clear_user(user, tmp.data_size))
+                       return -EFAULT;
                return -ENOMEM;
-
-       if (copy_from_user(dmi, user, tmp.data_size)) {
-               vfree(dmi);
-               return -EFAULT;
        }
 
+       if (copy_from_user(dmi, user, tmp.data_size))
+               goto bad;
+
+       /* Wipe the user buffer so we do not return it to userspace */
+       if (secure_data && clear_user(user, tmp.data_size))
+               goto bad;
+
        *param = dmi;
        return 0;
+
+bad:
+       if (secure_data)
+               memset(dmi, 0, tmp.data_size);
+       vfree(dmi);
+       return -EFAULT;
 }
 
 static int validate_params(uint cmd, struct dm_ioctl *param)
@@ -1534,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
        /* Always clear this flag */
        param->flags &= ~DM_BUFFER_FULL_FLAG;
        param->flags &= ~DM_UEVENT_GENERATED_FLAG;
+       param->flags &= ~DM_SECURE_DATA_FLAG;
 
        /* Ignores parameters */
        if (cmd == DM_REMOVE_ALL_CMD ||
@@ -1561,10 +1571,11 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
 static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
 {
        int r = 0;
+       int wipe_buffer;
        unsigned int cmd;
        struct dm_ioctl *uninitialized_var(param);
        ioctl_fn fn = NULL;
-       size_t param_size;
+       size_t input_param_size;
 
        /* only root can play with this */
        if (!capable(CAP_SYS_ADMIN))
@@ -1611,13 +1622,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
        if (r)
                return r;
 
+       input_param_size = param->data_size;
+       wipe_buffer = param->flags & DM_SECURE_DATA_FLAG;
+
        r = validate_params(cmd, param);
        if (r)
                goto out;
 
-       param_size = param->data_size;
        param->data_size = sizeof(*param);
-       r = fn(param, param_size);
+       r = fn(param, input_param_size);
 
        /*
         * Copy the results back to userland.
@@ -1625,8 +1638,11 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
        if (!r && copy_to_user(user, param, param->data_size))
                r = -EFAULT;
 
- out:
-       free_params(param);
+out:
+       if (wipe_buffer)
+               memset(param, 0, input_param_size);
+
+       vfree(param);
        return r;
 }
 
index 924f5f0084c27191604907eaa9983a2bf687b6c1..1bb73a13ca4003d841446efbe70ffda93a62061d 100644 (file)
@@ -37,13 +37,6 @@ struct dm_kcopyd_client {
        unsigned int nr_pages;
        unsigned int nr_free_pages;
 
-       /*
-        * Block devices to unplug.
-        * Non-NULL pointer means that a block device has some pending requests
-        * and needs to be unplugged.
-        */
-       struct block_device *unplug[2];
-
        struct dm_io_client *io_client;
 
        wait_queue_head_t destroyq;
@@ -315,31 +308,6 @@ static int run_complete_job(struct kcopyd_job *job)
        return 0;
 }
 
-/*
- * Unplug the block device at the specified index.
- */
-static void unplug(struct dm_kcopyd_client *kc, int rw)
-{
-       if (kc->unplug[rw] != NULL) {
-               blk_unplug(bdev_get_queue(kc->unplug[rw]));
-               kc->unplug[rw] = NULL;
-       }
-}
-
-/*
- * Prepare block device unplug. If there's another device
- * to be unplugged at the same array index, we unplug that
- * device first.
- */
-static void prepare_unplug(struct dm_kcopyd_client *kc, int rw,
-                          struct block_device *bdev)
-{
-       if (likely(kc->unplug[rw] == bdev))
-               return;
-       unplug(kc, rw);
-       kc->unplug[rw] = bdev;
-}
-
 static void complete_io(unsigned long error, void *context)
 {
        struct kcopyd_job *job = (struct kcopyd_job *) context;
@@ -386,16 +354,10 @@ static int run_io_job(struct kcopyd_job *job)
                .client = job->kc->io_client,
        };
 
-       if (job->rw == READ) {
+       if (job->rw == READ)
                r = dm_io(&io_req, 1, &job->source, NULL);
-               prepare_unplug(job->kc, READ, job->source.bdev);
-       } else {
-               if (job->num_dests > 1)
-                       io_req.bi_rw |= REQ_UNPLUG;
+       else
                r = dm_io(&io_req, job->num_dests, job->dests, NULL);
-               if (!(io_req.bi_rw & REQ_UNPLUG))
-                       prepare_unplug(job->kc, WRITE, job->dests[0].bdev);
-       }
 
        return r;
 }
@@ -466,6 +428,7 @@ static void do_work(struct work_struct *work)
 {
        struct dm_kcopyd_client *kc = container_of(work,
                                        struct dm_kcopyd_client, kcopyd_work);
+       struct blk_plug plug;
 
        /*
         * The order that these are called is *very* important.
@@ -473,18 +436,12 @@ static void do_work(struct work_struct *work)
         * Pages jobs when successful will jump onto the io jobs
         * list.  io jobs call wake when they complete and it all
         * starts again.
-        *
-        * Note that io_jobs add block devices to the unplug array,
-        * this array is cleared with "unplug" calls. It is thus
-        * forbidden to run complete_jobs after io_jobs and before
-        * unplug because the block device could be destroyed in
-        * job completion callback.
         */
+       blk_start_plug(&plug);
        process_jobs(&kc->complete_jobs, kc, run_complete_job);
        process_jobs(&kc->pages_jobs, kc, run_pages_job);
        process_jobs(&kc->io_jobs, kc, run_io_job);
-       unplug(kc, READ);
-       unplug(kc, WRITE);
+       blk_finish_plug(&plug);
 }
 
 /*
@@ -665,8 +622,6 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
        INIT_LIST_HEAD(&kc->io_jobs);
        INIT_LIST_HEAD(&kc->pages_jobs);
 
-       memset(kc->unplug, 0, sizeof(kc->unplug));
-
        kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
        if (!kc->job_pool)
                goto bad_slab;
index 6951536ea29ceab63c8dca6facdb8253ac311dac..a1f321889676d4b51eee4f08ce874e86d6449a57 100644 (file)
@@ -251,20 +251,20 @@ struct log_c {
  */
 static inline int log_test_bit(uint32_t *bs, unsigned bit)
 {
-       return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0;
+       return test_bit_le(bit, (unsigned long *) bs) ? 1 : 0;
 }
 
 static inline void log_set_bit(struct log_c *l,
                               uint32_t *bs, unsigned bit)
 {
-       ext2_set_bit(bit, (unsigned long *) bs);
+       __test_and_set_bit_le(bit, (unsigned long *) bs);
        l->touched_cleaned = 1;
 }
 
 static inline void log_clear_bit(struct log_c *l,
                                 uint32_t *bs, unsigned bit)
 {
-       ext2_clear_bit(bit, (unsigned long *) bs);
+       __test_and_clear_bit_le(bit, (unsigned long *) bs);
        l->touched_dirtied = 1;
 }
 
@@ -543,7 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
                return -EINVAL;
        }
 
-       r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev);
+       r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
        if (r)
                return r;
 
@@ -740,7 +740,7 @@ static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
                return 0;
 
        do {
-               *region = ext2_find_next_zero_bit(
+               *region = find_next_zero_bit_le(
                                             (unsigned long *) lc->sync_bits,
                                             lc->region_count,
                                             lc->sync_search);
index 4b0b63c290a6940eb520cf9b35d416c136f27036..a550a057d991bc309b68cfa0f97481365bb1de6e 100644 (file)
@@ -844,8 +844,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
 {
        /* target parameters */
        static struct param _params[] = {
-               {1, 1024, "invalid number of priority groups"},
-               {1, 1024, "invalid initial priority group number"},
+               {0, 1024, "invalid number of priority groups"},
+               {0, 1024, "invalid initial priority group number"},
        };
 
        int r;
@@ -879,6 +879,13 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
        if (r)
                goto bad;
 
+       if ((!m->nr_priority_groups && next_pg_num) ||
+           (m->nr_priority_groups && !next_pg_num)) {
+               ti->error = "invalid initial priority group";
+               r = -EINVAL;
+               goto bad;
+       }
+
        /* parse the priority groups */
        while (as.argc) {
                struct priority_group *pg;
@@ -1065,7 +1072,7 @@ out:
 static int action_dev(struct multipath *m, struct dm_dev *dev,
                      action_fn action)
 {
-       int r = 0;
+       int r = -EINVAL;
        struct pgpath *pgpath;
        struct priority_group *pg;
 
@@ -1415,7 +1422,7 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
        else if (m->current_pg)
                pg_num = m->current_pg->pg_num;
        else
-                       pg_num = 1;
+               pg_num = (m->nr_priority_groups ? 1 : 0);
 
        DMEMIT("%u ", pg_num);
 
@@ -1669,7 +1676,7 @@ out:
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,
index b9e1e15ef11cb3d45f53b8c06a0dd6b709fa1164..5ef136cdba91dd4a891f00920029962a54185d63 100644 (file)
@@ -394,7 +394,7 @@ static void raid_unplug(struct dm_target_callbacks *cb)
 {
        struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
 
-       md_raid5_unplug_device(rs->md.private);
+       md_raid5_kick_device(rs->md.private);
 }
 
 /*
index dee326775c6064b045c8cf523a25a528d9882caf..976ad4688afc2ee03189e208663429a74f759109 100644 (file)
@@ -842,8 +842,6 @@ static void do_mirror(struct work_struct *work)
        do_reads(ms, &reads);
        do_writes(ms, &writes);
        do_failures(ms, &failures);
-
-       dm_table_unplug_all(ms->ti->table);
 }
 
 /*-----------------------------------------------------------------
index fdde53cd12b7ef4f2bd910939bd5d08f49597829..a2d330942cb29f824c029973ae12a98a2d39efec 100644 (file)
@@ -1080,7 +1080,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        argv++;
        argc--;
 
-       r = dm_get_device(ti, cow_path, FMODE_READ | FMODE_WRITE, &s->cow);
+       r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow);
        if (r) {
                ti->error = "Cannot get COW device";
                goto bad_cow;
index dddfa14f29824ab1240b03df22893893003efee7..3d80cf0c152d1b4fedd46a0b67773842218a326c 100644 (file)
@@ -396,9 +396,29 @@ static void stripe_io_hints(struct dm_target *ti,
        blk_limits_io_opt(limits, chunk_size * sc->stripes);
 }
 
+static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+                       struct bio_vec *biovec, int max_size)
+{
+       struct stripe_c *sc = ti->private;
+       sector_t bvm_sector = bvm->bi_sector;
+       uint32_t stripe;
+       struct request_queue *q;
+
+       stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
+
+       q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
+       if (!q->merge_bvec_fn)
+               return max_size;
+
+       bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
+       bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
+
+       return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
 static struct target_type stripe_target = {
        .name   = "striped",
-       .version = {1, 3, 1},
+       .version = {1, 4, 0},
        .module = THIS_MODULE,
        .ctr    = stripe_ctr,
        .dtr    = stripe_dtr,
@@ -407,6 +427,7 @@ static struct target_type stripe_target = {
        .status = stripe_status,
        .iterate_devices = stripe_iterate_devices,
        .io_hints = stripe_io_hints,
+       .merge  = stripe_merge,
 };
 
 int __init dm_stripe_init(void)
index 38e4eb1bb9656ba565150a48d68594836f51c4f9..416d4e258df6df536d2cd7d38795e8e58b94efbc 100644 (file)
@@ -55,6 +55,7 @@ struct dm_table {
        struct dm_target *targets;
 
        unsigned discards_supported:1;
+       unsigned integrity_supported:1;
 
        /*
         * Indicates the rw permissions for the new logical
@@ -859,7 +860,7 @@ int dm_table_alloc_md_mempools(struct dm_table *t)
                return -EINVAL;
        }
 
-       t->mempools = dm_alloc_md_mempools(type);
+       t->mempools = dm_alloc_md_mempools(type, t->integrity_supported);
        if (!t->mempools)
                return -ENOMEM;
 
@@ -935,8 +936,10 @@ static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device
        struct dm_dev_internal *dd;
 
        list_for_each_entry(dd, devices, list)
-               if (bdev_get_integrity(dd->dm_dev.bdev))
+               if (bdev_get_integrity(dd->dm_dev.bdev)) {
+                       t->integrity_supported = 1;
                        return blk_integrity_register(dm_disk(md), NULL);
+               }
 
        return 0;
 }
@@ -1275,29 +1278,6 @@ int dm_table_any_busy_target(struct dm_table *t)
        return 0;
 }
 
-void dm_table_unplug_all(struct dm_table *t)
-{
-       struct dm_dev_internal *dd;
-       struct list_head *devices = dm_table_get_devices(t);
-       struct dm_target_callbacks *cb;
-
-       list_for_each_entry(dd, devices, list) {
-               struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
-               char b[BDEVNAME_SIZE];
-
-               if (likely(q))
-                       blk_unplug(q);
-               else
-                       DMWARN_LIMIT("%s: Cannot unplug nonexistent device %s",
-                                    dm_device_name(t->md),
-                                    bdevname(dd->dm_dev.bdev, b));
-       }
-
-       list_for_each_entry(cb, &t->target_callbacks, list)
-               if (cb->unplug_fn)
-                       cb->unplug_fn(cb);
-}
-
 struct mapped_device *dm_table_get_md(struct dm_table *t)
 {
        return t->md;
@@ -1345,4 +1325,3 @@ EXPORT_SYMBOL(dm_table_get_mode);
 EXPORT_SYMBOL(dm_table_get_md);
 EXPORT_SYMBOL(dm_table_put);
 EXPORT_SYMBOL(dm_table_get);
-EXPORT_SYMBOL(dm_table_unplug_all);
index eaa3af0e0632af0c96c5c17566024265578e2303..0cf68b478878f327598fb756fe2da173d5443468 100644 (file)
@@ -477,7 +477,8 @@ static void start_io_acct(struct dm_io *io)
        cpu = part_stat_lock();
        part_round_stats(cpu, &dm_disk(md)->part0);
        part_stat_unlock();
-       dm_disk(md)->part0.in_flight[rw] = atomic_inc_return(&md->pending[rw]);
+       atomic_set(&dm_disk(md)->part0.in_flight[rw],
+               atomic_inc_return(&md->pending[rw]));
 }
 
 static void end_io_acct(struct dm_io *io)
@@ -497,8 +498,8 @@ static void end_io_acct(struct dm_io *io)
         * After this is decremented the bio must not be touched if it is
         * a flush.
         */
-       dm_disk(md)->part0.in_flight[rw] = pending =
-               atomic_dec_return(&md->pending[rw]);
+       pending = atomic_dec_return(&md->pending[rw]);
+       atomic_set(&dm_disk(md)->part0.in_flight[rw], pending);
        pending += atomic_read(&md->pending[rw^0x1]);
 
        /* nudge anyone waiting on suspend queue */
@@ -807,8 +808,6 @@ void dm_requeue_unmapped_request(struct request *clone)
        dm_unprep_request(rq);
 
        spin_lock_irqsave(q->queue_lock, flags);
-       if (elv_queue_empty(q))
-               blk_plug_device(q);
        blk_requeue_request(q, rq);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
@@ -1613,10 +1612,10 @@ static void dm_request_fn(struct request_queue *q)
         * number of in-flight I/Os after the queue is stopped in
         * dm_suspend().
         */
-       while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) {
+       while (!blk_queue_stopped(q)) {
                rq = blk_peek_request(q);
                if (!rq)
-                       goto plug_and_out;
+                       goto delay_and_out;
 
                /* always use block 0 to find the target for flushes for now */
                pos = 0;
@@ -1627,7 +1626,7 @@ static void dm_request_fn(struct request_queue *q)
                BUG_ON(!dm_target_is_valid(ti));
 
                if (ti->type->busy && ti->type->busy(ti))
-                       goto plug_and_out;
+                       goto delay_and_out;
 
                blk_start_request(rq);
                clone = rq->special;
@@ -1647,11 +1646,8 @@ requeued:
        BUG_ON(!irqs_disabled());
        spin_lock(q->queue_lock);
 
-plug_and_out:
-       if (!elv_queue_empty(q))
-               /* Some requests still remain, retry later */
-               blk_plug_device(q);
-
+delay_and_out:
+       blk_delay_queue(q, HZ / 10);
 out:
        dm_table_put(map);
 
@@ -1680,20 +1676,6 @@ static int dm_lld_busy(struct request_queue *q)
        return r;
 }
 
-static void dm_unplug_all(struct request_queue *q)
-{
-       struct mapped_device *md = q->queuedata;
-       struct dm_table *map = dm_get_live_table(md);
-
-       if (map) {
-               if (dm_request_based(md))
-                       generic_unplug_device(q);
-
-               dm_table_unplug_all(map);
-               dm_table_put(map);
-       }
-}
-
 static int dm_any_congested(void *congested_data, int bdi_bits)
 {
        int r = bdi_bits;
@@ -1817,7 +1799,6 @@ static void dm_init_md_queue(struct mapped_device *md)
        md->queue->backing_dev_info.congested_data = md;
        blk_queue_make_request(md->queue, dm_request);
        blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
-       md->queue->unplug_fn = dm_unplug_all;
        blk_queue_merge_bvec(md->queue, dm_merge_bvec);
        blk_queue_flush(md->queue, REQ_FLUSH | REQ_FUA);
 }
@@ -2263,8 +2244,6 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
        int r = 0;
        DECLARE_WAITQUEUE(wait, current);
 
-       dm_unplug_all(md->queue);
-
        add_wait_queue(&md->wait, &wait);
 
        while (1) {
@@ -2539,7 +2518,6 @@ int dm_resume(struct mapped_device *md)
 
        clear_bit(DMF_SUSPENDED, &md->flags);
 
-       dm_table_unplug_all(map);
        r = 0;
 out:
        dm_table_put(map);
@@ -2643,9 +2621,10 @@ int dm_noflush_suspending(struct dm_target *ti)
 }
 EXPORT_SYMBOL_GPL(dm_noflush_suspending);
 
-struct dm_md_mempools *dm_alloc_md_mempools(unsigned type)
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity)
 {
        struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL);
+       unsigned int pool_size = (type == DM_TYPE_BIO_BASED) ? 16 : MIN_IOS;
 
        if (!pools)
                return NULL;
@@ -2662,13 +2641,18 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type)
        if (!pools->tio_pool)
                goto free_io_pool_and_out;
 
-       pools->bs = (type == DM_TYPE_BIO_BASED) ?
-                   bioset_create(16, 0) : bioset_create(MIN_IOS, 0);
+       pools->bs = bioset_create(pool_size, 0);
        if (!pools->bs)
                goto free_tio_pool_and_out;
 
+       if (integrity && bioset_integrity_create(pools->bs, pool_size))
+               goto free_bioset_and_out;
+
        return pools;
 
+free_bioset_and_out:
+       bioset_free(pools->bs);
+
 free_tio_pool_and_out:
        mempool_destroy(pools->tio_pool);
 
index 0c2dd5f4af7658936a2c44bfa62a6aa774e56723..1aaf16746da86f6bfb9c9ffaab334841c044d92a 100644 (file)
@@ -149,7 +149,7 @@ void dm_kcopyd_exit(void);
 /*
  * Mempool operations
  */
-struct dm_md_mempools *dm_alloc_md_mempools(unsigned type);
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity);
 void dm_free_md_mempools(struct dm_md_mempools *pools);
 
 #endif
index 0ed7f6bc2a7fb4ea9cd30d7879d4d4d1ab7a134e..abfb59a61ede75a25bc8f459456ed57eaf7acb71 100644 (file)
@@ -87,22 +87,6 @@ static int linear_mergeable_bvec(struct request_queue *q,
        return maxsectors << 9;
 }
 
-static void linear_unplug(struct request_queue *q)
-{
-       mddev_t *mddev = q->queuedata;
-       linear_conf_t *conf;
-       int i;
-
-       rcu_read_lock();
-       conf = rcu_dereference(mddev->private);
-
-       for (i=0; i < mddev->raid_disks; i++) {
-               struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
-               blk_unplug(r_queue);
-       }
-       rcu_read_unlock();
-}
-
 static int linear_congested(void *data, int bits)
 {
        mddev_t *mddev = data;
@@ -224,11 +208,9 @@ static int linear_run (mddev_t *mddev)
        md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
 
        blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
-       mddev->queue->unplug_fn = linear_unplug;
        mddev->queue->backing_dev_info.congested_fn = linear_congested;
        mddev->queue->backing_dev_info.congested_data = mddev;
-       md_integrity_register(mddev);
-       return 0;
+       return md_integrity_register(mddev);
 }
 
 static void free_conf(struct rcu_head *head)
index d5ad7723b1727ea0609241ffd77b9b99ac5a009a..06ecea751a39b8ec53935bcdfb331453d2e01b19 100644 (file)
@@ -780,8 +780,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
        bio->bi_end_io = super_written;
 
        atomic_inc(&mddev->pending_writes);
-       submit_bio(REQ_WRITE | REQ_SYNC | REQ_UNPLUG | REQ_FLUSH | REQ_FUA,
-                  bio);
+       submit_bio(REQ_WRITE | REQ_SYNC | REQ_FLUSH | REQ_FUA, bio);
 }
 
 void md_super_wait(mddev_t *mddev)
@@ -809,7 +808,7 @@ int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size,
        struct completion event;
        int ret;
 
-       rw |= REQ_SYNC | REQ_UNPLUG;
+       rw |= REQ_SYNC;
 
        bio->bi_bdev = (metadata_op && rdev->meta_bdev) ?
                rdev->meta_bdev : rdev->bdev;
@@ -1804,8 +1803,12 @@ int md_integrity_register(mddev_t *mddev)
                        mdname(mddev));
                return -EINVAL;
        }
-       printk(KERN_NOTICE "md: data integrity on %s enabled\n",
-               mdname(mddev));
+       printk(KERN_NOTICE "md: data integrity enabled on %s\n", mdname(mddev));
+       if (bioset_integrity_create(mddev->bio_set, BIO_POOL_SIZE)) {
+               printk(KERN_ERR "md: failed to create integrity pool for %s\n",
+                      mdname(mddev));
+               return -EINVAL;
+       }
        return 0;
 }
 EXPORT_SYMBOL(md_integrity_register);
@@ -4817,7 +4820,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                __md_stop_writes(mddev);
                md_stop(mddev);
                mddev->queue->merge_bvec_fn = NULL;
-               mddev->queue->unplug_fn = NULL;
                mddev->queue->backing_dev_info.congested_fn = NULL;
 
                /* tell userspace to handle 'inactive' */
@@ -6692,8 +6694,6 @@ EXPORT_SYMBOL_GPL(md_allow_write);
 
 void md_unplug(mddev_t *mddev)
 {
-       if (mddev->queue)
-               blk_unplug(mddev->queue);
        if (mddev->plug)
                mddev->plug->unplug_fn(mddev->plug);
 }
@@ -6876,7 +6876,6 @@ void md_do_sync(mddev_t *mddev)
                     >= mddev->resync_max - mddev->curr_resync_completed
                            )) {
                        /* time to update curr_resync_completed */
-                       md_unplug(mddev);
                        wait_event(mddev->recovery_wait,
                                   atomic_read(&mddev->recovery_active) == 0);
                        mddev->curr_resync_completed = j;
@@ -6952,7 +6951,6 @@ void md_do_sync(mddev_t *mddev)
                 * about not overloading the IO subsystem. (things like an
                 * e2fsck being done on the RAID array should execute fast)
                 */
-               md_unplug(mddev);
                cond_resched();
 
                currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
@@ -6971,8 +6969,6 @@ void md_do_sync(mddev_t *mddev)
         * this also signals 'finished resyncing' to md_stop
         */
  out:
-       md_unplug(mddev);
-
        wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
 
        /* tell personality that we are finished */
index 3a62d440e27b8105bb778d36950575f77fdd28a3..c35890990985632646483a97e849277023850b1a 100644 (file)
@@ -106,36 +106,6 @@ static void multipath_end_request(struct bio *bio, int error)
        rdev_dec_pending(rdev, conf->mddev);
 }
 
-static void unplug_slaves(mddev_t *mddev)
-{
-       multipath_conf_t *conf = mddev->private;
-       int i;
-
-       rcu_read_lock();
-       for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
-               if (rdev && !test_bit(Faulty, &rdev->flags)
-                   && atomic_read(&rdev->nr_pending)) {
-                       struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
-
-                       atomic_inc(&rdev->nr_pending);
-                       rcu_read_unlock();
-
-                       blk_unplug(r_queue);
-
-                       rdev_dec_pending(rdev, mddev);
-                       rcu_read_lock();
-               }
-       }
-       rcu_read_unlock();
-}
-
-static void multipath_unplug(struct request_queue *q)
-{
-       unplug_slaves(q->queuedata);
-}
-
-
 static int multipath_make_request(mddev_t *mddev, struct bio * bio)
 {
        multipath_conf_t *conf = mddev->private;
@@ -345,7 +315,7 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
                        p->rdev = rdev;
                        goto abort;
                }
-               md_integrity_register(mddev);
+               err = md_integrity_register(mddev);
        }
 abort:
 
@@ -517,10 +487,12 @@ static int multipath_run (mddev_t *mddev)
         */
        md_set_array_sectors(mddev, multipath_size(mddev, 0, 0));
 
-       mddev->queue->unplug_fn = multipath_unplug;
        mddev->queue->backing_dev_info.congested_fn = multipath_congested;
        mddev->queue->backing_dev_info.congested_data = mddev;
-       md_integrity_register(mddev);
+
+       if (md_integrity_register(mddev))
+               goto out_free_conf;
+
        return 0;
 
 out_free_conf:
index c0ac457f1218ca52a2d6d237be051a70198f0936..e86bf3682e1e29c65b61f0ca7d3b00f94533046a 100644 (file)
 #include "raid0.h"
 #include "raid5.h"
 
-static void raid0_unplug(struct request_queue *q)
-{
-       mddev_t *mddev = q->queuedata;
-       raid0_conf_t *conf = mddev->private;
-       mdk_rdev_t **devlist = conf->devlist;
-       int raid_disks = conf->strip_zone[0].nb_dev;
-       int i;
-
-       for (i=0; i < raid_disks; i++) {
-               struct request_queue *r_queue = bdev_get_queue(devlist[i]->bdev);
-
-               blk_unplug(r_queue);
-       }
-}
-
 static int raid0_congested(void *data, int bits)
 {
        mddev_t *mddev = data;
@@ -272,7 +257,6 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
                       mdname(mddev),
                       (unsigned long long)smallest->sectors);
        }
-       mddev->queue->unplug_fn = raid0_unplug;
        mddev->queue->backing_dev_info.congested_fn = raid0_congested;
        mddev->queue->backing_dev_info.congested_data = mddev;
 
@@ -395,8 +379,7 @@ static int raid0_run(mddev_t *mddev)
 
        blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
        dump_zones(mddev);
-       md_integrity_register(mddev);
-       return 0;
+       return md_integrity_register(mddev);
 }
 
 static int raid0_stop(mddev_t *mddev)
index 06cd712807d0c2d81c053e352a5f0cc2e73ce1b3..c2a21ae56d977d6249f9c8501f124e50c48f15dd 100644 (file)
 #define        NR_RAID1_BIOS 256
 
 
-static void unplug_slaves(mddev_t *mddev);
-
 static void allow_barrier(conf_t *conf);
 static void lower_barrier(conf_t *conf);
 
 static void * r1bio_pool_alloc(gfp_t gfp_flags, void *data)
 {
        struct pool_info *pi = data;
-       r1bio_t *r1_bio;
        int size = offsetof(r1bio_t, bios[pi->raid_disks]);
 
        /* allocate a r1bio with room for raid_disks entries in the bios array */
-       r1_bio = kzalloc(size, gfp_flags);
-       if (!r1_bio && pi->mddev)
-               unplug_slaves(pi->mddev);
-
-       return r1_bio;
+       return kzalloc(size, gfp_flags);
 }
 
 static void r1bio_pool_free(void *r1_bio, void *data)
@@ -91,10 +84,8 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
        int i, j;
 
        r1_bio = r1bio_pool_alloc(gfp_flags, pi);
-       if (!r1_bio) {
-               unplug_slaves(pi->mddev);
+       if (!r1_bio)
                return NULL;
-       }
 
        /*
         * Allocate bios : 1 for reading, n-1 for writing
@@ -520,37 +511,6 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
        return new_disk;
 }
 
-static void unplug_slaves(mddev_t *mddev)
-{
-       conf_t *conf = mddev->private;
-       int i;
-
-       rcu_read_lock();
-       for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
-               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-                       struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
-
-                       atomic_inc(&rdev->nr_pending);
-                       rcu_read_unlock();
-
-                       blk_unplug(r_queue);
-
-                       rdev_dec_pending(rdev, mddev);
-                       rcu_read_lock();
-               }
-       }
-       rcu_read_unlock();
-}
-
-static void raid1_unplug(struct request_queue *q)
-{
-       mddev_t *mddev = q->queuedata;
-
-       unplug_slaves(mddev);
-       md_wakeup_thread(mddev->thread);
-}
-
 static int raid1_congested(void *data, int bits)
 {
        mddev_t *mddev = data;
@@ -580,23 +540,16 @@ static int raid1_congested(void *data, int bits)
 }
 
 
-static int flush_pending_writes(conf_t *conf)
+static void flush_pending_writes(conf_t *conf)
 {
        /* Any writes that have been queued but are awaiting
         * bitmap updates get flushed here.
-        * We return 1 if any requests were actually submitted.
         */
-       int rv = 0;
-
        spin_lock_irq(&conf->device_lock);
 
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
-               /* Only take the spinlock to quiet a warning */
-               spin_lock(conf->mddev->queue->queue_lock);
-               blk_remove_plug(conf->mddev->queue);
-               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to
                 * disk before proceeding w/ I/O */
@@ -608,10 +561,14 @@ static int flush_pending_writes(conf_t *conf)
                        generic_make_request(bio);
                        bio = next;
                }
-               rv = 1;
        } else
                spin_unlock_irq(&conf->device_lock);
-       return rv;
+}
+
+static void md_kick_device(mddev_t *mddev)
+{
+       blk_flush_plug(current);
+       md_wakeup_thread(mddev->thread);
 }
 
 /* Barriers....
@@ -643,8 +600,7 @@ static void raise_barrier(conf_t *conf)
 
        /* Wait until no block IO is waiting */
        wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting,
-                           conf->resync_lock,
-                           raid1_unplug(conf->mddev->queue));
+                           conf->resync_lock, md_kick_device(conf->mddev));
 
        /* block any new IO from starting */
        conf->barrier++;
@@ -652,8 +608,7 @@ static void raise_barrier(conf_t *conf)
        /* Now wait for all pending IO to complete */
        wait_event_lock_irq(conf->wait_barrier,
                            !conf->nr_pending && conf->barrier < RESYNC_DEPTH,
-                           conf->resync_lock,
-                           raid1_unplug(conf->mddev->queue));
+                           conf->resync_lock, md_kick_device(conf->mddev));
 
        spin_unlock_irq(&conf->resync_lock);
 }
@@ -675,7 +630,7 @@ static void wait_barrier(conf_t *conf)
                conf->nr_waiting++;
                wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
                                    conf->resync_lock,
-                                   raid1_unplug(conf->mddev->queue));
+                                   md_kick_device(conf->mddev));
                conf->nr_waiting--;
        }
        conf->nr_pending++;
@@ -712,7 +667,7 @@ static void freeze_array(conf_t *conf)
                            conf->nr_pending == conf->nr_queued+1,
                            conf->resync_lock,
                            ({ flush_pending_writes(conf);
-                              raid1_unplug(conf->mddev->queue); }));
+                              md_kick_device(conf->mddev); }));
        spin_unlock_irq(&conf->resync_lock);
 }
 static void unfreeze_array(conf_t *conf)
@@ -962,7 +917,6 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r1_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
        r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL);
@@ -971,7 +925,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid1d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
-       if (do_sync)
+       if (do_sync || !bitmap)
                md_wakeup_thread(mddev->thread);
 
        return 0;
@@ -1178,7 +1132,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
                        p->rdev = rdev;
                        goto abort;
                }
-               md_integrity_register(mddev);
+               err = md_integrity_register(mddev);
        }
 abort:
 
@@ -1561,7 +1515,6 @@ static void raid1d(mddev_t *mddev)
        unsigned long flags;
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
-       int unplug=0;
        mdk_rdev_t *rdev;
 
        md_check_recovery(mddev);
@@ -1569,7 +1522,7 @@ static void raid1d(mddev_t *mddev)
        for (;;) {
                char b[BDEVNAME_SIZE];
 
-               unplug += flush_pending_writes(conf);
+               flush_pending_writes(conf);
 
                spin_lock_irqsave(&conf->device_lock, flags);
                if (list_empty(head)) {
@@ -1583,10 +1536,9 @@ static void raid1d(mddev_t *mddev)
 
                mddev = r1_bio->mddev;
                conf = mddev->private;
-               if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
+               if (test_bit(R1BIO_IsSync, &r1_bio->state))
                        sync_request_write(mddev, r1_bio);
-                       unplug = 1;
-               } else {
+               else {
                        int disk;
 
                        /* we got a read error. Maybe the drive is bad.  Maybe just
@@ -1636,14 +1588,11 @@ static void raid1d(mddev_t *mddev)
                                bio->bi_end_io = raid1_end_read_request;
                                bio->bi_rw = READ | do_sync;
                                bio->bi_private = r1_bio;
-                               unplug = 1;
                                generic_make_request(bio);
                        }
                }
                cond_resched();
        }
-       if (unplug)
-               unplug_slaves(mddev);
 }
 
 
@@ -2066,11 +2015,9 @@ static int run(mddev_t *mddev)
 
        md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
 
-       mddev->queue->unplug_fn = raid1_unplug;
        mddev->queue->backing_dev_info.congested_fn = raid1_congested;
        mddev->queue->backing_dev_info.congested_data = mddev;
-       md_integrity_register(mddev);
-       return 0;
+       return md_integrity_register(mddev);
 }
 
 static int stop(mddev_t *mddev)
index 747d061d8e05817878ac102a6438714d181e4356..f7b62370b37446a96d5595e8f247b84b3689b145 100644 (file)
  */
 #define        NR_RAID10_BIOS 256
 
-static void unplug_slaves(mddev_t *mddev);
-
 static void allow_barrier(conf_t *conf);
 static void lower_barrier(conf_t *conf);
 
 static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
 {
        conf_t *conf = data;
-       r10bio_t *r10_bio;
        int size = offsetof(struct r10bio_s, devs[conf->copies]);
 
        /* allocate a r10bio with room for raid_disks entries in the bios array */
-       r10_bio = kzalloc(size, gfp_flags);
-       if (!r10_bio && conf->mddev)
-               unplug_slaves(conf->mddev);
-
-       return r10_bio;
+       return kzalloc(size, gfp_flags);
 }
 
 static void r10bio_pool_free(void *r10_bio, void *data)
@@ -106,10 +99,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
        int nalloc;
 
        r10_bio = r10bio_pool_alloc(gfp_flags, conf);
-       if (!r10_bio) {
-               unplug_slaves(conf->mddev);
+       if (!r10_bio)
                return NULL;
-       }
 
        if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
                nalloc = conf->copies; /* resync */
@@ -597,37 +588,6 @@ rb_out:
        return disk;
 }
 
-static void unplug_slaves(mddev_t *mddev)
-{
-       conf_t *conf = mddev->private;
-       int i;
-
-       rcu_read_lock();
-       for (i=0; i < conf->raid_disks; i++) {
-               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
-               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-                       struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
-
-                       atomic_inc(&rdev->nr_pending);
-                       rcu_read_unlock();
-
-                       blk_unplug(r_queue);
-
-                       rdev_dec_pending(rdev, mddev);
-                       rcu_read_lock();
-               }
-       }
-       rcu_read_unlock();
-}
-
-static void raid10_unplug(struct request_queue *q)
-{
-       mddev_t *mddev = q->queuedata;
-
-       unplug_slaves(q->queuedata);
-       md_wakeup_thread(mddev->thread);
-}
-
 static int raid10_congested(void *data, int bits)
 {
        mddev_t *mddev = data;
@@ -649,23 +609,16 @@ static int raid10_congested(void *data, int bits)
        return ret;
 }
 
-static int flush_pending_writes(conf_t *conf)
+static void flush_pending_writes(conf_t *conf)
 {
        /* Any writes that have been queued but are awaiting
         * bitmap updates get flushed here.
-        * We return 1 if any requests were actually submitted.
         */
-       int rv = 0;
-
        spin_lock_irq(&conf->device_lock);
 
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
-               /* Spinlock only taken to quiet a warning */
-               spin_lock(conf->mddev->queue->queue_lock);
-               blk_remove_plug(conf->mddev->queue);
-               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to disk
                 * before proceeding w/ I/O */
@@ -677,11 +630,16 @@ static int flush_pending_writes(conf_t *conf)
                        generic_make_request(bio);
                        bio = next;
                }
-               rv = 1;
        } else
                spin_unlock_irq(&conf->device_lock);
-       return rv;
 }
+
+static void md_kick_device(mddev_t *mddev)
+{
+       blk_flush_plug(current);
+       md_wakeup_thread(mddev->thread);
+}
+
 /* Barriers....
  * Sometimes we need to suspend IO while we do something else,
  * either some resync/recovery, or reconfigure the array.
@@ -711,8 +669,7 @@ static void raise_barrier(conf_t *conf, int force)
 
        /* Wait until no block IO is waiting (unless 'force') */
        wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting,
-                           conf->resync_lock,
-                           raid10_unplug(conf->mddev->queue));
+                           conf->resync_lock, md_kick_device(conf->mddev));
 
        /* block any new IO from starting */
        conf->barrier++;
@@ -720,8 +677,7 @@ static void raise_barrier(conf_t *conf, int force)
        /* No wait for all pending IO to complete */
        wait_event_lock_irq(conf->wait_barrier,
                            !conf->nr_pending && conf->barrier < RESYNC_DEPTH,
-                           conf->resync_lock,
-                           raid10_unplug(conf->mddev->queue));
+                           conf->resync_lock, md_kick_device(conf->mddev));
 
        spin_unlock_irq(&conf->resync_lock);
 }
@@ -742,7 +698,7 @@ static void wait_barrier(conf_t *conf)
                conf->nr_waiting++;
                wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
                                    conf->resync_lock,
-                                   raid10_unplug(conf->mddev->queue));
+                                   md_kick_device(conf->mddev));
                conf->nr_waiting--;
        }
        conf->nr_pending++;
@@ -779,7 +735,7 @@ static void freeze_array(conf_t *conf)
                            conf->nr_pending == conf->nr_queued+1,
                            conf->resync_lock,
                            ({ flush_pending_writes(conf);
-                              raid10_unplug(conf->mddev->queue); }));
+                              md_kick_device(conf->mddev); }));
        spin_unlock_irq(&conf->resync_lock);
 }
 
@@ -974,7 +930,6 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r10_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
 
@@ -991,7 +946,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid10d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
-       if (do_sync)
+       if (do_sync || !mddev->bitmap)
                md_wakeup_thread(mddev->thread);
 
        return 0;
@@ -1233,7 +1188,7 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
                        p->rdev = rdev;
                        goto abort;
                }
-               md_integrity_register(mddev);
+               err = md_integrity_register(mddev);
        }
 abort:
 
@@ -1684,7 +1639,6 @@ static void raid10d(mddev_t *mddev)
        unsigned long flags;
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
-       int unplug=0;
        mdk_rdev_t *rdev;
 
        md_check_recovery(mddev);
@@ -1692,7 +1646,7 @@ static void raid10d(mddev_t *mddev)
        for (;;) {
                char b[BDEVNAME_SIZE];
 
-               unplug += flush_pending_writes(conf);
+               flush_pending_writes(conf);
 
                spin_lock_irqsave(&conf->device_lock, flags);
                if (list_empty(head)) {
@@ -1706,13 +1660,11 @@ static void raid10d(mddev_t *mddev)
 
                mddev = r10_bio->mddev;
                conf = mddev->private;
-               if (test_bit(R10BIO_IsSync, &r10_bio->state)) {
+               if (test_bit(R10BIO_IsSync, &r10_bio->state))
                        sync_request_write(mddev, r10_bio);
-                       unplug = 1;
-               } else  if (test_bit(R10BIO_IsRecover, &r10_bio->state)) {
+               else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
                        recovery_request_write(mddev, r10_bio);
-                       unplug = 1;
-               } else {
+               else {
                        int mirror;
                        /* we got a read error. Maybe the drive is bad.  Maybe just
                         * the block and we can fix it.
@@ -1759,14 +1711,11 @@ static void raid10d(mddev_t *mddev)
                                bio->bi_rw = READ | do_sync;
                                bio->bi_private = r10_bio;
                                bio->bi_end_io = raid10_end_read_request;
-                               unplug = 1;
                                generic_make_request(bio);
                        }
                }
                cond_resched();
        }
-       if (unplug)
-               unplug_slaves(mddev);
 }
 
 
@@ -2377,7 +2326,6 @@ static int run(mddev_t *mddev)
        md_set_array_sectors(mddev, size);
        mddev->resync_max_sectors = size;
 
-       mddev->queue->unplug_fn = raid10_unplug;
        mddev->queue->backing_dev_info.congested_fn = raid10_congested;
        mddev->queue->backing_dev_info.congested_data = mddev;
 
@@ -2395,7 +2343,10 @@ static int run(mddev_t *mddev)
 
        if (conf->near_copies < conf->raid_disks)
                blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
-       md_integrity_register(mddev);
+
+       if (md_integrity_register(mddev))
+               goto out_free_conf;
+
        return 0;
 
 out_free_conf:
index 78536fdbd87fec133894a10bdabd027061cee0eb..e867ee42b15239707c0dfede4be71d2bc9a72e20 100644 (file)
@@ -433,8 +433,6 @@ static int has_failed(raid5_conf_t *conf)
        return 0;
 }
 
-static void unplug_slaves(mddev_t *mddev);
-
 static struct stripe_head *
 get_active_stripe(raid5_conf_t *conf, sector_t sector,
                  int previous, int noblock, int noquiesce)
@@ -463,8 +461,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector,
                                                     < (conf->max_nr_stripes *3/4)
                                                     || !conf->inactive_blocked),
                                                    conf->device_lock,
-                                                   md_raid5_unplug_device(conf)
-                                       );
+                                                   md_raid5_kick_device(conf));
                                conf->inactive_blocked = 0;
                        } else
                                init_stripe(sh, sector, previous);
@@ -1473,8 +1470,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
                wait_event_lock_irq(conf->wait_for_stripe,
                                    !list_empty(&conf->inactive_list),
                                    conf->device_lock,
-                                   unplug_slaves(conf->mddev)
-                       );
+                                   blk_flush_plug(current));
                osh = get_free_stripe(conf);
                spin_unlock_irq(&conf->device_lock);
                atomic_set(&nsh->count, 1);
@@ -3645,58 +3641,19 @@ static void activate_bit_delay(raid5_conf_t *conf)
        }
 }
 
-static void unplug_slaves(mddev_t *mddev)
+void md_raid5_kick_device(raid5_conf_t *conf)
 {
-       raid5_conf_t *conf = mddev->private;
-       int i;
-       int devs = max(conf->raid_disks, conf->previous_raid_disks);
-
-       rcu_read_lock();
-       for (i = 0; i < devs; i++) {
-               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
-               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-                       struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
-
-                       atomic_inc(&rdev->nr_pending);
-                       rcu_read_unlock();
-
-                       blk_unplug(r_queue);
-
-                       rdev_dec_pending(rdev, mddev);
-                       rcu_read_lock();
-               }
-       }
-       rcu_read_unlock();
-}
-
-void md_raid5_unplug_device(raid5_conf_t *conf)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&conf->device_lock, flags);
-
-       if (plugger_remove_plug(&conf->plug)) {
-               conf->seq_flush++;
-               raid5_activate_delayed(conf);
-       }
+       blk_flush_plug(current);
+       raid5_activate_delayed(conf);
        md_wakeup_thread(conf->mddev->thread);
-
-       spin_unlock_irqrestore(&conf->device_lock, flags);
-
-       unplug_slaves(conf->mddev);
 }
-EXPORT_SYMBOL_GPL(md_raid5_unplug_device);
+EXPORT_SYMBOL_GPL(md_raid5_kick_device);
 
 static void raid5_unplug(struct plug_handle *plug)
 {
        raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug);
-       md_raid5_unplug_device(conf);
-}
 
-static void raid5_unplug_queue(struct request_queue *q)
-{
-       mddev_t *mddev = q->queuedata;
-       md_raid5_unplug_device(mddev->private);
+       md_raid5_kick_device(conf);
 }
 
 int md_raid5_congested(mddev_t *mddev, int bits)
@@ -4100,7 +4057,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                                 * add failed due to overlap.  Flush everything
                                 * and wait a while
                                 */
-                               md_raid5_unplug_device(conf);
+                               md_raid5_kick_device(conf);
                                release_stripe(sh);
                                schedule();
                                goto retry;
@@ -4365,7 +4322,6 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 
        if (sector_nr >= max_sector) {
                /* just being told to finish up .. nothing much to do */
-               unplug_slaves(mddev);
 
                if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
                        end_reshape(conf);
@@ -4569,7 +4525,6 @@ static void raid5d(mddev_t *mddev)
        spin_unlock_irq(&conf->device_lock);
 
        async_tx_issue_pending_all();
-       unplug_slaves(mddev);
 
        pr_debug("--- raid5d inactive\n");
 }
@@ -5204,7 +5159,7 @@ static int run(mddev_t *mddev)
 
                mddev->queue->backing_dev_info.congested_data = mddev;
                mddev->queue->backing_dev_info.congested_fn = raid5_congested;
-               mddev->queue->unplug_fn = raid5_unplug_queue;
+               mddev->queue->queue_lock = &conf->device_lock;
 
                chunk_size = mddev->chunk_sectors << 9;
                blk_queue_io_min(mddev->queue, chunk_size);
index 2ace0582b4098f102cb294aac4355c025ad4723e..8d563a4f022a778a6d9354a3c1bf514c6f5e10b6 100644 (file)
@@ -503,6 +503,6 @@ static inline int algorithm_is_DDF(int layout)
 }
 
 extern int md_raid5_congested(mddev_t *mddev, int bits);
-extern void md_raid5_unplug_device(raid5_conf_t *conf);
+extern void md_raid5_kick_device(raid5_conf_t *conf);
 extern int raid5_set_cache_size(mddev_t *mddev, int size);
 #endif
index 81b3ba83cc6558c0016042b33eb5feb694d8b66f..6995940b633a92b1197249d9c3f593c15edf644f 100644 (file)
@@ -13,6 +13,19 @@ if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
+#
+# Media controller
+#
+
+config MEDIA_CONTROLLER
+       bool "Media Controller API (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       ---help---
+         Enable the media controller API used to query media devices internal
+         topology and configure it dynamically.
+
+         This API is mostly used by camera interfaces in embedded platforms.
+
 #
 # V4L core and enabled API's
 #
@@ -40,6 +53,15 @@ config VIDEO_V4L2_COMMON
        depends on (I2C || I2C=n) && VIDEO_DEV
        default (I2C || I2C=n) && VIDEO_DEV
 
+config VIDEO_V4L2_SUBDEV_API
+       bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
+       depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
+       ---help---
+         Enables the V4L2 sub-device pad-level userspace API used to configure
+         video format, size and frame rate between hardware blocks.
+
+         This API is mostly used by camera interfaces in embedded platforms.
+
 #
 # DVB Core
 #
index b603ea645ede7b75a3a49029147a702edbf38d61..64755c99ded291e526a8dd7fa5a83e73496486e4 100644 (file)
@@ -2,6 +2,12 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
+media-objs     := media-device.o media-devnode.o media-entity.o
+
+ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+  obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+endif
+
 obj-y += common/ rc/ video/
 
 obj-$(CONFIG_VIDEO_DEV) += radio/
index bf14bd79e2fc599b7216e43d0a1c78564479dd7e..cdb645d574388230eefe87ad8326f58b8c4bdd27 100644 (file)
@@ -36,6 +36,8 @@ struct tda9887_priv {
        unsigned int       mode;
        unsigned int       audmode;
        v4l2_std_id        std;
+
+       bool               standby;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -568,7 +570,7 @@ static void tda9887_configure(struct dvb_frontend *fe)
        tda9887_do_config(fe);
        tda9887_set_insmod(fe);
 
-       if (priv->mode == T_STANDBY)
+       if (priv->standby)
                priv->data[1] |= cForcedMuteAudioON;
 
        tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
@@ -616,7 +618,7 @@ static void tda9887_standby(struct dvb_frontend *fe)
 {
        struct tda9887_priv *priv = fe->analog_demod_priv;
 
-       priv->mode = T_STANDBY;
+       priv->standby = true;
 
        tda9887_configure(fe);
 }
@@ -626,6 +628,7 @@ static void tda9887_set_params(struct dvb_frontend *fe,
 {
        struct tda9887_priv *priv = fe->analog_demod_priv;
 
+       priv->standby = false;
        priv->mode    = params->mode;
        priv->audmode = params->audmode;
        priv->std     = params->std;
@@ -686,7 +689,7 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
                return NULL;
        case 1:
                fe->analog_demod_priv = priv;
-               priv->mode = T_STANDBY;
+               priv->standby = true;
                tuner_info("tda988[5/6/7] found\n");
                break;
        default:
index 925399dffbed6c4f2820841d2139325edaaf43ed..bf78cb9fc52c2b5c5c497650096f0e780a481f69 100644 (file)
@@ -23,6 +23,7 @@ struct tea5761_priv {
        struct tuner_i2c_props i2c_props;
 
        u32 frequency;
+       bool standby;
 };
 
 /*****************************************************************************/
@@ -135,18 +136,19 @@ static void tea5761_status_dump(unsigned char *buffer)
 }
 
 /* Freq should be specifyed at 62.5 Hz */
-static int set_radio_freq(struct dvb_frontend *fe,
-                         struct analog_parameters *params)
+static int __set_radio_freq(struct dvb_frontend *fe,
+                           unsigned int freq,
+                           bool mono)
 {
        struct tea5761_priv *priv = fe->tuner_priv;
-       unsigned int frq = params->frequency;
+       unsigned int frq = freq;
        unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
        unsigned div;
        int rc;
 
        tuner_dbg("radio freq counter %d\n", frq);
 
-       if (params->mode == T_STANDBY) {
+       if (priv->standby) {
                tuner_dbg("TEA5761 set to standby mode\n");
                buffer[5] |= TEA5761_TNCTRL_MU;
        } else {
@@ -154,7 +156,7 @@ static int set_radio_freq(struct dvb_frontend *fe,
        }
 
 
-       if (params->audmode == V4L2_TUNER_MODE_MONO) {
+       if (mono) {
                tuner_dbg("TEA5761 set to mono\n");
                buffer[5] |= TEA5761_TNCTRL_MST;
        } else {
@@ -176,6 +178,26 @@ static int set_radio_freq(struct dvb_frontend *fe,
        return 0;
 }
 
+static int set_radio_freq(struct dvb_frontend *fe,
+                         struct analog_parameters *params)
+{
+       struct tea5761_priv *priv = fe->analog_demod_priv;
+
+       priv->standby = false;
+
+       return __set_radio_freq(fe, params->frequency,
+                               params->audmode == V4L2_TUNER_MODE_MONO);
+}
+
+static int set_radio_sleep(struct dvb_frontend *fe)
+{
+       struct tea5761_priv *priv = fe->analog_demod_priv;
+
+       priv->standby = true;
+
+       return __set_radio_freq(fe, priv->frequency, false);
+}
+
 static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
 {
        struct tea5761_priv *priv = fe->tuner_priv;
@@ -284,6 +306,7 @@ static struct dvb_tuner_ops tea5761_tuner_ops = {
                .name           = "tea5761", // Philips TEA5761HN FM Radio
        },
        .set_analog_params = set_radio_freq,
+       .sleep             = set_radio_sleep,
        .release           = tea5761_release,
        .get_frequency     = tea5761_get_frequency,
        .get_status        = tea5761_get_status,
index 58a513bcd747a934f9151aad950510786e52256d..afba6dc5e080396eb1aaade3c5d6ef0872251f08 100644 (file)
@@ -971,6 +971,22 @@ static struct tuner_params tuner_tena_9533_di_params[] = {
        },
 };
 
+/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */
+
+static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = {
+       { 16 * 166.25 /*MHz*/, 0x86, 0x01, },
+       { 16 * 466.25 /*MHz*/, 0x86, 0x02, },
+       { 16 * 999.99        , 0x86, 0x08, },
+};
+
+static struct tuner_params tuner_tena_tnf_5337_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_NTSC,
+               .ranges = tuner_tena_tnf_5337_ntsc_ranges,
+               .count  = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges),
+       },
+};
+
 /* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */
 
 static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
@@ -1842,6 +1858,11 @@ struct tunertype tuners[] = {
                .params = tuner_philips_fq1236_mk5_params,
                .count  = ARRAY_SIZE(tuner_philips_fq1236_mk5_params),
        },
+       [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */
+               .name   = "Tena TNF5337 MFD",
+               .params = tuner_tena_tnf_5337_params,
+               .count  = ARRAY_SIZE(tuner_tena_tnf_5337_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index b6ce528e1889f69bba7c514edb93092a3dec8478..16fba6b59616034382bbf09018795fb29cc4eba1 100644 (file)
@@ -685,7 +685,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
 {
        struct xc2028_data         *priv = fe->tuner_priv;
        struct firmware_properties new_fw;
-       int                        rc = 0, is_retry = 0;
+       int                        rc = 0, retry_count = 0;
        u16                        version, hwmodel;
        v4l2_std_id                std0;
 
@@ -855,9 +855,9 @@ read_not_reliable:
 
 fail:
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-       if (!is_retry) {
+       if (retry_count < 8) {
                msleep(50);
-               is_retry = 1;
+               retry_count++;
                tuner_dbg("Retrying firmware load\n");
                goto retry;
        }
@@ -907,7 +907,7 @@ ret:
 #define DIV 15625
 
 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
-                           enum tuner_mode new_mode,
+                           enum v4l2_tuner_type new_type,
                            unsigned int type,
                            v4l2_std_id std,
                            u16 int_freq)
@@ -933,7 +933,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
         * that xc2028 will be in a safe state.
         * Maybe this might also be needed for DTV.
         */
-       if (new_mode == T_ANALOG_TV) {
+       if (new_type == V4L2_TUNER_ANALOG_TV) {
                rc = send_seq(priv, {0x00, 0x00});
 
                /* Analog modes require offset = 0 */
@@ -1054,7 +1054,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
                if (priv->ctrl.input1)
                        type |= INPUT1;
                return generic_set_freq(fe, (625l * p->frequency) / 10,
-                               T_RADIO, type, 0, 0);
+                               V4L2_TUNER_RADIO, type, 0, 0);
        }
 
        /* if std is not defined, choose one */
@@ -1069,7 +1069,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
        p->std |= parse_audio_std_option();
 
        return generic_set_freq(fe, 62500l * p->frequency,
-                               T_ANALOG_TV, type, p->std, 0);
+                               V4L2_TUNER_ANALOG_TV, type, p->std, 0);
 }
 
 static int xc2028_set_params(struct dvb_frontend *fe,
@@ -1174,7 +1174,7 @@ static int xc2028_set_params(struct dvb_frontend *fe,
        }
 
        return generic_set_freq(fe, p->frequency,
-                               T_DIGITAL_TV, type, 0, demod);
+                               V4L2_TUNER_DIGITAL_TV, type, 0, demod);
 }
 
 static int xc2028_sleep(struct dvb_frontend *fe)
index 76ac5cd84af7049be9aae034094b6a7d9dbecfa3..1e28f7dcb26b6903b459b18e4329c6a0182c3759 100644 (file)
@@ -65,7 +65,7 @@ struct xc5000_priv {
 };
 
 /* Misc Defines */
-#define MAX_TV_STANDARD                        23
+#define MAX_TV_STANDARD                        24
 #define XC_MAX_I2C_WRITE_LENGTH                64
 
 /* Signal Types */
@@ -92,6 +92,8 @@ struct xc5000_priv {
 #define XREG_IF_OUT       0x05
 #define XREG_SEEK_MODE    0x07
 #define XREG_POWER_DOWN   0x0A /* Obsolete */
+/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
+#define XREG_OUTPUT_AMP   0x0B
 #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
 #define XREG_SMOOTHEDCVBS 0x0E
 #define XREG_XTALFREQ     0x0F
@@ -173,6 +175,7 @@ struct XC_TV_STANDARD {
 #define DTV7                   20
 #define FM_Radio_INPUT2        21
 #define FM_Radio_INPUT1        22
+#define FM_Radio_INPUT1_MONO   23
 
 static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
@@ -197,7 +200,8 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"DTV7/8",            0x00C0, 0x801B},
        {"DTV7",              0x00C0, 0x8007},
        {"FM Radio-INPUT2",   0x9802, 0x9002},
-       {"FM Radio-INPUT1",   0x0208, 0x9002}
+       {"FM Radio-INPUT1",   0x0208, 0x9002},
+       {"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
 };
 
 static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
@@ -683,6 +687,24 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                        return -EINVAL;
                }
                priv->rf_mode = XC_RF_MODE_AIR;
+       } else if (fe->ops.info.type == FE_QAM) {
+               dprintk(1, "%s() QAM\n", __func__);
+               switch (params->u.qam.modulation) {
+               case QAM_16:
+               case QAM_32:
+               case QAM_64:
+               case QAM_128:
+               case QAM_256:
+               case QAM_AUTO:
+                       dprintk(1, "%s() QAM modulation\n", __func__);
+                       priv->bandwidth = BANDWIDTH_8_MHZ;
+                       priv->video_standard = DTV7_8;
+                       priv->freq_hz = params->frequency - 2750000;
+                       priv->rf_mode = XC_RF_MODE_CABLE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
        } else {
                printk(KERN_ERR "xc5000 modulation type not supported!\n");
                return -EINVAL;
@@ -714,6 +736,8 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                return -EIO;
        }
 
+       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+
        xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
 
        if (debug)
@@ -818,6 +842,8 @@ tune_channel:
                return -EREMOTEIO;
        }
 
+       xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+
        xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
 
        if (debug)
@@ -845,6 +871,8 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                radio_input = FM_Radio_INPUT1;
        else if  (priv->radio_input == XC5000_RADIO_FM2)
                radio_input = FM_Radio_INPUT2;
+       else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
+               radio_input = FM_Radio_INPUT1_MONO;
        else {
                dprintk(1, "%s() unknown radio input %d\n", __func__,
                        priv->radio_input);
@@ -871,6 +899,12 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
                return -EREMOTEIO;
        }
 
+       if ((priv->radio_input == XC5000_RADIO_FM1) ||
+                               (priv->radio_input == XC5000_RADIO_FM2))
+               xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
+       else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
+               xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
+
        xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
 
        return 0;
@@ -1021,6 +1055,23 @@ static int xc5000_release(struct dvb_frontend *fe)
        return 0;
 }
 
+static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+       struct xc5000_priv *priv = fe->tuner_priv;
+       struct xc5000_config *p = priv_cfg;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (p->if_khz)
+               priv->if_khz = p->if_khz;
+
+       if (p->radio_input)
+               priv->radio_input = p->radio_input;
+
+       return 0;
+}
+
+
 static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .info = {
                .name           = "Xceive XC5000",
@@ -1033,6 +1084,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
        .init              = xc5000_init,
        .sleep             = xc5000_sleep,
 
+       .set_config        = xc5000_set_config,
        .set_params        = xc5000_set_params,
        .set_analog_params = xc5000_set_analog_params,
        .get_frequency     = xc5000_get_frequency,
index 3756e73649bea20345090242e075ac0dfc7aa8a3..e2957451b5321bd9a2c43c3a4df83e96329fbf7c 100644 (file)
@@ -40,6 +40,7 @@ struct xc5000_config {
 #define XC5000_RADIO_NOT_CONFIGURED            0
 #define XC5000_RADIO_FM1                       1
 #define XC5000_RADIO_FM2                       2
+#define XC5000_RADIO_FM1_MONO                  3
 
 /* For each bridge framework, when it attaches either analog or digital,
  * it has to store a reference back to its _core equivalent structure,
index 161ccfd471cb3703db631b8e7abd20eb2abc83ae..ee214c3b63d7050c8629f14ee8a6f148a1d881d2 100644 (file)
@@ -65,7 +65,7 @@ comment "Supported SDMC DM1105 Adapters"
 source "drivers/media/dvb/dm1105/Kconfig"
 
 comment "Supported FireWire (IEEE 1394) Adapters"
-       depends on DVB_CORE && IEEE1394
+       depends on DVB_CORE && FIREWIRE
 source "drivers/media/dvb/firewire/Kconfig"
 
 comment "Supported Earthsoft PT1 Adapters"
index f9f19be77181329c9fe2123532ccfeb268fb25f8..3b860504bf04636ffc058cf818c98bd55d523f97 100644 (file)
@@ -239,7 +239,6 @@ struct analog_demod_ops {
        void (*set_params)(struct dvb_frontend *fe,
                           struct analog_parameters *params);
        int  (*has_signal)(struct dvb_frontend *fe);
-       int  (*is_stereo)(struct dvb_frontend *fe);
        int  (*get_afc)(struct dvb_frontend *fe);
        void (*tuner_status)(struct dvb_frontend *fe);
        void (*standby)(struct dvb_frontend *fe);
index 3d48ba0193425b9b1971d5eb03385fcb94209d96..fe4f894183ffcf5bb65b85ab85b4ca0acc12473d 100644 (file)
@@ -358,3 +358,11 @@ config DVB_USB_LME2510
        select DVB_IX2505V if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
+
+config DVB_USB_TECHNISAT_USB2
+       tristate "Technisat DVB-S/S2 USB2.0 support"
+       depends on DVB_USB
+       select DVB_STB0899 if !DVB_FE_CUSTOMISE
+       select DVB_STB6100 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Technisat USB2 DVB-S/S2 device
index 5b1d12f2d59184a36138427f5e513d5722441a6c..4bac13da0c39eb55ecff23fe52b41b39be1d324c 100644 (file)
@@ -91,6 +91,9 @@ obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 dvb-usb-lmedm04-objs = lmedm04.o
 obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
 
+dvb-usb-technisat-usb2-objs = technisat-usb2.o
+obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
index 53b93a4b6f8acf27a7d543821c57a9d36a08c86c..f8e9bf116f2117a0287bc3e0554e880aa0b30e66 100644 (file)
@@ -38,8 +38,8 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
 }
 
 static struct rc_map_table rc_map_a800_table[] = {
-       { 0x0201, KEY_PROG1 },       /* SOURCE */
-       { 0x0200, KEY_POWER },       /* POWER */
+       { 0x0201, KEY_MODE },      /* SOURCE */
+       { 0x0200, KEY_POWER2 },      /* POWER */
        { 0x0205, KEY_1 },           /* 1 */
        { 0x0206, KEY_2 },           /* 2 */
        { 0x0207, KEY_3 },           /* 3 */
@@ -52,8 +52,8 @@ static struct rc_map_table rc_map_a800_table[] = {
        { 0x0212, KEY_LEFT },        /* L / DISPLAY */
        { 0x0211, KEY_0 },           /* 0 */
        { 0x0213, KEY_RIGHT },       /* R / CH RTN */
-       { 0x0217, KEY_PROG2 },       /* SNAP SHOT */
-       { 0x0210, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x0217, KEY_CAMERA },      /* SNAP SHOT */
+       { 0x0210, KEY_LAST },        /* 16-CH PREV */
        { 0x021e, KEY_VOLUMEDOWN },  /* VOL DOWN */
        { 0x020c, KEY_ZOOM },        /* FULL SCREEN */
        { 0x021f, KEY_VOLUMEUP },    /* VOL UP */
index 8671ca362c81f858f0a644ddf461c347e7974b80..100ebc37e99e2293699816a15556fdc672640e05 100644 (file)
@@ -479,6 +479,7 @@ static int af9015_init_endpoint(struct dvb_usb_device *d)
                ret = af9015_set_reg_bit(d, 0xd50b, 0);
        else
                ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+
 error:
        if (ret)
                err("endpoint init failed:%d", ret);
@@ -611,6 +612,11 @@ static int af9015_init(struct dvb_usb_device *d)
        int ret;
        deb_info("%s:\n", __func__);
 
+       /* init RC canary */
+       ret = af9015_write_reg(d, 0x98e9, 0xff);
+       if (ret)
+               goto error;
+
        ret = af9015_init_endpoint(d);
        if (ret)
                goto error;
@@ -659,9 +665,8 @@ error:
 static int af9015_download_firmware(struct usb_device *udev,
        const struct firmware *fw)
 {
-       int i, len, packets, remainder, ret;
+       int i, len, remaining, ret;
        struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
-       u16 addr = 0x5100; /* firmware start address */
        u16 checksum = 0;
 
        deb_info("%s:\n", __func__);
@@ -673,24 +678,20 @@ static int af9015_download_firmware(struct usb_device *udev,
        af9015_config.firmware_size = fw->size;
        af9015_config.firmware_checksum = checksum;
 
-       #define FW_PACKET_MAX_DATA  55
-
-       packets = fw->size / FW_PACKET_MAX_DATA;
-       remainder = fw->size % FW_PACKET_MAX_DATA;
-       len = FW_PACKET_MAX_DATA;
-       for (i = 0; i <= packets; i++) {
-               if (i == packets)  /* set size of the last packet */
-                       len = remainder;
+       #define FW_ADDR 0x5100 /* firmware start address */
+       #define LEN_MAX 55 /* max packet size */
+       for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+               len = remaining;
+               if (len > LEN_MAX)
+                       len = LEN_MAX;
 
                req.data_len = len;
-               req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
-               req.addr = addr;
-               addr += FW_PACKET_MAX_DATA;
+               req.data = (u8 *) &fw->data[fw->size - remaining];
+               req.addr = FW_ADDR + fw->size - remaining;
 
                ret = af9015_rw_udev(udev, &req);
                if (ret) {
-                       err("firmware download failed at packet %d with " \
-                               "code %d", i, ret);
+                       err("firmware download failed:%d", ret);
                        goto error;
                }
        }
@@ -738,6 +739,8 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
 };
 
 static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
+       { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC,
+               RC_MAP_TERRATEC_SLIM_2 },
        { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
                RC_MAP_TERRATEC_SLIM },
        { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
@@ -1016,22 +1019,38 @@ static int af9015_rc_query(struct dvb_usb_device *d)
 {
        struct af9015_state *priv = d->priv;
        int ret;
-       u8 buf[16];
+       u8 buf[17];
 
        /* read registers needed to detect remote controller code */
        ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
        if (ret)
                goto error;
 
-       if (buf[14] || buf[15]) {
+       /* If any of these are non-zero, assume invalid data */
+       if (buf[1] || buf[2] || buf[3])
+               return ret;
+
+       /* Check for repeat of previous code */
+       if ((priv->rc_repeat != buf[6] || buf[0]) &&
+                                       !memcmp(&buf[12], priv->rc_last, 4)) {
+               deb_rc("%s: key repeated\n", __func__);
+               rc_keydown(d->rc_dev, priv->rc_keycode, 0);
+               priv->rc_repeat = buf[6];
+               return ret;
+       }
+
+       /* Only process key if canary killed */
+       if (buf[16] != 0xff && buf[0] != 0x01) {
                deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
                        buf[12], buf[13], buf[14], buf[15]);
 
-               /* clean IR code from mem */
-               ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4);
+               /* Reset the canary */
+               ret = af9015_write_reg(d, 0x98e9, 0xff);
                if (ret)
                        goto error;
 
+               /* Remember this key */
+               memcpy(priv->rc_last, &buf[12], 4);
                if (buf[14] == (u8) ~buf[15]) {
                        if (buf[12] == (u8) ~buf[13]) {
                                /* NEC */
@@ -1041,15 +1060,17 @@ static int af9015_rc_query(struct dvb_usb_device *d)
                                priv->rc_keycode = buf[12] << 16 |
                                        buf[13] << 8 | buf[14];
                        }
-                       rc_keydown(d->rc_dev, priv->rc_keycode, 0);
                } else {
-                       priv->rc_keycode = 0; /* clear just for sure */
+                       /* 32 bit NEC */
+                       priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
+                                       buf[14] << 8 | buf[15];
                }
-       } else if (priv->rc_repeat != buf[6] || buf[0]) {
-               deb_rc("%s: key repeated\n", __func__);
                rc_keydown(d->rc_dev, priv->rc_keycode, 0);
        } else {
                deb_rc("%s: no key press\n", __func__);
+               /* Invalidate last keypress */
+               /* Not really needed, but helps with debug */
+               priv->rc_last[2] = priv->rc_last[3];
        }
 
        priv->rc_repeat = buf[6];
index f20cfa6ed6901ce04cbdd06525fc8a09bf68f494..beb3004f00ba31640aab86399fd7ef4889469d14 100644 (file)
@@ -102,6 +102,7 @@ struct af9015_state {
        struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
        u8 rc_repeat;
        u32 rc_keycode;
+       u8 rc_last[4];
 };
 
 struct af9015_config {
index 3537d65c04bc02ad6a417b94eeba872cb3a82b2f..b2a87f2c2c3e43f8bf73c42e9915d6249533e260 100644 (file)
@@ -32,6 +32,7 @@ extern int dvb_usb_dib0700_debug;
        // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
        // 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
        // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
+#define REQUEST_SET_I2C_PARAM       0x10
 #define REQUEST_SET_RC              0x11
 #define REQUEST_NEW_I2C_READ        0x12
 #define REQUEST_NEW_I2C_WRITE       0x13
@@ -61,6 +62,7 @@ extern struct i2c_algorithm dib0700_i2c_algo;
 extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
                        struct dvb_usb_device_description **desc, int *cold);
 extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type);
+extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz);
 
 extern int dib0700_device_count;
 extern int dvb_usb_dib0700_ir_proto;
index 98ffb40728e34eeaed9f90e981950cae3610630e..b79af68c54ae5e99b4b734031a32c29cad79eb91 100644 (file)
@@ -186,7 +186,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 msg[i].len,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
-                               err("i2c read error (status = %d)\n", result);
+                               deb_info("i2c read error (status = %d)\n", result);
                                break;
                        }
 
@@ -215,7 +215,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 0, 0, buf, msg[i].len + 4,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
-                               err("i2c write error (status = %d)\n", result);
+                               deb_info("i2c write error (status = %d)\n", result);
                                break;
                        }
                }
@@ -328,6 +328,31 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
        return dib0700_ctrl_wr(d, b, 10);
 }
 
+int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+{
+       u16 divider;
+       u8 b[8];
+
+       if (scl_kHz == 0)
+               return -EINVAL;
+
+       b[0] = REQUEST_SET_I2C_PARAM;
+       divider = (u16) (30000 / scl_kHz);
+       b[2] = (u8) (divider >> 8);
+       b[3] = (u8) (divider & 0xff);
+       divider = (u16) (72000 / scl_kHz);
+       b[4] = (u8) (divider >> 8);
+       b[5] = (u8) (divider & 0xff);
+       divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
+       b[6] = (u8) (divider >> 8);
+       b[7] = (u8) (divider & 0xff);
+
+       deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+               (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz);
+       return dib0700_ctrl_wr(d, b, 8);
+}
+
+
 int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
 {
        switch (clk_MHz) {
@@ -459,10 +484,20 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
 
-       if (onoff)
-               st->channel_state |=   1 << adap->id;
-       else
-               st->channel_state &= ~(1 << adap->id);
+       st->channel_state &= ~0x3;
+       if ((adap->stream.props.endpoint != 2)
+                       && (adap->stream.props.endpoint != 3)) {
+               deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint);
+               if (onoff)
+                       st->channel_state |=    1 << (adap->id);
+               else
+                       st->channel_state |=    1 << ~(adap->id);
+       } else {
+               if (onoff)
+                       st->channel_state |=    1 << (adap->stream.props.endpoint-2);
+               else
+                       st->channel_state |=    1 << (3-adap->stream.props.endpoint);
+       }
 
        b[2] |= st->channel_state;
 
index 193cdb77b76a278cf56f5cfc0afa63d1cd0a8bb6..97af266d7f1deb8543fe2343be238853e9e154be 100644 (file)
@@ -12,6 +12,7 @@
 #include "dib7000m.h"
 #include "dib7000p.h"
 #include "dib8000.h"
+#include "dib9000.h"
 #include "mt2060.h"
 #include "mt2266.h"
 #include "tuner-xc2028.h"
@@ -29,6 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif
 
 struct dib0700_adapter_state {
        int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+       const struct firmware *frontend_firmware;
 };
 
 /* Hauppauge Nova-T 500 (aka Bristol)
@@ -1243,13 +1245,13 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
 static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
        u16 pid, int onoff)
 {
-    return dib8000_pid_filter(adapter->fe, index, pid, onoff);
+       return dib8000_pid_filter(adapter->fe, index, pid, onoff);
 }
 
 static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
-       int onoff)
+               int onoff)
 {
-    return dib8000_pid_filter_ctrl(adapter->fe, onoff);
+       return dib8000_pid_filter_ctrl(adapter->fe, onoff);
 }
 
 /* STK807x */
@@ -1321,11 +1323,11 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 
 /* STK8096GP */
 struct dibx000_agc_config dib8090_agc_config[2] = {
-    {
+       {
        BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+        * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+        * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
        (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
        | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
 
@@ -1362,12 +1364,12 @@ struct dibx000_agc_config dib8090_agc_config[2] = {
        51,
 
        0,
-    },
-    {
+       },
+       {
        BAND_CBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+        * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+        * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
        (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
        | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
 
@@ -1404,159 +1406,1097 @@ struct dibx000_agc_config dib8090_agc_config[2] = {
        51,
 
        0,
-    }
+       }
 };
 
 static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
-    54000, 13500,
-    1, 18, 3, 1, 0,
-    0, 0, 1, 1, 2,
-    (3 << 14) | (1 << 12) | (599 << 0),
-    (0 << 25) | 0,
-    20199727,
-    12000000,
+       54000, 13500,
+       1, 18, 3, 1, 0,
+       0, 0, 1, 1, 2,
+       (3 << 14) | (1 << 12) | (599 << 0),
+       (0 << 25) | 0,
+       20199727,
+       12000000,
 };
 
 static int dib8090_get_adc_power(struct dvb_frontend *fe)
 {
-    return dib8000_get_adc_power(fe, 1);
+       return dib8000_get_adc_power(fe, 1);
+}
+
+static struct dib8000_config dib809x_dib8000_config[2] = {
+       {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 2,
+       .agc = dib8090_agc_config,
+       .agc_control = dib0090_dcc_freq,
+       .pll = &dib8090_pll_config_12mhz,
+       .tuner_is_baseband = 1,
+
+       .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+       .hostbus_diversity = 1,
+       .div_cfg = 0x31,
+       .output_mode = OUTMODE_MPEG2_FIFO,
+       .drives = 0x2d98,
+       .diversity_delay = 48,
+       .refclksel = 3,
+       }, {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 2,
+       .agc = dib8090_agc_config,
+       .agc_control = dib0090_dcc_freq,
+       .pll = &dib8090_pll_config_12mhz,
+       .tuner_is_baseband = 1,
+
+       .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+       .hostbus_diversity = 1,
+       .div_cfg = 0x31,
+       .output_mode = OUTMODE_DIVERSITY,
+       .drives = 0x2d08,
+       .diversity_delay = 1,
+       .refclksel = 3,
+       }
+};
+
+static struct dib0090_wbd_slope dib8090_wbd_table[] = {
+       /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */
+       { 120,     0, 500,  0,   500, 4 }, /* CBAND */
+       { 170,     0, 450,  0,   450, 4 }, /* CBAND */
+       { 380,    48, 373, 28,   259, 6 }, /* VHF */
+       { 860,    34, 700, 36,   616, 6 }, /* high UHF */
+       { 0xFFFF, 34, 700, 36,   616, 6 }, /* default */
+};
+
+static struct dib0090_config dib809x_dib0090_config = {
+       .io.pll_bypass = 1,
+       .io.pll_range = 1,
+       .io.pll_prediv = 1,
+       .io.pll_loopdiv = 20,
+       .io.adc_clock_ratio = 8,
+       .io.pll_int_loop_filt = 0,
+       .io.clock_khz = 12000,
+       .reset = dib80xx_tuner_reset,
+       .sleep = dib80xx_tuner_sleep,
+       .clkouttobamse = 1,
+       .analog_output = 1,
+       .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 1,
+       .get_adc_power = dib8090_get_adc_power,
+       .freq_offset_khz_uhf = -63,
+       .freq_offset_khz_vhf = -143,
+       .wbd = dib8090_wbd_table,
+       .fref_clock_ratio = 6,
+};
+
+static int dib8096_set_param_override(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u16 target;
+       int ret = 0;
+       enum frontend_tune_state tune_state = CT_SHUTDOWN;
+       u16 ltgain, rf_gain_limit;
+
+       ret = state->set_param_save(fe, fep);
+       if (ret < 0)
+               return ret;
+
+       target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
+       dib8000_set_wbd_ref(fe, target);
+
+
+       if (band == BAND_CBAND) {
+               deb_info("tuning in CBAND - soft-AGC startup\n");
+               dib0090_set_tune_state(fe, CT_AGC_START);
+               do {
+                       ret = dib0090_gain_control(fe);
+                       msleep(ret);
+                       tune_state = dib0090_get_tune_state(fe);
+                       if (tune_state == CT_AGC_STEP_0)
+                               dib8000_set_gpio(fe, 6, 0, 1);
+                       else if (tune_state == CT_AGC_STEP_1) {
+                               dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
+                               if (rf_gain_limit == 0)
+                                       dib8000_set_gpio(fe, 6, 0, 0);
+                       }
+               } while (tune_state < CT_AGC_STOP);
+               dib0090_pwm_gain_reset(fe);
+               dib8000_pwm_agc_reset(fe);
+               dib8000_set_tune_state(fe, CT_DEMOD_START);
+       } else {
+               deb_info("not tuning in CBAND - standard AGC startup\n");
+               dib0090_pwm_gain_reset(fe);
+       }
+
+       return 0;
+}
+
+static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+               return -ENODEV;
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+       return 0;
+}
+
+static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+
+       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+
+       return adap->fe == NULL ?  -ENODEV : 0;
+}
+
+static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c;
+       struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe, 1);
+
+       if (fe_slave) {
+               tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
+               if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
+                       return -ENODEV;
+               fe_slave->dvb = adap->fe->dvb;
+               fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
+       }
+       tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+               return -ENODEV;
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+
+       return 0;
+}
+
+static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_frontend *fe_slave;
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(1000);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80);
+
+       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
+       dib8000_set_slave_frontend(adap->fe, fe_slave);
+
+       return fe_slave == NULL ?  -ENODEV : 0;
+}
+
+/* STK9090M */
+static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+       return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff);
+}
+
+static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+       return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff);
+}
+
+static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+       return dib9000_set_gpio(fe, 5, 0, !onoff);
+}
+
+static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       return dib9000_set_gpio(fe, 0, 0, onoff);
+}
+
+static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len)
+{
+       u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 };
+       u8 rb[2];
+       struct i2c_msg msg[2] = {
+               {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2},
+               {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
+       };
+       u8 index_data;
+
+       dibx000_i2c_set_speed(i2c, 250);
+
+       if (i2c_transfer(i2c, msg, 2) != 2)
+               return -EIO;
+
+       switch (rb[0] << 8 | rb[1]) {
+       case 0:
+                       deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n");
+                       return -EIO;
+       case 1:
+                       deb_info("Found DiB0170 rev2");
+                       break;
+       case 2:
+                       deb_info("Found DiB0190 rev2");
+                       break;
+       default:
+                       deb_info("DiB01x0 not found");
+                       return -EIO;
+       }
+
+       for (index_data = 0; index_data < len; index_data += 2) {
+               wb[2] = (data[index_data + 1] >> 8) & 0xff;
+               wb[3] = (data[index_data + 1]) & 0xff;
+
+               if (data[index_data] == 0) {
+                       wb[0] = (data[index_data] >> 8) & 0xff;
+                       wb[1] = (data[index_data]) & 0xff;
+                       msg[0].len = 2;
+                       if (i2c_transfer(i2c, msg, 2) != 2)
+                               return -EIO;
+                       wb[2] |= rb[0];
+                       wb[3] |= rb[1] & ~(3 << 4);
+               }
+
+               wb[0] = (data[index_data] >> 8)&0xff;
+               wb[1] = (data[index_data])&0xff;
+               msg[0].len = 4;
+               if (i2c_transfer(i2c, &msg[0], 1) != 1)
+                       return -EIO;
+       }
+       return 0;
+}
+
+static struct dib9000_config stk9090m_config = {
+       .output_mpeg2_in_188_bytes = 1,
+       .output_mode = OUTMODE_MPEG2_FIFO,
+       .vcxo_timer = 279620,
+       .timing_frequency = 20452225,
+       .demod_clock_khz = 60000,
+       .xtal_clock_khz = 30000,
+       .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+       .subband = {
+               2,
+               {
+                       { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */
+                       { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */
+                       { 0 },
+               },
+       },
+       .gpio_function = {
+               { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+               { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+       },
+};
+
+static struct dib9000_config nim9090md_config[2] = {
+       {
+               .output_mpeg2_in_188_bytes = 1,
+               .output_mode = OUTMODE_MPEG2_FIFO,
+               .vcxo_timer = 279620,
+               .timing_frequency = 20452225,
+               .demod_clock_khz = 60000,
+               .xtal_clock_khz = 30000,
+               .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+       }, {
+               .output_mpeg2_in_188_bytes = 1,
+               .output_mode = OUTMODE_DIVERSITY,
+               .vcxo_timer = 279620,
+               .timing_frequency = 20452225,
+               .demod_clock_khz = 60000,
+               .xtal_clock_khz = 30000,
+               .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+               .subband = {
+                       2,
+                       {
+                               { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */
+                               { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */
+                               { 0 },
+                       },
+               },
+               .gpio_function = {
+                       { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+                       { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+               },
+       }
+};
+
+static struct dib0090_config dib9090_dib0090_config = {
+       .io.pll_bypass = 0,
+       .io.pll_range = 1,
+       .io.pll_prediv = 1,
+       .io.pll_loopdiv = 8,
+       .io.adc_clock_ratio = 8,
+       .io.pll_int_loop_filt = 0,
+       .io.clock_khz = 30000,
+       .reset = dib90x0_tuner_reset,
+       .sleep = dib90x0_tuner_sleep,
+       .clkouttobamse = 0,
+       .analog_output = 0,
+       .use_pwm_agc = 0,
+       .clkoutdrive = 0,
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+};
+
+static struct dib0090_config nim9090md_dib0090_config[2] = {
+       {
+               .io.pll_bypass = 0,
+               .io.pll_range = 1,
+               .io.pll_prediv = 1,
+               .io.pll_loopdiv = 8,
+               .io.adc_clock_ratio = 8,
+               .io.pll_int_loop_filt = 0,
+               .io.clock_khz = 30000,
+               .reset = dib90x0_tuner_reset,
+               .sleep = dib90x0_tuner_sleep,
+               .clkouttobamse = 1,
+               .analog_output = 0,
+               .use_pwm_agc = 0,
+               .clkoutdrive = 0,
+               .freq_offset_khz_uhf = 0,
+               .freq_offset_khz_vhf = 0,
+       }, {
+               .io.pll_bypass = 0,
+               .io.pll_range = 1,
+               .io.pll_prediv = 1,
+               .io.pll_loopdiv = 8,
+               .io.adc_clock_ratio = 8,
+               .io.pll_int_loop_filt = 0,
+               .io.clock_khz = 30000,
+               .reset = dib90x0_tuner_reset,
+               .sleep = dib90x0_tuner_sleep,
+               .clkouttobamse = 0,
+               .analog_output = 0,
+               .use_pwm_agc = 0,
+               .clkoutdrive = 0,
+               .freq_offset_khz_uhf = 0,
+               .freq_offset_khz_vhf = 0,
+       }
+};
+
+
+static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dib0700_state *st = adap->dev->priv;
+       u32 fw_version;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+       if (fw_version >= 0x10200)
+               st->fw_use_new_i2c_api = 1;
+       dib0700_set_i2c_speed(adap->dev, 340);
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80);
+
+       if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+               deb_info("%s: Upload failed. (file not found?)\n", __func__);
+               return -ENODEV;
+       } else {
+               deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+       }
+       stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size;
+       stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data;
+
+       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
+
+       return adap->fe == NULL ?  -ENODEV : 0;
+}
+
+static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe);
+       u16 data_dib190[10] = {
+               1, 0x1374,
+               2, 0x01a2,
+               7, 0x0020,
+               0, 0x00ef,
+               8, 0x0486,
+       };
+
+       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL)
+               return -ENODEV;
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
+               return -ENODEV;
+       dib0700_set_i2c_speed(adap->dev, 2000);
+       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+               return -ENODEV;
+       release_firmware(state->frontend_firmware);
+       return 0;
+}
+
+static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dib0700_state *st = adap->dev->priv;
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe_slave;
+       u32 fw_version;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+       if (fw_version >= 0x10200)
+               st->fw_use_new_i2c_api = 1;
+       dib0700_set_i2c_speed(adap->dev, 340);
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+               deb_info("%s: Upload failed. (file not found?)\n", __func__);
+               return -EIO;
+       } else {
+               deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+       }
+       nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size;
+       nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data;
+       nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size;
+       nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data;
+
+       dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
+       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
+
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
+       dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
+
+       fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
+       dib9000_set_slave_frontend(adap->fe, fe_slave);
+
+       return fe_slave == NULL ?  -ENODEV : 0;
+}
+
+static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe_slave;
+       u16 data_dib190[10] = {
+               1, 0x5374,
+               2, 0x01ae,
+               7, 0x0020,
+               0, 0x00ef,
+               8, 0x0406,
+       };
+       i2c = dib9000_get_tuner_interface(adap->fe);
+       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
+               return -ENODEV;
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
+               return -ENODEV;
+       dib0700_set_i2c_speed(adap->dev, 2000);
+       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+               return -ENODEV;
+
+       fe_slave = dib9000_get_slave_frontend(adap->fe, 1);
+       if (fe_slave != NULL) {
+               i2c = dib9000_get_component_bus_interface(adap->fe);
+               dib9000_set_i2c_adapter(fe_slave, i2c);
+
+               i2c = dib9000_get_tuner_interface(fe_slave);
+               if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
+                       return -ENODEV;
+               fe_slave->dvb = adap->fe->dvb;
+               dib9000_fw_set_component_bus_speed(adap->fe, 2000);
+               if (dib9000_firmware_post_pll_init(fe_slave) < 0)
+                       return -ENODEV;
+       }
+       release_firmware(state->frontend_firmware);
+
+       return 0;
 }
 
-static struct dib8000_config dib809x_dib8000_config = {
-    .output_mpeg2_in_188_bytes = 1,
-
-    .agc_config_count = 2,
-    .agc = dib8090_agc_config,
-    .agc_control = dib0090_dcc_freq,
-    .pll = &dib8090_pll_config_12mhz,
-    .tuner_is_baseband = 1,
-
-    .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-    .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-    .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-    .hostbus_diversity = 1,
-    .div_cfg = 0x31,
-    .output_mode = OUTMODE_MPEG2_FIFO,
-    .drives = 0x2d98,
-    .diversity_delay = 144,
-    .refclksel = 3,
-};
+/* NIM7090 */
+struct dib7090p_best_adc {
+       u32 timf;
+       u32 pll_loopdiv;
+       u32 pll_prediv;
+};
+
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+{
+       u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+
+       u16 xtal = 12000;
+       u32 fcp_min = 1900;  /* PLL Minimum Frequency comparator KHz */
+       u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */
+       u32 fdem_max = 76000;
+       u32 fdem_min = 69500;
+       u32 fcp = 0, fs = 0, fdem = 0;
+       u32 harmonic_id = 0;
+
+       adc->pll_loopdiv = loopdiv;
+       adc->pll_prediv = prediv;
+       adc->timf = 0;
+
+       deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min);
+
+       /* Find Min and Max prediv */
+       while ((xtal/max_prediv) >= fcp_min)
+               max_prediv++;
+
+       max_prediv--;
+       min_prediv = max_prediv;
+       while ((xtal/min_prediv) <= fcp_max) {
+               min_prediv--;
+               if (min_prediv == 1)
+                       break;
+       }
+       deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+       min_prediv = 2;
+
+       for (prediv = min_prediv ; prediv < max_prediv; prediv++) {
+               fcp = xtal / prediv;
+               if (fcp > fcp_min && fcp < fcp_max) {
+                       for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) {
+                               fdem = ((xtal/prediv) * loopdiv);
+                               fs   = fdem / 4;
+                               /* test min/max system restrictions */
+
+                               if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) {
+                                       spur = 0;
+                                       /* test fs harmonics positions */
+                                       for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ;  harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) {
+                                               if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) &&  ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) {
+                                                       spur = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (!spur) {
+                                               adc->pll_loopdiv = loopdiv;
+                                               adc->pll_prediv = prediv;
+                                               adc->timf = 2396745143UL/fdem*(1 << 9);
+                                               adc->timf += ((2396745143UL%fdem) << 9)/fdem;
+                                               deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if (!spur)
+                       break;
+       }
+
+
+       if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
+               return -EINVAL;
+       else
+               return 0;
+}
+
+static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dibx000_bandwidth_config pll;
+       u16 target;
+       struct dib7090p_best_adc adc;
+       int ret;
+
+       ret = state->set_param_save(fe, fep);
+       if (ret < 0)
+               return ret;
+
+       memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+       dib0090_pwm_gain_reset(fe);
+       target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2;
+       dib7000p_set_wbd_ref(fe, target);
+
+       if (dib7090p_get_best_sampling(fe, &adc) == 0) {
+               pll.pll_ratio  = adc.pll_loopdiv;
+               pll.pll_prediv = adc.pll_prediv;
+
+               dib7000p_update_pll(fe, &pll);
+               dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+       }
+       return 0;
+}
+
+static struct dib0090_wbd_slope dib7090_wbd_table[] = {
+       { 380,   81, 850, 64, 540,  4},
+       { 860,   51, 866, 21,  375, 4},
+       {1700,    0, 250, 0,   100, 6},
+       {2600,    0, 250, 0,   100, 6},
+       { 0xFFFF, 0,   0, 0,   0,   0},
+};
+
+struct dibx000_agc_config dib7090_agc_config[2] = {
+       {
+               .band_caps      = BAND_UHF,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+               * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+               .setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+               .inv_gain       = 687,
+               .time_stabiliz  = 10,
+
+               .alpha_level    = 0,
+               .thlock         = 118,
+
+               .wbd_inv        = 0,
+               .wbd_ref        = 1200,
+               .wbd_sel        = 3,
+               .wbd_alpha      = 5,
+
+               .agc1_max       = 65535,
+               .agc1_min       = 0,
+
+               .agc2_max       = 65535,
+               .agc2_min       = 0,
+
+               .agc1_pt1       = 0,
+               .agc1_pt2       = 32,
+               .agc1_pt3       = 114,
+               .agc1_slope1    = 143,
+               .agc1_slope2    = 144,
+               .agc2_pt1       = 114,
+               .agc2_pt2       = 227,
+               .agc2_slope1    = 116,
+               .agc2_slope2    = 117,
+
+               .alpha_mant     = 18,
+               .alpha_exp      = 0,
+               .beta_mant      = 20,
+               .beta_exp       = 59,
+
+               .perform_agc_softsplit = 0,
+       } , {
+               .band_caps      = BAND_FM | BAND_VHF | BAND_CBAND,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+               * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+               .setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+
+               .inv_gain       = 732,
+               .time_stabiliz  = 10,
+
+               .alpha_level    = 0,
+               .thlock         = 118,
+
+               .wbd_inv        = 0,
+               .wbd_ref        = 1200,
+               .wbd_sel        = 3,
+               .wbd_alpha      = 5,
+
+               .agc1_max       = 65535,
+               .agc1_min       = 0,
+
+               .agc2_max       = 65535,
+               .agc2_min       = 0,
+
+               .agc1_pt1       = 0,
+               .agc1_pt2       = 0,
+               .agc1_pt3       = 98,
+               .agc1_slope1    = 0,
+               .agc1_slope2    = 167,
+               .agc1_pt1       = 98,
+               .agc2_pt2       = 255,
+               .agc2_slope1    = 104,
+               .agc2_slope2    = 0,
+
+               .alpha_mant     = 18,
+               .alpha_exp      = 0,
+               .beta_mant      = 20,
+               .beta_exp       = 59,
+
+               .perform_agc_softsplit = 0,
+       }
+};
+
+static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
+       60000, 15000,
+       1, 5, 0, 0, 0,
+       0, 0, 1, 1, 2,
+       (3 << 14) | (1 << 12) | (524 << 0),
+       (0 << 25) | 0,
+       20452225,
+       15000000,
+};
+
+static struct dib7000p_config nim7090_dib7000p_config = {
+       .output_mpeg2_in_188_bytes  = 1,
+       .hostbus_diversity                      = 1,
+       .tuner_is_baseband                      = 1,
+       .update_lna                                     = NULL,
+
+       .agc_config_count                       = 2,
+       .agc                                            = dib7090_agc_config,
+
+       .bw                                                     = &dib7090_clock_config_12_mhz,
+
+       .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+       .pwm_freq_div                           = 0,
+
+       .agc_control                            = dib7090_agc_restart,
+
+       .spur_protect                           = 0,
+       .disable_sample_and_hold        = 0,
+       .enable_current_mirror          = 0,
+       .diversity_delay                        = 0,
+
+       .output_mode                            = OUTMODE_MPEG2_FIFO,
+       .enMpegOutput                           = 1,
+};
+
+static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
+       {
+               .output_mpeg2_in_188_bytes  = 1,
+               .hostbus_diversity                      = 1,
+               .tuner_is_baseband                      = 1,
+               .update_lna                                     = NULL,
+
+               .agc_config_count                       = 2,
+               .agc                                            = dib7090_agc_config,
+
+               .bw                                                     = &dib7090_clock_config_12_mhz,
+
+               .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+               .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+               .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+               .pwm_freq_div                           = 0,
+
+               .agc_control                            = dib7090_agc_restart,
+
+               .spur_protect                           = 0,
+               .disable_sample_and_hold        = 0,
+               .enable_current_mirror          = 0,
+               .diversity_delay                        = 0,
+
+               .output_mode                            = OUTMODE_MPEG2_PAR_GATED_CLK,
+               .default_i2c_addr                       = 0x90,
+               .enMpegOutput                           = 1,
+       }, {
+               .output_mpeg2_in_188_bytes  = 1,
+               .hostbus_diversity                      = 1,
+               .tuner_is_baseband                      = 1,
+               .update_lna                                     = NULL,
+
+               .agc_config_count                       = 2,
+               .agc                                            = dib7090_agc_config,
+
+               .bw                                                     = &dib7090_clock_config_12_mhz,
+
+               .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+               .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+               .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+               .pwm_freq_div                           = 0,
+
+               .agc_control                            = dib7090_agc_restart,
+
+               .spur_protect                           = 0,
+               .disable_sample_and_hold        = 0,
+               .enable_current_mirror          = 0,
+               .diversity_delay                        = 0,
+
+               .output_mode                            = OUTMODE_MPEG2_PAR_GATED_CLK,
+               .default_i2c_addr                       = 0x92,
+               .enMpegOutput                           = 0,
+       }
+};
+
+static const struct dib0090_config nim7090_dib0090_config = {
+       .io.clock_khz = 12000,
+       .io.pll_bypass = 0,
+       .io.pll_range = 0,
+       .io.pll_prediv = 3,
+       .io.pll_loopdiv = 6,
+       .io.adc_clock_ratio = 0,
+       .io.pll_int_loop_filt = 0,
+       .reset = dib7090_tuner_sleep,
+       .sleep = dib7090_tuner_sleep,
+
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+
+       .get_adc_power = dib7090_get_adc_power,
+
+       .clkouttobamse = 1,
+       .analog_output = 0,
+
+       .wbd_vhf_offset = 0,
+       .wbd_cband_offset = 0,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 0,
+
+       .fref_clock_ratio = 0,
+
+       .wbd = dib7090_wbd_table,
+
+       .ls_cfg_pad_drv = 0,
+       .data_tx_drv = 0,
+       .low_if = NULL,
+       .in_soc = 1,
+};
+
+static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
+       {
+               .io.clock_khz = 12000,
+               .io.pll_bypass = 0,
+               .io.pll_range = 0,
+               .io.pll_prediv = 3,
+               .io.pll_loopdiv = 6,
+               .io.adc_clock_ratio = 0,
+               .io.pll_int_loop_filt = 0,
+               .reset = dib7090_tuner_sleep,
+               .sleep = dib7090_tuner_sleep,
+
+               .freq_offset_khz_uhf = 50,
+               .freq_offset_khz_vhf = 70,
+
+               .get_adc_power = dib7090_get_adc_power,
+
+               .clkouttobamse = 1,
+               .analog_output = 0,
+
+               .wbd_vhf_offset = 0,
+               .wbd_cband_offset = 0,
+               .use_pwm_agc = 1,
+               .clkoutdrive = 0,
+
+               .fref_clock_ratio = 0,
+
+               .wbd = dib7090_wbd_table,
+
+               .ls_cfg_pad_drv = 0,
+               .data_tx_drv = 0,
+               .low_if = NULL,
+               .in_soc = 1,
+       }, {
+               .io.clock_khz = 12000,
+               .io.pll_bypass = 0,
+               .io.pll_range = 0,
+               .io.pll_prediv = 3,
+               .io.pll_loopdiv = 6,
+               .io.adc_clock_ratio = 0,
+               .io.pll_int_loop_filt = 0,
+               .reset = dib7090_tuner_sleep,
+               .sleep = dib7090_tuner_sleep,
+
+               .freq_offset_khz_uhf = -50,
+               .freq_offset_khz_vhf = -70,
+
+               .get_adc_power = dib7090_get_adc_power,
+
+               .clkouttobamse = 1,
+               .analog_output = 0,
+
+               .wbd_vhf_offset = 0,
+               .wbd_cband_offset = 0,
+               .use_pwm_agc = 1,
+               .clkoutdrive = 0,
+
+               .fref_clock_ratio = 0,
+
+               .wbd = dib7090_wbd_table,
 
-static struct dib0090_config dib809x_dib0090_config = {
-    .io.pll_bypass = 1,
-    .io.pll_range = 1,
-    .io.pll_prediv = 1,
-    .io.pll_loopdiv = 20,
-    .io.adc_clock_ratio = 8,
-    .io.pll_int_loop_filt = 0,
-    .io.clock_khz = 12000,
-    .reset = dib80xx_tuner_reset,
-    .sleep = dib80xx_tuner_sleep,
-    .clkouttobamse = 1,
-    .analog_output = 1,
-    .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
-    .wbd_vhf_offset = 100,
-    .wbd_cband_offset = 450,
-    .use_pwm_agc = 1,
-    .clkoutdrive = 1,
-    .get_adc_power = dib8090_get_adc_power,
-       .freq_offset_khz_uhf = 0,
-       .freq_offset_khz_vhf = -143,
+               .ls_cfg_pad_drv = 0,
+               .data_tx_drv = 0,
+               .low_if = NULL,
+               .in_soc = 1,
+       }
 };
 
-static int dib8096_set_param_override(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep)
+static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
 {
-    struct dvb_usb_adapter *adap = fe->dvb->priv;
-    struct dib0700_adapter_state *state = adap->priv;
-    u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
-    u16 offset;
-    int ret = 0;
-    enum frontend_tune_state tune_state = CT_SHUTDOWN;
-    u16 ltgain, rf_gain_limit;
-
-    ret = state->set_param_save(fe, fep);
-    if (ret < 0)
-       return ret;
-
-    switch (band) {
-    case BAND_VHF:
-           offset = 100;
-           break;
-    case BAND_UHF:
-           offset = 550;
-           break;
-    default:
-           offset = 0;
-           break;
-    }
-    offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
-    dib8000_set_wbd_ref(fe, offset);
-
-
-    if (band == BAND_CBAND) {
-       deb_info("tuning in CBAND - soft-AGC startup\n");
-       /* TODO specific wbd target for dib0090 - needed for startup ? */
-       dib0090_set_tune_state(fe, CT_AGC_START);
-       do {
-               ret = dib0090_gain_control(fe);
-               msleep(ret);
-               tune_state = dib0090_get_tune_state(fe);
-               if (tune_state == CT_AGC_STEP_0)
-                       dib8000_set_gpio(fe, 6, 0, 1);
-               else if (tune_state == CT_AGC_STEP_1) {
-                       dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
-                       if (rf_gain_limit == 0)
-                               dib8000_set_gpio(fe, 6, 0, 0);
-               }
-       } while (tune_state < CT_AGC_STOP);
-       dib0090_pwm_gain_reset(fe);
-       dib8000_pwm_agc_reset(fe);
-       dib8000_set_tune_state(fe, CT_DEMOD_START);
-    } else {
-       deb_info("not tuning in CBAND - standard AGC startup\n");
-       dib0090_pwm_gain_reset(fe);
-    }
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 
-    return 0;
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(20);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
+
+       return adap->fe == NULL ?  -ENODEV : 0;
 }
 
-static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
 {
-    struct dib0700_adapter_state *st = adap->priv;
-    struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL)
+               return -ENODEV;
 
-    if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
-       return -ENODEV;
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
 
-    st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-    adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
-    return 0;
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
 }
 
-static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
 {
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* The TFE7090 requires the dib0700 to not be in master mode */
+       st->disable_streaming_master_mode = 1;
+
        dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
-       msleep(10);
+       msleep(20);
        dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
        dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
        dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 
-       dib0700_ctrl_clock(adap->dev, 72, 1);
-
-       msleep(10);
+       msleep(20);
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
-       msleep(10);
+       msleep(20);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+       /* initialize IC 0 */
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config);
+       dib0700_set_i2c_speed(adap->dev, 340);
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+       dib7090_slave_reset(adap->fe);
+
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
+{
+       struct i2c_adapter *i2c;
+
+       if (adap->dev->adapter[0].fe == NULL) {
+               err("the master dib7090 has to be initialized first");
+               return -ENODEV; /* the master device has not been initialized */
+       }
+
+       i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
+       if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
+
+       adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
+       dib0700_set_i2c_speed(adap->dev, 200);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
+}
+
+static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
 }
 
 /* STK7070PD */
@@ -1856,6 +2796,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV282E) },
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
        { USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DIVERSITY) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090M) },
+/* 70 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM8096MD) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090MD) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM7090) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
+       { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -2465,7 +3411,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 2,
+               .num_device_descs = 3,
                .devices = {
                        {   "DiBcom STK7770P reference design",
                                { &dib0700_usb_id_table[59], NULL },
@@ -2477,6 +3423,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                        &dib0700_usb_id_table[60], NULL},
                                { NULL },
                        },
+                       {   "TechniSat AirStar TeleStick 2",
+                               { &dib0700_usb_id_table[74], NULL },
+                               { NULL },
+                       },
                },
 
                .rc.core = {
@@ -2609,6 +3559,205 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = dib90x0_pid_filter,
+                               .pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+                               .frontend_attach  = stk9090m_frontend_attach,
+                               .tuner_attach     = dib9090_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom STK9090M reference design",
+                               { &dib0700_usb_id_table[69], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk80xx_pid_filter,
+                               .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+                               .frontend_attach  = nim8096md_frontend_attach,
+                               .tuner_attach     = nim8096md_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM8096MD reference design",
+                               { &dib0700_usb_id_table[70], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = dib90x0_pid_filter,
+                               .pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+                               .frontend_attach  = nim9090md_frontend_attach,
+                               .tuner_attach     = nim9090md_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM9090MD reference design",
+                               { &dib0700_usb_id_table[71], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = nim7090_frontend_attach,
+                               .tuner_attach     = nim7090_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM7090 reference design",
+                               { &dib0700_usb_id_table[72], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = tfe7090pvr_frontend0_attach,
+                               .tuner_attach     = tfe7090pvr_tuner0_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = tfe7090pvr_frontend1_attach,
+                               .tuner_attach     = tfe7090pvr_tuner1_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom TFE7090PVR reference design",
+                               { &dib0700_usb_id_table[73], NULL },
+                               { NULL },
+                       },
+               },
+
                .rc.core = {
                        .rc_interval      = DEFAULT_RC_INTERVAL,
                        .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
index f2dbce7edb3b5885e47a5c395541a4dfdd881ee7..f6344cdd360f7acd99a2c3c93b022269d9acc6a8 100644 (file)
@@ -176,7 +176,7 @@ static struct rc_map_table rc_map_digitv_table[] = {
        { 0xaf59, KEY_AUX },
        { 0x5f5a, KEY_DVD },
        { 0x6f5a, KEY_POWER },
-       { 0x9f5a, KEY_MHP },     /* labelled 'Picture' */
+       { 0x9f5a, KEY_CAMERA },     /* labelled 'Picture' */
        { 0xaf5a, KEY_AUDIO },
        { 0x5f65, KEY_INFO },
        { 0x6f65, KEY_F13 },     /* 16:9 */
index 1a6310b619238030c64125eba61ec3578ed8fafe..3a8b7446b7b01c4f897183c9925b23e76438ee2a 100644 (file)
 #define USB_PID_DIBCOM_STK807XP                                0x1f90
 #define USB_PID_DIBCOM_STK807XPVR                      0x1f98
 #define USB_PID_DIBCOM_STK8096GP                        0x1fa0
+#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
 #define USB_PID_DIBCOM_STK7770P                                0x1e80
+#define USB_PID_DIBCOM_NIM7090                         0x1bb2
+#define USB_PID_DIBCOM_TFE7090PVR                      0x1bb4
+#define USB_PID_DIBCOM_NIM9090M                                0x2383
+#define USB_PID_DIBCOM_NIM9090MD                       0x2384
 #define USB_PID_DPOSH_M9206_COLD                       0x9206
 #define USB_PID_DPOSH_M9206_WARM                       0xa090
 #define USB_PID_E3C_EC168                              0x1689
 #define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
 #define USB_PID_TECHNISAT_USB2_HDCI_V1                 0x0001
 #define USB_PID_TECHNISAT_USB2_HDCI_V2                 0x0002
+#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2          0x0004
+#define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
 #endif
index 23005b3cf30bedaea413a1afba3627fe28d0d400..41bacff24960b7b7262d435ac575a147fac8c511 100644 (file)
@@ -8,60 +8,71 @@
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
 
+static unsigned int
+legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
+                               struct rc_map_table *keymap,
+                               unsigned int keymap_size)
+{
+       unsigned int index;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+       } else {
+               if (input_scancode_to_scalar(ke, &scancode))
+                       return keymap_size;
+
+               /* See if we can match the raw key code. */
+               for (index = 0; index < keymap_size; index++)
+                       if (keymap[index].scancode == scancode)
+                               break;
+
+               /* See if there is an unused hole in the map */
+               if (index >= keymap_size) {
+                       for (index = 0; index < keymap_size; index++) {
+                               if (keymap[index].keycode == KEY_RESERVED ||
+                                   keymap[index].keycode == KEY_UNKNOWN) {
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return index;
+}
+
 static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int *keycode)
+                                    struct input_keymap_entry *ke)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
-
        struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-       int i;
+       unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+       unsigned int index;
 
-       /* See if we can match the raw key code. */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].scancode == scancode) {
-                       *keycode = keymap[i].keycode;
-                       return 0;
-               }
+       index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+       if (index >= keymap_size)
+               return -EINVAL;
 
-       /*
-        * If is there extra space, returns KEY_RESERVED,
-        * otherwise, input core won't let legacy_dvb_usb_setkeycode
-        * to work
-        */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].keycode == KEY_RESERVED ||
-                   keymap[i].keycode == KEY_UNKNOWN) {
-                       *keycode = KEY_RESERVED;
-                       return 0;
-               }
+       ke->keycode = keymap[index].keycode;
+       if (ke->keycode == KEY_UNKNOWN)
+               ke->keycode = KEY_RESERVED;
+       ke->len = sizeof(keymap[index].scancode);
+       memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
+       ke->index = index;
 
-       return -EINVAL;
+       return 0;
 }
 
 static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int keycode)
+                                    const struct input_keymap_entry *ke,
+                                    unsigned int *old_keycode)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
-
        struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-       int i;
-
-       /* Search if it is replacing an existing keycode */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].scancode == scancode) {
-                       keymap[i].keycode = keycode;
-                       return 0;
-               }
-
-       /* Search if is there a clean entry. If so, use it */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].keycode == KEY_RESERVED ||
-                   keymap[i].keycode == KEY_UNKNOWN) {
-                       keymap[i].scancode = scancode;
-                       keymap[i].keycode = keycode;
-                       return 0;
-               }
+       unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+       unsigned int index;
 
+       index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
        /*
         * FIXME: Currently, it is not possible to increase the size of
         * scancode table. For it to happen, one possibility
@@ -69,8 +80,24 @@ static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
         * copying data, appending the new key on it, and freeing
         * the old one - or maybe just allocating some spare space
         */
+       if (index >= keymap_size)
+               return -EINVAL;
+
+       *old_keycode = keymap[index].keycode;
+       keymap->keycode = ke->keycode;
+       __set_bit(ke->keycode, dev->keybit);
+
+       if (*old_keycode != KEY_RESERVED) {
+               __clear_bit(*old_keycode, dev->keybit);
+               for (index = 0; index < keymap_size; index++) {
+                       if (keymap[index].keycode == *old_keycode) {
+                               __set_bit(*old_keycode, dev->keybit);
+                               break;
+                       }
+               }
+       }
 
-       return -EINVAL;
+       return 0;
 }
 
 /* Remote-control poll function - called every dib->rc_query_interval ms to see
@@ -246,7 +273,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
        dev->map_name = d->props.rc.core.rc_codes;
        dev->change_protocol = d->props.rc.core.change_protocol;
        dev->allowed_protos = d->props.rc.core.allowed_protos;
-       dev->driver_type = RC_DRIVER_SCANCODE;
+       dev->driver_type = d->props.rc.core.driver_type;
        usb_to_input_id(d->udev, &dev->input_id);
        dev->input_name = "IR-receiver inside an USB DVB receiver";
        dev->input_phys = d->rc_phys;
index 65fa9268e7f710801d75ca231da7dfcba6adbf46..76a80968482a602033cfead87ddd029301a832d2 100644 (file)
@@ -181,6 +181,7 @@ struct dvb_rc_legacy {
  * @rc_codes: name of rc codes table
  * @protocol: type of protocol(s) currently used by the driver
  * @allowed_protos: protocol(s) supported by the driver
+ * @driver_type: Used to point if a device supports raw mode
  * @change_protocol: callback to change protocol
  * @rc_query: called to query an event event.
  * @rc_interval: time in ms between two queries.
@@ -190,6 +191,7 @@ struct dvb_rc {
        char *rc_codes;
        u64 protocol;
        u64 allowed_protos;
+       enum rc_driver_type driver_type;
        int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
        char *module_name;
        int (*rc_query) (struct dvb_usb_device *d);
index 2c307ba0d28bc5dcef6c17644b0cc118d9c7dfa4..f5b9da18f61106bfa891aec4a69d5f839f052b65 100644 (file)
@@ -1,15 +1,16 @@
 /* DVB USB framework compliant Linux driver for the
-*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-*      TeVii S600, S630, S650,
-*      Prof 1100, 7500 Cards
-* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
-*
-*      This program is free software; you can redistribute it and/or modify it
-*      under the terms of the GNU General Public License as published by the
-*      Free Software Foundation, version 2.
-*
-* see Documentation/dvb/README.dvb-usb for more information
-*/
+ *     DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+ *     TeVii S600, S630, S650, S660, S480,
+ *     Prof 1100, 7500,
+ *     Geniatech SU3000 Cards
+ * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by)
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
 #include "dw2102.h"
 #include "si21xx.h"
 #include "stv0299.h"
 #define USB_PID_TEVII_S660 0xd660
 #endif
 
+#ifndef USB_PID_TEVII_S480_1
+#define USB_PID_TEVII_S480_1 0xd481
+#endif
+
+#ifndef USB_PID_TEVII_S480_2
+#define USB_PID_TEVII_S480_2 0xd482
+#endif
+
 #ifndef USB_PID_PROF_1100
 #define USB_PID_PROF_1100 0xb012
 #endif
@@ -67,7 +76,9 @@
 #define REG_21_SYMBOLRATE_BYTE2 0x21
 /* on my own*/
 #define DW2102_VOLTAGE_CTRL (0x1800)
+#define SU3000_STREAM_CTRL (0x1900)
 #define DW2102_RC_QUERY (0x1a00)
+#define DW2102_LED_CTRL (0x1b00)
 
 #define        err_str "did not find the firmware file. (%s) " \
                "Please see linux/Documentation/dvb/ for more details " \
@@ -78,6 +89,14 @@ struct rc_map_dvb_usb_table_table {
        int rc_keys_size;
 };
 
+struct su3000_state {
+       u8 initialized;
+};
+
+struct s6x0_state {
+       int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v);
+};
+
 /* debug */
 static int dvb_usb_dw2102_debug;
 module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
@@ -87,7 +106,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
 /* keymaps */
 static int ir_keymap;
 module_param_named(keymap, ir_keymap, int, 0644);
-MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ...");
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ..."
+                       " 256=none");
 
 /* demod probe */
 static int demod_probe = 1;
@@ -136,8 +156,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                /* read stv0299 register */
                value = msg[0].buf[0];/* register */
                for (i = 0; i < msg[1].len; i++) {
-                       value = value + i;
-                       ret = dw210x_op_rw(d->udev, 0xb5, value, 0,
+                       ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0,
                                        buf6, 2, DW210X_READ_MSG);
                        msg[1].buf[i] = buf6[0];
                }
@@ -483,10 +502,10 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        for (j = 0; j < num; j++) {
                switch (msg[j].addr) {
                case (DW2102_RC_QUERY): {
-                       u8 ibuf[4];
+                       u8 ibuf[5];
                        ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
-                                       ibuf, 4, DW210X_READ_MSG);
-                       memcpy(msg[j].buf, ibuf + 1, 2);
+                                       ibuf, 5, DW210X_READ_MSG);
+                       memcpy(msg[j].buf, ibuf + 3, 2);
                        break;
                }
                case (DW2102_VOLTAGE_CTRL): {
@@ -502,6 +521,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                        obuf, 2, DW210X_WRITE_MSG);
                        break;
                }
+               case (DW2102_LED_CTRL): {
+                       u8 obuf[2];
+
+                       obuf[0] = 5;
+                       obuf[1] = msg[j].buf[0];
+                       ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+                                       obuf, 2, DW210X_WRITE_MSG);
+                       break;
+               }
                /*case 0x55: cx24116
                case 0x6a: stv0903
                case 0x68: ds3000, stv0903
@@ -535,14 +563,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                        i += 16;
                                        len -= 16;
                                } while (len > 0);
-                       } else if ((udev->descriptor.idProduct == 0x7500)
-                                       && (j < (num - 1))) {
+                       } else if (j < (num - 1)) {
                                /* write register addr before read */
                                u8 obuf[msg[j].len + 2];
                                obuf[0] = msg[j + 1].len;
                                obuf[1] = (msg[j].addr << 1);
                                memcpy(obuf + 2, msg[j].buf, msg[j].len);
-                               ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
+                               ret = dw210x_op_rw(d->udev,
+                                               udev->descriptor.idProduct ==
+                                               0x7500 ? 0x92 : 0x90, 0, 0,
                                                obuf, msg[j].len + 2,
                                                DW210X_WRITE_MSG);
                                break;
@@ -552,8 +581,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                obuf[0] = msg[j].len + 1;
                                obuf[1] = (msg[j].addr << 1);
                                memcpy(obuf + 2, msg[j].buf, msg[j].len);
-                               ret = dw210x_op_rw(d->udev,
-                                               (num > 1 ? 0x90 : 0x80), 0, 0,
+                               ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
                                                obuf, msg[j].len + 2,
                                                DW210X_WRITE_MSG);
                                break;
@@ -561,14 +589,76 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        break;
                }
                }
-
-               msleep(3);
        }
 
        mutex_unlock(&d->i2c_mutex);
        return num;
 }
 
+static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                                               int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       u8 obuf[0x40], ibuf[0x40];
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 1:
+               switch (msg[0].addr) {
+               case SU3000_STREAM_CTRL:
+                       obuf[0] = msg[0].buf[0] + 0x36;
+                       obuf[1] = 3;
+                       obuf[2] = 0;
+                       if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0)
+                               err("i2c transfer failed.");
+                       break;
+               case DW2102_RC_QUERY:
+                       obuf[0] = 0x10;
+                       if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
+                               err("i2c transfer failed.");
+                       msg[0].buf[1] = ibuf[0];
+                       msg[0].buf[0] = ibuf[1];
+                       break;
+               default:
+                       /* always i2c write*/
+                       obuf[0] = 0x08;
+                       obuf[1] = msg[0].addr;
+                       obuf[2] = msg[0].len;
+
+                       memcpy(&obuf[3], msg[0].buf, msg[0].len);
+
+                       if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3,
+                                               ibuf, 1, 0) < 0)
+                               err("i2c transfer failed.");
+
+               }
+               break;
+       case 2:
+               /* always i2c read */
+               obuf[0] = 0x09;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[1].len;
+               obuf[3] = msg[0].addr;
+               memcpy(&obuf[4], msg[0].buf, msg[0].len);
+
+               if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4,
+                                       ibuf, msg[1].len + 1, 0) < 0)
+                       err("i2c transfer failed.");
+
+               memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+               break;
+       default:
+               warn("more than 2 i2c messages at a time is not handled yet.");
+               break;
+       }
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -604,6 +694,11 @@ static struct i2c_algorithm s6x0_i2c_algo = {
        .functionality = dw210x_i2c_func,
 };
 
+static struct i2c_algorithm su3000_i2c_algo = {
+       .master_xfer = su3000_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
        int i;
@@ -668,6 +763,82 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
        return 0;
 };
 
+static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       static u8 command_start[] = {0x00};
+       static u8 command_stop[] = {0x01};
+       struct i2c_msg msg = {
+               .addr = SU3000_STREAM_CTRL,
+               .flags = 0,
+               .buf = onoff ? command_start : command_stop,
+               .len = 1
+       };
+
+       i2c_transfer(&adap->dev->i2c_adap, &msg, 1);
+
+       return 0;
+}
+
+static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
+{
+       struct su3000_state *state = (struct su3000_state *)d->priv;
+       u8 obuf[] = {0xde, 0};
+
+       info("%s: %d, initialized %d\n", __func__, i, state->initialized);
+
+       if (i && !state->initialized) {
+               state->initialized = 1;
+               /* reset board */
+               dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
+       }
+
+       return 0;
+}
+
+static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       int i;
+       u8 obuf[] = { 0x1f, 0xf0 };
+       u8 ibuf[] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x51,
+                       .flags = 0,
+                       .buf = obuf,
+                       .len = 2,
+               }, {
+                       .addr = 0x51,
+                       .flags = I2C_M_RD,
+                       .buf = ibuf,
+                       .len = 1,
+
+               }
+       };
+
+       for (i = 0; i < 6; i++) {
+               obuf[1] = 0xf0 + i;
+               if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
+                       break;
+               else
+                       mac[i] = ibuf[0];
+
+               debug_dump(mac, 6, printk);
+       }
+
+       return 0;
+}
+
+static int su3000_identify_state(struct usb_device *udev,
+                                struct dvb_usb_device_properties *props,
+                                struct dvb_usb_device_description **desc,
+                                int *cold)
+{
+       info("%s\n", __func__);
+
+       *cold = 0;
+       return 0;
+}
+
 static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        static u8 command_13v[] = {0x00, 0x01};
@@ -692,6 +863,37 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
        return 0;
 }
 
+static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct dvb_usb_adapter *d =
+               (struct dvb_usb_adapter *)(fe->dvb->priv);
+       struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+
+       dw210x_set_voltage(fe, voltage);
+       if (st->old_set_voltage)
+               st->old_set_voltage(fe, voltage);
+
+       return 0;
+}
+
+static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
+{
+       static u8 led_off[] = { 0 };
+       static u8 led_on[] = { 1 };
+       struct i2c_msg msg = {
+               .addr = DW2102_LED_CTRL,
+               .flags = 0,
+               .buf = led_off,
+               .len = 1
+       };
+       struct dvb_usb_adapter *udev_adap =
+               (struct dvb_usb_adapter *)(fe->dvb->priv);
+
+       if (offon)
+               msg.buf = led_on;
+       i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+}
+
 static struct stv0299_config sharp_z0194a_config = {
        .demod_address = 0x68,
        .inittab = sharp_z0194a_inittab,
@@ -771,6 +973,12 @@ static struct stv0900_config prof_7500_stv0900_config = {
        .tun1_adc = 0,/* 2 Vpp */
        .path1_mode = 3,
        .tun1_type = 3,
+       .set_lock_led = dw210x_led_ctrl,
+};
+
+static struct ds3000_config su3000_ds3000_config = {
+       .demod_address = 0x68,
+       .ci_mode = 1,
 };
 
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
@@ -885,7 +1093,7 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
-static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
+static int zl100313_frontend_attach(struct dvb_usb_adapter *d)
 {
        d->fe = dvb_attach(mt312_attach, &zl313_config,
                        &d->dev->i2c_adap);
@@ -898,41 +1106,108 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
                }
        }
 
+       return -EIO;
+}
+
+static int stv0288_frontend_attach(struct dvb_usb_adapter *d)
+{
+       u8 obuf[] = {7, 1};
+
        d->fe = dvb_attach(stv0288_attach, &earda_config,
                        &d->dev->i2c_adap);
-       if (d->fe != NULL) {
-               if (dvb_attach(stb6000_attach, d->fe, 0x61,
-                               &d->dev->i2c_adap)) {
-                       d->fe->ops.set_voltage = dw210x_set_voltage;
-                       info("Attached stv0288+stb6000!\n");
-                       return 0;
-               }
-       }
+
+       if (d->fe == NULL)
+               return -EIO;
+
+       if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap))
+               return -EIO;
+
+       d->fe->ops.set_voltage = dw210x_set_voltage;
+
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
+       info("Attached stv0288+stb6000!\n");
+
+       return 0;
+
+}
+
+static int ds3000_frontend_attach(struct dvb_usb_adapter *d)
+{
+       struct s6x0_state *st = (struct s6x0_state *)d->dev->priv;
+       u8 obuf[] = {7, 1};
 
        d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
                        &d->dev->i2c_adap);
-       if (d->fe != NULL) {
-               d->fe->ops.set_voltage = dw210x_set_voltage;
-               info("Attached ds3000+ds2020!\n");
-               return 0;
-       }
 
-       return -EIO;
+       if (d->fe == NULL)
+               return -EIO;
+
+       st->old_set_voltage = d->fe->ops.set_voltage;
+       d->fe->ops.set_voltage = s660_set_voltage;
+
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
+       info("Attached ds3000+ds2020!\n");
+
+       return 0;
 }
 
 static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
 {
+       u8 obuf[] = {7, 1};
+
        d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
                                        &d->dev->i2c_adap, 0);
        if (d->fe == NULL)
                return -EIO;
+
        d->fe->ops.set_voltage = dw210x_set_voltage;
 
+       dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
+
        info("Attached STV0900+STB6100A!\n");
 
        return 0;
 }
 
+static int su3000_frontend_attach(struct dvb_usb_adapter *d)
+{
+       u8 obuf[3] = { 0xe, 0x80, 0 };
+       u8 ibuf[] = { 0 };
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       obuf[0] = 0xe;
+       obuf[1] = 0x83;
+       obuf[2] = 0;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       obuf[0] = 0xe;
+       obuf[1] = 0x83;
+       obuf[2] = 1;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       obuf[0] = 0x51;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+               err("command 0x51 transfer failed.");
+
+       d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
+                                       &d->dev->i2c_adap);
+       if (d->fe == NULL)
+               return -EIO;
+
+       info("Attached DS3000!\n");
+
+       return 0;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -949,8 +1224,8 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
 }
 
 static struct rc_map_table rc_map_dw210x_table[] = {
-       { 0xf80a, KEY_Q },              /*power*/
-       { 0xf80c, KEY_M },              /*mute*/
+       { 0xf80a, KEY_POWER2 },         /*power*/
+       { 0xf80c, KEY_MUTE },           /*mute*/
        { 0xf811, KEY_1 },
        { 0xf812, KEY_2 },
        { 0xf813, KEY_3 },
@@ -961,25 +1236,25 @@ static struct rc_map_table rc_map_dw210x_table[] = {
        { 0xf818, KEY_8 },
        { 0xf819, KEY_9 },
        { 0xf810, KEY_0 },
-       { 0xf81c, KEY_PAGEUP }, /*ch+*/
-       { 0xf80f, KEY_PAGEDOWN },       /*ch-*/
-       { 0xf81a, KEY_O },              /*vol+*/
-       { 0xf80e, KEY_Z },              /*vol-*/
-       { 0xf804, KEY_R },              /*rec*/
-       { 0xf809, KEY_D },              /*fav*/
-       { 0xf808, KEY_BACKSPACE },      /*rewind*/
-       { 0xf807, KEY_A },              /*fast*/
-       { 0xf80b, KEY_P },              /*pause*/
-       { 0xf802, KEY_ESC },    /*cancel*/
-       { 0xf803, KEY_G },              /*tab*/
+       { 0xf81c, KEY_CHANNELUP },      /*ch+*/
+       { 0xf80f, KEY_CHANNELDOWN },    /*ch-*/
+       { 0xf81a, KEY_VOLUMEUP },       /*vol+*/
+       { 0xf80e, KEY_VOLUMEDOWN },     /*vol-*/
+       { 0xf804, KEY_RECORD },         /*rec*/
+       { 0xf809, KEY_FAVORITES },      /*fav*/
+       { 0xf808, KEY_REWIND },         /*rewind*/
+       { 0xf807, KEY_FASTFORWARD },    /*fast*/
+       { 0xf80b, KEY_PAUSE },          /*pause*/
+       { 0xf802, KEY_ESC },            /*cancel*/
+       { 0xf803, KEY_TAB },            /*tab*/
        { 0xf800, KEY_UP },             /*up*/
-       { 0xf81f, KEY_ENTER },  /*ok*/
-       { 0xf801, KEY_DOWN },   /*down*/
-       { 0xf805, KEY_C },              /*cap*/
-       { 0xf806, KEY_S },              /*stop*/
-       { 0xf840, KEY_F },              /*full*/
-       { 0xf81e, KEY_W },              /*tvmode*/
-       { 0xf81b, KEY_B },              /*recall*/
+       { 0xf81f, KEY_OK },             /*ok*/
+       { 0xf801, KEY_DOWN },           /*down*/
+       { 0xf805, KEY_CAMERA },         /*cap*/
+       { 0xf806, KEY_STOP },           /*stop*/
+       { 0xf840, KEY_ZOOM },           /*full*/
+       { 0xf81e, KEY_TV },             /*tvmode*/
+       { 0xf81b, KEY_LAST },           /*recall*/
 };
 
 static struct rc_map_table rc_map_tevii_table[] = {
@@ -1067,10 +1342,49 @@ static struct rc_map_table rc_map_tbs_table[] = {
        { 0xf89b, KEY_MODE }
 };
 
+static struct rc_map_table rc_map_su3000_table[] = {
+       { 0x25, KEY_POWER },    /* right-bottom Red */
+       { 0x0a, KEY_MUTE },     /* -/-- */
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x00, KEY_0 },
+       { 0x20, KEY_UP },       /* CH+ */
+       { 0x21, KEY_DOWN },     /* CH+ */
+       { 0x12, KEY_VOLUMEUP }, /* Brightness Up */
+       { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
+       { 0x1f, KEY_RECORD },
+       { 0x17, KEY_PLAY },
+       { 0x16, KEY_PAUSE },
+       { 0x0b, KEY_STOP },
+       { 0x27, KEY_FASTFORWARD },/* >> */
+       { 0x26, KEY_REWIND },   /* << */
+       { 0x0d, KEY_OK },       /* Mute */
+       { 0x11, KEY_LEFT },     /* VOL- */
+       { 0x10, KEY_RIGHT },    /* VOL+ */
+       { 0x29, KEY_BACK },     /* button under 9 */
+       { 0x2c, KEY_MENU },     /* TTX */
+       { 0x2b, KEY_EPG },      /* EPG */
+       { 0x1e, KEY_RED },      /* OSD */
+       { 0x0e, KEY_GREEN },    /* Window */
+       { 0x2d, KEY_YELLOW },   /* button under << */
+       { 0x0f, KEY_BLUE },     /* bottom yellow button */
+       { 0x14, KEY_AUDIO },    /* Snapshot */
+       { 0x38, KEY_TV },       /* TV/Radio */
+       { 0x0c, KEY_ESC }       /* upper Red buttton */
+};
+
 static struct rc_map_dvb_usb_table_table keys_tables[] = {
        { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
        { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
        { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
+       { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) },
 };
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -1089,7 +1403,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
                keymap = keys_tables[ir_keymap - 1].rc_keys ;
                keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
-       }
+       } else if (ir_keymap > ARRAY_SIZE(keys_tables))
+               return 0; /* none */
 
        *state = REMOTE_NO_KEY_PRESSED;
        if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
@@ -1125,6 +1440,11 @@ static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(0x3011, USB_PID_PROF_1100)},
        {USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
        {USB_DEVICE(0x3034, 0x7500)},
+       {USB_DEVICE(0x1f4d, 0x3000)},
+       {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)},
+       {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)},
+       {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)},
+       {USB_DEVICE(0x1f4d, 0x3100)},
        { }
 };
 
@@ -1184,11 +1504,6 @@ static int dw2102_load_firmware(struct usb_device *dev,
                }
                /* init registers */
                switch (dev->descriptor.idProduct) {
-               case USB_PID_PROF_1100:
-                       s6x0_properties.rc.legacy.rc_map_table = rc_map_tbs_table;
-                       s6x0_properties.rc.legacy.rc_map_size =
-                                       ARRAY_SIZE(rc_map_tbs_table);
-                       break;
                case USB_PID_TEVII_S650:
                        dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
                        dw2104_properties.rc.legacy.rc_map_size =
@@ -1271,8 +1586,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .adapter = {
                {
                        .frontend_attach = dw2102_frontend_attach,
-                       .streaming_ctrl = NULL,
-                       .tuner_attach = NULL,
                        .stream = {
                                .type = USB_BULK,
                                .count = 8,
@@ -1324,8 +1637,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .adapter = {
                {
                        .frontend_attach = dw2104_frontend_attach,
-                       .streaming_ctrl = NULL,
-                       /*.tuner_attach = dw2104_tuner_attach,*/
                        .stream = {
                                .type = USB_BULK,
                                .count = 8,
@@ -1373,7 +1684,6 @@ static struct dvb_usb_device_properties dw3101_properties = {
        .adapter = {
                {
                        .frontend_attach = dw3101_frontend_attach,
-                       .streaming_ctrl = NULL,
                        .tuner_attach = dw3101_tuner_attach,
                        .stream = {
                                .type = USB_BULK,
@@ -1399,6 +1709,7 @@ static struct dvb_usb_device_properties dw3101_properties = {
 static struct dvb_usb_device_properties s6x0_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
+       .size_of_priv = sizeof(struct s6x0_state),
        .firmware = "dvb-usb-s630.fw",
        .no_reconnect = 1,
 
@@ -1416,9 +1727,7 @@ static struct dvb_usb_device_properties s6x0_properties = {
        .read_mac_address = s6x0_read_mac_address,
        .adapter = {
                {
-                       .frontend_attach = s6x0_frontend_attach,
-                       .streaming_ctrl = NULL,
-                       .tuner_attach = NULL,
+                       .frontend_attach = zl100313_frontend_attach,
                        .stream = {
                                .type = USB_BULK,
                                .count = 8,
@@ -1431,23 +1740,41 @@ static struct dvb_usb_device_properties s6x0_properties = {
                        },
                }
        },
-       .num_device_descs = 3,
+       .num_device_descs = 1,
        .devices = {
                {"TeVii S630 USB",
                        {&dw2102_table[6], NULL},
                        {NULL},
                },
-               {"Prof 1100 USB ",
-                       {&dw2102_table[7], NULL},
-                       {NULL},
-               },
-               {"TeVii S660 USB",
-                       {&dw2102_table[8], NULL},
-                       {NULL},
-               },
        }
 };
 
+struct dvb_usb_device_properties *p1100;
+static struct dvb_usb_device_description d1100 = {
+       "Prof 1100 USB ",
+       {&dw2102_table[7], NULL},
+       {NULL},
+};
+
+struct dvb_usb_device_properties *s660;
+static struct dvb_usb_device_description d660 = {
+       "TeVii S660 USB",
+       {&dw2102_table[8], NULL},
+       {NULL},
+};
+
+static struct dvb_usb_device_description d480_1 = {
+       "TeVii S480.1 USB",
+       {&dw2102_table[12], NULL},
+       {NULL},
+};
+
+static struct dvb_usb_device_description d480_2 = {
+       "TeVii S480.2 USB",
+       {&dw2102_table[13], NULL},
+       {NULL},
+};
+
 struct dvb_usb_device_properties *p7500;
 static struct dvb_usb_device_description d7500 = {
        "Prof 7500 USB DVB-S2",
@@ -1455,17 +1782,97 @@ static struct dvb_usb_device_description d7500 = {
        {NULL},
 };
 
+static struct dvb_usb_device_properties su3000_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .size_of_priv = sizeof(struct su3000_state),
+       .power_ctrl = su3000_power_ctrl,
+       .num_adapters = 1,
+       .identify_state = su3000_identify_state,
+       .i2c_algo = &su3000_i2c_algo,
+
+       .rc.legacy = {
+               .rc_map_table = rc_map_su3000_table,
+               .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+               .rc_interval = 150,
+               .rc_query = dw2102_rc_query,
+       },
+
+       .read_mac_address = su3000_read_mac_address,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .adapter = {
+               {
+                       .streaming_ctrl   = su3000_streaming_ctrl,
+                       .frontend_attach  = su3000_frontend_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       }
+               }
+       },
+       .num_device_descs = 3,
+       .devices = {
+               { "SU3000HD DVB-S USB2.0",
+                       { &dw2102_table[10], NULL },
+                       { NULL },
+               },
+               { "Terratec Cinergy S2 USB HD",
+                       { &dw2102_table[11], NULL },
+                       { NULL },
+               },
+               { "X3M TV SPC1400HD PCI",
+                       { &dw2102_table[14], NULL },
+                       { NULL },
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
+       p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       if (!p1100)
+               return -ENOMEM;
+       /* copy default structure */
+       memcpy(p1100, &s6x0_properties,
+                       sizeof(struct dvb_usb_device_properties));
+       /* fill only different fields */
+       p1100->firmware = "dvb-usb-p1100.fw";
+       p1100->devices[0] = d1100;
+       p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
+       p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+       p1100->adapter->frontend_attach = stv0288_frontend_attach;
+
+       s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+       if (!s660) {
+               kfree(p1100);
+               return -ENOMEM;
+       }
+       memcpy(s660, &s6x0_properties,
+                       sizeof(struct dvb_usb_device_properties));
+       s660->firmware = "dvb-usb-s660.fw";
+       s660->num_device_descs = 3;
+       s660->devices[0] = d660;
+       s660->devices[1] = d480_1;
+       s660->devices[2] = d480_2;
+       s660->adapter->frontend_attach = ds3000_frontend_attach;
 
        p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
-       if (!p7500)
+       if (!p7500) {
+               kfree(p1100);
+               kfree(s660);
                return -ENOMEM;
-       /* copy default structure */
+       }
        memcpy(p7500, &s6x0_properties,
                        sizeof(struct dvb_usb_device_properties));
-       /* fill only different fields */
        p7500->firmware = "dvb-usb-p7500.fw";
        p7500->devices[0] = d7500;
        p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
@@ -1480,8 +1887,14 @@ static int dw2102_probe(struct usb_interface *intf,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &s6x0_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, p1100,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, s660,
+                       THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, p7500,
-                       THIS_MODULE, NULL, adapter_nr))
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &su3000_properties,
+                                    THIS_MODULE, NULL, adapter_nr))
                return 0;
 
        return -ENODEV;
@@ -1514,7 +1927,8 @@ module_exit(dw2102_module_exit);
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
                                " DVB-C 3101 USB2.0,"
-                               " TeVii S600, S630, S650, S660 USB2.0,"
-                               " Prof 1100, 7500 USB2.0 devices");
+                               " TeVii S600, S630, S650, S660, S480,"
+                               " Prof 1100, 7500 USB2.0,"
+                               " Geniatech SU3000 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index 46ccd01a76967c9c2b192d8cec9dfa6e0dc1f666..cd26e7c1536a674d235430c80d8fe37a8b5bbd46 100644 (file)
@@ -2,7 +2,9 @@
  *
  * DM04/QQBOX DVB-S USB BOX    LME2510C + SHARP:BS2F7HZ7395
  *                             LME2510C + LG TDQY-P001F
+ *                             LME2510C + BS2F7HZ0194
  *                             LME2510 + LG TDQY-P001F
+ *                             LME2510 + BS2F7HZ0194
  *
  * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
  * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
  *
  * MVB0001F (LME2510C+LGTDQT-P001F)
  *
+ * MV0194 (LME2510+SHARP:BS2F7HZ0194)
+ * SHARP:BS2F7HZ0194 = (STV0299+IX2410)
+ *
+ * MVB0194 (LME2510C+SHARP0194)
+ *
  * For firmware see Documentation/dvb/lmedm04.txt
  *
  * I2C addresses:
  * 0xd0 - STV0288      - Demodulator
  * 0xc0 - Sharp IX2505V        - Tuner
- * --or--
+ * --
  * 0x1c - TDA10086   - Demodulator
  * 0xc0 - TDA8263    - Tuner
- *
- * ***Please Note***
- *             There are other variants of the DM04
- *             ***NOT SUPPORTED***
- *             MV0194 (LME2510+SHARP0194)
- *             MVB0194 (LME2510C+SHARP0194)
+ * --
+ * 0xd0 - STV0299      - Demodulator
+ * 0xc0 - IX2410       - Tuner
  *
  *
  * VID = 3344  PID LME2510=1122 LME2510C=1120
@@ -55,6 +59,9 @@
  *
  * QQbox suffers from noise on LNB voltage.
  *
+ *     LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
+ * with other tuners. After a cold reset streaming will not start.
+ *
  *     PID functions have been removed from this driver version due to
  * problems with different firmware and application versions.
  */
@@ -69,6 +76,9 @@
 #include "tda10086.h"
 #include "stv0288.h"
 #include "ix2505v.h"
+#include "stv0299.h"
+#include "dvb-pll.h"
+#include "z0194a.h"
 
 
 
@@ -96,8 +106,11 @@ MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define TUNER_DEFAULT  0x0
 #define TUNER_LG       0x1
 #define TUNER_S7395    0x2
+#define TUNER_S0194    0x3
 
 struct lme2510_state {
        u8 id;
@@ -191,7 +204,7 @@ static int lme2510_stream_restart(struct dvb_usb_device *d)
                        rbuff, sizeof(rbuff));
        return ret;
 }
-static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
+static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
 {
        struct dvb_usb_device *d = adap->dev;
 
@@ -237,7 +250,8 @@ static void lme2510_int_response(struct urb *lme_urb)
                case 0xaa:
                        debug_data_snipet(1, "INT Remote data snipet in", ibuf);
                        lme2510_remote_keypress(adap,
-                               (u16)(ibuf[4]<<8)+ibuf[5]);
+                               (u32)(ibuf[2] << 24) + (ibuf[3] << 16) +
+                               (ibuf[4] << 8) + ibuf[5]);
                        break;
                case 0xbb:
                        switch (st->tuner_config) {
@@ -249,6 +263,7 @@ static void lme2510_int_response(struct urb *lme_urb)
                                st->time_key = ibuf[7];
                                break;
                        case TUNER_S7395:
+                       case TUNER_S0194:
                                /* Tweak for earlier firmware*/
                                if (ibuf[1] == 0x03) {
                                        if (ibuf[2] > 1)
@@ -364,6 +379,18 @@ static int lme2510_msg(struct dvb_usb_device *d,
                                        msleep(5);
                        }
                        break;
+               case TUNER_S0194:
+                       if (wbuf[2] == 0xd0) {
+                               if (wbuf[3] == 0x1b) {
+                                       st->signal_lock = rbuf[1];
+                                       if ((st->stream_on & 1) &&
+                                               (st->signal_lock & 0x8)) {
+                                               lme2510_stream_restart(d);
+                                               st->i2c_talk_onoff = 0;
+                                       }
+                               }
+                       }
+                       break;
                default:
                        break;
                }
@@ -423,6 +450,34 @@ static int lme2510_msg(struct dvb_usb_device *d,
                                break;
                        }
                        break;
+               case TUNER_S0194:
+                       switch (wbuf[3]) {
+                       case 0x18:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = (st->signal_level & 0x80)
+                                               ? 0 : (st->signal_level * 2);
+                               break;
+                       case 0x24:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_sn;
+                               break;
+                       case 0x1b:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = st->signal_lock;
+                               break;
+                       case 0x19:
+                       case 0x25:
+                       case 0x1e:
+                       case 0x1d:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = 0x00;
+                               break;
+                       default:
+                               lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+                               st->i2c_talk_onoff = 1;
+                               break;
+                       }
+                       break;
                default:
                        break;
                }
@@ -517,17 +572,14 @@ static int lme2510_identify_state(struct usb_device *udev,
                struct dvb_usb_device_description **desc,
                int *cold)
 {
-       if (lme2510_return_status(udev) == 0x44)
-               *cold = 1;
-       else
-               *cold = 0;
+       *cold = 0;
        return 0;
 }
 
 static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct lme2510_state *st = adap->dev->priv;
-       static u8 clear_reg_3[] =  LME_CLEAR_PID;
+       static u8 clear_reg_3[] = LME_CLEAR_PID;
        static u8 rbuf[1];
        int ret = 0, rlen = sizeof(rbuf);
 
@@ -658,9 +710,6 @@ static int lme2510_download_firmware(struct usb_device *dev,
        return (ret < 0) ? -ENODEV : 0;
 }
 
-/* Default firmware for LME2510C */
-char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
-
 static void lme_coldreset(struct usb_device *dev)
 {
        int ret = 0, len_in;
@@ -678,49 +727,83 @@ static void lme_coldreset(struct usb_device *dev)
 static int lme_firmware_switch(struct usb_device *udev, int cold)
 {
        const struct firmware *fw = NULL;
-       char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
-       char lme2510c_lg[] = "dvb-usb-lme2510c-lg.fw";
-       char *firm_msg[] = {"Loading", "Switching to"};
-       int ret;
+       const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
+       const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
+       const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
+       const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
+       const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
+       const char *fw_lme;
+       int ret, cold_fw;
 
        cold = (cold > 0) ? (cold & 1) : 0;
 
-       if (udev->descriptor.idProduct == 0x1122)
-               return 0;
+       cold_fw = !cold;
 
-       switch (dvb_usb_lme2510_firmware) {
-       case 0:
-       default:
-               memcpy(&lme_firmware, lme2510c_s7395, sizeof(lme2510c_s7395));
-               ret = request_firmware(&fw, lme_firmware, &udev->dev);
-               if (ret == 0) {
-                       info("FRM %s S7395 Firmware", firm_msg[cold]);
+       if (udev->descriptor.idProduct == 0x1122) {
+               switch (dvb_usb_lme2510_firmware) {
+               default:
+                       dvb_usb_lme2510_firmware = TUNER_S0194;
+               case TUNER_S0194:
+                       fw_lme = fw_s0194;
+                       ret = request_firmware(&fw, fw_lme, &udev->dev);
+                       if (ret == 0) {
+                               cold = 0;/*lme2510-s0194 cannot cold reset*/
+                               break;
+                       }
+                       dvb_usb_lme2510_firmware = TUNER_LG;
+               case TUNER_LG:
+                       fw_lme = fw_lg;
+                       ret = request_firmware(&fw, fw_lme, &udev->dev);
+                       if (ret == 0)
+                               break;
+                       info("FRM No Firmware Found - please install");
+                       dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+                       cold = 0;
+                       cold_fw = 0;
                        break;
                }
-               if (cold == 0)
-                       dvb_usb_lme2510_firmware = 1;
-               else
+       } else {
+               switch (dvb_usb_lme2510_firmware) {
+               default:
+                       dvb_usb_lme2510_firmware = TUNER_S7395;
+               case TUNER_S7395:
+                       fw_lme = fw_c_s7395;
+                       ret = request_firmware(&fw, fw_lme, &udev->dev);
+                       if (ret == 0)
+                               break;
+                       dvb_usb_lme2510_firmware = TUNER_LG;
+               case TUNER_LG:
+                       fw_lme = fw_c_lg;
+                       ret = request_firmware(&fw, fw_lme, &udev->dev);
+                       if (ret == 0)
+                               break;
+                       dvb_usb_lme2510_firmware = TUNER_S0194;
+               case TUNER_S0194:
+                       fw_lme = fw_c_s0194;
+                       ret = request_firmware(&fw, fw_lme, &udev->dev);
+                       if (ret == 0)
+                               break;
+                       info("FRM No Firmware Found - please install");
+                       dvb_usb_lme2510_firmware = TUNER_DEFAULT;
                        cold = 0;
-       case 1:
-               memcpy(&lme_firmware, lme2510c_lg, sizeof(lme2510c_lg));
-               ret = request_firmware(&fw, lme_firmware, &udev->dev);
-               if (ret == 0) {
-                       info("FRM %s LG Firmware", firm_msg[cold]);
+                       cold_fw = 0;
                        break;
                }
-               info("FRM No Firmware Found - please install");
-               dvb_usb_lme2510_firmware = 0;
-               cold = 0;
-               break;
        }
 
-       release_firmware(fw);
+       if (cold_fw) {
+               info("FRM Loading %s file", fw_lme);
+               ret = lme2510_download_firmware(udev, fw);
+       }
 
        if (cold) {
+               info("FRM Changing to %s firmware", fw_lme);
                lme_coldreset(udev);
                return -ENODEV;
        }
 
+       release_firmware(fw);
+
        return ret;
 }
 
@@ -758,6 +841,18 @@ static struct ix2505v_config lme_tuner = {
        .tuner_chargepump = 0x3,
 };
 
+static struct stv0299_config sharp_z0194_config = {
+       .demod_address = 0xd0,
+       .inittab = sharp_z0194a_inittab,
+       .mclk = 88000000UL,
+       .invert = 0,
+       .skip_reinit = 0,
+       .lock_output = STV0299_LOCKOUTPUT_1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = sharp_z0194a_set_symbol_rate,
+};
+
 static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
                                        fe_sec_voltage_t voltage)
 {
@@ -793,7 +888,8 @@ static int lme_name(struct dvb_usb_adapter *adap)
 {
        struct lme2510_state *st = adap->dev->priv;
        const char *desc = adap->dev->desc->name;
-       char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395"};
+       char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
+                               " SHARP:BS2F7HZ0194"};
        char *name = adap->fe->ops.info.name;
 
        strlcpy(name, desc, 128);
@@ -820,26 +916,40 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
                st->i2c_tuner_gate_r = 4;
                st->i2c_tuner_addr = 0xc0;
                st->tuner_config = TUNER_LG;
-               if (dvb_usb_lme2510_firmware != 1) {
-                       dvb_usb_lme2510_firmware = 1;
+               if (dvb_usb_lme2510_firmware != TUNER_LG) {
+                       dvb_usb_lme2510_firmware = TUNER_LG;
                        ret = lme_firmware_switch(adap->dev->udev, 1);
-               } else /*stops LG/Sharp multi tuner problems*/
-                       dvb_usb_lme2510_firmware = 0;
+               }
+               goto end;
+       }
+
+       st->i2c_gate = 4;
+       adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
+                       &adap->dev->i2c_adap);
+       if (adap->fe) {
+               info("FE Found Stv0299");
+               st->i2c_tuner_gate_w = 4;
+               st->i2c_tuner_gate_r = 5;
+               st->i2c_tuner_addr = 0xc0;
+               st->tuner_config = TUNER_S0194;
+               if (dvb_usb_lme2510_firmware != TUNER_S0194) {
+                       dvb_usb_lme2510_firmware = TUNER_S0194;
+                       ret = lme_firmware_switch(adap->dev->udev, 1);
+               }
                goto end;
        }
 
        st->i2c_gate = 5;
        adap->fe = dvb_attach(stv0288_attach, &lme_config,
                        &adap->dev->i2c_adap);
-
        if (adap->fe) {
                info("FE Found Stv0288");
                st->i2c_tuner_gate_w = 4;
                st->i2c_tuner_gate_r = 5;
                st->i2c_tuner_addr = 0xc0;
                st->tuner_config = TUNER_S7395;
-               if (dvb_usb_lme2510_firmware != 0) {
-                       dvb_usb_lme2510_firmware = 0;
+               if (dvb_usb_lme2510_firmware != TUNER_S7395) {
+                       dvb_usb_lme2510_firmware = TUNER_S7395;
                        ret = lme_firmware_switch(adap->dev->udev, 1);
                }
        } else {
@@ -847,6 +957,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
                return -ENODEV;
        }
 
+
 end:   if (ret) {
                kfree(adap->fe);
                adap->fe = NULL;
@@ -855,14 +966,13 @@ end:      if (ret) {
 
        adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
        ret = lme_name(adap);
-
        return ret;
 }
 
 static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 {
        struct lme2510_state *st = adap->dev->priv;
-       char *tun_msg[] = {"", "TDA8263", "IX2505V"};
+       char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"};
        int ret = 0;
 
        switch (st->tuner_config) {
@@ -876,6 +986,11 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
                        &adap->dev->i2c_adap))
                        ret = st->tuner_config;
                break;
+       case TUNER_S0194:
+               if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0,
+                       &adap->dev->i2c_adap, DVB_PLL_OPERA1))
+                       ret = st->tuner_config;
+               break;
        default:
                break;
        }
@@ -936,7 +1051,10 @@ static int lme2510_probe(struct usb_interface *intf,
                return -ENODEV;
        }
 
-       lme_firmware_switch(udev, 0);
+       if (lme2510_return_status(udev) == 0x44) {
+               lme_firmware_switch(udev, 0);
+               return -ENODEV;
+       }
 
        if (0 == dvb_usb_device_init(intf, &lme2510_properties,
                                     THIS_MODULE, NULL, adapter_nr)) {
@@ -964,10 +1082,6 @@ MODULE_DEVICE_TABLE(usb, lme2510_table);
 
 static struct dvb_usb_device_properties lme2510_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .usb_ctrl = DEVICE_SPECIFIC,
-       .download_firmware = lme2510_download_firmware,
-       .firmware = "dvb-usb-lme2510-lg.fw",
-
        .size_of_priv = sizeof(struct lme2510_state),
        .num_adapters = 1,
        .adapter = {
@@ -1004,9 +1118,6 @@ static struct dvb_usb_device_properties lme2510_properties = {
 
 static struct dvb_usb_device_properties lme2510c_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .usb_ctrl = DEVICE_SPECIFIC,
-       .download_firmware = lme2510_download_firmware,
-       .firmware = (const char *)&lme_firmware,
        .size_of_priv = sizeof(struct lme2510_state),
        .num_adapters = 1,
        .adapter = {
@@ -1109,5 +1220,5 @@ module_exit(lme2510_module_exit);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.75");
+MODULE_VERSION("1.80");
 MODULE_LICENSE("GPL");
index 1f1b7d6980a5ba33ddeb1b684a2a29e806aad093..7e569f4dd80b89ce5def93e6a7228cd26bdd50d9 100644 (file)
@@ -342,23 +342,22 @@ static struct rc_map_table rc_map_opera1_table[] = {
        {0x49b6, KEY_8},
        {0x05fa, KEY_9},
        {0x45ba, KEY_0},
-       {0x09f6, KEY_UP},       /*chanup */
-       {0x1be5, KEY_DOWN},     /*chandown */
-       {0x5da3, KEY_LEFT},     /*voldown */
-       {0x5fa1, KEY_RIGHT},    /*volup */
-       {0x07f8, KEY_SPACE},    /*tab */
-       {0x1fe1, KEY_ENTER},    /*play ok */
-       {0x1be4, KEY_Z},        /*zoom */
-       {0x59a6, KEY_M},        /*mute */
-       {0x5ba5, KEY_F},        /*tv/f */
-       {0x19e7, KEY_R},        /*rec */
-       {0x01fe, KEY_S},        /*Stop */
-       {0x03fd, KEY_P},        /*pause */
-       {0x03fc, KEY_W},        /*<- -> */
-       {0x07f9, KEY_C},        /*capture */
-       {0x47b9, KEY_Q},        /*exit */
-       {0x43bc, KEY_O},        /*power */
-
+       {0x09f6, KEY_CHANNELUP},        /*chanup */
+       {0x1be5, KEY_CHANNELDOWN},      /*chandown */
+       {0x5da3, KEY_VOLUMEDOWN},       /*voldown */
+       {0x5fa1, KEY_VOLUMEUP},         /*volup */
+       {0x07f8, KEY_SPACE},            /*tab */
+       {0x1fe1, KEY_OK},               /*play ok */
+       {0x1be4, KEY_ZOOM},             /*zoom */
+       {0x59a6, KEY_MUTE},             /*mute */
+       {0x5ba5, KEY_RADIO},            /*tv/f */
+       {0x19e7, KEY_RECORD},           /*rec */
+       {0x01fe, KEY_STOP},             /*Stop */
+       {0x03fd, KEY_PAUSE},            /*pause */
+       {0x03fc, KEY_SCREEN},           /*<- -> */
+       {0x07f9, KEY_CAMERA},           /*capture */
+       {0x47b9, KEY_ESC},              /*exit */
+       {0x43bc, KEY_POWER2},           /*power */
 };
 
 static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c
new file mode 100644 (file)
index 0000000..08f8842
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ * Linux driver for Technisat DVB-S/S2 USB 2.0 device
+ *
+ * Copyright (C) 2010 Patrick Boettcher,
+ *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
+ *
+ * Development was sponsored by Technisat Digital UK Limited, whose
+ * registered office is Witan Gate House 500 - 600 Witan Gate West,
+ * Milton Keynes, MK9 1SH
+ *
+ * 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.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
+ * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
+ * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
+ * GNU General Public License for more details.
+ */
+
+#define DVB_USB_LOG_PREFIX "technisat-usb2"
+#include "dvb-usb.h"
+
+#include "stv6110x.h"
+#include "stv090x.h"
+
+/* module parameters */
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,
+               "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
+               DVB_USB_DEBUG_STATUS);
+
+/* disables all LED control command and
+ * also does not start the signal polling thread */
+static int disable_led_control;
+module_param(disable_led_control, int, 0444);
+MODULE_PARM_DESC(disable_led_control,
+               "disable LED control of the device "
+               "(default: 0 - LED control is active).");
+
+/* device private data */
+struct technisat_usb2_state {
+       struct dvb_usb_device *dev;
+       struct delayed_work green_led_work;
+       u8 power_state;
+
+       u16 last_scan_code;
+};
+
+/* debug print helpers */
+#define deb_info(args...)    dprintk(debug, 0x01, args)
+#define deb_eeprom(args...)  dprintk(debug, 0x02, args)
+#define deb_i2c(args...)     dprintk(debug, 0x04, args)
+#define deb_rc(args...)      dprintk(debug, 0x08, args)
+
+/* vendor requests */
+#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
+#define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
+#define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
+#define SET_GREEN_LED_VENDOR_REQUEST               0xB6
+#define SET_RED_LED_VENDOR_REQUEST                 0xB7
+#define GET_IR_DATA_VENDOR_REQUEST                 0xB8
+#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
+#define SET_USB_REENUMERATION                      0xBA
+
+/* i2c-access methods */
+#define I2C_SPEED_100KHZ_BIT 0x40
+
+#define I2C_STATUS_NAK 7
+#define I2C_STATUS_OK 8
+
+static int technisat_usb2_i2c_access(struct usb_device *udev,
+               u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+{
+       u8 b[64];
+       int ret, actual_length;
+
+       deb_i2c("i2c-access: %02x, tx: ", device_addr);
+       debug_dump(tx, txlen, deb_i2c);
+       deb_i2c(" ");
+
+       if (txlen > 62) {
+               err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
+                               device_addr);
+               txlen = 62;
+       }
+       if (rxlen > 62) {
+               err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
+                               device_addr);
+               txlen = 62;
+       }
+
+       b[0] = I2C_SPEED_100KHZ_BIT;
+       b[1] = device_addr << 1;
+
+       if (rx != NULL) {
+               b[0] |= rxlen;
+               b[1] |= 1;
+       }
+
+       memcpy(&b[2], tx, txlen);
+       ret = usb_bulk_msg(udev,
+                       usb_sndbulkpipe(udev, 0x01),
+                       b, 2 + txlen,
+                       NULL, 1000);
+
+       if (ret < 0) {
+               err("i2c-error: out failed %02x = %d", device_addr, ret);
+               return -ENODEV;
+       }
+
+       ret = usb_bulk_msg(udev,
+                       usb_rcvbulkpipe(udev, 0x01),
+                       b, 64, &actual_length, 1000);
+       if (ret < 0) {
+               err("i2c-error: in failed %02x = %d", device_addr, ret);
+               return -ENODEV;
+       }
+
+       if (b[0] != I2C_STATUS_OK) {
+               err("i2c-error: %02x = %d", device_addr, b[0]);
+               /* handle tuner-i2c-nak */
+               if (!(b[0] == I2C_STATUS_NAK &&
+                               device_addr == 0x60
+                               /* && device_is_technisat_usb2 */))
+                       return -ENODEV;
+       }
+
+       deb_i2c("status: %d, ", b[0]);
+
+       if (rx != NULL) {
+               memcpy(rx, &b[2], rxlen);
+
+               deb_i2c("rx (%d): ", rxlen);
+               debug_dump(rx, rxlen, deb_i2c);
+       }
+
+       deb_i2c("\n");
+
+       return 0;
+}
+
+static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+                               int num)
+{
+       int ret = 0, i;
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+       /* Ensure nobody else hits the i2c bus while we're sending our
+          sequence of messages, (such as the remote control thread) */
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
+                       ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
+                                               msg[i].buf, msg[i].len,
+                                               msg[i+1].buf, msg[i+1].len);
+                       if (ret != 0)
+                               break;
+                       i++;
+               } else {
+                       ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
+                                               msg[i].buf, msg[i].len,
+                                               NULL, 0);
+                       if (ret != 0)
+                               break;
+               }
+       }
+
+       if (ret == 0)
+               ret = i;
+
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm technisat_usb2_i2c_algo = {
+       .master_xfer   = technisat_usb2_i2c_xfer,
+       .functionality = technisat_usb2_i2c_func,
+};
+
+#if 0
+static void technisat_usb2_frontend_reset(struct usb_device *udev)
+{
+       usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       SET_FRONT_END_RESET_VENDOR_REQUEST,
+                       USB_TYPE_VENDOR | USB_DIR_OUT,
+                       10, 0,
+                       NULL, 0, 500);
+}
+#endif
+
+/* LED control */
+enum technisat_usb2_led_state {
+       LED_OFF,
+       LED_BLINK,
+       LED_ON,
+       LED_UNDEFINED
+};
+
+static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
+{
+       int ret;
+
+       u8 led[8] = {
+               red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
+               0
+       };
+
+       if (disable_led_control && state != LED_OFF)
+               return 0;
+
+       switch (state) {
+       case LED_ON:
+               led[1] = 0x82;
+               break;
+       case LED_BLINK:
+               led[1] = 0x82;
+               if (red) {
+                       led[2] = 0x02;
+                       led[3] = 10;
+                       led[4] = 10;
+               } else {
+                       led[2] = 0xff;
+                       led[3] = 50;
+                       led[4] = 50;
+               }
+               led[5] = 1;
+               break;
+
+       default:
+       case LED_OFF:
+               led[1] = 0x80;
+               break;
+       }
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+               red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
+               USB_TYPE_VENDOR | USB_DIR_OUT,
+               0, 0,
+               led, sizeof(led), 500);
+
+       mutex_unlock(&d->i2c_mutex);
+       return ret;
+}
+
+static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
+{
+       int ret;
+       u8 b = 0;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+               SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
+               USB_TYPE_VENDOR | USB_DIR_OUT,
+               (red << 8) | green, 0,
+               &b, 1, 500);
+
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static void technisat_usb2_green_led_control(struct work_struct *work)
+{
+       struct technisat_usb2_state *state =
+               container_of(work, struct technisat_usb2_state, green_led_work.work);
+       struct dvb_frontend *fe = state->dev->adapter[0].fe;
+
+       if (state->power_state == 0)
+               goto schedule;
+
+       if (fe != NULL) {
+               enum fe_status status;
+
+               if (fe->ops.read_status(fe, &status) != 0)
+                       goto schedule;
+
+               if (status & FE_HAS_LOCK) {
+                       u32 ber;
+
+                       if (fe->ops.read_ber(fe, &ber) != 0)
+                               goto schedule;
+
+                       if (ber > 1000)
+                               technisat_usb2_set_led(state->dev, 0, LED_BLINK);
+                       else
+                               technisat_usb2_set_led(state->dev, 0, LED_ON);
+               } else
+                       technisat_usb2_set_led(state->dev, 0, LED_OFF);
+       }
+
+schedule:
+       schedule_delayed_work(&state->green_led_work,
+                       msecs_to_jiffies(500));
+}
+
+/* method to find out whether the firmware has to be downloaded or not */
+static int technisat_usb2_identify_state(struct usb_device *udev,
+               struct dvb_usb_device_properties *props,
+               struct dvb_usb_device_description **desc, int *cold)
+{
+       int ret;
+       u8 version[3];
+
+       /* first select the interface */
+       if (usb_set_interface(udev, 0, 1) != 0)
+               err("could not set alternate setting to 0");
+       else
+               info("set alternate setting");
+
+       *cold = 0; /* by default do not download a firmware - just in case something is wrong */
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+               GET_VERSION_INFO_VENDOR_REQUEST,
+               USB_TYPE_VENDOR | USB_DIR_IN,
+               0, 0,
+               version, sizeof(version), 500);
+
+       if (ret < 0)
+               *cold = 1;
+       else {
+               info("firmware version: %d.%d", version[1], version[2]);
+               *cold = 0;
+       }
+
+       return 0;
+}
+
+/* power control */
+static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
+{
+       struct technisat_usb2_state *state = d->priv;
+
+       state->power_state = level;
+
+       if (disable_led_control)
+               return 0;
+
+       /* green led is turned off in any case - will be turned on when tuning */
+       technisat_usb2_set_led(d, 0, LED_OFF);
+       /* red led is turned on all the time */
+       technisat_usb2_set_led(d, 1, LED_ON);
+       return 0;
+}
+
+/* mac address reading - from the eeprom */
+#if 0
+static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
+{
+       u8 reg;
+       u8 b[16];
+       int i, j;
+
+       /* full EEPROM dump */
+       for (j = 0; j < 256 * 4; j += 16) {
+               reg = j;
+               if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
+                       break;
+
+               deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
+               for (i = 0; i < 16; i++)
+                       deb_eeprom("%02x ", b[i]);
+               deb_eeprom("\n");
+       }
+}
+#endif
+
+static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
+{
+       u8 lrc = 0;
+       while (--length)
+               lrc ^= *b++;
+       return lrc;
+}
+
+static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
+       u16 offset, u8 *b, u16 length, u8 tries)
+{
+       u8 bo = offset & 0xff;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = 0x50 | ((offset >> 8) & 0x3),
+                       .buf = &bo,
+                       .len = 1
+               }, {
+                       .addr = 0x50 | ((offset >> 8) & 0x3),
+                       .flags  = I2C_M_RD,
+                       .buf = b,
+                       .len = length
+               }
+       };
+
+       while (tries--) {
+               int status;
+
+               if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
+                       break;
+
+               status =
+                       technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
+
+               if (status)
+                       return 0;
+       }
+
+       return -EREMOTEIO;
+}
+
+#define EEPROM_MAC_START 0x3f8
+#define EEPROM_MAC_TOTAL 8
+static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
+               u8 mac[])
+{
+       u8 buf[EEPROM_MAC_TOTAL];
+
+       if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
+                               buf, EEPROM_MAC_TOTAL, 4) != 0)
+               return -ENODEV;
+
+       memcpy(mac, buf, 6);
+       return 0;
+}
+
+/* frontend attach */
+static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
+               fe_sec_voltage_t voltage)
+{
+       int i;
+       u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
+
+       gpio[2] = 1; /* high - voltage ? */
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               gpio[0] = 1;
+               break;
+       case SEC_VOLTAGE_18:
+               gpio[0] = 1;
+               gpio[1] = 1;
+               break;
+       default:
+       case SEC_VOLTAGE_OFF:
+               break;
+       }
+
+       for (i = 0; i < 3; i++)
+               if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
+                       return -EREMOTEIO;
+       return 0;
+}
+
+static struct stv090x_config technisat_usb2_stv090x_config = {
+       .device         = STV0903,
+       .demod_mode     = STV090x_SINGLE,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 8000000,
+       .address        = 0x68,
+
+       .ts1_mode       = STV090x_TSMODE_DVBCI,
+       .ts1_clk        = 13400000,
+       .ts1_tei        = 1,
+
+       .repeater_level = STV090x_RPTLEVEL_64,
+
+       .tuner_bbgain   = 6,
+};
+
+static struct stv6110x_config technisat_usb2_stv6110x_config = {
+       .addr           = 0x60,
+       .refclk         = 16000000,
+       .clk_div        = 2,
+};
+
+static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
+{
+       struct usb_device *udev = a->dev->udev;
+       int ret;
+
+       a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
+                       &a->dev->i2c_adap, STV090x_DEMODULATOR_0);
+
+       if (a->fe) {
+               struct stv6110x_devctl *ctl;
+
+               ctl = dvb_attach(stv6110x_attach,
+                               a->fe,
+                               &technisat_usb2_stv6110x_config,
+                               &a->dev->i2c_adap);
+
+               if (ctl) {
+                       technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
+                       technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
+                       technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
+                       technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+                       technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+                       technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+                       technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+                       technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
+                       technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
+                       technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
+                       technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
+
+                       /* call the init function once to initialize
+                          tuner's clock output divider and demod's
+                          master clock */
+                       if (a->fe->ops.init)
+                               a->fe->ops.init(a->fe);
+
+                       if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
+                               return -EAGAIN;
+
+                       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
+                                       USB_TYPE_VENDOR | USB_DIR_OUT,
+                                       0, 0,
+                                       NULL, 0, 500);
+                       mutex_unlock(&a->dev->i2c_mutex);
+
+                       if (ret != 0)
+                               err("could not set IF_CLK to external");
+
+                       a->fe->ops.set_voltage = technisat_usb2_set_voltage;
+
+                       /* if everything was successful assign a nice name to the frontend */
+                       strlcpy(a->fe->ops.info.name, a->dev->desc->name,
+                                       sizeof(a->fe->ops.info.name));
+               } else {
+                       dvb_frontend_detach(a->fe);
+                       a->fe = NULL;
+               }
+       }
+
+       technisat_usb2_set_led_timer(a->dev, 1, 1);
+
+       return a->fe == NULL ? -ENODEV : 0;
+}
+
+/* Remote control */
+
+/* the device is giving providing raw IR-signals to the host mapping
+ * it only to one remote control is just the default implementation
+ */
+#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
+#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
+
+#define FIRMWARE_CLOCK_TICK 83333
+#define FIRMWARE_CLOCK_DIVISOR 256
+
+#define IR_PERCENT_TOLERANCE 15
+
+#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
+#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
+
+#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
+#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
+
+#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+
+#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
+
+static int technisat_usb2_get_ir(struct dvb_usb_device *d)
+{
+       u8 buf[62], *b;
+       int ret;
+       struct ir_raw_event ev;
+
+       buf[0] = GET_IR_DATA_VENDOR_REQUEST;
+       buf[1] = 0x08;
+       buf[2] = 0x8f;
+       buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
+       buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+       ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+                       GET_IR_DATA_VENDOR_REQUEST,
+                       USB_TYPE_VENDOR | USB_DIR_OUT,
+                       0, 0,
+                       buf, 5, 500);
+       if (ret < 0)
+               goto unlock;
+
+       buf[1] = 0;
+       buf[2] = 0;
+       ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+                       GET_IR_DATA_VENDOR_REQUEST,
+                       USB_TYPE_VENDOR | USB_DIR_IN,
+                       0x8080, 0,
+                       buf, sizeof(buf), 500);
+
+unlock:
+       mutex_unlock(&d->i2c_mutex);
+
+       if (ret < 0)
+               return ret;
+
+       if (ret == 1)
+               return 0; /* no key pressed */
+
+       /* decoding */
+       b = buf+1;
+
+#if 0
+       deb_rc("RC: %d ", ret);
+       debug_dump(b, ret, deb_rc);
+#endif
+
+       ev.pulse = 0;
+       while (1) {
+               ev.pulse = !ev.pulse;
+               ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000;
+               ir_raw_event_store(d->rc_dev, &ev);
+
+               b++;
+               if (*b == 0xff) {
+                       ev.pulse = 0;
+                       ev.duration = 888888*2;
+                       ir_raw_event_store(d->rc_dev, &ev);
+                       break;
+               }
+       }
+
+       ir_raw_event_handle(d->rc_dev);
+
+       return 1;
+}
+
+static int technisat_usb2_rc_query(struct dvb_usb_device *d)
+{
+       int ret = technisat_usb2_get_ir(d);
+
+       if (ret < 0)
+               return ret;
+
+       if (ret == 0)
+               return 0;
+
+       if (!disable_led_control)
+               technisat_usb2_set_led(d, 1, LED_BLINK);
+
+       return 0;
+}
+
+/* DVB-USB and USB stuff follows */
+static struct usb_device_id technisat_usb2_id_table[] = {
+       { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) },
+       { 0 }           /* Terminating entry */
+};
+
+/* device description */
+static struct dvb_usb_device_properties technisat_usb2_devices = {
+       .caps              = DVB_USB_IS_AN_I2C_ADAPTER,
+
+       .usb_ctrl          = CYPRESS_FX2,
+
+       .identify_state    = technisat_usb2_identify_state,
+       .firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
+
+       .size_of_priv      = sizeof(struct technisat_usb2_state),
+
+       .i2c_algo          = &technisat_usb2_i2c_algo,
+
+       .power_ctrl        = technisat_usb2_power_ctrl,
+       .read_mac_address  = technisat_usb2_read_mac_address,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .frontend_attach  = technisat_usb2_frontend_attach,
+
+                       .stream = {
+                               .type = USB_ISOC,
+                               .count = 8,
+                               .endpoint = 0x2,
+                               .u = {
+                                       .isoc = {
+                                               .framesperurb = 32,
+                                               .framesize = 2048,
+                                               .interval = 3,
+                                       }
+                               }
+                       },
+
+                       .size_of_priv = 0,
+               },
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {   "Technisat SkyStar USB HD (DVB-S/S2)",
+                       { &technisat_usb2_id_table[0], NULL },
+                       { NULL },
+               },
+       },
+
+       .rc.core = {
+               .rc_interval = 100,
+               .rc_codes    = RC_MAP_TECHNISAT_USB2,
+               .module_name = "technisat-usb2",
+               .rc_query    = technisat_usb2_rc_query,
+               .allowed_protos = RC_TYPE_ALL,
+               .driver_type    = RC_DRIVER_IR_RAW,
+       }
+};
+
+static int technisat_usb2_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct dvb_usb_device *dev;
+
+       if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
+                               &dev, adapter_nr) != 0)
+               return -ENODEV;
+
+       if (dev) {
+               struct technisat_usb2_state *state = dev->priv;
+               state->dev = dev;
+
+               if (!disable_led_control) {
+                       INIT_DELAYED_WORK(&state->green_led_work,
+                                       technisat_usb2_green_led_control);
+                       schedule_delayed_work(&state->green_led_work,
+                                       msecs_to_jiffies(500));
+               }
+       }
+
+       return 0;
+}
+
+static void technisat_usb2_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *dev = usb_get_intfdata(intf);
+
+       /* work and stuff was only created when the device is is hot-state */
+       if (dev != NULL) {
+               struct technisat_usb2_state *state = dev->priv;
+               if (state != NULL) {
+                       cancel_delayed_work_sync(&state->green_led_work);
+                       flush_scheduled_work();
+               }
+       }
+
+       dvb_usb_device_exit(intf);
+}
+
+static struct usb_driver technisat_usb2_driver = {
+       .name       = "dvb_usb_technisat_usb2",
+       .probe      = technisat_usb2_probe,
+       .disconnect = technisat_usb2_disconnect,
+       .id_table   = technisat_usb2_id_table,
+};
+
+/* module stuff */
+static int __init technisat_usb2_module_init(void)
+{
+       int result = usb_register(&technisat_usb2_driver);
+       if (result) {
+               err("usb_register failed. Code %d", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit technisat_usb2_module_exit(void)
+{
+       usb_deregister(&technisat_usb2_driver);
+}
+
+module_init(technisat_usb2_module_init);
+module_exit(technisat_usb2_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
index 4afa29256df110d3383b6b469762cefbb46436b6..f3e9448c395520eb98847dade512e7b4553c4966 100644 (file)
@@ -1,6 +1,6 @@
 config DVB_FIREDTV
        tristate "FireDTV and FloppyDTV"
-       depends on DVB_CORE && (FIREWIRE || IEEE1394)
+       depends on DVB_CORE && FIREWIRE
        help
          Support for DVB receivers from Digital Everywhere
          which are connected via IEEE 1394 (FireWire).
@@ -13,12 +13,6 @@ config DVB_FIREDTV
 
 if DVB_FIREDTV
 
-config DVB_FIREDTV_FIREWIRE
-       def_bool FIREWIRE = y || (FIREWIRE = m && DVB_FIREDTV = m)
-
-config DVB_FIREDTV_IEEE1394
-       def_bool IEEE1394 = y || (IEEE1394 = m && DVB_FIREDTV = m)
-
 config DVB_FIREDTV_INPUT
        def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
 
index da84203d51c6226bb8a80c0769a1f0e2514180a0..357b3aab186b2d1645419a073bee2e26acdf9ba7 100644 (file)
@@ -1,9 +1,6 @@
 obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
 
-firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
-firedtv-$(CONFIG_DVB_FIREDTV_FIREWIRE) += firedtv-fw.o
-firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
+firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
 firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
 
 ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
deleted file mode 100644 (file)
index b34ca7a..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * FireDTV driver -- ieee1394 I/O backend
- *
- * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
- * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
- * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
- *
- *     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/errno.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <dma.h>
-#include <csr1212.h>
-#include <highlevel.h>
-#include <hosts.h>
-#include <ieee1394.h>
-#include <iso.h>
-#include <nodemgr.h>
-
-#include <dvb_demux.h>
-
-#include "firedtv.h"
-
-static LIST_HEAD(node_list);
-static DEFINE_SPINLOCK(node_list_lock);
-
-#define CIP_HEADER_SIZE                        8
-#define MPEG2_TS_HEADER_SIZE           4
-#define MPEG2_TS_SOURCE_PACKET_SIZE    (4 + 188)
-
-static void rawiso_activity_cb(struct hpsb_iso *iso)
-{
-       struct firedtv *f, *fdtv = NULL;
-       unsigned int i, num, packet;
-       unsigned char *buf;
-       unsigned long flags;
-       int count;
-
-       spin_lock_irqsave(&node_list_lock, flags);
-       list_for_each_entry(f, &node_list, list)
-               if (f->backend_data == iso) {
-                       fdtv = f;
-                       break;
-               }
-       spin_unlock_irqrestore(&node_list_lock, flags);
-
-       packet = iso->first_packet;
-       num = hpsb_iso_n_ready(iso);
-
-       if (!fdtv) {
-               pr_err("received at unknown iso channel\n");
-               goto out;
-       }
-
-       for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) {
-               buf = dma_region_i(&iso->data_buf, unsigned char,
-                       iso->infos[packet].offset + CIP_HEADER_SIZE);
-               count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
-                       MPEG2_TS_SOURCE_PACKET_SIZE;
-
-               /* ignore empty packet */
-               if (iso->infos[packet].len <= CIP_HEADER_SIZE)
-                       continue;
-
-               while (count--) {
-                       if (buf[MPEG2_TS_HEADER_SIZE] == 0x47)
-                               dvb_dmx_swfilter_packets(&fdtv->demux,
-                                               &buf[MPEG2_TS_HEADER_SIZE], 1);
-                       else
-                               dev_err(fdtv->device,
-                                       "skipping invalid packet\n");
-                       buf += MPEG2_TS_SOURCE_PACKET_SIZE;
-               }
-       }
-out:
-       hpsb_iso_recv_release_packets(iso, num);
-}
-
-static inline struct node_entry *node_of(struct firedtv *fdtv)
-{
-       return container_of(fdtv->device, struct unit_directory, device)->ne;
-}
-
-static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
-{
-       quadlet_t *d = data;
-       int ret;
-
-       ret = hpsb_node_lock(node_of(fdtv), addr,
-                            EXTCODE_COMPARE_SWAP, &d[1], d[0]);
-       d[0] = d[1];
-
-       return ret;
-}
-
-static int node_read(struct firedtv *fdtv, u64 addr, void *data)
-{
-       return hpsb_node_read(node_of(fdtv), addr, data, 4);
-}
-
-static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
-{
-       return hpsb_node_write(node_of(fdtv), addr, data, len);
-}
-
-#define FDTV_ISO_BUFFER_PACKETS 256
-#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200)
-
-static int start_iso(struct firedtv *fdtv)
-{
-       struct hpsb_iso *iso_handle;
-       int ret;
-
-       iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host,
-                               FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS,
-                               fdtv->isochannel, HPSB_ISO_DMA_DEFAULT,
-                               -1, /* stat.config.irq_interval */
-                               rawiso_activity_cb);
-       if (iso_handle == NULL) {
-               dev_err(fdtv->device, "cannot initialize iso receive\n");
-               return -ENOMEM;
-       }
-       fdtv->backend_data = iso_handle;
-
-       ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0);
-       if (ret != 0) {
-               dev_err(fdtv->device, "cannot start iso receive\n");
-               hpsb_iso_shutdown(iso_handle);
-               fdtv->backend_data = NULL;
-       }
-       return ret;
-}
-
-static void stop_iso(struct firedtv *fdtv)
-{
-       struct hpsb_iso *iso_handle = fdtv->backend_data;
-
-       if (iso_handle != NULL) {
-               hpsb_iso_stop(iso_handle);
-               hpsb_iso_shutdown(iso_handle);
-       }
-       fdtv->backend_data = NULL;
-}
-
-static const struct firedtv_backend fdtv_1394_backend = {
-       .lock           = node_lock,
-       .read           = node_read,
-       .write          = node_write,
-       .start_iso      = start_iso,
-       .stop_iso       = stop_iso,
-};
-
-static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                       int cts, u8 *data, size_t length)
-{
-       struct firedtv *f, *fdtv = NULL;
-       unsigned long flags;
-       int su;
-
-       if (length == 0 || (data[0] & 0xf0) != 0)
-               return;
-
-       su = data[1] & 0x7;
-
-       spin_lock_irqsave(&node_list_lock, flags);
-       list_for_each_entry(f, &node_list, list)
-               if (node_of(f)->host == host &&
-                   node_of(f)->nodeid == nodeid &&
-                   (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
-                       fdtv = f;
-                       break;
-               }
-       spin_unlock_irqrestore(&node_list_lock, flags);
-
-       if (fdtv)
-               avc_recv(fdtv, data, length);
-}
-
-static int node_probe(struct device *dev)
-{
-       struct unit_directory *ud =
-                       container_of(dev, struct unit_directory, device);
-       struct firedtv *fdtv;
-       int kv_len, err;
-       void *kv_str;
-
-       if (ud->model_name_kv) {
-               kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4;
-               kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
-       } else {
-               kv_len = 0;
-               kv_str = NULL;
-       }
-       fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
-       if (!fdtv)
-               return -ENOMEM;
-
-       /*
-        * Work around a bug in udev's path_id script:  Use the fw-host's dev
-        * instead of the unit directory's dev as parent of the input device.
-        */
-       err = fdtv_register_rc(fdtv, dev->parent->parent);
-       if (err)
-               goto fail_free;
-
-       spin_lock_irq(&node_list_lock);
-       list_add_tail(&fdtv->list, &node_list);
-       spin_unlock_irq(&node_list_lock);
-
-       err = avc_identify_subunit(fdtv);
-       if (err)
-               goto fail;
-
-       err = fdtv_dvb_register(fdtv);
-       if (err)
-               goto fail;
-
-       avc_register_remote_control(fdtv);
-
-       return 0;
-fail:
-       spin_lock_irq(&node_list_lock);
-       list_del(&fdtv->list);
-       spin_unlock_irq(&node_list_lock);
-       fdtv_unregister_rc(fdtv);
-fail_free:
-       kfree(fdtv);
-
-       return err;
-}
-
-static int node_remove(struct device *dev)
-{
-       struct firedtv *fdtv = dev_get_drvdata(dev);
-
-       fdtv_dvb_unregister(fdtv);
-
-       spin_lock_irq(&node_list_lock);
-       list_del(&fdtv->list);
-       spin_unlock_irq(&node_list_lock);
-
-       fdtv_unregister_rc(fdtv);
-       kfree(fdtv);
-
-       return 0;
-}
-
-static int node_update(struct unit_directory *ud)
-{
-       struct firedtv *fdtv = dev_get_drvdata(&ud->device);
-
-       if (fdtv->isochannel >= 0)
-               cmp_establish_pp_connection(fdtv, fdtv->subunit,
-                                           fdtv->isochannel);
-       return 0;
-}
-
-static struct hpsb_protocol_driver fdtv_driver = {
-       .name           = "firedtv",
-       .id_table       = fdtv_id_table,
-       .update         = node_update,
-       .driver         = {
-               .probe  = node_probe,
-               .remove = node_remove,
-       },
-};
-
-static struct hpsb_highlevel fdtv_highlevel = {
-       .name           = "firedtv",
-       .fcp_request    = fcp_request,
-};
-
-int __init fdtv_1394_init(void)
-{
-       int ret;
-
-       hpsb_register_highlevel(&fdtv_highlevel);
-       ret = hpsb_register_protocol(&fdtv_driver);
-       if (ret) {
-               printk(KERN_ERR "firedtv: failed to register protocol\n");
-               hpsb_unregister_highlevel(&fdtv_highlevel);
-       }
-       return ret;
-}
-
-void __exit fdtv_1394_exit(void)
-{
-       hpsb_unregister_protocol(&fdtv_driver);
-       hpsb_unregister_highlevel(&fdtv_highlevel);
-}
index f0f1842fab604fc60fd1d2849edb5dfccce0a513..fc5ccd8c923aef46e86343cd09bbd3fa64a737a8 100644 (file)
@@ -241,8 +241,8 @@ static int avc_write(struct firedtv *fdtv)
                if (unlikely(avc_debug))
                        debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
 
-               err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
-                               fdtv->avc_data, fdtv->avc_data_length);
+               err = fdtv_write(fdtv, FCP_COMMAND_REGISTER,
+                                fdtv->avc_data, fdtv->avc_data_length);
                if (err) {
                        dev_err(fdtv->device, "FCP command write failed\n");
 
@@ -1322,7 +1322,7 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
 
        mutex_lock(&fdtv->avc_mutex);
 
-       ret = fdtv->backend->read(fdtv, addr, data);
+       ret = fdtv_read(fdtv, addr, data);
        if (ret < 0)
                dev_err(fdtv->device, "CMP: read I/O error\n");
 
@@ -1340,7 +1340,7 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
        /* data[] is stack-allocated and should not be DMA-mapped. */
        memcpy(fdtv->avc_data, data, 8);
 
-       ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
+       ret = fdtv_lock(fdtv, addr, fdtv->avc_data);
        if (ret < 0)
                dev_err(fdtv->device, "CMP: lock I/O error\n");
        else
@@ -1405,10 +1405,7 @@ repeat:
                /* FIXME: this is for the worst case - optimize */
                set_opcr_overhead_id(opcr, 0);
 
-               /*
-                * FIXME: allocate isochronous channel and bandwidth at IRM
-                * fdtv->backend->alloc_resources(fdtv, channels_mask, bw);
-                */
+               /* FIXME: allocate isochronous channel and bandwidth at IRM */
        }
 
        set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
@@ -1424,8 +1421,6 @@ repeat:
                /*
                 * FIXME: if old_opcr.P2P_Connections > 0,
                 * deallocate isochronous channel and bandwidth at IRM
-                * if (...)
-                *      fdtv->backend->dealloc_resources(fdtv, channel, bw);
                 */
 
                if (++attempts < 6) /* arbitrary limit */
index 079e8c5b047567e40fe104314c417ed7bae676c5..fd8bbbfa5c598e39896aaae1ea5e001002bdb6d5 100644 (file)
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
 
 #include <dmxdev.h>
 #include <dvb_demux.h>
@@ -166,11 +161,11 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-int fdtv_dvb_register(struct firedtv *fdtv)
+int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
 {
        int err;
 
-       err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
+       err = dvb_register_adapter(&fdtv->adapter, name,
                                   THIS_MODULE, fdtv->device, adapter_nr);
        if (err < 0)
                goto fail_log;
@@ -210,7 +205,7 @@ int fdtv_dvb_register(struct firedtv *fdtv)
 
        dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
 
-       fdtv_frontend_init(fdtv);
+       fdtv_frontend_init(fdtv, name);
        err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
        if (err)
                goto fail_net_release;
@@ -248,127 +243,3 @@ void fdtv_dvb_unregister(struct firedtv *fdtv)
        dvb_dmx_release(&fdtv->demux);
        dvb_unregister_adapter(&fdtv->adapter);
 }
-
-const char *fdtv_model_names[] = {
-       [FIREDTV_UNKNOWN] = "unknown type",
-       [FIREDTV_DVB_S]   = "FireDTV S/CI",
-       [FIREDTV_DVB_C]   = "FireDTV C/CI",
-       [FIREDTV_DVB_T]   = "FireDTV T/CI",
-       [FIREDTV_DVB_S2]  = "FireDTV S2  ",
-};
-
-struct firedtv *fdtv_alloc(struct device *dev,
-                          const struct firedtv_backend *backend,
-                          const char *name, size_t name_len)
-{
-       struct firedtv *fdtv;
-       int i;
-
-       fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
-       if (!fdtv)
-               return NULL;
-
-       dev_set_drvdata(dev, fdtv);
-       fdtv->device            = dev;
-       fdtv->isochannel        = -1;
-       fdtv->voltage           = 0xff;
-       fdtv->tone              = 0xff;
-       fdtv->backend           = backend;
-
-       mutex_init(&fdtv->avc_mutex);
-       init_waitqueue_head(&fdtv->avc_wait);
-       mutex_init(&fdtv->demux_mutex);
-       INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
-
-       for (i = ARRAY_SIZE(fdtv_model_names); --i; )
-               if (strlen(fdtv_model_names[i]) <= name_len &&
-                   strncmp(name, fdtv_model_names[i], name_len) == 0)
-                       break;
-       fdtv->type = i;
-
-       return fdtv;
-}
-
-#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
-                    IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
-
-#define DIGITAL_EVERYWHERE_OUI 0x001287
-#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
-#define AVC_SW_VERSION_ENTRY   0x010001
-
-const struct ieee1394_device_id fdtv_id_table[] = {
-       {
-               /* FloppyDTV S/CI and FloppyDTV S2 */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000024,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {
-               /* FloppyDTV T/CI */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000025,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {
-               /* FloppyDTV C/CI */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000026,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {
-               /* FireDTV S/CI and FloppyDTV S2 */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000034,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {
-               /* FireDTV T/CI */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000035,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {
-               /* FireDTV C/CI */
-               .match_flags    = MATCH_FLAGS,
-               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
-               .model_id       = 0x000036,
-               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
-               .version        = AVC_SW_VERSION_ENTRY,
-       }, {}
-};
-MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
-
-static int __init fdtv_init(void)
-{
-       int ret;
-
-       ret = fdtv_fw_init();
-       if (ret < 0)
-               return ret;
-
-       ret = fdtv_1394_init();
-       if (ret < 0)
-               fdtv_fw_exit();
-
-       return ret;
-}
-
-static void __exit fdtv_exit(void)
-{
-       fdtv_1394_exit();
-       fdtv_fw_exit();
-}
-
-module_init(fdtv_init);
-module_exit(fdtv_exit);
-
-MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
-MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
-MODULE_DESCRIPTION("FireDTV DVB Driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("FireDTV DVB");
index d10920e2f3a29ff5645bdba226e5df6e5a1d70c2..8748a61be73d2d8e32d0b65fd95396c2c4269b5b 100644 (file)
@@ -36,14 +36,14 @@ static int fdtv_dvb_init(struct dvb_frontend *fe)
                return err;
        }
 
-       return fdtv->backend->start_iso(fdtv);
+       return fdtv_start_iso(fdtv);
 }
 
 static int fdtv_sleep(struct dvb_frontend *fe)
 {
        struct firedtv *fdtv = fe->sec_priv;
 
-       fdtv->backend->stop_iso(fdtv);
+       fdtv_stop_iso(fdtv);
        cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
        fdtv->isochannel = -1;
        return 0;
@@ -165,7 +165,7 @@ static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
        return 0;
 }
 
-void fdtv_frontend_init(struct firedtv *fdtv)
+void fdtv_frontend_init(struct firedtv *fdtv, const char *name)
 {
        struct dvb_frontend_ops *ops = &fdtv->fe.ops;
        struct dvb_frontend_info *fi = &ops->info;
@@ -266,7 +266,7 @@ void fdtv_frontend_init(struct firedtv *fdtv)
                dev_err(fdtv->device, "no frontend for model type %d\n",
                        fdtv->type);
        }
-       strcpy(fi->name, fdtv_model_names[fdtv->type]);
+       strcpy(fi->name, name);
 
        fdtv->fe.dvb = &fdtv->adapter;
        fdtv->fe.sec_priv = fdtv;
index 7424b0493f9d09344468ef1c43d6f3cad13ce824..8022b743af91a6ff0cba565b9b9438296ed5e1ef 100644 (file)
@@ -9,11 +9,18 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
 
 #include <asm/page.h>
+#include <asm/system.h>
 
 #include <dvb_demux.h>
 
@@ -41,17 +48,17 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
        return rcode != RCODE_COMPLETE ? -EIO : 0;
 }
 
-static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
+int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data)
 {
        return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
 }
 
-static int node_read(struct firedtv *fdtv, u64 addr, void *data)
+int fdtv_read(struct firedtv *fdtv, u64 addr, void *data)
 {
        return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
 }
 
-static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
 {
        return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
 }
@@ -67,7 +74,7 @@ static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
 #define N_PAGES                        DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
 #define IRQ_INTERVAL           16
 
-struct firedtv_receive_context {
+struct fdtv_ir_context {
        struct fw_iso_context *context;
        struct fw_iso_buffer buffer;
        int interrupt_packet;
@@ -75,7 +82,7 @@ struct firedtv_receive_context {
        char *pages[N_PAGES];
 };
 
-static int queue_iso(struct firedtv_receive_context *ctx, int index)
+static int queue_iso(struct fdtv_ir_context *ctx, int index)
 {
        struct fw_iso_packet p;
 
@@ -92,7 +99,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
                       size_t header_length, void *header, void *data)
 {
        struct firedtv *fdtv = data;
-       struct firedtv_receive_context *ctx = fdtv->backend_data;
+       struct fdtv_ir_context *ctx = fdtv->ir_context;
        __be32 *h, *h_end;
        int length, err, i = ctx->current_packet;
        char *p, *p_end;
@@ -121,9 +128,9 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
        ctx->current_packet = i;
 }
 
-static int start_iso(struct firedtv *fdtv)
+int fdtv_start_iso(struct firedtv *fdtv)
 {
-       struct firedtv_receive_context *ctx;
+       struct fdtv_ir_context *ctx;
        struct fw_device *device = device_of(fdtv);
        int i, err;
 
@@ -161,7 +168,7 @@ static int start_iso(struct firedtv *fdtv)
        if (err)
                goto fail;
 
-       fdtv->backend_data = ctx;
+       fdtv->ir_context = ctx;
 
        return 0;
 fail:
@@ -174,9 +181,9 @@ fail_free:
        return err;
 }
 
-static void stop_iso(struct firedtv *fdtv)
+void fdtv_stop_iso(struct firedtv *fdtv)
 {
-       struct firedtv_receive_context *ctx = fdtv->backend_data;
+       struct fdtv_ir_context *ctx = fdtv->ir_context;
 
        fw_iso_context_stop(ctx->context);
        fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
@@ -184,14 +191,6 @@ static void stop_iso(struct firedtv *fdtv)
        kfree(ctx);
 }
 
-static const struct firedtv_backend backend = {
-       .lock           = node_lock,
-       .read           = node_read,
-       .write          = node_write,
-       .start_iso      = start_iso,
-       .stop_iso       = stop_iso,
-};
-
 static void handle_fcp(struct fw_card *card, struct fw_request *request,
                       int tcode, int destination, int source, int generation,
                       unsigned long long offset, void *payload, size_t length,
@@ -238,6 +237,14 @@ static const struct fw_address_region fcp_region = {
        .end    = CSR_REGISTER_BASE + CSR_FCP_END,
 };
 
+static const char * const model_names[] = {
+       [FIREDTV_UNKNOWN] = "unknown type",
+       [FIREDTV_DVB_S]   = "FireDTV S/CI",
+       [FIREDTV_DVB_C]   = "FireDTV C/CI",
+       [FIREDTV_DVB_T]   = "FireDTV T/CI",
+       [FIREDTV_DVB_S2]  = "FireDTV S2  ",
+};
+
 /* Adjust the template string if models with longer names appear. */
 #define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
 
@@ -245,15 +252,31 @@ static int node_probe(struct device *dev)
 {
        struct firedtv *fdtv;
        char name[MAX_MODEL_NAME_LEN];
-       int name_len, err;
-
-       name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
-                                name, sizeof(name));
+       int name_len, i, err;
 
-       fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0);
+       fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
        if (!fdtv)
                return -ENOMEM;
 
+       dev_set_drvdata(dev, fdtv);
+       fdtv->device            = dev;
+       fdtv->isochannel        = -1;
+       fdtv->voltage           = 0xff;
+       fdtv->tone              = 0xff;
+
+       mutex_init(&fdtv->avc_mutex);
+       init_waitqueue_head(&fdtv->avc_wait);
+       mutex_init(&fdtv->demux_mutex);
+       INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
+
+       name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+                                name, sizeof(name));
+       for (i = ARRAY_SIZE(model_names); --i; )
+               if (strlen(model_names[i]) <= name_len &&
+                   strncmp(name, model_names[i], name_len) == 0)
+                       break;
+       fdtv->type = i;
+
        err = fdtv_register_rc(fdtv, dev);
        if (err)
                goto fail_free;
@@ -266,7 +289,7 @@ static int node_probe(struct device *dev)
        if (err)
                goto fail;
 
-       err = fdtv_dvb_register(fdtv);
+       err = fdtv_dvb_register(fdtv, model_names[fdtv->type]);
        if (err)
                goto fail;
 
@@ -309,6 +332,60 @@ static void node_update(struct fw_unit *unit)
                                            fdtv->isochannel);
 }
 
+#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
+                    IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
+
+#define DIGITAL_EVERYWHERE_OUI 0x001287
+#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
+#define AVC_SW_VERSION_ENTRY   0x010001
+
+static const struct ieee1394_device_id fdtv_id_table[] = {
+       {
+               /* FloppyDTV S/CI and FloppyDTV S2 */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000024,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FloppyDTV T/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000025,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FloppyDTV C/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000026,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV S/CI and FloppyDTV S2 */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000034,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV T/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000035,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV C/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000036,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {}
+};
+MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
+
 static struct fw_driver fdtv_driver = {
        .driver   = {
                .owner  = THIS_MODULE,
@@ -321,7 +398,7 @@ static struct fw_driver fdtv_driver = {
        .id_table = fdtv_id_table,
 };
 
-int __init fdtv_fw_init(void)
+static int __init fdtv_init(void)
 {
        int ret;
 
@@ -329,11 +406,24 @@ int __init fdtv_fw_init(void)
        if (ret < 0)
                return ret;
 
-       return driver_register(&fdtv_driver.driver);
+       ret = driver_register(&fdtv_driver.driver);
+       if (ret < 0)
+               fw_core_remove_address_handler(&fcp_handler);
+
+       return ret;
 }
 
-void fdtv_fw_exit(void)
+static void __exit fdtv_exit(void)
 {
        driver_unregister(&fdtv_driver.driver);
        fw_core_remove_address_handler(&fcp_handler);
 }
+
+module_init(fdtv_init);
+module_exit(fdtv_exit);
+
+MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
+MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
+MODULE_DESCRIPTION("FireDTV DVB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("FireDTV DVB");
index 78cc28f36914bcf3fde09f2ce7c74328f063a0ae..bd00b04e079ddd0b7f667b9581118b47633cc2f5 100644 (file)
@@ -70,15 +70,7 @@ enum model_type {
 
 struct device;
 struct input_dev;
-struct firedtv;
-
-struct firedtv_backend {
-       int (*lock)(struct firedtv *fdtv, u64 addr, void *data);
-       int (*read)(struct firedtv *fdtv, u64 addr, void *data);
-       int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
-       int (*start_iso)(struct firedtv *fdtv);
-       void (*stop_iso)(struct firedtv *fdtv);
-};
+struct fdtv_ir_context;
 
 struct firedtv {
        struct device *device;
@@ -104,12 +96,11 @@ struct firedtv {
        enum model_type         type;
        char                    subunit;
        char                    isochannel;
+       struct fdtv_ir_context  *ir_context;
+
        fe_sec_voltage_t        voltage;
        fe_sec_tone_mode_t      tone;
 
-       const struct firedtv_backend *backend;
-       void                    *backend_data;
-
        struct mutex            demux_mutex;
        unsigned long           channel_active;
        u16                     channel_pid[16];
@@ -118,15 +109,6 @@ struct firedtv {
        u8                      avc_data[512];
 };
 
-/* firedtv-1394.c */
-#ifdef CONFIG_DVB_FIREDTV_IEEE1394
-int fdtv_1394_init(void);
-void fdtv_1394_exit(void);
-#else
-static inline int fdtv_1394_init(void) { return 0; }
-static inline void fdtv_1394_exit(void) {}
-#endif
-
 /* firedtv-avc.c */
 int avc_recv(struct firedtv *fdtv, void *data, size_t length);
 int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
@@ -158,25 +140,18 @@ void fdtv_ca_release(struct firedtv *fdtv);
 /* firedtv-dvb.c */
 int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
 int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
-int fdtv_dvb_register(struct firedtv *fdtv);
+int fdtv_dvb_register(struct firedtv *fdtv, const char *name);
 void fdtv_dvb_unregister(struct firedtv *fdtv);
-struct firedtv *fdtv_alloc(struct device *dev,
-                          const struct firedtv_backend *backend,
-                          const char *name, size_t name_len);
-extern const char *fdtv_model_names[];
-extern const struct ieee1394_device_id fdtv_id_table[];
 
 /* firedtv-fe.c */
-void fdtv_frontend_init(struct firedtv *fdtv);
+void fdtv_frontend_init(struct firedtv *fdtv, const char *name);
 
 /* firedtv-fw.c */
-#ifdef CONFIG_DVB_FIREDTV_FIREWIRE
-int fdtv_fw_init(void);
-void fdtv_fw_exit(void);
-#else
-static inline int fdtv_fw_init(void) { return 0; }
-static inline void fdtv_fw_exit(void) {}
-#endif
+int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data);
+int fdtv_read(struct firedtv *fdtv, u64 addr, void *data);
+int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len);
+int fdtv_start_iso(struct firedtv *fdtv);
+void fdtv_stop_iso(struct firedtv *fdtv);
 
 /* firedtv-rc.c */
 #ifdef CONFIG_DVB_FIREDTV_INPUT
index b8519ba511e5326373dd6b873aa687bff3f0e94b..83093d1f4f74822c97df5dcc1edda6877df803b8 100644 (file)
@@ -349,6 +349,14 @@ config DVB_DIB7000P
          A DVB-T tuner module. Designed for mobile usage. Say Y when you want
          to support this frontend.
 
+config DVB_DIB9000
+       tristate "DiBcom 9000"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T tuner module. Designed for mobile usage. Say Y when you want
+         to support this frontend.
+
 config DVB_TDA10048
        tristate "Philips TDA10048HN based"
        depends on DVB_CORE && I2C
@@ -370,6 +378,13 @@ config DVB_EC100
        help
          Say Y when you want to support this frontend.
 
+config DVB_STV0367
+       tristate "ST STV0367 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-T/C tuner module. Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
        depends on DVB_CORE
 
index b1d9525aa7e3976d21b75bc610b6d9613e00ec95..3b0c4bdc4b2b2b6029b80c264a2d1f640a3248a4 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
 obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o
 obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o
 obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o
+obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o
 obj-$(CONFIG_DVB_MT312) += mt312.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
 obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -83,3 +84,4 @@ obj-$(CONFIG_DVB_DS3000) += ds3000.o
 obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
 obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
 obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
+obj-$(CONFIG_DVB_STV0367) += stv0367.o
index ba25fa0b0fc2a5bfb098a94c258f9d913c1806c5..345311c333838ace3ee21fd751051a74cb472270 100644 (file)
@@ -1323,13 +1323,11 @@ static struct dvb_frontend_ops af9013_ops;
 
 static int af9013_download_firmware(struct af9013_state *state)
 {
-       int i, len, packets, remainder, ret;
+       int i, len, remaining, ret;
        const struct firmware *fw;
-       u16 addr = 0x5100; /* firmware start address */
        u16 checksum = 0;
        u8 val;
        u8 fw_params[4];
-       u8 *data;
        u8 *fw_file = AF9013_DEFAULT_FIRMWARE;
 
        msleep(100);
@@ -1373,21 +1371,18 @@ static int af9013_download_firmware(struct af9013_state *state)
        if (ret)
                goto error_release;
 
-       #define FW_PACKET_MAX_DATA  16
-
-       packets = fw->size / FW_PACKET_MAX_DATA;
-       remainder = fw->size % FW_PACKET_MAX_DATA;
-       len = FW_PACKET_MAX_DATA;
-       for (i = 0; i <= packets; i++) {
-               if (i == packets)  /* set size of the last packet */
-                       len = remainder;
-
-               data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
-               ret = af9013_write_ofsm_regs(state, addr, data, len);
-               addr += FW_PACKET_MAX_DATA;
+       #define FW_ADDR 0x5100 /* firmware start address */
+       #define LEN_MAX 16 /* max packet size */
+       for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+               len = remaining;
+               if (len > LEN_MAX)
+                       len = LEN_MAX;
 
+               ret = af9013_write_ofsm_regs(state,
+                       FW_ADDR + fw->size - remaining,
+                       (u8 *) &fw->data[fw->size - remaining], len);
                if (ret) {
-                       err("firmware download failed at %d with %d", i, ret);
+                       err("firmware download failed:%d", ret);
                        goto error_release;
                }
        }
@@ -1466,20 +1461,6 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
        state->i2c = i2c;
        memcpy(&state->config, config, sizeof(struct af9013_config));
 
-       /* chip version */
-       ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
-       if (ret)
-               goto error;
-
-       /* ROM version */
-       for (i = 0; i < 2; i++) {
-               ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
-               if (ret)
-                       goto error;
-       }
-       deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
-               buf[2], buf[0], buf[1]);
-
        /* download firmware */
        if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) {
                ret = af9013_download_firmware(state);
@@ -1495,6 +1476,20 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
        }
        info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
 
+       /* chip version */
+       ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]);
+       if (ret)
+               goto error;
+
+       /* ROM version */
+       for (i = 0; i < 2; i++) {
+               ret = af9013_read_reg(state, 0x116b + i, &buf[i]);
+               if (ret)
+                       goto error;
+       }
+       deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__,
+               buf[2], buf[0], buf[1]);
+
        /* settings for mp2if */
        if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
                /* AF9015 split PSB to 1.5k + 0.5k */
index 65240b7801e83c9dbfed88aa03ec1ea0eb94ff28..52ff1a252a907186e4086a6bf9b0f606f215bfa7 100644 (file)
@@ -45,6 +45,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
        } \
 } while (0)
 
+#define CONFIG_SYS_DVBT
 #define CONFIG_SYS_ISDBT
 #define CONFIG_BAND_CBAND
 #define CONFIG_BAND_VHF
@@ -76,6 +77,34 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 #define EN_SBD          0x44E9
 #define EN_CAB          0x88E9
 
+/* Calibration defines */
+#define      DC_CAL 0x1
+#define     WBD_CAL 0x2
+#define    TEMP_CAL 0x4
+#define CAPTRIM_CAL 0x8
+
+#define KROSUS_PLL_LOCKED   0x800
+#define KROSUS              0x2
+
+/* Use those defines to identify SOC version */
+#define SOC               0x02
+#define SOC_7090_P1G_11R1 0x82
+#define SOC_7090_P1G_21R1 0x8a
+#define SOC_8090_P1G_11R1 0x86
+#define SOC_8090_P1G_21R1 0x8e
+
+/* else use thos ones to check */
+#define P1A_B      0x0
+#define P1C       0x1
+#define P1D_E_F    0x3
+#define P1G       0x7
+#define P1G_21R2   0xf
+
+#define MP001 0x1              /* Single 9090/8096 */
+#define MP005 0x4              /* Single Sband */
+#define MP008 0x6              /* Dual diversity VHF-UHF-LBAND */
+#define MP009 0x7              /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
+
 #define pgm_read_word(w) (*w)
 
 struct dc_calibration;
@@ -84,7 +113,7 @@ struct dib0090_tuning {
        u32 max_freq;           /* for every frequency less than or equal to that field: this information is correct */
        u8 switch_trim;
        u8 lna_tune;
-       u8 lna_bias;
+       u16 lna_bias;
        u16 v2i;
        u16 mix;
        u16 load;
@@ -99,13 +128,19 @@ struct dib0090_pll {
        u8 topresc;
 };
 
+struct dib0090_identity {
+       u8 version;
+       u8 product;
+       u8 p1g;
+       u8 in_soc;
+};
+
 struct dib0090_state {
        struct i2c_adapter *i2c;
        struct dvb_frontend *fe;
        const struct dib0090_config *config;
 
        u8 current_band;
-       u16 revision;
        enum frontend_tune_state tune_state;
        u32 current_rf;
 
@@ -143,7 +178,26 @@ struct dib0090_state {
        u8 tuner_is_tuned;
        u8 agc_freeze;
 
-       u8 reset;
+       struct dib0090_identity identity;
+
+       u32 rf_request;
+       u8 current_standard;
+
+       u8 calibrate;
+       u32 rest;
+       u16 bias;
+       s16 temperature;
+
+       u8 wbd_calibration_gain;
+       const struct dib0090_wbd_slope *current_wbd_table;
+       u16 wbdmux;
+};
+
+struct dib0090_fw_state {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe;
+       struct dib0090_identity identity;
+       const struct dib0090_config *config;
 };
 
 static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
@@ -171,6 +225,28 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
        return 0;
 }
 
+static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+{
+       u8 b[2];
+       struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
+       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C read failed\n");
+               return 0;
+       }
+       return (b[0] << 8) | b[1];
+}
+
+static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+{
+       u8 b[2] = { val >> 8, val & 0xff };
+       struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
+       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C write failed\n");
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
 #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
 #define ADC_TARGET -220
 #define GAIN_ALPHA 5
@@ -183,89 +259,327 @@ static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b,
        } while (--c);
 }
 
-static u16 dib0090_identify(struct dvb_frontend *fe)
+static int dib0090_identify(struct dvb_frontend *fe)
 {
        struct dib0090_state *state = fe->tuner_priv;
        u16 v;
+       struct dib0090_identity *identity = &state->identity;
 
        v = dib0090_read_reg(state, 0x1a);
 
-#ifdef FIRMWARE_FIREFLY
-       /* pll is not locked locked */
-       if (!(v & 0x800))
-               dprintk("FE%d : Identification : pll is not yet locked", fe->id);
-#endif
+       identity->p1g = 0;
+       identity->in_soc = 0;
+
+       dprintk("Tuner identification (Version = 0x%04x)", v);
 
        /* without PLL lock info */
-       v &= 0x3ff;
-       dprintk("P/V: %04x:", v);
+       v &= ~KROSUS_PLL_LOCKED;
 
-       if ((v >> 8) & 0xf)
-               dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf);
-       else
-               return 0xff;
-
-       v &= 0xff;
-       if (((v >> 5) & 0x7) == 0x1)
-               dprintk("FE%d : MP001 : 9090/8096", fe->id);
-       else if (((v >> 5) & 0x7) == 0x4)
-               dprintk("FE%d : MP005 : Single Sband", fe->id);
-       else if (((v >> 5) & 0x7) == 0x6)
-               dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id);
-       else if (((v >> 5) & 0x7) == 0x7)
-               dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id);
-       else
-               return 0xff;
-
-       /* revision only */
-       if ((v & 0x1f) == 0x3)
-               dprintk("FE%d : P1-D/E/F detected", fe->id);
-       else if ((v & 0x1f) == 0x1)
-               dprintk("FE%d : P1C detected", fe->id);
-       else if ((v & 0x1f) == 0x0) {
-#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
-               dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id);
-               dib0090_p1b_register(fe);
-#else
-               dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id);
-               return 0xff;
-#endif
+       identity->version = v & 0xff;
+       identity->product = (v >> 8) & 0xf;
+
+       if (identity->product != KROSUS)
+               goto identification_error;
+
+       if ((identity->version & 0x3) == SOC) {
+               identity->in_soc = 1;
+               switch (identity->version) {
+               case SOC_8090_P1G_11R1:
+                       dprintk("SOC 8090 P1-G11R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_8090_P1G_21R1:
+                       dprintk("SOC 8090 P1-G21R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_7090_P1G_11R1:
+                       dprintk("SOC 7090 P1-G11R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_7090_P1G_21R1:
+                       dprintk("SOC 7090 P1-G21R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               default:
+                       goto identification_error;
+               }
+       } else {
+               switch ((identity->version >> 5) & 0x7) {
+               case MP001:
+                       dprintk("MP001 : 9090/8096");
+                       break;
+               case MP005:
+                       dprintk("MP005 : Single Sband");
+                       break;
+               case MP008:
+                       dprintk("MP008 : diversity VHF-UHF-LBAND");
+                       break;
+               case MP009:
+                       dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
+                       break;
+               default:
+                       goto identification_error;
+               }
+
+               switch (identity->version & 0x1f) {
+               case P1G_21R2:
+                       dprintk("P1G_21R2 detected");
+                       identity->p1g = 1;
+                       break;
+               case P1G:
+                       dprintk("P1G detected");
+                       identity->p1g = 1;
+                       break;
+               case P1D_E_F:
+                       dprintk("P1D/E/F detected");
+                       break;
+               case P1C:
+                       dprintk("P1C detected");
+                       break;
+               case P1A_B:
+                       dprintk("P1-A/B detected: driver is deactivated - not available");
+                       goto identification_error;
+                       break;
+               default:
+                       goto identification_error;
+               }
+       }
+
+       return 0;
+
+identification_error:
+       return -EIO;
+}
+
+static int dib0090_fw_identify(struct dvb_frontend *fe)
+{
+       struct dib0090_fw_state *state = fe->tuner_priv;
+       struct dib0090_identity *identity = &state->identity;
+
+       u16 v = dib0090_fw_read_reg(state, 0x1a);
+       identity->p1g = 0;
+       identity->in_soc = 0;
+
+       dprintk("FE: Tuner identification (Version = 0x%04x)", v);
+
+       /* without PLL lock info */
+       v &= ~KROSUS_PLL_LOCKED;
+
+       identity->version = v & 0xff;
+       identity->product = (v >> 8) & 0xf;
+
+       if (identity->product != KROSUS)
+               goto identification_error;
+
+       if ((identity->version & 0x3) == SOC) {
+               identity->in_soc = 1;
+               switch (identity->version) {
+               case SOC_8090_P1G_11R1:
+                       dprintk("SOC 8090 P1-G11R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_8090_P1G_21R1:
+                       dprintk("SOC 8090 P1-G21R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_7090_P1G_11R1:
+                       dprintk("SOC 7090 P1-G11R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               case SOC_7090_P1G_21R1:
+                       dprintk("SOC 7090 P1-G21R1 Has been detected");
+                       identity->p1g = 1;
+                       break;
+               default:
+                       goto identification_error;
+               }
+       } else {
+               switch ((identity->version >> 5) & 0x7) {
+               case MP001:
+                       dprintk("MP001 : 9090/8096");
+                       break;
+               case MP005:
+                       dprintk("MP005 : Single Sband");
+                       break;
+               case MP008:
+                       dprintk("MP008 : diversity VHF-UHF-LBAND");
+                       break;
+               case MP009:
+                       dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
+                       break;
+               default:
+                       goto identification_error;
+               }
+
+               switch (identity->version & 0x1f) {
+               case P1G_21R2:
+                       dprintk("P1G_21R2 detected");
+                       identity->p1g = 1;
+                       break;
+               case P1G:
+                       dprintk("P1G detected");
+                       identity->p1g = 1;
+                       break;
+               case P1D_E_F:
+                       dprintk("P1D/E/F detected");
+                       break;
+               case P1C:
+                       dprintk("P1C detected");
+                       break;
+               case P1A_B:
+                       dprintk("P1-A/B detected: driver is deactivated - not available");
+                       goto identification_error;
+                       break;
+               default:
+                       goto identification_error;
+               }
        }
 
-       return v;
+       return 0;
+
+identification_error:
+       return -EIO;;
 }
 
 static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
 {
        struct dib0090_state *state = fe->tuner_priv;
+       u16 PllCfg, i, v;
 
        HARD_RESET(state);
 
-       dib0090_write_reg(state, 0x24, EN_PLL);
+       dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
        dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);        /* PLL, DIG_CLK and CRYSTAL remain */
 
-       /* adcClkOutRatio=8->7, release reset */
-       dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+       if (!cfg->in_soc) {
+               /* adcClkOutRatio=8->7, release reset */
+               dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+               if (cfg->clkoutdrive != 0)
+                       dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+                                         | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+               else
+                       dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+                                         | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+       }
+
+       /* Read Pll current config * */
+       PllCfg = dib0090_read_reg(state, 0x21);
+
+       /** Reconfigure PLL if current setting is different from default setting **/
+       if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
+                       && !cfg->io.pll_bypass) {
+
+               /* Set Bypass mode */
+               PllCfg |= (1 << 15);
+               dib0090_write_reg(state, 0x21, PllCfg);
+
+               /* Set Reset Pll */
+               PllCfg &= ~(1 << 13);
+               dib0090_write_reg(state, 0x21, PllCfg);
+
+       /*** Set new Pll configuration in bypass and reset state ***/
+               PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
+               dib0090_write_reg(state, 0x21, PllCfg);
+
+               /* Remove Reset Pll */
+               PllCfg |= (1 << 13);
+               dib0090_write_reg(state, 0x21, PllCfg);
+
+       /*** Wait for PLL lock ***/
+               i = 100;
+               do {
+                       v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
+                       if (v)
+                               break;
+               } while (--i);
+
+               if (i == 0) {
+                       dprintk("Pll: Unable to lock Pll");
+                       return;
+               }
+
+               /* Finally Remove Bypass mode */
+               PllCfg &= ~(1 << 15);
+               dib0090_write_reg(state, 0x21, PllCfg);
+       }
+
+       if (cfg->io.pll_bypass) {
+               PllCfg |= (cfg->io.pll_bypass << 15);
+               dib0090_write_reg(state, 0x21, PllCfg);
+       }
+}
+
+static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
+{
+       struct dib0090_fw_state *state = fe->tuner_priv;
+       u16 PllCfg;
+       u16 v;
+       int i;
+
+       dprintk("fw reset digital");
+       HARD_RESET(state);
+
+       dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
+       dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL);     /* PLL, DIG_CLK and CRYSTAL remain */
+
+       dib0090_fw_write_reg(state, 0x20,
+                       ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
+
+       v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
        if (cfg->clkoutdrive != 0)
-               dib0090_write_reg(state, 0x23,
-                                 (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg->
-                                                                                                                                          clkouttobamse
-                                                                                                                                          << 4) | (0
-                                                                                                                                                   <<
-                                                                                                                                                   2)
-                                 | (0));
+               v |= cfg->clkoutdrive << 5;
        else
-               dib0090_write_reg(state, 0x23,
-                                 (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg->
-                                                                                                                           clkouttobamse << 4) | (0
-                                                                                                                                                  <<
-                                                                                                                                                  2)
-                                 | (0));
+               v |= 7 << 5;
+
+       v |= 2 << 10;
+       dib0090_fw_write_reg(state, 0x23, v);
+
+       /* Read Pll current config * */
+       PllCfg = dib0090_fw_read_reg(state, 0x21);
 
-       /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */
-       dib0090_write_reg(state, 0x21,
-                         (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv));
+       /** Reconfigure PLL if current setting is different from default setting **/
+       if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
 
+               /* Set Bypass mode */
+               PllCfg |= (1 << 15);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+               /* Set Reset Pll */
+               PllCfg &= ~(1 << 13);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+       /*** Set new Pll configuration in bypass and reset state ***/
+               PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+               /* Remove Reset Pll */
+               PllCfg |= (1 << 13);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+
+       /*** Wait for PLL lock ***/
+               i = 100;
+               do {
+                       v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
+                       if (v)
+                               break;
+               } while (--i);
+
+               if (i == 0) {
+                       dprintk("Pll: Unable to lock Pll");
+                       return -EIO;
+               }
+
+               /* Finally Remove Bypass mode */
+               PllCfg &= ~(1 << 15);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+       }
+
+       if (cfg->io.pll_bypass) {
+               PllCfg |= (cfg->io.pll_bypass << 15);
+               dib0090_fw_write_reg(state, 0x21, PllCfg);
+       }
+
+       return dib0090_fw_identify(fe);
 }
 
 static int dib0090_wakeup(struct dvb_frontend *fe)
@@ -273,6 +587,9 @@ static int dib0090_wakeup(struct dvb_frontend *fe)
        struct dib0090_state *state = fe->tuner_priv;
        if (state->config->sleep)
                state->config->sleep(fe, 0);
+
+       /* enable dataTX in case we have been restarted in the wrong moment */
+       dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
        return 0;
 }
 
@@ -292,8 +609,75 @@ void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
        else
                dib0090_write_reg(state, 0x04, 1);
 }
+
 EXPORT_SYMBOL(dib0090_dcc_freq);
 
+static const u16 bb_ramp_pwm_normal_socs[] = {
+       550,                    /* max BB gain in 10th of dB */
+       (1 << 9) | 8,           /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+       440,
+       (4 << 9) | 0,           /* BB_RAMP3 = 26dB */
+       (0 << 9) | 208,         /* BB_RAMP4 */
+       (4 << 9) | 208,         /* BB_RAMP5 = 29dB */
+       (0 << 9) | 440,         /* BB_RAMP6 */
+};
+
+static const u16 rf_ramp_pwm_cband_7090[] = {
+       280,                    /* max RF gain in 10th of dB */
+       18,                     /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+       504,                    /* ramp_max = maximum X used on the ramp */
+       (29 << 10) | 364,       /* RF_RAMP5, LNA 1 = 8dB */
+       (0 << 10) | 504,        /* RF_RAMP6, LNA 1 */
+       (60 << 10) | 228,       /* RF_RAMP7, LNA 2 = 7.7dB */
+       (0 << 10) | 364,        /* RF_RAMP8, LNA 2 */
+       (34 << 10) | 109,       /* GAIN_4_1, LNA 3 = 6.8dB */
+       (0 << 10) | 228,        /* GAIN_4_2, LNA 3 */
+       (37 << 10) | 0,         /* RF_RAMP3, LNA 4 = 6.2dB */
+       (0 << 10) | 109,        /* RF_RAMP4, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_cband_8090[] = {
+       345,                    /* max RF gain in 10th of dB */
+       29,                     /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+       1000,                   /* ramp_max = maximum X used on the ramp */
+       (35 << 10) | 772,       /* RF_RAMP3, LNA 1 = 8dB */
+       (0 << 10) | 1000,       /* RF_RAMP4, LNA 1 */
+       (58 << 10) | 496,       /* RF_RAMP5, LNA 2 = 9.5dB */
+       (0 << 10) | 772,        /* RF_RAMP6, LNA 2 */
+       (27 << 10) | 200,       /* RF_RAMP7, LNA 3 = 10.5dB */
+       (0 << 10) | 496,        /* RF_RAMP8, LNA 3 */
+       (40 << 10) | 0,         /* GAIN_4_1, LNA 4 = 7dB */
+       (0 << 10) | 200,        /* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf_7090[] = {
+       407,                    /* max RF gain in 10th of dB */
+       13,                     /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+       529,                    /* ramp_max = maximum X used on the ramp */
+       (23 << 10) | 0,         /* RF_RAMP3, LNA 1 = 14.7dB */
+       (0 << 10) | 176,        /* RF_RAMP4, LNA 1 */
+       (63 << 10) | 400,       /* RF_RAMP5, LNA 2 = 8dB */
+       (0 << 10) | 529,        /* RF_RAMP6, LNA 2 */
+       (48 << 10) | 316,       /* RF_RAMP7, LNA 3 = 6.8dB */
+       (0 << 10) | 400,        /* RF_RAMP8, LNA 3 */
+       (29 << 10) | 176,       /* GAIN_4_1, LNA 4 = 11.5dB */
+       (0 << 10) | 316,        /* GAIN_4_2, LNA 4 */
+};
+
+static const u16 rf_ramp_pwm_uhf_8090[] = {
+       388,                    /* max RF gain in 10th of dB */
+       26,                     /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+       1008,                   /* ramp_max = maximum X used on the ramp */
+       (11 << 10) | 0,         /* RF_RAMP3, LNA 1 = 14.7dB */
+       (0 << 10) | 369,        /* RF_RAMP4, LNA 1 */
+       (41 << 10) | 809,       /* RF_RAMP5, LNA 2 = 8dB */
+       (0 << 10) | 1008,       /* RF_RAMP6, LNA 2 */
+       (27 << 10) | 659,       /* RF_RAMP7, LNA 3 = 6dB */
+       (0 << 10) | 809,        /* RF_RAMP8, LNA 3 */
+       (14 << 10) | 369,       /* GAIN_4_1, LNA 4 = 11.5dB */
+       (0 << 10) | 659,        /* GAIN_4_2, LNA 4 */
+};
+
 static const u16 rf_ramp_pwm_cband[] = {
        0,                      /* max RF gain in 10th of dB */
        0,                      /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
@@ -326,6 +710,16 @@ static const u16 rf_ramp_uhf[] = {
        0, 0, 127,              /* CBAND :  0.0 dB */
 };
 
+static const u16 rf_ramp_cband_broadmatching[] =       /* for p1G only */
+{
+       314,                    /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
+       84, 314, 127,           /* LNA1 */
+       80, 230, 255,           /* LNA2 */
+       80, 150, 127,           /* LNA3  It was measured 12dB, do not lock if 120 */
+       70, 70, 127,            /* LNA4 */
+       0, 0, 127,              /* CBAND */
+};
+
 static const u16 rf_ramp_cband[] = {
        332,                    /* max RF gain in 10th of dB */
        132, 252, 127,          /* LNA1,  dB */
@@ -380,8 +774,8 @@ static const u16 bb_ramp_pwm_normal[] = {
 };
 
 struct slope {
-       int16_t range;
-       int16_t slope;
+       s16 range;
+       s16 slope;
 };
 static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
 {
@@ -597,19 +991,39 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
 #endif
 #ifdef CONFIG_BAND_CBAND
                if (state->current_band == BAND_CBAND) {
-                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
-                       dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       if (state->identity.in_soc) {
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+                               if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
+                               else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+                       } else {
+                               dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       }
                } else
 #endif
 #ifdef CONFIG_BAND_VHF
                if (state->current_band == BAND_VHF) {
-                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
-                       dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       if (state->identity.in_soc) {
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+                       } else {
+                               dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       }
                } else
 #endif
                {
-                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
-                       dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       if (state->identity.in_soc) {
+                               if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
+                               else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+                                       dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+                       } else {
+                               dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
+                               dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+                       }
                }
 
                if (state->rf_ramp[0] != 0)
@@ -617,11 +1031,21 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
                else
                        dib0090_write_reg(state, 0x32, (0 << 11));
 
+               dib0090_write_reg(state, 0x04, 0x01);
                dib0090_write_reg(state, 0x39, (1 << 10));
        }
 }
+
 EXPORT_SYMBOL(dib0090_pwm_gain_reset);
 
+static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
+{
+       u16 adc_val = dib0090_read_reg(state, 0x1d);
+       if (state->identity.in_soc)
+               adc_val >>= 2;
+       return adc_val;
+}
+
 int dib0090_gain_control(struct dvb_frontend *fe)
 {
        struct dib0090_state *state = fe->tuner_priv;
@@ -643,18 +1067,21 @@ int dib0090_gain_control(struct dvb_frontend *fe)
                } else
 #endif
 #ifdef CONFIG_BAND_VHF
-               if (state->current_band == BAND_VHF) {
+               if (state->current_band == BAND_VHF && !state->identity.p1g) {
                        dib0090_set_rframp(state, rf_ramp_vhf);
                        dib0090_set_bbramp(state, bb_ramp_boost);
                } else
 #endif
 #ifdef CONFIG_BAND_CBAND
-               if (state->current_band == BAND_CBAND) {
+               if (state->current_band == BAND_CBAND && !state->identity.p1g) {
                        dib0090_set_rframp(state, rf_ramp_cband);
                        dib0090_set_bbramp(state, bb_ramp_boost);
                } else
 #endif
-               {
+               if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
+                       dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
+                       dib0090_set_bbramp(state, bb_ramp_boost);
+               } else {
                        dib0090_set_rframp(state, rf_ramp_uhf);
                        dib0090_set_bbramp(state, bb_ramp_boost);
                }
@@ -669,17 +1096,25 @@ int dib0090_gain_control(struct dvb_frontend *fe)
 
                *tune_state = CT_AGC_STEP_0;
        } else if (!state->agc_freeze) {
-               s16 wbd;
+               s16 wbd = 0, i, cnt;
 
                int adc;
-               wbd_val = dib0090_read_reg(state, 0x1d);
+               wbd_val = dib0090_get_slow_adc_val(state);
+
+               if (*tune_state == CT_AGC_STEP_0)
+                       cnt = 5;
+               else
+                       cnt = 1;
 
-               /* read and calc the wbd power */
-               wbd = dib0090_wbd_to_db(state, wbd_val);
+               for (i = 0; i < cnt; i++) {
+                       wbd_val = dib0090_get_slow_adc_val(state);
+                       wbd += dib0090_wbd_to_db(state, wbd_val);
+               }
+               wbd /= cnt;
                wbd_error = state->wbd_target - wbd;
 
                if (*tune_state == CT_AGC_STEP_0) {
-                       if (wbd_error < 0 && state->rf_gain_limit > 0) {
+                       if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
 #ifdef CONFIG_BAND_CBAND
                                /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
                                u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
@@ -700,39 +1135,39 @@ int dib0090_gain_control(struct dvb_frontend *fe)
                        adc_error = (s16) (((s32) ADC_TARGET) - adc);
 #ifdef CONFIG_STANDARD_DAB
                        if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
-                               adc_error += 130;
+                               adc_error -= 10;
 #endif
 #ifdef CONFIG_STANDARD_DVBT
                        if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
-                           (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
+                                       (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
                                adc_error += 60;
 #endif
 #ifdef CONFIG_SYS_ISDBT
                        if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
-                                                                                              0)
-                                                                                             &&
-                                                                                             ((state->fe->dtv_property_cache.layer[0].modulation ==
-                                                                                               QAM_64)
-                                                                                              || (state->fe->dtv_property_cache.layer[0].
-                                                                                                  modulation == QAM_16)))
-                                                                                            ||
-                                                                                            ((state->fe->dtv_property_cache.layer[1].segment_count >
-                                                                                              0)
-                                                                                             &&
-                                                                                             ((state->fe->dtv_property_cache.layer[1].modulation ==
-                                                                                               QAM_64)
-                                                                                              || (state->fe->dtv_property_cache.layer[1].
-                                                                                                  modulation == QAM_16)))
-                                                                                            ||
-                                                                                            ((state->fe->dtv_property_cache.layer[2].segment_count >
-                                                                                              0)
-                                                                                             &&
-                                                                                             ((state->fe->dtv_property_cache.layer[2].modulation ==
-                                                                                               QAM_64)
-                                                                                              || (state->fe->dtv_property_cache.layer[2].
-                                                                                                  modulation == QAM_16)))
-                           )
-                           )
+                                                               0)
+                                                       &&
+                                                       ((state->fe->dtv_property_cache.layer[0].modulation ==
+                                                         QAM_64)
+                                                        || (state->fe->dtv_property_cache.
+                                                                layer[0].modulation == QAM_16)))
+                                               ||
+                                               ((state->fe->dtv_property_cache.layer[1].segment_count >
+                                                 0)
+                                                &&
+                                                ((state->fe->dtv_property_cache.layer[1].modulation ==
+                                                  QAM_64)
+                                                 || (state->fe->dtv_property_cache.
+                                                         layer[1].modulation == QAM_16)))
+                                               ||
+                                               ((state->fe->dtv_property_cache.layer[2].segment_count >
+                                                 0)
+                                                &&
+                                                ((state->fe->dtv_property_cache.layer[2].modulation ==
+                                                  QAM_64)
+                                                 || (state->fe->dtv_property_cache.
+                                                         layer[2].modulation == QAM_16)))
+                                               )
+                               )
                                adc_error += 60;
 #endif
 
@@ -760,9 +1195,9 @@ int dib0090_gain_control(struct dvb_frontend *fe)
                }
 #ifdef DEBUG_AGC
                dprintk
-                   ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
-                    (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
-                    (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
+                       ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
+                        (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
+                        (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
 #endif
        }
 
@@ -771,6 +1206,7 @@ int dib0090_gain_control(struct dvb_frontend *fe)
                dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
        return ret;
 }
+
 EXPORT_SYMBOL(dib0090_gain_control);
 
 void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
@@ -785,13 +1221,47 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 *
        if (rflt)
                *rflt = (state->rf_lt_def >> 10) & 0x7;
 }
+
 EXPORT_SYMBOL(dib0090_get_current_gain);
 
-u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner)
+u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
 {
-       struct dib0090_state *st = tuner->tuner_priv;
-       return st->wbd_offset;
+       struct dib0090_state *state = fe->tuner_priv;
+       u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
+       s32 current_temp = state->temperature;
+       s32 wbd_thot, wbd_tcold;
+       const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
+
+       while (f_MHz > wbd->max_freq)
+               wbd++;
+
+       dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
+
+       if (current_temp < 0)
+               current_temp = 0;
+       if (current_temp > 128)
+               current_temp = 128;
+
+       state->wbdmux &= ~(7 << 13);
+       if (wbd->wbd_gain != 0)
+               state->wbdmux |= (wbd->wbd_gain << 13);
+       else
+               state->wbdmux |= (4 << 13);
+
+       dib0090_write_reg(state, 0x10, state->wbdmux);
+
+       wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
+       wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
+
+       wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
+
+       state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
+       dprintk("wbd-target: %d dB", (u32) state->wbd_target);
+       dprintk("wbd offset applied is %d", wbd_tcold);
+
+       return state->wbd_offset + wbd_tcold;
 }
+
 EXPORT_SYMBOL(dib0090_get_wbd_offset);
 
 static const u16 dib0090_defaults[] = {
@@ -801,7 +1271,7 @@ static const u16 dib0090_defaults[] = {
        0x99a0,
        0x6008,
        0x0000,
-       0x8acb,
+       0x8bcb,
        0x0000,
        0x0405,
        0x0000,
@@ -829,8 +1299,6 @@ static const u16 dib0090_defaults[] = {
        1, 0x39,
        0x0000,
 
-       1, 0x1b,
-       EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL,
        2, 0x1e,
        0x07FF,
        0x0007,
@@ -844,50 +1312,125 @@ static const u16 dib0090_defaults[] = {
        0
 };
 
-static int dib0090_reset(struct dvb_frontend *fe)
-{
-       struct dib0090_state *state = fe->tuner_priv;
-       u16 l, r, *n;
+static const u16 dib0090_p1g_additionnal_defaults[] = {
+       1, 0x05,
+       0xabcd,
 
-       dib0090_reset_digital(fe, state->config);
-       state->revision = dib0090_identify(fe);
+       1, 0x11,
+       0x00b4,
 
-       /* Revision definition */
-       if (state->revision == 0xff)
-               return -EINVAL;
-#ifdef EFUSE
-       else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */
-               dib0090_set_EFUSE(state);
-#endif
+       1, 0x1c,
+       0xfffd,
 
-#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
-       if (!(state->revision & 0x1))   /* it is P1B - reset is already done */
-               return 0;
-#endif
+       1, 0x40,
+       0x108,
+       0
+};
+
+static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
+{
+       u16 l, r;
 
-       /* Upload the default values */
-       n = (u16 *) dib0090_defaults;
        l = pgm_read_word(n++);
        while (l) {
                r = pgm_read_word(n++);
                do {
-                       /* DEBUG_TUNER */
-                       /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */
                        dib0090_write_reg(state, r, pgm_read_word(n++));
                        r++;
                } while (--l);
                l = pgm_read_word(n++);
        }
+}
+
+#define CAP_VALUE_MIN (u8)  9
+#define CAP_VALUE_MAX (u8) 40
+#define HR_MIN       (u8) 25
+#define HR_MAX       (u8) 40
+#define POLY_MIN      (u8)  0
+#define POLY_MAX      (u8)  8
+
+void dib0090_set_EFUSE(struct dib0090_state *state)
+{
+       u8 c, h, n;
+       u16 e2, e4;
+       u16 cal;
+
+       e2 = dib0090_read_reg(state, 0x26);
+       e4 = dib0090_read_reg(state, 0x28);
+
+       if ((state->identity.version == P1D_E_F) ||
+                       (state->identity.version == P1G) || (e2 == 0xffff)) {
+
+               dib0090_write_reg(state, 0x22, 0x10);
+               cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
+
+               if ((cal < 670) || (cal == 1023))
+                       cal = 850;
+               n = 165 - ((cal * 10)>>6) ;
+               e2 = e4 = (3<<12) | (34<<6) | (n);
+       }
+
+       if (e2 != e4)
+               e2 &= e4; /* Remove the redundancy  */
+
+       if (e2 != 0xffff) {
+               c = e2 & 0x3f;
+               n = (e2 >> 12) & 0xf;
+               h = (e2 >> 6) & 0x3f;
+
+               if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
+                       c = 32;
+               if ((h >= HR_MAX) || (h <= HR_MIN))
+                       h = 34;
+               if ((n >= POLY_MAX) || (n <= POLY_MIN))
+                       n = 3;
+
+               dib0090_write_reg(state, 0x13, (h << 10)) ;
+               e2 = (n<<11) | ((h>>2)<<6) | (c);
+               dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
+       }
+}
+
+static int dib0090_reset(struct dvb_frontend *fe)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+
+       dib0090_reset_digital(fe, state->config);
+       if (dib0090_identify(fe) < 0)
+               return -EIO;
+
+#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
+       if (!(state->identity.version & 0x1))   /* it is P1B - reset is already done */
+               return 0;
+#endif
+
+       if (!state->identity.in_soc) {
+               if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
+                       dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
+               else
+                       dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
+       }
+
+       dib0090_set_default_config(state, dib0090_defaults);
+
+       if (state->identity.in_soc)
+               dib0090_write_reg(state, 0x18, 0x2910);  /* charge pump current = 0 */
+
+       if (state->identity.p1g)
+               dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
+
+       /* Update the efuse : Only available for KROSUS > P1C  and SOC as well*/
+       if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
+               dib0090_set_EFUSE(state);
 
        /* Congigure in function of the crystal */
        if (state->config->io.clock_khz >= 24000)
-               l = 1;
+               dib0090_write_reg(state, 0x14, 1);
        else
-               l = 2;
-       dib0090_write_reg(state, 0x14, l);
+               dib0090_write_reg(state, 0x14, 2);
        dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
 
-       state->reset = 3;       /* enable iq-offset-calibration and wbd-calibration when tuning next time */
+       state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */
 
        return 0;
 }
@@ -927,11 +1470,11 @@ static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_st
 }
 
 struct dc_calibration {
-       uint8_t addr;
-       uint8_t offset;
-       uint8_t pga:1;
-       uint16_t bb1;
-       uint8_t i:1;
+       u8 addr;
+       u8 offset;
+       u8 pga:1;
+       u16 bb1;
+       u8 i:1;
 };
 
 static const struct dc_calibration dc_table[] = {
@@ -944,6 +1487,17 @@ static const struct dc_calibration dc_table[] = {
        {0},
 };
 
+static const struct dc_calibration dc_p1g_table[] = {
+       /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
+       /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
+       {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
+       {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
+       /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
+       {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
+       {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
+       {0},
+};
+
 static void dib0090_set_trim(struct dib0090_state *state)
 {
        u16 *val;
@@ -962,41 +1516,45 @@ static void dib0090_set_trim(struct dib0090_state *state)
 static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
 {
        int ret = 0;
+       u16 reg;
 
        switch (*tune_state) {
-
        case CT_TUNER_START:
-               /* init */
-               dprintk("Internal DC calibration");
-
-               /* the LNA is off */
-               dib0090_write_reg(state, 0x24, 0x02ed);
+               dprintk("Start DC offset calibration");
 
                /* force vcm2 = 0.8V */
                state->bb6 = 0;
                state->bb7 = 0x040d;
 
+               /* the LNA AND LO are off */
+               reg = dib0090_read_reg(state, 0x24) & 0x0ffb;   /* shutdown lna and lo */
+               dib0090_write_reg(state, 0x24, reg);
+
+               state->wbdmux = dib0090_read_reg(state, 0x10);
+               dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
+               dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
+
                state->dc = dc_table;
 
+               if (state->identity.p1g)
+                       state->dc = dc_p1g_table;
                *tune_state = CT_TUNER_STEP_0;
 
                /* fall through */
 
        case CT_TUNER_STEP_0:
+               dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
                dib0090_write_reg(state, 0x01, state->dc->bb1);
                dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
 
                state->step = 0;
-
                state->min_adc_diff = 1023;
-
                *tune_state = CT_TUNER_STEP_1;
                ret = 50;
                break;
 
        case CT_TUNER_STEP_1:
                dib0090_set_trim(state);
-
                *tune_state = CT_TUNER_STEP_2;
                break;
 
@@ -1007,7 +1565,13 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
                break;
 
        case CT_TUNER_STEP_5:   /* found an offset */
-               dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step);
+               dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
+               if (state->step == 0 && state->adc_diff < 0) {
+                       state->min_adc_diff = -1023;
+                       dprintk("Change of sign of the minimum adc diff");
+               }
+
+               dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
 
                /* first turn for this frequency */
                if (state->step == 0) {
@@ -1017,20 +1581,21 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
                                state->step = 0x10;
                }
 
-               state->adc_diff = ABS(state->adc_diff);
-
-               if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */
+               /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
+               if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
+                       /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
                        state->step++;
                        state->min_adc_diff = state->adc_diff;
                        *tune_state = CT_TUNER_STEP_1;
                } else {
-
                        /* the minimum was what we have seen in the step before */
-                       state->step--;
-                       dib0090_set_trim(state);
+                       if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
+                               dprintk("Since adc_diff N = %d  > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
+                               state->step--;
+                       }
 
-                       dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff,
-                               state->step);
+                       dib0090_set_trim(state);
+                       dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
 
                        state->dc++;
                        if (state->dc->addr == 0)       /* done */
@@ -1045,7 +1610,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
                dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
                dib0090_write_reg(state, 0x1f, 0x7);
                *tune_state = CT_TUNER_START;   /* reset done -> real tuning can now begin */
-               state->reset &= ~0x1;
+               state->calibrate &= ~DC_CAL;
        default:
                break;
        }
@@ -1054,21 +1619,43 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front
 
 static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
 {
+       u8 wbd_gain;
+       const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
+
        switch (*tune_state) {
        case CT_TUNER_START:
-               /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */
-               dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10));
-               dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff);
+               while (state->current_rf / 1000 > wbd->max_freq)
+                       wbd++;
+               if (wbd->wbd_gain != 0)
+                       wbd_gain = wbd->wbd_gain;
+               else {
+                       wbd_gain = 4;
+#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
+                       if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
+                               wbd_gain = 2;
+#endif
+               }
+
+               if (wbd_gain == state->wbd_calibration_gain) {  /* the WBD calibration has already been done */
+                       *tune_state = CT_TUNER_START;
+                       state->calibrate &= ~WBD_CAL;
+                       return 0;
+               }
 
+               dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
+
+               dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
                *tune_state = CT_TUNER_STEP_0;
+               state->wbd_calibration_gain = wbd_gain;
                return 90;      /* wait for the WBDMUX to switch and for the ADC to sample */
+
        case CT_TUNER_STEP_0:
-               state->wbd_offset = dib0090_read_reg(state, 0x1d);
+               state->wbd_offset = dib0090_get_slow_adc_val(state);
                dprintk("WBD calibration offset = %d", state->wbd_offset);
-
                *tune_state = CT_TUNER_START;   /* reset done -> real tuning can now begin */
-               state->reset &= ~0x2;
+               state->calibrate &= ~WBD_CAL;
                break;
+
        default:
                break;
        }
@@ -1092,6 +1679,15 @@ static void dib0090_set_bandwidth(struct dib0090_state *state)
        state->bb_1_def |= tmp;
 
        dib0090_write_reg(state, 0x01, state->bb_1_def);        /* be sure that we have the right bb-filter */
+
+       dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
+       dib0090_write_reg(state, 0x04, 0x1);    /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
+       if (state->identity.in_soc) {
+               dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
+       } else {
+               dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f));     /* 22 = cap_value */
+               dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
+       }
 }
 
 static const struct dib0090_pll dib0090_pll_table[] = {
@@ -1180,95 +1776,388 @@ static const struct dib0090_tuning dib0090_tuning_table[] = {
 #endif
 };
 
-#define WBD     0x781          /* 1 1 1 1 0000 0 0 1 */
-static int dib0090_tune(struct dvb_frontend *fe)
-{
-       struct dib0090_state *state = fe->tuner_priv;
-       const struct dib0090_tuning *tune = state->current_tune_table_index;
-       const struct dib0090_pll *pll = state->current_pll_table_index;
+static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
+#ifdef CONFIG_BAND_CBAND
+       {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_VHF
+       {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+       {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+       {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
+#endif
+#ifdef CONFIG_BAND_UHF
+       {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+       {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+       {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+       {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+       {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+       {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_pll dib0090_p1g_pll_table[] = {
+#ifdef CONFIG_BAND_CBAND
+       {57000, 0, 11, 48, 6},
+       {70000, 1, 11, 48, 6},
+       {86000, 0, 10, 32, 4},
+       {105000, 1, 10, 32, 4},
+       {115000, 0, 9, 24, 6},
+       {140000, 1, 9, 24, 6},
+       {170000, 0, 8, 16, 4},
+#endif
+#ifdef CONFIG_BAND_VHF
+       {200000, 1, 8, 16, 4},
+       {230000, 0, 7, 12, 6},
+       {280000, 1, 7, 12, 6},
+       {340000, 0, 6, 8, 4},
+       {380000, 1, 6, 8, 4},
+       {455000, 0, 5, 6, 6},
+#endif
+#ifdef CONFIG_BAND_UHF
+       {580000, 1, 5, 6, 6},
+       {680000, 0, 4, 4, 4},
+       {860000, 1, 4, 4, 4},
+#endif
+#ifdef CONFIG_BAND_LBAND
+       {1800000, 1, 2, 2, 4},
+#endif
+#ifdef CONFIG_BAND_SBAND
+       {2900000, 0, 1, 1, 6},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
+#ifdef CONFIG_BAND_CBAND
+       {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+       {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+       {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
+#endif
+#ifdef CONFIG_BAND_UHF
+       {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+       {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
+#endif
+#ifdef CONFIG_BAND_LBAND
+       {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+       {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+       {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
+#endif
+#ifdef CONFIG_BAND_SBAND
+       {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
+       {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
+#endif
+};
+
+static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
+#ifdef CONFIG_BAND_CBAND
+       {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+       {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+       {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+       {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
+#endif
+};
+
+static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+       int ret = 0;
+       u16 lo4 = 0xe900;
+
+       s16 adc_target;
+       u16 adc;
+       s8 step_sign;
+       u8 force_soft_search = 0;
+
+       if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+               force_soft_search = 1;
+
+       if (*tune_state == CT_TUNER_START) {
+               dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
+               dib0090_write_reg(state, 0x10, 0x2B1);
+               dib0090_write_reg(state, 0x1e, 0x0032);
+
+               if (!state->tuner_is_tuned) {
+                       /* prepare a complete captrim */
+                       if (!state->identity.p1g || force_soft_search)
+                               state->step = state->captrim = state->fcaptrim = 64;
+
+                       state->current_rf = state->rf_request;
+               } else {        /* we are already tuned to this frequency - the configuration is correct  */
+                       if (!state->identity.p1g || force_soft_search) {
+                               /* do a minimal captrim even if the frequency has not changed */
+                               state->step = 4;
+                               state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
+                       }
+               }
+               state->adc_diff = 3000;
+               *tune_state = CT_TUNER_STEP_0;
+
+       } else if (*tune_state == CT_TUNER_STEP_0) {
+               if (state->identity.p1g && !force_soft_search) {
+                       u8 ratio = 31;
+
+                       dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
+                       dib0090_read_reg(state, 0x40);
+                       ret = 50;
+               } else {
+                       state->step /= 2;
+                       dib0090_write_reg(state, 0x18, lo4 | state->captrim);
+
+                       if (state->identity.in_soc)
+                               ret = 25;
+               }
+               *tune_state = CT_TUNER_STEP_1;
+
+       } else if (*tune_state == CT_TUNER_STEP_1) {
+               if (state->identity.p1g && !force_soft_search) {
+                       dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
+                       dib0090_read_reg(state, 0x40);
+
+                       state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
+                       dprintk("***Final Captrim= 0x%x", state->fcaptrim);
+                       *tune_state = CT_TUNER_STEP_3;
+
+               } else {
+                       /* MERGE for all krosus before P1G */
+                       adc = dib0090_get_slow_adc_val(state);
+                       dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
+
+                       if (state->rest == 0 || state->identity.in_soc) {       /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
+                               adc_target = 200;
+                       } else
+                               adc_target = 400;
+
+                       if (adc >= adc_target) {
+                               adc -= adc_target;
+                               step_sign = -1;
+                       } else {
+                               adc = adc_target - adc;
+                               step_sign = 1;
+                       }
+
+                       if (adc < state->adc_diff) {
+                               dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
+                               state->adc_diff = adc;
+                               state->fcaptrim = state->captrim;
+                       }
+
+                       state->captrim += step_sign * state->step;
+                       if (state->step >= 1)
+                               *tune_state = CT_TUNER_STEP_0;
+                       else
+                               *tune_state = CT_TUNER_STEP_2;
+
+                       ret = 25;
+               }
+       } else if (*tune_state == CT_TUNER_STEP_2) {    /* this step is only used by krosus < P1G */
+               /*write the final cptrim config */
+               dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
+
+               *tune_state = CT_TUNER_STEP_3;
+
+       } else if (*tune_state == CT_TUNER_STEP_3) {
+               state->calibrate &= ~CAPTRIM_CAL;
+               *tune_state = CT_TUNER_STEP_0;
+       }
+
+       return ret;
+}
+
+static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
+{
+       int ret = 15;
+       s16 val;
+
+       switch (*tune_state) {
+       case CT_TUNER_START:
+               state->wbdmux = dib0090_read_reg(state, 0x10);
+               dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
+
+               state->bias = dib0090_read_reg(state, 0x13);
+               dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
+
+               *tune_state = CT_TUNER_STEP_0;
+               /* wait for the WBDMUX to switch and for the ADC to sample */
+               break;
+
+       case CT_TUNER_STEP_0:
+               state->adc_diff = dib0090_get_slow_adc_val(state);
+               dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
+               *tune_state = CT_TUNER_STEP_1;
+               break;
+
+       case CT_TUNER_STEP_1:
+               val = dib0090_get_slow_adc_val(state);
+               state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
+
+               dprintk("temperature: %d C", state->temperature - 30);
+
+               *tune_state = CT_TUNER_STEP_2;
+               break;
+
+       case CT_TUNER_STEP_2:
+               dib0090_write_reg(state, 0x13, state->bias);
+               dib0090_write_reg(state, 0x10, state->wbdmux);  /* write back original WBDMUX */
+
+               *tune_state = CT_TUNER_START;
+               state->calibrate &= ~TEMP_CAL;
+               if (state->config->analog_output == 0)
+                       dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
+
+               break;
+
+       default:
+               ret = 0;
+               break;
+       }
+       return ret;
+}
+
+#define WBD     0x781          /* 1 1 1 1 0000 0 0 1 */
+static int dib0090_tune(struct dvb_frontend *fe)
+{
+       struct dib0090_state *state = fe->tuner_priv;
+       const struct dib0090_tuning *tune = state->current_tune_table_index;
+       const struct dib0090_pll *pll = state->current_pll_table_index;
        enum frontend_tune_state *tune_state = &state->tune_state;
 
-       u32 rf;
-       u16 lo4 = 0xe900, lo5, lo6, Den;
+       u16 lo5, lo6, Den, tmp;
        u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
-       u16 tmp, adc;
-       int8_t step_sign;
        int ret = 10;           /* 1ms is the default delay most of the time */
        u8 c, i;
 
-       state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
-       rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
-                                                       BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf);
-       /* in any case we first need to do a reset if needed */
-       if (state->reset & 0x1)
-               return dib0090_dc_offset_calibration(state, tune_state);
-       else if (state->reset & 0x2)
-               return dib0090_wbd_calibration(state, tune_state);
-
-    /************************* VCO ***************************/
+       /************************* VCO ***************************/
        /* Default values for FG                                 */
        /* from these are needed :                               */
        /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv             */
 
-#ifdef CONFIG_SYS_ISDBT
-       if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
-               rf += 850;
-#endif
+       /* in any case we first need to do a calibration if needed */
+       if (*tune_state == CT_TUNER_START) {
+               /* deactivate DataTX before some calibrations */
+               if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
+                       dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
+               else
+                       /* Activate DataTX in case a calibration has been done before */
+                       if (state->config->analog_output == 0)
+                               dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
+       }
 
-       if (state->current_rf != rf) {
-               state->tuner_is_tuned = 0;
+       if (state->calibrate & DC_CAL)
+               return dib0090_dc_offset_calibration(state, tune_state);
+       else if (state->calibrate & WBD_CAL) {
+               if (state->current_rf == 0)
+                       state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
+               return dib0090_wbd_calibration(state, tune_state);
+       } else if (state->calibrate & TEMP_CAL)
+               return dib0090_get_temperature(state, tune_state);
+       else if (state->calibrate & CAPTRIM_CAL)
+               return dib0090_captrim_search(state, tune_state);
 
-               tune = dib0090_tuning_table;
+       if (*tune_state == CT_TUNER_START) {
+               /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
+               if (state->config->use_pwm_agc && state->identity.in_soc) {
+                       tmp = dib0090_read_reg(state, 0x39);
+                       if ((tmp >> 10) & 0x1)
+                               dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
+               }
 
-               tmp = (state->revision >> 5) & 0x7;
-               if (tmp == 0x4 || tmp == 0x7) {
-                       /* CBAND tuner version for VHF */
-                       if (state->current_band == BAND_FM || state->current_band == BAND_VHF) {
-                               /* Force CBAND */
-                               state->current_band = BAND_CBAND;
-                               tune = dib0090_tuning_table_fm_vhf_on_cband;
+               state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
+               state->rf_request =
+                       state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
+                                       BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
+                                       freq_offset_khz_vhf);
+
+               /* in ISDB-T 1seg we shift tuning frequency */
+               if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
+                                       && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
+                       const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
+                       u8 found_offset = 0;
+                       u32 margin_khz = 100;
+
+                       if (LUT_offset != NULL) {
+                               while (LUT_offset->RF_freq != 0xffff) {
+                                       if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
+                                                               && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
+                                                       && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
+                                               state->rf_request += LUT_offset->offset_khz;
+                                               found_offset = 1;
+                                               break;
+                                       }
+                                       LUT_offset++;
+                               }
                        }
-               }
 
-               pll = dib0090_pll_table;
-               /* Look for the interval */
-               while (rf > tune->max_freq)
-                       tune++;
-               while (rf > pll->max_freq)
-                       pll++;
-               state->current_tune_table_index = tune;
-               state->current_pll_table_index = pll;
-       }
+                       if (found_offset == 0)
+                               state->rf_request += 400;
+               }
+               if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
+                       state->tuner_is_tuned = 0;
+                       state->current_rf = 0;
+                       state->current_standard = 0;
 
-       if (*tune_state == CT_TUNER_START) {
+                       tune = dib0090_tuning_table;
+                       if (state->identity.p1g)
+                               tune = dib0090_p1g_tuning_table;
 
-               if (state->tuner_is_tuned == 0)
-                       state->current_rf = 0;
+                       tmp = (state->identity.version >> 5) & 0x7;
 
-               if (state->current_rf != rf) {
+                       if (state->identity.in_soc) {
+                               if (state->config->force_cband_input) { /* Use the CBAND input for all band */
+                                       if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
+                                                       || state->current_band & BAND_UHF) {
+                                               state->current_band = BAND_CBAND;
+                                               tune = dib0090_tuning_table_cband_7090;
+                                       }
+                               } else {        /* Use the CBAND input for all band under UHF */
+                                       if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
+                                               state->current_band = BAND_CBAND;
+                                               tune = dib0090_tuning_table_cband_7090;
+                                       }
+                               }
+                       } else
+                        if (tmp == 0x4 || tmp == 0x7) {
+                               /* CBAND tuner version for VHF */
+                               if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
+                                       state->current_band = BAND_CBAND;       /* Force CBAND */
+
+                                       tune = dib0090_tuning_table_fm_vhf_on_cband;
+                                       if (state->identity.p1g)
+                                               tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
+                               }
+                       }
 
-                       dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
+                       pll = dib0090_pll_table;
+                       if (state->identity.p1g)
+                               pll = dib0090_p1g_pll_table;
 
-                       /* external loop filter, otherwise:
-                        * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
-                        * lo6 = 0x0e34 */
-                       if (pll->vco_band)
-                               lo5 = 0x049e;
-                       else if (state->config->analog_output)
-                               lo5 = 0x041d;
-                       else
-                               lo5 = 0x041c;
+                       /* Look for the interval */
+                       while (state->rf_request > tune->max_freq)
+                               tune++;
+                       while (state->rf_request > pll->max_freq)
+                               pll++;
 
-                       lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);  /* bit 15 is the split to the slave, we do not do it here */
+                       state->current_tune_table_index = tune;
+                       state->current_pll_table_index = pll;
 
-                       if (!state->config->io.pll_int_loop_filt)
-                               lo6 = 0xff28;
-                       else
-                               lo6 = (state->config->io.pll_int_loop_filt << 3);
+                       dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
 
-                       VCOF_kHz = (pll->hfdiv * rf) * 2;
+                       VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
 
                        FREF = state->config->io.clock_khz;
+                       if (state->config->fref_clock_ratio != 0)
+                               FREF /= state->config->fref_clock_ratio;
 
                        FBDiv = (VCOF_kHz / pll->topresc / FREF);
                        Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
@@ -1283,144 +2172,132 @@ static int dib0090_tune(struct dvb_frontend *fe)
                        } else if (Rest > (FREF - 2 * LPF))
                                Rest = FREF - 2 * LPF;
                        Rest = (Rest * 6528) / (FREF / 10);
+                       state->rest = Rest;
 
-                       Den = 1;
+                       /* external loop filter, otherwise:
+                        * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
+                        * lo6 = 0x0e34 */
+
+                       if (Rest == 0) {
+                               if (pll->vco_band)
+                                       lo5 = 0x049f;
+                               else
+                                       lo5 = 0x041f;
+                       } else {
+                               if (pll->vco_band)
+                                       lo5 = 0x049e;
+                               else if (state->config->analog_output)
+                                       lo5 = 0x041d;
+                               else
+                                       lo5 = 0x041c;
+                       }
 
-                       dprintk(" *****  ******* Rest value = %d", Rest);
+                       if (state->identity.p1g) {      /* Bias is done automatically in P1G */
+                               if (state->identity.in_soc) {
+                                       if (state->identity.version == SOC_8090_P1G_11R1)
+                                               lo5 = 0x46f;
+                                       else
+                                               lo5 = 0x42f;
+                               } else
+                                       lo5 = 0x42c;
+                       }
+
+                       lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7);  /* bit 15 is the split to the slave, we do not do it here */
+
+                       if (!state->config->io.pll_int_loop_filt) {
+                               if (state->identity.in_soc)
+                                       lo6 = 0xff98;
+                               else if (state->identity.p1g || (Rest == 0))
+                                       lo6 = 0xfff8;
+                               else
+                                       lo6 = 0xff28;
+                       } else
+                               lo6 = (state->config->io.pll_int_loop_filt << 3);
+
+                       Den = 1;
 
                        if (Rest > 0) {
                                if (state->config->analog_output)
                                        lo6 |= (1 << 2) | 2;
-                               else
-                                       lo6 |= (1 << 2) | 1;
+                               else {
+                                       if (state->identity.in_soc)
+                                               lo6 |= (1 << 2) | 2;
+                                       else
+                                               lo6 |= (1 << 2) | 2;
+                               }
                                Den = 255;
                        }
-#ifdef CONFIG_BAND_SBAND
-                       if (state->current_band == BAND_SBAND)
-                               lo6 &= 0xfffb;
-#endif
-
                        dib0090_write_reg(state, 0x15, (u16) FBDiv);
-
-                       dib0090_write_reg(state, 0x16, (Den << 8) | 1);
-
+                       if (state->config->fref_clock_ratio != 0)
+                               dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
+                       else
+                               dib0090_write_reg(state, 0x16, (Den << 8) | 1);
                        dib0090_write_reg(state, 0x17, (u16) Rest);
-
                        dib0090_write_reg(state, 0x19, lo5);
-
                        dib0090_write_reg(state, 0x1c, lo6);
 
                        lo6 = tune->tuner_enable;
                        if (state->config->analog_output)
                                lo6 = (lo6 & 0xff9f) | 0x2;
 
-                       dib0090_write_reg(state, 0x24, lo6 | EN_LO
-#ifdef CONFIG_DIB0090_USE_PWM_AGC
-                                         | state->config->use_pwm_agc * EN_CRYSTAL
-#endif
-                           );
-
-                       state->current_rf = rf;
+                       dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
 
-                       /* prepare a complete captrim */
-                       state->step = state->captrim = state->fcaptrim = 64;
-
-               } else {        /* we are already tuned to this frequency - the configuration is correct  */
-
-                       /* do a minimal captrim even if the frequency has not changed */
-                       state->step = 4;
-                       state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
                }
-               state->adc_diff = 3000;
 
-               dib0090_write_reg(state, 0x10, 0x2B1);
-
-               dib0090_write_reg(state, 0x1e, 0x0032);
+               state->current_rf = state->rf_request;
+               state->current_standard = state->fe->dtv_property_cache.delivery_system;
 
                ret = 20;
-               *tune_state = CT_TUNER_STEP_1;
-       } else if (*tune_state == CT_TUNER_STEP_0) {
-               /* nothing */
-       } else if (*tune_state == CT_TUNER_STEP_1) {
-               state->step /= 2;
-               dib0090_write_reg(state, 0x18, lo4 | state->captrim);
-               *tune_state = CT_TUNER_STEP_2;
-       } else if (*tune_state == CT_TUNER_STEP_2) {
-
-               adc = dib0090_read_reg(state, 0x1d);
-               dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc,
-                       (u32) (adc) * (u32) 1800 / (u32) 1024);
-
-               if (adc >= 400) {
-                       adc -= 400;
-                       step_sign = -1;
-               } else {
-                       adc = 400 - adc;
-                       step_sign = 1;
-               }
+               state->calibrate = CAPTRIM_CAL; /* captrim serach now */
+       }
 
-               if (adc < state->adc_diff) {
-                       dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
-                       state->adc_diff = adc;
-                       state->fcaptrim = state->captrim;
+       else if (*tune_state == CT_TUNER_STEP_0) {      /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
+               const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
 
-               }
+               while (state->current_rf / 1000 > wbd->max_freq)
+                       wbd++;
 
-               state->captrim += step_sign * state->step;
-               if (state->step >= 1)
-                       *tune_state = CT_TUNER_STEP_1;
-               else
-                       *tune_state = CT_TUNER_STEP_3;
+               dib0090_write_reg(state, 0x1e, 0x07ff);
+               dprintk("Final Captrim: %d", (u32) state->fcaptrim);
+               dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
+               dprintk("VCO = %d", (u32) pll->vco_band);
+               dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
+               dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
+               dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
+               dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
+                       (u32) dib0090_read_reg(state, 0x1c) & 0x3);
 
-               ret = 15;
-       } else if (*tune_state == CT_TUNER_STEP_3) {
-               /*write the final cptrim config */
-               dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
+#define WBD     0x781          /* 1 1 1 1 0000 0 0 1 */
+               c = 4;
+               i = 3;
 
-#ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY
-               state->memory[state->memory_index].cap = state->fcaptrim;
-#endif
+               if (wbd->wbd_gain != 0)
+                       c = wbd->wbd_gain;
 
-               *tune_state = CT_TUNER_STEP_4;
-       } else if (*tune_state == CT_TUNER_STEP_4) {
-               dib0090_write_reg(state, 0x1e, 0x07ff);
+               state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
+               dib0090_write_reg(state, 0x10, state->wbdmux);
 
-               dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim);
-               dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code);
-               dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band);
-               dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf);
-               dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz);
-               dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
-               dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17),
-                       (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3);
+               if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
+                       dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
+                       dib0090_write_reg(state, 0x09, tune->lna_bias);
+                       dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
+               } else
+                       dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
 
-               c = 4;
-               i = 3;
-#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
-               if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) {
-                       c = 2;
-                       i = 2;
-               }
-#endif
-               dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD
-#ifdef CONFIG_DIB0090_USE_PWM_AGC
-                                                                       | (state->config->use_pwm_agc << 1)
-#endif
-                                 ));
-               dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0));
                dib0090_write_reg(state, 0x0c, tune->v2i);
                dib0090_write_reg(state, 0x0d, tune->mix);
                dib0090_write_reg(state, 0x0e, tune->load);
+               *tune_state = CT_TUNER_STEP_1;
 
-               *tune_state = CT_TUNER_STEP_5;
-       } else if (*tune_state == CT_TUNER_STEP_5) {
-
+       } else if (*tune_state == CT_TUNER_STEP_1) {
                /* initialize the lt gain register */
                state->rf_lt_def = 0x7c00;
-               dib0090_write_reg(state, 0x0f, state->rf_lt_def);
 
                dib0090_set_bandwidth(state);
                state->tuner_is_tuned = 1;
+
+               state->calibrate |= WBD_CAL;
+               state->calibrate |= TEMP_CAL;
                *tune_state = CT_TUNER_STOP;
        } else
                ret = FE_CALLBACK_TIME_NEVER;
@@ -1440,6 +2317,7 @@ enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
 
        return state->tune_state;
 }
+
 EXPORT_SYMBOL(dib0090_get_tune_state);
 
 int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
@@ -1449,6 +2327,7 @@ int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun
        state->tune_state = tune_state;
        return 0;
 }
+
 EXPORT_SYMBOL(dib0090_set_tune_state);
 
 static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
@@ -1462,7 +2341,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
 static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
 {
        struct dib0090_state *state = fe->tuner_priv;
-       uint32_t ret;
+       u32 ret;
 
        state->tune_state = CT_TUNER_START;
 
@@ -1492,6 +2371,29 @@ static const struct dvb_tuner_ops dib0090_ops = {
        .get_frequency = dib0090_get_frequency,
 };
 
+static const struct dvb_tuner_ops dib0090_fw_ops = {
+       .info = {
+                .name = "DiBcom DiB0090",
+                .frequency_min = 45000000,
+                .frequency_max = 860000000,
+                .frequency_step = 1000,
+                },
+       .release = dib0090_release,
+
+       .init = NULL,
+       .sleep = NULL,
+       .set_params = NULL,
+       .get_frequency = NULL,
+};
+
+static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
+       {470, 0, 250, 0, 100, 4},
+       {860, 51, 866, 21, 375, 4},
+       {1700, 0, 800, 0, 850, 4},
+       {2900, 0, 250, 0, 100, 6},
+       {0xFFFF, 0, 0, 0, 0, 0},
+};
+
 struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
 {
        struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
@@ -1503,6 +2405,11 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte
        st->fe = fe;
        fe->tuner_priv = st;
 
+       if (config->wbd == NULL)
+               st->current_wbd_table = dib0090_wbd_table_default;
+       else
+               st->current_wbd_table = config->wbd;
+
        if (dib0090_reset(fe) != 0)
                goto free_mem;
 
@@ -1515,8 +2422,34 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte
        fe->tuner_priv = NULL;
        return NULL;
 }
+
 EXPORT_SYMBOL(dib0090_register);
 
+struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
+{
+       struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
+       if (st == NULL)
+               return NULL;
+
+       st->config = config;
+       st->i2c = i2c;
+       st->fe = fe;
+       fe->tuner_priv = st;
+
+       if (dib0090_fw_reset_digital(fe, st->config) != 0)
+               goto free_mem;
+
+       dprintk("DiB0090 FW: successfully identified");
+       memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
+
+       return fe;
+free_mem:
+       kfree(st);
+       fe->tuner_priv = NULL;
+       return NULL;
+}
+EXPORT_SYMBOL(dib0090_fw_register);
+
 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
 MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
index aa7711e887766338f03d5cedb8767153c1279b18..13d85244ec160048cec20fb9ee6ac16f0a3211ca 100644 (file)
@@ -27,6 +27,21 @@ struct dib0090_io_config {
        u16 pll_int_loop_filt;
 };
 
+struct dib0090_wbd_slope {
+       u16 max_freq;           /* for every frequency less than or equal to that field: this information is correct */
+       u16 slope_cold;
+       u16 offset_cold;
+       u16 slope_hot;
+       u16 offset_hot;
+       u8 wbd_gain;
+};
+
+struct dib0090_low_if_offset_table {
+       int std;
+       u32 RF_freq;
+       s32 offset_khz;
+};
+
 struct dib0090_config {
        struct dib0090_io_config io;
        int (*reset) (struct dvb_frontend *, int);
@@ -47,10 +62,20 @@ struct dib0090_config {
        u16 wbd_cband_offset;
        u8 use_pwm_agc;
        u8 clkoutdrive;
+
+       u8 ls_cfg_pad_drv;
+       u8 data_tx_drv;
+
+       u8 in_soc;
+       const struct dib0090_low_if_offset_table *low_if;
+       u8 fref_clock_ratio;
+       u16 force_cband_input;
+       struct dib0090_wbd_slope *wbd;
 };
 
 #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE))
 extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
+extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config);
 extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast);
 extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe);
 extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner);
@@ -65,6 +90,12 @@ static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, str
        return NULL;
 }
 
+static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
 static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
index 6aa02cb80733b2abf8458a3fac6576e2f4e3628a..900af60b9d36f155af9c54486bb172f245cdcde6 100644 (file)
@@ -26,24 +26,29 @@ MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (defau
 
 #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
 
+struct i2c_device {
+       struct i2c_adapter *i2c_adap;
+       u8 i2c_addr;
+};
+
 struct dib7000p_state {
        struct dvb_frontend demod;
-    struct dib7000p_config cfg;
+       struct dib7000p_config cfg;
 
        u8 i2c_addr;
-       struct i2c_adapter   *i2c_adap;
+       struct i2c_adapter *i2c_adap;
 
        struct dibx000_i2c_master i2c_master;
 
        u16 wbd_ref;
 
-       u8  current_band;
+       u8 current_band;
        u32 current_bandwidth;
        struct dibx000_agc_config *current_agc;
        u32 timf;
 
-       u8 div_force_off : 1;
-       u8 div_state : 1;
+       u8 div_force_off:1;
+       u8 div_state:1;
        u16 div_sync_wait;
 
        u8 agc_state;
@@ -51,7 +56,13 @@ struct dib7000p_state {
        u16 gpio_dir;
        u16 gpio_val;
 
-       u8 sfn_workaround_active :1;
+       u8 sfn_workaround_active:1;
+
+#define SOC7090 0x7090
+       u16 version;
+
+       u16 tuner_enable;
+       struct i2c_adapter dib7090_tuner_adap;
 };
 
 enum dib7000p_power_mode {
@@ -60,17 +71,20 @@ enum dib7000p_power_mode {
        DIB7000P_POWER_INTERFACE_ONLY,
 };
 
+static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
+
 static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
 {
        u8 wb[2] = { reg >> 8, reg & 0xff };
        u8 rb[2];
        struct i2c_msg msg[2] = {
-               { .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
-               { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+               {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
+               {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
        };
 
        if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
-               dprintk("i2c read error on %d",reg);
+               dprintk("i2c read error on %d", reg);
 
        return (rb[0] << 8) | rb[1];
 }
@@ -86,7 +100,8 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
        };
        return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
-static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
+
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
 {
        u16 l = 0, r, *n;
        n = buf;
@@ -104,54 +119,54 @@ static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
 
 static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
 {
-       int    ret = 0;
+       int ret = 0;
        u16 outreg, fifo_threshold, smo_mode;
 
        outreg = 0;
        fifo_threshold = 1792;
        smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
 
-       dprintk( "setting output mode for demod %p to %d",
-                       &state->demod, mode);
+       dprintk("setting output mode for demod %p to %d", &state->demod, mode);
 
        switch (mode) {
-               case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
-                       outreg = (1 << 10);  /* 0x0400 */
-                       break;
-               case OUTMODE_MPEG2_PAR_CONT_CLK:    // STBs with parallel continues clock
-                       outreg = (1 << 10) | (1 << 6); /* 0x0440 */
-                       break;
-               case OUTMODE_MPEG2_SERIAL:          // STBs with serial input
-                       outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
-                       break;
-               case OUTMODE_DIVERSITY:
-                       if (state->cfg.hostbus_diversity)
-                               outreg = (1 << 10) | (4 << 6); /* 0x0500 */
-                       else
-                               outreg = (1 << 11);
-                       break;
-               case OUTMODE_MPEG2_FIFO:            // e.g. USB feeding
-                       smo_mode |= (3 << 1);
-                       fifo_threshold = 512;
-                       outreg = (1 << 10) | (5 << 6);
-                       break;
-               case OUTMODE_ANALOG_ADC:
-                       outreg = (1 << 10) | (3 << 6);
-                       break;
-               case OUTMODE_HIGH_Z:  // disable
-                       outreg = 0;
-                       break;
-               default:
-                       dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
-                       break;
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+               outreg = (1 << 10);     /* 0x0400 */
+               break;
+       case OUTMODE_MPEG2_PAR_CONT_CLK:
+               outreg = (1 << 10) | (1 << 6);  /* 0x0440 */
+               break;
+       case OUTMODE_MPEG2_SERIAL:
+               outreg = (1 << 10) | (2 << 6) | (0 << 1);       /* 0x0480 */
+               break;
+       case OUTMODE_DIVERSITY:
+               if (state->cfg.hostbus_diversity)
+                       outreg = (1 << 10) | (4 << 6);  /* 0x0500 */
+               else
+                       outreg = (1 << 11);
+               break;
+       case OUTMODE_MPEG2_FIFO:
+               smo_mode |= (3 << 1);
+               fifo_threshold = 512;
+               outreg = (1 << 10) | (5 << 6);
+               break;
+       case OUTMODE_ANALOG_ADC:
+               outreg = (1 << 10) | (3 << 6);
+               break;
+       case OUTMODE_HIGH_Z:
+               outreg = 0;
+               break;
+       default:
+               dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
+               break;
        }
 
        if (state->cfg.output_mpeg2_in_188_bytes)
-               smo_mode |= (1 << 5) ;
+               smo_mode |= (1 << 5);
 
-       ret |= dib7000p_write_word(state,  235, smo_mode);
-       ret |= dib7000p_write_word(state,  236, fifo_threshold); /* synchronous fread */
-       ret |= dib7000p_write_word(state, 1286, outreg);         /* P_Div_active */
+       ret |= dib7000p_write_word(state, 235, smo_mode);
+       ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
+       if (state->version != SOC7090)
+               ret |= dib7000p_write_word(state, 1286, outreg);        /* P_Div_active */
 
        return ret;
 }
@@ -161,13 +176,13 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
        struct dib7000p_state *state = demod->demodulator_priv;
 
        if (state->div_force_off) {
-               dprintk( "diversity combination deactivated - forced by COFDM parameters");
+               dprintk("diversity combination deactivated - forced by COFDM parameters");
                onoff = 0;
                dib7000p_write_word(state, 207, 0);
        } else
                dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
 
-       state->div_state = (u8)onoff;
+       state->div_state = (u8) onoff;
 
        if (onoff) {
                dib7000p_write_word(state, 204, 6);
@@ -184,37 +199,48 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
 static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
 {
        /* by default everything is powered off */
-       u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899  = 0x0003,
-               reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
+       u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
 
        /* now, depending on the requested mode, we power on */
        switch (mode) {
                /* power up everything in the demod */
-               case DIB7000P_POWER_ALL:
-                       reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
-                       break;
-
-               case DIB7000P_POWER_ANALOG_ADC:
-                       /* dem, cfg, iqc, sad, agc */
-                       reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
-                       /* nud */
-                       reg_776 &= ~((1 << 0));
-                       /* Dout */
+       case DIB7000P_POWER_ALL:
+               reg_774 = 0x0000;
+               reg_775 = 0x0000;
+               reg_776 = 0x0;
+               reg_899 = 0x0;
+               if (state->version == SOC7090)
+                       reg_1280 &= 0x001f;
+               else
+                       reg_1280 &= 0x01ff;
+               break;
+
+       case DIB7000P_POWER_ANALOG_ADC:
+               /* dem, cfg, iqc, sad, agc */
+               reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+               /* nud */
+               reg_776 &= ~((1 << 0));
+               /* Dout */
+               if (state->version != SOC7090)
                        reg_1280 &= ~((1 << 11));
-                       /* fall through wanted to enable the interfaces */
+               reg_1280 &= ~(1 << 6);
+               /* fall through wanted to enable the interfaces */
 
                /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
-               case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
+       case DIB7000P_POWER_INTERFACE_ONLY:     /* TODO power up either SDIO or I2C */
+               if (state->version == SOC7090)
+                       reg_1280 &= ~((1 << 7) | (1 << 5));
+               else
                        reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
-                       break;
+               break;
 
 /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
        }
 
-       dib7000p_write_word(state,  774,  reg_774);
-       dib7000p_write_word(state,  775,  reg_775);
-       dib7000p_write_word(state,  776,  reg_776);
-       dib7000p_write_word(state,  899,  reg_899);
+       dib7000p_write_word(state, 774, reg_774);
+       dib7000p_write_word(state, 775, reg_775);
+       dib7000p_write_word(state, 776, reg_776);
+       dib7000p_write_word(state, 899, reg_899);
        dib7000p_write_word(state, 1280, reg_1280);
 
        return 0;
@@ -222,40 +248,57 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
 
 static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
 {
-       u16 reg_908 = dib7000p_read_word(state, 908),
-              reg_909 = dib7000p_read_word(state, 909);
+       u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
+       u16 reg;
 
        switch (no) {
-               case DIBX000_SLOW_ADC_ON:
+       case DIBX000_SLOW_ADC_ON:
+               if (state->version == SOC7090) {
+                       reg = dib7000p_read_word(state, 1925);
+
+                       dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2));    /* en_slowAdc = 1 & reset_sladc = 1 */
+
+                       reg = dib7000p_read_word(state, 1925);  /* read acces to make it works... strange ... */
+                       msleep(200);
+                       dib7000p_write_word(state, 1925, reg & ~(1 << 4));      /* en_slowAdc = 1 & reset_sladc = 0 */
+
+                       reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
+                       dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524);      /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
+               } else {
                        reg_909 |= (1 << 1) | (1 << 0);
                        dib7000p_write_word(state, 909, reg_909);
                        reg_909 &= ~(1 << 1);
-                       break;
+               }
+               break;
 
-               case DIBX000_SLOW_ADC_OFF:
-                       reg_909 |=  (1 << 1) | (1 << 0);
-                       break;
+       case DIBX000_SLOW_ADC_OFF:
+               if (state->version == SOC7090) {
+                       reg = dib7000p_read_word(state, 1925);
+                       dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
+               } else
+                       reg_909 |= (1 << 1) | (1 << 0);
+               break;
 
-               case DIBX000_ADC_ON:
-                       reg_908 &= 0x0fff;
-                       reg_909 &= 0x0003;
-                       break;
+       case DIBX000_ADC_ON:
+               reg_908 &= 0x0fff;
+               reg_909 &= 0x0003;
+               break;
 
-               case DIBX000_ADC_OFF: // leave the VBG voltage on
-                       reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
-                       reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
-                       break;
+       case DIBX000_ADC_OFF:
+               reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
+               reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+               break;
 
-               case DIBX000_VBG_ENABLE:
-                       reg_908 &= ~(1 << 15);
-                       break;
+       case DIBX000_VBG_ENABLE:
+               reg_908 &= ~(1 << 15);
+               break;
 
-               case DIBX000_VBG_DISABLE:
-                       reg_908 |= (1 << 15);
-                       break;
+       case DIBX000_VBG_DISABLE:
+               reg_908 |= (1 << 15);
+               break;
 
-               default:
-                       break;
+       default:
+               break;
        }
 
 //     dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
@@ -275,17 +318,17 @@ static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
        state->current_bandwidth = bw;
 
        if (state->timf == 0) {
-               dprintk( "using default timf");
+               dprintk("using default timf");
                timf = state->cfg.bw->timf;
        } else {
-               dprintk( "using updated timf");
+               dprintk("using updated timf");
                timf = state->timf;
        }
 
        timf = timf * (bw / 50) / 160;
 
        dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
-       dib7000p_write_word(state, 24, (u16) ((timf      ) & 0xffff));
+       dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
 
        return 0;
 }
@@ -293,9 +336,12 @@ static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
 static int dib7000p_sad_calib(struct dib7000p_state *state)
 {
 /* internal */
-//     dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
        dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
-       dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
+
+       if (state->version == SOC7090)
+               dib7000p_write_word(state, 74, 2048);
+       else
+               dib7000p_write_word(state, 74, 776);
 
        /* do the calibration */
        dib7000p_write_word(state, 73, (1 << 0));
@@ -314,37 +360,91 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
        state->wbd_ref = value;
        return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
 }
-
 EXPORT_SYMBOL(dib7000p_set_wbd_ref);
+
 static void dib7000p_reset_pll(struct dib7000p_state *state)
 {
        struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
        u16 clk_cfg0;
 
-       /* force PLL bypass */
-       clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
-               (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
-               (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+       if (state->version == SOC7090) {
+               dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
+
+               while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
+                       ;
 
-       dib7000p_write_word(state, 900, clk_cfg0);
+               dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
+       } else {
+               /* force PLL bypass */
+               clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+                       (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+
+               dib7000p_write_word(state, 900, clk_cfg0);
 
-       /* P_pll_cfg */
-       dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
-       clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
-       dib7000p_write_word(state, 900, clk_cfg0);
+               /* P_pll_cfg */
+               dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
+               clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+               dib7000p_write_word(state, 900, clk_cfg0);
+       }
 
-       dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
-       dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000       ) & 0xffff));
-       dib7000p_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
-       dib7000p_write_word(state, 22, (u16) ( (bw->ifreq               ) & 0xffff));
+       dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
+       dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
+       dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
+       dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
 
        dib7000p_write_word(state, 72, bw->sad_cfg);
 }
 
+static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
+{
+       u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
+       internal |= (u32) dib7000p_read_word(state, 19);
+       internal /= 1000;
+
+       return internal;
+}
+
+int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
+       u8 loopdiv, prediv;
+       u32 internal, xtal;
+
+       /* get back old values */
+       prediv = reg_1856 & 0x3f;
+       loopdiv = (reg_1856 >> 6) & 0x3f;
+
+       if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
+               dprintk("Updating pll (prediv: old =  %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
+               reg_1856 &= 0xf000;
+               reg_1857 = dib7000p_read_word(state, 1857);
+               dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
+
+               dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
+
+               /* write new system clk into P_sec_len */
+               internal = dib7000p_get_internal_freq(state);
+               xtal = (internal / loopdiv) * prediv;
+               internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio;      /* new internal */
+               dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
+               dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
+
+               dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
+
+               while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
+                       dprintk("Waiting for PLL to lock");
+
+               return 0;
+       }
+       return -EIO;
+}
+EXPORT_SYMBOL(dib7000p_update_pll);
+
 static int dib7000p_reset_gpio(struct dib7000p_state *st)
 {
        /* reset the GPIOs */
-       dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+       dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
 
        dib7000p_write_word(st, 1029, st->gpio_dir);
        dib7000p_write_word(st, 1030, st->gpio_val);
@@ -360,13 +460,13 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st)
 static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
 {
        st->gpio_dir = dib7000p_read_word(st, 1029);
-       st->gpio_dir &= ~(1 << num);         /* reset the direction bit */
-       st->gpio_dir |=  (dir & 0x1) << num; /* set the new direction */
+       st->gpio_dir &= ~(1 << num);    /* reset the direction bit */
+       st->gpio_dir |= (dir & 0x1) << num;     /* set the new direction */
        dib7000p_write_word(st, 1029, st->gpio_dir);
 
        st->gpio_val = dib7000p_read_word(st, 1030);
-       st->gpio_val &= ~(1 << num);          /* reset the direction bit */
-       st->gpio_val |=  (val & 0x01) << num; /* set the new value */
+       st->gpio_val &= ~(1 << num);    /* reset the direction bit */
+       st->gpio_val |= (val & 0x01) << num;    /* set the new value */
        dib7000p_write_word(st, 1030, st->gpio_val);
 
        return 0;
@@ -377,96 +477,94 @@ int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
        struct dib7000p_state *state = demod->demodulator_priv;
        return dib7000p_cfg_gpio(state, num, dir, val);
 }
-
 EXPORT_SYMBOL(dib7000p_set_gpio);
-static u16 dib7000p_defaults[] =
 
-{
+static u16 dib7000p_defaults[] = {
        // auto search configuration
        3, 2,
-               0x0004,
-               0x1000,
-               0x0814, /* Equal Lock */
+       0x0004,
+       0x1000,
+       0x0814,                 /* Equal Lock */
 
        12, 6,
-               0x001b,
-               0x7740,
-               0x005b,
-               0x8d80,
-               0x01c9,
-               0xc380,
-               0x0000,
-               0x0080,
-               0x0000,
-               0x0090,
-               0x0001,
-               0xd4c0,
+       0x001b,
+       0x7740,
+       0x005b,
+       0x8d80,
+       0x01c9,
+       0xc380,
+       0x0000,
+       0x0080,
+       0x0000,
+       0x0090,
+       0x0001,
+       0xd4c0,
 
        1, 26,
-               0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+       0x6680,
 
        /* set ADC level to -16 */
        11, 79,
-               (1 << 13) - 825 - 117,
-               (1 << 13) - 837 - 117,
-               (1 << 13) - 811 - 117,
-               (1 << 13) - 766 - 117,
-               (1 << 13) - 737 - 117,
-               (1 << 13) - 693 - 117,
-               (1 << 13) - 648 - 117,
-               (1 << 13) - 619 - 117,
-               (1 << 13) - 575 - 117,
-               (1 << 13) - 531 - 117,
-               (1 << 13) - 501 - 117,
+       (1 << 13) - 825 - 117,
+       (1 << 13) - 837 - 117,
+       (1 << 13) - 811 - 117,
+       (1 << 13) - 766 - 117,
+       (1 << 13) - 737 - 117,
+       (1 << 13) - 693 - 117,
+       (1 << 13) - 648 - 117,
+       (1 << 13) - 619 - 117,
+       (1 << 13) - 575 - 117,
+       (1 << 13) - 531 - 117,
+       (1 << 13) - 501 - 117,
 
        1, 142,
-               0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+       0x0410,
 
        /* disable power smoothing */
        8, 145,
-               0,
-               0,
-               0,
-               0,
-               0,
-               0,
-               0,
-               0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
 
        1, 154,
-               1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+       1 << 13,
 
        1, 168,
-               0x0ccd, // P_pha3_thres, default 0x3000
-
-//     1, 169,
-//             0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+       0x0ccd,
 
        1, 183,
-               0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+       0x200f,
+
+       1, 212,
+               0x169,
 
        5, 187,
-               0x023d, // P_adp_regul_cnt=573, default: 410
-               0x00a4, // P_adp_noise_cnt=
-               0x00a4, // P_adp_regul_ext
-               0x7ff0, // P_adp_noise_ext
-               0x3ccc, // P_adp_fil
+       0x023d,
+       0x00a4,
+       0x00a4,
+       0x7ff0,
+       0x3ccc,
 
        1, 198,
-               0x800, // P_equal_thres_wgn
+       0x800,
 
        1, 222,
-               0x0010, // P_fec_ber_rs_len=2
+       0x0010,
 
        1, 235,
-               0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+       0x0062,
 
        2, 901,
-               0x0006, // P_clk_cfg1
-               (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
+       0x0006,
+       (3 << 10) | (1 << 6),
 
        1, 905,
-               0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
+       0x2c8e,
 
        0,
 };
@@ -475,51 +573,64 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
 {
        dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
 
+       if (state->version == SOC7090)
+               dibx000_reset_i2c_master(&state->i2c_master);
+
        dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
 
        /* restart all parts */
-       dib7000p_write_word(state,  770, 0xffff);
-       dib7000p_write_word(state,  771, 0xffff);
-       dib7000p_write_word(state,  772, 0x001f);
-       dib7000p_write_word(state,  898, 0x0003);
-       /* except i2c, sdio, gpio - control interfaces */
-       dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
-
-       dib7000p_write_word(state,  770, 0);
-       dib7000p_write_word(state,  771, 0);
-       dib7000p_write_word(state,  772, 0);
-       dib7000p_write_word(state,  898, 0);
+       dib7000p_write_word(state, 770, 0xffff);
+       dib7000p_write_word(state, 771, 0xffff);
+       dib7000p_write_word(state, 772, 0x001f);
+       dib7000p_write_word(state, 898, 0x0003);
+       dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
+
+       dib7000p_write_word(state, 770, 0);
+       dib7000p_write_word(state, 771, 0);
+       dib7000p_write_word(state, 772, 0);
+       dib7000p_write_word(state, 898, 0);
        dib7000p_write_word(state, 1280, 0);
 
        /* default */
        dib7000p_reset_pll(state);
 
        if (dib7000p_reset_gpio(state) != 0)
-               dprintk( "GPIO reset was not successful.");
-
-       if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
-               dprintk( "OUTPUT_MODE could not be reset.");
+               dprintk("GPIO reset was not successful.");
 
-       /* unforce divstr regardless whether i2c enumeration was done or not */
-       dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+       if (state->version == SOC7090) {
+               dib7000p_write_word(state, 899, 0);
 
-       dib7000p_set_bandwidth(state, 8000);
+               /* impulse noise */
+               dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
+               dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
+               dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
+               dib7000p_write_word(state, 273, (1<<6) | 30);
+       }
+       if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+               dprintk("OUTPUT_MODE could not be reset.");
 
        dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
        dib7000p_sad_calib(state);
        dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
 
-       // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
-       if(state->cfg.tuner_is_baseband)
-               dib7000p_write_word(state, 36,0x0755);
-       else
-               dib7000p_write_word(state, 36,0x1f55);
+       /* unforce divstr regardless whether i2c enumeration was done or not */
+       dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
+
+       dib7000p_set_bandwidth(state, 8000);
+
+       if (state->version == SOC7090) {
+               dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
+       } else {
+               if (state->cfg.tuner_is_baseband)
+                       dib7000p_write_word(state, 36, 0x0755);
+               else
+                       dib7000p_write_word(state, 36, 0x1f55);
+       }
 
        dib7000p_write_tab(state, dib7000p_defaults);
 
        dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
 
-
        return 0;
 }
 
@@ -527,9 +638,9 @@ static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
 {
        u16 tmp = 0;
        tmp = dib7000p_read_word(state, 903);
-       dib7000p_write_word(state, 903, (tmp | 0x1));   //pwr-up pll
+       dib7000p_write_word(state, 903, (tmp | 0x1));
        tmp = dib7000p_read_word(state, 900);
-       dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));     //use High freq clock
+       dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
 }
 
 static void dib7000p_restart_agc(struct dib7000p_state *state)
@@ -543,11 +654,9 @@ static int dib7000p_update_lna(struct dib7000p_state *state)
 {
        u16 dyn_gain;
 
-       // when there is no LNA to program return immediatly
        if (state->cfg.update_lna) {
-               // read dyn_gain here (because it is demod-dependent and not fe)
                dyn_gain = dib7000p_read_word(state, 394);
-               if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+               if (state->cfg.update_lna(&state->demod, dyn_gain)) {
                        dib7000p_restart_agc(state);
                        return 1;
                }
@@ -571,24 +680,24 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
                }
 
        if (agc == NULL) {
-               dprintk( "no valid AGC configuration found for band 0x%02x",band);
+               dprintk("no valid AGC configuration found for band 0x%02x", band);
                return -EINVAL;
        }
 
        state->current_agc = agc;
 
        /* AGC */
-       dib7000p_write_word(state, 75 ,  agc->setup );
-       dib7000p_write_word(state, 76 ,  agc->inv_gain );
-       dib7000p_write_word(state, 77 ,  agc->time_stabiliz );
+       dib7000p_write_word(state, 75, agc->setup);
+       dib7000p_write_word(state, 76, agc->inv_gain);
+       dib7000p_write_word(state, 77, agc->time_stabiliz);
        dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
 
        // Demod AGC loop configuration
        dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
-       dib7000p_write_word(state, 102, (agc->beta_mant << 6)  | agc->beta_exp);
+       dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
 
        /* AGC continued */
-       dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+       dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
                state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
 
        if (state->wbd_ref != 0)
@@ -598,101 +707,135 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
 
        dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
 
-       dib7000p_write_word(state, 107,  agc->agc1_max);
-       dib7000p_write_word(state, 108,  agc->agc1_min);
-       dib7000p_write_word(state, 109,  agc->agc2_max);
-       dib7000p_write_word(state, 110,  agc->agc2_min);
-       dib7000p_write_word(state, 111, (agc->agc1_pt1    << 8) | agc->agc1_pt2);
-       dib7000p_write_word(state, 112,  agc->agc1_pt3);
+       dib7000p_write_word(state, 107, agc->agc1_max);
+       dib7000p_write_word(state, 108, agc->agc1_min);
+       dib7000p_write_word(state, 109, agc->agc2_max);
+       dib7000p_write_word(state, 110, agc->agc2_min);
+       dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+       dib7000p_write_word(state, 112, agc->agc1_pt3);
        dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-       dib7000p_write_word(state, 114, (agc->agc2_pt1    << 8) | agc->agc2_pt2);
+       dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
        dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
        return 0;
 }
 
+static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
+{
+       u32 internal = dib7000p_get_internal_freq(state);
+       s32 unit_khz_dds_val = 67108864 / (internal);   /* 2**26 / Fsampling is the unit 1KHz offset */
+       u32 abs_offset_khz = ABS(offset_khz);
+       u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
+       u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
+
+       dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
+
+       if (offset_khz < 0)
+               unit_khz_dds_val *= -1;
+
+       /* IF tuner */
+       if (invert)
+               dds -= (abs_offset_khz * unit_khz_dds_val);     /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
+       else
+               dds += (abs_offset_khz * unit_khz_dds_val);
+
+       if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
+               dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
+               dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
+       }
+}
+
 static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
        struct dib7000p_state *state = demod->demodulator_priv;
        int ret = -1;
        u8 *agc_state = &state->agc_state;
        u8 agc_split;
+       u16 reg;
+       u32 upd_demod_gain_period = 0x1000;
 
        switch (state->agc_state) {
-               case 0:
-                       // set power-up level: interf+analog+AGC
-                       dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+       case 0:
+               dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+               if (state->version == SOC7090) {
+                       reg = dib7000p_read_word(state, 0x79b) & 0xff00;
+                       dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF);      /* lsb */
+                       dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
+
+                       /* enable adc i & q */
+                       reg = dib7000p_read_word(state, 0x780);
+                       dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
+               } else {
                        dib7000p_set_adc_state(state, DIBX000_ADC_ON);
                        dib7000p_pll_clk_cfg(state);
+               }
 
-                       if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
-                               return -1;
-
-                       ret = 7;
-                       (*agc_state)++;
-                       break;
+               if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
+                       return -1;
 
-               case 1:
-                       // AGC initialization
-                       if (state->cfg.agc_control)
-                               state->cfg.agc_control(&state->demod, 1);
-
-                       dib7000p_write_word(state, 78, 32768);
-                       if (!state->current_agc->perform_agc_softsplit) {
-                               /* we are using the wbd - so slow AGC startup */
-                               /* force 0 split on WBD and restart AGC */
-                               dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
-                               (*agc_state)++;
-                               ret = 5;
-                       } else {
-                               /* default AGC startup */
-                               (*agc_state) = 4;
-                               /* wait AGC rough lock time */
-                               ret = 7;
-                       }
+               dib7000p_set_dds(state, 0);
+               ret = 7;
+               (*agc_state)++;
+               break;
 
-                       dib7000p_restart_agc(state);
-                       break;
+       case 1:
+               if (state->cfg.agc_control)
+                       state->cfg.agc_control(&state->demod, 1);
 
-               case 2: /* fast split search path after 5sec */
-                       dib7000p_write_word(state,  75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
-                       dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
+               dib7000p_write_word(state, 78, 32768);
+               if (!state->current_agc->perform_agc_softsplit) {
+                       /* we are using the wbd - so slow AGC startup */
+                       /* force 0 split on WBD and restart AGC */
+                       dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
                        (*agc_state)++;
-                       ret = 14;
-                       break;
+                       ret = 5;
+               } else {
+                       /* default AGC startup */
+                       (*agc_state) = 4;
+                       /* wait AGC rough lock time */
+                       ret = 7;
+               }
 
-       case 3: /* split search ended */
-                       agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
-                       dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
+               dib7000p_restart_agc(state);
+               break;
 
-                       dib7000p_write_word(state, 75,  state->current_agc->setup);   /* std AGC loop */
-                       dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+       case 2:         /* fast split search path after 5sec */
+               dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4));   /* freeze AGC loop */
+               dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8));     /* fast split search 0.25kHz */
+               (*agc_state)++;
+               ret = 14;
+               break;
 
-                       dib7000p_restart_agc(state);
+       case 3:         /* split search ended */
+               agc_split = (u8) dib7000p_read_word(state, 396);        /* store the split value for the next time */
+               dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
 
-                       dprintk( "SPLIT %p: %hd", demod, agc_split);
+               dib7000p_write_word(state, 75, state->current_agc->setup);      /* std AGC loop */
+               dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split);        /* standard split search */
 
-                       (*agc_state)++;
-                       ret = 5;
-                       break;
+               dib7000p_restart_agc(state);
 
-               case 4: /* LNA startup */
-                       // wait AGC accurate lock time
-                       ret = 7;
+               dprintk("SPLIT %p: %hd", demod, agc_split);
 
-                       if (dib7000p_update_lna(state))
-                               // wait only AGC rough lock time
-                               ret = 5;
-                       else // nothing was done, go to the next state
-                               (*agc_state)++;
-                       break;
+               (*agc_state)++;
+               ret = 5;
+               break;
 
-               case 5:
-                       if (state->cfg.agc_control)
-                               state->cfg.agc_control(&state->demod, 0);
+       case 4:         /* LNA startup */
+               ret = 7;
+
+               if (dib7000p_update_lna(state))
+                       ret = 5;
+               else
                        (*agc_state)++;
-                       break;
-               default:
-                       break;
+               break;
+
+       case 5:
+               if (state->cfg.agc_control)
+                       state->cfg.agc_control(&state->demod, 0);
+               (*agc_state)++;
+               break;
+       default:
+               break;
        }
        return ret;
 }
@@ -703,45 +846,89 @@ static void dib7000p_update_timf(struct dib7000p_state *state)
        state->timf = timf * 160 / (state->current_bandwidth / 50);
        dib7000p_write_word(state, 23, (u16) (timf >> 16));
        dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
-       dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
+       dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
+
+}
 
+u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       switch (op) {
+       case DEMOD_TIMF_SET:
+               state->timf = timf;
+               break;
+       case DEMOD_TIMF_UPDATE:
+               dib7000p_update_timf(state);
+               break;
+       case DEMOD_TIMF_GET:
+               break;
+       }
+       dib7000p_set_bandwidth(state, state->current_bandwidth);
+       return state->timf;
 }
+EXPORT_SYMBOL(dib7000p_ctrl_timf);
 
 static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
 {
        u16 value, est[4];
 
-    dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 
        /* nfft, guard, qam, alpha */
        value = 0;
        switch (ch->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
-               case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
-               default:
-               case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+       case TRANSMISSION_MODE_2K:
+               value |= (0 << 7);
+               break;
+       case TRANSMISSION_MODE_4K:
+               value |= (2 << 7);
+               break;
+       default:
+       case TRANSMISSION_MODE_8K:
+               value |= (1 << 7);
+               break;
        }
        switch (ch->u.ofdm.guard_interval) {
-               case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
-               case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
-               case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
-               default:
-               case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+       case GUARD_INTERVAL_1_32:
+               value |= (0 << 5);
+               break;
+       case GUARD_INTERVAL_1_16:
+               value |= (1 << 5);
+               break;
+       case GUARD_INTERVAL_1_4:
+               value |= (3 << 5);
+               break;
+       default:
+       case GUARD_INTERVAL_1_8:
+               value |= (2 << 5);
+               break;
        }
        switch (ch->u.ofdm.constellation) {
-               case QPSK:  value |= (0 << 3); break;
-               case QAM_16: value |= (1 << 3); break;
-               default:
-               case QAM_64: value |= (2 << 3); break;
+       case QPSK:
+               value |= (0 << 3);
+               break;
+       case QAM_16:
+               value |= (1 << 3);
+               break;
+       default:
+       case QAM_64:
+               value |= (2 << 3);
+               break;
        }
        switch (HIERARCHY_1) {
-               case HIERARCHY_2: value |= 2; break;
-               case HIERARCHY_4: value |= 4; break;
-               default:
-               case HIERARCHY_1: value |= 1; break;
+       case HIERARCHY_2:
+               value |= 2;
+               break;
+       case HIERARCHY_4:
+               value |= 4;
+               break;
+       default:
+       case HIERARCHY_1:
+               value |= 1;
+               break;
        }
        dib7000p_write_word(state, 0, value);
-       dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
+       dib7000p_write_word(state, 5, (seq << 4) | 1);  /* do not force tps, search list 0 */
 
        /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
        value = 0;
@@ -752,39 +939,63 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
        if (1 == 1)
                value |= 1;
        switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
-               case FEC_2_3: value |= (2 << 1); break;
-               case FEC_3_4: value |= (3 << 1); break;
-               case FEC_5_6: value |= (5 << 1); break;
-               case FEC_7_8: value |= (7 << 1); break;
-               default:
-               case FEC_1_2: value |= (1 << 1); break;
+       case FEC_2_3:
+               value |= (2 << 1);
+               break;
+       case FEC_3_4:
+               value |= (3 << 1);
+               break;
+       case FEC_5_6:
+               value |= (5 << 1);
+               break;
+       case FEC_7_8:
+               value |= (7 << 1);
+               break;
+       default:
+       case FEC_1_2:
+               value |= (1 << 1);
+               break;
        }
        dib7000p_write_word(state, 208, value);
 
        /* offset loop parameters */
-       dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
-       dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
-       dib7000p_write_word(state, 29, 0x1273); // isi
-       dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
+       dib7000p_write_word(state, 26, 0x6680);
+       dib7000p_write_word(state, 32, 0x0003);
+       dib7000p_write_word(state, 29, 0x1273);
+       dib7000p_write_word(state, 33, 0x0005);
 
        /* P_dvsy_sync_wait */
        switch (ch->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_8K: value = 256; break;
-               case TRANSMISSION_MODE_4K: value = 128; break;
-               case TRANSMISSION_MODE_2K:
-               default: value = 64; break;
+       case TRANSMISSION_MODE_8K:
+               value = 256;
+               break;
+       case TRANSMISSION_MODE_4K:
+               value = 128;
+               break;
+       case TRANSMISSION_MODE_2K:
+       default:
+               value = 64;
+               break;
        }
        switch (ch->u.ofdm.guard_interval) {
-               case GUARD_INTERVAL_1_16: value *= 2; break;
-               case GUARD_INTERVAL_1_8:  value *= 4; break;
-               case GUARD_INTERVAL_1_4:  value *= 8; break;
-               default:
-               case GUARD_INTERVAL_1_32: value *= 1; break;
+       case GUARD_INTERVAL_1_16:
+               value *= 2;
+               break;
+       case GUARD_INTERVAL_1_8:
+               value *= 4;
+               break;
+       case GUARD_INTERVAL_1_4:
+               value *= 8;
+               break;
+       default:
+       case GUARD_INTERVAL_1_32:
+               value *= 1;
+               break;
        }
        if (state->cfg.diversity_delay == 0)
-               state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+               state->div_sync_wait = (value * 3) / 2 + 48;
        else
-               state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo
+               state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
 
        /* deactive the possibility of diversity reception if extended interleaver */
        state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
@@ -792,24 +1003,24 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
 
        /* channel estimation fine configuration */
        switch (ch->u.ofdm.constellation) {
-               case QAM_64:
-                       est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
-                       est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
-                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
-                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
-                       break;
-               case QAM_16:
-                       est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
-                       est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
-                       est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
-                       est[3] = 0xfff0;       /* P_adp_noise_ext -0.002 */
-                       break;
-               default:
-                       est[0] = 0x099a;       /* P_adp_regul_cnt 0.3 */
-                       est[1] = 0xffae;       /* P_adp_noise_cnt -0.01 */
-                       est[2] = 0x0333;       /* P_adp_regul_ext 0.1 */
-                       est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
-                       break;
+       case QAM_64:
+               est[0] = 0x0148;        /* P_adp_regul_cnt 0.04 */
+               est[1] = 0xfff0;        /* P_adp_noise_cnt -0.002 */
+               est[2] = 0x00a4;        /* P_adp_regul_ext 0.02 */
+               est[3] = 0xfff8;        /* P_adp_noise_ext -0.001 */
+               break;
+       case QAM_16:
+               est[0] = 0x023d;        /* P_adp_regul_cnt 0.07 */
+               est[1] = 0xffdf;        /* P_adp_noise_cnt -0.004 */
+               est[2] = 0x00a4;        /* P_adp_regul_ext 0.02 */
+               est[3] = 0xfff0;        /* P_adp_noise_ext -0.002 */
+               break;
+       default:
+               est[0] = 0x099a;        /* P_adp_regul_cnt 0.3 */
+               est[1] = 0xffae;        /* P_adp_noise_cnt -0.01 */
+               est[2] = 0x0333;        /* P_adp_regul_ext 0.1 */
+               est[3] = 0xfff8;        /* P_adp_noise_ext -0.002 */
+               break;
        }
        for (value = 0; value < 4; value++)
                dib7000p_write_word(state, 187 + value, est[value]);
@@ -820,14 +1031,15 @@ static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_fron
        struct dib7000p_state *state = demod->demodulator_priv;
        struct dvb_frontend_parameters schan;
        u32 value, factor;
+       u32 internal = dib7000p_get_internal_freq(state);
 
        schan = *ch;
        schan.u.ofdm.constellation = QAM_64;
-       schan.u.ofdm.guard_interval         = GUARD_INTERVAL_1_32;
-       schan.u.ofdm.transmission_mode          = TRANSMISSION_MODE_8K;
-       schan.u.ofdm.code_rate_HP  = FEC_2_3;
-       schan.u.ofdm.code_rate_LP  = FEC_3_4;
-       schan.u.ofdm.hierarchy_information          = 0;
+       schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+       schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+       schan.u.ofdm.code_rate_HP = FEC_2_3;
+       schan.u.ofdm.code_rate_LP = FEC_3_4;
+       schan.u.ofdm.hierarchy_information = 0;
 
        dib7000p_set_channel(state, &schan, 7);
 
@@ -837,16 +1049,15 @@ static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_fron
        else
                factor = 6;
 
-       // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
-       value = 30 * state->cfg.bw->internal * factor;
-       dib7000p_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
-       dib7000p_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
-       value = 100 * state->cfg.bw->internal * factor;
-       dib7000p_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
-       dib7000p_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
-       value = 500 * state->cfg.bw->internal * factor;
-       dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
-       dib7000p_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
+       value = 30 * internal * factor;
+       dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
+       dib7000p_write_word(state, 7, (u16) (value & 0xffff));
+       value = 100 * internal * factor;
+       dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
+       dib7000p_write_word(state, 9, (u16) (value & 0xffff));
+       value = 500 * internal * factor;
+       dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
+       dib7000p_write_word(state, 11, (u16) (value & 0xffff));
 
        value = dib7000p_read_word(state, 0);
        dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
@@ -861,101 +1072,101 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
        struct dib7000p_state *state = demod->demodulator_priv;
        u16 irq_pending = dib7000p_read_word(state, 1284);
 
-       if (irq_pending & 0x1) // failed
+       if (irq_pending & 0x1)
                return 1;
 
-       if (irq_pending & 0x2) // succeeded
+       if (irq_pending & 0x2)
                return 2;
 
-       return 0; // still pending
+       return 0;
 }
 
 static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
 {
-       static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
-       static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
-       24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
-       53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
-       82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
-       107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
-       128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
-       147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
-       166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
-       183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
-       199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
-       213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
-       225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
-       235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
-       244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
-       250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
-       254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255};
+       static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
+       static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+               24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+               53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+               82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+               107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+               128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+               147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+               166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+               183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+               199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+               213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+               225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+               235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+               244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+               250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+               254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+               255, 255, 255, 255, 255, 255
+       };
 
        u32 xtal = state->cfg.bw->xtal_hz / 1000;
        int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
        int k;
-       int coef_re[8],coef_im[8];
+       int coef_re[8], coef_im[8];
        int bw_khz = bw;
        u32 pha;
 
-       dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
-
+       dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
 
-       if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
+       if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
                return;
 
        bw_khz /= 100;
 
-       dib7000p_write_word(state, 142 ,0x0610);
+       dib7000p_write_word(state, 1420x0610);
 
        for (k = 0; k < 8; k++) {
-               pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
+               pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
 
-               if (pha==0) {
+               if (pha == 0) {
                        coef_re[k] = 256;
                        coef_im[k] = 0;
-               } else if(pha < 256) {
-                       coef_re[k] = sine[256-(pha&0xff)];
-                       coef_im[k] = sine[pha&0xff];
+               } else if (pha < 256) {
+                       coef_re[k] = sine[256 - (pha & 0xff)];
+                       coef_im[k] = sine[pha & 0xff];
                } else if (pha == 256) {
                        coef_re[k] = 0;
                        coef_im[k] = 256;
                } else if (pha < 512) {
-                       coef_re[k] = -sine[pha&0xff];
-                       coef_im[k] = sine[256 - (pha&0xff)];
+                       coef_re[k] = -sine[pha & 0xff];
+                       coef_im[k] = sine[256 - (pha & 0xff)];
                } else if (pha == 512) {
                        coef_re[k] = -256;
                        coef_im[k] = 0;
                } else if (pha < 768) {
-                       coef_re[k] = -sine[256-(pha&0xff)];
-                       coef_im[k] = -sine[pha&0xff];
+                       coef_re[k] = -sine[256 - (pha & 0xff)];
+                       coef_im[k] = -sine[pha & 0xff];
                } else if (pha == 768) {
                        coef_re[k] = 0;
                        coef_im[k] = -256;
                } else {
-                       coef_re[k] = sine[pha&0xff];
-                       coef_im[k] = -sine[256 - (pha&0xff)];
+                       coef_re[k] = sine[pha & 0xff];
+                       coef_im[k] = -sine[256 - (pha & 0xff)];
                }
 
                coef_re[k] *= notch[k];
-               coef_re[k] += (1<<14);
-               if (coef_re[k] >= (1<<24))
-                       coef_re[k]  = (1<<24) - 1;
-               coef_re[k] /= (1<<15);
+               coef_re[k] += (1 << 14);
+               if (coef_re[k] >= (1 << 24))
+                       coef_re[k] = (1 << 24) - 1;
+               coef_re[k] /= (1 << 15);
 
                coef_im[k] *= notch[k];
-               coef_im[k] += (1<<14);
-               if (coef_im[k] >= (1<<24))
-                       coef_im[k]  = (1<<24)-1;
-               coef_im[k] /= (1<<15);
+               coef_im[k] += (1 << 14);
+               if (coef_im[k] >= (1 << 24))
+                       coef_im[k] = (1 << 24) - 1;
+               coef_im[k] /= (1 << 15);
 
-               dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+               dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
 
                dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
                dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
                dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
        }
-       dib7000p_write_word(state,143 ,0);
+       dib7000p_write_word(state, 143, 0);
 }
 
 static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
@@ -976,11 +1187,11 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
        /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
        tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
        if (state->sfn_workaround_active) {
-               dprintk( "SFN workaround is active");
+               dprintk("SFN workaround is active");
                tmp |= (1 << 9);
-               dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
+               dib7000p_write_word(state, 166, 0x4000);
        } else {
-               dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
+               dib7000p_write_word(state, 166, 0x0000);
        }
        dib7000p_write_word(state, 29, tmp);
 
@@ -993,51 +1204,72 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
        /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
        tmp = (6 << 8) | 0x80;
        switch (ch->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
-               case TRANSMISSION_MODE_4K: tmp |= (8 << 12); break;
-               default:
-               case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
+       case TRANSMISSION_MODE_2K:
+               tmp |= (2 << 12);
+               break;
+       case TRANSMISSION_MODE_4K:
+               tmp |= (3 << 12);
+               break;
+       default:
+       case TRANSMISSION_MODE_8K:
+               tmp |= (4 << 12);
+               break;
        }
-       dib7000p_write_word(state, 26, tmp);  /* timf_a(6xxx) */
+       dib7000p_write_word(state, 26, tmp);    /* timf_a(6xxx) */
 
        /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
        tmp = (0 << 4);
        switch (ch->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
-               case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
-               default:
-               case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
+       case TRANSMISSION_MODE_2K:
+               tmp |= 0x6;
+               break;
+       case TRANSMISSION_MODE_4K:
+               tmp |= 0x7;
+               break;
+       default:
+       case TRANSMISSION_MODE_8K:
+               tmp |= 0x8;
+               break;
        }
-       dib7000p_write_word(state, 32,  tmp);
+       dib7000p_write_word(state, 32, tmp);
 
        /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
        tmp = (0 << 4);
        switch (ch->u.ofdm.transmission_mode) {
-               case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
-               case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
-               default:
-               case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
+       case TRANSMISSION_MODE_2K:
+               tmp |= 0x6;
+               break;
+       case TRANSMISSION_MODE_4K:
+               tmp |= 0x7;
+               break;
+       default:
+       case TRANSMISSION_MODE_8K:
+               tmp |= 0x8;
+               break;
        }
-       dib7000p_write_word(state, 33,  tmp);
+       dib7000p_write_word(state, 33, tmp);
 
-       tmp = dib7000p_read_word(state,509);
+       tmp = dib7000p_read_word(state, 509);
        if (!((tmp >> 6) & 0x1)) {
                /* restart the fec */
-               tmp = dib7000p_read_word(state,771);
+               tmp = dib7000p_read_word(state, 771);
                dib7000p_write_word(state, 771, tmp | (1 << 1));
                dib7000p_write_word(state, 771, tmp);
-               msleep(10);
-               tmp = dib7000p_read_word(state,509);
+               msleep(40);
+               tmp = dib7000p_read_word(state, 509);
        }
-
        // we achieved a lock - it's time to update the osc freq
-       if ((tmp >> 6) & 0x1)
+       if ((tmp >> 6) & 0x1) {
                dib7000p_update_timf(state);
+               /* P_timf_alpha += 2 */
+               tmp = dib7000p_read_word(state, 26);
+               dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
+       }
 
        if (state->cfg.spur_protect)
-               dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+               dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 
-    dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+       dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
        return 0;
 }
 
@@ -1046,63 +1278,82 @@ static int dib7000p_wakeup(struct dvb_frontend *demod)
        struct dib7000p_state *state = demod->demodulator_priv;
        dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
        dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+       if (state->version == SOC7090)
+               dib7000p_sad_calib(state);
        return 0;
 }
 
 static int dib7000p_sleep(struct dvb_frontend *demod)
 {
        struct dib7000p_state *state = demod->demodulator_priv;
+       if (state->version == SOC7090)
+               return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
        return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
 }
 
 static int dib7000p_identify(struct dib7000p_state *st)
 {
        u16 value;
-       dprintk( "checking demod on I2C address: %d (%x)",
-               st->i2c_addr, st->i2c_addr);
+       dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
 
        if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
-               dprintk( "wrong Vendor ID (read=0x%x)",value);
+               dprintk("wrong Vendor ID (read=0x%x)", value);
                return -EREMOTEIO;
        }
 
        if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
-               dprintk( "wrong Device ID (%x)",value);
+               dprintk("wrong Device ID (%x)", value);
                return -EREMOTEIO;
        }
 
        return 0;
 }
 
-
-static int dib7000p_get_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
-       u16 tps = dib7000p_read_word(state,463);
+       u16 tps = dib7000p_read_word(state, 463);
 
        fep->inversion = INVERSION_AUTO;
 
        fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
 
        switch ((tps >> 8) & 0x3) {
-               case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
-               case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
-               /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
+       case 0:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 1:
+               fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
        }
 
        switch (tps & 0x3) {
-               case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
-               case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
-               case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
-               case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+       case 0:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+               break;
        }
 
        switch ((tps >> 14) & 0x3) {
-               case 0: fep->u.ofdm.constellation = QPSK; break;
-               case 1: fep->u.ofdm.constellation = QAM_16; break;
-               case 2:
-               default: fep->u.ofdm.constellation = QAM_64; break;
+       case 0:
+               fep->u.ofdm.constellation = QPSK;
+               break;
+       case 1:
+               fep->u.ofdm.constellation = QAM_16;
+               break;
+       case 2:
+       default:
+               fep->u.ofdm.constellation = QAM_64;
+               break;
        }
 
        /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
@@ -1110,22 +1361,42 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
 
        fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
        switch ((tps >> 5) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
-               case 7:
-               default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
+       case 1:
+               fep->u.ofdm.code_rate_HP = FEC_1_2;
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_HP = FEC_2_3;
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_HP = FEC_3_4;
+               break;
+       case 5:
+               fep->u.ofdm.code_rate_HP = FEC_5_6;
+               break;
+       case 7:
+       default:
+               fep->u.ofdm.code_rate_HP = FEC_7_8;
+               break;
 
        }
 
        switch ((tps >> 2) & 0x7) {
-               case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
-               case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
-               case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
-               case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
-               case 7:
-               default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+       case 1:
+               fep->u.ofdm.code_rate_LP = FEC_1_2;
+               break;
+       case 2:
+               fep->u.ofdm.code_rate_LP = FEC_2_3;
+               break;
+       case 3:
+               fep->u.ofdm.code_rate_LP = FEC_3_4;
+               break;
+       case 5:
+               fep->u.ofdm.code_rate_LP = FEC_5_6;
+               break;
+       case 7:
+       default:
+               fep->u.ofdm.code_rate_LP = FEC_7_8;
+               break;
        }
 
        /* native interleaver: (dib7000p_read_word(state, 464) >>  5) & 0x1 */
@@ -1133,15 +1404,18 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int dib7000p_set_frontend(struct dvb_frontend* fe,
-                               struct dvb_frontend_parameters *fep)
+static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        int time, ret;
 
-       dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
+       if (state->version == SOC7090) {
+               dib7090_set_diversity_in(fe, 0);
+               dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
+       } else
+               dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
 
-    /* maybe the parameter has been changed */
+       /* maybe the parameter has been changed */
        state->sfn_workaround_active = buggy_sfn_workaround;
 
        if (fe->ops.tuner_ops.set_params)
@@ -1156,9 +1430,7 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
        } while (time != -1);
 
        if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
-               fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
-               fep->u.ofdm.constellation     == QAM_AUTO ||
-               fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
+               fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
                int i = 800, found;
 
                dib7000p_autosearch_start(fe, fep);
@@ -1167,9 +1439,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
                        found = dib7000p_autosearch_is_irq(fe);
                } while (found == 0 && i--);
 
-               dprintk("autosearch returns: %d",found);
+               dprintk("autosearch returns: %d", found);
                if (found == 0 || found == 1)
-                       return 0; // no channel found
+                       return 0;
 
                dib7000p_get_frontend(fe, fep);
        }
@@ -1177,11 +1449,15 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
        ret = dib7000p_tune(fe, fep);
 
        /* make this a config parameter */
-       dib7000p_set_output_mode(state, state->cfg.output_mode);
-    return ret;
+       if (state->version == SOC7090)
+               dib7090_set_output_mode(fe, state->cfg.output_mode);
+       else
+               dib7000p_set_output_mode(state, state->cfg.output_mode);
+
+       return ret;
 }
 
-static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 lock = dib7000p_read_word(state, 509);
@@ -1196,27 +1472,27 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
                *stat |= FE_HAS_VITERBI;
        if (lock & 0x0010)
                *stat |= FE_HAS_SYNC;
-    if ((lock & 0x0038) == 0x38)
+       if ((lock & 0x0038) == 0x38)
                *stat |= FE_HAS_LOCK;
 
        return 0;
 }
 
-static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
        return 0;
 }
 
-static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
+static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        *unc = dib7000p_read_word(state, 506);
        return 0;
 }
 
-static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 val = dib7000p_read_word(state, 394);
@@ -1224,7 +1500,7 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
        return 0;
 }
 
-static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
+static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
 {
        struct dib7000p_state *state = fe->demodulator_priv;
        u16 val;
@@ -1240,19 +1516,17 @@ static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
                noise_exp -= 0x40;
 
        signal_mant = (val >> 6) & 0xFF;
-       signal_exp  = (val & 0x3F);
+       signal_exp = (val & 0x3F);
        if ((signal_exp & 0x20) != 0)
                signal_exp -= 0x40;
 
        if (signal_mant != 0)
-               result = intlog10(2) * 10 * signal_exp + 10 *
-                       intlog10(signal_mant);
+               result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
        else
                result = intlog10(2) * 10 * signal_exp - 100;
 
        if (noise_mant != 0)
-               result -= intlog10(2) * 10 * noise_exp + 10 *
-                       intlog10(noise_mant);
+               result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
        else
                result -= intlog10(2) * 10 * noise_exp - 100;
 
@@ -1260,7 +1534,7 @@ static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
        return 0;
 }
 
-static int dib7000p_fe_get_tune_settings(struct dvb_frontendfe, struct dvb_frontend_tune_settings *tune)
+static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
 {
        tune->min_delay_ms = 1000;
        return 0;
@@ -1270,6 +1544,7 @@ static void dib7000p_release(struct dvb_frontend *demod)
 {
        struct dib7000p_state *st = demod->demodulator_priv;
        dibx000_exit_i2c_master(&st->i2c_master);
+       i2c_del_adapter(&st->dib7090_tuner_adap);
        kfree(st);
 }
 
@@ -1277,8 +1552,8 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
 {
        u8 tx[2], rx[2];
        struct i2c_msg msg[2] = {
-               { .addr = 18 >> 1, .flags = 0,        .buf = tx, .len = 2 },
-               { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
+               {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
+               {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
        };
 
        tx[0] = 0x03;
@@ -1303,7 +1578,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
 }
 EXPORT_SYMBOL(dib7000pc_detection);
 
-struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
 {
        struct dib7000p_state *st = demod->demodulator_priv;
        return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
@@ -1312,19 +1587,19 @@ EXPORT_SYMBOL(dib7000p_get_i2c_master);
 
 int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
-    struct dib7000p_state *state = fe->demodulator_priv;
-    u16 val = dib7000p_read_word(state, 235) & 0xffef;
-    val |= (onoff & 0x1) << 4;
-    dprintk("PID filter enabled %d", onoff);
-    return dib7000p_write_word(state, 235, val);
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 val = dib7000p_read_word(state, 235) & 0xffef;
+       val |= (onoff & 0x1) << 4;
+       dprintk("PID filter enabled %d", onoff);
+       return dib7000p_write_word(state, 235, val);
 }
 EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
 
 int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
-    struct dib7000p_state *state = fe->demodulator_priv;
-    dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
-    return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
+       struct dib7000p_state *state = fe->demodulator_priv;
+       dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
+       return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
 }
 EXPORT_SYMBOL(dib7000p_pid_filter);
 
@@ -1340,16 +1615,19 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
 
        dpst->i2c_adap = i2c;
 
-       for (k = no_of_demods-1; k >= 0; k--) {
+       for (k = no_of_demods - 1; k >= 0; k--) {
                dpst->cfg = cfg[k];
 
                /* designated i2c address */
-               new_addr          = (0x40 + k) << 1;
+               if (cfg[k].default_i2c_addr != 0)
+                       new_addr = cfg[k].default_i2c_addr + (k << 1);
+               else
+                       new_addr = (0x40 + k) << 1;
                dpst->i2c_addr = new_addr;
-               dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
+               dib7000p_write_word(dpst, 1287, 0x0003);        /* sram lead in, rdy */
                if (dib7000p_identify(dpst) != 0) {
                        dpst->i2c_addr = default_addr;
-                       dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
+                       dib7000p_write_word(dpst, 1287, 0x0003);        /* sram lead in, rdy */
                        if (dib7000p_identify(dpst) != 0) {
                                dprintk("DiB7000P #%d: not identified\n", k);
                                kfree(dpst);
@@ -1368,7 +1646,10 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
 
        for (k = 0; k < no_of_demods; k++) {
                dpst->cfg = cfg[k];
-               dpst->i2c_addr = (0x40 + k) << 1;
+               if (cfg[k].default_i2c_addr != 0)
+                       dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
+               else
+                       dpst->i2c_addr = (0x40 + k) << 1;
 
                // unforce divstr
                dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
@@ -1382,8 +1663,613 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
 }
 EXPORT_SYMBOL(dib7000p_i2c_enumeration);
 
+static const s32 lut_1000ln_mant[] = {
+       6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
+};
+
+static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u32 tmp_val = 0, exp = 0, mant = 0;
+       s32 pow_i;
+       u16 buf[2];
+       u8 ix = 0;
+
+       buf[0] = dib7000p_read_word(state, 0x184);
+       buf[1] = dib7000p_read_word(state, 0x185);
+       pow_i = (buf[0] << 16) | buf[1];
+       dprintk("raw pow_i = %d", pow_i);
+
+       tmp_val = pow_i;
+       while (tmp_val >>= 1)
+               exp++;
+
+       mant = (pow_i * 1000 / (1 << exp));
+       dprintk(" mant = %d exp = %d", mant / 1000, exp);
+
+       ix = (u8) ((mant - 1000) / 100);        /* index of the LUT */
+       dprintk(" ix = %d", ix);
+
+       pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
+       pow_i = (pow_i << 8) / 1000;
+       dprintk(" pow_i = %d", pow_i);
+
+       return pow_i;
+}
+
+static int map_addr_to_serpar_number(struct i2c_msg *msg)
+{
+       if ((msg->buf[0] <= 15))
+               msg->buf[0] -= 1;
+       else if (msg->buf[0] == 17)
+               msg->buf[0] = 15;
+       else if (msg->buf[0] == 16)
+               msg->buf[0] = 17;
+       else if (msg->buf[0] == 19)
+               msg->buf[0] = 16;
+       else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
+               msg->buf[0] -= 3;
+       else if (msg->buf[0] == 28)
+               msg->buf[0] = 23;
+       else
+               return -EINVAL;
+       return 0;
+}
+
+static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+       u8 n_overflow = 1;
+       u16 i = 1000;
+       u16 serpar_num = msg[0].buf[0];
+
+       while (n_overflow == 1 && i) {
+               n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
+               i--;
+               if (i == 0)
+                       dprintk("Tuner ITF: write busy (overflow)");
+       }
+       dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
+       dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
+
+       return num;
+}
+
+static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+       u8 n_overflow = 1, n_empty = 1;
+       u16 i = 1000;
+       u16 serpar_num = msg[0].buf[0];
+       u16 read_word;
+
+       while (n_overflow == 1 && i) {
+               n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
+               i--;
+               if (i == 0)
+                       dprintk("TunerITF: read busy (overflow)");
+       }
+       dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
+
+       i = 1000;
+       while (n_empty == 1 && i) {
+               n_empty = dib7000p_read_word(state, 1984) & 0x1;
+               i--;
+               if (i == 0)
+                       dprintk("TunerITF: read busy (empty)");
+       }
+       read_word = dib7000p_read_word(state, 1987);
+       msg[1].buf[0] = (read_word >> 8) & 0xff;
+       msg[1].buf[1] = (read_word) & 0xff;
+
+       return num;
+}
+
+static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       if (map_addr_to_serpar_number(&msg[0]) == 0) {  /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
+               if (num == 1) { /* write */
+                       return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
+               } else {        /* read */
+                       return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
+               }
+       }
+       return num;
+}
+
+int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
+{
+       struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+       u16 word;
+
+       if (num == 1) {         /* write */
+               dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
+       } else {
+               word = dib7000p_read_word(state, apb_address);
+               msg[1].buf[0] = (word >> 8) & 0xff;
+               msg[1].buf[1] = (word) & 0xff;
+       }
+
+       return num;
+}
+
+static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
+
+       u16 apb_address = 0, word;
+       int i = 0;
+       switch (msg[0].buf[0]) {
+       case 0x12:
+               apb_address = 1920;
+               break;
+       case 0x14:
+               apb_address = 1921;
+               break;
+       case 0x24:
+               apb_address = 1922;
+               break;
+       case 0x1a:
+               apb_address = 1923;
+               break;
+       case 0x22:
+               apb_address = 1924;
+               break;
+       case 0x33:
+               apb_address = 1926;
+               break;
+       case 0x34:
+               apb_address = 1927;
+               break;
+       case 0x35:
+               apb_address = 1928;
+               break;
+       case 0x36:
+               apb_address = 1929;
+               break;
+       case 0x37:
+               apb_address = 1930;
+               break;
+       case 0x38:
+               apb_address = 1931;
+               break;
+       case 0x39:
+               apb_address = 1932;
+               break;
+       case 0x2a:
+               apb_address = 1935;
+               break;
+       case 0x2b:
+               apb_address = 1936;
+               break;
+       case 0x2c:
+               apb_address = 1937;
+               break;
+       case 0x2d:
+               apb_address = 1938;
+               break;
+       case 0x2e:
+               apb_address = 1939;
+               break;
+       case 0x2f:
+               apb_address = 1940;
+               break;
+       case 0x30:
+               apb_address = 1941;
+               break;
+       case 0x31:
+               apb_address = 1942;
+               break;
+       case 0x32:
+               apb_address = 1943;
+               break;
+       case 0x3e:
+               apb_address = 1944;
+               break;
+       case 0x3f:
+               apb_address = 1945;
+               break;
+       case 0x40:
+               apb_address = 1948;
+               break;
+       case 0x25:
+               apb_address = 914;
+               break;
+       case 0x26:
+               apb_address = 915;
+               break;
+       case 0x27:
+               apb_address = 916;
+               break;
+       case 0x28:
+               apb_address = 917;
+               break;
+       case 0x1d:
+               i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
+               word = dib7000p_read_word(state, 384 + i);
+               msg[1].buf[0] = (word >> 8) & 0xff;
+               msg[1].buf[1] = (word) & 0xff;
+               return num;
+       case 0x1f:
+               if (num == 1) { /* write */
+                       word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
+                       word &= 0x3;
+                       word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
+                       dib7000p_write_word(state, 72, word);   /* Set the proper input */
+                       return num;
+               }
+       }
+
+       if (apb_address != 0)   /* R/W acces via APB */
+               return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
+       else                    /* R/W access via SERPAR  */
+               return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
+
+       return 0;
+}
+
+static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib7090_tuner_xfer_algo = {
+       .master_xfer = dib7090_tuner_xfer,
+       .functionality = dib7000p_i2c_func,
+};
+
+struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+{
+       struct dib7000p_state *st = fe->demodulator_priv;
+       return &st->dib7090_tuner_adap;
+}
+EXPORT_SYMBOL(dib7090_get_i2c_tuner);
+
+static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
+{
+       u16 reg;
+
+       /* drive host bus 2, 3, 4 */
+       reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive << 12) | (drive << 6) | drive;
+       dib7000p_write_word(state, 1798, reg);
+
+       /* drive host bus 5,6 */
+       reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
+       reg |= (drive << 8) | (drive << 2);
+       dib7000p_write_word(state, 1799, reg);
+
+       /* drive host bus 7, 8, 9 */
+       reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive << 12) | (drive << 6) | drive;
+       dib7000p_write_word(state, 1800, reg);
+
+       /* drive host bus 10, 11 */
+       reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
+       reg |= (drive << 8) | (drive << 2);
+       dib7000p_write_word(state, 1801, reg);
+
+       /* drive host bus 12, 13, 14 */
+       reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
+       reg |= (drive << 12) | (drive << 6) | drive;
+       dib7000p_write_word(state, 1802, reg);
+
+       return 0;
+}
+
+static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
+{
+       u32 quantif = 3;
+       u32 nom = (insertExtSynchro * P_Kin + syncSize);
+       u32 denom = P_Kout;
+       u32 syncFreq = ((nom << quantif) / denom);
+
+       if ((syncFreq & ((1 << quantif) - 1)) != 0)
+               syncFreq = (syncFreq >> quantif) + 1;
+       else
+               syncFreq = (syncFreq >> quantif);
+
+       if (syncFreq != 0)
+               syncFreq = syncFreq - 1;
+
+       return syncFreq;
+}
+
+static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
+{
+       u8 index_buf;
+       u16 rx_copy_buf[22];
+
+       dprintk("Configure DibStream Tx");
+       for (index_buf = 0; index_buf < 22; index_buf++)
+               rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
+
+       dib7000p_write_word(state, 1615, 1);
+       dib7000p_write_word(state, 1603, P_Kin);
+       dib7000p_write_word(state, 1605, P_Kout);
+       dib7000p_write_word(state, 1606, insertExtSynchro);
+       dib7000p_write_word(state, 1608, synchroMode);
+       dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
+       dib7000p_write_word(state, 1610, syncWord & 0xffff);
+       dib7000p_write_word(state, 1612, syncSize);
+       dib7000p_write_word(state, 1615, 0);
+
+       for (index_buf = 0; index_buf < 22; index_buf++)
+               dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
+
+       return 0;
+}
+
+static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
+               u32 dataOutRate)
+{
+       u32 syncFreq;
+
+       dprintk("Configure DibStream Rx");
+       if ((P_Kin != 0) && (P_Kout != 0)) {
+               syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
+               dib7000p_write_word(state, 1542, syncFreq);
+       }
+       dib7000p_write_word(state, 1554, 1);
+       dib7000p_write_word(state, 1536, P_Kin);
+       dib7000p_write_word(state, 1537, P_Kout);
+       dib7000p_write_word(state, 1539, synchroMode);
+       dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
+       dib7000p_write_word(state, 1541, syncWord & 0xffff);
+       dib7000p_write_word(state, 1543, syncSize);
+       dib7000p_write_word(state, 1544, dataOutRate);
+       dib7000p_write_word(state, 1554, 0);
+
+       return 0;
+}
+
+static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
+{
+       u16 reg;
+
+       dprintk("Enable Diversity on host bus");
+       reg = (1 << 8) | (1 << 5);
+       dib7000p_write_word(state, 1288, reg);
+
+       return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
+}
+
+static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
+{
+       u16 reg;
+
+       dprintk("Enable ADC on host bus");
+       reg = (1 << 7) | (1 << 5);
+       dib7000p_write_word(state, 1288, reg);
+
+       return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
+}
+
+static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
+{
+       u16 reg;
+
+       dprintk("Enable Mpeg on host bus");
+       reg = (1 << 9) | (1 << 5);
+       dib7000p_write_word(state, 1288, reg);
+
+       return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
+}
+
+static int dib7090_enMpegInput(struct dib7000p_state *state)
+{
+       dprintk("Enable Mpeg input");
+       return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);   /*outputRate = 8 */
+}
+
+static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
+{
+       u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
+
+       dprintk("Enable Mpeg mux");
+       dib7000p_write_word(state, 1287, reg);
+
+       reg &= ~(1 << 7);
+       dib7000p_write_word(state, 1287, reg);
+
+       reg = (1 << 4);
+       dib7000p_write_word(state, 1288, reg);
+
+       return 0;
+}
+
+static int dib7090_disableMpegMux(struct dib7000p_state *state)
+{
+       u16 reg;
+
+       dprintk("Disable Mpeg mux");
+       dib7000p_write_word(state, 1288, 0);
+
+       reg = dib7000p_read_word(state, 1287);
+       reg &= ~(1 << 7);
+       dib7000p_write_word(state, 1287, reg);
+
+       return 0;
+}
+
+static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+
+       switch (mode) {
+       case INPUT_MODE_DIVERSITY:
+                       dprintk("Enable diversity INPUT");
+                       dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
+                       break;
+       case INPUT_MODE_MPEG:
+                       dprintk("Enable Mpeg INPUT");
+                       dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
+                       break;
+       case INPUT_MODE_OFF:
+       default:
+                       dprintk("Disable INPUT");
+                       dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
+                       break;
+       }
+       return 0;
+}
+
+static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+       switch (onoff) {
+       case 0:         /* only use the internal way - not the diversity input */
+               dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
+               break;
+       case 1:         /* both ways */
+       case 2:         /* only the diversity input */
+               dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
+               break;
+       }
+
+       return 0;
+}
+
+static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+
+       u16 outreg, smo_mode, fifo_threshold;
+       u8 prefer_mpeg_mux_use = 1;
+       int ret = 0;
+
+       dib7090_host_bus_drive(state, 1);
+
+       fifo_threshold = 1792;
+       smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
+       outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
+
+       switch (mode) {
+       case OUTMODE_HIGH_Z:
+               outreg = 0;
+               break;
+
+       case OUTMODE_MPEG2_SERIAL:
+               if (prefer_mpeg_mux_use) {
+                       dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
+                       dib7090_enMpegOnHostBus(state);
+                       dib7090_enMpegInput(state);
+                       if (state->cfg.enMpegOutput == 1)
+                               dib7090_enMpegMux(state, 3, 1, 1);
+
+               } else {        /* Use Smooth block */
+                       dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
+                       dib7090_disableMpegMux(state);
+                       dib7000p_write_word(state, 1288, (1 << 6));
+                       outreg |= (2 << 6) | (0 << 1);
+               }
+               break;
+
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+               if (prefer_mpeg_mux_use) {
+                       dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
+                       dib7090_enMpegOnHostBus(state);
+                       dib7090_enMpegInput(state);
+                       if (state->cfg.enMpegOutput == 1)
+                               dib7090_enMpegMux(state, 2, 0, 0);
+               } else {        /* Use Smooth block */
+                       dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
+                       dib7090_disableMpegMux(state);
+                       dib7000p_write_word(state, 1288, (1 << 6));
+                       outreg |= (0 << 6);
+               }
+               break;
+
+       case OUTMODE_MPEG2_PAR_CONT_CLK:        /* Using Smooth block only */
+               dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
+               dib7090_disableMpegMux(state);
+               dib7000p_write_word(state, 1288, (1 << 6));
+               outreg |= (1 << 6);
+               break;
+
+       case OUTMODE_MPEG2_FIFO:        /* Using Smooth block because not supported by new Mpeg Mux bloc */
+               dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
+               dib7090_disableMpegMux(state);
+               dib7000p_write_word(state, 1288, (1 << 6));
+               outreg |= (5 << 6);
+               smo_mode |= (3 << 1);
+               fifo_threshold = 512;
+               break;
+
+       case OUTMODE_DIVERSITY:
+               dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
+               dib7090_disableMpegMux(state);
+               dib7090_enDivOnHostBus(state);
+               break;
+
+       case OUTMODE_ANALOG_ADC:
+               dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
+               dib7090_enAdcOnHostBus(state);
+               break;
+       }
+
+       if (state->cfg.output_mpeg2_in_188_bytes)
+               smo_mode |= (1 << 5);
+
+       ret |= dib7000p_write_word(state, 235, smo_mode);
+       ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
+       ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10));    /* allways set Dout active = 1 !!! */
+
+       return ret;
+}
+
+int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 en_cur_state;
+
+       dprintk("sleep dib7090: %d", onoff);
+
+       en_cur_state = dib7000p_read_word(state, 1922);
+
+       if (en_cur_state > 0xff)
+               state->tuner_enable = en_cur_state;
+
+       if (onoff)
+               en_cur_state &= 0x00ff;
+       else {
+               if (state->tuner_enable != 0)
+                       en_cur_state = state->tuner_enable;
+       }
+
+       dib7000p_write_word(state, 1922, en_cur_state);
+
+       return 0;
+}
+EXPORT_SYMBOL(dib7090_tuner_sleep);
+
+int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
+{
+       dprintk("AGC restart callback: %d", restart);
+       return 0;
+}
+EXPORT_SYMBOL(dib7090_agc_restart);
+
+int dib7090_get_adc_power(struct dvb_frontend *fe)
+{
+       return dib7000p_get_adc_power(fe);
+}
+EXPORT_SYMBOL(dib7090_get_adc_power);
+
+int dib7090_slave_reset(struct dvb_frontend *fe)
+{
+       struct dib7000p_state *state = fe->demodulator_priv;
+       u16 reg;
+
+       reg = dib7000p_read_word(state, 1794);
+       dib7000p_write_word(state, 1794, reg | (4 << 12));
+
+       dib7000p_write_word(state, 1032, 0xffff);
+       return 0;
+}
+EXPORT_SYMBOL(dib7090_slave_reset);
+
 static struct dvb_frontend_ops dib7000p_ops;
-struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
 {
        struct dvb_frontend *demod;
        struct dib7000p_state *st;
@@ -1400,28 +2286,41 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
        /* Ensure the output mode remains at the previous default if it's
         * not specifically set by the caller.
         */
-       if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
-           (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
+       if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
                st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
 
-       demod                   = &st->demod;
+       demod = &st->demod;
        demod->demodulator_priv = st;
        memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
 
-    dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
+       dib7000p_write_word(st, 1287, 0x0003);  /* sram lead in, rdy */
 
        if (dib7000p_identify(st) != 0)
                goto error;
 
+       st->version = dib7000p_read_word(st, 897);
+
        /* FIXME: make sure the dev.parent field is initialized, or else
-       request_firmware() will hit an OOPS (this should be moved somewhere
-       more common) */
-       st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+               request_firmware() will hit an OOPS (this should be moved somewhere
+               more common) */
 
        dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
 
+       /* init 7090 tuner adapter */
+       strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
+       st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
+       st->dib7090_tuner_adap.algo_data = NULL;
+       st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
+       i2c_set_adapdata(&st->dib7090_tuner_adap, st);
+       i2c_add_adapter(&st->dib7090_tuner_adap);
+
        dib7000p_demod_reset(st);
 
+       if (st->version == SOC7090) {
+               dib7090_set_output_mode(demod, st->cfg.output_mode);
+               dib7090_set_diversity_in(demod, 0);
+       }
+
        return demod;
 
 error:
@@ -1432,37 +2331,35 @@ EXPORT_SYMBOL(dib7000p_attach);
 
 static struct dvb_frontend_ops dib7000p_ops = {
        .info = {
-               .name = "DiBcom 7000PC",
-               .type = FE_OFDM,
-               .frequency_min      = 44250000,
-               .frequency_max      = 867250000,
-               .frequency_stepsize = 62500,
-               .caps = FE_CAN_INVERSION_AUTO |
-                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO |
-                       FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_RECOVER |
-                       FE_CAN_HIERARCHY_AUTO,
-       },
-
-       .release              = dib7000p_release,
-
-       .init                 = dib7000p_wakeup,
-       .sleep                = dib7000p_sleep,
-
-       .set_frontend         = dib7000p_set_frontend,
-       .get_tune_settings    = dib7000p_fe_get_tune_settings,
-       .get_frontend         = dib7000p_get_frontend,
-
-       .read_status          = dib7000p_read_status,
-       .read_ber             = dib7000p_read_ber,
+                .name = "DiBcom 7000PC",
+                .type = FE_OFDM,
+                .frequency_min = 44250000,
+                .frequency_max = 867250000,
+                .frequency_stepsize = 62500,
+                .caps = FE_CAN_INVERSION_AUTO |
+                FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
+                },
+
+       .release = dib7000p_release,
+
+       .init = dib7000p_wakeup,
+       .sleep = dib7000p_sleep,
+
+       .set_frontend = dib7000p_set_frontend,
+       .get_tune_settings = dib7000p_fe_get_tune_settings,
+       .get_frontend = dib7000p_get_frontend,
+
+       .read_status = dib7000p_read_status,
+       .read_ber = dib7000p_read_ber,
        .read_signal_strength = dib7000p_read_signal_strength,
-       .read_snr             = dib7000p_read_snr,
-       .read_ucblocks        = dib7000p_read_unc_blocks,
+       .read_snr = dib7000p_read_snr,
+       .read_ucblocks = dib7000p_read_unc_blocks,
 };
 
+MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
 MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
 MODULE_LICENSE("GPL");
index da17345bf5bdd66002ea64080e2c4456bfde1ca3..0179f9474bac050054c2842626edb97697e53b6f 100644 (file)
@@ -33,59 +33,54 @@ struct dib7000p_config {
        int (*agc_control) (struct dvb_frontend *, u8 before);
 
        u8 output_mode;
-       u8 disable_sample_and_hold : 1;
+       u8 disable_sample_and_hold:1;
 
-       u8 enable_current_mirror : 1;
-       u8 diversity_delay;
+       u8 enable_current_mirror:1;
+       u16 diversity_delay;
 
+       u8 default_i2c_addr;
+       u8 enMpegOutput:1;
 };
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
 
 #if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
-                                    defined(MODULE))
-extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
-                                           u8 i2c_addr,
-                                           struct dib7000p_config *cfg);
-extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *,
-                                                  enum dibx000_i2c_interface,
-                                                  int);
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
-                                   int no_of_demods, u8 default_addr,
-                                   struct dib7000p_config cfg[]);
+                                       defined(MODULE))
+extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
 extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
 extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
 extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
 extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
+extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
+extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
+extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart);
+extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
+extern int dib7090_get_adc_power(struct dvb_frontend *fe);
+extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
+extern int dib7090_slave_reset(struct dvb_frontend *fe);
 #else
-static inline
-struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
-                                    struct dib7000p_config *cfg)
+static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
 
-static inline
-struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
-                                           enum dibx000_i2c_interface i,
-                                           int x)
+static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
 
-static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
-                                          int no_of_demods, u8 default_addr,
-                                          struct dib7000p_config cfg[])
+static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
 
-static inline int dib7000p_set_gpio(struct dvb_frontend *fe,
-                                   u8 num, u8 dir, u8 val)
+static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
@@ -102,16 +97,59 @@ static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
+
 static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
-    printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-    return -ENODEV;
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
 }
 
 static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
 {
-    printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-    return -ENODEV;
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib7090_get_adc_power(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline int dib7090_slave_reset(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
 }
 #endif
 
index df17b91b3250b45596619a6a752d63061f4c8a45..c1c3e26906e2843b7893fa666c4929cf8442e7e4 100644 (file)
@@ -22,6 +22,7 @@
 #define LAYER_C   3
 
 #define FE_CALLBACK_TIME_NEVER 0xffffffff
+#define MAX_NUMBER_OF_FRONTENDS 6
 
 static int debug;
 module_param(debug, int, 0644);
@@ -37,7 +38,6 @@ struct i2c_device {
 };
 
 struct dib8000_state {
-       struct dvb_frontend fe;
        struct dib8000_config cfg;
 
        struct i2c_device i2c;
@@ -68,6 +68,8 @@ struct dib8000_state {
        u8 isdbt_cfg_loaded;
        enum frontend_tune_state tune_state;
        u32 status;
+
+       struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
 };
 
 enum dib8000_power_mode {
@@ -122,111 +124,111 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
        return dib8000_i2c_write16(&state->i2c, reg, val);
 }
 
-static const int16_t coeff_2k_sb_1seg_dqpsk[8] = {
+static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
        (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
-           (920 << 5) | 0x09
+               (920 << 5) | 0x09
 };
 
-static const int16_t coeff_2k_sb_1seg[8] = {
+static const s16 coeff_2k_sb_1seg[8] = {
        (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
 };
 
-static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
        (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
-           (-931 << 5) | 0x0f
+               (-931 << 5) | 0x0f
 };
 
-static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = {
+static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
        (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
-           (982 << 5) | 0x0c
+               (982 << 5) | 0x0c
 };
 
-static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = {
+static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
        (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
-           (-720 << 5) | 0x0d
+               (-720 << 5) | 0x0d
 };
 
-static const int16_t coeff_2k_sb_3seg[8] = {
+static const s16 coeff_2k_sb_3seg[8] = {
        (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
-           (-610 << 5) | 0x0a
+               (-610 << 5) | 0x0a
 };
 
-static const int16_t coeff_4k_sb_1seg_dqpsk[8] = {
+static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
        (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
-           (-922 << 5) | 0x0d
+               (-922 << 5) | 0x0d
 };
 
-static const int16_t coeff_4k_sb_1seg[8] = {
+static const s16 coeff_4k_sb_1seg[8] = {
        (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
-           (-655 << 5) | 0x0a
+               (-655 << 5) | 0x0a
 };
 
-static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
        (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
-           (-958 << 5) | 0x13
+               (-958 << 5) | 0x13
 };
 
-static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = {
+static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
        (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
-           (-568 << 5) | 0x0f
+               (-568 << 5) | 0x0f
 };
 
-static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = {
+static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
        (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
-           (-848 << 5) | 0x13
+               (-848 << 5) | 0x13
 };
 
-static const int16_t coeff_4k_sb_3seg[8] = {
+static const s16 coeff_4k_sb_3seg[8] = {
        (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
-           (-869 << 5) | 0x13
+               (-869 << 5) | 0x13
 };
 
-static const int16_t coeff_8k_sb_1seg_dqpsk[8] = {
+static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
        (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
-           (-598 << 5) | 0x10
+               (-598 << 5) | 0x10
 };
 
-static const int16_t coeff_8k_sb_1seg[8] = {
+static const s16 coeff_8k_sb_1seg[8] = {
        (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
-           (585 << 5) | 0x0f
+               (585 << 5) | 0x0f
 };
 
-static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
+static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
        (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
-           (0 << 5) | 0x14
+               (0 << 5) | 0x14
 };
 
-static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = {
+static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
        (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
-           (-877 << 5) | 0x15
+               (-877 << 5) | 0x15
 };
 
-static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = {
+static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
        (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
-           (-921 << 5) | 0x14
+               (-921 << 5) | 0x14
 };
 
-static const int16_t coeff_8k_sb_3seg[8] = {
+static const s16 coeff_8k_sb_3seg[8] = {
        (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
-           (690 << 5) | 0x14
+               (690 << 5) | 0x14
 };
 
-static const int16_t ana_fe_coeff_3seg[24] = {
+static const s16 ana_fe_coeff_3seg[24] = {
        81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
 };
 
-static const int16_t ana_fe_coeff_1seg[24] = {
+static const s16 ana_fe_coeff_1seg[24] = {
        249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
 };
 
-static const int16_t ana_fe_coeff_13seg[24] = {
+static const s16 ana_fe_coeff_13seg[24] = {
        396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
 };
 
 static u16 fft_to_mode(struct dib8000_state *state)
 {
        u16 mode;
-       switch (state->fe.dtv_property_cache.transmission_mode) {
+       switch (state->fe[0]->dtv_property_cache.transmission_mode) {
        case TRANSMISSION_MODE_2K:
                mode = 1;
                break;
@@ -249,16 +251,18 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state)
        dprintk("acquisition mode activated");
        dib8000_write_word(state, 298, nud);
 }
-
-static int dib8000_set_output_mode(struct dib8000_state *state, int mode)
+static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
 {
+       struct dib8000_state *state = fe->demodulator_priv;
+
        u16 outreg, fifo_threshold, smo_mode, sram = 0x0205;    /* by default SDRAM deintlv is enabled */
 
        outreg = 0;
        fifo_threshold = 1792;
        smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
 
-       dprintk("-I-  Setting output mode for demod %p to %d", &state->fe, mode);
+       dprintk("-I-    Setting output mode for demod %p to %d",
+                       &state->fe[0], mode);
 
        switch (mode) {
        case OUTMODE_MPEG2_PAR_GATED_CLK:       // STBs with parallel gated clock
@@ -292,7 +296,8 @@ static int dib8000_set_output_mode(struct dib8000_state *state, int mode)
                break;
 
        default:
-               dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe);
+               dprintk("Unhandled output_mode passed to be set for demod %p",
+                               &state->fe[0]);
                return -EINVAL;
        }
 
@@ -342,7 +347,8 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
 {
        /* by default everything is going to be powered off */
        u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
-           reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
+               reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
+               reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
 
        /* now, depending on the requested mode, we power on */
        switch (mode) {
@@ -411,8 +417,9 @@ static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_s
        return ret;
 }
 
-static int dib8000_set_bandwidth(struct dib8000_state *state, u32 bw)
+static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
 {
+       struct dib8000_state *state = fe->demodulator_priv;
        u32 timf;
 
        if (bw == 0)
@@ -478,7 +485,8 @@ static void dib8000_reset_pll(struct dib8000_state *state)
 
        // clk_cfg1
        clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
-           (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0);
+               (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
+               (pll->pll_range << 1) | (pll->pll_reset << 0);
 
        dib8000_write_word(state, 902, clk_cfg1);
        clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
@@ -488,11 +496,12 @@ static void dib8000_reset_pll(struct dib8000_state *state)
 
        /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
        if (state->cfg.pll->ADClkSrc == 0)
-               dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
+               dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
+                               (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
        else if (state->cfg.refclksel != 0)
-               dib8000_write_word(state, 904,
-                                  (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll->
-                                                                                                                       ADClkSrc << 7) | (0 << 1));
+               dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
+                               ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
+                               (pll->ADClkSrc << 7) | (0 << 1));
        else
                dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
 
@@ -560,7 +569,7 @@ static const u16 dib8000_defaults[] = {
        0xd4c0,
 
        /*1, 32,
-          0x6680 // P_corm_thres Lock algorithms configuration */
+               0x6680 // P_corm_thres Lock algorithms configuration */
 
        11, 80,                 /* set ADC level to -16 */
        (1 << 13) - 825 - 117,
@@ -623,14 +632,14 @@ static const u16 dib8000_defaults[] = {
        1, 285,
        0x0020,                 //p_fec_
        1, 299,
-       0x0062,                 // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+       0x0062,                 /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
 
        1, 338,
        (1 << 12) |             // P_ctrl_corm_thres4pre_freq_inh=1
-           (1 << 10) |         // P_ctrl_pre_freq_mode_sat=1
-           (0 << 9) |          // P_ctrl_pre_freq_inh=0
-           (3 << 5) |          // P_ctrl_pre_freq_step=3
-           (1 << 0),           // P_pre_freq_win_len=1
+               (1 << 10) |
+               (0 << 9) |              /* P_ctrl_pre_freq_inh=0 */
+               (3 << 5) |              /* P_ctrl_pre_freq_step=3 */
+               (1 << 0),               /* P_pre_freq_win_len=1 */
 
        1, 903,
        (0 << 4) | 2,           // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
@@ -717,7 +726,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
        if (dib8000_reset_gpio(state) != 0)
                dprintk("GPIO reset was not successful.");
 
-       if (dib8000_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
+       if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
                dprintk("OUTPUT_MODE could not be resetted.");
 
        state->current_agc = NULL;
@@ -752,7 +761,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
        /* unforce divstr regardless whether i2c enumeration was done or not */
        dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
 
-       dib8000_set_bandwidth(state, 6000);
+       dib8000_set_bandwidth(fe, 6000);
 
        dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
        dib8000_sad_calib(state);
@@ -778,7 +787,7 @@ static int dib8000_update_lna(struct dib8000_state *state)
                // read dyn_gain here (because it is demod-dependent and not tuner)
                dyn_gain = dib8000_read_word(state, 390);
 
-               if (state->cfg.update_lna(&state->fe, dyn_gain)) {      // LNA has changed
+               if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
                        dib8000_restart_agc(state);
                        return 1;
                }
@@ -865,7 +874,8 @@ static int dib8000_agc_soft_split(struct dib8000_state *state)
                split_offset = state->current_agc->split.max;
        else
                split_offset = state->current_agc->split.max *
-                   (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
+                       (agc - state->current_agc->split.min_thres) /
+                       (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
 
        dprintk("AGC split_offset: %d", split_offset);
 
@@ -900,7 +910,7 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
        case CT_AGC_STEP_0:
                //AGC initialization
                if (state->cfg.agc_control)
-                       state->cfg.agc_control(&state->fe, 1);
+                       state->cfg.agc_control(fe, 1);
 
                dib8000_restart_agc(state);
 
@@ -924,7 +934,7 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
                dib8000_agc_soft_split(state);
 
                if (state->cfg.agc_control)
-                       state->cfg.agc_control(&state->fe, 0);
+                       state->cfg.agc_control(fe, 0);
 
                *tune_state = CT_AGC_STOP;
                break;
@@ -936,29 +946,28 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
 
 }
 
-static const int32_t lut_1000ln_mant[] =
+static const s32 lut_1000ln_mant[] =
 {
        908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
 };
 
-int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode)
+s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
 {
-    struct dib8000_state *state = fe->demodulator_priv;
-    uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0;
-    int32_t val;
-
-    val = dib8000_read32(state, 384);
-    /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */
-    if (mode) {
-       tmp_val = val;
-       while (tmp_val >>= 1)
-               exp++;
-       mant = (val * 1000 / (1<<exp));
-       ix = (uint8_t)((mant-1000)/100); /* index of the LUT */
-       val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */
-       val = (val*256)/1000;
-    }
-    return val;
+       struct dib8000_state *state = fe->demodulator_priv;
+       u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
+       s32 val;
+
+       val = dib8000_read32(state, 384);
+       if (mode) {
+               tmp_val = val;
+               while (tmp_val >>= 1)
+                       exp++;
+               mant = (val * 1000 / (1<<exp));
+               ix = (u8)((mant-1000)/100); /* index of the LUT */
+               val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
+               val = (val*256)/1000;
+       }
+       return val;
 }
 EXPORT_SYMBOL(dib8000_get_adc_power);
 
@@ -1002,22 +1011,23 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
 
        i = dib8000_read_word(state, 26) & 1;   // P_dds_invspec
-       dib8000_write_word(state, 26, state->fe.dtv_property_cache.inversion ^ i);
+       dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode) {
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
                //compute new dds_freq for the seg and adjust prbs
                int seg_offset =
-                   state->fe.dtv_property_cache.isdbt_sb_segment_idx - (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) -
-                   (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2);
+                       state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
+                       (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
+                       (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
                int clk = state->cfg.pll->internal;
                u32 segtodds = ((u32) (430 << 23) / clk) << 3;  // segtodds = SegBW / Fclk * pow(2,26)
                int dds_offset = seg_offset * segtodds;
                int new_dds, sub_channel;
-               if ((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0)     // if even
+               if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
                        dds_offset -= (int)(segtodds / 2);
 
                if (state->cfg.pll->ifreq == 0) {
-                       if ((state->fe.dtv_property_cache.inversion ^ i) == 0) {
+                       if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
                                dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
                                new_dds = dds_offset;
                        } else
@@ -1027,35 +1037,35 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        //  - the segment of center frequency with an odd total number of segments
                        //  - the segment to the left of center frequency with an even total number of segments
                        //  - the segment to the right of center frequency with an even total number of segments
-                       if ((state->fe.dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe.dtv_property_cache.isdbt_sb_mode == 1)
-                           &&
-                           (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2)
-                             && (state->fe.dtv_property_cache.isdbt_sb_segment_idx ==
-                                 ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
-                            || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-                                && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2)))
-                            || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
-                                && (state->fe.dtv_property_cache.isdbt_sb_segment_idx ==
-                                    ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
-                           )) {
+                       if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
+                               && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
+                                       && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
+                                         && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
+                                 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
+                                        || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+                                                && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
+                                        || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
+                                                && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
+                                                        ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
+                                       )) {
                                new_dds -= ((u32) (850 << 22) / clk) << 4;      // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
                        }
                } else {
-                       if ((state->fe.dtv_property_cache.inversion ^ i) == 0)
+                       if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
                                new_dds = state->cfg.pll->ifreq - dds_offset;
                        else
                                new_dds = state->cfg.pll->ifreq + dds_offset;
                }
                dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
                dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
-               if (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2)    // if odd
-                       sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
-               else            // if even
-                       sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
+               if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
+                       sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
+               else
+                       sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
                sub_channel -= 6;
 
-               if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
-                   || state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
+               if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
+                               || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
                        dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1);    //adp_pass =1
                        dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14));    //pha3_force_pha_shift = 1
                } else {
@@ -1063,7 +1073,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
                }
 
-               switch (state->fe.dtv_property_cache.transmission_mode) {
+               switch (state->fe[0]->dtv_property_cache.transmission_mode) {
                case TRANSMISSION_MODE_2K:
                        switch (sub_channel) {
                        case -6:
@@ -1209,7 +1219,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        }
                        break;
                }
-       } else {                // if not state->fe.dtv_property_cache.isdbt_sb_mode
+       } else {
                dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
                dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
                dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
@@ -1218,7 +1228,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        dib8000_write_word(state, 10, (seq << 4));
        //  dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
 
-       switch (state->fe.dtv_property_cache.guard_interval) {
+       switch (state->fe[0]->dtv_property_cache.guard_interval) {
        case GUARD_INTERVAL_1_32:
                guard = 0;
                break;
@@ -1238,7 +1248,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
 
        max_constellation = DQPSK;
        for (i = 0; i < 3; i++) {
-               switch (state->fe.dtv_property_cache.layer[i].modulation) {
+               switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
                case DQPSK:
                        constellation = 0;
                        break;
@@ -1254,7 +1264,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        break;
                }
 
-               switch (state->fe.dtv_property_cache.layer[i].fec) {
+               switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
                case FEC_1_2:
                        crate = 1;
                        break;
@@ -1273,26 +1283,26 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        break;
                }
 
-               if ((state->fe.dtv_property_cache.layer[i].interleaving > 0) &&
-                   ((state->fe.dtv_property_cache.layer[i].interleaving <= 3) ||
-                    (state->fe.dtv_property_cache.layer[i].interleaving == 4 && state->fe.dtv_property_cache.isdbt_sb_mode == 1))
-                   )
-                       timeI = state->fe.dtv_property_cache.layer[i].interleaving;
+               if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
+                               ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
+                                (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
+                       )
+                       timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
                else
                        timeI = 0;
-               dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe.dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
-                                  (crate << 3) | timeI);
-               if (state->fe.dtv_property_cache.layer[i].segment_count > 0) {
+               dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
+                                       (crate << 3) | timeI);
+               if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
                        switch (max_constellation) {
                        case DQPSK:
                        case QPSK:
-                               if (state->fe.dtv_property_cache.layer[i].modulation == QAM_16 ||
-                                   state->fe.dtv_property_cache.layer[i].modulation == QAM_64)
-                                       max_constellation = state->fe.dtv_property_cache.layer[i].modulation;
+                               if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
+                                       state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
+                                       max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
                                break;
                        case QAM_16:
-                               if (state->fe.dtv_property_cache.layer[i].modulation == QAM_64)
-                                       max_constellation = state->fe.dtv_property_cache.layer[i].modulation;
+                               if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
+                                       max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
                                break;
                        }
                }
@@ -1303,34 +1313,34 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
 
        dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
-                          ((state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe.dtv_property_cache.
+                               ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
                                                                                                 isdbt_sb_mode & 1) << 4));
 
-       dprintk("mode = %d ; guard = %d", mode, state->fe.dtv_property_cache.guard_interval);
+       dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
 
        /* signal optimization parameter */
 
-       if (state->fe.dtv_property_cache.isdbt_partial_reception) {
-               seg_diff_mask = (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
+       if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
+               seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
                for (i = 1; i < 3; i++)
                        nbseg_diff +=
-                           (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count;
+                               (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
                for (i = 0; i < nbseg_diff; i++)
                        seg_diff_mask |= 1 << permu_seg[i + 1];
        } else {
                for (i = 0; i < 3; i++)
                        nbseg_diff +=
-                           (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count;
+                               (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
                for (i = 0; i < nbseg_diff; i++)
                        seg_diff_mask |= 1 << permu_seg[i];
        }
        dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
 
        state->differential_constellation = (seg_diff_mask != 0);
-       dib8000_set_diversity_in(&state->fe, state->diversity_onoff);
+       dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {  // ISDB-Tsb
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 1)  // 3-segments
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
                        seg_mask13 = 0x00E0;
                else            // 1-segment
                        seg_mask13 = 0x0040;
@@ -1340,7 +1350,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        // WRITE: Mode & Diff mask
        dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
 
-       if ((seg_diff_mask) || (state->fe.dtv_property_cache.isdbt_sb_mode))
+       if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
                dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
        else
                dib8000_write_word(state, 268, (2 << 9) | 39);  //init value
@@ -1351,26 +1361,25 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
 
        dib8000_write_word(state, 353, seg_mask13);     // ADDR 353
 
-/*     // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
-       // dib8000_write_word(state, 351, (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 );
+/*     // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
 
        // ---- SMALL ----
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {
-               switch (state->fe.dtv_property_cache.transmission_mode) {
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+               switch (state->fe[0]->dtv_property_cache.transmission_mode) {
                case TRANSMISSION_MODE_2K:
-                       if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) {        // 1-seg
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK)  // DQPSK
+                       if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
                                        ncoeff = coeff_2k_sb_1seg_dqpsk;
                                else    // QPSK or QAM
                                        ncoeff = coeff_2k_sb_1seg;
                        } else {        // 3-segments
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) {        // DQPSK on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK)  // DQPSK on external segments
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
                                                ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
                                        else    // QPSK or QAM on external segments
                                                ncoeff = coeff_2k_sb_3seg_0dqpsk;
                                } else {        // QPSK or QAM on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK)  // DQPSK on external segments
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
                                                ncoeff = coeff_2k_sb_3seg_1dqpsk;
                                        else    // QPSK or QAM on external segments
                                                ncoeff = coeff_2k_sb_3seg;
@@ -1379,20 +1388,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        break;
 
                case TRANSMISSION_MODE_4K:
-                       if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) {        // 1-seg
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK)  // DQPSK
+                       if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
                                        ncoeff = coeff_4k_sb_1seg_dqpsk;
                                else    // QPSK or QAM
                                        ncoeff = coeff_4k_sb_1seg;
                        } else {        // 3-segments
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) {        // DQPSK on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) {        // DQPSK on external segments
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
                                                ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
                                        } else {        // QPSK or QAM on external segments
                                                ncoeff = coeff_4k_sb_3seg_0dqpsk;
                                        }
                                } else {        // QPSK or QAM on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) {        // DQPSK on external segments
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
                                                ncoeff = coeff_4k_sb_3seg_1dqpsk;
                                        } else  // QPSK or QAM on external segments
                                                ncoeff = coeff_4k_sb_3seg;
@@ -1403,20 +1412,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                case TRANSMISSION_MODE_AUTO:
                case TRANSMISSION_MODE_8K:
                default:
-                       if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) {        // 1-seg
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK)  // DQPSK
+                       if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
                                        ncoeff = coeff_8k_sb_1seg_dqpsk;
                                else    // QPSK or QAM
                                        ncoeff = coeff_8k_sb_1seg;
                        } else {        // 3-segments
-                               if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) {        // DQPSK on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) {        // DQPSK on external segments
+                               if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
                                                ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
                                        } else {        // QPSK or QAM on external segments
                                                ncoeff = coeff_8k_sb_3seg_0dqpsk;
                                        }
                                } else {        // QPSK or QAM on central segment
-                                       if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) {        // DQPSK on external segments
+                                       if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
                                                ncoeff = coeff_8k_sb_3seg_1dqpsk;
                                        } else  // QPSK or QAM on external segments
                                                ncoeff = coeff_8k_sb_3seg;
@@ -1430,22 +1439,22 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
 
        // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
        dib8000_write_word(state, 351,
-                          (state->fe.dtv_property_cache.isdbt_sb_mode << 9) | (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
+                               (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
 
        // ---- COFF ----
        // Carloff, the most robust
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {  // Sound Broadcasting mode - use both TMCC and AC pilots
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
 
                // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
                // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1
                dib8000_write_word(state, 187,
-                                  (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 2)
-                                  | 0x3);
+                                       (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
+                                       | 0x3);
 
-/*             // P_small_coef_ext_enable = 1 */
-/*             dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
+/*             // P_small_coef_ext_enable = 1 */
+/*             dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
 
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) {        // Sound Broadcasting mode 1 seg
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
 
                        // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)
                        if (mode == 3)
@@ -1469,10 +1478,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                        dib8000_write_word(state, 186, 80);
                } else {        // Sound Broadcasting mode 3 seg
                        // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
-                       /*                 if (mode == 3) */
-                       /*                     dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
-                       /*                 else */
-                       /*                     dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
+                       /*      if (mode == 3) */
+                       /*              dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
+                       /*      else */
+                       /*              dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
                        dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
 
                        // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
@@ -1509,7 +1518,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
        }
        // ---- FFT ----
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 && state->fe.dtv_property_cache.isdbt_partial_reception == 0)       // 1-seg
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
                dib8000_write_word(state, 178, 64);     // P_fft_powrange=64
        else
                dib8000_write_word(state, 178, 32);     // P_fft_powrange=32
@@ -1518,12 +1527,12 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
         * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
         */
        /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
-          dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
+               dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
 
        dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask);    /* P_lmod4_seg_inh       */
        dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask);    /* P_pha3_seg_inh        */
        dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask);    /* P_tac_seg_inh         */
-       if ((!state->fe.dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
+       if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
                dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40);     /* P_equal_noise_seg_inh */
        else
                dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask);    /* P_equal_noise_seg_inh */
@@ -1538,8 +1547,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask));  /* P_des_seg_enabled     */
 
        /* offset loop parameters */
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 0)  // Sound Broadcasting mode 1 seg
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
                        /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
                        dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
 
@@ -1551,8 +1560,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
                dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 0)  // Sound Broadcasting mode 1 seg
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
                        /* P_ctrl_pha_off_max=3   P_ctrl_sfreq_inh =0  P_ctrl_sfreq_step = (11-P_mode)  */
                        dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
 
@@ -1564,7 +1573,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
                dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
 
        /* P_dvsy_sync_wait - reuse mode */
-       switch (state->fe.dtv_property_cache.transmission_mode) {
+       switch (state->fe[0]->dtv_property_cache.transmission_mode) {
        case TRANSMISSION_MODE_8K:
                mode = 256;
                break;
@@ -1624,15 +1633,15 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        }
 
        // ---- ANA_FE ----
-       if (state->fe.dtv_property_cache.isdbt_sb_mode) {
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 1)  // 3-segments
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
                        ana_fe = ana_fe_coeff_3seg;
                else            // 1-segment
                        ana_fe = ana_fe_coeff_1seg;
        } else
                ana_fe = ana_fe_coeff_13seg;
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
                for (mode = 0; mode < 24; mode++)
                        dib8000_write_word(state, 117 + mode, ana_fe[mode]);
 
@@ -1648,11 +1657,11 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        // "P_cspu_left_edge"  not used => do not care
        // "P_cspu_right_edge" not used => do not care
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {  // ISDB-Tsb
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
                dib8000_write_word(state, 228, 1);      // P_2d_mode_byp=1
                dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 0   // 1-segment
-                   && state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
+                       && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
                        //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
                        dib8000_write_word(state, 265, 15);     // P_equal_noise_sel = 15
                }
@@ -1664,7 +1673,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        // ---- TMCC ----
        for (i = 0; i < 3; i++)
                tmcc_pow +=
-                   (((state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe.dtv_property_cache.layer[i].segment_count);
+                       (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
        // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
        // Threshold is set at 1/4 of max power.
        tmcc_pow *= (1 << (9 - 2));
@@ -1678,7 +1687,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
        if (state->isdbt_cfg_loaded == 0)
                dib8000_write_word(state, 250, 3285);   /*p_2d_hspeed_thr0 */
 
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1)
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
                state->isdbt_cfg_loaded = 0;
        else
                state->isdbt_cfg_loaded = 1;
@@ -1693,38 +1702,38 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe)
 
        int slist = 0;
 
-       state->fe.dtv_property_cache.inversion = 0;
-       if (!state->fe.dtv_property_cache.isdbt_sb_mode)
-               state->fe.dtv_property_cache.layer[0].segment_count = 13;
-       state->fe.dtv_property_cache.layer[0].modulation = QAM_64;
-       state->fe.dtv_property_cache.layer[0].fec = FEC_2_3;
-       state->fe.dtv_property_cache.layer[0].interleaving = 0;
+       state->fe[0]->dtv_property_cache.inversion = 0;
+       if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
+               state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
+       state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
+       state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
+       state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
 
        //choose the right list, in sb, always do everything
-       if (state->fe.dtv_property_cache.isdbt_sb_mode) {
-               state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-               state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
                slist = 7;
                dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
        } else {
-               if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
-                       if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+               if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
+                       if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
                                slist = 7;
                                dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));       // P_mode = 1 to have autosearch start ok with mode2
                        } else
                                slist = 3;
                } else {
-                       if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
+                       if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
                                slist = 2;
                                dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));       // P_mode = 1
                        } else
                                slist = 0;
                }
 
-               if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
-                       state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
-               if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
-                       state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+               if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
+                       state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+               if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
+                       state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
 
                dprintk("using list for autosearch : %d", slist);
                dib8000_set_channel(state, (unsigned char)slist, 1);
@@ -1786,7 +1795,7 @@ static int dib8000_tune(struct dvb_frontend *fe)
        if (state == NULL)
                return -EINVAL;
 
-       dib8000_set_bandwidth(state, state->fe.dtv_property_cache.bandwidth_hz / 1000);
+       dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
        dib8000_set_channel(state, 0, 0);
 
        // restart demod
@@ -1799,17 +1808,16 @@ static int dib8000_tune(struct dvb_frontend *fe)
 
        // never achieved a lock before - wait for timfreq to update
        if (state->timf == 0) {
-               if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {
-                       if (state->fe.dtv_property_cache.isdbt_partial_reception == 0)  // Sound Broadcasting mode 1 seg
+               if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+                       if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
                                msleep(300);
                        else    // Sound Broadcasting mode 3 seg
                                msleep(500);
                } else          // 13 seg
                        msleep(200);
        }
-       //dump_reg(state);
-       if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) {
-               if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) {        // Sound Broadcasting mode 1 seg
+       if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+               if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
 
                        /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40  alpha to check on board */
                        dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
@@ -1854,26 +1862,38 @@ static int dib8000_tune(struct dvb_frontend *fe)
 static int dib8000_wakeup(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       int ret;
 
        dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
        dib8000_set_adc_state(state, DIBX000_ADC_ON);
        if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
                dprintk("could not start Slow ADC");
 
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
 static int dib8000_sleep(struct dvb_frontend *fe)
 {
-       struct dib8000_state *st = fe->demodulator_priv;
-       if (1) {
-               dib8000_set_output_mode(st, OUTMODE_HIGH_Z);
-               dib8000_set_power_mode(st, DIB8000M_POWER_INTERFACE_ONLY);
-               return dib8000_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(st, DIBX000_ADC_OFF);
-       } else {
+       struct dib8000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       int ret;
 
-               return 0;
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+               if (ret < 0)
+                       return ret;
        }
+
+       dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
+       dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
+       return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
 }
 
 enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
@@ -1891,16 +1911,40 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun
 }
 EXPORT_SYMBOL(dib8000_set_tune_state);
 
-
-
-
 static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        u16 i, val = 0;
+       fe_status_t stat;
+       u8 index_frontend, sub_index_frontend;
 
        fe->dtv_property_cache.bandwidth_hz = 6000000;
 
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+               if (stat&FE_HAS_SYNC) {
+                       dprintk("TMCC lock on the slave%i", index_frontend);
+                       /* synchronize the cache with the other frontends */
+                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+                       for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
+                               if (sub_index_frontend != index_frontend) {
+                                       state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
+                                       for (i = 0; i < 3; i++) {
+                                               state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
+                                               state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
+                                               state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
+                                               state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
+                                       }
+                               }
+                       }
+                       return 0;
+               }
+       }
+
        fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
 
        val = dib8000_read_word(state, 570);
@@ -1992,112 +2036,200 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
                        break;
                }
        }
+
+       /* synchronize the cache with the other frontends */
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
+               state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
+               state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
+               state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
+               state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
+               for (i = 0; i < 3; i++) {
+                       state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
+                       state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
+                       state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
+                       state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
+               }
+       }
        return 0;
 }
 
 static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
 {
        struct dib8000_state *state = fe->demodulator_priv;
+       u8 nbr_pending, exit_condition, index_frontend;
+       s8 index_frontend_success = -1;
        int time, ret;
+       int  time_slave = FE_CALLBACK_TIME_NEVER;
 
-       fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+       if (state->fe[0]->dtv_property_cache.frequency == 0) {
+               dprintk("dib8000: must at least specify frequency ");
+               return 0;
+       }
 
-       dib8000_set_output_mode(state, OUTMODE_HIGH_Z);
+       if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
+               dprintk("dib8000: no bandwidth specified, set to default ");
+               state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
+       }
+
+       for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               /* synchronization of the cache */
+               state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
+               memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
+
+               dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
+               if (state->fe[index_frontend]->ops.tuner_ops.set_params)
+                       state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
 
-       if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe, fep);
+               dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
+       }
 
        /* start up the AGC */
-       state->tune_state = CT_AGC_START;
        do {
-               time = dib8000_agc_startup(fe);
+               time = dib8000_agc_startup(state->fe[0]);
+               for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       time_slave = dib8000_agc_startup(state->fe[index_frontend]);
+                       if (time == FE_CALLBACK_TIME_NEVER)
+                               time = time_slave;
+                       else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
+                               time = time_slave;
+               }
                if (time != FE_CALLBACK_TIME_NEVER)
                        msleep(time / 10);
                else
                        break;
-       } while (state->tune_state != CT_AGC_STOP);
-
-       if (state->fe.dtv_property_cache.frequency == 0) {
-               dprintk("dib8000: must at least specify frequency ");
-               return 0;
-       }
-
-       if (state->fe.dtv_property_cache.bandwidth_hz == 0) {
-               dprintk("dib8000: no bandwidth specified, set to default ");
-               state->fe.dtv_property_cache.bandwidth_hz = 6000000;
-       }
+               exit_condition = 1;
+               for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
+                               exit_condition = 0;
+                               break;
+                       }
+               }
+       } while (exit_condition == 0);
+
+       for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+
+       if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
+                       (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
+                       (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
+                       (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
+                       (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
+                        (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
+                        (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
+                        ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
+                         (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
+                       (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
+                        (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
+                        (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
+                        ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
+                         (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
+                       (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
+                        (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
+                        (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
+                        ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
+                         (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
+                       (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
+                         ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
+                        ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
+                         ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
+                        ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
+               int i = 80000;
+               u8 found = 0;
+               u8 tune_failed = 0;
+
+               for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
+                       dib8000_autosearch_start(state->fe[index_frontend]);
+               }
 
-       state->tune_state = CT_DEMOD_START;
-
-       if ((state->fe.dtv_property_cache.delivery_system != SYS_ISDBT) ||
-           (state->fe.dtv_property_cache.inversion == INVERSION_AUTO) ||
-           (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
-           (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
-           (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
-            (state->fe.dtv_property_cache.layer[0].segment_count != 0xff) &&
-            (state->fe.dtv_property_cache.layer[0].segment_count != 0) &&
-            ((state->fe.dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
-             (state->fe.dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
-           (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
-            (state->fe.dtv_property_cache.layer[1].segment_count != 0xff) &&
-            (state->fe.dtv_property_cache.layer[1].segment_count != 0) &&
-            ((state->fe.dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
-             (state->fe.dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
-           (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
-            (state->fe.dtv_property_cache.layer[2].segment_count != 0xff) &&
-            (state->fe.dtv_property_cache.layer[2].segment_count != 0) &&
-            ((state->fe.dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
-             (state->fe.dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
-           (((state->fe.dtv_property_cache.layer[0].segment_count == 0) ||
-             ((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
-            ((state->fe.dtv_property_cache.layer[1].segment_count == 0) ||
-             ((state->fe.dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
-            ((state->fe.dtv_property_cache.layer[2].segment_count == 0) || ((state->fe.dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
-               int i = 800, found;
-
-               dib8000_set_bandwidth(state, fe->dtv_property_cache.bandwidth_hz / 1000);
-               dib8000_autosearch_start(fe);
                do {
-                       msleep(10);
-                       found = dib8000_autosearch_irq(fe);
-               } while (found == 0 && i--);
+                       msleep(20);
+                       nbr_pending = 0;
+                       exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
+                       for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                               if (((tune_failed >> index_frontend) & 0x1) == 0) {
+                                       found = dib8000_autosearch_irq(state->fe[index_frontend]);
+                                       switch (found) {
+                                       case 0: /* tune pending */
+                                                nbr_pending++;
+                                                break;
+                                       case 2:
+                                                dprintk("autosearch succeed on the frontend%i", index_frontend);
+                                                exit_condition = 2;
+                                                index_frontend_success = index_frontend;
+                                                break;
+                                       default:
+                                                dprintk("unhandled autosearch result");
+                                       case 1:
+                                                dprintk("autosearch failed for the frontend%i", index_frontend);
+                                                break;
+                                       }
+                               }
+                       }
 
-               dprintk("Frequency %d Hz, autosearch returns: %d", fep->frequency, found);
+                       /* if all tune are done and no success, exit: tune failed */
+                       if ((nbr_pending == 0) && (exit_condition == 0))
+                               exit_condition = 1;
+               } while ((exit_condition == 0) && i--);
 
-               if (found == 0 || found == 1)
-                       return 0;       // no channel found
+               if (exit_condition == 1) { /* tune failed */
+                       dprintk("tune failed");
+                       return 0;
+               }
+
+               dprintk("tune success on frontend%i", index_frontend_success);
 
                dib8000_get_frontend(fe, fep);
        }
 
-       ret = dib8000_tune(fe);
+       for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               ret = dib8000_tune(state->fe[index_frontend]);
+
+       /* set output mode and diversity input */
+       dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
+               dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
+       }
 
-       /* make this a config parameter */
-       dib8000_set_output_mode(state, state->cfg.output_mode);
+       /* turn off the diversity of the last chip */
+       dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
 
        return ret;
 }
 
+static u16 dib8000_read_lock(struct dvb_frontend *fe)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+
+       return dib8000_read_word(state, 568);
+}
+
 static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 {
        struct dib8000_state *state = fe->demodulator_priv;
-       u16 lock = dib8000_read_word(state, 568);
+       u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
+       u8 index_frontend;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
 
        *stat = 0;
 
-       if ((lock >> 13) & 1)
+       if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
                *stat |= FE_HAS_SIGNAL;
 
-       if ((lock >> 8) & 1) /* Equal */
+       if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
                *stat |= FE_HAS_CARRIER;
 
-       if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */
+       if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
                *stat |= FE_HAS_SYNC;
 
-       if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */
+       if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
                *stat |= FE_HAS_LOCK;
 
-       if ((lock >> 12) & 1) {
+       if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
                lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
                if (lock & 0x01)
                        *stat |= FE_HAS_VITERBI;
@@ -2131,44 +2263,120 @@ static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
 static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
 {
        struct dib8000_state *state = fe->demodulator_priv;
-       u16 val = dib8000_read_word(state, 390);
-       *strength = 65535 - val;
+       u8 index_frontend;
+       u16 val;
+
+       *strength = 0;
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+               if (val > 65535 - *strength)
+                       *strength = 65535;
+               else
+                       *strength += val;
+       }
+
+       val = 65535 - dib8000_read_word(state, 390);
+       if (val > 65535 - *strength)
+               *strength = 65535;
+       else
+               *strength += val;
        return 0;
 }
 
-static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
+static u32 dib8000_get_snr(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
+       u32 n, s, exp;
        u16 val;
-       s32 signal_mant, signal_exp, noise_mant, noise_exp;
-       u32 result = 0;
 
        val = dib8000_read_word(state, 542);
-       noise_mant = (val >> 6) & 0xff;
-       noise_exp = (val & 0x3f);
+       n = (val >> 6) & 0xff;
+       exp = (val & 0x3f);
+       if ((exp & 0x20) != 0)
+               exp -= 0x40;
+       n <<= exp+16;
 
        val = dib8000_read_word(state, 543);
-       signal_mant = (val >> 6) & 0xff;
-       signal_exp = (val & 0x3f);
+       s = (val >> 6) & 0xff;
+       exp = (val & 0x3f);
+       if ((exp & 0x20) != 0)
+               exp -= 0x40;
+       s <<= exp+16;
+
+       if (n > 0) {
+               u32 t = (s/n) << 16;
+               return t + ((s << 16) - n*t) / n;
+       }
+       return 0xffffffff;
+}
 
-       if ((noise_exp & 0x20) != 0)
-               noise_exp -= 0x40;
-       if ((signal_exp & 0x20) != 0)
-               signal_exp -= 0x40;
+static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       u32 snr_master;
 
-       if (signal_mant != 0)
-               result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
-       else
-               result = intlog10(2) * 10 * signal_exp - 100;
-       if (noise_mant != 0)
-               result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
+       snr_master = dib8000_get_snr(fe);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               snr_master += dib8000_get_snr(state->fe[index_frontend]);
+
+       if (snr_master != 0) {
+               snr_master = 10*intlog10(snr_master>>16);
+               *snr = snr_master / ((1 << 24) / 10);
+       }
        else
-               result -= intlog10(2) * 10 * noise_exp - 100;
+               *snr = 0;
 
-       *snr = result / ((1 << 24) / 10);
        return 0;
 }
 
+int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u8 index_frontend = 1;
+
+       while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+               index_frontend++;
+       if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
+               dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
+               state->fe[index_frontend] = fe_slave;
+               return 0;
+       }
+
+       dprintk("too many slave frontend");
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(dib8000_set_slave_frontend);
+
+int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       u8 index_frontend = 1;
+
+       while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+               index_frontend++;
+       if (index_frontend != 1) {
+               dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
+               state->fe[index_frontend] = NULL;
+               return 0;
+       }
+
+       dprintk("no frontend to be removed");
+       return -ENODEV;
+}
+EXPORT_SYMBOL(dib8000_remove_slave_frontend);
+
+struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+
+       if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
+               return NULL;
+       return state->fe[slave_index];
+}
+EXPORT_SYMBOL(dib8000_get_slave_frontend);
+
+
 int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
 {
        int k = 0;
@@ -2227,7 +2435,13 @@ static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron
 static void dib8000_release(struct dvb_frontend *fe)
 {
        struct dib8000_state *st = fe->demodulator_priv;
+       u8 index_frontend;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
+               dvb_frontend_detach(st->fe[index_frontend]);
+
        dibx000_exit_i2c_master(&st->i2c_master);
+       kfree(st->fe[0]);
        kfree(st);
 }
 
@@ -2242,19 +2456,19 @@ EXPORT_SYMBOL(dib8000_get_i2c_master);
 int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
 {
        struct dib8000_state *st = fe->demodulator_priv;
-    u16 val = dib8000_read_word(st, 299) & 0xffef;
-    val |= (onoff & 0x1) << 4;
+       u16 val = dib8000_read_word(st, 299) & 0xffef;
+       val |= (onoff & 0x1) << 4;
 
-    dprintk("pid filter enabled %d", onoff);
-    return dib8000_write_word(st, 299, val);
+       dprintk("pid filter enabled %d", onoff);
+       return dib8000_write_word(st, 299, val);
 }
 EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
 
 int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
 {
        struct dib8000_state *st = fe->demodulator_priv;
-    dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
-    return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
+       dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+       return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
 }
 EXPORT_SYMBOL(dib8000_pid_filter);
 
@@ -2298,6 +2512,9 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
        state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
        if (state == NULL)
                return NULL;
+       fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
+       if (fe == NULL)
+               goto error;
 
        memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
        state->i2c.adap = i2c_adap;
@@ -2311,9 +2528,9 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
        if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
                state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
 
-       fe = &state->fe;
+       state->fe[0] = fe;
        fe->demodulator_priv = state;
-       memcpy(&state->fe.ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
+       memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
 
        state->timf_default = cfg->pll->timf;
 
index e0a9ded11df49a2053e6e5594ea3c8c88ef3f771..617f9eba3a0967787eaa49b7da18f08d61473725 100644 (file)
@@ -50,6 +50,9 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st
 extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
 extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
 extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
+extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
+extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
 #else
 static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
 {
@@ -111,6 +114,23 @@ static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return 0;
 }
+static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
 #endif
 
 #endif
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
new file mode 100644 (file)
index 0000000..9151876
--- /dev/null
@@ -0,0 +1,2351 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family.
+ *
+ * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#include "dvb_math.h"
+#include "dvb_frontend.h"
+
+#include "dib9000.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0)
+#define MAX_NUMBER_OF_FRONTENDS 6
+
+struct i2c_device {
+       struct i2c_adapter *i2c_adap;
+       u8 i2c_addr;
+};
+
+/* lock */
+#define DIB_LOCK struct mutex
+#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0)
+#define DibReleaseLock(lock) mutex_unlock(lock)
+#define DibInitLock(lock) mutex_init(lock)
+#define DibFreeLock(lock)
+
+struct dib9000_state {
+       struct i2c_device i2c;
+
+       struct dibx000_i2c_master i2c_master;
+       struct i2c_adapter tuner_adap;
+       struct i2c_adapter component_bus;
+
+       u16 revision;
+       u8 reg_offs;
+
+       enum frontend_tune_state tune_state;
+       u32 status;
+       struct dvb_frontend_parametersContext channel_status;
+
+       u8 fe_id;
+
+#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff
+       u16 gpio_dir;
+#define DIB9000_GPIO_DEFAULT_VALUES     0x0000
+       u16 gpio_val;
+#define DIB9000_GPIO_DEFAULT_PWM_POS    0xffff
+       u16 gpio_pwm_pos;
+
+       union {                 /* common for all chips */
+               struct {
+                       u8 mobile_mode:1;
+               } host;
+
+               struct {
+                       struct dib9000_fe_memory_map {
+                               u16 addr;
+                               u16 size;
+                       } fe_mm[18];
+                       u8 memcmd;
+
+                       DIB_LOCK mbx_if_lock;   /* to protect read/write operations */
+                       DIB_LOCK mbx_lock;      /* to protect the whole mailbox handling */
+
+                       DIB_LOCK mem_lock;      /* to protect the memory accesses */
+                       DIB_LOCK mem_mbx_lock;  /* to protect the memory-based mailbox */
+
+#define MBX_MAX_WORDS (256 - 200 - 2)
+#define DIB9000_MSG_CACHE_SIZE 2
+                       u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS];
+                       u8 fw_is_running;
+               } risc;
+       } platform;
+
+       union {                 /* common for all platforms */
+               struct {
+                       struct dib9000_config cfg;
+               } d9;
+       } chip;
+
+       struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+       u16 component_bus_speed;
+};
+
+u32 fe_info[44] = { 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, 0, 0, 0, 0, 0,
+       0, 0, 0
+};
+
+enum dib9000_power_mode {
+       DIB9000_POWER_ALL = 0,
+
+       DIB9000_POWER_NO,
+       DIB9000_POWER_INTERF_ANALOG_AGC,
+       DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
+       DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD,
+       DIB9000_POWER_INTERFACE_ONLY,
+};
+
+enum dib9000_out_messages {
+       OUT_MSG_HBM_ACK,
+       OUT_MSG_HOST_BUF_FAIL,
+       OUT_MSG_REQ_VERSION,
+       OUT_MSG_BRIDGE_I2C_W,
+       OUT_MSG_BRIDGE_I2C_R,
+       OUT_MSG_BRIDGE_APB_W,
+       OUT_MSG_BRIDGE_APB_R,
+       OUT_MSG_SCAN_CHANNEL,
+       OUT_MSG_MONIT_DEMOD,
+       OUT_MSG_CONF_GPIO,
+       OUT_MSG_DEBUG_HELP,
+       OUT_MSG_SUBBAND_SEL,
+       OUT_MSG_ENABLE_TIME_SLICE,
+       OUT_MSG_FE_FW_DL,
+       OUT_MSG_FE_CHANNEL_SEARCH,
+       OUT_MSG_FE_CHANNEL_TUNE,
+       OUT_MSG_FE_SLEEP,
+       OUT_MSG_FE_SYNC,
+       OUT_MSG_CTL_MONIT,
+
+       OUT_MSG_CONF_SVC,
+       OUT_MSG_SET_HBM,
+       OUT_MSG_INIT_DEMOD,
+       OUT_MSG_ENABLE_DIVERSITY,
+       OUT_MSG_SET_OUTPUT_MODE,
+       OUT_MSG_SET_PRIORITARY_CHANNEL,
+       OUT_MSG_ACK_FRG,
+       OUT_MSG_INIT_PMU,
+};
+
+enum dib9000_in_messages {
+       IN_MSG_DATA,
+       IN_MSG_FRAME_INFO,
+       IN_MSG_CTL_MONIT,
+       IN_MSG_ACK_FREE_ITEM,
+       IN_MSG_DEBUG_BUF,
+       IN_MSG_MPE_MONITOR,
+       IN_MSG_RAWTS_MONITOR,
+       IN_MSG_END_BRIDGE_I2C_RW,
+       IN_MSG_END_BRIDGE_APB_RW,
+       IN_MSG_VERSION,
+       IN_MSG_END_OF_SCAN,
+       IN_MSG_MONIT_DEMOD,
+       IN_MSG_ERROR,
+       IN_MSG_FE_FW_DL_DONE,
+       IN_MSG_EVENT,
+       IN_MSG_ACK_CHANGE_SVC,
+       IN_MSG_HBM_PROF,
+};
+
+/* memory_access requests */
+#define FE_MM_W_CHANNEL                   0
+#define FE_MM_W_FE_INFO                   1
+#define FE_MM_RW_SYNC                     2
+
+#define FE_SYNC_CHANNEL          1
+#define FE_SYNC_W_GENERIC_MONIT         2
+#define FE_SYNC_COMPONENT_ACCESS 3
+
+#define FE_MM_R_CHANNEL_SEARCH_STATE      3
+#define FE_MM_R_CHANNEL_UNION_CONTEXT     4
+#define FE_MM_R_FE_INFO                   5
+#define FE_MM_R_FE_MONITOR                6
+
+#define FE_MM_W_CHANNEL_HEAD              7
+#define FE_MM_W_CHANNEL_UNION             8
+#define FE_MM_W_CHANNEL_CONTEXT           9
+#define FE_MM_R_CHANNEL_UNION            10
+#define FE_MM_R_CHANNEL_CONTEXT          11
+#define FE_MM_R_CHANNEL_TUNE_STATE       12
+
+#define FE_MM_R_GENERIC_MONITORING_SIZE         13
+#define FE_MM_W_GENERIC_MONITORING          14
+#define FE_MM_R_GENERIC_MONITORING          15
+
+#define FE_MM_W_COMPONENT_ACCESS         16
+#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17
+static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len);
+static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len);
+
+static u16 to_fw_output_mode(u16 mode)
+{
+       switch (mode) {
+       case OUTMODE_HIGH_Z:
+               return 0;
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+               return 4;
+       case OUTMODE_MPEG2_PAR_CONT_CLK:
+               return 8;
+       case OUTMODE_MPEG2_SERIAL:
+               return 16;
+       case OUTMODE_DIVERSITY:
+               return 128;
+       case OUTMODE_MPEG2_FIFO:
+               return 2;
+       case OUTMODE_ANALOG_ADC:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute)
+{
+       u32 chunk_size = 126;
+       u32 l;
+       int ret;
+       u8 wb[2] = { reg >> 8, reg & 0xff };
+       struct i2c_msg msg[2] = {
+               {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
+               {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len},
+       };
+
+       if (state->platform.risc.fw_is_running && (reg < 1024))
+               return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
+
+       if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+               wb[0] |= (1 << 5);
+       if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+               wb[0] |= (1 << 4);
+
+       do {
+               l = len < chunk_size ? len : chunk_size;
+               msg[1].len = l;
+               msg[1].buf = b;
+               ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0;
+               if (ret != 0) {
+                       dprintk("i2c read error on %d", reg);
+                       return -EREMOTEIO;
+               }
+
+               b += l;
+               len -= l;
+
+               if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
+                       reg += l / 2;
+       } while ((ret == 0) && len);
+
+       return 0;
+}
+
+static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
+{
+       u8 b[2];
+       u8 wb[2] = { reg >> 8, reg & 0xff };
+       struct i2c_msg msg[2] = {
+               {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
+               {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2},
+       };
+
+       if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
+               dprintk("read register %x error", reg);
+               return 0;
+       }
+
+       return (b[0] << 8) | b[1];
+}
+
+static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
+{
+       u8 b[2];
+       if (dib9000_read16_attr(state, reg, b, 2, 0) != 0)
+               return 0;
+       return (b[0] << 8 | b[1]);
+}
+
+static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
+{
+       u8 b[2];
+       if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0)
+               return 0;
+       return (b[0] << 8 | b[1]);
+}
+
+#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+
+static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
+{
+       u8 b[255];
+       u32 chunk_size = 126;
+       u32 l;
+       int ret;
+
+       struct i2c_msg msg = {
+               .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2
+       };
+
+       if (state->platform.risc.fw_is_running && (reg < 1024)) {
+               if (dib9000_risc_apb_access_write
+                   (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
+                       return -EINVAL;
+               return 0;
+       }
+
+       b[0] = (reg >> 8) & 0xff;
+       b[1] = (reg) & 0xff;
+
+       if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
+               b[0] |= (1 << 5);
+       if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+               b[0] |= (1 << 4);
+
+       do {
+               l = len < chunk_size ? len : chunk_size;
+               msg.len = l + 2;
+               memcpy(&b[2], buf, l);
+
+               ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+
+               buf += l;
+               len -= l;
+
+               if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT))
+                       reg += l / 2;
+       } while ((ret == 0) && len);
+
+       return ret;
+}
+
+static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+{
+       u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff };
+       struct i2c_msg msg = {
+               .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+       };
+
+       return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val)
+{
+       u8 b[2] = { val >> 8, val & 0xff };
+       return dib9000_write16_attr(state, reg, b, 2, 0);
+}
+
+static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute)
+{
+       u8 b[2] = { val >> 8, val & 0xff };
+       return dib9000_write16_attr(state, reg, b, 2, attribute);
+}
+
+#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0)
+#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute))
+
+#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0)
+#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0)
+
+#define MAC_IRQ      (1 << 1)
+#define IRQ_POL_MSK  (1 << 4)
+
+#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
+
+static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading)
+{
+       u8 b[14] = { 0 };
+
+/*      dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */
+/*      b[0] = 0 << 7; */
+       b[1] = 1;
+
+/*      b[2] = 0; */
+/*      b[3] = 0; */
+       b[4] = (u8) (addr >> 8);
+       b[5] = (u8) (addr & 0xff);
+
+/*      b[10] = 0; */
+/*      b[11] = 0; */
+       b[12] = (u8) (addr >> 8);
+       b[13] = (u8) (addr & 0xff);
+
+       addr += len;
+/*      b[6] = 0; */
+/*      b[7] = 0; */
+       b[8] = (u8) (addr >> 8);
+       b[9] = (u8) (addr & 0xff);
+
+       dib9000_write(state, 1056, b, 14);
+       if (reading)
+               dib9000_write_word(state, 1056, (1 << 15) | 1);
+       state->platform.risc.memcmd = -1;       /* if it was called directly reset it - to force a future setup-call to set it */
+}
+
+static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd)
+{
+       struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f];
+       /* decide whether we need to "refresh" the memory controller */
+       if (state->platform.risc.memcmd == cmd &&       /* same command */
+           !(cmd & 0x80 && m->size < 67))      /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */
+               return;
+       dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80);
+       state->platform.risc.memcmd = cmd;
+}
+
+static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len)
+{
+       if (!state->platform.risc.fw_is_running)
+               return -EIO;
+
+       DibAcquireLock(&state->platform.risc.mem_lock);
+       dib9000_risc_mem_setup(state, cmd | 0x80);
+       dib9000_risc_mem_read_chunks(state, b, len);
+       DibReleaseLock(&state->platform.risc.mem_lock);
+       return 0;
+}
+
+static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b)
+{
+       struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd];
+       if (!state->platform.risc.fw_is_running)
+               return -EIO;
+
+       DibAcquireLock(&state->platform.risc.mem_lock);
+       dib9000_risc_mem_setup(state, cmd);
+       dib9000_risc_mem_write_chunks(state, b, m->size);
+       DibReleaseLock(&state->platform.risc.mem_lock);
+       return 0;
+}
+
+static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len)
+{
+       u16 offs;
+
+       if (risc_id == 1)
+               offs = 16;
+       else
+               offs = 0;
+
+       /* config crtl reg */
+       dib9000_write_word(state, 1024 + offs, 0x000f);
+       dib9000_write_word(state, 1025 + offs, 0);
+       dib9000_write_word(state, 1031 + offs, key);
+
+       dprintk("going to download %dB of microcode", len);
+       if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) {
+               dprintk("error while downloading microcode for RISC %c", 'A' + risc_id);
+               return -EIO;
+       }
+
+       dprintk("Microcode for RISC %c loaded", 'A' + risc_id);
+
+       return 0;
+}
+
+static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id)
+{
+       u16 mbox_offs;
+       u16 reset_reg;
+       u16 tries = 1000;
+
+       if (risc_id == 1)
+               mbox_offs = 16;
+       else
+               mbox_offs = 0;
+
+       /* Reset mailbox  */
+       dib9000_write_word(state, 1027 + mbox_offs, 0x8000);
+
+       /* Read reset status */
+       do {
+               reset_reg = dib9000_read_word(state, 1027 + mbox_offs);
+               msleep(100);
+       } while ((reset_reg & 0x8000) && --tries);
+
+       if (reset_reg & 0x8000) {
+               dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id);
+               return -EIO;
+       }
+       dprintk("MBX: initialized");
+       return 0;
+}
+
+#define MAX_MAILBOX_TRY 100
+static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr)
+{
+       u8 *d, b[2];
+       u16 tmp;
+       u16 size;
+       u32 i;
+       int ret = 0;
+
+       if (!state->platform.risc.fw_is_running)
+               return -EINVAL;
+
+       DibAcquireLock(&state->platform.risc.mbx_if_lock);
+       tmp = MAX_MAILBOX_TRY;
+       do {
+               size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
+               if ((size + len + 1) > MBX_MAX_WORDS && --tmp) {
+                       dprintk("MBX: RISC mbx full, retrying");
+                       msleep(100);
+               } else
+                       break;
+       } while (1);
+
+       /*dprintk( "MBX: size: %d", size); */
+
+       if (tmp == 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+#ifdef DUMP_MSG
+       dprintk("--> %02x %d ", id, len + 1);
+       for (i = 0; i < len; i++)
+               dprintk("%04x ", data[i]);
+       dprintk("\n");
+#endif
+
+       /* byte-order conversion - works on big (where it is not necessary) or little endian */
+       d = (u8 *) data;
+       for (i = 0; i < len; i++) {
+               tmp = data[i];
+               *d++ = tmp >> 8;
+               *d++ = tmp & 0xff;
+       }
+
+       /* write msg */
+       b[0] = id;
+       b[1] = len + 1;
+       if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* update register nb_mes_in_RX */
+       ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
+
+out:
+       DibReleaseLock(&state->platform.risc.mbx_if_lock);
+
+       return ret;
+}
+
+static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr)
+{
+#ifdef DUMP_MSG
+       u16 *d = data;
+#endif
+
+       u16 tmp, i;
+       u8 size;
+       u8 mc_base;
+
+       if (!state->platform.risc.fw_is_running)
+               return 0;
+
+       DibAcquireLock(&state->platform.risc.mbx_if_lock);
+       if (risc_id == 1)
+               mc_base = 16;
+       else
+               mc_base = 0;
+
+       /* Length and type in the first word */
+       *data = dib9000_read_word_attr(state, 1029 + mc_base, attr);
+
+       size = *data & 0xff;
+       if (size <= MBX_MAX_WORDS) {
+               data++;
+               size--;         /* Initial word already read */
+
+               dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr);
+
+               /* to word conversion */
+               for (i = 0; i < size; i++) {
+                       tmp = *data;
+                       *data = (tmp >> 8) | (tmp << 8);
+                       data++;
+               }
+
+#ifdef DUMP_MSG
+               dprintk("<-- ");
+               for (i = 0; i < size + 1; i++)
+                       dprintk("%04x ", d[i]);
+               dprintk("\n");
+#endif
+       } else {
+               dprintk("MBX: message is too big for message cache (%d), flushing message", size);
+               size--;         /* Initial word already read */
+               while (size--)
+                       dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr);
+       }
+       /* Update register nb_mes_in_TX */
+       dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
+
+       DibReleaseLock(&state->platform.risc.mbx_if_lock);
+
+       return size + 1;
+}
+
+static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size)
+{
+       u32 ts = data[1] << 16 | data[0];
+       char *b = (char *)&data[2];
+
+       b[2 * (size - 2) - 1] = '\0';   /* Bullet proof the buffer */
+       if (*b == '~') {
+               b++;
+               dprintk(b);
+       } else
+               dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : "<emtpy>");
+       return 1;
+}
+
+static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr)
+{
+       int i;
+       u8 size;
+       u16 *block;
+       /* find a free slot */
+       for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
+               block = state->platform.risc.message_cache[i];
+               if (*block == 0) {
+                       size = dib9000_mbx_read(state, block, 1, attr);
+
+/*                      dprintk( "MBX: fetched %04x message to cache", *block); */
+
+                       switch (*block >> 8) {
+                       case IN_MSG_DEBUG_BUF:
+                               dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */
+                               *block = 0;     /* free the block */
+                               break;
+#if 0
+                       case IN_MSG_DATA:       /* FE-TRACE */
+                               dib9000_risc_data_process(state, block + 1, size);
+                               *block = 0;
+                               break;
+#endif
+                       default:
+                               break;
+                       }
+
+                       return 1;
+               }
+       }
+       dprintk("MBX: no free cache-slot found for new message...");
+       return -1;
+}
+
+static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
+{
+       if (risc_id == 0)
+               return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f;   /* 5 bit field */
+       else
+               return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f;    /* 7 bit field */
+}
+
+static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
+{
+       int ret = 0;
+       u16 tmp;
+
+       if (!state->platform.risc.fw_is_running)
+               return -1;
+
+       DibAcquireLock(&state->platform.risc.mbx_lock);
+
+       if (dib9000_mbx_count(state, 1, attr))  /* 1=RiscB */
+               ret = dib9000_mbx_fetch_to_cache(state, attr);
+
+       tmp = dib9000_read_word_attr(state, 1229, attr);        /* Clear the IRQ */
+/*      if (tmp) */
+/*              dprintk( "cleared IRQ: %x", tmp); */
+       DibReleaseLock(&state->platform.risc.mbx_lock);
+
+       return ret;
+}
+
+static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr)
+{
+       u8 i;
+       u16 *block;
+       u16 timeout = 30;
+
+       *msg = 0;
+       do {
+               /* dib9000_mbx_get_from_cache(); */
+               for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) {
+                       block = state->platform.risc.message_cache[i];
+                       if ((*block >> 8) == id) {
+                               *size = (*block & 0xff) - 1;
+                               memcpy(msg, block + 1, (*size) * 2);
+                               *block = 0;     /* free the block */
+                               i = 0;  /* signal that we found a message */
+                               break;
+                       }
+               }
+
+               if (i == 0)
+                       break;
+
+               if (dib9000_mbx_process(state, attr) == -1)     /* try to fetch one message - if any */
+                       return -1;
+
+       } while (--timeout);
+
+       if (timeout == 0) {
+               dprintk("waiting for message %d timed out", id);
+               return -1;
+       }
+
+       return i == 0;
+}
+
+static int dib9000_risc_check_version(struct dib9000_state *state)
+{
+       u8 r[4];
+       u8 size;
+       u16 fw_version = 0;
+
+       if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0)
+               return -EIO;
+
+       if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0)
+               return -EIO;
+
+       fw_version = (r[0] << 8) | r[1];
+       dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]);
+
+       if ((fw_version >> 10) != 7)
+               return -EINVAL;
+
+       switch (fw_version & 0x3ff) {
+       case 11:
+       case 12:
+       case 14:
+       case 15:
+       case 16:
+       case 17:
+               break;
+       default:
+               dprintk("RISC: invalid firmware version");
+               return -EINVAL;
+       }
+
+       dprintk("RISC: valid firmware version");
+       return 0;
+}
+
+static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB)
+{
+       /* Reconfig pool mac ram */
+       dib9000_write_word(state, 1225, 0x02);  /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */
+       dib9000_write_word(state, 1226, 0x05);
+
+       /* Toggles IP crypto to Host APB interface. */
+       dib9000_write_word(state, 1542, 1);
+
+       /* Set jump and no jump in the dma box */
+       dib9000_write_word(state, 1074, 0);
+       dib9000_write_word(state, 1075, 0);
+
+       /* Set MAC as APB Master. */
+       dib9000_write_word(state, 1237, 0);
+
+       /* Reset the RISCs */
+       if (codeA != NULL)
+               dib9000_write_word(state, 1024, 2);
+       else
+               dib9000_write_word(state, 1024, 15);
+       if (codeB != NULL)
+               dib9000_write_word(state, 1040, 2);
+
+       if (codeA != NULL)
+               dib9000_firmware_download(state, 0, 0x1234, codeA, lenA);
+       if (codeB != NULL)
+               dib9000_firmware_download(state, 1, 0x1234, codeB, lenB);
+
+       /* Run the RISCs */
+       if (codeA != NULL)
+               dib9000_write_word(state, 1024, 0);
+       if (codeB != NULL)
+               dib9000_write_word(state, 1040, 0);
+
+       if (codeA != NULL)
+               if (dib9000_mbx_host_init(state, 0) != 0)
+                       return -EIO;
+       if (codeB != NULL)
+               if (dib9000_mbx_host_init(state, 1) != 0)
+                       return -EIO;
+
+       msleep(100);
+       state->platform.risc.fw_is_running = 1;
+
+       if (dib9000_risc_check_version(state) != 0)
+               return -EINVAL;
+
+       state->platform.risc.memcmd = 0xff;
+       return 0;
+}
+
+static u16 dib9000_identify(struct i2c_device *client)
+{
+       u16 value;
+
+       value = dib9000_i2c_read16(client, 896);
+       if (value != 0x01b3) {
+               dprintk("wrong Vendor ID (0x%x)", value);
+               return 0;
+       }
+
+       value = dib9000_i2c_read16(client, 897);
+       if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) {
+               dprintk("wrong Device ID (0x%x)", value);
+               return 0;
+       }
+
+       /* protect this driver to be used with 7000PC */
+       if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) {
+               dprintk("this driver does not work with DiB7000PC");
+               return 0;
+       }
+
+       switch (value) {
+       case 0x4000:
+               dprintk("found DiB7000MA/PA/MB/PB");
+               break;
+       case 0x4001:
+               dprintk("found DiB7000HC");
+               break;
+       case 0x4002:
+               dprintk("found DiB7000MC");
+               break;
+       case 0x4003:
+               dprintk("found DiB9000A");
+               break;
+       case 0x4004:
+               dprintk("found DiB9000H");
+               break;
+       case 0x4005:
+               dprintk("found DiB9000M");
+               break;
+       }
+
+       return value;
+}
+
+static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode)
+{
+       /* by default everything is going to be powered off */
+       u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906;
+       u8 offset;
+
+       if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005)
+               offset = 1;
+       else
+               offset = 0;
+
+       reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */
+
+       /* now, depending on the requested mode, we power on */
+       switch (mode) {
+               /* power up everything in the demod */
+       case DIB9000_POWER_ALL:
+               reg_903 = 0x0000;
+               reg_904 = 0x0000;
+               reg_905 = 0x0000;
+               reg_906 = 0x0000;
+               break;
+
+               /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
+       case DIB9000_POWER_INTERFACE_ONLY:      /* TODO power up either SDIO or I2C or SRAM */
+               reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
+               break;
+
+       case DIB9000_POWER_INTERF_ANALOG_AGC:
+               reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
+               reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
+               reg_906 &= ~((1 << 0));
+               break;
+
+       case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
+               reg_903 = 0x0000;
+               reg_904 = 0x801f;
+               reg_905 = 0x0000;
+               reg_906 &= ~((1 << 0));
+               break;
+
+       case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD:
+               reg_903 = 0x0000;
+               reg_904 = 0x8000;
+               reg_905 = 0x010b;
+               reg_906 &= ~((1 << 0));
+               break;
+       default:
+       case DIB9000_POWER_NO:
+               break;
+       }
+
+       /* always power down unused parts */
+       if (!state->platform.host.mobile_mode)
+               reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
+
+       /* P_sdio_select_clk = 0 on MC and after */
+       if (state->revision != 0x4000)
+               reg_906 <<= 1;
+
+       dib9000_write_word(state, 903 + offset, reg_903);
+       dib9000_write_word(state, 904 + offset, reg_904);
+       dib9000_write_word(state, 905 + offset, reg_905);
+       dib9000_write_word(state, 906 + offset, reg_906);
+}
+
+static int dib9000_fw_reset(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+
+       dib9000_write_word(state, 1817, 0x0003);
+
+       dib9000_write_word(state, 1227, 1);
+       dib9000_write_word(state, 1227, 0);
+
+       switch ((state->revision = dib9000_identify(&state->i2c))) {
+       case 0x4003:
+       case 0x4004:
+       case 0x4005:
+               state->reg_offs = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* reset the i2c-master to use the host interface */
+       dibx000_reset_i2c_master(&state->i2c_master);
+
+       dib9000_set_power_mode(state, DIB9000_POWER_ALL);
+
+       /* unforce divstr regardless whether i2c enumeration was done or not */
+       dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1));
+       dib9000_write_word(state, 1796, 0);
+       dib9000_write_word(state, 1805, 0x805);
+
+       /* restart all parts */
+       dib9000_write_word(state, 898, 0xffff);
+       dib9000_write_word(state, 899, 0xffff);
+       dib9000_write_word(state, 900, 0x0001);
+       dib9000_write_word(state, 901, 0xff19);
+       dib9000_write_word(state, 902, 0x003c);
+
+       dib9000_write_word(state, 898, 0);
+       dib9000_write_word(state, 899, 0);
+       dib9000_write_word(state, 900, 0);
+       dib9000_write_word(state, 901, 0);
+       dib9000_write_word(state, 902, 0);
+
+       dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives);
+
+       dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY);
+
+       return 0;
+}
+
+static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len)
+{
+       u16 mb[10];
+       u8 i, s;
+
+       if (address >= 1024 || !state->platform.risc.fw_is_running)
+               return -EINVAL;
+
+       /* dprintk( "APB access thru rd fw %d %x", address, attribute); */
+
+       mb[0] = (u16) address;
+       mb[1] = len / 2;
+       dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute);
+       switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) {
+       case 1:
+               s--;
+               for (i = 0; i < s; i++) {
+                       b[i * 2] = (mb[i + 1] >> 8) & 0xff;
+                       b[i * 2 + 1] = (mb[i + 1]) & 0xff;
+               }
+               return 0;
+       default:
+               return -EIO;
+       }
+       return -EIO;
+}
+
+static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len)
+{
+       u16 mb[10];
+       u8 s, i;
+
+       if (address >= 1024 || !state->platform.risc.fw_is_running)
+               return -EINVAL;
+
+       /* dprintk( "APB access thru wr fw %d %x", address, attribute); */
+
+       mb[0] = (unsigned short)address;
+       for (i = 0; i < len && i < 20; i += 2)
+               mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]);
+
+       dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute);
+       return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
+}
+
+static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
+{
+       u8 index_loop = 10;
+
+       if (!state->platform.risc.fw_is_running)
+               return 0;
+       dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
+       do {
+               dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1);
+       } while (i && index_loop--);
+
+       if (index_loop > 0)
+               return 0;
+       return -EIO;
+}
+
+static int dib9000_fw_init(struct dib9000_state *state)
+{
+       struct dibGPIOFunction *f;
+       u16 b[40] = { 0 };
+       u8 i;
+       u8 size;
+
+       if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0)
+               return -EIO;
+
+       /* initialize the firmware */
+       for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) {
+               f = &state->chip.d9.cfg.gpio_function[i];
+               if (f->mask) {
+                       switch (f->function) {
+                       case BOARD_GPIO_FUNCTION_COMPONENT_ON:
+                               b[0] = (u16) f->mask;
+                               b[1] = (u16) f->direction;
+                               b[2] = (u16) f->value;
+                               break;
+                       case BOARD_GPIO_FUNCTION_COMPONENT_OFF:
+                               b[3] = (u16) f->mask;
+                               b[4] = (u16) f->direction;
+                               b[5] = (u16) f->value;
+                               break;
+                       }
+               }
+       }
+       if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0)
+               return -EIO;
+
+       /* subband */
+       b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */
+       for (i = 0; i < state->chip.d9.cfg.subband.size; i++) {
+               b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz;
+               b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask;
+               b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction;
+               b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value;
+       }
+       b[1 + i * 4] = 0;       /* fe_id */
+       if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0)
+               return -EIO;
+
+       /* 0 - id, 1 - no_of_frontends */
+       b[0] = (0 << 8) | 1;
+       /* 0 = i2c-address demod, 0 = tuner */
+       b[1] = (0 << 8) | (0);
+       b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff);
+       b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff);
+       b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff);
+       b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff);
+       b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff);
+       b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff);
+       b[29] = state->chip.d9.cfg.if_drives;
+       if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0)
+               return -EIO;
+
+       if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0)
+               return -EIO;
+
+       if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0)
+               return -EIO;
+
+       if (size > ARRAY_SIZE(b)) {
+               dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size,
+                       (int)ARRAY_SIZE(b));
+               return -EINVAL;
+       }
+
+       for (i = 0; i < size; i += 2) {
+               state->platform.risc.fe_mm[i / 2].addr = b[i + 0];
+               state->platform.risc.fe_mm[i / 2].size = b[i + 1];
+       }
+
+       return 0;
+}
+
+static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch)
+{
+       u8 b[9];
+       u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000;
+       if (state->fe_id % 2)
+               freq += 101;
+
+       b[0] = (u8) ((freq >> 0) & 0xff);
+       b[1] = (u8) ((freq >> 8) & 0xff);
+       b[2] = (u8) ((freq >> 16) & 0xff);
+       b[3] = (u8) ((freq >> 24) & 0xff);
+       b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff);
+       b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff);
+       b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff);
+       b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff);
+       b[8] = 0x80;            /* do not wait for CELL ID when doing autosearch */
+       if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT)
+               b[8] |= 1;
+       dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b);
+}
+
+static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       struct dibDVBTChannel {
+               s8 spectrum_inversion;
+
+               s8 nfft;
+               s8 guard;
+               s8 constellation;
+
+               s8 hrch;
+               s8 alpha;
+               s8 code_rate_hp;
+               s8 code_rate_lp;
+               s8 select_hp;
+
+               s8 intlv_native;
+       };
+       struct dibDVBTChannel ch;
+       int ret = 0;
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               goto error;
+               ret = -EIO;
+       }
+
+       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel));
+
+       switch (ch.spectrum_inversion & 0x7) {
+       case 1:
+               state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
+               break;
+       case 0:
+               state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
+               break;
+       }
+       switch (ch.nfft) {
+       case 0:
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+       case 2:
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
+               break;
+       case 1:
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+               break;
+       }
+       switch (ch.guard) {
+       case 0:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
+               break;
+       case 1:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
+               break;
+       case 2:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+               break;
+       case 3:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+               break;
+       }
+       switch (ch.constellation) {
+       case 2:
+               state->fe[0]->dtv_property_cache.modulation = QAM_64;
+               break;
+       case 1:
+               state->fe[0]->dtv_property_cache.modulation = QAM_16;
+               break;
+       case 0:
+               state->fe[0]->dtv_property_cache.modulation = QPSK;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
+               break;
+       }
+       switch (ch.hrch) {
+       case 0:
+               state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
+               break;
+       case 1:
+               state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+               break;
+       }
+       switch (ch.code_rate_hp) {
+       case 1:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
+               break;
+       case 2:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3;
+               break;
+       case 3:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4;
+               break;
+       case 5:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6;
+               break;
+       case 7:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
+               break;
+       }
+       switch (ch.code_rate_lp) {
+       case 1:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
+               break;
+       case 2:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3;
+               break;
+       case 3:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4;
+               break;
+       case 5:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6;
+               break;
+       case 7:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8;
+               break;
+       default:
+       case -1:
+               state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO;
+               break;
+       }
+
+error:
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+       return ret;
+}
+
+static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       struct dibDVBTChannel {
+               s8 spectrum_inversion;
+
+               s8 nfft;
+               s8 guard;
+               s8 constellation;
+
+               s8 hrch;
+               s8 alpha;
+               s8 code_rate_hp;
+               s8 code_rate_lp;
+               s8 select_hp;
+
+               s8 intlv_native;
+       };
+       struct dibDVBTChannel ch;
+
+       switch (state->fe[0]->dtv_property_cache.inversion) {
+       case INVERSION_ON:
+               ch.spectrum_inversion = 1;
+               break;
+       case INVERSION_OFF:
+               ch.spectrum_inversion = 0;
+               break;
+       default:
+       case INVERSION_AUTO:
+               ch.spectrum_inversion = -1;
+               break;
+       }
+       switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+               ch.nfft = 0;
+               break;
+       case TRANSMISSION_MODE_4K:
+               ch.nfft = 2;
+               break;
+       case TRANSMISSION_MODE_8K:
+               ch.nfft = 1;
+               break;
+       default:
+       case TRANSMISSION_MODE_AUTO:
+               ch.nfft = 1;
+               break;
+       }
+       switch (state->fe[0]->dtv_property_cache.guard_interval) {
+       case GUARD_INTERVAL_1_32:
+               ch.guard = 0;
+               break;
+       case GUARD_INTERVAL_1_16:
+               ch.guard = 1;
+               break;
+       case GUARD_INTERVAL_1_8:
+               ch.guard = 2;
+               break;
+       case GUARD_INTERVAL_1_4:
+               ch.guard = 3;
+               break;
+       default:
+       case GUARD_INTERVAL_AUTO:
+               ch.guard = -1;
+               break;
+       }
+       switch (state->fe[0]->dtv_property_cache.modulation) {
+       case QAM_64:
+               ch.constellation = 2;
+               break;
+       case QAM_16:
+               ch.constellation = 1;
+               break;
+       case QPSK:
+               ch.constellation = 0;
+               break;
+       default:
+       case QAM_AUTO:
+               ch.constellation = -1;
+               break;
+       }
+       switch (state->fe[0]->dtv_property_cache.hierarchy) {
+       case HIERARCHY_NONE:
+               ch.hrch = 0;
+               break;
+       case HIERARCHY_1:
+       case HIERARCHY_2:
+       case HIERARCHY_4:
+               ch.hrch = 1;
+               break;
+       default:
+       case HIERARCHY_AUTO:
+               ch.hrch = -1;
+               break;
+       }
+       ch.alpha = 1;
+       switch (state->fe[0]->dtv_property_cache.code_rate_HP) {
+       case FEC_1_2:
+               ch.code_rate_hp = 1;
+               break;
+       case FEC_2_3:
+               ch.code_rate_hp = 2;
+               break;
+       case FEC_3_4:
+               ch.code_rate_hp = 3;
+               break;
+       case FEC_5_6:
+               ch.code_rate_hp = 5;
+               break;
+       case FEC_7_8:
+               ch.code_rate_hp = 7;
+               break;
+       default:
+       case FEC_AUTO:
+               ch.code_rate_hp = -1;
+               break;
+       }
+       switch (state->fe[0]->dtv_property_cache.code_rate_LP) {
+       case FEC_1_2:
+               ch.code_rate_lp = 1;
+               break;
+       case FEC_2_3:
+               ch.code_rate_lp = 2;
+               break;
+       case FEC_3_4:
+               ch.code_rate_lp = 3;
+               break;
+       case FEC_5_6:
+               ch.code_rate_lp = 5;
+               break;
+       case FEC_7_8:
+               ch.code_rate_lp = 7;
+               break;
+       default:
+       case FEC_AUTO:
+               ch.code_rate_lp = -1;
+               break;
+       }
+       ch.select_hp = 1;
+       ch.intlv_native = 1;
+
+       dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch);
+
+       return 0;
+}
+
+static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN;
+       s8 i;
+
+       switch (state->tune_state) {
+       case CT_DEMOD_START:
+               dib9000_fw_set_channel_head(state, ch);
+
+               /* write the channel context - a channel is initialized to 0, so it is OK */
+               dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info);
+               dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info);
+
+               if (search)
+                       dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0);
+               else {
+                       dib9000_fw_set_channel_union(fe, ch);
+                       dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0);
+               }
+               state->tune_state = CT_DEMOD_STEP_1;
+               break;
+       case CT_DEMOD_STEP_1:
+               if (search)
+                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1);
+               else
+                       dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1);
+               switch (i) {    /* something happened */
+               case 0:
+                       break;
+               case -2:        /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */
+                       if (search)
+                               state->status = FE_STATUS_DEMOD_SUCCESS;
+                       else {
+                               state->tune_state = CT_DEMOD_STOP;
+                               state->status = FE_STATUS_LOCKED;
+                       }
+                       break;
+               default:
+                       state->status = FE_STATUS_TUNE_FAILED;
+                       state->tune_state = CT_DEMOD_STOP;
+                       break;
+               }
+               break;
+       default:
+               ret = FE_CALLBACK_TIME_NEVER;
+               break;
+       }
+
+       return ret;
+}
+
+static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 mode = (u16) onoff;
+       return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1);
+}
+
+static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 outreg, smo_mode;
+
+       dprintk("setting output mode for demod %p to %d", fe, mode);
+
+       switch (mode) {
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+               outreg = (1 << 10);     /* 0x0400 */
+               break;
+       case OUTMODE_MPEG2_PAR_CONT_CLK:
+               outreg = (1 << 10) | (1 << 6);  /* 0x0440 */
+               break;
+       case OUTMODE_MPEG2_SERIAL:
+               outreg = (1 << 10) | (2 << 6) | (0 << 1);       /* 0x0482 */
+               break;
+       case OUTMODE_DIVERSITY:
+               outreg = (1 << 10) | (4 << 6);  /* 0x0500 */
+               break;
+       case OUTMODE_MPEG2_FIFO:
+               outreg = (1 << 10) | (5 << 6);
+               break;
+       case OUTMODE_HIGH_Z:
+               outreg = 0;
+               break;
+       default:
+               dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]);
+               return -EINVAL;
+       }
+
+       dib9000_write_word(state, 1795, outreg);
+
+       switch (mode) {
+       case OUTMODE_MPEG2_PAR_GATED_CLK:
+       case OUTMODE_MPEG2_PAR_CONT_CLK:
+       case OUTMODE_MPEG2_SERIAL:
+       case OUTMODE_MPEG2_FIFO:
+               smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1);
+               if (state->chip.d9.cfg.output_mpeg2_in_188_bytes)
+                       smo_mode |= (1 << 5);
+               dib9000_write_word(state, 295, smo_mode);
+               break;
+       }
+
+       outreg = to_fw_output_mode(mode);
+       return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1);
+}
+
+static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
+       u16 i, len, t, index_msg;
+
+       for (index_msg = 0; index_msg < num; index_msg++) {
+               if (msg[index_msg].flags & I2C_M_RD) {  /* read */
+                       len = msg[index_msg].len;
+                       if (len > 16)
+                               len = 16;
+
+                       if (dib9000_read_word(state, 790) != 0)
+                               dprintk("TunerITF: read busy");
+
+                       dib9000_write_word(state, 784, (u16) (msg[index_msg].addr));
+                       dib9000_write_word(state, 787, (len / 2) - 1);
+                       dib9000_write_word(state, 786, 1);      /* start read */
+
+                       i = 1000;
+                       while (dib9000_read_word(state, 790) != (len / 2) && i)
+                               i--;
+
+                       if (i == 0)
+                               dprintk("TunerITF: read failed");
+
+                       for (i = 0; i < len; i += 2) {
+                               t = dib9000_read_word(state, 785);
+                               msg[index_msg].buf[i] = (t >> 8) & 0xff;
+                               msg[index_msg].buf[i + 1] = (t) & 0xff;
+                       }
+                       if (dib9000_read_word(state, 790) != 0)
+                               dprintk("TunerITF: read more data than expected");
+               } else {
+                       i = 1000;
+                       while (dib9000_read_word(state, 789) && i)
+                               i--;
+                       if (i == 0)
+                               dprintk("TunerITF: write busy");
+
+                       len = msg[index_msg].len;
+                       if (len > 16)
+                               len = 16;
+
+                       for (i = 0; i < len; i += 2)
+                               dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]);
+                       dib9000_write_word(state, 784, (u16) msg[index_msg].addr);
+                       dib9000_write_word(state, 787, (len / 2) - 1);
+                       dib9000_write_word(state, 786, 0);      /* start write */
+
+                       i = 1000;
+                       while (dib9000_read_word(state, 791) > 0 && i)
+                               i--;
+                       if (i == 0)
+                               dprintk("TunerITF: write failed");
+               }
+       }
+       return num;
+}
+
+int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+
+       state->component_bus_speed = speed;
+       return 0;
+}
+EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed);
+
+static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dib9000_state *state = i2c_get_adapdata(i2c_adap);
+       u8 type = 0;            /* I2C */
+       u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4;
+       u16 scl = state->component_bus_speed;   /* SCL frequency */
+       struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER];
+       u8 p[13] = { 0 };
+
+       p[0] = type;
+       p[1] = port;
+       p[2] = msg[0].addr << 1;
+
+       p[3] = (u8) scl & 0xff; /* scl */
+       p[4] = (u8) (scl >> 8);
+
+       p[7] = 0;
+       p[8] = 0;
+
+       p[9] = (u8) (msg[0].len);
+       p[10] = (u8) (msg[0].len >> 8);
+       if ((num > 1) && (msg[1].flags & I2C_M_RD)) {
+               p[11] = (u8) (msg[1].len);
+               p[12] = (u8) (msg[1].len >> 8);
+       } else {
+               p[11] = 0;
+               p[12] = 0;
+       }
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+
+       dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
+
+       {                       /* write-part */
+               dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0);
+               dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len);
+       }
+
+       /* do the transaction */
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
+               DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+               return 0;
+       }
+
+       /* read back any possible result */
+       if ((num > 1) && (msg[1].flags & I2C_M_RD))
+               dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
+
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+       return num;
+}
+
+static u32 dib9000_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dib9000_tuner_algo = {
+       .master_xfer = dib9000_tuner_xfer,
+       .functionality = dib9000_i2c_func,
+};
+
+static struct i2c_algorithm dib9000_component_bus_algo = {
+       .master_xfer = dib9000_fw_component_bus_xfer,
+       .functionality = dib9000_i2c_func,
+};
+
+struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
+{
+       struct dib9000_state *st = fe->demodulator_priv;
+       return &st->tuner_adap;
+}
+EXPORT_SYMBOL(dib9000_get_tuner_interface);
+
+struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
+{
+       struct dib9000_state *st = fe->demodulator_priv;
+       return &st->component_bus;
+}
+EXPORT_SYMBOL(dib9000_get_component_bus_interface);
+
+struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+{
+       struct dib9000_state *st = fe->demodulator_priv;
+       return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
+}
+EXPORT_SYMBOL(dib9000_get_i2c_master);
+
+int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+       struct dib9000_state *st = fe->demodulator_priv;
+
+       st->i2c.i2c_adap = i2c;
+       return 0;
+}
+EXPORT_SYMBOL(dib9000_set_i2c_adapter);
+
+static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val)
+{
+       st->gpio_dir = dib9000_read_word(st, 773);
+       st->gpio_dir &= ~(1 << num);    /* reset the direction bit */
+       st->gpio_dir |= (dir & 0x1) << num;     /* set the new direction */
+       dib9000_write_word(st, 773, st->gpio_dir);
+
+       st->gpio_val = dib9000_read_word(st, 774);
+       st->gpio_val &= ~(1 << num);    /* reset the direction bit */
+       st->gpio_val |= (val & 0x01) << num;    /* set the new value */
+       dib9000_write_word(st, 774, st->gpio_val);
+
+       dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val);
+
+       return 0;
+}
+
+int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       return dib9000_cfg_gpio(state, num, dir, val);
+}
+EXPORT_SYMBOL(dib9000_set_gpio);
+
+int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
+       val |= (onoff & 0x1) << 4;
+
+       dprintk("PID filter enabled %d", onoff);
+       return dib9000_write_word(state, 294 + 1, val);
+}
+EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
+
+int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+       return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib9000_fw_pid_filter);
+
+int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       return dib9000_fw_init(state);
+}
+EXPORT_SYMBOL(dib9000_firmware_post_pll_init);
+
+static void dib9000_release(struct dvb_frontend *demod)
+{
+       struct dib9000_state *st = demod->demodulator_priv;
+       u8 index_frontend;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
+               dvb_frontend_detach(st->fe[index_frontend]);
+
+       DibFreeLock(&state->platform.risc.mbx_if_lock);
+       DibFreeLock(&state->platform.risc.mbx_lock);
+       DibFreeLock(&state->platform.risc.mem_lock);
+       DibFreeLock(&state->platform.risc.mem_mbx_lock);
+       dibx000_exit_i2c_master(&st->i2c_master);
+
+       i2c_del_adapter(&st->tuner_adap);
+       i2c_del_adapter(&st->component_bus);
+       kfree(st->fe[0]);
+       kfree(st);
+}
+
+static int dib9000_wakeup(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int dib9000_sleep(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       int ret;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+               if (ret < 0)
+                       return ret;
+       }
+       return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
+}
+
+static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+{
+       tune->min_delay_ms = 1000;
+       return 0;
+}
+
+static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend, sub_index_frontend;
+       fe_status_t stat;
+       int ret;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+               if (stat & FE_HAS_SYNC) {
+                       dprintk("TPS lock on the slave%i", index_frontend);
+
+                       /* synchronize the cache with the other frontends */
+                       state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
+                       for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL);
+                            sub_index_frontend++) {
+                               if (sub_index_frontend != index_frontend) {
+                                       state->fe[sub_index_frontend]->dtv_property_cache.modulation =
+                                           state->fe[index_frontend]->dtv_property_cache.modulation;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.inversion =
+                                           state->fe[index_frontend]->dtv_property_cache.inversion;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode =
+                                           state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.guard_interval =
+                                           state->fe[index_frontend]->dtv_property_cache.guard_interval;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.hierarchy =
+                                           state->fe[index_frontend]->dtv_property_cache.hierarchy;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP =
+                                           state->fe[index_frontend]->dtv_property_cache.code_rate_HP;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP =
+                                           state->fe[index_frontend]->dtv_property_cache.code_rate_LP;
+                                       state->fe[sub_index_frontend]->dtv_property_cache.rolloff =
+                                           state->fe[index_frontend]->dtv_property_cache.rolloff;
+                               }
+                       }
+                       return 0;
+               }
+       }
+
+       /* get the channel from master chip */
+       ret = dib9000_fw_get_channel(fe, fep);
+       if (ret != 0)
+               return ret;
+
+       /* synchronize the cache with the other frontends */
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
+               state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
+               state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
+               state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation;
+               state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy;
+               state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP;
+               state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
+               state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+       }
+
+       return 0;
+}
+
+static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       state->tune_state = tune_state;
+       if (tune_state == CT_DEMOD_START)
+               state->status = FE_STATUS_TUNE_PENDING;
+
+       return 0;
+}
+
+static u32 dib9000_get_status(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       return state->status;
+}
+
+static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+
+       memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext));
+       return 0;
+}
+
+static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       int sleep_time, sleep_time_slave;
+       u32 frontend_status;
+       u8 nbr_pending, exit_condition, index_frontend, index_frontend_success;
+       struct dvb_frontend_parametersContext channel_status;
+
+       /* check that the correct parameters are set */
+       if (state->fe[0]->dtv_property_cache.frequency == 0) {
+               dprintk("dib9000: must specify frequency ");
+               return 0;
+       }
+
+       if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
+               dprintk("dib9000: must specify bandwidth ");
+               return 0;
+       }
+       fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+       /* set the master status */
+       if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
+           fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+               /* no channel specified, autosearch the channel */
+               state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN;
+       } else
+               state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+
+       /* set mode and status for the different frontends */
+       for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               dib9000_fw_set_diversity_in(state->fe[index_frontend], 1);
+
+               /* synchronization of the cache */
+               memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
+
+               state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT;
+               dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
+
+               dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status);
+               dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+       }
+
+       /* actual tune */
+       exit_condition = 0;     /* 0: tune pending; 1: tune failed; 2:tune success */
+       index_frontend_success = 0;
+       do {
+               sleep_time = dib9000_fw_tune(state->fe[0], NULL);
+               for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+                       if (sleep_time == FE_CALLBACK_TIME_NEVER)
+                               sleep_time = sleep_time_slave;
+                       else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
+                               sleep_time = sleep_time_slave;
+               }
+               if (sleep_time != FE_CALLBACK_TIME_NEVER)
+                       msleep(sleep_time / 10);
+               else
+                       break;
+
+               nbr_pending = 0;
+               exit_condition = 0;
+               index_frontend_success = 0;
+               for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       frontend_status = -dib9000_get_status(state->fe[index_frontend]);
+                       if (frontend_status > -FE_STATUS_TUNE_PENDING) {
+                               exit_condition = 2;     /* tune success */
+                               index_frontend_success = index_frontend;
+                               break;
+                       }
+                       if (frontend_status == -FE_STATUS_TUNE_PENDING)
+                               nbr_pending++;  /* some frontends are still tuning */
+               }
+               if ((exit_condition != 2) && (nbr_pending == 0))
+                       exit_condition = 1;     /* if all tune are done and no success, exit: tune failed */
+
+       } while (exit_condition == 0);
+
+       /* check the tune result */
+       if (exit_condition == 1) {      /* tune failed */
+               dprintk("tune failed");
+               return 0;
+       }
+
+       dprintk("tune success on frontend%i", index_frontend_success);
+
+       /* synchronize all the channel cache */
+       dib9000_get_frontend(state->fe[0], fep);
+
+       /* retune the other frontends with the found channel */
+       channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+       for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               /* only retune the frontends which was not tuned success */
+               if (index_frontend != index_frontend_success) {
+                       dib9000_set_channel_status(state->fe[index_frontend], &channel_status);
+                       dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
+               }
+       }
+       do {
+               sleep_time = FE_CALLBACK_TIME_NEVER;
+               for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       if (index_frontend != index_frontend_success) {
+                               sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL);
+                               if (sleep_time == FE_CALLBACK_TIME_NEVER)
+                                       sleep_time = sleep_time_slave;
+                               else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time))
+                                       sleep_time = sleep_time_slave;
+                       }
+               }
+               if (sleep_time != FE_CALLBACK_TIME_NEVER)
+                       msleep(sleep_time / 10);
+               else
+                       break;
+
+               nbr_pending = 0;
+               for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+                       if (index_frontend != index_frontend_success) {
+                               frontend_status = -dib9000_get_status(state->fe[index_frontend]);
+                               if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING))
+                                       nbr_pending++;  /* some frontends are still tuning */
+                       }
+               }
+       } while (nbr_pending != 0);
+
+       /* set the output mode */
+       dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
+
+       /* turn off the diversity for the last frontend */
+       dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
+
+       return 0;
+}
+
+static u16 dib9000_read_lock(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+
+       return dib9000_read_word(state, 535);
+}
+
+static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       u16 lock = 0, lock_slave = 0;
+
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
+
+       lock = dib9000_read_word(state, 535);
+
+       *stat = 0;
+
+       if ((lock & 0x8000) || (lock_slave & 0x8000))
+               *stat |= FE_HAS_SIGNAL;
+       if ((lock & 0x3000) || (lock_slave & 0x3000))
+               *stat |= FE_HAS_CARRIER;
+       if ((lock & 0x0100) || (lock_slave & 0x0100))
+               *stat |= FE_HAS_VITERBI;
+       if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38))
+               *stat |= FE_HAS_SYNC;
+       if ((lock & 0x0008) || (lock_slave & 0x0008))
+               *stat |= FE_HAS_LOCK;
+
+       return 0;
+}
+
+static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 c[16];
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+       *ber = c[10] << 16 | c[11];
+       return 0;
+}
+
+static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       u16 c[16];
+       u16 val;
+
+       *strength = 0;
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+               if (val > 65535 - *strength)
+                       *strength = 65535;
+               else
+                       *strength += val;
+       }
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+       val = 65535 - c[4];
+       if (val > 65535 - *strength)
+               *strength = 65535;
+       else
+               *strength += val;
+       return 0;
+}
+
+static u32 dib9000_get_snr(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 c[16];
+       u32 n, s, exp;
+       u16 val;
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+       val = c[7];
+       n = (val >> 4) & 0xff;
+       exp = ((val & 0xf) << 2);
+       val = c[8];
+       exp += ((val >> 14) & 0x3);
+       if ((exp & 0x20) != 0)
+               exp -= 0x40;
+       n <<= exp + 16;
+
+       s = (val >> 6) & 0xFF;
+       exp = (val & 0x3F);
+       if ((exp & 0x20) != 0)
+               exp -= 0x40;
+       s <<= exp + 16;
+
+       if (n > 0) {
+               u32 t = (s / n) << 16;
+               return t + ((s << 16) - n * t) / n;
+       }
+       return 0xffffffff;
+}
+
+static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+       u32 snr_master;
+
+       snr_master = dib9000_get_snr(fe);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               snr_master += dib9000_get_snr(state->fe[index_frontend]);
+
+       if ((snr_master >> 16) != 0) {
+               snr_master = 10 * intlog10(snr_master >> 16);
+               *snr = snr_master / ((1 << 24) / 10);
+       } else
+               *snr = 0;
+
+       return 0;
+}
+
+static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 c[16];
+
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+               return -EIO;
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+
+       *unc = c[12];
+       return 0;
+}
+
+int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+{
+       int k = 0;
+       u8 new_addr = 0;
+       struct i2c_device client = {.i2c_adap = i2c };
+
+       client.i2c_addr = default_addr + 16;
+       dib9000_i2c_write16(&client, 1796, 0x0);
+
+       for (k = no_of_demods - 1; k >= 0; k--) {
+               /* designated i2c address */
+               new_addr = first_addr + (k << 1);
+               client.i2c_addr = default_addr;
+
+               dib9000_i2c_write16(&client, 1817, 3);
+               dib9000_i2c_write16(&client, 1796, 0);
+               dib9000_i2c_write16(&client, 1227, 1);
+               dib9000_i2c_write16(&client, 1227, 0);
+
+               client.i2c_addr = new_addr;
+               dib9000_i2c_write16(&client, 1817, 3);
+               dib9000_i2c_write16(&client, 1796, 0);
+               dib9000_i2c_write16(&client, 1227, 1);
+               dib9000_i2c_write16(&client, 1227, 0);
+
+               if (dib9000_identify(&client) == 0) {
+                       client.i2c_addr = default_addr;
+                       if (dib9000_identify(&client) == 0) {
+                               dprintk("DiB9000 #%d: not identified", k);
+                               return -EIO;
+                       }
+               }
+
+               dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6));
+               dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2);
+
+               dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
+       }
+
+       for (k = 0; k < no_of_demods; k++) {
+               new_addr = first_addr | (k << 1);
+               client.i2c_addr = new_addr;
+
+               dib9000_i2c_write16(&client, 1794, (new_addr << 2));
+               dib9000_i2c_write16(&client, 1795, 0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(dib9000_i2c_enumeration);
+
+int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend = 1;
+
+       while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+               index_frontend++;
+       if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
+               dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
+               state->fe[index_frontend] = fe_slave;
+               return 0;
+       }
+
+       dprintk("too many slave frontend");
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(dib9000_set_slave_frontend);
+
+int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend = 1;
+
+       while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
+               index_frontend++;
+       if (index_frontend != 1) {
+               dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1);
+               state->fe[index_frontend] = NULL;
+               return 0;
+       }
+
+       dprintk("no frontend to be removed");
+       return -ENODEV;
+}
+EXPORT_SYMBOL(dib9000_remove_slave_frontend);
+
+struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+       struct dib9000_state *state = fe->demodulator_priv;
+
+       if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
+               return NULL;
+       return state->fe[slave_index];
+}
+EXPORT_SYMBOL(dib9000_get_slave_frontend);
+
+static struct dvb_frontend_ops dib9000_ops;
+struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg)
+{
+       struct dvb_frontend *fe;
+       struct dib9000_state *st;
+       st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL);
+       if (st == NULL)
+               return NULL;
+       fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
+       if (fe == NULL)
+               return NULL;
+
+       memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
+       st->i2c.i2c_adap = i2c_adap;
+       st->i2c.i2c_addr = i2c_addr;
+
+       st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
+       st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
+       st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
+
+       DibInitLock(&st->platform.risc.mbx_if_lock);
+       DibInitLock(&st->platform.risc.mbx_lock);
+       DibInitLock(&st->platform.risc.mem_lock);
+       DibInitLock(&st->platform.risc.mem_mbx_lock);
+
+       st->fe[0] = fe;
+       fe->demodulator_priv = st;
+       memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops));
+
+       /* Ensure the output mode remains at the previous default if it's
+        * not specifically set by the caller.
+        */
+       if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
+               st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO;
+
+       if (dib9000_identify(&st->i2c) == 0)
+               goto error;
+
+       dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr);
+
+       st->tuner_adap.dev.parent = i2c_adap->dev.parent;
+       strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name));
+       st->tuner_adap.algo = &dib9000_tuner_algo;
+       st->tuner_adap.algo_data = NULL;
+       i2c_set_adapdata(&st->tuner_adap, st);
+       if (i2c_add_adapter(&st->tuner_adap) < 0)
+               goto error;
+
+       st->component_bus.dev.parent = i2c_adap->dev.parent;
+       strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name));
+       st->component_bus.algo = &dib9000_component_bus_algo;
+       st->component_bus.algo_data = NULL;
+       st->component_bus_speed = 340;
+       i2c_set_adapdata(&st->component_bus, st);
+       if (i2c_add_adapter(&st->component_bus) < 0)
+               goto component_bus_add_error;
+
+       dib9000_fw_reset(fe);
+
+       return fe;
+
+component_bus_add_error:
+       i2c_del_adapter(&st->tuner_adap);
+error:
+       kfree(st);
+       return NULL;
+}
+EXPORT_SYMBOL(dib9000_attach);
+
+static struct dvb_frontend_ops dib9000_ops = {
+       .info = {
+                .name = "DiBcom 9000",
+                .type = FE_OFDM,
+                .frequency_min = 44250000,
+                .frequency_max = 867250000,
+                .frequency_stepsize = 62500,
+                .caps = FE_CAN_INVERSION_AUTO |
+                FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
+                },
+
+       .release = dib9000_release,
+
+       .init = dib9000_wakeup,
+       .sleep = dib9000_sleep,
+
+       .set_frontend = dib9000_set_frontend,
+       .get_tune_settings = dib9000_fe_get_tune_settings,
+       .get_frontend = dib9000_get_frontend,
+
+       .read_status = dib9000_read_status,
+       .read_ber = dib9000_read_ber,
+       .read_signal_strength = dib9000_read_signal_strength,
+       .read_snr = dib9000_read_snr,
+       .read_ucblocks = dib9000_read_unc_blocks,
+};
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib9000.h b/drivers/media/dvb/frontends/dib9000.h
new file mode 100644 (file)
index 0000000..b5781a4
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef DIB9000_H
+#define DIB9000_H
+
+#include "dibx000_common.h"
+
+struct dib9000_config {
+       u8 dvbt_mode;
+       u8 output_mpeg2_in_188_bytes;
+       u8 hostbus_diversity;
+       struct dibx000_bandwidth_config *bw;
+
+       u16 if_drives;
+
+       u32 timing_frequency;
+       u32 xtal_clock_khz;
+       u32 vcxo_timer;
+       u32 demod_clock_khz;
+
+       const u8 *microcode_B_fe_buffer;
+       u32 microcode_B_fe_size;
+
+       struct dibGPIOFunction gpio_function[2];
+       struct dibSubbandSelection subband;
+
+       u8 output_mode;
+};
+
+#define DEFAULT_DIB9000_I2C_ADDRESS 18
+
+#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg);
+extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr);
+extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe);
+extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating);
+extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val);
+extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
+extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe);
+extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe);
+extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
+extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe);
+extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c);
+extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed);
+#else
+static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+int dib9000_remove_slave_frontend(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+#endif
+
+#endif
index 2311c0a3406c953e4199c627a135be7fdc97843c..f6938f97feb49fd6f3dc258bafe253ebe06a54a2 100644 (file)
@@ -17,9 +17,145 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
        struct i2c_msg msg = {
                .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
        };
+
        return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
+static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+{
+       u8 wb[2] = { reg >> 8, reg & 0xff };
+       u8 rb[2];
+       struct i2c_msg msg[2] = {
+               {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2},
+               {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2},
+       };
+
+       if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+
+       return (rb[0] << 8) | rb[1];
+}
+
+static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+{
+       int i = 100;
+       u16 status;
+
+       while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0)
+               ;
+
+       /* i2c timed out */
+       if (i == 0)
+               return -EREMOTEIO;
+
+       /* no acknowledge */
+       if ((status & 0x0080) == 0)
+               return -EREMOTEIO;
+
+       return 0;
+}
+
+static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop)
+{
+       u16 data;
+       u16 da;
+       u16 i;
+       u16 txlen = msg->len, len;
+       const u8 *b = msg->buf;
+
+       while (txlen) {
+               dibx000_read_word(mst, mst->base_reg + 2);
+
+               len = txlen > 8 ? 8 : txlen;
+               for (i = 0; i < len; i += 2) {
+                       data = *b++ << 8;
+                       if (i+1 < len)
+                               data |= *b++;
+                       dibx000_write_word(mst, mst->base_reg, data);
+               }
+               da = (((u8) (msg->addr))  << 9) |
+                       (1           << 8) |
+                       (1           << 7) |
+                       (0           << 6) |
+                       (0           << 5) |
+                       ((len & 0x7) << 2) |
+                       (0           << 1) |
+                       (0           << 0);
+
+               if (txlen == msg->len)
+                       da |= 1 << 5; /* start */
+
+               if (txlen-len == 0 && stop)
+                       da |= 1 << 6; /* stop */
+
+               dibx000_write_word(mst, mst->base_reg+1, da);
+
+               if (dibx000_is_i2c_done(mst) != 0)
+                       return -EREMOTEIO;
+               txlen -= len;
+       }
+
+       return 0;
+}
+
+static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg)
+{
+       u16 da;
+       u8 *b = msg->buf;
+       u16 rxlen = msg->len, len;
+
+       while (rxlen) {
+               len = rxlen > 8 ? 8 : rxlen;
+               da = (((u8) (msg->addr)) << 9) |
+                       (1           << 8) |
+                       (1           << 7) |
+                       (0           << 6) |
+                       (0           << 5) |
+                       ((len & 0x7) << 2) |
+                       (1           << 1) |
+                       (0           << 0);
+
+               if (rxlen == msg->len)
+                       da |= 1 << 5; /* start */
+
+               if (rxlen-len == 0)
+                       da |= 1 << 6; /* stop */
+               dibx000_write_word(mst, mst->base_reg+1, da);
+
+               if (dibx000_is_i2c_done(mst) != 0)
+                       return -EREMOTEIO;
+
+               rxlen -= len;
+
+               while (len) {
+                       da = dibx000_read_word(mst, mst->base_reg);
+                       *b++ = (da >> 8) & 0xff;
+                       len--;
+                       if (len >= 1) {
+                               *b++ =  da   & 0xff;
+                               len--;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed)
+{
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+
+       if (mst->device_rev < DIB7000MC && speed < 235)
+               speed = 235;
+       return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed));
+
+}
+EXPORT_SYMBOL(dibx000_i2c_set_speed);
+
+static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
 
 static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
                                        enum dibx000_i2c_interface intf)
@@ -32,6 +168,60 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
        return 0;
 }
 
+static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+       int msg_index;
+       int ret = 0;
+
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2);
+       for (msg_index = 0; msg_index < num; msg_index++) {
+               if (msg[msg_index].flags & I2C_M_RD) {
+                       ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
+                       if (ret != 0)
+                               return 0;
+               } else {
+                       ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
+                       if (ret != 0)
+                               return 0;
+               }
+       }
+
+       return num;
+}
+
+static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+       int msg_index;
+       int ret = 0;
+
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4);
+       for (msg_index = 0; msg_index < num; msg_index++) {
+               if (msg[msg_index].flags & I2C_M_RD) {
+                       ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
+                       if (ret != 0)
+                               return 0;
+               } else {
+                       ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
+                       if (ret != 0)
+                               return 0;
+               }
+       }
+
+       return num;
+}
+
+static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
+       .master_xfer = dibx000_i2c_master_xfer_gpio12,
+       .functionality = dibx000_i2c_func,
+};
+
+static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
+       .master_xfer = dibx000_i2c_master_xfer_gpio34,
+       .functionality = dibx000_i2c_func,
+};
+
 static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
                                 u8 addr, int onoff)
 {
@@ -54,11 +244,37 @@ static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
        return 0;
 }
 
-static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
+static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
+                                       struct i2c_msg msg[], int num)
 {
-       return I2C_FUNC_I2C;
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+       struct i2c_msg m[2 + num];
+       u8 tx_open[4], tx_close[4];
+
+       memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
+
+       dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
+       m[0].addr = mst->i2c_addr;
+       m[0].buf = tx_open;
+       m[0].len = 4;
+
+       memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+
+       dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
+       m[num + 1].addr = mst->i2c_addr;
+       m[num + 1].buf = tx_close;
+       m[num + 1].len = 4;
+
+       return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
 }
 
+static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+       .master_xfer = dibx000_i2c_gated_gpio67_xfer,
+       .functionality = dibx000_i2c_func,
+};
+
 static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
                                        struct i2c_msg msg[], int num)
 {
@@ -91,8 +307,8 @@ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
 };
 
 struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
-                                           enum dibx000_i2c_interface intf,
-                                           int gating)
+                                               enum dibx000_i2c_interface intf,
+                                               int gating)
 {
        struct i2c_adapter *i2c = NULL;
 
@@ -101,6 +317,18 @@ struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
                if (gating)
                        i2c = &mst->gated_tuner_i2c_adap;
                break;
+       case DIBX000_I2C_INTERFACE_GPIO_1_2:
+               if (!gating)
+                       i2c = &mst->master_i2c_adap_gpio12;
+               break;
+       case DIBX000_I2C_INTERFACE_GPIO_3_4:
+               if (!gating)
+                       i2c = &mst->master_i2c_adap_gpio34;
+               break;
+       case DIBX000_I2C_INTERFACE_GPIO_6_7:
+               if (gating)
+                       i2c = &mst->master_i2c_adap_gpio67;
+               break;
        default:
                printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
                break;
@@ -126,8 +354,8 @@ void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst)
 EXPORT_SYMBOL(dibx000_reset_i2c_master);
 
 static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
-                           struct i2c_algorithm *algo, const char *name,
-                           struct dibx000_i2c_master *mst)
+                               struct i2c_algorithm *algo, const char *name,
+                               struct dibx000_i2c_master *mst)
 {
        strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
        i2c_adap->algo = algo;
@@ -139,7 +367,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
 }
 
 int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
-                           struct i2c_adapter *i2c_adap, u8 i2c_addr)
+                               struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
        u8 tx[4];
        struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
@@ -153,11 +381,33 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
        else
                mst->base_reg = 768;
 
+       mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent;
+       if (i2c_adapter_init
+                       (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
+                        "DiBX000 tuner I2C bus", mst) != 0)
+               printk(KERN_ERR
+                               "DiBX000: could not initialize the tuner i2c_adapter\n");
+
+       mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent;
+       if (i2c_adapter_init
+                       (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo,
+                        "DiBX000 master GPIO12 I2C bus", mst) != 0)
+               printk(KERN_ERR
+                               "DiBX000: could not initialize the master i2c_adapter\n");
+
+       mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent;
+       if (i2c_adapter_init
+                       (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo,
+                        "DiBX000 master GPIO34 I2C bus", mst) != 0)
+               printk(KERN_ERR
+                               "DiBX000: could not initialize the master i2c_adapter\n");
+
+       mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent;
        if (i2c_adapter_init
-           (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
-            "DiBX000 tuner I2C bus", mst) != 0)
+                       (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo,
+                        "DiBX000 master GPIO67 I2C bus", mst) != 0)
                printk(KERN_ERR
-                      "DiBX000: could not initialize the tuner i2c_adapter\n");
+                               "DiBX000: could not initialize the master i2c_adapter\n");
 
        /* initialize the i2c-master by closing the gate */
        dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
@@ -170,16 +420,19 @@ EXPORT_SYMBOL(dibx000_init_i2c_master);
 void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
 {
        i2c_del_adapter(&mst->gated_tuner_i2c_adap);
+       i2c_del_adapter(&mst->master_i2c_adap_gpio12);
+       i2c_del_adapter(&mst->master_i2c_adap_gpio34);
+       i2c_del_adapter(&mst->master_i2c_adap_gpio67);
 }
 EXPORT_SYMBOL(dibx000_exit_i2c_master);
 
 
 u32 systime(void)
 {
-    struct timespec t;
+       struct timespec t;
 
-    t = current_kernel_time();
-    return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
+       t = current_kernel_time();
+       return (t.tv_sec * 10000) + (t.tv_nsec / 100000);
 }
 EXPORT_SYMBOL(systime);
 
index 4f5d141a308dc45945a762db1a4433fd93086c8a..977d343369aa42c6dfdb4577bb69c886b6a7ef55 100644 (file)
@@ -4,7 +4,8 @@
 enum dibx000_i2c_interface {
        DIBX000_I2C_INTERFACE_TUNER = 0,
        DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
-       DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
+       DIBX000_I2C_INTERFACE_GPIO_3_4 = 2,
+       DIBX000_I2C_INTERFACE_GPIO_6_7 = 3
 };
 
 struct dibx000_i2c_master {
@@ -17,8 +18,11 @@ struct dibx000_i2c_master {
 
        enum dibx000_i2c_interface selected_interface;
 
-//      struct i2c_adapter  tuner_i2c_adap;
+/*     struct i2c_adapter  tuner_i2c_adap; */
        struct i2c_adapter gated_tuner_i2c_adap;
+       struct i2c_adapter master_i2c_adap_gpio12;
+       struct i2c_adapter master_i2c_adap_gpio34;
+       struct i2c_adapter master_i2c_adap_gpio67;
 
        struct i2c_adapter *i2c_adap;
        u8 i2c_addr;
@@ -27,14 +31,15 @@ struct dibx000_i2c_master {
 };
 
 extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
-                                  u16 device_rev, struct i2c_adapter *i2c_adap,
-                                  u8 i2c_addr);
+                                       u16 device_rev, struct i2c_adapter *i2c_adap,
+                                       u8 i2c_addr);
 extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
-                                                  *mst,
-                                                  enum dibx000_i2c_interface
-                                                  intf, int gating);
+                                                       *mst,
+                                                       enum dibx000_i2c_interface
+                                                       intf, int gating);
 extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
 extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
+extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed);
 
 extern u32 systime(void);
 
@@ -42,7 +47,7 @@ extern u32 systime(void);
 #define BAND_UHF   0x02
 #define BAND_VHF   0x04
 #define BAND_SBAND 0x08
-#define BAND_FM    0x10
+#define BAND_FM           0x10
 #define BAND_CBAND 0x20
 
 #define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \
@@ -135,9 +140,9 @@ enum dibx000_adc_states {
        DIBX000_VBG_DISABLE,
 };
 
-#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
-                            (v) == BANDWIDTH_7_MHZ  ? 7000 : \
-                            (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
+#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ  ? 8000 : \
+                               (v) == BANDWIDTH_7_MHZ  ? 7000 : \
+                               (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000)
 
 #define BANDWIDTH_TO_INDEX(v) ( \
        (v) == 8000 ? BANDWIDTH_8_MHZ : \
@@ -153,53 +158,57 @@ enum dibx000_adc_states {
 #define OUTMODE_MPEG2_FIFO          5
 #define OUTMODE_ANALOG_ADC          6
 
+#define INPUT_MODE_OFF                0x11
+#define INPUT_MODE_DIVERSITY          0x12
+#define INPUT_MODE_MPEG               0x13
+
 enum frontend_tune_state {
-    CT_TUNER_START = 10,
-    CT_TUNER_STEP_0,
-    CT_TUNER_STEP_1,
-    CT_TUNER_STEP_2,
-    CT_TUNER_STEP_3,
-    CT_TUNER_STEP_4,
-    CT_TUNER_STEP_5,
-    CT_TUNER_STEP_6,
-    CT_TUNER_STEP_7,
-    CT_TUNER_STOP,
-
-    CT_AGC_START = 20,
-    CT_AGC_STEP_0,
-    CT_AGC_STEP_1,
-    CT_AGC_STEP_2,
-    CT_AGC_STEP_3,
-    CT_AGC_STEP_4,
-    CT_AGC_STOP,
+       CT_TUNER_START = 10,
+       CT_TUNER_STEP_0,
+       CT_TUNER_STEP_1,
+       CT_TUNER_STEP_2,
+       CT_TUNER_STEP_3,
+       CT_TUNER_STEP_4,
+       CT_TUNER_STEP_5,
+       CT_TUNER_STEP_6,
+       CT_TUNER_STEP_7,
+       CT_TUNER_STOP,
+
+       CT_AGC_START = 20,
+       CT_AGC_STEP_0,
+       CT_AGC_STEP_1,
+       CT_AGC_STEP_2,
+       CT_AGC_STEP_3,
+       CT_AGC_STEP_4,
+       CT_AGC_STOP,
 
        CT_DEMOD_START = 30,
-    CT_DEMOD_STEP_1,
-    CT_DEMOD_STEP_2,
-    CT_DEMOD_STEP_3,
-    CT_DEMOD_STEP_4,
-    CT_DEMOD_STEP_5,
-    CT_DEMOD_STEP_6,
-    CT_DEMOD_STEP_7,
-    CT_DEMOD_STEP_8,
-    CT_DEMOD_STEP_9,
-    CT_DEMOD_STEP_10,
-    CT_DEMOD_SEARCH_NEXT = 41,
-    CT_DEMOD_STEP_LOCKED,
-    CT_DEMOD_STOP,
-
-    CT_DONE = 100,
-    CT_SHUTDOWN,
+       CT_DEMOD_STEP_1,
+       CT_DEMOD_STEP_2,
+       CT_DEMOD_STEP_3,
+       CT_DEMOD_STEP_4,
+       CT_DEMOD_STEP_5,
+       CT_DEMOD_STEP_6,
+       CT_DEMOD_STEP_7,
+       CT_DEMOD_STEP_8,
+       CT_DEMOD_STEP_9,
+       CT_DEMOD_STEP_10,
+       CT_DEMOD_SEARCH_NEXT = 41,
+       CT_DEMOD_STEP_LOCKED,
+       CT_DEMOD_STOP,
+
+       CT_DONE = 100,
+       CT_SHUTDOWN,
 
 };
 
 struct dvb_frontend_parametersContext {
 #define CHANNEL_STATUS_PARAMETERS_UNKNOWN   0x01
 #define CHANNEL_STATUS_PARAMETERS_SET       0x02
-    u8 status;
-    u32 tune_time_estimation[2];
-    s32 tps_available;
-    u16 tps[9];
+       u8 status;
+       u32 tune_time_estimation[2];
+       s32 tps_available;
+       u16 tps[9];
 };
 
 #define FE_STATUS_TUNE_FAILED          0
@@ -216,4 +225,49 @@ struct dvb_frontend_parametersContext {
 
 #define ABS(x) ((x < 0) ? (-x) : (x))
 
+#define DATA_BUS_ACCESS_MODE_8BIT                 0x01
+#define DATA_BUS_ACCESS_MODE_16BIT                0x02
+#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10
+
+struct dibGPIOFunction {
+#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1
+#define BOARD_GPIO_COMPONENT_DEMOD       2
+       u8 component;
+
+#define BOARD_GPIO_FUNCTION_BOARD_ON      1
+#define BOARD_GPIO_FUNCTION_BOARD_OFF     2
+#define BOARD_GPIO_FUNCTION_COMPONENT_ON  3
+#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4
+#define BOARD_GPIO_FUNCTION_SUBBAND_PWM   5
+#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO   6
+       u8 function;
+
+/* mask, direction and value are used specify which GPIO to change GPIO0
+ * is LSB and possible GPIO31 is MSB.  The same bit-position as in the
+ * mask is used for the direction and the value. Direction == 1 is OUT,
+ * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN
+ * value has no meaning.
+ *
+ * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be
+ * used to do the PWM. Direction gives the PWModulator to be used.
+ * Value gives the PWM value in device-dependent scale.
+ */
+       u32 mask;
+       u32 direction;
+       u32 value;
+};
+
+#define MAX_NB_SUBBANDS   8
+struct dibSubbandSelection {
+       u8  size; /* Actual number of subbands. */
+       struct {
+               u16 f_mhz;
+               struct dibGPIOFunction gpio;
+       } subband[MAX_NB_SUBBANDS];
+};
+
+#define DEMOD_TIMF_SET    0x00
+#define DEMOD_TIMF_GET    0x01
+#define DEMOD_TIMF_UPDATE 0x02
+
 #endif
index fc61d9230db8bd1d0eb9541e8698da647f0a5367..90bf573308b0eb51c7507d99206e01ac9af4747a 100644 (file)
@@ -229,31 +229,11 @@ static u8 ds3000_dvbs2_init_tab[] = {
        0xb8, 0x00,
 };
 
-/* DS3000 doesn't need some parameters as input and auto-detects them */
-/* save input from the application of those parameters */
-struct ds3000_tuning {
-       u32 frequency;
-       u32 symbol_rate;
-       fe_spectral_inversion_t inversion;
-       enum fe_code_rate fec;
-
-       /* input values */
-       u8 inversion_val;
-       fe_modulation_t delivery;
-       u8 rolloff;
-};
-
 struct ds3000_state {
        struct i2c_adapter *i2c;
        const struct ds3000_config *config;
-
        struct dvb_frontend frontend;
-
-       struct ds3000_tuning dcur;
-       struct ds3000_tuning dnxt;
-
        u8 skip_fw_load;
-
        /* previous uncorrected block counter for DVB-S2 */
        u16 prevUCBS2;
 };
@@ -305,7 +285,7 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
        struct i2c_msg msg;
        u8 *buf;
 
-       buf = kmalloc(3, GFP_KERNEL);
+       buf = kmalloc(33, GFP_KERNEL);
        if (buf == NULL) {
                printk(KERN_ERR "Unable to kmalloc\n");
                ret = -ENOMEM;
@@ -317,10 +297,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
        msg.addr = state->config->demod_address;
        msg.flags = 0;
        msg.buf = buf;
-       msg.len = 3;
+       msg.len = 33;
 
-       for (i = 0; i < len; i += 2) {
-               memcpy(buf + 1, data + i, 2);
+       for (i = 0; i < len; i += 32) {
+               memcpy(buf + 1, data + i, 32);
 
                dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len);
 
@@ -401,45 +381,6 @@ static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg)
        return b1[0];
 }
 
-static int ds3000_set_inversion(struct ds3000_state *state,
-                                       fe_spectral_inversion_t inversion)
-{
-       dprintk("%s(%d)\n", __func__, inversion);
-
-       switch (inversion) {
-       case INVERSION_OFF:
-       case INVERSION_ON:
-       case INVERSION_AUTO:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       state->dnxt.inversion = inversion;
-
-       return 0;
-}
-
-static int ds3000_set_symbolrate(struct ds3000_state *state, u32 rate)
-{
-       int ret = 0;
-
-       dprintk("%s()\n", __func__);
-
-       dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate);
-
-       /*  check if symbol rate is within limits */
-       if ((state->dnxt.symbol_rate >
-                               state->frontend.ops.info.symbol_rate_max) ||
-           (state->dnxt.symbol_rate <
-                               state->frontend.ops.info.symbol_rate_min))
-               ret = -EOPNOTSUPP;
-
-       state->dnxt.symbol_rate = rate;
-
-       return ret;
-}
-
 static int ds3000_load_firmware(struct dvb_frontend *fe,
                                        const struct firmware *fw);
 
@@ -509,23 +450,31 @@ static int ds3000_load_firmware(struct dvb_frontend *fe,
        return 0;
 }
 
-static void ds3000_dump_registers(struct dvb_frontend *fe)
+static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct ds3000_state *state = fe->demodulator_priv;
-       int x, y, reg = 0, val;
-
-       for (y = 0; y < 16; y++) {
-               dprintk("%s: %02x: ", __func__, y);
-               for (x = 0; x < 16; x++) {
-                       reg = (y << 4) + x;
-                       val = ds3000_readreg(state, reg);
-                       if (x != 15)
-                               dprintk("%02x ",  val);
-                       else
-                               dprintk("%02x\n", val);
-               }
+       u8 data;
+
+       dprintk("%s(%d)\n", __func__, voltage);
+
+       data = ds3000_readreg(state, 0xa2);
+       data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+       switch (voltage) {
+       case SEC_VOLTAGE_18:
+               data &= ~0x03;
+               break;
+       case SEC_VOLTAGE_13:
+               data &= ~0x03;
+               data |= 0x01;
+               break;
+       case SEC_VOLTAGE_OFF:
+               break;
        }
-       dprintk("%s: -- DS3000 DUMP DONE --\n", __func__);
+
+       ds3000_writereg(state, 0xa2, data);
+
+       return 0;
 }
 
 static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
@@ -562,16 +511,6 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status)
        return 0;
 }
 
-#define FE_IS_TUNED (FE_HAS_SIGNAL + FE_HAS_LOCK)
-static int ds3000_is_tuned(struct dvb_frontend *fe)
-{
-       fe_status_t tunerstat;
-
-       ds3000_read_status(fe, &tunerstat);
-
-       return ((tunerstat & FE_IS_TUNED) == FE_IS_TUNED);
-}
-
 /* read DS3000 BER value */
 static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
 {
@@ -792,13 +731,6 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
-/* Overwrite the current tuning params, we are about to tune */
-static void ds3000_clone_params(struct dvb_frontend *fe)
-{
-       struct ds3000_state *state = fe->demodulator_priv;
-       memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
-}
-
 static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
        struct ds3000_state *state = fe->demodulator_priv;
@@ -1016,287 +948,298 @@ static int ds3000_get_property(struct dvb_frontend *fe,
        return 0;
 }
 
-static int ds3000_tune(struct dvb_frontend *fe,
+static int ds3000_set_carrier_offset(struct dvb_frontend *fe,
+                                       s32 carrier_offset_khz)
+{
+       struct ds3000_state *state = fe->demodulator_priv;
+       s32 tmp;
+
+       tmp = carrier_offset_khz;
+       tmp *= 65536;
+       tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE);
+
+       if (tmp < 0)
+               tmp += 65536;
+
+       ds3000_writereg(state, 0x5f, tmp >> 8);
+       ds3000_writereg(state, 0x5e, tmp & 0xff);
+
+       return 0;
+}
+
+static int ds3000_set_frontend(struct dvb_frontend *fe,
                                struct dvb_frontend_parameters *p)
 {
        struct ds3000_state *state = fe->demodulator_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       int ret = 0, retune, i;
-       u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf;
+       int i;
+       fe_status_t status;
+       u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4;
+       s32 offset_khz;
        u16 value, ndiv;
        u32 f3db;
 
        dprintk("%s() ", __func__);
 
-       /* Load the firmware if required */
-       ret = ds3000_firmware_ondemand(fe);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: Unable initialise the firmware\n",
-                                                               __func__);
-               return ret;
+       if (state->config->set_ts_params)
+               state->config->set_ts_params(fe, 0);
+       /* Tune */
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x07, 0x02);
+       ds3000_tuner_writereg(state, 0x10, 0x00);
+       ds3000_tuner_writereg(state, 0x60, 0x79);
+       ds3000_tuner_writereg(state, 0x08, 0x01);
+       ds3000_tuner_writereg(state, 0x00, 0x01);
+       div4 = 0;
+
+       /* calculate and set freq divider */
+       if (p->frequency < 1146000) {
+               ds3000_tuner_writereg(state, 0x10, 0x11);
+               div4 = 1;
+               ndiv = ((p->frequency * (6 + 8) * 4) +
+                               (DS3000_XTAL_FREQ / 2)) /
+                               DS3000_XTAL_FREQ - 1024;
+       } else {
+               ds3000_tuner_writereg(state, 0x10, 0x01);
+               ndiv = ((p->frequency * (6 + 8) * 2) +
+                               (DS3000_XTAL_FREQ / 2)) /
+                               DS3000_XTAL_FREQ - 1024;
        }
 
-       state->dnxt.delivery = c->modulation;
-       state->dnxt.frequency = c->frequency;
-       state->dnxt.rolloff = 2; /* fixme */
-       state->dnxt.fec = c->fec_inner;
+       ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
+       ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
+
+       /* set pll */
+       ds3000_tuner_writereg(state, 0x03, 0x06);
+       ds3000_tuner_writereg(state, 0x51, 0x0f);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x10);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x51, 0x17);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x08);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       value = ds3000_tuner_readreg(state, 0x3d);
+       value &= 0x0f;
+       if ((value > 4) && (value < 15)) {
+               value -= 3;
+               if (value < 4)
+                       value = 4;
+               value = ((value << 3) | 0x01) & 0x79;
+       }
 
-       ret = ds3000_set_inversion(state, p->inversion);
-       if (ret !=  0)
-               return ret;
+       ds3000_tuner_writereg(state, 0x60, value);
+       ds3000_tuner_writereg(state, 0x51, 0x17);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x08);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+
+       /* set low-pass filter period */
+       ds3000_tuner_writereg(state, 0x04, 0x2e);
+       ds3000_tuner_writereg(state, 0x51, 0x1b);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x04);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000;
+       if ((c->symbol_rate / 1000) < 5000)
+               f3db += 3000;
+       if (f3db < 7000)
+               f3db = 7000;
+       if (f3db > 40000)
+               f3db = 40000;
+
+       /* set low-pass filter baseband */
+       value = ds3000_tuner_readreg(state, 0x26);
+       mlpf = 0x2e * 207 / ((value << 1) + 151);
+       mlpf_max = mlpf * 135 / 100;
+       mlpf_min = mlpf * 78 / 100;
+       if (mlpf_max > 63)
+               mlpf_max = 63;
+
+       /* rounded to the closest integer */
+       nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
+                       / (2766 * DS3000_XTAL_FREQ);
+       if (nlpf > 23)
+               nlpf = 23;
+       if (nlpf < 1)
+               nlpf = 1;
+
+       /* rounded to the closest integer */
+       mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+                       (1000 * f3db / 2)) / (1000 * f3db);
+
+       if (mlpf_new < mlpf_min) {
+               nlpf++;
+               mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
+                               (1000 * f3db / 2)) / (1000 * f3db);
+       }
 
-       ret = ds3000_set_symbolrate(state, c->symbol_rate);
-       if (ret !=  0)
-               return ret;
+       if (mlpf_new > mlpf_max)
+               mlpf_new = mlpf_max;
+
+       ds3000_tuner_writereg(state, 0x04, mlpf_new);
+       ds3000_tuner_writereg(state, 0x06, nlpf);
+       ds3000_tuner_writereg(state, 0x51, 0x1b);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x04);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(5);
+
+       /* unknown */
+       ds3000_tuner_writereg(state, 0x51, 0x1e);
+       ds3000_tuner_writereg(state, 0x51, 0x1f);
+       ds3000_tuner_writereg(state, 0x50, 0x01);
+       ds3000_tuner_writereg(state, 0x50, 0x00);
+       msleep(60);
+
+       offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ
+               / (6 + 8) / (div4 + 1) / 2 - p->frequency;
+
+       /* ds3000 global reset */
+       ds3000_writereg(state, 0x07, 0x80);
+       ds3000_writereg(state, 0x07, 0x00);
+       /* ds3000 build-in uC reset */
+       ds3000_writereg(state, 0xb2, 0x01);
+       /* ds3000 software reset */
+       ds3000_writereg(state, 0x00, 0x01);
 
-       /* discard the 'current' tuning parameters and prepare to tune */
-       ds3000_clone_params(fe);
-
-       retune = 1;     /* try 1 times */
-       dprintk("%s:   retune = %d\n", __func__, retune);
-       dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
-       dprintk("%s:   symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
-       dprintk("%s:   FEC       = %d \n", __func__,
-               state->dcur.fec);
-       dprintk("%s:   Inversion   = %d\n", __func__, state->dcur.inversion);
-
-       do {
-               /* Reset status register */
-               status = 0;
-               /* Tune */
-               /* TS2020 init */
-               ds3000_tuner_writereg(state, 0x42, 0x73);
-               ds3000_tuner_writereg(state, 0x05, 0x01);
-               ds3000_tuner_writereg(state, 0x62, 0xf5);
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x07, 0x02);
-               ds3000_tuner_writereg(state, 0x10, 0x00);
-               ds3000_tuner_writereg(state, 0x60, 0x79);
-               ds3000_tuner_writereg(state, 0x08, 0x01);
-               ds3000_tuner_writereg(state, 0x00, 0x01);
-               /* calculate and set freq divider */
-               if (state->dcur.frequency < 1146000) {
-                       ds3000_tuner_writereg(state, 0x10, 0x11);
-                       ndiv = ((state->dcur.frequency * (6 + 8) * 4) +
-                                       (DS3000_XTAL_FREQ / 2)) /
-                                       DS3000_XTAL_FREQ - 1024;
-               } else {
-                       ds3000_tuner_writereg(state, 0x10, 0x01);
-                       ndiv = ((state->dcur.frequency * (6 + 8) * 2) +
-                                       (DS3000_XTAL_FREQ / 2)) /
-                                       DS3000_XTAL_FREQ - 1024;
-               }
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               /* initialise the demod in DVB-S mode */
+               for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
+                       ds3000_writereg(state,
+                               ds3000_dvbs_init_tab[i],
+                               ds3000_dvbs_init_tab[i + 1]);
+               value = ds3000_readreg(state, 0xfe);
+               value &= 0xc0;
+               value |= 0x1b;
+               ds3000_writereg(state, 0xfe, value);
+               break;
+       case SYS_DVBS2:
+               /* initialise the demod in DVB-S2 mode */
+               for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
+                       ds3000_writereg(state,
+                               ds3000_dvbs2_init_tab[i],
+                               ds3000_dvbs2_init_tab[i + 1]);
+               ds3000_writereg(state, 0xfe, 0x98);
+               break;
+       default:
+               return 1;
+       }
 
-               ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8);
-               ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff);
-
-               /* set pll */
-               ds3000_tuner_writereg(state, 0x03, 0x06);
-               ds3000_tuner_writereg(state, 0x51, 0x0f);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x10);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x51, 0x17);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x08);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               value = ds3000_tuner_readreg(state, 0x3d);
-               value &= 0x0f;
-               if ((value > 4) && (value < 15)) {
-                       value -= 3;
-                       if (value < 4)
-                               value = 4;
-                       value = ((value << 3) | 0x01) & 0x79;
-               }
+       /* enable 27MHz clock output */
+       ds3000_writereg(state, 0x29, 0x80);
+       /* enable ac coupling */
+       ds3000_writereg(state, 0x25, 0x8a);
+
+       /* enhance symbol rate performance */
+       if ((c->symbol_rate / 1000) <= 5000) {
+               value = 29777 / (c->symbol_rate / 1000) + 1;
+               if (value % 2 != 0)
+                       value++;
+               ds3000_writereg(state, 0xc3, 0x0d);
+               ds3000_writereg(state, 0xc8, value);
+               ds3000_writereg(state, 0xc4, 0x10);
+               ds3000_writereg(state, 0xc7, 0x0e);
+       } else if ((c->symbol_rate / 1000) <= 10000) {
+               value = 92166 / (c->symbol_rate / 1000) + 1;
+               if (value % 2 != 0)
+                       value++;
+               ds3000_writereg(state, 0xc3, 0x07);
+               ds3000_writereg(state, 0xc8, value);
+               ds3000_writereg(state, 0xc4, 0x09);
+               ds3000_writereg(state, 0xc7, 0x12);
+       } else if ((c->symbol_rate / 1000) <= 20000) {
+               value = 64516 / (c->symbol_rate / 1000) + 1;
+               ds3000_writereg(state, 0xc3, value);
+               ds3000_writereg(state, 0xc8, 0x0e);
+               ds3000_writereg(state, 0xc4, 0x07);
+               ds3000_writereg(state, 0xc7, 0x18);
+       } else {
+               value = 129032 / (c->symbol_rate / 1000) + 1;
+               ds3000_writereg(state, 0xc3, value);
+               ds3000_writereg(state, 0xc8, 0x0a);
+               ds3000_writereg(state, 0xc4, 0x05);
+               ds3000_writereg(state, 0xc7, 0x24);
+       }
 
-               ds3000_tuner_writereg(state, 0x60, value);
-               ds3000_tuner_writereg(state, 0x51, 0x17);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x08);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-
-               /* set low-pass filter period */
-               ds3000_tuner_writereg(state, 0x04, 0x2e);
-               ds3000_tuner_writereg(state, 0x51, 0x1b);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x04);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000;
-               if ((state->dcur.symbol_rate / 1000) < 5000)
-                       f3db += 3000;
-               if (f3db < 7000)
-                       f3db = 7000;
-               if (f3db > 40000)
-                       f3db = 40000;
-
-               /* set low-pass filter baseband */
-               value = ds3000_tuner_readreg(state, 0x26);
-               mlpf = 0x2e * 207 / ((value << 1) + 151);
-               mlpf_max = mlpf * 135 / 100;
-               mlpf_min = mlpf * 78 / 100;
-               if (mlpf_max > 63)
-                       mlpf_max = 63;
-
-               /* rounded to the closest integer */
-               nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2))
-                               / (2766 * DS3000_XTAL_FREQ);
-               if (nlpf > 23)
-                       nlpf = 23;
-               if (nlpf < 1)
-                       nlpf = 1;
-
-               /* rounded to the closest integer */
-               mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-                               (1000 * f3db / 2)) / (1000 * f3db);
+       /* normalized symbol rate rounded to the closest integer */
+       value = (((c->symbol_rate / 1000) << 16) +
+                       (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
+       ds3000_writereg(state, 0x61, value & 0x00ff);
+       ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
 
-               if (mlpf_new < mlpf_min) {
-                       nlpf++;
-                       mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) +
-                                       (1000 * f3db / 2)) / (1000 * f3db);
-               }
+       /* co-channel interference cancellation disabled */
+       ds3000_writereg(state, 0x56, 0x00);
+
+       /* equalizer disabled */
+       ds3000_writereg(state, 0x76, 0x00);
 
-               if (mlpf_new > mlpf_max)
-                       mlpf_new = mlpf_max;
-
-               ds3000_tuner_writereg(state, 0x04, mlpf_new);
-               ds3000_tuner_writereg(state, 0x06, nlpf);
-               ds3000_tuner_writereg(state, 0x51, 0x1b);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x04);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(5);
-
-               /* unknown */
-               ds3000_tuner_writereg(state, 0x51, 0x1e);
-               ds3000_tuner_writereg(state, 0x51, 0x1f);
-               ds3000_tuner_writereg(state, 0x50, 0x01);
-               ds3000_tuner_writereg(state, 0x50, 0x00);
-               msleep(60);
-
-               /* ds3000 global reset */
-               ds3000_writereg(state, 0x07, 0x80);
-               ds3000_writereg(state, 0x07, 0x00);
-               /* ds3000 build-in uC reset */
-               ds3000_writereg(state, 0xb2, 0x01);
-               /* ds3000 software reset */
-               ds3000_writereg(state, 0x00, 0x01);
+       /*ds3000_writereg(state, 0x08, 0x03);
+       ds3000_writereg(state, 0xfd, 0x22);
+       ds3000_writereg(state, 0x08, 0x07);
+       ds3000_writereg(state, 0xfd, 0x42);
+       ds3000_writereg(state, 0x08, 0x07);*/
 
+       if (state->config->ci_mode) {
                switch (c->delivery_system) {
                case SYS_DVBS:
-                       /* initialise the demod in DVB-S mode */
-                       for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2)
-                               ds3000_writereg(state,
-                                       ds3000_dvbs_init_tab[i],
-                                       ds3000_dvbs_init_tab[i + 1]);
-                       value = ds3000_readreg(state, 0xfe);
-                       value &= 0xc0;
-                       value |= 0x1b;
-                       ds3000_writereg(state, 0xfe, value);
-                       break;
+               default:
+                       ds3000_writereg(state, 0xfd, 0x80);
+               break;
                case SYS_DVBS2:
-                       /* initialise the demod in DVB-S2 mode */
-                       for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2)
-                               ds3000_writereg(state,
-                                       ds3000_dvbs2_init_tab[i],
-                                       ds3000_dvbs2_init_tab[i + 1]);
-                       ds3000_writereg(state, 0xfe, 0x54);
+                       ds3000_writereg(state, 0xfd, 0x01);
                        break;
-               default:
-                       return 1;
                }
+       }
 
-               /* enable 27MHz clock output */
-               ds3000_writereg(state, 0x29, 0x80);
-               /* enable ac coupling */
-               ds3000_writereg(state, 0x25, 0x8a);
-
-               /* enhance symbol rate performance */
-               if ((state->dcur.symbol_rate / 1000) <= 5000) {
-                       value = 29777 / (state->dcur.symbol_rate / 1000) + 1;
-                       if (value % 2 != 0)
-                               value++;
-                       ds3000_writereg(state, 0xc3, 0x0d);
-                       ds3000_writereg(state, 0xc8, value);
-                       ds3000_writereg(state, 0xc4, 0x10);
-                       ds3000_writereg(state, 0xc7, 0x0e);
-               } else if ((state->dcur.symbol_rate / 1000) <= 10000) {
-                       value = 92166 / (state->dcur.symbol_rate / 1000) + 1;
-                       if (value % 2 != 0)
-                               value++;
-                       ds3000_writereg(state, 0xc3, 0x07);
-                       ds3000_writereg(state, 0xc8, value);
-                       ds3000_writereg(state, 0xc4, 0x09);
-                       ds3000_writereg(state, 0xc7, 0x12);
-               } else if ((state->dcur.symbol_rate / 1000) <= 20000) {
-                       value = 64516 / (state->dcur.symbol_rate / 1000) + 1;
-                       ds3000_writereg(state, 0xc3, value);
-                       ds3000_writereg(state, 0xc8, 0x0e);
-                       ds3000_writereg(state, 0xc4, 0x07);
-                       ds3000_writereg(state, 0xc7, 0x18);
-               } else {
-                       value = 129032 / (state->dcur.symbol_rate / 1000) + 1;
-                       ds3000_writereg(state, 0xc3, value);
-                       ds3000_writereg(state, 0xc8, 0x0a);
-                       ds3000_writereg(state, 0xc4, 0x05);
-                       ds3000_writereg(state, 0xc7, 0x24);
-               }
+       /* ds3000 out of software reset */
+       ds3000_writereg(state, 0x00, 0x00);
+       /* start ds3000 build-in uC */
+       ds3000_writereg(state, 0xb2, 0x00);
 
-               /* normalized symbol rate rounded to the closest integer */
-               value = (((state->dcur.symbol_rate / 1000) << 16) +
-                               (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE;
-               ds3000_writereg(state, 0x61, value & 0x00ff);
-               ds3000_writereg(state, 0x62, (value & 0xff00) >> 8);
-
-               /* co-channel interference cancellation disabled */
-               ds3000_writereg(state, 0x56, 0x00);
-
-               /* equalizer disabled */
-               ds3000_writereg(state, 0x76, 0x00);
-
-               /*ds3000_writereg(state, 0x08, 0x03);
-               ds3000_writereg(state, 0xfd, 0x22);
-               ds3000_writereg(state, 0x08, 0x07);
-               ds3000_writereg(state, 0xfd, 0x42);
-               ds3000_writereg(state, 0x08, 0x07);*/
-
-               /* ds3000 out of software reset */
-               ds3000_writereg(state, 0x00, 0x00);
-               /* start ds3000 build-in uC */
-               ds3000_writereg(state, 0xb2, 0x00);
-
-               /* TODO: calculate and set carrier offset */
-
-               /* wait before retrying */
-               for (i = 0; i < 30 ; i++) {
-                       if (ds3000_is_tuned(fe)) {
-                               dprintk("%s: Tuned\n", __func__);
-                               ds3000_dump_registers(fe);
-                               goto tuned;
-                       }
-                       msleep(1);
-               }
+       ds3000_set_carrier_offset(fe, offset_khz);
 
-               dprintk("%s: Not tuned\n", __func__);
-               ds3000_dump_registers(fe);
+       for (i = 0; i < 30 ; i++) {
+               ds3000_read_status(fe, &status);
+               if (status && FE_HAS_LOCK)
+                       break;
 
-       } while (--retune);
+               msleep(10);
+       }
 
-tuned:
-       return ret;
+       return 0;
+}
+
+static int ds3000_tune(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *p,
+                       unsigned int mode_flags,
+                       unsigned int *delay,
+                       fe_status_t *status)
+{
+       if (p) {
+               int ret = ds3000_set_frontend(fe, p);
+               if (ret)
+                       return ret;
+       }
+
+       *delay = HZ / 5;
+
+       return ds3000_read_status(fe, status);
 }
 
 static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
 {
        dprintk("%s()\n", __func__);
-       return DVBFE_ALGO_SW;
+       return DVBFE_ALGO_HW;
 }
 
 /*
@@ -1306,7 +1249,25 @@ static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe)
  */
 static int ds3000_initfe(struct dvb_frontend *fe)
 {
+       struct ds3000_state *state = fe->demodulator_priv;
+       int ret;
+
        dprintk("%s()\n", __func__);
+       /* hard reset */
+       ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08));
+       msleep(1);
+
+       /* TS2020 init */
+       ds3000_tuner_writereg(state, 0x42, 0x73);
+       ds3000_tuner_writereg(state, 0x05, 0x01);
+       ds3000_tuner_writereg(state, 0x62, 0xf5);
+       /* Load the firmware if required */
+       ret = ds3000_firmware_ondemand(fe);
+       if (ret != 0) {
+               printk(KERN_ERR "%s: Unable initialize firmware\n", __func__);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1345,6 +1306,7 @@ static struct dvb_frontend_ops ds3000_ops = {
        .read_signal_strength = ds3000_read_signal_strength,
        .read_snr = ds3000_read_snr,
        .read_ucblocks = ds3000_read_ucblocks,
+       .set_voltage = ds3000_set_voltage,
        .set_tone = ds3000_set_tone,
        .diseqc_send_master_cmd = ds3000_send_diseqc_msg,
        .diseqc_send_burst = ds3000_diseqc_send_burst,
@@ -1352,7 +1314,8 @@ static struct dvb_frontend_ops ds3000_ops = {
 
        .set_property = ds3000_set_property,
        .get_property = ds3000_get_property,
-       .set_frontend = ds3000_tune,
+       .set_frontend = ds3000_set_frontend,
+       .tune = ds3000_tune,
 };
 
 module_param(debug, int, 0644);
index 67f67038740a5e142f4b7ed298baa612e7800074..1b736888ea374cd6e3ccb78a3581b1d4bab0fae8 100644 (file)
@@ -27,6 +27,9 @@
 struct ds3000_config {
        /* the demodulator's i2c address */
        u8 demod_address;
+       u8 ci_mode;
+       /* Set device param to start dma */
+       int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
 
 #if defined(CONFIG_DVB_DS3000) || \
index 4d4d0bb5920ac1821dfcc2d2a28de3b016a9573a..62a65efdf8d6133817beb5b8dbbaf0f2e47d12e2 100644 (file)
@@ -64,6 +64,7 @@ struct dvb_pll_desc {
        void (*set)(struct dvb_frontend *fe, u8 *buf,
                    const struct dvb_frontend_parameters *params);
        u8   *initdata;
+       u8   *initdata2;
        u8   *sleepdata;
        int  count;
        struct {
@@ -321,26 +322,73 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
 static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
                      const struct dvb_frontend_parameters *params)
 {
-       if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
-               buf[2] |= 0x08;
+       struct dvb_pll_priv *priv = fe->tuner_priv;
+       u32 b_w  = (params->u.qpsk.symbol_rate * 27) / 32000;
+       struct i2c_msg msg = {
+               .addr = priv->pll_i2c_address,
+               .flags = 0,
+               .buf = buf,
+               .len = 4
+       };
+       int result;
+       u8 lpf;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+
+       result = i2c_transfer(priv->i2c, &msg, 1);
+       if (result != 1)
+               printk(KERN_ERR "%s: i2c_transfer failed:%d",
+                       __func__, result);
+
+       if (b_w <= 10000)
+               lpf = 0xc;
+       else if (b_w <= 12000)
+               lpf = 0x2;
+       else if (b_w <= 14000)
+               lpf = 0xa;
+       else if (b_w <= 16000)
+               lpf = 0x6;
+       else if (b_w <= 18000)
+               lpf = 0xe;
+       else if (b_w <= 20000)
+               lpf = 0x1;
+       else if (b_w <= 22000)
+               lpf = 0x9;
+       else if (b_w <= 24000)
+               lpf = 0x5;
+       else if (b_w <= 26000)
+               lpf = 0xd;
+       else if (b_w <= 28000)
+               lpf = 0x3;
+               else
+               lpf = 0xb;
+       buf[2] ^= 0x1c; /* Flip bits 3-5 */
+       /* Set lpf */
+       buf[2] |= ((lpf >> 2) & 0x3) << 3;
+       buf[3] |= (lpf & 0x3) << 2;
+
+       return;
 }
 
 static struct dvb_pll_desc dvb_pll_opera1 = {
        .name  = "Opera Tuner",
        .min   =  900000,
        .max   = 2250000,
+       .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 },
+       .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 },
        .iffreq= 0,
        .set   = opera1_bw,
        .count = 8,
        .entries = {
-               { 1064000, 500, 0xe5, 0xc6 },
-               { 1169000, 500, 0xe5, 0xe6 },
-               { 1299000, 500, 0xe5, 0x24 },
-               { 1444000, 500, 0xe5, 0x44 },
-               { 1606000, 500, 0xe5, 0x64 },
-               { 1777000, 500, 0xe5, 0x84 },
-               { 1941000, 500, 0xe5, 0xa4 },
-               { 2250000, 500, 0xe5, 0xc4 },
+               { 1064000, 500, 0xf9, 0xc2 },
+               { 1169000, 500, 0xf9, 0xe2 },
+               { 1299000, 500, 0xf9, 0x20 },
+               { 1444000, 500, 0xf9, 0x40 },
+               { 1606000, 500, 0xf9, 0x60 },
+               { 1777000, 500, 0xf9, 0x80 },
+               { 1941000, 500, 0xf9, 0xa0 },
+               { 2250000, 500, 0xf9, 0xc0 },
        }
 };
 
@@ -648,8 +696,17 @@ static int dvb_pll_init(struct dvb_frontend *fe)
                int result;
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+               result = i2c_transfer(priv->i2c, &msg, 1);
+               if (result != 1)
                        return result;
+               if (priv->pll_desc->initdata2) {
+                       msg.buf = priv->pll_desc->initdata2 + 1;
+                       msg.len = priv->pll_desc->initdata2[0];
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 1);
+                       result = i2c_transfer(priv->i2c, &msg, 1);
+                       if (result != 1)
+                               return result;
                }
                return 0;
        }
index 63db8fd2754cfdda42347abc419fe1e1d8238204..e3fe17fd96fb361744fa4b9824dd16259b031e63 100644 (file)
@@ -367,8 +367,11 @@ static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status)
        dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync);
 
        *status = 0;
-
-       if ((sync & 0x08) == 0x08) {
+       if (sync & 0x80)
+               *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+       if (sync & 0x10)
+               *status |= FE_HAS_VITERBI;
+       if (sync & 0x08) {
                *status |= FE_HAS_LOCK;
                dprintk("stv0288 has locked\n");
        }
diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c
new file mode 100644 (file)
index 0000000..4e0e6a8
--- /dev/null
@@ -0,0 +1,3459 @@
+/*
+ * stv0367.c
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+
+#include "stv0367.h"
+#include "stv0367_regs.h"
+#include "stv0367_priv.h"
+
+static int stvdebug;
+module_param_named(debug, stvdebug, int, 0644);
+
+static int i2cdebug;
+module_param_named(i2c_debug, i2cdebug, int, 0644);
+
+#define dprintk(args...) \
+       do { \
+               if (stvdebug) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+       /* DVB-C */
+
+struct stv0367cab_state {
+       enum stv0367_cab_signal_type    state;
+       u32     mclk;
+       u32     adc_clk;
+       s32     search_range;
+       s32     derot_offset;
+       /* results */
+       int locked;                     /* channel found                */
+       u32 freq_khz;                   /* found frequency (in kHz)     */
+       u32 symbol_rate;                /* found symbol rate (in Bds)   */
+       enum stv0367cab_mod modulation; /* modulation                   */
+       fe_spectral_inversion_t spect_inv; /* Spectrum Inversion        */
+};
+
+struct stv0367ter_state {
+       /* DVB-T */
+       enum stv0367_ter_signal_type state;
+       enum stv0367_ter_if_iq_mode if_iq_mode;
+       enum stv0367_ter_mode mode;/* mode 2K or 8K */
+       fe_guard_interval_t guard;
+       enum stv0367_ter_hierarchy hierarchy;
+       u32 frequency;
+       fe_spectral_inversion_t  sense; /*  current search spectrum */
+       u8  force; /* force mode/guard */
+       u8  bw; /* channel width 6, 7 or 8 in MHz */
+       u8  pBW; /* channel width used during previous lock */
+       u32 pBER;
+       u32 pPER;
+       u32 ucblocks;
+       s8  echo_pos; /* echo position */
+       u8  first_lock;
+       u8  unlock_counter;
+       u32 agc_val;
+};
+
+struct stv0367_state {
+       struct dvb_frontend fe;
+       struct i2c_adapter *i2c;
+       /* config settings */
+       const struct stv0367_config *config;
+       u8 chip_id;
+       /* DVB-C */
+       struct stv0367cab_state *cab_state;
+       /* DVB-T */
+       struct stv0367ter_state *ter_state;
+};
+
+struct st_register {
+       u16     addr;
+       u8      value;
+};
+
+/* values for STV4100 XTAL=30M int clk=53.125M*/
+static struct st_register def0367ter[STV0367TER_NBREGS] = {
+       {R367TER_ID,            0x60},
+       {R367TER_I2CRPT,        0xa0},
+       /* {R367TER_I2CRPT,     0x22},*/
+       {R367TER_TOPCTRL,       0x00},/* for xc5000; was 0x02 */
+       {R367TER_IOCFG0,        0x40},
+       {R367TER_DAC0R,         0x00},
+       {R367TER_IOCFG1,        0x00},
+       {R367TER_DAC1R,         0x00},
+       {R367TER_IOCFG2,        0x62},
+       {R367TER_SDFR,          0x00},
+       {R367TER_STATUS,        0xf8},
+       {R367TER_AUX_CLK,       0x0a},
+       {R367TER_FREESYS1,      0x00},
+       {R367TER_FREESYS2,      0x00},
+       {R367TER_FREESYS3,      0x00},
+       {R367TER_GPIO_CFG,      0x55},
+       {R367TER_GPIO_CMD,      0x00},
+       {R367TER_AGC2MAX,       0xff},
+       {R367TER_AGC2MIN,       0x00},
+       {R367TER_AGC1MAX,       0xff},
+       {R367TER_AGC1MIN,       0x00},
+       {R367TER_AGCR,          0xbc},
+       {R367TER_AGC2TH,        0x00},
+       {R367TER_AGC12C,        0x00},
+       {R367TER_AGCCTRL1,      0x85},
+       {R367TER_AGCCTRL2,      0x1f},
+       {R367TER_AGC1VAL1,      0x00},
+       {R367TER_AGC1VAL2,      0x00},
+       {R367TER_AGC2VAL1,      0x6f},
+       {R367TER_AGC2VAL2,      0x05},
+       {R367TER_AGC2PGA,       0x00},
+       {R367TER_OVF_RATE1,     0x00},
+       {R367TER_OVF_RATE2,     0x00},
+       {R367TER_GAIN_SRC1,     0xaa},/* for xc5000; was 0x2b */
+       {R367TER_GAIN_SRC2,     0xd6},/* for xc5000; was 0x04 */
+       {R367TER_INC_DEROT1,    0x55},
+       {R367TER_INC_DEROT2,    0x55},
+       {R367TER_PPM_CPAMP_DIR, 0x2c},
+       {R367TER_PPM_CPAMP_INV, 0x00},
+       {R367TER_FREESTFE_1,    0x00},
+       {R367TER_FREESTFE_2,    0x1c},
+       {R367TER_DCOFFSET,      0x00},
+       {R367TER_EN_PROCESS,    0x05},
+       {R367TER_SDI_SMOOTHER,  0x80},
+       {R367TER_FE_LOOP_OPEN,  0x1c},
+       {R367TER_FREQOFF1,      0x00},
+       {R367TER_FREQOFF2,      0x00},
+       {R367TER_FREQOFF3,      0x00},
+       {R367TER_TIMOFF1,       0x00},
+       {R367TER_TIMOFF2,       0x00},
+       {R367TER_EPQ,           0x02},
+       {R367TER_EPQAUTO,       0x01},
+       {R367TER_SYR_UPDATE,    0xf5},
+       {R367TER_CHPFREE,       0x00},
+       {R367TER_PPM_STATE_MAC, 0x23},
+       {R367TER_INR_THRESHOLD, 0xff},
+       {R367TER_EPQ_TPS_ID_CELL, 0xf9},
+       {R367TER_EPQ_CFG,       0x00},
+       {R367TER_EPQ_STATUS,    0x01},
+       {R367TER_AUTORELOCK,    0x81},
+       {R367TER_BER_THR_VMSB,  0x00},
+       {R367TER_BER_THR_MSB,   0x00},
+       {R367TER_BER_THR_LSB,   0x00},
+       {R367TER_CCD,           0x83},
+       {R367TER_SPECTR_CFG,    0x00},
+       {R367TER_CHC_DUMMY,     0x18},
+       {R367TER_INC_CTL,       0x88},
+       {R367TER_INCTHRES_COR1, 0xb4},
+       {R367TER_INCTHRES_COR2, 0x96},
+       {R367TER_INCTHRES_DET1, 0x0e},
+       {R367TER_INCTHRES_DET2, 0x11},
+       {R367TER_IIR_CELLNB,    0x8d},
+       {R367TER_IIRCX_COEFF1_MSB, 0x00},
+       {R367TER_IIRCX_COEFF1_LSB, 0x00},
+       {R367TER_IIRCX_COEFF2_MSB, 0x09},
+       {R367TER_IIRCX_COEFF2_LSB, 0x18},
+       {R367TER_IIRCX_COEFF3_MSB, 0x14},
+       {R367TER_IIRCX_COEFF3_LSB, 0x9c},
+       {R367TER_IIRCX_COEFF4_MSB, 0x00},
+       {R367TER_IIRCX_COEFF4_LSB, 0x00},
+       {R367TER_IIRCX_COEFF5_MSB, 0x36},
+       {R367TER_IIRCX_COEFF5_LSB, 0x42},
+       {R367TER_FEPATH_CFG,    0x00},
+       {R367TER_PMC1_FUNC,     0x65},
+       {R367TER_PMC1_FOR,      0x00},
+       {R367TER_PMC2_FUNC,     0x00},
+       {R367TER_STATUS_ERR_DA, 0xe0},
+       {R367TER_DIG_AGC_R,     0xfe},
+       {R367TER_COMAGC_TARMSB, 0x0b},
+       {R367TER_COM_AGC_TAR_ENMODE, 0x41},
+       {R367TER_COM_AGC_CFG,   0x3e},
+       {R367TER_COM_AGC_GAIN1, 0x39},
+       {R367TER_AUT_AGC_TARGETMSB, 0x0b},
+       {R367TER_LOCK_DET_MSB,  0x01},
+       {R367TER_AGCTAR_LOCK_LSBS, 0x40},
+       {R367TER_AUT_GAIN_EN,   0xf4},
+       {R367TER_AUT_CFG,       0xf0},
+       {R367TER_LOCKN,         0x23},
+       {R367TER_INT_X_3,       0x00},
+       {R367TER_INT_X_2,       0x03},
+       {R367TER_INT_X_1,       0x8d},
+       {R367TER_INT_X_0,       0xa0},
+       {R367TER_MIN_ERRX_MSB,  0x00},
+       {R367TER_COR_CTL,       0x23},
+       {R367TER_COR_STAT,      0xf6},
+       {R367TER_COR_INTEN,     0x00},
+       {R367TER_COR_INTSTAT,   0x3f},
+       {R367TER_COR_MODEGUARD, 0x03},
+       {R367TER_AGC_CTL,       0x08},
+       {R367TER_AGC_MANUAL1,   0x00},
+       {R367TER_AGC_MANUAL2,   0x00},
+       {R367TER_AGC_TARG,      0x16},
+       {R367TER_AGC_GAIN1,     0x53},
+       {R367TER_AGC_GAIN2,     0x1d},
+       {R367TER_RESERVED_1,    0x00},
+       {R367TER_RESERVED_2,    0x00},
+       {R367TER_RESERVED_3,    0x00},
+       {R367TER_CAS_CTL,       0x44},
+       {R367TER_CAS_FREQ,      0xb3},
+       {R367TER_CAS_DAGCGAIN,  0x12},
+       {R367TER_SYR_CTL,       0x04},
+       {R367TER_SYR_STAT,      0x10},
+       {R367TER_SYR_NCO1,      0x00},
+       {R367TER_SYR_NCO2,      0x00},
+       {R367TER_SYR_OFFSET1,   0x00},
+       {R367TER_SYR_OFFSET2,   0x00},
+       {R367TER_FFT_CTL,       0x00},
+       {R367TER_SCR_CTL,       0x70},
+       {R367TER_PPM_CTL1,      0xf8},
+       {R367TER_TRL_CTL,       0x14},/* for xc5000; was 0xac */
+       {R367TER_TRL_NOMRATE1,  0xae},/* for xc5000; was 0x1e */
+       {R367TER_TRL_NOMRATE2,  0x56},/* for xc5000; was 0x58 */
+       {R367TER_TRL_TIME1,     0x1d},
+       {R367TER_TRL_TIME2,     0xfc},
+       {R367TER_CRL_CTL,       0x24},
+       {R367TER_CRL_FREQ1,     0xad},
+       {R367TER_CRL_FREQ2,     0x9d},
+       {R367TER_CRL_FREQ3,     0xff},
+       {R367TER_CHC_CTL,       0x01},
+       {R367TER_CHC_SNR,       0xf0},
+       {R367TER_BDI_CTL,       0x00},
+       {R367TER_DMP_CTL,       0x00},
+       {R367TER_TPS_RCVD1,     0x30},
+       {R367TER_TPS_RCVD2,     0x02},
+       {R367TER_TPS_RCVD3,     0x01},
+       {R367TER_TPS_RCVD4,     0x00},
+       {R367TER_TPS_ID_CELL1,  0x00},
+       {R367TER_TPS_ID_CELL2,  0x00},
+       {R367TER_TPS_RCVD5_SET1, 0x02},
+       {R367TER_TPS_SET2,      0x02},
+       {R367TER_TPS_SET3,      0x01},
+       {R367TER_TPS_CTL,       0x00},
+       {R367TER_CTL_FFTOSNUM,  0x34},
+       {R367TER_TESTSELECT,    0x09},
+       {R367TER_MSC_REV,       0x0a},
+       {R367TER_PIR_CTL,       0x00},
+       {R367TER_SNR_CARRIER1,  0xa1},
+       {R367TER_SNR_CARRIER2,  0x9a},
+       {R367TER_PPM_CPAMP,     0x2c},
+       {R367TER_TSM_AP0,       0x00},
+       {R367TER_TSM_AP1,       0x00},
+       {R367TER_TSM_AP2 ,      0x00},
+       {R367TER_TSM_AP3,       0x00},
+       {R367TER_TSM_AP4,       0x00},
+       {R367TER_TSM_AP5,       0x00},
+       {R367TER_TSM_AP6,       0x00},
+       {R367TER_TSM_AP7,       0x00},
+       {R367TER_TSTRES,        0x00},
+       {R367TER_ANACTRL,       0x0D},/* PLL stoped, restart at init!!! */
+       {R367TER_TSTBUS,        0x00},
+       {R367TER_TSTRATE,       0x00},
+       {R367TER_CONSTMODE,     0x01},
+       {R367TER_CONSTCARR1,    0x00},
+       {R367TER_CONSTCARR2,    0x00},
+       {R367TER_ICONSTEL,      0x0a},
+       {R367TER_QCONSTEL,      0x15},
+       {R367TER_TSTBISTRES0,   0x00},
+       {R367TER_TSTBISTRES1,   0x00},
+       {R367TER_TSTBISTRES2,   0x28},
+       {R367TER_TSTBISTRES3,   0x00},
+       {R367TER_RF_AGC1,       0xff},
+       {R367TER_RF_AGC2,       0x83},
+       {R367TER_ANADIGCTRL,    0x19},
+       {R367TER_PLLMDIV,       0x01},/* for xc5000; was 0x0c */
+       {R367TER_PLLNDIV,       0x06},/* for xc5000; was 0x55 */
+       {R367TER_PLLSETUP,      0x18},
+       {R367TER_DUAL_AD12,     0x0C},/* for xc5000 AGC voltage 1.6V */
+       {R367TER_TSTBIST,       0x00},
+       {R367TER_PAD_COMP_CTRL, 0x00},
+       {R367TER_PAD_COMP_WR,   0x00},
+       {R367TER_PAD_COMP_RD,   0xe0},
+       {R367TER_SYR_TARGET_FFTADJT_MSB, 0x00},
+       {R367TER_SYR_TARGET_FFTADJT_LSB, 0x00},
+       {R367TER_SYR_TARGET_CHCADJT_MSB, 0x00},
+       {R367TER_SYR_TARGET_CHCADJT_LSB, 0x00},
+       {R367TER_SYR_FLAG,      0x00},
+       {R367TER_CRL_TARGET1,   0x00},
+       {R367TER_CRL_TARGET2,   0x00},
+       {R367TER_CRL_TARGET3,   0x00},
+       {R367TER_CRL_TARGET4,   0x00},
+       {R367TER_CRL_FLAG,      0x00},
+       {R367TER_TRL_TARGET1,   0x00},
+       {R367TER_TRL_TARGET2,   0x00},
+       {R367TER_TRL_CHC,       0x00},
+       {R367TER_CHC_SNR_TARG,  0x00},
+       {R367TER_TOP_TRACK,     0x00},
+       {R367TER_TRACKER_FREE1, 0x00},
+       {R367TER_ERROR_CRL1,    0x00},
+       {R367TER_ERROR_CRL2,    0x00},
+       {R367TER_ERROR_CRL3,    0x00},
+       {R367TER_ERROR_CRL4,    0x00},
+       {R367TER_DEC_NCO1,      0x2c},
+       {R367TER_DEC_NCO2,      0x0f},
+       {R367TER_DEC_NCO3,      0x20},
+       {R367TER_SNR,           0xf1},
+       {R367TER_SYR_FFTADJ1,   0x00},
+       {R367TER_SYR_FFTADJ2,   0x00},
+       {R367TER_SYR_CHCADJ1,   0x00},
+       {R367TER_SYR_CHCADJ2,   0x00},
+       {R367TER_SYR_OFF,       0x00},
+       {R367TER_PPM_OFFSET1,   0x00},
+       {R367TER_PPM_OFFSET2,   0x03},
+       {R367TER_TRACKER_FREE2, 0x00},
+       {R367TER_DEBG_LT10,     0x00},
+       {R367TER_DEBG_LT11,     0x00},
+       {R367TER_DEBG_LT12,     0x00},
+       {R367TER_DEBG_LT13,     0x00},
+       {R367TER_DEBG_LT14,     0x00},
+       {R367TER_DEBG_LT15,     0x00},
+       {R367TER_DEBG_LT16,     0x00},
+       {R367TER_DEBG_LT17,     0x00},
+       {R367TER_DEBG_LT18,     0x00},
+       {R367TER_DEBG_LT19,     0x00},
+       {R367TER_DEBG_LT1A,     0x00},
+       {R367TER_DEBG_LT1B,     0x00},
+       {R367TER_DEBG_LT1C,     0x00},
+       {R367TER_DEBG_LT1D,     0x00},
+       {R367TER_DEBG_LT1E,     0x00},
+       {R367TER_DEBG_LT1F,     0x00},
+       {R367TER_RCCFGH,        0x00},
+       {R367TER_RCCFGM,        0x00},
+       {R367TER_RCCFGL,        0x00},
+       {R367TER_RCINSDELH,     0x00},
+       {R367TER_RCINSDELM,     0x00},
+       {R367TER_RCINSDELL,     0x00},
+       {R367TER_RCSTATUS,      0x00},
+       {R367TER_RCSPEED,       0x6f},
+       {R367TER_RCDEBUGM,      0xe7},
+       {R367TER_RCDEBUGL,      0x9b},
+       {R367TER_RCOBSCFG,      0x00},
+       {R367TER_RCOBSM,        0x00},
+       {R367TER_RCOBSL,        0x00},
+       {R367TER_RCFECSPY,      0x00},
+       {R367TER_RCFSPYCFG,     0x00},
+       {R367TER_RCFSPYDATA,    0x00},
+       {R367TER_RCFSPYOUT,     0x00},
+       {R367TER_RCFSTATUS,     0x00},
+       {R367TER_RCFGOODPACK,   0x00},
+       {R367TER_RCFPACKCNT,    0x00},
+       {R367TER_RCFSPYMISC,    0x00},
+       {R367TER_RCFBERCPT4,    0x00},
+       {R367TER_RCFBERCPT3,    0x00},
+       {R367TER_RCFBERCPT2,    0x00},
+       {R367TER_RCFBERCPT1,    0x00},
+       {R367TER_RCFBERCPT0,    0x00},
+       {R367TER_RCFBERERR2,    0x00},
+       {R367TER_RCFBERERR1,    0x00},
+       {R367TER_RCFBERERR0,    0x00},
+       {R367TER_RCFSTATESM,    0x00},
+       {R367TER_RCFSTATESL,    0x00},
+       {R367TER_RCFSPYBER,     0x00},
+       {R367TER_RCFSPYDISTM,   0x00},
+       {R367TER_RCFSPYDISTL,   0x00},
+       {R367TER_RCFSPYOBS7,    0x00},
+       {R367TER_RCFSPYOBS6,    0x00},
+       {R367TER_RCFSPYOBS5,    0x00},
+       {R367TER_RCFSPYOBS4,    0x00},
+       {R367TER_RCFSPYOBS3,    0x00},
+       {R367TER_RCFSPYOBS2,    0x00},
+       {R367TER_RCFSPYOBS1,    0x00},
+       {R367TER_RCFSPYOBS0,    0x00},
+       {R367TER_TSGENERAL,     0x00},
+       {R367TER_RC1SPEED,      0x6f},
+       {R367TER_TSGSTATUS,     0x18},
+       {R367TER_FECM,          0x01},
+       {R367TER_VTH12,         0xff},
+       {R367TER_VTH23,         0xa1},
+       {R367TER_VTH34,         0x64},
+       {R367TER_VTH56,         0x40},
+       {R367TER_VTH67,         0x00},
+       {R367TER_VTH78,         0x2c},
+       {R367TER_VITCURPUN,     0x12},
+       {R367TER_VERROR,        0x01},
+       {R367TER_PRVIT,         0x3f},
+       {R367TER_VAVSRVIT,      0x00},
+       {R367TER_VSTATUSVIT,    0xbd},
+       {R367TER_VTHINUSE,      0xa1},
+       {R367TER_KDIV12,        0x20},
+       {R367TER_KDIV23,        0x40},
+       {R367TER_KDIV34,        0x20},
+       {R367TER_KDIV56,        0x30},
+       {R367TER_KDIV67,        0x00},
+       {R367TER_KDIV78,        0x30},
+       {R367TER_SIGPOWER,      0x54},
+       {R367TER_DEMAPVIT,      0x40},
+       {R367TER_VITSCALE,      0x00},
+       {R367TER_FFEC1PRG,      0x00},
+       {R367TER_FVITCURPUN,    0x12},
+       {R367TER_FVERROR,       0x01},
+       {R367TER_FVSTATUSVIT,   0xbd},
+       {R367TER_DEBUG_LT1,     0x00},
+       {R367TER_DEBUG_LT2,     0x00},
+       {R367TER_DEBUG_LT3,     0x00},
+       {R367TER_TSTSFMET,      0x00},
+       {R367TER_SELOUT,        0x00},
+       {R367TER_TSYNC,         0x00},
+       {R367TER_TSTERR,        0x00},
+       {R367TER_TSFSYNC,       0x00},
+       {R367TER_TSTSFERR,      0x00},
+       {R367TER_TSTTSSF1,      0x01},
+       {R367TER_TSTTSSF2,      0x1f},
+       {R367TER_TSTTSSF3,      0x00},
+       {R367TER_TSTTS1,        0x00},
+       {R367TER_TSTTS2,        0x1f},
+       {R367TER_TSTTS3,        0x01},
+       {R367TER_TSTTS4,        0x00},
+       {R367TER_TSTTSRC,       0x00},
+       {R367TER_TSTTSRS,       0x00},
+       {R367TER_TSSTATEM,      0xb0},
+       {R367TER_TSSTATEL,      0x40},
+       {R367TER_TSCFGH,        0xC0},
+       {R367TER_TSCFGM,        0xc0},/* for xc5000; was 0x00 */
+       {R367TER_TSCFGL,        0x20},
+       {R367TER_TSSYNC,        0x00},
+       {R367TER_TSINSDELH,     0x00},
+       {R367TER_TSINSDELM,     0x00},
+       {R367TER_TSINSDELL,     0x00},
+       {R367TER_TSDIVN,        0x03},
+       {R367TER_TSDIVPM,       0x00},
+       {R367TER_TSDIVPL,       0x00},
+       {R367TER_TSDIVQM,       0x00},
+       {R367TER_TSDIVQL,       0x00},
+       {R367TER_TSDILSTKM,     0x00},
+       {R367TER_TSDILSTKL,     0x00},
+       {R367TER_TSSPEED,       0x40},/* for xc5000; was 0x6f */
+       {R367TER_TSSTATUS,      0x81},
+       {R367TER_TSSTATUS2,     0x6a},
+       {R367TER_TSBITRATEM,    0x0f},
+       {R367TER_TSBITRATEL,    0xc6},
+       {R367TER_TSPACKLENM,    0x00},
+       {R367TER_TSPACKLENL,    0xfc},
+       {R367TER_TSBLOCLENM,    0x0a},
+       {R367TER_TSBLOCLENL,    0x80},
+       {R367TER_TSDLYH,        0x90},
+       {R367TER_TSDLYM,        0x68},
+       {R367TER_TSDLYL,        0x01},
+       {R367TER_TSNPDAV,       0x00},
+       {R367TER_TSBUFSTATH,    0x00},
+       {R367TER_TSBUFSTATM,    0x00},
+       {R367TER_TSBUFSTATL,    0x00},
+       {R367TER_TSDEBUGM,      0xcf},
+       {R367TER_TSDEBUGL,      0x1e},
+       {R367TER_TSDLYSETH,     0x00},
+       {R367TER_TSDLYSETM,     0x68},
+       {R367TER_TSDLYSETL,     0x00},
+       {R367TER_TSOBSCFG,      0x00},
+       {R367TER_TSOBSM,        0x47},
+       {R367TER_TSOBSL,        0x1f},
+       {R367TER_ERRCTRL1,      0x95},
+       {R367TER_ERRCNT1H,      0x80},
+       {R367TER_ERRCNT1M,      0x00},
+       {R367TER_ERRCNT1L,      0x00},
+       {R367TER_ERRCTRL2,      0x95},
+       {R367TER_ERRCNT2H,      0x00},
+       {R367TER_ERRCNT2M,      0x00},
+       {R367TER_ERRCNT2L,      0x00},
+       {R367TER_FECSPY,        0x88},
+       {R367TER_FSPYCFG,       0x2c},
+       {R367TER_FSPYDATA,      0x3a},
+       {R367TER_FSPYOUT,       0x06},
+       {R367TER_FSTATUS,       0x61},
+       {R367TER_FGOODPACK,     0xff},
+       {R367TER_FPACKCNT,      0xff},
+       {R367TER_FSPYMISC,      0x66},
+       {R367TER_FBERCPT4,      0x00},
+       {R367TER_FBERCPT3,      0x00},
+       {R367TER_FBERCPT2,      0x36},
+       {R367TER_FBERCPT1,      0x36},
+       {R367TER_FBERCPT0,      0x14},
+       {R367TER_FBERERR2,      0x00},
+       {R367TER_FBERERR1,      0x03},
+       {R367TER_FBERERR0,      0x28},
+       {R367TER_FSTATESM,      0x00},
+       {R367TER_FSTATESL,      0x02},
+       {R367TER_FSPYBER,       0x00},
+       {R367TER_FSPYDISTM,     0x01},
+       {R367TER_FSPYDISTL,     0x9f},
+       {R367TER_FSPYOBS7,      0xc9},
+       {R367TER_FSPYOBS6,      0x99},
+       {R367TER_FSPYOBS5,      0x08},
+       {R367TER_FSPYOBS4,      0xec},
+       {R367TER_FSPYOBS3,      0x01},
+       {R367TER_FSPYOBS2,      0x0f},
+       {R367TER_FSPYOBS1,      0xf5},
+       {R367TER_FSPYOBS0,      0x08},
+       {R367TER_SFDEMAP,       0x40},
+       {R367TER_SFERROR,       0x00},
+       {R367TER_SFAVSR,        0x30},
+       {R367TER_SFECSTATUS,    0xcc},
+       {R367TER_SFKDIV12,      0x20},
+       {R367TER_SFKDIV23,      0x40},
+       {R367TER_SFKDIV34,      0x20},
+       {R367TER_SFKDIV56,      0x20},
+       {R367TER_SFKDIV67,      0x00},
+       {R367TER_SFKDIV78,      0x20},
+       {R367TER_SFDILSTKM,     0x00},
+       {R367TER_SFDILSTKL,     0x00},
+       {R367TER_SFSTATUS,      0xb5},
+       {R367TER_SFDLYH,        0x90},
+       {R367TER_SFDLYM,        0x60},
+       {R367TER_SFDLYL,        0x01},
+       {R367TER_SFDLYSETH,     0xc0},
+       {R367TER_SFDLYSETM,     0x60},
+       {R367TER_SFDLYSETL,     0x00},
+       {R367TER_SFOBSCFG,      0x00},
+       {R367TER_SFOBSM,        0x47},
+       {R367TER_SFOBSL,        0x05},
+       {R367TER_SFECINFO,      0x40},
+       {R367TER_SFERRCTRL,     0x74},
+       {R367TER_SFERRCNTH,     0x80},
+       {R367TER_SFERRCNTM ,    0x00},
+       {R367TER_SFERRCNTL,     0x00},
+       {R367TER_SYMBRATEM,     0x2f},
+       {R367TER_SYMBRATEL,     0x50},
+       {R367TER_SYMBSTATUS,    0x7f},
+       {R367TER_SYMBCFG,       0x00},
+       {R367TER_SYMBFIFOM,     0xf4},
+       {R367TER_SYMBFIFOL,     0x0d},
+       {R367TER_SYMBOFFSM,     0xf0},
+       {R367TER_SYMBOFFSL,     0x2d},
+       {R367TER_DEBUG_LT4,     0x00},
+       {R367TER_DEBUG_LT5,     0x00},
+       {R367TER_DEBUG_LT6,     0x00},
+       {R367TER_DEBUG_LT7,     0x00},
+       {R367TER_DEBUG_LT8,     0x00},
+       {R367TER_DEBUG_LT9,     0x00},
+};
+
+#define RF_LOOKUP_TABLE_SIZE  31
+#define RF_LOOKUP_TABLE2_SIZE 16
+/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/
+s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = {
+       {/*AGC1*/
+               48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63,
+               64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+               76, 77, 78, 80, 83, 85, 88,
+       }, {/*RF(dbm)*/
+               22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+               34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47,
+               49, 50, 52, 53, 54, 55, 56,
+       }
+};
+/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/
+s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = {
+       {/*AGC2*/
+               28, 29, 31, 32, 34, 35, 36, 37,
+               38, 39, 40, 41, 42, 43, 44, 45,
+       }, {/*RF(dbm)*/
+               57, 58, 59, 60, 61, 62, 63, 64,
+               65, 66, 67, 68, 69, 70, 71, 72,
+       }
+};
+
+static struct st_register def0367cab[STV0367CAB_NBREGS] = {
+       {R367CAB_ID,            0x60},
+       {R367CAB_I2CRPT,        0xa0},
+       /*{R367CAB_I2CRPT,      0x22},*/
+       {R367CAB_TOPCTRL,       0x10},
+       {R367CAB_IOCFG0,        0x80},
+       {R367CAB_DAC0R,         0x00},
+       {R367CAB_IOCFG1,        0x00},
+       {R367CAB_DAC1R,         0x00},
+       {R367CAB_IOCFG2,        0x00},
+       {R367CAB_SDFR,          0x00},
+       {R367CAB_AUX_CLK,       0x00},
+       {R367CAB_FREESYS1,      0x00},
+       {R367CAB_FREESYS2,      0x00},
+       {R367CAB_FREESYS3,      0x00},
+       {R367CAB_GPIO_CFG,      0x55},
+       {R367CAB_GPIO_CMD,      0x01},
+       {R367CAB_TSTRES,        0x00},
+       {R367CAB_ANACTRL,       0x0d},/* was 0x00 need to check - I.M.L.*/
+       {R367CAB_TSTBUS,        0x00},
+       {R367CAB_RF_AGC1,       0xea},
+       {R367CAB_RF_AGC2,       0x82},
+       {R367CAB_ANADIGCTRL,    0x0b},
+       {R367CAB_PLLMDIV,       0x01},
+       {R367CAB_PLLNDIV,       0x08},
+       {R367CAB_PLLSETUP,      0x18},
+       {R367CAB_DUAL_AD12,     0x0C}, /* for xc5000 AGC voltage 1.6V */
+       {R367CAB_TSTBIST,       0x00},
+       {R367CAB_CTRL_1,        0x00},
+       {R367CAB_CTRL_2,        0x03},
+       {R367CAB_IT_STATUS1,    0x2b},
+       {R367CAB_IT_STATUS2,    0x08},
+       {R367CAB_IT_EN1,        0x00},
+       {R367CAB_IT_EN2,        0x00},
+       {R367CAB_CTRL_STATUS,   0x04},
+       {R367CAB_TEST_CTL,      0x00},
+       {R367CAB_AGC_CTL,       0x73},
+       {R367CAB_AGC_IF_CFG,    0x50},
+       {R367CAB_AGC_RF_CFG,    0x00},
+       {R367CAB_AGC_PWM_CFG,   0x03},
+       {R367CAB_AGC_PWR_REF_L, 0x5a},
+       {R367CAB_AGC_PWR_REF_H, 0x00},
+       {R367CAB_AGC_RF_TH_L,   0xff},
+       {R367CAB_AGC_RF_TH_H,   0x07},
+       {R367CAB_AGC_IF_LTH_L,  0x00},
+       {R367CAB_AGC_IF_LTH_H,  0x08},
+       {R367CAB_AGC_IF_HTH_L,  0xff},
+       {R367CAB_AGC_IF_HTH_H,  0x07},
+       {R367CAB_AGC_PWR_RD_L,  0xa0},
+       {R367CAB_AGC_PWR_RD_M,  0xe9},
+       {R367CAB_AGC_PWR_RD_H,  0x03},
+       {R367CAB_AGC_PWM_IFCMD_L,       0xe4},
+       {R367CAB_AGC_PWM_IFCMD_H,       0x00},
+       {R367CAB_AGC_PWM_RFCMD_L,       0xff},
+       {R367CAB_AGC_PWM_RFCMD_H,       0x07},
+       {R367CAB_IQDEM_CFG,     0x01},
+       {R367CAB_MIX_NCO_LL,    0x22},
+       {R367CAB_MIX_NCO_HL,    0x96},
+       {R367CAB_MIX_NCO_HH,    0x55},
+       {R367CAB_SRC_NCO_LL,    0xff},
+       {R367CAB_SRC_NCO_LH,    0x0c},
+       {R367CAB_SRC_NCO_HL,    0xf5},
+       {R367CAB_SRC_NCO_HH,    0x20},
+       {R367CAB_IQDEM_GAIN_SRC_L,      0x06},
+       {R367CAB_IQDEM_GAIN_SRC_H,      0x01},
+       {R367CAB_IQDEM_DCRM_CFG_LL,     0xfe},
+       {R367CAB_IQDEM_DCRM_CFG_LH,     0xff},
+       {R367CAB_IQDEM_DCRM_CFG_HL,     0x0f},
+       {R367CAB_IQDEM_DCRM_CFG_HH,     0x00},
+       {R367CAB_IQDEM_ADJ_COEFF0,      0x34},
+       {R367CAB_IQDEM_ADJ_COEFF1,      0xae},
+       {R367CAB_IQDEM_ADJ_COEFF2,      0x46},
+       {R367CAB_IQDEM_ADJ_COEFF3,      0x77},
+       {R367CAB_IQDEM_ADJ_COEFF4,      0x96},
+       {R367CAB_IQDEM_ADJ_COEFF5,      0x69},
+       {R367CAB_IQDEM_ADJ_COEFF6,      0xc7},
+       {R367CAB_IQDEM_ADJ_COEFF7,      0x01},
+       {R367CAB_IQDEM_ADJ_EN,  0x04},
+       {R367CAB_IQDEM_ADJ_AGC_REF,     0x94},
+       {R367CAB_ALLPASSFILT1,  0xc9},
+       {R367CAB_ALLPASSFILT2,  0x2d},
+       {R367CAB_ALLPASSFILT3,  0xa3},
+       {R367CAB_ALLPASSFILT4,  0xfb},
+       {R367CAB_ALLPASSFILT5,  0xf6},
+       {R367CAB_ALLPASSFILT6,  0x45},
+       {R367CAB_ALLPASSFILT7,  0x6f},
+       {R367CAB_ALLPASSFILT8,  0x7e},
+       {R367CAB_ALLPASSFILT9,  0x05},
+       {R367CAB_ALLPASSFILT10, 0x0a},
+       {R367CAB_ALLPASSFILT11, 0x51},
+       {R367CAB_TRL_AGC_CFG,   0x20},
+       {R367CAB_TRL_LPF_CFG,   0x28},
+       {R367CAB_TRL_LPF_ACQ_GAIN,      0x44},
+       {R367CAB_TRL_LPF_TRK_GAIN,      0x22},
+       {R367CAB_TRL_LPF_OUT_GAIN,      0x03},
+       {R367CAB_TRL_LOCKDET_LTH,       0x04},
+       {R367CAB_TRL_LOCKDET_HTH,       0x11},
+       {R367CAB_TRL_LOCKDET_TRGVAL,    0x20},
+       {R367CAB_IQ_QAM,        0x01},
+       {R367CAB_FSM_STATE,     0xa0},
+       {R367CAB_FSM_CTL,       0x08},
+       {R367CAB_FSM_STS,       0x0c},
+       {R367CAB_FSM_SNR0_HTH,  0x00},
+       {R367CAB_FSM_SNR1_HTH,  0x00},
+       {R367CAB_FSM_SNR2_HTH,  0x23},/* 0x00 */
+       {R367CAB_FSM_SNR0_LTH,  0x00},
+       {R367CAB_FSM_SNR1_LTH,  0x00},
+       {R367CAB_FSM_EQA1_HTH,  0x00},
+       {R367CAB_FSM_TEMPO,     0x32},
+       {R367CAB_FSM_CONFIG,    0x03},
+       {R367CAB_EQU_I_TESTTAP_L,       0x11},
+       {R367CAB_EQU_I_TESTTAP_M,       0x00},
+       {R367CAB_EQU_I_TESTTAP_H,       0x00},
+       {R367CAB_EQU_TESTAP_CFG,        0x00},
+       {R367CAB_EQU_Q_TESTTAP_L,       0xff},
+       {R367CAB_EQU_Q_TESTTAP_M,       0x00},
+       {R367CAB_EQU_Q_TESTTAP_H,       0x00},
+       {R367CAB_EQU_TAP_CTRL,  0x00},
+       {R367CAB_EQU_CTR_CRL_CONTROL_L, 0x11},
+       {R367CAB_EQU_CTR_CRL_CONTROL_H, 0x05},
+       {R367CAB_EQU_CTR_HIPOW_L,       0x00},
+       {R367CAB_EQU_CTR_HIPOW_H,       0x00},
+       {R367CAB_EQU_I_EQU_LO,  0xef},
+       {R367CAB_EQU_I_EQU_HI,  0x00},
+       {R367CAB_EQU_Q_EQU_LO,  0xee},
+       {R367CAB_EQU_Q_EQU_HI,  0x00},
+       {R367CAB_EQU_MAPPER,    0xc5},
+       {R367CAB_EQU_SWEEP_RATE,        0x80},
+       {R367CAB_EQU_SNR_LO,    0x64},
+       {R367CAB_EQU_SNR_HI,    0x03},
+       {R367CAB_EQU_GAMMA_LO,  0x00},
+       {R367CAB_EQU_GAMMA_HI,  0x00},
+       {R367CAB_EQU_ERR_GAIN,  0x36},
+       {R367CAB_EQU_RADIUS,    0xaa},
+       {R367CAB_EQU_FFE_MAINTAP,       0x00},
+       {R367CAB_EQU_FFE_LEAKAGE,       0x63},
+       {R367CAB_EQU_FFE_MAINTAP_POS,   0xdf},
+       {R367CAB_EQU_GAIN_WIDE, 0x88},
+       {R367CAB_EQU_GAIN_NARROW,       0x41},
+       {R367CAB_EQU_CTR_LPF_GAIN,      0xd1},
+       {R367CAB_EQU_CRL_LPF_GAIN,      0xa7},
+       {R367CAB_EQU_GLOBAL_GAIN,       0x06},
+       {R367CAB_EQU_CRL_LD_SEN,        0x85},
+       {R367CAB_EQU_CRL_LD_VAL,        0xe2},
+       {R367CAB_EQU_CRL_TFR,   0x20},
+       {R367CAB_EQU_CRL_BISTH_LO,      0x00},
+       {R367CAB_EQU_CRL_BISTH_HI,      0x00},
+       {R367CAB_EQU_SWEEP_RANGE_LO,    0x00},
+       {R367CAB_EQU_SWEEP_RANGE_HI,    0x00},
+       {R367CAB_EQU_CRL_LIMITER,       0x40},
+       {R367CAB_EQU_MODULUS_MAP,       0x90},
+       {R367CAB_EQU_PNT_GAIN,  0xa7},
+       {R367CAB_FEC_AC_CTR_0,  0x16},
+       {R367CAB_FEC_AC_CTR_1,  0x0b},
+       {R367CAB_FEC_AC_CTR_2,  0x88},
+       {R367CAB_FEC_AC_CTR_3,  0x02},
+       {R367CAB_FEC_STATUS,    0x12},
+       {R367CAB_RS_COUNTER_0,  0x7d},
+       {R367CAB_RS_COUNTER_1,  0xd0},
+       {R367CAB_RS_COUNTER_2,  0x19},
+       {R367CAB_RS_COUNTER_3,  0x0b},
+       {R367CAB_RS_COUNTER_4,  0xa3},
+       {R367CAB_RS_COUNTER_5,  0x00},
+       {R367CAB_BERT_0,        0x01},
+       {R367CAB_BERT_1,        0x25},
+       {R367CAB_BERT_2,        0x41},
+       {R367CAB_BERT_3,        0x39},
+       {R367CAB_OUTFORMAT_0,   0xc2},
+       {R367CAB_OUTFORMAT_1,   0x22},
+       {R367CAB_SMOOTHER_2,    0x28},
+       {R367CAB_TSMF_CTRL_0,   0x01},
+       {R367CAB_TSMF_CTRL_1,   0xc6},
+       {R367CAB_TSMF_CTRL_3,   0x43},
+       {R367CAB_TS_ON_ID_0,    0x00},
+       {R367CAB_TS_ON_ID_1,    0x00},
+       {R367CAB_TS_ON_ID_2,    0x00},
+       {R367CAB_TS_ON_ID_3,    0x00},
+       {R367CAB_RE_STATUS_0,   0x00},
+       {R367CAB_RE_STATUS_1,   0x00},
+       {R367CAB_RE_STATUS_2,   0x00},
+       {R367CAB_RE_STATUS_3,   0x00},
+       {R367CAB_TS_STATUS_0,   0x00},
+       {R367CAB_TS_STATUS_1,   0x00},
+       {R367CAB_TS_STATUS_2,   0xa0},
+       {R367CAB_TS_STATUS_3,   0x00},
+       {R367CAB_T_O_ID_0,      0x00},
+       {R367CAB_T_O_ID_1,      0x00},
+       {R367CAB_T_O_ID_2,      0x00},
+       {R367CAB_T_O_ID_3,      0x00},
+};
+
+static
+int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len)
+{
+       u8 buf[len + 2];
+       struct i2c_msg msg = {
+               .addr = state->config->demod_address,
+               .flags = 0,
+               .buf = buf,
+               .len = len + 2
+       };
+       int ret;
+
+       buf[0] = MSB(reg);
+       buf[1] = LSB(reg);
+       memcpy(buf + 2, data, len);
+
+       if (i2cdebug)
+               printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]);
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+       if (ret != 1)
+               printk(KERN_ERR "%s: i2c write error!\n", __func__);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data)
+{
+       return stv0367_writeregs(state, reg, &data, 1);
+}
+
+static u8 stv0367_readreg(struct stv0367_state *state, u16 reg)
+{
+       u8 b0[] = { 0, 0 };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = state->config->demod_address,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 2
+               }, {
+                       .addr = state->config->demod_address,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+       int ret;
+
+       b0[0] = MSB(reg);
+       b0[1] = LSB(reg);
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2)
+               printk(KERN_ERR "%s: i2c read error\n", __func__);
+
+       if (i2cdebug)
+               printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]);
+
+       return b1[0];
+}
+
+static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+{
+       u8 position = 0, i = 0;
+
+       (*mask) = label & 0xff;
+
+       while ((position == 0) && (i < 8)) {
+               position = ((*mask) >> i) & 0x01;
+               i++;
+       }
+
+       (*pos) = (i - 1);
+}
+
+static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val)
+{
+       u8 reg, mask, pos;
+
+       reg = stv0367_readreg(state, (label >> 16) & 0xffff);
+       extract_mask_pos(label, &mask, &pos);
+
+       val = mask & (val << pos);
+
+       reg = (reg & (~mask)) | val;
+       stv0367_writereg(state, (label >> 16) & 0xffff, reg);
+
+}
+
+static void stv0367_setbits(u8 *reg, u32 label, u8 val)
+{
+       u8 mask, pos;
+
+       extract_mask_pos(label, &mask, &pos);
+
+       val = mask & (val << pos);
+
+       (*reg) = ((*reg) & (~mask)) | val;
+}
+
+static u8 stv0367_readbits(struct stv0367_state *state, u32 label)
+{
+       u8 val = 0xff;
+       u8 mask, pos;
+
+       extract_mask_pos(label, &mask, &pos);
+
+       val = stv0367_readreg(state, label >> 16);
+       val = (val & mask) >> pos;
+
+       return val;
+}
+
+u8 stv0367_getbits(u8 reg, u32 label)
+{
+       u8 mask, pos;
+
+       extract_mask_pos(label, &mask, &pos);
+
+       return (reg & mask) >> pos;
+}
+
+static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       u8 tmp = stv0367_readreg(state, R367TER_I2CRPT);
+
+       dprintk("%s:\n", __func__);
+
+       if (enable) {
+               stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0);
+               stv0367_setbits(&tmp, F367TER_I2CT_ON, 1);
+       } else {
+               stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1);
+               stv0367_setbits(&tmp, F367TER_I2CT_ON, 0);
+       }
+
+       stv0367_writereg(state, R367TER_I2CRPT, tmp);
+
+       return 0;
+}
+
+static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       u32 freq = 0;
+       int err = 0;
+
+       dprintk("%s:\n", __func__);
+
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->get_frequency) {
+               err = tuner_ops->get_frequency(fe, &freq);
+               if (err < 0) {
+                       printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+
+               dprintk("%s: frequency=%d\n", __func__, freq);
+
+       } else
+               return -1;
+
+       return freq;
+}
+
+static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = {
+       {
+               {0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/
+               {0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */
+               {0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */
+               {0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */
+               {0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */
+               {0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */
+       }, {
+               {0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/
+               {0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29},
+               {0x2532, 0xC000, 0x251D, 0xC391, 0x706F},
+               {0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F},
+               {0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193},
+               {0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */
+       }, {
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+       }
+};
+
+static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = {
+       {
+               {0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/
+               {0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */
+               {0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */
+               {0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */
+               {0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */
+               {0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */
+       }, {
+               {0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/
+               {0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206},
+               {0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3},
+               {0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F},
+               {0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB},
+               {0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF}
+       }, {
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+       }
+};
+
+static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = {
+       {
+               {0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/
+               {0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */
+               {0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */
+               {0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */
+               {0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */
+               {0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */
+       }, {
+               {0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/
+               {0x225E, 0xC000, 0x2256, 0xC589, 0x7489},
+               {0x2293, 0xC000, 0x2295, 0xC209, 0x767E},
+               {0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746},
+               {0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799},
+               {0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757}
+
+       }, {
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+               {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}
+       }
+};
+
+static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz)
+{
+       u32 mclk_Hz = 0; /* master clock frequency (Hz) */
+       u32 m, n, p;
+
+       dprintk("%s:\n", __func__);
+
+       if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) {
+               n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV);
+               if (n == 0)
+                       n = n + 1;
+
+               m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV);
+               if (m == 0)
+                       m = m + 1;
+
+               p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV);
+               if (p > 5)
+                       p = 5;
+
+               mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p));
+
+               dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n",
+                               n, m, p, mclk_Hz, ExtClk_Hz);
+       } else
+               mclk_Hz = ExtClk_Hz;
+
+       dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz);
+
+       return mclk_Hz;
+}
+
+static int stv0367ter_filt_coeff_init(struct stv0367_state *state,
+                               u16 CellsCoeffs[3][6][5], u32 DemodXtal)
+{
+       int i, j, k, freq;
+
+       dprintk("%s:\n", __func__);
+
+       freq = stv0367ter_get_mclk(state, DemodXtal);
+
+       if (freq == 53125000)
+               k = 1; /* equivalent to Xtal 25M on 362*/
+       else if (freq == 54000000)
+               k = 0; /* equivalent to Xtal 27M on 362*/
+       else if (freq == 52500000)
+               k = 2; /* equivalent to Xtal 30M on 362*/
+       else
+               return 0;
+
+       for (i = 1; i <= 6; i++) {
+               stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1);
+
+               for (j = 1; j <= 5; j++) {
+                       stv0367_writereg(state,
+                               (R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)),
+                               MSB(CellsCoeffs[k][i-1][j-1]));
+                       stv0367_writereg(state,
+                               (R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)),
+                               LSB(CellsCoeffs[k][i-1][j-1]));
+               }
+       }
+
+       return 1;
+
+}
+
+static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state)
+{
+       dprintk("%s:\n", __func__);
+
+       stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00);
+
+       /* Lock detect 1 */
+       stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00);
+       stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
+       stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
+
+       /* Lock detect 2 */
+       stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01);
+       stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06);
+       stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04);
+
+       /* Lock detect 3 */
+       stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02);
+       stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
+       stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
+
+       /* Lock detect 4 */
+       stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03);
+       stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01);
+       stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00);
+
+}
+
+static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth,
+                                                       u32 DemodXtalValue)
+{
+       dprintk("%s:\n", __func__);
+
+       stv0367_writebits(state, F367TER_NRST_IIR, 0);
+
+       switch (Bandwidth) {
+       case 6:
+               if (!stv0367ter_filt_coeff_init(state,
+                               CellsCoeffs_6MHz_367cofdm,
+                               DemodXtalValue))
+                       return 0;
+               break;
+       case 7:
+               if (!stv0367ter_filt_coeff_init(state,
+                               CellsCoeffs_7MHz_367cofdm,
+                               DemodXtalValue))
+                       return 0;
+               break;
+       case 8:
+               if (!stv0367ter_filt_coeff_init(state,
+                               CellsCoeffs_8MHz_367cofdm,
+                               DemodXtalValue))
+                       return 0;
+               break;
+       default:
+               return 0;
+       }
+
+       stv0367_writebits(state, F367TER_NRST_IIR, 1);
+
+       return 1;
+}
+
+static void stv0367ter_agc_iir_rst(struct stv0367_state *state)
+{
+
+       u8 com_n;
+
+       dprintk("%s:\n", __func__);
+
+       com_n = stv0367_readbits(state, F367TER_COM_N);
+
+       stv0367_writebits(state, F367TER_COM_N, 0x07);
+
+       stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00);
+       stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00);
+
+       stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01);
+       stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01);
+
+       stv0367_writebits(state, F367TER_COM_N, com_n);
+
+}
+
+static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3)
+{
+       int local_tempo = 0;
+       switch (mode) {
+       case 0:
+               local_tempo = tempo1;
+               break;
+       case 1:
+               local_tempo = tempo2;
+               break ;
+
+       case 2:
+               local_tempo = tempo3;
+               break;
+
+       default:
+               break;
+       }
+       /*      msleep(local_tempo);  */
+       return local_tempo;
+}
+
+static enum
+stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state)
+{
+       int wd = 100;
+       unsigned short int SYR_var;
+       s32 SYRStatus;
+
+       dprintk("%s:\n", __func__);
+
+       SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
+
+       while ((!SYR_var) && (wd > 0)) {
+               usleep_range(2000, 3000);
+               wd -= 2;
+               SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK);
+       }
+
+       if (!SYR_var)
+               SYRStatus = FE_TER_NOSYMBOL;
+       else
+               SYRStatus =  FE_TER_SYMBOLOK;
+
+       dprintk("stv0367ter_check_syr SYRStatus %s\n",
+                               SYR_var == 0 ? "No Symbol" : "OK");
+
+       return SYRStatus;
+}
+
+static enum
+stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state,
+                                                               s32 FFTmode)
+{
+
+       s32  CPAMPvalue = 0, CPAMPStatus, CPAMPMin;
+       int wd = 0;
+
+       dprintk("%s:\n", __func__);
+
+       switch (FFTmode) {
+       case 0: /*2k mode*/
+               CPAMPMin = 20;
+               wd = 10;
+               break;
+       case 1: /*8k mode*/
+               CPAMPMin = 80;
+               wd = 55;
+               break;
+       case 2: /*4k mode*/
+               CPAMPMin = 40;
+               wd = 30;
+               break;
+       default:
+               CPAMPMin = 0xffff;  /*drives to NOCPAMP */
+               break;
+       }
+
+       dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd);
+
+       CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
+       while ((CPAMPvalue < CPAMPMin) && (wd > 0)) {
+               usleep_range(1000, 2000);
+               wd -= 1;
+               CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT);
+               /*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */
+       }
+       dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd);
+       if (CPAMPvalue < CPAMPMin) {
+               CPAMPStatus = FE_TER_NOCPAMP;
+               printk(KERN_ERR "CPAMP failed\n");
+       } else {
+               printk(KERN_ERR "CPAMP OK !\n");
+               CPAMPStatus = FE_TER_CPAMPOK;
+       }
+
+       return CPAMPStatus;
+}
+
+enum
+stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state)
+{
+       enum stv0367_ter_signal_type ret_flag;
+       short int wd, tempo;
+       u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard;
+       u8 tmp, tmp2;
+
+       dprintk("%s:\n", __func__);
+
+       if (state == NULL)
+               return FE_TER_SWNOK;
+
+       try = 0;
+       do {
+               ret_flag = FE_TER_LOCKOK;
+
+               stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+
+               if (state->config->if_iq_mode != 0)
+                       stv0367_writebits(state, F367TER_COM_N, 0x07);
+
+               stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */
+               stv0367_writebits(state, F367TER_MODE, 0);
+               stv0367_writebits(state, F367TER_SYR_TR_DIS, 0);
+               usleep_range(5000, 10000);
+
+               stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+
+
+               if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL)
+                       return FE_TER_NOSYMBOL;
+               else { /*
+                       if chip locked on wrong mode first try,
+                       it must lock correctly second try */
+                       mode = stv0367_readbits(state, F367TER_SYR_MODE);
+                       if (stv0367ter_check_cpamp(state, mode) ==
+                                                       FE_TER_NOCPAMP) {
+                               if (try == 0)
+                                       ret_flag = FE_TER_NOCPAMP;
+
+                       }
+               }
+
+               try++;
+       } while ((try < 10) && (ret_flag != FE_TER_LOCKOK));
+
+       tmp  = stv0367_readreg(state, R367TER_SYR_STAT);
+       tmp2 = stv0367_readreg(state, R367TER_STATUS);
+       dprintk("state=%p\n", state);
+       dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n",
+                                                       mode, tmp, tmp2);
+
+       tmp  = stv0367_readreg(state, R367TER_PRVIT);
+       tmp2 = stv0367_readreg(state, R367TER_I2CRPT);
+       dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2);
+
+       tmp  = stv0367_readreg(state, R367TER_GAIN_SRC1);
+       dprintk("GAIN_SRC1=0x%x\n", tmp);
+
+       if ((mode != 0) && (mode != 1) && (mode != 2))
+               return FE_TER_SWNOK;
+
+       /*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */
+
+       /*supress EPQ auto for SYR_GARD 1/16 or 1/32
+       and set channel predictor in automatic */
+#if 0
+       switch (guard) {
+
+       case 0:
+       case 1:
+               stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
+               stv0367_writereg(state, R367TER_CHC_CTL, 0x01);
+               break;
+       case 2:
+       case 3:
+               stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
+               stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
+               break;
+
+       default:
+               return FE_TER_SWNOK;
+       }
+#endif
+
+       /*reset fec an reedsolo FOR 367 only*/
+       stv0367_writebits(state, F367TER_RST_SFEC, 1);
+       stv0367_writebits(state, F367TER_RST_REEDSOLO, 1);
+       usleep_range(1000, 2000);
+       stv0367_writebits(state, F367TER_RST_SFEC, 0);
+       stv0367_writebits(state, F367TER_RST_REEDSOLO, 0);
+
+       u_var1 = stv0367_readbits(state, F367TER_LK);
+       u_var2 = stv0367_readbits(state, F367TER_PRF);
+       u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
+       /*      u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */
+
+       wd = stv0367ter_duration(mode, 125, 500, 250);
+       tempo = stv0367ter_duration(mode, 4, 16, 8);
+
+       /*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4))  && (wd>=0)) */
+       while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) {
+               usleep_range(1000 * tempo, 1000 * (tempo + 1));
+               wd -= tempo;
+               u_var1 = stv0367_readbits(state, F367TER_LK);
+               u_var2 = stv0367_readbits(state, F367TER_PRF);
+               u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK);
+               /*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */
+       }
+
+       if (!u_var1)
+               return FE_TER_NOLOCK;
+
+
+       if (!u_var2)
+               return FE_TER_NOPRFOUND;
+
+       if (!u_var3)
+               return FE_TER_NOTPS;
+
+       guard = stv0367_readbits(state, F367TER_SYR_GUARD);
+       stv0367_writereg(state, R367TER_CHC_CTL, 0x11);
+       switch (guard) {
+       case 0:
+       case 1:
+               stv0367_writebits(state, F367TER_AUTO_LE_EN, 0);
+               /*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/
+               stv0367_writebits(state, F367TER_SYR_FILTER, 0);
+               break;
+       case 2:
+       case 3:
+               stv0367_writebits(state, F367TER_AUTO_LE_EN, 1);
+               /*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/
+               stv0367_writebits(state, F367TER_SYR_FILTER, 1);
+               break;
+
+       default:
+               return FE_TER_SWNOK;
+       }
+
+       /* apply Sfec workaround if 8K 64QAM CR!=1/2*/
+       if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) &&
+                       (mode == 1) &&
+                       (stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) {
+               stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0);
+               stv0367_writereg(state, R367TER_SFDLYSETM, 0x60);
+               stv0367_writereg(state, R367TER_SFDLYSETL, 0x0);
+       } else
+               stv0367_writereg(state, R367TER_SFDLYSETH, 0x0);
+
+       wd = stv0367ter_duration(mode, 125, 500, 250);
+       u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
+
+       while ((!u_var4) && (wd >= 0)) {
+               usleep_range(1000 * tempo, 1000 * (tempo + 1));
+               wd -= tempo;
+               u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK);
+       }
+
+       if (!u_var4)
+               return FE_TER_NOLOCK;
+
+       /* for 367 leave COM_N at 0x7 for IQ_mode*/
+       /*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) {
+               tempo=0;
+               while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) &&
+               (stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) {
+                       ChipWaitOrAbort(state,1);
+                       tempo+=1;
+               }
+
+               stv0367_writebits(state,F367TER_COM_N,0x17);
+       } */
+
+       stv0367_writebits(state, F367TER_SYR_TR_DIS, 1);
+
+       dprintk("FE_TER_LOCKOK !!!\n");
+
+       return  FE_TER_LOCKOK;
+
+}
+
+static void stv0367ter_set_ts_mode(struct stv0367_state *state,
+                                       enum stv0367_ts_mode PathTS)
+{
+
+       dprintk("%s:\n", __func__);
+
+       if (state == NULL)
+               return;
+
+       stv0367_writebits(state, F367TER_TS_DIS, 0);
+       switch (PathTS) {
+       default:
+               /*for removing warning :default we can assume in parallel mode*/
+       case STV0367_PARALLEL_PUNCT_CLOCK:
+               stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0);
+               stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0);
+               break;
+       case STV0367_SERIAL_PUNCT_CLOCK:
+               stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1);
+               stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1);
+               break;
+       }
+}
+
+static void stv0367ter_set_clk_pol(struct stv0367_state *state,
+                                       enum stv0367_clk_pol clock)
+{
+
+       dprintk("%s:\n", __func__);
+
+       if (state == NULL)
+               return;
+
+       switch (clock) {
+       case STV0367_RISINGEDGE_CLOCK:
+               stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1);
+               break;
+       case STV0367_FALLINGEDGE_CLOCK:
+               stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
+               break;
+               /*case FE_TER_CLOCK_POLARITY_DEFAULT:*/
+       default:
+               stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0);
+               break;
+       }
+}
+
+#if 0
+static void stv0367ter_core_sw(struct stv0367_state *state)
+{
+
+       dprintk("%s:\n", __func__);
+
+       stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+       stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+       msleep(350);
+}
+#endif
+static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       dprintk("%s:\n", __func__);
+
+       if (standby_on) {
+               stv0367_writebits(state, F367TER_STDBY, 1);
+               stv0367_writebits(state, F367TER_STDBY_FEC, 1);
+               stv0367_writebits(state, F367TER_STDBY_CORE, 1);
+       } else {
+               stv0367_writebits(state, F367TER_STDBY, 0);
+               stv0367_writebits(state, F367TER_STDBY_FEC, 0);
+               stv0367_writebits(state, F367TER_STDBY_CORE, 0);
+       }
+
+       return 0;
+}
+
+static int stv0367ter_sleep(struct dvb_frontend *fe)
+{
+       return stv0367ter_standby(fe, 1);
+}
+
+int stv0367ter_init(struct dvb_frontend *fe)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       int i;
+
+       dprintk("%s:\n", __func__);
+
+       ter_state->pBER = 0;
+
+       for (i = 0; i < STV0367TER_NBREGS; i++)
+               stv0367_writereg(state, def0367ter[i].addr,
+                                       def0367ter[i].value);
+
+       switch (state->config->xtal) {
+               /*set internal freq to 53.125MHz */
+       case 25000000:
+               stv0367_writereg(state, R367TER_PLLMDIV, 0xa);
+               stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
+               stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+               break;
+       default:
+       case 27000000:
+               dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n");
+               stv0367_writereg(state, R367TER_PLLMDIV, 0x1);
+               stv0367_writereg(state, R367TER_PLLNDIV, 0x8);
+               stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+               break;
+       case 30000000:
+               stv0367_writereg(state, R367TER_PLLMDIV, 0xc);
+               stv0367_writereg(state, R367TER_PLLNDIV, 0x55);
+               stv0367_writereg(state, R367TER_PLLSETUP, 0x18);
+               break;
+       }
+
+       stv0367_writereg(state, R367TER_I2CRPT, 0xa0);
+       stv0367_writereg(state, R367TER_ANACTRL, 0x00);
+
+       /*Set TS1 and TS2 to serial or parallel mode */
+       stv0367ter_set_ts_mode(state, state->config->ts_mode);
+       stv0367ter_set_clk_pol(state, state->config->clk_pol);
+
+       state->chip_id = stv0367_readreg(state, R367TER_ID);
+       ter_state->first_lock = 0;
+       ter_state->unlock_counter = 2;
+
+       return 0;
+}
+
+static int stv0367ter_algo(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *param)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       int offset = 0, tempo = 0;
+       u8 u_var;
+       u8 /*constell,*/ counter, tps_rcvd[2];
+       s8 step;
+       s32 timing_offset = 0;
+       u32 trl_nomrate = 0, InternalFreq = 0, temp = 0;
+
+       dprintk("%s:\n", __func__);
+
+       ter_state->frequency = param->frequency;
+       ter_state->force = FE_TER_FORCENONE
+                       + stv0367_readbits(state, F367TER_FORCE) * 2;
+       ter_state->if_iq_mode = state->config->if_iq_mode;
+       switch (state->config->if_iq_mode) {
+       case FE_TER_NORMAL_IF_TUNER:  /* Normal IF mode */
+               dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n");
+               stv0367_writebits(state, F367TER_TUNER_BB, 0);
+               stv0367_writebits(state, F367TER_LONGPATH_IF, 0);
+               stv0367_writebits(state, F367TER_DEMUX_SWAP, 0);
+               break;
+       case FE_TER_LONGPATH_IF_TUNER:  /* Long IF mode */
+               dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n");
+               stv0367_writebits(state, F367TER_TUNER_BB, 0);
+               stv0367_writebits(state, F367TER_LONGPATH_IF, 1);
+               stv0367_writebits(state, F367TER_DEMUX_SWAP, 1);
+               break;
+       case FE_TER_IQ_TUNER:  /* IQ mode */
+               dprintk("ALGO: FE_TER_IQ_TUNER selected\n");
+               stv0367_writebits(state, F367TER_TUNER_BB, 1);
+               stv0367_writebits(state, F367TER_PPM_INVSEL, 0);
+               break;
+       default:
+               printk(KERN_ERR "ALGO: wrong TUNER type selected\n");
+               return -EINVAL;
+       }
+
+       usleep_range(5000, 7000);
+
+       switch (param->inversion) {
+       case INVERSION_AUTO:
+       default:
+               dprintk("%s: inversion AUTO\n", __func__);
+               if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
+                       stv0367_writebits(state, F367TER_IQ_INVERT,
+                                               ter_state->sense);
+               else
+                       stv0367_writebits(state, F367TER_INV_SPECTR,
+                                               ter_state->sense);
+
+               break;
+       case INVERSION_ON:
+       case INVERSION_OFF:
+               if (ter_state->if_iq_mode == FE_TER_IQ_TUNER)
+                       stv0367_writebits(state, F367TER_IQ_INVERT,
+                                               param->inversion);
+               else
+                       stv0367_writebits(state, F367TER_INV_SPECTR,
+                                               param->inversion);
+
+               break;
+       }
+
+       if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) &&
+                               (ter_state->pBW != ter_state->bw)) {
+               stv0367ter_agc_iir_lock_detect_set(state);
+
+               /*set fine agc target to 180 for LPIF or IQ mode*/
+               /* set Q_AGCTarget */
+               stv0367_writebits(state, F367TER_SEL_IQNTAR, 1);
+               stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
+               /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
+
+               /* set Q_AGCTarget */
+               stv0367_writebits(state, F367TER_SEL_IQNTAR, 0);
+               stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB);
+               /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */
+
+               if (!stv0367_iir_filt_init(state, ter_state->bw,
+                                               state->config->xtal))
+                       return -EINVAL;
+               /*set IIR filter once for 6,7 or 8MHz BW*/
+               ter_state->pBW = ter_state->bw;
+
+               stv0367ter_agc_iir_rst(state);
+       }
+
+       if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
+               stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01);
+       else
+               stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00);
+
+       InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000;
+       temp = (int)
+               ((((ter_state->bw * 64 * (1 << 15) * 100)
+                                               / (InternalFreq)) * 10) / 7);
+
+       stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2);
+       temp = temp / 2;
+       stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256);
+       stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256);
+
+       temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 +
+                       stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 +
+                       stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB);
+       temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq)));
+       stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256);
+       stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256);
+       temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 +
+                       stv0367_readbits(state, F367TER_GAIN_SRC_LO);
+
+       temp = (int)
+               ((InternalFreq - state->config->if_khz) * (1 << 16)
+                                                       / (InternalFreq));
+
+       dprintk("DEROT temp=0x%x\n", temp);
+       stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256);
+       stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256);
+
+       ter_state->echo_pos = 0;
+       ter_state->ucblocks = 0; /* liplianin */
+       ter_state->pBER = 0; /* liplianin */
+       stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos);
+
+       if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK)
+               return 0;
+
+       ter_state->state = FE_TER_LOCKOK;
+       /* update results */
+       tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2);
+       tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3);
+
+       ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE);
+       ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD);
+
+       ter_state->first_lock = 1; /* we know sense now :) */
+
+       ter_state->agc_val =
+                       (stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) +
+                       (stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) +
+                       stv0367_readbits(state, F367TER_AGC2_VAL_LO) +
+                       (stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8);
+
+       /* Carrier offset calculation */
+       stv0367_writebits(state, F367TER_FREEZE, 1);
+       offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ;
+       offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8);
+       offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO));
+       stv0367_writebits(state, F367TER_FREEZE, 0);
+       if (offset > 8388607)
+               offset -= 16777216;
+
+       offset = offset * 2 / 16384;
+
+       if (ter_state->mode == FE_TER_MODE_2K)
+               offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/
+       else if (ter_state->mode == FE_TER_MODE_4K)
+               offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/
+       else  if (ter_state->mode == FE_TER_MODE_8K)
+               offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/
+
+       if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) {
+               if ((stv0367_readbits(state, F367TER_INV_SPECTR) ==
+                               (stv0367_readbits(state,
+                                       F367TER_STATUS_INV_SPECRUM) == 1)))
+                       offset = offset * -1;
+       }
+
+       if (ter_state->bw == 6)
+               offset = (offset * 6) / 8;
+       else if (ter_state->bw == 7)
+               offset = (offset * 7) / 8;
+
+       ter_state->frequency += offset;
+
+       tempo = 10;  /* exit even if timing_offset stays null */
+       while ((timing_offset == 0) && (tempo > 0)) {
+               usleep_range(10000, 20000);     /*was 20ms  */
+               /* fine tuning of timing offset if required */
+               timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO)
+                               + 256 * stv0367_readbits(state,
+                                                       F367TER_TRL_TOFFSET_HI);
+               if (timing_offset >= 32768)
+                       timing_offset -= 65536;
+               trl_nomrate = (512 * stv0367_readbits(state,
+                                                       F367TER_TRL_NOMRATE_HI)
+                       + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2
+                       + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB));
+
+               timing_offset = ((signed)(1000000 / trl_nomrate) *
+                                                       timing_offset) / 2048;
+               tempo--;
+       }
+
+       if (timing_offset <= 0) {
+               timing_offset = (timing_offset - 11) / 22;
+               step = -1;
+       } else {
+               timing_offset = (timing_offset + 11) / 22;
+               step = 1;
+       }
+
+       for (counter = 0; counter < abs(timing_offset); counter++) {
+               trl_nomrate += step;
+               stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB,
+                                               trl_nomrate % 2);
+               stv0367_writebits(state, F367TER_TRL_NOMRATE_LO,
+                                               trl_nomrate / 2);
+               usleep_range(1000, 2000);
+       }
+
+       usleep_range(5000, 6000);
+       /* unlocks could happen in case of trl centring big step,
+       then a core off/on restarts demod */
+       u_var = stv0367_readbits(state, F367TER_LK);
+
+       if (!u_var) {
+               stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+               msleep(20);
+               stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+       }
+
+       return 0;
+}
+
+static int stv0367ter_set_frontend(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *param)
+{
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+
+       /*u8 trials[2]; */
+       s8 num_trials, index;
+       u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF };
+
+       stv0367ter_init(fe);
+
+       if (fe->ops.tuner_ops.set_params) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       switch (op->transmission_mode) {
+       default:
+       case TRANSMISSION_MODE_AUTO:
+       case TRANSMISSION_MODE_2K:
+               ter_state->mode = FE_TER_MODE_2K;
+               break;
+/*     case TRANSMISSION_MODE_4K:
+               pLook.mode = FE_TER_MODE_4K;
+               break;*/
+       case TRANSMISSION_MODE_8K:
+               ter_state->mode = FE_TER_MODE_8K;
+               break;
+       }
+
+       switch (op->guard_interval) {
+       default:
+       case GUARD_INTERVAL_1_32:
+       case GUARD_INTERVAL_1_16:
+       case GUARD_INTERVAL_1_8:
+       case GUARD_INTERVAL_1_4:
+               ter_state->guard = op->guard_interval;
+               break;
+       case GUARD_INTERVAL_AUTO:
+               ter_state->guard = GUARD_INTERVAL_1_32;
+               break;
+       }
+
+       switch (op->bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               ter_state->bw = FE_TER_CHAN_BW_6M;
+               break;
+       case BANDWIDTH_7_MHZ:
+               ter_state->bw = FE_TER_CHAN_BW_7M;
+               break;
+       case BANDWIDTH_8_MHZ:
+       default:
+               ter_state->bw = FE_TER_CHAN_BW_8M;
+       }
+
+       ter_state->hierarchy = FE_TER_HIER_NONE;
+
+       switch (param->inversion) {
+       case INVERSION_OFF:
+       case INVERSION_ON:
+               num_trials = 1;
+               break;
+       default:
+               num_trials = 2;
+               if (ter_state->first_lock)
+                       num_trials = 1;
+               break;
+       }
+
+       ter_state->state = FE_TER_NOLOCK;
+       index = 0;
+
+       while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) {
+               if (!ter_state->first_lock) {
+                       if (param->inversion == INVERSION_AUTO)
+                               ter_state->sense = SenseTrials[index];
+
+               }
+               stv0367ter_algo(fe,/* &pLook, result,*/ param);
+
+               if ((ter_state->state == FE_TER_LOCKOK) &&
+                               (param->inversion == INVERSION_AUTO) &&
+                                                               (index == 1)) {
+                       /* invert spectrum sense */
+                       SenseTrials[index] = SenseTrials[0];
+                       SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2;
+               }
+
+               index++;
+       }
+
+       return 0;
+}
+
+static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       u32 errs = 0;
+
+       /*wait for counting completion*/
+       if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) {
+               errs =
+                       ((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
+                       * (1 << 16))
+                       + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
+                       * (1 << 8))
+                       + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
+               ter_state->ucblocks = errs;
+       }
+
+       (*ucblocks) = ter_state->ucblocks;
+
+       return 0;
+}
+
+static int stv0367ter_get_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *param)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       struct dvb_ofdm_parameters *op = &param->u.ofdm;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       int error = 0;
+       enum stv0367_ter_mode mode;
+       int constell = 0,/* snr = 0,*/ Data = 0;
+
+       param->frequency = stv0367_get_tuner_freq(fe);
+       if ((int)param->frequency < 0)
+               param->frequency = c->frequency;
+
+       constell = stv0367_readbits(state, F367TER_TPS_CONST);
+       if (constell == 0)
+               op->constellation = QPSK;
+       else if (constell == 1)
+               op->constellation = QAM_16;
+       else
+               op->constellation = QAM_64;
+
+       param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR);
+
+       /* Get the Hierarchical mode */
+       Data = stv0367_readbits(state, F367TER_TPS_HIERMODE);
+
+       switch (Data) {
+       case 0:
+               op->hierarchy_information = HIERARCHY_NONE;
+               break;
+       case 1:
+               op->hierarchy_information = HIERARCHY_1;
+               break;
+       case 2:
+               op->hierarchy_information = HIERARCHY_2;
+               break;
+       case 3:
+               op->hierarchy_information = HIERARCHY_4;
+               break;
+       default:
+               op->hierarchy_information = HIERARCHY_AUTO;
+               break; /* error */
+       }
+
+       /* Get the FEC Rate */
+       if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO)
+               Data = stv0367_readbits(state, F367TER_TPS_LPCODE);
+       else
+               Data = stv0367_readbits(state, F367TER_TPS_HPCODE);
+
+       switch (Data) {
+       case 0:
+               op->code_rate_HP = FEC_1_2;
+               break;
+       case 1:
+               op->code_rate_HP = FEC_2_3;
+               break;
+       case 2:
+               op->code_rate_HP = FEC_3_4;
+               break;
+       case 3:
+               op->code_rate_HP = FEC_5_6;
+               break;
+       case 4:
+               op->code_rate_HP = FEC_7_8;
+               break;
+       default:
+               op->code_rate_HP = FEC_AUTO;
+               break; /* error */
+       }
+
+       mode = stv0367_readbits(state, F367TER_SYR_MODE);
+
+       switch (mode) {
+       case FE_TER_MODE_2K:
+               op->transmission_mode = TRANSMISSION_MODE_2K;
+               break;
+/*     case FE_TER_MODE_4K:
+               op->transmission_mode = TRANSMISSION_MODE_4K;
+               break;*/
+       case FE_TER_MODE_8K:
+               op->transmission_mode = TRANSMISSION_MODE_8K;
+               break;
+       default:
+               op->transmission_mode = TRANSMISSION_MODE_AUTO;
+       }
+
+       op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD);
+
+       return error;
+}
+
+static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       u32 snru32 = 0;
+       int cpt = 0;
+       u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG);
+
+       while (cpt < 10) {
+               usleep_range(2000, 3000);
+               if (cut == 0x50) /*cut 1.0 cut 1.1*/
+                       snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4;
+               else /*cu2.0*/
+                       snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR);
+
+               cpt++;
+       }
+
+       snru32 /= 10;/*average on 10 values*/
+
+       *snr = snru32 / 1000;
+
+       return 0;
+}
+
+#if 0
+static int stv0367ter_status(struct dvb_frontend *fe)
+{
+
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       int locked = FALSE;
+
+       locked = (stv0367_readbits(state, F367TER_LK));
+       if (!locked)
+               ter_state->unlock_counter += 1;
+       else
+               ter_state->unlock_counter = 0;
+
+       if (ter_state->unlock_counter > 2) {
+               if (!stv0367_readbits(state, F367TER_TPS_LOCK) ||
+                               (!stv0367_readbits(state, F367TER_LK))) {
+                       stv0367_writebits(state, F367TER_CORE_ACTIVE, 0);
+                       usleep_range(2000, 3000);
+                       stv0367_writebits(state, F367TER_CORE_ACTIVE, 1);
+                       msleep(350);
+                       locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) &&
+                                       (stv0367_readbits(state, F367TER_LK));
+               }
+
+       }
+
+       return locked;
+}
+#endif
+static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       dprintk("%s:\n", __func__);
+
+       *status = 0;
+
+       if (stv0367_readbits(state, F367TER_LK)) {
+               *status |= FE_HAS_LOCK;
+               dprintk("%s: stv0367 has locked\n", __func__);
+       }
+
+       return 0;
+}
+
+static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367ter_state *ter_state = state->ter_state;
+       u32 Errors = 0, tber = 0, temporary = 0;
+       int abc = 0, def = 0;
+
+
+       /*wait for counting completion*/
+       if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0)
+               Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT)
+                       * (1 << 16))
+                       + ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI)
+                       * (1 << 8))
+                       + ((u32)stv0367_readbits(state,
+                                               F367TER_SFEC_ERR_CNT_LO));
+       /*measurement not completed, load previous value*/
+       else {
+               tber = ter_state->pBER;
+               return 0;
+       }
+
+       abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE);
+       def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT);
+
+       if (Errors == 0) {
+               tber = 0;
+       } else if (abc == 0x7) {
+               if (Errors <= 4) {
+                       temporary = (Errors * 1000000000) / (8 * (1 << 14));
+                       temporary =  temporary;
+               } else if (Errors <= 42) {
+                       temporary = (Errors * 100000000) / (8 * (1 << 14));
+                       temporary = temporary * 10;
+               } else if (Errors <= 429) {
+                       temporary = (Errors * 10000000) / (8 * (1 << 14));
+                       temporary = temporary * 100;
+               } else if (Errors <= 4294) {
+                       temporary = (Errors * 1000000) / (8 * (1 << 14));
+                       temporary = temporary * 1000;
+               } else if (Errors <= 42949) {
+                       temporary = (Errors * 100000) / (8 * (1 << 14));
+                       temporary = temporary * 10000;
+               } else if (Errors <= 429496) {
+                       temporary = (Errors * 10000) / (8 * (1 << 14));
+                       temporary = temporary * 100000;
+               } else { /*if (Errors<4294967) 2^22 max error*/
+                       temporary = (Errors * 1000) / (8 * (1 << 14));
+                       temporary = temporary * 100000; /* still to *10 */
+               }
+
+               /* Byte error*/
+               if (def == 2)
+                       /*tber=Errors/(8*(1 <<14));*/
+                       tber = temporary;
+               else if (def == 3)
+                       /*tber=Errors/(8*(1 <<16));*/
+                       tber = temporary / 4;
+               else if (def == 4)
+                       /*tber=Errors/(8*(1 <<18));*/
+                       tber = temporary / 16;
+               else if (def == 5)
+                       /*tber=Errors/(8*(1 <<20));*/
+                       tber = temporary / 64;
+               else if (def == 6)
+                       /*tber=Errors/(8*(1 <<22));*/
+                       tber = temporary / 256;
+               else
+                       /* should not pass here*/
+                       tber = 0;
+
+               if ((Errors < 4294967) && (Errors > 429496))
+                       tber *= 10;
+
+       }
+
+       /* save actual value */
+       ter_state->pBER = tber;
+
+       (*ber) = tber;
+
+       return 0;
+}
+#if 0
+static u32 stv0367ter_get_per(struct stv0367_state *state)
+{
+       struct stv0367ter_state *ter_state = state->ter_state;
+       u32 Errors = 0, Per = 0, temporary = 0;
+       int abc = 0, def = 0, cpt = 0;
+
+       while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) &&
+                       (cpt < 400)) || ((Errors == 0) && (cpt < 400))) {
+               usleep_range(1000, 2000);
+               Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1)
+                       * (1 << 16))
+                       + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI)
+                       * (1 << 8))
+                       + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO));
+               cpt++;
+       }
+       abc = stv0367_readbits(state, F367TER_ERR_SRC1);
+       def = stv0367_readbits(state, F367TER_NUM_EVT1);
+
+       if (Errors == 0)
+               Per = 0;
+       else if (abc == 0x9) {
+               if (Errors <= 4) {
+                       temporary = (Errors * 1000000000) / (8 * (1 << 8));
+                       temporary =  temporary;
+               } else if (Errors <= 42) {
+                       temporary = (Errors * 100000000) / (8 * (1 << 8));
+                       temporary = temporary * 10;
+               } else if (Errors <= 429) {
+                       temporary = (Errors * 10000000) / (8 * (1 << 8));
+                       temporary = temporary * 100;
+               } else if (Errors <= 4294) {
+                       temporary = (Errors * 1000000) / (8 * (1 << 8));
+                       temporary = temporary * 1000;
+               } else if (Errors <= 42949) {
+                       temporary = (Errors * 100000) / (8 * (1 << 8));
+                       temporary = temporary * 10000;
+               } else { /*if(Errors<=429496)  2^16 errors max*/
+                       temporary = (Errors * 10000) / (8 * (1 << 8));
+                       temporary = temporary * 100000;
+               }
+
+               /* pkt error*/
+               if (def == 2)
+                       /*Per=Errors/(1 << 8);*/
+                       Per = temporary;
+               else if (def == 3)
+                       /*Per=Errors/(1 << 10);*/
+                       Per = temporary / 4;
+               else if (def == 4)
+                       /*Per=Errors/(1 << 12);*/
+                       Per = temporary / 16;
+               else if (def == 5)
+                       /*Per=Errors/(1 << 14);*/
+                       Per = temporary / 64;
+               else if (def == 6)
+                       /*Per=Errors/(1 << 16);*/
+                       Per = temporary / 256;
+               else
+                       Per = 0;
+
+       }
+       /* save actual value */
+       ter_state->pPER = Per;
+
+       return Per;
+}
+#endif
+static int stv0367_get_tune_settings(struct dvb_frontend *fe,
+                                       struct dvb_frontend_tune_settings
+                                       *fe_tune_settings)
+{
+       fe_tune_settings->min_delay_ms = 1000;
+       fe_tune_settings->step_size = 0;
+       fe_tune_settings->max_drift = 0;
+
+       return 0;
+}
+
+static void stv0367_release(struct dvb_frontend *fe)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       kfree(state->ter_state);
+       kfree(state->cab_state);
+       kfree(state);
+}
+
+static struct dvb_frontend_ops stv0367ter_ops = {
+       .info = {
+               .name                   = "ST STV0367 DVB-T",
+               .type                   = FE_OFDM,
+               .frequency_min          = 47000000,
+               .frequency_max          = 862000000,
+               .frequency_stepsize     = 15625,
+               .frequency_tolerance    = 0,
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                       FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_INVERSION_AUTO |
+                       FE_CAN_MUTE_TS
+       },
+       .release = stv0367_release,
+       .init = stv0367ter_init,
+       .sleep = stv0367ter_sleep,
+       .i2c_gate_ctrl = stv0367ter_gate_ctrl,
+       .set_frontend = stv0367ter_set_frontend,
+       .get_frontend = stv0367ter_get_frontend,
+       .get_tune_settings = stv0367_get_tune_settings,
+       .read_status = stv0367ter_read_status,
+       .read_ber = stv0367ter_read_ber,/* too slow */
+/*     .read_signal_strength = stv0367_read_signal_strength,*/
+       .read_snr = stv0367ter_read_snr,
+       .read_ucblocks = stv0367ter_read_ucblocks,
+};
+
+struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+                                  struct i2c_adapter *i2c)
+{
+       struct stv0367_state *state = NULL;
+       struct stv0367ter_state *ter_state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+       ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL);
+       if (ter_state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       state->config = config;
+       state->ter_state = ter_state;
+       state->fe.ops = stv0367ter_ops;
+       state->fe.demodulator_priv = state;
+       state->chip_id = stv0367_readreg(state, 0xf000);
+
+       dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
+
+       /* check if the demod is there */
+       if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
+               goto error;
+
+       return &state->fe;
+
+error:
+       kfree(ter_state);
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stv0367ter_attach);
+
+static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       dprintk("%s:\n", __func__);
+
+       stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0);
+
+       return 0;
+}
+
+static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       u32 mclk_Hz = 0;/* master clock frequency (Hz) */
+       u32 M, N, P;
+
+
+       if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) {
+               N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV);
+               if (N == 0)
+                       N = N + 1;
+
+               M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV);
+               if (M == 0)
+                       M = M + 1;
+
+               P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV);
+
+               if (P > 5)
+                       P = 5;
+
+               mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P));
+               dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n",
+                                                               mclk_Hz);
+       } else
+               mclk_Hz = ExtClk_Hz;
+
+       dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz);
+
+       return mclk_Hz;
+}
+
+static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz)
+{
+       u32 ADCClk_Hz = ExtClk_Hz;
+
+       ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz);
+
+       return ADCClk_Hz;
+}
+
+enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state,
+                                       u32 SymbolRate,
+                                       enum stv0367cab_mod QAMSize)
+{
+       /* Set QAM size */
+       stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize);
+
+       /* Set Registers settings specific to the QAM size */
+       switch (QAMSize) {
+       case FE_CAB_MOD_QAM4:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               break;
+       case FE_CAB_MOD_QAM16:
+               stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64);
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
+               stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+               stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a);
+               break;
+       case FE_CAB_MOD_QAM32:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e);
+               stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
+               stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
+               stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+               break;
+       case FE_CAB_MOD_QAM64:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82);
+               stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
+               if (SymbolRate > 45000000) {
+                       stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0);
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5);
+               } else if (SymbolRate > 25000000) {
+                       stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
+               } else {
+                       stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+               }
+               stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+               stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99);
+               break;
+       case FE_CAB_MOD_QAM128:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76);
+               stv0367_writereg(state, R367CAB_FSM_STATE, 0x90);
+               stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1);
+               if (SymbolRate > 45000000)
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+               else if (SymbolRate > 25000000)
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6);
+               else
+                       stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97);
+
+               stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f);
+               stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+               break;
+       case FE_CAB_MOD_QAM256:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94);
+               stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a);
+               stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0);
+               if (SymbolRate > 45000000)
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+               else if (SymbolRate > 25000000)
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1);
+               else
+                       stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1);
+
+               stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85);
+               stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40);
+               stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7);
+               break;
+       case FE_CAB_MOD_QAM512:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               break;
+       case FE_CAB_MOD_QAM1024:
+               stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00);
+               break;
+       default:
+               break;
+       }
+
+       return QAMSize;
+}
+
+static u32 stv0367cab_set_derot_freq(struct stv0367_state *state,
+                                       u32 adc_hz, s32 derot_hz)
+{
+       u32 sampled_if = 0;
+       u32 adc_khz;
+
+       adc_khz = adc_hz / 1000;
+
+       dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz);
+
+       if (adc_khz != 0) {
+               if (derot_hz < 1000000)
+                       derot_hz = adc_hz / 4; /* ZIF operation */
+               if (derot_hz > adc_hz)
+                       derot_hz = derot_hz - adc_hz;
+               sampled_if = (u32)derot_hz / 1000;
+               sampled_if *= 32768;
+               sampled_if /= adc_khz;
+               sampled_if *= 256;
+       }
+
+       if (sampled_if > 8388607)
+               sampled_if = 8388607;
+
+       dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if);
+
+       stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if);
+       stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8));
+       stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16));
+
+       return derot_hz;
+}
+
+static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz)
+{
+       u32 sampled_if;
+
+       sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) +
+                       (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) +
+                       (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16);
+
+       sampled_if /= 256;
+       sampled_if *= (adc_hz / 1000);
+       sampled_if += 1;
+       sampled_if /= 32768;
+
+       return sampled_if;
+}
+
+static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz,
+                       u32 mclk_hz, u32 SymbolRate,
+                       enum stv0367cab_mod QAMSize)
+{
+       u32 QamSizeCorr = 0;
+       u32 u32_tmp = 0, u32_tmp1 = 0;
+       u32 adp_khz;
+
+       dprintk("%s:\n", __func__);
+
+       /* Set Correction factor of SRC gain */
+       switch (QAMSize) {
+       case FE_CAB_MOD_QAM4:
+               QamSizeCorr = 1110;
+               break;
+       case FE_CAB_MOD_QAM16:
+               QamSizeCorr = 1032;
+               break;
+       case FE_CAB_MOD_QAM32:
+               QamSizeCorr =  954;
+               break;
+       case FE_CAB_MOD_QAM64:
+               QamSizeCorr =  983;
+               break;
+       case FE_CAB_MOD_QAM128:
+               QamSizeCorr =  957;
+               break;
+       case FE_CAB_MOD_QAM256:
+               QamSizeCorr =  948;
+               break;
+       case FE_CAB_MOD_QAM512:
+               QamSizeCorr =    0;
+               break;
+       case FE_CAB_MOD_QAM1024:
+               QamSizeCorr =  944;
+               break;
+       default:
+               break;
+       }
+
+       /* Transfer ratio calculation */
+       if (adc_hz != 0) {
+               u32_tmp = 256 * SymbolRate;
+               u32_tmp = u32_tmp / adc_hz;
+       }
+       stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp);
+
+       /* Symbol rate and SRC gain calculation */
+       adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
+       if (adp_khz != 0) {
+               u32_tmp = SymbolRate;
+               u32_tmp1 = SymbolRate;
+
+               if (u32_tmp < 2097152) { /* 2097152 = 2^21 */
+                       /* Symbol rate calculation */
+                       u32_tmp *= 2048; /* 2048 = 2^11 */
+                       u32_tmp = u32_tmp / adp_khz;
+                       u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */
+                       u32_tmp /= 125 ; /* 125 = 1000/2^3 */
+                       u32_tmp = u32_tmp * 8; /* 8 = 2^3 */
+
+                       /* SRC Gain Calculation */
+                       u32_tmp1 *= 2048; /* *2*2^10 */
+                       u32_tmp1 /= 439; /* *2/878 */
+                       u32_tmp1 *= 256; /* *2^8 */
+                       u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+                       u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+                       u32_tmp1 = u32_tmp1 / 10000000;
+
+               } else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */
+                       /* Symbol rate calculation */
+                       u32_tmp *= 1024 ; /* 1024 = 2**10 */
+                       u32_tmp = u32_tmp / adp_khz;
+                       u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
+                       u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+                       u32_tmp = u32_tmp * 16; /* 16 = 2**4 */
+
+                       /* SRC Gain Calculation */
+                       u32_tmp1 *= 1024; /* *2*2^9 */
+                       u32_tmp1 /= 439; /* *2/878 */
+                       u32_tmp1 *= 256; /* *2^8 */
+                       u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/
+                       u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+                       u32_tmp1 = u32_tmp1 / 5000000;
+               } else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */
+                       /* Symbol rate calculation */
+                       u32_tmp *= 512 ; /* 512 = 2**9 */
+                       u32_tmp = u32_tmp / adp_khz;
+                       u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */
+                       u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+                       u32_tmp = u32_tmp * 32; /* 32 = 2**5 */
+
+                       /* SRC Gain Calculation */
+                       u32_tmp1 *= 512; /* *2*2^8 */
+                       u32_tmp1 /= 439; /* *2/878 */
+                       u32_tmp1 *= 256; /* *2^8 */
+                       u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+                       u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+                       u32_tmp1 = u32_tmp1 / 2500000;
+               } else {
+                       /* Symbol rate calculation */
+                       u32_tmp *= 256 ; /* 256 = 2**8 */
+                       u32_tmp = u32_tmp / adp_khz;
+                       u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */
+                       u32_tmp /= 125 ; /* 125 = 1000/2**3 */
+                       u32_tmp = u32_tmp * 64; /* 64 = 2**6 */
+
+                       /* SRC Gain Calculation */
+                       u32_tmp1 *= 256; /* 2*2^7 */
+                       u32_tmp1 /= 439; /* *2/878 */
+                       u32_tmp1 *= 256; /* *2^8 */
+                       u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */
+                       u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */
+                       u32_tmp1 = u32_tmp1 / 1250000;
+               }
+       }
+#if 0
+       /* Filters' coefficients are calculated and written
+       into registers only if the filters are enabled */
+       if (stv0367_readbits(state, F367CAB_ADJ_EN)) {
+               stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz,
+                                                               SymbolRate);
+               /* AllPass filter must be enabled
+               when the adjacents filter is used */
+               stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1);
+               stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate);
+       } else
+               /* AllPass filter must be disabled
+               when the adjacents filter is not used */
+#endif
+       stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
+
+       stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp);
+       stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8));
+       stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16));
+       stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24));
+
+       stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff);
+       stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff);
+
+       return SymbolRate ;
+}
+
+static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz)
+{
+       u32 regsym;
+       u32 adp_khz;
+
+       regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) +
+               (stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) +
+               (stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) +
+               (stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24);
+
+       adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */
+
+       if (regsym < 134217728) {               /* 134217728L = 2**27*/
+               regsym = regsym * 32;           /* 32 = 2**5 */
+               regsym = regsym / 32768;        /* 32768L = 2**15 */
+               regsym = adp_khz * regsym;      /* AdpClk in kHz */
+               regsym = regsym / 128;          /* 128 = 2**7 */
+               regsym *= 125 ;                 /* 125 = 1000/2**3 */
+               regsym /= 2048 ;                /* 2048 = 2**11 */
+       } else if (regsym < 268435456) {        /* 268435456L = 2**28 */
+               regsym = regsym * 16;           /* 16 = 2**4 */
+               regsym = regsym / 32768;        /* 32768L = 2**15 */
+               regsym = adp_khz * regsym;      /* AdpClk in kHz */
+               regsym = regsym / 128;          /* 128 = 2**7 */
+               regsym *= 125 ;                 /* 125 = 1000/2**3*/
+               regsym /= 1024 ;                /* 256 = 2**10*/
+       } else if (regsym < 536870912) {        /* 536870912L = 2**29*/
+               regsym = regsym * 8;            /* 8 = 2**3 */
+               regsym = regsym / 32768;        /* 32768L = 2**15 */
+               regsym = adp_khz * regsym;      /* AdpClk in kHz */
+               regsym = regsym / 128;          /* 128 = 2**7 */
+               regsym *= 125 ;                 /* 125 = 1000/2**3 */
+               regsym /= 512 ;                 /* 128 = 2**9 */
+       } else {
+               regsym = regsym * 4;            /* 4 = 2**2 */
+               regsym = regsym / 32768;        /* 32768L = 2**15 */
+               regsym = adp_khz * regsym;      /* AdpClk in kHz */
+               regsym = regsym / 128;          /* 128 = 2**7 */
+               regsym *= 125 ;                 /* 125 = 1000/2**3 */
+               regsym /= 256 ;                 /* 64 = 2**8 */
+       }
+
+       return regsym;
+}
+
+static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       dprintk("%s:\n", __func__);
+
+       *status = 0;
+
+       if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) {
+               *status |= FE_HAS_LOCK;
+               dprintk("%s: stv0367 has locked\n", __func__);
+       }
+
+       return 0;
+}
+
+static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       dprintk("%s:\n", __func__);
+
+       if (standby_on) {
+               stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03);
+               stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01);
+               stv0367_writebits(state, F367CAB_STDBY, 1);
+               stv0367_writebits(state, F367CAB_STDBY_CORE, 1);
+               stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0);
+               stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0);
+               stv0367_writebits(state, F367CAB_POFFQ, 1);
+               stv0367_writebits(state, F367CAB_POFFI, 1);
+       } else {
+               stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00);
+               stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00);
+               stv0367_writebits(state, F367CAB_STDBY, 0);
+               stv0367_writebits(state, F367CAB_STDBY_CORE, 0);
+               stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1);
+               stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1);
+               stv0367_writebits(state, F367CAB_POFFQ, 0);
+               stv0367_writebits(state, F367CAB_POFFI, 0);
+       }
+
+       return 0;
+}
+
+static int stv0367cab_sleep(struct dvb_frontend *fe)
+{
+       return stv0367cab_standby(fe, 1);
+}
+
+int stv0367cab_init(struct dvb_frontend *fe)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367cab_state *cab_state = state->cab_state;
+       int i;
+
+       dprintk("%s:\n", __func__);
+
+       for (i = 0; i < STV0367CAB_NBREGS; i++)
+               stv0367_writereg(state, def0367cab[i].addr,
+                                               def0367cab[i].value);
+
+       switch (state->config->ts_mode) {
+       case STV0367_DVBCI_CLOCK:
+               dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n");
+               stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03);
+               break;
+       case STV0367_SERIAL_PUNCT_CLOCK:
+       case STV0367_SERIAL_CONT_CLOCK:
+               stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01);
+               break;
+       case STV0367_PARALLEL_PUNCT_CLOCK:
+       case STV0367_OUTPUTMODE_DEFAULT:
+               stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00);
+               break;
+       }
+
+       switch (state->config->clk_pol) {
+       case STV0367_RISINGEDGE_CLOCK:
+               stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00);
+               break;
+       case STV0367_FALLINGEDGE_CLOCK:
+       case STV0367_CLOCKPOLARITY_DEFAULT:
+               stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01);
+               break;
+       }
+
+       stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00);
+
+       stv0367_writebits(state, F367CAB_CT_NBST, 0x01);
+
+       stv0367_writebits(state, F367CAB_TS_SWAP, 0x01);
+
+       stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00);
+
+       stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */
+
+       cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal);
+       cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal);
+
+       return 0;
+}
+static
+enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
+                               struct dvb_frontend_parameters *param)
+{
+       struct dvb_qam_parameters *op = &param->u.qam;
+       struct stv0367cab_state *cab_state = state->cab_state;
+       enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC;
+       u32     QAMFEC_Lock, QAM_Lock, u32_tmp,
+               LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols,
+               CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut;
+       u8      TrackAGCAccum;
+       s32     tmp;
+
+       dprintk("%s:\n", __func__);
+
+       /* Timeouts calculation */
+       /* A max lock time of 25 ms is allowed for delayed AGC */
+       AGCTimeOut = 25;
+       /* 100000 symbols needed by the TRL as a maximum value */
+       TRLTimeOut = 100000000 / op->symbol_rate;
+       /* CRLSymbols is the needed number of symbols to achieve a lock
+          within [-4%, +4%] of the symbol rate.
+          CRL timeout is calculated
+          for a lock within [-search_range, +search_range].
+          EQL timeout can be changed depending on
+          the micro-reflections we want to handle.
+          A characterization must be performed
+          with these echoes to get new timeout values.
+       */
+       switch (op->modulation) {
+       case QAM_16:
+               CRLSymbols = 150000;
+               EQLTimeOut = 100;
+               break;
+       case QAM_32:
+               CRLSymbols = 250000;
+               EQLTimeOut = 100;
+               break;
+       case QAM_64:
+               CRLSymbols = 200000;
+               EQLTimeOut = 100;
+               break;
+       case QAM_128:
+               CRLSymbols = 250000;
+               EQLTimeOut = 100;
+               break;
+       case QAM_256:
+               CRLSymbols = 250000;
+               EQLTimeOut = 100;
+               break;
+       default:
+               CRLSymbols = 200000;
+               EQLTimeOut = 100;
+               break;
+       }
+#if 0
+       if (pIntParams->search_range < 0) {
+               CRLTimeOut = (25 * CRLSymbols *
+                               (-pIntParams->search_range / 1000)) /
+                                       (pIntParams->symbol_rate / 1000);
+       } else
+#endif
+       CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) /
+                                       (op->symbol_rate / 1000);
+
+       CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate;
+       /* Timeouts below 50ms are coerced */
+       if (CRLTimeOut < 50)
+               CRLTimeOut = 50;
+       /* A maximum of 100 TS packets is needed to get FEC lock even in case
+       the spectrum inversion needs to be changed.
+          This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps
+       */
+       FECTimeOut = 20;
+       DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut;
+
+       dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut);
+
+       /* Reset the TRL to ensure nothing starts until the
+          AGC is stable which ensures a better lock time
+       */
+       stv0367_writereg(state, R367CAB_CTRL_1, 0x04);
+       /* Set AGC accumulation time to minimum and lock threshold to maximum
+       in order to speed up the AGC lock */
+       TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL);
+       stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0);
+       /* Modulus Mapper is disabled */
+       stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0);
+       /* Disable the sweep function */
+       stv0367_writebits(state, F367CAB_SWEEP_EN, 0);
+       /* The sweep function is never used, Sweep rate must be set to 0 */
+       /* Set the derotator frequency in Hz */
+       stv0367cab_set_derot_freq(state, cab_state->adc_clk,
+               (1000 * (s32)state->config->if_khz + cab_state->derot_offset));
+       /* Disable the Allpass Filter when the symbol rate is out of range */
+       if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) {
+               stv0367_writebits(state, F367CAB_ADJ_EN, 0);
+               stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0);
+       }
+#if 0
+       /* Check if the tuner is locked */
+       tuner_lock = stv0367cab_tuner_get_status(fe);
+       if (tuner_lock == 0)
+               return FE_367CAB_NOTUNER;
+#endif
+       /* Relase the TRL to start demodulator acquisition */
+       /* Wait for QAM lock */
+       LockTime = 0;
+       stv0367_writereg(state, R367CAB_CTRL_1, 0x00);
+       do {
+               QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS);
+               if ((LockTime >= (DemodTimeOut - EQLTimeOut)) &&
+                                                       (QAM_Lock == 0x04))
+                       /*
+                        * We don't wait longer, the frequency/phase offset
+                        * must be too big
+                        */
+                       LockTime = DemodTimeOut;
+               else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) &&
+                                                       (QAM_Lock == 0x02))
+                       /*
+                        * We don't wait longer, either there is no signal or
+                        * it is not the right symbol rate or it is an analog
+                        * carrier
+                        */
+               {
+                       LockTime = DemodTimeOut;
+                       u32_tmp = stv0367_readbits(state,
+                                               F367CAB_AGC_PWR_WORD_LO) +
+                                       (stv0367_readbits(state,
+                                               F367CAB_AGC_PWR_WORD_ME) << 8) +
+                                       (stv0367_readbits(state,
+                                               F367CAB_AGC_PWR_WORD_HI) << 16);
+                       if (u32_tmp >= 131072)
+                               u32_tmp = 262144 - u32_tmp;
+                       u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state,
+                                                       F367CAB_AGC_IF_BWSEL)));
+
+                       if (u32_tmp < stv0367_readbits(state,
+                                               F367CAB_AGC_PWRREF_LO) +
+                                       256 * stv0367_readbits(state,
+                                               F367CAB_AGC_PWRREF_HI) - 10)
+                               QAM_Lock = 0x0f;
+               } else {
+                       usleep_range(10000, 20000);
+                       LockTime += 10;
+               }
+               dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime);
+               tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
+
+               dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
+
+       } while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) &&
+                                               (LockTime < DemodTimeOut));
+
+       dprintk("QAM_Lock=0x%x\n", QAM_Lock);
+
+       tmp = stv0367_readreg(state, R367CAB_IT_STATUS1);
+       dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp);
+       tmp = stv0367_readreg(state, R367CAB_IT_STATUS2);
+       dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp);
+
+       tmp  = stv0367cab_get_derot_freq(state, cab_state->adc_clk);
+       dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp);
+
+       if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) {
+               /* Wait for FEC lock */
+               LockTime = 0;
+               do {
+                       usleep_range(5000, 7000);
+                       LockTime += 5;
+                       QAMFEC_Lock = stv0367_readbits(state,
+                                                       F367CAB_QAMFEC_LOCK);
+               } while (!QAMFEC_Lock && (LockTime < FECTimeOut));
+       } else
+               QAMFEC_Lock = 0;
+
+       if (QAMFEC_Lock) {
+               signalType = FE_CAB_DATAOK;
+               cab_state->modulation = op->modulation;
+               cab_state->spect_inv = stv0367_readbits(state,
+                                                       F367CAB_QUAD_INV);
+#if 0
+/* not clear for me */
+               if (state->config->if_khz != 0) {
+                       if (state->config->if_khz > cab_state->adc_clk / 1000) {
+                               cab_state->freq_khz =
+                                       FE_Cab_TunerGetFrequency(pIntParams->hTuner)
+                               - stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+                               - cab_state->adc_clk / 1000 + state->config->if_khz;
+                       } else {
+                               cab_state->freq_khz =
+                                               FE_Cab_TunerGetFrequency(pIntParams->hTuner)
+                                               - stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+                                                                               + state->config->if_khz;
+                       }
+               } else {
+                       cab_state->freq_khz =
+                               FE_Cab_TunerGetFrequency(pIntParams->hTuner) +
+                               stv0367cab_get_derot_freq(state,
+                                                       cab_state->adc_clk) -
+                               cab_state->adc_clk / 4000;
+               }
+#endif
+               cab_state->symbol_rate = stv0367cab_GetSymbolRate(state,
+                                                       cab_state->mclk);
+               cab_state->locked = 1;
+
+               /* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/
+       } else {
+               switch (QAM_Lock) {
+               case 1:
+                       signalType = FE_CAB_NOAGC;
+                       break;
+               case 2:
+                       signalType = FE_CAB_NOTIMING;
+                       break;
+               case 3:
+                       signalType = FE_CAB_TIMINGOK;
+                       break;
+               case 4:
+                       signalType = FE_CAB_NOCARRIER;
+                       break;
+               case 5:
+                       signalType = FE_CAB_CARRIEROK;
+                       break;
+               case 7:
+                       signalType = FE_CAB_NOBLIND;
+                       break;
+               case 8:
+                       signalType = FE_CAB_BLINDOK;
+                       break;
+               case 10:
+                       signalType = FE_CAB_NODEMOD;
+                       break;
+               case 11:
+                       signalType = FE_CAB_DEMODOK;
+                       break;
+               case 12:
+                       signalType = FE_CAB_DEMODOK;
+                       break;
+               case 13:
+                       signalType = FE_CAB_NODEMOD;
+                       break;
+               case 14:
+                       signalType = FE_CAB_NOBLIND;
+                       break;
+               case 15:
+                       signalType = FE_CAB_NOSIGNAL;
+                       break;
+               default:
+                       break;
+               }
+
+       }
+
+       /* Set the AGC control values to tracking values */
+       stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum);
+       return signalType;
+}
+
+static int stv0367cab_set_frontend(struct dvb_frontend *fe,
+                               struct dvb_frontend_parameters *param)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367cab_state *cab_state = state->cab_state;
+       struct dvb_qam_parameters *op = &param->u.qam;
+       enum stv0367cab_mod QAMSize = 0;
+
+       dprintk("%s: freq = %d, srate = %d\n", __func__,
+                                       param->frequency, op->symbol_rate);
+
+       cab_state->derot_offset = 0;
+
+       switch (op->modulation) {
+       case QAM_16:
+               QAMSize = FE_CAB_MOD_QAM16;
+               break;
+       case QAM_32:
+               QAMSize = FE_CAB_MOD_QAM32;
+               break;
+       case QAM_64:
+               QAMSize = FE_CAB_MOD_QAM64;
+               break;
+       case QAM_128:
+               QAMSize = FE_CAB_MOD_QAM128;
+               break;
+       case QAM_256:
+               QAMSize = FE_CAB_MOD_QAM256;
+               break;
+       default:
+               break;
+       }
+
+       stv0367cab_init(fe);
+
+       /* Tuner Frequency Setting */
+       if (fe->ops.tuner_ops.set_params) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+               fe->ops.tuner_ops.set_params(fe, param);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+
+       stv0367cab_SetQamSize(
+                       state,
+                       op->symbol_rate,
+                       QAMSize);
+
+       stv0367cab_set_srate(state,
+                       cab_state->adc_clk,
+                       cab_state->mclk,
+                       op->symbol_rate,
+                       QAMSize);
+       /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */
+       cab_state->state = stv0367cab_algo(state, param);
+       return 0;
+}
+
+static int stv0367cab_get_frontend(struct dvb_frontend *fe,
+                                 struct dvb_frontend_parameters *param)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       struct stv0367cab_state *cab_state = state->cab_state;
+       struct dvb_qam_parameters *op = &param->u.qam;
+
+       enum stv0367cab_mod QAMSize;
+
+       dprintk("%s:\n", __func__);
+
+       op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk);
+
+       QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
+       switch (QAMSize) {
+       case FE_CAB_MOD_QAM16:
+               op->modulation = QAM_16;
+               break;
+       case FE_CAB_MOD_QAM32:
+               op->modulation = QAM_32;
+               break;
+       case FE_CAB_MOD_QAM64:
+               op->modulation = QAM_64;
+               break;
+       case FE_CAB_MOD_QAM128:
+               op->modulation = QAM_128;
+               break;
+       case QAM_256:
+               op->modulation = QAM_256;
+               break;
+       default:
+               break;
+       }
+
+       param->frequency = stv0367_get_tuner_freq(fe);
+
+       dprintk("%s: tuner frequency = %d\n", __func__, param->frequency);
+
+       if (state->config->if_khz == 0) {
+               param->frequency +=
+                       (stv0367cab_get_derot_freq(state, cab_state->adc_clk) -
+                       cab_state->adc_clk / 4000);
+               return 0;
+       }
+
+       if (state->config->if_khz > cab_state->adc_clk / 1000)
+               param->frequency += (state->config->if_khz
+                       - stv0367cab_get_derot_freq(state, cab_state->adc_clk)
+                       - cab_state->adc_clk / 1000);
+       else
+               param->frequency += (state->config->if_khz
+                       - stv0367cab_get_derot_freq(state, cab_state->adc_clk));
+
+       return 0;
+}
+
+#if 0
+void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize,
+                       u32 symbol_rate, FE_367qam_Monitor *Monitor_results)
+{
+       stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results);
+       stv0367cab_GetPacketsCount(state, Monitor_results);
+
+       return;
+}
+
+static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       return 0;
+}
+#endif
+static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state)
+{
+       s32 rfLevel = 0;
+       s32 RfAgcPwm = 0, IfAgcPwm = 0;
+       u8 i;
+
+       stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0);
+
+       RfAgcPwm =
+               (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) +
+               (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2);
+       RfAgcPwm = 100 * RfAgcPwm / 1023;
+
+       IfAgcPwm =
+               stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) +
+               (stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8);
+       if (IfAgcPwm >= 2048)
+               IfAgcPwm -= 2048;
+       else
+               IfAgcPwm += 2048;
+
+       IfAgcPwm = 100 * IfAgcPwm / 4095;
+
+       /* For DTT75467 on NIM */
+       if (RfAgcPwm < 90  && IfAgcPwm < 28) {
+               for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) {
+                       if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) {
+                               rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i];
+                               break;
+                       }
+               }
+               if (i == RF_LOOKUP_TABLE_SIZE)
+                       rfLevel = -56;
+       } else { /*if IF AGC>10*/
+               for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) {
+                       if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) {
+                               rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i];
+                               break;
+                       }
+               }
+               if (i == RF_LOOKUP_TABLE2_SIZE)
+                       rfLevel = -72;
+       }
+       return rfLevel;
+}
+
+static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+
+       s32 signal =  stv0367cab_get_rf_lvl(state);
+
+       dprintk("%s: signal=%d dBm\n", __func__, signal);
+
+       if (signal <= -72)
+               *strength = 65535;
+       else
+               *strength = (22 + signal) * (-1311);
+
+       dprintk("%s: strength=%d\n", __func__, (*strength));
+
+       return 0;
+}
+
+static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       u32 noisepercentage;
+       enum stv0367cab_mod QAMSize;
+       u32 regval = 0, temp = 0;
+       int power, i;
+
+       QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE);
+       switch (QAMSize) {
+       case FE_CAB_MOD_QAM4:
+               power = 21904;
+               break;
+       case FE_CAB_MOD_QAM16:
+               power = 20480;
+               break;
+       case FE_CAB_MOD_QAM32:
+               power = 23040;
+               break;
+       case FE_CAB_MOD_QAM64:
+               power = 21504;
+               break;
+       case FE_CAB_MOD_QAM128:
+               power = 23616;
+               break;
+       case FE_CAB_MOD_QAM256:
+               power = 21760;
+               break;
+       case FE_CAB_MOD_QAM512:
+               power = 1;
+               break;
+       case FE_CAB_MOD_QAM1024:
+               power = 21280;
+               break;
+       default:
+               power = 1;
+               break;
+       }
+
+       for (i = 0; i < 10; i++) {
+               regval += (stv0367_readbits(state, F367CAB_SNR_LO)
+                       + 256 * stv0367_readbits(state, F367CAB_SNR_HI));
+       }
+
+       regval /= 10; /*for average over 10 times in for loop above*/
+       if (regval != 0) {
+               temp = power
+                       * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER)));
+               temp /= regval;
+       }
+
+       /* table values, not needed to calculate logarithms */
+       if (temp >= 5012)
+               noisepercentage = 100;
+       else if (temp >= 3981)
+               noisepercentage = 93;
+       else if (temp >= 3162)
+               noisepercentage = 86;
+       else if (temp >= 2512)
+               noisepercentage = 79;
+       else if (temp >= 1995)
+               noisepercentage = 72;
+       else if (temp >= 1585)
+               noisepercentage = 65;
+       else if (temp >= 1259)
+               noisepercentage = 58;
+       else if (temp >= 1000)
+               noisepercentage = 50;
+       else if (temp >= 794)
+               noisepercentage = 43;
+       else if (temp >= 501)
+               noisepercentage = 36;
+       else if (temp >= 316)
+               noisepercentage = 29;
+       else if (temp >= 200)
+               noisepercentage = 22;
+       else if (temp >= 158)
+               noisepercentage = 14;
+       else if (temp >= 126)
+               noisepercentage = 7;
+       else
+               noisepercentage = 0;
+
+       dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage);
+
+       *snr = (noisepercentage * 65535) / 100;
+
+       return 0;
+}
+
+static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct stv0367_state *state = fe->demodulator_priv;
+       int corrected, tscount;
+
+       *ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8)
+                       | stv0367_readreg(state, R367CAB_RS_COUNTER_4);
+       corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8)
+                       | stv0367_readreg(state, R367CAB_RS_COUNTER_2);
+       tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8)
+                       | stv0367_readreg(state, R367CAB_RS_COUNTER_1);
+
+       dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n",
+                               __func__, *ucblocks, corrected, tscount);
+
+       return 0;
+};
+
+static struct dvb_frontend_ops stv0367cab_ops = {
+       .info = {
+               .name = "ST STV0367 DVB-C",
+               .type = FE_QAM,
+               .frequency_min = 47000000,
+               .frequency_max = 862000000,
+               .frequency_stepsize = 62500,
+               .symbol_rate_min = 870000,
+               .symbol_rate_max = 11700000,
+               .caps = 0x400 |/* FE_CAN_QAM_4 */
+                       FE_CAN_QAM_16 | FE_CAN_QAM_32  |
+                       FE_CAN_QAM_64 | FE_CAN_QAM_128 |
+                       FE_CAN_QAM_256 | FE_CAN_FEC_AUTO
+       },
+       .release                                = stv0367_release,
+       .init                                   = stv0367cab_init,
+       .sleep                                  = stv0367cab_sleep,
+       .i2c_gate_ctrl                          = stv0367cab_gate_ctrl,
+       .set_frontend                           = stv0367cab_set_frontend,
+       .get_frontend                           = stv0367cab_get_frontend,
+       .read_status                            = stv0367cab_read_status,
+/*     .read_ber                               = stv0367cab_read_ber, */
+       .read_signal_strength                   = stv0367cab_read_strength,
+       .read_snr                               = stv0367cab_read_snr,
+       .read_ucblocks                          = stv0367cab_read_ucblcks,
+       .get_tune_settings                      = stv0367_get_tune_settings,
+};
+
+struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+                                  struct i2c_adapter *i2c)
+{
+       struct stv0367_state *state = NULL;
+       struct stv0367cab_state *cab_state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+       cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL);
+       if (cab_state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->i2c = i2c;
+       state->config = config;
+       cab_state->search_range = 280000;
+       state->cab_state = cab_state;
+       state->fe.ops = stv0367cab_ops;
+       state->fe.demodulator_priv = state;
+       state->chip_id = stv0367_readreg(state, 0xf000);
+
+       dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id);
+
+       /* check if the demod is there */
+       if ((state->chip_id != 0x50) && (state->chip_id != 0x60))
+               goto error;
+
+       return &state->fe;
+
+error:
+       kfree(cab_state);
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stv0367cab_attach);
+
+MODULE_PARM_DESC(debug, "Set debug");
+MODULE_PARM_DESC(i2c_debug, "Set i2c debug");
+
+MODULE_AUTHOR("Igor M. Liplianin");
+MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv0367.h b/drivers/media/dvb/frontends/stv0367.h
new file mode 100644 (file)
index 0000000..93cc4a5
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * stv0367.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0367_H
+#define STV0367_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct stv0367_config {
+       u8 demod_address;
+       u32 xtal;
+       u32 if_khz;/*4500*/
+       int if_iq_mode;
+       int ts_mode;
+       int clk_pol;
+};
+
+#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \
+                                                       && defined(MODULE))
+extern struct
+dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+                                       struct i2c_adapter *i2c);
+extern struct
+dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+                                       struct i2c_adapter *i2c);
+#else
+static inline struct
+dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+static inline struct
+dvb_frontend *stv0367cab_attach(const struct stv0367_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0367_priv.h b/drivers/media/dvb/frontends/stv0367_priv.h
new file mode 100644 (file)
index 0000000..995db06
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * stv0367_priv.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/* Common driver error constants */
+
+#ifndef STV0367_PRIV_H
+#define STV0367_PRIV_H
+
+#ifndef TRUE
+    #define TRUE (1 == 1)
+#endif
+#ifndef FALSE
+    #define FALSE (!TRUE)
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* MACRO definitions */
+#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X))
+#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y))
+#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y))
+#define INRANGE(X, Y, Z) \
+       ((((X) <= (Y)) && ((Y) <= (Z))) || \
+       (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0)
+
+#ifndef MAKEWORD
+#define MAKEWORD(X, Y) (((X) << 8) + (Y))
+#endif
+
+#define LSB(X) (((X) & 0xff))
+#define MSB(Y) (((Y) >> 8) & 0xff)
+#define MMSB(Y)(((Y) >> 16) & 0xff)
+
+enum stv0367_ter_signal_type {
+       FE_TER_NOAGC = 0,
+       FE_TER_AGCOK = 5,
+       FE_TER_NOTPS = 6,
+       FE_TER_TPSOK = 7,
+       FE_TER_NOSYMBOL = 8,
+       FE_TER_BAD_CPQ = 9,
+       FE_TER_PRFOUNDOK = 10,
+       FE_TER_NOPRFOUND = 11,
+       FE_TER_LOCKOK = 12,
+       FE_TER_NOLOCK = 13,
+       FE_TER_SYMBOLOK = 15,
+       FE_TER_CPAMPOK = 16,
+       FE_TER_NOCPAMP = 17,
+       FE_TER_SWNOK = 18
+};
+
+enum stv0367_ts_mode {
+       STV0367_OUTPUTMODE_DEFAULT,
+       STV0367_SERIAL_PUNCT_CLOCK,
+       STV0367_SERIAL_CONT_CLOCK,
+       STV0367_PARALLEL_PUNCT_CLOCK,
+       STV0367_DVBCI_CLOCK
+};
+
+enum stv0367_clk_pol {
+       STV0367_CLOCKPOLARITY_DEFAULT,
+       STV0367_RISINGEDGE_CLOCK,
+       STV0367_FALLINGEDGE_CLOCK
+};
+
+enum stv0367_ter_bw {
+       FE_TER_CHAN_BW_6M = 6,
+       FE_TER_CHAN_BW_7M = 7,
+       FE_TER_CHAN_BW_8M = 8
+};
+
+#if 0
+enum FE_TER_Rate_TPS {
+       FE_TER_TPS_1_2 = 0,
+       FE_TER_TPS_2_3 = 1,
+       FE_TER_TPS_3_4 = 2,
+       FE_TER_TPS_5_6 = 3,
+       FE_TER_TPS_7_8 = 4
+};
+#endif
+
+enum stv0367_ter_mode {
+       FE_TER_MODE_2K,
+       FE_TER_MODE_8K,
+       FE_TER_MODE_4K
+};
+#if 0
+enum FE_TER_Hierarchy_Alpha {
+       FE_TER_HIER_ALPHA_NONE, /* Regular modulation */
+       FE_TER_HIER_ALPHA_1,    /* Hierarchical modulation a = 1*/
+       FE_TER_HIER_ALPHA_2,    /* Hierarchical modulation a = 2*/
+       FE_TER_HIER_ALPHA_4     /* Hierarchical modulation a = 4*/
+};
+#endif
+enum stv0367_ter_hierarchy {
+       FE_TER_HIER_NONE,       /*Hierarchy None*/
+       FE_TER_HIER_LOW_PRIO,   /*Hierarchy : Low Priority*/
+       FE_TER_HIER_HIGH_PRIO,  /*Hierarchy : High Priority*/
+       FE_TER_HIER_PRIO_ANY    /*Hierarchy  :Any*/
+};
+
+#if 0
+enum fe_stv0367_ter_spec {
+       FE_TER_INVERSION_NONE = 0,
+       FE_TER_INVERSION = 1,
+       FE_TER_INVERSION_AUTO = 2,
+       FE_TER_INVERSION_UNK  = 4
+};
+#endif
+
+enum stv0367_ter_if_iq_mode {
+       FE_TER_NORMAL_IF_TUNER = 0,
+       FE_TER_LONGPATH_IF_TUNER = 1,
+       FE_TER_IQ_TUNER = 2
+
+};
+
+#if 0
+enum FE_TER_FECRate {
+       FE_TER_FEC_NONE = 0x00, /* no FEC rate specified */
+       FE_TER_FEC_ALL = 0xFF,   /* Logical OR of all FECs */
+       FE_TER_FEC_1_2 = 1,
+       FE_TER_FEC_2_3 = (1 << 1),
+       FE_TER_FEC_3_4 = (1 << 2),
+       FE_TER_FEC_4_5 = (1 << 3),
+       FE_TER_FEC_5_6 = (1 << 4),
+       FE_TER_FEC_6_7 = (1 << 5),
+       FE_TER_FEC_7_8 = (1 << 6),
+       FE_TER_FEC_8_9 = (1 << 7)
+};
+
+enum FE_TER_Rate {
+       FE_TER_FE_1_2 = 0,
+       FE_TER_FE_2_3 = 1,
+       FE_TER_FE_3_4 = 2,
+       FE_TER_FE_5_6 = 3,
+       FE_TER_FE_6_7 = 4,
+       FE_TER_FE_7_8 = 5
+};
+#endif
+
+enum stv0367_ter_force {
+       FE_TER_FORCENONE = 0,
+       FE_TER_FORCE_M_G = 1
+};
+
+enum  stv0367cab_mod {
+       FE_CAB_MOD_QAM4,
+       FE_CAB_MOD_QAM16,
+       FE_CAB_MOD_QAM32,
+       FE_CAB_MOD_QAM64,
+       FE_CAB_MOD_QAM128,
+       FE_CAB_MOD_QAM256,
+       FE_CAB_MOD_QAM512,
+       FE_CAB_MOD_QAM1024
+};
+#if 0
+enum {
+       FE_CAB_FEC_A = 1,       /* J83 Annex A */
+       FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */
+       FE_CAB_FEC_C = (1 << 2) /* J83 Annex C */
+} FE_CAB_FECType_t;
+#endif
+struct stv0367_cab_signal_info {
+       int locked;
+       u32 frequency; /* kHz */
+       u32 symbol_rate; /* Mbds */
+       enum stv0367cab_mod modulation;
+       fe_spectral_inversion_t spect_inv;
+       s32 Power_dBmx10;       /* Power of the RF signal (dBm x 10) */
+       u32     CN_dBx10;       /* Carrier to noise ratio (dB x 10) */
+       u32     BER;            /* Bit error rate (x 10000000)  */
+};
+
+enum stv0367_cab_signal_type {
+       FE_CAB_NOTUNER,
+       FE_CAB_NOAGC,
+       FE_CAB_NOSIGNAL,
+       FE_CAB_NOTIMING,
+       FE_CAB_TIMINGOK,
+       FE_CAB_NOCARRIER,
+       FE_CAB_CARRIEROK,
+       FE_CAB_NOBLIND,
+       FE_CAB_BLINDOK,
+       FE_CAB_NODEMOD,
+       FE_CAB_DEMODOK,
+       FE_CAB_DATAOK
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0367_regs.h b/drivers/media/dvb/frontends/stv0367_regs.h
new file mode 100644 (file)
index 0000000..a96fbdc
--- /dev/null
@@ -0,0 +1,3614 @@
+/*
+ * stv0367_regs.h
+ *
+ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC.
+ *
+ * Copyright (C) ST Microelectronics.
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef STV0367_REGS_H
+#define STV0367_REGS_H
+
+/* ID */
+#define        R367TER_ID      0xf000
+#define        F367TER_IDENTIFICATIONREG       0xf00000ff
+
+/* I2CRPT */
+#define        R367TER_I2CRPT  0xf001
+#define        F367TER_I2CT_ON 0xf0010080
+#define        F367TER_ENARPT_LEVEL    0xf0010070
+#define        F367TER_SCLT_DELAY      0xf0010008
+#define        F367TER_SCLT_NOD        0xf0010004
+#define        F367TER_STOP_ENABLE     0xf0010002
+#define        F367TER_SDAT_NOD        0xf0010001
+
+/* TOPCTRL */
+#define        R367TER_TOPCTRL 0xf002
+#define        F367TER_STDBY   0xf0020080
+#define        F367TER_STDBY_FEC       0xf0020040
+#define        F367TER_STDBY_CORE      0xf0020020
+#define        F367TER_QAM_COFDM       0xf0020010
+#define        F367TER_TS_DIS  0xf0020008
+#define        F367TER_DIR_CLK_216     0xf0020004
+#define        F367TER_TUNER_BB        0xf0020002
+#define        F367TER_DVBT_H  0xf0020001
+
+/* IOCFG0 */
+#define        R367TER_IOCFG0  0xf003
+#define        F367TER_OP0_SD  0xf0030080
+#define        F367TER_OP0_VAL 0xf0030040
+#define        F367TER_OP0_OD  0xf0030020
+#define        F367TER_OP0_INV 0xf0030010
+#define        F367TER_OP0_DACVALUE_HI 0xf003000f
+
+/* DAc0R */
+#define        R367TER_DAC0R   0xf004
+#define        F367TER_OP0_DACVALUE_LO 0xf00400ff
+
+/* IOCFG1 */
+#define        R367TER_IOCFG1  0xf005
+#define        F367TER_IP0     0xf0050040
+#define        F367TER_OP1_OD  0xf0050020
+#define        F367TER_OP1_INV 0xf0050010
+#define        F367TER_OP1_DACVALUE_HI 0xf005000f
+
+/* DAC1R */
+#define        R367TER_DAC1R   0xf006
+#define        F367TER_OP1_DACVALUE_LO 0xf00600ff
+
+/* IOCFG2 */
+#define        R367TER_IOCFG2  0xf007
+#define        F367TER_OP2_LOCK_CONF   0xf00700e0
+#define        F367TER_OP2_OD  0xf0070010
+#define        F367TER_OP2_VAL 0xf0070008
+#define        F367TER_OP1_LOCK_CONF   0xf0070007
+
+/* SDFR */
+#define        R367TER_SDFR    0xf008
+#define        F367TER_OP0_FREQ        0xf00800f0
+#define        F367TER_OP1_FREQ        0xf008000f
+
+/* STATUS */
+#define        R367TER_STATUS  0xf009
+#define        F367TER_TPS_LOCK        0xf0090080
+#define        F367TER_SYR_LOCK        0xf0090040
+#define        F367TER_AGC_LOCK        0xf0090020
+#define        F367TER_PRF     0xf0090010
+#define        F367TER_LK      0xf0090008
+#define        F367TER_PR      0xf0090007
+
+/* AUX_CLK */
+#define        R367TER_AUX_CLK 0xf00a
+#define        F367TER_AUXFEC_CTL      0xf00a00c0
+#define        F367TER_DIS_CKX4        0xf00a0020
+#define        F367TER_CKSEL   0xf00a0018
+#define        F367TER_CKDIV_PROG      0xf00a0006
+#define        F367TER_AUXCLK_ENA      0xf00a0001
+
+/* FREESYS1 */
+#define        R367TER_FREESYS1        0xf00b
+#define        F367TER_FREE_SYS1       0xf00b00ff
+
+/* FREESYS2 */
+#define        R367TER_FREESYS2        0xf00c
+#define        F367TER_FREE_SYS2       0xf00c00ff
+
+/* FREESYS3 */
+#define        R367TER_FREESYS3        0xf00d
+#define        F367TER_FREE_SYS3       0xf00d00ff
+
+/* GPIO_CFG */
+#define        R367TER_GPIO_CFG        0xf00e
+#define        F367TER_GPIO7_NOD       0xf00e0080
+#define        F367TER_GPIO7_CFG       0xf00e0040
+#define        F367TER_GPIO6_NOD       0xf00e0020
+#define        F367TER_GPIO6_CFG       0xf00e0010
+#define        F367TER_GPIO5_NOD       0xf00e0008
+#define        F367TER_GPIO5_CFG       0xf00e0004
+#define        F367TER_GPIO4_NOD       0xf00e0002
+#define        F367TER_GPIO4_CFG       0xf00e0001
+
+/* GPIO_CMD */
+#define        R367TER_GPIO_CMD        0xf00f
+#define        F367TER_GPIO7_VAL       0xf00f0008
+#define        F367TER_GPIO6_VAL       0xf00f0004
+#define        F367TER_GPIO5_VAL       0xf00f0002
+#define        F367TER_GPIO4_VAL       0xf00f0001
+
+/* AGC2MAX */
+#define        R367TER_AGC2MAX 0xf010
+#define        F367TER_AGC2_MAX        0xf01000ff
+
+/* AGC2MIN */
+#define        R367TER_AGC2MIN 0xf011
+#define        F367TER_AGC2_MIN        0xf01100ff
+
+/* AGC1MAX */
+#define        R367TER_AGC1MAX 0xf012
+#define        F367TER_AGC1_MAX        0xf01200ff
+
+/* AGC1MIN */
+#define        R367TER_AGC1MIN 0xf013
+#define        F367TER_AGC1_MIN        0xf01300ff
+
+/* AGCR */
+#define        R367TER_AGCR    0xf014
+#define        F367TER_RATIO_A 0xf01400e0
+#define        F367TER_RATIO_B 0xf0140018
+#define        F367TER_RATIO_C 0xf0140007
+
+/* AGC2TH */
+#define        R367TER_AGC2TH  0xf015
+#define        F367TER_AGC2_THRES      0xf01500ff
+
+/* AGC12c */
+#define        R367TER_AGC12C  0xf016
+#define        F367TER_AGC1_IV 0xf0160080
+#define        F367TER_AGC1_OD 0xf0160040
+#define        F367TER_AGC1_LOAD       0xf0160020
+#define        F367TER_AGC2_IV 0xf0160010
+#define        F367TER_AGC2_OD 0xf0160008
+#define        F367TER_AGC2_LOAD       0xf0160004
+#define        F367TER_AGC12_MODE      0xf0160003
+
+/* AGCCTRL1 */
+#define        R367TER_AGCCTRL1        0xf017
+#define        F367TER_DAGC_ON 0xf0170080
+#define        F367TER_INVERT_AGC12    0xf0170040
+#define        F367TER_AGC1_MODE       0xf0170008
+#define        F367TER_AGC2_MODE       0xf0170007
+
+/* AGCCTRL2 */
+#define        R367TER_AGCCTRL2        0xf018
+#define        F367TER_FRZ2_CTRL       0xf0180060
+#define        F367TER_FRZ1_CTRL       0xf0180018
+#define        F367TER_TIME_CST        0xf0180007
+
+/* AGC1VAL1 */
+#define        R367TER_AGC1VAL1        0xf019
+#define        F367TER_AGC1_VAL_LO     0xf01900ff
+
+/* AGC1VAL2 */
+#define        R367TER_AGC1VAL2        0xf01a
+#define        F367TER_AGC1_VAL_HI     0xf01a000f
+
+/* AGC2VAL1 */
+#define        R367TER_AGC2VAL1        0xf01b
+#define        F367TER_AGC2_VAL_LO     0xf01b00ff
+
+/* AGC2VAL2 */
+#define        R367TER_AGC2VAL2        0xf01c
+#define        F367TER_AGC2_VAL_HI     0xf01c000f
+
+/* AGC2PGA */
+#define        R367TER_AGC2PGA 0xf01d
+#define        F367TER_AGC2_PGA        0xf01d00ff
+
+/* OVF_RATE1 */
+#define        R367TER_OVF_RATE1       0xf01e
+#define        F367TER_OVF_RATE_HI     0xf01e000f
+
+/* OVF_RATE2 */
+#define        R367TER_OVF_RATE2       0xf01f
+#define        F367TER_OVF_RATE_LO     0xf01f00ff
+
+/* GAIN_SRC1 */
+#define        R367TER_GAIN_SRC1       0xf020
+#define        F367TER_INV_SPECTR      0xf0200080
+#define        F367TER_IQ_INVERT       0xf0200040
+#define        F367TER_INR_BYPASS      0xf0200020
+#define        F367TER_STATUS_INV_SPECRUM      0xf0200010
+#define        F367TER_GAIN_SRC_HI     0xf020000f
+
+/* GAIN_SRC2 */
+#define        R367TER_GAIN_SRC2       0xf021
+#define        F367TER_GAIN_SRC_LO     0xf02100ff
+
+/* INC_DEROT1 */
+#define        R367TER_INC_DEROT1      0xf022
+#define        F367TER_INC_DEROT_HI    0xf02200ff
+
+/* INC_DEROT2 */
+#define        R367TER_INC_DEROT2      0xf023
+#define        F367TER_INC_DEROT_LO    0xf02300ff
+
+/* PPM_CPAMP_DIR */
+#define        R367TER_PPM_CPAMP_DIR   0xf024
+#define        F367TER_PPM_CPAMP_DIRECT        0xf02400ff
+
+/* PPM_CPAMP_INV */
+#define        R367TER_PPM_CPAMP_INV   0xf025
+#define        F367TER_PPM_CPAMP_INVER 0xf02500ff
+
+/* FREESTFE_1 */
+#define        R367TER_FREESTFE_1      0xf026
+#define        F367TER_SYMBOL_NUMBER_INC       0xf02600c0
+#define        F367TER_SEL_LSB 0xf0260004
+#define        F367TER_AVERAGE_ON      0xf0260002
+#define        F367TER_DC_ADJ  0xf0260001
+
+/* FREESTFE_2 */
+#define        R367TER_FREESTFE_2      0xf027
+#define        F367TER_SEL_SRCOUT      0xf02700c0
+#define        F367TER_SEL_SYRTHR      0xf027001f
+
+/* DCOFFSET */
+#define        R367TER_DCOFFSET        0xf028
+#define        F367TER_SELECT_I_Q      0xf0280080
+#define        F367TER_DC_OFFSET       0xf028007f
+
+/* EN_PROCESS */
+#define        R367TER_EN_PROCESS      0xf029
+#define        F367TER_FREE    0xf02900f0
+#define        F367TER_ENAB_MANUAL     0xf0290001
+
+/* SDI_SMOOTHER */
+#define        R367TER_SDI_SMOOTHER    0xf02a
+#define        F367TER_DIS_SMOOTH      0xf02a0080
+#define        F367TER_SDI_INC_SMOOTHER        0xf02a007f
+
+/* FE_LOOP_OPEN */
+#define        R367TER_FE_LOOP_OPEN    0xf02b
+#define        F367TER_TRL_LOOP_OP     0xf02b0002
+#define        F367TER_CRL_LOOP_OP     0xf02b0001
+
+/* FREQOFF1 */
+#define        R367TER_FREQOFF1        0xf02c
+#define        F367TER_FREQ_OFFSET_LOOP_OPEN_VHI       0xf02c00ff
+
+/* FREQOFF2 */
+#define        R367TER_FREQOFF2        0xf02d
+#define        F367TER_FREQ_OFFSET_LOOP_OPEN_HI        0xf02d00ff
+
+/* FREQOFF3 */
+#define        R367TER_FREQOFF3        0xf02e
+#define        F367TER_FREQ_OFFSET_LOOP_OPEN_LO        0xf02e00ff
+
+/* TIMOFF1 */
+#define        R367TER_TIMOFF1 0xf02f
+#define        F367TER_TIM_OFFSET_LOOP_OPEN_HI 0xf02f00ff
+
+/* TIMOFF2 */
+#define        R367TER_TIMOFF2 0xf030
+#define        F367TER_TIM_OFFSET_LOOP_OPEN_LO 0xf03000ff
+
+/* EPQ */
+#define        R367TER_EPQ     0xf031
+#define        F367TER_EPQ1    0xf03100ff
+
+/* EPQAUTO */
+#define        R367TER_EPQAUTO 0xf032
+#define        F367TER_EPQ2    0xf03200ff
+
+/* SYR_UPDATE */
+#define        R367TER_SYR_UPDATE      0xf033
+#define        F367TER_SYR_PROTV       0xf0330080
+#define        F367TER_SYR_PROTV_GAIN  0xf0330060
+#define        F367TER_SYR_FILTER      0xf0330010
+#define        F367TER_SYR_TRACK_THRES 0xf033000c
+
+/* CHPFREE */
+#define        R367TER_CHPFREE 0xf034
+#define        F367TER_CHP_FREE        0xf03400ff
+
+/* PPM_STATE_MAC */
+#define        R367TER_PPM_STATE_MAC   0xf035
+#define        F367TER_PPM_STATE_MACHINE_DECODER       0xf035003f
+
+/* INR_THRESHOLD */
+#define        R367TER_INR_THRESHOLD   0xf036
+#define        F367TER_INR_THRESH      0xf03600ff
+
+/* EPQ_TPS_ID_CELL */
+#define        R367TER_EPQ_TPS_ID_CELL 0xf037
+#define        F367TER_ENABLE_LGTH_TO_CF       0xf0370080
+#define        F367TER_DIS_TPS_RSVD    0xf0370040
+#define        F367TER_DIS_BCH 0xf0370020
+#define        F367TER_DIS_ID_CEL      0xf0370010
+#define        F367TER_TPS_ADJUST_SYM  0xf037000f
+
+/* EPQ_CFG */
+#define        R367TER_EPQ_CFG 0xf038
+#define        F367TER_EPQ_RANGE       0xf0380002
+#define        F367TER_EPQ_SOFT        0xf0380001
+
+/* EPQ_STATUS */
+#define        R367TER_EPQ_STATUS      0xf039
+#define        F367TER_SLOPE_INC       0xf03900fc
+#define        F367TER_TPS_FIELD       0xf0390003
+
+/* AUTORELOCK */
+#define        R367TER_AUTORELOCK      0xf03a
+#define        F367TER_BYPASS_BER_TEMPO        0xf03a0080
+#define        F367TER_BER_TEMPO       0xf03a0070
+#define        F367TER_BYPASS_COFDM_TEMPO      0xf03a0008
+#define        F367TER_COFDM_TEMPO     0xf03a0007
+
+/* BER_THR_VMSB */
+#define        R367TER_BER_THR_VMSB    0xf03b
+#define        F367TER_BER_THRESHOLD_HI        0xf03b00ff
+
+/* BER_THR_MSB */
+#define        R367TER_BER_THR_MSB     0xf03c
+#define        F367TER_BER_THRESHOLD_MID       0xf03c00ff
+
+/* BER_THR_LSB */
+#define        R367TER_BER_THR_LSB     0xf03d
+#define        F367TER_BER_THRESHOLD_LO        0xf03d00ff
+
+/* CCD */
+#define        R367TER_CCD     0xf03e
+#define        F367TER_CCD_DETECTED    0xf03e0080
+#define        F367TER_CCD_RESET       0xf03e0040
+#define        F367TER_CCD_THRESHOLD   0xf03e000f
+
+/* SPECTR_CFG */
+#define        R367TER_SPECTR_CFG      0xf03f
+#define        F367TER_SPECT_CFG       0xf03f0003
+
+/* CONSTMU_MSB */
+#define        R367TER_CONSTMU_MSB     0xf040
+#define        F367TER_CONSTMU_FREEZE  0xf0400080
+#define        F367TER_CONSTNU_FORCE_EN        0xf0400040
+#define        F367TER_CONST_MU_MSB    0xf040003f
+
+/* CONSTMU_LSB */
+#define        R367TER_CONSTMU_LSB     0xf041
+#define        F367TER_CONST_MU_LSB    0xf04100ff
+
+/* CONSTMU_MAX_MSB */
+#define        R367TER_CONSTMU_MAX_MSB 0xf042
+#define        F367TER_CONST_MU_MAX_MSB        0xf042003f
+
+/* CONSTMU_MAX_LSB */
+#define        R367TER_CONSTMU_MAX_LSB 0xf043
+#define        F367TER_CONST_MU_MAX_LSB        0xf04300ff
+
+/* ALPHANOISE */
+#define        R367TER_ALPHANOISE      0xf044
+#define        F367TER_USE_ALLFILTER   0xf0440080
+#define        F367TER_INTER_ON        0xf0440040
+#define        F367TER_ALPHA_NOISE     0xf044001f
+
+/* MAXGP_MSB */
+#define        R367TER_MAXGP_MSB       0xf045
+#define        F367TER_MUFILTER_LENGTH 0xf04500f0
+#define        F367TER_MAX_GP_MSB      0xf045000f
+
+/* MAXGP_LSB */
+#define        R367TER_MAXGP_LSB       0xf046
+#define        F367TER_MAX_GP_LSB      0xf04600ff
+
+/* ALPHAMSB */
+#define        R367TER_ALPHAMSB        0xf047
+#define        F367TER_CHC_DATARATE    0xf04700c0
+#define        F367TER_ALPHA_MSB       0xf047003f
+
+/* ALPHALSB */
+#define        R367TER_ALPHALSB        0xf048
+#define        F367TER_ALPHA_LSB       0xf04800ff
+
+/* PILOT_ACCU */
+#define        R367TER_PILOT_ACCU      0xf049
+#define        F367TER_USE_SCAT4ADDAPT 0xf0490080
+#define        F367TER_PILOT_ACC       0xf049001f
+
+/* PILOTMU_ACCU */
+#define        R367TER_PILOTMU_ACCU    0xf04a
+#define        F367TER_DISCARD_BAD_SP  0xf04a0080
+#define        F367TER_DISCARD_BAD_CP  0xf04a0040
+#define        F367TER_PILOT_MU_ACCU   0xf04a001f
+
+/* FILT_CHANNEL_EST */
+#define        R367TER_FILT_CHANNEL_EST        0xf04b
+#define        F367TER_USE_FILT_PILOT  0xf04b0080
+#define        F367TER_FILT_CHANNEL    0xf04b007f
+
+/* ALPHA_NOPISE_FREQ */
+#define        R367TER_ALPHA_NOPISE_FREQ       0xf04c
+#define        F367TER_NOISE_FREQ_FILT 0xf04c0040
+#define        F367TER_ALPHA_NOISE_FREQ        0xf04c003f
+
+/* RATIO_PILOT */
+#define        R367TER_RATIO_PILOT     0xf04d
+#define        F367TER_RATIO_MEAN_SP   0xf04d00f0
+#define        F367TER_RATIO_MEAN_CP   0xf04d000f
+
+/* CHC_CTL */
+#define        R367TER_CHC_CTL 0xf04e
+#define        F367TER_TRACK_EN        0xf04e0080
+#define        F367TER_NOISE_NORM_EN   0xf04e0040
+#define        F367TER_FORCE_CHC_RESET 0xf04e0020
+#define        F367TER_SHORT_TIME      0xf04e0010
+#define        F367TER_FORCE_STATE_EN  0xf04e0008
+#define        F367TER_FORCE_STATE     0xf04e0007
+
+/* EPQ_ADJUST */
+#define        R367TER_EPQ_ADJUST      0xf04f
+#define        F367TER_ADJUST_SCAT_IND 0xf04f00c0
+#define        F367TER_ONE_SYMBOL      0xf04f0010
+#define        F367TER_EPQ_DECAY       0xf04f000e
+#define        F367TER_HOLD_SLOPE      0xf04f0001
+
+/* EPQ_THRES */
+#define        R367TER_EPQ_THRES       0xf050
+#define        F367TER_EPQ_THR 0xf05000ff
+
+/* OMEGA_CTL */
+#define        R367TER_OMEGA_CTL       0xf051
+#define        F367TER_OMEGA_RST       0xf0510080
+#define        F367TER_FREEZE_OMEGA    0xf0510040
+#define        F367TER_OMEGA_SEL       0xf051003f
+
+/* GP_CTL */
+#define        R367TER_GP_CTL  0xf052
+#define        F367TER_CHC_STATE       0xf05200e0
+#define        F367TER_FREEZE_GP       0xf0520010
+#define        F367TER_GP_SEL  0xf052000f
+
+/* MUMSB */
+#define        R367TER_MUMSB   0xf053
+#define        F367TER_MU_MSB  0xf053007f
+
+/* MULSB */
+#define        R367TER_MULSB   0xf054
+#define        F367TER_MU_LSB  0xf05400ff
+
+/* GPMSB */
+#define        R367TER_GPMSB   0xf055
+#define        F367TER_CSI_THRESHOLD   0xf05500e0
+#define        F367TER_GP_MSB  0xf055000f
+
+/* GPLSB */
+#define        R367TER_GPLSB   0xf056
+#define        F367TER_GP_LSB  0xf05600ff
+
+/* OMEGAMSB */
+#define        R367TER_OMEGAMSB        0xf057
+#define        F367TER_OMEGA_MSB       0xf057007f
+
+/* OMEGALSB */
+#define        R367TER_OMEGALSB        0xf058
+#define        F367TER_OMEGA_LSB       0xf05800ff
+
+/* SCAT_NB */
+#define        R367TER_SCAT_NB 0xf059
+#define        F367TER_CHC_TEST        0xf05900f8
+#define        F367TER_SCAT_NUMB       0xf0590003
+
+/* CHC_DUMMY */
+#define        R367TER_CHC_DUMMY       0xf05a
+#define        F367TER_CHC_DUM 0xf05a00ff
+
+/* INC_CTL */
+#define        R367TER_INC_CTL 0xf05b
+#define        F367TER_INC_BYPASS      0xf05b0080
+#define        F367TER_INC_NDEPTH      0xf05b000c
+#define        F367TER_INC_MADEPTH     0xf05b0003
+
+/* INCTHRES_COR1 */
+#define        R367TER_INCTHRES_COR1   0xf05c
+#define        F367TER_INC_THRES_COR1  0xf05c00ff
+
+/* INCTHRES_COR2 */
+#define        R367TER_INCTHRES_COR2   0xf05d
+#define        F367TER_INC_THRES_COR2  0xf05d00ff
+
+/* INCTHRES_DET1 */
+#define        R367TER_INCTHRES_DET1   0xf05e
+#define        F367TER_INC_THRES_DET1  0xf05e003f
+
+/* INCTHRES_DET2 */
+#define        R367TER_INCTHRES_DET2   0xf05f
+#define        F367TER_INC_THRES_DET2  0xf05f003f
+
+/* IIR_CELLNB */
+#define        R367TER_IIR_CELLNB      0xf060
+#define        F367TER_NRST_IIR        0xf0600080
+#define        F367TER_IIR_CELL_NB     0xf0600007
+
+/* IIRCX_COEFF1_MSB */
+#define        R367TER_IIRCX_COEFF1_MSB        0xf061
+#define        F367TER_IIR_CX_COEFF1_MSB       0xf06100ff
+
+/* IIRCX_COEFF1_LSB */
+#define        R367TER_IIRCX_COEFF1_LSB        0xf062
+#define        F367TER_IIR_CX_COEFF1_LSB       0xf06200ff
+
+/* IIRCX_COEFF2_MSB */
+#define        R367TER_IIRCX_COEFF2_MSB        0xf063
+#define        F367TER_IIR_CX_COEFF2_MSB       0xf06300ff
+
+/* IIRCX_COEFF2_LSB */
+#define        R367TER_IIRCX_COEFF2_LSB        0xf064
+#define        F367TER_IIR_CX_COEFF2_LSB       0xf06400ff
+
+/* IIRCX_COEFF3_MSB */
+#define        R367TER_IIRCX_COEFF3_MSB        0xf065
+#define        F367TER_IIR_CX_COEFF3_MSB       0xf06500ff
+
+/* IIRCX_COEFF3_LSB */
+#define        R367TER_IIRCX_COEFF3_LSB        0xf066
+#define        F367TER_IIR_CX_COEFF3_LSB       0xf06600ff
+
+/* IIRCX_COEFF4_MSB */
+#define        R367TER_IIRCX_COEFF4_MSB        0xf067
+#define        F367TER_IIR_CX_COEFF4_MSB       0xf06700ff
+
+/* IIRCX_COEFF4_LSB */
+#define        R367TER_IIRCX_COEFF4_LSB        0xf068
+#define        F367TER_IIR_CX_COEFF4_LSB       0xf06800ff
+
+/* IIRCX_COEFF5_MSB */
+#define        R367TER_IIRCX_COEFF5_MSB        0xf069
+#define        F367TER_IIR_CX_COEFF5_MSB       0xf06900ff
+
+/* IIRCX_COEFF5_LSB */
+#define        R367TER_IIRCX_COEFF5_LSB        0xf06a
+#define        F367TER_IIR_CX_COEFF5_LSB       0xf06a00ff
+
+/* FEPATH_CFG */
+#define        R367TER_FEPATH_CFG      0xf06b
+#define        F367TER_DEMUX_SWAP      0xf06b0004
+#define        F367TER_DIGAGC_SWAP     0xf06b0002
+#define        F367TER_LONGPATH_IF     0xf06b0001
+
+/* PMC1_FUNC */
+#define        R367TER_PMC1_FUNC       0xf06c
+#define        F367TER_SOFT_RSTN       0xf06c0080
+#define        F367TER_PMC1_AVERAGE_TIME       0xf06c0078
+#define        F367TER_PMC1_WAIT_TIME  0xf06c0006
+#define        F367TER_PMC1_2N_SEL     0xf06c0001
+
+/* PMC1_FOR */
+#define        R367TER_PMC1_FOR        0xf06d
+#define        F367TER_PMC1_FORCE      0xf06d0080
+#define        F367TER_PMC1_FORCE_VALUE        0xf06d007c
+
+/* PMC2_FUNC */
+#define        R367TER_PMC2_FUNC       0xf06e
+#define        F367TER_PMC2_SOFT_STN   0xf06e0080
+#define        F367TER_PMC2_ACCU_TIME  0xf06e0070
+#define        F367TER_PMC2_CMDP_MN    0xf06e0008
+#define        F367TER_PMC2_SWAP       0xf06e0004
+
+/* STATUS_ERR_DA */
+#define        R367TER_STATUS_ERR_DA   0xf06f
+#define        F367TER_COM_USEGAINTRK  0xf06f0080
+#define        F367TER_COM_AGCLOCK     0xf06f0040
+#define        F367TER_AUT_AGCLOCK     0xf06f0020
+#define        F367TER_MIN_ERR_X_LSB   0xf06f000f
+
+/* DIG_AGC_R */
+#define        R367TER_DIG_AGC_R       0xf070
+#define        F367TER_COM_SOFT_RSTN   0xf0700080
+#define        F367TER_COM_AGC_ON      0xf0700040
+#define        F367TER_COM_EARLY       0xf0700020
+#define        F367TER_AUT_SOFT_RESETN 0xf0700010
+#define        F367TER_AUT_AGC_ON      0xf0700008
+#define        F367TER_AUT_EARLY       0xf0700004
+#define        F367TER_AUT_ROT_EN      0xf0700002
+#define        F367TER_LOCK_SOFT_RESETN        0xf0700001
+
+/* COMAGC_TARMSB */
+#define        R367TER_COMAGC_TARMSB   0xf071
+#define        F367TER_COM_AGC_TARGET_MSB      0xf07100ff
+
+/* COM_AGC_TAR_ENMODE */
+#define        R367TER_COM_AGC_TAR_ENMODE      0xf072
+#define        F367TER_COM_AGC_TARGET_LSB      0xf07200f0
+#define        F367TER_COM_ENMODE      0xf072000f
+
+/* COM_AGC_CFG */
+#define        R367TER_COM_AGC_CFG     0xf073
+#define        F367TER_COM_N   0xf07300f8
+#define        F367TER_COM_STABMODE    0xf0730006
+#define        F367TER_ERR_SEL 0xf0730001
+
+/* COM_AGC_GAIN1 */
+#define        R367TER_COM_AGC_GAIN1   0xf074
+#define        F367TER_COM_GAIN1aCK    0xf07400f0
+#define        F367TER_COM_GAIN1TRK    0xf074000f
+
+/* AUT_AGC_TARGETMSB */
+#define        R367TER_AUT_AGC_TARGETMSB       0xf075
+#define        F367TER_AUT_AGC_TARGET_MSB      0xf07500ff
+
+/* LOCK_DET_MSB */
+#define        R367TER_LOCK_DET_MSB    0xf076
+#define        F367TER_LOCK_DETECT_MSB 0xf07600ff
+
+/* AGCTAR_LOCK_LSBS */
+#define        R367TER_AGCTAR_LOCK_LSBS        0xf077
+#define        F367TER_AUT_AGC_TARGET_LSB      0xf07700f0
+#define        F367TER_LOCK_DETECT_LSB 0xf077000f
+
+/* AUT_GAIN_EN */
+#define        R367TER_AUT_GAIN_EN     0xf078
+#define        F367TER_AUT_ENMODE      0xf07800f0
+#define        F367TER_AUT_GAIN2       0xf078000f
+
+/* AUT_CFG */
+#define        R367TER_AUT_CFG 0xf079
+#define        F367TER_AUT_N   0xf07900f8
+#define        F367TER_INT_CHOICE      0xf0790006
+#define        F367TER_INT_LOAD        0xf0790001
+
+/* LOCKN */
+#define        R367TER_LOCKN   0xf07a
+#define        F367TER_LOCK_N  0xf07a00f8
+#define        F367TER_SEL_IQNTAR      0xf07a0004
+#define        F367TER_LOCK_DETECT_CHOICE      0xf07a0003
+
+/* INT_X_3 */
+#define        R367TER_INT_X_3 0xf07b
+#define        F367TER_INT_X3  0xf07b00ff
+
+/* INT_X_2 */
+#define        R367TER_INT_X_2 0xf07c
+#define        F367TER_INT_X2  0xf07c00ff
+
+/* INT_X_1 */
+#define        R367TER_INT_X_1 0xf07d
+#define        F367TER_INT_X1  0xf07d00ff
+
+/* INT_X_0 */
+#define        R367TER_INT_X_0 0xf07e
+#define        F367TER_INT_X0  0xf07e00ff
+
+/* MIN_ERRX_MSB */
+#define        R367TER_MIN_ERRX_MSB    0xf07f
+#define        F367TER_MIN_ERR_X_MSB   0xf07f00ff
+
+/* COR_CTL */
+#define        R367TER_COR_CTL 0xf080
+#define        F367TER_CORE_ACTIVE     0xf0800020
+#define        F367TER_HOLD    0xf0800010
+#define        F367TER_CORE_STATE_CTL  0xf080000f
+
+/* COR_STAT */
+#define        R367TER_COR_STAT        0xf081
+#define        F367TER_SCATT_LOCKED    0xf0810080
+#define        F367TER_TPS_LOCKED      0xf0810040
+#define        F367TER_SYR_LOCKED_COR  0xf0810020
+#define        F367TER_AGC_LOCKED_STAT 0xf0810010
+#define        F367TER_CORE_STATE_STAT 0xf081000f
+
+/* COR_INTEN */
+#define        R367TER_COR_INTEN       0xf082
+#define        F367TER_INTEN   0xf0820080
+#define        F367TER_INTEN_SYR       0xf0820020
+#define        F367TER_INTEN_FFT       0xf0820010
+#define        F367TER_INTEN_AGC       0xf0820008
+#define        F367TER_INTEN_TPS1      0xf0820004
+#define        F367TER_INTEN_TPS2      0xf0820002
+#define        F367TER_INTEN_TPS3      0xf0820001
+
+/* COR_INTSTAT */
+#define        R367TER_COR_INTSTAT     0xf083
+#define        F367TER_INTSTAT_SYR     0xf0830020
+#define        F367TER_INTSTAT_FFT     0xf0830010
+#define        F367TER_INTSAT_AGC      0xf0830008
+#define        F367TER_INTSTAT_TPS1    0xf0830004
+#define        F367TER_INTSTAT_TPS2    0xf0830002
+#define        F367TER_INTSTAT_TPS3    0xf0830001
+
+/* COR_MODEGUARD */
+#define        R367TER_COR_MODEGUARD   0xf084
+#define        F367TER_FORCE   0xf0840010
+#define        F367TER_MODE    0xf084000c
+#define        F367TER_GUARD   0xf0840003
+
+/* AGC_CTL */
+#define        R367TER_AGC_CTL 0xf085
+#define        F367TER_AGC_TIMING_FACTOR       0xf08500e0
+#define        F367TER_AGC_LAST        0xf0850010
+#define        F367TER_AGC_GAIN        0xf085000c
+#define        F367TER_AGC_NEG 0xf0850002
+#define        F367TER_AGC_SET 0xf0850001
+
+/* AGC_MANUAL1 */
+#define        R367TER_AGC_MANUAL1     0xf086
+#define        F367TER_AGC_VAL_LO      0xf08600ff
+
+/* AGC_MANUAL2 */
+#define        R367TER_AGC_MANUAL2     0xf087
+#define        F367TER_AGC_VAL_HI      0xf087000f
+
+/* AGC_TARG */
+#define        R367TER_AGC_TARG        0xf088
+#define        F367TER_AGC_TARGET      0xf08800ff
+
+/* AGC_GAIN1 */
+#define        R367TER_AGC_GAIN1       0xf089
+#define        F367TER_AGC_GAIN_LO     0xf08900ff
+
+/* AGC_GAIN2 */
+#define        R367TER_AGC_GAIN2       0xf08a
+#define        F367TER_AGC_LOCKED_GAIN2        0xf08a0010
+#define        F367TER_AGC_GAIN_HI     0xf08a000f
+
+/* RESERVED_1 */
+#define        R367TER_RESERVED_1      0xf08b
+#define        F367TER_RESERVED1       0xf08b00ff
+
+/* RESERVED_2 */
+#define        R367TER_RESERVED_2      0xf08c
+#define        F367TER_RESERVED2       0xf08c00ff
+
+/* RESERVED_3 */
+#define        R367TER_RESERVED_3      0xf08d
+#define        F367TER_RESERVED3       0xf08d00ff
+
+/* CAS_CTL */
+#define        R367TER_CAS_CTL 0xf08e
+#define        F367TER_CCS_ENABLE      0xf08e0080
+#define        F367TER_ACS_DISABLE     0xf08e0040
+#define        F367TER_DAGC_DIS        0xf08e0020
+#define        F367TER_DAGC_GAIN       0xf08e0018
+#define        F367TER_CCSMU   0xf08e0007
+
+/* CAS_FREQ */
+#define        R367TER_CAS_FREQ        0xf08f
+#define        F367TER_CCS_FREQ        0xf08f00ff
+
+/* CAS_DAGCGAIN */
+#define        R367TER_CAS_DAGCGAIN    0xf090
+#define        F367TER_CAS_DAGC_GAIN   0xf09000ff
+
+/* SYR_CTL */
+#define        R367TER_SYR_CTL 0xf091
+#define        F367TER_SICTH_ENABLE    0xf0910080
+#define        F367TER_LONG_ECHO       0xf0910078
+#define        F367TER_AUTO_LE_EN      0xf0910004
+#define        F367TER_SYR_BYPASS      0xf0910002
+#define        F367TER_SYR_TR_DIS      0xf0910001
+
+/* SYR_STAT */
+#define        R367TER_SYR_STAT        0xf092
+#define        F367TER_SYR_LOCKED_STAT 0xf0920010
+#define        F367TER_SYR_MODE        0xf092000c
+#define        F367TER_SYR_GUARD       0xf0920003
+
+/* SYR_NCO1 */
+#define        R367TER_SYR_NCO1        0xf093
+#define        F367TER_SYR_NCO_LO      0xf09300ff
+
+/* SYR_NCO2 */
+#define        R367TER_SYR_NCO2        0xf094
+#define        F367TER_SYR_NCO_HI      0xf094003f
+
+/* SYR_OFFSET1 */
+#define        R367TER_SYR_OFFSET1     0xf095
+#define        F367TER_SYR_OFFSET_LO   0xf09500ff
+
+/* SYR_OFFSET2 */
+#define        R367TER_SYR_OFFSET2     0xf096
+#define        F367TER_SYR_OFFSET_HI   0xf096003f
+
+/* FFT_CTL */
+#define        R367TER_FFT_CTL 0xf097
+#define        F367TER_SHIFT_FFT_TRIG  0xf0970018
+#define        F367TER_FFT_TRIGGER     0xf0970004
+#define        F367TER_FFT_MANUAL      0xf0970002
+#define        F367TER_IFFT_MODE       0xf0970001
+
+/* SCR_CTL */
+#define        R367TER_SCR_CTL 0xf098
+#define        F367TER_SYRADJDECAY     0xf0980070
+#define        F367TER_SCR_CPEDIS      0xf0980002
+#define        F367TER_SCR_DIS 0xf0980001
+
+/* PPM_CTL1 */
+#define        R367TER_PPM_CTL1        0xf099
+#define        F367TER_PPM_MAXFREQ     0xf0990030
+#define        F367TER_PPM_MAXTIM      0xf0990008
+#define        F367TER_PPM_INVSEL      0xf0990004
+#define        F367TER_PPM_SCATDIS     0xf0990002
+#define        F367TER_PPM_BYP 0xf0990001
+
+/* TRL_CTL */
+#define        R367TER_TRL_CTL 0xf09a
+#define        F367TER_TRL_NOMRATE_LSB 0xf09a0080
+#define        F367TER_TRL_GAIN_FACTOR 0xf09a0078
+#define        F367TER_TRL_LOOPGAIN    0xf09a0007
+
+/* TRL_NOMRATE1 */
+#define        R367TER_TRL_NOMRATE1    0xf09b
+#define        F367TER_TRL_NOMRATE_LO  0xf09b00ff
+
+/* TRL_NOMRATE2 */
+#define        R367TER_TRL_NOMRATE2    0xf09c
+#define        F367TER_TRL_NOMRATE_HI  0xf09c00ff
+
+/* TRL_TIME1 */
+#define        R367TER_TRL_TIME1       0xf09d
+#define        F367TER_TRL_TOFFSET_LO  0xf09d00ff
+
+/* TRL_TIME2 */
+#define        R367TER_TRL_TIME2       0xf09e
+#define        F367TER_TRL_TOFFSET_HI  0xf09e00ff
+
+/* CRL_CTL */
+#define        R367TER_CRL_CTL 0xf09f
+#define        F367TER_CRL_DIS 0xf09f0080
+#define        F367TER_CRL_GAIN_FACTOR 0xf09f0078
+#define        F367TER_CRL_LOOPGAIN    0xf09f0007
+
+/* CRL_FREQ1 */
+#define        R367TER_CRL_FREQ1       0xf0a0
+#define        F367TER_CRL_FOFFSET_LO  0xf0a000ff
+
+/* CRL_FREQ2 */
+#define        R367TER_CRL_FREQ2       0xf0a1
+#define        F367TER_CRL_FOFFSET_HI  0xf0a100ff
+
+/* CRL_FREQ3 */
+#define        R367TER_CRL_FREQ3       0xf0a2
+#define        F367TER_CRL_FOFFSET_VHI 0xf0a200ff
+
+/* TPS_SFRAME_CTL */
+#define        R367TER_TPS_SFRAME_CTL  0xf0a3
+#define        F367TER_TPS_SFRAME_SYNC 0xf0a30001
+
+/* CHC_SNR */
+#define        R367TER_CHC_SNR 0xf0a4
+#define        F367TER_CHCSNR  0xf0a400ff
+
+/* BDI_CTL */
+#define        R367TER_BDI_CTL 0xf0a5
+#define        F367TER_BDI_LPSEL       0xf0a50002
+#define        F367TER_BDI_SERIAL      0xf0a50001
+
+/* DMP_CTL */
+#define        R367TER_DMP_CTL 0xf0a6
+#define        F367TER_DMP_SCALING_FACTOR      0xf0a6001e
+#define        F367TER_DMP_SDDIS       0xf0a60001
+
+/* TPS_RCVD1 */
+#define        R367TER_TPS_RCVD1       0xf0a7
+#define        F367TER_TPS_CHANGE      0xf0a70040
+#define        F367TER_BCH_OK  0xf0a70020
+#define        F367TER_TPS_SYNC        0xf0a70010
+#define        F367TER_TPS_FRAME       0xf0a70003
+
+/* TPS_RCVD2 */
+#define        R367TER_TPS_RCVD2       0xf0a8
+#define        F367TER_TPS_HIERMODE    0xf0a80070
+#define        F367TER_TPS_CONST       0xf0a80003
+
+/* TPS_RCVD3 */
+#define        R367TER_TPS_RCVD3       0xf0a9
+#define        F367TER_TPS_LPCODE      0xf0a90070
+#define        F367TER_TPS_HPCODE      0xf0a90007
+
+/* TPS_RCVD4 */
+#define        R367TER_TPS_RCVD4       0xf0aa
+#define        F367TER_TPS_GUARD       0xf0aa0030
+#define        F367TER_TPS_MODE        0xf0aa0003
+
+/* TPS_ID_CELL1 */
+#define        R367TER_TPS_ID_CELL1    0xf0ab
+#define        F367TER_TPS_ID_CELL_LO  0xf0ab00ff
+
+/* TPS_ID_CELL2 */
+#define        R367TER_TPS_ID_CELL2    0xf0ac
+#define        F367TER_TPS_ID_CELL_HI  0xf0ac00ff
+
+/* TPS_RCVD5_SET1 */
+#define        R367TER_TPS_RCVD5_SET1  0xf0ad
+#define        F367TER_TPS_NA  0xf0ad00fC
+#define        F367TER_TPS_SETFRAME    0xf0ad0003
+
+/* TPS_SET2 */
+#define        R367TER_TPS_SET2        0xf0ae
+#define        F367TER_TPS_SETHIERMODE 0xf0ae0070
+#define        F367TER_TPS_SETCONST    0xf0ae0003
+
+/* TPS_SET3 */
+#define        R367TER_TPS_SET3        0xf0af
+#define        F367TER_TPS_SETLPCODE   0xf0af0070
+#define        F367TER_TPS_SETHPCODE   0xf0af0007
+
+/* TPS_CTL */
+#define        R367TER_TPS_CTL 0xf0b0
+#define        F367TER_TPS_IMM 0xf0b00004
+#define        F367TER_TPS_BCHDIS      0xf0b00002
+#define        F367TER_TPS_UPDDIS      0xf0b00001
+
+/* CTL_FFTOSNUM */
+#define        R367TER_CTL_FFTOSNUM    0xf0b1
+#define        F367TER_SYMBOL_NUMBER   0xf0b1007f
+
+/* TESTSELECT */
+#define        R367TER_TESTSELECT      0xf0b2
+#define        F367TER_TEST_SELECT     0xf0b2001f
+
+/* MSC_REV */
+#define        R367TER_MSC_REV 0xf0b3
+#define        F367TER_REV_NUMBER      0xf0b300ff
+
+/* PIR_CTL */
+#define        R367TER_PIR_CTL 0xf0b4
+#define        F367TER_FREEZE  0xf0b40001
+
+/* SNR_CARRIER1 */
+#define        R367TER_SNR_CARRIER1    0xf0b5
+#define        F367TER_SNR_CARRIER_LO  0xf0b500ff
+
+/* SNR_CARRIER2 */
+#define        R367TER_SNR_CARRIER2    0xf0b6
+#define        F367TER_MEAN    0xf0b600c0
+#define        F367TER_SNR_CARRIER_HI  0xf0b6001f
+
+/* PPM_CPAMP */
+#define        R367TER_PPM_CPAMP       0xf0b7
+#define        F367TER_PPM_CPC 0xf0b700ff
+
+/* TSM_AP0 */
+#define        R367TER_TSM_AP0 0xf0b8
+#define        F367TER_ADDRESS_BYTE_0  0xf0b800ff
+
+/* TSM_AP1 */
+#define        R367TER_TSM_AP1 0xf0b9
+#define        F367TER_ADDRESS_BYTE_1  0xf0b900ff
+
+/* TSM_AP2 */
+#define        R367TER_TSM_AP2 0xf0bA
+#define        F367TER_DATA_BYTE_0     0xf0ba00ff
+
+/* TSM_AP3 */
+#define        R367TER_TSM_AP3 0xf0bB
+#define        F367TER_DATA_BYTE_1     0xf0bb00ff
+
+/* TSM_AP4 */
+#define        R367TER_TSM_AP4 0xf0bC
+#define        F367TER_DATA_BYTE_2     0xf0bc00ff
+
+/* TSM_AP5 */
+#define        R367TER_TSM_AP5 0xf0bD
+#define        F367TER_DATA_BYTE_3     0xf0bd00ff
+
+/* TSM_AP6 */
+#define        R367TER_TSM_AP6 0xf0bE
+#define        F367TER_TSM_AP_6        0xf0be00ff
+
+/* TSM_AP7 */
+#define        R367TER_TSM_AP7 0xf0bF
+#define        F367TER_MEM_SELECT_BYTE 0xf0bf00ff
+
+/* TSTRES */
+#define        R367TER_TSTRES  0xf0c0
+#define        F367TER_FRES_DISPLAY    0xf0c00080
+#define        F367TER_FRES_FIFO_AD    0xf0c00020
+#define        F367TER_FRESRS  0xf0c00010
+#define        F367TER_FRESACS 0xf0c00008
+#define        F367TER_FRESFEC 0xf0c00004
+#define        F367TER_FRES_PRIF       0xf0c00002
+#define        F367TER_FRESCORE        0xf0c00001
+
+/* ANACTRL */
+#define        R367TER_ANACTRL 0xf0c1
+#define        F367TER_BYPASS_XTAL     0xf0c10040
+#define        F367TER_BYPASS_PLLXN    0xf0c1000c
+#define        F367TER_DIS_PAD_OSC     0xf0c10002
+#define        F367TER_STDBY_PLLXN     0xf0c10001
+
+/* TSTBUS */
+#define        R367TER_TSTBUS  0xf0c2
+#define        F367TER_TS_BYTE_CLK_INV 0xf0c20080
+#define        F367TER_CFG_IP  0xf0c20070
+#define        F367TER_CFG_TST 0xf0c2000f
+
+/* TSTRATE */
+#define        R367TER_TSTRATE 0xf0c6
+#define        F367TER_FORCEPHA        0xf0c60080
+#define        F367TER_FNEWPHA 0xf0c60010
+#define        F367TER_FROT90  0xf0c60008
+#define        F367TER_FR      0xf0c60007
+
+/* CONSTMODE */
+#define        R367TER_CONSTMODE       0xf0cb
+#define        F367TER_TST_PRIF        0xf0cb00e0
+#define        F367TER_CAR_TYPE        0xf0cb0018
+#define        F367TER_CONST_MODE      0xf0cb0003
+
+/* CONSTCARR1 */
+#define        R367TER_CONSTCARR1      0xf0cc
+#define        F367TER_CONST_CARR_LO   0xf0cc00ff
+
+/* CONSTCARR2 */
+#define        R367TER_CONSTCARR2      0xf0cd
+#define        F367TER_CONST_CARR_HI   0xf0cd001f
+
+/* ICONSTEL */
+#define        R367TER_ICONSTEL        0xf0ce
+#define        F367TER_PICONSTEL       0xf0ce00ff
+
+/* QCONSTEL */
+#define        R367TER_QCONSTEL        0xf0cf
+#define        F367TER_PQCONSTEL       0xf0cf00ff
+
+/* TSTBISTRES0 */
+#define        R367TER_TSTBISTRES0     0xf0d0
+#define        F367TER_BEND_PPM        0xf0d00080
+#define        F367TER_BBAD_PPM        0xf0d00040
+#define        F367TER_BEND_FFTW       0xf0d00020
+#define        F367TER_BBAD_FFTW       0xf0d00010
+#define        F367TER_BEND_FFT_BUF    0xf0d00008
+#define        F367TER_BBAD_FFT_BUF    0xf0d00004
+#define        F367TER_BEND_SYR        0xf0d00002
+#define        F367TER_BBAD_SYR        0xf0d00001
+
+/* TSTBISTRES1 */
+#define        R367TER_TSTBISTRES1     0xf0d1
+#define        F367TER_BEND_CHC_CP     0xf0d10080
+#define        F367TER_BBAD_CHC_CP     0xf0d10040
+#define        F367TER_BEND_CHCI       0xf0d10020
+#define        F367TER_BBAD_CHCI       0xf0d10010
+#define        F367TER_BEND_BDI        0xf0d10008
+#define        F367TER_BBAD_BDI        0xf0d10004
+#define        F367TER_BEND_SDI        0xf0d10002
+#define        F367TER_BBAD_SDI        0xf0d10001
+
+/* TSTBISTRES2 */
+#define        R367TER_TSTBISTRES2     0xf0d2
+#define        F367TER_BEND_CHC_INC    0xf0d20080
+#define        F367TER_BBAD_CHC_INC    0xf0d20040
+#define        F367TER_BEND_CHC_SPP    0xf0d20020
+#define        F367TER_BBAD_CHC_SPP    0xf0d20010
+#define        F367TER_BEND_CHC_CPP    0xf0d20008
+#define        F367TER_BBAD_CHC_CPP    0xf0d20004
+#define        F367TER_BEND_CHC_SP     0xf0d20002
+#define        F367TER_BBAD_CHC_SP     0xf0d20001
+
+/* TSTBISTRES3 */
+#define        R367TER_TSTBISTRES3     0xf0d3
+#define        F367TER_BEND_QAM        0xf0d30080
+#define        F367TER_BBAD_QAM        0xf0d30040
+#define        F367TER_BEND_SFEC_VIT   0xf0d30020
+#define        F367TER_BBAD_SFEC_VIT   0xf0d30010
+#define        F367TER_BEND_SFEC_DLINE 0xf0d30008
+#define        F367TER_BBAD_SFEC_DLINE 0xf0d30004
+#define        F367TER_BEND_SFEC_HW    0xf0d30002
+#define        F367TER_BBAD_SFEC_HW    0xf0d30001
+
+/* RF_AGC1 */
+#define        R367TER_RF_AGC1 0xf0d4
+#define        F367TER_RF_AGC1_LEVEL_HI        0xf0d400ff
+
+/* RF_AGC2 */
+#define        R367TER_RF_AGC2 0xf0d5
+#define        F367TER_REF_ADGP        0xf0d50080
+#define        F367TER_STDBY_ADCGP     0xf0d50020
+#define        F367TER_CHANNEL_SEL     0xf0d5001c
+#define        F367TER_RF_AGC1_LEVEL_LO        0xf0d50003
+
+/* ANADIGCTRL */
+#define        R367TER_ANADIGCTRL      0xf0d7
+#define        F367TER_SEL_CLKDEM      0xf0d70020
+#define        F367TER_EN_BUFFER_Q     0xf0d70010
+#define        F367TER_EN_BUFFER_I     0xf0d70008
+#define        F367TER_ADC_RIS_EGDE    0xf0d70004
+#define        F367TER_SGN_ADC 0xf0d70002
+#define        F367TER_SEL_AD12_SYNC   0xf0d70001
+
+/* PLLMDIV */
+#define        R367TER_PLLMDIV 0xf0d8
+#define        F367TER_PLL_MDIV        0xf0d800ff
+
+/* PLLNDIV */
+#define        R367TER_PLLNDIV 0xf0d9
+#define        F367TER_PLL_NDIV        0xf0d900ff
+
+/* PLLSETUP */
+#define        R367TER_PLLSETUP        0xf0dA
+#define        F367TER_PLL_PDIV        0xf0da0070
+#define        F367TER_PLL_KDIV        0xf0da000f
+
+/* DUAL_AD12 */
+#define        R367TER_DUAL_AD12       0xf0dB
+#define        F367TER_FS20M   0xf0db0020
+#define        F367TER_FS50M   0xf0db0010
+#define        F367TER_INMODe0 0xf0db0008
+#define        F367TER_POFFQ   0xf0db0004
+#define        F367TER_POFFI   0xf0db0002
+#define        F367TER_INMODE1 0xf0db0001
+
+/* TSTBIST */
+#define        R367TER_TSTBIST 0xf0dC
+#define        F367TER_TST_BYP_CLK     0xf0dc0080
+#define        F367TER_TST_GCLKENA_STD 0xf0dc0040
+#define        F367TER_TST_GCLKENA     0xf0dc0020
+#define        F367TER_TST_MEMBIST     0xf0dc001f
+
+/* PAD_COMP_CTRL */
+#define        R367TER_PAD_COMP_CTRL   0xf0dD
+#define        F367TER_COMPTQ  0xf0dd0010
+#define        F367TER_COMPEN  0xf0dd0008
+#define        F367TER_FREEZE2 0xf0dd0004
+#define        F367TER_SLEEP_INHBT     0xf0dd0002
+#define        F367TER_CHIP_SLEEP      0xf0dd0001
+
+/* PAD_COMP_WR */
+#define        R367TER_PAD_COMP_WR     0xf0de
+#define        F367TER_WR_ASRC 0xf0de007f
+
+/* PAD_COMP_RD */
+#define        R367TER_PAD_COMP_RD     0xf0df
+#define        F367TER_COMPOK  0xf0df0080
+#define        F367TER_RD_ASRC 0xf0df007f
+
+/* SYR_TARGET_FFTADJT_MSB */
+#define        R367TER_SYR_TARGET_FFTADJT_MSB  0xf100
+#define        F367TER_SYR_START       0xf1000080
+#define        F367TER_SYR_TARGET_FFTADJ_HI    0xf100000f
+
+/* SYR_TARGET_FFTADJT_LSB */
+#define        R367TER_SYR_TARGET_FFTADJT_LSB  0xf101
+#define        F367TER_SYR_TARGET_FFTADJ_LO    0xf10100ff
+
+/* SYR_TARGET_CHCADJT_MSB */
+#define        R367TER_SYR_TARGET_CHCADJT_MSB  0xf102
+#define        F367TER_SYR_TARGET_CHCADJ_HI    0xf102000f
+
+/* SYR_TARGET_CHCADJT_LSB */
+#define        R367TER_SYR_TARGET_CHCADJT_LSB  0xf103
+#define        F367TER_SYR_TARGET_CHCADJ_LO    0xf10300ff
+
+/* SYR_FLAG */
+#define        R367TER_SYR_FLAG        0xf104
+#define        F367TER_TRIG_FLG1       0xf1040080
+#define        F367TER_TRIG_FLG0       0xf1040040
+#define        F367TER_FFT_FLG1        0xf1040008
+#define        F367TER_FFT_FLG0        0xf1040004
+#define        F367TER_CHC_FLG1        0xf1040002
+#define        F367TER_CHC_FLG0        0xf1040001
+
+/* CRL_TARGET1 */
+#define        R367TER_CRL_TARGET1     0xf105
+#define        F367TER_CRL_START       0xf1050080
+#define        F367TER_CRL_TARGET_VHI  0xf105000f
+
+/* CRL_TARGET2 */
+#define        R367TER_CRL_TARGET2     0xf106
+#define        F367TER_CRL_TARGET_HI   0xf10600ff
+
+/* CRL_TARGET3 */
+#define        R367TER_CRL_TARGET3     0xf107
+#define        F367TER_CRL_TARGET_LO   0xf10700ff
+
+/* CRL_TARGET4 */
+#define        R367TER_CRL_TARGET4     0xf108
+#define        F367TER_CRL_TARGET_VLO  0xf10800ff
+
+/* CRL_FLAG */
+#define        R367TER_CRL_FLAG        0xf109
+#define        F367TER_CRL_FLAG1       0xf1090002
+#define        F367TER_CRL_FLAG0       0xf1090001
+
+/* TRL_TARGET1 */
+#define        R367TER_TRL_TARGET1     0xf10a
+#define        F367TER_TRL_TARGET_HI   0xf10a00ff
+
+/* TRL_TARGET2 */
+#define        R367TER_TRL_TARGET2     0xf10b
+#define        F367TER_TRL_TARGET_LO   0xf10b00ff
+
+/* TRL_CHC */
+#define        R367TER_TRL_CHC 0xf10c
+#define        F367TER_TRL_START       0xf10c0080
+#define        F367TER_CHC_START       0xf10c0040
+#define        F367TER_TRL_FLAG1       0xf10c0002
+#define        F367TER_TRL_FLAG0       0xf10c0001
+
+/* CHC_SNR_TARG */
+#define        R367TER_CHC_SNR_TARG    0xf10d
+#define        F367TER_CHC_SNR_TARGET  0xf10d00ff
+
+/* TOP_TRACK */
+#define        R367TER_TOP_TRACK       0xf10e
+#define        F367TER_TOP_START       0xf10e0080
+#define        F367TER_FIRST_FLAG      0xf10e0070
+#define        F367TER_TOP_FLAG1       0xf10e0008
+#define        F367TER_TOP_FLAG0       0xf10e0004
+#define        F367TER_CHC_FLAG1       0xf10e0002
+#define        F367TER_CHC_FLAG0       0xf10e0001
+
+/* TRACKER_FREE1 */
+#define        R367TER_TRACKER_FREE1   0xf10f
+#define        F367TER_TRACKER_FREE_1  0xf10f00ff
+
+/* ERROR_CRL1 */
+#define        R367TER_ERROR_CRL1      0xf110
+#define        F367TER_ERROR_CRL_VHI   0xf11000ff
+
+/* ERROR_CRL2 */
+#define        R367TER_ERROR_CRL2      0xf111
+#define        F367TER_ERROR_CRL_HI    0xf11100ff
+
+/* ERROR_CRL3 */
+#define        R367TER_ERROR_CRL3      0xf112
+#define        F367TER_ERROR_CRL_LOI   0xf11200ff
+
+/* ERROR_CRL4 */
+#define        R367TER_ERROR_CRL4      0xf113
+#define        F367TER_ERROR_CRL_VLO   0xf11300ff
+
+/* DEC_NCO1 */
+#define        R367TER_DEC_NCO1        0xf114
+#define        F367TER_DEC_NCO_VHI     0xf11400ff
+
+/* DEC_NCO2 */
+#define        R367TER_DEC_NCO2        0xf115
+#define        F367TER_DEC_NCO_HI      0xf11500ff
+
+/* DEC_NCO3 */
+#define        R367TER_DEC_NCO3        0xf116
+#define        F367TER_DEC_NCO_LO      0xf11600ff
+
+/* SNR */
+#define        R367TER_SNR     0xf117
+#define        F367TER_SNRATIO 0xf11700ff
+
+/* SYR_FFTADJ1 */
+#define        R367TER_SYR_FFTADJ1     0xf118
+#define        F367TER_SYR_FFTADJ_HI   0xf11800ff
+
+/* SYR_FFTADJ2 */
+#define        R367TER_SYR_FFTADJ2     0xf119
+#define        F367TER_SYR_FFTADJ_LO   0xf11900ff
+
+/* SYR_CHCADJ1 */
+#define        R367TER_SYR_CHCADJ1     0xf11a
+#define        F367TER_SYR_CHCADJ_HI   0xf11a00ff
+
+/* SYR_CHCADJ2 */
+#define        R367TER_SYR_CHCADJ2     0xf11b
+#define        F367TER_SYR_CHCADJ_LO   0xf11b00ff
+
+/* SYR_OFF */
+#define        R367TER_SYR_OFF 0xf11c
+#define        F367TER_SYR_OFFSET      0xf11c00ff
+
+/* PPM_OFFSET1 */
+#define        R367TER_PPM_OFFSET1     0xf11d
+#define        F367TER_PPM_OFFSET_HI   0xf11d00ff
+
+/* PPM_OFFSET2 */
+#define        R367TER_PPM_OFFSET2     0xf11e
+#define        F367TER_PPM_OFFSET_LO   0xf11e00ff
+
+/* TRACKER_FREE2 */
+#define        R367TER_TRACKER_FREE2   0xf11f
+#define        F367TER_TRACKER_FREE_2  0xf11f00ff
+
+/* DEBG_LT10 */
+#define        R367TER_DEBG_LT10       0xf120
+#define        F367TER_DEBUG_LT10      0xf12000ff
+
+/* DEBG_LT11 */
+#define        R367TER_DEBG_LT11       0xf121
+#define        F367TER_DEBUG_LT11      0xf12100ff
+
+/* DEBG_LT12 */
+#define        R367TER_DEBG_LT12       0xf122
+#define        F367TER_DEBUG_LT12      0xf12200ff
+
+/* DEBG_LT13 */
+#define        R367TER_DEBG_LT13       0xf123
+#define        F367TER_DEBUG_LT13      0xf12300ff
+
+/* DEBG_LT14 */
+#define        R367TER_DEBG_LT14       0xf124
+#define        F367TER_DEBUG_LT14      0xf12400ff
+
+/* DEBG_LT15 */
+#define        R367TER_DEBG_LT15       0xf125
+#define        F367TER_DEBUG_LT15      0xf12500ff
+
+/* DEBG_LT16 */
+#define        R367TER_DEBG_LT16       0xf126
+#define        F367TER_DEBUG_LT16      0xf12600ff
+
+/* DEBG_LT17 */
+#define        R367TER_DEBG_LT17       0xf127
+#define        F367TER_DEBUG_LT17      0xf12700ff
+
+/* DEBG_LT18 */
+#define        R367TER_DEBG_LT18       0xf128
+#define        F367TER_DEBUG_LT18      0xf12800ff
+
+/* DEBG_LT19 */
+#define        R367TER_DEBG_LT19       0xf129
+#define        F367TER_DEBUG_LT19      0xf12900ff
+
+/* DEBG_LT1a */
+#define        R367TER_DEBG_LT1A       0xf12a
+#define        F367TER_DEBUG_LT1A      0xf12a00ff
+
+/* DEBG_LT1b */
+#define        R367TER_DEBG_LT1B       0xf12b
+#define        F367TER_DEBUG_LT1B      0xf12b00ff
+
+/* DEBG_LT1c */
+#define        R367TER_DEBG_LT1C       0xf12c
+#define        F367TER_DEBUG_LT1C      0xf12c00ff
+
+/* DEBG_LT1D */
+#define        R367TER_DEBG_LT1D       0xf12d
+#define        F367TER_DEBUG_LT1D      0xf12d00ff
+
+/* DEBG_LT1E */
+#define        R367TER_DEBG_LT1E       0xf12e
+#define        F367TER_DEBUG_LT1E      0xf12e00ff
+
+/* DEBG_LT1F */
+#define        R367TER_DEBG_LT1F       0xf12f
+#define        F367TER_DEBUG_LT1F      0xf12f00ff
+
+/* RCCFGH */
+#define        R367TER_RCCFGH  0xf200
+#define        F367TER_TSRCFIFO_DVBCI  0xf2000080
+#define        F367TER_TSRCFIFO_SERIAL 0xf2000040
+#define        F367TER_TSRCFIFO_DISABLE        0xf2000020
+#define        F367TER_TSFIFO_2TORC    0xf2000010
+#define        F367TER_TSRCFIFO_HSGNLOUT       0xf2000008
+#define        F367TER_TSRCFIFO_ERRMODE        0xf2000006
+#define        F367TER_RCCFGH_0        0xf2000001
+
+/* RCCFGM */
+#define        R367TER_RCCFGM  0xf201
+#define        F367TER_TSRCFIFO_MANSPEED       0xf20100c0
+#define        F367TER_TSRCFIFO_PERMDATA       0xf2010020
+#define        F367TER_TSRCFIFO_NONEWSGNL      0xf2010010
+#define        F367TER_RCBYTE_OVERSAMPLING     0xf201000e
+#define        F367TER_TSRCFIFO_INVDATA        0xf2010001
+
+/* RCCFGL */
+#define        R367TER_RCCFGL  0xf202
+#define        F367TER_TSRCFIFO_BCLKDEL1cK     0xf20200c0
+#define        F367TER_RCCFGL_5        0xf2020020
+#define        F367TER_TSRCFIFO_DUTY50 0xf2020010
+#define        F367TER_TSRCFIFO_NSGNL2dATA     0xf2020008
+#define        F367TER_TSRCFIFO_DISSERMUX      0xf2020004
+#define        F367TER_RCCFGL_1        0xf2020002
+#define        F367TER_TSRCFIFO_STOPCKDIS      0xf2020001
+
+/* RCINSDELH */
+#define        R367TER_RCINSDELH       0xf203
+#define        F367TER_TSRCDEL_SYNCBYTE        0xf2030080
+#define        F367TER_TSRCDEL_XXHEADER        0xf2030040
+#define        F367TER_TSRCDEL_BBHEADER        0xf2030020
+#define        F367TER_TSRCDEL_DATAFIELD       0xf2030010
+#define        F367TER_TSRCINSDEL_ISCR 0xf2030008
+#define        F367TER_TSRCINSDEL_NPD  0xf2030004
+#define        F367TER_TSRCINSDEL_RSPARITY     0xf2030002
+#define        F367TER_TSRCINSDEL_CRC8 0xf2030001
+
+/* RCINSDELM */
+#define        R367TER_RCINSDELM       0xf204
+#define        F367TER_TSRCINS_BBPADDING       0xf2040080
+#define        F367TER_TSRCINS_BCHFEC  0xf2040040
+#define        F367TER_TSRCINS_LDPCFEC 0xf2040020
+#define        F367TER_TSRCINS_EMODCOD 0xf2040010
+#define        F367TER_TSRCINS_TOKEN   0xf2040008
+#define        F367TER_TSRCINS_XXXERR  0xf2040004
+#define        F367TER_TSRCINS_MATYPE  0xf2040002
+#define        F367TER_TSRCINS_UPL     0xf2040001
+
+/* RCINSDELL */
+#define        R367TER_RCINSDELL       0xf205
+#define        F367TER_TSRCINS_DFL     0xf2050080
+#define        F367TER_TSRCINS_SYNCD   0xf2050040
+#define        F367TER_TSRCINS_BLOCLEN 0xf2050020
+#define        F367TER_TSRCINS_SIGPCOUNT       0xf2050010
+#define        F367TER_TSRCINS_FIFO    0xf2050008
+#define        F367TER_TSRCINS_REALPACK        0xf2050004
+#define        F367TER_TSRCINS_TSCONFIG        0xf2050002
+#define        F367TER_TSRCINS_LATENCY 0xf2050001
+
+/* RCSTATUS */
+#define        R367TER_RCSTATUS        0xf206
+#define        F367TER_TSRCFIFO_LINEOK 0xf2060080
+#define        F367TER_TSRCFIFO_ERROR  0xf2060040
+#define        F367TER_TSRCFIFO_DATA7  0xf2060020
+#define        F367TER_RCSTATUS_4      0xf2060010
+#define        F367TER_TSRCFIFO_DEMODSEL       0xf2060008
+#define        F367TER_TSRC1FIFOSPEED_STORE    0xf2060004
+#define        F367TER_RCSTATUS_1      0xf2060002
+#define        F367TER_TSRCSERIAL_IMPOSSIBLE   0xf2060001
+
+/* RCSPEED */
+#define        R367TER_RCSPEED 0xf207
+#define        F367TER_TSRCFIFO_OUTSPEED       0xf20700ff
+
+/* RCDEBUGM */
+#define        R367TER_RCDEBUGM        0xf208
+#define        F367TER_SD_UNSYNC       0xf2080080
+#define        F367TER_ULFLOCK_DETECTM 0xf2080040
+#define        F367TER_SUL_SELECTOS    0xf2080020
+#define        F367TER_DILUL_NOSCRBLE  0xf2080010
+#define        F367TER_NUL_SCRB        0xf2080008
+#define        F367TER_UL_SCRB 0xf2080004
+#define        F367TER_SCRAULBAD       0xf2080002
+#define        F367TER_SCRAUL_UNSYNC   0xf2080001
+
+/* RCDEBUGL */
+#define        R367TER_RCDEBUGL        0xf209
+#define        F367TER_RS_ERR  0xf2090080
+#define        F367TER_LLFLOCK_DETECTM 0xf2090040
+#define        F367TER_NOT_SUL_SELECTOS        0xf2090020
+#define        F367TER_DILLL_NOSCRBLE  0xf2090010
+#define        F367TER_NLL_SCRB        0xf2090008
+#define        F367TER_LL_SCRB 0xf2090004
+#define        F367TER_SCRALLBAD       0xf2090002
+#define        F367TER_SCRALL_UNSYNC   0xf2090001
+
+/* RCOBSCFG */
+#define        R367TER_RCOBSCFG        0xf20a
+#define        F367TER_TSRCFIFO_OBSCFG 0xf20a00ff
+
+/* RCOBSM */
+#define        R367TER_RCOBSM  0xf20b
+#define        F367TER_TSRCFIFO_OBSDATA_HI     0xf20b00ff
+
+/* RCOBSL */
+#define        R367TER_RCOBSL  0xf20c
+#define        F367TER_TSRCFIFO_OBSDATA_LO     0xf20c00ff
+
+/* RCFECSPY */
+#define        R367TER_RCFECSPY        0xf210
+#define        F367TER_SPYRC_ENABLE    0xf2100080
+#define        F367TER_RCNO_SYNCBYTE   0xf2100040
+#define        F367TER_RCSERIAL_MODE   0xf2100020
+#define        F367TER_RCUNUSUAL_PACKET        0xf2100010
+#define        F367TER_BERRCMETER_DATAMODE     0xf210000c
+#define        F367TER_BERRCMETER_LMODE        0xf2100002
+#define        F367TER_BERRCMETER_RESET        0xf2100001
+
+/* RCFSPYCFG */
+#define        R367TER_RCFSPYCFG       0xf211
+#define        F367TER_FECSPYRC_INPUT  0xf21100c0
+#define        F367TER_RCRST_ON_ERROR  0xf2110020
+#define        F367TER_RCONE_SHOT      0xf2110010
+#define        F367TER_RCI2C_MODE      0xf211000c
+#define        F367TER_SPYRC_HSTERESIS 0xf2110003
+
+/* RCFSPYDATA */
+#define        R367TER_RCFSPYDATA      0xf212
+#define        F367TER_SPYRC_STUFFING  0xf2120080
+#define        F367TER_RCNOERR_PKTJITTER       0xf2120040
+#define        F367TER_SPYRC_CNULLPKT  0xf2120020
+#define        F367TER_SPYRC_OUTDATA_MODE      0xf212001f
+
+/* RCFSPYOUT */
+#define        R367TER_RCFSPYOUT       0xf213
+#define        F367TER_FSPYRC_DIRECT   0xf2130080
+#define        F367TER_RCFSPYOUT_6     0xf2130040
+#define        F367TER_SPYRC_OUTDATA_BUS       0xf2130038
+#define        F367TER_RCSTUFF_MODE    0xf2130007
+
+/* RCFSTATUS */
+#define        R367TER_RCFSTATUS       0xf214
+#define        F367TER_SPYRC_ENDSIM    0xf2140080
+#define        F367TER_RCVALID_SIM     0xf2140040
+#define        F367TER_RCFOUND_SIGNAL  0xf2140020
+#define        F367TER_RCDSS_SYNCBYTE  0xf2140010
+#define        F367TER_RCRESULT_STATE  0xf214000f
+
+/* RCFGOODPACK */
+#define        R367TER_RCFGOODPACK     0xf215
+#define        F367TER_RCGOOD_PACKET   0xf21500ff
+
+/* RCFPACKCNT */
+#define        R367TER_RCFPACKCNT      0xf216
+#define        F367TER_RCPACKET_COUNTER        0xf21600ff
+
+/* RCFSPYMISC */
+#define        R367TER_RCFSPYMISC      0xf217
+#define        F367TER_RCLABEL_COUNTER 0xf21700ff
+
+/* RCFBERCPT4 */
+#define        R367TER_RCFBERCPT4      0xf218
+#define        F367TER_FBERRCMETER_CPT_MMMMSB  0xf21800ff
+
+/* RCFBERCPT3 */
+#define        R367TER_RCFBERCPT3      0xf219
+#define        F367TER_FBERRCMETER_CPT_MMMSB   0xf21900ff
+
+/* RCFBERCPT2 */
+#define        R367TER_RCFBERCPT2      0xf21a
+#define        F367TER_FBERRCMETER_CPT_MMSB    0xf21a00ff
+
+/* RCFBERCPT1 */
+#define        R367TER_RCFBERCPT1      0xf21b
+#define        F367TER_FBERRCMETER_CPT_MSB     0xf21b00ff
+
+/* RCFBERCPT0 */
+#define        R367TER_RCFBERCPT0      0xf21c
+#define        F367TER_FBERRCMETER_CPT_LSB     0xf21c00ff
+
+/* RCFBERERR2 */
+#define        R367TER_RCFBERERR2      0xf21d
+#define        F367TER_FBERRCMETER_ERR_HI      0xf21d00ff
+
+/* RCFBERERR1 */
+#define        R367TER_RCFBERERR1      0xf21e
+#define        F367TER_FBERRCMETER_ERR 0xf21e00ff
+
+/* RCFBERERR0 */
+#define        R367TER_RCFBERERR0      0xf21f
+#define        F367TER_FBERRCMETER_ERR_LO      0xf21f00ff
+
+/* RCFSTATESM */
+#define        R367TER_RCFSTATESM      0xf220
+#define        F367TER_RCRSTATE_F      0xf2200080
+#define        F367TER_RCRSTATE_E      0xf2200040
+#define        F367TER_RCRSTATE_D      0xf2200020
+#define        F367TER_RCRSTATE_C      0xf2200010
+#define        F367TER_RCRSTATE_B      0xf2200008
+#define        F367TER_RCRSTATE_A      0xf2200004
+#define        F367TER_RCRSTATE_9      0xf2200002
+#define        F367TER_RCRSTATE_8      0xf2200001
+
+/* RCFSTATESL */
+#define        R367TER_RCFSTATESL      0xf221
+#define        F367TER_RCRSTATE_7      0xf2210080
+#define        F367TER_RCRSTATE_6      0xf2210040
+#define        F367TER_RCRSTATE_5      0xf2210020
+#define        F367TER_RCRSTATE_4      0xf2210010
+#define        F367TER_RCRSTATE_3      0xf2210008
+#define        F367TER_RCRSTATE_2      0xf2210004
+#define        F367TER_RCRSTATE_1      0xf2210002
+#define        F367TER_RCRSTATE_0      0xf2210001
+
+/* RCFSPYBER */
+#define        R367TER_RCFSPYBER       0xf222
+#define        F367TER_RCFSPYBER_7     0xf2220080
+#define        F367TER_SPYRCOBS_XORREAD        0xf2220040
+#define        F367TER_FSPYRCBER_OBSMODE       0xf2220020
+#define        F367TER_FSPYRCBER_SYNCBYT       0xf2220010
+#define        F367TER_FSPYRCBER_UNSYNC        0xf2220008
+#define        F367TER_FSPYRCBER_CTIME 0xf2220007
+
+/* RCFSPYDISTM */
+#define        R367TER_RCFSPYDISTM     0xf223
+#define        F367TER_RCPKTTIME_DISTANCE_HI   0xf22300ff
+
+/* RCFSPYDISTL */
+#define        R367TER_RCFSPYDISTL     0xf224
+#define        F367TER_RCPKTTIME_DISTANCE_LO   0xf22400ff
+
+/* RCFSPYOBS7 */
+#define        R367TER_RCFSPYOBS7      0xf228
+#define        F367TER_RCSPYOBS_SPYFAIL        0xf2280080
+#define        F367TER_RCSPYOBS_SPYFAIL1       0xf2280040
+#define        F367TER_RCSPYOBS_ERROR  0xf2280020
+#define        F367TER_RCSPYOBS_STROUT 0xf2280010
+#define        F367TER_RCSPYOBS_RESULTSTATE1   0xf228000f
+
+/* RCFSPYOBS6 */
+#define        R367TER_RCFSPYOBS6      0xf229
+#define        F367TER_RCSPYOBS_RESULTSTATe0   0xf22900f0
+#define        F367TER_RCSPYOBS_RESULTSTATEM1  0xf229000f
+
+/* RCFSPYOBS5 */
+#define        R367TER_RCFSPYOBS5      0xf22a
+#define        F367TER_RCSPYOBS_BYTEOFPACKET1  0xf22a00ff
+
+/* RCFSPYOBS4 */
+#define        R367TER_RCFSPYOBS4      0xf22b
+#define        F367TER_RCSPYOBS_BYTEVALUE1     0xf22b00ff
+
+/* RCFSPYOBS3 */
+#define        R367TER_RCFSPYOBS3      0xf22c
+#define        F367TER_RCSPYOBS_DATA1  0xf22c00ff
+
+/* RCFSPYOBS2 */
+#define        R367TER_RCFSPYOBS2      0xf22d
+#define        F367TER_RCSPYOBS_DATa0  0xf22d00ff
+
+/* RCFSPYOBS1 */
+#define        R367TER_RCFSPYOBS1      0xf22e
+#define        F367TER_RCSPYOBS_DATAM1 0xf22e00ff
+
+/* RCFSPYOBS0 */
+#define        R367TER_RCFSPYOBS0      0xf22f
+#define        F367TER_RCSPYOBS_DATAM2 0xf22f00ff
+
+/* TSGENERAL */
+#define        R367TER_TSGENERAL       0xf230
+#define        F367TER_TSGENERAL_7     0xf2300080
+#define        F367TER_TSGENERAL_6     0xf2300040
+#define        F367TER_TSFIFO_BCLK1aLL 0xf2300020
+#define        F367TER_TSGENERAL_4     0xf2300010
+#define        F367TER_MUXSTREAM_OUTMODE       0xf2300008
+#define        F367TER_TSFIFO_PERMPARAL        0xf2300006
+#define        F367TER_RST_REEDSOLO    0xf2300001
+
+/* RC1SPEED */
+#define        R367TER_RC1SPEED        0xf231
+#define        F367TER_TSRCFIFO1_OUTSPEED      0xf23100ff
+
+/* TSGSTATUS */
+#define        R367TER_TSGSTATUS       0xf232
+#define        F367TER_TSGSTATUS_7     0xf2320080
+#define        F367TER_TSGSTATUS_6     0xf2320040
+#define        F367TER_RSMEM_FULL      0xf2320020
+#define        F367TER_RS_MULTCALC     0xf2320010
+#define        F367TER_RSIN_OVERTIME   0xf2320008
+#define        F367TER_TSFIFO3_DEMODSEL        0xf2320004
+#define        F367TER_TSFIFO2_DEMODSEL        0xf2320002
+#define        F367TER_TSFIFO1_DEMODSEL        0xf2320001
+
+
+/* FECM */
+#define        R367TER_FECM    0xf233
+#define        F367TER_DSS_DVB 0xf2330080
+#define        F367TER_DEMOD_BYPASS    0xf2330040
+#define        F367TER_CMP_SLOWMODE    0xf2330020
+#define        F367TER_DSS_SRCH        0xf2330010
+#define        F367TER_FECM_3  0xf2330008
+#define        F367TER_DIFF_MODEVIT    0xf2330004
+#define        F367TER_SYNCVIT 0xf2330002
+#define        F367TER_I2CSYM  0xf2330001
+
+/* VTH12 */
+#define        R367TER_VTH12   0xf234
+#define        F367TER_VTH_12  0xf23400ff
+
+/* VTH23 */
+#define        R367TER_VTH23   0xf235
+#define        F367TER_VTH_23  0xf23500ff
+
+/* VTH34 */
+#define        R367TER_VTH34   0xf236
+#define        F367TER_VTH_34  0xf23600ff
+
+/* VTH56 */
+#define        R367TER_VTH56   0xf237
+#define        F367TER_VTH_56  0xf23700ff
+
+/* VTH67 */
+#define        R367TER_VTH67   0xf238
+#define        F367TER_VTH_67  0xf23800ff
+
+/* VTH78 */
+#define        R367TER_VTH78   0xf239
+#define        F367TER_VTH_78  0xf23900ff
+
+/* VITCURPUN */
+#define        R367TER_VITCURPUN       0xf23a
+#define        F367TER_VIT_MAPPING     0xf23a00e0
+#define        F367TER_VIT_CURPUN      0xf23a001f
+
+/* VERROR */
+#define        R367TER_VERROR  0xf23b
+#define        F367TER_REGERR_VIT      0xf23b00ff
+
+/* PRVIT */
+#define        R367TER_PRVIT   0xf23c
+#define        F367TER_PRVIT_7 0xf23c0080
+#define        F367TER_DIS_VTHLOCK     0xf23c0040
+#define        F367TER_E7_8VIT 0xf23c0020
+#define        F367TER_E6_7VIT 0xf23c0010
+#define        F367TER_E5_6VIT 0xf23c0008
+#define        F367TER_E3_4VIT 0xf23c0004
+#define        F367TER_E2_3VIT 0xf23c0002
+#define        F367TER_E1_2VIT 0xf23c0001
+
+/* VAVSRVIT */
+#define        R367TER_VAVSRVIT        0xf23d
+#define        F367TER_AMVIT   0xf23d0080
+#define        F367TER_FROZENVIT       0xf23d0040
+#define        F367TER_SNVIT   0xf23d0030
+#define        F367TER_TOVVIT  0xf23d000c
+#define        F367TER_HYPVIT  0xf23d0003
+
+/* VSTATUSVIT */
+#define        R367TER_VSTATUSVIT      0xf23e
+#define        F367TER_VITERBI_ON      0xf23e0080
+#define        F367TER_END_LOOPVIT     0xf23e0040
+#define        F367TER_VITERBI_DEPRF   0xf23e0020
+#define        F367TER_PRFVIT  0xf23e0010
+#define        F367TER_LOCKEDVIT       0xf23e0008
+#define        F367TER_VITERBI_DELOCK  0xf23e0004
+#define        F367TER_VIT_DEMODSEL    0xf23e0002
+#define        F367TER_VITERBI_COMPOUT 0xf23e0001
+
+/* VTHINUSE */
+#define        R367TER_VTHINUSE        0xf23f
+#define        F367TER_VIT_INUSE       0xf23f00ff
+
+/* KDIV12 */
+#define        R367TER_KDIV12  0xf240
+#define        F367TER_KDIV12_MANUAL   0xf2400080
+#define        F367TER_K_DIVIDER_12    0xf240007f
+
+/* KDIV23 */
+#define        R367TER_KDIV23  0xf241
+#define        F367TER_KDIV23_MANUAL   0xf2410080
+#define        F367TER_K_DIVIDER_23    0xf241007f
+
+/* KDIV34 */
+#define        R367TER_KDIV34  0xf242
+#define        F367TER_KDIV34_MANUAL   0xf2420080
+#define        F367TER_K_DIVIDER_34    0xf242007f
+
+/* KDIV56 */
+#define        R367TER_KDIV56  0xf243
+#define        F367TER_KDIV56_MANUAL   0xf2430080
+#define        F367TER_K_DIVIDER_56    0xf243007f
+
+/* KDIV67 */
+#define        R367TER_KDIV67  0xf244
+#define        F367TER_KDIV67_MANUAL   0xf2440080
+#define        F367TER_K_DIVIDER_67    0xf244007f
+
+/* KDIV78 */
+#define        R367TER_KDIV78  0xf245
+#define        F367TER_KDIV78_MANUAL   0xf2450080
+#define        F367TER_K_DIVIDER_78    0xf245007f
+
+/* SIGPOWER */
+#define        R367TER_SIGPOWER        0xf246
+#define        F367TER_SIGPOWER_MANUAL 0xf2460080
+#define        F367TER_SIG_POWER       0xf246007f
+
+/* DEMAPVIT */
+#define        R367TER_DEMAPVIT        0xf247
+#define        F367TER_DEMAPVIT_7      0xf2470080
+#define        F367TER_K_DIVIDER_VIT   0xf247007f
+
+/* VITSCALE */
+#define        R367TER_VITSCALE        0xf248
+#define        F367TER_NVTH_NOSRANGE   0xf2480080
+#define        F367TER_VERROR_MAXMODE  0xf2480040
+#define        F367TER_KDIV_MODE       0xf2480030
+#define        F367TER_NSLOWSN_LOCKED  0xf2480008
+#define        F367TER_DELOCK_PRFLOSS  0xf2480004
+#define        F367TER_DIS_RSFLOCK     0xf2480002
+#define        F367TER_VITSCALE_0      0xf2480001
+
+/* FFEC1PRG */
+#define        R367TER_FFEC1PRG        0xf249
+#define        F367TER_FDSS_DVB        0xf2490080
+#define        F367TER_FDSS_SRCH       0xf2490040
+#define        F367TER_FFECPROG_5      0xf2490020
+#define        F367TER_FFECPROG_4      0xf2490010
+#define        F367TER_FFECPROG_3      0xf2490008
+#define        F367TER_FFECPROG_2      0xf2490004
+#define        F367TER_FTS1_DISABLE    0xf2490002
+#define        F367TER_FTS2_DISABLE    0xf2490001
+
+/* FVITCURPUN */
+#define        R367TER_FVITCURPUN      0xf24a
+#define        F367TER_FVIT_MAPPING    0xf24a00e0
+#define        F367TER_FVIT_CURPUN     0xf24a001f
+
+/* FVERROR */
+#define        R367TER_FVERROR 0xf24b
+#define        F367TER_FREGERR_VIT     0xf24b00ff
+
+/* FVSTATUSVIT */
+#define        R367TER_FVSTATUSVIT     0xf24c
+#define        F367TER_FVITERBI_ON     0xf24c0080
+#define        F367TER_F1END_LOOPVIT   0xf24c0040
+#define        F367TER_FVITERBI_DEPRF  0xf24c0020
+#define        F367TER_FPRFVIT 0xf24c0010
+#define        F367TER_FLOCKEDVIT      0xf24c0008
+#define        F367TER_FVITERBI_DELOCK 0xf24c0004
+#define        F367TER_FVIT_DEMODSEL   0xf24c0002
+#define        F367TER_FVITERBI_COMPOUT        0xf24c0001
+
+/* DEBUG_LT1 */
+#define        R367TER_DEBUG_LT1       0xf24d
+#define        F367TER_DBG_LT1 0xf24d00ff
+
+/* DEBUG_LT2 */
+#define        R367TER_DEBUG_LT2       0xf24e
+#define        F367TER_DBG_LT2 0xf24e00ff
+
+/* DEBUG_LT3 */
+#define        R367TER_DEBUG_LT3       0xf24f
+#define        F367TER_DBG_LT3 0xf24f00ff
+
+/*     TSTSFMET */
+#define        R367TER_TSTSFMET        0xf250
+#define F367TER_TSTSFEC_METRIQUES      0xf25000ff
+
+/*     SELOUT */
+#define        R367TER_SELOUT  0xf252
+#define        F367TER_EN_SYNC 0xf2520080
+#define        F367TER_EN_TBUSDEMAP    0xf2520040
+#define        F367TER_SELOUT_5        0xf2520020
+#define        F367TER_SELOUT_4        0xf2520010
+#define        F367TER_TSTSYNCHRO_MODE 0xf2520002
+
+/*     TSYNC */
+#define R367TER_TSYNC  0xf253
+#define F367TER_CURPUN_INCMODE 0xf2530080
+#define F367TER_CERR_TSTMODE   0xf2530040
+#define F367TER_SHIFTSOF_MODE  0xf2530030
+#define F367TER_SLOWPHA_MODE   0xf2530008
+#define F367TER_PXX_BYPALL     0xf2530004
+#define F367TER_FROTA45_FIRST  0xf2530002
+#define F367TER_TST_BCHERROR   0xf2530001
+
+/*     TSTERR */
+#define R367TER_TSTERR 0xf254
+#define F367TER_TST_LONGPKT    0xf2540080
+#define F367TER_TST_ISSYION    0xf2540040
+#define F367TER_TST_NPDON      0xf2540020
+#define F367TER_TSTERR_4       0xf2540010
+#define F367TER_TRACEBACK_MODE 0xf2540008
+#define F367TER_TST_RSPARITY   0xf2540004
+#define F367TER_METRIQUE_MODE  0xf2540003
+
+/*     TSFSYNC */
+#define R367TER_TSFSYNC        0xf255
+#define F367TER_EN_SFECSYNC    0xf2550080
+#define F367TER_EN_SFECDEMAP   0xf2550040
+#define F367TER_SFCERR_TSTMODE 0xf2550020
+#define F367TER_SFECPXX_BYPALL 0xf2550010
+#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f
+
+/*     TSTSFERR */
+#define R367TER_TSTSFERR       0xf256
+#define F367TER_TSTSTERR_7     0xf2560080
+#define F367TER_TSTSTERR_6     0xf2560040
+#define F367TER_TSTSTERR_5     0xf2560020
+#define F367TER_TSTSTERR_4     0xf2560010
+#define F367TER_SFECTRACEBACK_MODE     0xf2560008
+#define F367TER_SFEC_NCONVPROG 0xf2560004
+#define F367TER_SFECMETRIQUE_MODE      0xf2560003
+
+/*     TSTTSSF1 */
+#define R367TER_TSTTSSF1       0xf258
+#define F367TER_TSTERSSF       0xf2580080
+#define F367TER_TSTTSSFEN      0xf2580040
+#define F367TER_SFEC_OUTMODE   0xf2580030
+#define F367TER_XLSF_NOFTHRESHOLD  0xf2580008
+#define F367TER_TSTTSSF_STACKSEL       0xf2580007
+
+/*     TSTTSSF2 */
+#define R367TER_TSTTSSF2       0xf259
+#define F367TER_DILSF_DBBHEADER        0xf2590080
+#define F367TER_TSTTSSF_DISBUG 0xf2590040
+#define F367TER_TSTTSSF_NOBADSTART     0xf2590020
+#define F367TER_TSTTSSF_SELECT 0xf259001f
+
+/*     TSTTSSF3 */
+#define R367TER_TSTTSSF3       0xf25a
+#define F367TER_TSTTSSF3_7     0xf25a0080
+#define F367TER_TSTTSSF3_6     0xf25a0040
+#define F367TER_TSTTSSF3_5     0xf25a0020
+#define F367TER_TSTTSSF3_4     0xf25a0010
+#define F367TER_TSTTSSF3_3     0xf25a0008
+#define F367TER_TSTTSSF3_2     0xf25a0004
+#define F367TER_TSTTSSF3_1     0xf25a0002
+#define F367TER_DISSF_CLKENABLE        0xf25a0001
+
+/*     TSTTS1 */
+#define R367TER_TSTTS1 0xf25c
+#define F367TER_TSTERS 0xf25c0080
+#define F367TER_TSFIFO_DSSSYNCB        0xf25c0040
+#define F367TER_TSTTS_FSPYBEFRS        0xf25c0020
+#define F367TER_NFORCE_SYNCBYTE        0xf25c0010
+#define F367TER_XL_NOFTHRESHOLD        0xf25c0008
+#define F367TER_TSTTS_FRFORCEPKT       0xf25c0004
+#define F367TER_DESCR_NOTAUTO  0xf25c0002
+#define F367TER_TSTTSEN        0xf25c0001
+
+/*     TSTTS2 */
+#define R367TER_TSTTS2 0xf25d
+#define F367TER_DIL_DBBHEADER  0xf25d0080
+#define F367TER_TSTTS_NOBADXXX 0xf25d0040
+#define F367TER_TSFIFO_DELSPEEDUP      0xf25d0020
+#define F367TER_TSTTS_SELECT   0xf25d001f
+
+/*     TSTTS3 */
+#define R367TER_TSTTS3 0xf25e
+#define F367TER_TSTTS_NOPKTGAIN        0xf25e0080
+#define F367TER_TSTTS_NOPKTENE 0xf25e0040
+#define F367TER_TSTTS_ISOLATION        0xf25e0020
+#define F367TER_TSTTS_DISBUG   0xf25e0010
+#define F367TER_TSTTS_NOBADSTART       0xf25e0008
+#define F367TER_TSTTS_STACKSEL 0xf25e0007
+
+/*     TSTTS4 */
+#define R367TER_TSTTS4 0xf25f
+#define F367TER_TSTTS4_7       0xf25f0080
+#define F367TER_TSTTS4_6       0xf25f0040
+#define F367TER_TSTTS4_5       0xf25f0020
+#define F367TER_TSTTS_DISDSTATE        0xf25f0010
+#define F367TER_TSTTS_FASTNOSYNC       0xf25f0008
+#define F367TER_EXT_FECSPYIN   0xf25f0004
+#define F367TER_TSTTS_NODPZERO 0xf25f0002
+#define F367TER_TSTTS_NODIV3   0xf25f0001
+
+/*     TSTTSRC */
+#define R367TER_TSTTSRC        0xf26c
+#define F367TER_TSTTSRC_7      0xf26c0080
+#define F367TER_TSRCFIFO_DSSSYNCB      0xf26c0040
+#define F367TER_TSRCFIFO_DPUNACTIVE    0xf26c0020
+#define F367TER_TSRCFIFO_DELSPEEDUP    0xf26c0010
+#define F367TER_TSTTSRC_NODIV3 0xf26c0008
+#define F367TER_TSTTSRC_FRFORCEPKT     0xf26c0004
+#define F367TER_SAT25_SDDORIGINE       0xf26c0002
+#define F367TER_TSTTSRC_INACTIVE       0xf26c0001
+
+/*     TSTTSRS */
+#define R367TER_TSTTSRS        0xf26d
+#define F367TER_TSTTSRS_7      0xf26d0080
+#define F367TER_TSTTSRS_6      0xf26d0040
+#define F367TER_TSTTSRS_5      0xf26d0020
+#define F367TER_TSTTSRS_4      0xf26d0010
+#define F367TER_TSTTSRS_3      0xf26d0008
+#define F367TER_TSTTSRS_2      0xf26d0004
+#define F367TER_TSTRS_DISRS2   0xf26d0002
+#define F367TER_TSTRS_DISRS1   0xf26d0001
+
+/* TSSTATEM */
+#define        R367TER_TSSTATEM        0xf270
+#define        F367TER_TSDIL_ON        0xf2700080
+#define        F367TER_TSSKIPRS_ON     0xf2700040
+#define        F367TER_TSRS_ON 0xf2700020
+#define        F367TER_TSDESCRAMB_ON   0xf2700010
+#define        F367TER_TSFRAME_MODE    0xf2700008
+#define        F367TER_TS_DISABLE      0xf2700004
+#define        F367TER_TSACM_MODE      0xf2700002
+#define        F367TER_TSOUT_NOSYNC    0xf2700001
+
+/* TSSTATEL */
+#define        R367TER_TSSTATEL        0xf271
+#define        F367TER_TSNOSYNCBYTE    0xf2710080
+#define        F367TER_TSPARITY_ON     0xf2710040
+#define        F367TER_TSSYNCOUTRS_ON  0xf2710020
+#define        F367TER_TSDVBS2_MODE    0xf2710010
+#define        F367TER_TSISSYI_ON      0xf2710008
+#define        F367TER_TSNPD_ON        0xf2710004
+#define        F367TER_TSCRC8_ON       0xf2710002
+#define        F367TER_TSDSS_PACKET    0xf2710001
+
+/* TSCFGH */
+#define        R367TER_TSCFGH  0xf272
+#define        F367TER_TSFIFO_DVBCI    0xf2720080
+#define        F367TER_TSFIFO_SERIAL   0xf2720040
+#define        F367TER_TSFIFO_TEIUPDATE        0xf2720020
+#define        F367TER_TSFIFO_DUTY50   0xf2720010
+#define        F367TER_TSFIFO_HSGNLOUT 0xf2720008
+#define        F367TER_TSFIFO_ERRMODE  0xf2720006
+#define        F367TER_RST_HWARE       0xf2720001
+
+/* TSCFGM */
+#define        R367TER_TSCFGM  0xf273
+#define        F367TER_TSFIFO_MANSPEED 0xf27300c0
+#define        F367TER_TSFIFO_PERMDATA 0xf2730020
+#define        F367TER_TSFIFO_NONEWSGNL        0xf2730010
+#define        F367TER_TSFIFO_BITSPEED 0xf2730008
+#define        F367TER_NPD_SPECDVBS2   0xf2730004
+#define        F367TER_TSFIFO_STOPCKDIS        0xf2730002
+#define        F367TER_TSFIFO_INVDATA  0xf2730001
+
+/* TSCFGL */
+#define        R367TER_TSCFGL  0xf274
+#define        F367TER_TSFIFO_BCLKDEL1cK       0xf27400c0
+#define        F367TER_BCHERROR_MODE   0xf2740030
+#define        F367TER_TSFIFO_NSGNL2dATA       0xf2740008
+#define        F367TER_TSFIFO_EMBINDVB 0xf2740004
+#define        F367TER_TSFIFO_DPUNACT  0xf2740002
+#define        F367TER_TSFIFO_NPDOFF   0xf2740001
+
+/* TSSYNC */
+#define        R367TER_TSSYNC  0xf275
+#define        F367TER_TSFIFO_PERMUTE  0xf2750080
+#define        F367TER_TSFIFO_FISCR3B  0xf2750060
+#define        F367TER_TSFIFO_SYNCMODE 0xf2750018
+#define        F367TER_TSFIFO_SYNCSEL  0xf2750007
+
+/* TSINSDELH */
+#define        R367TER_TSINSDELH       0xf276
+#define        F367TER_TSDEL_SYNCBYTE  0xf2760080
+#define        F367TER_TSDEL_XXHEADER  0xf2760040
+#define        F367TER_TSDEL_BBHEADER  0xf2760020
+#define        F367TER_TSDEL_DATAFIELD 0xf2760010
+#define        F367TER_TSINSDEL_ISCR   0xf2760008
+#define        F367TER_TSINSDEL_NPD    0xf2760004
+#define        F367TER_TSINSDEL_RSPARITY       0xf2760002
+#define        F367TER_TSINSDEL_CRC8   0xf2760001
+
+/* TSINSDELM */
+#define        R367TER_TSINSDELM       0xf277
+#define        F367TER_TSINS_BBPADDING 0xf2770080
+#define        F367TER_TSINS_BCHFEC    0xf2770040
+#define        F367TER_TSINS_LDPCFEC   0xf2770020
+#define        F367TER_TSINS_EMODCOD   0xf2770010
+#define        F367TER_TSINS_TOKEN     0xf2770008
+#define        F367TER_TSINS_XXXERR    0xf2770004
+#define        F367TER_TSINS_MATYPE    0xf2770002
+#define        F367TER_TSINS_UPL       0xf2770001
+
+/* TSINSDELL */
+#define        R367TER_TSINSDELL       0xf278
+#define        F367TER_TSINS_DFL       0xf2780080
+#define        F367TER_TSINS_SYNCD     0xf2780040
+#define        F367TER_TSINS_BLOCLEN   0xf2780020
+#define        F367TER_TSINS_SIGPCOUNT 0xf2780010
+#define        F367TER_TSINS_FIFO      0xf2780008
+#define        F367TER_TSINS_REALPACK  0xf2780004
+#define        F367TER_TSINS_TSCONFIG  0xf2780002
+#define        F367TER_TSINS_LATENCY   0xf2780001
+
+/* TSDIVN */
+#define        R367TER_TSDIVN  0xf279
+#define        F367TER_TSFIFO_LOWSPEED 0xf2790080
+#define        F367TER_BYTE_OVERSAMPLING       0xf2790070
+#define        F367TER_TSMANUAL_PACKETNBR      0xf279000f
+
+/* TSDIVPM */
+#define        R367TER_TSDIVPM 0xf27a
+#define        F367TER_TSMANUAL_P_HI   0xf27a00ff
+
+/* TSDIVPL */
+#define        R367TER_TSDIVPL 0xf27b
+#define        F367TER_TSMANUAL_P_LO   0xf27b00ff
+
+/* TSDIVQM */
+#define        R367TER_TSDIVQM 0xf27c
+#define        F367TER_TSMANUAL_Q_HI   0xf27c00ff
+
+/* TSDIVQL */
+#define        R367TER_TSDIVQL 0xf27d
+#define        F367TER_TSMANUAL_Q_LO   0xf27d00ff
+
+/* TSDILSTKM */
+#define        R367TER_TSDILSTKM       0xf27e
+#define        F367TER_TSFIFO_DILSTK_HI        0xf27e00ff
+
+/* TSDILSTKL */
+#define        R367TER_TSDILSTKL       0xf27f
+#define        F367TER_TSFIFO_DILSTK_LO        0xf27f00ff
+
+/* TSSPEED */
+#define        R367TER_TSSPEED 0xf280
+#define        F367TER_TSFIFO_OUTSPEED 0xf28000ff
+
+/* TSSTATUS */
+#define        R367TER_TSSTATUS        0xf281
+#define        F367TER_TSFIFO_LINEOK   0xf2810080
+#define        F367TER_TSFIFO_ERROR    0xf2810040
+#define        F367TER_TSFIFO_DATA7    0xf2810020
+#define        F367TER_TSFIFO_NOSYNC   0xf2810010
+#define        F367TER_ISCR_INITIALIZED        0xf2810008
+#define        F367TER_ISCR_UPDATED    0xf2810004
+#define        F367TER_SOFFIFO_UNREGUL 0xf2810002
+#define        F367TER_DIL_READY       0xf2810001
+
+/* TSSTATUS2 */
+#define        R367TER_TSSTATUS2       0xf282
+#define        F367TER_TSFIFO_DEMODSEL 0xf2820080
+#define        F367TER_TSFIFOSPEED_STORE       0xf2820040
+#define        F367TER_DILXX_RESET     0xf2820020
+#define        F367TER_TSSERIAL_IMPOSSIBLE     0xf2820010
+#define        F367TER_TSFIFO_UNDERSPEED       0xf2820008
+#define        F367TER_BITSPEED_EVENT  0xf2820004
+#define        F367TER_UL_SCRAMBDETECT 0xf2820002
+#define        F367TER_ULDTV67_FALSELOCK       0xf2820001
+
+/* TSBITRATEM */
+#define        R367TER_TSBITRATEM      0xf283
+#define        F367TER_TSFIFO_BITRATE_HI       0xf28300ff
+
+/* TSBITRATEL */
+#define        R367TER_TSBITRATEL      0xf284
+#define        F367TER_TSFIFO_BITRATE_LO       0xf28400ff
+
+/* TSPACKLENM */
+#define        R367TER_TSPACKLENM      0xf285
+#define        F367TER_TSFIFO_PACKCPT  0xf28500e0
+#define        F367TER_DIL_RPLEN_HI    0xf285001f
+
+/* TSPACKLENL */
+#define        R367TER_TSPACKLENL      0xf286
+#define        F367TER_DIL_RPLEN_LO    0xf28600ff
+
+/* TSBLOCLENM */
+#define        R367TER_TSBLOCLENM      0xf287
+#define        F367TER_TSFIFO_PFLEN_HI 0xf28700ff
+
+/* TSBLOCLENL */
+#define        R367TER_TSBLOCLENL      0xf288
+#define        F367TER_TSFIFO_PFLEN_LO 0xf28800ff
+
+/* TSDLYH */
+#define        R367TER_TSDLYH  0xf289
+#define        F367TER_SOFFIFO_TSTIMEVALID     0xf2890080
+#define        F367TER_SOFFIFO_SPEEDUP 0xf2890040
+#define        F367TER_SOFFIFO_STOP    0xf2890020
+#define        F367TER_SOFFIFO_REGULATED       0xf2890010
+#define        F367TER_SOFFIFO_REALSBOFF_HI    0xf289000f
+
+/* TSDLYM */
+#define        R367TER_TSDLYM  0xf28a
+#define        F367TER_SOFFIFO_REALSBOFF_MED   0xf28a00ff
+
+/* TSDLYL */
+#define        R367TER_TSDLYL  0xf28b
+#define        F367TER_SOFFIFO_REALSBOFF_LO    0xf28b00ff
+
+/* TSNPDAV */
+#define        R367TER_TSNPDAV 0xf28c
+#define        F367TER_TSNPD_AVERAGE   0xf28c00ff
+
+/* TSBUFSTATH */
+#define        R367TER_TSBUFSTATH      0xf28d
+#define        F367TER_TSISCR_3BYTES   0xf28d0080
+#define        F367TER_TSISCR_NEWDATA  0xf28d0040
+#define        F367TER_TSISCR_BUFSTAT_HI       0xf28d003f
+
+/* TSBUFSTATM */
+#define        R367TER_TSBUFSTATM      0xf28e
+#define        F367TER_TSISCR_BUFSTAT_MED      0xf28e00ff
+
+/* TSBUFSTATL */
+#define        R367TER_TSBUFSTATL      0xf28f
+#define        F367TER_TSISCR_BUFSTAT_LO       0xf28f00ff
+
+/* TSDEBUGM */
+#define        R367TER_TSDEBUGM        0xf290
+#define        F367TER_TSFIFO_ILLPACKET        0xf2900080
+#define        F367TER_DIL_NOSYNC      0xf2900040
+#define        F367TER_DIL_ISCR        0xf2900020
+#define        F367TER_DILOUT_BSYNCB   0xf2900010
+#define        F367TER_TSFIFO_EMPTYPKT 0xf2900008
+#define        F367TER_TSFIFO_EMPTYRD  0xf2900004
+#define        F367TER_SOFFIFO_STOPM   0xf2900002
+#define        F367TER_SOFFIFO_SPEEDUPM        0xf2900001
+
+/* TSDEBUGL */
+#define        R367TER_TSDEBUGL        0xf291
+#define        F367TER_TSFIFO_PACKLENFAIL      0xf2910080
+#define        F367TER_TSFIFO_SYNCBFAIL        0xf2910040
+#define        F367TER_TSFIFO_VITLIBRE 0xf2910020
+#define        F367TER_TSFIFO_BOOSTSPEEDM      0xf2910010
+#define        F367TER_TSFIFO_UNDERSPEEDM      0xf2910008
+#define        F367TER_TSFIFO_ERROR_EVNT       0xf2910004
+#define        F367TER_TSFIFO_FULL     0xf2910002
+#define        F367TER_TSFIFO_OVERFLOWM        0xf2910001
+
+/* TSDLYSETH */
+#define        R367TER_TSDLYSETH       0xf292
+#define        F367TER_SOFFIFO_OFFSET  0xf29200e0
+#define        F367TER_SOFFIFO_SYMBOFFSET_HI   0xf292001f
+
+/* TSDLYSETM */
+#define        R367TER_TSDLYSETM       0xf293
+#define        F367TER_SOFFIFO_SYMBOFFSET_MED  0xf29300ff
+
+/* TSDLYSETL */
+#define        R367TER_TSDLYSETL       0xf294
+#define        F367TER_SOFFIFO_SYMBOFFSET_LO   0xf29400ff
+
+/* TSOBSCFG */
+#define        R367TER_TSOBSCFG        0xf295
+#define        F367TER_TSFIFO_OBSCFG   0xf29500ff
+
+/* TSOBSM */
+#define        R367TER_TSOBSM  0xf296
+#define        F367TER_TSFIFO_OBSDATA_HI       0xf29600ff
+
+/* TSOBSL */
+#define        R367TER_TSOBSL  0xf297
+#define        F367TER_TSFIFO_OBSDATA_LO       0xf29700ff
+
+/* ERRCTRL1 */
+#define        R367TER_ERRCTRL1        0xf298
+#define        F367TER_ERR_SRC1        0xf29800f0
+#define        F367TER_ERRCTRL1_3      0xf2980008
+#define        F367TER_NUM_EVT1        0xf2980007
+
+/* ERRCNT1H */
+#define        R367TER_ERRCNT1H        0xf299
+#define        F367TER_ERRCNT1_OLDVALUE        0xf2990080
+#define        F367TER_ERR_CNT1        0xf299007f
+
+/* ERRCNT1M */
+#define        R367TER_ERRCNT1M        0xf29a
+#define        F367TER_ERR_CNT1_HI     0xf29a00ff
+
+/* ERRCNT1L */
+#define        R367TER_ERRCNT1L        0xf29b
+#define        F367TER_ERR_CNT1_LO     0xf29b00ff
+
+/* ERRCTRL2 */
+#define        R367TER_ERRCTRL2        0xf29c
+#define        F367TER_ERR_SRC2        0xf29c00f0
+#define        F367TER_ERRCTRL2_3      0xf29c0008
+#define        F367TER_NUM_EVT2        0xf29c0007
+
+/* ERRCNT2H */
+#define        R367TER_ERRCNT2H        0xf29d
+#define        F367TER_ERRCNT2_OLDVALUE        0xf29d0080
+#define        F367TER_ERR_CNT2_HI     0xf29d007f
+
+/* ERRCNT2M */
+#define        R367TER_ERRCNT2M        0xf29e
+#define        F367TER_ERR_CNT2_MED    0xf29e00ff
+
+/* ERRCNT2L */
+#define        R367TER_ERRCNT2L        0xf29f
+#define        F367TER_ERR_CNT2_LO     0xf29f00ff
+
+/* FECSPY */
+#define        R367TER_FECSPY  0xf2a0
+#define        F367TER_SPY_ENABLE      0xf2a00080
+#define        F367TER_NO_SYNCBYTE     0xf2a00040
+#define        F367TER_SERIAL_MODE     0xf2a00020
+#define        F367TER_UNUSUAL_PACKET  0xf2a00010
+#define        F367TER_BERMETER_DATAMODE       0xf2a0000c
+#define        F367TER_BERMETER_LMODE  0xf2a00002
+#define        F367TER_BERMETER_RESET  0xf2a00001
+
+/* FSPYCFG */
+#define        R367TER_FSPYCFG 0xf2a1
+#define        F367TER_FECSPY_INPUT    0xf2a100c0
+#define        F367TER_RST_ON_ERROR    0xf2a10020
+#define        F367TER_ONE_SHOT        0xf2a10010
+#define        F367TER_I2C_MOD 0xf2a1000c
+#define        F367TER_SPY_HYSTERESIS  0xf2a10003
+
+/* FSPYDATA */
+#define        R367TER_FSPYDATA        0xf2a2
+#define        F367TER_SPY_STUFFING    0xf2a20080
+#define        F367TER_NOERROR_PKTJITTER       0xf2a20040
+#define        F367TER_SPY_CNULLPKT    0xf2a20020
+#define        F367TER_SPY_OUTDATA_MODE        0xf2a2001f
+
+/* FSPYOUT */
+#define        R367TER_FSPYOUT 0xf2a3
+#define        F367TER_FSPY_DIRECT     0xf2a30080
+#define        F367TER_FSPYOUT_6       0xf2a30040
+#define        F367TER_SPY_OUTDATA_BUS 0xf2a30038
+#define        F367TER_STUFF_MODE      0xf2a30007
+
+/* FSTATUS */
+#define        R367TER_FSTATUS 0xf2a4
+#define        F367TER_SPY_ENDSIM      0xf2a40080
+#define        F367TER_VALID_SIM       0xf2a40040
+#define        F367TER_FOUND_SIGNAL    0xf2a40020
+#define        F367TER_DSS_SYNCBYTE    0xf2a40010
+#define        F367TER_RESULT_STATE    0xf2a4000f
+
+/* FGOODPACK */
+#define        R367TER_FGOODPACK       0xf2a5
+#define        F367TER_FGOOD_PACKET    0xf2a500ff
+
+/* FPACKCNT */
+#define        R367TER_FPACKCNT        0xf2a6
+#define        F367TER_FPACKET_COUNTER 0xf2a600ff
+
+/* FSPYMISC */
+#define        R367TER_FSPYMISC        0xf2a7
+#define        F367TER_FLABEL_COUNTER  0xf2a700ff
+
+/* FBERCPT4 */
+#define        R367TER_FBERCPT4        0xf2a8
+#define        F367TER_FBERMETER_CPT5  0xf2a800ff
+
+/* FBERCPT3 */
+#define        R367TER_FBERCPT3        0xf2a9
+#define        F367TER_FBERMETER_CPT4  0xf2a900ff
+
+/* FBERCPT2 */
+#define        R367TER_FBERCPT2        0xf2aa
+#define        F367TER_FBERMETER_CPT3  0xf2aa00ff
+
+/* FBERCPT1 */
+#define        R367TER_FBERCPT1        0xf2ab
+#define        F367TER_FBERMETER_CPT2  0xf2ab00ff
+
+/* FBERCPT0 */
+#define        R367TER_FBERCPT0        0xf2ac
+#define        F367TER_FBERMETER_CPT1  0xf2ac00ff
+
+/* FBERERR2 */
+#define        R367TER_FBERERR2        0xf2ad
+#define        F367TER_FBERMETER_ERR_HI        0xf2ad00ff
+
+/* FBERERR1 */
+#define        R367TER_FBERERR1        0xf2ae
+#define        F367TER_FBERMETER_ERR_MED       0xf2ae00ff
+
+/* FBERERR0 */
+#define        R367TER_FBERERR0        0xf2af
+#define        F367TER_FBERMETER_ERR_LO        0xf2af00ff
+
+/* FSTATESM */
+#define        R367TER_FSTATESM        0xf2b0
+#define        F367TER_RSTATE_F        0xf2b00080
+#define        F367TER_RSTATE_E        0xf2b00040
+#define        F367TER_RSTATE_D        0xf2b00020
+#define        F367TER_RSTATE_C        0xf2b00010
+#define        F367TER_RSTATE_B        0xf2b00008
+#define        F367TER_RSTATE_A        0xf2b00004
+#define        F367TER_RSTATE_9        0xf2b00002
+#define        F367TER_RSTATE_8        0xf2b00001
+
+/* FSTATESL */
+#define        R367TER_FSTATESL        0xf2b1
+#define        F367TER_RSTATE_7        0xf2b10080
+#define        F367TER_RSTATE_6        0xf2b10040
+#define        F367TER_RSTATE_5        0xf2b10020
+#define        F367TER_RSTATE_4        0xf2b10010
+#define        F367TER_RSTATE_3        0xf2b10008
+#define        F367TER_RSTATE_2        0xf2b10004
+#define        F367TER_RSTATE_1        0xf2b10002
+#define        F367TER_RSTATE_0        0xf2b10001
+
+/* FSPYBER */
+#define        R367TER_FSPYBER 0xf2b2
+#define        F367TER_FSPYBER_7       0xf2b20080
+#define        F367TER_FSPYOBS_XORREAD 0xf2b20040
+#define        F367TER_FSPYBER_OBSMODE 0xf2b20020
+#define        F367TER_FSPYBER_SYNCBYTE        0xf2b20010
+#define        F367TER_FSPYBER_UNSYNC  0xf2b20008
+#define        F367TER_FSPYBER_CTIME   0xf2b20007
+
+/* FSPYDISTM */
+#define        R367TER_FSPYDISTM       0xf2b3
+#define        F367TER_PKTTIME_DISTANCE_HI     0xf2b300ff
+
+/* FSPYDISTL */
+#define        R367TER_FSPYDISTL       0xf2b4
+#define        F367TER_PKTTIME_DISTANCE_LO     0xf2b400ff
+
+/* FSPYOBS7 */
+#define        R367TER_FSPYOBS7        0xf2b8
+#define        F367TER_FSPYOBS_SPYFAIL 0xf2b80080
+#define        F367TER_FSPYOBS_SPYFAIL1        0xf2b80040
+#define        F367TER_FSPYOBS_ERROR   0xf2b80020
+#define        F367TER_FSPYOBS_STROUT  0xf2b80010
+#define        F367TER_FSPYOBS_RESULTSTATE1    0xf2b8000f
+
+/* FSPYOBS6 */
+#define        R367TER_FSPYOBS6        0xf2b9
+#define        F367TER_FSPYOBS_RESULTSTATe0    0xf2b900f0
+#define        F367TER_FSPYOBS_RESULTSTATEM1   0xf2b9000f
+
+/* FSPYOBS5 */
+#define        R367TER_FSPYOBS5        0xf2ba
+#define        F367TER_FSPYOBS_BYTEOFPACKET1   0xf2ba00ff
+
+/* FSPYOBS4 */
+#define        R367TER_FSPYOBS4        0xf2bb
+#define        F367TER_FSPYOBS_BYTEVALUE1      0xf2bb00ff
+
+/* FSPYOBS3 */
+#define        R367TER_FSPYOBS3        0xf2bc
+#define        F367TER_FSPYOBS_DATA1   0xf2bc00ff
+
+/* FSPYOBS2 */
+#define        R367TER_FSPYOBS2        0xf2bd
+#define        F367TER_FSPYOBS_DATa0   0xf2bd00ff
+
+/* FSPYOBS1 */
+#define        R367TER_FSPYOBS1        0xf2be
+#define        F367TER_FSPYOBS_DATAM1  0xf2be00ff
+
+/* FSPYOBS0 */
+#define        R367TER_FSPYOBS0        0xf2bf
+#define        F367TER_FSPYOBS_DATAM2  0xf2bf00ff
+
+/* SFDEMAP */
+#define        R367TER_SFDEMAP 0xf2c0
+#define        F367TER_SFDEMAP_7       0xf2c00080
+#define        F367TER_SFEC_K_DIVIDER_VIT      0xf2c0007f
+
+/* SFERROR */
+#define        R367TER_SFERROR 0xf2c1
+#define        F367TER_SFEC_REGERR_VIT 0xf2c100ff
+
+/* SFAVSR */
+#define        R367TER_SFAVSR  0xf2c2
+#define        F367TER_SFEC_SUMERRORS  0xf2c20080
+#define        F367TER_SERROR_MAXMODE  0xf2c20040
+#define        F367TER_SN_SFEC 0xf2c20030
+#define        F367TER_KDIV_MODE_SFEC  0xf2c2000c
+#define        F367TER_SFAVSR_1        0xf2c20002
+#define        F367TER_SFAVSR_0        0xf2c20001
+
+/* SFECSTATUS */
+#define        R367TER_SFECSTATUS      0xf2c3
+#define        F367TER_SFEC_ON 0xf2c30080
+#define        F367TER_SFSTATUS_6      0xf2c30040
+#define        F367TER_SFSTATUS_5      0xf2c30020
+#define        F367TER_SFSTATUS_4      0xf2c30010
+#define        F367TER_LOCKEDSFEC      0xf2c30008
+#define        F367TER_SFEC_DELOCK     0xf2c30004
+#define        F367TER_SFEC_DEMODSEL1  0xf2c30002
+#define        F367TER_SFEC_OVFON      0xf2c30001
+
+/* SFKDIV12 */
+#define        R367TER_SFKDIV12        0xf2c4
+#define        F367TER_SFECKDIV12_MAN  0xf2c40080
+#define        F367TER_SFEC_K_DIVIDER_12       0xf2c4007f
+
+/* SFKDIV23 */
+#define        R367TER_SFKDIV23        0xf2c5
+#define        F367TER_SFECKDIV23_MAN  0xf2c50080
+#define        F367TER_SFEC_K_DIVIDER_23       0xf2c5007f
+
+/* SFKDIV34 */
+#define        R367TER_SFKDIV34        0xf2c6
+#define        F367TER_SFECKDIV34_MAN  0xf2c60080
+#define        F367TER_SFEC_K_DIVIDER_34       0xf2c6007f
+
+/* SFKDIV56 */
+#define        R367TER_SFKDIV56        0xf2c7
+#define        F367TER_SFECKDIV56_MAN  0xf2c70080
+#define        F367TER_SFEC_K_DIVIDER_56       0xf2c7007f
+
+/* SFKDIV67 */
+#define        R367TER_SFKDIV67        0xf2c8
+#define        F367TER_SFECKDIV67_MAN  0xf2c80080
+#define        F367TER_SFEC_K_DIVIDER_67       0xf2c8007f
+
+/* SFKDIV78 */
+#define        R367TER_SFKDIV78        0xf2c9
+#define        F367TER_SFECKDIV78_MAN  0xf2c90080
+#define        F367TER_SFEC_K_DIVIDER_78       0xf2c9007f
+
+/* SFDILSTKM */
+#define        R367TER_SFDILSTKM       0xf2ca
+#define        F367TER_SFEC_PACKCPT    0xf2ca00e0
+#define        F367TER_SFEC_DILSTK_HI  0xf2ca001f
+
+/* SFDILSTKL */
+#define        R367TER_SFDILSTKL       0xf2cb
+#define        F367TER_SFEC_DILSTK_LO  0xf2cb00ff
+
+/* SFSTATUS */
+#define        R367TER_SFSTATUS        0xf2cc
+#define        F367TER_SFEC_LINEOK     0xf2cc0080
+#define        F367TER_SFEC_ERROR      0xf2cc0040
+#define        F367TER_SFEC_DATA7      0xf2cc0020
+#define        F367TER_SFEC_OVERFLOW   0xf2cc0010
+#define        F367TER_SFEC_DEMODSEL2  0xf2cc0008
+#define        F367TER_SFEC_NOSYNC     0xf2cc0004
+#define        F367TER_SFEC_UNREGULA   0xf2cc0002
+#define        F367TER_SFEC_READY      0xf2cc0001
+
+/* SFDLYH */
+#define        R367TER_SFDLYH  0xf2cd
+#define        F367TER_SFEC_TSTIMEVALID        0xf2cd0080
+#define        F367TER_SFEC_SPEEDUP    0xf2cd0040
+#define        F367TER_SFEC_STOP       0xf2cd0020
+#define        F367TER_SFEC_REGULATED  0xf2cd0010
+#define        F367TER_SFEC_REALSYMBOFFSET     0xf2cd000f
+
+/* SFDLYM */
+#define        R367TER_SFDLYM  0xf2ce
+#define        F367TER_SFEC_REALSYMBOFFSET_HI  0xf2ce00ff
+
+/* SFDLYL */
+#define        R367TER_SFDLYL  0xf2cf
+#define        F367TER_SFEC_REALSYMBOFFSET_LO  0xf2cf00ff
+
+/* SFDLYSETH */
+#define        R367TER_SFDLYSETH       0xf2d0
+#define        F367TER_SFEC_OFFSET     0xf2d000e0
+#define        F367TER_SFECDLYSETH_4   0xf2d00010
+#define        F367TER_RST_SFEC        0xf2d00008
+#define        F367TER_SFECDLYSETH_2   0xf2d00004
+#define        F367TER_SFEC_DISABLE    0xf2d00002
+#define        F367TER_SFEC_UNREGUL    0xf2d00001
+
+/* SFDLYSETM */
+#define        R367TER_SFDLYSETM       0xf2d1
+#define        F367TER_SFECDLYSETM_7   0xf2d10080
+#define        F367TER_SFEC_SYMBOFFSET_HI      0xf2d1007f
+
+/* SFDLYSETL */
+#define        R367TER_SFDLYSETL       0xf2d2
+#define        F367TER_SFEC_SYMBOFFSET_LO      0xf2d200ff
+
+/* SFOBSCFG */
+#define        R367TER_SFOBSCFG        0xf2d3
+#define        F367TER_SFEC_OBSCFG     0xf2d300ff
+
+/* SFOBSM */
+#define        R367TER_SFOBSM  0xf2d4
+#define        F367TER_SFEC_OBSDATA_HI 0xf2d400ff
+
+/* SFOBSL */
+#define        R367TER_SFOBSL  0xf2d5
+#define        F367TER_SFEC_OBSDATA_LO 0xf2d500ff
+
+/* SFECINFO */
+#define        R367TER_SFECINFO        0xf2d6
+#define        F367TER_SFECINFO_7      0xf2d60080
+#define        F367TER_SFEC_SYNCDLSB   0xf2d60070
+#define        F367TER_SFCE_S1cPHASE   0xf2d6000f
+
+/* SFERRCTRL */
+#define        R367TER_SFERRCTRL       0xf2d8
+#define        F367TER_SFEC_ERR_SOURCE 0xf2d800f0
+#define        F367TER_SFERRCTRL_3     0xf2d80008
+#define        F367TER_SFEC_NUM_EVENT  0xf2d80007
+
+/* SFERRCNTH */
+#define        R367TER_SFERRCNTH       0xf2d9
+#define        F367TER_SFERRC_OLDVALUE 0xf2d90080
+#define        F367TER_SFEC_ERR_CNT    0xf2d9007f
+
+/* SFERRCNTM */
+#define        R367TER_SFERRCNTM       0xf2da
+#define        F367TER_SFEC_ERR_CNT_HI 0xf2da00ff
+
+/* SFERRCNTL */
+#define        R367TER_SFERRCNTL       0xf2db
+#define        F367TER_SFEC_ERR_CNT_LO 0xf2db00ff
+
+/* SYMBRATEM */
+#define        R367TER_SYMBRATEM       0xf2e0
+#define        F367TER_DEFGEN_SYMBRATE_HI      0xf2e000ff
+
+/* SYMBRATEL */
+#define        R367TER_SYMBRATEL       0xf2e1
+#define        F367TER_DEFGEN_SYMBRATE_LO      0xf2e100ff
+
+/* SYMBSTATUS */
+#define        R367TER_SYMBSTATUS      0xf2e2
+#define        F367TER_SYMBDLINE2_OFF  0xf2e20080
+#define        F367TER_SDDL_REINIT1    0xf2e20040
+#define        F367TER_SDD_REINIT1     0xf2e20020
+#define        F367TER_TOKENID_ERROR   0xf2e20010
+#define        F367TER_SYMBRATE_OVERFLOW       0xf2e20008
+#define        F367TER_SYMBRATE_UNDERFLOW      0xf2e20004
+#define        F367TER_TOKENID_RSTEVENT        0xf2e20002
+#define        F367TER_TOKENID_RESET1  0xf2e20001
+
+/* SYMBCFG */
+#define        R367TER_SYMBCFG 0xf2e3
+#define        F367TER_SYMBCFG_7       0xf2e30080
+#define        F367TER_SYMBCFG_6       0xf2e30040
+#define        F367TER_SYMBCFG_5       0xf2e30020
+#define        F367TER_SYMBCFG_4       0xf2e30010
+#define        F367TER_SYMRATE_FSPEED  0xf2e3000c
+#define        F367TER_SYMRATE_SSPEED  0xf2e30003
+
+/* SYMBFIFOM */
+#define        R367TER_SYMBFIFOM       0xf2e4
+#define        F367TER_SYMBFIFOM_7     0xf2e40080
+#define        F367TER_SYMBFIFOM_6     0xf2e40040
+#define        F367TER_DEFGEN_SYMFIFO_HI       0xf2e4003f
+
+/* SYMBFIFOL */
+#define        R367TER_SYMBFIFOL       0xf2e5
+#define        F367TER_DEFGEN_SYMFIFO_LO       0xf2e500ff
+
+/* SYMBOFFSM */
+#define        R367TER_SYMBOFFSM       0xf2e6
+#define        F367TER_TOKENID_RESET2  0xf2e60080
+#define        F367TER_SDDL_REINIT2    0xf2e60040
+#define        F367TER_SDD_REINIT2     0xf2e60020
+#define        F367TER_SYMBOFFSM_4     0xf2e60010
+#define        F367TER_SYMBOFFSM_3     0xf2e60008
+#define        F367TER_DEFGEN_SYMBOFFSET_HI    0xf2e60007
+
+/* SYMBOFFSL */
+#define        R367TER_SYMBOFFSL       0xf2e7
+#define        F367TER_DEFGEN_SYMBOFFSET_LO    0xf2e700ff
+
+/* DEBUG_LT4 */
+#define        R367TER_DEBUG_LT4       0xf400
+#define        F367TER_F_DEBUG_LT4     0xf40000ff
+
+/* DEBUG_LT5 */
+#define        R367TER_DEBUG_LT5       0xf401
+#define        F367TER_F_DEBUG_LT5     0xf40100ff
+
+/* DEBUG_LT6 */
+#define        R367TER_DEBUG_LT6       0xf402
+#define        F367TER_F_DEBUG_LT6     0xf40200ff
+
+/* DEBUG_LT7 */
+#define        R367TER_DEBUG_LT7       0xf403
+#define        F367TER_F_DEBUG_LT7     0xf40300ff
+
+/* DEBUG_LT8 */
+#define        R367TER_DEBUG_LT8       0xf404
+#define        F367TER_F_DEBUG_LT8     0xf40400ff
+
+/* DEBUG_LT9 */
+#define        R367TER_DEBUG_LT9       0xf405
+#define        F367TER_F_DEBUG_LT9     0xf40500ff
+
+#define STV0367TER_NBREGS      445
+
+/* ID */
+#define        R367CAB_ID      0xf000
+#define        F367CAB_IDENTIFICATIONREGISTER  0xf00000ff
+
+/* I2CRPT */
+#define        R367CAB_I2CRPT  0xf001
+#define        F367CAB_I2CT_ON 0xf0010080
+#define        F367CAB_ENARPT_LEVEL    0xf0010070
+#define        F367CAB_SCLT_DELAY      0xf0010008
+#define        F367CAB_SCLT_NOD        0xf0010004
+#define        F367CAB_STOP_ENABLE     0xf0010002
+#define        F367CAB_SDAT_NOD        0xf0010001
+
+/* TOPCTRL */
+#define        R367CAB_TOPCTRL 0xf002
+#define        F367CAB_STDBY   0xf0020080
+#define        F367CAB_STDBY_CORE      0xf0020020
+#define        F367CAB_QAM_COFDM       0xf0020010
+#define        F367CAB_TS_DIS  0xf0020008
+#define        F367CAB_DIR_CLK_216     0xf0020004
+
+/* IOCFG0 */
+#define        R367CAB_IOCFG0  0xf003
+#define        F367CAB_OP0_SD  0xf0030080
+#define        F367CAB_OP0_VAL 0xf0030040
+#define        F367CAB_OP0_OD  0xf0030020
+#define        F367CAB_OP0_INV 0xf0030010
+#define        F367CAB_OP0_DACVALUE_HI 0xf003000f
+
+/* DAc0R */
+#define        R367CAB_DAC0R   0xf004
+#define        F367CAB_OP0_DACVALUE_LO 0xf00400ff
+
+/* IOCFG1 */
+#define        R367CAB_IOCFG1  0xf005
+#define        F367CAB_IP0     0xf0050040
+#define        F367CAB_OP1_OD  0xf0050020
+#define        F367CAB_OP1_INV 0xf0050010
+#define        F367CAB_OP1_DACVALUE_HI 0xf005000f
+
+/* DAC1R */
+#define        R367CAB_DAC1R   0xf006
+#define        F367CAB_OP1_DACVALUE_LO 0xf00600ff
+
+/* IOCFG2 */
+#define        R367CAB_IOCFG2  0xf007
+#define        F367CAB_OP2_LOCK_CONF   0xf00700e0
+#define        F367CAB_OP2_OD  0xf0070010
+#define        F367CAB_OP2_VAL 0xf0070008
+#define        F367CAB_OP1_LOCK_CONF   0xf0070007
+
+/* SDFR */
+#define        R367CAB_SDFR    0xf008
+#define        F367CAB_OP0_FREQ        0xf00800f0
+#define        F367CAB_OP1_FREQ        0xf008000f
+
+/* AUX_CLK */
+#define        R367CAB_AUX_CLK 0xf00a
+#define        F367CAB_AUXFEC_CTL      0xf00a00c0
+#define        F367CAB_DIS_CKX4        0xf00a0020
+#define        F367CAB_CKSEL   0xf00a0018
+#define        F367CAB_CKDIV_PROG      0xf00a0006
+#define        F367CAB_AUXCLK_ENA      0xf00a0001
+
+/* FREESYS1 */
+#define        R367CAB_FREESYS1        0xf00b
+#define        F367CAB_FREESYS_1       0xf00b00ff
+
+/* FREESYS2 */
+#define        R367CAB_FREESYS2        0xf00c
+#define        F367CAB_FREESYS_2       0xf00c00ff
+
+/* FREESYS3 */
+#define        R367CAB_FREESYS3        0xf00d
+#define        F367CAB_FREESYS_3       0xf00d00ff
+
+/* GPIO_CFG */
+#define        R367CAB_GPIO_CFG        0xf00e
+#define        F367CAB_GPIO7_OD        0xf00e0080
+#define        F367CAB_GPIO7_CFG       0xf00e0040
+#define        F367CAB_GPIO6_OD        0xf00e0020
+#define        F367CAB_GPIO6_CFG       0xf00e0010
+#define        F367CAB_GPIO5_OD        0xf00e0008
+#define        F367CAB_GPIO5_CFG       0xf00e0004
+#define        F367CAB_GPIO4_OD        0xf00e0002
+#define        F367CAB_GPIO4_CFG       0xf00e0001
+
+/* GPIO_CMD */
+#define        R367CAB_GPIO_CMD        0xf00f
+#define        F367CAB_GPIO7_VAL       0xf00f0008
+#define        F367CAB_GPIO6_VAL       0xf00f0004
+#define        F367CAB_GPIO5_VAL       0xf00f0002
+#define        F367CAB_GPIO4_VAL       0xf00f0001
+
+/* TSTRES */
+#define        R367CAB_TSTRES  0xf0c0
+#define        F367CAB_FRES_DISPLAY    0xf0c00080
+#define        F367CAB_FRES_FIFO_AD    0xf0c00020
+#define        F367CAB_FRESRS  0xf0c00010
+#define        F367CAB_FRESACS 0xf0c00008
+#define        F367CAB_FRESFEC 0xf0c00004
+#define        F367CAB_FRES_PRIF       0xf0c00002
+#define        F367CAB_FRESCORE        0xf0c00001
+
+/* ANACTRL */
+#define        R367CAB_ANACTRL 0xf0c1
+#define        F367CAB_BYPASS_XTAL     0xf0c10040
+#define        F367CAB_BYPASS_PLLXN    0xf0c1000c
+#define        F367CAB_DIS_PAD_OSC     0xf0c10002
+#define        F367CAB_STDBY_PLLXN     0xf0c10001
+
+/* TSTBUS */
+#define        R367CAB_TSTBUS  0xf0c2
+#define        F367CAB_TS_BYTE_CLK_INV 0xf0c20080
+#define        F367CAB_CFG_IP  0xf0c20070
+#define        F367CAB_CFG_TST 0xf0c2000f
+
+/* RF_AGC1 */
+#define        R367CAB_RF_AGC1 0xf0d4
+#define        F367CAB_RF_AGC1_LEVEL_HI        0xf0d400ff
+
+/* RF_AGC2 */
+#define        R367CAB_RF_AGC2 0xf0d5
+#define        F367CAB_REF_ADGP        0xf0d50080
+#define        F367CAB_STDBY_ADCGP     0xf0d50020
+#define        F367CAB_RF_AGC1_LEVEL_LO        0xf0d50003
+
+/* ANADIGCTRL */
+#define        R367CAB_ANADIGCTRL      0xf0d7
+#define        F367CAB_SEL_CLKDEM      0xf0d70020
+#define        F367CAB_EN_BUFFER_Q     0xf0d70010
+#define        F367CAB_EN_BUFFER_I     0xf0d70008
+#define        F367CAB_ADC_RIS_EGDE    0xf0d70004
+#define        F367CAB_SGN_ADC 0xf0d70002
+#define        F367CAB_SEL_AD12_SYNC   0xf0d70001
+
+/* PLLMDIV */
+#define        R367CAB_PLLMDIV 0xf0d8
+#define        F367CAB_PLL_MDIV        0xf0d800ff
+
+/* PLLNDIV */
+#define        R367CAB_PLLNDIV 0xf0d9
+#define        F367CAB_PLL_NDIV        0xf0d900ff
+
+/* PLLSETUP */
+#define        R367CAB_PLLSETUP        0xf0da
+#define        F367CAB_PLL_PDIV        0xf0da0070
+#define        F367CAB_PLL_KDIV        0xf0da000f
+
+/* DUAL_AD12 */
+#define        R367CAB_DUAL_AD12       0xf0db
+#define        F367CAB_FS20M   0xf0db0020
+#define        F367CAB_FS50M   0xf0db0010
+#define        F367CAB_INMODe0 0xf0db0008
+#define        F367CAB_POFFQ   0xf0db0004
+#define        F367CAB_POFFI   0xf0db0002
+#define        F367CAB_INMODE1 0xf0db0001
+
+/* TSTBIST */
+#define        R367CAB_TSTBIST 0xf0dc
+#define        F367CAB_TST_BYP_CLK     0xf0dc0080
+#define        F367CAB_TST_GCLKENA_STD 0xf0dc0040
+#define        F367CAB_TST_GCLKENA     0xf0dc0020
+#define        F367CAB_TST_MEMBIST     0xf0dc001f
+
+/* CTRL_1 */
+#define        R367CAB_CTRL_1  0xf402
+#define        F367CAB_SOFT_RST        0xf4020080
+#define        F367CAB_EQU_RST 0xf4020008
+#define        F367CAB_CRL_RST 0xf4020004
+#define        F367CAB_TRL_RST 0xf4020002
+#define        F367CAB_AGC_RST 0xf4020001
+
+/* CTRL_2 */
+#define        R367CAB_CTRL_2  0xf403
+#define        F367CAB_DEINT_RST       0xf4030008
+#define        F367CAB_RS_RST  0xf4030004
+
+/* IT_STATUS1 */
+#define        R367CAB_IT_STATUS1      0xf408
+#define        F367CAB_SWEEP_OUT       0xf4080080
+#define        F367CAB_FSM_CRL 0xf4080040
+#define        F367CAB_CRL_LOCK        0xf4080020
+#define        F367CAB_MFSM    0xf4080010
+#define        F367CAB_TRL_LOCK        0xf4080008
+#define        F367CAB_TRL_AGC_LIMIT   0xf4080004
+#define        F367CAB_ADJ_AGC_LOCK    0xf4080002
+#define        F367CAB_AGC_QAM_LOCK    0xf4080001
+
+/* IT_STATUS2 */
+#define        R367CAB_IT_STATUS2      0xf409
+#define        F367CAB_TSMF_CNT        0xf4090080
+#define        F367CAB_TSMF_EOF        0xf4090040
+#define        F367CAB_TSMF_RDY        0xf4090020
+#define        F367CAB_FEC_NOCORR      0xf4090010
+#define        F367CAB_SYNCSTATE       0xf4090008
+#define        F367CAB_DEINT_LOCK      0xf4090004
+#define        F367CAB_FADDING_FRZ     0xf4090002
+#define        F367CAB_TAPMON_ALARM    0xf4090001
+
+/* IT_EN1 */
+#define        R367CAB_IT_EN1  0xf40a
+#define        F367CAB_SWEEP_OUTE      0xf40a0080
+#define        F367CAB_FSM_CRLE        0xf40a0040
+#define        F367CAB_CRL_LOCKE       0xf40a0020
+#define        F367CAB_MFSME   0xf40a0010
+#define        F367CAB_TRL_LOCKE       0xf40a0008
+#define        F367CAB_TRL_AGC_LIMITE  0xf40a0004
+#define        F367CAB_ADJ_AGC_LOCKE   0xf40a0002
+#define        F367CAB_AGC_LOCKE       0xf40a0001
+
+/* IT_EN2 */
+#define        R367CAB_IT_EN2  0xf40b
+#define        F367CAB_TSMF_CNTE       0xf40b0080
+#define        F367CAB_TSMF_EOFE       0xf40b0040
+#define        F367CAB_TSMF_RDYE       0xf40b0020
+#define        F367CAB_FEC_NOCORRE     0xf40b0010
+#define        F367CAB_SYNCSTATEE      0xf40b0008
+#define        F367CAB_DEINT_LOCKE     0xf40b0004
+#define        F367CAB_FADDING_FRZE    0xf40b0002
+#define        F367CAB_TAPMON_ALARME   0xf40b0001
+
+/* CTRL_STATUS */
+#define        R367CAB_CTRL_STATUS     0xf40c
+#define        F367CAB_QAMFEC_LOCK     0xf40c0004
+#define        F367CAB_TSMF_LOCK       0xf40c0002
+#define        F367CAB_TSMF_ERROR      0xf40c0001
+
+/* TEST_CTL */
+#define        R367CAB_TEST_CTL        0xf40f
+#define        F367CAB_TST_BLK_SEL     0xf40f0060
+#define        F367CAB_TST_BUS_SEL     0xf40f001f
+
+/* AGC_CTL */
+#define        R367CAB_AGC_CTL 0xf410
+#define        F367CAB_AGC_LCK_TH      0xf41000f0
+#define        F367CAB_AGC_ACCUMRSTSEL 0xf4100007
+
+/* AGC_IF_CFG */
+#define        R367CAB_AGC_IF_CFG      0xf411
+#define        F367CAB_AGC_IF_BWSEL    0xf41100f0
+#define        F367CAB_AGC_IF_FREEZE   0xf4110002
+
+/* AGC_RF_CFG */
+#define        R367CAB_AGC_RF_CFG      0xf412
+#define        F367CAB_AGC_RF_BWSEL    0xf4120070
+#define        F367CAB_AGC_RF_FREEZE   0xf4120002
+
+/* AGC_PWM_CFG */
+#define        R367CAB_AGC_PWM_CFG     0xf413
+#define        F367CAB_AGC_RF_PWM_TST  0xf4130080
+#define        F367CAB_AGC_RF_PWM_INV  0xf4130040
+#define        F367CAB_AGC_IF_PWM_TST  0xf4130008
+#define        F367CAB_AGC_IF_PWM_INV  0xf4130004
+#define        F367CAB_AGC_PWM_CLKDIV  0xf4130003
+
+/* AGC_PWR_REF_L */
+#define        R367CAB_AGC_PWR_REF_L   0xf414
+#define        F367CAB_AGC_PWRREF_LO   0xf41400ff
+
+/* AGC_PWR_REF_H */
+#define        R367CAB_AGC_PWR_REF_H   0xf415
+#define        F367CAB_AGC_PWRREF_HI   0xf4150003
+
+/* AGC_RF_TH_L */
+#define        R367CAB_AGC_RF_TH_L     0xf416
+#define        F367CAB_AGC_RF_TH_LO    0xf41600ff
+
+/* AGC_RF_TH_H */
+#define        R367CAB_AGC_RF_TH_H     0xf417
+#define        F367CAB_AGC_RF_TH_HI    0xf417000f
+
+/* AGC_IF_LTH_L */
+#define        R367CAB_AGC_IF_LTH_L    0xf418
+#define        F367CAB_AGC_IF_THLO_LO  0xf41800ff
+
+/* AGC_IF_LTH_H */
+#define        R367CAB_AGC_IF_LTH_H    0xf419
+#define        F367CAB_AGC_IF_THLO_HI  0xf419000f
+
+/* AGC_IF_HTH_L */
+#define        R367CAB_AGC_IF_HTH_L    0xf41a
+#define        F367CAB_AGC_IF_THHI_LO  0xf41a00ff
+
+/* AGC_IF_HTH_H */
+#define        R367CAB_AGC_IF_HTH_H    0xf41b
+#define        F367CAB_AGC_IF_THHI_HI  0xf41b000f
+
+/* AGC_PWR_RD_L */
+#define        R367CAB_AGC_PWR_RD_L    0xf41c
+#define        F367CAB_AGC_PWR_WORD_LO 0xf41c00ff
+
+/* AGC_PWR_RD_M */
+#define        R367CAB_AGC_PWR_RD_M    0xf41d
+#define        F367CAB_AGC_PWR_WORD_ME 0xf41d00ff
+
+/* AGC_PWR_RD_H */
+#define        R367CAB_AGC_PWR_RD_H    0xf41e
+#define        F367CAB_AGC_PWR_WORD_HI 0xf41e0003
+
+/* AGC_PWM_IFCMD_L */
+#define        R367CAB_AGC_PWM_IFCMD_L 0xf420
+#define        F367CAB_AGC_IF_PWMCMD_LO        0xf42000ff
+
+/* AGC_PWM_IFCMD_H */
+#define        R367CAB_AGC_PWM_IFCMD_H 0xf421
+#define        F367CAB_AGC_IF_PWMCMD_HI        0xf421000f
+
+/* AGC_PWM_RFCMD_L */
+#define        R367CAB_AGC_PWM_RFCMD_L 0xf422
+#define        F367CAB_AGC_RF_PWMCMD_LO        0xf42200ff
+
+/* AGC_PWM_RFCMD_H */
+#define        R367CAB_AGC_PWM_RFCMD_H 0xf423
+#define        F367CAB_AGC_RF_PWMCMD_HI        0xf423000f
+
+/* IQDEM_CFG */
+#define        R367CAB_IQDEM_CFG       0xf424
+#define        F367CAB_IQDEM_CLK_SEL   0xf4240004
+#define        F367CAB_IQDEM_INVIQ     0xf4240002
+#define        F367CAB_IQDEM_A2dTYPE   0xf4240001
+
+/* MIX_NCO_LL */
+#define        R367CAB_MIX_NCO_LL      0xf425
+#define        F367CAB_MIX_NCO_INC_LL  0xf42500ff
+
+/* MIX_NCO_HL */
+#define        R367CAB_MIX_NCO_HL      0xf426
+#define        F367CAB_MIX_NCO_INC_HL  0xf42600ff
+
+/* MIX_NCO_HH */
+#define        R367CAB_MIX_NCO_HH      0xf427
+#define        F367CAB_MIX_NCO_INVCNST 0xf4270080
+#define        F367CAB_MIX_NCO_INC_HH  0xf427007f
+
+/* SRC_NCO_LL */
+#define        R367CAB_SRC_NCO_LL      0xf428
+#define        F367CAB_SRC_NCO_INC_LL  0xf42800ff
+
+/* SRC_NCO_LH */
+#define        R367CAB_SRC_NCO_LH      0xf429
+#define        F367CAB_SRC_NCO_INC_LH  0xf42900ff
+
+/* SRC_NCO_HL */
+#define        R367CAB_SRC_NCO_HL      0xf42a
+#define        F367CAB_SRC_NCO_INC_HL  0xf42a00ff
+
+/* SRC_NCO_HH */
+#define        R367CAB_SRC_NCO_HH      0xf42b
+#define        F367CAB_SRC_NCO_INC_HH  0xf42b007f
+
+/* IQDEM_GAIN_SRC_L */
+#define        R367CAB_IQDEM_GAIN_SRC_L        0xf42c
+#define        F367CAB_GAIN_SRC_LO     0xf42c00ff
+
+/* IQDEM_GAIN_SRC_H */
+#define        R367CAB_IQDEM_GAIN_SRC_H        0xf42d
+#define        F367CAB_GAIN_SRC_HI     0xf42d0003
+
+/* IQDEM_DCRM_CFG_LL */
+#define        R367CAB_IQDEM_DCRM_CFG_LL       0xf430
+#define        F367CAB_DCRM0_DCIN_L    0xf43000ff
+
+/* IQDEM_DCRM_CFG_LH */
+#define        R367CAB_IQDEM_DCRM_CFG_LH       0xf431
+#define        F367CAB_DCRM1_I_DCIN_L  0xf43100fc
+#define        F367CAB_DCRM0_DCIN_H    0xf4310003
+
+/* IQDEM_DCRM_CFG_HL */
+#define        R367CAB_IQDEM_DCRM_CFG_HL       0xf432
+#define        F367CAB_DCRM1_Q_DCIN_L  0xf43200f0
+#define        F367CAB_DCRM1_I_DCIN_H  0xf432000f
+
+/* IQDEM_DCRM_CFG_HH */
+#define        R367CAB_IQDEM_DCRM_CFG_HH       0xf433
+#define        F367CAB_DCRM1_FRZ       0xf4330080
+#define        F367CAB_DCRM0_FRZ       0xf4330040
+#define        F367CAB_DCRM1_Q_DCIN_H  0xf433003f
+
+/* IQDEM_ADJ_COEFf0 */
+#define        R367CAB_IQDEM_ADJ_COEFF0        0xf434
+#define        F367CAB_ADJIIR_COEFF10_L        0xf43400ff
+
+/* IQDEM_ADJ_COEFF1 */
+#define        R367CAB_IQDEM_ADJ_COEFF1        0xf435
+#define        F367CAB_ADJIIR_COEFF11_L        0xf43500fc
+#define        F367CAB_ADJIIR_COEFF10_H        0xf4350003
+
+/* IQDEM_ADJ_COEFF2 */
+#define        R367CAB_IQDEM_ADJ_COEFF2        0xf436
+#define        F367CAB_ADJIIR_COEFF12_L        0xf43600f0
+#define        F367CAB_ADJIIR_COEFF11_H        0xf436000f
+
+/* IQDEM_ADJ_COEFF3 */
+#define        R367CAB_IQDEM_ADJ_COEFF3        0xf437
+#define        F367CAB_ADJIIR_COEFF20_L        0xf43700c0
+#define        F367CAB_ADJIIR_COEFF12_H        0xf437003f
+
+/* IQDEM_ADJ_COEFF4 */
+#define        R367CAB_IQDEM_ADJ_COEFF4        0xf438
+#define        F367CAB_ADJIIR_COEFF20_H        0xf43800ff
+
+/* IQDEM_ADJ_COEFF5 */
+#define        R367CAB_IQDEM_ADJ_COEFF5        0xf439
+#define        F367CAB_ADJIIR_COEFF21_L        0xf43900ff
+
+/* IQDEM_ADJ_COEFF6 */
+#define        R367CAB_IQDEM_ADJ_COEFF6        0xf43a
+#define        F367CAB_ADJIIR_COEFF22_L        0xf43a00fc
+#define        F367CAB_ADJIIR_COEFF21_H        0xf43a0003
+
+/* IQDEM_ADJ_COEFF7 */
+#define        R367CAB_IQDEM_ADJ_COEFF7        0xf43b
+#define        F367CAB_ADJIIR_COEFF22_H        0xf43b000f
+
+/* IQDEM_ADJ_EN */
+#define        R367CAB_IQDEM_ADJ_EN    0xf43c
+#define        F367CAB_ALLPASSFILT_EN  0xf43c0008
+#define        F367CAB_ADJ_AGC_EN      0xf43c0004
+#define        F367CAB_ADJ_COEFF_FRZ   0xf43c0002
+#define        F367CAB_ADJ_EN  0xf43c0001
+
+/* IQDEM_ADJ_AGC_REF */
+#define        R367CAB_IQDEM_ADJ_AGC_REF       0xf43d
+#define        F367CAB_ADJ_AGC_REF     0xf43d00ff
+
+/* ALLPASSFILT1 */
+#define        R367CAB_ALLPASSFILT1    0xf440
+#define        F367CAB_ALLPASSFILT_COEFF1_LO   0xf44000ff
+
+/* ALLPASSFILT2 */
+#define        R367CAB_ALLPASSFILT2    0xf441
+#define        F367CAB_ALLPASSFILT_COEFF1_ME   0xf44100ff
+
+/* ALLPASSFILT3 */
+#define        R367CAB_ALLPASSFILT3    0xf442
+#define        F367CAB_ALLPASSFILT_COEFF2_LO   0xf44200c0
+#define        F367CAB_ALLPASSFILT_COEFF1_HI   0xf442003f
+
+/* ALLPASSFILT4 */
+#define        R367CAB_ALLPASSFILT4    0xf443
+#define        F367CAB_ALLPASSFILT_COEFF2_MEL  0xf44300ff
+
+/* ALLPASSFILT5 */
+#define        R367CAB_ALLPASSFILT5    0xf444
+#define        F367CAB_ALLPASSFILT_COEFF2_MEH  0xf44400ff
+
+/* ALLPASSFILT6 */
+#define        R367CAB_ALLPASSFILT6    0xf445
+#define        F367CAB_ALLPASSFILT_COEFF3_LO   0xf44500f0
+#define        F367CAB_ALLPASSFILT_COEFF2_HI   0xf445000f
+
+/* ALLPASSFILT7 */
+#define        R367CAB_ALLPASSFILT7    0xf446
+#define        F367CAB_ALLPASSFILT_COEFF3_MEL  0xf44600ff
+
+/* ALLPASSFILT8 */
+#define        R367CAB_ALLPASSFILT8    0xf447
+#define        F367CAB_ALLPASSFILT_COEFF3_MEH  0xf44700ff
+
+/* ALLPASSFILT9 */
+#define        R367CAB_ALLPASSFILT9    0xf448
+#define        F367CAB_ALLPASSFILT_COEFF4_LO   0xf44800fc
+#define        F367CAB_ALLPASSFILT_COEFF3_HI   0xf4480003
+
+/* ALLPASSFILT10 */
+#define        R367CAB_ALLPASSFILT10   0xf449
+#define        F367CAB_ALLPASSFILT_COEFF4_ME   0xf44900ff
+
+/* ALLPASSFILT11 */
+#define        R367CAB_ALLPASSFILT11   0xf44a
+#define        F367CAB_ALLPASSFILT_COEFF4_HI   0xf44a00ff
+
+/* TRL_AGC_CFG */
+#define        R367CAB_TRL_AGC_CFG     0xf450
+#define        F367CAB_TRL_AGC_FREEZE  0xf4500080
+#define        F367CAB_TRL_AGC_REF     0xf450007f
+
+/* TRL_LPF_CFG */
+#define        R367CAB_TRL_LPF_CFG     0xf454
+#define        F367CAB_NYQPOINT_INV    0xf4540040
+#define        F367CAB_TRL_SHIFT       0xf4540030
+#define        F367CAB_NYQ_COEFF_SEL   0xf454000c
+#define        F367CAB_TRL_LPF_FREEZE  0xf4540002
+#define        F367CAB_TRL_LPF_CRT     0xf4540001
+
+/* TRL_LPF_ACQ_GAIN */
+#define        R367CAB_TRL_LPF_ACQ_GAIN        0xf455
+#define        F367CAB_TRL_GDIR_ACQ    0xf4550070
+#define        F367CAB_TRL_GINT_ACQ    0xf4550007
+
+/* TRL_LPF_TRK_GAIN */
+#define        R367CAB_TRL_LPF_TRK_GAIN        0xf456
+#define        F367CAB_TRL_GDIR_TRK    0xf4560070
+#define        F367CAB_TRL_GINT_TRK    0xf4560007
+
+/* TRL_LPF_OUT_GAIN */
+#define        R367CAB_TRL_LPF_OUT_GAIN        0xf457
+#define        F367CAB_TRL_GAIN_OUT    0xf4570007
+
+/* TRL_LOCKDET_LTH */
+#define        R367CAB_TRL_LOCKDET_LTH 0xf458
+#define        F367CAB_TRL_LCK_THLO    0xf4580007
+
+/* TRL_LOCKDET_HTH */
+#define        R367CAB_TRL_LOCKDET_HTH 0xf459
+#define        F367CAB_TRL_LCK_THHI    0xf45900ff
+
+/* TRL_LOCKDET_TRGVAL */
+#define        R367CAB_TRL_LOCKDET_TRGVAL      0xf45a
+#define        F367CAB_TRL_LCK_TRG     0xf45a00ff
+
+/* IQ_QAM */
+#define        R367CAB_IQ_QAM  0xf45c
+#define        F367CAB_IQ_INPUT        0xf45c0008
+#define        F367CAB_DETECT_MODE     0xf45c0007
+
+/* FSM_STATE */
+#define        R367CAB_FSM_STATE       0xf460
+#define        F367CAB_CRL_DFE 0xf4600080
+#define        F367CAB_DFE_START       0xf4600040
+#define        F367CAB_CTRLG_START     0xf4600030
+#define        F367CAB_FSM_FORCESTATE  0xf460000f
+
+/* FSM_CTL */
+#define        R367CAB_FSM_CTL 0xf461
+#define        F367CAB_FEC2_EN 0xf4610040
+#define        F367CAB_SIT_EN  0xf4610020
+#define        F367CAB_TRL_AHEAD       0xf4610010
+#define        F367CAB_TRL2_EN 0xf4610008
+#define        F367CAB_FSM_EQA1_EN     0xf4610004
+#define        F367CAB_FSM_BKP_DIS     0xf4610002
+#define        F367CAB_FSM_FORCE_EN    0xf4610001
+
+/* FSM_STS */
+#define        R367CAB_FSM_STS 0xf462
+#define        F367CAB_FSM_STATUS      0xf462000f
+
+/* FSM_SNR0_HTH */
+#define        R367CAB_FSM_SNR0_HTH    0xf463
+#define        F367CAB_SNR0_HTH        0xf46300ff
+
+/* FSM_SNR1_HTH */
+#define        R367CAB_FSM_SNR1_HTH    0xf464
+#define        F367CAB_SNR1_HTH        0xf46400ff
+
+/* FSM_SNR2_HTH */
+#define        R367CAB_FSM_SNR2_HTH    0xf465
+#define        F367CAB_SNR2_HTH        0xf46500ff
+
+/* FSM_SNR0_LTH */
+#define        R367CAB_FSM_SNR0_LTH    0xf466
+#define        F367CAB_SNR0_LTH        0xf46600ff
+
+/* FSM_SNR1_LTH */
+#define        R367CAB_FSM_SNR1_LTH    0xf467
+#define        F367CAB_SNR1_LTH        0xf46700ff
+
+/* FSM_EQA1_HTH */
+#define        R367CAB_FSM_EQA1_HTH    0xf468
+#define        F367CAB_SNR3_HTH_LO     0xf46800f0
+#define        F367CAB_EQA1_HTH        0xf468000f
+
+/* FSM_TEMPO */
+#define        R367CAB_FSM_TEMPO       0xf469
+#define        F367CAB_SIT     0xf46900c0
+#define        F367CAB_WST     0xf4690038
+#define        F367CAB_ELT     0xf4690006
+#define        F367CAB_SNR3_HTH_HI     0xf4690001
+
+/* FSM_CONFIG */
+#define        R367CAB_FSM_CONFIG      0xf46a
+#define        F367CAB_FEC2_DFEOFF     0xf46a0004
+#define        F367CAB_PRIT_STATE      0xf46a0002
+#define        F367CAB_MODMAP_STATE    0xf46a0001
+
+/* EQU_I_TESTTAP_L */
+#define        R367CAB_EQU_I_TESTTAP_L 0xf474
+#define        F367CAB_I_TEST_TAP_L    0xf47400ff
+
+/* EQU_I_TESTTAP_M */
+#define        R367CAB_EQU_I_TESTTAP_M 0xf475
+#define        F367CAB_I_TEST_TAP_M    0xf47500ff
+
+/* EQU_I_TESTTAP_H */
+#define        R367CAB_EQU_I_TESTTAP_H 0xf476
+#define        F367CAB_I_TEST_TAP_H    0xf476001f
+
+/* EQU_TESTAP_CFG */
+#define        R367CAB_EQU_TESTAP_CFG  0xf477
+#define        F367CAB_TEST_FFE_DFE_SEL        0xf4770040
+#define        F367CAB_TEST_TAP_SELECT 0xf477003f
+
+/* EQU_Q_TESTTAP_L */
+#define        R367CAB_EQU_Q_TESTTAP_L 0xf478
+#define        F367CAB_Q_TEST_TAP_L    0xf47800ff
+
+/* EQU_Q_TESTTAP_M */
+#define        R367CAB_EQU_Q_TESTTAP_M 0xf479
+#define        F367CAB_Q_TEST_TAP_M    0xf47900ff
+
+/* EQU_Q_TESTTAP_H */
+#define        R367CAB_EQU_Q_TESTTAP_H 0xf47a
+#define        F367CAB_Q_TEST_TAP_H    0xf47a001f
+
+/* EQU_TAP_CTRL */
+#define        R367CAB_EQU_TAP_CTRL    0xf47b
+#define        F367CAB_MTAP_FRZ        0xf47b0010
+#define        F367CAB_PRE_FREEZE      0xf47b0008
+#define        F367CAB_DFE_TAPMON_EN   0xf47b0004
+#define        F367CAB_FFE_TAPMON_EN   0xf47b0002
+#define        F367CAB_MTAP_ONLY       0xf47b0001
+
+/* EQU_CTR_CRL_CONTROL_L */
+#define        R367CAB_EQU_CTR_CRL_CONTROL_L   0xf47c
+#define        F367CAB_EQU_CTR_CRL_CONTROL_LO  0xf47c00ff
+
+/* EQU_CTR_CRL_CONTROL_H */
+#define        R367CAB_EQU_CTR_CRL_CONTROL_H   0xf47d
+#define        F367CAB_EQU_CTR_CRL_CONTROL_HI  0xf47d00ff
+
+/* EQU_CTR_HIPOW_L */
+#define        R367CAB_EQU_CTR_HIPOW_L 0xf47e
+#define        F367CAB_CTR_HIPOW_L     0xf47e00ff
+
+/* EQU_CTR_HIPOW_H */
+#define        R367CAB_EQU_CTR_HIPOW_H 0xf47f
+#define        F367CAB_CTR_HIPOW_H     0xf47f00ff
+
+/* EQU_I_EQU_LO */
+#define        R367CAB_EQU_I_EQU_LO    0xf480
+#define        F367CAB_EQU_I_EQU_L     0xf48000ff
+
+/* EQU_I_EQU_HI */
+#define        R367CAB_EQU_I_EQU_HI    0xf481
+#define        F367CAB_EQU_I_EQU_H     0xf4810003
+
+/* EQU_Q_EQU_LO */
+#define        R367CAB_EQU_Q_EQU_LO    0xf482
+#define        F367CAB_EQU_Q_EQU_L     0xf48200ff
+
+/* EQU_Q_EQU_HI */
+#define        R367CAB_EQU_Q_EQU_HI    0xf483
+#define        F367CAB_EQU_Q_EQU_H     0xf4830003
+
+/* EQU_MAPPER */
+#define        R367CAB_EQU_MAPPER      0xf484
+#define        F367CAB_QUAD_AUTO       0xf4840080
+#define        F367CAB_QUAD_INV        0xf4840040
+#define        F367CAB_QAM_MODE        0xf4840007
+
+/* EQU_SWEEP_RATE */
+#define        R367CAB_EQU_SWEEP_RATE  0xf485
+#define        F367CAB_SNR_PER 0xf48500c0
+#define        F367CAB_SWEEP_RATE      0xf485003f
+
+/* EQU_SNR_LO */
+#define        R367CAB_EQU_SNR_LO      0xf486
+#define        F367CAB_SNR_LO  0xf48600ff
+
+/* EQU_SNR_HI */
+#define        R367CAB_EQU_SNR_HI      0xf487
+#define        F367CAB_SNR_HI  0xf48700ff
+
+/* EQU_GAMMA_LO */
+#define        R367CAB_EQU_GAMMA_LO    0xf488
+#define        F367CAB_GAMMA_LO        0xf48800ff
+
+/* EQU_GAMMA_HI */
+#define        R367CAB_EQU_GAMMA_HI    0xf489
+#define        F367CAB_GAMMA_ME        0xf48900ff
+
+/* EQU_ERR_GAIN */
+#define        R367CAB_EQU_ERR_GAIN    0xf48a
+#define        F367CAB_EQA1MU  0xf48a0070
+#define        F367CAB_CRL2MU  0xf48a000e
+#define        F367CAB_GAMMA_HI        0xf48a0001
+
+/* EQU_RADIUS */
+#define        R367CAB_EQU_RADIUS      0xf48b
+#define        F367CAB_RADIUS  0xf48b00ff
+
+/* EQU_FFE_MAINTAP */
+#define        R367CAB_EQU_FFE_MAINTAP 0xf48c
+#define        F367CAB_FFE_MAINTAP_INIT        0xf48c00ff
+
+/* EQU_FFE_LEAKAGE */
+#define        R367CAB_EQU_FFE_LEAKAGE 0xf48e
+#define        F367CAB_LEAK_PER        0xf48e00f0
+#define        F367CAB_EQU_OUTSEL      0xf48e0002
+#define        F367CAB_PNT2dFE 0xf48e0001
+
+/* EQU_FFE_MAINTAP_POS */
+#define        R367CAB_EQU_FFE_MAINTAP_POS     0xf48f
+#define        F367CAB_FFE_LEAK_EN     0xf48f0080
+#define        F367CAB_DFE_LEAK_EN     0xf48f0040
+#define        F367CAB_FFE_MAINTAP_POS 0xf48f003f
+
+/* EQU_GAIN_WIDE */
+#define        R367CAB_EQU_GAIN_WIDE   0xf490
+#define        F367CAB_DFE_GAIN_WIDE   0xf49000f0
+#define        F367CAB_FFE_GAIN_WIDE   0xf490000f
+
+/* EQU_GAIN_NARROW */
+#define        R367CAB_EQU_GAIN_NARROW 0xf491
+#define        F367CAB_DFE_GAIN_NARROW 0xf49100f0
+#define        F367CAB_FFE_GAIN_NARROW 0xf491000f
+
+/* EQU_CTR_LPF_GAIN */
+#define        R367CAB_EQU_CTR_LPF_GAIN        0xf492
+#define        F367CAB_CTR_GTO 0xf4920080
+#define        F367CAB_CTR_GDIR        0xf4920070
+#define        F367CAB_SWEEP_EN        0xf4920008
+#define        F367CAB_CTR_GINT        0xf4920007
+
+/* EQU_CRL_LPF_GAIN */
+#define        R367CAB_EQU_CRL_LPF_GAIN        0xf493
+#define        F367CAB_CRL_GTO 0xf4930080
+#define        F367CAB_CRL_GDIR        0xf4930070
+#define        F367CAB_SWEEP_DIR       0xf4930008
+#define        F367CAB_CRL_GINT        0xf4930007
+
+/* EQU_GLOBAL_GAIN */
+#define        R367CAB_EQU_GLOBAL_GAIN 0xf494
+#define        F367CAB_CRL_GAIN        0xf49400f8
+#define        F367CAB_CTR_INC_GAIN    0xf4940004
+#define        F367CAB_CTR_FRAC        0xf4940003
+
+/* EQU_CRL_LD_SEN */
+#define        R367CAB_EQU_CRL_LD_SEN  0xf495
+#define        F367CAB_CTR_BADPOINT_EN 0xf4950080
+#define        F367CAB_CTR_GAIN        0xf4950070
+#define        F367CAB_LIMANEN 0xf4950008
+#define        F367CAB_CRL_LD_SEN      0xf4950007
+
+/* EQU_CRL_LD_VAL */
+#define        R367CAB_EQU_CRL_LD_VAL  0xf496
+#define        F367CAB_CRL_BISTH_LIMIT 0xf4960080
+#define        F367CAB_CARE_EN 0xf4960040
+#define        F367CAB_CRL_LD_PER      0xf4960030
+#define        F367CAB_CRL_LD_WST      0xf496000c
+#define        F367CAB_CRL_LD_TFS      0xf4960003
+
+/* EQU_CRL_TFR */
+#define        R367CAB_EQU_CRL_TFR     0xf497
+#define        F367CAB_CRL_LD_TFR      0xf49700ff
+
+/* EQU_CRL_BISTH_LO */
+#define        R367CAB_EQU_CRL_BISTH_LO        0xf498
+#define        F367CAB_CRL_BISTH_LO    0xf49800ff
+
+/* EQU_CRL_BISTH_HI */
+#define        R367CAB_EQU_CRL_BISTH_HI        0xf499
+#define        F367CAB_CRL_BISTH_HI    0xf49900ff
+
+/* EQU_SWEEP_RANGE_LO */
+#define        R367CAB_EQU_SWEEP_RANGE_LO      0xf49a
+#define        F367CAB_SWEEP_RANGE_LO  0xf49a00ff
+
+/* EQU_SWEEP_RANGE_HI */
+#define        R367CAB_EQU_SWEEP_RANGE_HI      0xf49b
+#define        F367CAB_SWEEP_RANGE_HI  0xf49b00ff
+
+/* EQU_CRL_LIMITER */
+#define        R367CAB_EQU_CRL_LIMITER 0xf49c
+#define        F367CAB_BISECTOR_EN     0xf49c0080
+#define        F367CAB_PHEST128_EN     0xf49c0040
+#define        F367CAB_CRL_LIM 0xf49c003f
+
+/* EQU_MODULUS_MAP */
+#define        R367CAB_EQU_MODULUS_MAP 0xf49d
+#define        F367CAB_PNT_DEPTH       0xf49d00e0
+#define        F367CAB_MODULUS_CMP     0xf49d001f
+
+/* EQU_PNT_GAIN */
+#define        R367CAB_EQU_PNT_GAIN    0xf49e
+#define        F367CAB_PNT_EN  0xf49e0080
+#define        F367CAB_MODULUSMAP_EN   0xf49e0040
+#define        F367CAB_PNT_GAIN        0xf49e003f
+
+/* FEC_AC_CTR_0 */
+#define        R367CAB_FEC_AC_CTR_0    0xf4a8
+#define        F367CAB_BE_BYPASS       0xf4a80020
+#define        F367CAB_REFRESH47       0xf4a80010
+#define        F367CAB_CT_NBST 0xf4a80008
+#define        F367CAB_TEI_ENA 0xf4a80004
+#define        F367CAB_DS_ENA  0xf4a80002
+#define        F367CAB_TSMF_EN 0xf4a80001
+
+/* FEC_AC_CTR_1 */
+#define        R367CAB_FEC_AC_CTR_1    0xf4a9
+#define        F367CAB_DEINT_DEPTH     0xf4a900ff
+
+/* FEC_AC_CTR_2 */
+#define        R367CAB_FEC_AC_CTR_2    0xf4aa
+#define        F367CAB_DEINT_M 0xf4aa00f8
+#define        F367CAB_DIS_UNLOCK      0xf4aa0004
+#define        F367CAB_DESCR_MODE      0xf4aa0003
+
+/* FEC_AC_CTR_3 */
+#define        R367CAB_FEC_AC_CTR_3    0xf4ab
+#define        F367CAB_DI_UNLOCK       0xf4ab0080
+#define        F367CAB_DI_FREEZE       0xf4ab0040
+#define        F367CAB_MISMATCH        0xf4ab0030
+#define        F367CAB_ACQ_MODE        0xf4ab000c
+#define        F367CAB_TRK_MODE        0xf4ab0003
+
+/* FEC_STATUS */
+#define        R367CAB_FEC_STATUS      0xf4ac
+#define        F367CAB_DEINT_SMCNTR    0xf4ac00e0
+#define        F367CAB_DEINT_SYNCSTATE 0xf4ac0018
+#define        F367CAB_DEINT_SYNLOST   0xf4ac0004
+#define        F367CAB_DESCR_SYNCSTATE 0xf4ac0002
+
+/* RS_COUNTER_0 */
+#define        R367CAB_RS_COUNTER_0    0xf4ae
+#define        F367CAB_BK_CT_L 0xf4ae00ff
+
+/* RS_COUNTER_1 */
+#define        R367CAB_RS_COUNTER_1    0xf4af
+#define        F367CAB_BK_CT_H 0xf4af00ff
+
+/* RS_COUNTER_2 */
+#define        R367CAB_RS_COUNTER_2    0xf4b0
+#define        F367CAB_CORR_CT_L       0xf4b000ff
+
+/* RS_COUNTER_3 */
+#define        R367CAB_RS_COUNTER_3    0xf4b1
+#define        F367CAB_CORR_CT_H       0xf4b100ff
+
+/* RS_COUNTER_4 */
+#define        R367CAB_RS_COUNTER_4    0xf4b2
+#define        F367CAB_UNCORR_CT_L     0xf4b200ff
+
+/* RS_COUNTER_5 */
+#define        R367CAB_RS_COUNTER_5    0xf4b3
+#define        F367CAB_UNCORR_CT_H     0xf4b300ff
+
+/* BERT_0 */
+#define        R367CAB_BERT_0  0xf4b4
+#define        F367CAB_RS_NOCORR       0xf4b40004
+#define        F367CAB_CT_HOLD 0xf4b40002
+#define        F367CAB_CT_CLEAR        0xf4b40001
+
+/* BERT_1 */
+#define        R367CAB_BERT_1  0xf4b5
+#define        F367CAB_BERT_ON 0xf4b50020
+#define        F367CAB_BERT_ERR_SRC    0xf4b50010
+#define        F367CAB_BERT_ERR_MODE   0xf4b50008
+#define        F367CAB_BERT_NBYTE      0xf4b50007
+
+/* BERT_2 */
+#define        R367CAB_BERT_2  0xf4b6
+#define        F367CAB_BERT_ERRCOUNT_L 0xf4b600ff
+
+/* BERT_3 */
+#define        R367CAB_BERT_3  0xf4b7
+#define        F367CAB_BERT_ERRCOUNT_H 0xf4b700ff
+
+/* OUTFORMAT_0 */
+#define        R367CAB_OUTFORMAT_0     0xf4b8
+#define        F367CAB_CLK_POLARITY    0xf4b80080
+#define        F367CAB_FEC_TYPE        0xf4b80040
+#define        F367CAB_SYNC_STRIP      0xf4b80008
+#define        F367CAB_TS_SWAP 0xf4b80004
+#define        F367CAB_OUTFORMAT       0xf4b80003
+
+/* OUTFORMAT_1 */
+#define        R367CAB_OUTFORMAT_1     0xf4b9
+#define        F367CAB_CI_DIVRANGE     0xf4b900ff
+
+/* SMOOTHER_2 */
+#define        R367CAB_SMOOTHER_2      0xf4be
+#define        F367CAB_FIFO_BYPASS     0xf4be0020
+
+/* TSMF_CTRL_0 */
+#define        R367CAB_TSMF_CTRL_0     0xf4c0
+#define        F367CAB_TS_NUMBER       0xf4c0001e
+#define        F367CAB_SEL_MODE        0xf4c00001
+
+/* TSMF_CTRL_1 */
+#define        R367CAB_TSMF_CTRL_1     0xf4c1
+#define        F367CAB_CHECK_ERROR_BIT 0xf4c10080
+#define        F367CAB_CHCK_F_SYNC     0xf4c10040
+#define        F367CAB_H_MODE  0xf4c10008
+#define        F367CAB_D_V_MODE        0xf4c10004
+#define        F367CAB_MODE    0xf4c10003
+
+/* TSMF_CTRL_3 */
+#define        R367CAB_TSMF_CTRL_3     0xf4c3
+#define        F367CAB_SYNC_IN_COUNT   0xf4c300f0
+#define        F367CAB_SYNC_OUT_COUNT  0xf4c3000f
+
+/* TS_ON_ID_0 */
+#define        R367CAB_TS_ON_ID_0      0xf4c4
+#define        F367CAB_TS_ID_L 0xf4c400ff
+
+/* TS_ON_ID_1 */
+#define        R367CAB_TS_ON_ID_1      0xf4c5
+#define        F367CAB_TS_ID_H 0xf4c500ff
+
+/* TS_ON_ID_2 */
+#define        R367CAB_TS_ON_ID_2      0xf4c6
+#define        F367CAB_ON_ID_L 0xf4c600ff
+
+/* TS_ON_ID_3 */
+#define        R367CAB_TS_ON_ID_3      0xf4c7
+#define        F367CAB_ON_ID_H 0xf4c700ff
+
+/* RE_STATUS_0 */
+#define        R367CAB_RE_STATUS_0     0xf4c8
+#define        F367CAB_RECEIVE_STATUS_L        0xf4c800ff
+
+/* RE_STATUS_1 */
+#define        R367CAB_RE_STATUS_1     0xf4c9
+#define        F367CAB_RECEIVE_STATUS_LH       0xf4c900ff
+
+/* RE_STATUS_2 */
+#define        R367CAB_RE_STATUS_2     0xf4ca
+#define        F367CAB_RECEIVE_STATUS_HL       0xf4ca00ff
+
+/* RE_STATUS_3 */
+#define        R367CAB_RE_STATUS_3     0xf4cb
+#define        F367CAB_RECEIVE_STATUS_HH       0xf4cb003f
+
+/* TS_STATUS_0 */
+#define        R367CAB_TS_STATUS_0     0xf4cc
+#define        F367CAB_TS_STATUS_L     0xf4cc00ff
+
+/* TS_STATUS_1 */
+#define        R367CAB_TS_STATUS_1     0xf4cd
+#define        F367CAB_TS_STATUS_H     0xf4cd007f
+
+/* TS_STATUS_2 */
+#define        R367CAB_TS_STATUS_2     0xf4ce
+#define        F367CAB_ERROR   0xf4ce0080
+#define        F367CAB_EMERGENCY       0xf4ce0040
+#define        F367CAB_CRE_TS  0xf4ce0030
+#define        F367CAB_VER     0xf4ce000e
+#define        F367CAB_M_LOCK  0xf4ce0001
+
+/* TS_STATUS_3 */
+#define        R367CAB_TS_STATUS_3     0xf4cf
+#define        F367CAB_UPDATE_READY    0xf4cf0080
+#define        F367CAB_END_FRAME_HEADER        0xf4cf0040
+#define        F367CAB_CONTCNT 0xf4cf0020
+#define        F367CAB_TS_IDENTIFIER_SEL       0xf4cf000f
+
+/* T_O_ID_0 */
+#define        R367CAB_T_O_ID_0        0xf4d0
+#define        F367CAB_ON_ID_I_L       0xf4d000ff
+
+/* T_O_ID_1 */
+#define        R367CAB_T_O_ID_1        0xf4d1
+#define        F367CAB_ON_ID_I_H       0xf4d100ff
+
+/* T_O_ID_2 */
+#define        R367CAB_T_O_ID_2        0xf4d2
+#define        F367CAB_TS_ID_I_L       0xf4d200ff
+
+/* T_O_ID_3 */
+#define        R367CAB_T_O_ID_3        0xf4d3
+#define        F367CAB_TS_ID_I_H       0xf4d300ff
+
+#define STV0367CAB_NBREGS      187
+
+#endif
index e3e35d1ce8384270837e1b77ebe27de09f4d4d92..91c7ee8b2313159d096cb2a7debd18e8cd065381 100644 (file)
@@ -53,6 +53,8 @@ struct stv0900_config {
        u8 tun2_type;
        /* Set device param to start dma */
        int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
+       /* Hook for Lock LED */
+       void (*set_lock_led)(struct dvb_frontend *fe, int offon);
 };
 
 #if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
index 4f5e7d3a0e610bf4ebc02c6f2f7e01fdef01c712..0ca316d6fffacf68733df21fe3e5419149b8ea0f 100644 (file)
@@ -1604,6 +1604,9 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe,
        p_search.standard = STV0900_AUTO_SEARCH;
        p_search.iq_inversion = STV0900_IQ_AUTO;
        p_search.search_algo = STV0900_BLIND_SEARCH;
+       /* Speeds up DVB-S searching */
+       if (c->delivery_system == SYS_DVBS)
+               p_search.standard = STV0900_SEARCH_DVBS1;
 
        intp->srch_standard[demod] = p_search.standard;
        intp->symbol_rate[demod] = p_search.symbol_rate;
@@ -1660,8 +1663,14 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status)
                        | FE_HAS_VITERBI
                        | FE_HAS_SYNC
                        | FE_HAS_LOCK;
-       } else
+               if (state->config->set_lock_led)
+                       state->config->set_lock_led(fe, 1);
+       } else {
+               *status = 0;
+               if (state->config->set_lock_led)
+                       state->config->set_lock_led(fe, 0);
                dprintk("DEMOD LOCK FAIL\n");
+       }
 
        return 0;
 }
@@ -1831,6 +1840,9 @@ static void stv0900_release(struct dvb_frontend *fe)
 
        dprintk("%s\n", __func__);
 
+       if (state->config->set_lock_led)
+               state->config->set_lock_led(fe, 0);
+
        if ((--(state->internal->dmds_used)) <= 0) {
 
                dprintk("%s: Actually removing\n", __func__);
@@ -1842,6 +1854,18 @@ static void stv0900_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
+static int stv0900_sleep(struct dvb_frontend *fe)
+{
+       struct stv0900_state *state = fe->demodulator_priv;
+
+       dprintk("%s\n", __func__);
+
+       if (state->config->set_lock_led)
+               state->config->set_lock_led(fe, 0);
+
+       return 0;
+}
+
 static int stv0900_get_frontend(struct dvb_frontend *fe,
                                struct dvb_frontend_parameters *p)
 {
@@ -1876,6 +1900,7 @@ static struct dvb_frontend_ops stv0900_ops = {
        .release                        = stv0900_release,
        .init                           = stv0900_init,
        .get_frontend                   = stv0900_get_frontend,
+       .sleep                          = stv0900_sleep,
        .get_frontend_algo              = stv0900_frontend_algo,
        .i2c_gate_ctrl                  = stv0900_i2c_gate_ctrl,
        .diseqc_send_master_cmd         = stv0900_send_master_cmd,
index 4e0fc2c8a41c24eeabd940e8e79547547d1f6163..41d0f0a6655d522c4c5eaf376746e1fbe950cedb 100644 (file)
@@ -767,8 +767,12 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
         * In case of any error, the lock is unlocked and exit within the
         * relevant operations themselves.
         */
-       if (enable)
-               mutex_lock(&state->internal->tuner_lock);
+       if (enable) {
+               if (state->config->tuner_i2c_lock)
+                       state->config->tuner_i2c_lock(&state->frontend, 1);
+               else
+                       mutex_lock(&state->internal->tuner_lock);
+       }
 
        reg = STV090x_READ_DEMOD(state, I2CRPT);
        if (enable) {
@@ -784,13 +788,20 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
                        goto err;
        }
 
-       if (!enable)
-               mutex_unlock(&state->internal->tuner_lock);
+       if (!enable) {
+               if (state->config->tuner_i2c_lock)
+                       state->config->tuner_i2c_lock(&state->frontend, 0);
+               else
+                       mutex_unlock(&state->internal->tuner_lock);
+       }
 
        return 0;
 err:
        dprintk(FE_ERROR, 1, "I/O error");
-       mutex_unlock(&state->internal->tuner_lock);
+       if (state->config->tuner_i2c_lock)
+               state->config->tuner_i2c_lock(&state->frontend, 0);
+       else
+               mutex_unlock(&state->internal->tuner_lock);
        return -1;
 }
 
@@ -2883,10 +2894,12 @@ static int stv090x_optimize_track(struct stv090x_state *state)
                STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
                if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
                        goto err;
-               if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
-                       goto err;
-               if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
-                       goto err;
+               if (state->internal->dev_ver >= 0x30) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
+                               goto err;
+               }
                if (state->frame_len == STV090x_LONG_FRAME) {
                        reg = STV090x_READ_DEMOD(state, DMDMODCOD);
                        modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
@@ -3846,6 +3859,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
 {
        struct stv090x_state *state = fe->demodulator_priv;
        u32 reg;
+       u8 full_standby = 0;
 
        if (stv090x_i2c_gate_ctrl(state, 1) < 0)
                goto err;
@@ -3858,24 +3872,119 @@ static int stv090x_sleep(struct dvb_frontend *fe)
        if (stv090x_i2c_gate_ctrl(state, 0) < 0)
                goto err;
 
-       dprintk(FE_DEBUG, 1, "Set %s to sleep",
-               state->device == STV0900 ? "STV0900" : "STV0903");
+       dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep",
+               state->device == STV0900 ? "STV0900" : "STV0903",
+               state->demod);
 
-       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
-       STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
-       if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
-               goto err;
+       mutex_lock(&state->internal->demod_lock);
 
-       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
-       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
-               goto err;
+       switch (state->demod) {
+       case STV090x_DEMODULATOR_0:
+               /* power off ADC 1 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+               STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+                       goto err;
+               /* power off DiSEqC 1 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+               STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+                       goto err;
+
+               /* check whether path 2 is already sleeping, that is when
+                  ADC2 is off */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+               if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0)
+                       full_standby = 1;
+
+               /* stop clocks */
+               reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+               /* packet delineator 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1);
+               /* ADC 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1);
+               /* FEC clock is shared between the two paths, only stop it
+                  when full standby is possible */
+               if (full_standby)
+                       STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+                       goto err;
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               /* sampling 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1);
+               /* viterbi 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1);
+               /* TS clock is shared between the two paths, only stop it
+                  when full standby is possible */
+               if (full_standby)
+                       STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_DEMODULATOR_1:
+               /* power off ADC 2 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+               STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+                       goto err;
+               /* power off DiSEqC 2 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+               STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+                       goto err;
+
+               /* check whether path 1 is already sleeping, that is when
+                  ADC1 is off */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+               if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0)
+                       full_standby = 1;
+
+               /* stop clocks */
+               reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+               /* packet delineator 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1);
+               /* ADC 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1);
+               /* FEC clock is shared between the two paths, only stop it
+                  when full standby is possible */
+               if (full_standby)
+                       STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+                       goto err;
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               /* sampling 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1);
+               /* viterbi 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1);
+               /* TS clock is shared between the two paths, only stop it
+                  when full standby is possible */
+               if (full_standby)
+                       STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               break;
 
+       default:
+               dprintk(FE_ERROR, 1, "Wrong demodulator!");
+               break;
+       }
+
+       if (full_standby) {
+               /* general power off */
+               reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+               STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+                       goto err;
+       }
+
+       mutex_unlock(&state->internal->demod_lock);
        return 0;
 
 err_gateoff:
        stv090x_i2c_gate_ctrl(state, 0);
 err:
+       mutex_unlock(&state->internal->demod_lock);
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
 }
@@ -3885,21 +3994,94 @@ static int stv090x_wakeup(struct dvb_frontend *fe)
        struct stv090x_state *state = fe->demodulator_priv;
        u32 reg;
 
-       dprintk(FE_DEBUG, 1, "Wake %s from standby",
-               state->device == STV0900 ? "STV0900" : "STV0903");
+       dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby",
+               state->device == STV0900 ? "STV0900" : "STV0903",
+               state->demod);
+
+       mutex_lock(&state->internal->demod_lock);
 
+       /* general power on */
        reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
        STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
        if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
                goto err;
 
-       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
-       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
-       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
-               goto err;
+       switch (state->demod) {
+       case STV090x_DEMODULATOR_0:
+               /* power on ADC 1 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+               STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+                       goto err;
+               /* power on DiSEqC 1 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR2);
+               STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
+                       goto err;
+
+               /* activate clocks */
+               reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+               /* packet delineator 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0);
+               /* ADC 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0);
+               /* FEC clock */
+               STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+                       goto err;
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               /* sampling 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0);
+               /* viterbi 1 clock */
+               STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0);
+               /* TS clock */
+               STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               break;
 
+       case STV090x_DEMODULATOR_1:
+               /* power on ADC 2 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+               STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
+                       goto err;
+               /* power on DiSEqC 2 */
+               reg = stv090x_read_reg(state, STV090x_TSTTNR4);
+               STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1);
+               if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
+                       goto err;
+
+               /* activate clocks */
+               reg = stv090x_read_reg(state, STV090x_STOPCLK1);
+               /* packet delineator 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0);
+               /* ADC 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0);
+               /* FEC clock */
+               STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
+                       goto err;
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               /* sampling 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0);
+               /* viterbi 2 clock */
+               STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0);
+               /* TS clock */
+               STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               break;
+
+       default:
+               dprintk(FE_ERROR, 1, "Wrong demodulator!");
+               break;
+       }
+
+       mutex_unlock(&state->internal->demod_lock);
        return 0;
 err:
+       mutex_unlock(&state->internal->demod_lock);
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
 }
@@ -4169,6 +4351,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
        switch (state->config->ts1_mode) {
        case STV090x_TSMODE_PARALLEL_PUNCTURED:
                reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
                if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
@@ -4177,6 +4360,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_DVBCI:
                reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
                if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
@@ -4185,6 +4369,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_SERIAL_PUNCTURED:
                reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
                if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
@@ -4193,6 +4378,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_SERIAL_CONTINUOUS:
                reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
                if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
@@ -4206,6 +4392,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
        switch (state->config->ts2_mode) {
        case STV090x_TSMODE_PARALLEL_PUNCTURED:
                reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
                if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4214,6 +4401,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_DVBCI:
                reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
                if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4222,6 +4410,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_SERIAL_PUNCTURED:
                reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
                if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4230,6 +4419,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 
        case STV090x_TSMODE_SERIAL_CONTINUOUS:
                reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei);
                STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
                STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
                if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4506,16 +4696,26 @@ static int stv090x_setup(struct dvb_frontend *fe)
        if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
                goto err;
 
-       /* workaround for stuck DiSEqC output */
-       if (config->diseqc_envelope_mode)
-               stv090x_send_diseqc_burst(fe, SEC_MINI_A);
-
        return 0;
 err:
        dprintk(FE_ERROR, 1, "I/O error");
        return -1;
 }
 
+int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
+               u8 xor_value)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u8 reg = 0;
+
+       STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir);
+       STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value);
+       STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value);
+
+       return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
+}
+EXPORT_SYMBOL(stv090x_set_gpio);
+
 static struct dvb_frontend_ops stv090x_ops = {
 
        .info = {
@@ -4580,39 +4780,35 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
                state->internal = temp_int->internal;
                state->internal->num_used++;
                dprintk(FE_INFO, 1, "Found Internal Structure!");
-               dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
-                       state->device == STV0900 ? "STV0900" : "STV0903",
-                       demod,
-                       state->internal->dev_ver);
-               return &state->frontend;
        } else {
                state->internal = kmalloc(sizeof(struct stv090x_internal),
                                          GFP_KERNEL);
+               if (!state->internal)
+                       goto error;
                temp_int = append_internal(state->internal);
+               if (!temp_int) {
+                       kfree(state->internal);
+                       goto error;
+               }
                state->internal->num_used = 1;
                state->internal->mclk = 0;
                state->internal->dev_ver = 0;
                state->internal->i2c_adap = state->i2c;
                state->internal->i2c_addr = state->config->address;
                dprintk(FE_INFO, 1, "Create New Internal Structure!");
-       }
 
-       mutex_init(&state->internal->demod_lock);
-       mutex_init(&state->internal->tuner_lock);
+               mutex_init(&state->internal->demod_lock);
+               mutex_init(&state->internal->tuner_lock);
 
-       if (stv090x_sleep(&state->frontend) < 0) {
-               dprintk(FE_ERROR, 1, "Error putting device to sleep");
-               goto error;
+               if (stv090x_setup(&state->frontend) < 0) {
+                       dprintk(FE_ERROR, 1, "Error setting up device");
+                       goto err_remove;
+               }
        }
 
-       if (stv090x_setup(&state->frontend) < 0) {
-               dprintk(FE_ERROR, 1, "Error setting up device");
-               goto error;
-       }
-       if (stv090x_wakeup(&state->frontend) < 0) {
-               dprintk(FE_ERROR, 1, "Error waking device");
-               goto error;
-       }
+       /* workaround for stuck DiSEqC output */
+       if (config->diseqc_envelope_mode)
+               stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
 
        dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
               state->device == STV0900 ? "STV0900" : "STV0903",
@@ -4621,6 +4817,9 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
 
        return &state->frontend;
 
+err_remove:
+       remove_dev(state->internal);
+       kfree(state->internal);
 error:
        kfree(state);
        return NULL;
index dd1b93ae4e9d2e570c68409b19b010575d259de3..29cdc2b71314539b26f4530aa56095bde229c45a 100644 (file)
@@ -78,6 +78,9 @@ struct stv090x_config {
        u32 ts1_clk;
        u32 ts2_clk;
 
+       u8 ts1_tei : 1;
+       u8 ts2_tei : 1;
+
        enum stv090x_i2crpt     repeater_level;
 
        u8                      tuner_bbgain; /* default: 10db */
@@ -97,6 +100,7 @@ struct stv090x_config {
        int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
        int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
        int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+       void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
 };
 
 #if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
@@ -104,6 +108,11 @@ struct stv090x_config {
 extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
                                           struct i2c_adapter *i2c,
                                           enum stv090x_demodulator demod);
+
+/* dir = 0 -> output, dir = 1 -> input/open-drain */
+extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
+               u8 dir, u8 value, u8 xor_value);
+
 #else
 
 static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
@@ -113,6 +122,13 @@ static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *c
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
+
+static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
+               u8 opd, u8 value, u8 xor_value)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 #endif /* CONFIG_DVB_STV090x */
 
 #endif /* __STV090x_H */
index 2502855dd7847d5c644130500088602a4bd3f224..93741ee14297399f028daf5c7dfcb3320d2f0f1d 100644 (file)
 #define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD        8
 
 #define STV090x_Px_NOSPLHy(__x, __y)           (0xf48f - (__x - 1) * 0x200 - __y * 0x1)
-#define STv090x_P1_NOSPLH0                     STV090x_Px_NOSPLHy(1, 0)
-#define STv090x_P1_NOSPLH1                     STV090x_Px_NOSPLHy(1, 1)
-#define STv090x_P2_NOSPLH0                     STV090x_Px_NOSPLHy(2, 0)
-#define STv090x_P2_NOSPLH1                     STV090x_Px_NOSPLHy(2, 1)
+#define STV090x_P1_NOSPLH0                     STV090x_Px_NOSPLHy(1, 0)
+#define STV090x_P1_NOSPLH1                     STV090x_Px_NOSPLHy(1, 1)
+#define STV090x_P2_NOSPLH0                     STV090x_Px_NOSPLHy(2, 0)
+#define STV090x_P2_NOSPLH1                     STV090x_Px_NOSPLHy(2, 1)
 #define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0
 #define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8
 
 
 #define STV090x_Px_BCLC2S28(__x)               (0xf49d - (__x - 1) * 0x200)
 #define STV090x_P1_BCLC2S28                    STV090x_Px_BCLC2S28(1)
-#define STV090x_P2_BCLC2S28                    STV090x_Px_BCLC2S28(1)
+#define STV090x_P2_BCLC2S28                    STV090x_Px_BCLC2S28(2)
 #define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4
 #define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2
 #define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0
 
 #define STV090x_Px_BCLC2S216A(__x)             (0xf49e - (__x - 1) * 0x200)
 #define STV090x_P1_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
-#define STV090x_P2_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
+#define STV090x_P2_BCLC2S216A                  STV090x_Px_BCLC2S216A(2)
 #define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD       4
 #define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD       2
 #define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD       0
 
 #define STV090x_Px_BCLC2S232A(__x)             (0xf49f - (__x - 1) * 0x200)
 #define STV090x_P1_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
-#define STV090x_P2_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
+#define STV090x_P2_BCLC2S232A                  STV090x_Px_BCLC2S232A(2)
 #define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD       4
 #define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD       2
 #define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD       0
 
 #define STV090x_Px_CCIACC(__x)                 (0xf4c4 - (__x - 1) * 0x200)
 #define STV090x_P1_CCIACC                      STV090x_Px_CCIACC(1)
-#define STV090x_P2_CCIACC                      STV090x_Px_CCIACC(1)
+#define STV090x_P2_CCIACC                      STV090x_Px_CCIACC(2)
 #define STV090x_OFFST_Px_CCI_VALUE_FIELD       0
 #define STV090x_WIDTH_Px_CCI_VALUE_FIELD       8
 
index 4627f491656bcf90f239ff419a1a627672ddb38f..81aa984c551f3516b7179aaab4624d4039252df9 100644 (file)
@@ -463,16 +463,16 @@ struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
                                    const struct zl10036_config *config,
                                    struct i2c_adapter *i2c)
 {
-       struct zl10036_state *state = NULL;
+       struct zl10036_state *state;
        int ret;
 
-       if (NULL == config) {
+       if (!config) {
                printk(KERN_ERR "%s: no config specified", __func__);
-               goto error;
+               return NULL;
        }
 
        state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL);
-       if (NULL == state)
+       if (!state)
                return NULL;
 
        state->config = config;
@@ -507,7 +507,7 @@ struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
        return fe;
 
 error:
-       zl10036_release(fe);
+       kfree(state);
        return NULL;
 }
 EXPORT_SYMBOL(zl10036_attach);
index 0608aabb14eeab3b4a883bf0d2330d0063701cf3..2bc96874d044ef02973eda58e2ab259111058f4a 100644 (file)
@@ -9,3 +9,6 @@ obj-$(CONFIG_DVB_NGENE) += ngene.o
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
 EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+
+# For the staging CI driver cxd2099
+EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
index 4692a41ad95b8b598ab2b16c9a92a776db522898..fcf4be901ec8675bed8d9346b3e4ca22e73264fa 100644 (file)
 
 static int tuner_attach_stv6110(struct ngene_channel *chan)
 {
+       struct i2c_adapter *i2c;
        struct stv090x_config *feconf = (struct stv090x_config *)
                chan->dev->card_info->fe_config[chan->number];
        struct stv6110x_config *tunerconf = (struct stv6110x_config *)
                chan->dev->card_info->tuner_config[chan->number];
        struct stv6110x_devctl *ctl;
 
-       ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf,
-                        &chan->i2c_adapter);
+       /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+       if (chan->number < 2)
+               i2c = &chan->dev->channel[0].i2c_adapter;
+       else
+               i2c = &chan->dev->channel[1].i2c_adapter;
+
+       ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c);
        if (ctl == NULL) {
                printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n");
                return -ENODEV;
        }
 
        feconf->tuner_init          = ctl->tuner_init;
+       feconf->tuner_sleep         = ctl->tuner_sleep;
        feconf->tuner_set_mode      = ctl->tuner_set_mode;
        feconf->tuner_set_frequency = ctl->tuner_set_frequency;
        feconf->tuner_get_frequency = ctl->tuner_get_frequency;
@@ -78,29 +85,106 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
 
 static int demod_attach_stv0900(struct ngene_channel *chan)
 {
+       struct i2c_adapter *i2c;
        struct stv090x_config *feconf = (struct stv090x_config *)
                chan->dev->card_info->fe_config[chan->number];
 
-       chan->fe = dvb_attach(stv090x_attach,
-                       feconf,
-                       &chan->i2c_adapter,
-                       chan->number == 0 ? STV090x_DEMODULATOR_0 :
-                                           STV090x_DEMODULATOR_1);
+       /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+       /* Note: Both adapters share the same i2c bus, but the demod     */
+       /*       driver requires that each demod has its own i2c adapter */
+       if (chan->number < 2)
+               i2c = &chan->dev->channel[0].i2c_adapter;
+       else
+               i2c = &chan->dev->channel[1].i2c_adapter;
+
+       chan->fe = dvb_attach(stv090x_attach, feconf, i2c,
+                       (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0
+                                               : STV090x_DEMODULATOR_1);
        if (chan->fe == NULL) {
                printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n");
                return -ENODEV;
        }
 
-       if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0,
+       /* store channel info */
+       if (feconf->tuner_i2c_lock)
+               chan->fe->analog_demod_priv = chan;
+
+       if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0,
                        0, chan->dev->card_info->lnb[chan->number])) {
                printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
                dvb_frontend_detach(chan->fe);
+               chan->fe = NULL;
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
+{
+       struct ngene_channel *chan = fe->analog_demod_priv;
+
+       if (lock)
+               down(&chan->dev->pll_mutex);
+       else
+               up(&chan->dev->pll_mutex);
+}
+
+static int cineS2_probe(struct ngene_channel *chan)
+{
+       struct i2c_adapter *i2c;
+       struct stv090x_config *fe_conf;
+       u8 buf[3];
+       struct i2c_msg i2c_msg = { .flags = 0, .buf = buf };
+       int rc;
+
+       /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */
+       if (chan->number < 2)
+               i2c = &chan->dev->channel[0].i2c_adapter;
+       else
+               i2c = &chan->dev->channel[1].i2c_adapter;
+
+       fe_conf = chan->dev->card_info->fe_config[chan->number];
+       i2c_msg.addr = fe_conf->address;
+
+       /* probe demod */
+       i2c_msg.len = 2;
+       buf[0] = 0xf1;
+       buf[1] = 0x00;
+       rc = i2c_transfer(i2c, &i2c_msg, 1);
+       if (rc != 1)
+               return -ENODEV;
+
+       /* demod found, attach it */
+       rc = demod_attach_stv0900(chan);
+       if (rc < 0 || chan->number < 2)
+               return rc;
+
+       /* demod #2: reprogram outputs DPN1 & DPN2 */
+       i2c_msg.len = 3;
+       buf[0] = 0xf1;
+       switch (chan->number) {
+       case 2:
+               buf[1] = 0x5c;
+               buf[2] = 0xc2;
+               break;
+       case 3:
+               buf[1] = 0x61;
+               buf[2] = 0xcc;
+               break;
+       default:
                return -ENODEV;
        }
+       rc = i2c_transfer(i2c, &i2c_msg, 1);
+       if (rc != 1) {
+               printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+               return -EIO;
+       }
 
        return 0;
 }
 
+
 static struct lgdt330x_config aver_m780 = {
        .demod_address = 0xb2 >> 1,
        .demod_chip    = LGDT3303,
@@ -151,6 +235,29 @@ static struct stv090x_config fe_cineS2 = {
        .adc2_range     = STV090x_ADC_1Vpp,
 
        .diseqc_envelope_mode = true,
+
+       .tuner_i2c_lock = cineS2_tuner_i2c_lock,
+};
+
+static struct stv090x_config fe_cineS2_2 = {
+       .device         = STV0900,
+       .demod_mode     = STV090x_DUAL,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 27000000,
+       .address        = 0x69,
+
+       .ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+       .ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+       .repeater_level = STV090x_RPTLEVEL_16,
+
+       .adc1_range     = STV090x_ADC_1Vpp,
+       .adc2_range     = STV090x_ADC_1Vpp,
+
+       .diseqc_envelope_mode = true,
+
+       .tuner_i2c_lock = cineS2_tuner_i2c_lock,
 };
 
 static struct stv6110x_config tuner_cineS2_0 = {
@@ -175,7 +282,8 @@ static struct ngene_info ngene_info_cineS2 = {
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0b, 0x08},
        .tsf            = {3, 3},
-       .fw_version     = 15,
+       .fw_version     = 18,
+       .msi_supported  = true,
 };
 
 static struct ngene_info ngene_info_satixS2 = {
@@ -188,46 +296,54 @@ static struct ngene_info ngene_info_satixS2 = {
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0b, 0x08},
        .tsf            = {3, 3},
-       .fw_version     = 15,
+       .fw_version     = 18,
+       .msi_supported  = true,
 };
 
 static struct ngene_info ngene_info_satixS2v2 = {
        .type           = NGENE_SIDEWINDER,
        .name           = "Mystique SaTiX-S2 Dual (v2)",
-       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
-       .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110},
-       .fe_config      = {&fe_cineS2, &fe_cineS2},
-       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
-       .lnb            = {0x0a, 0x08},
+       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+                          NGENE_IO_TSOUT},
+       .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+       .lnb            = {0x0a, 0x08, 0x0b, 0x09},
        .tsf            = {3, 3},
-       .fw_version     = 15,
+       .fw_version     = 18,
+       .msi_supported  = true,
 };
 
 static struct ngene_info ngene_info_cineS2v5 = {
        .type           = NGENE_SIDEWINDER,
        .name           = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)",
-       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
-       .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110},
-       .fe_config      = {&fe_cineS2, &fe_cineS2},
-       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
-       .lnb            = {0x0a, 0x08},
+       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+                          NGENE_IO_TSOUT},
+       .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+       .lnb            = {0x0a, 0x08, 0x0b, 0x09},
        .tsf            = {3, 3},
-       .fw_version     = 15,
+       .fw_version     = 18,
+       .msi_supported  = true,
 };
 
+
 static struct ngene_info ngene_info_duoFlexS2 = {
        .type           = NGENE_SIDEWINDER,
        .name           = "Digital Devices DuoFlex S2 miniPCIe",
-       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
-       .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110},
-       .fe_config      = {&fe_cineS2, &fe_cineS2},
-       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1},
-       .lnb            = {0x0a, 0x08},
+       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
+                          NGENE_IO_TSOUT},
+       .demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
+       .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
+       .lnb            = {0x0a, 0x08, 0x0b, 0x09},
        .tsf            = {3, 3},
-       .fw_version     = 15,
+       .fw_version     = 18,
+       .msi_supported  = true,
 };
 
 static struct ngene_info ngene_info_m780 = {
@@ -321,6 +437,7 @@ static struct pci_driver ngene_pci_driver = {
        .probe       = ngene_probe,
        .remove      = __devexit_p(ngene_remove),
        .err_handler = &ngene_errors,
+       .shutdown    = ngene_shutdown,
 };
 
 static __init int module_init_ngene(void)
index dc073bdc623aa03d689defa616ffa7a1cd430b62..175a0f6c2a4c1b11a06925ba907274ee4d1737e8 100644 (file)
@@ -45,6 +45,9 @@ static int one_adapter = 1;
 module_param(one_adapter, int, 0444);
 MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
 
+static int shutdown_workaround;
+module_param(shutdown_workaround, int, 0644);
+MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
 
 static int debug;
 module_param(debug, int, 0444);
@@ -143,7 +146,7 @@ static void demux_tasklet(unsigned long data)
                        }
                } else {
                        if (chan->HWState == HWSTATE_RUN) {
-                               u32 Flags = 0;
+                               u32 Flags = chan->DataFormatFlags;
                                IBufferExchange *exch1 = chan->pBufferExchange;
                                IBufferExchange *exch2 = chan->pBufferExchange2;
                                if (Cur->ngeneBuffer.SR.Flags & 0x01)
@@ -474,9 +477,9 @@ static u8 SPDIFConfiguration[10] = {
 
 /* Set NGENE I2S Config to transport stream compatible mode */
 
-static u8 TS_I2SConfiguration[4] = { 0x3E, 0x1A, 0x00, 0x00 }; /*3e 18 00 00 ?*/
+static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
 
-static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 };
+static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
 
 static u8 ITUDecoderSetup[4][16] = {
        {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20,  /* SDTV */
@@ -749,13 +752,11 @@ void set_transfer(struct ngene_channel *chan, int state)
                if (chan->mode & NGENE_IO_TSOUT) {
                        chan->pBufferExchange = tsout_exchange;
                        /* 0x66666666 = 50MHz *2^33 /250MHz */
-                       chan->AudioDTOValue = 0x66666666;
-                       /* set_dto(chan, 38810700+1000); */
-                       /* set_dto(chan, 19392658); */
+                       chan->AudioDTOValue = 0x80000000;
+                       chan->AudioDTOUpdated = 1;
                }
                if (chan->mode & NGENE_IO_TSIN)
                        chan->pBufferExchange = tsin_exchange;
-               /* ngwritel(0, 0x9310); */
                spin_unlock_irq(&chan->state_lock);
        } else
                ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
@@ -1168,6 +1169,7 @@ static void ngene_release_buffers(struct ngene *dev)
                iounmap(dev->iomem);
        free_common_buffers(dev);
        vfree(dev->tsout_buf);
+       vfree(dev->tsin_buf);
        vfree(dev->ain_buf);
        vfree(dev->vin_buf);
        vfree(dev);
@@ -1184,6 +1186,13 @@ static int ngene_get_buffers(struct ngene *dev)
                dvb_ringbuffer_init(&dev->tsout_rbuf,
                                    dev->tsout_buf, TSOUT_BUF_SIZE);
        }
+       if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
+               dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
+               if (!dev->tsin_buf)
+                       return -ENOMEM;
+               dvb_ringbuffer_init(&dev->tsin_rbuf,
+                                   dev->tsin_buf, TSIN_BUF_SIZE);
+       }
        if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
                dev->ain_buf = vmalloc(AIN_BUF_SIZE);
                if (!dev->ain_buf)
@@ -1257,6 +1266,10 @@ static int ngene_load_firm(struct ngene *dev)
                fw_name = "ngene_17.fw";
                dev->cmd_timeout_workaround = true;
                break;
+       case 18:
+               size = 0;
+               fw_name = "ngene_18.fw";
+               break;
        }
 
        if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
@@ -1266,6 +1279,8 @@ static int ngene_load_firm(struct ngene *dev)
                        ": Copy %s to your hotplug directory!\n", fw_name);
                return -1;
        }
+       if (size == 0)
+               size = fw->size;
        if (size != fw->size) {
                printk(KERN_ERR DEVICE_NAME
                        ": Firmware %s has invalid size!", fw_name);
@@ -1301,6 +1316,35 @@ static void ngene_stop(struct ngene *dev)
 #endif
 }
 
+static int ngene_buffer_config(struct ngene *dev)
+{
+       int stat;
+
+       if (dev->card_info->fw_version >= 17) {
+               u8 tsin12_config[6]   = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
+               u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
+               u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
+               u8 *bconf = tsin12_config;
+
+               if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
+                   dev->card_info->io_type[3]&NGENE_IO_TSIN) {
+                       bconf = tsin1234_config;
+                       if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
+                           dev->ci.en)
+                               bconf = tsio1235_config;
+               }
+               stat = ngene_command_config_free_buf(dev, bconf);
+       } else {
+               int bconf = BUFFER_CONFIG_4422;
+
+               if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+                       bconf = BUFFER_CONFIG_3333;
+               stat = ngene_command_config_buf(dev, bconf);
+       }
+       return stat;
+}
+
+
 static int ngene_start(struct ngene *dev)
 {
        int stat;
@@ -1365,23 +1409,6 @@ static int ngene_start(struct ngene *dev)
        if (stat < 0)
                goto fail;
 
-       if (dev->card_info->fw_version == 17) {
-               u8 tsin4_config[6] = {
-                       3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0};
-               u8 default_config[6] = {
-                       4096 / 64, 4096 / 64, 0, 2048 / 64, 2048 / 64, 0};
-               u8 *bconf = default_config;
-
-               if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
-                       bconf = tsin4_config;
-               dprintk(KERN_DEBUG DEVICE_NAME ": FW 17 buffer config\n");
-               stat = ngene_command_config_free_buf(dev, bconf);
-       } else {
-               int bconf = BUFFER_CONFIG_4422;
-               if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
-                       bconf = BUFFER_CONFIG_3333;
-               stat = ngene_command_config_buf(dev, bconf);
-       }
        if (!stat)
                return stat;
 
@@ -1397,9 +1424,6 @@ fail2:
        return stat;
 }
 
-
-
-
 /****************************************************************************/
 /****************************************************************************/
 /****************************************************************************/
@@ -1408,20 +1432,25 @@ static void release_channel(struct ngene_channel *chan)
 {
        struct dvb_demux *dvbdemux = &chan->demux;
        struct ngene *dev = chan->dev;
-       struct ngene_info *ni = dev->card_info;
-       int io = ni->io_type[chan->number];
 
-       if (chan->dev->cmd_timeout_workaround && chan->running)
+       if (chan->running)
                set_transfer(chan, 0);
 
        tasklet_kill(&chan->demux_tasklet);
 
-       if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
-               if (chan->fe) {
-                       dvb_unregister_frontend(chan->fe);
-                       dvb_frontend_detach(chan->fe);
-                       chan->fe = NULL;
-               }
+       if (chan->ci_dev) {
+               dvb_unregister_device(chan->ci_dev);
+               chan->ci_dev = NULL;
+       }
+
+       if (chan->fe) {
+               dvb_unregister_frontend(chan->fe);
+               dvb_frontend_detach(chan->fe);
+               chan->fe = NULL;
+       }
+
+       if (chan->has_demux) {
+               dvb_net_release(&chan->dvbnet);
                dvbdemux->dmx.close(&dvbdemux->dmx);
                dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
                                              &chan->hw_frontend);
@@ -1429,9 +1458,12 @@ static void release_channel(struct ngene_channel *chan)
                                              &chan->mem_frontend);
                dvb_dmxdev_release(&chan->dmxdev);
                dvb_dmx_release(&chan->demux);
+               chan->has_demux = false;
+       }
 
-               if (chan->number == 0 || !one_adapter)
-                       dvb_unregister_adapter(&dev->adapter[chan->number]);
+       if (chan->has_adapter) {
+               dvb_unregister_adapter(&dev->adapter[chan->number]);
+               chan->has_adapter = false;
        }
 }
 
@@ -1449,9 +1481,27 @@ static int init_channel(struct ngene_channel *chan)
        chan->type = io;
        chan->mode = chan->type;        /* for now only one mode */
 
+       if (io & NGENE_IO_TSIN) {
+               chan->fe = NULL;
+               if (ni->demod_attach[nr]) {
+                       ret = ni->demod_attach[nr](chan);
+                       if (ret < 0)
+                               goto err;
+               }
+               if (chan->fe && ni->tuner_attach[nr]) {
+                       ret = ni->tuner_attach[nr](chan);
+                       if (ret < 0)
+                               goto err;
+               }
+       }
+
+       if (!dev->ci.en && (io & NGENE_IO_TSOUT))
+               return 0;
+
        if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
                if (nr >= STREAM_AUDIOIN1)
                        chan->DataFormatFlags = DF_SWAP32;
+
                if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
                        adapter = &dev->adapter[nr];
                        ret = dvb_register_adapter(adapter, "nGene",
@@ -1459,40 +1509,50 @@ static int init_channel(struct ngene_channel *chan)
                                                   &chan->dev->pci_dev->dev,
                                                   adapter_nr);
                        if (ret < 0)
-                               return ret;
+                               goto err;
                        if (dev->first_adapter == NULL)
                                dev->first_adapter = adapter;
-               } else {
+                       chan->has_adapter = true;
+               } else
                        adapter = dev->first_adapter;
-               }
+       }
 
+       if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
+               dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
+               set_transfer(chan, 1);
+               set_transfer(&chan->dev->channel[2], 1);
+               dvb_register_device(adapter, &chan->ci_dev,
+                                   &ngene_dvbdev_ci, (void *) chan,
+                                   DVB_DEVICE_SEC);
+               if (!chan->ci_dev)
+                       goto err;
+       }
+
+       if (chan->fe) {
+               if (dvb_register_frontend(adapter, chan->fe) < 0)
+                       goto err;
+               chan->has_demux = true;
+       }
+
+       if (chan->has_demux) {
                ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
                                              ngene_start_feed,
                                              ngene_stop_feed, chan);
                ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
                                                 &chan->hw_frontend,
                                                 &chan->mem_frontend, adapter);
+               ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
        }
 
-       if (io & NGENE_IO_TSIN) {
+       return ret;
+
+err:
+       if (chan->fe) {
+               dvb_frontend_detach(chan->fe);
                chan->fe = NULL;
-               if (ni->demod_attach[nr])
-                       ni->demod_attach[nr](chan);
-               if (chan->fe) {
-                       if (dvb_register_frontend(adapter, chan->fe) < 0) {
-                               if (chan->fe->ops.release)
-                                       chan->fe->ops.release(chan->fe);
-                               chan->fe = NULL;
-                       }
-               }
-               if (chan->fe && ni->tuner_attach[nr])
-                       if (ni->tuner_attach[nr] (chan) < 0) {
-                               printk(KERN_ERR DEVICE_NAME
-                                      ": Tuner attach failed on channel %d!\n",
-                                      nr);
-                       }
        }
-       return ret;
+       release_channel(chan);
+       return 0;
 }
 
 static int init_channels(struct ngene *dev)
@@ -1510,6 +1570,57 @@ static int init_channels(struct ngene *dev)
        return 0;
 }
 
+static void cxd_attach(struct ngene *dev)
+{
+       struct ngene_ci *ci = &dev->ci;
+
+       ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter);
+       ci->dev = dev;
+       return;
+}
+
+static void cxd_detach(struct ngene *dev)
+{
+       struct ngene_ci *ci = &dev->ci;
+
+       dvb_ca_en50221_release(ci->en);
+       kfree(ci->en);
+       ci->en = 0;
+}
+
+/***********************************/
+/* workaround for shutdown failure */
+/***********************************/
+
+static void ngene_unlink(struct ngene *dev)
+{
+       struct ngene_command com;
+
+       com.cmd.hdr.Opcode = CMD_MEM_WRITE;
+       com.cmd.hdr.Length = 3;
+       com.cmd.MemoryWrite.address = 0x910c;
+       com.cmd.MemoryWrite.data = 0xff;
+       com.in_len = 3;
+       com.out_len = 1;
+
+       down(&dev->cmd_mutex);
+       ngwritel(0, NGENE_INT_ENABLE);
+       ngene_command_mutex(dev, &com);
+       up(&dev->cmd_mutex);
+}
+
+void ngene_shutdown(struct pci_dev *pdev)
+{
+       struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+
+       if (!dev || !shutdown_workaround)
+               return;
+
+       printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n");
+       ngene_unlink(dev);
+       pci_disable_device(pdev);
+}
+
 /****************************************************************************/
 /* device probe/remove calls ************************************************/
 /****************************************************************************/
@@ -1522,6 +1633,8 @@ void __devexit ngene_remove(struct pci_dev *pdev)
        tasklet_kill(&dev->event_tasklet);
        for (i = MAX_STREAM - 1; i >= 0; i--)
                release_channel(&dev->channel[i]);
+       if (dev->ci.en)
+               cxd_detach(dev);
        ngene_stop(dev);
        ngene_release_buffers(dev);
        pci_set_drvdata(pdev, NULL);
@@ -1557,6 +1670,13 @@ int __devinit ngene_probe(struct pci_dev *pci_dev,
        if (stat < 0)
                goto fail1;
 
+       cxd_attach(dev);
+
+       stat = ngene_buffer_config(dev);
+       if (stat < 0)
+               goto fail1;
+
+
        dev->i2c_current_bus = -1;
 
        /* Register DVB adapters and devices for both channels */
index 3832e5983c19104b92c29d273392dfdae53cc074..0b4943233166e67824ff39cbebb5a859fe4b1497 100644 (file)
 /* COMMAND API interface ****************************************************/
 /****************************************************************************/
 
+static ssize_t ts_write(struct file *file, const char *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ngene_channel *chan = dvbdev->priv;
+       struct ngene *dev = chan->dev;
+
+       if (wait_event_interruptible(dev->tsout_rbuf.queue,
+                                    dvb_ringbuffer_free
+                                    (&dev->tsout_rbuf) >= count) < 0)
+               return 0;
+
+       dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+
+       return count;
+}
+
+static ssize_t ts_read(struct file *file, char *buf,
+                      size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ngene_channel *chan = dvbdev->priv;
+       struct ngene *dev = chan->dev;
+       int left, avail;
+
+       left = count;
+       while (left) {
+               if (wait_event_interruptible(
+                           dev->tsin_rbuf.queue,
+                           dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
+                       return -EAGAIN;
+               avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
+               if (avail > left)
+                       avail = left;
+               dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
+               left -= avail;
+               buf += avail;
+       }
+       return count;
+}
+
+static const struct file_operations ci_fops = {
+       .owner   = THIS_MODULE,
+       .read    = ts_read,
+       .write   = ts_write,
+       .open    = dvb_generic_open,
+       .release = dvb_generic_release,
+};
+
+struct dvb_device ngene_dvbdev_ci = {
+       .priv    = 0,
+       .readers = -1,
+       .writers = -1,
+       .users   = -1,
+       .fops    = &ci_fops,
+};
+
+
 /****************************************************************************/
 /* DVB functions and API interface ******************************************/
 /****************************************************************************/
@@ -63,10 +121,21 @@ static void swap_buffer(u32 *p, u32 len)
 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 {
        struct ngene_channel *chan = priv;
+       struct ngene *dev = chan->dev;
 
 
-       if (chan->users > 0)
+       if (flags & DF_SWAP32)
+               swap_buffer(buf, len);
+       if (dev->ci.en && chan->number == 2) {
+               if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) {
+                       dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len);
+                       wake_up_interruptible(&dev->tsin_rbuf.queue);
+               }
+               return 0;
+       }
+       if (chan->users > 0) {
                dvb_dmx_swfilter(&chan->demux, buf, len);
+       }
        return NULL;
 }
 
index 8fb4200f83f847e73d0f17b6e70e0a33dd107df1..40fce9e3ae66323435ec36cfb75d1049361a85f7 100644 (file)
 #include "dmxdev.h"
 #include "dvbdev.h"
 #include "dvb_demux.h"
+#include "dvb_ca_en50221.h"
 #include "dvb_frontend.h"
 #include "dvb_ringbuffer.h"
+#include "dvb_net.h"
+#include "cxd2099.h"
 
 #define DEVICE_NAME "ngene"
 
@@ -636,14 +639,18 @@ struct ngene_channel {
        int                   number;
        int                   type;
        int                   mode;
+       bool                  has_adapter;
+       bool                  has_demux;
 
        struct dvb_frontend  *fe;
        struct dmxdev         dmxdev;
        struct dvb_demux      demux;
+       struct dvb_net        dvbnet;
        struct dmx_frontend   hw_frontend;
        struct dmx_frontend   mem_frontend;
        int                   users;
        struct video_device  *v4l_dev;
+       struct dvb_device    *ci_dev;
        struct tasklet_struct demux_tasklet;
 
        struct SBufferHeader *nextBuffer;
@@ -710,6 +717,15 @@ struct ngene_channel {
        int running;
 };
 
+
+struct ngene_ci {
+       struct device         device;
+       struct i2c_adapter    i2c_adapter;
+
+       struct ngene         *dev;
+       struct dvb_ca_en50221 *en;
+};
+
 struct ngene;
 
 typedef void (rx_cb_t)(struct ngene *, u32, u8);
@@ -774,6 +790,10 @@ struct ngene {
 #define TSOUT_BUF_SIZE (512*188*8)
        struct dvb_ringbuffer tsout_rbuf;
 
+       u8                   *tsin_buf;
+#define TSIN_BUF_SIZE (512*188*8)
+       struct dvb_ringbuffer tsin_rbuf;
+
        u8                   *ain_buf;
 #define AIN_BUF_SIZE (128*1024)
        struct dvb_ringbuffer ain_rbuf;
@@ -785,6 +805,8 @@ struct ngene {
 
        unsigned long         exp_val;
        int prev_cmd;
+
+       struct ngene_ci       ci;
 };
 
 struct ngene_info {
@@ -863,6 +885,7 @@ struct ngene_buffer {
 int __devinit ngene_probe(struct pci_dev *pci_dev,
                          const struct pci_device_id *id);
 void __devexit ngene_remove(struct pci_dev *pdev);
+void ngene_shutdown(struct pci_dev *pdev);
 int ngene_command(struct ngene *dev, struct ngene_command *com);
 int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
 void set_transfer(struct ngene_channel *chan, int state);
@@ -872,6 +895,7 @@ void FillTSBuffer(void *Buffer, int Length, u32 Flags);
 int ngene_i2c_init(struct ngene *dev, int dev_nr);
 
 /* Provided by ngene-dvb.c */
+extern struct dvb_device ngene_dvbdev_ci;
 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags);
 int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed);
index 25b43e587fa6c274142debf1a0ec3ab2f5593c7f..af121db88ea002318bf28cb4135c7955ff334927 100644 (file)
@@ -64,7 +64,7 @@ static struct sms_board sms_boards[] = {
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
-               .rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW,
+               .rc_codes = RC_MAP_HAUPPAUGE,
                .board_cfg.leds_power = 26,
                .board_cfg.led0 = 27,
                .board_cfg.led1 = 28,
index b82756db5bd17aa2a870caf1fd4695777acbc3a4..1d79ada864d6a9c9510529309f0a486e9f0e9b79 100644 (file)
@@ -26,7 +26,7 @@
  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  *
  *
- * the project's page is at http://www.linuxtv.org/ 
+ * the project's page is at http://www.linuxtv.org/
  */
 
 #include <linux/module.h>
@@ -102,6 +102,7 @@ struct budget_ci_ir {
        int rc5_device;
        u32 ir_key;
        bool have_command;
+       bool full_rc5;          /* Outputs a full RC5 code */
 };
 
 struct budget_ci {
@@ -154,11 +155,18 @@ static void msp430_ir_interrupt(unsigned long data)
                return;
        budget_ci->ir.have_command = false;
 
-       /* FIXME: We should generate complete scancodes with device info */
        if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
            budget_ci->ir.rc5_device != (command & 0x1f))
                return;
 
+       if (budget_ci->ir.full_rc5) {
+               rc_keydown(dev,
+                          budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
+                          (command & 0x20) ? 1 : 0);
+               return;
+       }
+
+       /* FIXME: We should generate complete scancodes for all devices */
        rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
 }
 
@@ -206,7 +214,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        case 0x1011:
        case 0x1012:
                /* The hauppauge keymap is a superset of these remotes */
-               dev->map_name = RC_MAP_HAUPPAUGE_NEW;
+               dev->map_name = RC_MAP_HAUPPAUGE;
+               budget_ci->ir.full_rc5 = true;
 
                if (rc5_device < 0)
                        budget_ci->ir.rc5_device = 0x1f;
index 40625b26ac10a52a305d156f91b7040abba73a39..cbe2f0de1442f11f8b5f2ccb0efe3fdec10bf027 100644 (file)
@@ -334,6 +334,7 @@ static int ttusb_boot_dsp(struct ttusb *ttusb)
        err = ttusb_cmd(ttusb, b, 4, 0);
 
       done:
+       release_firmware(fw);
        if (err) {
                dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
                        __func__, err);
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
new file mode 100644 (file)
index 0000000..16b70b4
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Media device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/media.h>
+
+#include <media/media-device.h>
+#include <media/media-devnode.h>
+#include <media/media-entity.h>
+
+/* -----------------------------------------------------------------------------
+ * Userspace API
+ */
+
+static int media_device_open(struct file *filp)
+{
+       return 0;
+}
+
+static int media_device_close(struct file *filp)
+{
+       return 0;
+}
+
+static int media_device_get_info(struct media_device *dev,
+                                struct media_device_info __user *__info)
+{
+       struct media_device_info info;
+
+       memset(&info, 0, sizeof(info));
+
+       strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
+       strlcpy(info.model, dev->model, sizeof(info.model));
+       strlcpy(info.serial, dev->serial, sizeof(info.serial));
+       strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
+
+       info.media_version = MEDIA_API_VERSION;
+       info.hw_revision = dev->hw_revision;
+       info.driver_version = dev->driver_version;
+
+       return copy_to_user(__info, &info, sizeof(*__info));
+}
+
+static struct media_entity *find_entity(struct media_device *mdev, u32 id)
+{
+       struct media_entity *entity;
+       int next = id & MEDIA_ENT_ID_FLAG_NEXT;
+
+       id &= ~MEDIA_ENT_ID_FLAG_NEXT;
+
+       spin_lock(&mdev->lock);
+
+       media_device_for_each_entity(entity, mdev) {
+               if ((entity->id == id && !next) ||
+                   (entity->id > id && next)) {
+                       spin_unlock(&mdev->lock);
+                       return entity;
+               }
+       }
+
+       spin_unlock(&mdev->lock);
+
+       return NULL;
+}
+
+static long media_device_enum_entities(struct media_device *mdev,
+                                      struct media_entity_desc __user *uent)
+{
+       struct media_entity *ent;
+       struct media_entity_desc u_ent;
+
+       if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
+               return -EFAULT;
+
+       ent = find_entity(mdev, u_ent.id);
+
+       if (ent == NULL)
+               return -EINVAL;
+
+       u_ent.id = ent->id;
+       u_ent.name[0] = '\0';
+       if (ent->name)
+               strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
+       u_ent.type = ent->type;
+       u_ent.revision = ent->revision;
+       u_ent.flags = ent->flags;
+       u_ent.group_id = ent->group_id;
+       u_ent.pads = ent->num_pads;
+       u_ent.links = ent->num_links - ent->num_backlinks;
+       u_ent.v4l.major = ent->v4l.major;
+       u_ent.v4l.minor = ent->v4l.minor;
+       if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
+               return -EFAULT;
+       return 0;
+}
+
+static void media_device_kpad_to_upad(const struct media_pad *kpad,
+                                     struct media_pad_desc *upad)
+{
+       upad->entity = kpad->entity->id;
+       upad->index = kpad->index;
+       upad->flags = kpad->flags;
+}
+
+static long media_device_enum_links(struct media_device *mdev,
+                                   struct media_links_enum __user *ulinks)
+{
+       struct media_entity *entity;
+       struct media_links_enum links;
+
+       if (copy_from_user(&links, ulinks, sizeof(links)))
+               return -EFAULT;
+
+       entity = find_entity(mdev, links.entity);
+       if (entity == NULL)
+               return -EINVAL;
+
+       if (links.pads) {
+               unsigned int p;
+
+               for (p = 0; p < entity->num_pads; p++) {
+                       struct media_pad_desc pad;
+                       media_device_kpad_to_upad(&entity->pads[p], &pad);
+                       if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
+                               return -EFAULT;
+               }
+       }
+
+       if (links.links) {
+               struct media_link_desc __user *ulink;
+               unsigned int l;
+
+               for (l = 0, ulink = links.links; l < entity->num_links; l++) {
+                       struct media_link_desc link;
+
+                       /* Ignore backlinks. */
+                       if (entity->links[l].source->entity != entity)
+                               continue;
+
+                       media_device_kpad_to_upad(entity->links[l].source,
+                                                 &link.source);
+                       media_device_kpad_to_upad(entity->links[l].sink,
+                                                 &link.sink);
+                       link.flags = entity->links[l].flags;
+                       if (copy_to_user(ulink, &link, sizeof(*ulink)))
+                               return -EFAULT;
+                       ulink++;
+               }
+       }
+       if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
+               return -EFAULT;
+       return 0;
+}
+
+static long media_device_setup_link(struct media_device *mdev,
+                                   struct media_link_desc __user *_ulink)
+{
+       struct media_link *link = NULL;
+       struct media_link_desc ulink;
+       struct media_entity *source;
+       struct media_entity *sink;
+       int ret;
+
+       if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
+               return -EFAULT;
+
+       /* Find the source and sink entities and link.
+        */
+       source = find_entity(mdev, ulink.source.entity);
+       sink = find_entity(mdev, ulink.sink.entity);
+
+       if (source == NULL || sink == NULL)
+               return -EINVAL;
+
+       if (ulink.source.index >= source->num_pads ||
+           ulink.sink.index >= sink->num_pads)
+               return -EINVAL;
+
+       link = media_entity_find_link(&source->pads[ulink.source.index],
+                                     &sink->pads[ulink.sink.index]);
+       if (link == NULL)
+               return -EINVAL;
+
+       /* Setup the link on both entities. */
+       ret = __media_entity_setup_link(link, ulink.flags);
+
+       if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
+               return -EFAULT;
+
+       return ret;
+}
+
+static long media_device_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+       struct media_device *dev = to_media_device(devnode);
+       long ret;
+
+       switch (cmd) {
+       case MEDIA_IOC_DEVICE_INFO:
+               ret = media_device_get_info(dev,
+                               (struct media_device_info __user *)arg);
+               break;
+
+       case MEDIA_IOC_ENUM_ENTITIES:
+               ret = media_device_enum_entities(dev,
+                               (struct media_entity_desc __user *)arg);
+               break;
+
+       case MEDIA_IOC_ENUM_LINKS:
+               mutex_lock(&dev->graph_mutex);
+               ret = media_device_enum_links(dev,
+                               (struct media_links_enum __user *)arg);
+               mutex_unlock(&dev->graph_mutex);
+               break;
+
+       case MEDIA_IOC_SETUP_LINK:
+               mutex_lock(&dev->graph_mutex);
+               ret = media_device_setup_link(dev,
+                               (struct media_link_desc __user *)arg);
+               mutex_unlock(&dev->graph_mutex);
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+static const struct media_file_operations media_device_fops = {
+       .owner = THIS_MODULE,
+       .open = media_device_open,
+       .ioctl = media_device_ioctl,
+       .release = media_device_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * sysfs
+ */
+
+static ssize_t show_model(struct device *cd,
+                         struct device_attribute *attr, char *buf)
+{
+       struct media_device *mdev = to_media_device(to_media_devnode(cd));
+
+       return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
+}
+
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+/* -----------------------------------------------------------------------------
+ * Registration/unregistration
+ */
+
+static void media_device_release(struct media_devnode *mdev)
+{
+}
+
+/**
+ * media_device_register - register a media device
+ * @mdev:      The media device
+ *
+ * The caller is responsible for initializing the media device before
+ * registration. The following fields must be set:
+ *
+ * - dev must point to the parent device
+ * - model must be filled with the device model name
+ */
+int __must_check media_device_register(struct media_device *mdev)
+{
+       int ret;
+
+       if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+               return -EINVAL;
+
+       mdev->entity_id = 1;
+       INIT_LIST_HEAD(&mdev->entities);
+       spin_lock_init(&mdev->lock);
+       mutex_init(&mdev->graph_mutex);
+
+       /* Register the device node. */
+       mdev->devnode.fops = &media_device_fops;
+       mdev->devnode.parent = mdev->dev;
+       mdev->devnode.release = media_device_release;
+       ret = media_devnode_register(&mdev->devnode);
+       if (ret < 0)
+               return ret;
+
+       ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
+       if (ret < 0) {
+               media_devnode_unregister(&mdev->devnode);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register);
+
+/**
+ * media_device_unregister - unregister a media device
+ * @mdev:      The media device
+ *
+ */
+void media_device_unregister(struct media_device *mdev)
+{
+       struct media_entity *entity;
+       struct media_entity *next;
+
+       list_for_each_entry_safe(entity, next, &mdev->entities, list)
+               media_device_unregister_entity(entity);
+
+       device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+       media_devnode_unregister(&mdev->devnode);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister);
+
+/**
+ * media_device_register_entity - Register an entity with a media device
+ * @mdev:      The media device
+ * @entity:    The entity
+ */
+int __must_check media_device_register_entity(struct media_device *mdev,
+                                             struct media_entity *entity)
+{
+       /* Warn if we apparently re-register an entity */
+       WARN_ON(entity->parent != NULL);
+       entity->parent = mdev;
+
+       spin_lock(&mdev->lock);
+       if (entity->id == 0)
+               entity->id = mdev->entity_id++;
+       else
+               mdev->entity_id = max(entity->id + 1, mdev->entity_id);
+       list_add_tail(&entity->list, &mdev->entities);
+       spin_unlock(&mdev->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity);
+
+/**
+ * media_device_unregister_entity - Unregister an entity
+ * @entity:    The entity
+ *
+ * If the entity has never been registered this function will return
+ * immediately.
+ */
+void media_device_unregister_entity(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->parent;
+
+       if (mdev == NULL)
+               return;
+
+       spin_lock(&mdev->lock);
+       list_del(&entity->list);
+       spin_unlock(&mdev->lock);
+       entity->parent = NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity);
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
new file mode 100644 (file)
index 0000000..af5263c
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Media device node
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Based on drivers/media/video/v4l2_dev.c code authored by
+ *     Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
+ *     Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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
+ *
+ * --
+ *
+ * Generic media device node infrastructure to register and unregister
+ * character devices using a dynamic major number and proper reference
+ * counting.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <media/media-devnode.h>
+
+#define MEDIA_NUM_DEVICES      256
+#define MEDIA_NAME             "media"
+
+static dev_t media_dev_t;
+
+/*
+ *     Active devices
+ */
+static DEFINE_MUTEX(media_devnode_lock);
+static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
+
+/* Called when the last user of the media device exits. */
+static void media_devnode_release(struct device *cd)
+{
+       struct media_devnode *mdev = to_media_devnode(cd);
+
+       mutex_lock(&media_devnode_lock);
+
+       /* Delete the cdev on this minor as well */
+       cdev_del(&mdev->cdev);
+
+       /* Mark device node number as free */
+       clear_bit(mdev->minor, media_devnode_nums);
+
+       mutex_unlock(&media_devnode_lock);
+
+       /* Release media_devnode and perform other cleanups as needed. */
+       if (mdev->release)
+               mdev->release(mdev);
+}
+
+static struct bus_type media_bus_type = {
+       .name = MEDIA_NAME,
+};
+
+static ssize_t media_read(struct file *filp, char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct media_devnode *mdev = media_devnode_data(filp);
+
+       if (!mdev->fops->read)
+               return -EINVAL;
+       if (!media_devnode_is_registered(mdev))
+               return -EIO;
+       return mdev->fops->read(filp, buf, sz, off);
+}
+
+static ssize_t media_write(struct file *filp, const char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct media_devnode *mdev = media_devnode_data(filp);
+
+       if (!mdev->fops->write)
+               return -EINVAL;
+       if (!media_devnode_is_registered(mdev))
+               return -EIO;
+       return mdev->fops->write(filp, buf, sz, off);
+}
+
+static unsigned int media_poll(struct file *filp,
+                              struct poll_table_struct *poll)
+{
+       struct media_devnode *mdev = media_devnode_data(filp);
+
+       if (!media_devnode_is_registered(mdev))
+               return POLLERR | POLLHUP;
+       if (!mdev->fops->poll)
+               return DEFAULT_POLLMASK;
+       return mdev->fops->poll(filp, poll);
+}
+
+static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct media_devnode *mdev = media_devnode_data(filp);
+
+       if (!mdev->fops->ioctl)
+               return -ENOTTY;
+
+       if (!media_devnode_is_registered(mdev))
+               return -EIO;
+
+       return mdev->fops->ioctl(filp, cmd, arg);
+}
+
+/* Override for the open function */
+static int media_open(struct inode *inode, struct file *filp)
+{
+       struct media_devnode *mdev;
+       int ret;
+
+       /* Check if the media device is available. This needs to be done with
+        * the media_devnode_lock held to prevent an open/unregister race:
+        * without the lock, the device could be unregistered and freed between
+        * the media_devnode_is_registered() and get_device() calls, leading to
+        * a crash.
+        */
+       mutex_lock(&media_devnode_lock);
+       mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
+       /* return ENXIO if the media device has been removed
+          already or if it is not registered anymore. */
+       if (!media_devnode_is_registered(mdev)) {
+               mutex_unlock(&media_devnode_lock);
+               return -ENXIO;
+       }
+       /* and increase the device refcount */
+       get_device(&mdev->dev);
+       mutex_unlock(&media_devnode_lock);
+
+       filp->private_data = mdev;
+
+       if (mdev->fops->open) {
+               ret = mdev->fops->open(filp);
+               if (ret) {
+                       put_device(&mdev->dev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* Override for the release function */
+static int media_release(struct inode *inode, struct file *filp)
+{
+       struct media_devnode *mdev = media_devnode_data(filp);
+       int ret = 0;
+
+       if (mdev->fops->release)
+               mdev->fops->release(filp);
+
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       put_device(&mdev->dev);
+       filp->private_data = NULL;
+       return ret;
+}
+
+static const struct file_operations media_devnode_fops = {
+       .owner = THIS_MODULE,
+       .read = media_read,
+       .write = media_write,
+       .open = media_open,
+       .unlocked_ioctl = media_ioctl,
+       .release = media_release,
+       .poll = media_poll,
+       .llseek = no_llseek,
+};
+
+/**
+ * media_devnode_register - register a media device node
+ * @mdev: media device node structure we want to register
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+ * or if the registration of the device node fails.
+ *
+ * Zero is returned on success.
+ *
+ * Note that if the media_devnode_register call fails, the release() callback of
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
+int __must_check media_devnode_register(struct media_devnode *mdev)
+{
+       int minor;
+       int ret;
+
+       /* Part 1: Find a free minor number */
+       mutex_lock(&media_devnode_lock);
+       minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES);
+       if (minor == MEDIA_NUM_DEVICES) {
+               mutex_unlock(&media_devnode_lock);
+               printk(KERN_ERR "could not get a free minor\n");
+               return -ENFILE;
+       }
+
+       set_bit(mdev->minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+
+       mdev->minor = minor;
+
+       /* Part 2: Initialize and register the character device */
+       cdev_init(&mdev->cdev, &media_devnode_fops);
+       mdev->cdev.owner = mdev->fops->owner;
+
+       ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+               goto error;
+       }
+
+       /* Part 3: Register the media device */
+       mdev->dev.bus = &media_bus_type;
+       mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
+       mdev->dev.release = media_devnode_release;
+       if (mdev->parent)
+               mdev->dev.parent = mdev->parent;
+       dev_set_name(&mdev->dev, "media%d", mdev->minor);
+       ret = device_register(&mdev->dev);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: device_register failed\n", __func__);
+               goto error;
+       }
+
+       /* Part 4: Activate this minor. The char device can now be used. */
+       set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+
+       return 0;
+
+error:
+       cdev_del(&mdev->cdev);
+       clear_bit(mdev->minor, media_devnode_nums);
+       return ret;
+}
+
+/**
+ * media_devnode_unregister - unregister a media device node
+ * @mdev: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
+void media_devnode_unregister(struct media_devnode *mdev)
+{
+       /* Check if mdev was ever registered at all */
+       if (!media_devnode_is_registered(mdev))
+               return;
+
+       mutex_lock(&media_devnode_lock);
+       clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+       mutex_unlock(&media_devnode_lock);
+       device_unregister(&mdev->dev);
+}
+
+/*
+ *     Initialise media for linux
+ */
+static int __init media_devnode_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Linux media interface: v0.10\n");
+       ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
+                                 MEDIA_NAME);
+       if (ret < 0) {
+               printk(KERN_WARNING "media: unable to allocate major\n");
+               return ret;
+       }
+
+       ret = bus_register(&media_bus_type);
+       if (ret < 0) {
+               unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+               printk(KERN_WARNING "media: bus_register failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void __exit media_devnode_exit(void)
+{
+       bus_unregister(&media_bus_type);
+       unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+}
+
+module_init(media_devnode_init)
+module_exit(media_devnode_exit)
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Device node registration for media drivers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
new file mode 100644 (file)
index 0000000..23640ed
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Media entity
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <media/media-entity.h>
+#include <media/media-device.h>
+
+/**
+ * media_entity_init - Initialize a media entity
+ *
+ * @num_pads: Total number of sink and source pads.
+ * @extra_links: Initial estimate of the number of extra links.
+ * @pads: Array of 'num_pads' pads.
+ *
+ * The total number of pads is an intrinsic property of entities known by the
+ * entity driver, while the total number of links depends on hardware design
+ * and is an extrinsic property unknown to the entity driver. However, in most
+ * use cases the entity driver can guess the number of links which can safely
+ * be assumed to be equal to or larger than the number of pads.
+ *
+ * For those reasons the links array can be preallocated based on the entity
+ * driver guess and will be reallocated later if extra links need to be
+ * created.
+ *
+ * This function allocates a links array with enough space to hold at least
+ * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
+ * be set to the number of allocated elements.
+ *
+ * The pads array is managed by the entity driver and passed to
+ * media_entity_init() where its pointer will be stored in the entity structure.
+ */
+int
+media_entity_init(struct media_entity *entity, u16 num_pads,
+                 struct media_pad *pads, u16 extra_links)
+{
+       struct media_link *links;
+       unsigned int max_links = num_pads + extra_links;
+       unsigned int i;
+
+       links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
+       if (links == NULL)
+               return -ENOMEM;
+
+       entity->group_id = 0;
+       entity->max_links = max_links;
+       entity->num_links = 0;
+       entity->num_backlinks = 0;
+       entity->num_pads = num_pads;
+       entity->pads = pads;
+       entity->links = links;
+
+       for (i = 0; i < num_pads; i++) {
+               pads[i].entity = entity;
+               pads[i].index = i;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_init);
+
+void
+media_entity_cleanup(struct media_entity *entity)
+{
+       kfree(entity->links);
+}
+EXPORT_SYMBOL_GPL(media_entity_cleanup);
+
+/* -----------------------------------------------------------------------------
+ * Graph traversal
+ */
+
+static struct media_entity *
+media_entity_other(struct media_entity *entity, struct media_link *link)
+{
+       if (link->source->entity == entity)
+               return link->sink->entity;
+       else
+               return link->source->entity;
+}
+
+/* push an entity to traversal stack */
+static void stack_push(struct media_entity_graph *graph,
+                      struct media_entity *entity)
+{
+       if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
+               WARN_ON(1);
+               return;
+       }
+       graph->top++;
+       graph->stack[graph->top].link = 0;
+       graph->stack[graph->top].entity = entity;
+}
+
+static struct media_entity *stack_pop(struct media_entity_graph *graph)
+{
+       struct media_entity *entity;
+
+       entity = graph->stack[graph->top].entity;
+       graph->top--;
+
+       return entity;
+}
+
+#define stack_peek(en) ((en)->stack[(en)->top - 1].entity)
+#define link_top(en)   ((en)->stack[(en)->top].link)
+#define stack_top(en)  ((en)->stack[(en)->top].entity)
+
+/**
+ * media_entity_graph_walk_start - Start walking the media graph at a given entity
+ * @graph: Media graph structure that will be used to walk the graph
+ * @entity: Starting entity
+ *
+ * This function initializes the graph traversal structure to walk the entities
+ * graph starting at the given entity. The traversal structure must not be
+ * modified by the caller during graph traversal. When done the structure can
+ * safely be freed.
+ */
+void media_entity_graph_walk_start(struct media_entity_graph *graph,
+                                  struct media_entity *entity)
+{
+       graph->top = 0;
+       graph->stack[graph->top].entity = NULL;
+       stack_push(graph, entity);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
+
+/**
+ * media_entity_graph_walk_next - Get the next entity in the graph
+ * @graph: Media graph structure
+ *
+ * Perform a depth-first traversal of the given media entities graph.
+ *
+ * The graph structure must have been previously initialized with a call to
+ * media_entity_graph_walk_start().
+ *
+ * Return the next entity in the graph or NULL if the whole graph have been
+ * traversed.
+ */
+struct media_entity *
+media_entity_graph_walk_next(struct media_entity_graph *graph)
+{
+       if (stack_top(graph) == NULL)
+               return NULL;
+
+       /*
+        * Depth first search. Push entity to stack and continue from
+        * top of the stack until no more entities on the level can be
+        * found.
+        */
+       while (link_top(graph) < stack_top(graph)->num_links) {
+               struct media_entity *entity = stack_top(graph);
+               struct media_link *link = &entity->links[link_top(graph)];
+               struct media_entity *next;
+
+               /* The link is not enabled so we do not follow. */
+               if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
+                       link_top(graph)++;
+                       continue;
+               }
+
+               /* Get the entity in the other end of the link . */
+               next = media_entity_other(entity, link);
+
+               /* Was it the entity we came here from? */
+               if (next == stack_peek(graph)) {
+                       link_top(graph)++;
+                       continue;
+               }
+
+               /* Push the new entity to stack and start over. */
+               link_top(graph)++;
+               stack_push(graph, next);
+       }
+
+       return stack_pop(graph);
+}
+EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+
+/* -----------------------------------------------------------------------------
+ * Pipeline management
+ */
+
+/**
+ * media_entity_pipeline_start - Mark a pipeline as streaming
+ * @entity: Starting entity
+ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as streaming. The given pipeline object is assigned to
+ * every entity in the pipeline and stored in the media_entity pipe field.
+ *
+ * Calls to this function can be nested, in which case the same number of
+ * media_entity_pipeline_stop() calls will be required to stop streaming. The
+ * pipeline pointer must be identical for all nested calls to
+ * media_entity_pipeline_start().
+ */
+void media_entity_pipeline_start(struct media_entity *entity,
+                                struct media_pipeline *pipe)
+{
+       struct media_device *mdev = entity->parent;
+       struct media_entity_graph graph;
+
+       mutex_lock(&mdev->graph_mutex);
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               entity->stream_count++;
+               WARN_ON(entity->pipe && entity->pipe != pipe);
+               entity->pipe = pipe;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
+
+/**
+ * media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * @entity: Starting entity
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as not streaming. The media_entity pipe field is
+ * reset to NULL.
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made, the same
+ * number of calls to this function are required to mark the pipeline as not
+ * streaming.
+ */
+void media_entity_pipeline_stop(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->parent;
+       struct media_entity_graph graph;
+
+       mutex_lock(&mdev->graph_mutex);
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               entity->stream_count--;
+               if (entity->stream_count == 0)
+                       entity->pipe = NULL;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
+
+/* -----------------------------------------------------------------------------
+ * Module use count
+ */
+
+/*
+ * media_entity_get - Get a reference to the parent module
+ * @entity: The entity
+ *
+ * Get a reference to the parent media device module.
+ *
+ * The function will return immediately if @entity is NULL.
+ *
+ * Return a pointer to the entity on success or NULL on failure.
+ */
+struct media_entity *media_entity_get(struct media_entity *entity)
+{
+       if (entity == NULL)
+               return NULL;
+
+       if (entity->parent->dev &&
+           !try_module_get(entity->parent->dev->driver->owner))
+               return NULL;
+
+       return entity;
+}
+EXPORT_SYMBOL_GPL(media_entity_get);
+
+/*
+ * media_entity_put - Release the reference to the parent module
+ * @entity: The entity
+ *
+ * Release the reference count acquired by media_entity_get().
+ *
+ * The function will return immediately if @entity is NULL.
+ */
+void media_entity_put(struct media_entity *entity)
+{
+       if (entity == NULL)
+               return;
+
+       if (entity->parent->dev)
+               module_put(entity->parent->dev->driver->owner);
+}
+EXPORT_SYMBOL_GPL(media_entity_put);
+
+/* -----------------------------------------------------------------------------
+ * Links management
+ */
+
+static struct media_link *media_entity_add_link(struct media_entity *entity)
+{
+       if (entity->num_links >= entity->max_links) {
+               struct media_link *links = entity->links;
+               unsigned int max_links = entity->max_links + 2;
+               unsigned int i;
+
+               links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
+               if (links == NULL)
+                       return NULL;
+
+               for (i = 0; i < entity->num_links; i++)
+                       links[i].reverse->reverse = &links[i];
+
+               entity->max_links = max_links;
+               entity->links = links;
+       }
+
+       return &entity->links[entity->num_links++];
+}
+
+int
+media_entity_create_link(struct media_entity *source, u16 source_pad,
+                        struct media_entity *sink, u16 sink_pad, u32 flags)
+{
+       struct media_link *link;
+       struct media_link *backlink;
+
+       BUG_ON(source == NULL || sink == NULL);
+       BUG_ON(source_pad >= source->num_pads);
+       BUG_ON(sink_pad >= sink->num_pads);
+
+       link = media_entity_add_link(source);
+       if (link == NULL)
+               return -ENOMEM;
+
+       link->source = &source->pads[source_pad];
+       link->sink = &sink->pads[sink_pad];
+       link->flags = flags;
+
+       /* Create the backlink. Backlinks are used to help graph traversal and
+        * are not reported to userspace.
+        */
+       backlink = media_entity_add_link(sink);
+       if (backlink == NULL) {
+               source->num_links--;
+               return -ENOMEM;
+       }
+
+       backlink->source = &source->pads[source_pad];
+       backlink->sink = &sink->pads[sink_pad];
+       backlink->flags = flags;
+
+       link->reverse = backlink;
+       backlink->reverse = link;
+
+       sink->num_backlinks++;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_create_link);
+
+static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
+{
+       const u32 mask = MEDIA_LNK_FL_ENABLED;
+       int ret;
+
+       /* Notify both entities. */
+       ret = media_entity_call(link->source->entity, link_setup,
+                               link->source, link->sink, flags);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
+               return ret;
+
+       ret = media_entity_call(link->sink->entity, link_setup,
+                               link->sink, link->source, flags);
+       if (ret < 0 && ret != -ENOIOCTLCMD) {
+               media_entity_call(link->source->entity, link_setup,
+                                 link->source, link->sink, link->flags);
+               return ret;
+       }
+
+       link->flags = (link->flags & ~mask) | (flags & mask);
+       link->reverse->flags = link->flags;
+
+       return 0;
+}
+
+/**
+ * __media_entity_setup_link - Configure a media link
+ * @link: The link being configured
+ * @flags: Link configuration flags
+ *
+ * The bulk of link setup is handled by the two entities connected through the
+ * link. This function notifies both entities of the link configuration change.
+ *
+ * If the link is immutable or if the current and new configuration are
+ * identical, return immediately.
+ *
+ * The user is expected to hold link->source->parent->mutex. If not,
+ * media_entity_setup_link() should be used instead.
+ */
+int __media_entity_setup_link(struct media_link *link, u32 flags)
+{
+       struct media_device *mdev;
+       struct media_entity *source, *sink;
+       int ret = -EBUSY;
+
+       if (link == NULL)
+               return -EINVAL;
+
+       if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
+               return link->flags == flags ? 0 : -EINVAL;
+
+       if (link->flags == flags)
+               return 0;
+
+       source = link->source->entity;
+       sink = link->sink->entity;
+
+       if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
+           (source->stream_count || sink->stream_count))
+               return -EBUSY;
+
+       mdev = source->parent;
+
+       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
+               ret = mdev->link_notify(link->source, link->sink,
+                                       MEDIA_LNK_FL_ENABLED);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = __media_entity_setup_link_notify(link, flags);
+       if (ret < 0)
+               goto err;
+
+       if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
+               mdev->link_notify(link->source, link->sink, 0);
+
+       return 0;
+
+err:
+       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
+               mdev->link_notify(link->source, link->sink, 0);
+
+       return ret;
+}
+
+int media_entity_setup_link(struct media_link *link, u32 flags)
+{
+       int ret;
+
+       mutex_lock(&link->source->entity->parent->graph_mutex);
+       ret = __media_entity_setup_link(link, flags);
+       mutex_unlock(&link->source->entity->parent->graph_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(media_entity_setup_link);
+
+/**
+ * media_entity_find_link - Find a link between two pads
+ * @source: Source pad
+ * @sink: Sink pad
+ *
+ * Return a pointer to the link between the two entities. If no such link
+ * exists, return NULL.
+ */
+struct media_link *
+media_entity_find_link(struct media_pad *source, struct media_pad *sink)
+{
+       struct media_link *link;
+       unsigned int i;
+
+       for (i = 0; i < source->entity->num_links; ++i) {
+               link = &source->entity->links[i];
+
+               if (link->source->entity == source->entity &&
+                   link->source->index == source->index &&
+                   link->sink->entity == sink->entity &&
+                   link->sink->index == sink->index)
+                       return link;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(media_entity_find_link);
+
+/**
+ * media_entity_remote_source - Find the source pad at the remote end of a link
+ * @pad: Sink pad at the local end of the link
+ *
+ * Search for a remote source pad connected to the given sink pad by iterating
+ * over all links originating or terminating at that pad until an enabled link
+ * is found.
+ *
+ * Return a pointer to the pad at the remote end of the first found enabled
+ * link, or NULL if no enabled link has been found.
+ */
+struct media_pad *media_entity_remote_source(struct media_pad *pad)
+{
+       unsigned int i;
+
+       for (i = 0; i < pad->entity->num_links; i++) {
+               struct media_link *link = &pad->entity->links[i];
+
+               if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+                       continue;
+
+               if (link->source == pad)
+                       return link->sink;
+
+               if (link->sink == pad)
+                       return link->source;
+       }
+
+       return NULL;
+
+}
+EXPORT_SYMBOL_GPL(media_entity_remote_source);
index ecdffa6aac664e477b7608b563ee578d43b40936..299994c3aa74a01b7d9de6ef60fda37f6d1e0af5 100644 (file)
@@ -441,6 +441,7 @@ config RADIO_TIMBERDALE
 config RADIO_WL1273
        tristate "Texas Instruments WL1273 I2C FM Radio"
        depends on I2C && VIDEO_V4L2
+       select MFD_CORE
        select MFD_WL1273_CORE
        select FW_LOADER
        ---help---
@@ -454,4 +455,7 @@ config RADIO_WL1273
          To compile this driver as a module, choose M here: the
          module will be called radio-wl1273.
 
+# TI's ST based wl128x FM radio
+source "drivers/media/radio/wl128x/Kconfig"
+
 endif # RADIO_ADAPTERS
index 717656d2f749d48657e72b082f428f8c20d8956a..2faa333719860dd92713dea4d2139c5a9080e7ae 100644 (file)
@@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
 obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
 obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
 obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
+obj-$(CONFIG_RADIO_WL128X) += wl128x/
 
 EXTRA_CFLAGS += -Isound
index ed9cd7ad06042c630ec147e6a3b830a5a2e3904f..3d8cc425fa6b6206e394548e8abdf482f7aa3a73 100644 (file)
@@ -129,7 +129,7 @@ devices, that would be 76 and 91.  */
 #define STARTED        0
 #define STOPPED        1
 
-#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
+#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
                             const struct usb_device_id *id);
@@ -148,10 +148,9 @@ struct dsbr100_device {
        struct v4l2_device v4l2_dev;
 
        u8 *transfer_buffer;
-       struct mutex lock;      /* buffer locking */
+       struct mutex v4l2_lock;
        int curfreq;
        int stereo;
-       int removed;
        int status;
 };
 
@@ -182,8 +181,6 @@ static int dsbr100_start(struct dsbr100_device *radio)
        int retval;
        int request;
 
-       mutex_lock(&radio->lock);
-
        retval = usb_control_msg(radio->usbdev,
                usb_rcvctrlpipe(radio->usbdev, 0),
                USB_REQ_GET_STATUS,
@@ -207,11 +204,9 @@ static int dsbr100_start(struct dsbr100_device *radio)
        }
 
        radio->status = STARTED;
-       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
-       mutex_unlock(&radio->lock);
        dev_err(&radio->usbdev->dev,
                "%s - usb_control_msg returned %i, request %i\n",
                        __func__, retval, request);
@@ -225,8 +220,6 @@ static int dsbr100_stop(struct dsbr100_device *radio)
        int retval;
        int request;
 
-       mutex_lock(&radio->lock);
-
        retval = usb_control_msg(radio->usbdev,
                usb_rcvctrlpipe(radio->usbdev, 0),
                USB_REQ_GET_STATUS,
@@ -250,11 +243,9 @@ static int dsbr100_stop(struct dsbr100_device *radio)
        }
 
        radio->status = STOPPED;
-       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
-       mutex_unlock(&radio->lock);
        dev_err(&radio->usbdev->dev,
                "%s - usb_control_msg returned %i, request %i\n",
                        __func__, retval, request);
@@ -269,8 +260,6 @@ static int dsbr100_setfreq(struct dsbr100_device *radio)
        int request;
        int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
 
-       mutex_lock(&radio->lock);
-
        retval = usb_control_msg(radio->usbdev,
                usb_rcvctrlpipe(radio->usbdev, 0),
                DSB100_TUNE,
@@ -306,12 +295,10 @@ static int dsbr100_setfreq(struct dsbr100_device *radio)
        }
 
        radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
-       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
 usb_control_msg_failed:
        radio->stereo = -1;
-       mutex_unlock(&radio->lock);
        dev_err(&radio->usbdev->dev,
                "%s - usb_control_msg returned %i, request %i\n",
                        __func__, retval, request);
@@ -324,8 +311,6 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 {
        int retval;
 
-       mutex_lock(&radio->lock);
-
        retval = usb_control_msg(radio->usbdev,
                usb_rcvctrlpipe(radio->usbdev, 0),
                USB_REQ_GET_STATUS,
@@ -340,33 +325,8 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
        } else {
                radio->stereo = !(radio->transfer_buffer[0] & 0x01);
        }
-
-       mutex_unlock(&radio->lock);
 }
 
-/* USB subsystem interface begins here */
-
-/*
- * Handle unplugging of the device.
- * We call video_unregister_device in any case.
- * The last function called in this procedure is
- * usb_dsbr100_video_device_release
- */
-static void usb_dsbr100_disconnect(struct usb_interface *intf)
-{
-       struct dsbr100_device *radio = usb_get_intfdata(intf);
-
-       usb_set_intfdata (intf, NULL);
-
-       mutex_lock(&radio->lock);
-       radio->removed = 1;
-       mutex_unlock(&radio->lock);
-
-       video_unregister_device(&radio->videodev);
-       v4l2_device_disconnect(&radio->v4l2_dev);
-}
-
-
 static int vidioc_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *v)
 {
@@ -385,10 +345,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
        if (v->index > 0)
                return -EINVAL;
 
@@ -410,16 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
-       struct dsbr100_device *radio = video_drvdata(file);
-
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       return 0;
+       return v->index ? -EINVAL : 0;
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
@@ -428,13 +375,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        struct dsbr100_device *radio = video_drvdata(file);
        int retval;
 
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
-       mutex_lock(&radio->lock);
        radio->curfreq = f->frequency;
-       mutex_unlock(&radio->lock);
 
        retval = dsbr100_setfreq(radio);
        if (retval < 0)
@@ -447,10 +388,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
        f->type = V4L2_TUNER_RADIO;
        f->frequency = radio->curfreq;
        return 0;
@@ -472,10 +409,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                ctrl->value = radio->status;
@@ -490,10 +423,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        struct dsbr100_device *radio = video_drvdata(file);
        int retval;
 
-       /* safety check */
-       if (radio->removed)
-               return -EIO;
-
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value) {
@@ -535,25 +464,44 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
 
 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-       if (i != 0)
-               return -EINVAL;
-       return 0;
+       return i ? -EINVAL : 0;
 }
 
 static int vidioc_s_audio(struct file *file, void *priv,
                                        struct v4l2_audio *a)
 {
-       if (a->index != 0)
-               return -EINVAL;
-       return 0;
+       return a->index ? -EINVAL : 0;
+}
+
+/* USB subsystem interface begins here */
+
+/*
+ * Handle unplugging of the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_dsbr100_video_device_release
+ */
+static void usb_dsbr100_disconnect(struct usb_interface *intf)
+{
+       struct dsbr100_device *radio = usb_get_intfdata(intf);
+
+       v4l2_device_get(&radio->v4l2_dev);
+       mutex_lock(&radio->v4l2_lock);
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(&radio->videodev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
+       mutex_unlock(&radio->v4l2_lock);
+       v4l2_device_put(&radio->v4l2_dev);
 }
 
+
 /* Suspend device - stop device. */
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
+       mutex_lock(&radio->v4l2_lock);
        if (radio->status == STARTED) {
                retval = dsbr100_stop(radio);
                if (retval < 0)
@@ -564,11 +512,9 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
                 * we set status equal to STARTED.
                 * On resume we will check status and run radio if needed.
                 */
-
-               mutex_lock(&radio->lock);
                radio->status = STARTED;
-               mutex_unlock(&radio->lock);
        }
+       mutex_unlock(&radio->v4l2_lock);
 
        dev_info(&intf->dev, "going into suspend..\n");
 
@@ -581,11 +527,13 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
+       mutex_lock(&radio->v4l2_lock);
        if (radio->status == STARTED) {
                retval = dsbr100_start(radio);
                if (retval < 0)
                        dev_warn(&intf->dev, "dsbr100_start failed\n");
        }
+       mutex_unlock(&radio->v4l2_lock);
 
        dev_info(&intf->dev, "coming out of suspend..\n");
 
@@ -593,9 +541,9 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
 }
 
 /* free data structures */
-static void usb_dsbr100_video_device_release(struct video_device *videodev)
+static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
 {
-       struct dsbr100_device *radio = videodev_to_radio(videodev);
+       struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
 
        v4l2_device_unregister(&radio->v4l2_dev);
        kfree(radio->transfer_buffer);
@@ -605,7 +553,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
        .owner          = THIS_MODULE,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -644,6 +592,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
        }
 
        v4l2_dev = &radio->v4l2_dev;
+       v4l2_dev->release = usb_dsbr100_release;
 
        retval = v4l2_device_register(&intf->dev, v4l2_dev);
        if (retval < 0) {
@@ -653,15 +602,14 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
                return retval;
        }
 
+       mutex_init(&radio->v4l2_lock);
        strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
        radio->videodev.v4l2_dev = v4l2_dev;
        radio->videodev.fops = &usb_dsbr100_fops;
        radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
-       radio->videodev.release = usb_dsbr100_video_device_release;
-
-       mutex_init(&radio->lock);
+       radio->videodev.release = video_device_release_empty;
+       radio->videodev.lock = &radio->v4l2_lock;
 
-       radio->removed = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN * FREQ_MUL;
        radio->status = STOPPED;
index 726d367ad8d0f2119b5e832d8ccca593d2a6d3fa..444b4cf7e65c0ae14e8454954ea199567487c437 100644 (file)
@@ -224,7 +224,8 @@ static int radio_si4713_s_frequency(struct file *file, void *p,
                                                        s_frequency, vf);
 }
 
-static long radio_si4713_default(struct file *file, void *p, int cmd, void *arg)
+static long radio_si4713_default(struct file *file, void *p,
+                               bool valid_prio, int cmd, void *arg)
 {
        return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
                                                        ioctl, cmd, arg);
index a185610b376be1a14e79b52751c7f95aab777dd0..1e3a8dd820a4382a26272ff4557024e64adc619d 100644 (file)
@@ -21,6 +21,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
@@ -148,7 +149,7 @@ static const struct v4l2_file_operations timbradio_fops = {
 
 static int __devinit timbradio_probe(struct platform_device *pdev)
 {
-       struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
+       struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
        struct timbradio *tr;
        int err;
 
index 7ecc8e657663edba0c23a6b2cbb1628f1e7dd606..e2550dc2944f939812805d2c23778c86df2ff7e0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Driver for the Texas Instruments WL1273 FM radio.
  *
- * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Nokia Corporation
  * Author: Matti J. Aaltonen <matti.j.aaltonen@nokia.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -67,7 +67,6 @@ struct wl1273_device {
 
        /* RDS */
        unsigned int rds_on;
-       struct delayed_work work;
 
        wait_queue_head_t read_queue;
        struct mutex lock; /* for serializing fm radio operations */
@@ -104,58 +103,6 @@ static unsigned int rds_buf = 100;
 module_param(rds_buf, uint, 0);
 MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100");
 
-static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
-{
-       struct i2c_client *client = core->client;
-       u8 b[2];
-       int r;
-
-       r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
-       if (r != 2) {
-               dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
-               return -EREMOTEIO;
-       }
-
-       *value = (u16)b[0] << 8 | b[1];
-
-       return 0;
-}
-
-static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
-{
-       struct i2c_client *client = core->client;
-       u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
-       int r;
-
-       r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
-       if (r) {
-               dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
-               return r;
-       }
-
-       return 0;
-}
-
-static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
-{
-       struct i2c_client *client = core->client;
-       struct i2c_msg msg;
-       int r;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.buf = data;
-       msg.len = len;
-
-       r = i2c_transfer(client->adapter, &msg, 1);
-       if (r != 1) {
-               dev_err(&client->dev, "%s: write error.\n", __func__);
-               return -EREMOTEIO;
-       }
-
-       return 0;
-}
-
 static int wl1273_fm_write_fw(struct wl1273_core *core,
                              __u8 *fw, int len)
 {
@@ -188,94 +135,6 @@ static int wl1273_fm_write_fw(struct wl1273_core *core,
        return r;
 }
 
-/**
- * wl1273_fm_set_audio() -     Set audio mode.
- * @core:                      A pointer to the device struct.
- * @new_mode:                  The new audio mode.
- *
- * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
- */
-static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
-{
-       int r = 0;
-
-       if (core->mode == WL1273_MODE_OFF ||
-           core->mode == WL1273_MODE_SUSPENDED)
-               return -EPERM;
-
-       if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
-               r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
-                                       WL1273_PCM_DEF_MODE);
-               if (r)
-                       goto out;
-
-               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
-                                       core->i2s_mode);
-               if (r)
-                       goto out;
-
-               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
-                                       WL1273_AUDIO_ENABLE_I2S);
-               if (r)
-                       goto out;
-
-       } else if (core->mode == WL1273_MODE_RX &&
-                  new_mode == WL1273_AUDIO_ANALOG) {
-               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
-                                       WL1273_AUDIO_ENABLE_ANALOG);
-               if (r)
-                       goto out;
-
-       } else if (core->mode == WL1273_MODE_TX &&
-                  new_mode == WL1273_AUDIO_DIGITAL) {
-               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
-                                       core->i2s_mode);
-               if (r)
-                       goto out;
-
-               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
-                                       WL1273_AUDIO_IO_SET_I2S);
-               if (r)
-                       goto out;
-
-       } else if (core->mode == WL1273_MODE_TX &&
-                  new_mode == WL1273_AUDIO_ANALOG) {
-               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
-                                       WL1273_AUDIO_IO_SET_ANALOG);
-               if (r)
-                       goto out;
-       }
-
-       core->audio_mode = new_mode;
-out:
-       return r;
-}
-
-/**
- * wl1273_fm_set_volume() -    Set volume.
- * @core:                      A pointer to the device struct.
- * @volume:                    The new volume value.
- */
-static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
-{
-       u16 val;
-       int r;
-
-       if (volume > WL1273_MAX_VOLUME)
-               return -EINVAL;
-
-       if (core->volume == volume)
-               return 0;
-
-       val = volume;
-       r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
-       if (r)
-               return r;
-
-       core->volume = volume;
-       return 0;
-}
-
 #define WL1273_FIFO_HAS_DATA(status)   (1 << 5 & status)
 #define WL1273_RDS_CORRECTABLE_ERROR   (1 << 3)
 #define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4)
@@ -306,7 +165,7 @@ static int wl1273_fm_rds(struct wl1273_device *radio)
        if (core->mode != WL1273_MODE_RX)
                return 0;
 
-       r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+       r = core->read(core, WL1273_RDS_SYNC_GET, &val);
        if (r)
                return r;
 
@@ -374,7 +233,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
        u16 flags;
        int r;
 
-       r = wl1273_fm_read_reg(core, WL1273_FLAG_GET, &flags);
+       r = core->read(core, WL1273_FLAG_GET, &flags);
        if (r)
                goto out;
 
@@ -398,7 +257,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
        if (flags & WL1273_LEV_EVENT) {
                u16 level;
 
-               r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &level);
+               r = core->read(core, WL1273_RSSI_LVL_GET, &level);
                if (r)
                        goto out;
 
@@ -439,8 +298,8 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
                dev_dbg(radio->dev, "IRQ: FR:\n");
 
                if (core->mode == WL1273_MODE_RX) {
-                       r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
-                                               TUNER_MODE_STOP_SEARCH);
+                       r = core->write(core, WL1273_TUNER_MODE_SET,
+                                       TUNER_MODE_STOP_SEARCH);
                        if (r) {
                                dev_err(radio->dev,
                                        "%s: TUNER_MODE_SET fails: %d\n",
@@ -448,7 +307,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
                                goto out;
                        }
 
-                       r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &freq);
+                       r = core->read(core, WL1273_FREQ_SET, &freq);
                        if (r)
                                goto out;
 
@@ -467,7 +326,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
                        dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency);
 
                } else {
-                       r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &freq);
+                       r = core->read(core, WL1273_CHANL_SET, &freq);
                        if (r)
                                goto out;
 
@@ -477,8 +336,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
        }
 
 out:
-       wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
-                           radio->irq_flags);
+       core->write(core, WL1273_INT_MASK_SET, radio->irq_flags);
        complete(&radio->busy);
 
        return IRQ_HANDLED;
@@ -512,7 +370,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
        dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq);
 
        /* Set the current tx channel */
-       r = wl1273_fm_write_cmd(core, WL1273_CHANL_SET, freq / 10);
+       r = core->write(core, WL1273_CHANL_SET, freq / 10);
        if (r)
                return r;
 
@@ -526,7 +384,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
        dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r);
 
        /* Enable the output power */
-       r = wl1273_fm_write_cmd(core, WL1273_POWER_ENB_SET, 1);
+       r = core->write(core, WL1273_POWER_ENB_SET, 1);
        if (r)
                return r;
 
@@ -566,20 +424,20 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq)
 
        dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq);
 
-       wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+       core->write(core, WL1273_INT_MASK_SET, radio->irq_flags);
 
        if (radio->band == WL1273_BAND_JAPAN)
                f = (freq - WL1273_BAND_JAPAN_LOW) / 50;
        else
                f = (freq - WL1273_BAND_OTHER_LOW) / 50;
 
-       r = wl1273_fm_write_cmd(core, WL1273_FREQ_SET, f);
+       r = core->write(core, WL1273_FREQ_SET, f);
        if (r) {
                dev_err(radio->dev, "FREQ_SET fails\n");
                goto err;
        }
 
-       r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET);
+       r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET);
        if (r) {
                dev_err(radio->dev, "TUNER_MODE_SET fails\n");
                goto err;
@@ -609,7 +467,7 @@ static int wl1273_fm_get_freq(struct wl1273_device *radio)
        int r;
 
        if (core->mode == WL1273_MODE_RX) {
-               r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &f);
+               r = core->read(core, WL1273_FREQ_SET, &f);
                if (r)
                        return r;
 
@@ -619,7 +477,7 @@ static int wl1273_fm_get_freq(struct wl1273_device *radio)
                else
                        freq = WL1273_BAND_OTHER_LOW + 50 * f;
        } else {
-               r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &f);
+               r = core->read(core, WL1273_CHANL_SET, &f);
                if (r)
                        return r;
 
@@ -670,7 +528,7 @@ static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio)
        }
 
        /* ignore possible error here */
-       wl1273_fm_write_cmd(core, WL1273_RESET, 0);
+       core->write(core, WL1273_RESET, 0);
 
        dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r);
 out:
@@ -683,14 +541,14 @@ static int wl1273_fm_stop(struct wl1273_device *radio)
        struct wl1273_core *core = radio->core;
 
        if (core->mode == WL1273_MODE_RX) {
-               int r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+               int r = core->write(core, WL1273_POWER_SET,
                                    WL1273_POWER_SET_OFF);
                if (r)
                        dev_err(radio->dev, "%s: POWER_SET fails: %d\n",
                                __func__, r);
        } else if (core->mode == WL1273_MODE_TX) {
-               int r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
-                                           WL1273_PUPD_SET_OFF);
+               int r = core->write(core, WL1273_PUPD_SET,
+                                   WL1273_PUPD_SET_OFF);
                if (r)
                        dev_err(radio->dev,
                                "%s: PUPD_SET fails: %d\n", __func__, r);
@@ -725,11 +583,11 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
                        val |= WL1273_POWER_SET_RDS;
 
                /* If this fails try again */
-               r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+               r = core->write(core, WL1273_POWER_SET, val);
                if (r) {
                        msleep(100);
 
-                       r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+                       r = core->write(core, WL1273_POWER_SET, val);
                        if (r) {
                                dev_err(dev, "%s: POWER_SET fails\n", __func__);
                                goto fail;
@@ -742,11 +600,10 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
 
        } else if (new_mode == WL1273_MODE_TX) {
                /* If this fails try again once */
-               r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
-                                       WL1273_PUPD_SET_ON);
+               r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON);
                if (r) {
                        msleep(100);
-                       r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+                       r = core->write(core, WL1273_PUPD_SET,
                                        WL1273_PUPD_SET_ON);
                        if (r) {
                                dev_err(dev, "%s: PUPD_SET fails\n", __func__);
@@ -755,9 +612,9 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
                }
 
                if (radio->rds_on)
-                       r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+                       r = core->write(core, WL1273_RDS_DATA_ENB, 1);
                else
-                       r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+                       r = core->write(core, WL1273_RDS_DATA_ENB, 0);
        } else {
                dev_warn(dev, "%s: Illegal mode.\n", __func__);
        }
@@ -777,14 +634,14 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
                        if (radio->rds_on)
                                val |= WL1273_POWER_SET_RDS;
 
-                       r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+                       r = core->write(core, WL1273_POWER_SET, val);
                        if (r) {
                                dev_err(dev, "%s: POWER_SET fails\n", __func__);
                                goto fail;
                        }
                } else if (new_mode == WL1273_MODE_TX) {
-                       r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
-                                               WL1273_PUPD_SET_ON);
+                       r = core->write(core, WL1273_PUPD_SET,
+                                       WL1273_PUPD_SET_ON);
                        if (r) {
                                dev_err(dev, "%s: PUPD_SET fails\n", __func__);
                                goto fail;
@@ -808,10 +665,10 @@ static int wl1273_fm_suspend(struct wl1273_device *radio)
 
        /* Cannot go from OFF to SUSPENDED */
        if (core->mode == WL1273_MODE_RX)
-               r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+               r = core->write(core, WL1273_POWER_SET,
                                WL1273_POWER_SET_RETENTION);
        else if (core->mode == WL1273_MODE_TX)
-               r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+               r = core->write(core, WL1273_PUPD_SET,
                                WL1273_PUPD_SET_RETENTION);
        else
                r = -EINVAL;
@@ -852,8 +709,7 @@ static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode)
                }
 
                core->mode = mode;
-               r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
-                                       radio->irq_flags);
+               r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags);
                if (r) {
                        dev_err(dev, "INT_MASK_SET fails.\n");
                        goto out;
@@ -951,22 +807,21 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio,
        INIT_COMPLETION(radio->busy);
        dev_dbg(radio->dev, "%s: BUSY\n", __func__);
 
-       r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+       r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags);
        if (r)
                goto out;
 
        dev_dbg(radio->dev, "%s\n", __func__);
 
-       r = wl1273_fm_write_cmd(core, WL1273_SEARCH_LVL_SET, level);
+       r = core->write(core, WL1273_SEARCH_LVL_SET, level);
        if (r)
                goto out;
 
-       r = wl1273_fm_write_cmd(core, WL1273_SEARCH_DIR_SET, dir);
+       r = core->write(core, WL1273_SEARCH_DIR_SET, dir);
        if (r)
                goto out;
 
-       r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
-                               TUNER_MODE_AUTO_SEEK);
+       r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK);
        if (r)
                goto out;
 
@@ -994,8 +849,7 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio,
        INIT_COMPLETION(radio->busy);
        dev_dbg(radio->dev, "%s: BUSY\n", __func__);
 
-       r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
-                               TUNER_MODE_AUTO_SEEK);
+       r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK);
        if (r)
                goto out;
 
@@ -1020,7 +874,7 @@ static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio)
            core->mode == WL1273_MODE_SUSPENDED)
                return -EPERM;
 
-       r = wl1273_fm_read_reg(core, WL1273_READ_FMANT_TUNE_VALUE, &val);
+       r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val);
        if (r) {
                dev_err(dev, "%s: read error: %d\n", __func__, r);
                goto out;
@@ -1066,7 +920,7 @@ static int wl1273_fm_set_preemphasis(struct wl1273_device *radio,
                goto out;
        }
 
-       r = wl1273_fm_write_cmd(core, WL1273_PREMPH_SET, em);
+       r = core->write(core, WL1273_PREMPH_SET, em);
        if (r)
                goto out;
 
@@ -1086,7 +940,7 @@ static int wl1273_fm_rds_on(struct wl1273_device *radio)
        if (radio->rds_on)
                return 0;
 
-       r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+       r = core->write(core, WL1273_POWER_SET,
                        WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS);
        if (r)
                goto out;
@@ -1108,19 +962,16 @@ static int wl1273_fm_rds_off(struct wl1273_device *radio)
 
        radio->irq_flags &= ~WL1273_RDS_EVENT;
 
-       r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+       r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags);
        if (r)
                goto out;
 
-       /* stop rds reception */
-       cancel_delayed_work(&radio->work);
-
        /* Service pending read */
        wake_up_interruptible(&radio->read_queue);
 
        dev_dbg(radio->dev, "%s\n", __func__);
 
-       r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, WL1273_POWER_SET_FM);
+       r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM);
        if (r)
                goto out;
 
@@ -1143,14 +994,14 @@ static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode)
                return -EPERM;
 
        if (new_mode == WL1273_RDS_RESET) {
-               r = wl1273_fm_write_cmd(core, WL1273_RDS_CNTRL_SET, 1);
+               r = core->write(core, WL1273_RDS_CNTRL_SET, 1);
                return r;
        }
 
        if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) {
-               r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+               r = core->write(core, WL1273_RDS_DATA_ENB, 0);
        } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) {
-               r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+               r = core->write(core, WL1273_RDS_DATA_ENB, 1);
        } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) {
                r = wl1273_fm_rds_off(radio);
        } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) {
@@ -1171,12 +1022,13 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
                                    size_t count, loff_t *ppos)
 {
        struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+       struct wl1273_core *core = radio->core;
        u16 val;
        int r;
 
        dev_dbg(radio->dev, "%s\n", __func__);
 
-       if (radio->core->mode != WL1273_MODE_TX)
+       if (core->mode != WL1273_MODE_TX)
                return count;
 
        if (radio->rds_users == 0) {
@@ -1184,7 +1036,7 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
                return 0;
        }
 
-       if (mutex_lock_interruptible(&radio->core->lock))
+       if (mutex_lock_interruptible(&core->lock))
                return -EINTR;
        /*
         * Multiple processes can open the device, but only
@@ -1202,7 +1054,7 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
        else
                val = count;
 
-       wl1273_fm_write_cmd(radio->core, WL1273_RDS_CONFIG_DATA_SET, val);
+       core->write(core, WL1273_RDS_CONFIG_DATA_SET, val);
 
        if (copy_from_user(radio->write_buf + 1, buf, val)) {
                r = -EFAULT;
@@ -1213,11 +1065,11 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
        dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf);
 
        radio->write_buf[0] = WL1273_RDS_DATA_SET;
-       wl1273_fm_write_data(radio->core, radio->write_buf, val + 1);
+       core->write_data(core, radio->write_buf, val + 1);
 
        r = val;
 out:
-       mutex_unlock(&radio->core->lock);
+       mutex_unlock(&core->lock);
 
        return r;
 }
@@ -1263,8 +1115,8 @@ static int wl1273_fm_fops_open(struct file *file)
 
                radio->irq_flags |= WL1273_RDS_EVENT;
 
-               r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
-                                       radio->irq_flags);
+               r = core->write(core, WL1273_INT_MASK_SET,
+                               radio->irq_flags);
                if (r) {
                        mutex_unlock(&core->lock);
                        goto out;
@@ -1295,9 +1147,9 @@ static int wl1273_fm_fops_release(struct file *file)
                        radio->irq_flags &= ~WL1273_RDS_EVENT;
 
                        if (core->mode == WL1273_MODE_RX) {
-                               r = wl1273_fm_write_cmd(core,
-                                                       WL1273_INT_MASK_SET,
-                                                       radio->irq_flags);
+                               r = core->write(core,
+                                               WL1273_INT_MASK_SET,
+                                               radio->irq_flags);
                                if (r) {
                                        mutex_unlock(&core->lock);
                                        goto out;
@@ -1324,7 +1176,7 @@ static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf,
 
        dev_dbg(radio->dev, "%s\n", __func__);
 
-       if (radio->core->mode != WL1273_MODE_RX)
+       if (core->mode != WL1273_MODE_RX)
                return 0;
 
        if (radio->rds_users == 0) {
@@ -1345,7 +1197,7 @@ static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf,
        }
        radio->owner = file;
 
-       r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+       r = core->read(core, WL1273_RDS_SYNC_GET, &val);
        if (r) {
                dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__);
                goto out;
@@ -1466,23 +1318,24 @@ static int wl1273_fm_vidioc_s_input(struct file *file, void *priv,
  */
 static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power)
 {
+       struct wl1273_core *core = radio->core;
        int r;
 
-       if (radio->core->mode == WL1273_MODE_OFF ||
-           radio->core->mode == WL1273_MODE_SUSPENDED)
+       if (core->mode == WL1273_MODE_OFF ||
+           core->mode == WL1273_MODE_SUSPENDED)
                return -EPERM;
 
-       mutex_lock(&radio->core->lock);
+       mutex_lock(&core->lock);
 
        /* Convert the dBuV value to chip presentation */
-       r = wl1273_fm_write_cmd(radio->core, WL1273_POWER_LEV_SET, 122 - power);
+       r = core->write(core, WL1273_POWER_LEV_SET, 122 - power);
        if (r)
                goto out;
 
        radio->tx_power = power;
 
 out:
-       mutex_unlock(&radio->core->lock);
+       mutex_unlock(&core->lock);
        return r;
 }
 
@@ -1493,23 +1346,24 @@ out:
 static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio,
                                    unsigned int spacing)
 {
+       struct wl1273_core *core = radio->core;
        int r;
 
        if (spacing == 0) {
-               r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
-                                       WL1273_SPACING_100kHz);
+               r = core->write(core, WL1273_SCAN_SPACING_SET,
+                               WL1273_SPACING_100kHz);
                radio->spacing = 100;
        } else if (spacing - 50000 < 25000) {
-               r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
-                                       WL1273_SPACING_50kHz);
+               r = core->write(core, WL1273_SCAN_SPACING_SET,
+                               WL1273_SPACING_50kHz);
                radio->spacing = 50;
        } else if (spacing - 100000 < 50000) {
-               r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
-                                       WL1273_SPACING_100kHz);
+               r = core->write(core, WL1273_SCAN_SPACING_SET,
+                               WL1273_SPACING_100kHz);
                radio->spacing = 100;
        } else {
-               r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
-                                       WL1273_SPACING_200kHz);
+               r = core->write(core, WL1273_SCAN_SPACING_SET,
+                               WL1273_SPACING_200kHz);
                radio->spacing = 200;
        }
 
@@ -1567,17 +1421,17 @@ static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl)
                        return -EINTR;
 
                if (core->mode == WL1273_MODE_RX && ctrl->val)
-                       r = wl1273_fm_write_cmd(core,
-                                               WL1273_MUTE_STATUS_SET,
-                                               WL1273_MUTE_HARD_LEFT |
-                                               WL1273_MUTE_HARD_RIGHT);
+                       r = core->write(core,
+                                       WL1273_MUTE_STATUS_SET,
+                                       WL1273_MUTE_HARD_LEFT |
+                                       WL1273_MUTE_HARD_RIGHT);
                else if (core->mode == WL1273_MODE_RX)
-                       r = wl1273_fm_write_cmd(core,
-                                               WL1273_MUTE_STATUS_SET, 0x0);
+                       r = core->write(core,
+                                       WL1273_MUTE_STATUS_SET, 0x0);
                else if (core->mode == WL1273_MODE_TX && ctrl->val)
-                       r = wl1273_fm_write_cmd(core, WL1273_MUTE, 1);
+                       r = core->write(core, WL1273_MUTE, 1);
                else if (core->mode == WL1273_MODE_TX)
-                       r = wl1273_fm_write_cmd(core, WL1273_MUTE, 0);
+                       r = core->write(core, WL1273_MUTE, 0);
 
                mutex_unlock(&core->lock);
                break;
@@ -1672,7 +1526,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
        if (mutex_lock_interruptible(&core->lock))
                return -EINTR;
 
-       r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+       r = core->read(core, WL1273_STEREO_GET, &val);
        if (r)
                goto out;
 
@@ -1681,7 +1535,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
        else
                tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-       r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+       r = core->read(core, WL1273_RSSI_LVL_GET, &val);
        if (r)
                goto out;
 
@@ -1690,7 +1544,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
 
        tuner->afc = 0;
 
-       r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+       r = core->read(core, WL1273_RDS_SYNC_GET, &val);
        if (r)
                goto out;
 
@@ -1736,8 +1590,7 @@ static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
                dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r);
 
        if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
-               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
-                                       WL1273_RX_MONO);
+               r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO);
                if (r < 0) {
                        dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
                                 __func__, r);
@@ -1745,8 +1598,7 @@ static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
                }
                radio->stereo = false;
        } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) {
-               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
-                                       WL1273_RX_STEREO);
+               r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO);
                if (r < 0) {
                        dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
                                 __func__, r);
@@ -1885,10 +1737,10 @@ static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv,
                r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF);
 
        if (modulator->txsubchans & V4L2_TUNER_SUB_MONO)
-               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, WL1273_TX_MONO);
+               r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO);
        else
-               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
-                                       WL1273_RX_STEREO);
+               r = core->write(core, WL1273_MONO_SET,
+                               WL1273_RX_STEREO);
        if (r < 0)
                dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
                         "MONO_SET fails: %d\n", r);
@@ -1923,7 +1775,7 @@ static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv,
        if (mutex_lock_interruptible(&core->lock))
                return -EINTR;
 
-       r = wl1273_fm_read_reg(core, WL1273_MONO_SET, &val);
+       r = core->read(core, WL1273_MONO_SET, &val);
        if (r)
                goto out;
 
@@ -1960,38 +1812,38 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
                return 0;
        }
 
-       r = wl1273_fm_read_reg(core, WL1273_ASIC_ID_GET, &val);
+       r = core->read(core, WL1273_ASIC_ID_GET, &val);
        if (r)
                dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__);
        else
                dev_info(dev, "ASIC_ID: 0x%04x\n", val);
 
-       r = wl1273_fm_read_reg(core, WL1273_ASIC_VER_GET, &val);
+       r = core->read(core, WL1273_ASIC_VER_GET, &val);
        if (r)
                dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__);
        else
                dev_info(dev, "ASIC Version: 0x%04x\n", val);
 
-       r = wl1273_fm_read_reg(core, WL1273_FIRM_VER_GET, &val);
+       r = core->read(core, WL1273_FIRM_VER_GET, &val);
        if (r)
                dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__);
        else
                dev_info(dev, "FW version: %d(0x%04x)\n", val, val);
 
-       r = wl1273_fm_read_reg(core, WL1273_BAND_SET, &val);
+       r = core->read(core, WL1273_BAND_SET, &val);
        if (r)
                dev_err(dev, "%s: Get BAND fails.\n", __func__);
        else
                dev_info(dev, "BAND: %d\n", val);
 
        if (core->mode == WL1273_MODE_TX) {
-               r = wl1273_fm_read_reg(core, WL1273_PUPD_SET, &val);
+               r = core->read(core, WL1273_PUPD_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get PUPD fails.\n", __func__);
                else
                        dev_info(dev, "PUPD: 0x%04x\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &val);
+               r = core->read(core, WL1273_CHANL_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get CHANL fails.\n", __func__);
                else
@@ -1999,13 +1851,13 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
        } else if (core->mode == WL1273_MODE_RX) {
                int bf = radio->rangelow;
 
-               r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &val);
+               r = core->read(core, WL1273_FREQ_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get FREQ fails.\n", __func__);
                else
                        dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50);
 
-               r = wl1273_fm_read_reg(core, WL1273_MOST_MODE_SET, &val);
+               r = core->read(core, WL1273_MOST_MODE_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get MOST_MODE fails.\n",
                                __func__);
@@ -2016,7 +1868,7 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
                else
                        dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_MOST_BLEND_SET, &val);
+               r = core->read(core, WL1273_MOST_BLEND_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__);
                else if (val == 0)
@@ -2027,7 +1879,7 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
                else
                        dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+               r = core->read(core, WL1273_STEREO_GET, &val);
                if (r)
                        dev_err(dev, "%s: Get STEREO fails.\n", __func__);
                else if (val == 0)
@@ -2037,25 +1889,25 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
                else
                        dev_info(dev, "STEREO: Unexpected value: %d\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+               r = core->read(core, WL1273_RSSI_LVL_GET, &val);
                if (r)
                        dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__);
                else
                        dev_info(dev, "RX signal strength: %d\n", (s16) val);
 
-               r = wl1273_fm_read_reg(core, WL1273_POWER_SET, &val);
+               r = core->read(core, WL1273_POWER_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get POWER fails.\n", __func__);
                else
                        dev_info(dev, "POWER: 0x%04x\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_INT_MASK_SET, &val);
+               r = core->read(core, WL1273_INT_MASK_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get INT_MASK fails.\n", __func__);
                else
                        dev_info(dev, "INT_MASK: 0x%04x\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+               r = core->read(core, WL1273_RDS_SYNC_GET, &val);
                if (r)
                        dev_err(dev, "%s: Get RDS_SYNC fails.\n",
                                __func__);
@@ -2067,14 +1919,14 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
                else
                        dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_I2S_MODE_CONFIG_SET, &val);
+               r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n",
                                __func__);
                else
                        dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val);
 
-               r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
+               r = core->read(core, WL1273_VOLUME_SET, &val);
                if (r)
                        dev_err(dev, "%s: Get VOLUME fails.\n", __func__);
                else
@@ -2138,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
 
 static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
 {
-       struct wl1273_core **core = pdev->dev.platform_data;
+       struct wl1273_core **core = mfd_get_data(pdev);
        struct wl1273_device *radio;
        struct v4l2_ctrl *ctrl;
        int r = 0;
@@ -2184,10 +2036,6 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
        radio->stereo = true;
        radio->bus_type = "I2C";
 
-       radio->core->write = wl1273_fm_write_cmd;
-       radio->core->set_audio = wl1273_fm_set_audio;
-       radio->core->set_volume = wl1273_fm_set_volume;
-
        if (radio->core->pdata->request_resources) {
                r = radio->core->pdata->request_resources(radio->core->client);
                if (r) {
@@ -2319,7 +2167,6 @@ module_init(wl1273_fm_module_init);
 
 static void __exit wl1273_fm_module_exit(void)
 {
-       flush_scheduled_work();
        platform_driver_unregister(&wl1273_fm_radio_driver);
        pr_info(DRIVER_DESC ", Exiting.\n");
 }
index 60c176fe328ec4a38fb163e401428a148558a81e..38ae6cd65790ff9da2ec9cf2cbc0620ac5ac7c59 100644 (file)
@@ -460,7 +460,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
        count /= 3;
 
        /* copy RDS block out of internal buffer and to user buffer */
-       mutex_lock(&radio->lock);
        while (block_count < count) {
                if (radio->rd_index == radio->wr_index)
                        break;
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
new file mode 100644 (file)
index 0000000..749f67b
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# TI's wl128x FM driver based on TI's ST driver.
+#
+menu "Texas Instruments WL128x FM driver (ST based)"
+config RADIO_WL128X
+       tristate "Texas Instruments WL128x FM Radio"
+       depends on VIDEO_V4L2 && RFKILL
+       select TI_ST
+       help
+       Choose Y here if you have this FM radio chip.
+
+       In order to control your radio card, you will need to use programs
+       that are compatible with the Video For Linux 2 API.  Information on
+       this API and pointers to "v4l2" programs may be found at
+       <file:Documentation/video4linux/API.html>.
+
+endmenu
diff --git a/drivers/media/radio/wl128x/Makefile b/drivers/media/radio/wl128x/Makefile
new file mode 100644 (file)
index 0000000..32a0ead
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for TI's shared transport driver based wl128x
+# FM radio.
+#
+obj-$(CONFIG_RADIO_WL128X)     += fm_drv.o
+fm_drv-objs            := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
new file mode 100644 (file)
index 0000000..5db6fd1
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  Common header for all FM driver sub-modules.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_DRV_H
+#define _FM_DRV_H
+
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#define FM_DRV_VERSION            "0.10"
+/* Should match with FM_DRV_VERSION */
+#define FM_DRV_RADIO_VERSION      KERNEL_VERSION(0, 0, 1)
+#define FM_DRV_NAME               "ti_fmdrv"
+#define FM_DRV_CARD_SHORT_NAME    "TI FM Radio"
+#define FM_DRV_CARD_LONG_NAME     "Texas Instruments FM Radio"
+
+/* Flag info */
+#define FM_INTTASK_RUNNING            0
+#define FM_INTTASK_SCHEDULE_PENDING   1
+#define FM_FW_DW_INPROGRESS     2
+#define FM_CORE_READY                 3
+#define FM_CORE_TRANSPORT_READY       4
+#define FM_AF_SWITCH_INPROGRESS              5
+#define FM_CORE_TX_XMITING           6
+
+#define FM_TUNE_COMPLETE             0x1
+#define FM_BAND_LIMIT                0x2
+
+#define FM_DRV_TX_TIMEOUT      (5*HZ)  /* 5 seconds */
+#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
+
+#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0]))
+
+#define fmerr(format, ...) \
+       printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__)
+#define fmwarn(format, ...) \
+       printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__)
+#ifdef DEBUG
+#define fmdbg(format, ...) \
+       printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__)
+#else /* DEBUG */
+#define fmdbg(format, ...)
+#endif
+enum {
+       FM_MODE_OFF,
+       FM_MODE_TX,
+       FM_MODE_RX,
+       FM_MODE_ENTRY_MAX
+};
+
+#define FM_RX_RDS_INFO_FIELD_MAX       8       /* 4 Group * 2 Bytes */
+
+/* RX RDS data format */
+struct fm_rdsdata_format {
+       union {
+               struct {
+                       u8 buff[FM_RX_RDS_INFO_FIELD_MAX];
+               } groupdatabuff;
+               struct {
+                       u16 pidata;
+                       u8 blk_b[2];
+                       u8 blk_c[2];
+                       u8 blk_d[2];
+               } groupgeneral;
+               struct {
+                       u16 pidata;
+                       u8 blk_b[2];
+                       u8 af[2];
+                       u8 ps[2];
+               } group0A;
+               struct {
+                       u16 pi[2];
+                       u8 blk_b[2];
+                       u8 ps[2];
+               } group0B;
+       } data;
+};
+
+/* FM region (Europe/US, Japan) info */
+struct region_info {
+       u32 chanl_space;
+       u32 bot_freq;
+       u32 top_freq;
+       u8 fm_band;
+};
+struct fmdev;
+typedef void (*int_handler_prototype) (struct fmdev *);
+
+/* FM Interrupt processing related info */
+struct fm_irq {
+       u8 stage;
+       u16 flag;       /* FM interrupt flag */
+       u16 mask;       /* FM interrupt mask */
+       /* Interrupt process timeout handler */
+       struct timer_list timer;
+       u8 retry;
+       int_handler_prototype *handlers;
+};
+
+/* RDS info */
+struct fm_rds {
+       u8 flag;        /* RX RDS on/off status */
+       u8 last_blk_idx;        /* Last received RDS block */
+
+       /* RDS buffer */
+       wait_queue_head_t read_queue;
+       u32 buf_size;   /* Size is always multiple of 3 */
+       u32 wr_idx;
+       u32 rd_idx;
+       u8 *buff;
+};
+
+#define FM_RDS_MAX_AF_LIST             25
+
+/*
+ * Current RX channel Alternate Frequency cache.
+ * This info is used to switch to other freq (AF)
+ * when current channel signal strengh is below RSSI threshold.
+ */
+struct tuned_station_info {
+       u16 picode;
+       u32 af_cache[FM_RDS_MAX_AF_LIST];
+       u8 afcache_size;
+       u8 af_list_max;
+};
+
+/* FM RX mode info */
+struct fm_rx {
+       struct region_info region;      /* Current selected band */
+       u32 freq;       /* Current RX frquency */
+       u8 mute_mode;   /* Current mute mode */
+       u8 deemphasis_mode; /* Current deemphasis mode */
+       /* RF dependent soft mute mode */
+       u8 rf_depend_mute;
+       u16 volume;     /* Current volume level */
+       u16 rssi_threshold;     /* Current RSSI threshold level */
+       /* Holds the index of the current AF jump */
+       u8 afjump_idx;
+       /* Will hold the frequency before the jump */
+       u32 freq_before_jump;
+       u8 rds_mode;    /* RDS operation mode (RDS/RDBS) */
+       u8 af_mode;     /* Alternate frequency on/off */
+       struct tuned_station_info stat_info;
+       struct fm_rds rds;
+};
+
+#define FMTX_RDS_TXT_STR_SIZE  25
+/*
+ * FM TX RDS data
+ *
+ * @ text_type: is the text following PS or RT
+ * @ text: radio text string which could either be PS or RT
+ * @ af_freq: alternate frequency for Tx
+ * TODO: to be declared in application
+ */
+struct tx_rds {
+       u8 text_type;
+       u8 text[FMTX_RDS_TXT_STR_SIZE];
+       u8 flag;
+       u32 af_freq;
+};
+/*
+ * FM TX global data
+ *
+ * @ pwr_lvl: Power Level of the Transmission from mixer control
+ * @ xmit_state: Transmission state = Updated locally upon Start/Stop
+ * @ audio_io: i2S/Analog
+ * @ tx_frq: Transmission frequency
+ */
+struct fmtx_data {
+       u8 pwr_lvl;
+       u8 xmit_state;
+       u8 audio_io;
+       u8 region;
+       u16 aud_mode;
+       u32 preemph;
+       u32 tx_frq;
+       struct tx_rds rds;
+};
+
+/* FM driver operation structure */
+struct fmdev {
+       struct video_device *radio_dev; /* V4L2 video device pointer */
+       struct snd_card *card;  /* Card which holds FM mixer controls */
+       u16 asci_id;
+       spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
+       spinlock_t resp_skb_lock; /* To protect access to received SKB */
+
+       long flag;              /*  FM driver state machine info */
+       u8 streg_cbdata; /* status of ST registration */
+
+       struct sk_buff_head rx_q;       /* RX queue */
+       struct tasklet_struct rx_task;  /* RX Tasklet */
+
+       struct sk_buff_head tx_q;       /* TX queue */
+       struct tasklet_struct tx_task;  /* TX Tasklet */
+       unsigned long last_tx_jiffies;  /* Timestamp of last pkt sent */
+       atomic_t tx_cnt;        /* Number of packets can send at a time */
+
+       struct sk_buff *resp_skb;       /* Response from the chip */
+       /* Main task completion handler */
+       struct completion maintask_comp;
+       /* Opcode of last command sent to the chip */
+       u8 pre_op;
+       /* Handler used for wakeup when response packet is received */
+       struct completion *resp_comp;
+       struct fm_irq irq_info;
+       u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */
+       struct fm_rx rx;        /* FM receiver info */
+       struct fmtx_data tx_data;
+
+       /* V4L2 ctrl framwork handler*/
+       struct v4l2_ctrl_handler ctrl_handler;
+
+       /* For core assisted locking */
+       struct mutex mutex;
+};
+#endif
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
new file mode 100644 (file)
index 0000000..64454d3
--- /dev/null
@@ -0,0 +1,1677 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  This sub-module of FM driver is common for FM RX and TX
+ *  functionality. This module is responsible for:
+ *  1) Forming group of Channel-8 commands to perform particular
+ *     functionality (eg., frequency set require more than
+ *     one Channel-8 command to be sent to the chip).
+ *  2) Sending each Channel-8 command to the chip and reading
+ *     response back over Shared Transport.
+ *  3) Managing TX and RX Queues and Tasklets.
+ *  4) Handling FM Interrupt packet and taking appropriate action.
+ *  5) Loading FM firmware to the chip (common, FM TX, and FM RX
+ *     firmware files based on mode selection)
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *  Author: Raja Mani <raja_mani@ti.com>
+ *  Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_common.h"
+#include <linux/ti_wilink_st.h>
+#include "fmdrv_rx.h"
+#include "fmdrv_tx.h"
+
+/* Region info */
+static struct region_info region_configs[] = {
+       /* Europe/US */
+       {
+        .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
+        .bot_freq = 87500,     /* 87.5 MHz */
+        .top_freq = 108000,    /* 108 MHz */
+        .fm_band = 0,
+        },
+       /* Japan */
+       {
+        .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
+        .bot_freq = 76000,     /* 76 MHz */
+        .top_freq = 90000,     /* 90 MHz */
+        .fm_band = 1,
+        },
+};
+
+/* Band selection */
+static u8 default_radio_region;        /* Europe/US */
+module_param(default_radio_region, byte, 0);
+MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
+
+/* RDS buffer blocks */
+static u32 default_rds_buf = 300;
+module_param(default_rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
+
+/* Radio Nr */
+static u32 radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* FM irq handlers forward declaration */
+static void fm_irq_send_flag_getcmd(struct fmdev *);
+static void fm_irq_handle_flag_getcmd_resp(struct fmdev *);
+static void fm_irq_handle_hw_malfunction(struct fmdev *);
+static void fm_irq_handle_rds_start(struct fmdev *);
+static void fm_irq_send_rdsdata_getcmd(struct fmdev *);
+static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *);
+static void fm_irq_handle_rds_finish(struct fmdev *);
+static void fm_irq_handle_tune_op_ended(struct fmdev *);
+static void fm_irq_handle_power_enb(struct fmdev *);
+static void fm_irq_handle_low_rssi_start(struct fmdev *);
+static void fm_irq_afjump_set_pi(struct fmdev *);
+static void fm_irq_handle_set_pi_resp(struct fmdev *);
+static void fm_irq_afjump_set_pimask(struct fmdev *);
+static void fm_irq_handle_set_pimask_resp(struct fmdev *);
+static void fm_irq_afjump_setfreq(struct fmdev *);
+static void fm_irq_handle_setfreq_resp(struct fmdev *);
+static void fm_irq_afjump_enableint(struct fmdev *);
+static void fm_irq_afjump_enableint_resp(struct fmdev *);
+static void fm_irq_start_afjump(struct fmdev *);
+static void fm_irq_handle_start_afjump_resp(struct fmdev *);
+static void fm_irq_afjump_rd_freq(struct fmdev *);
+static void fm_irq_afjump_rd_freq_resp(struct fmdev *);
+static void fm_irq_handle_low_rssi_finish(struct fmdev *);
+static void fm_irq_send_intmsk_cmd(struct fmdev *);
+static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *);
+
+/*
+ * When FM common module receives interrupt packet, following handlers
+ * will be executed one after another to service the interrupt(s)
+ */
+enum fmc_irq_handler_index {
+       FM_SEND_FLAG_GETCMD_IDX,
+       FM_HANDLE_FLAG_GETCMD_RESP_IDX,
+
+       /* HW malfunction irq handler */
+       FM_HW_MAL_FUNC_IDX,
+
+       /* RDS threshold reached irq handler */
+       FM_RDS_START_IDX,
+       FM_RDS_SEND_RDS_GETCMD_IDX,
+       FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX,
+       FM_RDS_FINISH_IDX,
+
+       /* Tune operation ended irq handler */
+       FM_HW_TUNE_OP_ENDED_IDX,
+
+       /* TX power enable irq handler */
+       FM_HW_POWER_ENB_IDX,
+
+       /* Low RSSI irq handler */
+       FM_LOW_RSSI_START_IDX,
+       FM_AF_JUMP_SETPI_IDX,
+       FM_AF_JUMP_HANDLE_SETPI_RESP_IDX,
+       FM_AF_JUMP_SETPI_MASK_IDX,
+       FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX,
+       FM_AF_JUMP_SET_AF_FREQ_IDX,
+       FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX,
+       FM_AF_JUMP_ENABLE_INT_IDX,
+       FM_AF_JUMP_ENABLE_INT_RESP_IDX,
+       FM_AF_JUMP_START_AFJUMP_IDX,
+       FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX,
+       FM_AF_JUMP_RD_FREQ_IDX,
+       FM_AF_JUMP_RD_FREQ_RESP_IDX,
+       FM_LOW_RSSI_FINISH_IDX,
+
+       /* Interrupt process post action */
+       FM_SEND_INTMSK_CMD_IDX,
+       FM_HANDLE_INTMSK_CMD_RESP_IDX,
+};
+
+/* FM interrupt handler table */
+static int_handler_prototype int_handler_table[] = {
+       fm_irq_send_flag_getcmd,
+       fm_irq_handle_flag_getcmd_resp,
+       fm_irq_handle_hw_malfunction,
+       fm_irq_handle_rds_start, /* RDS threshold reached irq handler */
+       fm_irq_send_rdsdata_getcmd,
+       fm_irq_handle_rdsdata_getcmd_resp,
+       fm_irq_handle_rds_finish,
+       fm_irq_handle_tune_op_ended,
+       fm_irq_handle_power_enb, /* TX power enable irq handler */
+       fm_irq_handle_low_rssi_start,
+       fm_irq_afjump_set_pi,
+       fm_irq_handle_set_pi_resp,
+       fm_irq_afjump_set_pimask,
+       fm_irq_handle_set_pimask_resp,
+       fm_irq_afjump_setfreq,
+       fm_irq_handle_setfreq_resp,
+       fm_irq_afjump_enableint,
+       fm_irq_afjump_enableint_resp,
+       fm_irq_start_afjump,
+       fm_irq_handle_start_afjump_resp,
+       fm_irq_afjump_rd_freq,
+       fm_irq_afjump_rd_freq_resp,
+       fm_irq_handle_low_rssi_finish,
+       fm_irq_send_intmsk_cmd, /* Interrupt process post action */
+       fm_irq_handle_intmsk_cmd_resp
+};
+
+long (*g_st_write) (struct sk_buff *skb);
+static struct completion wait_for_fmdrv_reg_comp;
+
+static inline void fm_irq_call(struct fmdev *fmdev)
+{
+       fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
+}
+
+/* Continue next function in interrupt handler table */
+static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage)
+{
+       fmdev->irq_info.stage = stage;
+       fm_irq_call(fmdev);
+}
+
+static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage)
+{
+       fmdev->irq_info.stage = stage;
+       mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
+}
+
+#ifdef FM_DUMP_TXRX_PKT
+ /* To dump outgoing FM Channel-8 packets */
+inline void dump_tx_skb_data(struct sk_buff *skb)
+{
+       int len, len_org;
+       u8 index;
+       struct fm_cmd_msg_hdr *cmd_hdr;
+
+       cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data;
+       printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x",
+              fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr,
+              cmd_hdr->len, cmd_hdr->op,
+              cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen);
+
+       len_org = skb->len - FM_CMD_MSG_HDR_SIZE;
+       if (len_org > 0) {
+               printk("\n   data(%d): ", cmd_hdr->dlen);
+               len = min(len_org, 14);
+               for (index = 0; index < len; index++)
+                       printk("%x ",
+                              skb->data[FM_CMD_MSG_HDR_SIZE + index]);
+               printk("%s", (len_org > 14) ? ".." : "");
+       }
+       printk("\n");
+}
+
+ /* To dump incoming FM Channel-8 packets */
+inline void dump_rx_skb_data(struct sk_buff *skb)
+{
+       int len, len_org;
+       u8 index;
+       struct fm_event_msg_hdr *evt_hdr;
+
+       evt_hdr = (struct fm_event_msg_hdr *)skb->data;
+       printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x "
+           "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len,
+           evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op,
+           (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen);
+
+       len_org = skb->len - FM_EVT_MSG_HDR_SIZE;
+       if (len_org > 0) {
+               printk("\n   data(%d): ", evt_hdr->dlen);
+               len = min(len_org, 14);
+               for (index = 0; index < len; index++)
+                       printk("%x ",
+                              skb->data[FM_EVT_MSG_HDR_SIZE + index]);
+               printk("%s", (len_org > 14) ? ".." : "");
+       }
+       printk("\n");
+}
+#endif
+
+void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
+{
+       fmdev->rx.region = region_configs[region_to_set];
+}
+
+/*
+ * FM common sub-module will schedule this tasklet whenever it receives
+ * FM packet from ST driver.
+ */
+static void recv_tasklet(unsigned long arg)
+{
+       struct fmdev *fmdev;
+       struct fm_irq *irq_info;
+       struct fm_event_msg_hdr *evt_hdr;
+       struct sk_buff *skb;
+       u8 num_fm_hci_cmds;
+       unsigned long flags;
+
+       fmdev = (struct fmdev *)arg;
+       irq_info = &fmdev->irq_info;
+       /* Process all packets in the RX queue */
+       while ((skb = skb_dequeue(&fmdev->rx_q))) {
+               if (skb->len < sizeof(struct fm_event_msg_hdr)) {
+                       fmerr("skb(%p) has only %d bytes, "
+                               "at least need %zu bytes to decode\n", skb,
+                               skb->len, sizeof(struct fm_event_msg_hdr));
+                       kfree_skb(skb);
+                       continue;
+               }
+
+               evt_hdr = (void *)skb->data;
+               num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds;
+
+               /* FM interrupt packet? */
+               if (evt_hdr->op == FM_INTERRUPT) {
+                       /* FM interrupt handler started already? */
+                       if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+                               set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+                               if (irq_info->stage != 0) {
+                                       fmerr("Inval stage resetting to zero\n");
+                                       irq_info->stage = 0;
+                               }
+
+                               /*
+                                * Execute first function in interrupt handler
+                                * table.
+                                */
+                               irq_info->handlers[irq_info->stage](fmdev);
+                       } else {
+                               set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag);
+                       }
+                       kfree_skb(skb);
+               }
+               /* Anyone waiting for this with completion handler? */
+               else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) {
+
+                       spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+                       fmdev->resp_skb = skb;
+                       spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+                       complete(fmdev->resp_comp);
+
+                       fmdev->resp_comp = NULL;
+                       atomic_set(&fmdev->tx_cnt, 1);
+               }
+               /* Is this for interrupt handler? */
+               else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) {
+                       if (fmdev->resp_skb != NULL)
+                               fmerr("Response SKB ptr not NULL\n");
+
+                       spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+                       fmdev->resp_skb = skb;
+                       spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+                       /* Execute interrupt handler where state index points */
+                       irq_info->handlers[irq_info->stage](fmdev);
+
+                       kfree_skb(skb);
+                       atomic_set(&fmdev->tx_cnt, 1);
+               } else {
+                       fmerr("Nobody claimed SKB(%p),purging\n", skb);
+               }
+
+               /*
+                * Check flow control field. If Num_FM_HCI_Commands field is
+                * not zero, schedule FM TX tasklet.
+                */
+               if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt))
+                       if (!skb_queue_empty(&fmdev->tx_q))
+                               tasklet_schedule(&fmdev->tx_task);
+       }
+}
+
+/* FM send tasklet: is scheduled when FM packet has to be sent to chip */
+static void send_tasklet(unsigned long arg)
+{
+       struct fmdev *fmdev;
+       struct sk_buff *skb;
+       int len;
+
+       fmdev = (struct fmdev *)arg;
+
+       if (!atomic_read(&fmdev->tx_cnt))
+               return;
+
+       /* Check, is there any timeout happenned to last transmitted packet */
+       if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) {
+               fmerr("TX timeout occurred\n");
+               atomic_set(&fmdev->tx_cnt, 1);
+       }
+
+       /* Send queued FM TX packets */
+       skb = skb_dequeue(&fmdev->tx_q);
+       if (!skb)
+               return;
+
+       atomic_dec(&fmdev->tx_cnt);
+       fmdev->pre_op = fm_cb(skb)->fm_op;
+
+       if (fmdev->resp_comp != NULL)
+               fmerr("Response completion handler is not NULL\n");
+
+       fmdev->resp_comp = fm_cb(skb)->completion;
+
+       /* Write FM packet to ST driver */
+       len = g_st_write(skb);
+       if (len < 0) {
+               kfree_skb(skb);
+               fmdev->resp_comp = NULL;
+               fmerr("TX tasklet failed to send skb(%p)\n", skb);
+               atomic_set(&fmdev->tx_cnt, 1);
+       } else {
+               fmdev->last_tx_jiffies = jiffies;
+       }
+}
+
+/*
+ * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * transmission
+ */
+static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type,        void *payload,
+               int payload_len, struct completion *wait_completion)
+{
+       struct sk_buff *skb;
+       struct fm_cmd_msg_hdr *hdr;
+       int size;
+
+       if (fm_op >= FM_INTERRUPT) {
+               fmerr("Invalid fm opcode - %d\n", fm_op);
+               return -EINVAL;
+       }
+       if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) {
+               fmerr("Payload data is NULL during fw download\n");
+               return -EINVAL;
+       }
+       if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag))
+               size =
+                   FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len);
+       else
+               size = payload_len;
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb) {
+               fmerr("No memory to create new SKB\n");
+               return -ENOMEM;
+       }
+       /*
+        * Don't fill FM header info for the commands which come from
+        * FM firmware file.
+        */
+       if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) ||
+                       test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+               /* Fill command header info */
+               hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE);
+               hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER;  /* 0x08 */
+
+               /* 3 (fm_opcode,rd_wr,dlen) + payload len) */
+               hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
+
+               /* FM opcode */
+               hdr->op = fm_op;
+
+               /* read/write type */
+               hdr->rd_wr = type;
+               hdr->dlen = payload_len;
+               fm_cb(skb)->fm_op = fm_op;
+
+               /*
+                * If firmware download has finished and the command is
+                * not a read command then payload is != NULL - a write
+                * command with u16 payload - convert to be16
+                */
+               if (payload != NULL)
+                       *(u16 *)payload = cpu_to_be16(*(u16 *)payload);
+
+       } else if (payload != NULL) {
+               fm_cb(skb)->fm_op = *((u8 *)payload + 2);
+       }
+       if (payload != NULL)
+               memcpy(skb_put(skb, payload_len), payload, payload_len);
+
+       fm_cb(skb)->completion = wait_completion;
+       skb_queue_tail(&fmdev->tx_q, skb);
+       tasklet_schedule(&fmdev->tx_task);
+
+       return 0;
+}
+
+/* Sends FM Channel-8 command to the chip and waits for the response */
+u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+               unsigned int payload_len, void *response, int *response_len)
+{
+       struct sk_buff *skb;
+       struct fm_event_msg_hdr *evt_hdr;
+       unsigned long flags;
+       u32 ret;
+
+       init_completion(&fmdev->maintask_comp);
+       ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len,
+                           &fmdev->maintask_comp);
+       if (ret)
+               return ret;
+
+       ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT);
+       if (!ret) {
+               fmerr("Timeout(%d sec),didn't get reg"
+                          "completion signal from RX tasklet\n",
+                          jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+               return -ETIMEDOUT;
+       }
+       if (!fmdev->resp_skb) {
+               fmerr("Reponse SKB is missing\n");
+               return -EFAULT;
+       }
+       spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+       skb = fmdev->resp_skb;
+       fmdev->resp_skb = NULL;
+       spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+       evt_hdr = (void *)skb->data;
+       if (evt_hdr->status != 0) {
+               fmerr("Received event pkt status(%d) is not zero\n",
+                          evt_hdr->status);
+               kfree_skb(skb);
+               return -EIO;
+       }
+       /* Send response data to caller */
+       if (response != NULL && response_len != NULL && evt_hdr->dlen) {
+               /* Skip header info and copy only response data */
+               skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+               memcpy(response, skb->data, evt_hdr->dlen);
+               *response_len = evt_hdr->dlen;
+       } else if (response_len != NULL && evt_hdr->dlen == 0) {
+               *response_len = 0;
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+
+/* --- Helper functions used in FM interrupt handlers ---*/
+static inline u32 check_cmdresp_status(struct fmdev *fmdev,
+               struct sk_buff **skb)
+{
+       struct fm_event_msg_hdr *fm_evt_hdr;
+       unsigned long flags;
+
+       del_timer(&fmdev->irq_info.timer);
+
+       spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+       *skb = fmdev->resp_skb;
+       fmdev->resp_skb = NULL;
+       spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+       fm_evt_hdr = (void *)(*skb)->data;
+       if (fm_evt_hdr->status != 0) {
+               fmerr("irq: opcode %x response status is not zero "
+                               "Initiating irq recovery process\n",
+                               fm_evt_hdr->op);
+
+               mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
+               return -1;
+       }
+
+       return 0;
+}
+
+static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage)
+{
+       struct sk_buff *skb;
+
+       if (!check_cmdresp_status(fmdev, &skb))
+               fm_irq_call_stage(fmdev, stage);
+}
+
+/*
+ * Interrupt process timeout handler.
+ * One of the irq handler did not get proper response from the chip. So take
+ * recovery action here. FM interrupts are disabled in the beginning of
+ * interrupt process. Therefore reset stage index to re-enable default
+ * interrupts. So that next interrupt will be processed as usual.
+ */
+static void int_timeout_handler(unsigned long data)
+{
+       struct fmdev *fmdev;
+       struct fm_irq *fmirq;
+
+       fmdbg("irq: timeout,trying to re-enable fm interrupts\n");
+       fmdev = (struct fmdev *)data;
+       fmirq = &fmdev->irq_info;
+       fmirq->retry++;
+
+       if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) {
+               /* Stop recovery action (interrupt reenable process) and
+                * reset stage index & retry count values */
+               fmirq->stage = 0;
+               fmirq->retry = 0;
+               fmerr("Recovery action failed during"
+                               "irq processing, max retry reached\n");
+               return;
+       }
+       fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
+}
+
+/* --------- FM interrupt handlers ------------*/
+static void fm_irq_send_flag_getcmd(struct fmdev *fmdev)
+{
+       u16 flag;
+
+       /* Send FLAG_GET command , to know the source of interrupt */
+       if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL))
+               fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX);
+}
+
+static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
+{
+       struct sk_buff *skb;
+       struct fm_event_msg_hdr *fm_evt_hdr;
+
+       if (check_cmdresp_status(fmdev, &skb))
+               return;
+
+       fm_evt_hdr = (void *)skb->data;
+
+       /* Skip header info and copy only response data */
+       skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+       memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
+
+       fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+       fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
+
+       /* Continue next function in interrupt handler table */
+       fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX);
+}
+
+static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev)
+{
+       if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
+               fmerr("irq: HW MAL int received - do nothing\n");
+
+       /* Continue next function in interrupt handler table */
+       fm_irq_call_stage(fmdev, FM_RDS_START_IDX);
+}
+
+static void fm_irq_handle_rds_start(struct fmdev *fmdev)
+{
+       if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
+               fmdbg("irq: rds threshold reached\n");
+               fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX;
+       } else {
+               /* Continue next function in interrupt handler table */
+               fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX;
+       }
+
+       fm_irq_call(fmdev);
+}
+
+static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev)
+{
+       /* Send the command to read RDS data from the chip */
+       if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL,
+                           (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL))
+               fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX);
+}
+
+/* Keeps track of current RX channel AF (Alternate Frequency) */
+static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af)
+{
+       struct tuned_station_info *stat_info = &fmdev->rx.stat_info;
+       u8 reg_idx = fmdev->rx.region.fm_band;
+       u8 index;
+       u32 freq;
+
+       /* First AF indicates the number of AF follows. Reset the list */
+       if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) {
+               fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1);
+               fmdev->rx.stat_info.afcache_size = 0;
+               fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max);
+               return;
+       }
+
+       if (af < FM_RDS_MIN_AF)
+               return;
+       if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF)
+               return;
+       if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN)
+               return;
+
+       freq = fmdev->rx.region.bot_freq + (af * 100);
+       if (freq == fmdev->rx.freq) {
+               fmdbg("Current freq(%d) is matching with received AF(%d)\n",
+                               fmdev->rx.freq, freq);
+               return;
+       }
+       /* Do check in AF cache */
+       for (index = 0; index < stat_info->afcache_size; index++) {
+               if (stat_info->af_cache[index] == freq)
+                       break;
+       }
+       /* Reached the limit of the list - ignore the next AF */
+       if (index == stat_info->af_list_max) {
+               fmdbg("AF cache is full\n");
+               return;
+       }
+       /*
+        * If we reached the end of the list then this AF is not
+        * in the list - add it.
+        */
+       if (index == stat_info->afcache_size) {
+               fmdbg("Storing AF %d to cache index %d\n", freq, index);
+               stat_info->af_cache[index] = freq;
+               stat_info->afcache_size++;
+       }
+}
+
+/*
+ * Converts RDS buffer data from big endian format
+ * to little endian format.
+ */
+static void fm_rdsparse_swapbytes(struct fmdev *fmdev,
+               struct fm_rdsdata_format *rds_format)
+{
+       u8 byte1;
+       u8 index = 0;
+       u8 *rds_buff;
+
+       /*
+        * Since in Orca the 2 RDS Data bytes are in little endian and
+        * in Dolphin they are in big endian, the parsing of the RDS data
+        * is chip dependent
+        */
+       if (fmdev->asci_id != 0x6350) {
+               rds_buff = &rds_format->data.groupdatabuff.buff[0];
+               while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
+                       byte1 = rds_buff[index];
+                       rds_buff[index] = rds_buff[index + 1];
+                       rds_buff[index + 1] = byte1;
+                       index += 2;
+               }
+       }
+}
+
+static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
+{
+       struct sk_buff *skb;
+       struct fm_rdsdata_format rds_fmt;
+       struct fm_rds *rds = &fmdev->rx.rds;
+       unsigned long group_idx, flags;
+       u8 *rds_data, meta_data, tmpbuf[3];
+       u8 type, blk_idx;
+       u16 cur_picode;
+       u32 rds_len;
+
+       if (check_cmdresp_status(fmdev, &skb))
+               return;
+
+       /* Skip header info */
+       skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+       rds_data = skb->data;
+       rds_len = skb->len;
+
+       /* Parse the RDS data */
+       while (rds_len >= FM_RDS_BLK_SIZE) {
+               meta_data = rds_data[2];
+               /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
+               type = (meta_data & 0x07);
+
+               /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */
+               blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+               fmdbg("Block index:%d(%s)\n", blk_idx,
+                          (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok");
+
+               if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0)
+                       break;
+
+               if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) {
+                       fmdbg("Block sequence mismatch\n");
+                       rds->last_blk_idx = -1;
+                       break;
+               }
+
+               /* Skip checkword (control) byte and copy only data byte */
+               memcpy(&rds_fmt.data.groupdatabuff.
+                               buff[blk_idx * (FM_RDS_BLK_SIZE - 1)],
+                               rds_data, (FM_RDS_BLK_SIZE - 1));
+
+               rds->last_blk_idx = blk_idx;
+
+               /* If completed a whole group then handle it */
+               if (blk_idx == FM_RDS_BLK_IDX_D) {
+                       fmdbg("Good block received\n");
+                       fm_rdsparse_swapbytes(fmdev, &rds_fmt);
+
+                       /*
+                        * Extract PI code and store in local cache.
+                        * We need this during AF switch processing.
+                        */
+                       cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
+                       if (fmdev->rx.stat_info.picode != cur_picode)
+                               fmdev->rx.stat_info.picode = cur_picode;
+
+                       fmdbg("picode:%d\n", cur_picode);
+
+                       group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
+                       fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2,
+                                       (group_idx % 2) ? "B" : "A");
+
+                       group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
+                       if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) {
+                               fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]);
+                               fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]);
+                       }
+               }
+               rds_len -= FM_RDS_BLK_SIZE;
+               rds_data += FM_RDS_BLK_SIZE;
+       }
+
+       /* Copy raw rds data to internal rds buffer */
+       rds_data = skb->data;
+       rds_len = skb->len;
+
+       spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+       while (rds_len > 0) {
+               /*
+                * Fill RDS buffer as per V4L2 specification.
+                * Store control byte
+                */
+               type = (rds_data[2] & 0x07);
+               blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+               tmpbuf[2] = blk_idx;    /* Offset name */
+               tmpbuf[2] |= blk_idx << 3;      /* Received offset */
+
+               /* Store data byte */
+               tmpbuf[0] = rds_data[0];
+               tmpbuf[1] = rds_data[1];
+
+               memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE);
+               rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size;
+
+               /* Check for overflow & start over */
+               if (rds->wr_idx == rds->rd_idx) {
+                       fmdbg("RDS buffer overflow\n");
+                       rds->wr_idx = 0;
+                       rds->rd_idx = 0;
+                       break;
+               }
+               rds_len -= FM_RDS_BLK_SIZE;
+               rds_data += FM_RDS_BLK_SIZE;
+       }
+       spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+       /* Wakeup read queue */
+       if (rds->wr_idx != rds->rd_idx)
+               wake_up_interruptible(&rds->read_queue);
+
+       fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX);
+}
+
+static void fm_irq_handle_rds_finish(struct fmdev *fmdev)
+{
+       fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX);
+}
+
+static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev)
+{
+       if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
+           irq_info.mask) {
+               fmdbg("irq: tune ended/bandlimit reached\n");
+               if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
+                       fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX;
+               } else {
+                       complete(&fmdev->maintask_comp);
+                       fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
+               }
+       } else
+               fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
+
+       fm_irq_call(fmdev);
+}
+
+static void fm_irq_handle_power_enb(struct fmdev *fmdev)
+{
+       if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
+               fmdbg("irq: Power Enabled/Disabled\n");
+               complete(&fmdev->maintask_comp);
+       }
+
+       fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX);
+}
+
+static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev)
+{
+       if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) &&
+           (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
+           (fmdev->rx.freq != FM_UNDEFINED_FREQ) &&
+           (fmdev->rx.stat_info.afcache_size != 0)) {
+               fmdbg("irq: rssi level has fallen below threshold level\n");
+
+               /* Disable further low RSSI interrupts */
+               fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+               fmdev->rx.afjump_idx = 0;
+               fmdev->rx.freq_before_jump = fmdev->rx.freq;
+               fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
+       } else {
+               /* Continue next function in interrupt handler table */
+               fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX;
+       }
+
+       fm_irq_call(fmdev);
+}
+
+static void fm_irq_afjump_set_pi(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       /* Set PI code - must be updated if the AF list is not empty */
+       payload = fmdev->rx.stat_info.picode;
+       if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX);
+}
+
+static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev)
+{
+       fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX);
+}
+
+/*
+ * Set PI mask.
+ * 0xFFFF = Enable PI code matching
+ * 0x0000 = Disable PI code matching
+ */
+static void fm_irq_afjump_set_pimask(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       payload = 0x0000;
+       if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX);
+}
+
+static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev)
+{
+       fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX);
+}
+
+static void fm_irq_afjump_setfreq(struct fmdev *fmdev)
+{
+       u16 frq_index;
+       u16 payload;
+
+       fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]);
+       frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] -
+            fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+       payload = frq_index;
+       if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX);
+}
+
+static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev)
+{
+       fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX);
+}
+
+static void fm_irq_afjump_enableint(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       /* Enable FR (tuning operation ended) interrupt */
+       payload = FM_FR_EVENT;
+       if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX);
+}
+
+static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev)
+{
+       fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX);
+}
+
+static void fm_irq_start_afjump(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       payload = FM_TUNER_AF_JUMP_MODE;
+       if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX);
+}
+
+static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev)
+{
+       struct sk_buff *skb;
+
+       if (check_cmdresp_status(fmdev, &skb))
+               return;
+
+       fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
+       set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag);
+       clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+}
+
+static void fm_irq_afjump_rd_freq(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX);
+}
+
+static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev)
+{
+       struct sk_buff *skb;
+       u16 read_freq;
+       u32 curr_freq, jumped_freq;
+
+       if (check_cmdresp_status(fmdev, &skb))
+               return;
+
+       /* Skip header info and copy only response data */
+       skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+       memcpy(&read_freq, skb->data, sizeof(read_freq));
+       read_freq = be16_to_cpu(read_freq);
+       curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
+
+       jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
+
+       /* If the frequency was changed the jump succeeded */
+       if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) {
+               fmdbg("Successfully switched to alternate freq %d\n", curr_freq);
+               fmdev->rx.freq = curr_freq;
+               fm_rx_reset_rds_cache(fmdev);
+
+               /* AF feature is on, enable low level RSSI interrupt */
+               if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+                       fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+               fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
+       } else {                /* jump to the next freq in the AF list */
+               fmdev->rx.afjump_idx++;
+
+               /* If we reached the end of the list - stop searching */
+               if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) {
+                       fmdbg("AF switch processing failed\n");
+                       fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
+               } else {        /* AF List is not over - try next one */
+
+                       fmdbg("Trying next freq in AF cache\n");
+                       fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
+               }
+       }
+       fm_irq_call(fmdev);
+}
+
+static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev)
+{
+       fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
+}
+
+static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev)
+{
+       u16 payload;
+
+       /* Re-enable FM interrupts */
+       payload = fmdev->irq_info.mask;
+
+       if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL))
+               fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX);
+}
+
+static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev)
+{
+       struct sk_buff *skb;
+
+       if (check_cmdresp_status(fmdev, &skb))
+               return;
+       /*
+        * This is last function in interrupt table to be executed.
+        * So, reset stage index to 0.
+        */
+       fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
+
+       /* Start processing any pending interrupt */
+       if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag))
+               fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
+       else
+               clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+}
+
+/* Returns availability of RDS data in internel buffer */
+u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
+                               struct poll_table_struct *pts)
+{
+       poll_wait(file, &fmdev->rx.rds.read_queue, pts);
+       if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx)
+               return 0;
+
+       return -EAGAIN;
+}
+
+/* Copies RDS data from internal buffer to user buffer */
+u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
+               u8 __user *buf, size_t count)
+{
+       u32 block_count;
+       unsigned long flags;
+       int ret;
+
+       if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) {
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+
+               ret = wait_event_interruptible(fmdev->rx.rds.read_queue,
+                               (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx));
+               if (ret)
+                       return -EINTR;
+       }
+
+       /* Calculate block count from byte count */
+       count /= 3;
+       block_count = 0;
+       ret = 0;
+
+       spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+
+       while (block_count < count) {
+               if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx)
+                       break;
+
+               if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
+                                       FM_RDS_BLK_SIZE))
+                       break;
+
+               fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE;
+               if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size)
+                       fmdev->rx.rds.rd_idx = 0;
+
+               block_count++;
+               buf += FM_RDS_BLK_SIZE;
+               ret += FM_RDS_BLK_SIZE;
+       }
+       spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+       return ret;
+}
+
+u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+{
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               return fm_rx_set_freq(fmdev, freq_to_set);
+
+       case FM_MODE_TX:
+               return fm_tx_set_freq(fmdev, freq_to_set);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
+{
+       if (fmdev->rx.freq == FM_UNDEFINED_FREQ) {
+               fmerr("RX frequency is not set\n");
+               return -EPERM;
+       }
+       if (cur_tuned_frq == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               *cur_tuned_frq = fmdev->rx.freq;
+               return 0;
+
+       case FM_MODE_TX:
+               *cur_tuned_frq = 0;     /* TODO : Change this later */
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+
+}
+
+u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
+{
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               return fm_rx_set_region(fmdev, region_to_set);
+
+       case FM_MODE_TX:
+               return fm_tx_set_region(fmdev, region_to_set);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               return fm_rx_set_mute_mode(fmdev, mute_mode_toset);
+
+       case FM_MODE_TX:
+               return fm_tx_set_mute_mode(fmdev, mute_mode_toset);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               return fm_rx_set_stereo_mono(fmdev, mode);
+
+       case FM_MODE_TX:
+               return fm_tx_set_stereo_mono(fmdev, mode);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+       switch (fmdev->curr_fmmode) {
+       case FM_MODE_RX:
+               return fm_rx_set_rds_mode(fmdev, rds_en_dis);
+
+       case FM_MODE_TX:
+               return fm_tx_set_rds_mode(fmdev, rds_en_dis);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Sends power off command to the chip */
+static u32 fm_power_down(struct fmdev *fmdev)
+{
+       u16 payload;
+       u32 ret;
+
+       if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+               fmerr("FM core is not ready\n");
+               return -EPERM;
+       }
+       if (fmdev->curr_fmmode == FM_MODE_OFF) {
+               fmdbg("FM chip is already in OFF state\n");
+               return 0;
+       }
+
+       payload = 0x0;
+       ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+               sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return fmc_release(fmdev);
+}
+
+/* Reads init command from FM firmware file and loads to the chip */
+static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
+{
+       const struct firmware *fw_entry;
+       struct bts_header *fw_header;
+       struct bts_action *action;
+       struct bts_action_delay *delay;
+       u8 *fw_data;
+       int ret, fw_len, cmd_cnt;
+
+       cmd_cnt = 0;
+       set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
+
+       ret = request_firmware(&fw_entry, fw_name,
+                               &fmdev->radio_dev->dev);
+       if (ret < 0) {
+               fmerr("Unable to read firmware(%s) content\n", fw_name);
+               return ret;
+       }
+       fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size);
+
+       fw_data = (void *)fw_entry->data;
+       fw_len = fw_entry->size;
+
+       fw_header = (struct bts_header *)fw_data;
+       if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
+               fmerr("%s not a legal TI firmware file\n", fw_name);
+               ret = -EINVAL;
+               goto rel_fw;
+       }
+       fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic);
+
+       /* Skip file header info , we already verified it */
+       fw_data += sizeof(struct bts_header);
+       fw_len -= sizeof(struct bts_header);
+
+       while (fw_data && fw_len > 0) {
+               action = (struct bts_action *)fw_data;
+
+               switch (action->type) {
+               case ACTION_SEND_COMMAND:       /* Send */
+                       if (fmc_send_cmd(fmdev, 0, 0, action->data,
+                                               action->size, NULL, NULL))
+                               goto rel_fw;
+
+                       cmd_cnt++;
+                       break;
+
+               case ACTION_DELAY:      /* Delay */
+                       delay = (struct bts_action_delay *)action->data;
+                       mdelay(delay->msec);
+                       break;
+               }
+
+               fw_data += (sizeof(struct bts_action) + (action->size));
+               fw_len -= (sizeof(struct bts_action) + (action->size));
+       }
+       fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt);
+rel_fw:
+       release_firmware(fw_entry);
+       clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
+
+       return ret;
+}
+
+/* Loads default RX configuration to the chip */
+static u32 load_default_rx_configuration(struct fmdev *fmdev)
+{
+       int ret;
+
+       ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME);
+       if (ret < 0)
+               return ret;
+
+       return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD);
+}
+
+/* Does FM power on sequence */
+static u32 fm_power_up(struct fmdev *fmdev, u8 mode)
+{
+       u16 payload, asic_id, asic_ver;
+       int resp_len, ret;
+       u8 fw_name[50];
+
+       if (mode >= FM_MODE_ENTRY_MAX) {
+               fmerr("Invalid firmware download option\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Initialize FM common module. FM GPIO toggling is
+        * taken care in Shared Transport driver.
+        */
+       ret = fmc_prepare(fmdev);
+       if (ret < 0) {
+               fmerr("Unable to prepare FM Common\n");
+               return ret;
+       }
+
+       payload = FM_ENABLE;
+       if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL))
+               goto rel;
+
+       /* Allow the chip to settle down in Channel-8 mode */
+       msleep(20);
+
+       if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL,
+                       sizeof(asic_id), &asic_id, &resp_len))
+               goto rel;
+
+       if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL,
+                       sizeof(asic_ver), &asic_ver, &resp_len))
+               goto rel;
+
+       fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n",
+               be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+       sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
+               be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+       ret = fm_download_firmware(fmdev, fw_name);
+       if (ret < 0) {
+               fmdbg("Failed to download firmware file %s\n", fw_name);
+               goto rel;
+       }
+       sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ?
+                       FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
+                       be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+       ret = fm_download_firmware(fmdev, fw_name);
+       if (ret < 0) {
+               fmdbg("Failed to download firmware file %s\n", fw_name);
+               goto rel;
+       } else
+               return ret;
+rel:
+       return fmc_release(fmdev);
+}
+
+/* Set FM Modes(TX, RX, OFF) */
+u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
+{
+       int ret = 0;
+
+       if (fm_mode >= FM_MODE_ENTRY_MAX) {
+               fmerr("Invalid FM mode\n");
+               return -EINVAL;
+       }
+       if (fmdev->curr_fmmode == fm_mode) {
+               fmdbg("Already fm is in mode(%d)\n", fm_mode);
+               return ret;
+       }
+
+       switch (fm_mode) {
+       case FM_MODE_OFF:       /* OFF Mode */
+               ret = fm_power_down(fmdev);
+               if (ret < 0) {
+                       fmerr("Failed to set OFF mode\n");
+                       return ret;
+               }
+               break;
+
+       case FM_MODE_TX:        /* TX Mode */
+       case FM_MODE_RX:        /* RX Mode */
+               /* Power down before switching to TX or RX mode */
+               if (fmdev->curr_fmmode != FM_MODE_OFF) {
+                       ret = fm_power_down(fmdev);
+                       if (ret < 0) {
+                               fmerr("Failed to set OFF mode\n");
+                               return ret;
+                       }
+                       msleep(30);
+               }
+               ret = fm_power_up(fmdev, fm_mode);
+               if (ret < 0) {
+                       fmerr("Failed to load firmware\n");
+                       return ret;
+               }
+       }
+       fmdev->curr_fmmode = fm_mode;
+
+       /* Set default configuration */
+       if (fmdev->curr_fmmode == FM_MODE_RX) {
+               fmdbg("Loading default rx configuration..\n");
+               ret = load_default_rx_configuration(fmdev);
+               if (ret < 0)
+                       fmerr("Failed to load default values\n");
+       }
+
+       return ret;
+}
+
+/* Returns current FM mode (TX, RX, OFF) */
+u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
+{
+       if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+               fmerr("FM core is not ready\n");
+               return -EPERM;
+       }
+       if (fmmode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *fmmode = fmdev->curr_fmmode;
+       return 0;
+}
+
+/* Called by ST layer when FM packet is available */
+static long fm_st_receive(void *arg, struct sk_buff *skb)
+{
+       struct fmdev *fmdev;
+
+       fmdev = (struct fmdev *)arg;
+
+       if (skb == NULL) {
+               fmerr("Invalid SKB received from ST\n");
+               return -EFAULT;
+       }
+
+       if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
+               fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb);
+               return -EINVAL;
+       }
+
+       memcpy(skb_push(skb, 1), &skb->cb[0], 1);
+       skb_queue_tail(&fmdev->rx_q, skb);
+       tasklet_schedule(&fmdev->rx_task);
+
+       return 0;
+}
+
+/*
+ * Called by ST layer to indicate protocol registration completion
+ * status.
+ */
+static void fm_st_reg_comp_cb(void *arg, char data)
+{
+       struct fmdev *fmdev;
+
+       fmdev = (struct fmdev *)arg;
+       fmdev->streg_cbdata = data;
+       complete(&wait_for_fmdrv_reg_comp);
+}
+
+/*
+ * This function will be called from FM V4L2 open function.
+ * Register with ST driver and initialize driver data.
+ */
+u32 fmc_prepare(struct fmdev *fmdev)
+{
+       static struct st_proto_s fm_st_proto;
+       u32 ret;
+
+       if (test_bit(FM_CORE_READY, &fmdev->flag)) {
+               fmdbg("FM Core is already up\n");
+               return 0;
+       }
+
+       memset(&fm_st_proto, 0, sizeof(fm_st_proto));
+       fm_st_proto.type = ST_FM;
+       fm_st_proto.recv = fm_st_receive;
+       fm_st_proto.match_packet = NULL;
+       fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb;
+       fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */
+       fm_st_proto.priv_data = fmdev;
+
+       ret = st_register(&fm_st_proto);
+       if (ret == -EINPROGRESS) {
+               init_completion(&wait_for_fmdrv_reg_comp);
+               fmdev->streg_cbdata = -EINPROGRESS;
+               fmdbg("%s waiting for ST reg completion signal\n", __func__);
+
+               ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
+                               FM_ST_REG_TIMEOUT);
+
+               if (!ret) {
+                       fmerr("Timeout(%d sec), didn't get reg "
+                                       "completion signal from ST\n",
+                                       jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
+                       return -ETIMEDOUT;
+               }
+               if (fmdev->streg_cbdata != 0) {
+                       fmerr("ST reg comp CB called with error "
+                                       "status %d\n", fmdev->streg_cbdata);
+                       return -EAGAIN;
+               }
+
+               ret = 0;
+       } else if (ret == -1) {
+               fmerr("st_register failed %d\n", ret);
+               return -EAGAIN;
+       }
+
+       if (fm_st_proto.write != NULL) {
+               g_st_write = fm_st_proto.write;
+       } else {
+               fmerr("Failed to get ST write func pointer\n");
+               ret = st_unregister(ST_FM);
+               if (ret < 0)
+                       fmerr("st_unregister failed %d\n", ret);
+               return -EAGAIN;
+       }
+
+       spin_lock_init(&fmdev->rds_buff_lock);
+       spin_lock_init(&fmdev->resp_skb_lock);
+
+       /* Initialize TX queue and TX tasklet */
+       skb_queue_head_init(&fmdev->tx_q);
+       tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev);
+
+       /* Initialize RX Queue and RX tasklet */
+       skb_queue_head_init(&fmdev->rx_q);
+       tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev);
+
+       fmdev->irq_info.stage = 0;
+       atomic_set(&fmdev->tx_cnt, 1);
+       fmdev->resp_comp = NULL;
+
+       init_timer(&fmdev->irq_info.timer);
+       fmdev->irq_info.timer.function = &int_timeout_handler;
+       fmdev->irq_info.timer.data = (unsigned long)fmdev;
+       /*TODO: add FM_STIC_EVENT later */
+       fmdev->irq_info.mask = FM_MAL_EVENT;
+
+       /* Region info */
+       memcpy(&fmdev->rx.region, &region_configs[default_radio_region],
+                       sizeof(struct region_info));
+
+       fmdev->rx.mute_mode = FM_MUTE_OFF;
+       fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
+       fmdev->rx.rds.flag = FM_RDS_DISABLE;
+       fmdev->rx.freq = FM_UNDEFINED_FREQ;
+       fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS;
+       fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF;
+       fmdev->irq_info.retry = 0;
+
+       fm_rx_reset_rds_cache(fmdev);
+       init_waitqueue_head(&fmdev->rx.rds.read_queue);
+
+       fm_rx_reset_station_info(fmdev);
+       set_bit(FM_CORE_READY, &fmdev->flag);
+
+       return ret;
+}
+
+/*
+ * This function will be called from FM V4L2 release function.
+ * Unregister from ST driver.
+ */
+u32 fmc_release(struct fmdev *fmdev)
+{
+       u32 ret;
+
+       if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+               fmdbg("FM Core is already down\n");
+               return 0;
+       }
+       /* Sevice pending read */
+       wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+       tasklet_kill(&fmdev->tx_task);
+       tasklet_kill(&fmdev->rx_task);
+
+       skb_queue_purge(&fmdev->tx_q);
+       skb_queue_purge(&fmdev->rx_q);
+
+       fmdev->resp_comp = NULL;
+       fmdev->rx.freq = 0;
+
+       ret = st_unregister(ST_FM);
+       if (ret < 0)
+               fmerr("Failed to de-register FM from ST %d\n", ret);
+       else
+               fmdbg("Successfully unregistered from ST\n");
+
+       clear_bit(FM_CORE_READY, &fmdev->flag);
+       return ret;
+}
+
+/*
+ * Module init function. Ask FM V4L module to register video device.
+ * Allocate memory for FM driver context and RX RDS buffer.
+ */
+static int __init fm_drv_init(void)
+{
+       struct fmdev *fmdev = NULL;
+       u32 ret = -ENOMEM;
+
+       fmdbg("FM driver version %s\n", FM_DRV_VERSION);
+
+       fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL);
+       if (NULL == fmdev) {
+               fmerr("Can't allocate operation structure memory\n");
+               return ret;
+       }
+       fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE;
+       fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
+       if (NULL == fmdev->rx.rds.buff) {
+               fmerr("Can't allocate rds ring buffer\n");
+               goto rel_dev;
+       }
+
+       ret = fm_v4l2_init_video_device(fmdev, radio_nr);
+       if (ret < 0)
+               goto rel_rdsbuf;
+
+       fmdev->irq_info.handlers = int_handler_table;
+       fmdev->curr_fmmode = FM_MODE_OFF;
+       fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF;
+       fmdev->tx_data.preemph = FM_TX_PREEMPH_50US;
+       return ret;
+
+rel_rdsbuf:
+       kfree(fmdev->rx.rds.buff);
+rel_dev:
+       kfree(fmdev);
+
+       return ret;
+}
+
+/* Module exit function. Ask FM V4L module to unregister video device */
+static void __exit fm_drv_exit(void)
+{
+       struct fmdev *fmdev = NULL;
+
+       fmdev = fm_v4l2_deinit_video_device();
+       if (fmdev != NULL) {
+               kfree(fmdev->rx.rds.buff);
+               kfree(fmdev);
+       }
+}
+
+module_init(fm_drv_init);
+module_exit(fm_drv_exit);
+
+/* ------------- Module Info ------------- */
+MODULE_AUTHOR("Manjunatha Halli <manjunatha_halli@ti.com>");
+MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION);
+MODULE_VERSION(FM_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h
new file mode 100644 (file)
index 0000000..427c416
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  FM Common module header file
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FMDRV_COMMON_H
+#define _FMDRV_COMMON_H
+
+#define FM_ST_REG_TIMEOUT   msecs_to_jiffies(6000)     /* 6 sec */
+#define FM_PKT_LOGICAL_CHAN_NUMBER  0x08   /* Logical channel 8 */
+
+#define REG_RD       0x1
+#define REG_WR      0x0
+
+struct fm_reg_table {
+       u8 opcode;
+       u8 type;
+       u8 *name;
+};
+
+#define STEREO_GET               0
+#define RSSI_LVL_GET             1
+#define IF_COUNT_GET             2
+#define FLAG_GET                 3
+#define RDS_SYNC_GET             4
+#define RDS_DATA_GET             5
+#define FREQ_SET                 10
+#define AF_FREQ_SET              11
+#define MOST_MODE_SET            12
+#define MOST_BLEND_SET           13
+#define DEMPH_MODE_SET           14
+#define SEARCH_LVL_SET           15
+#define BAND_SET                 16
+#define MUTE_STATUS_SET          17
+#define RDS_PAUSE_LVL_SET        18
+#define RDS_PAUSE_DUR_SET        19
+#define RDS_MEM_SET              20
+#define RDS_BLK_B_SET            21
+#define RDS_MSK_B_SET            22
+#define RDS_PI_MASK_SET          23
+#define RDS_PI_SET               24
+#define RDS_SYSTEM_SET           25
+#define INT_MASK_SET             26
+#define SEARCH_DIR_SET           27
+#define VOLUME_SET               28
+#define AUDIO_ENABLE_SET         29
+#define PCM_MODE_SET             30
+#define I2S_MODE_CONFIG_SET      31
+#define POWER_SET                32
+#define INTX_CONFIG_SET          33
+#define PULL_EN_SET              34
+#define HILO_SET                 35
+#define SWITCH2FREF              36
+#define FREQ_DRIFT_REPORT        37
+
+#define PCE_GET                  40
+#define FIRM_VER_GET             41
+#define ASIC_VER_GET             42
+#define ASIC_ID_GET              43
+#define MAN_ID_GET               44
+#define TUNER_MODE_SET           45
+#define STOP_SEARCH              46
+#define RDS_CNTRL_SET            47
+
+#define WRITE_HARDWARE_REG       100
+#define CODE_DOWNLOAD            101
+#define RESET                    102
+
+#define FM_POWER_MODE            254
+#define FM_INTERRUPT             255
+
+/* Transmitter API */
+
+#define CHANL_SET                55
+#define CHANL_BW_SET           56
+#define REF_SET                  57
+#define POWER_ENB_SET            90
+#define POWER_ATT_SET            58
+#define POWER_LEV_SET            59
+#define AUDIO_DEV_SET            60
+#define PILOT_DEV_SET            61
+#define RDS_DEV_SET              62
+#define TX_BAND_SET              65
+#define PUPD_SET                 91
+#define AUDIO_IO_SET             63
+#define PREMPH_SET               64
+#define MONO_SET                 66
+#define MUTE                     92
+#define MPX_LMT_ENABLE           67
+#define PI_SET                   93
+#define ECC_SET                  69
+#define PTY                      70
+#define AF                       71
+#define DISPLAY_MODE             74
+#define RDS_REP_SET              77
+#define RDS_CONFIG_DATA_SET      98
+#define RDS_DATA_SET             99
+#define RDS_DATA_ENB             94
+#define TA_SET                   78
+#define TP_SET                   79
+#define DI_SET                   80
+#define MS_SET                   81
+#define PS_SCROLL_SPEED          82
+#define TX_AUDIO_LEVEL_TEST      96
+#define TX_AUDIO_LEVEL_TEST_THRESHOLD    73
+#define TX_AUDIO_INPUT_LEVEL_RANGE_SET   54
+#define RX_ANTENNA_SELECT        87
+#define I2C_DEV_ADDR_SET         86
+#define REF_ERR_CALIB_PARAM_SET          88
+#define REF_ERR_CALIB_PERIODICITY_SET    89
+#define SOC_INT_TRIGGER                  52
+#define SOC_AUDIO_PATH_SET               83
+#define SOC_PCMI_OVERRIDE                84
+#define SOC_I2S_OVERRIDE         85
+#define RSSI_BLOCK_SCAN_FREQ_SET 95
+#define RSSI_BLOCK_SCAN_START    97
+#define RSSI_BLOCK_SCAN_DATA_GET  5
+#define READ_FMANT_TUNE_VALUE            104
+
+/* SKB helpers */
+struct fm_skb_cb {
+       __u8 fm_op;
+       struct completion *completion;
+};
+
+#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb))
+
+/* FM Channel-8 command message format */
+struct fm_cmd_msg_hdr {
+       __u8 hdr;               /* Logical Channel-8 */
+       __u8 len;               /* Number of bytes follows */
+       __u8 op;                /* FM Opcode */
+       __u8 rd_wr;             /* Read/Write command */
+       __u8 dlen;              /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_CMD_MSG_HDR_SIZE    5       /* sizeof(struct fm_cmd_msg_hdr) */
+
+/* FM Channel-8 event messgage format */
+struct fm_event_msg_hdr {
+       __u8 header;            /* Logical Channel-8 */
+       __u8 len;               /* Number of bytes follows */
+       __u8 status;            /* Event status */
+       __u8 num_fm_hci_cmds;   /* Number of pkts the host allowed to send */
+       __u8 op;                /* FM Opcode */
+       __u8 rd_wr;             /* Read/Write command */
+       __u8 dlen;              /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_EVT_MSG_HDR_SIZE     7      /* sizeof(struct fm_event_msg_hdr) */
+
+/* TI's magic number in firmware file */
+#define FM_FW_FILE_HEADER_MAGIC             0x42535442
+
+#define FM_ENABLE   1
+#define FM_DISABLE  0
+
+/* FLAG_GET register bits */
+#define FM_FR_EVENT            (1 << 0)
+#define FM_BL_EVENT            (1 << 1)
+#define FM_RDS_EVENT           (1 << 2)
+#define FM_BBLK_EVENT          (1 << 3)
+#define FM_LSYNC_EVENT         (1 << 4)
+#define FM_LEV_EVENT           (1 << 5)
+#define FM_IFFR_EVENT          (1 << 6)
+#define FM_PI_EVENT            (1 << 7)
+#define FM_PD_EVENT            (1 << 8)
+#define FM_STIC_EVENT          (1 << 9)
+#define FM_MAL_EVENT           (1 << 10)
+#define FM_POW_ENB_EVENT       (1 << 11)
+
+/*
+ * Firmware files of FM. ASIC ID and ASIC version will be appened to this,
+ * later.
+ */
+#define FM_FMC_FW_FILE_START      ("fmc_ch8")
+#define FM_RX_FW_FILE_START       ("fm_rx_ch8")
+#define FM_TX_FW_FILE_START       ("fm_tx_ch8")
+
+#define FM_UNDEFINED_FREQ                 0xFFFFFFFF
+
+/* Band types */
+#define FM_BAND_EUROPE_US      0
+#define FM_BAND_JAPAN          1
+
+/* Seek directions */
+#define FM_SEARCH_DIRECTION_DOWN       0
+#define FM_SEARCH_DIRECTION_UP         1
+
+/* Tunner modes */
+#define FM_TUNER_STOP_SEARCH_MODE      0
+#define FM_TUNER_PRESET_MODE           1
+#define FM_TUNER_AUTONOMOUS_SEARCH_MODE        2
+#define FM_TUNER_AF_JUMP_MODE          3
+
+/* Min and Max volume */
+#define FM_RX_VOLUME_MIN       0
+#define FM_RX_VOLUME_MAX       70
+
+/* Volume gain step */
+#define FM_RX_VOLUME_GAIN_STEP 0x370
+
+/* Mute modes */
+#define        FM_MUTE_ON              0
+#define FM_MUTE_OFF            1
+#define        FM_MUTE_ATTENUATE       2
+
+#define FM_RX_UNMUTE_MODE              0x00
+#define FM_RX_RF_DEP_MODE              0x01
+#define FM_RX_AC_MUTE_MODE             0x02
+#define FM_RX_HARD_MUTE_LEFT_MODE      0x04
+#define FM_RX_HARD_MUTE_RIGHT_MODE     0x08
+#define FM_RX_SOFT_MUTE_FORCE_MODE     0x10
+
+/* RF dependent mute mode */
+#define FM_RX_RF_DEPENDENT_MUTE_ON     1
+#define FM_RX_RF_DEPENDENT_MUTE_OFF    0
+
+/* RSSI threshold min and max */
+#define FM_RX_RSSI_THRESHOLD_MIN       -128
+#define FM_RX_RSSI_THRESHOLD_MAX       127
+
+/* Stereo/Mono mode */
+#define FM_STEREO_MODE         0
+#define FM_MONO_MODE           1
+#define FM_STEREO_SOFT_BLEND   1
+
+/* FM RX De-emphasis filter modes */
+#define FM_RX_EMPHASIS_FILTER_50_USEC  0
+#define FM_RX_EMPHASIS_FILTER_75_USEC  1
+
+/* FM RDS modes */
+#define FM_RDS_DISABLE 0
+#define FM_RDS_ENABLE  1
+
+#define FM_NO_PI_CODE  0
+
+/* FM and RX RDS block enable/disable  */
+#define FM_RX_PWR_SET_FM_ON_RDS_OFF            0x1
+#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON                0x3
+#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF       0x0
+
+/* RX RDS */
+#define FM_RX_RDS_FLUSH_FIFO           0x1
+#define FM_RX_RDS_FIFO_THRESHOLD       64      /* tuples */
+#define FM_RDS_BLK_SIZE                3       /* 3 bytes */
+
+/* RDS block types */
+#define FM_RDS_BLOCK_A         0
+#define FM_RDS_BLOCK_B         1
+#define FM_RDS_BLOCK_C         2
+#define FM_RDS_BLOCK_Ctag      3
+#define FM_RDS_BLOCK_D         4
+#define FM_RDS_BLOCK_E         5
+
+#define FM_RDS_BLK_IDX_A               0
+#define FM_RDS_BLK_IDX_B               1
+#define FM_RDS_BLK_IDX_C               2
+#define FM_RDS_BLK_IDX_D               3
+#define FM_RDS_BLK_IDX_UNKNOWN 0xF0
+
+#define FM_RDS_STATUS_ERR_MASK 0x18
+
+/*
+ * Represents an RDS group type & version.
+ * There are 15 groups, each group has 2 versions: A and B.
+ */
+#define FM_RDS_GROUP_TYPE_MASK_0A          ((unsigned long)1<<0)
+#define FM_RDS_GROUP_TYPE_MASK_0B          ((unsigned long)1<<1)
+#define FM_RDS_GROUP_TYPE_MASK_1A          ((unsigned long)1<<2)
+#define FM_RDS_GROUP_TYPE_MASK_1B          ((unsigned long)1<<3)
+#define FM_RDS_GROUP_TYPE_MASK_2A          ((unsigned long)1<<4)
+#define FM_RDS_GROUP_TYPE_MASK_2B          ((unsigned long)1<<5)
+#define FM_RDS_GROUP_TYPE_MASK_3A          ((unsigned long)1<<6)
+#define FM_RDS_GROUP_TYPE_MASK_3B           ((unsigned long)1<<7)
+#define FM_RDS_GROUP_TYPE_MASK_4A          ((unsigned long)1<<8)
+#define FM_RDS_GROUP_TYPE_MASK_4B          ((unsigned long)1<<9)
+#define FM_RDS_GROUP_TYPE_MASK_5A          ((unsigned long)1<<10)
+#define FM_RDS_GROUP_TYPE_MASK_5B          ((unsigned long)1<<11)
+#define FM_RDS_GROUP_TYPE_MASK_6A          ((unsigned long)1<<12)
+#define FM_RDS_GROUP_TYPE_MASK_6B          ((unsigned long)1<<13)
+#define FM_RDS_GROUP_TYPE_MASK_7A          ((unsigned long)1<<14)
+#define FM_RDS_GROUP_TYPE_MASK_7B          ((unsigned long)1<<15)
+#define FM_RDS_GROUP_TYPE_MASK_8A           ((unsigned long)1<<16)
+#define FM_RDS_GROUP_TYPE_MASK_8B          ((unsigned long)1<<17)
+#define FM_RDS_GROUP_TYPE_MASK_9A          ((unsigned long)1<<18)
+#define FM_RDS_GROUP_TYPE_MASK_9B          ((unsigned long)1<<19)
+#define FM_RDS_GROUP_TYPE_MASK_10A         ((unsigned long)1<<20)
+#define FM_RDS_GROUP_TYPE_MASK_10B         ((unsigned long)1<<21)
+#define FM_RDS_GROUP_TYPE_MASK_11A         ((unsigned long)1<<22)
+#define FM_RDS_GROUP_TYPE_MASK_11B         ((unsigned long)1<<23)
+#define FM_RDS_GROUP_TYPE_MASK_12A         ((unsigned long)1<<24)
+#define FM_RDS_GROUP_TYPE_MASK_12B         ((unsigned long)1<<25)
+#define FM_RDS_GROUP_TYPE_MASK_13A         ((unsigned long)1<<26)
+#define FM_RDS_GROUP_TYPE_MASK_13B         ((unsigned long)1<<27)
+#define FM_RDS_GROUP_TYPE_MASK_14A         ((unsigned long)1<<28)
+#define FM_RDS_GROUP_TYPE_MASK_14B         ((unsigned long)1<<29)
+#define FM_RDS_GROUP_TYPE_MASK_15A         ((unsigned long)1<<30)
+#define FM_RDS_GROUP_TYPE_MASK_15B         ((unsigned long)1<<31)
+
+/* RX Alternate Frequency info */
+#define FM_RDS_MIN_AF                    1
+#define FM_RDS_MAX_AF                  204
+#define FM_RDS_MAX_AF_JAPAN            140
+#define FM_RDS_1_AF_FOLLOWS            225
+#define FM_RDS_25_AF_FOLLOWS           249
+
+/* RDS system type (RDS/RBDS) */
+#define FM_RDS_SYSTEM_RDS              0
+#define FM_RDS_SYSTEM_RBDS             1
+
+/* AF on/off */
+#define FM_RX_RDS_AF_SWITCH_MODE_ON    1
+#define FM_RX_RDS_AF_SWITCH_MODE_OFF   0
+
+/* Retry count when interrupt process goes wrong */
+#define FM_IRQ_TIMEOUT_RETRY_MAX       5       /* 5 times */
+
+/* Audio IO set values */
+#define FM_RX_AUDIO_ENABLE_I2S 0x01
+#define FM_RX_AUDIO_ENABLE_ANALOG      0x02
+#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG      0x03
+#define FM_RX_AUDIO_ENABLE_DISABLE     0x00
+
+/* HI/LO set values */
+#define FM_RX_IFFREQ_TO_HI_SIDE                0x0
+#define FM_RX_IFFREQ_TO_LO_SIDE                0x1
+#define FM_RX_IFFREQ_HILO_AUTOMATIC    0x2
+
+/*
+ * Default RX mode configuration. Chip will be configured
+ * with this default values after loading RX firmware.
+ */
+#define FM_DEFAULT_RX_VOLUME           10
+#define FM_DEFAULT_RSSI_THRESHOLD      3
+
+/* Range for TX power level in units for dB/uV */
+#define FM_PWR_LVL_LOW                 91
+#define FM_PWR_LVL_HIGH                        122
+
+/* Chip specific default TX power level value */
+#define FM_PWR_LVL_DEF                 4
+
+/* FM TX Pre-emphasis filter values */
+#define FM_TX_PREEMPH_OFF              1
+#define FM_TX_PREEMPH_50US             0
+#define FM_TX_PREEMPH_75US             2
+
+/* FM TX antenna impedence values */
+#define FM_TX_ANT_IMP_50               0
+#define FM_TX_ANT_IMP_200              1
+#define FM_TX_ANT_IMP_500              2
+
+/* Functions exported by FM common sub-module */
+u32 fmc_prepare(struct fmdev *);
+u32 fmc_release(struct fmdev *);
+
+void fmc_update_region_info(struct fmdev *, u8);
+u32 fmc_send_cmd(struct fmdev *, u8, u16,
+                               void *, unsigned int, void *, int *);
+u32 fmc_is_rds_data_available(struct fmdev *, struct file *,
+                               struct poll_table_struct *);
+u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
+                                       u8 __user *, size_t);
+
+u32 fmc_set_freq(struct fmdev *, u32);
+u32 fmc_set_mode(struct fmdev *, u8);
+u32 fmc_set_region(struct fmdev *, u8);
+u32 fmc_set_mute_mode(struct fmdev *, u8);
+u32 fmc_set_stereo_mono(struct fmdev *, u16);
+u32 fmc_set_rds_mode(struct fmdev *, u8);
+
+u32 fmc_get_freq(struct fmdev *, u32 *);
+u32 fmc_get_region(struct fmdev *, u8 *);
+u32 fmc_get_mode(struct fmdev *, u8 *);
+
+/*
+ * channel spacing
+ */
+#define FM_CHANNEL_SPACING_50KHZ 1
+#define FM_CHANNEL_SPACING_100KHZ 2
+#define FM_CHANNEL_SPACING_200KHZ 4
+#define FM_FREQ_MUL 50
+
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
new file mode 100644 (file)
index 0000000..ec529b5
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  This sub-module of FM driver implements FM RX functionality.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *  Author: Raja Mani <raja_mani@ti.com>
+ *  Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_common.h"
+#include "fmdrv_rx.h"
+
+void fm_rx_reset_rds_cache(struct fmdev *fmdev)
+{
+       fmdev->rx.rds.flag = FM_RDS_DISABLE;
+       fmdev->rx.rds.last_blk_idx = 0;
+       fmdev->rx.rds.wr_idx = 0;
+       fmdev->rx.rds.rd_idx = 0;
+
+       if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+               fmdev->irq_info.mask |= FM_LEV_EVENT;
+}
+
+void fm_rx_reset_station_info(struct fmdev *fmdev)
+{
+       fmdev->rx.stat_info.picode = FM_NO_PI_CODE;
+       fmdev->rx.stat_info.afcache_size = 0;
+       fmdev->rx.stat_info.af_list_max = 0;
+}
+
+u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
+{
+       unsigned long timeleft;
+       u16 payload, curr_frq, intr_flag;
+       u32 curr_frq_in_khz;
+       u32 ret, resp_len;
+
+       if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
+               fmerr("Invalid frequency %d\n", freq);
+               return -EINVAL;
+       }
+
+       /* Set audio enable */
+       payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG;
+
+       ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Set hilo to automatic selection */
+       payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
+       ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Calculate frequency index and set*/
+       payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+       ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Read flags - just to clear any pending interrupts if we had */
+       ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Enable FR, BL interrupts */
+       intr_flag = fmdev->irq_info.mask;
+       fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
+       payload = fmdev->irq_info.mask;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Start tune */
+       payload = FM_TUNER_PRESET_MODE;
+       ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               goto exit;
+
+       /* Wait for tune ended interrupt */
+       init_completion(&fmdev->maintask_comp);
+       timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+                       FM_DRV_TX_TIMEOUT);
+       if (!timeleft) {
+               fmerr("Timeout(%d sec),didn't get tune ended int\n",
+                          jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+               ret = -ETIMEDOUT;
+               goto exit;
+       }
+
+       /* Read freq back to confirm */
+       ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len);
+       if (ret < 0)
+               goto exit;
+
+       curr_frq = be16_to_cpu(curr_frq);
+       curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
+
+       if (curr_frq_in_khz != freq) {
+               pr_info("Frequency is set to (%d) but "
+                          "requested freq is (%d)\n", curr_frq_in_khz, freq);
+       }
+
+       /* Update local cache  */
+       fmdev->rx.freq = curr_frq_in_khz;
+exit:
+       /* Re-enable default FM interrupts */
+       fmdev->irq_info.mask = intr_flag;
+       payload = fmdev->irq_info.mask;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Reset RDS cache and current station pointers */
+       fm_rx_reset_rds_cache(fmdev);
+       fm_rx_reset_station_info(fmdev);
+
+       return ret;
+}
+
+static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
+{
+       u16 payload;
+       u32 ret;
+
+       if (spacing > 0 && spacing <= 50000)
+               spacing = FM_CHANNEL_SPACING_50KHZ;
+       else if (spacing > 50000 && spacing <= 100000)
+               spacing = FM_CHANNEL_SPACING_100KHZ;
+       else
+               spacing = FM_CHANNEL_SPACING_200KHZ;
+
+       /* set channel spacing */
+       payload = spacing;
+       ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL;
+
+       return ret;
+}
+
+u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
+               u32 wrap_around, u32 spacing)
+{
+       u32 resp_len;
+       u16 curr_frq, next_frq, last_frq;
+       u16 payload, int_reason, intr_flag;
+       u16 offset, space_idx;
+       unsigned long timeleft;
+       u32 ret;
+
+       /* Set channel spacing */
+       ret = fm_rx_set_channel_spacing(fmdev, spacing);
+       if (ret < 0) {
+               fmerr("Failed to set channel spacing\n");
+               return ret;
+       }
+
+       /* Read the current frequency from chip */
+       ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
+                       sizeof(curr_frq), &curr_frq, &resp_len);
+       if (ret < 0)
+               return ret;
+
+       curr_frq = be16_to_cpu(curr_frq);
+       last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+       /* Check the offset in order to be aligned to the channel spacing*/
+       space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL;
+       offset = curr_frq % space_idx;
+
+       next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ :
+                               curr_frq - space_idx /* Seek Down */ ;
+
+       /*
+        * Add or subtract offset in order to stay aligned to the channel
+        * spacing.
+        */
+       if ((short)next_frq < 0)
+               next_frq = last_frq - offset;
+       else if (next_frq > last_frq)
+               next_frq = 0 + offset;
+
+again:
+       /* Set calculated next frequency to perform seek */
+       payload = next_frq;
+       ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Set search direction (0:Seek Down, 1:Seek Up) */
+       payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN);
+       ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Read flags - just to clear any pending interrupts if we had */
+       ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Enable FR, BL interrupts */
+       intr_flag = fmdev->irq_info.mask;
+       fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
+       payload = fmdev->irq_info.mask;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Start seek */
+       payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
+       ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Wait for tune ended/band limit reached interrupt */
+       init_completion(&fmdev->maintask_comp);
+       timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+                       FM_DRV_RX_SEEK_TIMEOUT);
+       if (!timeleft) {
+               fmerr("Timeout(%d sec),didn't get tune ended int\n",
+                          jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
+               return -ETIMEDOUT;
+       }
+
+       int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
+
+       /* Re-enable default FM interrupts */
+       fmdev->irq_info.mask = intr_flag;
+       payload = fmdev->irq_info.mask;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       if (int_reason & FM_BL_EVENT) {
+               if (wrap_around == 0) {
+                       fmdev->rx.freq = seek_upward ?
+                               fmdev->rx.region.top_freq :
+                               fmdev->rx.region.bot_freq;
+               } else {
+                       fmdev->rx.freq = seek_upward ?
+                               fmdev->rx.region.bot_freq :
+                               fmdev->rx.region.top_freq;
+                       /* Calculate frequency index to write */
+                       next_frq = (fmdev->rx.freq -
+                                       fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+                       goto again;
+               }
+       } else {
+               /* Read freq to know where operation tune operation stopped */
+               ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
+                               &curr_frq, &resp_len);
+               if (ret < 0)
+                       return ret;
+
+               curr_frq = be16_to_cpu(curr_frq);
+               fmdev->rx.freq = (fmdev->rx.region.bot_freq +
+                               ((u32)curr_frq * FM_FREQ_MUL));
+
+       }
+       /* Reset RDS cache and current station pointers */
+       fm_rx_reset_rds_cache(fmdev);
+       fm_rx_reset_station_info(fmdev);
+
+       return ret;
+}
+
+u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) {
+               fmerr("Volume is not within(%d-%d) range\n",
+                          FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
+               return -EINVAL;
+       }
+       vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
+
+       payload = vol_to_set;
+       ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.volume = vol_to_set;
+       return ret;
+}
+
+/* Get volume */
+u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_vol == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP;
+
+       return 0;
+}
+
+/* To get current band's bottom and top frequency */
+u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
+{
+       if (bot_freq != NULL)
+               *bot_freq = fmdev->rx.region.bot_freq;
+
+       if (top_freq != NULL)
+               *top_freq = fmdev->rx.region.top_freq;
+
+       return 0;
+}
+
+/* Returns current band index (0-Europe/US; 1-Japan) */
+void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
+{
+       *region = fmdev->rx.region.fm_band;
+}
+
+/* Sets band (0-Europe/US; 1-Japan) */
+u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
+{
+       u16 payload;
+       u32 new_frq = 0;
+       u32 ret;
+
+       if (region_to_set != FM_BAND_EUROPE_US &&
+           region_to_set != FM_BAND_JAPAN) {
+               fmerr("Invalid band\n");
+               return -EINVAL;
+       }
+
+       if (fmdev->rx.region.fm_band == region_to_set) {
+               fmerr("Requested band is already configured\n");
+               return 0;
+       }
+
+       /* Send cmd to set the band  */
+       payload = (u16)region_to_set;
+       ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmc_update_region_info(fmdev, region_to_set);
+
+       /* Check whether current RX frequency is within band boundary */
+       if (fmdev->rx.freq < fmdev->rx.region.bot_freq)
+               new_frq = fmdev->rx.region.bot_freq;
+       else if (fmdev->rx.freq > fmdev->rx.region.top_freq)
+               new_frq = fmdev->rx.region.top_freq;
+
+       if (new_frq) {
+               fmdbg("Current freq is not within band limit boundary,"
+                               "switching to %d KHz\n", new_frq);
+                /* Current RX frequency is not in range. So, update it */
+               ret = fm_rx_set_freq(fmdev, new_frq);
+       }
+
+       return ret;
+}
+
+/* Reads current mute mode (Mute Off/On/Attenuate)*/
+u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_mute_mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_mute_mode = fmdev->rx.mute_mode;
+
+       return 0;
+}
+
+static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
+{
+       u16 payload, muteval;
+       u32 ret;
+
+       muteval = 0;
+       switch (fmdev->rx.mute_mode) {
+       case FM_MUTE_ON:
+               muteval = FM_RX_AC_MUTE_MODE;
+               break;
+
+       case FM_MUTE_OFF:
+               muteval = FM_RX_UNMUTE_MODE;
+               break;
+
+       case FM_MUTE_ATTENUATE:
+               muteval = FM_RX_SOFT_MUTE_FORCE_MODE;
+               break;
+       }
+       if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
+               muteval |= FM_RX_RF_DEP_MODE;
+       else
+               muteval &= ~FM_RX_RF_DEP_MODE;
+
+       payload = muteval;
+       ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/* Configures mute mode (Mute Off/On/Attenuate) */
+u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+       u8 org_state;
+       u32 ret;
+
+       if (fmdev->rx.mute_mode == mute_mode_toset)
+               return 0;
+
+       org_state = fmdev->rx.mute_mode;
+       fmdev->rx.mute_mode = mute_mode_toset;
+
+       ret = fm_config_rx_mute_reg(fmdev);
+       if (ret < 0) {
+               fmdev->rx.mute_mode = org_state;
+               return ret;
+       }
+
+       return 0;
+}
+
+/* Gets RF dependent soft mute mode enable/disable status */
+u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_mute_mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_mute_mode = fmdev->rx.rf_depend_mute;
+
+       return 0;
+}
+
+/* Sets RF dependent soft mute mode */
+u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
+{
+       u8 org_state;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
+           rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
+               fmerr("Invalid RF dependent soft mute\n");
+               return -EINVAL;
+       }
+       if (fmdev->rx.rf_depend_mute == rfdepend_mute)
+               return 0;
+
+       org_state = fmdev->rx.rf_depend_mute;
+       fmdev->rx.rf_depend_mute = rfdepend_mute;
+
+       ret = fm_config_rx_mute_reg(fmdev);
+       if (ret < 0) {
+               fmdev->rx.rf_depend_mute = org_state;
+               return ret;
+       }
+
+       return 0;
+}
+
+/* Returns the signal strength level of current channel */
+u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
+{
+       u16 curr_rssi_lel;
+       u32 resp_len;
+       u32 ret;
+
+       if (rssilvl == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+       /* Read current RSSI level */
+       ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
+                       &curr_rssi_lel, &resp_len);
+       if (ret < 0)
+               return ret;
+
+       *rssilvl = be16_to_cpu(curr_rssi_lel);
+
+       return 0;
+}
+
+/*
+ * Sets the signal strength level that once reached
+ * will stop the auto search process
+ */
+u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
+{
+       u16 payload;
+       u32 ret;
+
+       if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
+                       rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
+               fmerr("Invalid RSSI threshold level\n");
+               return -EINVAL;
+       }
+       payload = (u16)rssi_lvl_toset;
+       ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.rssi_threshold = rssi_lvl_toset;
+
+       return 0;
+}
+
+/* Returns current RX RSSI threshold value */
+u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_rssi_lvl == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_rssi_lvl = fmdev->rx.rssi_threshold;
+
+       return 0;
+}
+
+/* Sets RX stereo/mono modes */
+u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+       u16 payload;
+       u32 ret;
+
+       if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
+               fmerr("Invalid mode\n");
+               return -EINVAL;
+       }
+
+       /* Set stereo/mono mode */
+       payload = (u16)mode;
+       ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Set stereo blending mode */
+       payload = FM_STEREO_SOFT_BLEND;
+       ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/* Gets current RX stereo/mono mode */
+u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
+{
+       u16 curr_mode;
+       u32 ret, resp_len;
+
+       if (mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
+                       &curr_mode, &resp_len);
+       if (ret < 0)
+               return ret;
+
+       *mode = be16_to_cpu(curr_mode);
+
+       return 0;
+}
+
+/* Choose RX de-emphasis filter mode (50us/75us) */
+u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
+                       mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
+               fmerr("Invalid rx de-emphasis mode (%d)\n", mode);
+               return -EINVAL;
+       }
+
+       payload = mode;
+       ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.deemphasis_mode = mode;
+
+       return 0;
+}
+
+/* Gets current RX de-emphasis filter mode */
+u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_deemphasis_mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_deemphasis_mode = fmdev->rx.deemphasis_mode;
+
+       return 0;
+}
+
+/* Enable/Disable RX RDS */
+u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+       u16 payload;
+       u32 ret;
+
+       if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
+               fmerr("Invalid rds option\n");
+               return -EINVAL;
+       }
+
+       if (rds_en_dis == FM_RDS_ENABLE
+           && fmdev->rx.rds.flag == FM_RDS_DISABLE) {
+               /* Turn on RX RDS and RDS circuit */
+               payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON;
+               ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+                               sizeof(payload), NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Clear and reset RDS FIFO */
+               payload = FM_RX_RDS_FLUSH_FIFO;
+               ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
+               sizeof(payload), NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Read flags - just to clear any pending interrupts. */
+               ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
+                               NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Set RDS FIFO threshold value */
+               payload = FM_RX_RDS_FIFO_THRESHOLD;
+               ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
+               sizeof(payload), NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Enable RDS interrupt */
+               fmdev->irq_info.mask |= FM_RDS_EVENT;
+               payload = fmdev->irq_info.mask;
+               ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                               sizeof(payload), NULL, NULL);
+               if (ret < 0) {
+                       fmdev->irq_info.mask &= ~FM_RDS_EVENT;
+                       return ret;
+               }
+
+               /* Update our local flag */
+               fmdev->rx.rds.flag = FM_RDS_ENABLE;
+       } else if (rds_en_dis == FM_RDS_DISABLE
+                  && fmdev->rx.rds.flag == FM_RDS_ENABLE) {
+               /* Turn off RX RDS */
+               payload = FM_RX_PWR_SET_FM_ON_RDS_OFF;
+               ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+                               sizeof(payload), NULL, NULL);
+               if (ret < 0)
+                       return ret;
+
+               /* Reset RDS pointers */
+               fmdev->rx.rds.last_blk_idx = 0;
+               fmdev->rx.rds.wr_idx = 0;
+               fmdev->rx.rds.rd_idx = 0;
+               fm_rx_reset_station_info(fmdev);
+
+               /* Update RDS local cache */
+               fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
+               fmdev->rx.rds.flag = FM_RDS_DISABLE;
+       }
+
+       return 0;
+}
+
+/* Returns current RX RDS enable/disable status */
+u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (curr_rds_en_dis == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *curr_rds_en_dis = fmdev->rx.rds.flag;
+
+       return 0;
+}
+
+/* Sets RDS operation mode (RDS/RDBS) */
+u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
+               fmerr("Invalid rds mode\n");
+               return -EINVAL;
+       }
+       /* Set RDS operation mode */
+       payload = (u16)rds_mode;
+       ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.rds_mode = rds_mode;
+
+       return 0;
+}
+
+/* Returns current RDS operation mode */
+u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (rds_mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *rds_mode = fmdev->rx.rds_mode;
+
+       return 0;
+}
+
+/* Configures Alternate Frequency switch mode */
+u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
+           af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
+               fmerr("Invalid af mode\n");
+               return -EINVAL;
+       }
+       /* Enable/disable low RSSI interrupt based on af_mode */
+       if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+               fmdev->irq_info.mask |= FM_LEV_EVENT;
+       else
+               fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+       payload = fmdev->irq_info.mask;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->rx.af_mode = af_mode;
+
+       return 0;
+}
+
+/* Returns Alternate Frequency switch status */
+u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
+{
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       if (af_mode == NULL) {
+               fmerr("Invalid memory\n");
+               return -ENOMEM;
+       }
+
+       *af_mode = fmdev->rx.af_mode;
+
+       return 0;
+}
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h
new file mode 100644 (file)
index 0000000..329e62f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  FM RX module header.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FMDRV_RX_H
+#define _FMDRV_RX_H
+
+u32 fm_rx_set_freq(struct fmdev *, u32);
+u32 fm_rx_set_mute_mode(struct fmdev *, u8);
+u32 fm_rx_set_stereo_mono(struct fmdev *, u16);
+u32 fm_rx_set_rds_mode(struct fmdev *, u8);
+u32 fm_rx_set_rds_system(struct fmdev *, u8);
+u32 fm_rx_set_volume(struct fmdev *, u16);
+u32 fm_rx_set_rssi_threshold(struct fmdev *, short);
+u32 fm_rx_set_region(struct fmdev *, u8);
+u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
+u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16);
+u32 fm_rx_set_af_switch(struct fmdev *, u8);
+
+void fm_rx_reset_rds_cache(struct fmdev *);
+void fm_rx_reset_station_info(struct fmdev *);
+
+u32 fm_rx_seek(struct fmdev *, u32, u32, u32);
+
+u32 fm_rx_get_rds_mode(struct fmdev *, u8 *);
+u32 fm_rx_get_rds_system(struct fmdev *, u8 *);
+u32 fm_rx_get_mute_mode(struct fmdev *, u8 *);
+u32 fm_rx_get_volume(struct fmdev *, u16 *);
+u32 fm_rx_get_band_freq_range(struct fmdev *,
+                                       u32 *, u32 *);
+u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *);
+u32 fm_rx_get_rssi_level(struct fmdev *, u16 *);
+u32 fm_rx_get_rssi_threshold(struct fmdev *, short *);
+u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
+u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *);
+u32 fm_rx_get_af_switch(struct fmdev *, u8 *);
+void fm_rx_get_region(struct fmdev *, u8 *);
+
+u32 fm_rx_set_chanl_spacing(struct fmdev *, u8);
+u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c
new file mode 100644 (file)
index 0000000..be54068
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  This sub-module of FM driver implements FM TX functionality.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_common.h"
+#include "fmdrv_tx.h"
+
+u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->tx_data.aud_mode == mode)
+               return 0;
+
+       fmdbg("stereo mode: %d\n", mode);
+
+       /* Set Stereo/Mono mode */
+       payload = (1 - mode);
+       ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fmdev->tx_data.aud_mode = mode;
+
+       return ret;
+}
+
+static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
+{
+       u16 payload;
+       u32 ret;
+
+       ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
+                       strlen(rds_text), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Scroll mode */
+       payload = (u16)0x1;
+       ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
+{
+       u16 payload;
+       u32 ret;
+
+       /* Setting unique PI TODO: how unique? */
+       payload = (u16)0xcafe;
+       ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Set decoder id */
+       payload = (u16)0xa;
+       ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* TODO: RDS_MODE_GET? */
+       return 0;
+}
+
+static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
+{
+       u16 payload;
+       u32 ret;
+
+       len |= type << 8;
+       payload = len;
+       ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* TODO: LENGTH_GET? */
+       return 0;
+}
+
+u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+       u16 payload;
+       u32 ret;
+       u8 rds_text[] = "Zoom2\n";
+
+       fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
+                  FM_RDS_ENABLE, FM_RDS_DISABLE);
+
+       if (rds_en_dis == FM_RDS_ENABLE) {
+               /* Set RDS length */
+               set_rds_len(fmdev, 0, strlen(rds_text));
+
+               /* Set RDS text */
+               set_rds_text(fmdev, rds_text);
+
+               /* Set RDS mode */
+               set_rds_data_mode(fmdev, 0x0);
+       }
+
+       /* Send command to enable RDS */
+       if (rds_en_dis == FM_RDS_ENABLE)
+               payload = 0x01;
+       else
+               payload = 0x00;
+
+       ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       if (rds_en_dis == FM_RDS_ENABLE) {
+               /* Set RDS length */
+               set_rds_len(fmdev, 0, strlen(rds_text));
+
+               /* Set RDS text */
+               set_rds_text(fmdev, rds_text);
+       }
+       fmdev->tx_data.rds.flag = rds_en_dis;
+
+       return 0;
+}
+
+u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+
+       fm_tx_set_rds_mode(fmdev, 0);
+
+       /* Set RDS length */
+       set_rds_len(fmdev, rds_type, strlen(rds_text));
+
+       /* Set RDS text */
+       set_rds_text(fmdev, rds_text);
+
+       /* Set RDS mode */
+       set_rds_data_mode(fmdev, 0x0);
+
+       payload = 1;
+       ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
+{
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+
+       fmdbg("AF: %d\n", af);
+
+       af = (af - 87500) / 100;
+       payload = (u16)af;
+       ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
+{
+       u16 payload;
+       u32 ret;
+
+       if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
+               fmerr("Invalid band\n");
+               return -EINVAL;
+       }
+
+       /* Send command to set the band */
+       payload = (u16)region;
+       ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+       u16 payload;
+       u32 ret;
+
+       fmdbg("tx: mute mode %d\n", mute_mode_toset);
+
+       payload = mute_mode_toset;
+       ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/* Set TX Audio I/O */
+static u32 set_audio_io(struct fmdev *fmdev)
+{
+       struct fmtx_data *tx = &fmdev->tx_data;
+       u16 payload;
+       u32 ret;
+
+       /* Set Audio I/O Enable */
+       payload = tx->audio_io;
+       ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* TODO: is audio set? */
+       return 0;
+}
+
+/* Start TX Transmission */
+static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
+{
+       struct fmtx_data *tx = &fmdev->tx_data;
+       unsigned long timeleft;
+       u16 payload;
+       u32 ret;
+
+       /* Enable POWER_ENB interrupts */
+       payload = FM_POW_ENB_EVENT;
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Set Power Enable */
+       payload = new_xmit_state;
+       ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* Wait for Power Enabled */
+       init_completion(&fmdev->maintask_comp);
+       timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+                       FM_DRV_TX_TIMEOUT);
+       if (!timeleft) {
+               fmerr("Timeout(%d sec),didn't get tune ended interrupt\n",
+                          jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+               return -ETIMEDOUT;
+       }
+
+       set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+       tx->xmit_state = new_xmit_state;
+
+       return 0;
+}
+
+/* Set TX power level */
+u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
+{
+       u16 payload;
+       struct fmtx_data *tx = &fmdev->tx_data;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+       fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl);
+
+       /* If the core isn't ready update global variable */
+       if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+               tx->pwr_lvl = new_pwr_lvl;
+               return 0;
+       }
+
+       /* Set power level: Application will specify power level value in
+        * units of dB/uV, whereas range and step are specific to FM chip.
+        * For TI's WL chips, convert application specified power level value
+        * to chip specific value by subtracting 122 from it. Refer to TI FM
+        * data sheet for details.
+        * */
+
+       payload = (FM_PWR_LVL_HIGH - new_pwr_lvl);
+       ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       /* TODO: is the power level set? */
+       tx->pwr_lvl = new_pwr_lvl;
+
+       return 0;
+}
+
+/*
+ * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
+ * Convert V4L2 specified filter values to chip specific filter values.
+ */
+u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
+{
+       struct fmtx_data *tx = &fmdev->tx_data;
+       u16 payload;
+       u32 ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+
+       switch (preemphasis) {
+       case V4L2_PREEMPHASIS_DISABLED:
+               payload = FM_TX_PREEMPH_OFF;
+               break;
+       case V4L2_PREEMPHASIS_50_uS:
+               payload = FM_TX_PREEMPH_50US;
+               break;
+       case V4L2_PREEMPHASIS_75_uS:
+               payload = FM_TX_PREEMPH_75US;
+               break;
+       }
+
+       ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       tx->preemph = payload;
+
+       return ret;
+}
+
+/* Get the TX tuning capacitor value.*/
+u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
+{
+       u16 curr_val;
+       u32 ret, resp_len;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+
+       ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD,
+                       NULL, sizeof(curr_val), &curr_val, &resp_len);
+       if (ret < 0)
+               return ret;
+
+       curr_val = be16_to_cpu(curr_val);
+
+       return curr_val;
+}
+
+/* Set TX Frequency */
+u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+{
+       struct fmtx_data *tx = &fmdev->tx_data;
+       u16 payload, chanl_index;
+       u32 ret;
+
+       if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
+               enable_xmit(fmdev, 0);
+               clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+       }
+
+       /* Enable FR, BL interrupts */
+       payload = (FM_FR_EVENT | FM_BL_EVENT);
+       ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       tx->tx_frq = (unsigned long)freq_to_set;
+       fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq);
+
+       chanl_index = freq_to_set / 10;
+
+       /* Set current tuner channel */
+       payload = chanl_index;
+       ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload,
+                       sizeof(payload), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl);
+       fm_tx_set_preemph_filter(fmdev, tx->preemph);
+
+       tx->audio_io = 0x01;    /* I2S */
+       set_audio_io(fmdev);
+
+       enable_xmit(fmdev, 0x01);       /* Enable transmission */
+
+       tx->aud_mode = FM_STEREO_MODE;
+       tx->rds.flag = FM_RDS_DISABLE;
+
+       return 0;
+}
+
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h
new file mode 100644 (file)
index 0000000..e393a2b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  FM TX module header.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FMDRV_TX_H
+#define _FMDRV_TX_H
+
+u32 fm_tx_set_freq(struct fmdev *, u32);
+u32 fm_tx_set_pwr_lvl(struct fmdev *, u8);
+u32 fm_tx_set_region(struct fmdev *, u8);
+u32 fm_tx_set_mute_mode(struct fmdev *, u8);
+u32 fm_tx_set_stereo_mono(struct fmdev *, u16);
+u32 fm_tx_set_rds_mode(struct fmdev *, u8);
+u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
+u32 fm_tx_set_af(struct fmdev *, u32);
+u32 fm_tx_set_preemph_filter(struct fmdev *, u32);
+u32 fm_tx_get_tune_cap_val(struct fmdev *);
+
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
new file mode 100644 (file)
index 0000000..d50e5ac
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *  This file provides interfaces to V4L2 subsystem.
+ *
+ *  This module registers with V4L2 subsystem as Radio
+ *  data system interface (/dev/radio). During the registration,
+ *  it will expose two set of function pointers.
+ *
+ *    1) File operation related API (open, close, read, write, poll...etc).
+ *    2) Set of V4L2 IOCTL complaint API.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *  Author: Raja Mani <raja_mani@ti.com>
+ *  Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_common.h"
+#include "fmdrv_rx.h"
+#include "fmdrv_tx.h"
+
+static struct video_device *gradio_dev;
+static u8 radio_disconnected;
+
+/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
+
+/* Read RX RDS data */
+static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
+                                       size_t count, loff_t *ppos)
+{
+       u8 rds_mode;
+       int ret;
+       struct fmdev *fmdev;
+
+       fmdev = video_drvdata(file);
+
+       if (!radio_disconnected) {
+               fmerr("FM device is already disconnected\n");
+               return -EIO;
+       }
+
+       /* Turn on RDS mode , if it is disabled */
+       ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
+       if (ret < 0) {
+               fmerr("Unable to read current rds mode\n");
+               return ret;
+       }
+
+       if (rds_mode == FM_RDS_DISABLE) {
+               ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
+               if (ret < 0) {
+                       fmerr("Failed to enable rds mode\n");
+                       return ret;
+               }
+       }
+
+       /* Copy RDS data from internal buffer to user buffer */
+       return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+}
+
+/* Write TX RDS data */
+static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
+               size_t count, loff_t *ppos)
+{
+       struct tx_rds rds;
+       int ret;
+       struct fmdev *fmdev;
+
+       ret = copy_from_user(&rds, buf, sizeof(rds));
+       fmdbg("(%d)type: %d, text %s, af %d\n",
+                  ret, rds.text_type, rds.text, rds.af_freq);
+
+       fmdev = video_drvdata(file);
+       fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
+       fm_tx_set_af(fmdev, rds.af_freq);
+
+       return 0;
+}
+
+static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
+{
+       int ret;
+       struct fmdev *fmdev;
+
+       fmdev = video_drvdata(file);
+       ret = fmc_is_rds_data_available(fmdev, file, pts);
+       if (ret < 0)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+/*
+ * Handle open request for "/dev/radioX" device.
+ * Start with FM RX mode as default.
+ */
+static int fm_v4l2_fops_open(struct file *file)
+{
+       int ret;
+       struct fmdev *fmdev = NULL;
+
+       /* Don't allow multiple open */
+       if (radio_disconnected) {
+               fmerr("FM device is already opened\n");
+               return -EBUSY;
+       }
+
+       fmdev = video_drvdata(file);
+
+       ret = fmc_prepare(fmdev);
+       if (ret < 0) {
+               fmerr("Unable to prepare FM CORE\n");
+               return ret;
+       }
+
+       fmdbg("Load FM RX firmware..\n");
+
+       ret = fmc_set_mode(fmdev, FM_MODE_RX);
+       if (ret < 0) {
+               fmerr("Unable to load FM RX firmware\n");
+               return ret;
+       }
+       radio_disconnected = 1;
+
+       return ret;
+}
+
+static int fm_v4l2_fops_release(struct file *file)
+{
+       int ret;
+       struct fmdev *fmdev;
+
+       fmdev = video_drvdata(file);
+       if (!radio_disconnected) {
+               fmdbg("FM device is already closed\n");
+               return 0;
+       }
+
+       ret = fmc_set_mode(fmdev, FM_MODE_OFF);
+       if (ret < 0) {
+               fmerr("Unable to turn off the chip\n");
+               return ret;
+       }
+
+       ret = fmc_release(fmdev);
+       if (ret < 0) {
+               fmerr("FM CORE release failed\n");
+               return ret;
+       }
+       radio_disconnected = 0;
+
+       return ret;
+}
+
+/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */
+static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability)
+{
+       strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
+       strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
+                       sizeof(capability->card));
+       sprintf(capability->bus_info, "UART");
+       capability->version = FM_DRV_RADIO_VERSION;
+       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+               V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
+               V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
+               V4L2_CAP_RDS_CAPTURE;
+
+       return 0;
+}
+
+static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct fmdev *fmdev = container_of(ctrl->handler,
+                       struct fmdev, ctrl_handler);
+
+       switch (ctrl->id) {
+       case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               ctrl->val = fm_tx_get_tune_cap_val(fmdev);
+               break;
+       default:
+               fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
+               break;
+       }
+
+       return 0;
+}
+
+static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct fmdev *fmdev = container_of(ctrl->handler,
+                       struct fmdev, ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:     /* set volume */
+               return fm_rx_set_volume(fmdev, (u16)ctrl->val);
+
+       case V4L2_CID_AUDIO_MUTE:       /* set mute */
+               return fmc_set_mute_mode(fmdev, (u8)ctrl->val);
+
+       case V4L2_CID_TUNE_POWER_LEVEL:
+               /* set TX power level - ext control */
+               return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val);
+
+       case V4L2_CID_TUNE_PREEMPHASIS:
+               return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       memset(audio, 0, sizeof(*audio));
+       strcpy(audio->name, "Radio");
+       audio->capability = V4L2_AUDCAP_STEREO;
+
+       return 0;
+}
+
+static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       if (audio->index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Get tuner attributes. If current mode is NOT RX, return error */
+static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+       u32 bottom_freq;
+       u32 top_freq;
+       u16 stereo_mono_mode;
+       u16 rssilvl;
+       int ret;
+
+       if (tuner->index != 0)
+               return -EINVAL;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX)
+               return -EPERM;
+
+       ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq);
+       if (ret != 0)
+               return ret;
+
+       ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode);
+       if (ret != 0)
+               return ret;
+
+       ret = fm_rx_get_rssi_level(fmdev, &rssilvl);
+       if (ret != 0)
+               return ret;
+
+       strcpy(tuner->name, "FM");
+       tuner->type = V4L2_TUNER_RADIO;
+       /* Store rangelow and rangehigh freq in unit of 62.5 Hz */
+       tuner->rangelow = bottom_freq * 16;
+       tuner->rangehigh = top_freq * 16;
+       tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
+       ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
+       tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+                           V4L2_TUNER_CAP_LOW;
+       tuner->audmode = (stereo_mono_mode ?
+                         V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
+
+       /*
+        * Actual rssi value lies in between -128 to +127.
+        * Convert this range from 0 to 255 by adding +128
+        */
+       rssilvl += 128;
+
+       /*
+        * Return signal strength value should be within 0 to 65535.
+        * Find out correct signal radio by multiplying (65535/255) = 257
+        */
+       tuner->signal = rssilvl * 257;
+       tuner->afc = 0;
+
+       return ret;
+}
+
+/*
+ * Set tuner attributes. If current mode is NOT RX, set to RX.
+ * Currently, we set only audio mode (mono/stereo) and RDS state (on/off).
+ * Should we set other tuner attributes, too?
+ */
+static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+       u16 aud_mode;
+       u8 rds_mode;
+       int ret;
+
+       if (tuner->index != 0)
+               return -EINVAL;
+
+       aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
+                       FM_STEREO_MODE : FM_MONO_MODE;
+       rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
+                       FM_RDS_ENABLE : FM_RDS_DISABLE;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX) {
+               ret = fmc_set_mode(fmdev, FM_MODE_RX);
+               if (ret < 0) {
+                       fmerr("Failed to set RX mode\n");
+                       return ret;
+               }
+       }
+
+       ret = fmc_set_stereo_mono(fmdev, aud_mode);
+       if (ret < 0) {
+               fmerr("Failed to set RX stereo/mono mode\n");
+               return ret;
+       }
+
+       ret = fmc_set_rds_mode(fmdev, rds_mode);
+       if (ret < 0)
+               fmerr("Failed to set RX RDS mode\n");
+
+       return ret;
+}
+
+/* Get tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+       int ret;
+
+       ret = fmc_get_freq(fmdev, &freq->frequency);
+       if (ret < 0) {
+               fmerr("Failed to get frequency\n");
+               return ret;
+       }
+
+       /* Frequency unit of 62.5 Hz*/
+       freq->frequency = (u32) freq->frequency * 16;
+
+       return 0;
+}
+
+/* Set tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+
+       /*
+        * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency
+        * in units of 62.5 Hz.
+        */
+       freq->frequency = (u32)(freq->frequency / 16);
+
+       return fmc_set_freq(fmdev, freq->frequency);
+}
+
+/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */
+static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+               struct v4l2_hw_freq_seek *seek)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+       int ret;
+
+       if (fmdev->curr_fmmode != FM_MODE_RX) {
+               ret = fmc_set_mode(fmdev, FM_MODE_RX);
+               if (ret != 0) {
+                       fmerr("Failed to set RX mode\n");
+                       return ret;
+               }
+       }
+
+       ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around,
+                       seek->spacing);
+       if (ret < 0)
+               fmerr("RX seek failed - %d\n", ret);
+
+       return ret;
+}
+/* Get modulator attributes. If mode is not TX, return no attributes. */
+static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv,
+               struct v4l2_modulator *mod)
+{
+       struct fmdev *fmdev = video_drvdata(file);;
+
+       if (mod->index != 0)
+               return -EINVAL;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX)
+               return -EPERM;
+
+       mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ?
+                               V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) |
+                               ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ?
+                               V4L2_TUNER_SUB_RDS : 0);
+
+       mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+                               V4L2_TUNER_CAP_LOW;
+
+       return 0;
+}
+
+/* Set modulator attributes. If mode is not TX, set to TX. */
+static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv,
+               struct v4l2_modulator *mod)
+{
+       struct fmdev *fmdev = video_drvdata(file);
+       u8 rds_mode;
+       u16 aud_mode;
+       int ret;
+
+       if (mod->index != 0)
+               return -EINVAL;
+
+       if (fmdev->curr_fmmode != FM_MODE_TX) {
+               ret = fmc_set_mode(fmdev, FM_MODE_TX);
+               if (ret != 0) {
+                       fmerr("Failed to set TX mode\n");
+                       return ret;
+               }
+       }
+
+       aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ?
+                       FM_STEREO_MODE : FM_MONO_MODE;
+       rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ?
+                       FM_RDS_ENABLE : FM_RDS_DISABLE;
+       ret = fm_tx_set_stereo_mono(fmdev, aud_mode);
+       if (ret < 0) {
+               fmerr("Failed to set mono/stereo mode for TX\n");
+               return ret;
+       }
+       ret = fm_tx_set_rds_mode(fmdev, rds_mode);
+       if (ret < 0)
+               fmerr("Failed to set rds mode for TX\n");
+
+       return ret;
+}
+
+static const struct v4l2_file_operations fm_drv_fops = {
+       .owner = THIS_MODULE,
+       .read = fm_v4l2_fops_read,
+       .write = fm_v4l2_fops_write,
+       .poll = fm_v4l2_fops_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .open = fm_v4l2_fops_open,
+       .release = fm_v4l2_fops_release,
+};
+
+static const struct v4l2_ctrl_ops fm_ctrl_ops = {
+       .s_ctrl = fm_v4l2_s_ctrl,
+       .g_volatile_ctrl = fm_g_volatile_ctrl,
+};
+static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
+       .vidioc_querycap = fm_v4l2_vidioc_querycap,
+       .vidioc_g_audio = fm_v4l2_vidioc_g_audio,
+       .vidioc_s_audio = fm_v4l2_vidioc_s_audio,
+       .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
+       .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
+       .vidioc_g_frequency = fm_v4l2_vidioc_g_freq,
+       .vidioc_s_frequency = fm_v4l2_vidioc_s_freq,
+       .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
+       .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator,
+       .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator
+};
+
+/* V4L2 RADIO device parent structure */
+static struct video_device fm_viddev_template = {
+       .fops = &fm_drv_fops,
+       .ioctl_ops = &fm_drv_ioctl_ops,
+       .name = FM_DRV_NAME,
+       .release = video_device_release,
+};
+
+int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
+{
+       struct v4l2_ctrl *ctrl;
+       int ret;
+
+       /* Init mutex for core locking */
+       mutex_init(&fmdev->mutex);
+
+       /* Allocate new video device */
+       gradio_dev = video_device_alloc();
+       if (NULL == gradio_dev) {
+               fmerr("Can't allocate video device\n");
+               return -ENOMEM;
+       }
+
+       /* Setup FM driver's V4L2 properties */
+       memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template));
+
+       video_set_drvdata(gradio_dev, fmdev);
+
+       gradio_dev->lock = &fmdev->mutex;
+
+       /* Register with V4L2 subsystem as RADIO device */
+       if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
+               video_device_release(gradio_dev);
+               fmerr("Could not register video device\n");
+               return -ENOMEM;
+       }
+
+       fmdev->radio_dev = gradio_dev;
+
+       /* Register to v4l2 ctrl handler framework */
+       fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler;
+
+       ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5);
+       if (ret < 0) {
+               fmerr("(fmdev): Can't init ctrl handler\n");
+               v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+               return -EBUSY;
+       }
+
+       /*
+        * Following controls are handled by V4L2 control framework.
+        * Added in ascending ID order.
+        */
+       v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN,
+                       FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX);
+
+       v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+
+       v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops,
+                       V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS,
+                       0, V4L2_PREEMPHASIS_75_uS);
+
+       v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+                       V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW,
+                       FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH);
+
+       ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+                       V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0,
+                       255, 1, 255);
+
+       if (ctrl)
+               ctrl->is_volatile = 1;
+
+       return 0;
+}
+
+void *fm_v4l2_deinit_video_device(void)
+{
+       struct fmdev *fmdev;
+
+
+       fmdev = video_get_drvdata(gradio_dev);
+
+       /* Unregister to v4l2 ctrl handler framework*/
+       v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+
+       /* Unregister RADIO device from V4L2 subsystem */
+       video_unregister_device(gradio_dev);
+
+       return fmdev;
+}
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.h b/drivers/media/radio/wl128x/fmdrv_v4l2.h
new file mode 100644 (file)
index 0000000..0ba79d7
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  FM V4L2 module header.
+ *
+ *  Copyright (C) 2011 Texas Instruments
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FMDRV_V4L2_H
+#define _FMDRV_V4L2_H
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+int fm_v4l2_init_video_device(struct fmdev *, int);
+void *fm_v4l2_deinit_video_device(void);
+
+#endif
index 3785162f928e64e0b339965d4ad923d343768593..7f03142a329f73d75e9c5d683d23acfc323475ec 100644 (file)
@@ -135,6 +135,19 @@ config IR_MCEUSB
           To compile this driver as a module, choose M here: the
           module will be called mceusb.
 
+config IR_ITE_CIR
+       tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver"
+       depends on PNP
+       depends on RC_CORE
+       ---help---
+          Say Y here to enable support for integrated infrared receivers
+          /transceivers made by ITE Tech Inc. These are found in
+          several ASUS devices, like the ASUS Digimatrix or the ASUS
+          EEEBox 1501U.
+
+          To compile this driver as a module, choose M here: the
+          module will be called ite-cir.
+
 config IR_NUVOTON
        tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
        depends on PNP
@@ -161,20 +174,20 @@ config IR_STREAMZAP
           module will be called streamzap.
 
 config IR_WINBOND_CIR
-        tristate "Winbond IR remote control"
-        depends on X86 && PNP
+       tristate "Winbond IR remote control"
+       depends on X86 && PNP
        depends on RC_CORE
-        select NEW_LEDS
-        select LEDS_CLASS
-        select LEDS_TRIGGERS
-        select BITREVERSE
-       ---help---
-           Say Y here if you want to use the IR remote functionality found
-           in some Winbond SuperI/O chips. Currently only the WPCD376I
-           chip is supported (included in some Intel Media series
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_TRIGGERS
+       select BITREVERSE
+       ---help---
+          Say Y here if you want to use the IR remote functionality found
+          in some Winbond SuperI/O chips. Currently only the WPCD376I
+          chip is supported (included in some Intel Media series
           motherboards).
 
-           To compile this driver as a module, choose M here: the module will
+          To compile this driver as a module, choose M here: the module will
           be called winbond_cir.
 
 config RC_LOOPBACK
index 67b4f7fe257710d0c0d01494c66b0b0487fdd9c0..c6cfe70d862f374b8f1be88e9e3e7a5fbaf3a309 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
 obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
 obj-$(CONFIG_IR_MCEUSB) += mceusb.o
 obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
index e7dc6b46fdfac2df6f6ead2661d4fed6ea4c4358..f714e1a22c9206cd2e679cfc087817b0cb8e4c79 100644 (file)
@@ -277,12 +277,21 @@ static const struct {
        u64 hw_code;
        u32 keycode;
 } imon_panel_key_table[] = {
-       { 0x000000000f00ffeell, KEY_PROG1 }, /* Go */
+       { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
+       { 0x000000001200ffeell, KEY_UP },
+       { 0x000000001300ffeell, KEY_DOWN },
+       { 0x000000001400ffeell, KEY_LEFT },
+       { 0x000000001500ffeell, KEY_RIGHT },
+       { 0x000000001600ffeell, KEY_ENTER },
+       { 0x000000001700ffeell, KEY_ESC },
        { 0x000000001f00ffeell, KEY_AUDIO },
        { 0x000000002000ffeell, KEY_VIDEO },
        { 0x000000002100ffeell, KEY_CAMERA },
        { 0x000000002700ffeell, KEY_DVD },
        { 0x000000002300ffeell, KEY_TV },
+       { 0x000000002b00ffeell, KEY_EXIT },
+       { 0x000000002c00ffeell, KEY_SELECT },
+       { 0x000000002d00ffeell, KEY_MENU },
        { 0x000000000500ffeell, KEY_PREVIOUS },
        { 0x000000000700ffeell, KEY_REWIND },
        { 0x000000000400ffeell, KEY_STOP },
index 7b58b4a1729ba92ab55a723721c63ee011a29183..63ee722dbd0204ea61860971b1c1d0a37d923dff 100644 (file)
@@ -49,6 +49,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
        struct nec_dec *data = &dev->raw->nec;
        u32 scancode;
        u8 address, not_address, command, not_command;
+       bool send_32bits = false;
 
        if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
                return 0;
@@ -164,10 +165,15 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
                if ((command ^ not_command) != 0xff) {
                        IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
                                   data->bits);
-                       break;
+                       send_32bits = true;
                }
 
-               if ((address ^ not_address) != 0xff) {
+               if (send_32bits) {
+                       /* NEC transport, but modified protocol, used by at
+                        * least Apple and TiVo remotes */
+                       scancode = data->bits;
+                       IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
+               } else if ((address ^ not_address) != 0xff) {
                        /* Extended NEC */
                        scancode = address     << 16 |
                                   not_address <<  8 |
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
new file mode 100644 (file)
index 0000000..ac0e42b
--- /dev/null
@@ -0,0 +1,1736 @@
+/*
+ * Driver for ITE Tech Inc. IT8712F/IT8512 CIR
+ *
+ * Copyright (C) 2010 Juan JesĆŗs GarcĆ­a de Soria <skandalfo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ *
+ * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the
+ * skeleton provided by the nuvoton-cir driver.
+ *
+ * The lirc_it87 driver was originally written by Hans-Gunter Lutke Uphues
+ * <hg_lu@web.de> in 2001, with enhancements by Christoph Bartelmus
+ * <lirc@bartelmus.de>, Andrew Calkin <r_tay@hotmail.com> and James Edwards
+ * <jimbo-lirc@edwardsclan.net>.
+ *
+ * The lirc_ite8709 driver was written by GrĆ©gory LardiĆØre
+ * <spmf2004-lirc@yahoo.fr> in 2008.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/bitops.h>
+#include <media/rc-core.h>
+#include <linux/pci_ids.h>
+
+#include "ite-cir.h"
+
+/* module parameters */
+
+/* debug level */
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */
+static int rx_low_carrier_freq;
+module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, "
+                "0 for no RX demodulation");
+
+/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */
+static int rx_high_carrier_freq;
+module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, "
+                "Hz, 0 for no RX demodulation");
+
+/* override tx carrier frequency */
+static int tx_carrier_freq;
+module_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz");
+
+/* override tx duty cycle */
+static int tx_duty_cycle;
+module_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100");
+
+/* override default sample period */
+static long sample_period;
+module_param(sample_period, long, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_period, "Override carrier sample period, us");
+
+/* override detected model id */
+static int model_number = -1;
+module_param(model_number, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(model_number, "Use this model number, don't autodetect");
+
+
+/* HW-independent code functions */
+
+/* check whether carrier frequency is high frequency */
+static inline bool ite_is_high_carrier_freq(unsigned int freq)
+{
+       return freq >= ITE_HCF_MIN_CARRIER_FREQ;
+}
+
+/* get the bits required to program the carrier frequency in CFQ bits,
+ * unshifted */
+static u8 ite_get_carrier_freq_bits(unsigned int freq)
+{
+       if (ite_is_high_carrier_freq(freq)) {
+               if (freq < 425000)
+                       return ITE_CFQ_400;
+
+               else if (freq < 465000)
+                       return ITE_CFQ_450;
+
+               else if (freq < 490000)
+                       return ITE_CFQ_480;
+
+               else
+                       return ITE_CFQ_500;
+       } else {
+                       /* trim to limits */
+               if (freq < ITE_LCF_MIN_CARRIER_FREQ)
+                       freq = ITE_LCF_MIN_CARRIER_FREQ;
+               if (freq > ITE_LCF_MAX_CARRIER_FREQ)
+                       freq = ITE_LCF_MAX_CARRIER_FREQ;
+
+               /* convert to kHz and subtract the base freq */
+               freq =
+                   DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ,
+                                     1000);
+
+               return (u8) freq;
+       }
+}
+
+/* get the bits required to program the pulse with in TXMPW */
+static u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle)
+{
+       unsigned long period_ns, on_ns;
+
+       /* sanitize freq into range */
+       if (freq < ITE_LCF_MIN_CARRIER_FREQ)
+               freq = ITE_LCF_MIN_CARRIER_FREQ;
+       if (freq > ITE_HCF_MAX_CARRIER_FREQ)
+               freq = ITE_HCF_MAX_CARRIER_FREQ;
+
+       period_ns = 1000000000UL / freq;
+       on_ns = period_ns * duty_cycle / 100;
+
+       if (ite_is_high_carrier_freq(freq)) {
+               if (on_ns < 750)
+                       return ITE_TXMPW_A;
+
+               else if (on_ns < 850)
+                       return ITE_TXMPW_B;
+
+               else if (on_ns < 950)
+                       return ITE_TXMPW_C;
+
+               else if (on_ns < 1080)
+                       return ITE_TXMPW_D;
+
+               else
+                       return ITE_TXMPW_E;
+       } else {
+               if (on_ns < 6500)
+                       return ITE_TXMPW_A;
+
+               else if (on_ns < 7850)
+                       return ITE_TXMPW_B;
+
+               else if (on_ns < 9650)
+                       return ITE_TXMPW_C;
+
+               else if (on_ns < 11950)
+                       return ITE_TXMPW_D;
+
+               else
+                       return ITE_TXMPW_E;
+       }
+}
+
+/* decode raw bytes as received by the hardware, and push them to the ir-core
+ * layer */
+static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
+                            length)
+{
+       u32 sample_period;
+       unsigned long *ldata;
+       unsigned int next_one, next_zero, size;
+       DEFINE_IR_RAW_EVENT(ev);
+
+       if (length == 0)
+               return;
+
+       sample_period = dev->params.sample_period;
+       ldata = (unsigned long *)data;
+       size = length << 3;
+       next_one = find_next_bit_le(ldata, size, 0);
+       if (next_one > 0) {
+               ev.pulse = true;
+               ev.duration =
+                   ITE_BITS_TO_NS(next_one, sample_period);
+               ir_raw_event_store_with_filter(dev->rdev, &ev);
+       }
+
+       while (next_one < size) {
+               next_zero = find_next_zero_bit_le(ldata, size, next_one + 1);
+               ev.pulse = false;
+               ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
+               ir_raw_event_store_with_filter(dev->rdev, &ev);
+
+               if (next_zero < size) {
+                       next_one =
+                           find_next_bit_le(ldata,
+                                                    size,
+                                                    next_zero + 1);
+                       ev.pulse = true;
+                       ev.duration =
+                           ITE_BITS_TO_NS(next_one - next_zero,
+                                          sample_period);
+                       ir_raw_event_store_with_filter
+                           (dev->rdev, &ev);
+               } else
+                       next_one = size;
+       }
+
+       ir_raw_event_handle(dev->rdev);
+
+       ite_dbg_verbose("decoded %d bytes.", length);
+}
+
+/* set all the rx/tx carrier parameters; this must be called with the device
+ * spinlock held */
+static void ite_set_carrier_params(struct ite_dev *dev)
+{
+       unsigned int freq, low_freq, high_freq;
+       int allowance;
+       bool use_demodulator;
+       bool for_tx = dev->transmitting;
+
+       ite_dbg("%s called", __func__);
+
+       if (for_tx) {
+               /* we don't need no stinking calculations */
+               freq = dev->params.tx_carrier_freq;
+               allowance = ITE_RXDCR_DEFAULT;
+               use_demodulator = false;
+       } else {
+               low_freq = dev->params.rx_low_carrier_freq;
+               high_freq = dev->params.rx_high_carrier_freq;
+
+               if (low_freq == 0) {
+                       /* don't demodulate */
+                       freq =
+                       ITE_DEFAULT_CARRIER_FREQ;
+                       allowance = ITE_RXDCR_DEFAULT;
+                       use_demodulator = false;
+               } else {
+                       /* calculate the middle freq */
+                       freq = (low_freq + high_freq) / 2;
+
+                       /* calculate the allowance */
+                       allowance =
+                           DIV_ROUND_CLOSEST(10000 * (high_freq - low_freq),
+                                             ITE_RXDCR_PER_10000_STEP
+                                             * (high_freq + low_freq));
+
+                       if (allowance < 1)
+                               allowance = 1;
+
+                       if (allowance > ITE_RXDCR_MAX)
+                               allowance = ITE_RXDCR_MAX;
+               }
+       }
+
+       /* set the carrier parameters in a device-dependent way */
+       dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq),
+                use_demodulator, ite_get_carrier_freq_bits(freq), allowance,
+                ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle));
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t ite_cir_isr(int irq, void *data)
+{
+       struct ite_dev *dev = data;
+       unsigned long flags;
+       irqreturn_t ret = IRQ_RETVAL(IRQ_NONE);
+       u8 rx_buf[ITE_RX_FIFO_LEN];
+       int rx_bytes;
+       int iflags;
+
+       ite_dbg_verbose("%s firing", __func__);
+
+       /* grab the spinlock */
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* read the interrupt flags */
+       iflags = dev->params.get_irq_causes(dev);
+
+       /* check for the receive interrupt */
+       if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) {
+               /* read the FIFO bytes */
+               rx_bytes =
+                       dev->params.get_rx_bytes(dev, rx_buf,
+                                            ITE_RX_FIFO_LEN);
+
+               if (rx_bytes > 0) {
+                       /* drop the spinlock, since the ir-core layer
+                        * may call us back again through
+                        * ite_s_idle() */
+                       spin_unlock_irqrestore(&dev->
+                                                                        lock,
+                                                                        flags);
+
+                       /* decode the data we've just received */
+                       ite_decode_bytes(dev, rx_buf,
+                                                                  rx_bytes);
+
+                       /* reacquire the spinlock */
+                       spin_lock_irqsave(&dev->lock,
+                                                                   flags);
+
+                       /* mark the interrupt as serviced */
+                       ret = IRQ_RETVAL(IRQ_HANDLED);
+               }
+       } else if (iflags & ITE_IRQ_TX_FIFO) {
+               /* FIFO space available interrupt */
+               ite_dbg_verbose("got interrupt for TX FIFO");
+
+               /* wake any sleeping transmitter */
+               wake_up_interruptible(&dev->tx_queue);
+
+               /* mark the interrupt as serviced */
+               ret = IRQ_RETVAL(IRQ_HANDLED);
+       }
+
+       /* drop the spinlock */
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       ite_dbg_verbose("%s done returning %d", __func__, (int)ret);
+
+       return ret;
+}
+
+/* set the rx carrier freq range, guess it's in Hz... */
+static int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32
+                                   carrier_high)
+{
+       unsigned long flags;
+       struct ite_dev *dev = rcdev->priv;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->params.rx_low_carrier_freq = carrier_low;
+       dev->params.rx_high_carrier_freq = carrier_high;
+       ite_set_carrier_params(dev);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/* set the tx carrier freq, guess it's in Hz... */
+static int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
+{
+       unsigned long flags;
+       struct ite_dev *dev = rcdev->priv;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->params.tx_carrier_freq = carrier;
+       ite_set_carrier_params(dev);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/* set the tx duty cycle by controlling the pulse width */
+static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)
+{
+       unsigned long flags;
+       struct ite_dev *dev = rcdev->priv;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->params.tx_duty_cycle = duty_cycle;
+       ite_set_carrier_params(dev);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/* transmit out IR pulses; what you get here is a batch of alternating
+ * pulse/space/pulse/space lengths that we should write out completely through
+ * the FIFO, blocking on a full FIFO */
+static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+{
+       unsigned long flags;
+       struct ite_dev *dev = rcdev->priv;
+       bool is_pulse = false;
+       int remaining_us, fifo_avail, fifo_remaining, last_idx = 0;
+       int max_rle_us, next_rle_us;
+       int ret = n;
+       u8 last_sent[ITE_TX_FIFO_LEN];
+       u8 val;
+
+       ite_dbg("%s called", __func__);
+
+       /* clear the array just in case */
+       memset(last_sent, 0, ARRAY_SIZE(last_sent));
+
+       /* n comes in bytes; convert to ints */
+       n /= sizeof(int);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* let everybody know we're now transmitting */
+       dev->transmitting = true;
+
+       /* and set the carrier values for transmission */
+       ite_set_carrier_params(dev);
+
+       /* calculate how much time we can send in one byte */
+       max_rle_us =
+           (ITE_BAUDRATE_DIVISOR * dev->params.sample_period *
+            ITE_TX_MAX_RLE) / 1000;
+
+       /* disable the receiver */
+       dev->params.disable_rx(dev);
+
+       /* this is where we'll begin filling in the FIFO, until it's full.
+        * then we'll just activate the interrupt, wait for it to wake us up
+        * again, disable it, continue filling the FIFO... until everything
+        * has been pushed out */
+       fifo_avail =
+           ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev);
+
+       while (n > 0 && dev->in_use) {
+               /* transmit the next sample */
+               is_pulse = !is_pulse;
+               remaining_us = *(txbuf++);
+               n--;
+
+               ite_dbg("%s: %ld",
+                                     ((is_pulse) ? "pulse" : "space"),
+                                     (long int)
+                                     remaining_us);
+
+               /* repeat while the pulse is non-zero length */
+               while (remaining_us > 0 && dev->in_use) {
+                       if (remaining_us > max_rle_us)
+                               next_rle_us = max_rle_us;
+
+                       else
+                               next_rle_us = remaining_us;
+
+                       remaining_us -= next_rle_us;
+
+                       /* check what's the length we have to pump out */
+                       val = (ITE_TX_MAX_RLE * next_rle_us) / max_rle_us;
+
+                       /* put it into the sent buffer */
+                       last_sent[last_idx++] = val;
+                       last_idx &= (ITE_TX_FIFO_LEN);
+
+                       /* encode it for 7 bits */
+                       val = (val - 1) & ITE_TX_RLE_MASK;
+
+                       /* take into account pulse/space prefix */
+                       if (is_pulse)
+                               val |= ITE_TX_PULSE;
+
+                       else
+                               val |= ITE_TX_SPACE;
+
+                       /*
+                        * if we get to 0 available, read again, just in case
+                        * some other slot got freed
+                        */
+                       if (fifo_avail <= 0)
+                               fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev);
+
+                       /* if it's still full */
+                       if (fifo_avail <= 0) {
+                               /* enable the tx interrupt */
+                               dev->params.
+                               enable_tx_interrupt(dev);
+
+                               /* drop the spinlock */
+                               spin_unlock_irqrestore(&dev->lock, flags);
+
+                               /* wait for the FIFO to empty enough */
+                               wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8);
+
+                               /* get the spinlock again */
+                               spin_lock_irqsave(&dev->lock, flags);
+
+                               /* disable the tx interrupt again. */
+                               dev->params.
+                               disable_tx_interrupt(dev);
+                       }
+
+                       /* now send the byte through the FIFO */
+                       dev->params.put_tx_byte(dev, val);
+                       fifo_avail--;
+               }
+       }
+
+       /* wait and don't return until the whole FIFO has been sent out;
+        * otherwise we could configure the RX carrier params instead of the
+        * TX ones while the transmission is still being performed! */
+       fifo_remaining = dev->params.get_tx_used_slots(dev);
+       remaining_us = 0;
+       while (fifo_remaining > 0) {
+               fifo_remaining--;
+               last_idx--;
+               last_idx &= (ITE_TX_FIFO_LEN - 1);
+               remaining_us += last_sent[last_idx];
+       }
+       remaining_us = (remaining_us * max_rle_us) / (ITE_TX_MAX_RLE);
+
+       /* drop the spinlock while we sleep */
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /* sleep remaining_us microseconds */
+       mdelay(DIV_ROUND_UP(remaining_us, 1000));
+
+       /* reacquire the spinlock */
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* now we're not transmitting anymore */
+       dev->transmitting = false;
+
+       /* and set the carrier values for reception */
+       ite_set_carrier_params(dev);
+
+       /* reenable the receiver */
+       if (dev->in_use)
+               dev->params.enable_rx(dev);
+
+       /* notify transmission end */
+       wake_up_interruptible(&dev->tx_ended);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return ret;
+}
+
+/* idle the receiver if needed */
+static void ite_s_idle(struct rc_dev *rcdev, bool enable)
+{
+       unsigned long flags;
+       struct ite_dev *dev = rcdev->priv;
+
+       ite_dbg("%s called", __func__);
+
+       if (enable) {
+               spin_lock_irqsave(&dev->lock, flags);
+               dev->params.idle_rx(dev);
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+}
+
+
+/* IT8712F HW-specific functions */
+
+/* retrieve a bitmask of the current causes for a pending interrupt; this may
+ * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN
+ * */
+static int it87_get_irq_causes(struct ite_dev *dev)
+{
+       u8 iflags;
+       int ret = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read the interrupt flags */
+       iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II;
+
+       switch (iflags) {
+       case IT87_II_RXDS:
+               ret = ITE_IRQ_RX_FIFO;
+               break;
+       case IT87_II_RXFO:
+               ret = ITE_IRQ_RX_FIFO_OVERRUN;
+               break;
+       case IT87_II_TXLDL:
+               ret = ITE_IRQ_TX_FIFO;
+               break;
+       }
+
+       return ret;
+}
+
+/* set the carrier parameters; to be called with the spinlock held */
+static void it87_set_carrier_params(struct ite_dev *dev, bool high_freq,
+                                   bool use_demodulator,
+                                   u8 carrier_freq_bits, u8 allowance_bits,
+                                   u8 pulse_width_bits)
+{
+       u8 val;
+
+       ite_dbg("%s called", __func__);
+
+       /* program the RCR register */
+       val = inb(dev->cir_addr + IT87_RCR)
+               & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR);
+
+       if (high_freq)
+               val |= IT87_HCFS;
+
+       if (use_demodulator)
+               val |= IT87_RXEND;
+
+       val |= allowance_bits;
+
+       outb(val, dev->cir_addr + IT87_RCR);
+
+       /* program the TCR2 register */
+       outb((carrier_freq_bits << IT87_CFQ_SHIFT) | pulse_width_bits,
+               dev->cir_addr + IT87_TCR2);
+}
+
+/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock
+ * held */
+static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size)
+{
+       int fifo, read = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read how many bytes are still in the FIFO */
+       fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC;
+
+       while (fifo > 0 && buf_size > 0) {
+               *(buf++) = inb(dev->cir_addr + IT87_DR);
+               fifo--;
+               read++;
+               buf_size--;
+       }
+
+       return read;
+}
+
+/* return how many bytes are still in the FIFO; this will be called
+ * with the device spinlock NOT HELD while waiting for the TX FIFO to get
+ * empty; let's expect this won't be a problem */
+static int it87_get_tx_used_slots(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC;
+}
+
+/* put a byte to the TX fifo; this should be called with the spinlock held */
+static void it87_put_tx_byte(struct ite_dev *dev, u8 value)
+{
+       outb(value, dev->cir_addr + IT87_DR);
+}
+
+/* idle the receiver so that we won't receive samples until another
+  pulse is detected; this must be called with the device spinlock held */
+static void it87_idle_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable streaming by clearing RXACT writing it as 1 */
+       outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT,
+               dev->cir_addr + IT87_RCR);
+
+       /* clear the FIFO */
+       outb(inb(dev->cir_addr + IT87_TCR1) | IT87_FIFOCLR,
+               dev->cir_addr + IT87_TCR1);
+}
+
+/* disable the receiver; this must be called with the device spinlock held */
+static void it87_disable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the receiver interrupts */
+       outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE),
+               dev->cir_addr + IT87_IER);
+
+       /* disable the receiver */
+       outb(inb(dev->cir_addr + IT87_RCR) & ~IT87_RXEN,
+               dev->cir_addr + IT87_RCR);
+
+       /* clear the FIFO and RXACT (actually RXACT should have been cleared
+       * in the previous outb() call) */
+       it87_idle_rx(dev);
+}
+
+/* enable the receiver; this must be called with the device spinlock held */
+static void it87_enable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the receiver by setting RXEN */
+       outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN,
+               dev->cir_addr + IT87_RCR);
+
+       /* just prepare it to idle for the next reception */
+       it87_idle_rx(dev);
+
+       /* enable the receiver interrupts and master enable flag */
+       outb(inb(dev->cir_addr + IT87_IER) | IT87_RDAIE | IT87_RFOIE | IT87_IEC,
+               dev->cir_addr + IT87_IER);
+}
+
+/* disable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it87_disable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the transmitter interrupts */
+       outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE,
+               dev->cir_addr + IT87_IER);
+}
+
+/* enable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it87_enable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the transmitter interrupts and master enable flag */
+       outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC,
+               dev->cir_addr + IT87_IER);
+}
+
+/* disable the device; this must be called with the device spinlock held */
+static void it87_disable(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* clear out all interrupt enable flags */
+       outb(inb(dev->cir_addr + IT87_IER) &
+               ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE),
+               dev->cir_addr + IT87_IER);
+
+       /* disable the receiver */
+       it87_disable_rx(dev);
+
+       /* erase the FIFO */
+       outb(IT87_FIFOCLR | inb(dev->cir_addr + IT87_TCR1),
+               dev->cir_addr + IT87_TCR1);
+}
+
+/* initialize the hardware */
+static void it87_init_hardware(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable just the baud rate divisor register,
+       disabling all the interrupts at the same time */
+       outb((inb(dev->cir_addr + IT87_IER) &
+               ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE)) | IT87_BR,
+               dev->cir_addr + IT87_IER);
+
+       /* write out the baud rate divisor */
+       outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT87_BDLR);
+       outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, dev->cir_addr + IT87_BDHR);
+
+       /* disable the baud rate divisor register again */
+       outb(inb(dev->cir_addr + IT87_IER) & ~IT87_BR,
+               dev->cir_addr + IT87_IER);
+
+       /* program the RCR register defaults */
+       outb(ITE_RXDCR_DEFAULT, dev->cir_addr + IT87_RCR);
+
+       /* program the TCR1 register */
+       outb(IT87_TXMPM_DEFAULT | IT87_TXENDF | IT87_TXRLE
+               | IT87_FIFOTL_DEFAULT | IT87_FIFOCLR,
+               dev->cir_addr + IT87_TCR1);
+
+       /* program the carrier parameters */
+       ite_set_carrier_params(dev);
+}
+
+/* IT8512F on ITE8708 HW-specific functions */
+
+/* retrieve a bitmask of the current causes for a pending interrupt; this may
+ * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN
+ * */
+static int it8708_get_irq_causes(struct ite_dev *dev)
+{
+       u8 iflags;
+       int ret = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read the interrupt flags */
+       iflags = inb(dev->cir_addr + IT8708_C0IIR);
+
+       if (iflags & IT85_TLDLI)
+               ret |= ITE_IRQ_TX_FIFO;
+       if (iflags & IT85_RDAI)
+               ret |= ITE_IRQ_RX_FIFO;
+       if (iflags & IT85_RFOI)
+               ret |= ITE_IRQ_RX_FIFO_OVERRUN;
+
+       return ret;
+}
+
+/* set the carrier parameters; to be called with the spinlock held */
+static void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq,
+                                     bool use_demodulator,
+                                     u8 carrier_freq_bits, u8 allowance_bits,
+                                     u8 pulse_width_bits)
+{
+       u8 val;
+
+       ite_dbg("%s called", __func__);
+
+       /* program the C0CFR register, with HRAE=1 */
+       outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE,
+               dev->cir_addr + IT8708_BANKSEL);
+
+       val = (inb(dev->cir_addr + IT8708_C0CFR)
+               & ~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits;
+
+       if (high_freq)
+               val |= IT85_HCFS;
+
+       outb(val, dev->cir_addr + IT8708_C0CFR);
+
+       outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE,
+                  dev->cir_addr + IT8708_BANKSEL);
+
+       /* program the C0RCR register */
+       val = inb(dev->cir_addr + IT8708_C0RCR)
+               & ~(IT85_RXEND | IT85_RXDCR);
+
+       if (use_demodulator)
+               val |= IT85_RXEND;
+
+       val |= allowance_bits;
+
+       outb(val, dev->cir_addr + IT8708_C0RCR);
+
+       /* program the C0TCR register */
+       val = inb(dev->cir_addr + IT8708_C0TCR) & ~IT85_TXMPW;
+       val |= pulse_width_bits;
+       outb(val, dev->cir_addr + IT8708_C0TCR);
+}
+
+/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock
+ * held */
+static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size)
+{
+       int fifo, read = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read how many bytes are still in the FIFO */
+       fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC;
+
+       while (fifo > 0 && buf_size > 0) {
+               *(buf++) = inb(dev->cir_addr + IT8708_C0DR);
+               fifo--;
+               read++;
+               buf_size--;
+       }
+
+       return read;
+}
+
+/* return how many bytes are still in the FIFO; this will be called
+ * with the device spinlock NOT HELD while waiting for the TX FIFO to get
+ * empty; let's expect this won't be a problem */
+static int it8708_get_tx_used_slots(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC;
+}
+
+/* put a byte to the TX fifo; this should be called with the spinlock held */
+static void it8708_put_tx_byte(struct ite_dev *dev, u8 value)
+{
+       outb(value, dev->cir_addr + IT8708_C0DR);
+}
+
+/* idle the receiver so that we won't receive samples until another
+  pulse is detected; this must be called with the device spinlock held */
+static void it8708_idle_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable streaming by clearing RXACT writing it as 1 */
+       outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT,
+               dev->cir_addr + IT8708_C0RCR);
+
+       /* clear the FIFO */
+       outb(inb(dev->cir_addr + IT8708_C0MSTCR) | IT85_FIFOCLR,
+               dev->cir_addr + IT8708_C0MSTCR);
+}
+
+/* disable the receiver; this must be called with the device spinlock held */
+static void it8708_disable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the receiver interrupts */
+       outb(inb(dev->cir_addr + IT8708_C0IER) &
+               ~(IT85_RDAIE | IT85_RFOIE),
+               dev->cir_addr + IT8708_C0IER);
+
+       /* disable the receiver */
+       outb(inb(dev->cir_addr + IT8708_C0RCR) & ~IT85_RXEN,
+               dev->cir_addr + IT8708_C0RCR);
+
+       /* clear the FIFO and RXACT (actually RXACT should have been cleared
+        * in the previous outb() call) */
+       it8708_idle_rx(dev);
+}
+
+/* enable the receiver; this must be called with the device spinlock held */
+static void it8708_enable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the receiver by setting RXEN */
+       outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN,
+               dev->cir_addr + IT8708_C0RCR);
+
+       /* just prepare it to idle for the next reception */
+       it8708_idle_rx(dev);
+
+       /* enable the receiver interrupts and master enable flag */
+       outb(inb(dev->cir_addr + IT8708_C0IER)
+               |IT85_RDAIE | IT85_RFOIE | IT85_IEC,
+               dev->cir_addr + IT8708_C0IER);
+}
+
+/* disable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it8708_disable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the transmitter interrupts */
+       outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE,
+               dev->cir_addr + IT8708_C0IER);
+}
+
+/* enable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it8708_enable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the transmitter interrupts and master enable flag */
+       outb(inb(dev->cir_addr + IT8708_C0IER)
+               |IT85_TLDLIE | IT85_IEC,
+               dev->cir_addr + IT8708_C0IER);
+}
+
+/* disable the device; this must be called with the device spinlock held */
+static void it8708_disable(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* clear out all interrupt enable flags */
+       outb(inb(dev->cir_addr + IT8708_C0IER) &
+               ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+               dev->cir_addr + IT8708_C0IER);
+
+       /* disable the receiver */
+       it8708_disable_rx(dev);
+
+       /* erase the FIFO */
+       outb(IT85_FIFOCLR | inb(dev->cir_addr + IT8708_C0MSTCR),
+               dev->cir_addr + IT8708_C0MSTCR);
+}
+
+/* initialize the hardware */
+static void it8708_init_hardware(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable all the interrupts */
+       outb(inb(dev->cir_addr + IT8708_C0IER) &
+               ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+               dev->cir_addr + IT8708_C0IER);
+
+       /* program the baud rate divisor */
+       outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE,
+               dev->cir_addr + IT8708_BANKSEL);
+
+       outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT8708_C0BDLR);
+       outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff,
+                  dev->cir_addr + IT8708_C0BDHR);
+
+       outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE,
+                  dev->cir_addr + IT8708_BANKSEL);
+
+       /* program the C0MSTCR register defaults */
+       outb((inb(dev->cir_addr + IT8708_C0MSTCR) &
+                       ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL |
+                         IT85_FIFOCLR | IT85_RESET)) |
+                      IT85_FIFOTL_DEFAULT,
+                      dev->cir_addr + IT8708_C0MSTCR);
+
+       /* program the C0RCR register defaults */
+       outb((inb(dev->cir_addr + IT8708_C0RCR) &
+                       ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND |
+                         IT85_RXACT | IT85_RXDCR)) |
+                      ITE_RXDCR_DEFAULT,
+                      dev->cir_addr + IT8708_C0RCR);
+
+       /* program the C0TCR register defaults */
+       outb((inb(dev->cir_addr + IT8708_C0TCR) &
+                       ~(IT85_TXMPM | IT85_TXMPW))
+                      |IT85_TXRLE | IT85_TXENDF |
+                      IT85_TXMPM_DEFAULT | IT85_TXMPW_DEFAULT,
+                      dev->cir_addr + IT8708_C0TCR);
+
+       /* program the carrier parameters */
+       ite_set_carrier_params(dev);
+}
+
+/* IT8512F on ITE8709 HW-specific functions */
+
+/* read a byte from the SRAM module */
+static inline u8 it8709_rm(struct ite_dev *dev, int index)
+{
+       outb(index, dev->cir_addr + IT8709_RAM_IDX);
+       return inb(dev->cir_addr + IT8709_RAM_VAL);
+}
+
+/* write a byte to the SRAM module */
+static inline void it8709_wm(struct ite_dev *dev, u8 val, int index)
+{
+       outb(index, dev->cir_addr + IT8709_RAM_IDX);
+       outb(val, dev->cir_addr + IT8709_RAM_VAL);
+}
+
+static void it8709_wait(struct ite_dev *dev)
+{
+       int i = 0;
+       /*
+        * loop until device tells it's ready to continue
+        * iterations count is usually ~750 but can sometimes achieve 13000
+        */
+       for (i = 0; i < 15000; i++) {
+               udelay(2);
+               if (it8709_rm(dev, IT8709_MODE) == IT8709_IDLE)
+                       break;
+       }
+}
+
+/* read the value of a CIR register */
+static u8 it8709_rr(struct ite_dev *dev, int index)
+{
+       /* just wait in case the previous access was a write */
+       it8709_wait(dev);
+       it8709_wm(dev, index, IT8709_REG_IDX);
+       it8709_wm(dev, IT8709_READ, IT8709_MODE);
+
+       /* wait for the read data to be available */
+       it8709_wait(dev);
+
+       /* return the read value */
+       return it8709_rm(dev, IT8709_REG_VAL);
+}
+
+/* write the value of a CIR register */
+static void it8709_wr(struct ite_dev *dev, u8 val, int index)
+{
+       /* we wait before writing, and not afterwards, since this allows us to
+        * pipeline the host CPU with the microcontroller */
+       it8709_wait(dev);
+       it8709_wm(dev, val, IT8709_REG_VAL);
+       it8709_wm(dev, index, IT8709_REG_IDX);
+       it8709_wm(dev, IT8709_WRITE, IT8709_MODE);
+}
+
+/* retrieve a bitmask of the current causes for a pending interrupt; this may
+ * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN
+ * */
+static int it8709_get_irq_causes(struct ite_dev *dev)
+{
+       u8 iflags;
+       int ret = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read the interrupt flags */
+       iflags = it8709_rm(dev, IT8709_IIR);
+
+       if (iflags & IT85_TLDLI)
+               ret |= ITE_IRQ_TX_FIFO;
+       if (iflags & IT85_RDAI)
+               ret |= ITE_IRQ_RX_FIFO;
+       if (iflags & IT85_RFOI)
+               ret |= ITE_IRQ_RX_FIFO_OVERRUN;
+
+       return ret;
+}
+
+/* set the carrier parameters; to be called with the spinlock held */
+static void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq,
+                                     bool use_demodulator,
+                                     u8 carrier_freq_bits, u8 allowance_bits,
+                                     u8 pulse_width_bits)
+{
+       u8 val;
+
+       ite_dbg("%s called", __func__);
+
+       val = (it8709_rr(dev, IT85_C0CFR)
+                    &~(IT85_HCFS | IT85_CFQ)) |
+           carrier_freq_bits;
+
+       if (high_freq)
+               val |= IT85_HCFS;
+
+       it8709_wr(dev, val, IT85_C0CFR);
+
+       /* program the C0RCR register */
+       val = it8709_rr(dev, IT85_C0RCR)
+               & ~(IT85_RXEND | IT85_RXDCR);
+
+       if (use_demodulator)
+               val |= IT85_RXEND;
+
+       val |= allowance_bits;
+
+       it8709_wr(dev, val, IT85_C0RCR);
+
+       /* program the C0TCR register */
+       val = it8709_rr(dev, IT85_C0TCR) & ~IT85_TXMPW;
+       val |= pulse_width_bits;
+       it8709_wr(dev, val, IT85_C0TCR);
+}
+
+/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock
+ * held */
+static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size)
+{
+       int fifo, read = 0;
+
+       ite_dbg("%s called", __func__);
+
+       /* read how many bytes are still in the FIFO */
+       fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC;
+
+       while (fifo > 0 && buf_size > 0) {
+               *(buf++) = it8709_rm(dev, IT8709_FIFO + read);
+               fifo--;
+               read++;
+               buf_size--;
+       }
+
+       /* 'clear' the FIFO by setting the writing index to 0; this is
+        * completely bound to be racy, but we can't help it, since it's a
+        * limitation of the protocol */
+       it8709_wm(dev, 0, IT8709_RFSR);
+
+       return read;
+}
+
+/* return how many bytes are still in the FIFO; this will be called
+ * with the device spinlock NOT HELD while waiting for the TX FIFO to get
+ * empty; let's expect this won't be a problem */
+static int it8709_get_tx_used_slots(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC;
+}
+
+/* put a byte to the TX fifo; this should be called with the spinlock held */
+static void it8709_put_tx_byte(struct ite_dev *dev, u8 value)
+{
+       it8709_wr(dev, value, IT85_C0DR);
+}
+
+/* idle the receiver so that we won't receive samples until another
+  pulse is detected; this must be called with the device spinlock held */
+static void it8709_idle_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable streaming by clearing RXACT writing it as 1 */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT,
+                           IT85_C0RCR);
+
+       /* clear the FIFO */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0MSTCR) | IT85_FIFOCLR,
+                           IT85_C0MSTCR);
+}
+
+/* disable the receiver; this must be called with the device spinlock held */
+static void it8709_disable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the receiver interrupts */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER) &
+                           ~(IT85_RDAIE | IT85_RFOIE),
+                           IT85_C0IER);
+
+       /* disable the receiver */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) & ~IT85_RXEN,
+                           IT85_C0RCR);
+
+       /* clear the FIFO and RXACT (actually RXACT should have been cleared
+        * in the previous it8709_wr(dev, ) call) */
+       it8709_idle_rx(dev);
+}
+
+/* enable the receiver; this must be called with the device spinlock held */
+static void it8709_enable_rx(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the receiver by setting RXEN */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN,
+                           IT85_C0RCR);
+
+       /* just prepare it to idle for the next reception */
+       it8709_idle_rx(dev);
+
+       /* enable the receiver interrupts and master enable flag */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER)
+                           |IT85_RDAIE | IT85_RFOIE | IT85_IEC,
+                           IT85_C0IER);
+}
+
+/* disable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it8709_disable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable the transmitter interrupts */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE,
+                           IT85_C0IER);
+}
+
+/* enable the transmitter interrupt; this must be called with the device
+ * spinlock held */
+static void it8709_enable_tx_interrupt(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* enable the transmitter interrupts and master enable flag */
+       it8709_wr(dev, it8709_rr(dev, IT85_C0IER)
+                           |IT85_TLDLIE | IT85_IEC,
+                           IT85_C0IER);
+}
+
+/* disable the device; this must be called with the device spinlock held */
+static void it8709_disable(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* clear out all interrupt enable flags */
+       it8709_wr(dev,
+                           it8709_rr(dev,
+                                     IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
+                                                     IT85_RDAIE |
+                                                     IT85_TLDLIE), IT85_C0IER);
+
+       /* disable the receiver */
+       it8709_disable_rx(dev);
+
+       /* erase the FIFO */
+       it8709_wr(dev, IT85_FIFOCLR | it8709_rr(dev, IT85_C0MSTCR),
+                           IT85_C0MSTCR);
+}
+
+/* initialize the hardware */
+static void it8709_init_hardware(struct ite_dev *dev)
+{
+       ite_dbg("%s called", __func__);
+
+       /* disable all the interrupts */
+       it8709_wr(dev,
+                           it8709_rr(dev,
+                                     IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
+                                                     IT85_RDAIE |
+                                                     IT85_TLDLIE), IT85_C0IER);
+
+       /* program the baud rate divisor */
+       it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR);
+       it8709_wr(dev, (ITE_BAUDRATE_DIVISOR >> 8) & 0xff,
+                       IT85_C0BDHR);
+
+       /* program the C0MSTCR register defaults */
+       it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & ~(IT85_ILSEL |
+                                                                  IT85_ILE
+                                                                  | IT85_FIFOTL
+                                                                  |
+                                                                  IT85_FIFOCLR
+                                                                  |
+                                                                  IT85_RESET))
+                           | IT85_FIFOTL_DEFAULT, IT85_C0MSTCR);
+
+       /* program the C0RCR register defaults */
+       it8709_wr(dev,
+                           (it8709_rr(dev, IT85_C0RCR) &
+                            ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND
+                              | IT85_RXACT | IT85_RXDCR)) |
+                           ITE_RXDCR_DEFAULT, IT85_C0RCR);
+
+       /* program the C0TCR register defaults */
+       it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR)
+                                 &~(IT85_TXMPM | IT85_TXMPW))
+                           |IT85_TXRLE | IT85_TXENDF |
+                           IT85_TXMPM_DEFAULT |
+                           IT85_TXMPW_DEFAULT, IT85_C0TCR);
+
+       /* program the carrier parameters */
+       ite_set_carrier_params(dev);
+}
+
+
+/* generic hardware setup/teardown code */
+
+/* activate the device for use */
+static int ite_open(struct rc_dev *rcdev)
+{
+       struct ite_dev *dev = rcdev->priv;
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->in_use = true;
+
+       /* enable the receiver */
+       dev->params.enable_rx(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+/* deactivate the device for use */
+static void ite_close(struct rc_dev *rcdev)
+{
+       struct ite_dev *dev = rcdev->priv;
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->in_use = false;
+
+       /* wait for any transmission to end */
+       spin_unlock_irqrestore(&dev->lock, flags);
+       wait_event_interruptible(dev->tx_ended, !dev->transmitting);
+       spin_lock_irqsave(&dev->lock, flags);
+
+       dev->params.disable(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* supported models and their parameters */
+static const struct ite_dev_params ite_dev_descs[] = {
+       {       /* 0: ITE8704 */
+              .model = "ITE8704 CIR transceiver",
+              .io_region_size = IT87_IOREG_LENGTH,
+              .hw_tx_capable = true,
+              .sample_period = (u32) (1000000000ULL / 115200),
+              .tx_carrier_freq = 38000,
+              .tx_duty_cycle = 33,
+              .rx_low_carrier_freq = 0,
+              .rx_high_carrier_freq = 0,
+
+               /* operations */
+              .get_irq_causes = it87_get_irq_causes,
+              .enable_rx = it87_enable_rx,
+              .idle_rx = it87_idle_rx,
+              .disable_rx = it87_idle_rx,
+              .get_rx_bytes = it87_get_rx_bytes,
+              .enable_tx_interrupt = it87_enable_tx_interrupt,
+              .disable_tx_interrupt = it87_disable_tx_interrupt,
+              .get_tx_used_slots = it87_get_tx_used_slots,
+              .put_tx_byte = it87_put_tx_byte,
+              .disable = it87_disable,
+              .init_hardware = it87_init_hardware,
+              .set_carrier_params = it87_set_carrier_params,
+              },
+       {       /* 1: ITE8713 */
+              .model = "ITE8713 CIR transceiver",
+              .io_region_size = IT87_IOREG_LENGTH,
+              .hw_tx_capable = true,
+              .sample_period = (u32) (1000000000ULL / 115200),
+              .tx_carrier_freq = 38000,
+              .tx_duty_cycle = 33,
+              .rx_low_carrier_freq = 0,
+              .rx_high_carrier_freq = 0,
+
+               /* operations */
+              .get_irq_causes = it87_get_irq_causes,
+              .enable_rx = it87_enable_rx,
+              .idle_rx = it87_idle_rx,
+              .disable_rx = it87_idle_rx,
+              .get_rx_bytes = it87_get_rx_bytes,
+              .enable_tx_interrupt = it87_enable_tx_interrupt,
+              .disable_tx_interrupt = it87_disable_tx_interrupt,
+              .get_tx_used_slots = it87_get_tx_used_slots,
+              .put_tx_byte = it87_put_tx_byte,
+              .disable = it87_disable,
+              .init_hardware = it87_init_hardware,
+              .set_carrier_params = it87_set_carrier_params,
+              },
+       {       /* 2: ITE8708 */
+              .model = "ITE8708 CIR transceiver",
+              .io_region_size = IT8708_IOREG_LENGTH,
+              .hw_tx_capable = true,
+              .sample_period = (u32) (1000000000ULL / 115200),
+              .tx_carrier_freq = 38000,
+              .tx_duty_cycle = 33,
+              .rx_low_carrier_freq = 0,
+              .rx_high_carrier_freq = 0,
+
+               /* operations */
+              .get_irq_causes = it8708_get_irq_causes,
+              .enable_rx = it8708_enable_rx,
+              .idle_rx = it8708_idle_rx,
+              .disable_rx = it8708_idle_rx,
+              .get_rx_bytes = it8708_get_rx_bytes,
+              .enable_tx_interrupt = it8708_enable_tx_interrupt,
+              .disable_tx_interrupt =
+              it8708_disable_tx_interrupt,
+              .get_tx_used_slots = it8708_get_tx_used_slots,
+              .put_tx_byte = it8708_put_tx_byte,
+              .disable = it8708_disable,
+              .init_hardware = it8708_init_hardware,
+              .set_carrier_params = it8708_set_carrier_params,
+              },
+       {       /* 3: ITE8709 */
+              .model = "ITE8709 CIR transceiver",
+              .io_region_size = IT8709_IOREG_LENGTH,
+              .hw_tx_capable = true,
+              .sample_period = (u32) (1000000000ULL / 115200),
+              .tx_carrier_freq = 38000,
+              .tx_duty_cycle = 33,
+              .rx_low_carrier_freq = 0,
+              .rx_high_carrier_freq = 0,
+
+               /* operations */
+              .get_irq_causes = it8709_get_irq_causes,
+              .enable_rx = it8709_enable_rx,
+              .idle_rx = it8709_idle_rx,
+              .disable_rx = it8709_idle_rx,
+              .get_rx_bytes = it8709_get_rx_bytes,
+              .enable_tx_interrupt = it8709_enable_tx_interrupt,
+              .disable_tx_interrupt =
+              it8709_disable_tx_interrupt,
+              .get_tx_used_slots = it8709_get_tx_used_slots,
+              .put_tx_byte = it8709_put_tx_byte,
+              .disable = it8709_disable,
+              .init_hardware = it8709_init_hardware,
+              .set_carrier_params = it8709_set_carrier_params,
+              },
+};
+
+static const struct pnp_device_id ite_ids[] = {
+       {"ITE8704", 0},         /* Default model */
+       {"ITE8713", 1},         /* CIR found in EEEBox 1501U */
+       {"ITE8708", 2},         /* Bridged IT8512 */
+       {"ITE8709", 3},         /* SRAM-Bridged IT8512 */
+       {"", 0},
+};
+
+/* allocate memory, probe hardware, and initialize everything */
+static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
+                    *dev_id)
+{
+       const struct ite_dev_params *dev_desc = NULL;
+       struct ite_dev *itdev = NULL;
+       struct rc_dev *rdev = NULL;
+       int ret = -ENOMEM;
+       int model_no;
+
+       ite_dbg("%s called", __func__);
+
+       itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL);
+       if (!itdev)
+               return ret;
+
+       /* input device for IR remote (and tx) */
+       rdev = rc_allocate_device();
+       if (!rdev)
+               goto failure;
+
+       ret = -ENODEV;
+
+       /* get the model number */
+       model_no = (int)dev_id->driver_data;
+       ite_pr(KERN_NOTICE, "Auto-detected model: %s\n",
+               ite_dev_descs[model_no].model);
+
+       if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) {
+               model_no = model_number;
+               ite_pr(KERN_NOTICE, "The model has been fixed by a module "
+                       "parameter.");
+       }
+
+       ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model);
+
+       /* get the description for the device */
+       dev_desc = &ite_dev_descs[model_no];
+
+       /* validate pnp resources */
+       if (!pnp_port_valid(pdev, 0) ||
+           pnp_port_len(pdev, 0) != dev_desc->io_region_size) {
+               dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+               goto failure;
+       }
+
+       if (!pnp_irq_valid(pdev, 0)) {
+               dev_err(&pdev->dev, "PNP IRQ not valid!\n");
+               goto failure;
+       }
+
+       /* store resource values */
+       itdev->cir_addr = pnp_port_start(pdev, 0);
+       itdev->cir_irq = pnp_irq(pdev, 0);
+
+       /* initialize spinlocks */
+       spin_lock_init(&itdev->lock);
+
+       /* initialize raw event */
+       init_ir_raw_event(&itdev->rawir);
+
+       ret = -EBUSY;
+       /* now claim resources */
+       if (!request_region(itdev->cir_addr,
+                               dev_desc->io_region_size, ITE_DRIVER_NAME))
+               goto failure;
+
+       if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED,
+                       ITE_DRIVER_NAME, (void *)itdev))
+               goto failure;
+
+       /* set driver data into the pnp device */
+       pnp_set_drvdata(pdev, itdev);
+       itdev->pdev = pdev;
+
+       /* initialize waitqueues for transmission */
+       init_waitqueue_head(&itdev->tx_queue);
+       init_waitqueue_head(&itdev->tx_ended);
+
+       /* copy model-specific parameters */
+       itdev->params = *dev_desc;
+
+       /* apply any overrides */
+       if (sample_period > 0)
+               itdev->params.sample_period = sample_period;
+
+       if (tx_carrier_freq > 0)
+               itdev->params.tx_carrier_freq = tx_carrier_freq;
+
+       if (tx_duty_cycle > 0 && tx_duty_cycle <= 100)
+               itdev->params.tx_duty_cycle = tx_duty_cycle;
+
+       if (rx_low_carrier_freq > 0)
+               itdev->params.rx_low_carrier_freq = rx_low_carrier_freq;
+
+       if (rx_high_carrier_freq > 0)
+               itdev->params.rx_high_carrier_freq = rx_high_carrier_freq;
+
+       /* print out parameters */
+       ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int)
+                        itdev->params.hw_tx_capable);
+       ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long)
+                    itdev->params.sample_period);
+       ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int)
+                    itdev->params.tx_carrier_freq);
+       ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int)
+                    itdev->params.tx_duty_cycle);
+       ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int)
+                    itdev->params.rx_low_carrier_freq);
+       ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int)
+                    itdev->params.rx_high_carrier_freq);
+
+       /* set up hardware initial state */
+       itdev->params.init_hardware(itdev);
+
+       /* set up ir-core props */
+       rdev->priv = itdev;
+       rdev->driver_type = RC_DRIVER_IR_RAW;
+       rdev->allowed_protos = RC_TYPE_ALL;
+       rdev->open = ite_open;
+       rdev->close = ite_close;
+       rdev->s_idle = ite_s_idle;
+       rdev->s_rx_carrier_range = ite_set_rx_carrier_range;
+       rdev->min_timeout = ITE_MIN_IDLE_TIMEOUT;
+       rdev->max_timeout = ITE_MAX_IDLE_TIMEOUT;
+       rdev->timeout = ITE_IDLE_TIMEOUT;
+       rdev->rx_resolution = ITE_BAUDRATE_DIVISOR *
+                               itdev->params.sample_period;
+       rdev->tx_resolution = ITE_BAUDRATE_DIVISOR *
+                               itdev->params.sample_period;
+
+       /* set up transmitter related values if needed */
+       if (itdev->params.hw_tx_capable) {
+               rdev->tx_ir = ite_tx_ir;
+               rdev->s_tx_carrier = ite_set_tx_carrier;
+               rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle;
+       }
+
+       rdev->input_name = dev_desc->model;
+       rdev->input_id.bustype = BUS_HOST;
+       rdev->input_id.vendor = PCI_VENDOR_ID_ITE;
+       rdev->input_id.product = 0;
+       rdev->input_id.version = 0;
+       rdev->driver_name = ITE_DRIVER_NAME;
+       rdev->map_name = RC_MAP_RC6_MCE;
+
+       ret = rc_register_device(rdev);
+       if (ret)
+               goto failure;
+
+       itdev->rdev = rdev;
+       ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+
+       return 0;
+
+failure:
+       if (itdev->cir_irq)
+               free_irq(itdev->cir_irq, itdev);
+
+       if (itdev->cir_addr)
+               release_region(itdev->cir_addr, itdev->params.io_region_size);
+
+       rc_free_device(rdev);
+       kfree(itdev);
+
+       return ret;
+}
+
+static void __devexit ite_remove(struct pnp_dev *pdev)
+{
+       struct ite_dev *dev = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* disable hardware */
+       dev->params.disable(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /* free resources */
+       free_irq(dev->cir_irq, dev);
+       release_region(dev->cir_addr, dev->params.io_region_size);
+
+       rc_unregister_device(dev->rdev);
+
+       kfree(dev);
+}
+
+static int ite_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+       struct ite_dev *dev = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* disable all interrupts */
+       dev->params.disable(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return 0;
+}
+
+static int ite_resume(struct pnp_dev *pdev)
+{
+       int ret = 0;
+       struct ite_dev *dev = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       if (dev->transmitting) {
+               /* wake up the transmitter */
+               wake_up_interruptible(&dev->tx_queue);
+       } else {
+               /* enable the receiver */
+               dev->params.enable_rx(dev);
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return ret;
+}
+
+static void ite_shutdown(struct pnp_dev *pdev)
+{
+       struct ite_dev *dev = pnp_get_drvdata(pdev);
+       unsigned long flags;
+
+       ite_dbg("%s called", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* disable all interrupts */
+       dev->params.disable(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static struct pnp_driver ite_driver = {
+       .name           = ITE_DRIVER_NAME,
+       .id_table       = ite_ids,
+       .probe          = ite_probe,
+       .remove         = __devexit_p(ite_remove),
+       .suspend        = ite_suspend,
+       .resume         = ite_resume,
+       .shutdown       = ite_shutdown,
+};
+
+int ite_init(void)
+{
+       return pnp_register_driver(&ite_driver);
+}
+
+void ite_exit(void)
+{
+       pnp_unregister_driver(&ite_driver);
+}
+
+MODULE_DEVICE_TABLE(pnp, ite_ids);
+MODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver");
+
+MODULE_AUTHOR("Juan J. Garcia de Soria <skandalfo@gmail.com>");
+MODULE_LICENSE("GPL");
+
+module_init(ite_init);
+module_exit(ite_exit);
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
new file mode 100644 (file)
index 0000000..16a19f5
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Driver for ITE Tech Inc. IT8712F/IT8512F CIR
+ *
+ * Copyright (C) 2010 Juan JesĆŗs GarcĆ­a de Soria <skandalfo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+/* platform driver name to register */
+#define ITE_DRIVER_NAME "ite-cir"
+
+/* logging macros */
+#define ite_pr(level, text, ...) \
+       printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+#define ite_dbg(text, ...) do { \
+       if (debug) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \
+} while (0)
+
+#define ite_dbg_verbose(text, ...) do {\
+       if (debug > 1) \
+               printk(KERN_DEBUG \
+                       KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \
+} while (0)
+
+/* FIFO sizes */
+#define ITE_TX_FIFO_LEN 32
+#define ITE_RX_FIFO_LEN 32
+
+/* interrupt types */
+#define ITE_IRQ_TX_FIFO        1
+#define ITE_IRQ_RX_FIFO        2
+#define ITE_IRQ_RX_FIFO_OVERRUN    4
+
+/* forward declaration */
+struct ite_dev;
+
+/* struct for storing the parameters of different recognized devices */
+struct ite_dev_params {
+       /* model of the device */
+       const char *model;
+
+       /* size of the I/O region */
+       int io_region_size;
+
+       /* true if the hardware supports transmission */
+       bool hw_tx_capable;
+
+       /* base sampling period, in ns */
+       u32 sample_period;
+
+       /* rx low carrier frequency, in Hz, 0 means no demodulation */
+       unsigned int rx_low_carrier_freq;
+
+       /* tx high carrier frequency, in Hz, 0 means no demodulation */
+       unsigned int rx_high_carrier_freq;
+
+       /* tx carrier frequency, in Hz */
+       unsigned int tx_carrier_freq;
+
+       /* duty cycle, 0-100 */
+       int tx_duty_cycle;
+
+       /* hw-specific operation function pointers; most of these must be
+        * called while holding the spin lock, except for the TX FIFO length
+        * one */
+       /* get pending interrupt causes */
+       int (*get_irq_causes) (struct ite_dev *dev);
+
+       /* enable rx */
+       void (*enable_rx) (struct ite_dev *dev);
+
+       /* make rx enter the idle state; keep listening for a pulse, but stop
+        * streaming space bytes */
+       void (*idle_rx) (struct ite_dev *dev);
+
+       /* disable rx completely */
+       void (*disable_rx) (struct ite_dev *dev);
+
+       /* read bytes from RX FIFO; return read count */
+       int (*get_rx_bytes) (struct ite_dev *dev, u8 *buf, int buf_size);
+
+       /* enable tx FIFO space available interrupt */
+       void (*enable_tx_interrupt) (struct ite_dev *dev);
+
+       /* disable tx FIFO space available interrupt */
+       void (*disable_tx_interrupt) (struct ite_dev *dev);
+
+       /* get number of full TX FIFO slots */
+       int (*get_tx_used_slots) (struct ite_dev *dev);
+
+       /* put a byte to the TX FIFO */
+       void (*put_tx_byte) (struct ite_dev *dev, u8 value);
+
+       /* disable hardware completely */
+       void (*disable) (struct ite_dev *dev);
+
+       /* initialize the hardware */
+       void (*init_hardware) (struct ite_dev *dev);
+
+       /* set the carrier parameters */
+       void (*set_carrier_params) (struct ite_dev *dev, bool high_freq,
+                                   bool use_demodulator, u8 carrier_freq_bits,
+                                   u8 allowance_bits, u8 pulse_width_bits);
+};
+
+/* ITE CIR device structure */
+struct ite_dev {
+       struct pnp_dev *pdev;
+       struct rc_dev *rdev;
+       struct ir_raw_event rawir;
+
+       /* sync data */
+       spinlock_t lock;
+       bool in_use, transmitting;
+
+       /* transmit support */
+       int tx_fifo_allowance;
+       wait_queue_head_t tx_queue, tx_ended;
+
+       /* hardware I/O settings */
+       unsigned long cir_addr;
+       int cir_irq;
+
+       /* overridable copy of model parameters */
+       struct ite_dev_params params;
+};
+
+/* common values for all kinds of hardware */
+
+/* baud rate divisor default */
+#define ITE_BAUDRATE_DIVISOR           1
+
+/* low-speed carrier frequency limits (Hz) */
+#define ITE_LCF_MIN_CARRIER_FREQ       27000
+#define ITE_LCF_MAX_CARRIER_FREQ       58000
+
+/* high-speed carrier frequency limits (Hz) */
+#define ITE_HCF_MIN_CARRIER_FREQ       400000
+#define ITE_HCF_MAX_CARRIER_FREQ       500000
+
+/* default carrier freq for when demodulator is off (Hz) */
+#define ITE_DEFAULT_CARRIER_FREQ       38000
+
+/* default idling timeout in ns (0.2 seconds) */
+#define ITE_IDLE_TIMEOUT               200000000UL
+
+/* limit timeout values */
+#define ITE_MIN_IDLE_TIMEOUT           100000000UL
+#define ITE_MAX_IDLE_TIMEOUT           1000000000UL
+
+/* convert bits to us */
+#define ITE_BITS_TO_NS(bits, sample_period) \
+((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period))
+
+/*
+ * n in RDCR produces a tolerance of +/- n * 6.25% around the center
+ * carrier frequency...
+ *
+ * From two limit frequencies, L (low) and H (high), we can get both the
+ * center frequency F = (L + H) / 2 and the variation from the center
+ * frequency A = (H - L) / (H + L). We can use this in order to honor the
+ * s_rx_carrier_range() call in ir-core. We'll suppose that any request
+ * setting L=0 means we must shut down the demodulator.
+ */
+#define ITE_RXDCR_PER_10000_STEP 625
+
+/* high speed carrier freq values */
+#define ITE_CFQ_400            0x03
+#define ITE_CFQ_450            0x08
+#define ITE_CFQ_480            0x0b
+#define ITE_CFQ_500            0x0d
+
+/* values for pulse widths */
+#define ITE_TXMPW_A            0x02
+#define ITE_TXMPW_B            0x03
+#define ITE_TXMPW_C            0x04
+#define ITE_TXMPW_D            0x05
+#define ITE_TXMPW_E            0x06
+
+/* values for demodulator carrier range allowance */
+#define ITE_RXDCR_DEFAULT      0x01    /* default carrier range */
+#define ITE_RXDCR_MAX          0x07    /* default carrier range */
+
+/* DR TX bits */
+#define ITE_TX_PULSE           0x00
+#define ITE_TX_SPACE           0x80
+#define ITE_TX_MAX_RLE         0x80
+#define ITE_TX_RLE_MASK                0x7f
+
+/*
+ * IT8712F
+ *
+ * hardware data obtained from:
+ *
+ * IT8712F
+ * Environment Control ā€“ Low Pin Count Input / Output
+ * (EC - LPC I/O)
+ * Preliminary Specification V0. 81
+ */
+
+/* register offsets */
+#define IT87_DR                0x00    /* data register */
+#define IT87_IER       0x01    /* interrupt enable register */
+#define IT87_RCR       0x02    /* receiver control register */
+#define IT87_TCR1      0x03    /* transmitter control register 1 */
+#define IT87_TCR2      0x04    /* transmitter control register 2 */
+#define IT87_TSR       0x05    /* transmitter status register */
+#define IT87_RSR       0x06    /* receiver status register */
+#define IT87_BDLR      0x05    /* baud rate divisor low byte register */
+#define IT87_BDHR      0x06    /* baud rate divisor high byte register */
+#define IT87_IIR       0x07    /* interrupt identification register */
+
+#define IT87_IOREG_LENGTH 0x08 /* length of register file */
+
+/* IER bits */
+#define IT87_TLDLIE    0x01    /* transmitter low data interrupt enable */
+#define IT87_RDAIE     0x02    /* receiver data available interrupt enable */
+#define IT87_RFOIE     0x04    /* receiver FIFO overrun interrupt enable */
+#define IT87_IEC       0x08    /* interrupt enable control */
+#define IT87_BR                0x10    /* baud rate register enable */
+#define IT87_RESET     0x20    /* reset */
+
+/* RCR bits */
+#define IT87_RXDCR     0x07    /* receiver demodulation carrier range mask */
+#define IT87_RXACT     0x08    /* receiver active */
+#define IT87_RXEND     0x10    /* receiver demodulation enable */
+#define IT87_RXEN      0x20    /* receiver enable */
+#define IT87_HCFS      0x40    /* high-speed carrier frequency select */
+#define IT87_RDWOS     0x80    /* receiver data without sync */
+
+/* TCR1 bits */
+#define IT87_TXMPM     0x03    /* transmitter modulation pulse mode mask */
+#define IT87_TXMPM_DEFAULT 0x00        /* modulation pulse mode default */
+#define IT87_TXENDF    0x04    /* transmitter deferral */
+#define IT87_TXRLE     0x08    /* transmitter run length enable */
+#define IT87_FIFOTL    0x30    /* FIFO level threshold mask */
+#define IT87_FIFOTL_DEFAULT 0x20       /* FIFO level threshold default
+                                        * 0x00 -> 1, 0x10 -> 7, 0x20 -> 17,
+                                        * 0x30 -> 25 */
+#define IT87_ILE       0x40    /* internal loopback enable */
+#define IT87_FIFOCLR   0x80    /* FIFO clear bit */
+
+/* TCR2 bits */
+#define IT87_TXMPW     0x07    /* transmitter modulation pulse width mask */
+#define IT87_TXMPW_DEFAULT 0x04        /* default modulation pulse width */
+#define IT87_CFQ       0xf8    /* carrier frequency mask */
+#define IT87_CFQ_SHIFT 3       /* carrier frequency bit shift */
+
+/* TSR bits */
+#define IT87_TXFBC     0x3f    /* transmitter FIFO byte count mask */
+
+/* RSR bits */
+#define IT87_RXFBC     0x3f    /* receiver FIFO byte count mask */
+#define IT87_RXFTO     0x80    /* receiver FIFO time-out */
+
+/* IIR bits */
+#define IT87_IP                0x01    /* interrupt pending */
+#define IT87_II                0x06    /* interrupt identification mask */
+#define IT87_II_NOINT  0x00    /* no interrupt */
+#define IT87_II_TXLDL  0x02    /* transmitter low data level */
+#define IT87_II_RXDS   0x04    /* receiver data stored */
+#define IT87_II_RXFO   0x06    /* receiver FIFO overrun */
+
+/*
+ * IT8512E/F
+ *
+ * Hardware data obtained from:
+ *
+ * IT8512E/F
+ * Embedded Controller
+ * Preliminary Specification V0.4.1
+ *
+ * Note that the CIR registers are not directly available to the host, because
+ * they only are accessible to the integrated microcontroller. Thus, in order
+ * use it, some kind of bridging is required. As the bridging may depend on
+ * the controller firmware in use, we are going to use the PNP ID in order to
+ * determine the strategy and ports available. See after these generic
+ * IT8512E/F register definitions for register definitions for those
+ * strategies.
+ */
+
+/* register offsets */
+#define IT85_C0DR      0x00    /* data register */
+#define IT85_C0MSTCR   0x01    /* master control register */
+#define IT85_C0IER     0x02    /* interrupt enable register */
+#define IT85_C0IIR     0x03    /* interrupt identification register */
+#define IT85_C0CFR     0x04    /* carrier frequency register */
+#define IT85_C0RCR     0x05    /* receiver control register */
+#define IT85_C0TCR     0x06    /* transmitter control register */
+#define IT85_C0SCK     0x07    /* slow clock control register */
+#define IT85_C0BDLR    0x08    /* baud rate divisor low byte register */
+#define IT85_C0BDHR    0x09    /* baud rate divisor high byte register */
+#define IT85_C0TFSR    0x0a    /* transmitter FIFO status register */
+#define IT85_C0RFSR    0x0b    /* receiver FIFO status register */
+#define IT85_C0WCL     0x0d    /* wakeup code length register */
+#define IT85_C0WCR     0x0e    /* wakeup code read/write register */
+#define IT85_C0WPS     0x0f    /* wakeup power control/status register */
+
+#define IT85_IOREG_LENGTH 0x10 /* length of register file */
+
+/* C0MSTCR bits */
+#define IT85_RESET     0x01    /* reset */
+#define IT85_FIFOCLR   0x02    /* FIFO clear bit */
+#define IT85_FIFOTL    0x0c    /* FIFO level threshold mask */
+#define IT85_FIFOTL_DEFAULT 0x08       /* FIFO level threshold default
+                                        * 0x00 -> 1, 0x04 -> 7, 0x08 -> 17,
+                                        * 0x0c -> 25 */
+#define IT85_ILE       0x10    /* internal loopback enable */
+#define IT85_ILSEL     0x20    /* internal loopback select */
+
+/* C0IER bits */
+#define IT85_TLDLIE    0x01    /* TX low data level interrupt enable */
+#define IT85_RDAIE     0x02    /* RX data available interrupt enable */
+#define IT85_RFOIE     0x04    /* RX FIFO overrun interrupt enable */
+#define IT85_IEC       0x80    /* interrupt enable function control */
+
+/* C0IIR bits */
+#define IT85_TLDLI     0x01    /* transmitter low data level interrupt */
+#define IT85_RDAI      0x02    /* receiver data available interrupt */
+#define IT85_RFOI      0x04    /* receiver FIFO overrun interrupt */
+#define IT85_NIP       0x80    /* no interrupt pending */
+
+/* C0CFR bits */
+#define IT85_CFQ       0x1f    /* carrier frequency mask */
+#define IT85_HCFS      0x20    /* high speed carrier frequency select */
+
+/* C0RCR bits */
+#define IT85_RXDCR     0x07    /* receiver demodulation carrier range mask */
+#define IT85_RXACT     0x08    /* receiver active */
+#define IT85_RXEND     0x10    /* receiver demodulation enable */
+#define IT85_RDWOS     0x20    /* receiver data without sync */
+#define IT85_RXEN      0x80    /* receiver enable */
+
+/* C0TCR bits */
+#define IT85_TXMPW     0x07    /* transmitter modulation pulse width mask */
+#define IT85_TXMPW_DEFAULT 0x04        /* default modulation pulse width */
+#define IT85_TXMPM     0x18    /* transmitter modulation pulse mode mask */
+#define IT85_TXMPM_DEFAULT 0x00        /* modulation pulse mode default */
+#define IT85_TXENDF    0x20    /* transmitter deferral */
+#define IT85_TXRLE     0x40    /* transmitter run length enable */
+
+/* C0SCK bits */
+#define IT85_SCKS      0x01    /* slow clock select */
+#define IT85_TXDCKG    0x02    /* TXD clock gating */
+#define IT85_DLL1P8E   0x04    /* DLL 1.8432M enable */
+#define IT85_DLLTE     0x08    /* DLL test enable */
+#define IT85_BRCM      0x70    /* baud rate count mode */
+#define IT85_DLLOCK    0x80    /* DLL lock */
+
+/* C0TFSR bits */
+#define IT85_TXFBC     0x3f    /* transmitter FIFO count mask */
+
+/* C0RFSR bits */
+#define IT85_RXFBC     0x3f    /* receiver FIFO count mask */
+#define IT85_RXFTO     0x80    /* receiver FIFO time-out */
+
+/* C0WCL bits */
+#define IT85_WCL       0x3f    /* wakeup code length mask */
+
+/* C0WPS bits */
+#define IT85_CIRPOSIE  0x01    /* power on/off status interrupt enable */
+#define IT85_CIRPOIS   0x02    /* power on/off interrupt status */
+#define IT85_CIRPOII   0x04    /* power on/off interrupt identification */
+#define IT85_RCRST     0x10    /* wakeup code reading counter reset bit */
+#define IT85_WCRST     0x20    /* wakeup code writing counter reset bit */
+
+/*
+ * ITE8708
+ *
+ * Hardware data obtained from hacked driver for IT8512 in this forum post:
+ *
+ *  http://ubuntuforums.org/showthread.php?t=1028640
+ *
+ * Although there's no official documentation for that driver, analysis would
+ * suggest that it maps the 16 registers of IT8512 onto two 8-register banks,
+ * selectable by a single bank-select bit that's mapped onto both banks. The
+ * IT8512 registers are mapped in a different order, so that the first bank
+ * maps the ones that are used more often, and two registers that share a
+ * reserved high-order bit are placed at the same offset in both banks in
+ * order to reuse the reserved bit as the bank select bit.
+ */
+
+/* register offsets */
+
+/* mapped onto both banks */
+#define IT8708_BANKSEL 0x07    /* bank select register */
+#define IT8708_HRAE    0x80    /* high registers access enable */
+
+/* mapped onto the low bank */
+#define IT8708_C0DR    0x00    /* data register */
+#define IT8708_C0MSTCR 0x01    /* master control register */
+#define IT8708_C0IER   0x02    /* interrupt enable register */
+#define IT8708_C0IIR   0x03    /* interrupt identification register */
+#define IT8708_C0RFSR  0x04    /* receiver FIFO status register */
+#define IT8708_C0RCR   0x05    /* receiver control register */
+#define IT8708_C0TFSR  0x06    /* transmitter FIFO status register */
+#define IT8708_C0TCR   0x07    /* transmitter control register */
+
+/* mapped onto the high bank */
+#define IT8708_C0BDLR  0x01    /* baud rate divisor low byte register */
+#define IT8708_C0BDHR  0x02    /* baud rate divisor high byte register */
+#define IT8708_C0CFR   0x04    /* carrier frequency register */
+
+/* registers whose bank mapping we don't know, since they weren't being used
+ * in the hacked driver... most probably they belong to the high bank too,
+ * since they fit in the holes the other registers leave */
+#define IT8708_C0SCK   0x03    /* slow clock control register */
+#define IT8708_C0WCL   0x05    /* wakeup code length register */
+#define IT8708_C0WCR   0x06    /* wakeup code read/write register */
+#define IT8708_C0WPS   0x07    /* wakeup power control/status register */
+
+#define IT8708_IOREG_LENGTH 0x08       /* length of register file */
+
+/* two more registers that are defined in the hacked driver, but can't be
+ * found in the data sheets; no idea what they are or how they are accessed,
+ * since the hacked driver doesn't seem to use them */
+#define IT8708_CSCRR   0x00
+#define IT8708_CGPINTR 0x01
+
+/* CSCRR bits */
+#define IT8708_CSCRR_SCRB 0x3f
+#define IT8708_CSCRR_PM        0x80
+
+/* CGPINTR bits */
+#define IT8708_CGPINT  0x01
+
+/*
+ * ITE8709
+ *
+ * Hardware interfacing data obtained from the original lirc_ite8709 driver.
+ * Verbatim from its sources:
+ *
+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and
+ * a specific firmware running on the IT8512's embedded micro-controller.
+ * In addition of the embedded micro-controller, the IT8512 chip contains a
+ * CIR module and several other modules. A few modules are directly accessible
+ * by the host CPU, but most of them are only accessible by the
+ * micro-controller. The CIR module is only accessible by the
+ * micro-controller.
+ *
+ * The battery-backed SRAM module is accessible by the host CPU and the
+ * micro-controller. So one of the MC's firmware role is to act as a bridge
+ * between the host CPU and the CIR module. The firmware implements a kind of
+ * communication protocol using the SRAM module as a shared memory. The IT8512
+ * specification is publicly available on ITE's web site, but the
+ * communication protocol is not, so it was reverse-engineered.
+ */
+
+/* register offsets */
+#define IT8709_RAM_IDX 0x00    /* index into the SRAM module bytes */
+#define IT8709_RAM_VAL 0x01    /* read/write data to the indexed byte */
+
+#define IT8709_IOREG_LENGTH 0x02       /* length of register file */
+
+/* register offsets inside the SRAM module */
+#define IT8709_MODE    0x1a    /* request/ack byte */
+#define IT8709_REG_IDX 0x1b    /* index of the CIR register to access */
+#define IT8709_REG_VAL 0x1c    /* value read/to be written */
+#define IT8709_IIR     0x1e    /* interrupt identification register */
+#define IT8709_RFSR    0x1f    /* receiver FIFO status register */
+#define IT8709_FIFO    0x20    /* start of in RAM RX FIFO copy */
+
+/* MODE values */
+#define IT8709_IDLE    0x00
+#define IT8709_WRITE   0x01
+#define IT8709_READ    0x02
index 0659e9f501445a97925c56b7c518f4a61b1e501c..85cac7ddbcec89870e944954e2c923358703b255 100644 (file)
@@ -37,7 +37,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-gadmei-rm008z.o \
                        rc-genius-tvgo-a11mce.o \
                        rc-gotview7135.o \
-                       rc-hauppauge-new.o \
                        rc-imon-mce.o \
                        rc-imon-pad.o \
                        rc-iodata-bctv7e.o \
@@ -68,14 +67,15 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-proteus-2309.o \
                        rc-purpletv.o \
                        rc-pv951.o \
-                       rc-rc5-hauppauge-new.o \
-                       rc-rc5-tv.o \
+                       rc-hauppauge.o \
                        rc-rc6-mce.o \
                        rc-real-audio-220-32-keys.o \
                        rc-streamzap.o \
                        rc-tbs-nec.o \
+                       rc-technisat-usb2.o \
                        rc-terratec-cinergy-xs.o \
                        rc-terratec-slim.o \
+                       rc-terratec-slim-2.o \
                        rc-tevii-nec.o \
                        rc-total-media-in-hand.o \
                        rc-trekstor.o \
index 136d3952dedc3bbf3d1173481bdd6150c2eae776..9a8752fdcca1f0b3f22398b04887206defc07ed6 100644 (file)
@@ -50,9 +50,9 @@ static struct rc_map_table adstech_dvb_t_pci[] = {
        { 0x13, KEY_TUNER },            /* Live */
        { 0x0a, KEY_A },
        { 0x12, KEY_B },
-       { 0x03, KEY_PROG1 },            /* 1 */
-       { 0x01, KEY_PROG2 },            /* 2 */
-       { 0x00, KEY_PROG3 },            /* 3 */
+       { 0x03, KEY_RED },              /* 1 */
+       { 0x01, KEY_GREEN },            /* 2 */
+       { 0x00, KEY_YELLOW },           /* 3 */
        { 0x06, KEY_DVD },
        { 0x48, KEY_AUX },              /* Photo */
        { 0x40, KEY_VIDEO },
index 3ddb41bc075e298b7baeeea87500cb867b599352..c25809d4c8138f445cff1ece2a9bf61f6de5e2f6 100644 (file)
@@ -26,12 +26,12 @@ static struct rc_map_table avermedia_dvbt[] = {
        { 0x16, KEY_8 },                /* '8' / 'down arrow' */
        { 0x36, KEY_9 },                /* '9' */
 
-       { 0x20, KEY_LIST },             /* 'source' */
+       { 0x20, KEY_VIDEO },            /* 'source' */
        { 0x10, KEY_TEXT },             /* 'teletext' */
        { 0x00, KEY_POWER },            /* 'power' */
        { 0x04, KEY_AUDIO },            /* 'audio' */
        { 0x06, KEY_ZOOM },             /* 'full screen' */
-       { 0x18, KEY_VIDEO },            /* 'display' */
+       { 0x18, KEY_SWITCHVIDEOMODE },  /* 'display' */
        { 0x38, KEY_SEARCH },           /* 'loop' */
        { 0x08, KEY_INFO },             /* 'preview' */
        { 0x2a, KEY_REWIND },           /* 'backward <<' */
index 357fea58a46e15e69372d50e3cde05b52dd539d1..3d2cbe4e5e46c1f3739aebd937322cd160938e71 100644 (file)
@@ -108,7 +108,7 @@ static struct rc_map_table avermedia_m135a[] = {
        { 0x0414, KEY_TEXT },
        { 0x0415, KEY_EPG },
        { 0x041a, KEY_TV2 },      /* PIP */
-       { 0x041b, KEY_MHP },      /* Snapshot */
+       { 0x041b, KEY_CAMERA },      /* Snapshot */
 
        { 0x0417, KEY_RECORD },
        { 0x0416, KEY_PLAYPAUSE },
index e694e6eac37e1bc38d66c35cc98a6cbbaec9e7a5..8cd7f28808bdad9541c7a4438f5cc5eb1bdd6cde 100644 (file)
@@ -56,7 +56,7 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = {
        { 0x0414, KEY_TEXT },
        { 0x0415, KEY_EPG },
        { 0x041a, KEY_TV2 },      /* PIP */
-       { 0x041b, KEY_MHP },      /* Snapshot */
+       { 0x041b, KEY_CAMERA },      /* Snapshot */
 
        { 0x0417, KEY_RECORD },
        { 0x0416, KEY_PLAYPAUSE },
index f4ca1fff455dceb34f73252fa8f25bfa685cf711..9d68af217d8b0d92f0fee0dd8a123f4fa930c9dd 100644 (file)
@@ -31,7 +31,7 @@ static struct rc_map_table avermedia_rm_ks[] = {
        { 0x0505, KEY_VOLUMEDOWN },
        { 0x0506, KEY_MUTE },
        { 0x0507, KEY_RIGHT },
-       { 0x0508, KEY_PROG1 },
+       { 0x0508, KEY_RED },
        { 0x0509, KEY_1 },
        { 0x050a, KEY_2 },
        { 0x050b, KEY_3 },
index 4b787fa94f08cce03be8e2ab28701ea1f3c3ccad..8bf058f67f0c7802856c2e31d558c7feac79f4b2 100644 (file)
@@ -28,7 +28,7 @@ static struct rc_map_table behold_columbus[] = {
         *                             */
 
        { 0x13, KEY_MUTE },
-       { 0x11, KEY_PROPS },
+       { 0x11, KEY_VIDEO },
        { 0x1C, KEY_TUNER },    /* KEY_TV/KEY_RADIO     */
        { 0x12, KEY_POWER },
 
index 0ee1f149364ce4bf3937f478f11b9d1b7279cb2b..c909a234c77651db350494450e4d64d0202c6d30 100644 (file)
@@ -97,7 +97,7 @@ static struct rc_map_table behold[] = {
        { 0x6b861a, KEY_STOP },
        { 0x6b860e, KEY_TEXT },
        { 0x6b861f, KEY_RED },  /*XXX KEY_AUDIO */
-       { 0x6b861e, KEY_YELLOW },       /*XXX KEY_SOURCE        */
+       { 0x6b861e, KEY_VIDEO },
 
        /*  0x1d   0x13     0x19  *
         * SLEEP  PREVIEW   DVB   *
index 97fc3862f608a3ba4d97ef165f90eca06dbdc327..2f66e4310d20801e09a5baa3a159ba20a5228786 100644 (file)
@@ -12,7 +12,8 @@
 
 #include <media/rc-map.h>
 
-/* From reading the following remotes:
+/*
+ * From reading the following remotes:
  * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
  * Hauppauge (from NOVA-CI-s box product)
  * This is a "middle of the road" approach, differences are noted
index 99520ff65b6157768fc96b1137a25ab703c66168..cf3a6bfb190c33cc1a4c33a08855ec7fe4ebd68a 100644 (file)
@@ -25,7 +25,7 @@ static struct rc_map_table cinergy[] = {
        { 0x09, KEY_9 },
 
        { 0x0a, KEY_POWER },
-       { 0x0b, KEY_PROG1 },            /* app */
+       { 0x0b, KEY_MEDIA },            /* app */
        { 0x0c, KEY_ZOOM },             /* zoom/fullscreen */
        { 0x0d, KEY_CHANNELUP },        /* channel */
        { 0x0e, KEY_CHANNELDOWN },      /* channel- */
index 43912bd02a9e94201a49a6925bc794173a2ac44c..82c0200029afd2c05f9bf8f668dd2c232294b33a 100644 (file)
@@ -32,7 +32,7 @@ static struct rc_map_table dntv_live_dvb_t[] = {
        { 0x0c, KEY_SEARCH },           /* scan */
        { 0x0d, KEY_STOP },
        { 0x0e, KEY_PAUSE },
-       { 0x0f, KEY_LIST },             /* source */
+       { 0x0f, KEY_VIDEO },            /* source */
 
        { 0x10, KEY_MUTE },
        { 0x11, KEY_REWIND },           /* backward << */
index afa4e92284ef546e71df080a76428600801477e2..e56ac6e9670ad299a31f87b25cc8d9f3882d134b 100644 (file)
@@ -24,7 +24,7 @@ static struct rc_map_table encore_enltv[] = {
        { 0x1e, KEY_TV },
        { 0x00, KEY_VIDEO },
        { 0x01, KEY_AUDIO },            /* music */
-       { 0x02, KEY_MHP },              /* picture */
+       { 0x02, KEY_CAMERA },           /* picture */
 
        { 0x1f, KEY_1 },
        { 0x03, KEY_2 },
@@ -77,7 +77,7 @@ static struct rc_map_table encore_enltv[] = {
        { 0x50, KEY_SLEEP },            /* shutdown */
        { 0x51, KEY_MODE },             /* stereo > main */
        { 0x52, KEY_SELECT },           /* stereo > sap */
-       { 0x53, KEY_PROG1 },            /* teletext */
+       { 0x53, KEY_TEXT },             /* teletext */
 
 
        { 0x59, KEY_RED },              /* AP1 */
index 7d5b00ed4ff2f97831a297831be1901e7c14209d..b6264f1bc4c113d13331b066dead373587364786 100644 (file)
@@ -32,7 +32,7 @@ static struct rc_map_table encore_enltv2[] = {
        { 0x64, KEY_LAST },             /* +100 */
        { 0x4e, KEY_AGAIN },            /* Recall */
 
-       { 0x6c, KEY_SWITCHVIDEOMODE },  /* Video Source */
+       { 0x6c, KEY_VIDEO },            /* Video Source */
        { 0x5e, KEY_MENU },
        { 0x56, KEY_SCREEN },
        { 0x7a, KEY_SETUP },
index aea2f4acf7d8b21fc83c5c35fc9b1ed8f46f83d2..a8b0f66edaa9c15beb69d3fb181548d299292e3d 100644 (file)
@@ -37,8 +37,8 @@ static struct rc_map_table flydvb[] = {
        { 0x13, KEY_CHANNELDOWN },      /* CH- */
        { 0x1d, KEY_ENTER },            /* Enter */
 
-       { 0x1a, KEY_MODE },             /* PIP */
-       { 0x18, KEY_TUNER },            /* Source */
+       { 0x1a, KEY_TV2 },              /* PIP */
+       { 0x18, KEY_VIDEO },            /* Source */
 
        { 0x1e, KEY_RECORD },           /* Record/Pause */
        { 0x15, KEY_ANGLE },            /* Swap (no label on key) */
diff --git a/drivers/media/rc/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c
deleted file mode 100644 (file)
index bd11da4..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* hauppauge-new.h - Keytable for hauppauge_new Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/* Hauppauge: the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- * almost rc5 coding, but some non-standard keys */
-
-static struct rc_map_table hauppauge_new[] = {
-       /* Keys 0 to 9 */
-       { 0x00, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-
-       { 0x0a, KEY_TEXT },             /* keypad asterisk as well */
-       { 0x0b, KEY_RED },              /* red button */
-       { 0x0c, KEY_RADIO },
-       { 0x0d, KEY_MENU },
-       { 0x0e, KEY_SUBTITLE },         /* also the # key */
-       { 0x0f, KEY_MUTE },
-       { 0x10, KEY_VOLUMEUP },
-       { 0x11, KEY_VOLUMEDOWN },
-       { 0x12, KEY_PREVIOUS },         /* previous channel */
-       { 0x14, KEY_UP },
-       { 0x15, KEY_DOWN },
-       { 0x16, KEY_LEFT },
-       { 0x17, KEY_RIGHT },
-       { 0x18, KEY_VIDEO },            /* Videos */
-       { 0x19, KEY_AUDIO },            /* Music */
-       /* 0x1a: Pictures - presume this means
-          "Multimedia Home Platform" -
-          no "PICTURES" key in input.h
-        */
-       { 0x1a, KEY_MHP },
-
-       { 0x1b, KEY_EPG },              /* Guide */
-       { 0x1c, KEY_TV },
-       { 0x1e, KEY_NEXTSONG },         /* skip >| */
-       { 0x1f, KEY_EXIT },             /* back/exit */
-       { 0x20, KEY_CHANNELUP },        /* channel / program + */
-       { 0x21, KEY_CHANNELDOWN },      /* channel / program - */
-       { 0x22, KEY_CHANNEL },          /* source (old black remote) */
-       { 0x24, KEY_PREVIOUSSONG },     /* replay |< */
-       { 0x25, KEY_ENTER },            /* OK */
-       { 0x26, KEY_SLEEP },            /* minimize (old black remote) */
-       { 0x29, KEY_BLUE },             /* blue key */
-       { 0x2e, KEY_GREEN },            /* green button */
-       { 0x30, KEY_PAUSE },            /* pause */
-       { 0x32, KEY_REWIND },           /* backward << */
-       { 0x34, KEY_FASTFORWARD },      /* forward >> */
-       { 0x35, KEY_PLAY },
-       { 0x36, KEY_STOP },
-       { 0x37, KEY_RECORD },           /* recording */
-       { 0x38, KEY_YELLOW },           /* yellow key */
-       { 0x3b, KEY_SELECT },           /* top right button */
-       { 0x3c, KEY_ZOOM },             /* full */
-       { 0x3d, KEY_POWER },            /* system power (green button) */
-};
-
-static struct rc_map_list hauppauge_new_map = {
-       .map = {
-               .scan    = hauppauge_new,
-               .size    = ARRAY_SIZE(hauppauge_new),
-               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
-               .name    = RC_MAP_HAUPPAUGE_NEW,
-       }
-};
-
-static int __init init_rc_map_hauppauge_new(void)
-{
-       return rc_map_register(&hauppauge_new_map);
-}
-
-static void __exit exit_rc_map_hauppauge_new(void)
-{
-       rc_map_unregister(&hauppauge_new_map);
-}
-
-module_init(init_rc_map_hauppauge_new)
-module_exit(exit_rc_map_hauppauge_new)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c
new file mode 100644 (file)
index 0000000..cd3db77
--- /dev/null
@@ -0,0 +1,241 @@
+/* rc-hauppauge.c - Keytable for Hauppauge Remote Controllers
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * This map currently contains the code for four different RCs:
+ *     - New Hauppauge Gray;
+ *     - Old Hauppauge Gray (with a golden screen for media keys);
+ *     - Hauppauge Black;
+ *     - DSR-0112 remote bundled with Haupauge MiniStick.
+ *
+ * Copyright (c) 2010-2011 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Hauppauge:the newer, gray remotes (seems there are multiple
+ * slightly different versions), shipped with cx88+ivtv cards.
+ *
+ * This table contains the complete RC5 code, instead of just the data part
+ */
+
+static struct rc_map_table rc5_hauppauge_new[] = {
+       /*
+        * Remote Controller Hauppauge Gray found on modern devices
+        * Keycodes start with address = 0x1e
+        */
+
+       { 0x1e3b, KEY_SELECT },         /* GO / house symbol */
+       { 0x1e3d, KEY_POWER2 },         /* system power (green button) */
+
+       { 0x1e1c, KEY_TV },
+       { 0x1e18, KEY_VIDEO },          /* Videos */
+       { 0x1e19, KEY_AUDIO },          /* Music */
+       { 0x1e1a, KEY_CAMERA },         /* Pictures */
+
+       { 0x1e1b, KEY_EPG },            /* Guide */
+       { 0x1e0c, KEY_RADIO },
+
+       { 0x1e14, KEY_UP },
+       { 0x1e15, KEY_DOWN },
+       { 0x1e16, KEY_LEFT },
+       { 0x1e17, KEY_RIGHT },
+       { 0x1e25, KEY_OK },             /* OK */
+
+       { 0x1e1f, KEY_EXIT },           /* back/exit */
+       { 0x1e0d, KEY_MENU },
+
+       { 0x1e10, KEY_VOLUMEUP },
+       { 0x1e11, KEY_VOLUMEDOWN },
+
+       { 0x1e12, KEY_PREVIOUS },       /* previous channel */
+       { 0x1e0f, KEY_MUTE },
+
+       { 0x1e20, KEY_CHANNELUP },      /* channel / program + */
+       { 0x1e21, KEY_CHANNELDOWN },    /* channel / program - */
+
+       { 0x1e37, KEY_RECORD },         /* recording */
+       { 0x1e36, KEY_STOP },
+
+       { 0x1e32, KEY_REWIND },         /* backward << */
+       { 0x1e35, KEY_PLAY },
+       { 0x1e34, KEY_FASTFORWARD },    /* forward >> */
+
+       { 0x1e24, KEY_PREVIOUSSONG },   /* replay |< */
+       { 0x1e30, KEY_PAUSE },          /* pause */
+       { 0x1e1e, KEY_NEXTSONG },       /* skip >| */
+
+       { 0x1e01, KEY_1 },
+       { 0x1e02, KEY_2 },
+       { 0x1e03, KEY_3 },
+
+       { 0x1e04, KEY_4 },
+       { 0x1e05, KEY_5 },
+       { 0x1e06, KEY_6 },
+
+       { 0x1e07, KEY_7 },
+       { 0x1e08, KEY_8 },
+       { 0x1e09, KEY_9 },
+
+       { 0x1e0a, KEY_TEXT },           /* keypad asterisk as well */
+       { 0x1e00, KEY_0 },
+       { 0x1e0e, KEY_SUBTITLE },       /* also the Pound key (#) */
+
+       { 0x1e0b, KEY_RED },            /* red button */
+       { 0x1e2e, KEY_GREEN },          /* green button */
+       { 0x1e38, KEY_YELLOW },         /* yellow key */
+       { 0x1e29, KEY_BLUE },           /* blue key */
+
+       /*
+        * Old Remote Controller Hauppauge Gray with a golden screen
+        * Keycodes start with address = 0x1f
+        */
+       { 0x1f3d, KEY_POWER2 },         /* system power (green button) */
+       { 0x1f3b, KEY_SELECT },         /* GO */
+
+       /* Keys 0 to 9 */
+       { 0x1f00, KEY_0 },
+       { 0x1f01, KEY_1 },
+       { 0x1f02, KEY_2 },
+       { 0x1f03, KEY_3 },
+       { 0x1f04, KEY_4 },
+       { 0x1f05, KEY_5 },
+       { 0x1f06, KEY_6 },
+       { 0x1f07, KEY_7 },
+       { 0x1f08, KEY_8 },
+       { 0x1f09, KEY_9 },
+
+       { 0x1f1f, KEY_EXIT },           /* back/exit */
+       { 0x1f0d, KEY_MENU },
+
+       { 0x1f10, KEY_VOLUMEUP },
+       { 0x1f11, KEY_VOLUMEDOWN },
+       { 0x1f20, KEY_CHANNELUP },      /* channel / program + */
+       { 0x1f21, KEY_CHANNELDOWN },    /* channel / program - */
+       { 0x1f25, KEY_ENTER },          /* OK */
+
+       { 0x1f0b, KEY_RED },            /* red button */
+       { 0x1f2e, KEY_GREEN },          /* green button */
+       { 0x1f38, KEY_YELLOW },         /* yellow key */
+       { 0x1f29, KEY_BLUE },           /* blue key */
+
+       { 0x1f0f, KEY_MUTE },
+       { 0x1f0c, KEY_RADIO },          /* There's no indicator on this key */
+       { 0x1f3c, KEY_ZOOM },           /* full */
+
+       { 0x1f32, KEY_REWIND },         /* backward << */
+       { 0x1f35, KEY_PLAY },
+       { 0x1f34, KEY_FASTFORWARD },    /* forward >> */
+
+       { 0x1f37, KEY_RECORD },         /* recording */
+       { 0x1f36, KEY_STOP },
+       { 0x1f30, KEY_PAUSE },          /* pause */
+
+       { 0x1f24, KEY_PREVIOUSSONG },   /* replay |< */
+       { 0x1f1e, KEY_NEXTSONG },       /* skip >| */
+
+       /*
+        * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick
+        * Keycodes start with address = 0x1d
+        */
+       { 0x1d00, KEY_0 },
+       { 0x1d01, KEY_1 },
+       { 0x1d02, KEY_2 },
+       { 0x1d03, KEY_3 },
+       { 0x1d04, KEY_4 },
+       { 0x1d05, KEY_5 },
+       { 0x1d06, KEY_6 },
+       { 0x1d07, KEY_7 },
+       { 0x1d08, KEY_8 },
+       { 0x1d09, KEY_9 },
+       { 0x1d0a, KEY_TEXT },
+       { 0x1d0d, KEY_MENU },
+       { 0x1d0f, KEY_MUTE },
+       { 0x1d10, KEY_VOLUMEUP },
+       { 0x1d11, KEY_VOLUMEDOWN },
+       { 0x1d12, KEY_PREVIOUS },        /* Prev.Ch .. ??? */
+       { 0x1d14, KEY_UP },
+       { 0x1d15, KEY_DOWN },
+       { 0x1d16, KEY_LEFT },
+       { 0x1d17, KEY_RIGHT },
+       { 0x1d1c, KEY_TV },
+       { 0x1d1e, KEY_NEXT },           /* >|             */
+       { 0x1d1f, KEY_EXIT },
+       { 0x1d20, KEY_CHANNELUP },
+       { 0x1d21, KEY_CHANNELDOWN },
+       { 0x1d24, KEY_LAST },           /* <|             */
+       { 0x1d25, KEY_OK },
+       { 0x1d30, KEY_PAUSE },
+       { 0x1d32, KEY_REWIND },
+       { 0x1d34, KEY_FASTFORWARD },
+       { 0x1d35, KEY_PLAY },
+       { 0x1d36, KEY_STOP },
+       { 0x1d37, KEY_RECORD },
+       { 0x1d3b, KEY_GOTO },
+       { 0x1d3d, KEY_POWER },
+       { 0x1d3f, KEY_HOME },
+
+       /*
+        * Keycodes for the old Black Remote Controller
+        * This one also uses RC-5 protocol
+        * Keycodes start with address = 0x00
+        */
+       { 0x001f, KEY_TV },
+       { 0x0020, KEY_CHANNELUP },
+       { 0x000c, KEY_RADIO },
+
+       { 0x0011, KEY_VOLUMEDOWN },
+       { 0x002e, KEY_ZOOM },           /* full screen */
+       { 0x0010, KEY_VOLUMEUP },
+
+       { 0x000d, KEY_MUTE },
+       { 0x0021, KEY_CHANNELDOWN },
+       { 0x0022, KEY_VIDEO },          /* source */
+
+       { 0x0001, KEY_1 },
+       { 0x0002, KEY_2 },
+       { 0x0003, KEY_3 },
+
+       { 0x0004, KEY_4 },
+       { 0x0005, KEY_5 },
+       { 0x0006, KEY_6 },
+
+       { 0x0007, KEY_7 },
+       { 0x0008, KEY_8 },
+       { 0x0009, KEY_9 },
+
+       { 0x001e, KEY_RED },    /* Reserved */
+       { 0x0000, KEY_0 },
+       { 0x0026, KEY_SLEEP },  /* Minimize */
+};
+
+static struct rc_map_list rc5_hauppauge_new_map = {
+       .map = {
+               .scan    = rc5_hauppauge_new,
+               .size    = ARRAY_SIZE(rc5_hauppauge_new),
+               .rc_type = RC_TYPE_RC5,
+               .name    = RC_MAP_HAUPPAUGE,
+       }
+};
+
+static int __init init_rc_map_rc5_hauppauge_new(void)
+{
+       return rc_map_register(&rc5_hauppauge_new_map);
+}
+
+static void __exit exit_rc_map_rc5_hauppauge_new(void)
+{
+       rc_map_unregister(&rc5_hauppauge_new_map);
+}
+
+module_init(init_rc_map_rc5_hauppauge_new)
+module_exit(exit_rc_map_rc5_hauppauge_new)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
index cb67184e015c6d440e9380182c4d8fa50716ae27..937a81989f00c7c9559f6a8da078f573c75396c3 100644 (file)
@@ -111,7 +111,7 @@ static struct rc_map_table imon_mce[] = {
        { 0x800ff44d, KEY_TITLE },
 
        { 0x800ff40c, KEY_POWER },
-       { 0x800ff40d, KEY_PROG1 }, /* Windows MCE button */
+       { 0x800ff40d, KEY_LEFTMETA }, /* Windows MCE button */
 
 };
 
index eef46b73ca7b8532e0a13aa0afa4fdc93524798c..63d42bd24c9e382280235cb889701c69ddd2eb29 100644 (file)
@@ -125,7 +125,7 @@ static struct rc_map_table imon_pad[] = {
        { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/
        { 0x02000065, KEY_COMPOSE }, /* RightMenu */
        { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */
-       { 0x2ab195b7, KEY_PROG1 }, /* Go or MultiMon */
+       { 0x2ab195b7, KEY_LEFTMETA }, /* Go or MultiMon */
        { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
 };
 
index 3ce6ef79fc347330230ab8c681d5b7f8efddf869..7f33edb4724437625ceb9839d6c1a6ed2d6a2330 100644 (file)
@@ -17,7 +17,7 @@
 
 static struct rc_map_table kworld_315u[] = {
        { 0x6143, KEY_POWER },
-       { 0x6101, KEY_TUNER },          /* source */
+       { 0x6101, KEY_VIDEO },          /* source */
        { 0x610b, KEY_ZOOM },
        { 0x6103, KEY_POWER2 },         /* shutdown */
 
index e45f0b8759d0ec5768fa04730ccec143000ed5ed..08d183120e412fa00c084592d35084f4f2260383 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 static struct rc_map_table kworld_plus_tv_analog[] = {
-       { 0x0c, KEY_PROG1 },            /* Kworld key */
+       { 0x0c, KEY_LEFTMETA },         /* Kworld key */
        { 0x16, KEY_CLOSECD },          /* -> ) */
        { 0x1d, KEY_POWER2 },
 
index 875cd81477c7f346949798bb451425d9eddf1856..3c1913926c1af1608ba9d0db829f5faa59931b89 100644 (file)
 
 
 static struct rc_map_table lme2510_rc[] = {
-       { 0xba45, KEY_0 },
-       { 0xa05f, KEY_1 },
-       { 0xaf50, KEY_2 },
-       { 0xa25d, KEY_3 },
-       { 0xbe41, KEY_4 },
-       { 0xf50a, KEY_5 },
-       { 0xbd42, KEY_6 },
-       { 0xb847, KEY_7 },
-       { 0xb649, KEY_8 },
-       { 0xfa05, KEY_9 },
-       { 0xbc43, KEY_POWER },
-       { 0xb946, KEY_SUBTITLE },
-       { 0xf906, KEY_PAUSE },
-       { 0xfc03, KEY_MEDIA_REPEAT},
-       { 0xfd02, KEY_PAUSE },
-       { 0xa15e, KEY_VOLUMEUP },
-       { 0xa35c, KEY_VOLUMEDOWN },
-       { 0xf609, KEY_CHANNELUP },
-       { 0xe51a, KEY_CHANNELDOWN },
-       { 0xe11e, KEY_PLAY },
-       { 0xe41b, KEY_ZOOM },
-       { 0xa659, KEY_MUTE },
-       { 0xa55a, KEY_TV },
-       { 0xe718, KEY_RECORD },
-       { 0xf807, KEY_EPG },
-       { 0xfe01, KEY_STOP },
-
+       /* Type 1 - 26 buttons */
+       { 0xef12ba45, KEY_0 },
+       { 0xef12a05f, KEY_1 },
+       { 0xef12af50, KEY_2 },
+       { 0xef12a25d, KEY_3 },
+       { 0xef12be41, KEY_4 },
+       { 0xef12f50a, KEY_5 },
+       { 0xef12bd42, KEY_6 },
+       { 0xef12b847, KEY_7 },
+       { 0xef12b649, KEY_8 },
+       { 0xef12fa05, KEY_9 },
+       { 0xef12bc43, KEY_POWER },
+       { 0xef12b946, KEY_SUBTITLE },
+       { 0xef12f906, KEY_PAUSE },
+       { 0xef12fc03, KEY_MEDIA_REPEAT},
+       { 0xef12fd02, KEY_PAUSE },
+       { 0xef12a15e, KEY_VOLUMEUP },
+       { 0xef12a35c, KEY_VOLUMEDOWN },
+       { 0xef12f609, KEY_CHANNELUP },
+       { 0xef12e51a, KEY_CHANNELDOWN },
+       { 0xef12e11e, KEY_PLAY },
+       { 0xef12e41b, KEY_ZOOM },
+       { 0xef12a659, KEY_MUTE },
+       { 0xef12a55a, KEY_TV },
+       { 0xef12e718, KEY_RECORD },
+       { 0xef12f807, KEY_EPG },
+       { 0xef12fe01, KEY_STOP },
+       /* Type 2 - 20 buttons */
+       { 0xff40ea15, KEY_0 },
+       { 0xff40f708, KEY_1 },
+       { 0xff40f609, KEY_2 },
+       { 0xff40f50a, KEY_3 },
+       { 0xff40f30c, KEY_4 },
+       { 0xff40f20d, KEY_5 },
+       { 0xff40f10e, KEY_6 },
+       { 0xff40ef10, KEY_7 },
+       { 0xff40ee11, KEY_8 },
+       { 0xff40ed12, KEY_9 },
+       { 0xff40ff00, KEY_POWER },
+       { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
+       { 0xff40e51a, KEY_PAUSE }, /* Timeshift */
+       { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+       { 0xff40f906, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/
+       { 0xff40fe01, KEY_CHANNELUP },
+       { 0xff40fa05, KEY_CHANNELDOWN },
+       { 0xff40eb14, KEY_ZOOM },
+       { 0xff40e718, KEY_RECORD },
+       { 0xff40e916, KEY_STOP },
+       /* Type 3 - 20 buttons */
+       { 0xff00e31c, KEY_0 },
+       { 0xff00f807, KEY_1 },
+       { 0xff00ea15, KEY_2 },
+       { 0xff00f609, KEY_3 },
+       { 0xff00e916, KEY_4 },
+       { 0xff00e619, KEY_5 },
+       { 0xff00f20d, KEY_6 },
+       { 0xff00f30c, KEY_7 },
+       { 0xff00e718, KEY_8 },
+       { 0xff00a15e, KEY_9 },
+       { 0xff00ba45, KEY_POWER },
+       { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
+       { 0xff00b54a, KEY_PAUSE }, /* Timeshift */
+       { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+       { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/
+       { 0xff00b946, KEY_CHANNELUP },
+       { 0xff00bf40, KEY_CHANNELDOWN },
+       { 0xff00f708, KEY_ZOOM },
+       { 0xff00bd42, KEY_RECORD },
+       { 0xff00a55a, KEY_STOP },
 };
 
 static struct rc_map_list lme2510_map = {
index fa8fd0ab94c72d3ccf61bd99d22cc87ecac6fcb3..8e9969d1239b252e59974a443210e52ac07eb6a6 100644 (file)
@@ -62,7 +62,7 @@ static struct rc_map_table msi_tvanywhere_plus[] = {
        { 0x13, KEY_AGAIN },            /* Recall */
 
        { 0x1e, KEY_POWER },            /* Power */
-       { 0x07, KEY_TUNER },            /* Source */
+       { 0x07, KEY_VIDEO },            /* Source */
        { 0x1c, KEY_SEARCH },           /* Scan */
        { 0x18, KEY_MUTE },             /* Mute */
 
index 3e6f077eb7008308a15b1b96651ac7db2a94c9e4..ddae20e9cd96d11ae78a2c42cb1fad1d12f24cc6 100644 (file)
@@ -27,7 +27,7 @@ static struct rc_map_table nebula[] = {
        { 0x0b, KEY_AUX },
        { 0x0c, KEY_DVD },
        { 0x0d, KEY_POWER },
-       { 0x0e, KEY_MHP },      /* labelled 'Picture' */
+       { 0x0e, KEY_CAMERA },   /* labelled 'Picture' */
        { 0x0f, KEY_AUDIO },
        { 0x10, KEY_INFO },
        { 0x11, KEY_F13 },      /* 16:9 */
index 629ee9d84537bf8a990925fb14ecaf542c4add26..f1c1281fbc170c0e43371b6c79d14578b780b8d9 100644 (file)
@@ -29,7 +29,7 @@ static struct rc_map_table norwood[] = {
        { 0x28, KEY_8 },
        { 0x29, KEY_9 },
 
-       { 0x78, KEY_TUNER },            /* Video Source        */
+       { 0x78, KEY_VIDEO },            /* Video Source        */
        { 0x2c, KEY_EXIT },             /* Open/Close software */
        { 0x2a, KEY_SELECT },           /* 2 Digit Select      */
        { 0x69, KEY_AGAIN },            /* Recall              */
index fa5ae5981eb8bd5793fa1a578ba9b7c03b6ab212..7cdef6e6cc0f5123573c11a56625163daac74e00 100644 (file)
@@ -36,7 +36,7 @@ static struct rc_map_table pctv_sedna[] = {
        { 0x0e, KEY_STOP },
        { 0x0f, KEY_PREVIOUSSONG },
        { 0x10, KEY_ZOOM },
-       { 0x11, KEY_TUNER },    /* Source */
+       { 0x11, KEY_VIDEO },    /* Source */
        { 0x12, KEY_POWER },
        { 0x13, KEY_MUTE },
        { 0x15, KEY_CHANNELDOWN },
index 8d9f664e0a2d04cd924bd5701b159e458ea8157e..125fc3949c15f6470b3058bf7a72e6efe9186239 100644 (file)
@@ -34,7 +34,7 @@ static struct rc_map_table pixelview_mk12[] = {
        { 0x866b13, KEY_AGAIN },        /* loop */
        { 0x866b10, KEY_DIGITS },       /* +100 */
 
-       { 0x866b00, KEY_MEDIA },        /* source */
+       { 0x866b00, KEY_VIDEO },                /* source */
        { 0x866b18, KEY_MUTE },         /* mute */
        { 0x866b19, KEY_CAMERA },       /* snapshot */
        { 0x866b1a, KEY_SEARCH },       /* scan */
index 777a70076be2d9aeb25f2e8c45d9d9ea95caf7e5..bd78d6ac1e16f1c55caea1cd151c6c61cf00eea2 100644 (file)
@@ -33,7 +33,7 @@ static struct rc_map_table pixelview_new[] = {
        { 0x3e, KEY_0 },
 
        { 0x1c, KEY_AGAIN },            /* LOOP */
-       { 0x3f, KEY_MEDIA },            /* Source */
+       { 0x3f, KEY_VIDEO },            /* Source */
        { 0x1f, KEY_LAST },             /* +100 */
        { 0x1b, KEY_MUTE },
 
index 0ec5988916b9a056a7d7c4fa69538823155a3571..06187e7db4467856de66c77f149311d99f6fdfe6 100644 (file)
@@ -15,7 +15,7 @@
 static struct rc_map_table pixelview[] = {
 
        { 0x1e, KEY_POWER },    /* power */
-       { 0x07, KEY_MEDIA },    /* source */
+       { 0x07, KEY_VIDEO },    /* source */
        { 0x1c, KEY_SEARCH },   /* scan */
 
 
index 83a418de12c64f695317ffb50dedc472ab78effb..5e8beee94de4ec6b05169411e5fe3042a3658532 100644 (file)
@@ -46,10 +46,10 @@ static struct rc_map_table pv951[] = {
        { 0x0c, KEY_SEARCH },           /* AUTOSCAN */
 
        /* Not sure what to do with these ones! */
-       { 0x0f, KEY_SELECT },           /* SOURCE */
+       { 0x0f, KEY_VIDEO },            /* SOURCE */
        { 0x0a, KEY_KPPLUS },           /* +100 */
        { 0x14, KEY_EQUAL },            /* SYNC */
-       { 0x1c, KEY_MEDIA },            /* PC/TV */
+       { 0x1c, KEY_TV },               /* PC/TV */
 };
 
 static struct rc_map_list pv951_map = {
diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
deleted file mode 100644 (file)
index dfc9b15..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* rc5-hauppauge-new.h - Keytable for rc5_hauppauge_new Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/*
- * Hauppauge:the newer, gray remotes (seems there are multiple
- * slightly different versions), shipped with cx88+ivtv cards.
- *
- * This table contains the complete RC5 code, instead of just the data part
- */
-
-static struct rc_map_table rc5_hauppauge_new[] = {
-       /* Keys 0 to 9 */
-       { 0x1e00, KEY_0 },
-       { 0x1e01, KEY_1 },
-       { 0x1e02, KEY_2 },
-       { 0x1e03, KEY_3 },
-       { 0x1e04, KEY_4 },
-       { 0x1e05, KEY_5 },
-       { 0x1e06, KEY_6 },
-       { 0x1e07, KEY_7 },
-       { 0x1e08, KEY_8 },
-       { 0x1e09, KEY_9 },
-
-       { 0x1e0a, KEY_TEXT },           /* keypad asterisk as well */
-       { 0x1e0b, KEY_RED },            /* red button */
-       { 0x1e0c, KEY_RADIO },
-       { 0x1e0d, KEY_MENU },
-       { 0x1e0e, KEY_SUBTITLE },               /* also the # key */
-       { 0x1e0f, KEY_MUTE },
-       { 0x1e10, KEY_VOLUMEUP },
-       { 0x1e11, KEY_VOLUMEDOWN },
-       { 0x1e12, KEY_PREVIOUS },               /* previous channel */
-       { 0x1e14, KEY_UP },
-       { 0x1e15, KEY_DOWN },
-       { 0x1e16, KEY_LEFT },
-       { 0x1e17, KEY_RIGHT },
-       { 0x1e18, KEY_VIDEO },          /* Videos */
-       { 0x1e19, KEY_AUDIO },          /* Music */
-       /* 0x1e1a: Pictures - presume this means
-          "Multimedia Home Platform" -
-          no "PICTURES" key in input.h
-        */
-       { 0x1e1a, KEY_MHP },
-
-       { 0x1e1b, KEY_EPG },            /* Guide */
-       { 0x1e1c, KEY_TV },
-       { 0x1e1e, KEY_NEXTSONG },               /* skip >| */
-       { 0x1e1f, KEY_EXIT },           /* back/exit */
-       { 0x1e20, KEY_CHANNELUP },      /* channel / program + */
-       { 0x1e21, KEY_CHANNELDOWN },    /* channel / program - */
-       { 0x1e22, KEY_CHANNEL },                /* source (old black remote) */
-       { 0x1e24, KEY_PREVIOUSSONG },   /* replay |< */
-       { 0x1e25, KEY_ENTER },          /* OK */
-       { 0x1e26, KEY_SLEEP },          /* minimize (old black remote) */
-       { 0x1e29, KEY_BLUE },           /* blue key */
-       { 0x1e2e, KEY_GREEN },          /* green button */
-       { 0x1e30, KEY_PAUSE },          /* pause */
-       { 0x1e32, KEY_REWIND },         /* backward << */
-       { 0x1e34, KEY_FASTFORWARD },    /* forward >> */
-       { 0x1e35, KEY_PLAY },
-       { 0x1e36, KEY_STOP },
-       { 0x1e37, KEY_RECORD },         /* recording */
-       { 0x1e38, KEY_YELLOW },         /* yellow key */
-       { 0x1e3b, KEY_SELECT },         /* top right button */
-       { 0x1e3c, KEY_ZOOM },           /* full */
-       { 0x1e3d, KEY_POWER },          /* system power (green button) */
-
-       /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */
-       { 0x1d00, KEY_0 },
-       { 0x1d01, KEY_1 },
-       { 0x1d02, KEY_2 },
-       { 0x1d03, KEY_3 },
-       { 0x1d04, KEY_4 },
-       { 0x1d05, KEY_5 },
-       { 0x1d06, KEY_6 },
-       { 0x1d07, KEY_7 },
-       { 0x1d08, KEY_8 },
-       { 0x1d09, KEY_9 },
-       { 0x1d0a, KEY_TEXT },
-       { 0x1d0d, KEY_MENU },
-       { 0x1d0f, KEY_MUTE },
-       { 0x1d10, KEY_VOLUMEUP },
-       { 0x1d11, KEY_VOLUMEDOWN },
-       { 0x1d12, KEY_PREVIOUS },        /* Prev.Ch .. ??? */
-       { 0x1d14, KEY_UP },
-       { 0x1d15, KEY_DOWN },
-       { 0x1d16, KEY_LEFT },
-       { 0x1d17, KEY_RIGHT },
-       { 0x1d1c, KEY_TV },
-       { 0x1d1e, KEY_NEXT },           /* >|             */
-       { 0x1d1f, KEY_EXIT },
-       { 0x1d20, KEY_CHANNELUP },
-       { 0x1d21, KEY_CHANNELDOWN },
-       { 0x1d24, KEY_LAST },           /* <|             */
-       { 0x1d25, KEY_OK },
-       { 0x1d30, KEY_PAUSE },
-       { 0x1d32, KEY_REWIND },
-       { 0x1d34, KEY_FASTFORWARD },
-       { 0x1d35, KEY_PLAY },
-       { 0x1d36, KEY_STOP },
-       { 0x1d37, KEY_RECORD },
-       { 0x1d3b, KEY_GOTO },
-       { 0x1d3d, KEY_POWER },
-       { 0x1d3f, KEY_HOME },
-};
-
-static struct rc_map_list rc5_hauppauge_new_map = {
-       .map = {
-               .scan    = rc5_hauppauge_new,
-               .size    = ARRAY_SIZE(rc5_hauppauge_new),
-               .rc_type = RC_TYPE_RC5,
-               .name    = RC_MAP_RC5_HAUPPAUGE_NEW,
-       }
-};
-
-static int __init init_rc_map_rc5_hauppauge_new(void)
-{
-       return rc_map_register(&rc5_hauppauge_new_map);
-}
-
-static void __exit exit_rc_map_rc5_hauppauge_new(void)
-{
-       rc_map_unregister(&rc5_hauppauge_new_map);
-}
-
-module_init(init_rc_map_rc5_hauppauge_new)
-module_exit(exit_rc_map_rc5_hauppauge_new)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-rc5-tv.c b/drivers/media/rc/keymaps/rc-rc5-tv.c
deleted file mode 100644 (file)
index 4fcef9f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* rc5-tv.h - Keytable for rc5_tv Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/* generic RC5 keytable                                          */
-/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
-/* used by old (black) Hauppauge remotes                         */
-
-static struct rc_map_table rc5_tv[] = {
-       /* Keys 0 to 9 */
-       { 0x00, KEY_0 },
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-
-       { 0x0b, KEY_CHANNEL },          /* channel / program (japan: 11) */
-       { 0x0c, KEY_POWER },            /* standby */
-       { 0x0d, KEY_MUTE },             /* mute / demute */
-       { 0x0f, KEY_TV },               /* display */
-       { 0x10, KEY_VOLUMEUP },
-       { 0x11, KEY_VOLUMEDOWN },
-       { 0x12, KEY_BRIGHTNESSUP },
-       { 0x13, KEY_BRIGHTNESSDOWN },
-       { 0x1e, KEY_SEARCH },           /* search + */
-       { 0x20, KEY_CHANNELUP },        /* channel / program + */
-       { 0x21, KEY_CHANNELDOWN },      /* channel / program - */
-       { 0x22, KEY_CHANNEL },          /* alt / channel */
-       { 0x23, KEY_LANGUAGE },         /* 1st / 2nd language */
-       { 0x26, KEY_SLEEP },            /* sleeptimer */
-       { 0x2e, KEY_MENU },             /* 2nd controls (USA: menu) */
-       { 0x30, KEY_PAUSE },
-       { 0x32, KEY_REWIND },
-       { 0x33, KEY_GOTO },
-       { 0x35, KEY_PLAY },
-       { 0x36, KEY_STOP },
-       { 0x37, KEY_RECORD },           /* recording */
-       { 0x3c, KEY_TEXT },             /* teletext submode (Japan: 12) */
-       { 0x3d, KEY_SUSPEND },          /* system standby */
-
-};
-
-static struct rc_map_list rc5_tv_map = {
-       .map = {
-               .scan    = rc5_tv,
-               .size    = ARRAY_SIZE(rc5_tv),
-               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
-               .name    = RC_MAP_RC5_TV,
-       }
-};
-
-static int __init init_rc_map_rc5_tv(void)
-{
-       return rc_map_register(&rc5_tv_map);
-}
-
-static void __exit exit_rc_map_rc5_tv(void)
-{
-       rc_map_unregister(&rc5_tv_map);
-}
-
-module_init(init_rc_map_rc5_tv)
-module_exit(exit_rc_map_rc5_tv)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
index 2f5dc0622b94c57dbe0d8ba3e63d0da3b5f6d6c6..8dd519ecc58e6ffe5f78acf31a6388181373e07b 100644 (file)
@@ -30,7 +30,7 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f040a, KEY_DELETE },
        { 0x800f040b, KEY_ENTER },
        { 0x800f040c, KEY_POWER },              /* PC Power */
-       { 0x800f040d, KEY_PROG1 },              /* Windows MCE button */
+       { 0x800f040d, KEY_LEFTMETA },           /* Windows MCE button */
        { 0x800f040e, KEY_MUTE },
        { 0x800f040f, KEY_INFO },
 
index 2d14598592d8979e2cfb3468d676741855c50124..6813d1102118357f86ad0d1c146ad2fcb905eead 100644 (file)
@@ -35,7 +35,7 @@ static struct rc_map_table real_audio_220_32_keys[] = {
        { 0x15, KEY_CHANNELDOWN},
        { 0x16, KEY_ENTER},
 
-       { 0x11, KEY_LIST},              /* Source */
+       { 0x11, KEY_VIDEO},             /* Source */
        { 0x0d, KEY_AUDIO},             /* stereo */
 
        { 0x0f, KEY_PREVIOUS},          /* Prev */
diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c
new file mode 100644 (file)
index 0000000..4afe577
--- /dev/null
@@ -0,0 +1,93 @@
+/* rc-technisat-usb2.c - Keytable for SkyStar HD USB
+ *
+ * Copyright (C) 2010 Patrick Boettcher,
+ *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
+ *
+ * Development was sponsored by Technisat Digital UK Limited, whose
+ * registered office is Witan Gate House 500 - 600 Witan Gate West,
+ * Milton Keynes, MK9 1SH
+ *
+ * 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.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
+ * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
+ * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
+ * GNU General Public License for more details.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table technisat_usb2[] = {
+       {0x0a0c, KEY_POWER},
+       {0x0a01, KEY_1},
+       {0x0a02, KEY_2},
+       {0x0a03, KEY_3},
+       {0x0a0d, KEY_MUTE},
+       {0x0a04, KEY_4},
+       {0x0a05, KEY_5},
+       {0x0a06, KEY_6},
+       {0x0a38, KEY_VIDEO}, /* EXT */
+       {0x0a07, KEY_7},
+       {0x0a08, KEY_8},
+       {0x0a09, KEY_9},
+       {0x0a00, KEY_0},
+       {0x0a4f, KEY_INFO},
+       {0x0a20, KEY_CHANNELUP},
+       {0x0a52, KEY_MENU},
+       {0x0a11, KEY_VOLUMEUP},
+       {0x0a57, KEY_OK},
+       {0x0a10, KEY_VOLUMEDOWN},
+       {0x0a2f, KEY_EPG},
+       {0x0a21, KEY_CHANNELDOWN},
+       {0x0a22, KEY_REFRESH},
+       {0x0a3c, KEY_TEXT},
+       {0x0a76, KEY_ENTER}, /* HOOK */
+       {0x0a0f, KEY_HELP},
+       {0x0a6b, KEY_RED},
+       {0x0a6c, KEY_GREEN},
+       {0x0a6d, KEY_YELLOW},
+       {0x0a6e, KEY_BLUE},
+       {0x0a29, KEY_STOP},
+       {0x0a23, KEY_LANGUAGE},
+       {0x0a53, KEY_TV},
+       {0x0a0a, KEY_PROGRAM},
+};
+
+static struct rc_map_list technisat_usb2_map = {
+       .map = {
+               .scan    = technisat_usb2,
+               .size    = ARRAY_SIZE(technisat_usb2),
+               .rc_type = RC_TYPE_RC5,
+               .name    = RC_MAP_TECHNISAT_USB2,
+       }
+};
+
+static int __init init_rc_map(void)
+{
+       return rc_map_register(&technisat_usb2_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+       rc_map_unregister(&technisat_usb2_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c
new file mode 100644 (file)
index 0000000..4409391
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * TerraTec remote controller keytable
+ *
+ * Copyright (C) 2011 Martin Groszhauser <mgroszhauser@gmail.com>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * TerraTec slim remote, 6 rows, 3 columns.
+ * Keytable from Martin Groszhauser <mgroszhauser@gmail.com>
+ */
+static struct rc_map_table terratec_slim_2[] = {
+       { 0x8001, KEY_MUTE },            /* MUTE */
+       { 0x8002, KEY_VOLUMEDOWN },
+       { 0x8003, KEY_CHANNELDOWN },
+       { 0x8004, KEY_1 },
+       { 0x8005, KEY_2 },
+       { 0x8006, KEY_3 },
+       { 0x8007, KEY_4 },
+       { 0x8008, KEY_5 },
+       { 0x8009, KEY_6 },
+       { 0x800a, KEY_7 },
+       { 0x800c, KEY_ZOOM },            /* [fullscreen] */
+       { 0x800d, KEY_0 },
+       { 0x800e, KEY_AGAIN },           /* [two arrows forming a circle] */
+       { 0x8012, KEY_POWER2 },          /* [red power button] */
+       { 0x801a, KEY_VOLUMEUP },
+       { 0x801b, KEY_8 },
+       { 0x801e, KEY_CHANNELUP },
+       { 0x801f, KEY_9 },
+};
+
+static struct rc_map_list terratec_slim_2_map = {
+       .map = {
+               .scan    = terratec_slim_2,
+               .size    = ARRAY_SIZE(terratec_slim_2),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_TERRATEC_SLIM_2,
+       }
+};
+
+static int __init init_rc_map_terratec_slim_2(void)
+{
+       return rc_map_register(&terratec_slim_2_map);
+}
+
+static void __exit exit_rc_map_terratec_slim_2(void)
+{
+       rc_map_unregister(&terratec_slim_2_map);
+}
+
+module_init(init_rc_map_terratec_slim_2)
+module_exit(exit_rc_map_terratec_slim_2)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index 2747db43b70ce64fe399de787de0f693f814401a..0062ca291959af7f2be242ad1241a376a463b598 100644 (file)
@@ -27,15 +27,15 @@ static struct rc_map_table winfast[] = {
        { 0x0e, KEY_8 },
        { 0x0f, KEY_9 },
 
-       { 0x00, KEY_POWER },
+       { 0x00, KEY_POWER2 },
        { 0x1b, KEY_AUDIO },            /* Audio Source */
        { 0x02, KEY_TUNER },            /* TV/FM, not on Y0400052 */
        { 0x1e, KEY_VIDEO },            /* Video Source */
        { 0x16, KEY_INFO },             /* Display information */
-       { 0x04, KEY_VOLUMEUP },
-       { 0x08, KEY_VOLUMEDOWN },
-       { 0x0c, KEY_CHANNELUP },
-       { 0x10, KEY_CHANNELDOWN },
+       { 0x04, KEY_LEFT },
+       { 0x08, KEY_RIGHT },
+       { 0x0c, KEY_UP },
+       { 0x10, KEY_DOWN },
        { 0x03, KEY_ZOOM },             /* fullscreen */
        { 0x1f, KEY_TEXT },             /* closed caption/teletext */
        { 0x20, KEY_SLEEP },
@@ -47,7 +47,7 @@ static struct rc_map_table winfast[] = {
        { 0x2e, KEY_BLUE },
        { 0x18, KEY_KPPLUS },           /* fine tune + , not on Y040052 */
        { 0x19, KEY_KPMINUS },          /* fine tune - , not on Y040052 */
-       { 0x2a, KEY_MEDIA },            /* PIP (Picture in picture */
+       { 0x2a, KEY_TV2 },              /* PIP (Picture in picture */
        { 0x21, KEY_DOT },
        { 0x13, KEY_ENTER },
        { 0x11, KEY_LAST },             /* Recall (last channel */
@@ -57,7 +57,7 @@ static struct rc_map_table winfast[] = {
        { 0x25, KEY_TIME },             /* Time Shifting */
        { 0x26, KEY_STOP },
        { 0x27, KEY_RECORD },
-       { 0x28, KEY_SAVE },             /* Screenshot */
+       { 0x28, KEY_CAMERA },           /* Screenshot */
        { 0x2f, KEY_MENU },
        { 0x30, KEY_CANCEL },
        { 0x31, KEY_CHANNEL },          /* Channel Surf */
@@ -70,10 +70,10 @@ static struct rc_map_table winfast[] = {
        { 0x38, KEY_DVD },
 
        { 0x1a, KEY_MODE},              /* change to MCE mode on Y04G0051 */
-       { 0x3e, KEY_F21 },              /* MCE +VOL, on Y04G0033 */
-       { 0x3a, KEY_F22 },              /* MCE -VOL, on Y04G0033 */
-       { 0x3b, KEY_F23 },              /* MCE +CH,  on Y04G0033 */
-       { 0x3f, KEY_F24 }               /* MCE -CH,  on Y04G0033 */
+       { 0x3e, KEY_VOLUMEUP },         /* MCE +VOL, on Y04G0033 */
+       { 0x3a, KEY_VOLUMEDOWN },       /* MCE -VOL, on Y04G0033 */
+       { 0x3b, KEY_CHANNELUP },        /* MCE +CH,  on Y04G0033 */
+       { 0x3f, KEY_CHANNELDOWN }       /* MCE -CH,  on Y04G0033 */
 };
 
 static struct rc_map_list winfast_map = {
index e4f8eac7f7173b1e72bb2baee585ce70d4b1f01f..044fb7a382d6bd888898cc889b78cdba15eeec90 100644 (file)
@@ -186,7 +186,7 @@ static const struct mceusb_model mceusb_model[] = {
                 * remotes, but we should have something handy,
                 * to allow testing it
                 */
-               .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
+               .rc_map = RC_MAP_HAUPPAUGE,
                .name = "Conexant Hybrid TV (cx231xx) MCE IR",
        },
        [CX_HYBRID_TV] = {
@@ -261,7 +261,7 @@ static struct usb_device_id mceusb_dev_table[] = {
          .driver_info = MCE_GEN2_TX_INV },
        /* Topseed eHome Infrared Transceiver */
        { USB_DEVICE(VENDOR_TOPSEED, 0x0011),
-         .driver_info = MCE_GEN2_TX_INV },
+         .driver_info = MCE_GEN3 },
        /* Ricavision internal Infrared Transceiver */
        { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
        /* Itron ione Libra Q-11 */
index 5b4422ef4e6d4705566bc8f45a23cf6a9e9719fc..5ac1baf45c8e8514a2a4c12e29bb26f30bb3b0d7 100644 (file)
@@ -966,8 +966,8 @@ struct rc_dev *rc_allocate_device(void)
                return NULL;
        }
 
-       dev->input_dev->getkeycode_new = ir_getkeycode;
-       dev->input_dev->setkeycode_new = ir_setkeycode;
+       dev->input_dev->getkeycode = ir_getkeycode;
+       dev->input_dev->setkeycode = ir_setkeycode;
        input_set_drvdata(dev->input_dev, dev);
 
        spin_lock_init(&dev->rc_map.lock);
index aa021600e9df352c33fdc0131bd5b2c8113774de..4498b944dec81d8af9e9ae7a30370bde671bcce2 100644 (file)
@@ -42,8 +42,30 @@ config VIDEO_TUNER
 
 config V4L2_MEM2MEM_DEV
        tristate
-       depends on VIDEOBUF_GEN
+       depends on VIDEOBUF2_CORE
 
+config VIDEOBUF2_CORE
+       tristate
+
+config VIDEOBUF2_MEMOPS
+       tristate
+
+config VIDEOBUF2_DMA_CONTIG
+       select VIDEOBUF2_CORE
+       select VIDEOBUF2_MEMOPS
+       tristate
+
+config VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_CORE
+       select VIDEOBUF2_MEMOPS
+       tristate
+
+
+config VIDEOBUF2_DMA_SG
+       #depends on HAS_DMA
+       select VIDEOBUF2_CORE
+       select VIDEOBUF2_MEMOPS
+       tristate
 #
 # Multimedia Video device configuration
 #
@@ -527,7 +549,7 @@ config VIDEO_VIVI
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
        depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        select FONT_8x16
-       select VIDEOBUF_VMALLOC
+       select VIDEOBUF2_VMALLOC
        default n
        ---help---
          Enables a virtual video driver. This device shows a color bar
@@ -718,10 +740,30 @@ config VIDEO_VIA_CAMERA
           Chrome9 chipsets.  Currently only tested on OLPC xo-1.5 systems
           with ov7670 sensors.
 
+config VIDEO_NOON010PC30
+       tristate "NOON010PC30 CIF camera sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This driver supports NOON010PC30 CIF camera from Siliconfile
+
+config VIDEO_OMAP3
+       tristate "OMAP 3 Camera support (EXPERIMENTAL)"
+       select OMAP_IOMMU
+       depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
+       ---help---
+         Driver for an OMAP 3 camera controller.
+
+config VIDEO_OMAP3_DEBUG
+       bool "OMAP 3 Camera debug messages"
+       depends on VIDEO_OMAP3
+       ---help---
+         Enable debug messages on OMAP 3 camera controller driver.
+
 config SOC_CAMERA
        tristate "SoC camera support"
        depends on VIDEO_V4L2 && HAS_DMA && I2C
        select VIDEOBUF_GEN
+       select VIDEOBUF2_CORE
        help
          SoC Camera is a common API to several cameras, not connecting
          over a bus like PCI or USB. For example some i2c camera connected
@@ -809,6 +851,12 @@ config SOC_CAMERA_OV9640
        help
          This is a ov9640 camera driver
 
+config SOC_CAMERA_OV9740
+       tristate "ov9740 camera support"
+       depends on SOC_CAMERA && I2C
+       help
+         This is a ov9740 camera driver
+
 config MX1_VIDEO
        bool
 
@@ -848,7 +896,7 @@ config VIDEO_SH_MOBILE_CSI2
 config VIDEO_SH_MOBILE_CEU
        tristate "SuperH Mobile CEU Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
-       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF2_DMA_CONTIG
        ---help---
          This is a v4l2 driver for the SuperH Mobile CEU Interface
 
@@ -967,7 +1015,7 @@ if V4L_MEM2MEM_DRIVERS
 config VIDEO_MEM2MEM_TESTDEV
        tristate "Virtual test device for mem2mem framework"
        depends on VIDEO_DEV && VIDEO_V4L2
-       select VIDEOBUF_VMALLOC
+       select VIDEOBUF2_VMALLOC
        select V4L2_MEM2MEM_DEV
        default n
        ---help---
@@ -977,7 +1025,7 @@ config VIDEO_MEM2MEM_TESTDEV
 config  VIDEO_SAMSUNG_S5P_FIMC
        tristate "Samsung S5P FIMC (video postprocessor) driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
-       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
          This is a v4l2 driver for the S5P camera interface
index a509d317e258d9580d146e5ea1473f9fbab36f39..ace5d8b5722151d8920dd0217b8248e1218917d6 100644 (file)
@@ -11,7 +11,7 @@ stkwebcam-objs        :=      stk-webcam.o stk-sensor.o
 omap2cam-objs  :=      omap24xxcam.o omap24xxcam-dma.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
-                       v4l2-event.o v4l2-ctrls.o
+                       v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
 
 # V4L2 core modules
 
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
+obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_OV2640)               += ov2640.o
 obj-$(CONFIG_SOC_CAMERA_OV6650)                += ov6650.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)                += ov9640.o
+obj-$(CONFIG_SOC_CAMERA_OV9740)                += ov9740.o
 obj-$(CONFIG_SOC_CAMERA_RJ54N1)                += rj54n1cb0c.o
 obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
@@ -111,6 +113,12 @@ obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 
+obj-$(CONFIG_VIDEOBUF2_CORE)           += videobuf2-core.o
+obj-$(CONFIG_VIDEOBUF2_MEMOPS)         += videobuf2-memops.o
+obj-$(CONFIG_VIDEOBUF2_VMALLOC)                += videobuf2-vmalloc.o
+obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG)     += videobuf2-dma-contig.o
+obj-$(CONFIG_VIDEOBUF2_DMA_SG)         += videobuf2-dma-sg.o
+
 obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
@@ -121,6 +129,8 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 
+obj-$(CONFIG_VIDEO_OMAP3)      += omap3isp/
+
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
 obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
index 41b2930d0ce4e59640ab946e81db7e234f5aca06..021fab23070d395bc548928fd42534549b5ead46 100644 (file)
@@ -29,6 +29,7 @@
 #include <media/adv7343.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #include "adv7343_regs.h"
 
@@ -41,15 +42,13 @@ MODULE_PARM_DESC(debug, "Debug level 0-1");
 
 struct adv7343_state {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        u8 reg00;
        u8 reg01;
        u8 reg02;
        u8 reg35;
        u8 reg80;
        u8 reg82;
-       int bright;
-       int hue;
-       int gain;
        u32 output;
        v4l2_std_id std;
 };
@@ -59,6 +58,11 @@ static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
        return container_of(sd, struct adv7343_state, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;
+}
+
 static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -268,111 +272,22 @@ static int adv7343_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
-                                               ADV7343_BRIGHTNESS_MAX, 1,
-                                               ADV7343_BRIGHTNESS_DEF);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
-                                               ADV7343_HUE_MAX, 1 ,
-                                               ADV7343_HUE_DEF);
-       case V4L2_CID_GAIN:
-               return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
-                                               ADV7343_GAIN_MAX, 1,
-                                               ADV7343_GAIN_DEF);
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct adv7343_state *state = to_state(sd);
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
-                                       ctrl->value > ADV7343_BRIGHTNESS_MAX) {
-                       v4l2_dbg(1, debug, sd,
-                                       "invalid brightness settings %d\n",
-                                                               ctrl->value);
-                       return -ERANGE;
-               }
-
-               state->bright = ctrl->value;
-               err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
-                                       state->bright);
-               break;
-
-       case V4L2_CID_HUE:
-               if (ctrl->value < ADV7343_HUE_MIN ||
-                                       ctrl->value > ADV7343_HUE_MAX) {
-                       v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
-                                                               ctrl->value);
-                       return -ERANGE;
-               }
-
-               state->hue = ctrl->value;
-               err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
-               break;
-
-       case V4L2_CID_GAIN:
-               if (ctrl->value < ADV7343_GAIN_MIN ||
-                                       ctrl->value > ADV7343_GAIN_MAX) {
-                       v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
-                                                               ctrl->value);
-                       return -ERANGE;
-               }
-
-               if ((ctrl->value > POSITIVE_GAIN_MAX) &&
-                       (ctrl->value < NEGATIVE_GAIN_MIN)) {
-                       v4l2_dbg(1, debug, sd,
-                               "gain settings not within the specified range\n");
-                       return -ERANGE;
-               }
-
-               state->gain = ctrl->value;
-               err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       if (err < 0)
-               v4l2_err(sd, "Failed to set the encoder controls\n");
-
-       return err;
-}
-
-static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct adv7343_state *state = to_state(sd);
+       struct v4l2_subdev *sd = to_sd(ctrl);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = state->bright;
-               break;
+               return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+                                       ctrl->val);
 
        case V4L2_CID_HUE:
-               ctrl->value = state->hue;
-               break;
+               return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);
 
        case V4L2_CID_GAIN:
-               ctrl->value = state->gain;
-               break;
-
-       default:
-               return -EINVAL;
+               return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);
        }
-
-       return 0;
+       return -EINVAL;
 }
 
 static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
@@ -383,12 +298,20 @@ static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
        return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
 }
 
+static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
+       .s_ctrl = adv7343_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops adv7343_core_ops = {
-       .log_status     = adv7343_log_status,
-       .g_chip_ident   = adv7343_g_chip_ident,
-       .g_ctrl         = adv7343_g_ctrl,
-       .s_ctrl         = adv7343_s_ctrl,
-       .queryctrl      = adv7343_queryctrl,
+       .log_status = adv7343_log_status,
+       .g_chip_ident = adv7343_g_chip_ident,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 };
 
 static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
@@ -468,6 +391,7 @@ static int adv7343_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        struct adv7343_state *state;
+       int err;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -490,15 +414,46 @@ static int adv7343_probe(struct i2c_client *client,
        state->std = V4L2_STD_NTSC;
 
        v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
-       return adv7343_initialize(&state->sd);
+
+       v4l2_ctrl_handler_init(&state->hdl, 2);
+       v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,
+                                            ADV7343_BRIGHTNESS_MAX, 1,
+                                            ADV7343_BRIGHTNESS_DEF);
+       v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+                       V4L2_CID_HUE, ADV7343_HUE_MIN,
+                                     ADV7343_HUE_MAX, 1,
+                                     ADV7343_HUE_DEF);
+       v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+                       V4L2_CID_GAIN, ADV7343_GAIN_MIN,
+                                      ADV7343_GAIN_MAX, 1,
+                                      ADV7343_GAIN_DEF);
+       state->sd.ctrl_handler = &state->hdl;
+       if (state->hdl.error) {
+               int err = state->hdl.error;
+
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&state->hdl);
+
+       err = adv7343_initialize(&state->sd);
+       if (err) {
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+       }
+       return err;
 }
 
 static int adv7343_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct adv7343_state *state = to_state(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
+       v4l2_ctrl_handler_free(&state->hdl);
+       kfree(state);
 
        return 0;
 }
index 3431045b33da4a7f936a1be09cb7f4441dc22ef2..4466067643465563dfbe0db7057b2f50c4e9d2e3 100644 (file)
@@ -102,10 +102,6 @@ struct adv7343_std_info {
 
 /* Bit masks for DAC output levels */
 #define DAC_OUTPUT_LEVEL_MASK          (0xFF)
-#define POSITIVE_GAIN_MAX              (0x40)
-#define POSITIVE_GAIN_MIN              (0x00)
-#define NEGATIVE_GAIN_MAX              (0xFF)
-#define NEGATIVE_GAIN_MIN              (0xC0)
 
 /* Bit masks for soft reset register */
 #define SOFT_RESET                     (0x02)
@@ -178,8 +174,8 @@ struct adv7343_std_info {
 #define ADV7343_HUE_MAX                (255)
 #define ADV7343_HUE_MIN                (0)
 #define ADV7343_HUE_DEF                (127)
-#define ADV7343_GAIN_MAX       (255)
-#define ADV7343_GAIN_MIN       (0)
+#define ADV7343_GAIN_MAX       (64)
+#define ADV7343_GAIN_MIN       (-64)
 #define ADV7343_GAIN_DEF       (0)
 
 #endif
index 01be89fa5c7896e7595f3fde2047db16f160121a..39fc923fc46bc74b512d24243cd7387c5cf0f250 100644 (file)
@@ -185,8 +185,7 @@ void au0828_card_setup(struct au0828_dev *dev)
        static u8 eeprom[256];
        struct tuner_setup tun_setup;
        struct v4l2_subdev *sd;
-       unsigned int mode_mask = T_ANALOG_TV |
-                                T_DIGITAL_TV;
+       unsigned int mode_mask = T_ANALOG_TV;
 
        dprintk(1, "%s()\n", __func__);
 
index f1edf1d4afe8e4c3d1111cb59ff333b18827f679..518216743c9ca4dbc5b1efde12f9bf805a73f349 100644 (file)
@@ -96,7 +96,6 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = {
 /*-------------------------------------------------------------------*/
 static void urb_completion(struct urb *purb)
 {
-       u8 *ptr;
        struct au0828_dev *dev = purb->context;
        int ptype = usb_pipetype(purb->pipe);
 
@@ -114,8 +113,6 @@ static void urb_completion(struct urb *purb)
                return;
        }
 
-       ptr = (u8 *)purb->transfer_buffer;
-
        /* Feed the transport payload into the kernel demux */
        dvb_dmx_swfilter_packets(&dev->dvb.demux,
                purb->transfer_buffer, purb->actual_length / 188);
index 9c475c600fc9c9a0d8a5f7a568dae7a88579ee4d..6ad83a15d073c07cb9ed0eda2029df155eb5cc15 100644 (file)
@@ -1177,10 +1177,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
        int ret;
        int width = format->fmt.pix.width;
        int height = format->fmt.pix.height;
-       unsigned int maxwidth, maxheight;
-
-       maxwidth = 720;
-       maxheight = 480;
 
        if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
index c38300fc0b1d805629e251bb3cedd36634cc3751..f87204461cb41db609b97549250d80a468aeb4b9 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 #include <media/bt819.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -52,16 +53,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct bt819 {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        unsigned char reg[32];
 
        v4l2_std_id norm;
        int ident;
        int input;
        int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
 static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
@@ -69,6 +67,11 @@ static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
        return container_of(sd, struct bt819, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct bt819, hdl)->sd;
+}
+
 struct timing {
        int hactive;
        int hdelay;
@@ -333,71 +336,35 @@ static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-               break;
-
-       case V4L2_CID_CONTRAST:
-               v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
-               break;
-
-       case V4L2_CID_SATURATION:
-               v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
-               break;
-
-       case V4L2_CID_HUE:
-               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct v4l2_subdev *sd = to_sd(ctrl);
        struct bt819 *decoder = to_bt819(sd);
        int temp;
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               if (decoder->bright == ctrl->value)
-                       break;
-               decoder->bright = ctrl->value;
-               bt819_write(decoder, 0x0a, decoder->bright);
+               bt819_write(decoder, 0x0a, ctrl->val);
                break;
 
        case V4L2_CID_CONTRAST:
-               if (decoder->contrast == ctrl->value)
-                       break;
-               decoder->contrast = ctrl->value;
-               bt819_write(decoder, 0x0c, decoder->contrast & 0xff);
-               bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01));
+               bt819_write(decoder, 0x0c, ctrl->val & 0xff);
+               bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01));
                break;
 
        case V4L2_CID_SATURATION:
-               if (decoder->sat == ctrl->value)
-                       break;
-               decoder->sat = ctrl->value;
-               bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff);
-               bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01));
+               bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff);
+               bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01));
 
                /* Ratio between U gain and V gain must stay the same as
                   the ratio between the default U and V gain values. */
-               temp = (decoder->sat * 180) / 254;
+               temp = (ctrl->val * 180) / 254;
                bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
                bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
                break;
 
        case V4L2_CID_HUE:
-               if (decoder->hue == ctrl->value)
-                       break;
-               decoder->hue = ctrl->value;
-               bt819_write(decoder, 0x0f, decoder->hue);
+               bt819_write(decoder, 0x0f, ctrl->val);
                break;
 
        default:
@@ -406,29 +373,6 @@ static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct bt819 *decoder = to_bt819(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = decoder->bright;
-               break;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = decoder->contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               ctrl->value = decoder->sat;
-               break;
-       case V4L2_CID_HUE:
-               ctrl->value = decoder->hue;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
        struct bt819 *decoder = to_bt819(sd);
@@ -439,11 +383,19 @@ static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
+       .s_ctrl = bt819_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops bt819_core_ops = {
        .g_chip_ident = bt819_g_chip_ident,
-       .g_ctrl = bt819_g_ctrl,
-       .s_ctrl = bt819_s_ctrl,
-       .queryctrl = bt819_queryctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = bt819_s_std,
 };
 
@@ -505,23 +457,40 @@ static int bt819_probe(struct i2c_client *client,
        decoder->norm = V4L2_STD_NTSC;
        decoder->input = 0;
        decoder->enable = 1;
-       decoder->bright = 0;
-       decoder->contrast = 0xd8;       /* 100% of original signal */
-       decoder->hue = 0;
-       decoder->sat = 0xfe;            /* 100% of original signal */
 
        i = bt819_init(sd);
        if (i < 0)
                v4l2_dbg(1, debug, sd, "init status %d\n", i);
+
+       v4l2_ctrl_handler_init(&decoder->hdl, 4);
+       v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 511, 1, 0xd8);
+       v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 511, 1, 0xfe);
+       v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       sd->ctrl_handler = &decoder->hdl;
+       if (decoder->hdl.error) {
+               int err = decoder->hdl.error;
+
+               v4l2_ctrl_handler_free(&decoder->hdl);
+               kfree(decoder);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&decoder->hdl);
        return 0;
 }
 
 static int bt819_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct bt819 *decoder = to_bt819(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_bt819(sd));
+       v4l2_ctrl_handler_free(&decoder->hdl);
+       kfree(decoder);
        return 0;
 }
 
index 7f58756d72c8f8f69ff1bf125ab62769d744acad..242f0d512238b2139594be31b4a443e3d8e1c493 100644 (file)
@@ -3616,7 +3616,7 @@ void __devinit bttv_init_tuner(struct bttv *btv)
                                &btv->c.i2c_adap, "tuner",
                                0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
 
-               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+               tun_setup.mode_mask = T_ANALOG_TV;
                tun_setup.type = btv->tuner_type;
                tun_setup.addr = addr;
 
index e8b64bca9db22b1c5d72a89b740653060fb864fd..677d70c0e1cebf100649d52dec6587ab443a1b80 100644 (file)
@@ -193,12 +193,10 @@ static void bttv_rc5_timer_end(unsigned long data)
 {
        struct bttv_ir *ir = (struct bttv_ir *)data;
        struct timeval tv;
-       unsigned long current_jiffies;
        u32 gap;
        u32 rc5 = 0;
 
        /* get time */
-       current_jiffies = jiffies;
        do_gettimeofday(&tv);
 
        /* avoid overflow with gap >1s */
index aaffca8e13fde4a0aa2f3a30848b25590fcbc021..ee91e295c90a0273de2332c425b62f042564eff6 100644 (file)
@@ -519,22 +519,16 @@ int cpia2_do_command(struct camera_data *cam,
  *  cpia2_send_command
  *
  *****************************************************************************/
+
+#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read")
+#define BINDEX(cmd) (cmd->req_mode & 0x03)
+
 int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
 {
        u8 count;
        u8 start;
-       u8 block_index;
        u8 *buffer;
        int retval;
-       const char* dir;
-
-       if (cmd->direction == TRANSFER_WRITE) {
-               dir = "Write";
-       } else {
-               dir = "Read";
-       }
-
-       block_index = cmd->req_mode & 0x03;
 
        switch (cmd->req_mode & 0x0c) {
        case CAMERAACCESS_TYPE_RANDOM:
@@ -542,32 +536,32 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
                start = 0;
                buffer = (u8 *) & cmd->buffer;
                if (debugs_on & DEBUG_REG)
-                       DBG("%s Random: Register block %s\n", dir,
-                           block_name[block_index]);
+                       DBG("%s Random: Register block %s\n", DIR(cmd),
+                           block_name[BINDEX(cmd)]);
                break;
        case CAMERAACCESS_TYPE_BLOCK:
                count = cmd->reg_count;
                start = cmd->start;
                buffer = cmd->buffer.block_data;
                if (debugs_on & DEBUG_REG)
-                       DBG("%s Block: Register block %s\n", dir,
-                           block_name[block_index]);
+                       DBG("%s Block: Register block %s\n", DIR(cmd),
+                           block_name[BINDEX(cmd)]);
                break;
        case CAMERAACCESS_TYPE_MASK:
                count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
                start = 0;
                buffer = (u8 *) & cmd->buffer;
                if (debugs_on & DEBUG_REG)
-                       DBG("%s Mask: Register block %s\n", dir,
-                           block_name[block_index]);
+                       DBG("%s Mask: Register block %s\n", DIR(cmd),
+                           block_name[BINDEX(cmd)]);
                break;
        case CAMERAACCESS_TYPE_REPEAT:  /* For patch blocks only */
                count = cmd->reg_count;
                start = cmd->start;
                buffer = cmd->buffer.block_data;
                if (debugs_on & DEBUG_REG)
-                       DBG("%s Repeat: Register block %s\n", dir,
-                           block_name[block_index]);
+                       DBG("%s Repeat: Register block %s\n", DIR(cmd),
+                           block_name[BINDEX(cmd)]);
                break;
        default:
                LOG("%s: invalid request mode\n",__func__);
@@ -584,10 +578,10 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
                for (i = 0; i < cmd->reg_count; i++) {
                        if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
                                KINFO("%s Block: [0x%02X] = 0x%02X\n",
-                                   dir, start + i, buffer[i]);
+                                   DIR(cmd), start + i, buffer[i]);
                        if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
                                KINFO("%s Random: [0x%02X] = 0x%02X\n",
-                                   dir, cmd->buffer.registers[i].index,
+                                   DIR(cmd), cmd->buffer.registers[i].index,
                                    cmd->buffer.registers[i].value);
                }
        }
index 9bad398429366934a83fc3d2c1c8cddabb6fbf50..5111bbcefad5f4ff1e76d5e316d38306fdf50a5c 100644 (file)
@@ -395,10 +395,15 @@ static int sync(struct camera_data *cam, int frame_nr)
  *
  *****************************************************************************/
 
-static int ioctl_set_gpio(void *arg, struct camera_data *cam)
+static long cpia2_default(struct file *file, void *fh, bool valid_prio,
+                         int cmd, void *arg)
 {
+       struct camera_data *cam = video_drvdata(file);
        __u32 gpio_val;
 
+       if (cmd != CPIA2_CID_GPIO)
+               return -EINVAL;
+
        gpio_val = *(__u32*) arg;
 
        if (gpio_val &~ 0xFFU)
@@ -415,11 +420,10 @@ static int ioctl_set_gpio(void *arg, struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_querycap(void *arg, struct camera_data *cam)
+static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc)
 {
-       struct v4l2_capability *vc = arg;
+       struct camera_data *cam = video_drvdata(file);
 
-       memset(vc, 0, sizeof(*vc));
        strcpy(vc->driver, "cpia2");
 
        if (cam->params.pnp_id.product == 0x151)
@@ -479,22 +483,26 @@ static int ioctl_querycap(void *arg, struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam)
+static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
-       struct v4l2_input *i = arg;
-
-       if(ioclt_nr  != VIDIOC_G_INPUT) {
-               if (i->index != 0)
-                      return -EINVAL;
-       }
-
-       memset(i, 0, sizeof(*i));
+       if (i->index)
+               return -EINVAL;
        strcpy(i->name, "Camera");
        i->type = V4L2_INPUT_TYPE_CAMERA;
+       return 0;
+}
 
+static int cpia2_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
        return 0;
 }
 
+static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
+{
+       return i ? -EINVAL : 0;
+}
+
 /******************************************************************************
  *
  *  ioctl_enum_fmt
@@ -503,9 +511,9 @@ static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_enum_fmt(void *arg,struct camera_data *cam)
+static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
+                                           struct v4l2_fmtdesc *f)
 {
-       struct v4l2_fmtdesc *f = arg;
        int index = f->index;
 
        if (index < 0 || index > 1)
@@ -539,12 +547,10 @@ static int ioctl_enum_fmt(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_try_fmt(void *arg,struct camera_data *cam)
+static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
+                                         struct v4l2_format *f)
 {
-       struct v4l2_format *f = arg;
-
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-              return -EINVAL;
+       struct camera_data *cam = video_drvdata(file);
 
        if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
            f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
@@ -603,12 +609,17 @@ static int ioctl_try_fmt(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
+static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
+                                       struct v4l2_format *f)
 {
-       struct v4l2_format *f = arg;
+       struct camera_data *cam = video_drvdata(file);
+       struct cpia2_fh *fh = _fh;
        int err, frame;
 
-       err = ioctl_try_fmt(arg, cam);
+       err = v4l2_prio_check(&cam->prio, fh->prio);
+       if (err)
+               return err;
+       err = cpia2_try_fmt_vid_cap(file, _fh, f);
        if(err != 0)
                return err;
 
@@ -658,12 +669,10 @@ static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
  *
  *****************************************************************************/
 
-static int ioctl_get_fmt(void *arg,struct camera_data *cam)
+static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
+                                       struct v4l2_format *f)
 {
-       struct v4l2_format *f = arg;
-
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-              return -EINVAL;
+       struct camera_data *cam = video_drvdata(file);
 
        f->fmt.pix.width = cam->width;
        f->fmt.pix.height = cam->height;
@@ -686,9 +695,9 @@ static int ioctl_get_fmt(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_cropcap(void *arg,struct camera_data *cam)
+static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
 {
-       struct v4l2_cropcap *c = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
               return -EINVAL;
@@ -715,9 +724,9 @@ static int ioctl_cropcap(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_queryctrl(void *arg,struct camera_data *cam)
+static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
 {
-       struct v4l2_queryctrl *c = arg;
+       struct camera_data *cam = video_drvdata(file);
        int i;
 
        for(i=0; i<NUM_CONTROLS; ++i) {
@@ -783,12 +792,9 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_querymenu(void *arg,struct camera_data *cam)
+static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m)
 {
-       struct v4l2_querymenu *m = arg;
-
-       memset(m->name, 0, sizeof(m->name));
-       m->reserved = 0;
+       struct camera_data *cam = video_drvdata(file);
 
        switch(m->id) {
        case CPIA2_CID_FLICKER_MODE:
@@ -837,9 +843,9 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
+static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
 {
-       struct v4l2_control *c = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        switch(c->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -955,9 +961,9 @@ static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_s_ctrl(void *arg,struct camera_data *cam)
+static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
 {
-       struct v4l2_control *c = arg;
+       struct camera_data *cam = video_drvdata(file);
        int i;
        int retval = 0;
 
@@ -1031,9 +1037,9 @@ static int ioctl_s_ctrl(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam)
+static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
 {
-       struct v4l2_jpegcompression *parms = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        memset(parms, 0, sizeof(*parms));
 
@@ -1072,9 +1078,9 @@ static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam)
+static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
 {
-       struct v4l2_jpegcompression *parms = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
            parms->APP_len, parms->COM_len);
@@ -1121,9 +1127,9 @@ static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_reqbufs(void *arg,struct camera_data *cam)
+static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
 {
-       struct v4l2_requestbuffers *req = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
           req->memory != V4L2_MEMORY_MMAP)
@@ -1144,9 +1150,9 @@ static int ioctl_reqbufs(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_querybuf(void *arg,struct camera_data *cam)
+static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       struct v4l2_buffer *buf = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
           buf->index > cam->num_frames)
@@ -1192,9 +1198,9 @@ static int ioctl_querybuf(void *arg,struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_qbuf(void *arg,struct camera_data *cam)
+static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       struct v4l2_buffer *buf = arg;
+       struct camera_data *cam = video_drvdata(file);
 
        if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
           buf->memory != V4L2_MEMORY_MMAP ||
@@ -1248,9 +1254,9 @@ static int find_earliest_filled_buffer(struct camera_data *cam)
  *
  *****************************************************************************/
 
-static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
+static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       struct v4l2_buffer *buf = arg;
+       struct camera_data *cam = video_drvdata(file);
        int frame;
 
        if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
@@ -1296,210 +1302,56 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
        return 0;
 }
 
-/******************************************************************************
- *
- *  cpia2_ioctl
- *
- *****************************************************************************/
-static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
 {
-       struct camera_data *cam = video_drvdata(file);
-       long retval = 0;
-
-       if (!cam)
-               return -ENOTTY;
-
-       if (!cam->present)
-               return -ENODEV;
-
-       /* Priority check */
-       switch (cmd) {
-       case VIDIOC_S_FMT:
-       {
-               struct cpia2_fh *fh = file->private_data;
-               retval = v4l2_prio_check(&cam->prio, fh->prio);
-               if (retval)
-                       return retval;
-               break;
-       }
-       default:
-               break;
-       }
-
-       switch (cmd) {
-       /* CPIA2 extension to Video4Linux API */
-       case CPIA2_IOC_SET_GPIO:
-               retval = ioctl_set_gpio(arg, cam);
-               break;
-       case VIDIOC_QUERYCAP:
-               retval = ioctl_querycap(arg,cam);
-               break;
-
-       case VIDIOC_ENUMINPUT:
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-               retval = ioctl_input(cmd, arg, cam);
-               break;
-
-       case VIDIOC_ENUM_FMT:
-               retval = ioctl_enum_fmt(arg,cam);
-               break;
-       case VIDIOC_TRY_FMT:
-               retval = ioctl_try_fmt(arg,cam);
-               break;
-       case VIDIOC_G_FMT:
-               retval = ioctl_get_fmt(arg,cam);
-               break;
-       case VIDIOC_S_FMT:
-               retval = ioctl_set_fmt(arg,cam,file->private_data);
-               break;
+       struct cpia2_fh *fh = _fh;
 
-       case VIDIOC_CROPCAP:
-               retval = ioctl_cropcap(arg,cam);
-               break;
-       case VIDIOC_G_CROP:
-       case VIDIOC_S_CROP:
-               // TODO: I think cropping can be implemented - SJB
-               retval = -EINVAL;
-               break;
-
-       case VIDIOC_QUERYCTRL:
-               retval = ioctl_queryctrl(arg,cam);
-               break;
-       case VIDIOC_QUERYMENU:
-               retval = ioctl_querymenu(arg,cam);
-               break;
-       case VIDIOC_G_CTRL:
-               retval = ioctl_g_ctrl(arg,cam);
-               break;
-       case VIDIOC_S_CTRL:
-               retval = ioctl_s_ctrl(arg,cam);
-               break;
-
-       case VIDIOC_G_JPEGCOMP:
-               retval = ioctl_g_jpegcomp(arg,cam);
-               break;
-       case VIDIOC_S_JPEGCOMP:
-               retval = ioctl_s_jpegcomp(arg,cam);
-               break;
-
-       case VIDIOC_G_PRIORITY:
-       {
-               struct cpia2_fh *fh = file->private_data;
-               *(enum v4l2_priority*)arg = fh->prio;
-               break;
-       }
-       case VIDIOC_S_PRIORITY:
-       {
-               struct cpia2_fh *fh = file->private_data;
-               enum v4l2_priority prio;
-               prio = *(enum v4l2_priority*)arg;
-               if(cam->streaming &&
-                  prio != fh->prio &&
-                  fh->prio == V4L2_PRIORITY_RECORD) {
-                       /* Can't drop record priority while streaming */
-                       retval = -EBUSY;
-               } else if(prio == V4L2_PRIORITY_RECORD &&
-                  prio != fh->prio &&
-                  v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) {
-                       /* Only one program can record at a time */
-                       retval = -EBUSY;
-               } else {
-                       retval = v4l2_prio_change(&cam->prio, &fh->prio, prio);
-               }
-               break;
-       }
-
-       case VIDIOC_REQBUFS:
-               retval = ioctl_reqbufs(arg,cam);
-               break;
-       case VIDIOC_QUERYBUF:
-               retval = ioctl_querybuf(arg,cam);
-               break;
-       case VIDIOC_QBUF:
-               retval = ioctl_qbuf(arg,cam);
-               break;
-       case VIDIOC_DQBUF:
-               retval = ioctl_dqbuf(arg,cam,file);
-               break;
-       case VIDIOC_STREAMON:
-       {
-               int type;
-               DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
-               type = *(int*)arg;
-               if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       retval = -EINVAL;
-
-               if(!cam->streaming) {
-                       retval = cpia2_usb_stream_start(cam,
-                                         cam->params.camera_state.stream_mode);
-               } else {
-                       retval = -EINVAL;
-               }
-
-               break;
-       }
-       case VIDIOC_STREAMOFF:
-       {
-               int type;
-               DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
-               type = *(int*)arg;
-               if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       retval = -EINVAL;
-
-               if(cam->streaming) {
-                       retval = cpia2_usb_stream_stop(cam);
-               } else {
-                       retval = -EINVAL;
-               }
-
-               break;
-       }
-
-       case VIDIOC_ENUMOUTPUT:
-       case VIDIOC_G_OUTPUT:
-       case VIDIOC_S_OUTPUT:
-       case VIDIOC_G_MODULATOR:
-       case VIDIOC_S_MODULATOR:
-
-       case VIDIOC_ENUMAUDIO:
-       case VIDIOC_G_AUDIO:
-       case VIDIOC_S_AUDIO:
+       *p = fh->prio;
+       return 0;
+}
 
-       case VIDIOC_ENUMAUDOUT:
-       case VIDIOC_G_AUDOUT:
-       case VIDIOC_S_AUDOUT:
+static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
+{
+       struct camera_data *cam = video_drvdata(file);
+       struct cpia2_fh *fh = fh;
 
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
+       if (cam->streaming && prio != fh->prio &&
+                       fh->prio == V4L2_PRIORITY_RECORD)
+               /* Can't drop record priority while streaming */
+               return -EBUSY;
 
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY:
+       if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio &&
+                       v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD)
+               /* Only one program can record at a time */
+               return -EBUSY;
+       return v4l2_prio_change(&cam->prio, &fh->prio, prio);
+}
 
-       case VIDIOC_OVERLAY:
-       case VIDIOC_G_FBUF:
-       case VIDIOC_S_FBUF:
+static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+       struct camera_data *cam = video_drvdata(file);
 
-       case VIDIOC_G_PARM:
-       case VIDIOC_S_PARM:
-               retval = -EINVAL;
-               break;
-       default:
-               retval = -ENOIOCTLCMD;
-               break;
-       }
+       DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
+       if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
-       return retval;
+       if (!cam->streaming)
+               return cpia2_usb_stream_start(cam,
+                               cam->params.camera_state.stream_mode);
+       return -EINVAL;
 }
 
-static long cpia2_ioctl(struct file *file,
-                      unsigned int cmd, unsigned long arg)
+static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 {
-       return video_usercopy(file, cmd, arg, cpia2_do_ioctl);
+       struct camera_data *cam = video_drvdata(file);
+
+       DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
+       if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->streaming)
+               return cpia2_usb_stream_stop(cam);
+       return -EINVAL;
 }
 
 /******************************************************************************
@@ -1550,6 +1402,33 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
        v4l2_prio_init(&cam->prio);
 }
 
+static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
+       .vidioc_querycap                    = cpia2_querycap,
+       .vidioc_enum_input                  = cpia2_enum_input,
+       .vidioc_g_input                     = cpia2_g_input,
+       .vidioc_s_input                     = cpia2_s_input,
+       .vidioc_enum_fmt_vid_cap            = cpia2_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap               = cpia2_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap               = cpia2_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap             = cpia2_try_fmt_vid_cap,
+       .vidioc_queryctrl                   = cpia2_queryctrl,
+       .vidioc_querymenu                   = cpia2_querymenu,
+       .vidioc_g_ctrl                      = cpia2_g_ctrl,
+       .vidioc_s_ctrl                      = cpia2_s_ctrl,
+       .vidioc_g_jpegcomp                  = cpia2_g_jpegcomp,
+       .vidioc_s_jpegcomp                  = cpia2_s_jpegcomp,
+       .vidioc_cropcap                     = cpia2_cropcap,
+       .vidioc_reqbufs                     = cpia2_reqbufs,
+       .vidioc_querybuf                    = cpia2_querybuf,
+       .vidioc_qbuf                        = cpia2_qbuf,
+       .vidioc_dqbuf                       = cpia2_dqbuf,
+       .vidioc_streamon                    = cpia2_streamon,
+       .vidioc_streamoff                   = cpia2_streamoff,
+       .vidioc_g_priority                  = cpia2_g_priority,
+       .vidioc_s_priority                  = cpia2_s_priority,
+       .vidioc_default                     = cpia2_default,
+};
+
 /***
  * The v4l video device structure initialized for this device
  ***/
@@ -1559,7 +1438,7 @@ static const struct v4l2_file_operations cpia2_fops = {
        .release        = cpia2_close,
        .read           = cpia2_v4l_read,
        .poll           = cpia2_v4l_poll,
-       .unlocked_ioctl = cpia2_ioctl,
+       .unlocked_ioctl = video_ioctl2,
        .mmap           = cpia2_mmap,
 };
 
@@ -1567,6 +1446,7 @@ static struct video_device cpia2_template = {
        /* I could not find any place for the old .initialize initializer?? */
        .name =         "CPiA2 Camera",
        .fops =         &cpia2_fops,
+       .ioctl_ops =    &cpia2_ioctl_ops,
        .release =      video_device_release,
 };
 
index 9358fe77e5622c28445163b1351ddf6078035d21..5909f2557ab4fbadbaec0a58d7635a37f0d86db7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
 MODULE_AUTHOR("Hans Verkuil");
@@ -36,6 +37,20 @@ module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
 
+struct cs5345_state {
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct cs5345_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct cs5345_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd;
+}
 
 /* ----------------------------------------------------------------------- */
 
@@ -65,33 +80,20 @@ static int cs5345_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-               ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
-               return 0;
-       }
-       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-               return -EINVAL;
-       ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
-       if (ctrl->value >= 32)
-               ctrl->value = ctrl->value - 64;
-       return 0;
-}
+       struct v4l2_subdev *sd = to_sd(ctrl);
 
-static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-               cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0);
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f);
+               cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f);
                return 0;
        }
-       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-               return -EINVAL;
-       if (ctrl->value > 24 || ctrl->value < -24)
-               return -EINVAL;
-       cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
-       cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
-       return 0;
+       return -EINVAL;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -144,11 +146,20 @@ static int cs5345_log_status(struct v4l2_subdev *sd)
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
+       .s_ctrl = cs5345_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops cs5345_core_ops = {
        .log_status = cs5345_log_status,
        .g_chip_ident = cs5345_g_chip_ident,
-       .g_ctrl = cs5345_g_ctrl,
-       .s_ctrl = cs5345_s_ctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = cs5345_g_register,
        .s_register = cs5345_s_register,
@@ -169,6 +180,7 @@ static const struct v4l2_subdev_ops cs5345_ops = {
 static int cs5345_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       struct cs5345_state *state;
        struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
@@ -178,11 +190,28 @@ static int cs5345_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
-       if (sd == NULL)
+       state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL);
+       if (state == NULL)
                return -ENOMEM;
+       sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
 
+       v4l2_ctrl_handler_init(&state->hdl, 2);
+       v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0);
+       sd->ctrl_handler = &state->hdl;
+       if (state->hdl.error) {
+               int err = state->hdl.error;
+
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+               return err;
+       }
+       /* set volume/mute */
+       v4l2_ctrl_handler_setup(&state->hdl);
+
        cs5345_write(sd, 0x02, 0x00);
        cs5345_write(sd, 0x04, 0x01);
        cs5345_write(sd, 0x09, 0x01);
@@ -194,9 +223,11 @@ static int cs5345_probe(struct i2c_client *client,
 static int cs5345_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct cs5345_state *state = to_state(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(sd);
+       v4l2_ctrl_handler_free(&state->hdl);
+       kfree(state);
        return 0;
 }
 
index 43d09a24b2624ee936373388e6b195521922c8ff..4a24ffb17a7d85177d9792a7c5f4eebf51e65a32 100644 (file)
@@ -342,17 +342,6 @@ void cx18_av_audio_set_path(struct cx18 *cx)
        }
 }
 
-static int get_volume(struct cx18 *cx)
-{
-       /* Volume runs +18dB to -96dB in 1/2dB steps
-        * change to fit the msp3400 -114dB to +12dB range */
-
-       /* check PATH1_VOLUME */
-       int vol = 228 - cx18_av_read(cx, 0x8d4);
-       vol = (vol / 2) + 23;
-       return vol << 9;
-}
-
 static void set_volume(struct cx18 *cx, int volume)
 {
        /* First convert the volume to msp3400 values (0-127) */
@@ -369,52 +358,18 @@ static void set_volume(struct cx18 *cx, int volume)
        cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
 }
 
-static int get_bass(struct cx18 *cx)
-{
-       /* bass is 49 steps +12dB to -12dB */
-
-       /* check PATH1_EQ_BASS_VOL */
-       int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
-       bass = (((48 - bass) * 0xffff) + 47) / 48;
-       return bass;
-}
-
 static void set_bass(struct cx18 *cx, int bass)
 {
        /* PATH1_EQ_BASS_VOL */
        cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
 }
 
-static int get_treble(struct cx18 *cx)
-{
-       /* treble is 49 steps +12dB to -12dB */
-
-       /* check PATH1_EQ_TREBLE_VOL */
-       int treble = cx18_av_read(cx, 0x8db) & 0x3f;
-       treble = (((48 - treble) * 0xffff) + 47) / 48;
-       return treble;
-}
-
 static void set_treble(struct cx18 *cx, int treble)
 {
        /* PATH1_EQ_TREBLE_VOL */
        cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
 }
 
-static int get_balance(struct cx18 *cx)
-{
-       /* balance is 7 bit, 0 to -96dB */
-
-       /* check PATH1_BAL_LEVEL */
-       int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
-       /* check PATH1_BAL_LEFT */
-       if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
-               balance = 0x80 - balance;
-       else
-               balance = 0x80 + balance;
-       return balance << 8;
-}
-
 static void set_balance(struct cx18 *cx, int balance)
 {
        int bal = balance >> 8;
@@ -431,12 +386,6 @@ static void set_balance(struct cx18 *cx, int balance)
        }
 }
 
-static int get_mute(struct cx18 *cx)
-{
-       /* check SRC1_MUTE_EN */
-       return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
-}
-
 static void set_mute(struct cx18 *cx, int mute)
 {
        struct cx18_av_state *state = &cx->av_state;
@@ -490,50 +439,33 @@ int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        return retval;
 }
 
-int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = get_volume(cx);
-               break;
-       case V4L2_CID_AUDIO_BASS:
-               ctrl->value = get_bass(cx);
-               break;
-       case V4L2_CID_AUDIO_TREBLE:
-               ctrl->value = get_treble(cx);
-               break;
-       case V4L2_CID_AUDIO_BALANCE:
-               ctrl->value = get_balance(cx);
-               break;
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = get_mute(cx);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
+       struct v4l2_subdev *sd = to_sd(ctrl);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
-{
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_VOLUME:
-               set_volume(cx, ctrl->value);
+               set_volume(cx, ctrl->val);
                break;
        case V4L2_CID_AUDIO_BASS:
-               set_bass(cx, ctrl->value);
+               set_bass(cx, ctrl->val);
                break;
        case V4L2_CID_AUDIO_TREBLE:
-               set_treble(cx, ctrl->value);
+               set_treble(cx, ctrl->val);
                break;
        case V4L2_CID_AUDIO_BALANCE:
-               set_balance(cx, ctrl->value);
+               set_balance(cx, ctrl->val);
                break;
        case V4L2_CID_AUDIO_MUTE:
-               set_mute(cx, ctrl->value);
+               set_mute(cx, ctrl->val);
                break;
        default:
                return -EINVAL;
        }
        return 0;
 }
+
+const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = {
+       .s_ctrl = cx18_av_audio_s_ctrl,
+};
index a41951cab276a1b6ff68f8fe26c550b6ec9f0869..f164b7f610a50320d1c11bcad00e0473efd02811 100644 (file)
@@ -129,6 +129,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
 {
        struct cx18_av_state *state = to_cx18_av_state(sd);
        struct cx18 *cx = v4l2_get_subdevdata(sd);
+       int default_volume;
        u32 v;
 
        cx18_av_loadfw(cx);
@@ -247,8 +248,23 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
 /*             CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
 /*    } */
        cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
-       state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
-       state->default_volume = ((state->default_volume / 2) + 23) << 9;
+       default_volume = cx18_av_read(cx, 0x8d4);
+       /*
+        * Enforce the legacy volume scale mapping limits to avoid
+        * -ERANGE errors when initializing the volume control
+        */
+       if (default_volume > 228) {
+               /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+               default_volume = 228;
+               cx18_av_write(cx, 0x8d4, 228);
+       } else if (default_volume < 20) {
+               /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+               default_volume = 20;
+               cx18_av_write(cx, 0x8d4, 20);
+       }
+       default_volume = (((228 - default_volume) >> 1) + 23) << 9;
+       state->volume->cur.val = state->volume->default_value = default_volume;
+       v4l2_ctrl_handler_setup(&state->hdl);
 }
 
 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
@@ -901,126 +917,35 @@ static int cx18_av_s_radio(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct v4l2_subdev *sd = to_sd(ctrl);
        struct cx18 *cx = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               if (ctrl->value < 0 || ctrl->value > 255) {
-                       CX18_ERR_DEV(sd, "invalid brightness setting %d\n",
-                                    ctrl->value);
-                       return -ERANGE;
-               }
-
-               cx18_av_write(cx, 0x414, ctrl->value - 128);
+               cx18_av_write(cx, 0x414, ctrl->val - 128);
                break;
 
        case V4L2_CID_CONTRAST:
-               if (ctrl->value < 0 || ctrl->value > 127) {
-                       CX18_ERR_DEV(sd, "invalid contrast setting %d\n",
-                                    ctrl->value);
-                       return -ERANGE;
-               }
-
-               cx18_av_write(cx, 0x415, ctrl->value << 1);
+               cx18_av_write(cx, 0x415, ctrl->val << 1);
                break;
 
        case V4L2_CID_SATURATION:
-               if (ctrl->value < 0 || ctrl->value > 127) {
-                       CX18_ERR_DEV(sd, "invalid saturation setting %d\n",
-                                    ctrl->value);
-                       return -ERANGE;
-               }
-
-               cx18_av_write(cx, 0x420, ctrl->value << 1);
-               cx18_av_write(cx, 0x421, ctrl->value << 1);
+               cx18_av_write(cx, 0x420, ctrl->val << 1);
+               cx18_av_write(cx, 0x421, ctrl->val << 1);
                break;
 
        case V4L2_CID_HUE:
-               if (ctrl->value < -128 || ctrl->value > 127) {
-                       CX18_ERR_DEV(sd, "invalid hue setting %d\n",
-                                    ctrl->value);
-                       return -ERANGE;
-               }
-
-               cx18_av_write(cx, 0x422, ctrl->value);
+               cx18_av_write(cx, 0x422, ctrl->val);
                break;
 
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_MUTE:
-               return cx18_av_audio_s_ctrl(cx, ctrl);
-
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
-               break;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = cx18_av_read(cx, 0x415) >> 1;
-               break;
-       case V4L2_CID_SATURATION:
-               ctrl->value = cx18_av_read(cx, 0x420) >> 1;
-               break;
-       case V4L2_CID_HUE:
-               ctrl->value = (s8)cx18_av_read(cx, 0x422);
-               break;
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_MUTE:
-               return cx18_av_audio_g_ctrl(cx, ctrl);
        default:
                return -EINVAL;
        }
        return 0;
 }
 
-static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       struct cx18_av_state *state = to_cx18_av_state(sd);
-
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-       default:
-               break;
-       }
-
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535,
-                       65535 / 100, state->default_volume);
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
-       default:
-               return -EINVAL;
-       }
-       return -EINVAL;
-}
-
 static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
 {
        struct cx18_av_state *state = to_cx18_av_state(sd);
@@ -1356,14 +1281,22 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
 }
 #endif
 
+static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
+       .s_ctrl = cx18_av_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
        .g_chip_ident = cx18_av_g_chip_ident,
        .log_status = cx18_av_log_status,
        .load_fw = cx18_av_load_fw,
        .reset = cx18_av_reset,
-       .queryctrl = cx18_av_queryctrl,
-       .g_ctrl = cx18_av_g_ctrl,
-       .s_ctrl = cx18_av_s_ctrl,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = cx18_av_s_std,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = cx18_av_g_register,
@@ -1427,8 +1360,42 @@ int cx18_av_probe(struct cx18 *cx)
        snprintf(sd->name, sizeof(sd->name),
                 "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
        sd->grp_id = CX18_HW_418_AV;
+       v4l2_ctrl_handler_init(&state->hdl, 9);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+
+       state->volume = v4l2_ctrl_new_std(&state->hdl,
+                       &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+                       0, 65535, 65535 / 100, 0);
+       v4l2_ctrl_new_std(&state->hdl,
+                       &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+                       0, 1, 1, 0);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+                       V4L2_CID_AUDIO_BALANCE,
+                       0, 65535, 65535 / 100, 32768);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+                       V4L2_CID_AUDIO_BASS,
+                       0, 65535, 65535 / 100, 32768);
+       v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
+                       V4L2_CID_AUDIO_TREBLE,
+                       0, 65535, 65535 / 100, 32768);
+       sd->ctrl_handler = &state->hdl;
+       if (state->hdl.error) {
+               int err = state->hdl.error;
+
+               v4l2_ctrl_handler_free(&state->hdl);
+               return err;
+       }
        err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
-       if (!err)
+       if (err)
+               v4l2_ctrl_handler_free(&state->hdl);
+       else
                cx18_av_init(cx);
        return err;
 }
index 1956991795e3ab6b20d4a6b7b05ce3ddda5aecc2..188c9c3d2db10727daf71bbf723bf1e4b2c7cd5e 100644 (file)
@@ -26,6 +26,7 @@
 #define _CX18_AV_CORE_H_
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 struct cx18;
 
@@ -95,13 +96,14 @@ enum cx18_av_audio_input {
 
 struct cx18_av_state {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_ctrl *volume;
        int radio;
        v4l2_std_id std;
        enum cx18_av_video_input vid_input;
        enum cx18_av_audio_input aud_input;
        u32 audclk_freq;
        int audmode;
-       int default_volume;
        u32 id;
        u32 rev;
        int is_initialized;
@@ -347,6 +349,11 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
        return container_of(sd, struct cx18_av_state, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd;
+}
+
 /* ----------------------------------------------------------------------- */
 /* cx18_av-core.c                                                         */
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
@@ -369,10 +376,9 @@ int cx18_av_loadfw(struct cx18 *cx);
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-audio.c                                                         */
-int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
-int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
 int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
 void cx18_av_audio_set_path(struct cx18 *cx);
+extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops;
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-vbi.c                                                           */
index 97d7b7e100a3d50ff43f948de3baccac0c9b069e..282a3d29fdaa2a20bd677328f53b35bce61f4b7d 100644 (file)
 #include "cx18-mailbox.h"
 #include "cx18-controls.h"
 
-/* Must be sorted from low to high control ID! */
-static const u32 user_ctrls[] = {
-       V4L2_CID_USER_CLASS,
-       V4L2_CID_BRIGHTNESS,
-       V4L2_CID_CONTRAST,
-       V4L2_CID_SATURATION,
-       V4L2_CID_HUE,
-       V4L2_CID_AUDIO_VOLUME,
-       V4L2_CID_AUDIO_BALANCE,
-       V4L2_CID_AUDIO_BASS,
-       V4L2_CID_AUDIO_TREBLE,
-       V4L2_CID_AUDIO_MUTE,
-       V4L2_CID_AUDIO_LOUDNESS,
-       0
-};
-
-static const u32 *ctrl_classes[] = {
-       user_ctrls,
-       cx2341x_mpeg_ctrls,
-       NULL
-};
-
-int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
-{
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
-       const char *name;
-
-       qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
-       if (qctrl->id == 0)
-               return -EINVAL;
-
-       switch (qctrl->id) {
-       /* Standard V4L2 controls */
-       case V4L2_CID_USER_CLASS:
-               return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_HUE:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_CONTRAST:
-               if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
-                       qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-               return 0;
-
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-               if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
-                       qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-               return 0;
-
-       default:
-               if (cx2341x_ctrl_query(&cx->params, qctrl))
-                       qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-               return 0;
-       }
-       strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
-       qctrl->name[sizeof(qctrl->name) - 1] = 0;
-       return 0;
-}
-
-int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
+static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
-       struct v4l2_queryctrl qctrl;
-
-       qctrl.id = qmenu->id;
-       cx18_queryctrl(file, fh, &qctrl);
-       return v4l2_ctrl_query_menu(qmenu, &qctrl,
-                       cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
-}
-
-static int cx18_try_ctrl(struct file *file, void *fh,
-                                       struct v4l2_ext_control *vctrl)
-{
-       struct v4l2_queryctrl qctrl;
-       const char * const *menu_items = NULL;
-       int err;
-
-       qctrl.id = vctrl->id;
-       err = cx18_queryctrl(file, fh, &qctrl);
-       if (err)
-               return err;
-       if (qctrl.type == V4L2_CTRL_TYPE_MENU)
-               menu_items = v4l2_ctrl_get_menu(qctrl.id);
-       return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
-}
-
-static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
-{
-       switch (vctrl->id) {
-               /* Standard V4L2 controls */
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_HUE:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_CONTRAST:
-               return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
-
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-               return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
-
-       default:
-               CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
-{
-       switch (vctrl->id) {
-               /* Standard V4L2 controls */
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_HUE:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_CONTRAST:
-               return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
-
-       case V4L2_CID_AUDIO_VOLUME:
-       case V4L2_CID_AUDIO_MUTE:
-       case V4L2_CID_AUDIO_BALANCE:
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-       case V4L2_CID_AUDIO_LOUDNESS:
-               return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
+       struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+       int type = cxhdl->stream_type->val;
 
-       default:
-               CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int cx18_setup_vbi_fmt(struct cx18 *cx,
-                             enum v4l2_mpeg_stream_vbi_fmt fmt,
-                             enum v4l2_mpeg_stream_type type)
-{
-       if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
-               return -EINVAL;
        if (atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
@@ -230,121 +89,43 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
        return 0;
 }
 
-int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
-       struct v4l2_control ctrl;
-
-       if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-               int i;
-               int err = 0;
-
-               for (i = 0; i < c->count; i++) {
-                       ctrl.id = c->controls[i].id;
-                       ctrl.value = c->controls[i].value;
-                       err = cx18_g_ctrl(cx, &ctrl);
-                       c->controls[i].value = ctrl.value;
-                       if (err) {
-                               c->error_idx = i;
-                               break;
-                       }
-               }
-               return err;
-       }
-       if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-               return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
-       return -EINVAL;
+       struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
+       int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+       struct v4l2_mbus_framefmt fmt;
+
+       /* fix videodecoder resolution */
+       fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+       fmt.height = cxhdl->height;
+       fmt.code = V4L2_MBUS_FMT_FIXED;
+       v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
+       return 0;
 }
 
-int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
 {
-       struct cx18_open_id *id = fh;
-       struct cx18 *cx = id->cx;
-       int ret;
-       struct v4l2_control ctrl;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
-
-       if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-               int i;
-               int err = 0;
-
-               for (i = 0; i < c->count; i++) {
-                       ctrl.id = c->controls[i].id;
-                       ctrl.value = c->controls[i].value;
-                       err = cx18_s_ctrl(cx, &ctrl);
-                       c->controls[i].value = ctrl.value;
-                       if (err) {
-                               c->error_idx = i;
-                               break;
-                       }
-               }
-               return err;
-       }
-       if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
-               static u32 freqs[3] = { 44100, 48000, 32000 };
-               struct cx18_api_func_private priv;
-               struct cx2341x_mpeg_params p = cx->params;
-               int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
-                                               c, VIDIOC_S_EXT_CTRLS);
-               unsigned int idx;
-
-               if (err)
-                       return err;
+       static const u32 freqs[3] = { 44100, 48000, 32000 };
+       struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
 
-               if (p.video_encoding != cx->params.video_encoding) {
-                       int is_mpeg1 = p.video_encoding ==
-                                               V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
-                       struct v4l2_mbus_framefmt fmt;
-
-                       /* fix videodecoder resolution */
-                       fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1);
-                       fmt.height = cx->params.height;
-                       fmt.code = V4L2_MBUS_FMT_FIXED;
-                       v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
-               }
-               priv.cx = cx;
-               priv.s = &cx->streams[id->type];
-               err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
-               if (!err &&
-                   (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
-                    cx->params.stream_type != p.stream_type))
-                       err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
-                                                p.stream_type);
-               cx->params = p;
-               cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-               idx = p.audio_properties & 0x03;
-               /* The audio clock of the digitizer must match the codec sample
-                  rate otherwise you get some very strange effects. */
-               if (idx < ARRAY_SIZE(freqs))
-                       cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
-               return err;
-       }
-       return -EINVAL;
+       /* The audio clock of the digitizer must match the codec sample
+          rate otherwise you get some very strange effects. */
+       if (idx < ARRAY_SIZE(freqs))
+               cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
+       return 0;
 }
 
-int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
 
-       if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
-               int i;
-               int err = 0;
-
-               for (i = 0; i < c->count; i++) {
-                       err = cx18_try_ctrl(file, fh, &c->controls[i]);
-                       if (err) {
-                               c->error_idx = i;
-                               break;
-                       }
-               }
-               return err;
-       }
-       if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-               return cx2341x_ext_ctrls(&cx->params,
-                                               atomic_read(&cx->ana_capturing),
-                                               c, VIDIOC_TRY_EXT_CTRLS);
-       return -EINVAL;
+       cx->dualwatch_stereo_mode = val;
+       return 0;
 }
+
+struct cx2341x_handler_ops cx18_cxhdl_ops = {
+       .s_audio_mode = cx18_s_audio_mode,
+       .s_audio_sampling_freq = cx18_s_audio_sampling_freq,
+       .s_video_encoding = cx18_s_video_encoding,
+       .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt,
+};
index e46323700b81ca358d10aafec1df1275d23346ba..cb5dfc7b20546969a1cdd06f23467cba229901a7 100644 (file)
@@ -21,9 +21,4 @@
  *  02111-1307  USA
  */
 
-int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
-int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
-int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
-int cx18_try_ext_ctrls(struct file *file, void *fh,
-                       struct v4l2_ext_controls *a);
-int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
+extern struct cx2341x_handler_ops cx18_cxhdl_ops;
index b1c3cbd9274387d253e6c3506b6a01c547d8d156..321c1b79794c05c623833467b74a967059740285 100644 (file)
@@ -36,6 +36,7 @@
 #include "cx18-scb.h"
 #include "cx18-mailbox.h"
 #include "cx18-ioctl.h"
+#include "cx18-controls.h"
 #include "tuner-xc2028.h"
 
 #include <media/tveeprom.h>
@@ -729,15 +730,22 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        cx->open_id = 1;
 
        /* Initial settings */
-       cx2341x_fill_defaults(&cx->params);
-       cx->temporal_strength = cx->params.video_temporal_filter;
-       cx->spatial_strength = cx->params.video_spatial_filter;
-       cx->filter_mode = cx->params.video_spatial_filter_mode |
-               (cx->params.video_temporal_filter_mode << 1) |
-               (cx->params.video_median_filter_type << 2);
-       cx->params.port = CX2341X_PORT_MEMORY;
-       cx->params.capabilities =
-                               CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+       cx->cxhdl.port = CX2341X_PORT_MEMORY;
+       cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+       cx->cxhdl.ops = &cx18_cxhdl_ops;
+       cx->cxhdl.func = cx18_api_func;
+       cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+       ret = cx2341x_handler_init(&cx->cxhdl, 50);
+       if (ret)
+               return ret;
+       cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
+
+       cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
+       cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
+       cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
+               (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
+               (cx->cxhdl.video_median_filter_type->cur.val << 2);
+
        init_waitqueue_head(&cx->cap_w);
        init_waitqueue_head(&cx->mb_apu_waitq);
        init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -1049,7 +1057,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
        else
                cx->is_50hz = 1;
 
-       cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+       cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
 
        if (cx->options.radio > 0)
                cx->v4l2_cap |= V4L2_CAP_RADIO;
@@ -1095,7 +1103,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 
        /* Load cx18 submodules (cx18-alsa) */
        request_modules(cx);
-
        return 0;
 
 free_streams:
@@ -1278,6 +1285,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
                for (i = 0; i < CX18_VBI_FRAMES; i++)
                        kfree(cx->vbi.sliced_mpeg_data[i]);
 
+       v4l2_ctrl_handler_free(&cx->av_state.hdl);
+
        CX18_INFO("Removed %s\n", cx->card_name);
 
        v4l2_device_unregister(v4l2_dev);
index f736679d25178a5e78ae815f24ca006779f66eaa..b86a740c68df82b3dc833e5b4a577bed6f4fedf8 100644 (file)
@@ -50,6 +50,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
 #include <media/tuner.h>
 #include <media/ir-kbd-i2c.h>
 #include "cx18-mailbox.h"
@@ -405,12 +406,22 @@ struct cx18_stream {
 };
 
 struct cx18_open_id {
+       struct v4l2_fh fh;
        u32 open_id;
        int type;
-       enum v4l2_priority prio;
        struct cx18 *cx;
 };
 
+static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
+{
+       return container_of(fh, struct cx18_open_id, fh);
+}
+
+static inline struct cx18_open_id *file2id(struct file *file)
+{
+       return fh2id(file->private_data);
+}
+
 /* forward declaration of struct defined in cx18-cards.h */
 struct cx18_card;
 
@@ -565,7 +576,7 @@ struct cx18 {
        struct cx18_av_state av_state;
 
        /* codec settings */
-       struct cx2341x_mpeg_params params;
+       struct cx2341x_handler cxhdl;
        u32 filter_mode;
        u32 temporal_strength;
        u32 spatial_strength;
@@ -593,7 +604,6 @@ struct cx18 {
                                   uninitialized value in the stream->id. */
 
        u32 base_addr;
-       struct v4l2_prio_state prio;
 
        u8 card_rev;
        void __iomem *enc_mem, *reg_mem;
index 9f23b90732f2d38ffdfe3e56edb9939501f26654..e9802d99439b15462b371a46563bb6e1093b94fb 100644 (file)
@@ -160,13 +160,10 @@ EXPORT_SYMBOL(cx18_release_stream);
 static void cx18_dualwatch(struct cx18 *cx)
 {
        struct v4l2_tuner vt;
-       u32 new_bitmap;
        u32 new_stereo_mode;
-       const u32 stereo_mask = 0x0300;
        const u32 dual = 0x0200;
-       u32 h;
 
-       new_stereo_mode = cx->params.audio_properties & stereo_mask;
+       new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
        memset(&vt, 0, sizeof(vt));
        cx18_call_all(cx, tuner, g_tuner, &vt);
        if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
@@ -176,25 +173,10 @@ static void cx18_dualwatch(struct cx18 *cx)
        if (new_stereo_mode == cx->dualwatch_stereo_mode)
                return;
 
-       new_bitmap = new_stereo_mode
-                       | (cx->params.audio_properties & ~stereo_mask);
-
-       CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
-                       "new audio_bitmask=0x%ux\n",
-                       cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
-
-       h = cx18_find_handle(cx);
-       if (h == CX18_INVALID_TASK_HANDLE) {
-               CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
-               return;
-       }
-
-       if (cx18_vapi(cx,
-                     CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
-               cx->dualwatch_stereo_mode = new_stereo_mode;
-               return;
-       }
-       CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+       CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+                          cx->dualwatch_stereo_mode, new_stereo_mode);
+       if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
+               CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
 }
 
 
@@ -603,7 +585,7 @@ start_failed:
 ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
                loff_t *pos)
 {
-       struct cx18_open_id *id = filp->private_data;
+       struct cx18_open_id *id = file2id(filp);
        struct cx18 *cx = id->cx;
        struct cx18_stream *s = &cx->streams[id->type];
        int rc;
@@ -620,7 +602,7 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
 
 unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
 {
-       struct cx18_open_id *id = filp->private_data;
+       struct cx18_open_id *id = file2id(filp);
        struct cx18 *cx = id->cx;
        struct cx18_stream *s = &cx->streams[id->type];
        int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
@@ -694,13 +676,15 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
 
 int cx18_v4l2_close(struct file *filp)
 {
-       struct cx18_open_id *id = filp->private_data;
+       struct v4l2_fh *fh = filp->private_data;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        struct cx18_stream *s = &cx->streams[id->type];
 
        CX18_DEBUG_IOCTL("close() of %s\n", s->name);
 
-       v4l2_prio_close(&cx->prio, id->prio);
+       v4l2_fh_del(fh);
+       v4l2_fh_exit(fh);
 
        /* Easy case first: this stream was never claimed by us */
        if (s->id != id->open_id) {
@@ -724,8 +708,8 @@ int cx18_v4l2_close(struct file *filp)
                if (atomic_read(&cx->ana_capturing) > 0) {
                        /* Undo video mute */
                        cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
-                               cx->params.video_mute |
-                                       (cx->params.video_mute_yuv << 8));
+                           (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) |
+                           (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8)));
                }
                /* Done! Unmute and continue. */
                cx18_unmute(cx);
@@ -746,22 +730,24 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
        CX18_DEBUG_FILE("open %s\n", s->name);
 
        /* Allocate memory */
-       item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
+       item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
        if (NULL == item) {
                CX18_DEBUG_WARN("nomem on v4l2 open\n");
                return -ENOMEM;
        }
+       v4l2_fh_init(&item->fh, s->video_dev);
+
        item->cx = cx;
        item->type = s->type;
-       v4l2_prio_open(&cx->prio, &item->prio);
 
        item->open_id = cx->open_id++;
-       filp->private_data = item;
+       filp->private_data = &item->fh;
 
        if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
                /* Try to claim this stream */
                if (cx18_claim_stream(item, item->type)) {
                        /* No, it's already in use */
+                       v4l2_fh_exit(&item->fh);
                        kfree(item);
                        return -EBUSY;
                }
@@ -771,6 +757,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
                                /* switching to radio while capture is
                                   in progress is not polite */
                                cx18_release_stream(s);
+                               v4l2_fh_exit(&item->fh);
                                kfree(item);
                                return -EBUSY;
                        }
@@ -787,6 +774,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
                /* Done! Unmute and continue. */
                cx18_unmute(cx);
        }
+       v4l2_fh_add(&item->fh);
        return 0;
 }
 
index c330fb917b50bfd0ea1f3f22fb3d378d9fe3f2b0..040aaa87579ddf0c21f4a9d786a8d636ac5ebfe0 100644 (file)
@@ -96,7 +96,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
        /* Our default information for ir-kbd-i2c.c to use */
        switch (hw) {
        case CX18_HW_Z8F0811_IR_RX_HAUP:
-               init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+               init_data->ir_codes = RC_MAP_HAUPPAUGE;
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
                init_data->type = RC_TYPE_RC5;
                init_data->name = cx->card_name;
index 7150195740dc89174b2ea6f38b8828ba788ad2cd..86c30b9963e534d14ce3e5000927876c901daf42 100644 (file)
@@ -148,12 +148,12 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
 static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
                                struct v4l2_format *fmt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
-       pixfmt->width = cx->params.width;
-       pixfmt->height = cx->params.height;
+       pixfmt->width = cx->cxhdl.width;
+       pixfmt->height = cx->cxhdl.height;
        pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
        pixfmt->field = V4L2_FIELD_INTERLACED;
        pixfmt->priv = 0;
@@ -173,7 +173,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
 static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
                                struct v4l2_format *fmt)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
 
        vbifmt->sampling_rate = 27000000;
@@ -192,7 +192,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 
        /* sane, V4L2 spec compliant, defaults */
@@ -221,7 +221,7 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
 static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
                                struct v4l2_format *fmt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
@@ -252,7 +252,7 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 
        vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
@@ -271,30 +271,26 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
 static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
                                struct v4l2_format *fmt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        struct v4l2_mbus_framefmt mbus_fmt;
        int ret;
        int w, h;
 
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
-
        ret = cx18_try_fmt_vid_cap(file, fh, fmt);
        if (ret)
                return ret;
        w = fmt->fmt.pix.width;
        h = fmt->fmt.pix.height;
 
-       if (cx->params.width == w && cx->params.height == h)
+       if (cx->cxhdl.width == w && cx->cxhdl.height == h)
                return 0;
 
        if (atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
-       mbus_fmt.width = cx->params.width = w;
-       mbus_fmt.height = cx->params.height = h;
+       mbus_fmt.width = cx->cxhdl.width = w;
+       mbus_fmt.height = cx->cxhdl.height = h;
        mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
        v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
        return cx18_g_fmt_vid_cap(file, fh, fmt);
@@ -303,14 +299,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
 static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
                                struct v4l2_format *fmt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        int ret;
 
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
-
        /*
         * Changing the Encoder's Raw VBI parameters won't have any effect
         * if any analog capture is ongoing
@@ -337,15 +329,11 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
 static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_format *fmt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        int ret;
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
-
        cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
 
        /*
@@ -372,7 +360,7 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
 static int cx18_g_chip_ident(struct file *file, void *fh,
                                struct v4l2_dbg_chip_ident *chip)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        int err = 0;
 
        chip->ident = V4L2_IDENT_NONE;
@@ -442,7 +430,7 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
 static int cx18_g_register(struct file *file, void *fh,
                                struct v4l2_dbg_register *reg)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
@@ -454,7 +442,7 @@ static int cx18_g_register(struct file *file, void *fh,
 static int cx18_s_register(struct file *file, void *fh,
                                struct v4l2_dbg_register *reg)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (v4l2_chip_match_host(&reg->match))
                return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
@@ -464,26 +452,10 @@ static int cx18_s_register(struct file *file, void *fh,
 }
 #endif
 
-static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
-{
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
-
-       *p = v4l2_prio_max(&cx->prio);
-       return 0;
-}
-
-static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
-{
-       struct cx18_open_id *id = fh;
-       struct cx18 *cx = id->cx;
-
-       return v4l2_prio_change(&cx->prio, &id->prio, prio);
-}
-
 static int cx18_querycap(struct file *file, void *fh,
                                struct v4l2_capability *vcap)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
@@ -496,14 +468,14 @@ static int cx18_querycap(struct file *file, void *fh,
 
 static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        return cx18_get_audio_input(cx, vin->index, vin);
 }
 
 static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        vin->index = cx->audio_input;
        return cx18_get_audio_input(cx, vin->index, vin);
@@ -511,7 +483,7 @@ static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
 
 static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (vout->index >= cx->nof_audio_inputs)
                return -EINVAL;
@@ -522,7 +494,7 @@ static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
 
 static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        /* set it to defaults from our table */
        return cx18_get_input(cx, vin->index, vin);
@@ -531,7 +503,7 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 static int cx18_cropcap(struct file *file, void *fh,
                        struct v4l2_cropcap *cropcap)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -546,13 +518,8 @@ static int cx18_cropcap(struct file *file, void *fh,
 
 static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
-       int ret;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -562,7 +529,7 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
 static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
@@ -590,7 +557,7 @@ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
 
 static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        *i = cx->active_input;
        return 0;
@@ -598,13 +565,8 @@ static int cx18_g_input(struct file *file, void *fh, unsigned int *i)
 
 int cx18_s_input(struct file *file, void *fh, unsigned int inp)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
-       int ret;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
 
        if (inp >= cx->nof_inputs)
                return -EINVAL;
@@ -633,7 +595,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
 static int cx18_g_frequency(struct file *file, void *fh,
                                struct v4l2_frequency *vf)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (vf->tuner != 0)
                return -EINVAL;
@@ -644,13 +606,8 @@ static int cx18_g_frequency(struct file *file, void *fh,
 
 int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
-       int ret;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
 
        if (vf->tuner != 0)
                return -EINVAL;
@@ -664,7 +621,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
 static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        *std = cx->std;
        return 0;
@@ -672,13 +629,8 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
 
 int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
-       int ret;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
 
        if ((*std & V4L2_STD_ALL) == 0)
                return -EINVAL;
@@ -696,9 +648,10 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
 
        cx->std = *std;
        cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
-       cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
-       cx->params.width = 720;
-       cx->params.height = cx->is_50hz ? 576 : 480;
+       cx->is_50hz = !cx->is_60hz;
+       cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
+       cx->cxhdl.width = 720;
+       cx->cxhdl.height = cx->is_50hz ? 576 : 480;
        cx->vbi.count = cx->is_50hz ? 18 : 12;
        cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
        cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
@@ -712,13 +665,8 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
 
 static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
-       int ret;
-
-       ret = v4l2_prio_check(&cx->prio, id->prio);
-       if (ret)
-               return ret;
 
        if (vt->index != 0)
                return -EINVAL;
@@ -729,7 +677,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 
 static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        if (vt->index != 0)
                return -EINVAL;
@@ -750,7 +698,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
                                        struct v4l2_sliced_vbi_cap *cap)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
        int f, l;
 
@@ -871,7 +819,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
 static int cx18_g_enc_index(struct file *file, void *fh,
                                struct v4l2_enc_idx *idx)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
        s32 tmp;
        struct cx18_mdl *mdl;
@@ -918,7 +866,7 @@ static int cx18_g_enc_index(struct file *file, void *fh,
 static int cx18_encoder_cmd(struct file *file, void *fh,
                                struct v4l2_encoder_cmd *enc)
 {
-       struct cx18_open_id *id = fh;
+       struct cx18_open_id *id = fh2id(fh);
        struct cx18 *cx = id->cx;
        u32 h;
 
@@ -979,7 +927,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
 static int cx18_try_encoder_cmd(struct file *file, void *fh,
                                struct v4l2_encoder_cmd *enc)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        switch (enc->cmd) {
        case V4L2_ENC_CMD_START:
@@ -1011,7 +959,7 @@ static int cx18_try_encoder_cmd(struct file *file, void *fh,
 
 static int cx18_log_status(struct file *file, void *fh)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
        struct v4l2_input vidin;
        struct v4l2_audio audin;
        int i;
@@ -1035,7 +983,7 @@ static int cx18_log_status(struct file *file, void *fh)
        mutex_unlock(&cx->gpio_lock);
        CX18_INFO("Tuner: %s\n",
                test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
-       cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
+       v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
        CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
        for (i = 0; i < CX18_MAX_STREAMS; i++) {
                struct cx18_stream *s = &cx->streams[i];
@@ -1056,9 +1004,10 @@ static int cx18_log_status(struct file *file, void *fh)
        return 0;
 }
 
-static long cx18_default(struct file *file, void *fh, int cmd, void *arg)
+static long cx18_default(struct file *file, void *fh, bool valid_prio,
+                                                       int cmd, void *arg)
 {
-       struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
+       struct cx18 *cx = fh2id(fh)->cx;
 
        switch (cmd) {
        case VIDIOC_INT_RESET: {
@@ -1080,14 +1029,12 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
                    unsigned long arg)
 {
        struct video_device *vfd = video_devdata(filp);
-       struct cx18_open_id *id = filp->private_data;
+       struct cx18_open_id *id = file2id(filp);
        struct cx18 *cx = id->cx;
        long res;
 
        mutex_lock(&cx->serialize_lock);
 
-       /* FIXME - consolidate v4l2_prio_check()'s here */
-
        if (cx18_debug & CX18_DBGFLG_IOCTL)
                vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
        res = video_ioctl2(filp, cmd, arg);
@@ -1098,8 +1045,6 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd,
 
 static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_querycap                = cx18_querycap,
-       .vidioc_g_priority              = cx18_g_priority,
-       .vidioc_s_priority              = cx18_s_priority,
        .vidioc_s_audio                 = cx18_s_audio,
        .vidioc_g_audio                 = cx18_g_audio,
        .vidioc_enumaudio               = cx18_enumaudio,
@@ -1136,11 +1081,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
        .vidioc_s_register              = cx18_s_register,
 #endif
        .vidioc_default                 = cx18_default,
-       .vidioc_queryctrl               = cx18_queryctrl,
-       .vidioc_querymenu               = cx18_querymenu,
-       .vidioc_g_ext_ctrls             = cx18_g_ext_ctrls,
-       .vidioc_s_ext_ctrls             = cx18_s_ext_ctrls,
-       .vidioc_try_ext_ctrls           = cx18_try_ext_ctrls,
 };
 
 void cx18_set_funcs(struct video_device *vdev)
index c545f3beef78a551b6b94b9722e2acc06febc007..9605d54bd08390b897ea104a1e98a2a9c837a0f0 100644 (file)
@@ -716,9 +716,8 @@ static int cx18_set_filter_param(struct cx18_stream *s)
 int cx18_api_func(void *priv, u32 cmd, int in, int out,
                u32 data[CX2341X_MBOX_MAX_DATA])
 {
-       struct cx18_api_func_private *api_priv = priv;
-       struct cx18 *cx = api_priv->cx;
-       struct cx18_stream *s = api_priv->s;
+       struct cx18_stream *s = priv;
+       struct cx18 *cx = s->cx;
 
        switch (cmd) {
        case CX2341X_ENC_SET_OUTPUT_PORT:
index 077952fcbcca9bf688a61d356dcd9718f3134477..05fe6bdbe0623fa212131537f6d4e907e95e87d7 100644 (file)
@@ -81,11 +81,6 @@ struct cx18_mailbox {
 
 struct cx18_stream;
 
-struct cx18_api_func_private {
-       struct cx18 *cx;
-       struct cx18_stream *s;
-};
-
 int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
 int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
                int args, ...);
index 94f5d7967c5cef04772a718a25fad7c59443e52e..c6e2ca3b1149ad37305a04dc40befac5b0ef8996 100644 (file)
@@ -207,6 +207,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
        s->video_dev->fops = &cx18_v4l2_enc_fops;
        s->video_dev->release = video_device_release;
        s->video_dev->tvnorms = V4L2_STD_ALL;
+       set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags);
        cx18_set_funcs(s->video_dev);
        return 0;
 }
@@ -572,7 +573,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
                 * Set the MDL size to the exact size needed for one frame.
                 * Use enough buffers per MDL to cover the MDL size
                 */
-               s->mdl_size = 720 * s->cx->params.height * 3 / 2;
+               s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
                s->bufs_per_mdl = s->mdl_size / s->buf_size;
                if (s->mdl_size % s->buf_size)
                        s->bufs_per_mdl++;
@@ -607,7 +608,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        u32 data[MAX_MB_ARGUMENTS];
        struct cx18 *cx = s->cx;
        int captype = 0;
-       struct cx18_api_func_private priv;
        struct cx18_stream *s_idx;
 
        if (!cx18_stream_enabled(s))
@@ -620,7 +620,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                captype = CAPTURE_CHANNEL_TYPE_MPEG;
                cx->mpg_data_received = cx->vbi_data_inserted = 0;
                cx->dualwatch_jiffies = jiffies;
-               cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
+               cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
                cx->search_pack_header = 0;
                break;
 
@@ -710,21 +710,21 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                                 s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
 
                /* Call out to the common CX2341x API setup for user controls */
-               priv.cx = cx;
-               priv.s = s;
-               cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
+               cx->cxhdl.priv = s;
+               cx2341x_handler_setup(&cx->cxhdl);
 
                /*
                 * When starting a capture and we're set for radio,
                 * ensure the video is muted, despite the user control.
                 */
-               if (!cx->params.video_mute &&
+               if (!cx->cxhdl.video_mute &&
                    test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
                        cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
-                                 (cx->params.video_mute_yuv << 8) | 1);
+                         (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
        }
 
        if (atomic_read(&cx->tot_capturing) == 0) {
+               cx2341x_handler_set_busy(&cx->cxhdl, 1);
                clear_bit(CX18_F_I_EOS, &cx->i_flags);
                cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
        }
@@ -826,6 +826,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        if (atomic_read(&cx->tot_capturing) > 0)
                return 0;
 
+       cx2341x_handler_set_busy(&cx->cxhdl, 0);
        cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
        wake_up(&s->waitq);
 
index 7e40035028d20a8eb67dc92ebfa244828df6c5f5..935f557acbd043e31fadf680847b26ddc83717c6 100644 (file)
 /* The are no buffers ready. Try again soon! */
 #define CXERR_NODATA_AGAIN      0x00001E
 
-/* The stream is stopping. Function not alllowed now! */
+/* The stream is stopping. Function not allowed now! */
 #define CXERR_STOPPING_STATUS   0x00001F
 
 /* Trying to access hardware when the power is turned OFF */
index fc9526a5b7469483203b2e776c0cb3f05735f614..f8f0e59cd58389fe6c8fbdd5ee8c8e294e25a9ea 100644 (file)
@@ -942,13 +942,13 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
 
        p_current_fw = vmalloc(1884180 * 4);
        p_fw = p_current_fw;
-       if (p_current_fw == 0) {
+       if (p_current_fw == NULL) {
                dprintk(2, "FAIL!!!\n");
                return -1;
        }
 
        p_buffer = vmalloc(4096);
-       if (p_buffer == 0) {
+       if (p_buffer == NULL) {
                dprintk(2, "FAIL!!!\n");
                return -1;
        }
index c53e97295a0d1d460d5117641e332c1ff109494a..62843d39817cacb5f7368cf927d0566d3f81e3aa 100644 (file)
@@ -759,11 +759,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
        case CX231XX_VMUX_TELEVISION:
        case CX231XX_VMUX_CABLE:
        default:
-               switch (dev->model) {
-               case CX231XX_BOARD_CNXT_CARRAERA:
-               case CX231XX_BOARD_CNXT_RDE_250:
-               case CX231XX_BOARD_CNXT_SHELBY:
-               case CX231XX_BOARD_CNXT_RDU_250:
+               /* TODO: Test if this is also needed for xc2028/xc3028 */
+               if (dev->board.tuner_type == TUNER_XC5000) {
                        /* Disable the use of  DIF   */
 
                        status = vid_blk_read_word(dev, AFE_CTRL, &value);
@@ -820,8 +817,7 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
                                MODE_CTRL, FLD_INPUT_MODE,
                                cx231xx_set_field(FLD_INPUT_MODE,
                                                INPUT_MODE_CVBS_0));
-                       break;
-               default:
+               } else {
                        /* Enable the DIF for the tuner */
 
                        /* Reinitialize the DIF */
@@ -1275,6 +1271,8 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
        int status = 0;
        bool current_is_port_3;
 
+       if (dev->board.dont_use_port_3)
+               is_port_3 = false;
        status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
                                       PWR_CTL_EN, value, 4);
        if (status < 0)
@@ -2550,7 +2548,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
                case 4: /* ts1 */
                        cx231xx_info("%s: set ts1 registers", __func__);
 
-               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+               if (dev->board.has_417) {
                        cx231xx_info(" MPEG\n");
                        value &= 0xFFFFFFFC;
                        value |= 0x3;
index 588f3e8f028b28c04db0c381abfaf62421a9b2ec..f49230d170e6e871a3661f0558af85b88c2e039a 100644 (file)
@@ -261,6 +261,9 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x1c,
                .gpio_pin_status_mask = 0x4001000,
                .norm = V4L2_STD_PAL,
+               .no_alt_vanc = 1,
+               .external_av = 1,
+               .has_417 = 1,
 
                .input = {{
                                .type = CX231XX_VMUX_COMPOSITE1,
@@ -357,19 +360,19 @@ struct cx231xx_board cx231xx_boards[] = {
                        .type = CX231XX_VMUX_TELEVISION,
                        .vmux = CX231XX_VIN_3_1,
                        .amux = CX231XX_AMUX_VIDEO,
-                       .gpio = 0,
+                       .gpio = NULL,
                }, {
                        .type = CX231XX_VMUX_COMPOSITE1,
                        .vmux = CX231XX_VIN_2_1,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                }, {
                        .type = CX231XX_VMUX_SVIDEO,
                        .vmux = CX231XX_VIN_1_1 |
                                (CX231XX_VIN_1_2 << 8) |
                                CX25840_SVIDEO_ON,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                } },
        },
        [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = {
@@ -382,18 +385,20 @@ struct cx231xx_board cx231xx_boards[] = {
                .agc_analog_digital_select_gpio = 0x0c,
                .gpio_pin_status_mask = 0x4001000,
                .norm = V4L2_STD_NTSC,
+               .no_alt_vanc = 1,
+               .external_av = 1,
                .input = {{
                        .type = CX231XX_VMUX_COMPOSITE1,
                        .vmux = CX231XX_VIN_2_1,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                }, {
                        .type = CX231XX_VMUX_SVIDEO,
                        .vmux = CX231XX_VIN_1_1 |
                                (CX231XX_VIN_1_2 << 8) |
                                CX25840_SVIDEO_ON,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                } },
        },
        [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
@@ -420,21 +425,50 @@ struct cx231xx_board cx231xx_boards[] = {
                        .type = CX231XX_VMUX_TELEVISION,
                        .vmux = CX231XX_VIN_3_1,
                        .amux = CX231XX_AMUX_VIDEO,
-                       .gpio = 0,
+                       .gpio = NULL,
                }, {
                        .type = CX231XX_VMUX_COMPOSITE1,
                        .vmux = CX231XX_VIN_2_1,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                }, {
                        .type = CX231XX_VMUX_SVIDEO,
                        .vmux = CX231XX_VIN_1_1 |
                                (CX231XX_VIN_1_2 << 8) |
                                CX25840_SVIDEO_ON,
                        .amux = CX231XX_AMUX_LINE_IN,
-                       .gpio = 0,
+                       .gpio = NULL,
                } },
        },
+       [CX231XX_BOARD_PV_XCAPTURE_USB] = {
+               .name = "Pixelview Xcapture USB",
+               .tuner_type = TUNER_ABSENT,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .demod_xfer_mode = 0,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .norm = V4L2_STD_NTSC,
+               .no_alt_vanc = 1,
+               .external_av = 1,
+               .dont_use_port_3 = 1,
+
+               .input = {{
+                               .type = CX231XX_VMUX_COMPOSITE1,
+                               .vmux = CX231XX_VIN_2_1,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }, {
+                               .type = CX231XX_VMUX_SVIDEO,
+                               .vmux = CX231XX_VIN_1_1 |
+                                       (CX231XX_VIN_1_2 << 8) |
+                                       CX25840_SVIDEO_ON,
+                               .amux = CX231XX_AMUX_LINE_IN,
+                               .gpio = NULL,
+                       }
+               },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -464,6 +498,8 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
        {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001),
         .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
+       {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
+        .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
        {},
 };
 
@@ -772,7 +808,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
        /* Reset other chips required if they are tied up with GPIO pins */
        cx231xx_add_into_devlist(dev);
 
-       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+       if (dev->board.has_417) {
                printk(KERN_INFO "attach 417 %d\n", dev->model);
                if (cx231xx_417_register(dev) < 0) {
                        printk(KERN_ERR
@@ -844,110 +880,110 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        udev = usb_get_dev(interface_to_usbdev(interface));
        ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
-       if (ifnum == 1) {
-               /*
-                * Interface number 0 - IR interface
-                */
-               /* Check to see next free device and mark as used */
-               nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
-               cx231xx_devused |= 1 << nr;
-
-               if (nr >= CX231XX_MAXBOARDS) {
-                       cx231xx_err(DRIVER_NAME
-                ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
-                       cx231xx_devused &= ~(1 << nr);
-                       return -ENOMEM;
-               }
-
-               /* allocate memory for our device state and initialize it */
-               dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-               if (dev == NULL) {
-                       cx231xx_err(DRIVER_NAME ": out of memory!\n");
-                       cx231xx_devused &= ~(1 << nr);
-                       return -ENOMEM;
-               }
-
-               snprintf(dev->name, 29, "cx231xx #%d", nr);
-               dev->devno = nr;
-               dev->model = id->driver_info;
-               dev->video_mode.alt = -1;
-               dev->interface_count++;
-
-               /* reset gpio dir and value */
-               dev->gpio_dir = 0;
-               dev->gpio_val = 0;
-               dev->xc_fw_load_done = 0;
-               dev->has_alsa_audio = 1;
-               dev->power_mode = -1;
-               atomic_set(&dev->devlist_count, 0);
-
-               /* 0 - vbi ; 1 -sliced cc mode */
-               dev->vbi_or_sliced_cc_mode = 0;
-
-               /* get maximum no.of IAD interfaces */
-               assoc_desc = udev->actconfig->intf_assoc[0];
-               dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
-
-               /* init CIR module TBD */
+       /*
+        * Interface number 0 - IR interface (handled by mceusb driver)
+        * Interface number 1 - AV interface (handled by this driver)
+        */
+       if (ifnum != 1)
+               return -ENODEV;
 
-               /* store the current interface */
-               lif = interface;
+       /* Check to see next free device and mark as used */
+       nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
+       cx231xx_devused |= 1 << nr;
 
-               /*mode_tv: digital=1 or analog=0*/
-               dev->mode_tv = 0;
+       if (nr >= CX231XX_MAXBOARDS) {
+               cx231xx_err(DRIVER_NAME
+                ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
+               cx231xx_devused &= ~(1 << nr);
+               return -ENOMEM;
+       }
 
-               dev->USE_ISO = transfer_mode;
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               cx231xx_err(DRIVER_NAME ": out of memory!\n");
+               cx231xx_devused &= ~(1 << nr);
+               return -ENOMEM;
+       }
 
-               switch (udev->speed) {
-               case USB_SPEED_LOW:
-                       speed = "1.5";
-                       break;
-               case USB_SPEED_UNKNOWN:
-               case USB_SPEED_FULL:
-                       speed = "12";
-                       break;
-               case USB_SPEED_HIGH:
-                       speed = "480";
-                       break;
-               default:
-                       speed = "unknown";
-               }
+       snprintf(dev->name, 29, "cx231xx #%d", nr);
+       dev->devno = nr;
+       dev->model = id->driver_info;
+       dev->video_mode.alt = -1;
+
+       dev->interface_count++;
+       /* reset gpio dir and value */
+       dev->gpio_dir = 0;
+       dev->gpio_val = 0;
+       dev->xc_fw_load_done = 0;
+       dev->has_alsa_audio = 1;
+       dev->power_mode = -1;
+       atomic_set(&dev->devlist_count, 0);
+
+       /* 0 - vbi ; 1 -sliced cc mode */
+       dev->vbi_or_sliced_cc_mode = 0;
+
+       /* get maximum no.of IAD interfaces */
+       assoc_desc = udev->actconfig->intf_assoc[0];
+       dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
+
+       /* init CIR module TBD */
+
+       /* store the current interface */
+       lif = interface;
+
+       /*mode_tv: digital=1 or analog=0*/
+       dev->mode_tv = 0;
+
+       dev->USE_ISO = transfer_mode;
+
+       switch (udev->speed) {
+       case USB_SPEED_LOW:
+               speed = "1.5";
+               break;
+       case USB_SPEED_UNKNOWN:
+       case USB_SPEED_FULL:
+               speed = "12";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "480";
+               break;
+       default:
+               speed = "unknown";
+       }
 
-               if (udev->manufacturer)
-                       strlcpy(descr, udev->manufacturer, sizeof(descr));
+       if (udev->manufacturer)
+               strlcpy(descr, udev->manufacturer, sizeof(descr));
 
-               if (udev->product) {
-                       if (*descr)
-                               strlcat(descr, " ", sizeof(descr));
-                       strlcat(descr, udev->product, sizeof(descr));
-               }
+       if (udev->product) {
                if (*descr)
                        strlcat(descr, " ", sizeof(descr));
-
-               cx231xx_info("New device %s@ %s Mbps "
-                    "(%04x:%04x) with %d interfaces\n",
-                    descr,
-                    speed,
-                    le16_to_cpu(udev->descriptor.idVendor),
-                    le16_to_cpu(udev->descriptor.idProduct),
-                    dev->max_iad_interface_count);
-
-               /* store the interface 0 back */
-               lif = udev->actconfig->interface[0];
-
-               /* increment interface count */
-               dev->interface_count++;
-
-               /* get device number */
-               nr = dev->devno;
-
-               assoc_desc = udev->actconfig->intf_assoc[0];
-               if (assoc_desc->bFirstInterface != ifnum) {
-                       cx231xx_err(DRIVER_NAME ": Not found "
-                                   "matching IAD interface\n");
-                       return -ENODEV;
-               }
-       } else {
+               strlcat(descr, udev->product, sizeof(descr));
+       }
+       if (*descr)
+               strlcat(descr, " ", sizeof(descr));
+
+       cx231xx_info("New device %s@ %s Mbps "
+            "(%04x:%04x) with %d interfaces\n",
+            descr,
+            speed,
+            le16_to_cpu(udev->descriptor.idVendor),
+            le16_to_cpu(udev->descriptor.idProduct),
+            dev->max_iad_interface_count);
+
+       /* store the interface 0 back */
+       lif = udev->actconfig->interface[0];
+
+       /* increment interface count */
+       dev->interface_count++;
+
+       /* get device number */
+       nr = dev->devno;
+
+       assoc_desc = udev->actconfig->intf_assoc[0];
+       if (assoc_desc->bFirstInterface != ifnum) {
+               cx231xx_err(DRIVER_NAME ": Not found "
+                           "matching IAD interface\n");
                return -ENODEV;
        }
 
index 7d62d58617f55e8d25877f282dd29311e978de95..abe500feb7dd8adad785380eaa1a86ad4b5d5440 100644 (file)
@@ -571,6 +571,8 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
                                                             alt];
                break;
        case INDEX_VANC:
+               if (dev->board.no_alt_vanc)
+                       return 0;
                usb_interface_index =
                    dev->current_pcb_config.hs_config_info[0].interface_info.
                    vanc_index + 1;
@@ -600,8 +602,7 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
                usb_interface_index, alt);
                /*To workaround error number=-71 on EP0 for videograbber,
                 need add following codes.*/
-               if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
-                   dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+               if (dev->board.no_alt_vanc)
                        return -1;
        }
 
@@ -1301,8 +1302,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
        /* init hardware */
        /* Note : with out calling set power mode function,
        afe can not be set up correctly */
-       if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
-           dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+       if (dev->board.external_av) {
                errCode = cx231xx_set_power_mode(dev,
                                 POLARIS_AVMODE_ENXTERNAL_AV);
                if (errCode < 0) {
@@ -1322,11 +1322,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
                }
        }
 
-       /* reset the Tuner */
-       if ((dev->model == CX231XX_BOARD_CNXT_CARRAERA) ||
-               (dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
-               (dev->model == CX231XX_BOARD_CNXT_SHELBY) ||
-               (dev->model == CX231XX_BOARD_CNXT_RDU_250))
+       /* reset the Tuner, if it is a Xceive tuner */
+       if ((dev->board.tuner_type == TUNER_XC5000) ||
+           (dev->board.tuner_type == TUNER_XC2028))
                        cx231xx_gpio_set(dev, dev->board.tuner_gpio);
 
        /* initialize Colibri block */
index 835670623dfbc4540b28d5d51eee0d6223cc4b9e..925f3a04e53c40daf32e28970a9e7df22397f81c 100644 (file)
@@ -54,6 +54,21 @@ do {                                                 \
       }                                                \
 } while (0)
 
+static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus,
+                       const struct i2c_msg *msg, int tuner_type)
+{
+       if (bus->nr != dev->board.tuner_i2c_master)
+               return false;
+
+       if (msg->addr != dev->board.tuner_addr)
+               return false;
+
+       if (dev->tuner_type != tuner_type)
+               return false;
+
+       return true;
+}
+
 /*
  * cx231xx_i2c_send_bytes()
  */
@@ -71,9 +86,7 @@ int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap,
        u16 saddr = 0;
        u8 need_gpio = 0;
 
-       if ((bus->nr == 1) && (msg->addr == 0x61)
-           && (dev->tuner_type == TUNER_XC5000)) {
-
+       if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
                size = msg->len;
 
                if (size == 2) {        /* register write sub addr */
@@ -180,9 +193,7 @@ static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap,
        u16 saddr = 0;
        u8 need_gpio = 0;
 
-       if ((bus->nr == 1) && (msg->addr == 0x61)
-           && dev->tuner_type == TUNER_XC5000) {
-
+       if (is_tuner(dev, bus, msg, TUNER_XC5000)) {
                if (msg->len == 2)
                        saddr = msg->buf[0] << 8 | msg->buf[1];
                else if (msg->len == 1)
@@ -274,9 +285,7 @@ static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap,
        else if (msg1->len == 1)
                saddr = msg1->buf[0];
 
-       if ((bus->nr == 1) && (msg2->addr == 0x61)
-           && dev->tuner_type == TUNER_XC5000) {
-
+       if (is_tuner(dev, bus, msg2, TUNER_XC5000)) {
                if ((msg2->len < 16)) {
 
                        dprintk1(1,
@@ -454,8 +463,8 @@ static char *i2c_devs[128] = {
        [0x32 >> 1] = "GeminiIII",
        [0x02 >> 1] = "Aquarius",
        [0xa0 >> 1] = "eeprom",
-       [0xc0 >> 1] = "tuner/XC3028",
-       [0xc2 >> 1] = "tuner/XC5000",
+       [0xc0 >> 1] = "tuner",
+       [0xc2 >> 1] = "tuner",
 };
 
 /*
index 7e3e8c4f19b7c980990a7aa7e0c78d110b18b6fd..ffd5af914c448fa0aae422526bbd9c90c4e3a379 100644 (file)
@@ -2190,8 +2190,7 @@ static int cx231xx_v4l2_open(struct file *filp)
                dev->height = norm_maxh(dev);
 
                /* Power up in Analog TV mode */
-               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
-                   dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+               if (dev->board.external_av)
                        cx231xx_set_power_mode(dev,
                                 POLARIS_AVMODE_ENXTERNAL_AV);
                else
@@ -2231,9 +2230,7 @@ static int cx231xx_v4l2_open(struct file *filp)
        if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                /* Set the required alternate setting  VBI interface works in
                   Bulk mode only */
-               if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
-                   dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
-                       cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+               cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
 
                videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
                                            NULL, &dev->vbi_mode.slock,
@@ -2275,7 +2272,7 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
                cx231xx_info("V4L2 device %s deregistered\n",
                             video_device_node_name(dev->vdev));
 
-               if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER)
+               if (dev->board.has_417)
                        cx231xx_417_unregister(dev);
 
                if (video_is_registered(dev->vdev))
@@ -2302,10 +2299,13 @@ static int cx231xx_v4l2_close(struct file *filp)
        if (res_check(fh))
                res_free(fh);
 
-       /*To workaround error number=-71 on EP0 for VideoGrabber,
-                need exclude following.*/
-       if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
-           dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+       /*
+        * To workaround error number=-71 on EP0 for VideoGrabber,
+        *       need exclude following.
+        * FIXME: It is probably safe to remove most of these, as we're
+        * now avoiding the alternate setting for INDEX_VANC
+        */
+       if (!dev->board.no_alt_vanc)
                if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                        videobuf_stop(&fh->vb_vidq);
                        videobuf_mmap_free(&fh->vb_vidq);
index 72bbea2bcd56980b7caa5b1a6e7305c9a86dfaf4..bd4a9cf29577d134dc831ce4330c116f2f0b9d47 100644 (file)
@@ -64,6 +64,7 @@
 #define CX231XX_BOARD_HAUPPAUGE_EXETER  8
 #define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
 #define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
+#define CX231XX_BOARD_PV_XCAPTURE_USB 11
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
@@ -353,7 +354,11 @@ struct cx231xx_board {
 
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
+       unsigned int has_417:1;
        unsigned int valid:1;
+       unsigned int no_alt_vanc:1;
+       unsigned int external_av:1;
+       unsigned int dont_use_port_3:1;
 
        unsigned char xclk, i2c_speed;
 
@@ -464,7 +469,7 @@ struct cx231xx_fh {
 #define I2C_STOP                0x0
 /* 1-- do not transmit STOP at end of transaction */
 #define I2C_NOSTOP              0x1
-/* 1--alllow slave to insert clock wait states */
+/* 1--allow slave to insert clock wait states */
 #define I2C_SYNC                0x1
 
 struct cx231xx_i2c {
index 6b4a516addfea765dd7fe35e817d0c60a1e877f1..3b6e7f28568e41164613d204c71fcea8ea05c19c 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_CX23885
        tristate "Conexant cx23885 (2388x successor) support"
-       depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+       depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
+       select SND_PCM
        select I2C_ALGOBIT
        select VIDEO_BTCX
        select VIDEO_TUNER
@@ -33,3 +34,12 @@ config VIDEO_CX23885
          To compile this driver as a module, choose M here: the
          module will be called cx23885
 
+config MEDIA_ALTERA_CI
+       tristate "Altera FPGA based CI module"
+       depends on VIDEO_CX23885 && DVB_CORE
+       select STAPL_ALTERA
+       ---help---
+         An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card.
+
+         To compile this driver as a module, choose M here: the
+         module will be called altera-ci
index e2ee95f660d8760e21a61be69b3a16ff49d7ff0a..23293c7b6ac7bd722d01ca394ce2196bf17b4e5b 100644 (file)
@@ -5,6 +5,7 @@ cx23885-objs    := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
                    cx23885-f300.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c
new file mode 100644 (file)
index 0000000..678539b
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * altera-ci.c
+ *
+ *  CI driver in conjunction with NetUp Dual DVB-T/C RF CI card
+ *
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * currently cx23885 GPIO's used.
+ * GPIO-0 ~INT in
+ * GPIO-1 TMS out
+ * GPIO-2 ~reset chips out
+ * GPIO-3 to GPIO-10 data/addr for CA in/out
+ * GPIO-11 ~CS out
+ * GPIO-12 AD_RG out
+ * GPIO-13 ~WR out
+ * GPIO-14 ~RD out
+ * GPIO-15 ~RDY in
+ * GPIO-16 TCK out
+ * GPIO-17 TDO in
+ * GPIO-18 TDI out
+ */
+/*
+ *  Bit definitions for MC417_RWD and MC417_OEN registers
+ * bits 31-16
+ * +-----------+
+ * | Reserved  |
+ * +-----------+
+ *   bit 15  bit 14  bit 13 bit 12  bit 11  bit 10  bit 9   bit 8
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |  TDI  |  TDO  |  TCK  |  RDY# |  #RD  |  #WR  | AD_RG |  #CS  |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *  bit 7   bit 6   bit 5   bit 4   bit 3   bit 2   bit 1   bit 0
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#include <linux/version.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+#include "altera-ci.h"
+#include "dvb_ca_en50221.h"
+
+/* FPGA regs */
+#define NETUP_CI_INT_CTRL      0x00
+#define NETUP_CI_BUSCTRL2      0x01
+#define NETUP_CI_ADDR0         0x04
+#define NETUP_CI_ADDR1         0x05
+#define NETUP_CI_DATA          0x06
+#define NETUP_CI_BUSCTRL       0x07
+#define NETUP_CI_PID_ADDR0     0x08
+#define NETUP_CI_PID_ADDR1     0x09
+#define NETUP_CI_PID_DATA      0x0a
+#define NETUP_CI_TSA_DIV       0x0c
+#define NETUP_CI_TSB_DIV       0x0d
+#define NETUP_CI_REVISION      0x0f
+
+/* const for ci op */
+#define NETUP_CI_FLG_CTL       1
+#define NETUP_CI_FLG_RD                1
+#define NETUP_CI_FLG_AD                1
+
+static unsigned int ci_dbg;
+module_param(ci_dbg, int, 0644);
+MODULE_PARM_DESC(ci_dbg, "Enable CI debugging");
+
+static unsigned int pid_dbg;
+module_param(pid_dbg, int, 0644);
+MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging");
+
+MODULE_DESCRIPTION("altera FPGA CI module");
+MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
+MODULE_LICENSE("GPL");
+
+#define ci_dbg_print(args...) \
+       do { \
+               if (ci_dbg) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+#define pid_dbg_print(args...) \
+       do { \
+               if (pid_dbg) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+struct altera_ci_state;
+struct netup_hw_pid_filter;
+
+struct fpga_internal {
+       void *dev;
+       struct mutex fpga_mutex;/* two CI's on the same fpga */
+       struct netup_hw_pid_filter *pid_filt[2];
+       struct altera_ci_state *state[2];
+       struct work_struct work;
+       int (*fpga_rw) (void *dev, int flag, int data, int rw);
+       int cis_used;
+       int filts_used;
+       int strt_wrk;
+};
+
+/* stores all private variables for communication with CI */
+struct altera_ci_state {
+       struct fpga_internal *internal;
+       struct dvb_ca_en50221 ca;
+       int status;
+       int nr;
+};
+
+/* stores all private variables for hardware pid filtering */
+struct netup_hw_pid_filter {
+       struct fpga_internal *internal;
+       struct dvb_demux *demux;
+       /* save old functions */
+       int (*start_feed)(struct dvb_demux_feed *feed);
+       int (*stop_feed)(struct dvb_demux_feed *feed);
+
+       int status;
+       int nr;
+};
+
+/* internal params node */
+struct fpga_inode {
+       /* pointer for internal params, one for each pair of CI's */
+       struct fpga_internal            *internal;
+       struct fpga_inode               *next_inode;
+};
+
+/* first internal params */
+static struct fpga_inode *fpga_first_inode;
+
+/* find chip by dev */
+static struct fpga_inode *find_inode(void *dev)
+{
+       struct fpga_inode *temp_chip = fpga_first_inode;
+
+       if (temp_chip == NULL)
+               return temp_chip;
+
+       /*
+        Search for the last fpga CI chip or
+        find it by dev */
+       while ((temp_chip != NULL) &&
+                               (temp_chip->internal->dev != dev))
+               temp_chip = temp_chip->next_inode;
+
+       return temp_chip;
+}
+/* check demux */
+static struct fpga_internal *check_filter(struct fpga_internal *temp_int,
+                                               void *demux_dev, int filt_nr)
+{
+       if (temp_int == NULL)
+               return NULL;
+
+       if ((temp_int->pid_filt[filt_nr]) == NULL)
+               return NULL;
+
+       if (temp_int->pid_filt[filt_nr]->demux == demux_dev)
+               return temp_int;
+
+       return NULL;
+}
+
+/* find chip by demux */
+static struct fpga_inode *find_dinode(void *demux_dev)
+{
+       struct fpga_inode *temp_chip = fpga_first_inode;
+       struct fpga_internal *temp_int;
+
+       /*
+        * Search of the last fpga CI chip or
+        * find it by demux
+        */
+       while (temp_chip != NULL) {
+               if (temp_chip->internal != NULL) {
+                       temp_int = temp_chip->internal;
+                       if (check_filter(temp_int, demux_dev, 0))
+                               break;
+                       if (check_filter(temp_int, demux_dev, 1))
+                               break;
+               }
+
+               temp_chip = temp_chip->next_inode;
+       }
+
+       return temp_chip;
+}
+
+/* deallocating chip */
+static void remove_inode(struct fpga_internal *internal)
+{
+       struct fpga_inode *prev_node = fpga_first_inode;
+       struct fpga_inode *del_node = find_inode(internal->dev);
+
+       if (del_node != NULL) {
+               if (del_node == fpga_first_inode) {
+                       fpga_first_inode = del_node->next_inode;
+               } else {
+                       while (prev_node->next_inode != del_node)
+                               prev_node = prev_node->next_inode;
+
+                       if (del_node->next_inode == NULL)
+                               prev_node->next_inode = NULL;
+                       else
+                               prev_node->next_inode =
+                                       prev_node->next_inode->next_inode;
+               }
+
+               kfree(del_node);
+       }
+}
+
+/* allocating new chip */
+static struct fpga_inode *append_internal(struct fpga_internal *internal)
+{
+       struct fpga_inode *new_node = fpga_first_inode;
+
+       if (new_node == NULL) {
+               new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
+               fpga_first_inode = new_node;
+       } else {
+               while (new_node->next_inode != NULL)
+                       new_node = new_node->next_inode;
+
+               new_node->next_inode =
+                               kmalloc(sizeof(struct fpga_inode), GFP_KERNEL);
+               if (new_node->next_inode != NULL)
+                       new_node = new_node->next_inode;
+               else
+                       new_node = NULL;
+       }
+
+       if (new_node != NULL) {
+               new_node->internal = internal;
+               new_node->next_inode = NULL;
+       }
+
+       return new_node;
+}
+
+static int netup_fpga_op_rw(struct fpga_internal *inter, int addr,
+                                                       u8 val, u8 read)
+{
+       inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0);
+       return inter->fpga_rw(inter->dev, 0, val, read);
+}
+
+/* flag - mem/io, read - read/write */
+int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot,
+                               u8 flag, u8 read, int addr, u8 val)
+{
+
+       struct altera_ci_state *state = en50221->data;
+       struct fpga_internal *inter = state->internal;
+
+       u8 store;
+       int mem = 0;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       mutex_lock(&inter->fpga_mutex);
+
+       netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0);
+       netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0);
+       store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+
+       store &= 0x0f;
+       store |= ((state->nr << 7) | (flag << 6));
+
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0);
+       mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__,
+                       (read) ? "read" : "write", addr,
+                       (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem",
+                       (read) ? mem : val);
+
+       return mem;
+}
+
+int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr)
+{
+       return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0);
+}
+
+int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
+                                               int slot, int addr, u8 data)
+{
+       return altera_ci_op_cam(en50221, slot, 0, 0, addr, data);
+}
+
+int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+       return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL,
+                                               NETUP_CI_FLG_RD, addr, 0);
+}
+
+int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot,
+                                               u8 addr, u8 data)
+{
+       return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data);
+}
+
+int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct altera_ci_state *state = en50221->data;
+       struct fpga_internal *inter = state->internal;
+       /* reasonable timeout for CI reset is 10 seconds */
+       unsigned long t_out = jiffies + msecs_to_jiffies(9999);
+       int ret;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       mutex_lock(&inter->fpga_mutex);
+
+       ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+                               (ret & 0xcf) | (1 << (5 - state->nr)), 0);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       for (;;) {
+               mdelay(50);
+
+               mutex_lock(&inter->fpga_mutex);
+
+               ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+                                               0, NETUP_CI_FLG_RD);
+               mutex_unlock(&inter->fpga_mutex);
+
+               if ((ret & (1 << (5 - state->nr))) == 0)
+                       break;
+               if (time_after(jiffies, t_out))
+                       break;
+       }
+
+
+       ci_dbg_print("%s: %d msecs\n", __func__,
+               jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out));
+
+       return 0;
+}
+
+int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+       /* not implemented */
+       return 0;
+}
+
+int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot)
+{
+       struct altera_ci_state *state = en50221->data;
+       struct fpga_internal *inter = state->internal;
+       int ret;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (0 != slot)
+               return -EINVAL;
+
+       mutex_lock(&inter->fpga_mutex);
+
+       ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL,
+                               (ret & 0x0f) | (1 << (3 - state->nr)), 0);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       return 0;
+}
+
+/* work handler */
+static void netup_read_ci_status(struct work_struct *work)
+{
+       struct fpga_internal *inter =
+                       container_of(work, struct fpga_internal, work);
+       int ret;
+
+       ci_dbg_print("%s\n", __func__);
+
+       mutex_lock(&inter->fpga_mutex);
+       /* ack' irq */
+       ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD);
+       ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       if (inter->state[1] != NULL) {
+               inter->state[1]->status =
+                               ((ret & 1) == 0 ?
+                               DVB_CA_EN50221_POLL_CAM_PRESENT |
+                               DVB_CA_EN50221_POLL_CAM_READY : 0);
+               ci_dbg_print("%s: setting CI[1] status = 0x%x\n",
+                               __func__, inter->state[1]->status);
+       };
+
+       if (inter->state[0] != NULL) {
+               inter->state[0]->status =
+                               ((ret & 2) == 0 ?
+                               DVB_CA_EN50221_POLL_CAM_PRESENT |
+                               DVB_CA_EN50221_POLL_CAM_READY : 0);
+               ci_dbg_print("%s: setting CI[0] status = 0x%x\n",
+                               __func__, inter->state[0]->status);
+       };
+}
+
+/* CI irq handler */
+int altera_ci_irq(void *dev)
+{
+       struct fpga_inode *temp_int = NULL;
+       struct fpga_internal *inter = NULL;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (dev != NULL) {
+               temp_int = find_inode(dev);
+               if (temp_int != NULL) {
+                       inter = temp_int->internal;
+                       schedule_work(&inter->work);
+               }
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL(altera_ci_irq);
+
+int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot,
+                                                               int open)
+{
+       struct altera_ci_state *state = en50221->data;
+
+       if (0 != slot)
+               return -EINVAL;
+
+       return state->status;
+}
+
+void altera_hw_filt_release(void *main_dev, int filt_nr)
+{
+       struct fpga_inode *temp_int = find_inode(main_dev);
+       struct netup_hw_pid_filter *pid_filt = NULL;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (temp_int != NULL) {
+               pid_filt = temp_int->internal->pid_filt[filt_nr - 1];
+               /* stored old feed controls */
+               pid_filt->demux->start_feed = pid_filt->start_feed;
+               pid_filt->demux->stop_feed = pid_filt->stop_feed;
+
+               if (((--(temp_int->internal->filts_used)) <= 0) &&
+                        ((temp_int->internal->cis_used) <= 0)) {
+
+                       ci_dbg_print("%s: Actually removing\n", __func__);
+
+                       remove_inode(temp_int->internal);
+                       kfree(pid_filt->internal);
+               }
+
+               kfree(pid_filt);
+
+       }
+
+}
+EXPORT_SYMBOL(altera_hw_filt_release);
+
+void altera_ci_release(void *dev, int ci_nr)
+{
+       struct fpga_inode *temp_int = find_inode(dev);
+       struct altera_ci_state *state = NULL;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (temp_int != NULL) {
+               state = temp_int->internal->state[ci_nr - 1];
+               altera_hw_filt_release(dev, ci_nr);
+
+
+               if (((temp_int->internal->filts_used) <= 0) &&
+                               ((--(temp_int->internal->cis_used)) <= 0)) {
+
+                       ci_dbg_print("%s: Actually removing\n", __func__);
+
+                       remove_inode(temp_int->internal);
+                       kfree(state->internal);
+               }
+
+               if (state != NULL) {
+                       if (state->ca.data != NULL)
+                               dvb_ca_en50221_release(&state->ca);
+
+                       kfree(state);
+               }
+       }
+
+}
+EXPORT_SYMBOL(altera_ci_release);
+
+static void altera_pid_control(struct netup_hw_pid_filter *pid_filt,
+               u16 pid, int onoff)
+{
+       struct fpga_internal *inter = pid_filt->internal;
+       u8 store = 0;
+
+       /* pid 0-0x1f always enabled, don't touch them */
+       if ((pid == 0x2000) || (pid < 0x20))
+               return;
+
+       mutex_lock(&inter->fpga_mutex);
+
+       netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0);
+       netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
+                       ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0);
+
+       store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD);
+
+       if (onoff)/* 0 - on, 1 - off */
+               store |= (1 << (pid & 7));
+       else
+               store &= ~(1 << (pid & 7));
+
+       netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__,
+               pid_filt->nr, pid, pid, onoff ? "off" : "on");
+}
+
+static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt,
+                                       int filt_nr, int onoff)
+{
+       struct fpga_internal *inter = pid_filt->internal;
+       u8 store = 0;
+       int i;
+
+       pid_dbg_print("%s: pid_filt->nr[%d]  now %s\n", __func__, pid_filt->nr,
+                       onoff ? "off" : "on");
+
+       if (onoff)/* 0 - on, 1 - off */
+               store = 0xff;/* ignore pid */
+       else
+               store = 0;/* enable pid */
+
+       mutex_lock(&inter->fpga_mutex);
+
+       for (i = 0; i < 1024; i++) {
+               netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0);
+
+               netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1,
+                               ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0);
+               /* pid 0-0x1f always enabled */
+               netup_fpga_op_rw(inter, NETUP_CI_PID_DATA,
+                               (i > 3 ? store : 0), 0);
+       }
+
+       mutex_unlock(&inter->fpga_mutex);
+}
+
+int altera_pid_feed_control(void *demux_dev, int filt_nr,
+               struct dvb_demux_feed *feed, int onoff)
+{
+       struct fpga_inode *temp_int = find_dinode(demux_dev);
+       struct fpga_internal *inter = temp_int->internal;
+       struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1];
+
+       altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1);
+       /* call old feed proc's */
+       if (onoff)
+               pid_filt->start_feed(feed);
+       else
+               pid_filt->stop_feed(feed);
+
+       if (feed->pid == 0x2000)
+               altera_toggle_fullts_streaming(pid_filt, filt_nr,
+                                               onoff ? 0 : 1);
+
+       return 0;
+}
+EXPORT_SYMBOL(altera_pid_feed_control);
+
+int altera_ci_start_feed(struct dvb_demux_feed *feed, int num)
+{
+       altera_pid_feed_control(feed->demux, num, feed, 1);
+
+       return 0;
+}
+
+int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num)
+{
+       altera_pid_feed_control(feed->demux, num, feed, 0);
+
+       return 0;
+}
+
+int altera_ci_start_feed_1(struct dvb_demux_feed *feed)
+{
+       return altera_ci_start_feed(feed, 1);
+}
+
+int altera_ci_stop_feed_1(struct dvb_demux_feed *feed)
+{
+       return altera_ci_stop_feed(feed, 1);
+}
+
+int altera_ci_start_feed_2(struct dvb_demux_feed *feed)
+{
+       return altera_ci_start_feed(feed, 2);
+}
+
+int altera_ci_stop_feed_2(struct dvb_demux_feed *feed)
+{
+       return altera_ci_stop_feed(feed, 2);
+}
+
+int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr)
+{
+       struct netup_hw_pid_filter *pid_filt = NULL;
+       struct fpga_inode *temp_int = find_inode(config->dev);
+       struct fpga_internal *inter = NULL;
+       int ret = 0;
+
+       pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL);
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (!pid_filt) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (temp_int != NULL) {
+               inter = temp_int->internal;
+               (inter->filts_used)++;
+               ci_dbg_print("%s: Find Internal Structure!\n", __func__);
+       } else {
+               inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
+               if (!inter) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               temp_int = append_internal(inter);
+               inter->filts_used = 1;
+               inter->dev = config->dev;
+               inter->fpga_rw = config->fpga_rw;
+               mutex_init(&inter->fpga_mutex);
+               inter->strt_wrk = 1;
+               ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
+       }
+
+       ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__,
+                                               pid_filt, hw_filt_nr - 1);
+       inter->pid_filt[hw_filt_nr - 1] = pid_filt;
+       pid_filt->demux = config->demux;
+       pid_filt->internal = inter;
+       pid_filt->nr = hw_filt_nr - 1;
+       /* store old feed controls */
+       pid_filt->start_feed = config->demux->start_feed;
+       pid_filt->stop_feed = config->demux->stop_feed;
+       /* replace with new feed controls */
+       if (hw_filt_nr == 1) {
+               pid_filt->demux->start_feed = altera_ci_start_feed_1;
+               pid_filt->demux->stop_feed = altera_ci_stop_feed_1;
+       } else if (hw_filt_nr == 2) {
+               pid_filt->demux->start_feed = altera_ci_start_feed_2;
+               pid_filt->demux->stop_feed = altera_ci_stop_feed_2;
+       }
+
+       altera_toggle_fullts_streaming(pid_filt, 0, 1);
+
+       return 0;
+err:
+       ci_dbg_print("%s: Can't init hardware filter: Error %d\n",
+                    __func__, ret);
+
+       kfree(pid_filt);
+
+       return ret;
+}
+EXPORT_SYMBOL(altera_hw_filt_init);
+
+int altera_ci_init(struct altera_ci_config *config, int ci_nr)
+{
+       struct altera_ci_state *state;
+       struct fpga_inode *temp_int = find_inode(config->dev);
+       struct fpga_internal *inter = NULL;
+       int ret = 0;
+       u8 store = 0;
+
+       state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL);
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (!state) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (temp_int != NULL) {
+               inter = temp_int->internal;
+               (inter->cis_used)++;
+               ci_dbg_print("%s: Find Internal Structure!\n", __func__);
+       } else {
+               inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL);
+               if (!inter) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               temp_int = append_internal(inter);
+               inter->cis_used = 1;
+               inter->dev = config->dev;
+               inter->fpga_rw = config->fpga_rw;
+               mutex_init(&inter->fpga_mutex);
+               inter->strt_wrk = 1;
+               ci_dbg_print("%s: Create New Internal Structure!\n", __func__);
+       }
+
+       ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__,
+                                               state, ci_nr - 1);
+       inter->state[ci_nr - 1] = state;
+       state->internal = inter;
+       state->nr = ci_nr - 1;
+
+       state->ca.owner = THIS_MODULE;
+       state->ca.read_attribute_mem = altera_ci_read_attribute_mem;
+       state->ca.write_attribute_mem = altera_ci_write_attribute_mem;
+       state->ca.read_cam_control = altera_ci_read_cam_ctl;
+       state->ca.write_cam_control = altera_ci_write_cam_ctl;
+       state->ca.slot_reset = altera_ci_slot_reset;
+       state->ca.slot_shutdown = altera_ci_slot_shutdown;
+       state->ca.slot_ts_enable = altera_ci_slot_ts_ctl;
+       state->ca.poll_slot_status = altera_poll_ci_slot_status;
+       state->ca.data = state;
+
+       ret = dvb_ca_en50221_init(config->adapter,
+                                  &state->ca,
+                                  /* flags */ 0,
+                                  /* n_slots */ 1);
+       if (0 != ret)
+               goto err;
+
+       altera_hw_filt_init(config, ci_nr);
+
+       if (inter->strt_wrk) {
+               INIT_WORK(&inter->work, netup_read_ci_status);
+               inter->strt_wrk = 0;
+       }
+
+       ci_dbg_print("%s: CI initialized!\n", __func__);
+
+       mutex_lock(&inter->fpga_mutex);
+
+       /* Enable div */
+       netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0);
+       netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0);
+
+       /* enable TS out */
+       store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
+       store |= (3 << 4);
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+
+       ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD);
+       /* enable irq */
+       netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret);
+
+       schedule_work(&inter->work);
+
+       return 0;
+err:
+       ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret);
+
+       kfree(state);
+
+       return ret;
+}
+EXPORT_SYMBOL(altera_ci_init);
+
+int altera_ci_tuner_reset(void *dev, int ci_nr)
+{
+       struct fpga_inode *temp_int = find_inode(dev);
+       struct fpga_internal *inter = NULL;
+       u8 store;
+
+       ci_dbg_print("%s\n", __func__);
+
+       if (temp_int == NULL)
+               return -1;
+
+       if (temp_int->internal == NULL)
+               return -1;
+
+       inter = temp_int->internal;
+
+       mutex_lock(&inter->fpga_mutex);
+
+       store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD);
+       store &= ~(4 << (2 - ci_nr));
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+       msleep(100);
+       store |= (4 << (2 - ci_nr));
+       netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0);
+
+       mutex_unlock(&inter->fpga_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(altera_ci_tuner_reset);
diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/video/cx23885/altera-ci.h
new file mode 100644 (file)
index 0000000..70e4fd6
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * altera-ci.c
+ *
+ *  CI driver in conjunction with NetUp Dual DVB-T/C RF CI card
+ *
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __ALTERA_CI_H
+#define __ALTERA_CI_H
+
+#define ALT_DATA       0x000000ff
+#define ALT_TDI                0x00008000
+#define ALT_TDO                0x00004000
+#define ALT_TCK                0x00002000
+#define ALT_RDY                0x00001000
+#define ALT_RD         0x00000800
+#define ALT_WR         0x00000400
+#define ALT_AD_RG      0x00000200
+#define ALT_CS         0x00000100
+
+struct altera_ci_config {
+       void *dev;/* main dev, for example cx23885_dev */
+       void *adapter;/* for CI to connect to */
+       struct dvb_demux *demux;/* for hardware PID filter to connect to */
+       int (*fpga_rw) (void *dev, int ad_rg, int val, int rw);
+};
+
+#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \
+                                                       && defined(MODULE))
+
+extern int altera_ci_init(struct altera_ci_config *config, int ci_nr);
+extern void altera_ci_release(void *dev, int ci_nr);
+extern int altera_ci_irq(void *dev);
+extern int altera_ci_tuner_reset(void *dev, int ci_nr);
+
+#else
+
+static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+static inline void altera_ci_release(void *dev, int ci_nr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int altera_ci_irq(void *dev)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+static inline int altera_ci_tuner_reset(void *dev, int ci_nr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+#endif
+#if 0
+static inline int altera_hw_filt_init(struct altera_ci_config *config,
+                                                       int hw_filt_nr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+static inline void altera_hw_filt_release(void *dev, int filt_nr)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+}
+
+static inline int altera_pid_feed_control(void *dev, int filt_nr,
+               struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+
+#endif /* CONFIG_MEDIA_ALTERA_CI */
+
+#endif /* __ALTERA_CI_H */
index b298b730943c550498b7ec79055955a0a8fa5e33..ea88722cb4ab3250ce7719961610e3857057e41e 100644 (file)
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <media/cx25840.h>
+#include <linux/firmware.h>
+#include <staging/altera.h>
 
 #include "cx23885.h"
 #include "tuner-xc2028.h"
 #include "netup-init.h"
+#include "altera-ci.h"
+#include "xc5000.h"
 #include "cx23888-ir.h"
 
 static unsigned int enable_885_ir;
@@ -90,6 +94,7 @@ struct cx23885_board cx23885_boards[] = {
                .portc          = CX23885_MPEG_DVB,
                .tuner_type     = TUNER_PHILIPS_TDA8290,
                .tuner_addr     = 0x42, /* 0x84 >> 1 */
+               .tuner_bus      = 1,
                .input          = {{
                        .type   = CX23885_VMUX_TELEVISION,
                        .vmux   =       CX25840_VIN7_CH3 |
@@ -187,7 +192,7 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
        },
        [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = {
-               .cimax          = 1,
+               .ci_type        = 1,
                .name           = "NetUP Dual DVB-S2 CI",
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
@@ -212,6 +217,7 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Mygica X8506 DMB-TH",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
+               .tuner_bus      = 1,
                .porta          = CX23885_ANALOG_VIDEO,
                .portb          = CX23885_MPEG_DVB,
                .input          = {
@@ -241,6 +247,7 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Magic-Pro ProHDTV Extreme 2",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
+               .tuner_bus      = 1,
                .porta          = CX23885_ANALOG_VIDEO,
                .portb          = CX23885_MPEG_DVB,
                .input          = {
@@ -289,6 +296,7 @@ struct cx23885_board cx23885_boards[] = {
                .porta          = CX23885_ANALOG_VIDEO,
                .tuner_type     = TUNER_XC2028,
                .tuner_addr     = 0x61,
+               .tuner_bus      = 1,
                .input          = {{
                        .type   = CX23885_VMUX_TELEVISION,
                        .vmux   = CX25840_VIN2_CH1 |
@@ -313,6 +321,7 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "GoTView X5 3D Hybrid",
                .tuner_type     = TUNER_XC5000,
                .tuner_addr     = 0x64,
+               .tuner_bus      = 1,
                .porta          = CX23885_ANALOG_VIDEO,
                .portb          = CX23885_MPEG_DVB,
                .input          = {{
@@ -329,6 +338,21 @@ struct cx23885_board cx23885_boards[] = {
                                  CX25840_SVIDEO_CHROMA4,
                } },
        },
+       [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = {
+               .ci_type        = 2,
+               .name           = "NetUP Dual DVB-T/C-CI RF",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .portb          = CX23885_MPEG_DVB,
+               .portc          = CX23885_MPEG_DVB,
+               .num_fds_portb  = 2,
+               .num_fds_portc  = 2,
+               .tuner_type     = TUNER_XC5000,
+               .tuner_addr     = 0x64,
+               .input          = { {
+                               .type   = CX23885_VMUX_TELEVISION,
+                               .vmux   = CX25840_COMPOSITE1,
+               } },
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -520,6 +544,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x5654,
                .subdevice = 0x2390,
                .card      = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
+       }, {
+               .subvendor = 0x1b55,
+               .subdevice = 0xe2e4,
+               .card      = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -740,6 +768,9 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
                /* Tuner Reset Command */
                bitmask = 0x02;
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+               altera_ci_tuner_reset(dev, port->nr);
+               break;
        }
 
        if (bitmask) {
@@ -998,6 +1029,33 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
                cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+               /* GPIO-0 ~INT in
+                  GPIO-1 TMS out
+                  GPIO-2 ~reset chips out
+                  GPIO-3 to GPIO-10 data/addr for CA in/out
+                  GPIO-11 ~CS out
+                  GPIO-12 ADDR out
+                  GPIO-13 ~WR out
+                  GPIO-14 ~RD out
+                  GPIO-15 ~RDY in
+                  GPIO-16 TCK out
+                  GPIO-17 TDO in
+                  GPIO-18 TDI out
+                */
+               cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */
+               /* GPIO-0 as INT, reset & TMS low */
+               cx_clear(GP0_IO, 0x00010006);
+               mdelay(100);/* reset delay */
+               cx_set(GP0_IO, 0x00000004); /* reset high */
+               cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */
+               /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */
+               cx_write(MC417_OEN, 0x00005000);
+               /* ~RD, ~WR high; ADDR low; ~CS high */
+               cx_write(MC417_RWD, 0x00000d00);
+               /* enable irq */
+               cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
+               break;
        }
 }
 
@@ -1113,6 +1171,31 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
        }
 }
 
+int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
+{
+       int data;
+       int tdo = 0;
+       struct cx23885_dev *dev = (struct cx23885_dev *)device;
+       /*TMS*/
+       data = ((cx_read(GP0_IO)) & (~0x00000002));
+       data |= (tms ? 0x00020002 : 0x00020000);
+       cx_write(GP0_IO, data);
+
+       /*TDI*/
+       data = ((cx_read(MC417_RWD)) & (~0x0000a000));
+       data |= (tdi ? 0x00008000 : 0);
+       cx_write(MC417_RWD, data);
+       if (read_tdo)
+               tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/
+
+       cx_write(MC417_RWD, data | 0x00002000);
+       udelay(1);
+       /*TCK*/
+       cx_write(MC417_RWD, data);
+
+       return tdo;
+}
+
 void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
 {
        switch (dev->board) {
@@ -1212,6 +1295,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
                ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1271,6 +1355,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_MYGICA_X8506:
@@ -1293,6 +1378,29 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
                netup_initialize(dev);
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+               int ret;
+               const struct firmware *fw;
+               const char *filename = "dvb-netup-altera-01.fw";
+               char *action = "configure";
+               struct altera_config netup_config = {
+                       .dev = dev,
+                       .action = action,
+                       .jtag_io = netup_jtag_io,
+               };
+
+               netup_initialize(dev);
+
+               ret = request_firmware(&fw, filename, &dev->pci->dev);
+               if (ret != 0)
+                       printk(KERN_ERR "did not find the firmware file. (%s) "
+                       "Please see linux/Documentation/dvb/ for more details "
+                       "on firmware-problems.", filename);
+               else
+                       altera_init(&netup_config, fw);
+
+               break;
+       }
        }
 }
 
index 359882419b7f588b7c698dbcfb6a39ddb1603301..9933810b4e33a34499261f65e9fc6df883862640 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <asm/div64.h>
+#include <linux/firmware.h>
 
 #include "cx23885.h"
 #include "cimax2.h"
+#include "altera-ci.h"
 #include "cx23888-ir.h"
 #include "cx23885-ir.h"
 #include "cx23885-av.h"
@@ -902,8 +904,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        dev->pci_bus  = dev->pci->bus->number;
        dev->pci_slot = PCI_SLOT(dev->pci->devfn);
        cx23885_irq_add(dev, 0x001f00);
-       if (cx23885_boards[dev->board].cimax > 0)
-               cx23885_irq_add(dev, 0x01800000); /* for CiMaxes */
 
        /* External Master 1 Bus */
        dev->i2c_bus[0].nr = 0;
@@ -970,11 +970,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        /* Assume some sensible defaults */
        dev->tuner_type = cx23885_boards[dev->board].tuner_type;
        dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
+       dev->tuner_bus = cx23885_boards[dev->board].tuner_bus;
        dev->radio_type = cx23885_boards[dev->board].radio_type;
        dev->radio_addr = cx23885_boards[dev->board].radio_addr;
 
-       dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
-               __func__, dev->tuner_type, dev->tuner_addr);
+       dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n",
+               __func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus);
        dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
                __func__, dev->radio_type, dev->radio_addr);
 
@@ -1004,6 +1005,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        }
 
        if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+               if (cx23885_boards[dev->board].num_fds_portb)
+                       dev->ts1.num_frontends =
+                               cx23885_boards[dev->board].num_fds_portb;
                if (cx23885_dvb_register(&dev->ts1) < 0) {
                        printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
                               __func__);
@@ -1018,6 +1022,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        }
 
        if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+               if (cx23885_boards[dev->board].num_fds_portc)
+                       dev->ts2.num_frontends =
+                               cx23885_boards[dev->board].num_fds_portc;
                if (cx23885_dvb_register(&dev->ts2) < 0) {
                        printk(KERN_ERR
                                "%s() Failed to register dvb on VID_C\n",
@@ -1034,6 +1041,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 
        cx23885_dev_checkrevision(dev);
 
+       /* disable MSI for NetUP cards, otherwise CI is not working */
+       if (cx23885_boards[dev->board].ci_type > 0)
+               cx_clear(RDR_RDRCTL1, 1 << 8);
+
        return 0;
 }
 
@@ -1822,14 +1833,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
                                PCI_MSK_IR);
        }
 
-       if (cx23885_boards[dev->board].cimax > 0 &&
-               ((pci_status & PCI_MSK_GPIO0) ||
-                       (pci_status & PCI_MSK_GPIO1))) {
-
-               if (cx23885_boards[dev->board].cimax > 0)
-                       handled += netup_ci_slot_status(dev, pci_status);
+       if (cx23885_boards[dev->board].ci_type == 1 &&
+                       (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0)))
+               handled += netup_ci_slot_status(dev, pci_status);
 
-       }
+       if (cx23885_boards[dev->board].ci_type == 2 &&
+                       (pci_status & PCI_MSK_GPIO0))
+               handled += altera_ci_irq(dev);
 
        if (ts1_status) {
                if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
@@ -2064,7 +2074,10 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
 
        switch (dev->board) {
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
-               cx23885_irq_add_enable(dev, 0x01800000); /* for NetUP */
+               cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0);
+               break;
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+               cx23885_irq_add_enable(dev, PCI_MSK_GPIO0);
                break;
        }
 
index 5958cb882e939db4908aa44cdefef8d8cb3948fc..3c315f94cc8512c33f6a43a264722411fcf43a93 100644 (file)
@@ -58,6 +58,8 @@
 #include "atbm8830.h"
 #include "ds3000.h"
 #include "cx23885-f300.h"
+#include "altera-ci.h"
+#include "stv0367.h"
 
 static unsigned int debug;
 
@@ -108,6 +110,22 @@ static void dvb_buf_release(struct videobuf_queue *q,
        cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
 }
 
+static void cx23885_dvb_gate_ctrl(struct cx23885_tsport  *port, int open)
+{
+       struct videobuf_dvb_frontends *f;
+       struct videobuf_dvb_frontend *fe;
+
+       f = &port->frontends;
+
+       if (f->gate <= 1) /* undefined or fe0 */
+               fe = videobuf_dvb_get_frontend(f, 1);
+       else
+               fe = videobuf_dvb_get_frontend(f, f->gate);
+
+       if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+               fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+}
+
 static struct videobuf_queue_ops dvb_qops = {
        .buf_setup    = dvb_buf_setup,
        .buf_prepare  = dvb_buf_prepare,
@@ -570,12 +588,84 @@ static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
        .i2c_address = 0x60,
        .osc_clk = 20
 };
+static struct stv0367_config netup_stv0367_config[] = {
+       {
+               .demod_address = 0x1c,
+               .xtal = 27000000,
+               .if_khz = 4500,
+               .if_iq_mode = 0,
+               .ts_mode = 1,
+               .clk_pol = 0,
+       }, {
+               .demod_address = 0x1d,
+               .xtal = 27000000,
+               .if_khz = 4500,
+               .if_iq_mode = 0,
+               .ts_mode = 1,
+               .clk_pol = 0,
+       },
+};
+
+static struct xc5000_config netup_xc5000_config[] = {
+       {
+               .i2c_address = 0x61,
+               .if_khz = 4500,
+       }, {
+               .i2c_address = 0x64,
+               .if_khz = 4500,
+       },
+};
+
+int netup_altera_fpga_rw(void *device, int flag, int data, int read)
+{
+       struct cx23885_dev *dev = (struct cx23885_dev *)device;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1);
+       uint32_t mem = 0;
+
+       mem = cx_read(MC417_RWD);
+       if (read)
+               cx_set(MC417_OEN, ALT_DATA);
+       else {
+               cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */
+               mem &= ~ALT_DATA;
+               mem |= (data & ALT_DATA);
+       }
+
+       if (flag)
+               mem |= ALT_AD_RG;
+       else
+               mem &= ~ALT_AD_RG;
+
+       mem &= ~ALT_CS;
+       if (read)
+               mem = (mem & ~ALT_RD) | ALT_WR;
+       else
+               mem = (mem & ~ALT_WR) | ALT_RD;
+
+       cx_write(MC417_RWD, mem);  /* start RW cycle */
+
+       for (;;) {
+               mem = cx_read(MC417_RWD);
+               if ((mem & ALT_RDY) == 0)
+                       break;
+               if (time_after(jiffies, timeout))
+                       break;
+               udelay(1);
+       }
+
+       cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS);
+       if (read)
+               return mem & ALT_DATA;
+
+       return 0;
+};
 
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
        struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
-       struct videobuf_dvb_frontend *fe0;
+       struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+       int mfe_shared = 0; /* bus not shared by default */
        int ret;
 
        /* Get the first frontend */
@@ -586,6 +676,12 @@ static int dvb_register(struct cx23885_tsport *port)
        /* init struct videobuf_dvb */
        fe0->dvb.name = dev->name;
 
+       /* multi-frontend gate control is undefined or defaults to fe0 */
+       port->frontends.gate = 0;
+
+       /* Sets the gate control callback to be used by i2c command calls */
+       port->gate_ctrl = cx23885_dvb_gate_ctrl;
+
        /* init frontend */
        switch (dev->board) {
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
@@ -966,20 +1062,64 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
-
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+               i2c_bus = &dev->i2c_bus[0];
+               mfe_shared = 1;/* MFE */
+               port->frontends.gate = 0;/* not clear for me yet */
+               /* ports B, C */
+               /* MFE frontend 1 DVB-T */
+               fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
+                                       &netup_stv0367_config[port->nr - 1],
+                                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       if (NULL == dvb_attach(xc5000_attach,
+                                       fe0->dvb.frontend,
+                                       &i2c_bus->i2c_adap,
+                                       &netup_xc5000_config[port->nr - 1]))
+                               goto frontend_detach;
+                       /* load xc5000 firmware */
+                       fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
+               }
+               /* MFE frontend 2 */
+               fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+               if (fe1 == NULL)
+                       goto frontend_detach;
+               /* DVB-C init */
+               fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
+                                       &netup_stv0367_config[port->nr - 1],
+                                       &i2c_bus->i2c_adap);
+               if (fe1->dvb.frontend != NULL) {
+                       fe1->dvb.frontend->id = 1;
+                       if (NULL == dvb_attach(xc5000_attach,
+                                       fe1->dvb.frontend,
+                                       &i2c_bus->i2c_adap,
+                                       &netup_xc5000_config[port->nr - 1]))
+                               goto frontend_detach;
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
                       dev->name);
                break;
        }
-       if (NULL == fe0->dvb.frontend) {
+
+       if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
                printk(KERN_ERR "%s: frontend initialization failed\n",
-                       dev->name);
-               return -1;
+                      dev->name);
+               goto frontend_detach;
        }
+
        /* define general-purpose callback pointer */
        fe0->dvb.frontend->callback = cx23885_tuner_callback;
+       if (fe1)
+               fe1->dvb.frontend->callback = cx23885_tuner_callback;
+#if 0
+       /* Ensure all frontends negotiate bus access */
+       fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+       if (fe1)
+               fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl;
+#endif
 
        /* Put the analog decoder in standby to keep it quiet */
        call_all(dev, core, s_power, 0);
@@ -989,10 +1129,10 @@ static int dvb_register(struct cx23885_tsport *port)
 
        /* register everything */
        ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
-                                       &dev->pci->dev, adapter_nr, 0,
+                                       &dev->pci->dev, adapter_nr, mfe_shared,
                                        cx23885_dvb_fe_ioctl_override);
        if (ret)
-               return ret;
+               goto frontend_detach;
 
        /* init CI & MAC */
        switch (dev->board) {
@@ -1008,6 +1148,17 @@ static int dvb_register(struct cx23885_tsport *port)
                netup_ci_init(port);
                break;
                }
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+               struct altera_ci_config netup_ci_cfg = {
+                       .dev = dev,/* magic number to identify*/
+                       .adapter = &port->frontends.adapter,/* for CI */
+                       .demux = &fe0->dvb.demux,/* for hw pid filter */
+                       .fpga_rw = netup_altera_fpga_rw,
+               };
+
+               altera_ci_init(&netup_ci_cfg, port->nr);
+               break;
+               }
        case CX23885_BOARD_TEVII_S470: {
                u8 eeprom[256]; /* 24C02 i2c eeprom */
 
@@ -1024,6 +1175,11 @@ static int dvb_register(struct cx23885_tsport *port)
        }
 
        return ret;
+
+frontend_detach:
+       port->gate_ctrl = NULL;
+       videobuf_dvb_dealloc_frontends(&port->frontends);
+       return -EINVAL;
 }
 
 int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -1100,8 +1256,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
                netup_ci_exit(port);
                break;
+       case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
+               altera_ci_release(port->dev, port->nr);
+               break;
        }
 
+       port->gate_ctrl = NULL;
+
        return 0;
 }
 
index 199b9964bbe5ab27776b9dd2f9d2d59dd96c9a2b..e97cafd839846ed89d63e5ea0391af97ae990320 100644 (file)
@@ -264,7 +264,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
                driver_type = RC_DRIVER_IR_RAW;
                allowed_protos = RC_TYPE_ALL;
                /* The grey Hauppauge RC-5 remote */
-               rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
+               rc_map = RC_MAP_HAUPPAUGE;
                break;
        case CX23885_BOARD_TEVII_S470:
                /* Integrated CX23885 IR controller */
index a28772db11f0e0da220f85142febbf0d0b235ddb..c87ac682ebbef37d251c3b65967963b5371c4d31 100644 (file)
@@ -292,6 +292,7 @@ Channel manager Data Structure entry = 20 DWORD
 #define RDR_CFG0       0x00050000
 #define RDR_CFG1       0x00050004
 #define RDR_CFG2       0x00050008
+#define RDR_RDRCTL1    0x0005030c
 #define RDR_TLCTL0     0x00050318
 
 /* APB DMAC Current Buffer Pointer */
index 644fcb808c0bbbc3ace52ba1d4ee523a02bd2575..ee57f6bedbe3dd186d4f3255d55a0e82d8f4d151 100644 (file)
@@ -1468,16 +1468,17 @@ int cx23885_video_register(struct cx23885_dev *dev)
 
        cx23885_irq_add_enable(dev, 0x01);
 
-       if (TUNER_ABSENT != dev->tuner_type) {
+       if ((TUNER_ABSENT != dev->tuner_type) &&
+                       ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) {
                struct v4l2_subdev *sd = NULL;
 
                if (dev->tuner_addr)
                        sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_bus[1].i2c_adap,
+                               &dev->i2c_bus[dev->tuner_bus].i2c_adap,
                                "tuner", dev->tuner_addr, NULL);
                else
                        sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_bus[1].i2c_adap,
+                               &dev->i2c_bus[dev->tuner_bus].i2c_adap,
                                "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
                if (sd) {
                        struct tuner_setup tun_setup;
index 62e41ab65810155c8a5373cbb914e02edfca7cf8..8db2797bc7c34892cd4bdd01b9ef966260d62e58 100644 (file)
@@ -85,6 +85,7 @@
 #define CX23885_BOARD_MYGICA_X8558PRO          27
 #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID     29
+#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
@@ -204,10 +205,12 @@ typedef enum {
 struct cx23885_board {
        char                    *name;
        port_t                  porta, portb, portc;
+       int             num_fds_portb, num_fds_portc;
        unsigned int            tuner_type;
        unsigned int            radio_type;
        unsigned char           tuner_addr;
        unsigned char           radio_addr;
+       unsigned int            tuner_bus;
 
        /* Vendors can and do run the PCIe bridge at different
         * clock rates, driven physically by crystals on the PCBs.
@@ -220,7 +223,7 @@ struct cx23885_board {
         */
        u32                     clk_freq;
        struct cx23885_input    input[MAX_CX23885_INPUT];
-       int                     cimax; /* for NetUP */
+       int                     ci_type; /* for NetUP */
 };
 
 struct cx23885_subid {
@@ -303,6 +306,7 @@ struct cx23885_tsport {
 
        /* Allow a single tsport to have multiple frontends */
        u32                        num_frontends;
+       void                (*gate_ctrl)(struct cx23885_tsport *port, int open);
        void                       *port_priv;
 };
 
@@ -362,6 +366,7 @@ struct cx23885_dev {
        v4l2_std_id                tvnorm;
        unsigned int               tuner_type;
        unsigned char              tuner_addr;
+       unsigned int               tuner_bus;
        unsigned int               radio_type;
        unsigned char              radio_addr;
        unsigned int               has_radio;
index 54b7fcd469a8a9b2db267e81ac163d0e579ce31b..423c1af8a782473d21d6bb6eccfe97d3be9effb0 100644 (file)
@@ -40,6 +40,7 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
+#include <media/wm8775.h>
 
 #include "cx88.h"
 #include "cx88-reg.h"
@@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       struct v4l2_control client_ctl;
+       int left = value->value.integer.value[0];
+       int right = value->value.integer.value[1];
+       int v, b;
+
+       memset(&client_ctl, 0, sizeof(client_ctl));
+
+       /* Pass volume & balance onto any WM8775 */
+       if (left >= right) {
+               v = left << 10;
+               b = left ? (0x8000 * right) / left : 0x8000;
+       } else {
+               v = right << 10;
+               b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
+       }
+       client_ctl.value = v;
+       client_ctl.id = V4L2_CID_AUDIO_VOLUME;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+       client_ctl.value = b;
+       client_ctl.id = V4L2_CID_AUDIO_BALANCE;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+}
+
 /* OK - TODO: test it */
 static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *value)
@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
        int changed = 0;
        u32 old;
 
+       if (core->board.audio_chip == V4L2_IDENT_WM8775)
+               snd_cx88_wm8775_volume_put(kcontrol, value);
+
        left = value->value.integer.value[0] & 0x3f;
        right = value->value.integer.value[1] & 0x3f;
        b = right - left;
        if (b < 0) {
-           v = 0x3f - left;
-           b = (-b) | 0x40;
+               v = 0x3f - left;
+               b = (-b) | 0x40;
        } else {
-           v = 0x3f - right;
+               v = 0x3f - right;
        }
        /* Do we really know this will always be called with IRQs on? */
        spin_lock_irq(&chip->reg_lock);
        old = cx_read(AUD_VOL_CTL);
        if (v != (old & 0x3f)) {
-           cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
-           changed = 1;
+               cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
+               changed = 1;
        }
-       if (cx_read(AUD_BAL_CTL) != b) {
-           cx_write(AUD_BAL_CTL, b);
-           changed = 1;
+       if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
+               cx_write(AUD_BAL_CTL, b);
+               changed = 1;
        }
        spin_unlock_irq(&chip->reg_lock);
 
@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
                  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-       .name = "Playback Volume",
+       .name = "Analog-TV Volume",
        .info = snd_cx88_volume_info,
        .get = snd_cx88_volume_get,
        .put = snd_cx88_volume_put,
@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
        vol = cx_read(AUD_VOL_CTL);
        if (value->value.integer.value[0] != !(vol & bit)) {
                vol ^= bit;
-               cx_write(AUD_VOL_CTL, vol);
+               cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
+               /* Pass mute onto any WM8775 */
+               if ((core->board.audio_chip == V4L2_IDENT_WM8775) &&
+                   ((1<<6) == bit)) {
+                       struct v4l2_control client_ctl;
+
+                       memset(&client_ctl, 0, sizeof(client_ctl));
+                       client_ctl.value = 0 != (vol & bit);
+                       client_ctl.id = V4L2_CID_AUDIO_MUTE;
+                       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+               }
                ret = 1;
        }
        spin_unlock_irq(&chip->reg_lock);
@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
 
 static const struct snd_kcontrol_new snd_cx88_dac_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Playback Switch",
+       .name = "Audio-Out Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = snd_cx88_switch_get,
        .put = snd_cx88_switch_put,
@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
 
 static const struct snd_kcontrol_new snd_cx88_source_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Switch",
+       .name = "Analog-TV Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = snd_cx88_switch_get,
        .put = snd_cx88_switch_put,
        .private_value = (1<<6),
 };
 
+static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       struct v4l2_control client_ctl;
+
+       memset(&client_ctl, 0, sizeof(client_ctl));
+       client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+       call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
+       value->value.integer.value[0] = client_ctl.value ? 1 : 0;
+
+       return 0;
+}
+
+static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
+{
+       snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+       struct cx88_core *core = chip->core;
+       struct v4l2_control client_ctl;
+
+       memset(&client_ctl, 0, sizeof(client_ctl));
+       client_ctl.value = 0 != value->value.integer.value[0];
+       client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_cx88_alc_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Line-In ALC Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = snd_cx88_alc_get,
+       .put = snd_cx88_alc_put,
+};
+
 /****************************************************************************
                        Basic Flow for Sound Devices
  ****************************************************************************/
@@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card)
 static int devno;
 static int __devinit snd_cx88_create(struct snd_card *card,
                                     struct pci_dev *pci,
-                                    snd_cx88_card_t **rchip)
+                                    snd_cx88_card_t **rchip,
+                                    struct cx88_core **core_ptr)
 {
        snd_cx88_card_t   *chip;
        struct cx88_core  *core;
@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
                dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
                err = -EIO;
-               cx88_core_put(core,pci);
+               cx88_core_put(core, pci);
                return err;
        }
 
@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
        *rchip = chip;
+       *core_ptr = core;
 
        return 0;
 }
@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 {
        struct snd_card  *card;
        snd_cx88_card_t  *chip;
+       struct cx88_core *core = NULL;
        int              err;
 
        if (devno >= SNDRV_CARDS)
@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 
        card->private_free = snd_cx88_dev_free;
 
-       err = snd_cx88_create(card, pci, &chip);
+       err = snd_cx88_create(card, pci, &chip, &core);
        if (err < 0)
                goto error;
 
@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
        if (err < 0)
                goto error;
 
+       /* If there's a wm8775 then add a Line-In ALC switch */
+       if (core->board.audio_chip == V4L2_IDENT_WM8775)
+               snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));
+
        strcpy (card->driver, "CX88x");
        sprintf(card->shortname, "Conexant CX%x", pci->device);
        sprintf(card->longname, "%s at %#llx",
index 4e6ee5584cb32c9f78c21762bb89796ec476f84a..27222c92b603cf140419f7ba1448a62e2cfa3c11 100644 (file)
@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .audio_chip = V4L2_IDENT_WM8775,
+               .audio_chip     = V4L2_IDENT_WM8775,
+               .i2sinputcntl   = 2,
                .input          = {{
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
@@ -1952,6 +1953,18 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_TEVII_S464] = {
+               .name           = "TeVii S464 DVB-S/S2",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_OMICOM_SS4_PCI] = {
                .name           = "Omicom SS4 DVB-S/S2 PCI",
                .tuner_type     = UNSET,
@@ -2527,6 +2540,10 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0xd460,
                .subdevice = 0x9022,
                .card      = CX88_BOARD_TEVII_S460,
+       }, {
+               .subvendor = 0xd464,
+               .subdevice = 0x9022,
+               .card      = CX88_BOARD_TEVII_S464,
        }, {
                .subvendor = 0xA044,
                .subdevice = 0x2011,
@@ -3165,9 +3182,7 @@ static void cx88_card_setup(struct cx88_core *core)
 {
        static u8 eeprom[256];
        struct tuner_setup tun_setup;
-       unsigned int mode_mask = T_RADIO     |
-                                T_ANALOG_TV |
-                                T_DIGITAL_TV;
+       unsigned int mode_mask = T_RADIO | T_ANALOG_TV;
 
        memset(&tun_setup, 0, sizeof(tun_setup));
 
@@ -3287,6 +3302,7 @@ static void cx88_card_setup(struct cx88_core *core)
        }
        case  CX88_BOARD_TEVII_S420:
        case  CX88_BOARD_TEVII_S460:
+       case  CX88_BOARD_TEVII_S464:
        case  CX88_BOARD_OMICOM_SS4_PCI:
        case  CX88_BOARD_TBS_8910:
        case  CX88_BOARD_TBS_8920:
index 90717ee944ec5632e62ae2d3462f7987718671db..7b8c9d3b6efcc54a349b7584293b36a77384db56 100644 (file)
@@ -57,6 +57,7 @@
 #include "stb6100.h"
 #include "stb6100_proc.h"
 #include "mb86a16.h"
+#include "ds3000.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -648,6 +649,20 @@ static const struct cx24116_config tevii_s460_config = {
        .reset_device  = cx24116_reset_device,
 };
 
+static int ds3000_set_ts_param(struct dvb_frontend *fe,
+       int is_punctured)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       dev->ts_gen_cntrl = 4;
+
+       return 0;
+}
+
+static struct ds3000_config tevii_ds3000_config = {
+       .demod_address = 0x68,
+       .set_ts_params = ds3000_set_ts_param,
+};
+
 static const struct stv0900_config prof_7301_stv0900_config = {
        .demod_address = 0x6a,
 /*     demod_mode = 0,*/
@@ -1381,6 +1396,14 @@ static int dvb_register(struct cx8802_dev *dev)
                if (fe0->dvb.frontend != NULL)
                        fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
                break;
+       case CX88_BOARD_TEVII_S464:
+               fe0->dvb.frontend = dvb_attach(ds3000_attach,
+                                               &tevii_ds3000_config,
+                                               &core->i2c_adap);
+               if (fe0->dvb.frontend != NULL)
+                       fe0->dvb.frontend->ops.set_voltage =
+                                                       tevii_dvbs_set_voltage;
+               break;
        case CX88_BOARD_OMICOM_SS4_PCI:
        case CX88_BOARD_TBS_8920:
        case CX88_BOARD_PROF_7300:
index 06f7d1d009440a985948539c937ced3dd1cedf21..c820e2f53527333b6fe7a42961776deadb15c45a 100644 (file)
@@ -283,7 +283,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
        case CX88_BOARD_HAUPPAUGE_IRONLY:
-               ir_codes = RC_MAP_HAUPPAUGE_NEW;
+               ir_codes = RC_MAP_HAUPPAUGE;
                ir->sampling = 1;
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
@@ -373,6 +373,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                ir_codes = RC_MAP_TBS_NEC;
                ir->sampling = 0xff00; /* address */
                break;
+       case CX88_BOARD_TEVII_S464:
        case CX88_BOARD_TEVII_S460:
        case CX88_BOARD_TEVII_S420:
                ir_codes = RC_MAP_TEVII_NEC;
@@ -603,7 +604,7 @@ void cx88_i2c_init_ir(struct cx88_core *core)
                if (*addrp == 0x71) {
                        /* Hauppauge XVR */
                        core->init_data.name = "cx88 Hauppauge XVR remote";
-                       core->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
+                       core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
                        core->init_data.type = RC_TYPE_RC5;
                        core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
 
index 08220de3d74deda0c974f9eb2654541c6b9945bc..770ec05b5e9b7da789db5f1ae3a2823066be1f23 100644 (file)
@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)
                break;
        case WW_I2SADC:
                set_audio_start(core, 0x01);
-               /* Slave/Philips/Autobaud */
-               cx_write(AUD_I2SINPUTCNTL, 0);
+               /*
+                * Slave/Philips/Autobaud
+                * NB on Nova-S bit1 NPhilipsSony appears to be inverted:
+                *      0= Sony, 1=Philips
+                */
+               cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl);
                /* Switch to "I2S ADC mode" */
                cx_write(AUD_I2SCNTL, 0x1);
                set_audio_finish(core, EN_I2SIN_ENABLE);
index 508dabbed9868aa95815d77bcd54a576524f0f5e..287a41ee1c4f6d6cd2a0a1ced34cd2950c5aaf7f 100644 (file)
@@ -40,6 +40,7 @@
 #include "cx88.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/wm8775.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -989,6 +990,32 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
                ctl->value = c->v.minimum;
        if (ctl->value > c->v.maximum)
                ctl->value = c->v.maximum;
+
+       /* Pass changes onto any WM8775 */
+       if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+               struct v4l2_control client_ctl;
+               memset(&client_ctl, 0, sizeof(client_ctl));
+               client_ctl.id = ctl->id;
+
+               switch (ctl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       client_ctl.value = ctl->value;
+                       break;
+               case V4L2_CID_AUDIO_VOLUME:
+                       client_ctl.value = (ctl->value) ?
+                               (0x90 + ctl->value) << 8 : 0;
+                       break;
+               case V4L2_CID_AUDIO_BALANCE:
+                       client_ctl.value = ctl->value << 9;
+                       break;
+               default:
+                       client_ctl.id = 0;
+                       break;
+               }
+               if (client_ctl.id)
+                       call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+       }
+
        mask=c->mask;
        switch (ctl->id) {
        case V4L2_CID_AUDIO_BALANCE:
@@ -1526,7 +1553,9 @@ static int radio_queryctrl (struct file *file, void *priv,
        if (c->id <  V4L2_CID_BASE ||
                c->id >= V4L2_CID_LASTP1)
                return -EINVAL;
-       if (c->id == V4L2_CID_AUDIO_MUTE) {
+       if (c->id == V4L2_CID_AUDIO_MUTE ||
+               c->id == V4L2_CID_AUDIO_VOLUME ||
+               c->id == V4L2_CID_AUDIO_BALANCE) {
                for (i = 0; i < CX8800_CTLS; i++) {
                        if (cx8800_ctls[i].v.id == c->id)
                                break;
@@ -1672,7 +1701,7 @@ static const struct v4l2_file_operations video_fops =
        .read          = video_read,
        .poll          = video_poll,
        .mmap          = video_mmap,
-       .ioctl         = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1722,7 +1751,7 @@ static const struct v4l2_file_operations radio_fops =
        .owner         = THIS_MODULE,
        .open          = video_open,
        .release       = video_release,
-       .ioctl         = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
@@ -1856,9 +1885,24 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        /* load and configure helper modules */
 
-       if (core->board.audio_chip == V4L2_IDENT_WM8775)
-               v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
-                               "wm8775", 0x36 >> 1, NULL);
+       if (core->board.audio_chip == V4L2_IDENT_WM8775) {
+               struct i2c_board_info wm8775_info = {
+                       .type = "wm8775",
+                       .addr = 0x36 >> 1,
+                       .platform_data = &core->wm8775_data,
+               };
+               struct v4l2_subdev *sd;
+
+               if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1)
+                       core->wm8775_data.is_nova_s = true;
+               else
+                       core->wm8775_data.is_nova_s = false;
+
+               sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
+                               &wm8775_info, NULL);
+               if (sd != NULL)
+                       sd->grp_id = WM8775_GID;
+       }
 
        if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
                /* This probes for a tda9874 as is used on some
@@ -1882,6 +1926,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                request_module("ir-kbd-i2c");
        }
 
+       /* Sets device info at pci_dev */
+       pci_set_drvdata(pci_dev, dev);
+
+       /* initial device configuration */
+       mutex_lock(&core->lock);
+       cx88_set_tvnorm(core, core->tvnorm);
+       init_controls(core);
+       cx88_video_mux(core, 0);
+
        /* register v4l devices */
        dev->video_dev = cx88_vdev_init(core,dev->pci,
                                        &cx8800_video_template,"video");
@@ -1923,16 +1976,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                       core->name, video_device_node_name(dev->radio_dev));
        }
 
-       /* everything worked */
-       pci_set_drvdata(pci_dev,dev);
-
-       /* initial device configuration */
-       mutex_lock(&core->lock);
-       cx88_set_tvnorm(core,core->tvnorm);
-       init_controls(core);
-       cx88_video_mux(core,0);
-       mutex_unlock(&core->lock);
-
        /* start tvaudio thread */
        if (core->board.tuner_type != TUNER_ABSENT) {
                core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
@@ -1942,11 +1985,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
                               core->name, err);
                }
        }
+       mutex_unlock(&core->lock);
+
        return 0;
 
 fail_unreg:
        cx8800_unregister_video(dev);
        free_irq(pci_dev->irq, dev);
+       mutex_unlock(&core->lock);
 fail_core:
        cx88_core_put(core,dev->pci);
 fail_free:
index c9981e77416a6f8292721b53333bd9cbba1da35c..9b3742a7746c5d6d57d87705da194690fefaa7fd 100644 (file)
@@ -33,6 +33,7 @@
 #include <media/cx2341x.h>
 #include <media/videobuf-dvb.h>
 #include <media/ir-kbd-i2c.h>
+#include <media/wm8775.h>
 
 #include "btcx-risc.h"
 #include "cx88-reg.h"
@@ -240,6 +241,7 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_PROF_7301               83
 #define CX88_BOARD_SAMSUNG_SMT_7020        84
 #define CX88_BOARD_TWINHAN_VP1027_DVBS     85
+#define CX88_BOARD_TEVII_S464              86
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -273,6 +275,9 @@ struct cx88_board {
        enum cx88_board_type    mpeg;
        unsigned int            audio_chip;
        int                     num_frontends;
+
+       /* Used for I2S devices */
+       int                     i2sinputcntl;
 };
 
 struct cx88_subid {
@@ -379,6 +384,7 @@ struct cx88_core {
 
        /* I2C remote data */
        struct IR_i2c_init_data    init_data;
+       struct wm8775_platform_data wm8775_data;
 
        struct mutex               lock;
        /* various v4l controls */
@@ -398,17 +404,21 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
        return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
 }
 
-#define call_all(core, o, f, args...)                          \
+#define WM8775_GID     (1 << 0)
+
+#define call_hw(core, grpid, o, f, args...) \
        do {                                                    \
                if (!core->i2c_rc) {                            \
                        if (core->gate_ctrl)                    \
                                core->gate_ctrl(core, 1);       \
-                       v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
+                       v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
                        if (core->gate_ctrl)                    \
                                core->gate_ctrl(core, 0);       \
                }                                               \
        } while (0)
 
+#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
+
 struct cx8800_dev;
 struct cx8802_dev;
 
index 353eadaa823e72aa87ff3412bb1f0b8fbd05841e..71e961e53a56184b07bbbcdd5f752754313b8930 100644 (file)
@@ -1719,7 +1719,7 @@ unlock_out:
 
 
 static long vpfe_param_handler(struct file *file, void *priv,
-               int cmd, void *param)
+               bool valid_prio, int cmd, void *param)
 {
        struct vpfe_device *vpfe_dev = video_drvdata(file);
        int ret = 0;
index 87f77a34eeabd092a678208dcac815caf0c230cc..69fcea82d01cb356831622486f68a8e289c1f325 100644 (file)
@@ -834,7 +834,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware = 1,
                .has_dvb      = 1,
                .dvb_gpio     = hauppauge_wintv_hvr_900_digital,
-               .ir_codes     = RC_MAP_HAUPPAUGE_NEW,
+               .ir_codes     = RC_MAP_HAUPPAUGE,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -859,7 +859,7 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
-               .ir_codes     = RC_MAP_HAUPPAUGE_NEW,
+               .ir_codes     = RC_MAP_HAUPPAUGE,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -885,7 +885,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = RC_MAP_HAUPPAUGE_NEW,
+               .ir_codes       = RC_MAP_HAUPPAUGE,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -911,7 +911,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = RC_MAP_RC5_HAUPPAUGE_NEW,
+               .ir_codes       = RC_MAP_HAUPPAUGE,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -2430,7 +2430,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
                dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
                break;
        case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-               dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW;
+               dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
                dev->init_data.get_key = em28xx_get_key_em_haup;
                dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
                break;
index f34d524ccb09fe30169e81eb18e92497816a3f11..a83131bd00b2b13e2808b06386fb6a816b3b60e7 100644 (file)
@@ -1387,6 +1387,27 @@ static int vidioc_queryctrl(struct file *file, void *priv,
                return -EINVAL;
 }
 
+/*
+ * FIXME: This is an indirect way to check if a control exists at a
+ * subdev. Instead of that hack, maybe the better would be to change all
+ * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
+ */
+static int check_subdev_ctrl(struct em28xx *dev, int id)
+{
+       struct v4l2_queryctrl qc;
+
+       memset(&qc, 0, sizeof(qc));
+       qc.id = id;
+
+       /* enumerate V4L2 device controls */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
+
+       if (qc.type)
+               return 0;
+       else
+               return -EINVAL;
+}
+
 static int vidioc_g_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
@@ -1399,7 +1420,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
                return rc;
        rc = 0;
 
-
        /* Set an AC97 control */
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
                rc = ac97_get_ctrl(dev, ctrl);
@@ -1408,6 +1428,9 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        /* It were not an AC97 control. Sends it to the v4l2 dev interface */
        if (rc == 1) {
+               if (check_subdev_ctrl(dev, ctrl->id))
+                       return -EINVAL;
+
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
                rc = 0;
        }
@@ -1434,8 +1457,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
        if (rc == 1) {
-               rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
-
+               rc = check_subdev_ctrl(dev, ctrl->id);
+               if (!rc)
+                       v4l2_device_call_all(&dev->v4l2_dev, 0,
+                                            core, s_ctrl, ctrl);
                /*
                 * In the case of non-AC97 volume controls, we still need
                 * to do some setups at em28xx, in order to mute/unmute
@@ -1452,7 +1477,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                        rc = em28xx_audio_analog_set(dev);
                }
        }
-       return rc;
+       return (rc < 0) ? rc : 0;
 }
 
 static int vidioc_g_tuner(struct file *file, void *priv,
index dda56ff834f42c09625f54c971497d6cee17a4bf..eb04e8b599899db09ae7ebe7d0d0cf11ca0f0176 100644 (file)
@@ -104,6 +104,15 @@ config USB_GSPCA_MR97310A
          To compile this driver as a module, choose M here: the
          module will be called gspca_mr97310a.
 
+config USB_GSPCA_NW80X
+       tristate "Divio based (NW80x) USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the NW80x chips.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_nw80x.
+
 config USB_GSPCA_OV519
        tristate "OV51x / OVFX2 / W996xCF USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -346,6 +355,16 @@ config USB_GSPCA_VC032X
          To compile this driver as a module, choose M here: the
          module will be called gspca_vc032x.
 
+config USB_GSPCA_VICAM
+       tristate "ViCam USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for the 3com homeconnect camera
+         (vicam).
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_vicam.
+
 config USB_GSPCA_XIRLINK_CIT
        tristate "Xirlink C-It USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 24e695b8b077c46a7bc988889954e271e485ec28..855fbc8c9c472a3bd59bdb94502d15dac33b87a8 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
 obj-$(CONFIG_USB_GSPCA_KONICA)   += gspca_konica.o
 obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
 obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
+obj-$(CONFIG_USB_GSPCA_NW80X)    += gspca_nw80x.o
 obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
 obj-$(CONFIG_USB_GSPCA_OV534)    += gspca_ov534.o
 obj-$(CONFIG_USB_GSPCA_OV534_9)  += gspca_ov534_9.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
 obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
 obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
 obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_VICAM)    += gspca_vicam.o
 obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
 obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
 
@@ -47,6 +49,7 @@ gspca_jeilinj-objs  := jeilinj.o
 gspca_konica-objs   := konica.o
 gspca_mars-objs     := mars.o
 gspca_mr97310a-objs := mr97310a.o
+gspca_nw80x-objs    := nw80x.o
 gspca_ov519-objs    := ov519.o
 gspca_ov534-objs    := ov534.o
 gspca_ov534_9-objs  := ov534_9.o
@@ -73,6 +76,7 @@ gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
 gspca_tv8532-objs   := tv8532.o
 gspca_vc032x-objs   := vc032x.o
+gspca_vicam-objs    := vicam.o
 gspca_xirlink_cit-objs := xirlink_cit.o
 gspca_zc3xx-objs    := zc3xx.o
 
diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/video/gspca/autogain_functions.h
new file mode 100644 (file)
index 0000000..46777ee
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Functions for auto gain.
+ *
+ * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+   http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+static inline int auto_gain_n_exposure(
+                       struct gspca_dev *gspca_dev,
+                       int avg_lum,
+                       int desired_avg_lum,
+                       int deadzone,
+                       int gain_knee,
+                       int exposure_knee)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, steps, gain, orig_gain, exposure, orig_exposure;
+       int retval = 0;
+
+       orig_gain = gain = sd->ctrls[GAIN].val;
+       orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
+
+       /* If we are of a multiple of deadzone, do multiple steps to reach the
+          desired lumination fast (with the risc of a slight overshoot) */
+       steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+       PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+               avg_lum, desired_avg_lum, steps);
+
+       for (i = 0; i < steps; i++) {
+               if (avg_lum > desired_avg_lum) {
+                       if (gain > gain_knee)
+                               gain--;
+                       else if (exposure > exposure_knee)
+                               exposure--;
+                       else if (gain > sd->ctrls[GAIN].def)
+                               gain--;
+                       else if (exposure > sd->ctrls[EXPOSURE].min)
+                               exposure--;
+                       else if (gain > sd->ctrls[GAIN].min)
+                               gain--;
+                       else
+                               break;
+               } else {
+                       if (gain < sd->ctrls[GAIN].def)
+                               gain++;
+                       else if (exposure < exposure_knee)
+                               exposure++;
+                       else if (gain < gain_knee)
+                               gain++;
+                       else if (exposure < sd->ctrls[EXPOSURE].max)
+                               exposure++;
+                       else if (gain < sd->ctrls[GAIN].max)
+                               gain++;
+                       else
+                               break;
+               }
+       }
+
+       if (gain != orig_gain) {
+               sd->ctrls[GAIN].val = gain;
+               setgain(gspca_dev);
+               retval = 1;
+       }
+       if (exposure != orig_exposure) {
+               sd->ctrls[EXPOSURE].val = exposure;
+               setexposure(gspca_dev);
+               retval = 1;
+       }
+
+       if (retval)
+               PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+                       gain, exposure);
+       return retval;
+}
+
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+   (usually this means we can only control the clockdiv to change exposure)
+   As changing the clockdiv so that the fps drops from 30 to 15 fps for
+   example, will lead to a huge exposure change (it effectively doubles),
+   this algorithm normally tries to only adjust the gain (between 40 and
+   80 %) and if that does not help, only then changes exposure. This leads
+   to a much more stable image then using the knee algorithm which at
+   certain points of the knee graph will only try to adjust exposure,
+   which leads to oscilating as one exposure step is huge.
+
+   Note this assumes that the sd struct for the cam in question has
+   exp_too_high_cnt and exp_too_high_cnt int members for use by this function.
+
+   Returns 0 if no changes were made, 1 if the gain and or exposure settings
+   where changed. */
+static inline int coarse_grained_expo_autogain(
+                       struct gspca_dev *gspca_dev,
+                       int avg_lum,
+                       int desired_avg_lum,
+                       int deadzone)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int steps, gain, orig_gain, exposure, orig_exposure;
+       int gain_low, gain_high;
+       int retval = 0;
+
+       orig_gain = gain = sd->ctrls[GAIN].val;
+       orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
+
+       gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2;
+       gain_low += sd->ctrls[GAIN].min;
+       gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4;
+       gain_high += sd->ctrls[GAIN].min;
+
+       /* If we are of a multiple of deadzone, do multiple steps to reach the
+          desired lumination fast (with the risc of a slight overshoot) */
+       steps = (desired_avg_lum - avg_lum) / deadzone;
+
+       PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+               avg_lum, desired_avg_lum, steps);
+
+       if ((gain + steps) > gain_high &&
+           exposure < sd->ctrls[EXPOSURE].max) {
+               gain = gain_high;
+               sd->exp_too_low_cnt++;
+               sd->exp_too_high_cnt = 0;
+       } else if ((gain + steps) < gain_low &&
+                  exposure > sd->ctrls[EXPOSURE].min) {
+               gain = gain_low;
+               sd->exp_too_high_cnt++;
+               sd->exp_too_low_cnt = 0;
+       } else {
+               gain += steps;
+               if (gain > sd->ctrls[GAIN].max)
+                       gain = sd->ctrls[GAIN].max;
+               else if (gain < sd->ctrls[GAIN].min)
+                       gain = sd->ctrls[GAIN].min;
+               sd->exp_too_high_cnt = 0;
+               sd->exp_too_low_cnt = 0;
+       }
+
+       if (sd->exp_too_high_cnt > 3) {
+               exposure--;
+               sd->exp_too_high_cnt = 0;
+       } else if (sd->exp_too_low_cnt > 3) {
+               exposure++;
+               sd->exp_too_low_cnt = 0;
+       }
+
+       if (gain != orig_gain) {
+               sd->ctrls[GAIN].val = gain;
+               setgain(gspca_dev);
+               retval = 1;
+       }
+       if (exposure != orig_exposure) {
+               sd->ctrls[EXPOSURE].val = exposure;
+               setexposure(gspca_dev);
+               retval = 1;
+       }
+
+       if (retval)
+               PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+                       gain, exposure);
+       return retval;
+}
index 4bf2cab98d64cd2a4c38a8f77de2ffb57f1decf5..9ddbac680663523c46f4e8027707388695819948 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cpia CPiA (1) gspca driver
  *
- * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the in kernel v4l1 cpia driver which is :
  *
@@ -28,6 +28,7 @@
 
 #define MODULE_NAME "cpia1"
 
+#include <linux/input.h>
 #include "gspca.h"
 
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
@@ -653,10 +654,15 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command,
                break;
 
        case CPIA_COMMAND_ReadMCPorts:
-               if (!sd->params.qx3.qx3_detected)
-                       break;
                /* test button press */
-               sd->params.qx3.button = ((gspca_dev->usb_buf[1] & 0x02) == 0);
+               a = ((gspca_dev->usb_buf[1] & 0x02) == 0);
+               if (a != sd->params.qx3.button) {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+                       input_report_key(gspca_dev->input_dev, KEY_CAMERA, a);
+                       input_sync(gspca_dev->input_dev);
+#endif
+                       sd->params.qx3.button = a;
+               }
                if (sd->params.qx3.button) {
                        /* button pressed - unlock the latch */
                        do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
@@ -1400,7 +1406,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
                if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
                     sd->exposure_status == EXPOSURE_DARK) &&
                    sd->exposure_count >= DARK_TIME * framerate &&
-                   sd->params.sensorFps.divisor < 3) {
+                   sd->params.sensorFps.divisor < 2) {
 
                        /* dark for too long */
                        ++sd->params.sensorFps.divisor;
@@ -1456,7 +1462,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
                if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
                     sd->exposure_status == EXPOSURE_DARK) &&
                    sd->exposure_count >= DARK_TIME * framerate &&
-                   sd->params.sensorFps.divisor < 3) {
+                   sd->params.sensorFps.divisor < 2) {
 
                        /* dark for too long */
                        ++sd->params.sensorFps.divisor;
@@ -1738,6 +1744,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        command_pause(gspca_dev);
 
        /* save camera state for later open (developers guide ch 3.5.3) */
@@ -1748,6 +1756,17 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
        /* Update the camera status */
        do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       /* If the last button state is pressed, release it now! */
+       if (sd->params.qx3.button) {
+               /* The camera latch will hold the pressed state until we reset
+                  the latch, so we do not reset sd->params.qx3.button now, to
+                  avoid a false keypress being reported the next sd_start */
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+               input_sync(gspca_dev->input_dev);
+       }
+#endif
 }
 
 /* this function is called at probe and resume time */
@@ -1852,8 +1871,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
 
        /* Update our knowledge of the camera state */
        do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
-       if (sd->params.qx3.qx3_detected)
-               do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
+       do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -2085,6 +2103,9 @@ static const struct sd_desc sd_desc = {
        .dq_callback = sd_dq_callback,
        .pkt_scan = sd_pkt_scan,
        .querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       .other_input = 1,
+#endif
 };
 
 /* -- module initialisation -- */
index f21f2a258ae0ee5722ebebcd1e9925202bead369..9c6a643caf01c3d64aa64993947456c746c29266 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Main USB camera driver
  *
- * Copyright (C) 2008-2010 Jean-FranƧois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2011 Jean-FranƧois Moine <http://moinejf.free.fr>
  *
  * Camera button input handling by MĆ”rton NĆ©meth
  * Copyright (C) 2009-2010 MĆ”rton NĆ©meth <nm127@freemail.hu>
@@ -414,7 +414,6 @@ resubmit:
  *     - 0 or many INTER_PACKETs
  *     - one LAST_PACKET
  * DISCARD_PACKET invalidates the whole frame.
- * On LAST_PACKET, a new frame is returned.
  */
 void gspca_frame_add(struct gspca_dev *gspca_dev,
                        enum gspca_packet_type packet_type,
@@ -631,7 +630,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
                ep = &alt->endpoint[i];
                attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
                if (attr == xfer
-                   && ep->desc.wMaxPacketSize != 0)
+                   && ep->desc.wMaxPacketSize != 0
+                   && usb_endpoint_dir_in(&ep->desc))
                        return ep;
        }
        return NULL;
@@ -1525,10 +1525,12 @@ static int vidioc_reqbufs(struct file *file, void *priv,
                gspca_dev->usb_err = 0;
                gspca_stream_off(gspca_dev);
                mutex_unlock(&gspca_dev->usb_lock);
+
+               /* Don't restart the stream when switching from read
+                * to mmap mode */
+               if (gspca_dev->memory == GSPCA_MEMORY_READ)
+                       streaming = 0;
        }
-       /* Don't restart the stream when switching from read to mmap mode */
-       if (gspca_dev->memory == GSPCA_MEMORY_READ)
-               streaming = 0;
 
        /* free the previous allocated buffers, if any */
        if (gspca_dev->nframes != 0)
@@ -2152,7 +2154,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_g_chip_ident    = vidioc_g_chip_ident,
 };
 
-static struct video_device gspca_template = {
+static const struct video_device gspca_template = {
        .name = "gspca main driver",
        .fops = &dev_fops,
        .ioctl_ops = &dev_ioctl_ops,
index 06b777f5379ef7c7f92198cbe53306e6387be183..36dae38b1e38cef1df2acc8c56e71845f14dfba5 100644 (file)
@@ -183,7 +183,6 @@ static void jlj_dostream(struct work_struct *work)
        struct sd *dev = container_of(work, struct sd, work_struct);
        struct gspca_dev *gspca_dev = &dev->gspca_dev;
        int blocks_left; /* 0x200-sized blocks remaining in current frame. */
-       int size_in_blocks;
        int act_len;
        int packet_type;
        int ret;
@@ -209,7 +208,6 @@ static void jlj_dostream(struct work_struct *work)
                        act_len, JEILINJ_MAX_TRANSFER);
                if (ret < 0 || act_len < FRAME_HEADER_LEN)
                        goto quit_stream;
-               size_in_blocks = buffer[0x0a];
                blocks_left = buffer[0x0a] - 1;
                PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
 
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c
new file mode 100644 (file)
index 0000000..8e754fd
--- /dev/null
@@ -0,0 +1,2145 @@
+/*
+ * DivIO nw80x subdriver
+ *
+ * Copyright (C) 2011 Jean-FranƧois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2003 Sylvain Munaut <tnt@246tNt.com>
+ *                     Kjell Claesson <keyson@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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
+ */
+
+#define MODULE_NAME "nw80x"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("NW80x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int webcam;
+
+/* controls */
+enum e_ctrl {
+       GAIN,
+       EXPOSURE,
+       AUTOGAIN,
+       NCTRLS          /* number of controls */
+};
+
+#define AUTOGAIN_DEF 1
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       struct gspca_ctrl ctrls[NCTRLS];
+
+       u32 ae_res;
+       s8 ag_cnt;
+#define AG_CNT_START 13
+       u8 exp_too_low_cnt;
+       u8 exp_too_high_cnt;
+
+       u8 bridge;
+       u8 webcam;
+};
+
+enum bridges {
+       BRIDGE_NW800,   /* and et31x110 */
+       BRIDGE_NW801,
+       BRIDGE_NW802,
+};
+enum webcams {
+       Generic800,
+       SpaceCam,       /* Trust 120 SpaceCam */
+       SpaceCam2,      /* other Trust 120 SpaceCam */
+       Cvideopro,      /* Conceptronic Video Pro */
+       Dlink350c,
+       DS3303u,
+       Kr651us,
+       Kritter,
+       Mustek300,
+       Proscope,
+       Twinkle,
+       DvcV6,
+       P35u,
+       Generic802,
+       NWEBCAMS        /* number of webcams */
+};
+
+static const u8 webcam_chip[NWEBCAMS] = {
+       [Generic800]    = BRIDGE_NW800, /* 06a5:0000
+                                        * Typhoon Webcam 100 USB */
+
+       [SpaceCam]      = BRIDGE_NW800, /* 06a5:d800
+                               * Trust SpaceCam120 or SpaceCam100 PORTABLE */
+
+       [SpaceCam2]     = BRIDGE_NW800, /* 06a5:d800 - pas106
+                       * other Trust SpaceCam120 or SpaceCam100 PORTABLE */
+
+       [Cvideopro]     = BRIDGE_NW802, /* 06a5:d001
+                       * Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' */
+
+       [Dlink350c]     = BRIDGE_NW802, /* 06a5:d001
+                                        * D-Link NetQam Pro 250plus */
+
+       [DS3303u]       = BRIDGE_NW801, /* 06a5:d001
+                               * Plustek Opticam 500U or ProLink DS3303u */
+
+       [Kr651us]       = BRIDGE_NW802, /* 06a5:d001
+                                        * Panasonic GP-KR651US */
+
+       [Kritter]       = BRIDGE_NW802, /* 06a5:d001
+                                        * iRez Kritter cam */
+
+       [Mustek300]     = BRIDGE_NW802, /* 055f:d001
+                                        * Mustek Wcam 300 mini */
+
+       [Proscope]      = BRIDGE_NW802, /* 06a5:d001
+                                        * Scalar USB Microscope (ProScope) */
+
+       [Twinkle]       = BRIDGE_NW800, /* 06a5:d800 - hv7121b? (seems pas106)
+                                        * Divio Chicony TwinkleCam
+                                        * DSB-C110 */
+
+       [DvcV6]         = BRIDGE_NW802, /* 0502:d001
+                                        * DVC V6 */
+
+       [P35u]          = BRIDGE_NW801, /* 052b:d001, 06a5:d001 and 06be:d001
+                                        * EZCam Pro p35u */
+
+       [Generic802]    = BRIDGE_NW802,
+};
+/*
+ * other webcams:
+ *     - nw801 046d:d001
+ *             Logitech QuickCam Pro (dark focus ring)
+ *     - nw801 0728:d001
+ *             AVerMedia Camguard
+ *     - nw??? 06a5:d001
+ *             D-Link NetQam Pro 250plus
+ *     - nw800 065a:d800
+ *             Showcam NGS webcam
+ *     - nw??? ????:????
+ *             Sceptre svc300
+ */
+
+/*
+ * registers
+ *    nw800/et31x110     nw801           nw802
+ *     0000..009e      0000..00a1      0000..009e
+ *     0200..0211         id              id
+ *     0300..0302         id              id
+ *     0400..0406        (inex)        0400..0406
+ *     0500..0505      0500..0506        (inex)
+ *     0600..061a      0600..0601      0600..0601
+ *     0800..0814         id              id
+ *     1000..109c      1000..10a1      1000..109a
+ */
+
+/* resolutions
+ *     nw800: 320x240, 352x288
+ *     nw801/802: 320x240, 640x480
+ */
+static const struct v4l2_pix_format cif_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 4 / 8,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+       {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 4 / 8,
+               .colorspace = V4L2_COLORSPACE_JPEG}
+};
+static const struct v4l2_pix_format vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 4 / 8,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+       {640, 480, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+};
+
+/*
+ * The sequences below contain:
+ *     - 1st and 2nd bytes: either
+ *             - register number (BE)
+ *             - I2C0 + i2c address
+ *     - 3rd byte: data length (=0 for end of sequence)
+ *     - n bytes: data
+ */
+#define I2C0 0xff
+
+static const u8 nw800_init[] = {
+       0x04, 0x05, 0x01, 0x61,
+       0x04, 0x04, 0x01, 0x01,
+       0x04, 0x06, 0x01, 0x04,
+       0x04, 0x04, 0x03, 0x00, 0x00, 0x00,
+       0x05, 0x05, 0x01, 0x00,
+       0, 0, 0
+};
+static const u8 nw800_start[] = {
+       0x04, 0x06, 0x01, 0xc0,
+       0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f,
+                         0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24,
+                         0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08,
+                         0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04,
+                         0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0,
+       0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20,
+       0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62,
+                         0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20,
+                         0x01, 0x60, 0x01, 0x00, 0x00,
+
+       0x04, 0x04, 0x01, 0xff,
+       0x04, 0x06, 0x01, 0xc4,
+
+       0x04, 0x06, 0x01, 0xc0,
+       0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f,
+                         0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24,
+                         0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08,
+                         0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04,
+                         0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0,
+       0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20,
+       0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62,
+                         0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20,
+                         0x01, 0x60, 0x01, 0x00, 0x00,
+
+       0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00,
+                         0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65,
+                         0x40,
+       0x00, 0x80, 0x01, 0xa0,
+       0x10, 0x1a, 0x01, 0x00,
+       0x00, 0x91, 0x02, 0x6c, 0x01,
+       0x00, 0x03, 0x02, 0xc8, 0x01,
+       0x10, 0x1a, 0x01, 0x00,
+       0x10, 0x00, 0x01, 0x83,
+       0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01,
+                         0x20, 0x01, 0x60, 0x01,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x10, 0x1b, 0x02, 0x69, 0x00,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x05, 0x02, 0x01, 0x02,
+       0x06, 0x00, 0x02, 0x04, 0xd9,
+       0x05, 0x05, 0x01, 0x20,
+       0x05, 0x05, 0x01, 0x21,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83,
+                         0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0,
+                         0xea,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x13, 0x13,
+       0x10, 0x03, 0x01, 0x14,
+       0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83,
+                         0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0,
+                         0xea,
+       0x10, 0x0b, 0x01, 0x14,
+       0x10, 0x0d, 0x01, 0x20,
+       0x10, 0x0c, 0x01, 0x34,
+       0x04, 0x06, 0x01, 0xc3,
+       0x04, 0x04, 0x01, 0x00,
+       0x05, 0x02, 0x01, 0x02,
+       0x06, 0x00, 0x02, 0x00, 0x48,
+       0x05, 0x05, 0x01, 0x20,
+       0x05, 0x05, 0x01, 0x21,
+       0, 0, 0
+};
+
+/* 06a5:d001 - nw801 - Panasonic
+ *             P35u */
+static const u8 nw801_start_1[] = {
+       0x05, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e,
+                         0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x69, 0xa8, 0x1f, 0x00,
+                         0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00,
+                         0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00,
+                         0x36, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
+       0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x22, 0x02, 0x80, 0x00, 0x1e, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x0a, 0x15, 0x08, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x01, 0x35, 0xfd, 0x07, 0x3d, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x02,
+                         0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+                         0x40, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x06,
+                         0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7,
+       0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80,
+                         0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, 0xa4,
+                         0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, 0xcf,
+                         0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64,
+                         0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2,
+                         0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+       0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x82, 0x02,
+                         0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01,
+                         0xf0, 0x00,
+       0, 0, 0,
+};
+static const u8 nw801_start_qvga[] = {
+       0x02, 0x00, 0x10, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x18, 0x0b, 0x06, 0xa2, 0x86, 0x78,
+       0x02, 0x0f, 0x01, 0x6b,
+       0x10, 0x1a, 0x01, 0x15,
+       0x00, 0x00, 0x01, 0x1e,
+       0x10, 0x00, 0x01, 0x2f,
+       0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00,
+                                                       /* AE window */
+       0, 0, 0,
+};
+static const u8 nw801_start_vga[] = {
+       0x02, 0x00, 0x10, 0x78, 0xa0, 0x97, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xf0,
+       0x02, 0x0f, 0x01, 0xd5,
+       0x10, 0x1a, 0x01, 0x15,
+       0x00, 0x00, 0x01, 0x0e,
+       0x10, 0x00, 0x01, 0x22,
+       0x10, 0x8c, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01,
+       0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01,
+       0, 0, 0,
+};
+static const u8 nw801_start_2[] = {
+       0x10, 0x04, 0x01, 0x1a,
+       0x10, 0x19, 0x01, 0x09,                         /* clock */
+       0x10, 0x24, 0x06, 0xc0, 0x00, 0x3f, 0x02, 0x00, 0x01,
+                                                        /* .. gain .. */
+       0x00, 0x03, 0x02, 0x92, 0x03,
+       0x00, 0x1d, 0x04, 0xf2, 0x00, 0x24, 0x07,
+       0x00, 0x7b, 0x01, 0xcf,
+       0x10, 0x94, 0x01, 0x07,
+       0x05, 0x05, 0x01, 0x01,
+       0x05, 0x04, 0x01, 0x01,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8,
+                         0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0,
+                         0xf0,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x0c, 0x0c,
+       0x10, 0x03, 0x01, 0x08,
+       0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8,
+                         0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0,
+                         0xf0,
+       0x10, 0x0b, 0x01, 0x0b,
+       0x10, 0x0d, 0x01, 0x0b,
+       0x10, 0x0c, 0x01, 0x1f,
+       0x05, 0x06, 0x01, 0x03,
+       0, 0, 0
+};
+
+/* nw802 (sharp IR3Y38M?) */
+static const u8 nw802_start[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x4d,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x08, 0x00, 0x18, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x1d, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0xff, 0x01, 0xc0, 0x00, 0x14,
+                         0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x00,
+       0x10, 0x00, 0x01, 0xad,
+       0x00, 0x00, 0x01, 0x08,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00,
+       0x10, 0x1d, 0x08, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0,
+       0x10, 0x0e, 0x01, 0x27,
+       0x10, 0x41, 0x11, 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b,
+                         0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2,
+                         0xd8,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x14, 0x14,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x41, 0x11, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, 0x74,
+                         0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, 0xf1,
+                         0xff,
+/*                       0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b,
+ *                       0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2,
+ *                       0xd8, */
+       0x10, 0x0b, 0x01, 0x10,
+       0x10, 0x0d, 0x01, 0x11,
+       0x10, 0x0c, 0x01, 0x1c,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+/* et31x110 - Trust 120 SpaceCam */
+static const u8 spacecam_init[] = {
+       0x04, 0x05, 0x01, 0x01,
+       0x04, 0x04, 0x01, 0x01,
+       0x04, 0x06, 0x01, 0x04,
+       0x04, 0x04, 0x03, 0x00, 0x00, 0x00,
+       0x05, 0x05, 0x01, 0x00,
+       0, 0, 0
+};
+static const u8 spacecam_start[] = {
+       0x04, 0x06, 0x01, 0x44,
+       0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f,
+                         0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24,
+                         0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08,
+                         0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04,
+                         0x00, 0x4b, 0x00, 0x7c, 0x00, 0x80, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62,
+                         0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20,
+                         0x01, 0x60, 0x01, 0x00, 0x00,
+       0x04, 0x06, 0x01, 0xc0,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00,
+                         0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65,
+                         0x40,
+       0x00, 0x80, 0x01, 0xa0,
+       0x10, 0x1a, 0x01, 0x00,
+       0x00, 0x91, 0x02, 0x32, 0x01,
+       0x00, 0x03, 0x02, 0x08, 0x02,
+       0x10, 0x00, 0x01, 0x83,
+       0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01,
+                         0x20, 0x01, 0x60, 0x01,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9,
+                         0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
+                         0xf9,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x13, 0x13,
+       0x10, 0x03, 0x01, 0x06,
+       0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9,
+                         0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
+                         0xf9,
+       0x10, 0x0b, 0x01, 0x08,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1f,
+       0x04, 0x06, 0x01, 0xc3,
+       0x04, 0x05, 0x01, 0x40,
+       0x04, 0x04, 0x01, 0x40,
+       0, 0, 0
+};
+/* et31x110 - pas106 - other Trust SpaceCam120 */
+static const u8 spacecam2_start[] = {
+       0x04, 0x06, 0x01, 0x44,
+       0x04, 0x06, 0x01, 0x00,
+       0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f,
+                         0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc,
+                         0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03,
+                         0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04,
+                         0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00,
+       0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62,
+                         0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20,
+                         0x01, 0x60, 0x01, 0x00, 0x00,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x04, 0x04, 0x01, 0x40,
+       0x04, 0x04, 0x01, 0x00,
+       I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05,
+                         0x00, 0x00, 0x05, 0x05,
+       I2C0, 0x40, 0x02, 0x11, 0x06,
+       I2C0, 0x40, 0x02, 0x14, 0x00,
+       I2C0, 0x40, 0x02, 0x13, 0x01,           /* i2c end */
+       0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00,
+                         0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65,
+                         0x40,
+       I2C0, 0x40, 0x02, 0x02, 0x0c,           /* pixel clock */
+       I2C0, 0x40, 0x02, 0x0f, 0x00,
+       I2C0, 0x40, 0x02, 0x13, 0x01,           /* i2c end */
+       0x10, 0x00, 0x01, 0x01,
+       0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01,
+                         0x20, 0x01, 0x60, 0x01,
+       I2C0, 0x40, 0x02, 0x05, 0x0f,           /* exposure */
+       I2C0, 0x40, 0x02, 0x13, 0x01,           /* i2c end */
+       I2C0, 0x40, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00,
+                                               /* gains */
+       I2C0, 0x40, 0x03, 0x12, 0x04, 0x01,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7,
+                         0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7,
+                         0xf9,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x13, 0x13,
+       0x10, 0x03, 0x01, 0x06,
+       0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7,
+                         0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7,
+                         0xf9,
+       0x10, 0x0b, 0x01, 0x11,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x14,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x05, 0x01, 0x61,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* nw802 - Conceptronic Video Pro */
+static const u8 cvideopro_start[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4,
+                         0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54,
+                         0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6,
+                         0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30,
+       0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f,
+                         0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c,
+                         0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x03,
+       0x10, 0x00, 0x01, 0xac,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x3b, 0x01,
+       0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00,
+       0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x1d, 0x02, 0x40, 0x06,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0,
+                         0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x12, 0x12,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0,
+                         0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x0b, 0x01, 0x09,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x2f,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* nw802 - D-link dru-350c cam */
+static const u8 dlink_start[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14,
+                         0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x00,
+       0x10, 0x00, 0x01, 0xad,
+       0x00, 0x00, 0x01, 0x08,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00,
+       0x10, 0x1d, 0x08, 0x40, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x0e, 0x01, 0x20,
+       0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f,
+                         0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf,
+                         0xea,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x11, 0x11,
+       0x10, 0x03, 0x01, 0x10,
+       0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f,
+                         0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf,
+                         0xea,
+       0x10, 0x0b, 0x01, 0x19,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1e,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* 06a5:d001 - nw801 - Sony
+ *             Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */
+/*fixme: 320x240 only*/
+static const u8 ds3303_start[] = {
+       0x05, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x16, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e,
+                         0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa9, 0xa8, 0x1f, 0x00,
+                         0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00,
+                         0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00,
+                         0x36, 0x00,
+       0x02, 0x00, 0x12, 0x03, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0x50,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x2f, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a,
+                         0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4,
+                         0x00, 0x01, 0x15, 0xfd, 0x07, 0x3d, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x8c, 0x04, 0x01, 0x20,
+                         0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
+                         0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x03,
+                         0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7,
+       0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80,
+                         0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, 0x88,
+                         0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, 0xcb,
+                         0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64,
+                         0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2,
+                         0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+       0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, 0x01,
+                         0x00, 0x00, 0xef, 0x00, 0x02, 0x0a, 0x82, 0x02,
+                         0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01,
+                         0xf0, 0x00,
+
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x3f, 0x00, 0xf2, 0x8f, 0x81,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x15,
+       0x10, 0x00, 0x01, 0x2f,
+       0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00,
+       0x10, 0x26, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x24, 0x02, 0x40, 0x06,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6,
+                         0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
+                         0xf9,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x16, 0x16,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6,
+                         0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9,
+                         0xf9,
+       0x10, 0x0b, 0x01, 0x26,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1c,
+       0x05, 0x06, 0x01, 0x03,
+       0x05, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* 06a5:d001 - nw802 - Panasonic
+ *             GP-KR651US (Philips TDA8786) */
+static const u8 kr651_start_1[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x48,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4,
+                         0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54,
+                         0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6,
+                         0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30,
+       0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f,
+                         0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x02, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c,
+                         0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0, 0, 0
+};
+static const u8 kr651_start_qvga[] = {
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x03,
+       0x10, 0x00, 0x01, 0xac,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00,
+       0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00,
+       0x10, 0x1d, 0x02, 0x28, 0x01,
+       0, 0, 0
+};
+static const u8 kr651_start_vga[] = {
+       0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x30, 0x03, 0x01, 0x82, 0x82, 0x98,
+                         0x80,
+       0x10, 0x1a, 0x01, 0x03,
+       0x10, 0x00, 0x01, 0xa0,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01,
+       0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00,
+       0x10, 0x1d, 0x02, 0x68, 0x00,
+};
+static const u8 kr651_start_2[] = {
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8,
+                         0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x0c, 0x0c,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8,
+                         0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x0b, 0x01, 0x10,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x2d,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* nw802 - iRez Kritter cam */
+static const u8 kritter_start[] = {
+       0x04, 0x06, 0x01, 0x06,
+       0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0x94, 0x03, 0x18, 0x00, 0x48,
+                         0x0f, 0x1e, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x0b, 0x00, 0x1b, 0x00, 0x0a, 0x01, 0x28,
+                         0x07, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54,
+                         0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6,
+                         0x00, 0x5d, 0x00, 0x0e, 0x00, 0x7e, 0x00, 0x30,
+       0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f,
+                         0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0b, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x02, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c,
+                         0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x03,
+       0x10, 0x00, 0x01, 0xaf,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x3b, 0x01,
+       0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00,
+       0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00,
+       0x10, 0x1d, 0x02, 0x00, 0x00,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86,
+                         0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4,
+                         0xcb,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x0d, 0x0d,
+       0x10, 0x03, 0x01, 0x02,
+       0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86,
+                         0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4,
+                         0xcb,
+       0x10, 0x0b, 0x01, 0x17,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1e,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* nw802 - Mustek Wcam 300 mini */
+static const u8 mustek_start[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0xfc, 0x05, 0x0c, 0x06,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x13, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14,
+                         0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x00,
+       0x10, 0x00, 0x01, 0xad,
+       0x00, 0x00, 0x01, 0x08,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1d, 0x08, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
+       0x10, 0x0e, 0x01, 0x0f,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e,
+                         0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9,
+                         0xff,
+       0x10, 0x0f, 0x02, 0x11, 0x11,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e,
+                         0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9,
+                         0xff,
+       0x10, 0x0b, 0x01, 0x1c,
+       0x10, 0x0d, 0x01, 0x1a,
+       0x10, 0x0c, 0x01, 0x34,
+       0x04, 0x05, 0x01, 0x61,
+       0x04, 0x04, 0x01, 0x40,
+       0x04, 0x06, 0x01, 0x03,
+       0, 0, 0
+};
+
+/* nw802 - Scope USB Microscope M2 (ProScope) (Hitachi HD49322BF) */
+static const u8 proscope_init[] = {
+       0x04, 0x05, 0x01, 0x21,
+       0x04, 0x04, 0x01, 0x01,
+       0, 0, 0
+};
+static const u8 proscope_start_1[] = {
+       0x04, 0x06, 0x01, 0x04,
+       0x00, 0x00, 0x40, 0x10, 0x01, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x04,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x08, 0x00, 0x17, 0x00, 0xce, 0x00, 0xf4,
+                         0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0xce, 0x00, 0xf8, 0x03, 0x3e, 0x00, 0x86,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0xb6,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xf6, 0x03, 0x34, 0x04, 0xf6, 0x03, 0x34,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xe8,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x1f, 0x0f, 0x08, 0x20, 0xa8, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xad, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a,
+                         0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x8c, 0x04, 0x01,
+                         0x20, 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f,
+                         0x88, 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4,
+                         0xcb, 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f,
+                         0x01, 0x00, 0x00, 0xef, 0x00, 0x09, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0, 0, 0
+};
+static const u8 proscope_start_qvga[] = {
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x06,
+       0x00, 0x03, 0x02, 0xf9, 0x02,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x0e, 0x01, 0x10,
+       0, 0, 0
+};
+static const u8 proscope_start_vga[] = {
+       0x00, 0x03, 0x02, 0xf9, 0x02,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01,
+       0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x16, 0x00, 0x00, 0x82, 0x84, 0x00,
+                         0x80,
+       0x10, 0x1a, 0x01, 0x06,
+       0x10, 0x00, 0x01, 0xa1,
+       0x10, 0x1b, 0x02, 0x00, 0x00,
+       0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01,
+       0x10, 0x0e, 0x01, 0x10,
+       0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae,
+                         0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2,
+                         0xf9,
+       0x10, 0x03, 0x01, 0x00,
+       0, 0, 0
+};
+static const u8 proscope_start_2[] = {
+       0x10, 0x0f, 0x02, 0x0c, 0x0c,
+       0x10, 0x03, 0x01, 0x0c,
+       0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae,
+                         0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2,
+                         0xf9,
+       0x10, 0x0b, 0x01, 0x0b,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1b,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x05, 0x01, 0x21,
+       0x04, 0x04, 0x01, 0x00,
+       0, 0, 0
+};
+
+/* nw800 - hv7121b? (seems pas106) - Divio Chicony TwinkleCam */
+static const u8 twinkle_start[] = {
+       0x04, 0x06, 0x01, 0x44,
+       0x04, 0x06, 0x01, 0x00,
+       0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f,
+                         0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc,
+                         0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86,
+                         0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e,
+                         0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78,
+                         0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46,
+                         0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0,
+                         0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e,
+       0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03,
+                         0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04,
+                         0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00,
+       0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08,
+                         0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62,
+                         0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20,
+                         0x01, 0x60, 0x01, 0x00, 0x00,
+
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       0x04, 0x04, 0x01, 0x10,
+       0x04, 0x04, 0x01, 0x00,
+       0x04, 0x05, 0x01, 0x61,
+       0x04, 0x04, 0x01, 0x01,
+       I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x0a,
+       I2C0, 0x40, 0x02, 0x11, 0x06,
+       I2C0, 0x40, 0x02, 0x14, 0x00,
+       I2C0, 0x40, 0x02, 0x13, 0x01,           /* i2c end */
+       I2C0, 0x40, 0x02, 0x07, 0x01,
+       0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00,
+                         0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65,
+                         0x40,
+       I2C0, 0x40, 0x02, 0x02, 0x0c,
+       I2C0, 0x40, 0x02, 0x13, 0x01,
+       0x10, 0x00, 0x01, 0x01,
+       0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01,
+                         0x20, 0x01, 0x60, 0x01,
+       I2C0, 0x40, 0x02, 0x05, 0x0f,
+       I2C0, 0x40, 0x02, 0x13, 0x01,
+       I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17,
+       I2C0, 0x40, 0x03, 0x12, 0x00, 0x01,
+       0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01,
+       I2C0, 0x40, 0x02, 0x12, 0x00,
+       I2C0, 0x40, 0x02, 0x0e, 0x00,
+       I2C0, 0x40, 0x02, 0x11, 0x06,
+       0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7,
+                         0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7,
+                         0xf9,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x0c, 0x0c,
+       0x10, 0x03, 0x01, 0x06,
+       0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7,
+                         0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7,
+                         0xf9,
+       0x10, 0x0b, 0x01, 0x19,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x0d,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x05, 0x01, 0x61,
+       0x04, 0x04, 0x01, 0x41,
+       0, 0, 0
+};
+
+/* nw802 dvc-v6 */
+static const u8 dvcv6_start[] = {
+       0x04, 0x06, 0x01, 0x06,
+       0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c,
+                         0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19,
+                         0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19,
+                         0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4,
+                         0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0,
+                         0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+                         0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54,
+                         0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6,
+                         0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30,
+       0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f,
+                         0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11,
+                         0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94,
+                         0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00,
+       0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00,
+                         0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0,
+                         0x40, 0x20,
+       0x03, 0x00, 0x03, 0x03, 0x00, 0x00,
+       0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00,
+       0x06, 0x00, 0x02, 0x09, 0x99,
+       0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a,
+                         0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c,
+                         0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+                         0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
+                         0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06,
+                         0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80,
+       0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99,
+                         0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc,
+                         0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54,
+                         0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2,
+                         0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43,
+                         0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3,
+                         0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32,
+                         0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3,
+       0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82,
+                         0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40,
+                         0x01, 0xf0, 0x00,
+       0x00, 0x03, 0x02, 0x94, 0x03,
+       0x00, 0x1d, 0x04, 0x0a, 0x01, 0x28, 0x07,
+       0x00, 0x7b, 0x02, 0xe0, 0x00,
+       0x10, 0x8d, 0x01, 0x00,
+       0x00, 0x09, 0x04, 0x1e, 0x00, 0x0c, 0x02,
+       0x00, 0x91, 0x02, 0x0b, 0x02,
+       0x10, 0x00, 0x01, 0xaf,
+       0x02, 0x00, 0x11, 0x3c, 0x50, 0x8f, 0x3c, 0x50, 0x00, 0x00, 0x00,
+                         0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0,
+                         0x40,
+       0x10, 0x1a, 0x01, 0x02,
+       0x10, 0x00, 0x01, 0xaf,
+       0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00,
+       0x10, 0x1b, 0x02, 0x07, 0x01,
+       0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00,
+       0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00,
+       0x10, 0x1d, 0x02, 0x40, 0x06,
+       0x10, 0x0e, 0x01, 0x08,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa,
+                         0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x03, 0x01, 0x00,
+       0x10, 0x0f, 0x02, 0x12, 0x12,
+       0x10, 0x03, 0x01, 0x11,
+       0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa,
+                         0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc,
+                         0xdc,
+       0x10, 0x0b, 0x01, 0x16,
+       0x10, 0x0d, 0x01, 0x10,
+       0x10, 0x0c, 0x01, 0x1a,
+       0x04, 0x06, 0x01, 0x03,
+       0x04, 0x04, 0x01, 0x00,
+};
+
+static const u8 *webcam_start[] = {
+       [Generic800] = nw800_start,
+       [SpaceCam] = spacecam_start,
+       [SpaceCam2] = spacecam2_start,
+       [Cvideopro] = cvideopro_start,
+       [Dlink350c] = dlink_start,
+       [DS3303u] = ds3303_start,
+       [Kr651us] = kr651_start_1,
+       [Kritter] = kritter_start,
+       [Mustek300] = mustek_start,
+       [Proscope] = proscope_start_1,
+       [Twinkle] = twinkle_start,
+       [DvcV6] = dvcv6_start,
+       [P35u] = nw801_start_1,
+       [Generic802] = nw802_start,
+};
+
+/* -- write a register -- */
+static void reg_w(struct gspca_dev *gspca_dev,
+                       u16 index,
+                       const u8 *data,
+                       int len)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       if (len == 1)
+               PDEBUG(D_USBO, "SET 00 0000 %04x %02x", index, *data);
+       else
+               PDEBUG(D_USBO, "SET 00 0000 %04x %02x %02x ...",
+                               index, *data, data[1]);
+       memcpy(gspca_dev->usb_buf, data, len);
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       0x00,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x00,           /* value */
+                       index,
+                       gspca_dev->usb_buf,
+                       len,
+                       500);
+       if (ret < 0) {
+               err("reg_w err %d", ret);
+               gspca_dev->usb_err = ret;
+       }
+}
+
+/* -- read registers in usb_buf -- */
+static void reg_r(struct gspca_dev *gspca_dev,
+                       u16 index,
+                       int len)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+       ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       0x00,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x00, index,
+                       gspca_dev->usb_buf, len, 500);
+       if (ret < 0) {
+               err("reg_r err %d", ret);
+               gspca_dev->usb_err = ret;
+               return;
+       }
+       if (len == 1)
+               PDEBUG(D_USBI, "GET 00 0000 %04x %02x",
+                               index, gspca_dev->usb_buf[0]);
+       else
+               PDEBUG(D_USBI, "GET 00 0000 %04x %02x %02x ..",
+                               index, gspca_dev->usb_buf[0],
+                               gspca_dev->usb_buf[1]);
+}
+
+static void i2c_w(struct gspca_dev *gspca_dev,
+                       u8 i2c_addr,
+                       const u8 *data,
+                       int len)
+{
+       u8 val[2];
+       int i;
+
+       reg_w(gspca_dev, 0x0600, data + 1, len - 1);
+       reg_w(gspca_dev, 0x0600, data, len);
+       val[0] = len;
+       val[1] = i2c_addr;
+       reg_w(gspca_dev, 0x0502, val, 2);
+       val[0] = 0x01;
+       reg_w(gspca_dev, 0x0501, val, 1);
+       for (i = 5; --i >= 0; ) {
+               msleep(4);
+               reg_r(gspca_dev, 0x0505, 1);
+               if (gspca_dev->usb_err < 0)
+                       return;
+               if (gspca_dev->usb_buf[0] == 0)
+                       return;
+       }
+       gspca_dev->usb_err = -ETIME;
+}
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+                       const u8 *cmd)
+{
+       u16 reg;
+       int len;
+
+       for (;;) {
+               reg = *cmd++ << 8;
+               reg += *cmd++;
+               len = *cmd++;
+               if (len == 0)
+                       break;
+               if (cmd[-3] != I2C0)
+                       reg_w(gspca_dev, reg, cmd, len);
+               else
+                       i2c_w(gspca_dev, reg, cmd, len);
+               cmd += len;
+       }
+}
+
+static int swap_bits(int v)
+{
+       int r, i;
+
+       r = 0;
+       for (i = 0; i < 8; i++) {
+               r <<= 1;
+               if (v & 1)
+                       r++;
+               v >>= 1;
+       }
+       return r;
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 val, v[2];
+
+       val = sd->ctrls[GAIN].val;
+       switch (sd->webcam) {
+       case P35u:
+               /* Note the control goes from 0-255 not 0-127, but anything
+                  above 127 just means amplifying noise */
+               val >>= 1;                      /* 0 - 255 -> 0 - 127 */
+               reg_w(gspca_dev, 0x1026, &val, 1);
+               break;
+       case Kr651us:
+               /* 0 - 253 */
+               val = swap_bits(val);
+               v[0] = val << 3;
+               v[1] = val >> 5;
+               reg_w(gspca_dev, 0x101d, v, 2); /* SIF reg0/1 (AGC) */
+               break;
+       }
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s16 val;
+       u8 v[2];
+
+       val = sd->ctrls[EXPOSURE].val;
+       switch (sd->webcam) {
+       case P35u:
+               v[0] = ((9 - val) << 3) | 0x01;
+               reg_w(gspca_dev, 0x1019, v, 1);
+               break;
+       case Cvideopro:
+       case DvcV6:
+       case Kritter:
+       case Kr651us:
+               v[0] = val;
+               v[1] = val >> 8;
+               reg_w(gspca_dev, 0x101b, v, 2);
+               break;
+       }
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int w, h;
+
+       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
+               return;
+       if (!sd->ctrls[AUTOGAIN].val) {
+               sd->ag_cnt = -1;
+               return;
+       }
+       sd->ag_cnt = AG_CNT_START;
+
+       reg_r(gspca_dev, 0x1004, 1);
+       if (gspca_dev->usb_buf[0] & 0x04) {     /* if AE_FULL_FRM */
+               sd->ae_res = gspca_dev->width * gspca_dev->height;
+       } else {                                /* get the AE window size */
+               reg_r(gspca_dev, 0x1011, 8);
+               w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]
+                 - (gspca_dev->usb_buf[3] << 8) - gspca_dev->usb_buf[2];
+               h = (gspca_dev->usb_buf[5] << 8) + gspca_dev->usb_buf[4]
+                 - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6];
+               sd->ae_res = h * w;
+               if (sd->ae_res == 0)
+                       sd->ae_res = gspca_dev->width * gspca_dev->height;
+       }
+}
+
+static int nw802_test_reg(struct gspca_dev *gspca_dev,
+                       u16 index,
+                       u8 value)
+{
+       /* write the value */
+       reg_w(gspca_dev, index, &value, 1);
+
+       /* read it */
+       reg_r(gspca_dev, index, 1);
+
+       return gspca_dev->usb_buf[0] == value;
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if ((unsigned) webcam >= NWEBCAMS)
+               webcam = 0;
+       sd->webcam = webcam;
+       gspca_dev->cam.reverse_alts = 1;
+       gspca_dev->cam.ctrls = sd->ctrls;
+       sd->ag_cnt = -1;
+
+       /*
+        * Autodetect sequence inspired from some log.
+        * We try to detect what registers exist or not.
+        * If 0x0500 does not exist => NW802
+        * If it does, test 0x109b. If it doesn't exist,
+        * then it's a NW801. Else, a NW800
+        * If a et31x110 (nw800 and 06a5:d800)
+        *      get the sensor ID
+        */
+       if (!nw802_test_reg(gspca_dev, 0x0500, 0x55)) {
+               sd->bridge = BRIDGE_NW802;
+               if (sd->webcam == Generic800)
+                       sd->webcam = Generic802;
+       } else if (!nw802_test_reg(gspca_dev, 0x109b, 0xaa)) {
+               sd->bridge = BRIDGE_NW801;
+               if (sd->webcam == Generic800)
+                       sd->webcam = P35u;
+       } else if (id->idVendor == 0x06a5 && id->idProduct == 0xd800) {
+               reg_r(gspca_dev, 0x0403, 1);            /* GPIO */
+               PDEBUG(D_PROBE, "et31x110 sensor type %02x",
+                               gspca_dev->usb_buf[0]);
+               switch (gspca_dev->usb_buf[0] >> 1) {
+               case 0x00:                              /* ?? */
+                       if (sd->webcam == Generic800)
+                               sd->webcam = SpaceCam;
+                       break;
+               case 0x01:                              /* Hynix? */
+                       if (sd->webcam == Generic800)
+                               sd->webcam = Twinkle;
+                       break;
+               case 0x0a:                              /* Pixart */
+                       if (sd->webcam == Generic800)
+                               sd->webcam = SpaceCam2;
+                       break;
+               }
+       }
+       if (webcam_chip[sd->webcam] != sd->bridge) {
+               err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge);
+               gspca_dev->usb_err = -ENODEV;
+               return gspca_dev->usb_err;
+       }
+       PDEBUG(D_PROBE, "Bridge nw80%d - type: %d", sd->bridge, sd->webcam);
+
+       if (sd->bridge == BRIDGE_NW800) {
+               switch (sd->webcam) {
+               case DS3303u:
+                       gspca_dev->cam.cam_mode = cif_mode;     /* qvga */
+                       break;
+               default:
+                       gspca_dev->cam.cam_mode = &cif_mode[1]; /* cif */
+                       break;
+               }
+               gspca_dev->cam.nmodes = 1;
+       } else {
+               gspca_dev->cam.cam_mode = vga_mode;
+               switch (sd->webcam) {
+               case Kr651us:
+               case Proscope:
+               case P35u:
+                       gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+                       break;
+               default:
+                       gspca_dev->cam.nmodes = 1;      /* qvga only */
+                       break;
+               }
+       }
+       switch (sd->webcam) {
+       case P35u:
+/*             sd->ctrls[EXPOSURE].max = 9;
+ *             sd->ctrls[EXPOSURE].def = 9; */
+               /* coarse expo auto gain function gain minimum, to avoid
+                * a large settings jump the first auto adjustment */
+               sd->ctrls[GAIN].def = 255 / 5 * 2;
+               break;
+       case Cvideopro:
+       case DvcV6:
+       case Kritter:
+               gspca_dev->ctrl_dis = (1 << GAIN) | (1 << AUTOGAIN);
+               /* fall thru */
+       case Kr651us:
+               sd->ctrls[EXPOSURE].max = 315;
+               sd->ctrls[EXPOSURE].def = 150;
+               break;
+       default:
+               gspca_dev->ctrl_dis = (1 << GAIN) | (1 << EXPOSURE)
+                                        | (1 << AUTOGAIN);
+               break;
+       }
+
+#if AUTOGAIN_DEF
+       if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN)))
+               gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE);
+#endif
+       return gspca_dev->usb_err;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->bridge) {
+       case BRIDGE_NW800:
+               switch (sd->webcam) {
+               case SpaceCam:
+                       reg_w_buf(gspca_dev, spacecam_init);
+                       break;
+               default:
+                       reg_w_buf(gspca_dev, nw800_init);
+                       break;
+               }
+               break;
+       default:
+               switch (sd->webcam) {
+               case Mustek300:
+               case P35u:
+               case Proscope:
+                       reg_w_buf(gspca_dev, proscope_init);
+                       break;
+               }
+               break;
+       }
+       return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       const u8 *cmd;
+
+       cmd = webcam_start[sd->webcam];
+       reg_w_buf(gspca_dev, cmd);
+       switch (sd->webcam) {
+       case P35u:
+               if (gspca_dev->width == 320)
+                       reg_w_buf(gspca_dev, nw801_start_qvga);
+               else
+                       reg_w_buf(gspca_dev, nw801_start_vga);
+               reg_w_buf(gspca_dev, nw801_start_2);
+               break;
+       case Kr651us:
+               if (gspca_dev->width == 320)
+                       reg_w_buf(gspca_dev, kr651_start_qvga);
+               else
+                       reg_w_buf(gspca_dev, kr651_start_vga);
+               reg_w_buf(gspca_dev, kr651_start_2);
+               break;
+       case Proscope:
+               if (gspca_dev->width == 320)
+                       reg_w_buf(gspca_dev, proscope_start_qvga);
+               else
+                       reg_w_buf(gspca_dev, proscope_start_vga);
+               reg_w_buf(gspca_dev, proscope_start_2);
+               break;
+       }
+
+       setgain(gspca_dev);
+       setexposure(gspca_dev);
+       setautogain(gspca_dev);
+       sd->exp_too_high_cnt = 0;
+       sd->exp_too_low_cnt = 0;
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 value;
+
+       /* 'go' off */
+       if (sd->bridge != BRIDGE_NW801) {
+               value = 0x02;
+               reg_w(gspca_dev, 0x0406, &value, 1);
+       }
+
+       /* LED off */
+       switch (sd->webcam) {
+       case Cvideopro:
+       case Kr651us:
+       case DvcV6:
+       case Kritter:
+               value = 0xff;
+               break;
+       case Dlink350c:
+               value = 0x21;
+               break;
+       case SpaceCam:
+       case SpaceCam2:
+       case Proscope:
+       case Twinkle:
+               value = 0x01;
+               break;
+       default:
+               return;
+       }
+       reg_w(gspca_dev, 0x0404, &value, 1);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data,                       /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       /*
+        * frame header = '00 00 hh ww ss xx ff ff'
+        * with:
+        *      - 'hh': height / 4
+        *      - 'ww': width / 4
+        *      - 'ss': frame sequence number c0..dd
+        */
+       if (data[0] == 0x00 && data[1] == 0x00
+        && data[6] == 0xff && data[7] == 0xff) {
+               gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, data + 8, len - 8);
+       } else {
+               gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+       }
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->ctrls[AUTOGAIN].val = val;
+       if (val)
+               gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE);
+       else
+               gspca_dev->ctrl_inac = 0;
+       if (gspca_dev->streaming)
+               setautogain(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
+#include "autogain_functions.h"
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int luma;
+
+       if (sd->ag_cnt < 0)
+               return;
+       if (--sd->ag_cnt >= 0)
+               return;
+       sd->ag_cnt = AG_CNT_START;
+
+       /* get the average luma */
+       reg_r(gspca_dev, sd->bridge == BRIDGE_NW801 ? 0x080d : 0x080c, 4);
+       luma = (gspca_dev->usb_buf[3] << 24) + (gspca_dev->usb_buf[2] << 16)
+               + (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
+       luma /= sd->ae_res;
+
+       switch (sd->webcam) {
+       case P35u:
+               coarse_grained_expo_autogain(gspca_dev, luma, 100, 5);
+               break;
+       default:
+               auto_gain_n_exposure(gspca_dev, luma, 100, 5, 230, 0);
+               break;
+       }
+}
+
+/* V4L2 controls supported by the driver */
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[GAIN] = {
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 0,
+               .maximum = 253,
+               .step    = 1,
+               .default_value = 128
+           },
+           .set_control = setgain
+       },
+[EXPOSURE] = {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+               .maximum = 9,
+               .step    = 1,
+               .default_value = 9
+           },
+           .set_control = setexposure
+       },
+[AUTOGAIN] = {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = AUTOGAIN_DEF,
+               .flags   = V4L2_CTRL_FLAG_UPDATE
+           },
+           .set = sd_setautogain
+       },
+};
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+       .dq_callback = do_autogain,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x046d, 0xd001)},
+       {USB_DEVICE(0x0502, 0xd001)},
+       {USB_DEVICE(0x052b, 0xd001)},
+       {USB_DEVICE(0x055f, 0xd001)},
+       {USB_DEVICE(0x06a5, 0x0000)},
+       {USB_DEVICE(0x06a5, 0xd001)},
+       {USB_DEVICE(0x06a5, 0xd800)},
+       {USB_DEVICE(0x06be, 0xd001)},
+       {USB_DEVICE(0x0728, 0xd001)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(webcam, int, 0644);
+MODULE_PARM_DESC(webcam,
+       "Webcam type\n"
+       "0: generic\n"
+       "1: Trust 120 SpaceCam\n"
+       "2: other Trust 120 SpaceCam\n"
+       "3: Conceptronic Video Pro\n"
+       "4: D-link dru-350c\n"
+       "5: Plustek Opticam 500U\n"
+       "6: Panasonic GP-KR651US\n"
+       "7: iRez Kritter\n"
+       "8: Mustek Wcam 300 mini\n"
+       "9: Scalar USB Microscope M2 (Proscope)\n"
+       "10: Divio Chicony TwinkleCam\n"
+       "11: DVC-V6\n");
index 8ab2c452c25effdba21d956e494bbe6b7ea3ff39..fd1b6082c96daec8b4312ac67106bac4ad7b13ac 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * OV519 driver
  *
- * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
+ * Copyright (C) 2008-2011 Jean-FranƧois Moine <moinejf@free.fr>
  * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
  *
  * This module is adapted from the ov51x-jpeg package, which itself
@@ -61,10 +61,12 @@ static int i2c_detect_tries = 10;
 enum e_ctrl {
        BRIGHTNESS,
        CONTRAST,
+       EXPOSURE,
        COLORS,
        HFLIP,
        VFLIP,
        AUTOBRIGHT,
+       AUTOGAIN,
        FREQ,
        NCTRL           /* number of controls */
 };
@@ -118,6 +120,7 @@ struct sd {
 };
 enum sensors {
        SEN_OV2610,
+       SEN_OV2610AE,
        SEN_OV3610,
        SEN_OV6620,
        SEN_OV6630,
@@ -141,9 +144,11 @@ enum sensors {
 /* V4L2 controls supported by the driver */
 static void setbrightness(struct gspca_dev *gspca_dev);
 static void setcontrast(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
 static void setcolors(struct gspca_dev *gspca_dev);
 static void sethvflip(struct gspca_dev *gspca_dev);
 static void setautobright(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static void setfreq(struct gspca_dev *gspca_dev);
 static void setfreq_i(struct sd *sd);
 
@@ -172,6 +177,18 @@ static const struct ctrl sd_ctrls[] = {
            },
            .set_control = setcontrast,
        },
+[EXPOSURE] = {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 127,
+           },
+           .set_control = setexposure,
+       },
 [COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
@@ -221,6 +238,19 @@ static const struct ctrl sd_ctrls[] = {
            },
            .set_control = setautobright,
        },
+[AUTOGAIN] = {
+           {
+               .id      = V4L2_CID_AUTOGAIN,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Auto Gain",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 1,
+               .flags   = V4L2_CTRL_FLAG_UPDATE
+           },
+           .set = sd_setautogain,
+       },
 [FREQ] = {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -237,48 +267,78 @@ static const struct ctrl sd_ctrls[] = {
 
 /* table of the disabled controls */
 static const unsigned ctrl_dis[] = {
-[SEN_OV2610] =         (1 << NCTRL) - 1,       /* no control */
+[SEN_OV2610] =         ((1 << NCTRL) - 1)      /* no control */
+                       ^ ((1 << EXPOSURE)      /* but exposure */
+                        | (1 << AUTOGAIN)),    /* and autogain */
+
+[SEN_OV2610AE] =       ((1 << NCTRL) - 1)      /* no control */
+                       ^ ((1 << EXPOSURE)      /* but exposure */
+                        | (1 << AUTOGAIN)),    /* and autogain */
 
 [SEN_OV3610] =         (1 << NCTRL) - 1,       /* no control */
 
 [SEN_OV6620] =         (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV6630] =         (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV66308AF] =      (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7610] =         (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7620] =         (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7620AE] =       (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7640] =         (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << AUTOBRIGHT) |
-                       (1 << CONTRAST),
+                       (1 << CONTRAST) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7648] =         (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << AUTOBRIGHT) |
-                       (1 << CONTRAST),
+                       (1 << CONTRAST) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
-[SEN_OV7660] =         (1 << AUTOBRIGHT),
+[SEN_OV7660] =         (1 << AUTOBRIGHT) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV7670] =         (1 << COLORS) |
-                       (1 << AUTOBRIGHT),
+                       (1 << AUTOBRIGHT) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV76BE] =         (1 << HFLIP) |
-                       (1 << VFLIP),
+                       (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN),
 
 [SEN_OV8610] =         (1 << HFLIP) |
                        (1 << VFLIP) |
+                       (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
                        (1 << FREQ),
 };
 
@@ -428,6 +488,11 @@ static const struct v4l2_pix_format ovfx2_cif_mode[] = {
                .priv = 0},
 };
 static const struct v4l2_pix_format ovfx2_ov2610_mode[] = {
+       {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 800,
+               .sizeimage = 800 * 600,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
        {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 1600,
                .sizeimage = 1600 * 1200,
@@ -544,6 +609,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
  * buffers, there are some pretty strict real time constraints for
  * isochronous transfer for larger frame sizes).
  */
+/*jfm: this value works well for 1600x1200, but not 800x600 - see isoc_init */
 #define OVFX2_BULK_SIZE (13 * 4096)
 
 /* I2C registers */
@@ -656,6 +722,24 @@ static const struct ov_i2c_regvals norm_2610[] = {
        { 0x12, 0x80 }, /* reset */
 };
 
+static const struct ov_i2c_regvals norm_2610ae[] = {
+       {0x12, 0x80},   /* reset */
+       {0x13, 0xcd},
+       {0x09, 0x01},
+       {0x0d, 0x00},
+       {0x11, 0x80},
+       {0x12, 0x20},   /* 1600x1200 */
+       {0x33, 0x0c},
+       {0x35, 0x90},
+       {0x36, 0x37},
+/* ms-win traces */
+       {0x11, 0x83},   /* clock / 3 ? */
+       {0x2d, 0x00},   /* 60 Hz filter */
+       {0x24, 0xb0},   /* normal colors */
+       {0x25, 0x90},
+       {0x10, 0x43},
+};
+
 static const struct ov_i2c_regvals norm_3620b[] = {
        /*
         * From the datasheet: "Note that after writing to register COMH
@@ -2621,6 +2705,9 @@ static void ov_hires_configure(struct sd *sd)
        if (high == 0x96 && low == 0x40) {
                PDEBUG(D_PROBE, "Sensor is an OV2610");
                sd->sensor = SEN_OV2610;
+       } else if (high == 0x96 && low == 0x41) {
+               PDEBUG(D_PROBE, "Sensor is an OV2610AE");
+               sd->sensor = SEN_OV2610AE;
        } else if (high == 0x36 && (low & 0x0f) == 0x00) {
                PDEBUG(D_PROBE, "Sensor is an OV3610");
                sd->sensor = SEN_OV3610;
@@ -3171,6 +3258,13 @@ static void ov519_set_fr(struct sd *sd)
        ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       i2c_w_mask(sd, 0x13, sd->ctrls[AUTOGAIN].val ? 0x05 : 0x00, 0x05);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -3295,15 +3389,22 @@ static int sd_init(struct gspca_dev *gspca_dev)
                }
                break;
        case BRIDGE_OVFX2:
-               if (sd->sensor == SEN_OV2610) {
+               switch (sd->sensor) {
+               case SEN_OV2610:
+               case SEN_OV2610AE:
                        cam->cam_mode = ovfx2_ov2610_mode;
                        cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode);
-               } else if (sd->sensor == SEN_OV3610) {
+                       break;
+               case SEN_OV3610:
                        cam->cam_mode = ovfx2_ov3610_mode;
                        cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
-               } else if (sd->sif) {
-                       cam->cam_mode = ov519_sif_mode;
-                       cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+                       break;
+               default:
+                       if (sd->sif) {
+                               cam->cam_mode = ov519_sif_mode;
+                               cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+                       }
+                       break;
                }
                break;
        case BRIDGE_W9968CF:
@@ -3325,6 +3426,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
                /* Enable autogain, autoexpo, awb, bandfilter */
                i2c_w_mask(sd, 0x13, 0x27, 0x27);
                break;
+       case SEN_OV2610AE:
+               write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae));
+
+               /* enable autoexpo */
+               i2c_w_mask(sd, 0x13, 0x05, 0x05);
+               break;
        case SEN_OV3610:
                write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b));
 
@@ -3397,6 +3504,22 @@ error:
        return -EINVAL;
 }
 
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->bridge) {
+       case BRIDGE_OVFX2:
+               if (gspca_dev->width == 1600)
+                       gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE;
+               else
+                       gspca_dev->cam.bulk_size = 7 * 4096;
+               break;
+       }
+       return 0;
+}
+
 /* Set up the OV511/OV511+ with the given image parameters.
  *
  * Do not put any sensor-specific code in here (including I2C I/O functions)
@@ -3827,6 +3950,25 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
                i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
                return;
+       case SEN_OV2610AE: {
+               u8 v;
+
+               /* frame rates:
+                *      10fps / 5 fps for 1600x1200
+                *      40fps / 20fps for 800x600
+                */
+               v = 80;
+               if (qvga) {
+                       if (sd->frame_rate < 25)
+                               v = 0x81;
+               } else {
+                       if (sd->frame_rate < 10)
+                               v = 0x81;
+               }
+               i2c_w(sd, 0x11, v);
+               i2c_w(sd, 0x12, qvga ? 0x60 : 0x20);
+               return;
+           }
        case SEN_OV3610:
                if (qvga) {
                        xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
@@ -3975,6 +4117,7 @@ static void set_ov_sensor_window(struct sd *sd)
        /* mode setup is fully handled in mode_init_ov_sensor_regs for these */
        switch (sd->sensor) {
        case SEN_OV2610:
+       case SEN_OV2610AE:
        case SEN_OV3610:
        case SEN_OV7670:
                mode_init_ov_sensor_regs(sd);
@@ -4110,12 +4253,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
                setcontrast(gspca_dev);
        if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS)))
                setbrightness(gspca_dev);
+       if (!(sd->gspca_dev.ctrl_dis & (1 << EXPOSURE)))
+               setexposure(gspca_dev);
        if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS)))
                setcolors(gspca_dev);
        if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP))))
                sethvflip(gspca_dev);
        if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT)))
                setautobright(gspca_dev);
+       if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOGAIN)))
+               setautogain(gspca_dev);
        if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ)))
                setfreq_i(sd);
 
@@ -4529,6 +4676,14 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        }
 }
 
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (!sd->ctrls[AUTOGAIN].val)
+               i2c_w(sd, 0x10, sd->ctrls[EXPOSURE].val);
+}
+
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -4587,6 +4742,22 @@ static void setautobright(struct gspca_dev *gspca_dev)
        i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10);
 }
 
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->ctrls[AUTOGAIN].val = val;
+       if (val) {
+               gspca_dev->ctrl_inac |= (1 << EXPOSURE);
+       } else {
+               gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
+               sd->ctrls[EXPOSURE].val = i2c_r(sd, 0x10);
+       }
+       if (gspca_dev->streaming)
+               setautogain(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
 static void setfreq_i(struct sd *sd)
 {
        if (sd->sensor == SEN_OV7660
@@ -4731,6 +4902,7 @@ static const struct sd_desc sd_desc = {
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
        .init = sd_init,
+       .isoc_init = sd_isoc_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
index 04da228027360331195ebb9f38c8d77e74fc9ef5..0c6369b7fe1892e0fcae05608587e8cd4999f333 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ov534-ov772x gspca driver
+ * ov534-ov7xxx gspca driver
  *
  * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
  * Copyright (C) 2008 Jim Paris <jim@jtan.com>
@@ -49,54 +49,59 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
 MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       GAIN,
+       EXPOSURE,
+       AGC,
+       AWB,
+       AEC,
+       SHARPNESS,
+       HFLIP,
+       VFLIP,
+       COLORS,
+       LIGHTFREQ,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       struct gspca_ctrl ctrls[NCTRLS];
+
        __u32 last_pts;
        u16 last_fid;
        u8 frame_rate;
 
-       u8 brightness;
-       u8 contrast;
-       u8 gain;
-       u8 exposure;
-       u8 agc;
-       u8 awb;
-       u8 aec;
-       s8 sharpness;
-       u8 hflip;
-       u8 vflip;
-       u8 freqfltr;
+       u8 sensor;
+};
+enum sensors {
+       SENSOR_OV767x,
+       SENSOR_OV772x,
+       NSENSORS
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
 static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_querymenu(struct gspca_dev *gspca_dev,
-               struct v4l2_querymenu *menu);
+static void setawb(struct gspca_dev *gspca_dev);
+static void setaec(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+
+static int sd_start(struct gspca_dev *gspca_dev);
+static void sd_stopN(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[] = {
-       {       /* 0 */
+[BRIGHTNESS] = {
                {
                        .id      = V4L2_CID_BRIGHTNESS,
                        .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -104,13 +109,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 255,
                        .step    = 1,
-#define BRIGHTNESS_DEF 0
-                       .default_value = BRIGHTNESS_DEF,
+                       .default_value = 0,
                },
-               .set = sd_setbrightness,
-               .get = sd_getbrightness,
+               .set_control = setbrightness
        },
-       {       /* 1 */
+[CONTRAST] = {
                {
                        .id      = V4L2_CID_CONTRAST,
                        .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -118,13 +121,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 255,
                        .step    = 1,
-#define CONTRAST_DEF 32
-                       .default_value = CONTRAST_DEF,
+                       .default_value = 32,
                },
-               .set = sd_setcontrast,
-               .get = sd_getcontrast,
+               .set_control = setcontrast
        },
-       {       /* 2 */
+[GAIN] = {
                {
                        .id      = V4L2_CID_GAIN,
                        .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -132,13 +133,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 63,
                        .step    = 1,
-#define GAIN_DEF 20
-                       .default_value = GAIN_DEF,
+                       .default_value = 20,
                },
-               .set = sd_setgain,
-               .get = sd_getgain,
+               .set_control = setgain
        },
-       {       /* 3 */
+[EXPOSURE] = {
                {
                        .id      = V4L2_CID_EXPOSURE,
                        .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -146,13 +145,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 255,
                        .step    = 1,
-#define EXPO_DEF 120
-                       .default_value = EXPO_DEF,
+                       .default_value = 120,
                },
-               .set = sd_setexposure,
-               .get = sd_getexposure,
+               .set_control = setexposure
        },
-       {       /* 4 */
+[AGC] = {
                {
                        .id      = V4L2_CID_AUTOGAIN,
                        .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -160,14 +157,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define AGC_DEF 1
-                       .default_value = AGC_DEF,
+                       .default_value = 1,
                },
-               .set = sd_setagc,
-               .get = sd_getagc,
+               .set = sd_setagc
        },
-#define AWB_IDX 5
-       {       /* 5 */
+[AWB] = {
                {
                        .id      = V4L2_CID_AUTO_WHITE_BALANCE,
                        .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -175,13 +169,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define AWB_DEF 1
-                       .default_value = AWB_DEF,
+                       .default_value = 1,
                },
-               .set = sd_setawb,
-               .get = sd_getawb,
+               .set_control = setawb
        },
-       {       /* 6 */
+[AEC] = {
                {
                        .id      = V4L2_CID_EXPOSURE_AUTO,
                        .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -189,13 +181,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define AEC_DEF 1
-                       .default_value = AEC_DEF,
+                       .default_value = 1,
                },
-               .set = sd_setaec,
-               .get = sd_getaec,
+               .set_control = setaec
        },
-       {       /* 7 */
+[SHARPNESS] = {
                {
                        .id      = V4L2_CID_SHARPNESS,
                        .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -203,13 +193,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 63,
                        .step    = 1,
-#define SHARPNESS_DEF 0
-                       .default_value = SHARPNESS_DEF,
+                       .default_value = 0,
                },
-               .set = sd_setsharpness,
-               .get = sd_getsharpness,
+               .set_control = setsharpness
        },
-       {       /* 8 */
+[HFLIP] = {
                {
                        .id      = V4L2_CID_HFLIP,
                        .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -217,13 +205,11 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define HFLIP_DEF 0
-                       .default_value = HFLIP_DEF,
+                       .default_value = 0,
                },
-               .set = sd_sethflip,
-               .get = sd_gethflip,
+               .set_control = sethvflip
        },
-       {       /* 9 */
+[VFLIP] = {
                {
                        .id      = V4L2_CID_VFLIP,
                        .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -231,13 +217,23 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define VFLIP_DEF 0
-                       .default_value = VFLIP_DEF,
+                       .default_value = 0,
                },
-               .set = sd_setvflip,
-               .get = sd_getvflip,
+               .set_control = sethvflip
        },
-       {       /* 10 */
+[COLORS] = {
+               {
+                       .id      = V4L2_CID_SATURATION,
+                       .type    = V4L2_CTRL_TYPE_INTEGER,
+                       .name    = "Saturation",
+                       .minimum = 0,
+                       .maximum = 6,
+                       .step    = 1,
+                       .default_value = 3,
+               },
+               .set_control = setcolors
+       },
+[LIGHTFREQ] = {
                {
                        .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                        .type    = V4L2_CTRL_TYPE_MENU,
@@ -245,11 +241,9 @@ static const struct ctrl sd_ctrls[] = {
                        .minimum = 0,
                        .maximum = 1,
                        .step    = 1,
-#define FREQFLTR_DEF 0
-                       .default_value = FREQFLTR_DEF,
+                       .default_value = 0,
                },
-               .set = sd_setfreqfltr,
-               .get = sd_getfreqfltr,
+               .set_control = setlightfreq
        },
 };
 
@@ -265,6 +259,16 @@ static const struct v4l2_pix_format ov772x_mode[] = {
         .colorspace = V4L2_COLORSPACE_SRGB,
         .priv = 0},
 };
+static const struct v4l2_pix_format ov767x_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG},
+};
 
 static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30};
 static const u8 vga_rates[] = {60, 50, 40, 30, 15};
@@ -280,7 +284,288 @@ static const struct framerates ov772x_framerates[] = {
        },
 };
 
-static const u8 bridge_init[][2] = {
+struct reg_array {
+       const u8 (*val)[2];
+       int len;
+};
+
+static const u8 bridge_init_767x[][2] = {
+/* comments from the ms-win file apollo7670.set */
+/* str1 */
+       {0xf1, 0x42},
+       {0x88, 0xf8},
+       {0x89, 0xff},
+       {0x76, 0x03},
+       {0x92, 0x03},
+       {0x95, 0x10},
+       {0xe2, 0x00},
+       {0xe7, 0x3e},
+       {0x8d, 0x1c},
+       {0x8e, 0x00},
+       {0x8f, 0x00},
+       {0x1f, 0x00},
+       {0xc3, 0xf9},
+       {0x89, 0xff},
+       {0x88, 0xf8},
+       {0x76, 0x03},
+       {0x92, 0x01},
+       {0x93, 0x18},
+       {0x1c, 0x00},
+       {0x1d, 0x48},
+       {0x1d, 0x00},
+       {0x1d, 0xff},
+       {0x1d, 0x02},
+       {0x1d, 0x58},
+       {0x1d, 0x00},
+       {0x1c, 0x0a},
+       {0x1d, 0x0a},
+       {0x1d, 0x0e},
+       {0xc0, 0x50},   /* HSize 640 */
+       {0xc1, 0x3c},   /* VSize 480 */
+       {0x34, 0x05},   /* enable Audio Suspend mode */
+       {0xc2, 0x0c},   /* Input YUV */
+       {0xc3, 0xf9},   /* enable PRE */
+       {0x34, 0x05},   /* enable Audio Suspend mode */
+       {0xe7, 0x2e},   /* this solves failure of "SuspendResumeTest" */
+       {0x31, 0xf9},   /* enable 1.8V Suspend */
+       {0x35, 0x02},   /* turn on JPEG */
+       {0xd9, 0x10},
+       {0x25, 0x42},   /* GPIO[8]:Input */
+       {0x94, 0x11},   /* If the default setting is loaded when
+                        * system boots up, this flag is closed here */
+};
+static const u8 sensor_init_767x[][2] = {
+       {0x12, 0x80},
+       {0x11, 0x03},
+       {0x3a, 0x04},
+       {0x12, 0x00},
+       {0x17, 0x13},
+       {0x18, 0x01},
+       {0x32, 0xb6},
+       {0x19, 0x02},
+       {0x1a, 0x7a},
+       {0x03, 0x0a},
+       {0x0c, 0x00},
+       {0x3e, 0x00},
+       {0x70, 0x3a},
+       {0x71, 0x35},
+       {0x72, 0x11},
+       {0x73, 0xf0},
+       {0xa2, 0x02},
+       {0x7a, 0x2a},   /* set Gamma=1.6 below */
+       {0x7b, 0x12},
+       {0x7c, 0x1d},
+       {0x7d, 0x2d},
+       {0x7e, 0x45},
+       {0x7f, 0x50},
+       {0x80, 0x59},
+       {0x81, 0x62},
+       {0x82, 0x6b},
+       {0x83, 0x73},
+       {0x84, 0x7b},
+       {0x85, 0x8a},
+       {0x86, 0x98},
+       {0x87, 0xb2},
+       {0x88, 0xca},
+       {0x89, 0xe0},
+       {0x13, 0xe0},
+       {0x00, 0x00},
+       {0x10, 0x00},
+       {0x0d, 0x40},
+       {0x14, 0x38},   /* gain max 16x */
+       {0xa5, 0x05},
+       {0xab, 0x07},
+       {0x24, 0x95},
+       {0x25, 0x33},
+       {0x26, 0xe3},
+       {0x9f, 0x78},
+       {0xa0, 0x68},
+       {0xa1, 0x03},
+       {0xa6, 0xd8},
+       {0xa7, 0xd8},
+       {0xa8, 0xf0},
+       {0xa9, 0x90},
+       {0xaa, 0x94},
+       {0x13, 0xe5},
+       {0x0e, 0x61},
+       {0x0f, 0x4b},
+       {0x16, 0x02},
+       {0x21, 0x02},
+       {0x22, 0x91},
+       {0x29, 0x07},
+       {0x33, 0x0b},
+       {0x35, 0x0b},
+       {0x37, 0x1d},
+       {0x38, 0x71},
+       {0x39, 0x2a},
+       {0x3c, 0x78},
+       {0x4d, 0x40},
+       {0x4e, 0x20},
+       {0x69, 0x00},
+       {0x6b, 0x4a},
+       {0x74, 0x10},
+       {0x8d, 0x4f},
+       {0x8e, 0x00},
+       {0x8f, 0x00},
+       {0x90, 0x00},
+       {0x91, 0x00},
+       {0x96, 0x00},
+       {0x9a, 0x80},
+       {0xb0, 0x84},
+       {0xb1, 0x0c},
+       {0xb2, 0x0e},
+       {0xb3, 0x82},
+       {0xb8, 0x0a},
+       {0x43, 0x0a},
+       {0x44, 0xf0},
+       {0x45, 0x34},
+       {0x46, 0x58},
+       {0x47, 0x28},
+       {0x48, 0x3a},
+       {0x59, 0x88},
+       {0x5a, 0x88},
+       {0x5b, 0x44},
+       {0x5c, 0x67},
+       {0x5d, 0x49},
+       {0x5e, 0x0e},
+       {0x6c, 0x0a},
+       {0x6d, 0x55},
+       {0x6e, 0x11},
+       {0x6f, 0x9f},
+       {0x6a, 0x40},
+       {0x01, 0x40},
+       {0x02, 0x40},
+       {0x13, 0xe7},
+       {0x4f, 0x80},
+       {0x50, 0x80},
+       {0x51, 0x00},
+       {0x52, 0x22},
+       {0x53, 0x5e},
+       {0x54, 0x80},
+       {0x58, 0x9e},
+       {0x41, 0x08},
+       {0x3f, 0x00},
+       {0x75, 0x04},
+       {0x76, 0xe1},
+       {0x4c, 0x00},
+       {0x77, 0x01},
+       {0x3d, 0xc2},
+       {0x4b, 0x09},
+       {0xc9, 0x60},
+       {0x41, 0x38},   /* jfm: auto sharpness + auto de-noise  */
+       {0x56, 0x40},
+       {0x34, 0x11},
+       {0x3b, 0xc2},
+       {0xa4, 0x8a},   /* Night mode trigger point */
+       {0x96, 0x00},
+       {0x97, 0x30},
+       {0x98, 0x20},
+       {0x99, 0x20},
+       {0x9a, 0x84},
+       {0x9b, 0x29},
+       {0x9c, 0x03},
+       {0x9d, 0x4c},
+       {0x9e, 0x3f},
+       {0x78, 0x04},
+       {0x79, 0x01},
+       {0xc8, 0xf0},
+       {0x79, 0x0f},
+       {0xc8, 0x00},
+       {0x79, 0x10},
+       {0xc8, 0x7e},
+       {0x79, 0x0a},
+       {0xc8, 0x80},
+       {0x79, 0x0b},
+       {0xc8, 0x01},
+       {0x79, 0x0c},
+       {0xc8, 0x0f},
+       {0x79, 0x0d},
+       {0xc8, 0x20},
+       {0x79, 0x09},
+       {0xc8, 0x80},
+       {0x79, 0x02},
+       {0xc8, 0xc0},
+       {0x79, 0x03},
+       {0xc8, 0x20},
+       {0x79, 0x26},
+};
+static const u8 bridge_start_vga_767x[][2] = {
+/* str59 JPG */
+       {0x94, 0xaa},
+       {0xf1, 0x42},
+       {0xe5, 0x04},
+       {0xc0, 0x50},
+       {0xc1, 0x3c},
+       {0xc2, 0x0c},
+       {0x35, 0x02},   /* turn on JPEG */
+       {0xd9, 0x10},
+       {0xda, 0x00},   /* for higher clock rate(30fps) */
+       {0x34, 0x05},   /* enable Audio Suspend mode */
+       {0xc3, 0xf9},   /* enable PRE */
+       {0x8c, 0x00},   /* CIF VSize LSB[2:0] */
+       {0x8d, 0x1c},   /* output YUV */
+/*     {0x34, 0x05},    * enable Audio Suspend mode (?) */
+       {0x50, 0x00},   /* H/V divider=0 */
+       {0x51, 0xa0},   /* input H=640/4 */
+       {0x52, 0x3c},   /* input V=480/4 */
+       {0x53, 0x00},   /* offset X=0 */
+       {0x54, 0x00},   /* offset Y=0 */
+       {0x55, 0x00},   /* H/V size[8]=0 */
+       {0x57, 0x00},   /* H-size[9]=0 */
+       {0x5c, 0x00},   /* output size[9:8]=0 */
+       {0x5a, 0xa0},   /* output H=640/4 */
+       {0x5b, 0x78},   /* output V=480/4 */
+       {0x1c, 0x0a},
+       {0x1d, 0x0a},
+       {0x94, 0x11},
+};
+static const u8 sensor_start_vga_767x[][2] = {
+       {0x11, 0x01},
+       {0x1e, 0x04},
+       {0x19, 0x02},
+       {0x1a, 0x7a},
+};
+static const u8 bridge_start_qvga_767x[][2] = {
+/* str86 JPG */
+       {0x94, 0xaa},
+       {0xf1, 0x42},
+       {0xe5, 0x04},
+       {0xc0, 0x80},
+       {0xc1, 0x60},
+       {0xc2, 0x0c},
+       {0x35, 0x02},   /* turn on JPEG */
+       {0xd9, 0x10},
+       {0xc0, 0x50},   /* CIF HSize 640 */
+       {0xc1, 0x3c},   /* CIF VSize 480 */
+       {0x8c, 0x00},   /* CIF VSize LSB[2:0] */
+       {0x8d, 0x1c},   /* output YUV */
+       {0x34, 0x05},   /* enable Audio Suspend mode */
+       {0xc2, 0x4c},   /* output YUV and Enable DCW */
+       {0xc3, 0xf9},   /* enable PRE */
+       {0x1c, 0x00},   /* indirect addressing */
+       {0x1d, 0x48},   /* output YUV422 */
+       {0x50, 0x89},   /* H/V divider=/2; plus DCW AVG */
+       {0x51, 0xa0},   /* DCW input H=640/4 */
+       {0x52, 0x78},   /* DCW input V=480/4 */
+       {0x53, 0x00},   /* offset X=0 */
+       {0x54, 0x00},   /* offset Y=0 */
+       {0x55, 0x00},   /* H/V size[8]=0 */
+       {0x57, 0x00},   /* H-size[9]=0 */
+       {0x5c, 0x00},   /* DCW output size[9:8]=0 */
+       {0x5a, 0x50},   /* DCW output H=320/4 */
+       {0x5b, 0x3c},   /* DCW output V=240/4 */
+       {0x1c, 0x0a},
+       {0x1d, 0x0a},
+       {0x94, 0x11},
+};
+static const u8 sensor_start_qvga_767x[][2] = {
+       {0x11, 0x01},
+       {0x1e, 0x04},
+       {0x19, 0x02},
+       {0x1a, 0x7a},
+};
+
+static const u8 bridge_init_772x[][2] = {
        { 0xc2, 0x0c },
        { 0x88, 0xf8 },
        { 0xc3, 0x69 },
@@ -338,7 +623,7 @@ static const u8 bridge_init[][2] = {
        { 0xc1, 0x3c },
        { 0xc2, 0x0c },
 };
-static const u8 sensor_init[][2] = {
+static const u8 sensor_init_772x[][2] = {
        { 0x12, 0x80 },
        { 0x11, 0x01 },
 /*fixme: better have a delay?*/
@@ -431,7 +716,7 @@ static const u8 sensor_init[][2] = {
        { 0x8e, 0x00 },         /* De-noise threshold */
        { 0x0c, 0xd0 }
 };
-static const u8 bridge_start_vga[][2] = {
+static const u8 bridge_start_vga_772x[][2] = {
        {0x1c, 0x00},
        {0x1d, 0x40},
        {0x1d, 0x02},
@@ -442,7 +727,7 @@ static const u8 bridge_start_vga[][2] = {
        {0xc0, 0x50},
        {0xc1, 0x3c},
 };
-static const u8 sensor_start_vga[][2] = {
+static const u8 sensor_start_vga_772x[][2] = {
        {0x12, 0x00},
        {0x17, 0x26},
        {0x18, 0xa0},
@@ -452,7 +737,7 @@ static const u8 sensor_start_vga[][2] = {
        {0x2c, 0xf0},
        {0x65, 0x20},
 };
-static const u8 bridge_start_qvga[][2] = {
+static const u8 bridge_start_qvga_772x[][2] = {
        {0x1c, 0x00},
        {0x1d, 0x40},
        {0x1d, 0x02},
@@ -463,7 +748,7 @@ static const u8 bridge_start_qvga[][2] = {
        {0xc0, 0x28},
        {0xc1, 0x1e},
 };
-static const u8 sensor_start_qvga[][2] = {
+static const u8 sensor_start_qvga_772x[][2] = {
        {0x12, 0x40},
        {0x17, 0x3f},
        {0x18, 0x50},
@@ -646,6 +931,8 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
                {30, 0x04, 0x41, 0x04},
        };
 
+       if (sd->sensor != SENSOR_OV772x)
+               return;
        if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) {
                r = rate_0;
                i = ARRAY_SIZE(rate_0);
@@ -669,15 +956,28 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       int val;
 
-       sccb_reg_write(gspca_dev, 0x9b, sd->brightness);
+       val = sd->ctrls[BRIGHTNESS].val;
+       if (sd->sensor == SENSOR_OV767x) {
+               if (val < 0)
+                       val = 0x80 - val;
+               sccb_reg_write(gspca_dev, 0x55, val);   /* bright */
+       } else {
+               sccb_reg_write(gspca_dev, 0x9b, val);
+       }
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
 
-       sccb_reg_write(gspca_dev, 0x9c, sd->contrast);
+       val = sd->ctrls[CONTRAST].val;
+       if (sd->sensor == SENSOR_OV767x)
+               sccb_reg_write(gspca_dev, 0x56, val);   /* contras */
+       else
+               sccb_reg_write(gspca_dev, 0x9c, val);
 }
 
 static void setgain(struct gspca_dev *gspca_dev)
@@ -685,10 +985,10 @@ static void setgain(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
-       if (sd->agc)
+       if (sd->ctrls[AGC].val)
                return;
 
-       val = sd->gain;
+       val = sd->ctrls[GAIN].val;
        switch (val & 0x30) {
        case 0x00:
                val &= 0x0f;
@@ -715,25 +1015,32 @@ static void setexposure(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
-       if (sd->aec)
+       if (sd->ctrls[AEC].val)
                return;
 
-       /* 'val' is one byte and represents half of the exposure value we are
-        * going to set into registers, a two bytes value:
-        *
-        *    MSB: ((u16) val << 1) >> 8   == val >> 7
-        *    LSB: ((u16) val << 1) & 0xff == val << 1
-        */
-       val = sd->exposure;
-       sccb_reg_write(gspca_dev, 0x08, val >> 7);
-       sccb_reg_write(gspca_dev, 0x10, val << 1);
+       val = sd->ctrls[EXPOSURE].val;
+       if (sd->sensor == SENSOR_OV767x) {
+
+               /* set only aec[9:2] */
+               sccb_reg_write(gspca_dev, 0x10, val);   /* aech */
+       } else {
+
+               /* 'val' is one byte and represents half of the exposure value
+                * we are going to set into registers, a two bytes value:
+                *
+                *    MSB: ((u16) val << 1) >> 8   == val >> 7
+                *    LSB: ((u16) val << 1) & 0xff == val << 1
+                */
+               sccb_reg_write(gspca_dev, 0x08, val >> 7);
+               sccb_reg_write(gspca_dev, 0x10, val << 1);
+       }
 }
 
 static void setagc(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (sd->agc) {
+       if (sd->ctrls[AGC].val) {
                sccb_reg_write(gspca_dev, 0x13,
                                sccb_reg_read(gspca_dev, 0x13) | 0x04);
                sccb_reg_write(gspca_dev, 0x64,
@@ -752,15 +1059,17 @@ static void setawb(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (sd->awb) {
+       if (sd->ctrls[AWB].val) {
                sccb_reg_write(gspca_dev, 0x13,
                                sccb_reg_read(gspca_dev, 0x13) | 0x02);
-               sccb_reg_write(gspca_dev, 0x63,
+               if (sd->sensor == SENSOR_OV772x)
+                       sccb_reg_write(gspca_dev, 0x63,
                                sccb_reg_read(gspca_dev, 0x63) | 0xc0);
        } else {
                sccb_reg_write(gspca_dev, 0x13,
                                sccb_reg_read(gspca_dev, 0x13) & ~0x02);
-               sccb_reg_write(gspca_dev, 0x63,
+               if (sd->sensor == SENSOR_OV772x)
+                       sccb_reg_write(gspca_dev, 0x63,
                                sccb_reg_read(gspca_dev, 0x63) & ~0xc0);
        }
 }
@@ -768,14 +1077,22 @@ static void setawb(struct gspca_dev *gspca_dev)
 static void setaec(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 data;
 
-       if (sd->aec)
+       data = sd->sensor == SENSOR_OV767x ?
+                       0x05 :          /* agc + aec */
+                       0x01;           /* agc */
+       if (sd->ctrls[AEC].val)
                sccb_reg_write(gspca_dev, 0x13,
-                               sccb_reg_read(gspca_dev, 0x13) | 0x01);
+                               sccb_reg_read(gspca_dev, 0x13) | data);
        else {
                sccb_reg_write(gspca_dev, 0x13,
-                               sccb_reg_read(gspca_dev, 0x13) & ~0x01);
-               setexposure(gspca_dev);
+                               sccb_reg_read(gspca_dev, 0x13) & ~data);
+               if (sd->sensor == SENSOR_OV767x)
+                       sd->ctrls[EXPOSURE].val =
+                               sccb_reg_read(gspca_dev, 10);   /* aech */
+               else
+                       setexposure(gspca_dev);
        }
 }
 
@@ -784,43 +1101,67 @@ static void setsharpness(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
 
-       val = sd->sharpness;
+       val = sd->ctrls[SHARPNESS].val;
        sccb_reg_write(gspca_dev, 0x91, val);   /* Auto de-noise threshold */
        sccb_reg_write(gspca_dev, 0x8e, val);   /* De-noise threshold */
 }
 
-static void sethflip(struct gspca_dev *gspca_dev)
+static void sethvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
 
-       if (sd->hflip == 0)
-               sccb_reg_write(gspca_dev, 0x0c,
-                               sccb_reg_read(gspca_dev, 0x0c) | 0x40);
-       else
-               sccb_reg_write(gspca_dev, 0x0c,
-                               sccb_reg_read(gspca_dev, 0x0c) & ~0x40);
+       if (sd->sensor == SENSOR_OV767x) {
+               val = sccb_reg_read(gspca_dev, 0x1e);   /* mvfp */
+               val &= ~0x30;
+               if (sd->ctrls[HFLIP].val)
+                       val |= 0x20;
+               if (sd->ctrls[VFLIP].val)
+                       val |= 0x10;
+               sccb_reg_write(gspca_dev, 0x1e, val);
+       } else {
+               val = sccb_reg_read(gspca_dev, 0x0c);
+               val &= ~0xc0;
+               if (sd->ctrls[HFLIP].val == 0)
+                       val |= 0x40;
+               if (sd->ctrls[VFLIP].val == 0)
+                       val |= 0x80;
+               sccb_reg_write(gspca_dev, 0x0c, val);
+       }
 }
 
-static void setvflip(struct gspca_dev *gspca_dev)
+static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
+       int i;
+       static u8 color_tb[][6] = {
+               {0x42, 0x42, 0x00, 0x11, 0x30, 0x41},
+               {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},
+               {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},
+               {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},
+               {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},
+               {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},
+               {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},
+       };
 
-       if (sd->vflip == 0)
-               sccb_reg_write(gspca_dev, 0x0c,
-                               sccb_reg_read(gspca_dev, 0x0c) | 0x80);
-       else
-               sccb_reg_write(gspca_dev, 0x0c,
-                               sccb_reg_read(gspca_dev, 0x0c) & ~0x80);
+       val = sd->ctrls[COLORS].val;
+       for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)
+               sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);
 }
 
-static void setfreqfltr(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
 
-       if (sd->freqfltr == 0)
-               sccb_reg_write(gspca_dev, 0x2b, 0x00);
-       else
-               sccb_reg_write(gspca_dev, 0x2b, 0x9e);
+       val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00;
+       if (sd->sensor == SENSOR_OV767x) {
+               sccb_reg_write(gspca_dev, 0x2a, 0x00);
+               if (val)
+                       val = 0x9d;     /* insert dummy to 25fps for 50Hz */
+       }
+       sccb_reg_write(gspca_dev, 0x2b, val);
 }
 
 
@@ -833,39 +1174,33 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
 
+       cam->ctrls = sd->ctrls;
+
+       /* the auto white balance control works only when auto gain is set */
+       if (sd_ctrls[AGC].qctrl.default_value == 0)
+               gspca_dev->ctrl_inac |= (1 << AWB);
+
        cam->cam_mode = ov772x_mode;
        cam->nmodes = ARRAY_SIZE(ov772x_mode);
-       cam->mode_framerates = ov772x_framerates;
-
-       cam->bulk = 1;
-       cam->bulk_size = 16384;
-       cam->bulk_nurbs = 2;
 
        sd->frame_rate = 30;
 
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
-       sd->gain = GAIN_DEF;
-       sd->exposure = EXPO_DEF;
-#if AGC_DEF != 0
-       sd->agc = AGC_DEF;
-#else
-       gspca_dev->ctrl_inac |= (1 << AWB_IDX);
-#endif
-       sd->awb = AWB_DEF;
-       sd->aec = AEC_DEF;
-       sd->sharpness = SHARPNESS_DEF;
-       sd->hflip = HFLIP_DEF;
-       sd->vflip = VFLIP_DEF;
-       sd->freqfltr = FREQFLTR_DEF;
-
        return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        u16 sensor_id;
+       static const struct reg_array bridge_init[NSENSORS] = {
+       [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)},
+       [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)},
+       };
+       static const struct reg_array sensor_init[NSENSORS] = {
+       [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)},
+       [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)},
+       };
 
        /* reset bridge */
        ov534_reg_write(gspca_dev, 0xe7, 0x3a);
@@ -886,48 +1221,100 @@ static int sd_init(struct gspca_dev *gspca_dev)
        sensor_id |= sccb_reg_read(gspca_dev, 0x0b);
        PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
 
+       if ((sensor_id & 0xfff0) == 0x7670) {
+               sd->sensor = SENSOR_OV767x;
+               gspca_dev->ctrl_dis = (1 << GAIN) |
+                                       (1 << AGC) |
+                                       (1 << SHARPNESS);       /* auto */
+               sd->ctrls[BRIGHTNESS].min = -127;
+               sd->ctrls[BRIGHTNESS].max = 127;
+               sd->ctrls[BRIGHTNESS].def = 0;
+               sd->ctrls[CONTRAST].max = 0x80;
+               sd->ctrls[CONTRAST].def = 0x40;
+               sd->ctrls[EXPOSURE].min = 0x08;
+               sd->ctrls[EXPOSURE].max = 0x60;
+               sd->ctrls[EXPOSURE].def = 0x13;
+               sd->ctrls[SHARPNESS].max = 9;
+               sd->ctrls[SHARPNESS].def = 4;
+               sd->ctrls[HFLIP].def = 1;
+               gspca_dev->cam.cam_mode = ov767x_mode;
+               gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode);
+       } else {
+               sd->sensor = SENSOR_OV772x;
+               gspca_dev->ctrl_dis = (1 << COLORS);
+               gspca_dev->cam.bulk = 1;
+               gspca_dev->cam.bulk_size = 16384;
+               gspca_dev->cam.bulk_nurbs = 2;
+               gspca_dev->cam.mode_framerates = ov772x_framerates;
+       }
+
        /* initialize */
-       reg_w_array(gspca_dev, bridge_init,
-                       ARRAY_SIZE(bridge_init));
+       reg_w_array(gspca_dev, bridge_init[sd->sensor].val,
+                       bridge_init[sd->sensor].len);
        ov534_set_led(gspca_dev, 1);
-       sccb_w_array(gspca_dev, sensor_init,
-                       ARRAY_SIZE(sensor_init));
-       ov534_reg_write(gspca_dev, 0xe0, 0x09);
-       ov534_set_led(gspca_dev, 0);
-       set_frame_rate(gspca_dev);
+       sccb_w_array(gspca_dev, sensor_init[sd->sensor].val,
+                       sensor_init[sd->sensor].len);
+       if (sd->sensor == SENSOR_OV767x)
+               sd_start(gspca_dev);
+       sd_stopN(gspca_dev);
+/*     set_frame_rate(gspca_dev);      */
 
        return gspca_dev->usb_err;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int mode;
+       static const struct reg_array bridge_start[NSENSORS][2] = {
+       [SENSOR_OV767x] = {{bridge_start_qvga_767x,
+                                       ARRAY_SIZE(bridge_start_qvga_767x)},
+                       {bridge_start_vga_767x,
+                                       ARRAY_SIZE(bridge_start_vga_767x)}},
+       [SENSOR_OV772x] = {{bridge_start_qvga_772x,
+                                       ARRAY_SIZE(bridge_start_qvga_772x)},
+                       {bridge_start_vga_772x,
+                                       ARRAY_SIZE(bridge_start_vga_772x)}},
+       };
+       static const struct reg_array sensor_start[NSENSORS][2] = {
+       [SENSOR_OV767x] = {{sensor_start_qvga_767x,
+                                       ARRAY_SIZE(sensor_start_qvga_767x)},
+                       {sensor_start_vga_767x,
+                                       ARRAY_SIZE(sensor_start_vga_767x)}},
+       [SENSOR_OV772x] = {{sensor_start_qvga_772x,
+                                       ARRAY_SIZE(sensor_start_qvga_772x)},
+                       {sensor_start_vga_772x,
+                                       ARRAY_SIZE(sensor_start_vga_772x)}},
+       };
+
+       /* (from ms-win trace) */
+       if (sd->sensor == SENSOR_OV767x)
+               sccb_reg_write(gspca_dev, 0x1e, 0x04);
+                                       /* black sun enable ? */
+
+       mode = gspca_dev->curr_mode;    /* 0: 320x240, 1: 640x480 */
+       reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val,
+                               bridge_start[sd->sensor][mode].len);
+       sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val,
+                               sensor_start[sd->sensor][mode].len);
 
-       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
-       if (mode != 0) {        /* 320x240 */
-               reg_w_array(gspca_dev, bridge_start_qvga,
-                               ARRAY_SIZE(bridge_start_qvga));
-               sccb_w_array(gspca_dev, sensor_start_qvga,
-                               ARRAY_SIZE(sensor_start_qvga));
-       } else {                /* 640x480 */
-               reg_w_array(gspca_dev, bridge_start_vga,
-                               ARRAY_SIZE(bridge_start_vga));
-               sccb_w_array(gspca_dev, sensor_start_vga,
-                               ARRAY_SIZE(sensor_start_vga));
-       }
        set_frame_rate(gspca_dev);
 
-       setagc(gspca_dev);
+       if (!(gspca_dev->ctrl_dis & (1 << AGC)))
+               setagc(gspca_dev);
        setawb(gspca_dev);
        setaec(gspca_dev);
-       setgain(gspca_dev);
+       if (!(gspca_dev->ctrl_dis & (1 << GAIN)))
+               setgain(gspca_dev);
        setexposure(gspca_dev);
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
-       setsharpness(gspca_dev);
-       setvflip(gspca_dev);
-       sethflip(gspca_dev);
-       setfreqfltr(gspca_dev);
+       if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS)))
+               setsharpness(gspca_dev);
+       sethvflip(gspca_dev);
+       if (!(gspca_dev->ctrl_dis & (1 << COLORS)))
+               setcolors(gspca_dev);
+       setlightfreq(gspca_dev);
 
        ov534_set_led(gspca_dev, 1);
        ov534_reg_write(gspca_dev, 0xe0, 0x00);
@@ -957,9 +1344,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        __u32 this_pts;
        u16 this_fid;
        int remaining_len = len;
+       int payload_len;
 
+       payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
        do {
-               len = min(remaining_len, 2048);
+               len = min(remaining_len, payload_len);
 
                /* Payloads are prefixed with a UVC-style header.  We
                   consider a frame to start when the FID toggles, or the PTS
@@ -999,8 +1388,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                /* If this packet is marked as EOF, end the frame */
                } else if (data[1] & UVC_STREAM_EOF) {
                        sd->last_pts = 0;
-                       if (gspca_dev->image_len + len - 12 !=
-                           gspca_dev->width * gspca_dev->height * 2) {
+                       if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV
+                        && gspca_dev->image_len + len - 12 !=
+                                  gspca_dev->width * gspca_dev->height * 2) {
                                PDEBUG(D_PACK, "wrong sized frame");
                                goto discard;
                        }
@@ -1026,212 +1416,27 @@ scan_next:
        } while (remaining_len > 0);
 }
 
-/* controls */
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gain = val;
-       if (gspca_dev->streaming)
-               setgain(gspca_dev);
-       return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->gain;
-       return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->exposure = val;
-       if (gspca_dev->streaming)
-               setexposure(gspca_dev);
-       return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->exposure;
-       return 0;
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
-       return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
 static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->agc = val;
-
-       if (gspca_dev->streaming) {
+       sd->ctrls[AGC].val = val;
 
-               /* the auto white balance control works only
-                * when auto gain is set */
-               if (val)
-                       gspca_dev->ctrl_inac &= ~(1 << AWB_IDX);
-               else
-                       gspca_dev->ctrl_inac |= (1 << AWB_IDX);
-               setagc(gspca_dev);
+       /* the auto white balance control works only
+        * when auto gain is set */
+       if (val) {
+               gspca_dev->ctrl_inac &= ~(1 << AWB);
+       } else {
+               gspca_dev->ctrl_inac |= (1 << AWB);
+               if (sd->ctrls[AWB].val) {
+                       sd->ctrls[AWB].val = 0;
+                       if (gspca_dev->streaming)
+                               setawb(gspca_dev);
+               }
        }
-       return 0;
-}
-
-static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->agc;
-       return 0;
-}
-
-static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->awb = val;
-       if (gspca_dev->streaming)
-               setawb(gspca_dev);
-       return 0;
-}
-
-static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->awb;
-       return 0;
-}
-
-static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->aec = val;
-       if (gspca_dev->streaming)
-               setaec(gspca_dev);
-       return 0;
-}
-
-static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->aec;
-       return 0;
-}
-
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->sharpness = val;
-       if (gspca_dev->streaming)
-               setsharpness(gspca_dev);
-       return 0;
-}
-
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->sharpness;
-       return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hflip = val;
-       if (gspca_dev->streaming)
-               sethflip(gspca_dev);
-       return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->hflip;
-       return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->vflip = val;
-       if (gspca_dev->streaming)
-               setvflip(gspca_dev);
-       return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->vflip;
-       return 0;
-}
-
-static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->freqfltr = val;
        if (gspca_dev->streaming)
-               setfreqfltr(gspca_dev);
-       return 0;
-}
-
-static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->freqfltr;
-       return 0;
+               setagc(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
 static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -1302,6 +1507,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x1415, 0x2000)},
+       {USB_DEVICE(0x06f8, 0x3002)},
        {}
 };
 
index fcf29897b71308f9148ddf40bdb515497e09f5c6..c431900cd292a11f690808e2718c953dff6324e2 100644 (file)
@@ -151,6 +151,13 @@ static const struct dmi_system_id flip_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
                }
        },
+       {
+               .ident = "MSI MS-1633X",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+                       DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
+               }
+       },
        {
                .ident = "MSI MS-1635X",
                .matches = {
@@ -369,7 +376,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = SCALE_160x120},
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .sizeimage = 320 * 240 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = SCALE_320x240 | MODE_JPEG},
        {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -384,7 +391,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = SCALE_320x240},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 640,
-               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .sizeimage = 640 * 480 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = SCALE_640x480 | MODE_JPEG},
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -417,7 +424,7 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .priv = SCALE_160x120},
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .sizeimage = 320 * 240 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = SCALE_320x240 | MODE_JPEG},
        {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -432,7 +439,7 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .priv = SCALE_320x240},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 640,
-               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .sizeimage = 640 * 480 * 4 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = SCALE_640x480 | MODE_JPEG},
        {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
@@ -884,6 +891,9 @@ static struct i2c_reg_u8 ov7660_init[] = {
        {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
        {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
        {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
+       /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
+          0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
+       {0x17, 0x10}, {0x18, 0x61},
        {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
        {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
        {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
@@ -1332,10 +1342,8 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
                        return -ENODEV;
                }
        }
-       /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
-       sd->hstart = 1;
-       sd->vstart = 1;
+       sd->hstart = 3;
+       sd->vstart = 3;
        return 0;
 }
 
@@ -1608,6 +1616,18 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
        }
 
        switch (sd->sensor) {
+       case SENSOR_OV7660:
+               value = 0x01;
+               if (hflip)
+                       value |= 0x20;
+               if (vflip) {
+                       value |= 0x10;
+                       sd->vstart = 2;
+               } else
+                       sd->vstart = 3;
+               reg_w1(gspca_dev, 0x1182, sd->vstart);
+               i2c_w1(gspca_dev, 0x1e, value);
+               break;
        case SENSOR_OV9650:
                i2c_r1(gspca_dev, 0x1e, &value);
                value &= ~0x30;
@@ -2482,7 +2502,7 @@ static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
        {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
-       {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
        {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
        {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
@@ -2494,7 +2514,7 @@ static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
        {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
        {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
-       {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
+       {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
        {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
        {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
index c6cd68d66b533a9b08e87f114e5cba69d48bfe24..5a08738fba3068a4aa37766ddbe1475f8b7f572c 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *             sonix sn9c102 (bayer) library
- *             Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
- * Add Pas106 Stefano Mozzi (C) 2004
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2011 Jean-FranƧois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
+ * Add Pas106 Stefano Mozzi (C) 2004
  *
  * 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
@@ -52,13 +52,26 @@ all:
 #include <linux/input.h>
 #include "gspca.h"
 
-MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
+MODULE_AUTHOR("Jean-FranƧois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       GAIN,
+       EXPOSURE,
+       AUTOGAIN,
+       FREQ,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       struct gspca_ctrl ctrls[NCTRLS];
+
        atomic_t avg_lum;
        int prev_avg_lum;
        int exp_too_low_cnt;
@@ -66,13 +79,8 @@ struct sd {
        int header_read;
        u8 header[12]; /* Header without sof marker */
 
-       unsigned short exposure;
-       unsigned char gain;
-       unsigned char brightness;
-       unsigned char autogain;
        unsigned char autogain_ignore_frames;
        unsigned char frames_to_drop;
-       unsigned char freq;             /* light freq filter setting */
 
        __u8 bridge;                    /* Type of bridge */
 #define BRIDGE_101 0
@@ -113,10 +121,9 @@ struct sensor_data {
 #define MODE_REDUCED_SIF 0x20  /* vga mode (320x240 / 160x120) on sif cam */
 
 /* ctrl_dis helper macros */
-#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << COARSE_EXPOSURE_IDX) | \
-                (1 << AUTOGAIN_IDX))
-#define NO_FREQ (1 << FREQ_IDX)
-#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
+#define NO_EXPO ((1 << EXPOSURE) | (1 << AUTOGAIN))
+#define NO_FREQ (1 << FREQ)
+#define NO_BRIGHTNESS (1 << BRIGHTNESS)
 
 #define COMP 0xc7              /* 0x87 //0x07 */
 #define COMP1 0xc9             /* 0x89 //0x09 */
@@ -141,20 +148,14 @@ struct sensor_data {
 #define AUTOGAIN_IGNORE_FRAMES 1
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static void setfreq(struct gspca_dev *gspca_dev);
 
-static const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
-       {
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -162,14 +163,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define BRIGHTNESS_DEF 127
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 127,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness
        },
-#define GAIN_IDX 1
-       {
+[GAIN] = {
            {
                .id      = V4L2_CID_GAIN,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -177,48 +175,31 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define GAIN_DEF 127
 #define GAIN_KNEE 230
-               .default_value = GAIN_DEF,
+               .default_value = 127,
            },
-           .set = sd_setgain,
-           .get = sd_getgain,
+           .set_control = setgain
        },
-#define EXPOSURE_IDX 2
-       {
+[EXPOSURE] = {
                {
                        .id = V4L2_CID_EXPOSURE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
                        .name = "Exposure",
-#define EXPOSURE_DEF  66 /*  33 ms / 30 fps (except on PASXXX) */
-#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */
                        .minimum = 0,
                        .maximum = 1023,
                        .step = 1,
-                       .default_value = EXPOSURE_DEF,
+                       .default_value = 66,
+                               /*  33 ms / 30 fps (except on PASXXX) */
+#define EXPOSURE_KNEE 200      /* 100 ms / 10 fps (except on PASXXX) */
                        .flags = 0,
                },
-               .set = sd_setexposure,
-               .get = sd_getexposure,
+               .set_control = setexposure
        },
-#define COARSE_EXPOSURE_IDX 3
-       {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "Exposure",
+/* for coarse exposure */
+#define COARSE_EXPOSURE_MIN 2
+#define COARSE_EXPOSURE_MAX 15
 #define COARSE_EXPOSURE_DEF  2 /* 30 fps */
-                       .minimum = 2,
-                       .maximum = 15,
-                       .step = 1,
-                       .default_value = COARSE_EXPOSURE_DEF,
-                       .flags = 0,
-               },
-               .set = sd_setexposure,
-               .get = sd_getexposure,
-       },
-#define AUTOGAIN_IDX 4
-       {
+[AUTOGAIN] = {
                {
                        .id = V4L2_CID_AUTOGAIN,
                        .type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -228,13 +209,11 @@ static const struct ctrl sd_ctrls[] = {
                        .step = 1,
 #define AUTOGAIN_DEF 1
                        .default_value = AUTOGAIN_DEF,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_UPDATE
                },
                .set = sd_setautogain,
-               .get = sd_getautogain,
        },
-#define FREQ_IDX 5
-       {
+[FREQ] = {
                {
                        .id      = V4L2_CID_POWER_LINE_FREQUENCY,
                        .type    = V4L2_CTRL_TYPE_MENU,
@@ -245,8 +224,7 @@ static const struct ctrl sd_ctrls[] = {
 #define FREQ_DEF 0
                        .default_value = FREQ_DEF,
                },
-               .set = sd_setfreq,
-               .get = sd_getfreq,
+               .set_control = setfreq
        },
 };
 
@@ -553,7 +531,7 @@ static const __u8 tas5130_sensor_init[][8] = {
        {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
 };
 
-static struct sensor_data sensor_data[] = {
+static const struct sensor_data sensor_data[] = {
 SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
 SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
 SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60),
@@ -646,7 +624,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 
                /* change reg 0x06 */
                i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
-               i2cOV[3] = sd->brightness;
+               i2cOV[3] = sd->ctrls[BRIGHTNESS].val;
                if (i2c_w(gspca_dev, i2cOV) < 0)
                        goto err;
                break;
@@ -664,13 +642,13 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        i2cpdoit[2] = 0x13;
                }
 
-               if (sd->brightness < 127) {
+               if (sd->ctrls[BRIGHTNESS].val < 127) {
                        /* change reg 0x0b, signreg */
                        i2cpbright[3] = 0x01;
                        /* set reg 0x0c, offset */
-                       i2cpbright[4] = 127 - sd->brightness;
+                       i2cpbright[4] = 127 - sd->ctrls[BRIGHTNESS].val;
                } else
-                       i2cpbright[4] = sd->brightness - 127;
+                       i2cpbright[4] = sd->ctrls[BRIGHTNESS].val - 127;
 
                if (i2c_w(gspca_dev, i2cpbright) < 0)
                        goto err;
@@ -687,16 +665,16 @@ err:
 static void setsensorgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       unsigned char gain = sd->gain;
+       u8 gain = sd->ctrls[GAIN].val;
 
        switch (sd->sensor) {
        case SENSOR_HV7131D: {
                __u8 i2c[] =
                        {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17};
 
-               i2c[3] = 0x3f - (sd->gain / 4);
-               i2c[4] = 0x3f - (sd->gain / 4);
-               i2c[5] = 0x3f - (sd->gain / 4);
+               i2c[3] = 0x3f - (gain / 4);
+               i2c[4] = 0x3f - (gain / 4);
+               i2c[5] = 0x3f - (gain / 4);
 
                if (i2c_w(gspca_dev, i2c) < 0)
                        goto err;
@@ -759,11 +737,11 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
                        i2cpdoit[2] = 0x13;
                }
 
-               i2cpgain[3] = sd->gain >> 3;
-               i2cpcolorgain[3] = sd->gain >> 4;
-               i2cpcolorgain[4] = sd->gain >> 4;
-               i2cpcolorgain[5] = sd->gain >> 4;
-               i2cpcolorgain[6] = sd->gain >> 4;
+               i2cpgain[3] = gain >> 3;
+               i2cpcolorgain[3] = gain >> 4;
+               i2cpcolorgain[4] = gain >> 4;
+               i2cpcolorgain[5] = gain >> 4;
+               i2cpcolorgain[6] = gain >> 4;
 
                if (i2c_w(gspca_dev, i2cpgain) < 0)
                        goto err;
@@ -792,13 +770,13 @@ static void setgain(struct gspca_dev *gspca_dev)
        }
 
        if (sd->bridge == BRIDGE_103) {
-               gain = sd->gain >> 1;
+               gain = sd->ctrls[GAIN].val >> 1;
                buf[0] = gain; /* Red */
                buf[1] = gain; /* Green */
                buf[2] = gain; /* Blue */
                reg_w(gspca_dev, 0x05, buf, 3);
        } else {
-               gain = sd->gain >> 4;
+               gain = sd->ctrls[GAIN].val >> 4;
                buf[0] = gain << 4 | gain; /* Red and blue */
                buf[1] = gain; /* Green */
                reg_w(gspca_dev, 0x10, buf, 2);
@@ -820,7 +798,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
                      where the framerate starts dropping
                   2) At 6138 the framerate has already dropped to 2 fps,
                      going any lower makes little sense */
-               __u16 reg = sd->exposure * 6;
+               u16 reg = sd->ctrls[EXPOSURE].val * 6;
+
                i2c[3] = reg >> 8;
                i2c[4] = reg & 0xff;
                if (i2c_w(gspca_dev, i2c) != 0)
@@ -832,7 +811,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
                /* register 19's high nibble contains the sn9c10x clock divider
                   The high nibble configures the no fps according to the
                   formula: 60 / high_nibble. With a maximum of 30 fps */
-               __u8 reg = sd->exposure;
+               u8 reg = sd->ctrls[EXPOSURE].val;
+
                reg = (reg << 4) | 0x0b;
                reg_w(gspca_dev, 0x19, &reg, 1);
                break;
@@ -868,7 +848,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
                } else
                        reg10_max = 0x41;
 
-               reg11 = (15 * sd->exposure + 999) / 1000;
+               reg11 = (15 * sd->ctrls[EXPOSURE].val + 999) / 1000;
                if (reg11 < 1)
                        reg11 = 1;
                else if (reg11 > 16)
@@ -881,14 +861,16 @@ static void setexposure(struct gspca_dev *gspca_dev)
                        reg11 = 4;
 
                /* frame exposure time in ms = 1000 * reg11 / 30    ->
-               reg10 = (sd->exposure / 2) * reg10_max / (1000 * reg11 / 30) */
-               reg10 = (sd->exposure * 15 * reg10_max) / (1000 * reg11);
+               reg10 = (sd->ctrls[EXPOSURE].val / 2) * reg10_max
+                               / (1000 * reg11 / 30) */
+               reg10 = (sd->ctrls[EXPOSURE].val * 15 * reg10_max)
+                               / (1000 * reg11);
 
                /* Don't allow this to get below 10 when using autogain, the
                   steps become very large (relatively) when below 10 causing
                   the image to oscilate from much too dark, to much too bright
                   and back again. */
-               if (sd->autogain && reg10 < 10)
+               if (sd->ctrls[AUTOGAIN].val && reg10 < 10)
                        reg10 = 10;
                else if (reg10 > reg10_max)
                        reg10 = reg10_max;
@@ -927,15 +909,16 @@ static void setexposure(struct gspca_dev *gspca_dev)
                   frame exposure times (like we are doing with the ov chips),
                   as that sometimes leads to jumps in the exposure control,
                   which are bad for auto exposure. */
-               if (sd->exposure < 200) {
-                       i2cpexpo[3] = 255 - (sd->exposure * 255) / 200;
+               if (sd->ctrls[EXPOSURE].val < 200) {
+                       i2cpexpo[3] = 255 - (sd->ctrls[EXPOSURE].val * 255)
+                                               / 200;
                        framerate_ctrl = 500;
                } else {
                        /* The PAS202's exposure control goes from 0 - 4095,
                           but anything below 500 causes vsync issues, so scale
                           our 200-1023 to 500-4095 */
-                       framerate_ctrl = (sd->exposure - 200) * 1000 / 229 +
-                                        500;
+                       framerate_ctrl = (sd->ctrls[EXPOSURE].val - 200)
+                                                       * 1000 / 229 +  500;
                }
 
                i2cpframerate[3] = framerate_ctrl >> 6;
@@ -959,15 +942,15 @@ static void setexposure(struct gspca_dev *gspca_dev)
 
                /* For values below 150 use partial frame exposure, above
                   that use framerate ctrl */
-               if (sd->exposure < 150) {
-                       i2cpexpo[3] = 150 - sd->exposure;
+               if (sd->ctrls[EXPOSURE].val < 150) {
+                       i2cpexpo[3] = 150 - sd->ctrls[EXPOSURE].val;
                        framerate_ctrl = 300;
                } else {
                        /* The PAS106's exposure control goes from 0 - 4095,
                           but anything below 300 causes vsync issues, so scale
                           our 150-1023 to 300-4095 */
-                       framerate_ctrl = (sd->exposure - 150) * 1000 / 230 +
-                                        300;
+                       framerate_ctrl = (sd->ctrls[EXPOSURE].val - 150)
+                                               * 1000 / 230 + 300;
                }
 
                i2cpframerate[3] = framerate_ctrl >> 4;
@@ -998,7 +981,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
                   0x2b register, see ov6630 datasheet.
                   0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
                __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
-               switch (sd->freq) {
+               switch (sd->ctrls[FREQ].val) {
                default:
 /*             case 0:                  * no filter*/
 /*             case 2:                  * 60 hz */
@@ -1017,7 +1000,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
        }
 }
 
-#include "coarse_expo_autogain.h"
+#include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
@@ -1025,7 +1008,8 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum = atomic_read(&sd->avg_lum);
 
-       if (avg_lum == -1 || !sd->autogain)
+       if ((gspca_dev->ctrl_dis & (1 << AUTOGAIN)) ||
+           avg_lum == -1 || !sd->ctrls[AUTOGAIN].val)
                return;
 
        if (sd->autogain_ignore_frames > 0) {
@@ -1045,17 +1029,20 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        }
 
        if (sensor_data[sd->sensor].flags & F_COARSE_EXPO)
-               result = gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
-                               sd->brightness * desired_avg_lum / 127,
+               result = coarse_grained_expo_autogain(gspca_dev, avg_lum,
+                               sd->ctrls[BRIGHTNESS].val
+                                               * desired_avg_lum / 127,
                                deadzone);
        else
-               result = gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
-                               sd->brightness * desired_avg_lum / 127,
+               result = auto_gain_n_exposure(gspca_dev, avg_lum,
+                               sd->ctrls[BRIGHTNESS].val
+                                               * desired_avg_lum / 127,
                                deadzone, GAIN_KNEE, EXPOSURE_KNEE);
 
        if (result) {
                PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d",
-                       (int)sd->gain, (int)sd->exposure);
+                       (int) sd->ctrls[GAIN].val,
+                       (int) sd->ctrls[EXPOSURE].val);
                sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
        }
 }
@@ -1074,9 +1061,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
        /* copy the webcam info from the device id */
        sd->sensor = id->driver_info >> 8;
        sd->bridge = id->driver_info & 0xff;
+
        gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
+#if AUTOGAIN_DEF
+       if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN)))
+               gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE);
+#endif
 
        cam = &gspca_dev->cam;
+       cam->ctrls = sd->ctrls;
        if (!(sensor_data[sd->sensor].flags & F_SIF)) {
                cam->cam_mode = vga_mode;
                cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -1086,20 +1079,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
        cam->npkt = 36;                 /* 36 packets per ISOC message */
 
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->gain = GAIN_DEF;
        if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
-               sd->exposure = COARSE_EXPOSURE_DEF;
-               gspca_dev->ctrl_dis |= (1 << EXPOSURE_IDX);
-       } else {
-               sd->exposure = EXPOSURE_DEF;
-               gspca_dev->ctrl_dis |= (1 << COARSE_EXPOSURE_IDX);
+               sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
+               sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
+               sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
        }
-       if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
-               sd->autogain = 0; /* Disable do_autogain callback */
-       else
-               sd->autogain = AUTOGAIN_DEF;
-       sd->freq = FREQ_DEF;
 
        return 0;
 }
@@ -1398,65 +1382,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gain = val;
-       if (gspca_dev->streaming)
-               setgain(gspca_dev);
-       return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->gain;
-       return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->exposure = val;
-       if (gspca_dev->streaming)
-               setexposure(gspca_dev);
-       return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->exposure;
-       return 0;
-}
-
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->autogain = val;
+       sd->ctrls[AUTOGAIN].val = val;
        sd->exp_too_high_cnt = 0;
        sd->exp_too_low_cnt = 0;
 
@@ -1464,9 +1394,10 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
           we are on a valid point of the autogain gain /
           exposure knee graph, and give this change time to
           take effect before doing autogain. */
-       if (sd->autogain && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) {
-               sd->exposure = EXPOSURE_DEF;
-               sd->gain = GAIN_DEF;
+       if (sd->ctrls[AUTOGAIN].val
+        && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) {
+               sd->ctrls[EXPOSURE].val = sd->ctrls[EXPOSURE].def;
+               sd->ctrls[GAIN].val = sd->ctrls[GAIN].def;
                if (gspca_dev->streaming) {
                        sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
                        setexposure(gspca_dev);
@@ -1474,32 +1405,11 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
                }
        }
 
-       return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->autogain;
-       return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->freq = val;
-       if (gspca_dev->streaming)
-               setfreq(gspca_dev);
-       return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
+       if (sd->ctrls[AUTOGAIN].val)
+               gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE);
+       else
+               gspca_dev->ctrl_inac = 0;
 
-       *val = sd->freq;
        return 0;
 }
 
index d6f39ce1b7e1612dc53fb602a707f13c6d492359..6415aff5cbd1675cb4f96d106b9eb72b78b8977b 100644 (file)
@@ -29,8 +29,6 @@ MODULE_AUTHOR("Jean-FranƧois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-static int starcam;
-
 /* controls */
 enum e_ctrl {
        BRIGHTNESS,
@@ -57,11 +55,18 @@ struct sd {
        atomic_t avg_lum;
        u32 exposure;
 
+       struct work_struct work;
+       struct workqueue_struct *work_thread;
+
+       u32 pktsz;                      /* (used by pkt_scan) */
+       u16 npkt;
+       u8 nchg;
+       s8 short_mark;
+
        u8 quality;                     /* image quality */
-#define QUALITY_MIN 60
-#define QUALITY_MAX 95
-#define QUALITY_DEF 80
-       u8 jpegqual;                    /* webcam quality */
+#define QUALITY_MIN 25
+#define QUALITY_MAX 90
+#define QUALITY_DEF 70
 
        u8 reg01;
        u8 reg17;
@@ -99,6 +104,8 @@ enum sensors {
        SENSOR_SP80708,
 };
 
+static void qual_upd(struct work_struct *work);
+
 /* device flags */
 #define F_PDN_INV      0x01    /* inverse pin S_PWR_DN / sn_xxx tables */
 #define F_ILLUM                0x02    /* presence of illuminator */
@@ -401,7 +408,7 @@ static const u8 sn_hv7131[0x1c] = {
 
 static const u8 sn_mi0360[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x61,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x63,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
        0x81,   0x5d,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
@@ -847,18 +854,8 @@ static const u8 mt9v111_sensor_init[][8] = {
        {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
        {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
        {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */
-       {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x03, 0x01, 0xe1, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x04, 0x02, 0x81, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
        {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */
-       {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x03, 0x01, 0xe6, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x04, 0x02, 0x86, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10},
        {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */
-       {0xb1, 0x5c, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x10},
        {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */
        {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */
        {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */
@@ -872,15 +869,10 @@ static const u8 mt9v111_sensor_init[][8] = {
        {}
 };
 static const u8 mt9v111_sensor_param1[][8] = {
-       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10},
-       {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, /* green1 gain */
-       {0xd1, 0x5c, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, /* red gain */
-       /*******/
-       {0xb1, 0x5c, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x10}, /* vert blanking */
-       {0xb1, 0x5c, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, /* horiz blanking */
-       {0xd1, 0x5c, 0x2c, 0x00, 0xad, 0x00, 0xad, 0x10}, /* blue gain */
+       {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xad, 0x10}, /* G1 and B gains */
+       {0xd1, 0x5c, 0x2d, 0x00, 0xad, 0x00, 0x33, 0x10}, /* R and G2 gains */
+       {0xb1, 0x5c, 0x06, 0x00, 0x40, 0x00, 0x00, 0x10}, /* vert blanking */
+       {0xb1, 0x5c, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, /* horiz blanking */
        {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */
        {}
 };
@@ -1784,7 +1776,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        sd->ag_cnt = -1;
        sd->quality = QUALITY_DEF;
-       sd->jpegqual = 80;
+
+       /* if USB 1.1, let some bandwidth for the audio device */
+       if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
+               gspca_dev->nbalt--;
+
+       INIT_WORK(&sd->work, qual_upd);
 
        return 0;
 }
@@ -1794,7 +1791,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        const u8 *sn9c1xx;
-       u8 regGpio[] = { 0x29, 0x74 };          /* with audio */
+       u8 regGpio[] = { 0x29, 0x70 };          /* no audio */
        u8 regF1;
 
        /* setup a selector by bridge */
@@ -1806,6 +1803,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
        if (gspca_dev->usb_err < 0)
                return gspca_dev->usb_err;
        PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
+       if (gspca_dev->audio)
+               regGpio[1] |= 0x04;             /* with audio */
        switch (sd->bridge) {
        case BRIDGE_SN9C102P:
        case BRIDGE_SN9C105:
@@ -1838,14 +1837,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case BRIDGE_SN9C102P:
                reg_w1(gspca_dev, 0x02, regGpio[1]);
                break;
-       case BRIDGE_SN9C105:
-               reg_w(gspca_dev, 0x01, regGpio, 2);
-               break;
-       case BRIDGE_SN9C110:
-               reg_w1(gspca_dev, 0x02, 0x62);
-               break;
-       case BRIDGE_SN9C120:
-               regGpio[1] = 0x70;              /* no audio */
+       default:
                reg_w(gspca_dev, 0x01, regGpio, 2);
                break;
        }
@@ -1944,10 +1936,10 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
                u8 expo_c1[] =
                        { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 };
 
-               if (expo > 0x0280)
-                       expo = 0x0280;
-               else if (expo < 0x0040)
-                       expo = 0x0040;
+               if (expo > 0x0390)
+                       expo = 0x0390;
+               else if (expo < 0x0060)
+                       expo = 0x0060;
                expo_c1[3] = expo >> 8;
                expo_c1[4] = expo;
                i2c_w8(gspca_dev, expo_c1);
@@ -2004,10 +1996,13 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                sd->exposure = setexposure(gspca_dev, expo);
                break;
        case SENSOR_GC0307:
-       case SENSOR_MT9V111:
                expo = brightness;
                sd->exposure = setexposure(gspca_dev, expo);
                return;                 /* don't set the Y offset */
+       case SENSOR_MT9V111:
+               expo = brightness << 2;
+               sd->exposure = setexposure(gspca_dev, expo);
+               return;                 /* don't set the Y offset */
        case SENSOR_OM6802:
                expo = brightness << 2;
                sd->exposure = setexposure(gspca_dev, expo);
@@ -2199,14 +2194,11 @@ static void setillum(struct gspca_dev *gspca_dev)
                        sd->ctrls[ILLUM].val ? 0x64 : 0x60);
                break;
        case SENSOR_MT9V111:
-               if (starcam)
-                       reg_w1(gspca_dev, 0x02,
-                               sd->ctrls[ILLUM].val ?
-                                               0x55 : 0x54);   /* 370i */
-               else
-                       reg_w1(gspca_dev, 0x02,
-                               sd->ctrls[ILLUM].val ?
-                                               0x66 : 0x64);   /* Clip */
+               reg_w1(gspca_dev, 0x02,
+                       sd->ctrls[ILLUM].val ? 0x77 : 0x74);
+/* should have been: */
+/*                                             0x55 : 0x54);   * 370i */
+/*                                             0x66 : 0x64);   * Clip */
                break;
        }
 }
@@ -2271,18 +2263,12 @@ static void setfreq(struct gspca_dev *gspca_dev)
 static void setjpegqual(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i, sc;
 
-       if (sd->jpegqual < 50)
-               sc = 5000 / sd->jpegqual;
-       else
-               sc = 200 - sd->jpegqual * 2;
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 #if USB_BUF_SZ < 64
 #error "No room enough in usb_buf for quantization table"
 #endif
-       for (i = 0; i < 64; i++)
-               gspca_dev->usb_buf[i] =
-                       (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+       memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
@@ -2290,9 +2276,7 @@ static void setjpegqual(struct gspca_dev *gspca_dev)
                        0x0100, 0,
                        gspca_dev->usb_buf, 64,
                        500);
-       for (i = 0; i < 64; i++)
-               gspca_dev->usb_buf[i] =
-                       (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+       memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0x08,
@@ -2305,6 +2289,19 @@ static void setjpegqual(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x18, sd->reg18);
 }
 
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+       struct sd *sd = container_of(work, struct sd, work);
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+       mutex_lock(&gspca_dev->usb_lock);
+       PDEBUG(D_STREAM, "qual_upd %d%%", sd->quality);
+       setjpegqual(gspca_dev);
+       mutex_unlock(&gspca_dev->usb_lock);
+}
+
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
@@ -2338,7 +2335,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* create the JPEG header */
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
-       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 
        /* initialize the bridge */
        sn9c1xx = sn_tb[sd->sensor];
@@ -2619,6 +2615,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setcolors(gspca_dev);
        setautogain(gspca_dev);
        setfreq(gspca_dev);
+
+       sd->pktsz = sd->npkt = 0;
+       sd->nchg = sd->short_mark = 0;
+       sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
+
        return gspca_dev->usb_err;
 }
 
@@ -2695,6 +2696,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        /* reg_w1(gspca_dev, 0xf1, 0x01); */
 }
 
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->work_thread != NULL) {
+               mutex_unlock(&gspca_dev->usb_lock);
+               destroy_workqueue(sd->work_thread);
+               mutex_lock(&gspca_dev->usb_lock);
+               sd->work_thread = NULL;
+       }
+}
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2732,6 +2747,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                                        (unsigned int) (expotimes << 8));
                        break;
                case SENSOR_OM6802:
+               case SENSOR_MT9V111:
                        expotimes = sd->exposure;
                        expotimes += (luma_mean - delta) >> 2;
                        if (expotimes < 0)
@@ -2744,7 +2760,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 /*             case SENSOR_MO4000: */
 /*             case SENSOR_MI0360: */
 /*             case SENSOR_MI0360B: */
-/*             case SENSOR_MT9V111: */
                        expotimes = sd->exposure;
                        expotimes += (luma_mean - delta) >> 6;
                        if (expotimes < 0)
@@ -2757,6 +2772,29 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        }
 }
 
+/* set the average luminosity from an isoc marker */
+static void set_lum(struct sd *sd,
+                   u8 *data)
+{
+       int avg_lum;
+
+       /*      w0 w1 w2
+        *      w3 w4 w5
+        *      w6 w7 w8
+        */
+       avg_lum = (data[27] << 8) + data[28]            /* w3 */
+
+               + (data[31] << 8) + data[32]            /* w5 */
+
+               + (data[23] << 8) + data[24]            /* w1 */
+
+               + (data[35] << 8) + data[36]            /* w7 */
+
+               + (data[29] << 10) + (data[30] << 2);   /* w4 * 4 */
+       avg_lum >>= 10;
+       atomic_set(&sd->avg_lum, avg_lum);
+}
+
 /* scan the URB packets */
 /* This function is run at interrupt level. */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -2764,70 +2802,141 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int sof, avg_lum;
-
-       /* the image ends on a 64 bytes block starting with
-        *      ff d9 ff ff 00 c4 c4 96
-        * and followed by various information including luminosity */
-       /* this block may be splitted between two packets */
-       /* a new image always starts in a new packet */
-       switch (gspca_dev->last_packet_type) {
-       case DISCARD_PACKET:            /* restart image building */
-               sof = len - 64;
-               if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9)
-                       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
-               return;
-       case LAST_PACKET:               /* put the JPEG 422 header */
+       int i, new_qual;
+
+       /*
+        * A frame ends on the marker
+        *              ff ff 00 c4 c4 96 ..
+        * which is 62 bytes long and is followed by various information
+        * including statuses and luminosity.
+        *
+        * A marker may be splitted on two packets.
+        *
+        * The 6th byte of a marker contains the bits:
+        *      0x08: USB full
+        *      0xc0: frame sequence
+        * When the bit 'USB full' is set, the frame must be discarded;
+        * this is also the case when the 2 bytes before the marker are
+        * not the JPEG end of frame ('ff d9').
+        */
+
+/*fixme: assumption about the following code:
+ *     - there can be only one marker in a packet
+ */
+
+       /* skip the remaining bytes of a short marker */
+       i = sd->short_mark;
+       if (i != 0) {
+               sd->short_mark = 0;
+               if (i < 0       /* if 'ff' at end of previous packet */
+                && data[0] == 0xff
+                && data[1] == 0x00)
+                       goto marker_found;
+               if (data[0] == 0xff && data[1] == 0xff) {
+                       i = 0;
+                       goto marker_found;
+               }
+               len -= i;
+               if (len <= 0)
+                       return;
+               data += i;
+       }
+
+       /* count the packets and their size */
+       sd->npkt++;
+       sd->pktsz += len;
+
+       /* search backwards if there is a marker in the packet */
+       for (i = len - 1; --i >= 0; ) {
+               if (data[i] != 0xff) {
+                       i--;
+                       continue;
+               }
+               if (data[i + 1] == 0xff) {
+
+                       /* (there may be 'ff ff' inside a marker) */
+                       if (i + 2 >= len || data[i + 2] == 0x00)
+                               goto marker_found;
+               }
+       }
+
+       /* no marker found */
+       /* add the JPEG header if first fragment */
+       if (data[len - 1] == 0xff)
+               sd->short_mark = -1;
+       if (gspca_dev->last_packet_type == LAST_PACKET)
                gspca_frame_add(gspca_dev, FIRST_PACKET,
                                sd->jpeg_hdr, JPEG_HDR_SZ);
-               break;
-       }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+       return;
+
+       /* marker found */
+       /* if some error, discard the frame and decrease the quality */
+marker_found:
+       new_qual = 0;
+       if (i > 2) {
+               if (data[i - 2] != 0xff || data[i - 1] != 0xd9) {
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       new_qual = -3;
+               }
+       } else if (i + 6 < len) {
+               if (data[i + 6] & 0x08) {
+                       gspca_dev->last_packet_type = DISCARD_PACKET;
+                       new_qual = -5;
+               }
+       }
 
-       data = gspca_dev->image;
-       if (data == NULL)
-               return;
-       sof = gspca_dev->image_len - 64;
-       if (data[sof] != 0xff
-        || data[sof + 1] != 0xd9)
-               return;
+       gspca_frame_add(gspca_dev, LAST_PACKET, data, i);
 
-       /* end of image found - remove the trailing data */
-       gspca_dev->image_len = sof + 2;
-       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
-       if (sd->ag_cnt < 0)
-               return;
-/* w1 w2 w3 */
-/* w4 w5 w6 */
-/* w7 w8 */
-/* w4 */
-       avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
-/* w6 */
-       avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
-/* w2 */
-       avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
-/* w8 */
-       avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
-/* w5 */
-       avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
-       avg_lum >>= 4;
-       atomic_set(&sd->avg_lum, avg_lum);
-}
+       /* compute the filling rate and a new JPEG quality */
+       if (new_qual == 0) {
+               int r;
 
-static int sd_set_jcomp(struct gspca_dev *gspca_dev,
-                       struct v4l2_jpegcompression *jcomp)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
+               r = (sd->pktsz * 100) /
+                       (sd->npkt *
+                               gspca_dev->urb[0]->iso_frame_desc[0].length);
+               if (r >= 85)
+                       new_qual = -3;
+               else if (r < 75)
+                       new_qual = 2;
+       }
+       if (new_qual != 0) {
+               sd->nchg += new_qual;
+               if (sd->nchg < -6 || sd->nchg >= 12) {
+                       sd->nchg = 0;
+                       new_qual += sd->quality;
+                       if (new_qual < QUALITY_MIN)
+                               new_qual = QUALITY_MIN;
+                       else if (new_qual > QUALITY_MAX)
+                               new_qual = QUALITY_MAX;
+                       if (new_qual != sd->quality) {
+                               sd->quality = new_qual;
+                               queue_work(sd->work_thread, &sd->work);
+                       }
+               }
+       } else {
+               sd->nchg = 0;
+       }
+       sd->pktsz = sd->npkt = 0;
 
-       if (jcomp->quality < QUALITY_MIN)
-               sd->quality = QUALITY_MIN;
-       else if (jcomp->quality > QUALITY_MAX)
-               sd->quality = QUALITY_MAX;
-       else
-               sd->quality = jcomp->quality;
-       if (gspca_dev->streaming)
-               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
-       return 0;
+       /* if the marker is smaller than 62 bytes,
+        * memorize the number of bytes to skip in the next packet */
+       if (i + 62 > len) {                     /* no more usable data */
+               sd->short_mark = i + 62 - len;
+               return;
+       }
+       if (sd->ag_cnt >= 0)
+               set_lum(sd, data + i);
+
+       /* if more data, start a new frame */
+       i += 62;
+       if (i < len) {
+               data += i;
+               len -= i;
+               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                               sd->jpeg_hdr, JPEG_HDR_SZ);
+               gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+       }
 }
 
 static int sd_get_jcomp(struct gspca_dev *gspca_dev,
@@ -2891,10 +3000,10 @@ static const struct sd_desc sd_desc = {
        .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
        .get_jcomp = sd_get_jcomp,
-       .set_jcomp = sd_set_jcomp,
        .querymenu = sd_querymenu,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
@@ -3004,7 +3113,3 @@ static void __exit sd_mod_exit(void)
 
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
-
-module_param(starcam, int, 0644);
-MODULE_PARM_DESC(starcam,
-       "StarCam model. 0: Clip, 1: 370i");
index 7e06614292936b15576fbf3f669d62369fd1b025..abf1658fa33e9e4ca175e2f69a56ed9651d3e1ec 100644 (file)
@@ -525,11 +525,9 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
                          const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
 
        PDEBUG(D_PROBE, "Configuring camera");
 
-       cam = &gspca_dev->cam;
        sd->desc = sd_desc;
        sd->bridge = id->driver_info;
        gspca_dev->sd_desc = &sd->desc;
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c
new file mode 100644 (file)
index 0000000..84dfbab
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * gspca ViCam subdriver
+ *
+ * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the usbvideo vicam driver, which is:
+ *
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
+ *                    Christopher L Cheney (ccheney@cheney.cx),
+ *                    Pavel Machek (pavel@ucw.cz),
+ *                    John Tyner (jtyner@cs.ucr.edu),
+ *                    Monroe Williams (monroe@pobox.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
+ * 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
+ */
+
+#define MODULE_NAME "vicam"
+#define HEADER_SIZE 64
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/ihex.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+enum e_ctrl {
+       GAIN,
+       EXPOSURE,
+       NCTRL           /* number of controls */
+};
+
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct work_struct work_struct;
+       struct workqueue_struct *work_thread;
+       struct gspca_ctrl ctrls[NCTRL];
+};
+
+/* The vicam sensor has a resolution of 512 x 244, with I believe square
+   pixels, but this is forced to a 4:3 ratio by optics. So it has
+   non square pixels :( */
+static struct v4l2_pix_format vicam_mode[] = {
+       { 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 256,
+               .sizeimage = 256 * 122,
+               .colorspace = V4L2_COLORSPACE_SRGB,},
+       /* 2 modes with somewhat more square pixels */
+       { 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 256,
+               .sizeimage = 256 * 200,
+               .colorspace = V4L2_COLORSPACE_SRGB,},
+       { 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 256,
+               .sizeimage = 256 * 240,
+               .colorspace = V4L2_COLORSPACE_SRGB,},
+#if 0   /* This mode has extremely non square pixels, testing use only */
+       { 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 512,
+               .sizeimage = 512 * 122,
+               .colorspace = V4L2_COLORSPACE_SRGB,},
+#endif
+       { 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+               .bytesperline = 512,
+               .sizeimage = 512 * 244,
+               .colorspace = V4L2_COLORSPACE_SRGB,},
+};
+
+static const struct ctrl sd_ctrls[] = {
+[GAIN] = {
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+               .default_value = 200,
+           },
+       },
+[EXPOSURE] = {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+               .maximum = 2047,
+               .step    = 1,
+               .default_value = 256,
+           },
+       },
+};
+
+static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request,
+       u16 value, u16 index, u8 *data, u16 len)
+{
+       int ret;
+
+       ret = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             request,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             value, index, data, len, 1000);
+       if (ret < 0)
+               err("control msg req %02X error %d", request, ret);
+
+       return ret;
+}
+
+static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state)
+{
+       int ret;
+
+       ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0);
+       if (ret < 0)
+               return ret;
+
+       if (state)
+               ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0);
+
+       return ret;
+}
+
+/*
+ *  request and read a block of data - see warning on vicam_command.
+ */
+static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int ret, unscaled_height, act_len = 0;
+       u8 *req_data = gspca_dev->usb_buf;
+
+       memset(req_data, 0, 16);
+       req_data[0] = sd->ctrls[GAIN].val;
+       if (gspca_dev->width == 256)
+               req_data[1] |= 0x01; /* low nibble x-scale */
+       if (gspca_dev->height <= 122) {
+               req_data[1] |= 0x10; /* high nibble y-scale */
+               unscaled_height = gspca_dev->height * 2;
+       } else
+               unscaled_height = gspca_dev->height;
+       req_data[2] = 0x90; /* unknown, does not seem to do anything */
+       if (unscaled_height <= 200)
+               req_data[3] = 0x06; /* vend? */
+       else if (unscaled_height <= 242) /* Yes 242 not 240 */
+               req_data[3] = 0x07; /* vend? */
+       else /* Up to 244 lines with req_data[3] == 0x08 */
+               req_data[3] = 0x08; /* vend? */
+
+       if (sd->ctrls[EXPOSURE].val < 256) {
+               /* Frame rate maxed out, use partial frame expo time */
+               req_data[4] = 255 - sd->ctrls[EXPOSURE].val;
+               req_data[5] = 0x00;
+               req_data[6] = 0x00;
+               req_data[7] = 0x01;
+       } else {
+               /* Modify frame rate */
+               req_data[4] = 0x00;
+               req_data[5] = 0x00;
+               req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF;
+               req_data[7] = sd->ctrls[EXPOSURE].val >> 8;
+       }
+       req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */
+       /* bytes 9-15 do not seem to affect exposure or image quality */
+
+       mutex_lock(&gspca_dev->usb_lock);
+       ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16);
+       mutex_unlock(&gspca_dev->usb_lock);
+       if (ret < 0)
+               return ret;
+
+       ret = usb_bulk_msg(gspca_dev->dev,
+                          usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+                          data, size, &act_len, 10000);
+       /* successful, it returns 0, otherwise  negative */
+       if (ret < 0 || act_len != size) {
+               err("bulk read fail (%d) len %d/%d",
+                       ret, act_len, size);
+               return -EIO;
+       }
+       return 0;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface we take the gspca
+ * usb_lock when performing USB operations. In practice the only thing we need
+ * to protect against is the usb_set_interface call that gspca makes during
+ * stream_off as the camera doesn't provide any controls that the user could try
+ * to change.
+ */
+static void vicam_dostream(struct work_struct *work)
+{
+       struct sd *sd = container_of(work, struct sd, work_struct);
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+       int ret, frame_sz;
+       u8 *buffer;
+
+       frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage +
+                  HEADER_SIZE;
+       buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA);
+       if (!buffer) {
+               err("Couldn't allocate USB buffer");
+               goto exit;
+       }
+
+       while (gspca_dev->present && gspca_dev->streaming) {
+               ret = vicam_read_frame(gspca_dev, buffer, frame_sz);
+               if (ret < 0)
+                       break;
+
+               /* Note the frame header contents seem to be completely
+                  constant, they do not change with either image, or
+                  settings. So we simply discard it. The frames have
+                  a very similar 64 byte footer, which we don't even
+                  bother reading from the cam */
+               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                               buffer + HEADER_SIZE,
+                               frame_sz - HEADER_SIZE);
+               gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+       }
+exit:
+       kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+               const struct usb_device_id *id)
+{
+       struct cam *cam = &gspca_dev->cam;
+       struct sd *sd = (struct sd *)gspca_dev;
+
+       /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk = 1;
+       cam->bulk_size = 64;
+       cam->cam_mode = vicam_mode;
+       cam->nmodes = ARRAY_SIZE(vicam_mode);
+       cam->ctrls = sd->ctrls;
+
+       INIT_WORK(&sd->work_struct, vicam_dostream);
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       int ret;
+       const struct ihex_binrec *rec;
+       const struct firmware *uninitialized_var(fw);
+       u8 *firmware_buf;
+
+       ret = request_ihex_firmware(&fw, "vicam/firmware.fw",
+                                   &gspca_dev->dev->dev);
+       if (ret) {
+               err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
+               return ret;
+       }
+
+       firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!firmware_buf) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+       for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
+               memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len));
+               ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf,
+                                       be16_to_cpu(rec->len));
+               if (ret < 0)
+                       break;
+       }
+
+       kfree(firmware_buf);
+exit:
+       release_firmware(fw);
+       return ret;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int ret;
+
+       ret = vicam_set_camera_power(gspca_dev, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Start the workqueue function to do the streaming */
+       sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
+       queue_work(sd->work_thread, &sd->work_struct);
+
+       return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *dev = (struct sd *)gspca_dev;
+
+       /* wait for the work queue to terminate */
+       mutex_unlock(&gspca_dev->usb_lock);
+       /* This waits for vicam_dostream to finish */
+       destroy_workqueue(dev->work_thread);
+       dev->work_thread = NULL;
+       mutex_lock(&gspca_dev->usb_lock);
+
+       vicam_set_camera_power(gspca_dev, 0);
+}
+
+/* Table of supported USB devices */
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x04c1, 0x009d)},
+       {USB_DEVICE(0x0602, 0x1001)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name   = MODULE_NAME,
+       .ctrls  = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init   = sd_init,
+       .start  = sd_start,
+       .stop0  = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id,
+                       &sd_desc,
+                       sizeof(struct sd),
+                       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name       = MODULE_NAME,
+       .id_table   = device_table,
+       .probe      = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume  = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index bfb559c3b71383bde525291fa5b9b31ccab70b24..a1bd94e8ce5289418a6f86e0412888ff65e8baf7 100644 (file)
 #define ZC3XX_R1A6_YMEANAFTERAE        0x01a6
 #define ZC3XX_R1A7_CALCGLOBALMEAN      0x01a7
 
-#define ZC3XX_R1A2_BLUEMEANAFTERAGC    0x01a2
-
 /* Matrixes */
 
 /* Color matrix is like :
index 47236a58bf335f00419fed7a2b58b3fa02e5d4d3..fa164e861cde9b1107cd829db39666f4e2b21b9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Z-Star/Vimicro zc301/zc302p/vc30x library
  *
- * Copyright (C) 2009-2010 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
  * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
  *
  * This program is free software; you can redistribute it and/or modify
@@ -39,6 +39,7 @@ static int force_sensor = -1;
 enum e_ctrl {
        BRIGHTNESS,
        CONTRAST,
+       EXPOSURE,
        GAMMA,
        AUTOGAIN,
        LIGHTFREQ,
@@ -46,6 +47,8 @@ enum e_ctrl {
        NCTRLS          /* number of controls */
 };
 
+#define AUTOGAIN_DEF 1
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
@@ -73,7 +76,7 @@ enum sensors {
        SENSOR_CS2102K,
        SENSOR_GC0303,
        SENSOR_GC0305,
-       SENSOR_HDCS2020b,
+       SENSOR_HDCS2020,
        SENSOR_HV7131B,
        SENSOR_HV7131R,
        SENSOR_ICM105A,
@@ -92,7 +95,8 @@ enum sensors {
 
 /* V4L2 controls supported by the driver */
 static void setcontrast(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static void setlightfreq(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
 
@@ -121,6 +125,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
            },
            .set_control = setcontrast
        },
+[EXPOSURE] = {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0x30d,
+               .maximum        = 0x493e,
+               .step           = 1,
+               .default_value  = 0x927
+           },
+           .set_control = setexposure
+       },
 [GAMMA] = {
            {
                .id      = V4L2_CID_GAMMA,
@@ -141,9 +157,10 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-               .default_value = 1,
+               .default_value = AUTOGAIN_DEF,
+               .flags   = V4L2_CTRL_FLAG_UPDATE
            },
-           .set_control = setautogain
+           .set = sd_setautogain
        },
 [LIGHTFREQ] = {
            {
@@ -1498,7 +1515,7 @@ static const struct usb_action gc0305_NoFliker[] = {
        {}
 };
 
-static const struct usb_action hdcs2020b_InitialScale[] = {
+static const struct usb_action hdcs2020_InitialScale[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
        {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* qtable 0x05 */
@@ -1630,7 +1647,7 @@ static const struct usb_action hdcs2020b_InitialScale[] = {
        {0xa0, 0x40, ZC3XX_R118_BGAIN},
        {}
 };
-static const struct usb_action hdcs2020b_Initial[] = {
+static const struct usb_action hdcs2020_Initial[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
        {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -1758,7 +1775,7 @@ static const struct usb_action hdcs2020b_Initial[] = {
        {0xa0, 0x40, ZC3XX_R118_BGAIN},
        {}
 };
-static const struct usb_action hdcs2020b_50HZ[] = {
+static const struct usb_action hdcs2020_50HZ[] = {
        {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
        {0xaa, 0x13, 0x0018},                   /* 00,13,18,aa */
        {0xaa, 0x14, 0x0001},                   /* 00,14,01,aa */
@@ -1779,7 +1796,7 @@ static const struct usb_action hdcs2020b_50HZ[] = {
        {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */
        {}
 };
-static const struct usb_action hdcs2020b_60HZ[] = {
+static const struct usb_action hdcs2020_60HZ[] = {
        {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
        {0xaa, 0x13, 0x0031},                   /* 00,13,31,aa */
        {0xaa, 0x14, 0x0001},                   /* 00,14,01,aa */
@@ -1800,7 +1817,7 @@ static const struct usb_action hdcs2020b_60HZ[] = {
        {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */
        {}
 };
-static const struct usb_action hdcs2020b_NoFliker[] = {
+static const struct usb_action hdcs2020_NoFliker[] = {
        {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
        {0xaa, 0x13, 0x0010},                   /* 00,13,10,aa */
        {0xaa, 0x14, 0x0001},                   /* 00,14,01,aa */
@@ -2126,7 +2143,6 @@ static const struct usb_action hv7131r_Initial[] = {
        {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
        {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
        {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-
        {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
        {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
        {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
@@ -2878,7 +2894,7 @@ static const struct usb_action mc501cb_Initial[] = {
        {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
        {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
        {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
-       {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+       {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
        {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
        {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
        {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
@@ -2998,7 +3014,7 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
        {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
        {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
        {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
-       {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+       {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
        {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
        {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
        {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
@@ -3310,7 +3326,7 @@ static const struct usb_action ov7620_50HZ[] = {
        {0xaa, 0x10, 0x0082},                           /* 00,10,82,aa */
        {0xaa, 0x76, 0x0003},                           /* 00,76,03,aa */
 /*     {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},            * 00,02,40,cc
-                                                        if mode0 (640x480) */
+                                                        if mode0 (640x480) */
        {}
 };
 static const struct usb_action ov7620_60HZ[] = {
@@ -5828,7 +5844,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
                [SENSOR_CS2102K] =      NULL,
                [SENSOR_GC0303] =       gc0303_matrix,
                [SENSOR_GC0305] =       gc0305_matrix,
-               [SENSOR_HDCS2020b] =    NULL,
+               [SENSOR_HDCS2020] =     NULL,
                [SENSOR_HV7131B] =      NULL,
                [SENSOR_HV7131R] =      po2030_matrix,
                [SENSOR_ICM105A] =      po2030_matrix,
@@ -5927,6 +5943,26 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, gr[i], 0x0130 + i);    /* gradient */
 }
 
+static void getexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
+               | (i2c_read(gspca_dev, 0x26) << 1)
+               | (i2c_read(gspca_dev, 0x27) >> 7);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int val;
+
+       val = sd->ctrls[EXPOSURE].val;
+       i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
+       i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
+       i2c_write(gspca_dev, 0x27, val << 7, 0x00);
+}
+
 static void setquality(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -5990,10 +6026,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
                {gc0305_NoFliker, gc0305_NoFliker,
                 gc0305_50HZ, gc0305_50HZ,
                 gc0305_60HZ, gc0305_60HZ},
-       [SENSOR_HDCS2020b] =
-               {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
-                hdcs2020b_50HZ, hdcs2020b_50HZ,
-                hdcs2020b_60HZ, hdcs2020b_60HZ},
+       [SENSOR_HDCS2020] =
+               {hdcs2020_NoFliker, hdcs2020_NoFliker,
+                hdcs2020_50HZ, hdcs2020_50HZ,
+                hdcs2020_60HZ, hdcs2020_60HZ},
        [SENSOR_HV7131B] =
                {hv7131b_NoFliker, hv7131b_NoFlikerScale,
                 hv7131b_50HZ, hv7131b_50HZScale,
@@ -6091,7 +6127,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
 
 static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
 {
-       reg_w(gspca_dev, 0x01, 0x0000);         /* led off */
+       reg_w(gspca_dev, 0x01, 0x0000);         /* bridge reset */
        switch (sensor) {
        case SENSOR_PAS106:
                reg_w(gspca_dev, 0x03, 0x003a);
@@ -6310,6 +6346,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
                return 0x0a;                    /* PB0330 */
        }
 
+       /* probe gc0303 / gc0305 */
        reg_w(gspca_dev, 0x01, 0x0000);
        reg_w(gspca_dev, 0x01, 0x0001);
        reg_w(gspca_dev, 0x98, 0x008b);
@@ -6414,6 +6451,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
        gspca_dev->cam.ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
 
+       /* if USB 1.1, let some bandwidth for the audio device */
+       if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
+               gspca_dev->nbalt--;
+
        return 0;
 }
 
@@ -6429,7 +6470,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                [SENSOR_CS2102K] =      5,
                [SENSOR_GC0303] =       3,
                [SENSOR_GC0305] =       4,
-               [SENSOR_HDCS2020b] =    4,
+               [SENSOR_HDCS2020] =     4,
                [SENSOR_HV7131B] =      4,
                [SENSOR_HV7131R] =      4,
                [SENSOR_ICM105A] =      4,
@@ -6450,7 +6491,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                [SENSOR_CS2102K] =      1,
                [SENSOR_GC0303] =       1,
                [SENSOR_GC0305] =       1,
-               [SENSOR_HDCS2020b] =    1,
+               [SENSOR_HDCS2020] =     1,
                [SENSOR_HV7131B] =      1,
                [SENSOR_HV7131R] =      1,
                [SENSOR_ICM105A] =      1,
@@ -6513,8 +6554,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        sd->sensor = SENSOR_CS2102;
                        break;
                case 0x08:
-                       PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)");
-                       sd->sensor = SENSOR_HDCS2020b;
+                       PDEBUG(D_PROBE, "Find Sensor HDCS2020");
+                       sd->sensor = SENSOR_HDCS2020;
                        break;
                case 0x0a:
                        PDEBUG(D_PROBE,
@@ -6619,10 +6660,19 @@ static int sd_init(struct gspca_dev *gspca_dev)
        sd->ctrls[GAMMA].def = gamma[sd->sensor];
 
        switch (sd->sensor) {
+       case SENSOR_HV7131R:
+               break;
        case SENSOR_OV7630C:
-               gspca_dev->ctrl_dis = (1 << LIGHTFREQ);
+               gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
+               break;
+       default:
+               gspca_dev->ctrl_dis = (1 << EXPOSURE);
                break;
        }
+#if AUTOGAIN_DEF
+       if (sd->ctrls[AUTOGAIN].val)
+               gspca_dev->ctrl_inac = (1 << EXPOSURE);
+#endif
 
        /* switch off the led */
        reg_w(gspca_dev, 0x01, 0x0000);
@@ -6644,8 +6694,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                {gc0303_Initial, gc0303_InitialScale},
        [SENSOR_GC0305] =
                        {gc0305_Initial, gc0305_InitialScale},
-       [SENSOR_HDCS2020b] =
-                       {hdcs2020b_Initial, hdcs2020b_InitialScale},
+       [SENSOR_HDCS2020] =
+                       {hdcs2020_Initial, hdcs2020_InitialScale},
        [SENSOR_HV7131B] =
                        {hv7131b_Initial, hv7131b_InitialScale},
        [SENSOR_HV7131R] =
@@ -6739,7 +6789,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* set the gamma tables when not set */
        switch (sd->sensor) {
        case SENSOR_CS2102K:            /* gamma set in xxx_Initial */
-       case SENSOR_HDCS2020b:
+       case SENSOR_HDCS2020:
        case SENSOR_OV7630C:
                break;
        default:
@@ -6768,9 +6818,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x40, 0x0117);
                break;
        case SENSOR_HV7131R:
-               i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */
-               i2c_write(gspca_dev, 0x26, 0x93, 0x00);
-               i2c_write(gspca_dev, 0x27, 0xe0, 0x00);
+               if (!sd->ctrls[AUTOGAIN].val)
+                       setexposure(gspca_dev);
                reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
                break;
        case SENSOR_GC0305:
@@ -6848,6 +6897,23 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->ctrls[AUTOGAIN].val = val;
+       if (val) {
+               gspca_dev->ctrl_inac |= (1 << EXPOSURE);
+       } else {
+               gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
+               if (gspca_dev->streaming)
+                       getexposure(gspca_dev);
+       }
+       if (gspca_dev->streaming)
+               setautogain(gspca_dev);
+       return gspca_dev->usb_err;
+}
+
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
index e53fa55d56a1a9aea270c839c2bddc73c100e5f7..2a1ac287591db29fa94d87fdd9fd08b44e0decaf 100644 (file)
@@ -52,25 +52,36 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev)
        };
 
        /* Our default information for ir-kbd-i2c.c to use */
-       init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+       init_data->ir_codes = RC_MAP_HAUPPAUGE;
        init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
        init_data->type = RC_TYPE_RC5;
        init_data->name = "HD-PVR";
+       init_data->polling_interval = 405; /* ms, duplicated from Windows */
        hdpvr_ir_rx_i2c_board_info.platform_data = init_data;
 
        return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info);
 }
 
 static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
-                         unsigned char addr, char *data, int len)
+                         unsigned char addr, char *wdata, int wlen,
+                         char *data, int len)
 {
        int ret;
 
-       if (len > sizeof(dev->i2c_buf))
+       if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf)))
                return -EINVAL;
 
-       ret = usb_control_msg(dev->udev,
-                             usb_rcvctrlpipe(dev->udev, 0),
+       if (wlen) {
+               memcpy(&dev->i2c_buf, wdata, wlen);
+               ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+                                     REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
+                                     (bus << 8) | addr, 0, &dev->i2c_buf,
+                                     wlen, 1000);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_READ, CTRL_READ_REQUEST,
                              (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
 
@@ -92,16 +103,14 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
                return -EINVAL;
 
        memcpy(&dev->i2c_buf, data, len);
-       ret = usb_control_msg(dev->udev,
-                             usb_sndctrlpipe(dev->udev, 0),
+       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
                              (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
 
        if (ret < 0)
                return ret;
 
-       ret = usb_control_msg(dev->udev,
-                             usb_rcvctrlpipe(dev->udev, 0),
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                              REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
                              0, 0, &dev->i2c_buf, 2, 1000);
 
@@ -117,24 +126,49 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
                          int num)
 {
        struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
-       int retval = 0, i, addr;
+       int retval = 0, addr;
 
        if (num <= 0)
                return 0;
 
        mutex_lock(&dev->i2c_mutex);
 
-       for (i = 0; i < num && !retval; i++) {
-               addr = msgs[i].addr << 1;
+       addr = msgs[0].addr << 1;
 
-               if (msgs[i].flags & I2C_M_RD)
-                       retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf,
-                                               msgs[i].len);
+       if (num == 1) {
+               if (msgs[0].flags & I2C_M_RD)
+                       retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0,
+                                               msgs[0].buf, msgs[0].len);
                else
-                       retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf,
-                                                msgs[i].len);
+                       retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf,
+                                                msgs[0].len);
+       } else if (num == 2) {
+               if (msgs[0].addr != msgs[1].addr) {
+                       v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer "
+                                 "with conflicting target addresses\n");
+                       retval = -EINVAL;
+                       goto out;
+               }
+
+               if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) {
+                       v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with "
+                                 "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD,
+                                 msgs[1].flags & I2C_M_RD);
+                       retval = -EINVAL;
+                       goto out;
+               }
+
+               /*
+                * Write followed by atomic read is the only complex xfer that
+                * we actually support here.
+                */
+               retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len,
+                                       msgs[1].buf, msgs[1].len);
+       } else {
+               v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num);
        }
 
+out:
        mutex_unlock(&dev->i2c_mutex);
 
        return retval ? retval : num;
@@ -158,11 +192,11 @@ static struct i2c_adapter hdpvr_i2c_adapter_template = {
 
 static int hdpvr_activate_ir(struct hdpvr_device *dev)
 {
-       char buffer[8];
+       char buffer[2];
 
        mutex_lock(&dev->i2c_mutex);
 
-       hdpvr_i2c_read(dev, 0, 0x54, buffer, 1);
+       hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1);
 
        buffer[0] = 0;
        buffer[1] = 0x8;
index a221ad68b330c6b86ba5fb808532f587dc6eefb1..3ab875d036e10cdc1a530cffb75246a76bdc3d2f 100644 (file)
 static int debug;
 module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
-static int hauppauge;
-module_param(hauppauge, int, 0644);    /* Choose Hauppauge remote */
-MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
-
 
 #define MODULE_NAME "ir-kbd-i2c"
 #define dprintk(level, fmt, arg...)    if (debug >= level) \
@@ -105,10 +101,6 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
                /* invalid key press */
                return 0;
 
-       if (dev!=0x1e && dev!=0x1f)
-               /* not a hauppauge remote */
-               return 0;
-
        if (!range)
                code += 64;
 
@@ -116,7 +108,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
                start, range, toggle, dev, code);
 
        /* return key */
-       *ir_key = code;
+       *ir_key = (dev << 8) | code;
        *ir_raw = ircode;
        return 1;
 }
@@ -312,11 +304,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                name        = "Hauppauge";
                ir->get_key = get_key_haup;
                rc_type     = RC_TYPE_RC5;
-               if (hauppauge == 1) {
-                       ir_codes    = RC_MAP_HAUPPAUGE_NEW;
-               } else {
-                       ir_codes    = RC_MAP_RC5_TV;
-               }
+               ir_codes    = RC_MAP_HAUPPAUGE;
                break;
        case 0x30:
                name        = "KNC One";
@@ -340,7 +328,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                name        = "Hauppauge/Zilog Z8";
                ir->get_key = get_key_haup_xvr;
                rc_type     = RC_TYPE_RC5;
-               ir_codes    = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV;
+               ir_codes    = RC_MAP_HAUPPAUGE;
                break;
        }
 
index 04bacdbd10bbf6053fbb0e9ff162bfd12bf1d357..84bdf0f42a8eb81a3b4016869547e24cb2d46202 100644 (file)
@@ -383,7 +383,6 @@ struct ivtv_open_id {
        u32 open_id;                    /* unique ID for this file descriptor */
        int type;                       /* stream type */
        int yuv_frames;                 /* 1: started OUT_UDMA_YUV output mode */
-       enum v4l2_priority prio;        /* priority */
        struct ivtv *itv;
 };
 
@@ -710,7 +709,6 @@ struct ivtv {
 
        /* Miscellaneous */
        u32 open_id;                    /* incremented each time an open occurs, is >= 1 */
-       struct v4l2_prio_state prio;    /* priority state */
        int search_pack_header;         /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */
        int speed;                      /* current playback speed setting */
        u8 speed_mute_audio;            /* 1 if audio should be muted when fast forward */
index c57a58523ca8f57fdb66da2fe33516bd0f01fdee..a7f54b010a5c705e1fd0320b1f9aaaaf8ec8f7aa 100644 (file)
@@ -856,7 +856,6 @@ int ivtv_v4l2_close(struct file *filp)
 
        IVTV_DEBUG_FILE("close %s\n", s->name);
 
-       v4l2_prio_close(&itv->prio, id->prio);
        v4l2_fh_del(fh);
        v4l2_fh_exit(fh);
 
@@ -973,7 +972,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
        }
        item->itv = itv;
        item->type = s->type;
-       v4l2_prio_open(&itv->prio, &item->prio);
 
        item->open_id = itv->open_id++;
        filp->private_data = &item->fh;
@@ -982,6 +980,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                /* Try to claim this stream */
                if (ivtv_claim_stream(item, item->type)) {
                        /* No, it's already in use */
+                       v4l2_fh_exit(&item->fh);
                        kfree(item);
                        return -EBUSY;
                }
index 9fb86a081c0fe43f9f0f891ba7b3c47eb009b377..d47f41a0ef66482dde6eec7437120b8ec462862e 100644 (file)
@@ -205,15 +205,14 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
                break;
        case IVTV_HW_I2C_IR_RX_HAUP_EXT:
        case IVTV_HW_I2C_IR_RX_HAUP_INT:
-               /* Default to old black remote */
-               init_data->ir_codes = RC_MAP_RC5_TV;
+               init_data->ir_codes = RC_MAP_HAUPPAUGE;
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
                init_data->type = RC_TYPE_RC5;
                init_data->name = itv->card_name;
                break;
        case IVTV_HW_Z8F0811_IR_RX_HAUP:
                /* Default to grey remote */
-               init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+               init_data->ir_codes = RC_MAP_HAUPPAUGE;
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
                init_data->type = RC_TYPE_RC5;
                init_data->name = itv->card_name;
index b686da5e432661390d3dfcc1a42c5d3726761675..1689783cd19aa81261147b35870a485eb16736aa 100644 (file)
@@ -313,7 +313,7 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
 
 static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 
        vbifmt->reserved[0] = 0;
@@ -334,7 +334,7 @@ static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo
 
 static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
@@ -358,7 +358,7 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 
 static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
 
        vbifmt->sampling_rate = 27000000;
@@ -377,7 +377,7 @@ static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
 static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
        vbifmt->reserved[0] = 0;
@@ -398,7 +398,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
 
 static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
@@ -439,7 +439,7 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
 
 static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        struct v4l2_window *winfmt = &fmt->fmt.win;
 
        if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
@@ -463,7 +463,7 @@ static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_
 
 static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        int w = fmt->fmt.pix.width;
        int h = fmt->fmt.pix.height;
@@ -492,7 +492,7 @@ static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format
 static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
        if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
@@ -512,7 +512,7 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_
 
 static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        s32 w = fmt->fmt.pix.width;
        s32 h = fmt->fmt.pix.height;
        int field = fmt->fmt.pix.field;
@@ -546,7 +546,7 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format
 
 static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        u32 chromakey = fmt->fmt.win.chromakey;
        u8 global_alpha = fmt->fmt.win.global_alpha;
 
@@ -565,7 +565,7 @@ static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo
 
 static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct v4l2_mbus_framefmt mbus_fmt;
        int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
@@ -594,7 +594,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 
 static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
                return -EBUSY;
@@ -607,7 +607,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
 static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
 {
        struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
 
@@ -625,7 +625,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
 
 static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
        int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
@@ -670,7 +670,7 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
 
 static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
 
        if (ret == 0) {
@@ -683,7 +683,7 @@ static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f
 
 static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        chip->ident = V4L2_IDENT_NONE;
        chip->revision = 0;
@@ -727,7 +727,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 
 static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (v4l2_chip_match_host(&reg->match))
                return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
@@ -739,7 +739,7 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register
 
 static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (v4l2_chip_match_host(&reg->match))
                return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
@@ -750,26 +750,9 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register
 }
 #endif
 
-static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
-{
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
-
-       *p = v4l2_prio_max(&itv->prio);
-
-       return 0;
-}
-
-static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
-{
-       struct ivtv_open_id *id = fh;
-       struct ivtv *itv = id->itv;
-
-       return v4l2_prio_change(&itv->prio, &id->prio, prio);
-}
-
 static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
@@ -781,14 +764,14 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
 
 static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        return ivtv_get_audio_input(itv, vin->index, vin);
 }
 
 static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        vin->index = itv->audio_input;
        return ivtv_get_audio_input(itv, vin->index, vin);
@@ -796,7 +779,7 @@ static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
 
 static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (vout->index >= itv->nof_audio_inputs)
                return -EINVAL;
@@ -809,7 +792,7 @@ static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
 
 static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        /* set it to defaults from our table */
        return ivtv_get_audio_output(itv, vin->index, vin);
@@ -817,7 +800,7 @@ static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vi
 
 static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        vin->index = 0;
        return ivtv_get_audio_output(itv, vin->index, vin);
@@ -825,14 +808,14 @@ static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
 
 static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        return ivtv_get_audio_output(itv, vout->index, vout);
 }
 
 static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        /* set it to defaults from our table */
        return ivtv_get_input(itv, vin->index, vin);
@@ -840,14 +823,14 @@ static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
 
 static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        return ivtv_get_output(itv, vout->index, vout);
 }
 
 static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
        int streamtype;
@@ -884,7 +867,7 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca
 
 static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
        int streamtype;
@@ -910,7 +893,7 @@ static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
 static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
        int streamtype;
@@ -952,7 +935,7 @@ static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes
 
 static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        static struct v4l2_fmtdesc formats[] = {
                { 0, 0, 0,
@@ -980,7 +963,7 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes
 
 static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        *i = itv->active_input;
 
@@ -989,7 +972,7 @@ static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
 
 int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (inp < 0 || inp >= itv->nof_inputs)
                return -EINVAL;
@@ -1023,7 +1006,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
 
 static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                return -EINVAL;
@@ -1035,7 +1018,7 @@ static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
 
 static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (outp >= itv->card->nof_outputs)
                return -EINVAL;
@@ -1057,7 +1040,7 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
 
 static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (vf->tuner != 0)
                return -EINVAL;
@@ -1068,7 +1051,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
 
 int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (vf->tuner != 0)
                return -EINVAL;
@@ -1082,7 +1065,7 @@ int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
 static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        *std = itv->std;
        return 0;
@@ -1091,7 +1074,7 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
 int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
 {
        DEFINE_WAIT(wait);
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
        int f;
 
@@ -1170,7 +1153,7 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
 
 static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
        if (vt->index != 0)
@@ -1183,7 +1166,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 
 static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        if (vt->index != 0)
                return -EINVAL;
@@ -1203,7 +1186,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 
 static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
        int f, l;
 
@@ -1233,7 +1216,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced
 
 static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        struct v4l2_enc_idx_entry *e = idx->entry;
        int entries;
        int i;
@@ -1256,7 +1239,7 @@ static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *id
 
 static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
 
@@ -1308,7 +1291,7 @@ static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd
 
 static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
 
        switch (enc->cmd) {
        case V4L2_ENC_CMD_START:
@@ -1338,7 +1321,7 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder
 
 static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        u32 data[CX2341X_MBOX_MAX_DATA];
        struct yuv_playback_info *yi = &itv->yuv_info;
 
@@ -1425,7 +1408,7 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
 
 static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
 
@@ -1445,7 +1428,7 @@ static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
 
 static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
 {
-       struct ivtv_open_id *id = fh;
+       struct ivtv_open_id *id = fh2id(fh);
        struct ivtv *itv = id->itv;
 
        if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
@@ -1470,7 +1453,7 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti
 
 static int ivtv_log_status(struct file *file, void *fh)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
        u32 data[CX2341X_MBOX_MAX_DATA];
 
        int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
@@ -1795,9 +1778,25 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        return 0;
 }
 
-static long ivtv_default(struct file *file, void *fh, int cmd, void *arg)
+static long ivtv_default(struct file *file, void *fh, bool valid_prio,
+                        int cmd, void *arg)
 {
-       struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+       struct ivtv *itv = fh2id(fh)->itv;
+
+       if (!valid_prio) {
+               switch (cmd) {
+               case VIDEO_PLAY:
+               case VIDEO_STOP:
+               case VIDEO_FREEZE:
+               case VIDEO_CONTINUE:
+               case VIDEO_COMMAND:
+               case VIDEO_SELECT_SOURCE:
+               case AUDIO_SET_MUTE:
+               case AUDIO_CHANNEL_SELECT:
+               case AUDIO_BILINGUAL_CHANNEL_SELECT:
+                       return -EBUSY;
+               }
+       }
 
        switch (cmd) {
        case VIDIOC_INT_RESET: {
@@ -1836,30 +1835,8 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
                unsigned int cmd, unsigned long arg)
 {
        struct video_device *vfd = video_devdata(filp);
-       struct ivtv_open_id *id = fh2id(filp->private_data);
        long ret;
 
-       /* check priority */
-       switch (cmd) {
-       case VIDIOC_S_CTRL:
-       case VIDIOC_S_STD:
-       case VIDIOC_S_INPUT:
-       case VIDIOC_S_OUTPUT:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_S_FMT:
-       case VIDIOC_S_CROP:
-       case VIDIOC_S_AUDIO:
-       case VIDIOC_S_AUDOUT:
-       case VIDIOC_S_EXT_CTRLS:
-       case VIDIOC_S_FBUF:
-       case VIDIOC_S_PRIORITY:
-       case VIDIOC_OVERLAY:
-               ret = v4l2_prio_check(&itv->prio, id->prio);
-               if (ret)
-                       return ret;
-       }
-
        if (ivtv_debug & IVTV_DBGFLG_IOCTL)
                vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
        ret = video_ioctl2(filp, cmd, arg);
@@ -1884,8 +1861,6 @@ long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
 static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_querycap                    = ivtv_querycap,
-       .vidioc_g_priority                  = ivtv_g_priority,
-       .vidioc_s_priority                  = ivtv_s_priority,
        .vidioc_s_audio                     = ivtv_s_audio,
        .vidioc_g_audio                     = ivtv_g_audio,
        .vidioc_enumaudio                   = ivtv_enumaudio,
index 512607e0cda367d401a291465e51536d46378793..942683336555e02311c6d0b1d63acdab633fc777 100644 (file)
@@ -214,6 +214,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        s->vdev->fops = ivtv_stream_info[type].fops;
        s->vdev->release = video_device_release;
        s->vdev->tvnorms = V4L2_STD_ALL;
+       set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
        ivtv_set_funcs(s->vdev);
        return 0;
 }
index 1daf1dd65bf764d080db02f390ff9cc709c7c6c0..69cc8166b20becc3a59dfbcd0955eecf53032cd7 100644 (file)
@@ -132,7 +132,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
        if (user_dma.page_count != err) {
                IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
                           err, user_dma.page_count);
-               return -EINVAL;
+               if (err >= 0) {
+                       for (i = 0; i < err; i++)
+                               put_page(dma->map[i]);
+                       return -EINVAL;
+               }
+               return err;
        }
 
        dma->page_count = user_dma.page_count;
index 2dfa957b0fd5c3dc03d8c69e6e6cfbcc7d906bfc..b6eb51ce773503ad60031b999934253edbc39d67 100644 (file)
@@ -174,7 +174,7 @@ ivtv_write_vbi_from_user(struct ivtv *itv,
                        ret = -EFAULT;
                        break;
                }
-               ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+               ivtv_write_vbi_line(itv, &d, &cc, &found_cc);
        }
 
        if (found_cc)
index c0875378acc2ffa372426c8ea05ed8497cddd7a8..dcbab6ad4c26ee8843336f673aeb1f9f7fe7ef80 100644 (file)
@@ -77,23 +77,51 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
        /* Get user pages for DMA Xfer */
        down_read(&current->mm->mmap_sem);
        y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
-       uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
+       uv_pages = 0; /* silence gcc. value is set and consumed only if: */
+       if (y_pages == y_dma.page_count) {
+               uv_pages = get_user_pages(current, current->mm,
+                                         uv_dma.uaddr, uv_dma.page_count, 0, 1,
+                                         &dma->map[y_pages], NULL);
+       }
        up_read(&current->mm->mmap_sem);
 
-       dma->page_count = y_dma.page_count + uv_dma.page_count;
-
-       if (y_pages + uv_pages != dma->page_count) {
-               IVTV_DEBUG_WARN
-                   ("failed to map user pages, returned %d instead of %d\n",
-                    y_pages + uv_pages, dma->page_count);
-
-               for (i = 0; i < dma->page_count; i++) {
-                       put_page(dma->map[i]);
+       if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
+               int rc = -EFAULT;
+
+               if (y_pages == y_dma.page_count) {
+                       IVTV_DEBUG_WARN
+                               ("failed to map uv user pages, returned %d "
+                                "expecting %d\n", uv_pages, uv_dma.page_count);
+
+                       if (uv_pages >= 0) {
+                               for (i = 0; i < uv_pages; i++)
+                                       put_page(dma->map[y_pages + i]);
+                               rc = -EFAULT;
+                       } else {
+                               rc = uv_pages;
+                       }
+               } else {
+                       IVTV_DEBUG_WARN
+                               ("failed to map y user pages, returned %d "
+                                "expecting %d\n", y_pages, y_dma.page_count);
                }
-               dma->page_count = 0;
-               return -EINVAL;
+               if (y_pages >= 0) {
+                       for (i = 0; i < y_pages; i++)
+                               put_page(dma->map[i]);
+                       /*
+                        * Inherit the -EFAULT from rc's
+                        * initialization, but allow it to be
+                        * overriden by uv_pages above if it was an
+                        * actual errno.
+                        */
+               } else {
+                       rc = y_pages;
+               }
+               return rc;
        }
 
+       dma->page_count = y_pages + uv_pages;
+
        /* Fill & map SG List */
        if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
                IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
index e7e717800ee26f5beca36d03cded34d27b76c478..b03d74e09a3c1083f226942e7b82f708797a38fc 100644 (file)
@@ -8,7 +8,7 @@
  * operation (via the mem2mem framework).
  *
  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * Pawel Osciak, <p.osciak@samsung.com>
+ * Pawel Osciak, <pawel@osciak.com>
  * Marek Szyprowski, <m.szyprowski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 
 #define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
 
 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
-MODULE_AUTHOR("Pawel Osciak, <p.osciak@samsung.com>");
+MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
 MODULE_LICENSE("GPL");
 
 
@@ -201,11 +201,6 @@ struct m2mtest_ctx {
        struct v4l2_m2m_ctx     *m2m_ctx;
 };
 
-struct m2mtest_buffer {
-       /* vb must be first! */
-       struct videobuf_buffer  vb;
-};
-
 static struct v4l2_queryctrl *get_ctrl(int id)
 {
        int i;
@@ -219,37 +214,41 @@ static struct v4l2_queryctrl *get_ctrl(int id)
 }
 
 static int device_process(struct m2mtest_ctx *ctx,
-                         struct m2mtest_buffer *in_buf,
-                         struct m2mtest_buffer *out_buf)
+                         struct vb2_buffer *in_vb,
+                         struct vb2_buffer *out_vb)
 {
        struct m2mtest_dev *dev = ctx->dev;
+       struct m2mtest_q_data *q_data;
        u8 *p_in, *p_out;
        int x, y, t, w;
        int tile_w, bytes_left;
-       struct videobuf_queue *src_q;
-       struct videobuf_queue *dst_q;
+       int width, height, bytesperline;
 
-       src_q = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
-       dst_q = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
-       p_in = videobuf_queue_to_vaddr(src_q, &in_buf->vb);
-       p_out = videobuf_queue_to_vaddr(dst_q, &out_buf->vb);
+       q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+       width   = q_data->width;
+       height  = q_data->height;
+       bytesperline    = (q_data->width * q_data->fmt->depth) >> 3;
+
+       p_in = vb2_plane_vaddr(in_vb, 0);
+       p_out = vb2_plane_vaddr(out_vb, 0);
        if (!p_in || !p_out) {
                v4l2_err(&dev->v4l2_dev,
                         "Acquiring kernel pointers to buffers failed\n");
                return -EFAULT;
        }
 
-       if (in_buf->vb.size > out_buf->vb.size) {
+       if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) {
                v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
                return -EINVAL;
        }
 
-       tile_w = (in_buf->vb.width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
+       tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3))
                / MEM2MEM_NUM_TILES;
-       bytes_left = in_buf->vb.bytesperline - tile_w * MEM2MEM_NUM_TILES;
+       bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
        w = 0;
 
-       for (y = 0; y < in_buf->vb.height; ++y) {
+       for (y = 0; y < height; ++y) {
                for (t = 0; t < MEM2MEM_NUM_TILES; ++t) {
                        if (w & 0x1) {
                                for (x = 0; x < tile_w; ++x)
@@ -301,6 +300,21 @@ static void job_abort(void *priv)
        ctx->aborting = 1;
 }
 
+static void m2mtest_lock(void *priv)
+{
+       struct m2mtest_ctx *ctx = priv;
+       struct m2mtest_dev *dev = ctx->dev;
+       mutex_lock(&dev->dev_mutex);
+}
+
+static void m2mtest_unlock(void *priv)
+{
+       struct m2mtest_ctx *ctx = priv;
+       struct m2mtest_dev *dev = ctx->dev;
+       mutex_unlock(&dev->dev_mutex);
+}
+
+
 /* device_run() - prepares and starts the device
  *
  * This simulates all the immediate preparations required before starting
@@ -311,7 +325,7 @@ static void device_run(void *priv)
 {
        struct m2mtest_ctx *ctx = priv;
        struct m2mtest_dev *dev = ctx->dev;
-       struct m2mtest_buffer *src_buf, *dst_buf;
+       struct vb2_buffer *src_buf, *dst_buf;
 
        src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
        dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
@@ -322,12 +336,11 @@ static void device_run(void *priv)
        schedule_irq(dev, ctx->transtime);
 }
 
-
 static void device_isr(unsigned long priv)
 {
        struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
        struct m2mtest_ctx *curr_ctx;
-       struct m2mtest_buffer *src_buf, *dst_buf;
+       struct vb2_buffer *src_vb, *dst_vb;
        unsigned long flags;
 
        curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
@@ -338,31 +351,26 @@ static void device_isr(unsigned long priv)
                return;
        }
 
-       src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
-       dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
        curr_ctx->num_processed++;
 
+       spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
+       v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+       v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+       spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
+
        if (curr_ctx->num_processed == curr_ctx->translen
            || curr_ctx->aborting) {
                dprintk(curr_ctx->dev, "Finishing transaction\n");
                curr_ctx->num_processed = 0;
-               spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
-               src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
-               wake_up(&src_buf->vb.done);
-               wake_up(&dst_buf->vb.done);
-               spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
                v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
        } else {
-               spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
-               src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
-               wake_up(&src_buf->vb.done);
-               wake_up(&dst_buf->vb.done);
-               spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
                device_run(curr_ctx);
        }
 }
 
-
 /*
  * video ioctls
  */
@@ -423,7 +431,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
 
 static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
        struct m2mtest_q_data *q_data;
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
@@ -434,7 +442,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 
        f->fmt.pix.width        = q_data->width;
        f->fmt.pix.height       = q_data->height;
-       f->fmt.pix.field        = vq->field;
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
        f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
        f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
        f->fmt.pix.sizeimage    = q_data->sizeimage;
@@ -523,7 +531,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
 static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
 {
        struct m2mtest_q_data *q_data;
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
 
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
        if (!vq)
@@ -533,7 +541,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
        if (!q_data)
                return -EINVAL;
 
-       if (videobuf_queue_is_busy(vq)) {
+       if (vb2_is_busy(vq)) {
                v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
                return -EBUSY;
        }
@@ -543,7 +551,6 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
        q_data->height          = f->fmt.pix.height;
        q_data->sizeimage       = q_data->width * q_data->height
                                * q_data->fmt->depth >> 3;
-       vq->field               = f->fmt.pix.field;
 
        dprintk(ctx->dev,
                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
@@ -733,120 +740,94 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
  * Queue operations
  */
 
-static void m2mtest_buf_release(struct videobuf_queue *vq,
-                               struct videobuf_buffer *vb)
-{
-       struct m2mtest_ctx *ctx = vq->priv_data;
-
-       dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
-               vq->type, vb->i, vb->state);
-
-       videobuf_vmalloc_free(vb);
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int m2mtest_buf_setup(struct videobuf_queue *vq, unsigned int *count,
-                         unsigned int *size)
+static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
 {
-       struct m2mtest_ctx *ctx = vq->priv_data;
+       struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
        struct m2mtest_q_data *q_data;
+       unsigned int size, count = *nbuffers;
 
        q_data = get_q_data(vq->type);
 
-       *size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
-       dprintk(ctx->dev, "size:%d, w/h %d/%d, depth: %d\n",
-               *size, q_data->width, q_data->height, q_data->fmt->depth);
+       size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
 
-       if (0 == *count)
-               *count = MEM2MEM_DEF_NUM_BUFS;
+       while (size * count > MEM2MEM_VID_MEM_LIMIT)
+               (count)--;
 
-       while (*size * *count > MEM2MEM_VID_MEM_LIMIT)
-               (*count)--;
+       *nplanes = 1;
+       *nbuffers = count;
+       sizes[0] = size;
 
-       v4l2_info(&ctx->dev->v4l2_dev,
-                 "%d buffers of size %d set up.\n", *count, *size);
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
 
        return 0;
 }
 
-static int m2mtest_buf_prepare(struct videobuf_queue *vq,
-                              struct videobuf_buffer *vb,
-                              enum v4l2_field field)
+static int m2mtest_buf_prepare(struct vb2_buffer *vb)
 {
-       struct m2mtest_ctx *ctx = vq->priv_data;
+       struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
        struct m2mtest_q_data *q_data;
-       int ret;
 
-       dprintk(ctx->dev, "type: %d, index: %d, state: %d\n",
-               vq->type, vb->i, vb->state);
+       dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
 
-       q_data = get_q_data(vq->type);
+       q_data = get_q_data(vb->vb2_queue->type);
 
-       if (vb->baddr) {
-               /* User-provided buffer */
-               if (vb->bsize < q_data->sizeimage) {
-                       /* Buffer too small to fit a frame */
-                       v4l2_err(&ctx->dev->v4l2_dev,
-                                "User-provided buffer too small\n");
-                       return -EINVAL;
-               }
-       } else if (vb->state != VIDEOBUF_NEEDS_INIT
-                       && vb->bsize < q_data->sizeimage) {
-               /* We provide the buffer, but it's already been initialized
-                * and is too small */
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
                return -EINVAL;
        }
 
-       vb->width       = q_data->width;
-       vb->height      = q_data->height;
-       vb->bytesperline = (q_data->width * q_data->fmt->depth) >> 3;
-       vb->size        = q_data->sizeimage;
-       vb->field       = field;
-
-       if (VIDEOBUF_NEEDS_INIT == vb->state) {
-               ret = videobuf_iolock(vq, vb, NULL);
-               if (ret) {
-                       v4l2_err(&ctx->dev->v4l2_dev,
-                                "Iolock failed\n");
-                       goto fail;
-               }
-       }
-
-       vb->state = VIDEOBUF_PREPARED;
+       vb2_set_plane_payload(vb, 0, q_data->sizeimage);
 
        return 0;
-fail:
-       m2mtest_buf_release(vq, vb);
-       return ret;
 }
 
-static void m2mtest_buf_queue(struct videobuf_queue *vq,
-                          struct videobuf_buffer *vb)
+static void m2mtest_buf_queue(struct vb2_buffer *vb)
 {
-       struct m2mtest_ctx *ctx = vq->priv_data;
-
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+       struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
 }
 
-static struct videobuf_queue_ops m2mtest_qops = {
-       .buf_setup      = m2mtest_buf_setup,
-       .buf_prepare    = m2mtest_buf_prepare,
-       .buf_queue      = m2mtest_buf_queue,
-       .buf_release    = m2mtest_buf_release,
+static struct vb2_ops m2mtest_qops = {
+       .queue_setup     = m2mtest_queue_setup,
+       .buf_prepare     = m2mtest_buf_prepare,
+       .buf_queue       = m2mtest_buf_queue,
 };
 
-static void queue_init(void *priv, struct videobuf_queue *vq,
-                      enum v4l2_buf_type type)
+static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 {
        struct m2mtest_ctx *ctx = priv;
-       struct m2mtest_dev *dev = ctx->dev;
+       int ret;
 
-       videobuf_queue_vmalloc_init(vq, &m2mtest_qops, dev->v4l2_dev.dev,
-                                   &dev->irqlock, type, V4L2_FIELD_NONE,
-                                   sizeof(struct m2mtest_buffer), priv,
-                                   &dev->dev_mutex);
-}
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_MMAP;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->ops = &m2mtest_qops;
+       src_vq->mem_ops = &vb2_vmalloc_memops;
 
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_MMAP;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &m2mtest_qops;
+       dst_vq->mem_ops = &vb2_vmalloc_memops;
+
+       return vb2_queue_init(dst_vq);
+}
 
 /*
  * File operations
@@ -866,7 +847,8 @@ static int m2mtest_open(struct file *file)
        ctx->transtime = MEM2MEM_DEF_TRANSTIME;
        ctx->num_processed = 0;
 
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, dev->m2m_dev, queue_init);
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
        if (IS_ERR(ctx->m2m_ctx)) {
                int ret = PTR_ERR(ctx->m2m_ctx);
 
@@ -932,6 +914,8 @@ static struct v4l2_m2m_ops m2m_ops = {
        .device_run     = device_run,
        .job_ready      = job_ready,
        .job_abort      = job_abort,
+       .lock           = m2mtest_lock,
+       .unlock         = m2mtest_unlock,
 };
 
 static int m2mtest_probe(struct platform_device *pdev)
@@ -990,6 +974,7 @@ static int m2mtest_probe(struct platform_device *pdev)
 
        return 0;
 
+       v4l2_m2m_release(dev->m2m_dev);
 err_m2m:
        video_unregister_device(dev->vfd);
 rel_vdev:
index 48d2c2419c13134abf0c55cdf347bdfd97c897bd..b09a3c80a15e3ce41e3e73cb55faf7f6b22c7f82 100644 (file)
@@ -1547,7 +1547,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
        return 0;
 }
 
-static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+static long vidioc_default(struct file *file, void *fh, bool valid_prio,
+                                               int cmd, void *arg)
 {
        switch (cmd) {
        case MEYEIOC_G_PARAMS:
index f7fc88d240e6e5bf56f3eb9b4fba1e72ecd9bf36..e2bbd8c35c9860a9ad1bd16d0ded17df64fae1ca 100644 (file)
@@ -79,7 +79,7 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
 static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
        /* Order important - see above */
        {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
 };
 
 struct mt9m001 {
index 6a784c87e5ffb1434297b1aa7d589a9f066a84ac..e313d83900922a8a9df8020f54d69e69c56e3bd4 100644 (file)
@@ -95,7 +95,7 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
 static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
        /* Order important - see above */
        {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
-       {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
+       {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
 };
 
 struct mt9v022 {
@@ -392,7 +392,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
         * icd->try_fmt(), datawidth is from our supported format list
         */
        switch (mf->code) {
-       case V4L2_MBUS_FMT_GREY8_1X8:
+       case V4L2_MBUS_FMT_Y8_1X8:
        case V4L2_MBUS_FMT_Y10_1X10:
                if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
                        return -EINVAL;
index b9cb4a436959b8bd82b535b87d326546f134069c..502e2a40964c1e5f372948988cbd82f710ca4135 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 
 
 #define MAX_VIDEO_MEM 16
 
+enum csi_buffer_state {
+       CSI_BUF_NEEDS_INIT,
+       CSI_BUF_PREPARED,
+};
+
 struct mx3_camera_buffer {
        /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer                  vb;
-       enum v4l2_mbus_pixelcode                code;
+       struct vb2_buffer                       vb;
+       enum csi_buffer_state                   state;
+       struct list_head                        queue;
 
        /* One descriptot per scatterlist (per frame) */
        struct dma_async_tx_descriptor          *txd;
@@ -108,6 +114,9 @@ struct mx3_camera_dev {
        struct list_head        capture;
        spinlock_t              lock;           /* Protects video buffer lists */
        struct mx3_camera_buffer *active;
+       struct vb2_alloc_ctx    *alloc_ctx;
+       enum v4l2_field         field;
+       int                     sequence;
 
        /* IDMAC / dmaengine interface */
        struct idmac_channel    *idmac_channel[1];      /* We need one channel */
@@ -130,6 +139,11 @@ static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
        __raw_writel(value, mx3->base + reg);
 }
 
+static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb)
+{
+       return container_of(vb, struct mx3_camera_buffer, vb);
+}
+
 /* Called from the IPU IDMAC ISR */
 static void mx3_cam_dma_done(void *arg)
 {
@@ -137,20 +151,20 @@ static void mx3_cam_dma_done(void *arg)
        struct dma_chan *chan = desc->txd.chan;
        struct idmac_channel *ichannel = to_idmac_chan(chan);
        struct mx3_camera_dev *mx3_cam = ichannel->client;
-       struct videobuf_buffer *vb;
 
        dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
                desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
 
        spin_lock(&mx3_cam->lock);
        if (mx3_cam->active) {
-               vb = &mx3_cam->active->vb;
-
-               list_del_init(&vb->queue);
-               vb->state = VIDEOBUF_DONE;
-               do_gettimeofday(&vb->ts);
-               vb->field_count++;
-               wake_up(&vb->done);
+               struct vb2_buffer *vb = &mx3_cam->active->vb;
+               struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+
+               list_del_init(&buf->queue);
+               do_gettimeofday(&vb->v4l2_buf.timestamp);
+               vb->v4l2_buf.field = mx3_cam->field;
+               vb->v4l2_buf.sequence = mx3_cam->sequence++;
+               vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
        }
 
        if (list_empty(&mx3_cam->capture)) {
@@ -165,50 +179,22 @@ static void mx3_cam_dma_done(void *arg)
        }
 
        mx3_cam->active = list_entry(mx3_cam->capture.next,
-                                    struct mx3_camera_buffer, vb.queue);
-       mx3_cam->active->vb.state = VIDEOBUF_ACTIVE;
+                                    struct mx3_camera_buffer, queue);
        spin_unlock(&mx3_cam->lock);
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf)
-{
-       struct soc_camera_device *icd = vq->priv_data;
-       struct videobuf_buffer *vb = &buf->vb;
-       struct dma_async_tx_descriptor *txd = buf->txd;
-       struct idmac_channel *ichan;
-
-       BUG_ON(in_interrupt());
-
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
-
-       /*
-        * This waits until this buffer is out of danger, i.e., until it is no
-        * longer in STATE_QUEUED or STATE_ACTIVE
-        */
-       videobuf_waiton(vq, vb, 0, 0);
-       if (txd) {
-               ichan = to_idmac_chan(txd->chan);
-               async_tx_ack(txd);
-       }
-       videobuf_dma_contig_free(vq, vb);
-       buf->txd = NULL;
-
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
 /*
  * Videobuf operations
  */
 
 /*
  * Calculate the __buffer__ (not data) size and number of buffers.
- * Called with .vb_lock held
  */
-static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
-                             unsigned int *size)
+static int mx3_videobuf_setup(struct vb2_queue *vq,
+                       unsigned int *count, unsigned int *num_planes,
+                       unsigned long sizes[], void *alloc_ctxs[])
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
@@ -220,162 +206,133 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (!mx3_cam->idmac_channel[0])
                return -EINVAL;
 
-       *size = bytes_per_line * icd->user_height;
+       *num_planes = 1;
+
+       mx3_cam->sequence = 0;
+       sizes[0] = bytes_per_line * icd->user_height;
+       alloc_ctxs[0] = mx3_cam->alloc_ctx;
 
        if (!*count)
                *count = 32;
 
-       if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
-               *count = MAX_VIDEO_MEM * 1024 * 1024 / *size;
+       if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+               *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0];
 
        return 0;
 }
 
-/* Called with .vb_lock held */
-static int mx3_videobuf_prepare(struct videobuf_queue *vq,
-               struct videobuf_buffer *vb, enum v4l2_field field)
+static int mx3_videobuf_prepare(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
-       struct mx3_camera_buffer *buf =
-               container_of(vb, struct mx3_camera_buffer, vb);
+       struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+       struct scatterlist *sg;
+       struct mx3_camera_buffer *buf;
        size_t new_size;
-       int ret;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
 
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       new_size = bytes_per_line * icd->user_height;
+       buf = to_mx3_vb(vb);
+       sg = &buf->sg;
 
-       /*
-        * I think, in buf_prepare you only have to protect global data,
-        * the actual buffer is yours
-        */
-
-       if (buf->code   != icd->current_fmt->code ||
-           vb->width   != icd->user_width ||
-           vb->height  != icd->user_height ||
-           vb->field   != field) {
-               buf->code       = icd->current_fmt->code;
-               vb->width       = icd->user_width;
-               vb->height      = icd->user_height;
-               vb->field       = field;
-               if (vb->state != VIDEOBUF_NEEDS_INIT)
-                       free_buffer(vq, buf);
-       }
+       new_size = bytes_per_line * icd->user_height;
 
-       if (vb->baddr && vb->bsize < new_size) {
-               /* User provided buffer, but it is too small */
-               ret = -ENOMEM;
-               goto out;
+       if (vb2_plane_size(vb, 0) < new_size) {
+               dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n",
+                       vb2_plane_size(vb, 0), new_size);
+               return -ENOBUFS;
        }
 
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
-               struct scatterlist *sg = &buf->sg;
-
-               /*
-                * The total size of video-buffers that will be allocated / mapped.
-                * *size that we calculated in videobuf_setup gets assigned to
-                * vb->bsize, and now we use the same calculation to get vb->size.
-                */
-               vb->size = new_size;
-
-               /* This actually (allocates and) maps buffers */
-               ret = videobuf_iolock(vq, vb, NULL);
-               if (ret)
-                       goto fail;
-
-               /*
-                * We will have to configure the IDMAC channel. It has two slots
-                * for DMA buffers, we shall enter the first two buffers there,
-                * and then submit new buffers in DMA-ready interrupts
-                */
-               sg_init_table(sg, 1);
-               sg_dma_address(sg)      = videobuf_to_dma_contig(vb);
-               sg_dma_len(sg)          = vb->size;
+       if (buf->state == CSI_BUF_NEEDS_INIT) {
+               sg_dma_address(sg)      = vb2_dma_contig_plane_paddr(vb, 0);
+               sg_dma_len(sg)          = new_size;
 
                buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
                        &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
                        DMA_PREP_INTERRUPT);
-               if (!buf->txd) {
-                       ret = -EIO;
-                       goto fail;
-               }
+               if (!buf->txd)
+                       return -EIO;
 
                buf->txd->callback_param        = buf->txd;
                buf->txd->callback              = mx3_cam_dma_done;
 
-               vb->state = VIDEOBUF_PREPARED;
+               buf->state = CSI_BUF_PREPARED;
        }
 
-       return 0;
+       vb2_set_plane_payload(vb, 0, new_size);
 
-fail:
-       free_buffer(vq, buf);
-out:
-       return ret;
+       return 0;
 }
 
 static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
 {
        /* Add more formats as need arises and test possibilities appear... */
        switch (fourcc) {
-       case V4L2_PIX_FMT_RGB565:
-               return IPU_PIX_FMT_RGB565;
        case V4L2_PIX_FMT_RGB24:
                return IPU_PIX_FMT_RGB24;
-       case V4L2_PIX_FMT_RGB332:
-               return IPU_PIX_FMT_RGB332;
-       case V4L2_PIX_FMT_YUV422P:
-               return IPU_PIX_FMT_YVU422P;
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_RGB565:
        default:
                return IPU_PIX_FMT_GENERIC;
        }
 }
 
-/*
- * Called with .vb_lock mutex held and
- * under spinlock_irqsave(&mx3_cam->lock, ...)
- */
-static void mx3_videobuf_queue(struct videobuf_queue *vq,
-                              struct videobuf_buffer *vb)
+static void mx3_videobuf_queue(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
-       struct mx3_camera_buffer *buf =
-               container_of(vb, struct mx3_camera_buffer, vb);
+       struct mx3_camera_buffer *buf = to_mx3_vb(vb);
        struct dma_async_tx_descriptor *txd = buf->txd;
        struct idmac_channel *ichan = to_idmac_chan(txd->chan);
        struct idmac_video_param *video = &ichan->params.video;
        dma_cookie_t cookie;
        u32 fourcc = icd->current_fmt->host_fmt->fourcc;
-
-       BUG_ON(!irqs_disabled());
+       unsigned long flags;
 
        /* This is the configuration of one sg-element */
        video->out_pixel_fmt    = fourcc_to_ipu_pix(fourcc);
-       video->out_width        = icd->user_width;
-       video->out_height       = icd->user_height;
-       video->out_stride       = icd->user_width;
+
+       if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
+               /*
+                * If the IPU DMA channel is configured to transport
+                * generic 8-bit data, we have to set up correctly the
+                * geometry parameters upon the current pixel format.
+                * So, since the DMA horizontal parameters are expressed
+                * in bytes not pixels, convert these in the right unit.
+                */
+               int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+               BUG_ON(bytes_per_line <= 0);
+
+               video->out_width        = bytes_per_line;
+               video->out_height       = icd->user_height;
+               video->out_stride       = bytes_per_line;
+       } else {
+               /*
+                * For IPU known formats the pixel unit will be managed
+                * successfully by the IPU code
+                */
+               video->out_width        = icd->user_width;
+               video->out_height       = icd->user_height;
+               video->out_stride       = icd->user_width;
+       }
 
 #ifdef DEBUG
        /* helps to see what DMA actually has written */
-       memset((void *)vb->baddr, 0xaa, vb->bsize);
+       if (vb2_plane_vaddr(vb, 0))
+               memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
-       list_add_tail(&vb->queue, &mx3_cam->capture);
+       spin_lock_irqsave(&mx3_cam->lock, flags);
+       list_add_tail(&buf->queue, &mx3_cam->capture);
 
-       if (!mx3_cam->active) {
+       if (!mx3_cam->active)
                mx3_cam->active = buf;
-               vb->state = VIDEOBUF_ACTIVE;
-       } else {
-               vb->state = VIDEOBUF_QUEUED;
-       }
 
        spin_unlock_irq(&mx3_cam->lock);
 
@@ -383,67 +340,87 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
        dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
                cookie, sg_dma_address(&buf->sg));
 
-       spin_lock_irq(&mx3_cam->lock);
-
        if (cookie >= 0)
                return;
 
-       /* Submit error */
-       vb->state = VIDEOBUF_PREPARED;
+       spin_lock_irq(&mx3_cam->lock);
 
-       list_del_init(&vb->queue);
+       /* Submit error */
+       list_del_init(&buf->queue);
 
        if (mx3_cam->active == buf)
                mx3_cam->active = NULL;
+
+       spin_unlock_irqrestore(&mx3_cam->lock, flags);
+       vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
 }
 
-/* Called with .vb_lock held */
-static void mx3_videobuf_release(struct videobuf_queue *vq,
-                                struct videobuf_buffer *vb)
+static void mx3_videobuf_release(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
-       struct mx3_camera_buffer *buf =
-               container_of(vb, struct mx3_camera_buffer, vb);
+       struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+       struct dma_async_tx_descriptor *txd = buf->txd;
        unsigned long flags;
 
        dev_dbg(icd->dev.parent,
-               "Release%s DMA 0x%08x (state %d), queue %sempty\n",
+               "Release%s DMA 0x%08x, queue %sempty\n",
                mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
-               vb->state, list_empty(&vb->queue) ? "" : "not ");
+               list_empty(&buf->queue) ? "" : "not ");
+
        spin_lock_irqsave(&mx3_cam->lock, flags);
-       if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
-           !list_empty(&vb->queue)) {
-               vb->state = VIDEOBUF_ERROR;
 
-               list_del_init(&vb->queue);
-               if (mx3_cam->active == buf)
-                       mx3_cam->active = NULL;
+       if (mx3_cam->active == buf)
+               mx3_cam->active = NULL;
+
+       /* Doesn't hurt also if the list is empty */
+       list_del_init(&buf->queue);
+       buf->state = CSI_BUF_NEEDS_INIT;
+
+       if (txd) {
+               buf->txd = NULL;
+               if (mx3_cam->idmac_channel[0])
+                       async_tx_ack(txd);
        }
+
        spin_unlock_irqrestore(&mx3_cam->lock, flags);
-       free_buffer(vq, buf);
 }
 
-static struct videobuf_queue_ops mx3_videobuf_ops = {
-       .buf_setup      = mx3_videobuf_setup,
-       .buf_prepare    = mx3_videobuf_prepare,
-       .buf_queue      = mx3_videobuf_queue,
-       .buf_release    = mx3_videobuf_release,
+static int mx3_videobuf_init(struct vb2_buffer *vb)
+{
+       struct mx3_camera_buffer *buf = to_mx3_vb(vb);
+       /* This is for locking debugging only */
+       INIT_LIST_HEAD(&buf->queue);
+       sg_init_table(&buf->sg, 1);
+
+       buf->state = CSI_BUF_NEEDS_INIT;
+       buf->txd = NULL;
+
+       return 0;
+}
+
+static struct vb2_ops mx3_videobuf_ops = {
+       .queue_setup    = mx3_videobuf_setup,
+       .buf_prepare    = mx3_videobuf_prepare,
+       .buf_queue      = mx3_videobuf_queue,
+       .buf_cleanup    = mx3_videobuf_release,
+       .buf_init       = mx3_videobuf_init,
+       .wait_prepare   = soc_camera_unlock,
+       .wait_finish    = soc_camera_lock,
 };
 
-static void mx3_camera_init_videobuf(struct videobuf_queue *q,
+static int mx3_camera_init_videobuf(struct vb2_queue *q,
                                     struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct mx3_camera_dev *mx3_cam = ici->priv;
-
-       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, icd->dev.parent,
-                                      &mx3_cam->lock,
-                                      V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                      V4L2_FIELD_NONE,
-                                      sizeof(struct mx3_camera_buffer), icd,
-                                      &icd->video_lock);
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR;
+       q->drv_priv = icd;
+       q->ops = &mx3_videobuf_ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->buf_struct_size = sizeof(struct mx3_camera_buffer);
+
+       return vb2_queue_init(q);
 }
 
 /* First part of ipu_csi_init_interface() */
@@ -538,18 +515,6 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
                 icd->devnum);
 }
 
-static bool channel_change_requested(struct soc_camera_device *icd,
-                                    struct v4l2_rect *rect)
-{
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct mx3_camera_dev *mx3_cam = ici->priv;
-       struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
-
-       /* Do buffers have to be re-allocated or channel re-configured? */
-       return ichan && rect->width * rect->height >
-               icd->user_width * icd->user_height;
-}
-
 static int test_platform_param(struct mx3_camera_dev *mx3_cam,
                               unsigned char buswidth, unsigned long *flags)
 {
@@ -734,18 +699,36 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
        if (xlate) {
                xlate->host_fmt = fmt;
                xlate->code     = code;
+               dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n",
+                       (fmt->fourcc >> (0*8)) & 0xFF,
+                       (fmt->fourcc >> (1*8)) & 0xFF,
+                       (fmt->fourcc >> (2*8)) & 0xFF,
+                       (fmt->fourcc >> (3*8)) & 0xFF);
                xlate++;
-               dev_dbg(dev, "Providing format %x in pass-through mode\n",
-                       xlate->host_fmt->fourcc);
        }
 
        return formats;
 }
 
 static void configure_geometry(struct mx3_camera_dev *mx3_cam,
-                              unsigned int width, unsigned int height)
+                              unsigned int width, unsigned int height,
+                              enum v4l2_mbus_pixelcode code)
 {
        u32 ctrl, width_field, height_field;
+       const struct soc_mbus_pixelfmt *fmt;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       BUG_ON(!fmt);
+
+       if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
+               /*
+                * As the CSI will be configured to output BAYER, here
+                * the width parameter count the number of samples to
+                * capture to complete the whole image width.
+                */
+               width *= soc_mbus_samples_per_pixel(fmt);
+               BUG_ON(width < 0);
+       }
 
        /* Setup frame size - this cannot be changed on-the-fly... */
        width_field = width - 1;
@@ -772,18 +755,6 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
        struct dma_chan_request rq = {.mx3_cam = mx3_cam,
                                      .id = IDMAC_IC_7};
 
-       if (*ichan) {
-               struct videobuf_buffer *vb, *_vb;
-               dma_release_channel(&(*ichan)->dma_chan);
-               *ichan = NULL;
-               mx3_cam->active = NULL;
-               list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
-                       list_del_init(&vb->queue);
-                       vb->state = VIDEOBUF_ERROR;
-                       wake_up(&vb->done);
-               }
-       }
-
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
        dma_cap_set(DMA_PRIVATE, mask);
@@ -843,19 +814,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
                        return ret;
        }
 
-       if (mf.width != icd->user_width || mf.height != icd->user_height) {
-               /*
-                * We now know pixel formats and can decide upon DMA-channel(s)
-                * So far only direct camera-to-memory is supported
-                */
-               if (channel_change_requested(icd, rect)) {
-                       ret = acquire_dma_channel(mx3_cam);
-                       if (ret < 0)
-                               return ret;
-               }
-
-               configure_geometry(mx3_cam, mf.width, mf.height);
-       }
+       if (mf.width != icd->user_width || mf.height != icd->user_height)
+               configure_geometry(mx3_cam, mf.width, mf.height, mf.code);
 
        dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
@@ -887,17 +847,13 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
        stride_align(&pix->width);
        dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
 
-       ret = acquire_dma_channel(mx3_cam);
-       if (ret < 0)
-               return ret;
-
        /*
         * Might have to perform a complete interface initialisation like in
         * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
         * mxc_v4l2_s_fmt()
         */
 
-       configure_geometry(mx3_cam, pix->width, pix->height);
+       configure_geometry(mx3_cam, pix->width, pix->height, xlate->code);
 
        mf.width        = pix->width;
        mf.height       = pix->height;
@@ -912,12 +868,25 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
        if (mf.code != xlate->code)
                return -EINVAL;
 
+       if (!mx3_cam->idmac_channel[0]) {
+               ret = acquire_dma_channel(mx3_cam);
+               if (ret < 0)
+                       return ret;
+       }
+
        pix->width              = mf.width;
        pix->height             = mf.height;
        pix->field              = mf.field;
+       mx3_cam->field          = mf.field;
        pix->colorspace         = mf.colorspace;
        icd->current_fmt        = xlate;
 
+       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+                                                   xlate->host_fmt);
+       if (pix->bytesperline < 0)
+               return pix->bytesperline;
+       pix->sizeimage = pix->height * pix->bytesperline;
+
        dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
 
        return ret;
@@ -991,7 +960,7 @@ static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
 
-       return videobuf_poll_stream(file, &icd->vb_vidq, pt);
+       return vb2_poll(&icd->vb2_vidq, file, pt);
 }
 
 static int mx3_camera_querycap(struct soc_camera_host *ici,
@@ -1165,7 +1134,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
        .set_fmt        = mx3_camera_set_fmt,
        .try_fmt        = mx3_camera_try_fmt,
        .get_formats    = mx3_camera_get_formats,
-       .init_videobuf  = mx3_camera_init_videobuf,
+       .init_videobuf2 = mx3_camera_init_videobuf,
        .reqbufs        = mx3_camera_reqbufs,
        .poll           = mx3_camera_poll,
        .querycap       = mx3_camera_querycap,
@@ -1241,6 +1210,12 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
        soc_host->v4l2_dev.dev  = &pdev->dev;
        soc_host->nr            = pdev->id;
 
+       mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(mx3_cam->alloc_ctx)) {
+               err = PTR_ERR(mx3_cam->alloc_ctx);
+               goto eallocctx;
+       }
+
        err = soc_camera_host_register(soc_host);
        if (err)
                goto ecamhostreg;
@@ -1251,6 +1226,8 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
        return 0;
 
 ecamhostreg:
+       vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+eallocctx:
        iounmap(base);
 eioremap:
        clk_put(mx3_cam->clk);
@@ -1280,6 +1257,8 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev)
        if (WARN_ON(mx3_cam->idmac_channel[0]))
                dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
 
+       vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx);
+
        vfree(mx3_cam);
 
        dmaengine_put();
index e8846a09b0266863d34e444b8cc69d980dc8d5a5..0b38500235055bc176ebbc444f277a276c3b00d5 100644 (file)
@@ -643,7 +643,8 @@ static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_regist
 }
 #endif
 
-static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+static long vidioc_default(struct file *file, void *fh, bool valid_prio,
+                                                       int cmd, void *arg)
 {
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c
new file mode 100644 (file)
index 0000000..35f722a
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * Initial register configuration based on a driver authored by
+ * HeungJun Kim <riverful.kim@samsung.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 vergsion.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <media/noon010pc30.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable.");
+
+#define MODULE_NAME            "NOON010PC30"
+
+/*
+ * Register offsets within a page
+ * b15..b8 - page id, b7..b0 - register address
+ */
+#define POWER_CTRL_REG         0x0001
+#define PAGEMODE_REG           0x03
+#define DEVICE_ID_REG          0x0004
+#define NOON010PC30_ID         0x86
+#define VDO_CTL_REG(n)         (0x0010 + (n))
+#define SYNC_CTL_REG           0x0012
+/* Window size and position */
+#define WIN_ROWH_REG           0x0013
+#define WIN_ROWL_REG           0x0014
+#define WIN_COLH_REG           0x0015
+#define WIN_COLL_REG           0x0016
+#define WIN_HEIGHTH_REG                0x0017
+#define WIN_HEIGHTL_REG                0x0018
+#define WIN_WIDTHH_REG         0x0019
+#define WIN_WIDTHL_REG         0x001A
+#define HBLANKH_REG            0x001B
+#define HBLANKL_REG            0x001C
+#define VSYNCH_REG             0x001D
+#define VSYNCL_REG             0x001E
+/* VSYNC control */
+#define VS_CTL_REG(n)          (0x00A1 + (n))
+/* page 1 */
+#define ISP_CTL_REG(n)         (0x0110 + (n))
+#define YOFS_REG               0x0119
+#define DARK_YOFS_REG          0x011A
+#define SAT_CTL_REG            0x0120
+#define BSAT_REG               0x0121
+#define RSAT_REG               0x0122
+/* Color correction */
+#define CMC_CTL_REG            0x0130
+#define CMC_OFSGH_REG          0x0133
+#define CMC_OFSGL_REG          0x0135
+#define CMC_SIGN_REG           0x0136
+#define CMC_GOFS_REG           0x0137
+#define CMC_COEF_REG(n)                (0x0138 + (n))
+#define CMC_OFS_REG(n)         (0x0141 + (n))
+/* Gamma correction */
+#define GMA_CTL_REG            0x0160
+#define GMA_COEF_REG(n)                (0x0161 + (n))
+/* Lens Shading */
+#define LENS_CTRL_REG          0x01D0
+#define LENS_XCEN_REG          0x01D1
+#define LENS_YCEN_REG          0x01D2
+#define LENS_RC_REG            0x01D3
+#define LENS_GC_REG            0x01D4
+#define LENS_BC_REG            0x01D5
+#define L_AGON_REG             0x01D6
+#define L_AGOFF_REG            0x01D7
+/* Page 3 - Auto Exposure */
+#define AE_CTL_REG(n)          (0x0310 + (n))
+#define AE_CTL9_REG            0x032C
+#define AE_CTL10_REG           0x032D
+#define AE_YLVL_REG            0x031C
+#define AE_YTH_REG(n)          (0x031D + (n))
+#define AE_WGT_REG             0x0326
+#define EXP_TIMEH_REG          0x0333
+#define EXP_TIMEM_REG          0x0334
+#define EXP_TIMEL_REG          0x0335
+#define EXP_MMINH_REG          0x0336
+#define EXP_MMINL_REG          0x0337
+#define EXP_MMAXH_REG          0x0338
+#define EXP_MMAXM_REG          0x0339
+#define EXP_MMAXL_REG          0x033A
+/* Page 4 - Auto White Balance */
+#define AWB_CTL_REG(n)         (0x0410 + (n))
+#define AWB_ENABE              0x80
+#define AWB_WGHT_REG           0x0419
+#define BGAIN_PAR_REG(n)       (0x044F + (n))
+/* Manual white balance, when AWB_CTL2[0]=1 */
+#define MWB_RGAIN_REG          0x0466
+#define MWB_BGAIN_REG          0x0467
+
+/* The token to mark an array end */
+#define REG_TERM               0xFFFF
+
+struct noon010_format {
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_colorspace colorspace;
+       u16 ispctl1_reg;
+};
+
+struct noon010_frmsize {
+       u16 width;
+       u16 height;
+       int vid_ctl1;
+};
+
+static const char * const noon010_supply_name[] = {
+       "vdd_core", "vddio", "vdda"
+};
+
+#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name)
+
+struct noon010_info {
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+       const struct noon010pc30_platform_data *pdata;
+       const struct noon010_format *curr_fmt;
+       const struct noon010_frmsize *curr_win;
+       unsigned int hflip:1;
+       unsigned int vflip:1;
+       unsigned int power:1;
+       u8 i2c_reg_page;
+       struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES];
+       u32 gpio_nreset;
+       u32 gpio_nstby;
+};
+
+struct i2c_regval {
+       u16 addr;
+       u16 val;
+};
+
+/* Supported resolutions. */
+static const struct noon010_frmsize noon010_sizes[] = {
+       {
+               .width          = 352,
+               .height         = 288,
+               .vid_ctl1       = 0,
+       }, {
+               .width          = 176,
+               .height         = 144,
+               .vid_ctl1       = 0x10,
+       }, {
+               .width          = 88,
+               .height         = 72,
+               .vid_ctl1       = 0x20,
+       },
+};
+
+/* Supported pixel formats. */
+static const struct noon010_format noon010_formats[] = {
+       {
+               .code           = V4L2_MBUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x03,
+       }, {
+               .code           = V4L2_MBUS_FMT_YVYU8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x02,
+       }, {
+               .code           = V4L2_MBUS_FMT_VYUY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0,
+       }, {
+               .code           = V4L2_MBUS_FMT_UYVY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x01,
+       }, {
+               .code           = V4L2_MBUS_FMT_RGB565_2X8_BE,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .ispctl1_reg    = 0x40,
+       },
+};
+
+static const struct i2c_regval noon010_base_regs[] = {
+       { WIN_COLL_REG,         0x06 }, { HBLANKL_REG,          0x7C },
+       /* Color corection and saturation */
+       { ISP_CTL_REG(0),       0x30 }, { ISP_CTL_REG(2),       0x30 },
+       { YOFS_REG,             0x80 }, { DARK_YOFS_REG,        0x04 },
+       { SAT_CTL_REG,          0x1F }, { BSAT_REG,             0x90 },
+       { CMC_CTL_REG,          0x0F }, { CMC_OFSGH_REG,        0x3C },
+       { CMC_OFSGL_REG,        0x2C }, { CMC_SIGN_REG,         0x3F },
+       { CMC_COEF_REG(0),      0x79 }, { CMC_OFS_REG(0),       0x00 },
+       { CMC_COEF_REG(1),      0x39 }, { CMC_OFS_REG(1),       0x00 },
+       { CMC_COEF_REG(2),      0x00 }, { CMC_OFS_REG(2),       0x00 },
+       { CMC_COEF_REG(3),      0x11 }, { CMC_OFS_REG(3),       0x8B },
+       { CMC_COEF_REG(4),      0x65 }, { CMC_OFS_REG(4),       0x07 },
+       { CMC_COEF_REG(5),      0x14 }, { CMC_OFS_REG(5),       0x04 },
+       { CMC_COEF_REG(6),      0x01 }, { CMC_OFS_REG(6),       0x9C },
+       { CMC_COEF_REG(7),      0x33 }, { CMC_OFS_REG(7),       0x89 },
+       { CMC_COEF_REG(8),      0x74 }, { CMC_OFS_REG(8),       0x25 },
+       /* Automatic white balance */
+       { AWB_CTL_REG(0),       0x78 }, { AWB_CTL_REG(1),       0x2E },
+       { AWB_CTL_REG(2),       0x20 }, { AWB_CTL_REG(3),       0x85 },
+       /* Auto exposure */
+       { AE_CTL_REG(0),        0xDC }, { AE_CTL_REG(1),        0x81 },
+       { AE_CTL_REG(2),        0x30 }, { AE_CTL_REG(3),        0xA5 },
+       { AE_CTL_REG(4),        0x40 }, { AE_CTL_REG(5),        0x51 },
+       { AE_CTL_REG(6),        0x33 }, { AE_CTL_REG(7),        0x7E },
+       { AE_CTL9_REG,          0x00 }, { AE_CTL10_REG,         0x02 },
+       { AE_YLVL_REG,          0x44 }, { AE_YTH_REG(0),        0x34 },
+       { AE_YTH_REG(1),        0x30 }, { AE_WGT_REG,           0xD5 },
+       /* Lens shading compensation */
+       { LENS_CTRL_REG,        0x01 }, { LENS_XCEN_REG,        0x80 },
+       { LENS_YCEN_REG,        0x70 }, { LENS_RC_REG,          0x53 },
+       { LENS_GC_REG,          0x40 }, { LENS_BC_REG,          0x3E },
+       { REG_TERM,             0 },
+};
+
+static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct noon010_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct noon010_info, hdl)->sd;
+}
+
+static inline int set_i2c_page(struct noon010_info *info,
+                              struct i2c_client *client, unsigned int reg)
+{
+       u32 page = reg >> 8 & 0xFF;
+       int ret = 0;
+
+       if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
+               ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
+               if (!ret)
+                       info->i2c_reg_page = page;
+       }
+       return ret;
+}
+
+static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct noon010_info *info = to_noon010(sd);
+       int ret = set_i2c_page(info, client, reg_addr);
+
+       if (ret)
+               return ret;
+       return i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
+}
+
+static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct noon010_info *info = to_noon010(sd);
+       int ret = set_i2c_page(info, client, reg_addr);
+
+       if (ret)
+               return ret;
+       return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val);
+}
+
+static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd,
+                                        const struct i2c_regval *msg)
+{
+       while (msg->addr != REG_TERM) {
+               int ret = cam_i2c_write(sd, msg->addr, msg->val);
+
+               if (ret)
+                       return ret;
+               msg++;
+       }
+       return 0;
+}
+
+/* Device reset and sleep mode control */
+static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep)
+{
+       struct noon010_info *info = to_noon010(sd);
+       u8 reg = sleep ? 0xF1 : 0xF0;
+       int ret = 0;
+
+       if (reset)
+               ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+       if (!ret) {
+               ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
+               if (reset && !ret)
+                       info->i2c_reg_page = -1;
+       }
+       return ret;
+}
+
+/* Automatic white balance control */
+static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+
+       ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F);
+       if (!ret)
+               ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B);
+       return ret;
+}
+
+static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip)
+{
+       struct noon010_info *info = to_noon010(sd);
+       int reg, ret;
+
+       reg = cam_i2c_read(sd, VDO_CTL_REG(1));
+       if (reg < 0)
+               return reg;
+
+       reg &= 0x7C;
+       if (hflip)
+               reg |= 0x01;
+       if (vflip)
+               reg |= 0x02;
+
+       ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80);
+       if (!ret) {
+               info->hflip = hflip;
+               info->vflip = vflip;
+       }
+       return ret;
+}
+
+/* Configure resolution and color format */
+static int noon010_set_params(struct v4l2_subdev *sd)
+{
+       struct noon010_info *info = to_noon010(sd);
+       int ret;
+
+       if (!info->curr_win)
+               return -EINVAL;
+
+       ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1);
+
+       if (!ret && info->curr_fmt)
+               ret = cam_i2c_write(sd, ISP_CTL_REG(0),
+                               info->curr_fmt->ispctl1_reg);
+       return ret;
+}
+
+/* Find nearest matching image pixel size. */
+static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf)
+{
+       unsigned int min_err = ~0;
+       int i = ARRAY_SIZE(noon010_sizes);
+       const struct noon010_frmsize *fsize = &noon010_sizes[0],
+               *match = NULL;
+
+       while (i--) {
+               int err = abs(fsize->width - mf->width)
+                               + abs(fsize->height - mf->height);
+
+               if (err < min_err) {
+                       min_err = err;
+                       match = fsize;
+               }
+               fsize++;
+       }
+       if (match) {
+               mf->width  = match->width;
+               mf->height = match->height;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int power_enable(struct noon010_info *info)
+{
+       int ret;
+
+       if (info->power) {
+               v4l2_info(&info->sd, "%s: sensor is already on\n", __func__);
+               return 0;
+       }
+
+       if (gpio_is_valid(info->gpio_nstby))
+               gpio_set_value(info->gpio_nstby, 0);
+
+       if (gpio_is_valid(info->gpio_nreset))
+               gpio_set_value(info->gpio_nreset, 0);
+
+       ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply);
+       if (ret)
+               return ret;
+
+       if (gpio_is_valid(info->gpio_nreset)) {
+               msleep(50);
+               gpio_set_value(info->gpio_nreset, 1);
+       }
+       if (gpio_is_valid(info->gpio_nstby)) {
+               udelay(1000);
+               gpio_set_value(info->gpio_nstby, 1);
+       }
+       if (gpio_is_valid(info->gpio_nreset)) {
+               udelay(1000);
+               gpio_set_value(info->gpio_nreset, 0);
+               msleep(100);
+               gpio_set_value(info->gpio_nreset, 1);
+               msleep(20);
+       }
+       info->power = 1;
+
+       v4l2_dbg(1, debug, &info->sd,  "%s: sensor is on\n", __func__);
+       return 0;
+}
+
+static int power_disable(struct noon010_info *info)
+{
+       int ret;
+
+       if (!info->power) {
+               v4l2_info(&info->sd, "%s: sensor is already off\n", __func__);
+               return 0;
+       }
+
+       ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply);
+       if (ret)
+               return ret;
+
+       if (gpio_is_valid(info->gpio_nstby))
+               gpio_set_value(info->gpio_nstby, 0);
+
+       if (gpio_is_valid(info->gpio_nreset))
+               gpio_set_value(info->gpio_nreset, 0);
+
+       info->power = 0;
+
+       v4l2_dbg(1, debug, &info->sd,  "%s: sensor is off\n", __func__);
+
+       return 0;
+}
+
+static int noon010_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+
+       v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
+                __func__, ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               return noon010_enable_autowhitebalance(sd, ctrl->val);
+       case V4L2_CID_BLUE_BALANCE:
+               return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val);
+       case V4L2_CID_RED_BALANCE:
+               return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                           enum v4l2_mbus_pixelcode *code)
+{
+       if (!code || index >= ARRAY_SIZE(noon010_formats))
+               return -EINVAL;
+
+       *code = noon010_formats[index].code;
+       return 0;
+}
+
+static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+       struct noon010_info *info = to_noon010(sd);
+       int ret;
+
+       if (!mf)
+               return -EINVAL;
+
+       if (!info->curr_win || !info->curr_fmt) {
+               ret = noon010_set_params(sd);
+               if (ret)
+                       return ret;
+       }
+
+       mf->width       = info->curr_win->width;
+       mf->height      = info->curr_win->height;
+       mf->code        = info->curr_fmt->code;
+       mf->colorspace  = info->curr_fmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+/* Return nearest media bus frame format. */
+static const struct noon010_format *try_fmt(struct v4l2_subdev *sd,
+                                           struct v4l2_mbus_framefmt *mf)
+{
+       int i = ARRAY_SIZE(noon010_formats);
+
+       noon010_try_frame_size(mf);
+
+       while (i--)
+               if (mf->code == noon010_formats[i].code)
+                       break;
+
+       mf->code = noon010_formats[i].code;
+
+       return &noon010_formats[i];
+}
+
+static int noon010_try_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_mbus_framefmt *mf)
+{
+       if (!sd || !mf)
+               return -EINVAL;
+
+       try_fmt(sd, mf);
+       return 0;
+}
+
+static int noon010_s_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct noon010_info *info = to_noon010(sd);
+
+       if (!sd || !mf)
+               return -EINVAL;
+
+       info->curr_fmt = try_fmt(sd, mf);
+
+       return noon010_set_params(sd);
+}
+
+static int noon010_base_config(struct v4l2_subdev *sd)
+{
+       struct noon010_info *info = to_noon010(sd);
+       int ret;
+
+       ret = noon010_bulk_write_reg(sd, noon010_base_regs);
+       if (!ret) {
+               info->curr_fmt = &noon010_formats[0];
+               info->curr_win = &noon010_sizes[0];
+               ret = noon010_set_params(sd);
+       }
+       if (!ret)
+               ret = noon010_set_flip(sd, 1, 0);
+       if (!ret)
+               ret = noon010_power_ctrl(sd, false, false);
+
+       /* sync the handler and the registers state */
+       v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl);
+       return ret;
+}
+
+static int noon010_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct noon010_info *info = to_noon010(sd);
+       const struct noon010pc30_platform_data *pdata = info->pdata;
+       int ret = 0;
+
+       if (WARN(pdata == NULL, "No platform data!\n"))
+               return -ENOMEM;
+
+       if (on) {
+               ret = power_enable(info);
+               if (ret)
+                       return ret;
+               ret = noon010_base_config(sd);
+       } else {
+               noon010_power_ctrl(sd, false, true);
+               ret = power_disable(info);
+               info->curr_win = NULL;
+               info->curr_fmt = NULL;
+       }
+
+       return ret;
+}
+
+static int noon010_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip,
+                                         V4L2_IDENT_NOON010PC30, 0);
+}
+
+static int noon010_log_status(struct v4l2_subdev *sd)
+{
+       struct noon010_info *info = to_noon010(sd);
+
+       v4l2_ctrl_handler_log_status(&info->hdl, sd->name);
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops noon010_ctrl_ops = {
+       .s_ctrl = noon010_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops noon010_core_ops = {
+       .g_chip_ident   = noon010_g_chip_ident,
+       .s_power        = noon010_s_power,
+       .g_ctrl         = v4l2_subdev_g_ctrl,
+       .s_ctrl         = v4l2_subdev_s_ctrl,
+       .queryctrl      = v4l2_subdev_queryctrl,
+       .querymenu      = v4l2_subdev_querymenu,
+       .g_ext_ctrls    = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls  = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls    = v4l2_subdev_s_ext_ctrls,
+       .log_status     = noon010_log_status,
+};
+
+static const struct v4l2_subdev_video_ops noon010_video_ops = {
+       .g_mbus_fmt     = noon010_g_fmt,
+       .s_mbus_fmt     = noon010_s_fmt,
+       .try_mbus_fmt   = noon010_try_fmt,
+       .enum_mbus_fmt  = noon010_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops noon010_ops = {
+       .core   = &noon010_core_ops,
+       .video  = &noon010_video_ops,
+};
+
+/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */
+static int noon010_detect(struct i2c_client *client, struct noon010_info *info)
+{
+       int ret;
+
+       ret = power_enable(info);
+       if (ret)
+               return ret;
+
+       ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
+       if (ret < 0)
+               dev_err(&client->dev, "I2C read failed: 0x%X\n", ret);
+
+       power_disable(info);
+
+       return ret == NOON010PC30_ID ? 0 : -ENODEV;
+}
+
+static int noon010_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct noon010_info *info;
+       struct v4l2_subdev *sd;
+       const struct noon010pc30_platform_data *pdata
+               = client->dev.platform_data;
+       int ret;
+       int i;
+
+       if (!pdata) {
+               dev_err(&client->dev, "No platform data!\n");
+               return -EIO;
+       }
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       sd = &info->sd;
+       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+       v4l2_i2c_subdev_init(sd, client, &noon010_ops);
+
+       v4l2_ctrl_handler_init(&info->hdl, 3);
+
+       v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+                         V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+       v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+                         V4L2_CID_RED_BALANCE, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops,
+                         V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64);
+
+       sd->ctrl_handler = &info->hdl;
+
+       ret = info->hdl.error;
+       if (ret)
+               goto np_err;
+
+       info->pdata             = client->dev.platform_data;
+       info->i2c_reg_page      = -1;
+       info->gpio_nreset       = -EINVAL;
+       info->gpio_nstby        = -EINVAL;
+
+       if (gpio_is_valid(pdata->gpio_nreset)) {
+               ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST");
+               if (ret) {
+                       dev_err(&client->dev, "GPIO request error: %d\n", ret);
+                       goto np_err;
+               }
+               info->gpio_nreset = pdata->gpio_nreset;
+               gpio_direction_output(info->gpio_nreset, 0);
+               gpio_export(info->gpio_nreset, 0);
+       }
+
+       if (gpio_is_valid(pdata->gpio_nstby)) {
+               ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY");
+               if (ret) {
+                       dev_err(&client->dev, "GPIO request error: %d\n", ret);
+                       goto np_gpio_err;
+               }
+               info->gpio_nstby = pdata->gpio_nstby;
+               gpio_direction_output(info->gpio_nstby, 0);
+               gpio_export(info->gpio_nstby, 0);
+       }
+
+       for (i = 0; i < NOON010_NUM_SUPPLIES; i++)
+               info->supply[i].supply = noon010_supply_name[i];
+
+       ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES,
+                                info->supply);
+       if (ret)
+               goto np_reg_err;
+
+       ret = noon010_detect(client, info);
+       if (!ret)
+               return 0;
+
+       /* the sensor detection failed */
+       regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
+np_reg_err:
+       if (gpio_is_valid(info->gpio_nstby))
+               gpio_free(info->gpio_nstby);
+np_gpio_err:
+       if (gpio_is_valid(info->gpio_nreset))
+               gpio_free(info->gpio_nreset);
+np_err:
+       v4l2_ctrl_handler_free(&info->hdl);
+       v4l2_device_unregister_subdev(sd);
+       kfree(info);
+       return ret;
+}
+
+static int noon010_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct noon010_info *info = to_noon010(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&info->hdl);
+
+       regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply);
+
+       if (gpio_is_valid(info->gpio_nreset))
+               gpio_free(info->gpio_nreset);
+
+       if (gpio_is_valid(info->gpio_nstby))
+               gpio_free(info->gpio_nstby);
+
+       kfree(info);
+       return 0;
+}
+
+static const struct i2c_device_id noon010_id[] = {
+       { MODULE_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, noon010_id);
+
+
+static struct i2c_driver noon010_i2c_driver = {
+       .driver = {
+               .name = MODULE_NAME
+       },
+       .probe          = noon010_probe,
+       .remove         = noon010_remove,
+       .id_table       = noon010_id,
+};
+
+static int __init noon010_init(void)
+{
+       return i2c_add_driver(&noon010_i2c_driver);
+}
+
+static void __exit noon010_exit(void)
+{
+       i2c_del_driver(&noon010_i2c_driver);
+}
+
+module_init(noon010_init);
+module_exit(noon010_exit);
+
+MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
index 0a2fb2bfdbfbbfeee180ee521495452fdc29234e..eab31cbd68eb354ffb5685bec2e738c88981b633 100644 (file)
@@ -811,8 +811,8 @@ static irqreturn_t cam_isr(int irq, void *data)
        spin_lock_irqsave(&pcdev->lock, flags);
 
        if (WARN_ON(!buf)) {
-               dev_warn(dev, "%s: unhandled camera interrupt, status == "
-                               "%#x\n", __func__, it_status);
+               dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+                        __func__, it_status);
                suspend_capture(pcdev);
                disable_capture(pcdev);
                goto out;
@@ -1088,15 +1088,15 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
                        xlate->host_fmt = &omap1_cam_formats[code];
                        xlate->code     = code;
                        xlate++;
-                       dev_dbg(dev, "%s: providing format %s "
-                                       "as byte swapped code #%d\n", __func__,
-                                       omap1_cam_formats[code].name, code);
+                       dev_dbg(dev,
+                               "%s: providing format %s as byte swapped code #%d\n",
+                               __func__, omap1_cam_formats[code].name, code);
                }
        default:
                if (xlate)
-                       dev_dbg(dev, "%s: providing format %s "
-                                       "in pass-through mode\n", __func__,
-                                       fmt->name);
+                       dev_dbg(dev,
+                               "%s: providing format %s in pass-through mode\n",
+                               __func__, fmt->name);
        }
        formats++;
        if (xlate) {
@@ -1139,29 +1139,29 @@ static int dma_align(int *width, int *height,
        return 1;
 }
 
-#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...)    \
-({                                                                        \
-       struct soc_camera_sense sense = {                                  \
-               .master_clock           = pcdev->camexclk,                 \
-               .pixel_clock_max        = 0,                               \
-       };                                                                 \
-       int __ret;                                                         \
-                                                                          \
-       if (pcdev->pdata)                                                  \
-               sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \
-       icd->sense = &sense;                                               \
-       __ret = v4l2_subdev_call(sd, video, function, ##args);             \
-       icd->sense = NULL;                                                 \
-                                                                          \
-       if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {                      \
-               if (sense.pixel_clock > sense.pixel_clock_max) {           \
-                       dev_err(dev, "%s: pixel clock %lu "                \
-                                       "set by the camera too high!\n",   \
-                                       __func__, sense.pixel_clock);      \
-                       __ret = -EINVAL;                                   \
-               }                                                          \
-       }                                                                  \
-       __ret;                                                             \
+#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...)              \
+({                                                                                  \
+       struct soc_camera_sense sense = {                                            \
+               .master_clock           = pcdev->camexclk,                           \
+               .pixel_clock_max        = 0,                                         \
+       };                                                                           \
+       int __ret;                                                                   \
+                                                                                    \
+       if (pcdev->pdata)                                                            \
+               sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000;           \
+       icd->sense = &sense;                                                         \
+       __ret = v4l2_subdev_call(sd, video, function, ##args);                       \
+       icd->sense = NULL;                                                           \
+                                                                                    \
+       if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {                                \
+               if (sense.pixel_clock > sense.pixel_clock_max) {                     \
+                       dev_err(dev,                                                 \
+                               "%s: pixel clock %lu set by the camera too high!\n", \
+                               __func__, sense.pixel_clock);                        \
+                       __ret = -EINVAL;                                             \
+               }                                                                    \
+       }                                                                            \
+       __ret;                                                                       \
 })
 
 static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
@@ -1664,10 +1664,10 @@ static int __exit omap1_cam_remove(struct platform_device *pdev)
        res = pcdev->res;
        release_mem_region(res->start, resource_size(res));
 
-       kfree(pcdev);
-
        clk_put(pcdev->clk);
 
+       kfree(pcdev);
+
        dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
 
        return 0;
index 01755276290251dfdb1ca70a26a1c61c4636c14c..f6626e87dbc55248577f3d479067a87316a8ac99 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
diff --git a/drivers/media/video/omap3isp/Makefile b/drivers/media/video/omap3isp/Makefile
new file mode 100644 (file)
index 0000000..b1b3447
--- /dev/null
@@ -0,0 +1,13 @@
+# Makefile for OMAP3 ISP driver
+
+ifdef CONFIG_VIDEO_OMAP3_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+omap3-isp-objs += \
+       isp.o ispqueue.o ispvideo.o \
+       ispcsiphy.o ispccp2.o ispcsi2.o \
+       ispccdc.o isppreview.o ispresizer.o \
+       ispstat.o isph3a_aewb.o isph3a_af.o isphist.o
+
+obj-$(CONFIG_VIDEO_OMAP3) += omap3-isp.o
diff --git a/drivers/media/video/omap3isp/cfa_coef_table.h b/drivers/media/video/omap3isp/cfa_coef_table.h
new file mode 100644 (file)
index 0000000..c60df0e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * cfa_coef_table.h
+ *
+ * TI OMAP3 ISP - CFA coefficients table
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
+  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
+  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+  0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
+  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
+  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
+  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+  0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
+244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
+244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248
diff --git a/drivers/media/video/omap3isp/gamma_table.h b/drivers/media/video/omap3isp/gamma_table.h
new file mode 100644 (file)
index 0000000..78deebf
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * gamma_table.h
+ *
+ * TI OMAP3 ISP - Default gamma table for all components
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+  0,   0,   1,   2,   3,   3,   4,   5,   6,   8,  10,  12,  14,  16,  18,  20,
+ 22,  23,  25,  26,  28,  29,  31,  32,  34,  35,  36,  37,  39,  40,  41,  42,
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  52,  53,  54,  55,  56,  57,
+ 58,  59,  60,  61,  62,  63,  63,  64,  65,  66,  66,  67,  68,  69,  69,  70,
+ 71,  72,  72,  73,  74,  75,  75,  76,  77,  78,  78,  79,  80,  81,  81,  82,
+ 83,  84,  84,  85,  86,  87,  88,  88,  89,  90,  91,  91,  92,  93,  94,  94,
+ 95,  96,  97,  97,  98,  98,  99,  99, 100, 100, 101, 101, 102, 103, 104, 104,
+105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117,
+117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125,
+126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133,
+134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
+142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149,
+150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155,
+156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162,
+162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168,
+168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174,
+174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179,
+179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183,
+183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187,
+187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191,
+191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195,
+195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199,
+199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203,
+203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207,
+207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210,
+210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
+211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
+213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
+216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
+219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221,
+221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223,
+223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225,
+225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226,
+226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
+228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230,
+230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232,
+232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235,
+235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
+236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238,
+238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
+238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240,
+240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242,
+242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
+246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
+246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248,
+248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
+250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
+253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
new file mode 100644 (file)
index 0000000..1a9963b
--- /dev/null
@@ -0,0 +1,2220 @@
+/*
+ * isp.c
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2007-2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * Contributors:
+ *     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *     Sakari Ailus <sakari.ailus@iki.fi>
+ *     David Cohen <dacohen@gmail.com>
+ *     Stanimir Varbanov <svarbanov@mm-sol.com>
+ *     Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
+ *     Tuukka Toivonen <tuukkat76@gmail.com>
+ *     Sergio Aguirre <saaguirre@ti.com>
+ *     Antti Koskipaa <akoskipa@gmail.com>
+ *     Ivan T. Ivanov <iivanov@mm-sol.com>
+ *     RaniSuneela <r-m@ti.com>
+ *     Atanas Filipov <afilipov@mm-sol.com>
+ *     Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
+ *     Hiroshi DOYU <hiroshi.doyu@nokia.com>
+ *     Nayden Kanchev <nkanchev@mm-sol.com>
+ *     Phil Carmody <ext-phil.2.carmody@nokia.com>
+ *     Artem Bityutskiy <artem.bityutskiy@nokia.com>
+ *     Dominic Curran <dcurran@ti.com>
+ *     Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
+ *     Pallavi Kulkarni <p-kulkarni@ti.com>
+ *     Vaibhav Hiremath <hvaibhav@ti.com>
+ *     Mohit Jalori <mjalori@ti.com>
+ *     Sameer Venkatraman <sameerv@ti.com>
+ *     Senthilvadivu Guruswamy <svadivu@ti.com>
+ *     Thara Gopinath <thara@ti.com>
+ *     Toni Leinonen <toni.leinonen@nokia.com>
+ *     Troy Laramy <t-laramy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+#include "isppreview.h"
+#include "ispresizer.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+#include "isph3a.h"
+#include "isphist.h"
+
+static unsigned int autoidle;
+module_param(autoidle, int, 0444);
+MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
+
+static void isp_save_ctx(struct isp_device *isp);
+
+static void isp_restore_ctx(struct isp_device *isp);
+
+static const struct isp_res_mapping isp_res_maps[] = {
+       {
+               .isp_rev = ISP_REVISION_2_0,
+               .map = 1 << OMAP3_ISP_IOMEM_MAIN |
+                      1 << OMAP3_ISP_IOMEM_CCP2 |
+                      1 << OMAP3_ISP_IOMEM_CCDC |
+                      1 << OMAP3_ISP_IOMEM_HIST |
+                      1 << OMAP3_ISP_IOMEM_H3A |
+                      1 << OMAP3_ISP_IOMEM_PREV |
+                      1 << OMAP3_ISP_IOMEM_RESZ |
+                      1 << OMAP3_ISP_IOMEM_SBL |
+                      1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+                      1 << OMAP3_ISP_IOMEM_CSIPHY2,
+       },
+       {
+               .isp_rev = ISP_REVISION_15_0,
+               .map = 1 << OMAP3_ISP_IOMEM_MAIN |
+                      1 << OMAP3_ISP_IOMEM_CCP2 |
+                      1 << OMAP3_ISP_IOMEM_CCDC |
+                      1 << OMAP3_ISP_IOMEM_HIST |
+                      1 << OMAP3_ISP_IOMEM_H3A |
+                      1 << OMAP3_ISP_IOMEM_PREV |
+                      1 << OMAP3_ISP_IOMEM_RESZ |
+                      1 << OMAP3_ISP_IOMEM_SBL |
+                      1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
+                      1 << OMAP3_ISP_IOMEM_CSIPHY2 |
+                      1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
+                      1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
+                      1 << OMAP3_ISP_IOMEM_CSIPHY1 |
+                      1 << OMAP3_ISP_IOMEM_CSI2C_REGS2,
+       },
+};
+
+/* Structure for saving/restoring ISP module registers */
+static struct isp_reg isp_reg_list[] = {
+       {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
+       {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0},
+       {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0},
+       {0, ISP_TOK_TERM, 0}
+};
+
+/*
+ * omap3isp_flush - Post pending L3 bus writes by doing a register readback
+ * @isp: OMAP3 ISP device
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ */
+void omap3isp_flush(struct isp_device *isp)
+{
+       isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+       isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+}
+
+/*
+ * isp_enable_interrupts - Enable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_enable_interrupts(struct isp_device *isp)
+{
+       static const u32 irq = IRQ0ENABLE_CSIA_IRQ
+                            | IRQ0ENABLE_CSIB_IRQ
+                            | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ
+                            | IRQ0ENABLE_CCDC_LSC_DONE_IRQ
+                            | IRQ0ENABLE_CCDC_VD0_IRQ
+                            | IRQ0ENABLE_CCDC_VD1_IRQ
+                            | IRQ0ENABLE_HS_VS_IRQ
+                            | IRQ0ENABLE_HIST_DONE_IRQ
+                            | IRQ0ENABLE_H3A_AWB_DONE_IRQ
+                            | IRQ0ENABLE_H3A_AF_DONE_IRQ
+                            | IRQ0ENABLE_PRV_DONE_IRQ
+                            | IRQ0ENABLE_RSZ_DONE_IRQ;
+
+       isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+       isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/*
+ * isp_disable_interrupts - Disable ISP interrupts.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_interrupts(struct isp_device *isp)
+{
+       isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
+/**
+ * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @isp: OMAP3 ISP device
+ * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
+ * @xclksel: XCLK to configure (0 = A, 1 = B).
+ *
+ * Configures the specified MCLK divisor in the ISP timing control register
+ * (TCTRL_CTRL) to generate the desired xclk clock value.
+ *
+ * Divisor = cam_mclk_hz / xclk
+ *
+ * Returns the final frequency that is actually being generated
+ **/
+static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
+{
+       u32 divisor;
+       u32 currentxclk;
+       unsigned long mclk_hz;
+
+       if (!omap3isp_get(isp))
+               return 0;
+
+       mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+
+       if (xclk >= mclk_hz) {
+               divisor = ISPTCTRL_CTRL_DIV_BYPASS;
+               currentxclk = mclk_hz;
+       } else if (xclk >= 2) {
+               divisor = mclk_hz / xclk;
+               if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
+                       divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+               currentxclk = mclk_hz / divisor;
+       } else {
+               divisor = xclk;
+               currentxclk = 0;
+       }
+
+       switch (xclksel) {
+       case 0:
+               isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+                               ISPTCTRL_CTRL_DIVA_MASK,
+                               divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
+               dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
+                       currentxclk);
+               break;
+       case 1:
+               isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+                               ISPTCTRL_CTRL_DIVB_MASK,
+                               divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
+               dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
+                       currentxclk);
+               break;
+       default:
+               omap3isp_put(isp);
+               dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
+                       "xclk. Must be 0 (A) or 1 (B).\n");
+               return -EINVAL;
+       }
+
+       /* Do we go from stable whatever to clock? */
+       if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2)
+               omap3isp_get(isp);
+       /* Stopping the clock. */
+       else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2)
+               omap3isp_put(isp);
+
+       isp->xclk_divisor[xclksel] = divisor;
+
+       omap3isp_put(isp);
+
+       return currentxclk;
+}
+
+/*
+ * isp_power_settings - Sysconfig settings, for Power Management.
+ * @isp: OMAP3 ISP device
+ * @idle: Consider idle state.
+ *
+ * Sets the power settings for the ISP, and SBL bus.
+ */
+static void isp_power_settings(struct isp_device *isp, int idle)
+{
+       isp_reg_writel(isp,
+                      ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
+                               ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) <<
+                       ISP_SYSCONFIG_MIDLEMODE_SHIFT) |
+                       ((isp->revision == ISP_REVISION_15_0) ?
+                         ISP_SYSCONFIG_AUTOIDLE : 0),
+                      OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+
+       if (isp->autoidle)
+               isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
+                              ISP_CTRL);
+}
+
+/*
+ * Configure the bridge and lane shifter. Valid inputs are
+ *
+ * CCDC_INPUT_PARALLEL: Parallel interface
+ * CCDC_INPUT_CSI2A: CSI2a receiver
+ * CCDC_INPUT_CCP2B: CCP2b receiver
+ * CCDC_INPUT_CSI2C: CSI2c receiver
+ *
+ * The bridge and lane shifter are configured according to the selected input
+ * and the ISP platform data.
+ */
+void omap3isp_configure_bridge(struct isp_device *isp,
+                              enum ccdc_input_entity input,
+                              const struct isp_parallel_platform_data *pdata)
+{
+       u32 ispctrl_val;
+
+       ispctrl_val  = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+       ispctrl_val &= ~ISPCTRL_SHIFT_MASK;
+       ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
+       ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
+       ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
+
+       switch (input) {
+       case CCDC_INPUT_PARALLEL:
+               ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
+               ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT;
+               ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
+               ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
+               break;
+
+       case CCDC_INPUT_CSI2A:
+               ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA;
+               break;
+
+       case CCDC_INPUT_CCP2B:
+               ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
+               break;
+
+       case CCDC_INPUT_CSI2C:
+               ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC;
+               break;
+
+       default:
+               return;
+       }
+
+       ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
+       ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
+
+       isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+}
+
+/**
+ * isp_set_pixel_clock - Configures the ISP pixel clock
+ * @isp: OMAP3 ISP device
+ * @pixelclk: Average pixel clock in Hz
+ *
+ * Set the average pixel clock required by the sensor. The ISP will use the
+ * lowest possible memory bandwidth settings compatible with the clock.
+ **/
+static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk)
+{
+       isp->isp_ccdc.vpcfg.pixelclk = pixelclk;
+}
+
+void omap3isp_hist_dma_done(struct isp_device *isp)
+{
+       if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
+           omap3isp_stat_pcr_busy(&isp->isp_hist)) {
+               /* Histogram cannot be enabled in this frame anymore */
+               atomic_set(&isp->isp_hist.buf_err, 1);
+               dev_dbg(isp->dev, "hist: Out of synchronization with "
+                                 "CCDC. Ignoring next buffer.\n");
+       }
+}
+
+static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
+{
+       static const char *name[] = {
+               "CSIA_IRQ",
+               "res1",
+               "res2",
+               "CSIB_LCM_IRQ",
+               "CSIB_IRQ",
+               "res5",
+               "res6",
+               "res7",
+               "CCDC_VD0_IRQ",
+               "CCDC_VD1_IRQ",
+               "CCDC_VD2_IRQ",
+               "CCDC_ERR_IRQ",
+               "H3A_AF_DONE_IRQ",
+               "H3A_AWB_DONE_IRQ",
+               "res14",
+               "res15",
+               "HIST_DONE_IRQ",
+               "CCDC_LSC_DONE",
+               "CCDC_LSC_PREFETCH_COMPLETED",
+               "CCDC_LSC_PREFETCH_ERROR",
+               "PRV_DONE_IRQ",
+               "CBUFF_IRQ",
+               "res22",
+               "res23",
+               "RSZ_DONE_IRQ",
+               "OVF_IRQ",
+               "res26",
+               "res27",
+               "MMU_ERR_IRQ",
+               "OCP_ERR_IRQ",
+               "SEC_ERR_IRQ",
+               "HS_VS_IRQ",
+       };
+       int i;
+
+       dev_dbg(isp->dev, "");
+
+       for (i = 0; i < ARRAY_SIZE(name); i++) {
+               if ((1 << i) & irqstatus)
+                       printk(KERN_CONT "%s ", name[i]);
+       }
+       printk(KERN_CONT "\n");
+}
+
+static void isp_isr_sbl(struct isp_device *isp)
+{
+       struct device *dev = isp->dev;
+       u32 sbl_pcr;
+
+       /*
+        * Handle shared buffer logic overflows for video buffers.
+        * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
+        */
+       sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+       isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+       sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
+
+       if (sbl_pcr)
+               dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
+
+       if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
+                    | ISPSBL_PCR_CSIB_WBL_OVF)) {
+               isp->isp_ccdc.error = 1;
+               if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
+                       isp->isp_prev.error = 1;
+               if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
+                       isp->isp_res.error = 1;
+       }
+
+       if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
+               isp->isp_prev.error = 1;
+               if (isp->isp_res.input == RESIZER_INPUT_VP &&
+                   !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
+                       isp->isp_res.error = 1;
+       }
+
+       if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
+                      | ISPSBL_PCR_RSZ2_WBL_OVF
+                      | ISPSBL_PCR_RSZ3_WBL_OVF
+                      | ISPSBL_PCR_RSZ4_WBL_OVF))
+               isp->isp_res.error = 1;
+
+       if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
+               omap3isp_stat_sbl_overflow(&isp->isp_af);
+
+       if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF)
+               omap3isp_stat_sbl_overflow(&isp->isp_aewb);
+}
+
+/*
+ * isp_isr - Interrupt Service Routine for Camera ISP module.
+ * @irq: Not used currently.
+ * @_isp: Pointer to the OMAP3 ISP device
+ *
+ * Handles the corresponding callback if plugged in.
+ *
+ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
+ * IRQ wasn't handled.
+ */
+static irqreturn_t isp_isr(int irq, void *_isp)
+{
+       static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ |
+                                      IRQ0STATUS_CCDC_LSC_DONE_IRQ |
+                                      IRQ0STATUS_CCDC_VD0_IRQ |
+                                      IRQ0STATUS_CCDC_VD1_IRQ |
+                                      IRQ0STATUS_HS_VS_IRQ;
+       struct isp_device *isp = _isp;
+       u32 irqstatus;
+       int ret;
+
+       irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+       isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+       isp_isr_sbl(isp);
+
+       if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
+               ret = omap3isp_csi2_isr(&isp->isp_csi2a);
+               if (ret)
+                       isp->isp_ccdc.error = 1;
+       }
+
+       if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+               ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
+               if (ret)
+                       isp->isp_ccdc.error = 1;
+       }
+
+       if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
+               if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
+                       omap3isp_preview_isr_frame_sync(&isp->isp_prev);
+               if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
+                       omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+               omap3isp_stat_isr_frame_sync(&isp->isp_aewb);
+               omap3isp_stat_isr_frame_sync(&isp->isp_af);
+               omap3isp_stat_isr_frame_sync(&isp->isp_hist);
+       }
+
+       if (irqstatus & ccdc_events)
+               omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events);
+
+       if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) {
+               if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER)
+                       omap3isp_resizer_isr_frame_sync(&isp->isp_res);
+               omap3isp_preview_isr(&isp->isp_prev);
+       }
+
+       if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ)
+               omap3isp_resizer_isr(&isp->isp_res);
+
+       if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ)
+               omap3isp_stat_isr(&isp->isp_aewb);
+
+       if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ)
+               omap3isp_stat_isr(&isp->isp_af);
+
+       if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ)
+               omap3isp_stat_isr(&isp->isp_hist);
+
+       omap3isp_flush(isp);
+
+#if defined(DEBUG) && defined(ISP_ISR_DEBUG)
+       isp_isr_dbg(isp, irqstatus);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline power management
+ *
+ * Entities must be powered up when part of a pipeline that contains at least
+ * one open video device node.
+ *
+ * To achieve this use the entity use_count field to track the number of users.
+ * For entities corresponding to video device nodes the use_count field stores
+ * the users count of the node. For entities corresponding to subdevs the
+ * use_count field stores the total number of users of all video device nodes
+ * in the pipeline.
+ *
+ * The omap3isp_pipeline_pm_use() function must be called in the open() and
+ * close() handlers of video device nodes. It increments or decrements the use
+ * count of all subdev entities in the pipeline.
+ *
+ * To react to link management on powered pipelines, the link setup notification
+ * callback updates the use count of all entities in the source and sink sides
+ * of the link.
+ */
+
+/*
+ * isp_pipeline_pm_use_count - Count the number of users of a pipeline
+ * @entity: The entity
+ *
+ * Return the total number of users of all video device nodes in the pipeline.
+ */
+static int isp_pipeline_pm_use_count(struct media_entity *entity)
+{
+       struct media_entity_graph graph;
+       int use = 0;
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+                       use += entity->use_count;
+       }
+
+       return use;
+}
+
+/*
+ * isp_pipeline_pm_power_one - Apply power change to an entity
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Change the entity use count by @change. If the entity is a subdev update its
+ * power state by calling the core::s_power operation when the use count goes
+ * from 0 to != 0 or from != 0 to 0.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
+{
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+              ? media_entity_to_v4l2_subdev(entity) : NULL;
+
+       if (entity->use_count == 0 && change > 0 && subdev != NULL) {
+               ret = v4l2_subdev_call(subdev, core, s_power, 1);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return ret;
+       }
+
+       entity->use_count += change;
+       WARN_ON(entity->use_count < 0);
+
+       if (entity->use_count == 0 && change < 0 && subdev != NULL)
+               v4l2_subdev_call(subdev, core, s_power, 0);
+
+       return 0;
+}
+
+/*
+ * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Walk the pipeline to update the use count and the power state of all non-node
+ * entities.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int isp_pipeline_pm_power(struct media_entity *entity, int change)
+{
+       struct media_entity_graph graph;
+       struct media_entity *first = entity;
+       int ret = 0;
+
+       if (!change)
+               return 0;
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+                       ret = isp_pipeline_pm_power_one(entity, change);
+
+       if (!ret)
+               return 0;
+
+       media_entity_graph_walk_start(&graph, first);
+
+       while ((first = media_entity_graph_walk_next(&graph))
+              && first != entity)
+               if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+                       isp_pipeline_pm_power_one(first, -change);
+
+       return ret;
+}
+
+/*
+ * omap3isp_pipeline_pm_use - Update the use count of an entity
+ * @entity: The entity
+ * @use: Use (1) or stop using (0) the entity
+ *
+ * Update the use count of all entities in the pipeline and power entities on or
+ * off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. No failure can occur when the use parameter is
+ * set to 0.
+ */
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
+{
+       int change = use ? 1 : -1;
+       int ret;
+
+       mutex_lock(&entity->parent->graph_mutex);
+
+       /* Apply use count to node. */
+       entity->use_count += change;
+       WARN_ON(entity->use_count < 0);
+
+       /* Apply power change to connected non-nodes. */
+       ret = isp_pipeline_pm_power(entity, change);
+
+       mutex_unlock(&entity->parent->graph_mutex);
+
+       return ret;
+}
+
+/*
+ * isp_pipeline_link_notify - Link management notification callback
+ * @source: Pad at the start of the link
+ * @sink: Pad at the end of the link
+ * @flags: New link flags that will be applied
+ *
+ * React to link management on powered pipelines by updating the use count of
+ * all entities in the source and sink sides of the link. Entities are powered
+ * on or off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. This function will not fail for disconnection
+ * events.
+ */
+static int isp_pipeline_link_notify(struct media_pad *source,
+                                   struct media_pad *sink, u32 flags)
+{
+       int source_use = isp_pipeline_pm_use_count(source->entity);
+       int sink_use = isp_pipeline_pm_use_count(sink->entity);
+       int ret;
+
+       if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+               /* Powering off entities is assumed to never fail. */
+               isp_pipeline_pm_power(source->entity, -sink_use);
+               isp_pipeline_pm_power(sink->entity, -source_use);
+               return 0;
+       }
+
+       ret = isp_pipeline_pm_power(source->entity, sink_use);
+       if (ret < 0)
+               return ret;
+
+       ret = isp_pipeline_pm_power(sink->entity, source_use);
+       if (ret < 0)
+               isp_pipeline_pm_power(source->entity, -sink_use);
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline stream management
+ */
+
+/*
+ * isp_pipeline_enable - Enable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @mode: Stream mode (single shot or continuous)
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successfull, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int isp_pipeline_enable(struct isp_pipeline *pipe,
+                              enum isp_pipeline_stream_state mode)
+{
+       struct isp_device *isp = pipe->output->isp;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       pipe->do_propagation = false;
+
+       entity = &pipe->output->video.entity;
+       while (1) {
+               pad = &entity->pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               pad = media_entity_remote_source(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               entity = pad->entity;
+               subdev = media_entity_to_v4l2_subdev(entity);
+
+               ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       break;
+
+               if (subdev == &isp->isp_ccdc.subdev) {
+                       v4l2_subdev_call(&isp->isp_aewb.subdev, video,
+                                       s_stream, mode);
+                       v4l2_subdev_call(&isp->isp_af.subdev, video,
+                                       s_stream, mode);
+                       v4l2_subdev_call(&isp->isp_hist.subdev, video,
+                                       s_stream, mode);
+                       pipe->do_propagation = true;
+               }
+       }
+
+       /* Frame number propagation. In continuous streaming mode the number
+        * is incremented in the frame start ISR. In mem-to-mem mode
+        * singleshot is used and frame start IRQs are not available.
+        * Thus we have to increment the number here.
+        */
+       if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
+               atomic_inc(&pipe->frame_number);
+
+       return ret;
+}
+
+static int isp_pipeline_wait_resizer(struct isp_device *isp)
+{
+       return omap3isp_resizer_busy(&isp->isp_res);
+}
+
+static int isp_pipeline_wait_preview(struct isp_device *isp)
+{
+       return omap3isp_preview_busy(&isp->isp_prev);
+}
+
+static int isp_pipeline_wait_ccdc(struct isp_device *isp)
+{
+       return omap3isp_stat_busy(&isp->isp_af)
+           || omap3isp_stat_busy(&isp->isp_aewb)
+           || omap3isp_stat_busy(&isp->isp_hist)
+           || omap3isp_ccdc_busy(&isp->isp_ccdc);
+}
+
+#define ISP_STOP_TIMEOUT       msecs_to_jiffies(1000)
+
+static int isp_pipeline_wait(struct isp_device *isp,
+                            int(*busy)(struct isp_device *isp))
+{
+       unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
+
+       while (!time_after(jiffies, timeout)) {
+               if (!busy(isp))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * isp_pipeline_disable - Disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
+ *
+ * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
+ * can't be stopped (in which case a software reset of the ISP is probably
+ * necessary).
+ */
+static int isp_pipeline_disable(struct isp_pipeline *pipe)
+{
+       struct isp_device *isp = pipe->output->isp;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       int failure = 0;
+       int ret;
+
+       /*
+        * We need to stop all the modules after CCDC first or they'll
+        * never stop since they may not get a full frame from CCDC.
+        */
+       entity = &pipe->output->video.entity;
+       while (1) {
+               pad = &entity->pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               pad = media_entity_remote_source(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               entity = pad->entity;
+               subdev = media_entity_to_v4l2_subdev(entity);
+
+               if (subdev == &isp->isp_ccdc.subdev) {
+                       v4l2_subdev_call(&isp->isp_aewb.subdev,
+                                        video, s_stream, 0);
+                       v4l2_subdev_call(&isp->isp_af.subdev,
+                                        video, s_stream, 0);
+                       v4l2_subdev_call(&isp->isp_hist.subdev,
+                                        video, s_stream, 0);
+               }
+
+               v4l2_subdev_call(subdev, video, s_stream, 0);
+
+               if (subdev == &isp->isp_res.subdev)
+                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
+               else if (subdev == &isp->isp_prev.subdev)
+                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
+               else if (subdev == &isp->isp_ccdc.subdev)
+                       ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
+               else
+                       ret = 0;
+
+               if (ret) {
+                       dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
+                       failure = -ETIMEDOUT;
+               }
+       }
+
+       return failure;
+}
+
+/*
+ * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: ISP pipeline
+ * @state: Stream state (stopped, single shot or continuous)
+ *
+ * Set the pipeline to the given stream state. Pipelines can be started in
+ * single-shot or continuous mode.
+ *
+ * Return 0 if successfull, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+                                enum isp_pipeline_stream_state state)
+{
+       int ret;
+
+       if (state == ISP_PIPELINE_STREAM_STOPPED)
+               ret = isp_pipeline_disable(pipe);
+       else
+               ret = isp_pipeline_enable(pipe, state);
+       pipe->stream_state = state;
+
+       return ret;
+}
+
+/*
+ * isp_pipeline_resume - Resume streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Resume video output and input and re-enable pipeline.
+ */
+static void isp_pipeline_resume(struct isp_pipeline *pipe)
+{
+       int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT;
+
+       omap3isp_video_resume(pipe->output, !singleshot);
+       if (singleshot)
+               omap3isp_video_resume(pipe->input, 0);
+       isp_pipeline_enable(pipe, pipe->stream_state);
+}
+
+/*
+ * isp_pipeline_suspend - Suspend streaming on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Suspend pipeline.
+ */
+static void isp_pipeline_suspend(struct isp_pipeline *pipe)
+{
+       isp_pipeline_disable(pipe);
+}
+
+/*
+ * isp_pipeline_is_last - Verify if entity has an enabled link to the output
+ *                       video node
+ * @me: ISP module's media entity
+ *
+ * Returns 1 if the entity has an enabled link to the output video node or 0
+ * otherwise. It's true only while pipeline can have no more than one output
+ * node.
+ */
+static int isp_pipeline_is_last(struct media_entity *me)
+{
+       struct isp_pipeline *pipe;
+       struct media_pad *pad;
+
+       if (!me->pipe)
+               return 0;
+       pipe = to_isp_pipeline(me);
+       if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
+               return 0;
+       pad = media_entity_remote_source(&pipe->output->pad);
+       return pad->entity == me;
+}
+
+/*
+ * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Suspend the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_suspend_module_pipeline(struct media_entity *me)
+{
+       if (isp_pipeline_is_last(me))
+               isp_pipeline_suspend(to_isp_pipeline(me));
+}
+
+/*
+ * isp_resume_module_pipeline - Resume pipeline to which belongs the module
+ * @me: ISP module's media entity
+ *
+ * Resume the whole pipeline if module's entity has an enabled link to the
+ * output video node. It works only while pipeline can have no more than one
+ * output node.
+ */
+static void isp_resume_module_pipeline(struct media_entity *me)
+{
+       if (isp_pipeline_is_last(me))
+               isp_pipeline_resume(to_isp_pipeline(me));
+}
+
+/*
+ * isp_suspend_modules - Suspend ISP submodules.
+ * @isp: OMAP3 ISP device
+ *
+ * Returns 0 if suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to suspend the submodules.
+ */
+static int isp_suspend_modules(struct isp_device *isp)
+{
+       unsigned long timeout;
+
+       omap3isp_stat_suspend(&isp->isp_aewb);
+       omap3isp_stat_suspend(&isp->isp_af);
+       omap3isp_stat_suspend(&isp->isp_hist);
+       isp_suspend_module_pipeline(&isp->isp_res.subdev.entity);
+       isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity);
+       isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity);
+       isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity);
+       isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity);
+
+       timeout = jiffies + ISP_STOP_TIMEOUT;
+       while (omap3isp_stat_busy(&isp->isp_af)
+           || omap3isp_stat_busy(&isp->isp_aewb)
+           || omap3isp_stat_busy(&isp->isp_hist)
+           || omap3isp_preview_busy(&isp->isp_prev)
+           || omap3isp_resizer_busy(&isp->isp_res)
+           || omap3isp_ccdc_busy(&isp->isp_ccdc)) {
+               if (time_after(jiffies, timeout)) {
+                       dev_info(isp->dev, "can't stop modules.\n");
+                       return 1;
+               }
+               msleep(1);
+       }
+
+       return 0;
+}
+
+/*
+ * isp_resume_modules - Resume ISP submodules.
+ * @isp: OMAP3 ISP device
+ */
+static void isp_resume_modules(struct isp_device *isp)
+{
+       omap3isp_stat_resume(&isp->isp_aewb);
+       omap3isp_stat_resume(&isp->isp_af);
+       omap3isp_stat_resume(&isp->isp_hist);
+       isp_resume_module_pipeline(&isp->isp_res.subdev.entity);
+       isp_resume_module_pipeline(&isp->isp_prev.subdev.entity);
+       isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity);
+       isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity);
+       isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity);
+}
+
+/*
+ * isp_reset - Reset ISP with a timeout wait for idle.
+ * @isp: OMAP3 ISP device
+ */
+static int isp_reset(struct isp_device *isp)
+{
+       unsigned long timeout = 0;
+
+       isp_reg_writel(isp,
+                      isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
+                      | ISP_SYSCONFIG_SOFTRESET,
+                      OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
+       while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN,
+                              ISP_SYSSTATUS) & 0x1)) {
+               if (timeout++ > 10000) {
+                       dev_alert(isp->dev, "cannot reset ISP\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+       }
+
+       return 0;
+}
+
+/*
+ * isp_save_context - Saves the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ *            modify on OMAP.
+ */
+static void
+isp_save_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+       struct isp_reg *next = reg_list;
+
+       for (; next->reg != ISP_TOK_TERM; next++)
+               next->val = isp_reg_readl(isp, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_restore_context - Restores the values of the ISP module registers.
+ * @isp: OMAP3 ISP device
+ * @reg_list: Structure containing pairs of register address and value to
+ *            modify on OMAP.
+ */
+static void
+isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list)
+{
+       struct isp_reg *next = reg_list;
+
+       for (; next->reg != ISP_TOK_TERM; next++)
+               isp_reg_writel(isp, next->val, next->mmio_range, next->reg);
+}
+
+/*
+ * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for saving the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_save_ctx(struct isp_device *isp)
+{
+       isp_save_context(isp, isp_reg_list);
+       if (isp->iommu)
+               iommu_save_ctx(isp->iommu);
+}
+
+/*
+ * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @isp: OMAP3 ISP device
+ *
+ * Routine for restoring the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ */
+static void isp_restore_ctx(struct isp_device *isp)
+{
+       isp_restore_context(isp, isp_reg_list);
+       if (isp->iommu)
+               iommu_restore_ctx(isp->iommu);
+       omap3isp_ccdc_restore_context(isp);
+       omap3isp_preview_restore_context(isp);
+}
+
+/* -----------------------------------------------------------------------------
+ * SBL resources management
+ */
+#define OMAP3_ISP_SBL_READ     (OMAP3_ISP_SBL_CSI1_READ | \
+                                OMAP3_ISP_SBL_CCDC_LSC_READ | \
+                                OMAP3_ISP_SBL_PREVIEW_READ | \
+                                OMAP3_ISP_SBL_RESIZER_READ)
+#define OMAP3_ISP_SBL_WRITE    (OMAP3_ISP_SBL_CSI1_WRITE | \
+                                OMAP3_ISP_SBL_CSI2A_WRITE | \
+                                OMAP3_ISP_SBL_CSI2C_WRITE | \
+                                OMAP3_ISP_SBL_CCDC_WRITE | \
+                                OMAP3_ISP_SBL_PREVIEW_WRITE)
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+       u32 sbl = 0;
+
+       isp->sbl_resources |= res;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)
+               sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)
+               sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)
+               sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)
+               sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE)
+               sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+       if (isp->sbl_resources & OMAP3_ISP_SBL_READ)
+               sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res)
+{
+       u32 sbl = 0;
+
+       isp->sbl_resources &= ~res;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ))
+               sbl |= ISPCTRL_SBL_SHARED_RPORTA;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ))
+               sbl |= ISPCTRL_SBL_SHARED_RPORTB;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE))
+               sbl |= ISPCTRL_SBL_SHARED_WPORTC;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE))
+               sbl |= ISPCTRL_SBL_WR0_RAM_EN;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE))
+               sbl |= ISPCTRL_SBL_WR1_RAM_EN;
+
+       if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ))
+               sbl |= ISPCTRL_SBL_RD_RAM_EN;
+
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
+}
+
+/*
+ * isp_module_sync_idle - Helper to sync module with its idle state
+ * @me: ISP submodule's media entity
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule needs to wait for next interrupt. If
+ * yes, makes the caller to sleep while waiting for such event.
+ */
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+                             atomic_t *stopping)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(me);
+
+       if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED ||
+           (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+            !isp_pipeline_ready(pipe)))
+               return 0;
+
+       /*
+        * atomic_set() doesn't include memory barrier on ARM platform for SMP
+        * scenario. We'll call it here to avoid race conditions.
+        */
+       atomic_set(stopping, 1);
+       smp_mb();
+
+       /*
+        * If module is the last one, it's writing to memory. In this case,
+        * it's necessary to check if the module is already paused due to
+        * DMA queue underrun or if it has to wait for next interrupt to be
+        * idle.
+        * If it isn't the last one, the function won't sleep but *stopping
+        * will still be set to warn next submodule caller's interrupt the
+        * module wants to be idle.
+        */
+       if (isp_pipeline_is_last(me)) {
+               struct isp_video *video = pipe->output;
+               unsigned long flags;
+               spin_lock_irqsave(&video->queue->irqlock, flags);
+               if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+                       spin_unlock_irqrestore(&video->queue->irqlock, flags);
+                       atomic_set(stopping, 0);
+                       smp_mb();
+                       return 0;
+               }
+               spin_unlock_irqrestore(&video->queue->irqlock, flags);
+               if (!wait_event_timeout(*wait, !atomic_read(stopping),
+                                       msecs_to_jiffies(1000))) {
+                       atomic_set(stopping, 0);
+                       smp_mb();
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
+ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISP submodule was stopping. In case of yes, it
+ * notices the caller by setting stopping to 0 and waking up the wait queue.
+ * Returns 1 if it was stopping or 0 otherwise.
+ */
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+                                    atomic_t *stopping)
+{
+       if (atomic_cmpxchg(stopping, 1, 0)) {
+               wake_up(wait);
+               return 1;
+       }
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Clock management
+ */
+
+#define ISPCTRL_CLKS_MASK      (ISPCTRL_H3A_CLK_EN | \
+                                ISPCTRL_HIST_CLK_EN | \
+                                ISPCTRL_RSZ_CLK_EN | \
+                                (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \
+                                (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN))
+
+static void __isp_subclk_update(struct isp_device *isp)
+{
+       u32 clk = 0;
+
+       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A)
+               clk |= ISPCTRL_H3A_CLK_EN;
+
+       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
+               clk |= ISPCTRL_HIST_CLK_EN;
+
+       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER)
+               clk |= ISPCTRL_RSZ_CLK_EN;
+
+       /* NOTE: For CCDC & Preview submodules, we need to affect internal
+        *       RAM aswell.
+        */
+       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
+               clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
+
+       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW)
+               clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN;
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                       ISPCTRL_CLKS_MASK, clk);
+}
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+                           enum isp_subclk_resource res)
+{
+       isp->subclk_resources |= res;
+
+       __isp_subclk_update(isp);
+}
+
+void omap3isp_subclk_disable(struct isp_device *isp,
+                            enum isp_subclk_resource res)
+{
+       isp->subclk_resources &= ~res;
+
+       __isp_subclk_update(isp);
+}
+
+/*
+ * isp_enable_clocks - Enable ISP clocks
+ * @isp: OMAP3 ISP device
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ */
+static int isp_enable_clocks(struct isp_device *isp)
+{
+       int r;
+       unsigned long rate;
+       int divisor;
+
+       /*
+        * cam_mclk clock chain:
+        *   dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk
+        *
+        * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are
+        * set to the same value. Hence the rate set for dpll4_m5
+        * has to be twice of what is set on OMAP3430 to get
+        * the required value for cam_mclk
+        */
+       if (cpu_is_omap3630())
+               divisor = 1;
+       else
+               divisor = 2;
+
+       r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]);
+       if (r) {
+               dev_err(isp->dev, "clk_enable cam_ick failed\n");
+               goto out_clk_enable_ick;
+       }
+       r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK],
+                        CM_CAM_MCLK_HZ/divisor);
+       if (r) {
+               dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n");
+               goto out_clk_enable_mclk;
+       }
+       r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]);
+       if (r) {
+               dev_err(isp->dev, "clk_enable cam_mclk failed\n");
+               goto out_clk_enable_mclk;
+       }
+       rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+       if (rate != CM_CAM_MCLK_HZ)
+               dev_warn(isp->dev, "unexpected cam_mclk rate:\n"
+                                  " expected : %d\n"
+                                  " actual   : %ld\n", CM_CAM_MCLK_HZ, rate);
+       r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]);
+       if (r) {
+               dev_err(isp->dev, "clk_enable csi2_fck failed\n");
+               goto out_clk_enable_csi2_fclk;
+       }
+       return 0;
+
+out_clk_enable_csi2_fclk:
+       clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+out_clk_enable_mclk:
+       clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+out_clk_enable_ick:
+       return r;
+}
+
+/*
+ * isp_disable_clocks - Disable ISP clocks
+ * @isp: OMAP3 ISP device
+ */
+static void isp_disable_clocks(struct isp_device *isp)
+{
+       clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
+       clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
+       clk_disable(isp->clock[ISP_CLK_CSI2_FCK]);
+}
+
+static const char *isp_clocks[] = {
+       "cam_ick",
+       "cam_mclk",
+       "dpll4_m5_ck",
+       "csi2_96m_fck",
+       "l3_ick",
+};
+
+static void isp_put_clocks(struct isp_device *isp)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+               if (isp->clock[i]) {
+                       clk_put(isp->clock[i]);
+                       isp->clock[i] = NULL;
+               }
+       }
+}
+
+static int isp_get_clocks(struct isp_device *isp)
+{
+       struct clk *clk;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
+               clk = clk_get(isp->dev, isp_clocks[i]);
+               if (IS_ERR(clk)) {
+                       dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
+                       isp_put_clocks(isp);
+                       return PTR_ERR(clk);
+               }
+
+               isp->clock[i] = clk;
+       }
+
+       return 0;
+}
+
+/*
+ * omap3isp_get - Acquire the ISP resource.
+ *
+ * Initializes the clocks for the first acquire.
+ *
+ * Increment the reference count on the ISP. If the first reference is taken,
+ * enable clocks and power-up all submodules.
+ *
+ * Return a pointer to the ISP device structure, or NULL if an error occured.
+ */
+struct isp_device *omap3isp_get(struct isp_device *isp)
+{
+       struct isp_device *__isp = isp;
+
+       if (isp == NULL)
+               return NULL;
+
+       mutex_lock(&isp->isp_mutex);
+       if (isp->ref_count > 0)
+               goto out;
+
+       if (isp_enable_clocks(isp) < 0) {
+               __isp = NULL;
+               goto out;
+       }
+
+       /* We don't want to restore context before saving it! */
+       if (isp->has_context)
+               isp_restore_ctx(isp);
+       else
+               isp->has_context = 1;
+
+       isp_enable_interrupts(isp);
+
+out:
+       if (__isp != NULL)
+               isp->ref_count++;
+       mutex_unlock(&isp->isp_mutex);
+
+       return __isp;
+}
+
+/*
+ * omap3isp_put - Release the ISP
+ *
+ * Decrement the reference count on the ISP. If the last reference is released,
+ * power-down all submodules, disable clocks and free temporary buffers.
+ */
+void omap3isp_put(struct isp_device *isp)
+{
+       if (isp == NULL)
+               return;
+
+       mutex_lock(&isp->isp_mutex);
+       BUG_ON(isp->ref_count == 0);
+       if (--isp->ref_count == 0) {
+               isp_disable_interrupts(isp);
+               isp_save_ctx(isp);
+               isp_disable_clocks(isp);
+       }
+       mutex_unlock(&isp->isp_mutex);
+}
+
+/* --------------------------------------------------------------------------
+ * Platform device driver
+ */
+
+/*
+ * omap3isp_print_status - Prints the values of the ISP Control Module registers
+ * @isp: OMAP3 ISP device
+ */
+#define ISP_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name))
+#define SBL_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name))
+
+void omap3isp_print_status(struct isp_device *isp)
+{
+       dev_dbg(isp->dev, "-------------ISP Register dump--------------\n");
+
+       ISP_PRINT_REGISTER(isp, SYSCONFIG);
+       ISP_PRINT_REGISTER(isp, SYSSTATUS);
+       ISP_PRINT_REGISTER(isp, IRQ0ENABLE);
+       ISP_PRINT_REGISTER(isp, IRQ0STATUS);
+       ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH);
+       ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY);
+       ISP_PRINT_REGISTER(isp, CTRL);
+       ISP_PRINT_REGISTER(isp, TCTRL_CTRL);
+       ISP_PRINT_REGISTER(isp, TCTRL_FRAME);
+       ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY);
+       ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY);
+       ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY);
+       ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH);
+       ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH);
+       ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH);
+
+       SBL_PRINT_REGISTER(isp, PCR);
+       SBL_PRINT_REGISTER(isp, SDR_REQ_EXP);
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * Power management support.
+ *
+ * As the ISP can't properly handle an input video stream interruption on a non
+ * frame boundary, the ISP pipelines need to be stopped before sensors get
+ * suspended. However, as suspending the sensors can require a running clock,
+ * which can be provided by the ISP, the ISP can't be completely suspended
+ * before the sensor.
+ *
+ * To solve this problem power management support is split into prepare/complete
+ * and suspend/resume operations. The pipelines are stopped in prepare() and the
+ * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in
+ * resume(), and the the pipelines are restarted in complete().
+ *
+ * TODO: PM dependencies between the ISP and sensors are not modeled explicitly
+ * yet.
+ */
+static int isp_pm_prepare(struct device *dev)
+{
+       struct isp_device *isp = dev_get_drvdata(dev);
+       int reset;
+
+       WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+       if (isp->ref_count == 0)
+               return 0;
+
+       reset = isp_suspend_modules(isp);
+       isp_disable_interrupts(isp);
+       isp_save_ctx(isp);
+       if (reset)
+               isp_reset(isp);
+
+       return 0;
+}
+
+static int isp_pm_suspend(struct device *dev)
+{
+       struct isp_device *isp = dev_get_drvdata(dev);
+
+       WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+       if (isp->ref_count)
+               isp_disable_clocks(isp);
+
+       return 0;
+}
+
+static int isp_pm_resume(struct device *dev)
+{
+       struct isp_device *isp = dev_get_drvdata(dev);
+
+       if (isp->ref_count == 0)
+               return 0;
+
+       return isp_enable_clocks(isp);
+}
+
+static void isp_pm_complete(struct device *dev)
+{
+       struct isp_device *isp = dev_get_drvdata(dev);
+
+       if (isp->ref_count == 0)
+               return;
+
+       isp_restore_ctx(isp);
+       isp_enable_interrupts(isp);
+       isp_resume_modules(isp);
+}
+
+#else
+
+#define isp_pm_prepare NULL
+#define isp_pm_suspend NULL
+#define isp_pm_resume  NULL
+#define isp_pm_complete        NULL
+
+#endif /* CONFIG_PM */
+
+static void isp_unregister_entities(struct isp_device *isp)
+{
+       omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
+       omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
+       omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
+       omap3isp_preview_unregister_entities(&isp->isp_prev);
+       omap3isp_resizer_unregister_entities(&isp->isp_res);
+       omap3isp_stat_unregister_entities(&isp->isp_aewb);
+       omap3isp_stat_unregister_entities(&isp->isp_af);
+       omap3isp_stat_unregister_entities(&isp->isp_hist);
+
+       v4l2_device_unregister(&isp->v4l2_dev);
+       media_device_unregister(&isp->media_dev);
+}
+
+/*
+ * isp_register_subdev_group - Register a group of subdevices
+ * @isp: OMAP3 ISP device
+ * @board_info: I2C subdevs board information array
+ *
+ * Register all I2C subdevices in the board_info array. The array must be
+ * terminated by a NULL entry, and the first entry must be the sensor.
+ *
+ * Return a pointer to the sensor media entity if it has been successfully
+ * registered, or NULL otherwise.
+ */
+static struct v4l2_subdev *
+isp_register_subdev_group(struct isp_device *isp,
+                    struct isp_subdev_i2c_board_info *board_info)
+{
+       struct v4l2_subdev *sensor = NULL;
+       unsigned int first;
+
+       if (board_info->board_info == NULL)
+               return NULL;
+
+       for (first = 1; board_info->board_info; ++board_info, first = 0) {
+               struct v4l2_subdev *subdev;
+               struct i2c_adapter *adapter;
+
+               adapter = i2c_get_adapter(board_info->i2c_adapter_id);
+               if (adapter == NULL) {
+                       printk(KERN_ERR "%s: Unable to get I2C adapter %d for "
+                               "device %s\n", __func__,
+                               board_info->i2c_adapter_id,
+                               board_info->board_info->type);
+                       continue;
+               }
+
+               subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
+                               board_info->board_info, NULL);
+               if (subdev == NULL) {
+                       printk(KERN_ERR "%s: Unable to register subdev %s\n",
+                               __func__, board_info->board_info->type);
+                       continue;
+               }
+
+               if (first)
+                       sensor = subdev;
+       }
+
+       return sensor;
+}
+
+static int isp_register_entities(struct isp_device *isp)
+{
+       struct isp_platform_data *pdata = isp->pdata;
+       struct isp_v4l2_subdevs_group *subdevs;
+       int ret;
+
+       isp->media_dev.dev = isp->dev;
+       strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
+               sizeof(isp->media_dev.model));
+       isp->media_dev.link_notify = isp_pipeline_link_notify;
+       ret = media_device_register(&isp->media_dev);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: Media device registration failed (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       isp->v4l2_dev.mdev = &isp->media_dev;
+       ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
+                       __func__, ret);
+               goto done;
+       }
+
+       /* Register internal entities */
+       ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_preview_register_entities(&isp->isp_prev,
+                                                &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       /* Register external entities */
+       for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) {
+               struct v4l2_subdev *sensor;
+               struct media_entity *input;
+               unsigned int flags;
+               unsigned int pad;
+
+               sensor = isp_register_subdev_group(isp, subdevs->subdevs);
+               if (sensor == NULL)
+                       continue;
+
+               sensor->host_priv = subdevs;
+
+               /* Connect the sensor to the correct interface module. Parallel
+                * sensors are connected directly to the CCDC, while serial
+                * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
+                * through CSIPHY1 or CSIPHY2.
+                */
+               switch (subdevs->interface) {
+               case ISP_INTERFACE_PARALLEL:
+                       input = &isp->isp_ccdc.subdev.entity;
+                       pad = CCDC_PAD_SINK;
+                       flags = 0;
+                       break;
+
+               case ISP_INTERFACE_CSI2A_PHY2:
+                       input = &isp->isp_csi2a.subdev.entity;
+                       pad = CSI2_PAD_SINK;
+                       flags = MEDIA_LNK_FL_IMMUTABLE
+                             | MEDIA_LNK_FL_ENABLED;
+                       break;
+
+               case ISP_INTERFACE_CCP2B_PHY1:
+               case ISP_INTERFACE_CCP2B_PHY2:
+                       input = &isp->isp_ccp2.subdev.entity;
+                       pad = CCP2_PAD_SINK;
+                       flags = 0;
+                       break;
+
+               case ISP_INTERFACE_CSI2C_PHY1:
+                       input = &isp->isp_csi2c.subdev.entity;
+                       pad = CSI2_PAD_SINK;
+                       flags = MEDIA_LNK_FL_IMMUTABLE
+                             | MEDIA_LNK_FL_ENABLED;
+                       break;
+
+               default:
+                       printk(KERN_ERR "%s: invalid interface type %u\n",
+                              __func__, subdevs->interface);
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               ret = media_entity_create_link(&sensor->entity, 0, input, pad,
+                                              flags);
+               if (ret < 0)
+                       goto done;
+       }
+
+       ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
+
+done:
+       if (ret < 0)
+               isp_unregister_entities(isp);
+
+       return ret;
+}
+
+static void isp_cleanup_modules(struct isp_device *isp)
+{
+       omap3isp_h3a_aewb_cleanup(isp);
+       omap3isp_h3a_af_cleanup(isp);
+       omap3isp_hist_cleanup(isp);
+       omap3isp_resizer_cleanup(isp);
+       omap3isp_preview_cleanup(isp);
+       omap3isp_ccdc_cleanup(isp);
+       omap3isp_ccp2_cleanup(isp);
+       omap3isp_csi2_cleanup(isp);
+}
+
+static int isp_initialize_modules(struct isp_device *isp)
+{
+       int ret;
+
+       ret = omap3isp_csiphy_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "CSI PHY initialization failed\n");
+               goto error_csiphy;
+       }
+
+       ret = omap3isp_csi2_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "CSI2 initialization failed\n");
+               goto error_csi2;
+       }
+
+       ret = omap3isp_ccp2_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "CCP2 initialization failed\n");
+               goto error_ccp2;
+       }
+
+       ret = omap3isp_ccdc_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "CCDC initialization failed\n");
+               goto error_ccdc;
+       }
+
+       ret = omap3isp_preview_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "Preview initialization failed\n");
+               goto error_preview;
+       }
+
+       ret = omap3isp_resizer_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "Resizer initialization failed\n");
+               goto error_resizer;
+       }
+
+       ret = omap3isp_hist_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "Histogram initialization failed\n");
+               goto error_hist;
+       }
+
+       ret = omap3isp_h3a_aewb_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "H3A AEWB initialization failed\n");
+               goto error_h3a_aewb;
+       }
+
+       ret = omap3isp_h3a_af_init(isp);
+       if (ret < 0) {
+               dev_err(isp->dev, "H3A AF initialization failed\n");
+               goto error_h3a_af;
+       }
+
+       /* Connect the submodules. */
+       ret = media_entity_create_link(
+                       &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+                       &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
+                       &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
+                       &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+                       &isp->isp_aewb.subdev.entity, 0,
+                       MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+                       &isp->isp_af.subdev.entity, 0,
+                       MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
+                       &isp->isp_hist.subdev.entity, 0,
+                       MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+       if (ret < 0)
+               goto error_link;
+
+       return 0;
+
+error_link:
+       omap3isp_h3a_af_cleanup(isp);
+error_h3a_af:
+       omap3isp_h3a_aewb_cleanup(isp);
+error_h3a_aewb:
+       omap3isp_hist_cleanup(isp);
+error_hist:
+       omap3isp_resizer_cleanup(isp);
+error_resizer:
+       omap3isp_preview_cleanup(isp);
+error_preview:
+       omap3isp_ccdc_cleanup(isp);
+error_ccdc:
+       omap3isp_ccp2_cleanup(isp);
+error_ccp2:
+       omap3isp_csi2_cleanup(isp);
+error_csi2:
+error_csiphy:
+       return ret;
+}
+
+/*
+ * isp_remove - Remove ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Always returns 0.
+ */
+static int isp_remove(struct platform_device *pdev)
+{
+       struct isp_device *isp = platform_get_drvdata(pdev);
+       int i;
+
+       isp_unregister_entities(isp);
+       isp_cleanup_modules(isp);
+
+       omap3isp_get(isp);
+       iommu_put(isp->iommu);
+       omap3isp_put(isp);
+
+       free_irq(isp->irq_num, isp);
+       isp_put_clocks(isp);
+
+       for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+               if (isp->mmio_base[i]) {
+                       iounmap(isp->mmio_base[i]);
+                       isp->mmio_base[i] = NULL;
+               }
+
+               if (isp->mmio_base_phys[i]) {
+                       release_mem_region(isp->mmio_base_phys[i],
+                                          isp->mmio_size[i]);
+                       isp->mmio_base_phys[i] = 0;
+               }
+       }
+
+       regulator_put(isp->isp_csiphy1.vdd);
+       regulator_put(isp->isp_csiphy2.vdd);
+       kfree(isp);
+
+       return 0;
+}
+
+static int isp_map_mem_resource(struct platform_device *pdev,
+                               struct isp_device *isp,
+                               enum isp_mem_resources res)
+{
+       struct resource *mem;
+
+       /* request the mem region for the camera registers */
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
+       if (!mem) {
+               dev_err(isp->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+               dev_err(isp->dev,
+                       "cannot reserve camera register I/O region\n");
+               return -ENODEV;
+       }
+       isp->mmio_base_phys[res] = mem->start;
+       isp->mmio_size[res] = resource_size(mem);
+
+       /* map the region */
+       isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
+                                             isp->mmio_size[res]);
+       if (!isp->mmio_base[res]) {
+               dev_err(isp->dev, "cannot map camera register I/O region\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/*
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Returns 0 if successful,
+ *   -ENOMEM if no memory available,
+ *   -ENODEV if no platform device resources found
+ *     or no space for remapping registers,
+ *   -EINVAL if couldn't install ISR,
+ *   or clk_get return error value.
+ */
+static int isp_probe(struct platform_device *pdev)
+{
+       struct isp_platform_data *pdata = pdev->dev.platform_data;
+       struct isp_device *isp;
+       int ret;
+       int i, m;
+
+       if (pdata == NULL)
+               return -EINVAL;
+
+       isp = kzalloc(sizeof(*isp), GFP_KERNEL);
+       if (!isp) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               return -ENOMEM;
+       }
+
+       isp->autoidle = autoidle;
+       isp->platform_cb.set_xclk = isp_set_xclk;
+       isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
+
+       mutex_init(&isp->isp_mutex);
+       spin_lock_init(&isp->stat_lock);
+
+       isp->dev = &pdev->dev;
+       isp->pdata = pdata;
+       isp->ref_count = 0;
+
+       isp->raw_dmamask = DMA_BIT_MASK(32);
+       isp->dev->dma_mask = &isp->raw_dmamask;
+       isp->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+       platform_set_drvdata(pdev, isp);
+
+       /* Regulators */
+       isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
+       isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
+
+       /* Clocks */
+       ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
+       if (ret < 0)
+               goto error;
+
+       ret = isp_get_clocks(isp);
+       if (ret < 0)
+               goto error;
+
+       if (omap3isp_get(isp) == NULL)
+               goto error;
+
+       ret = isp_reset(isp);
+       if (ret < 0)
+               goto error_isp;
+
+       /* Memory resources */
+       isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+       dev_info(isp->dev, "Revision %d.%d found\n",
+                (isp->revision & 0xf0) >> 4, isp->revision & 0x0f);
+
+       for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
+               if (isp->revision == isp_res_maps[m].isp_rev)
+                       break;
+
+       if (m == ARRAY_SIZE(isp_res_maps)) {
+               dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n",
+                       (isp->revision & 0xf0) >> 4, isp->revision & 0xf);
+               ret = -ENODEV;
+               goto error_isp;
+       }
+
+       for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
+               if (isp_res_maps[m].map & 1 << i) {
+                       ret = isp_map_mem_resource(pdev, isp, i);
+                       if (ret)
+                               goto error_isp;
+               }
+       }
+
+       /* IOMMU */
+       isp->iommu = iommu_get("isp");
+       if (IS_ERR_OR_NULL(isp->iommu)) {
+               isp->iommu = NULL;
+               ret = -ENODEV;
+               goto error_isp;
+       }
+
+       /* Interrupt */
+       isp->irq_num = platform_get_irq(pdev, 0);
+       if (isp->irq_num <= 0) {
+               dev_err(isp->dev, "No IRQ resource\n");
+               ret = -ENODEV;
+               goto error_isp;
+       }
+
+       if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
+               dev_err(isp->dev, "Unable to request IRQ\n");
+               ret = -EINVAL;
+               goto error_isp;
+       }
+
+       /* Entities */
+       ret = isp_initialize_modules(isp);
+       if (ret < 0)
+               goto error_irq;
+
+       ret = isp_register_entities(isp);
+       if (ret < 0)
+               goto error_modules;
+
+       isp_power_settings(isp, 1);
+       omap3isp_put(isp);
+
+       return 0;
+
+error_modules:
+       isp_cleanup_modules(isp);
+error_irq:
+       free_irq(isp->irq_num, isp);
+error_isp:
+       iommu_put(isp->iommu);
+       omap3isp_put(isp);
+error:
+       isp_put_clocks(isp);
+
+       for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
+               if (isp->mmio_base[i]) {
+                       iounmap(isp->mmio_base[i]);
+                       isp->mmio_base[i] = NULL;
+               }
+
+               if (isp->mmio_base_phys[i]) {
+                       release_mem_region(isp->mmio_base_phys[i],
+                                          isp->mmio_size[i]);
+                       isp->mmio_base_phys[i] = 0;
+               }
+       }
+       regulator_put(isp->isp_csiphy2.vdd);
+       regulator_put(isp->isp_csiphy1.vdd);
+       platform_set_drvdata(pdev, NULL);
+       kfree(isp);
+
+       return ret;
+}
+
+static const struct dev_pm_ops omap3isp_pm_ops = {
+       .prepare = isp_pm_prepare,
+       .suspend = isp_pm_suspend,
+       .resume = isp_pm_resume,
+       .complete = isp_pm_complete,
+};
+
+static struct platform_device_id omap3isp_id_table[] = {
+       { "omap3isp", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
+
+static struct platform_driver omap3isp_driver = {
+       .probe = isp_probe,
+       .remove = isp_remove,
+       .id_table = omap3isp_id_table,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "omap3isp",
+               .pm     = &omap3isp_pm_ops,
+       },
+};
+
+/*
+ * isp_init - ISP module initialization.
+ */
+static int __init isp_init(void)
+{
+       return platform_driver_register(&omap3isp_driver);
+}
+
+/*
+ * isp_cleanup - ISP module cleanup.
+ */
+static void __exit isp_cleanup(void)
+{
+       platform_driver_unregister(&omap3isp_driver);
+}
+
+module_init(isp_init);
+module_exit(isp_cleanup);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("TI OMAP3 ISP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
new file mode 100644 (file)
index 0000000..cf5214e
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * isp.h
+ *
+ * TI OMAP3 ISP - Core
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CORE_H
+#define OMAP3_ISP_CORE_H
+
+#include <media/v4l2-device.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+
+#include "ispstat.h"
+#include "ispccdc.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+#include "isppreview.h"
+#include "ispcsiphy.h"
+#include "ispcsi2.h"
+#include "ispccp2.h"
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+#define ISP_TOK_TERM           0xFFFFFFFF      /*
+                                                * terminating token for ISP
+                                                * modules reg list
+                                                */
+#define to_isp_device(ptr_module)                              \
+       container_of(ptr_module, struct isp_device, isp_##ptr_module)
+#define to_device(ptr_module)                                          \
+       (to_isp_device(ptr_module)->dev)
+
+enum isp_mem_resources {
+       OMAP3_ISP_IOMEM_MAIN,
+       OMAP3_ISP_IOMEM_CCP2,
+       OMAP3_ISP_IOMEM_CCDC,
+       OMAP3_ISP_IOMEM_HIST,
+       OMAP3_ISP_IOMEM_H3A,
+       OMAP3_ISP_IOMEM_PREV,
+       OMAP3_ISP_IOMEM_RESZ,
+       OMAP3_ISP_IOMEM_SBL,
+       OMAP3_ISP_IOMEM_CSI2A_REGS1,
+       OMAP3_ISP_IOMEM_CSIPHY2,
+       OMAP3_ISP_IOMEM_CSI2A_REGS2,
+       OMAP3_ISP_IOMEM_CSI2C_REGS1,
+       OMAP3_ISP_IOMEM_CSIPHY1,
+       OMAP3_ISP_IOMEM_CSI2C_REGS2,
+       OMAP3_ISP_IOMEM_LAST
+};
+
+enum isp_sbl_resource {
+       OMAP3_ISP_SBL_CSI1_READ         = 0x1,
+       OMAP3_ISP_SBL_CSI1_WRITE        = 0x2,
+       OMAP3_ISP_SBL_CSI2A_WRITE       = 0x4,
+       OMAP3_ISP_SBL_CSI2C_WRITE       = 0x8,
+       OMAP3_ISP_SBL_CCDC_LSC_READ     = 0x10,
+       OMAP3_ISP_SBL_CCDC_WRITE        = 0x20,
+       OMAP3_ISP_SBL_PREVIEW_READ      = 0x40,
+       OMAP3_ISP_SBL_PREVIEW_WRITE     = 0x80,
+       OMAP3_ISP_SBL_RESIZER_READ      = 0x100,
+       OMAP3_ISP_SBL_RESIZER_WRITE     = 0x200,
+};
+
+enum isp_subclk_resource {
+       OMAP3_ISP_SUBCLK_CCDC           = (1 << 0),
+       OMAP3_ISP_SUBCLK_H3A            = (1 << 1),
+       OMAP3_ISP_SUBCLK_HIST           = (1 << 2),
+       OMAP3_ISP_SUBCLK_PREVIEW        = (1 << 3),
+       OMAP3_ISP_SUBCLK_RESIZER        = (1 << 4),
+};
+
+enum isp_interface_type {
+       ISP_INTERFACE_PARALLEL,
+       ISP_INTERFACE_CSI2A_PHY2,
+       ISP_INTERFACE_CCP2B_PHY1,
+       ISP_INTERFACE_CCP2B_PHY2,
+       ISP_INTERFACE_CSI2C_PHY1,
+};
+
+/* ISP: OMAP 34xx ES 1.0 */
+#define ISP_REVISION_1_0               0x10
+/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */
+#define ISP_REVISION_2_0               0x20
+/* ISP2P: OMAP 36xx */
+#define ISP_REVISION_15_0              0xF0
+
+/*
+ * struct isp_res_mapping - Map ISP io resources to ISP revision.
+ * @isp_rev: ISP_REVISION_x_x
+ * @map: bitmap for enum isp_mem_resources
+ */
+struct isp_res_mapping {
+       u32 isp_rev;
+       u32 map;
+};
+
+/*
+ * struct isp_reg - Structure for ISP register values.
+ * @reg: 32-bit Register address.
+ * @val: 32-bit Register value.
+ */
+struct isp_reg {
+       enum isp_mem_resources mmio_range;
+       u32 reg;
+       u32 val;
+};
+
+/**
+ * struct isp_parallel_platform_data - Parallel interface platform data
+ * @width: Parallel bus width in bits (8, 10, 11 or 12)
+ * @data_lane_shift: Data lane shifter
+ *             0 - CAMEXT[13:0] -> CAM[13:0]
+ *             1 - CAMEXT[13:2] -> CAM[11:0]
+ *             2 - CAMEXT[13:4] -> CAM[9:0]
+ *             3 - CAMEXT[13:6] -> CAM[7:0]
+ * @clk_pol: Pixel clock polarity
+ *             0 - Non Inverted, 1 - Inverted
+ * @bridge: CCDC Bridge input control
+ *             ISPCTRL_PAR_BRIDGE_DISABLE - Disable
+ *             ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian
+ *             ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian
+ */
+struct isp_parallel_platform_data {
+       unsigned int width;
+       unsigned int data_lane_shift:2;
+       unsigned int clk_pol:1;
+       unsigned int bridge:4;
+};
+
+/**
+ * struct isp_ccp2_platform_data - CCP2 interface platform data
+ * @strobe_clk_pol: Strobe/clock polarity
+ *             0 - Non Inverted, 1 - Inverted
+ * @crc: Enable the cyclic redundancy check
+ * @ccp2_mode: Enable CCP2 compatibility mode
+ *             0 - MIPI-CSI1 mode, 1 - CCP2 mode
+ * @phy_layer: Physical layer selection
+ *             ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer
+ *             ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer
+ * @vpclk_div: Video port output clock control
+ */
+struct isp_ccp2_platform_data {
+       unsigned int strobe_clk_pol:1;
+       unsigned int crc:1;
+       unsigned int ccp2_mode:1;
+       unsigned int phy_layer:1;
+       unsigned int vpclk_div:2;
+};
+
+/**
+ * struct isp_csi2_platform_data - CSI2 interface platform data
+ * @crc: Enable the cyclic redundancy check
+ * @vpclk_div: Video port output clock control
+ */
+struct isp_csi2_platform_data {
+       unsigned crc:1;
+       unsigned vpclk_div:2;
+};
+
+struct isp_subdev_i2c_board_info {
+       struct i2c_board_info *board_info;
+       int i2c_adapter_id;
+};
+
+struct isp_v4l2_subdevs_group {
+       struct isp_subdev_i2c_board_info *subdevs;
+       enum isp_interface_type interface;
+       union {
+               struct isp_parallel_platform_data parallel;
+               struct isp_ccp2_platform_data ccp2;
+               struct isp_csi2_platform_data csi2;
+       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
+};
+
+struct isp_platform_data {
+       struct isp_v4l2_subdevs_group *subdevs;
+       void (*set_constraints)(struct isp_device *isp, bool enable);
+};
+
+struct isp_platform_callback {
+       u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
+       int (*csiphy_config)(struct isp_csiphy *phy,
+                            struct isp_csiphy_dphy_cfg *dphy,
+                            struct isp_csiphy_lanes_cfg *lanes);
+       void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
+};
+
+/*
+ * struct isp_device - ISP device structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @revision: Stores current ISP module revision.
+ * @irq_num: Currently used IRQ number.
+ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
+ *             regions.
+ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
+ *                  regions.
+ * @mmio_size: Array with ISP register regions size in bytes.
+ * @raw_dmamask: Raw DMA mask
+ * @stat_lock: Spinlock for handling statistics
+ * @isp_mutex: Mutex for serializing requests to ISP.
+ * @has_context: Context has been saved at least once and can be restored.
+ * @ref_count: Reference count for handling multiple ISP requests.
+ * @cam_ick: Pointer to camera interface clock structure.
+ * @cam_mclk: Pointer to camera functional clock structure.
+ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
+ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @irq: Currently attached ISP ISR callbacks information structure.
+ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
+ *           White Balance SCM.
+ * @isp_res: Pointer to current settings for ISP Resizer.
+ * @isp_prev: Pointer to current settings for ISP Preview.
+ * @isp_ccdc: Pointer to current settings for ISP CCDC.
+ * @iommu: Pointer to requested IOMMU instance for ISP.
+ * @platform_cb: ISP driver callback function pointers for platform code
+ *
+ * This structure is used to store the OMAP ISP Information.
+ */
+struct isp_device {
+       struct v4l2_device v4l2_dev;
+       struct media_device media_dev;
+       struct device *dev;
+       u32 revision;
+
+       /* platform HW resources */
+       struct isp_platform_data *pdata;
+       unsigned int irq_num;
+
+       void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
+       unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
+       resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
+
+       u64 raw_dmamask;
+
+       /* ISP Obj */
+       spinlock_t stat_lock;   /* common lock for statistic drivers */
+       struct mutex isp_mutex; /* For handling ref_count field */
+       int has_context;
+       int ref_count;
+       unsigned int autoidle;
+       u32 xclk_divisor[2];    /* Two clocks, a and b. */
+#define ISP_CLK_CAM_ICK                0
+#define ISP_CLK_CAM_MCLK       1
+#define ISP_CLK_DPLL4_M5_CK    2
+#define ISP_CLK_CSI2_FCK       3
+#define ISP_CLK_L3_ICK         4
+       struct clk *clock[5];
+
+       /* ISP modules */
+       struct ispstat isp_af;
+       struct ispstat isp_aewb;
+       struct ispstat isp_hist;
+       struct isp_res_device isp_res;
+       struct isp_prev_device isp_prev;
+       struct isp_ccdc_device isp_ccdc;
+       struct isp_csi2_device isp_csi2a;
+       struct isp_csi2_device isp_csi2c;
+       struct isp_ccp2_device isp_ccp2;
+       struct isp_csiphy isp_csiphy1;
+       struct isp_csiphy isp_csiphy2;
+
+       unsigned int sbl_resources;
+       unsigned int subclk_resources;
+
+       struct iommu *iommu;
+
+       struct isp_platform_callback platform_cb;
+};
+
+#define v4l2_dev_to_isp_device(dev) \
+       container_of(dev, struct isp_device, v4l2_dev)
+
+void omap3isp_hist_dma_done(struct isp_device *isp);
+
+void omap3isp_flush(struct isp_device *isp);
+
+int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+                             atomic_t *stopping);
+
+int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
+                                    atomic_t *stopping);
+
+int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
+                                enum isp_pipeline_stream_state state);
+void omap3isp_configure_bridge(struct isp_device *isp,
+                              enum ccdc_input_entity input,
+                              const struct isp_parallel_platform_data *pdata);
+
+#define ISP_XCLK_NONE                  -1
+#define ISP_XCLK_A                     0
+#define ISP_XCLK_B                     1
+
+struct isp_device *omap3isp_get(struct isp_device *isp);
+void omap3isp_put(struct isp_device *isp);
+
+void omap3isp_print_status(struct isp_device *isp);
+
+void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res);
+void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res);
+
+void omap3isp_subclk_enable(struct isp_device *isp,
+                           enum isp_subclk_resource res);
+void omap3isp_subclk_disable(struct isp_device *isp,
+                            enum isp_subclk_resource res);
+
+int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
+
+int omap3isp_register_entities(struct platform_device *pdev,
+                              struct v4l2_device *v4l2_dev);
+void omap3isp_unregister_entities(struct platform_device *pdev);
+
+/*
+ * isp_reg_readl - Read value of an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to read from.
+ *
+ * Returns an unsigned 32 bit value with the required register contents.
+ */
+static inline
+u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
+                 u32 reg_offset)
+{
+       return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_writel - Write value to an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @reg_value: 32 bit value to write to the register.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to write into.
+ */
+static inline
+void isp_reg_writel(struct isp_device *isp, u32 reg_value,
+                   enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+{
+       __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/*
+ * isp_reg_and - Clear individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ */
+static inline
+void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
+                u32 reg, u32 clr_bits)
+{
+       u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+       isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_set - Set individual bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @set_bits: 32 bit value which would be set in the register.
+ */
+static inline
+void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+                u32 reg, u32 set_bits)
+{
+       u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+       isp_reg_writel(isp, v | set_bits, mmio_range, reg);
+}
+
+/*
+ * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @clr_bits: 32 bit value which would be cleared in the register.
+ * @set_bits: 32 bit value which would be set in the register.
+ *
+ * The clear operation is done first, and then the set operation.
+ */
+static inline
+void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
+                    u32 reg, u32 clr_bits, u32 set_bits)
+{
+       u32 v = isp_reg_readl(isp, mmio_range, reg);
+
+       isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg);
+}
+
+static inline enum v4l2_buf_type
+isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad)
+{
+       if (pad >= subdev->entity.num_pads)
+               return 0;
+
+       if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK)
+               return V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       else
+               return V4L2_BUF_TYPE_VIDEO_CAPTURE;
+}
+
+#endif /* OMAP3_ISP_CORE_H */
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
new file mode 100644 (file)
index 0000000..5ff9d14
--- /dev/null
@@ -0,0 +1,2268 @@
+/*
+ * ispccdc.c
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <media/v4l2-event.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which);
+
+static const unsigned int ccdc_fmts[] = {
+       V4L2_MBUS_FMT_Y8_1X8,
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+       V4L2_MBUS_FMT_SGRBG12_1X12,
+       V4L2_MBUS_FMT_SRGGB12_1X12,
+       V4L2_MBUS_FMT_SBGGR12_1X12,
+       V4L2_MBUS_FMT_SGBRG12_1X12,
+};
+
+/*
+ * ccdc_print_status - Print current CCDC Module register values.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Also prints other debug information stored in the CCDC module.
+ */
+#define CCDC_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
+
+static void ccdc_print_status(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
+
+       CCDC_PRINT_REGISTER(isp, PCR);
+       CCDC_PRINT_REGISTER(isp, SYN_MODE);
+       CCDC_PRINT_REGISTER(isp, HD_VD_WID);
+       CCDC_PRINT_REGISTER(isp, PIX_LINES);
+       CCDC_PRINT_REGISTER(isp, HORZ_INFO);
+       CCDC_PRINT_REGISTER(isp, VERT_START);
+       CCDC_PRINT_REGISTER(isp, VERT_LINES);
+       CCDC_PRINT_REGISTER(isp, CULLING);
+       CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
+       CCDC_PRINT_REGISTER(isp, SDOFST);
+       CCDC_PRINT_REGISTER(isp, SDR_ADDR);
+       CCDC_PRINT_REGISTER(isp, CLAMP);
+       CCDC_PRINT_REGISTER(isp, DCSUB);
+       CCDC_PRINT_REGISTER(isp, COLPTN);
+       CCDC_PRINT_REGISTER(isp, BLKCMP);
+       CCDC_PRINT_REGISTER(isp, FPC);
+       CCDC_PRINT_REGISTER(isp, FPC_ADDR);
+       CCDC_PRINT_REGISTER(isp, VDINT);
+       CCDC_PRINT_REGISTER(isp, ALAW);
+       CCDC_PRINT_REGISTER(isp, REC656IF);
+       CCDC_PRINT_REGISTER(isp, CFG);
+       CCDC_PRINT_REGISTER(isp, FMTCFG);
+       CCDC_PRINT_REGISTER(isp, FMT_HORZ);
+       CCDC_PRINT_REGISTER(isp, FMT_VERT);
+       CCDC_PRINT_REGISTER(isp, PRGEVEN0);
+       CCDC_PRINT_REGISTER(isp, PRGEVEN1);
+       CCDC_PRINT_REGISTER(isp, PRGODD0);
+       CCDC_PRINT_REGISTER(isp, PRGODD1);
+       CCDC_PRINT_REGISTER(isp, VP_OUT);
+       CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
+       CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
+       CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
+       CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * omap3isp_ccdc_busy - Get busy state of the CCDC.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
+               ISPCCDC_PCR_BUSY;
+}
+
+/* -----------------------------------------------------------------------------
+ * Lens Shading Compensation
+ */
+
+/*
+ * ccdc_lsc_validate_config - Check that LSC configuration is valid.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @lsc_cfg: the LSC configuration to check.
+ *
+ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
+ */
+static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
+                                   struct omap3isp_ccdc_lsc_config *lsc_cfg)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       struct v4l2_mbus_framefmt *format;
+       unsigned int paxel_width, paxel_height;
+       unsigned int paxel_shift_x, paxel_shift_y;
+       unsigned int min_width, min_height, min_size;
+       unsigned int input_width, input_height;
+
+       paxel_shift_x = lsc_cfg->gain_mode_m;
+       paxel_shift_y = lsc_cfg->gain_mode_n;
+
+       if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
+           (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
+               dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
+               return -EINVAL;
+       }
+
+       if (lsc_cfg->offset & 3) {
+               dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
+                       "4\n");
+               return -EINVAL;
+       }
+
+       if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
+               dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
+               return -EINVAL;
+       }
+
+       format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+                                  V4L2_SUBDEV_FORMAT_ACTIVE);
+       input_width = format->width;
+       input_height = format->height;
+
+       /* Calculate minimum bytesize for validation */
+       paxel_width = 1 << paxel_shift_x;
+       min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
+                    >> paxel_shift_x) + 1;
+
+       paxel_height = 1 << paxel_shift_y;
+       min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
+                    >> paxel_shift_y) + 1;
+
+       min_size = 4 * min_width * min_height;
+       if (min_size > lsc_cfg->size) {
+               dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
+               return -EINVAL;
+       }
+       if (lsc_cfg->offset < (min_width * 4)) {
+               dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
+               return -EINVAL;
+       }
+       if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
+               dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
+{
+       isp_reg_writel(to_isp_device(ccdc), addr,
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
+}
+
+/*
+ * ccdc_lsc_setup_regs - Configures the lens shading compensation module
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
+                               struct omap3isp_ccdc_lsc_config *cfg)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       int reg;
+
+       isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
+                      ISPCCDC_LSC_TABLE_OFFSET);
+
+       reg = 0;
+       reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
+       reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
+       reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
+       isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
+
+       reg = 0;
+       reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
+       reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
+       reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
+       reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
+       isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
+                      ISPCCDC_LSC_INITIAL);
+}
+
+static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       unsigned int wait;
+
+       isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+                      OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+       /* timeout 1 ms */
+       for (wait = 0; wait < 1000; wait++) {
+               if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
+                                 IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
+                       isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
+                                      OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+                       return 0;
+               }
+
+               rmb();
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
+/*
+ * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables LSC, 1 Enables LSC.
+ */
+static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       const struct v4l2_mbus_framefmt *format =
+               __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
+                                 V4L2_SUBDEV_FORMAT_ACTIVE);
+
+       if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
+           (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
+           (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
+           (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
+               return -EINVAL;
+
+       if (enable)
+               omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+                       ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
+
+       if (enable) {
+               if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
+                       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
+                                   ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
+                       ccdc->lsc.state = LSC_STATE_STOPPED;
+                       dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
+                       return -ETIMEDOUT;
+               }
+               ccdc->lsc.state = LSC_STATE_RUNNING;
+       } else {
+               ccdc->lsc.state = LSC_STATE_STOPPING;
+       }
+
+       return 0;
+}
+
+static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
+                            ISPCCDC_LSC_BUSY;
+}
+
+/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
+ * @ccdc: Pointer to ISP CCDC device
+ * @req: New configuration request
+ *
+ * context: in_interrupt()
+ */
+static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
+                               struct ispccdc_lsc_config_req *req)
+{
+       if (!req->enable)
+               return -EINVAL;
+
+       if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
+               dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
+               return -EINVAL;
+       }
+
+       if (ccdc_lsc_busy(ccdc))
+               return -EBUSY;
+
+       ccdc_lsc_setup_regs(ccdc, &req->config);
+       ccdc_lsc_program_table(ccdc, req->table);
+       return 0;
+}
+
+/*
+ * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Disables LSC, and defers enablement to shadow registers update time.
+ */
+static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       /*
+        * From OMAP3 TRM: When this event is pending, the module
+        * goes into transparent mode (output =input). Normal
+        * operation can be resumed at the start of the next frame
+        * after:
+        *  1) Clearing this event
+        *  2) Disabling the LSC module
+        *  3) Enabling it
+        */
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
+                   ISPCCDC_LSC_ENABLE);
+       ccdc->lsc.state = LSC_STATE_STOPPED;
+}
+
+static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
+                                 struct ispccdc_lsc_config_req *req)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       if (req == NULL)
+               return;
+
+       if (req->iovm)
+               dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
+                            req->iovm->sgt->nents, DMA_TO_DEVICE);
+       if (req->table)
+               iommu_vfree(isp->iommu, req->table);
+       kfree(req);
+}
+
+static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
+                               struct list_head *queue)
+{
+       struct ispccdc_lsc_config_req *req, *n;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+       list_for_each_entry_safe(req, n, queue, list) {
+               list_del(&req->list);
+               spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+               ccdc_lsc_free_request(ccdc, req);
+               spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+       }
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static void ccdc_lsc_free_table_work(struct work_struct *work)
+{
+       struct isp_ccdc_device *ccdc;
+       struct ispccdc_lsc *lsc;
+
+       lsc = container_of(work, struct ispccdc_lsc, table_work);
+       ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
+
+       ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
+}
+
+/*
+ * ccdc_lsc_config - Configure the LSC module from a userspace request
+ *
+ * Store the request LSC configuration in the LSC engine request pointer. The
+ * configuration will be applied to the hardware when the CCDC will be enabled,
+ * or at the next LSC interrupt if the CCDC is already running.
+ */
+static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
+                          struct omap3isp_ccdc_update_config *config)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       struct ispccdc_lsc_config_req *req;
+       unsigned long flags;
+       void *table;
+       u16 update;
+       int ret;
+
+       update = config->update &
+                (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
+       if (!update)
+               return 0;
+
+       if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
+               dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
+                       "need to be supplied\n", __func__);
+               return -EINVAL;
+       }
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (req == NULL)
+               return -ENOMEM;
+
+       if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
+               if (copy_from_user(&req->config, config->lsc_cfg,
+                                  sizeof(req->config))) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+
+               req->enable = 1;
+
+               req->table = iommu_vmalloc(isp->iommu, 0, req->config.size,
+                                          IOMMU_FLAG);
+               if (IS_ERR_VALUE(req->table)) {
+                       req->table = 0;
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               req->iovm = find_iovm_area(isp->iommu, req->table);
+               if (req->iovm == NULL) {
+                       ret = -ENOMEM;
+                       goto done;
+               }
+
+               if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
+                               req->iovm->sgt->nents, DMA_TO_DEVICE)) {
+                       ret = -ENOMEM;
+                       req->iovm = NULL;
+                       goto done;
+               }
+
+               dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
+                                   req->iovm->sgt->nents, DMA_TO_DEVICE);
+
+               table = da_to_va(isp->iommu, req->table);
+               if (copy_from_user(table, config->lsc, req->config.size)) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+
+               dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
+                                      req->iovm->sgt->nents, DMA_TO_DEVICE);
+       }
+
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+       if (ccdc->lsc.request) {
+               list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+               schedule_work(&ccdc->lsc.table_work);
+       }
+       ccdc->lsc.request = req;
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+       ret = 0;
+
+done:
+       if (ret < 0)
+               ccdc_lsc_free_request(ccdc, req);
+
+       return ret;
+}
+
+static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+       if (ccdc->lsc.active) {
+               spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+               return 1;
+       }
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+       return 0;
+}
+
+static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
+{
+       struct ispccdc_lsc *lsc = &ccdc->lsc;
+
+       if (lsc->state != LSC_STATE_STOPPED)
+               return -EINVAL;
+
+       if (lsc->active) {
+               list_add_tail(&lsc->active->list, &lsc->free_queue);
+               lsc->active = NULL;
+       }
+
+       if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
+               omap3isp_sbl_disable(to_isp_device(ccdc),
+                               OMAP3_ISP_SBL_CCDC_LSC_READ);
+               list_add_tail(&lsc->request->list, &lsc->free_queue);
+               lsc->request = NULL;
+               goto done;
+       }
+
+       lsc->active = lsc->request;
+       lsc->request = NULL;
+       __ccdc_lsc_enable(ccdc, 1);
+
+done:
+       if (!list_empty(&lsc->free_queue))
+               schedule_work(&lsc->table_work);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Parameters configuration
+ */
+
+/*
+ * ccdc_configure_clamp - Configure optical-black or digital clamping
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * The CCDC performs either optical-black or digital clamp. Configure and enable
+ * the selected clamp method.
+ */
+static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       u32 clamp;
+
+       if (ccdc->obclamp) {
+               clamp  = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
+               clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
+               clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
+               clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
+               isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
+       } else {
+               isp_reg_writel(isp, ccdc->clamp.dcsubval,
+                              OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
+       }
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
+                       ISPCCDC_CLAMP_CLAMPEN,
+                       ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
+}
+
+/*
+ * ccdc_configure_fpc - Configure Faulty Pixel Correction
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
+
+       if (!ccdc->fpc_en)
+               return;
+
+       isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
+                      ISPCCDC_FPC_ADDR);
+       /* The FPNUM field must be set before enabling FPC. */
+       isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+       isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
+                      ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+}
+
+/*
+ * ccdc_configure_black_comp - Configure Black Level Compensation.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       u32 blcomp;
+
+       blcomp  = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
+       blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
+       blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
+       blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
+
+       isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
+}
+
+/*
+ * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
+                       ISPCCDC_SYN_MODE_LPF,
+                       ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
+}
+
+/*
+ * ccdc_configure_alaw - Configure A-law compression.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       u32 alaw = 0;
+
+       switch (ccdc->syncif.datsz) {
+       case 8:
+               return;
+
+       case 10:
+               alaw = ISPCCDC_ALAW_GWDI_9_0;
+               break;
+       case 11:
+               alaw = ISPCCDC_ALAW_GWDI_10_1;
+               break;
+       case 12:
+               alaw = ISPCCDC_ALAW_GWDI_11_2;
+               break;
+       case 13:
+               alaw = ISPCCDC_ALAW_GWDI_12_3;
+               break;
+       }
+
+       if (ccdc->alaw)
+               alaw |= ISPCCDC_ALAW_CCDTBL;
+
+       isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
+}
+
+/*
+ * ccdc_config_imgattr - Configure sensor image specific attributes.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @colptn: Color pattern of the sensor.
+ */
+static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
+}
+
+/*
+ * ccdc_config - Set CCDC configuration from userspace
+ * @ccdc: Pointer to ISP CCDC device.
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ */
+static int ccdc_config(struct isp_ccdc_device *ccdc,
+                      struct omap3isp_ccdc_update_config *ccdc_struct)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ccdc->lock, flags);
+       ccdc->shadow_update = 1;
+       spin_unlock_irqrestore(&ccdc->lock, flags);
+
+       if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
+               ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
+               ccdc->update |= OMAP3ISP_CCDC_ALAW;
+       }
+
+       if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
+               ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
+               ccdc->update |= OMAP3ISP_CCDC_LPF;
+       }
+
+       if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
+               if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
+                                  sizeof(ccdc->clamp))) {
+                       ccdc->shadow_update = 0;
+                       return -EFAULT;
+               }
+
+               ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
+               ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
+       }
+
+       if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
+               if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
+                                  sizeof(ccdc->blcomp))) {
+                       ccdc->shadow_update = 0;
+                       return -EFAULT;
+               }
+
+               ccdc->update |= OMAP3ISP_CCDC_BCOMP;
+       }
+
+       ccdc->shadow_update = 0;
+
+       if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
+               u32 table_old = 0;
+               u32 table_new;
+               u32 size;
+
+               if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+                       return -EBUSY;
+
+               ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
+
+               if (ccdc->fpc_en) {
+                       if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
+                                          sizeof(ccdc->fpc)))
+                               return -EFAULT;
+
+                       /*
+                        * table_new must be 64-bytes aligned, but it's
+                        * already done by iommu_vmalloc().
+                        */
+                       size = ccdc->fpc.fpnum * 4;
+                       table_new = iommu_vmalloc(isp->iommu, 0, size,
+                                                 IOMMU_FLAG);
+                       if (IS_ERR_VALUE(table_new))
+                               return -ENOMEM;
+
+                       if (copy_from_user(da_to_va(isp->iommu, table_new),
+                                          (__force void __user *)
+                                          ccdc->fpc.fpcaddr, size)) {
+                               iommu_vfree(isp->iommu, table_new);
+                               return -EFAULT;
+                       }
+
+                       table_old = ccdc->fpc.fpcaddr;
+                       ccdc->fpc.fpcaddr = table_new;
+               }
+
+               ccdc_configure_fpc(ccdc);
+               if (table_old != 0)
+                       iommu_vfree(isp->iommu, table_old);
+       }
+
+       return ccdc_lsc_config(ccdc, ccdc_struct);
+}
+
+static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
+{
+       if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
+               ccdc_configure_alaw(ccdc);
+               ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
+       }
+
+       if (ccdc->update & OMAP3ISP_CCDC_LPF) {
+               ccdc_configure_lpf(ccdc);
+               ccdc->update &= ~OMAP3ISP_CCDC_LPF;
+       }
+
+       if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
+               ccdc_configure_clamp(ccdc);
+               ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
+       }
+
+       if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
+               ccdc_configure_black_comp(ccdc);
+               ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
+       }
+}
+
+/*
+ * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
+ * @dev: Pointer to ISP device
+ */
+void omap3isp_ccdc_restore_context(struct isp_device *isp)
+{
+       struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
+
+       ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
+                    | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
+       ccdc_apply_controls(ccdc);
+       ccdc_configure_fpc(ccdc);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+/*
+ * ccdc_config_vp - Configure the Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       struct isp_device *isp = to_isp_device(ccdc);
+       unsigned long l3_ick = pipe->l3_ick;
+       unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
+       unsigned int div = 0;
+       u32 fmtcfg_vp;
+
+       fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
+                 & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
+
+       switch (ccdc->syncif.datsz) {
+       case 8:
+       case 10:
+               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+               break;
+       case 11:
+               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+               break;
+       case 12:
+               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+               break;
+       case 13:
+               fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+               break;
+       };
+
+       if (pipe->input)
+               div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
+       else if (ccdc->vpcfg.pixelclk)
+               div = l3_ick / ccdc->vpcfg.pixelclk;
+
+       div = clamp(div, 2U, max_div);
+       fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+
+       isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+}
+
+/*
+ * ccdc_enable_vp - Enable Video Port.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables VP, 1 Enables VP
+ *
+ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
+ */
+static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
+                       ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
+}
+
+/*
+ * ccdc_config_outlineoffset - Configure memory saving output line offset
+ * @ccdc: Pointer to ISP CCDC device.
+ * @offset: Address offset to start a new line. Must be twice the
+ *          Output width and aligned on 32 byte boundary
+ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
+ *           output.
+ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ *
+ * - Configures the output line offset when stored in memory
+ * - Sets the odd/even line pattern to store the output
+ *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
+ * - Configures the number of even and odd line fields in case of rearranging
+ * the lines.
+ */
+static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
+                                       u32 offset, u8 oddeven, u8 numlines)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_writel(isp, offset & 0xffff,
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                   ISPCCDC_SDOFST_FINV);
+
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                   ISPCCDC_SDOFST_FOFST_4L);
+
+       switch (oddeven) {
+       case EVENEVEN:
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
+               break;
+       case ODDEVEN:
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
+               break;
+       case EVENODD:
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
+               break;
+       case ODDODD:
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+                           (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * ccdc_set_outaddr - Set memory address to save output image
+ * @ccdc: Pointer to ISP CCDC device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ */
+static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
+}
+
+/*
+ * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_rate: Maximum calculated data rate.
+ *
+ * Returns in *max_rate less value between calculated and passed
+ */
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+                           unsigned int *max_rate)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       unsigned int rate;
+
+       if (pipe == NULL)
+               return;
+
+       /*
+        * TRM says that for parallel sensors the maximum data rate
+        * should be 90% form L3/2 clock, otherwise just L3/2.
+        */
+       if (ccdc->input == CCDC_INPUT_PARALLEL)
+               rate = pipe->l3_ick / 2 * 9 / 10;
+       else
+               rate = pipe->l3_ick / 2;
+
+       *max_rate = min(*max_rate, rate);
+}
+
+/*
+ * ccdc_config_sync_if - Set CCDC sync interface configuration
+ * @ccdc: Pointer to ISP CCDC device.
+ * @syncif: Structure containing the sync parameters like field state, CCDC in
+ *          master/slave mode, raw/yuv data, polarity of data, field, hs, vs
+ *          signals.
+ */
+static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
+                               struct ispccdc_syncif *syncif)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
+                                    ISPCCDC_SYN_MODE);
+
+       syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
+
+       if (syncif->fldstat)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
+
+       syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK;
+       switch (syncif->datsz) {
+       case 8:
+               syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
+               break;
+       case 10:
+               syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
+               break;
+       case 11:
+               syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
+               break;
+       case 12:
+               syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
+               break;
+       };
+
+       if (syncif->fldmode)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
+
+       if (syncif->datapol)
+               syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
+
+       if (syncif->fldpol)
+               syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
+
+       if (syncif->hdpol)
+               syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
+
+       if (syncif->vdpol)
+               syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
+
+       if (syncif->ccdc_mastermode) {
+               syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
+               isp_reg_writel(isp,
+                              syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
+                            | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
+                              OMAP3_ISP_IOMEM_CCDC,
+                              ISPCCDC_HD_VD_WID);
+
+               isp_reg_writel(isp,
+                              syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
+                            | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
+                              OMAP3_ISP_IOMEM_CCDC,
+                              ISPCCDC_PIX_LINES);
+       } else
+               syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
+                             ISPCCDC_SYN_MODE_VDHDOUT);
+
+       isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+       if (!syncif->bt_r656_en)
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                           ISPCCDC_REC656IF_R656ON);
+}
+
+/* CCDC formats descriptions */
+static const u32 ccdc_sgrbg_pattern =
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_srggb_pattern =
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sbggr_pattern =
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static const u32 ccdc_sgbrg_pattern =
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+       ISPCCDC_COLPTN_Gb_G  << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+       ISPCCDC_COLPTN_B_Mg  << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+       ISPCCDC_COLPTN_R_Ye  << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+       ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
+
+static void ccdc_configure(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+       struct isp_parallel_platform_data *pdata = NULL;
+       struct v4l2_subdev *sensor;
+       struct v4l2_mbus_framefmt *format;
+       struct media_pad *pad;
+       unsigned long flags;
+       u32 syn_mode;
+       u32 ccdc_pattern;
+
+       if (ccdc->input == CCDC_INPUT_PARALLEL) {
+               pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
+               sensor = media_entity_to_v4l2_subdev(pad->entity);
+               pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
+                       ->bus.parallel;
+       }
+
+       omap3isp_configure_bridge(isp, ccdc->input, pdata);
+
+       ccdc->syncif.datsz = pdata ? pdata->width : 10;
+       ccdc_config_sync_if(ccdc, &ccdc->syncif);
+
+       /* CCDC_PAD_SINK */
+       format = &ccdc->formats[CCDC_PAD_SINK];
+
+       syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+       /* Use the raw, unprocessed data when writing to memory. The H3A and
+        * histogram modules are still fed with lens shading corrected data.
+        */
+       syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+
+       if (ccdc->output & CCDC_OUTPUT_MEMORY)
+               syn_mode |= ISPCCDC_SYN_MODE_WEN;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+
+       if (ccdc->output & CCDC_OUTPUT_RESIZER)
+               syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+
+       /* Use PACK8 mode for 1byte per pixel formats. */
+       if (omap3isp_video_format_info(format->code)->bpp <= 8)
+               syn_mode |= ISPCCDC_SYN_MODE_PACK8;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
+
+       isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
+       /* Mosaic filter */
+       switch (format->code) {
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+       case V4L2_MBUS_FMT_SRGGB12_1X12:
+               ccdc_pattern = ccdc_srggb_pattern;
+               break;
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+       case V4L2_MBUS_FMT_SBGGR12_1X12:
+               ccdc_pattern = ccdc_sbggr_pattern;
+               break;
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+       case V4L2_MBUS_FMT_SGBRG12_1X12:
+               ccdc_pattern = ccdc_sgbrg_pattern;
+               break;
+       default:
+               /* Use GRBG */
+               ccdc_pattern = ccdc_sgrbg_pattern;
+               break;
+       }
+       ccdc_config_imgattr(ccdc, ccdc_pattern);
+
+       /* Generate VD0 on the last line of the image and VD1 on the
+        * 2/3 height line.
+        */
+       isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
+                      ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
+
+       /* CCDC_PAD_SOURCE_OF */
+       format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
+
+       isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+                      ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
+       isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
+       isp_reg_writel(isp, (format->height - 1)
+                       << ISPCCDC_VERT_LINES_NLV_SHIFT,
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
+
+       ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
+
+       /* CCDC_PAD_SOURCE_VP */
+       format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
+
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+                      (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
+       isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+                      ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
+
+       isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+                      (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+                      OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
+
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+       if (ccdc->lsc.request == NULL)
+               goto unlock;
+
+       WARN_ON(ccdc->lsc.active);
+
+       /* Get last good LSC configuration. If it is not supported for
+        * the current active resolution discard it.
+        */
+       if (ccdc->lsc.active == NULL &&
+           __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
+               ccdc->lsc.active = ccdc->lsc.request;
+       } else {
+               list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
+               schedule_work(&ccdc->lsc.table_work);
+       }
+
+       ccdc->lsc.request = NULL;
+
+unlock:
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+
+       ccdc_apply_controls(ccdc);
+}
+
+static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
+                       ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
+}
+
+static int ccdc_disable(struct isp_ccdc_device *ccdc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&ccdc->lock, flags);
+       if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+               ccdc->stopping = CCDC_STOP_REQUEST;
+       spin_unlock_irqrestore(&ccdc->lock, flags);
+
+       ret = wait_event_timeout(ccdc->wait,
+                                ccdc->stopping == CCDC_STOP_FINISHED,
+                                msecs_to_jiffies(2000));
+       if (ret == 0) {
+               ret = -ETIMEDOUT;
+               dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
+       }
+
+       omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
+
+       mutex_lock(&ccdc->ioctl_lock);
+       ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+       ccdc->lsc.request = ccdc->lsc.active;
+       ccdc->lsc.active = NULL;
+       cancel_work_sync(&ccdc->lsc.table_work);
+       ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+       mutex_unlock(&ccdc->ioctl_lock);
+
+       ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+       return ret > 0 ? 0 : ret;
+}
+
+static void ccdc_enable(struct isp_ccdc_device *ccdc)
+{
+       if (ccdc_lsc_is_configured(ccdc))
+               __ccdc_lsc_enable(ccdc, 1);
+       __ccdc_enable(ccdc, 1);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Returns zero if the CCDC is idle and the image has been written to
+ * memory, too.
+ */
+static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
+{
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       return omap3isp_ccdc_busy(ccdc)
+               | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
+                  ISPSBL_CCDC_WR_0_DATA_READY)
+               | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
+                  ISPSBL_CCDC_WR_0_DATA_READY)
+               | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
+                  ISPSBL_CCDC_WR_0_DATA_READY)
+               | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
+                  ISPSBL_CCDC_WR_0_DATA_READY);
+}
+
+/*
+ * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
+ * @ccdc: Pointer to ISP CCDC device.
+ * @max_wait: Max retry count in us for wait for idle/busy transition.
+ */
+static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
+                             unsigned int max_wait)
+{
+       unsigned int wait = 0;
+
+       if (max_wait == 0)
+               max_wait = 10000; /* 10 ms */
+
+       for (wait = 0; wait <= max_wait; wait++) {
+               if (!ccdc_sbl_busy(ccdc))
+                       return 0;
+
+               rmb();
+               udelay(1);
+       }
+
+       return -EBUSY;
+}
+
+/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
+ * @ccdc: Pointer to ISP CCDC device.
+ * @event: Pointing which event trigger handler
+ *
+ * Return 1 when the event and stopping request combination is satisfyied,
+ * zero otherwise.
+ */
+static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
+{
+       int rval = 0;
+
+       switch ((ccdc->stopping & 3) | event) {
+       case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
+               if (ccdc->lsc.state != LSC_STATE_STOPPED)
+                       __ccdc_lsc_enable(ccdc, 0);
+               __ccdc_enable(ccdc, 0);
+               ccdc->stopping = CCDC_STOP_EXECUTED;
+               return 1;
+
+       case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
+               ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
+               if (ccdc->lsc.state == LSC_STATE_STOPPED)
+                       ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+               rval = 1;
+               break;
+
+       case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
+               ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
+               rval = 1;
+               break;
+
+       case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
+               return 1;
+       }
+
+       if (ccdc->stopping == CCDC_STOP_FINISHED) {
+               wake_up(&ccdc->wait);
+               rval = 1;
+       }
+
+       return rval;
+}
+
+static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
+{
+       struct video_device *vdev = &ccdc->subdev.devnode;
+       struct v4l2_event event;
+
+       memset(&event, 0, sizeof(event));
+       event.type = V4L2_EVENT_OMAP3ISP_HS_VS;
+
+       v4l2_event_queue(vdev, &event);
+}
+
+/*
+ * ccdc_lsc_isr - Handle LSC events
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: LSC events
+ */
+static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
+{
+       unsigned long flags;
+
+       if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
+               ccdc_lsc_error_handler(ccdc);
+               ccdc->error = 1;
+               dev_dbg(to_device(ccdc), "lsc prefetch error\n");
+       }
+
+       if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
+               return;
+
+       /* LSC_DONE interrupt occur, there are two cases
+        * 1. stopping for reconfiguration
+        * 2. stopping because of STREAM OFF command
+        */
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+       if (ccdc->lsc.state == LSC_STATE_STOPPING)
+               ccdc->lsc.state = LSC_STATE_STOPPED;
+
+       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
+               goto done;
+
+       if (ccdc->lsc.state != LSC_STATE_RECONFIG)
+               goto done;
+
+       /* LSC is in STOPPING state, change to the new state */
+       ccdc->lsc.state = LSC_STATE_STOPPED;
+
+       /* This is an exception. Start of frame and LSC_DONE interrupt
+        * have been received on the same time. Skip this event and wait
+        * for better times.
+        */
+       if (events & IRQ0STATUS_HS_VS_IRQ)
+               goto done;
+
+       /* The LSC engine is stopped at this point. Enable it if there's a
+        * pending request.
+        */
+       if (ccdc->lsc.request == NULL)
+               goto done;
+
+       ccdc_lsc_enable(ccdc);
+
+done:
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
+       struct isp_device *isp = to_isp_device(ccdc);
+       struct isp_buffer *buffer;
+       int restart = 0;
+
+       /* The CCDC generates VD0 interrupts even when disabled (the datasheet
+        * doesn't explicitly state if that's supposed to happen or not, so it
+        * can be considered as a hardware bug or as a feature, but we have to
+        * deal with it anyway). Disabling the CCDC when no buffer is available
+        * would thus not be enough, we need to handle the situation explicitly.
+        */
+       if (list_empty(&ccdc->video_out.dmaqueue))
+               goto done;
+
+       /* We're in continuous mode, and memory writes were disabled due to a
+        * buffer underrun. Reenable them now that we have a buffer. The buffer
+        * address has been set in ccdc_video_queue.
+        */
+       if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
+               restart = 1;
+               ccdc->underrun = 0;
+               goto done;
+       }
+
+       if (ccdc_sbl_wait_idle(ccdc, 1000)) {
+               dev_info(isp->dev, "CCDC won't become idle!\n");
+               goto done;
+       }
+
+       buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
+       if (buffer != NULL) {
+               ccdc_set_outaddr(ccdc, buffer->isp_addr);
+               restart = 1;
+       }
+
+       pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+       if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
+           isp_pipeline_ready(pipe))
+               omap3isp_pipeline_set_stream(pipe,
+                                       ISP_PIPELINE_STREAM_SINGLESHOT);
+
+done:
+       ccdc->error = 0;
+       return restart;
+}
+
+/*
+ * ccdc_vd0_isr - Handle VD0 event
+ * @ccdc: Pointer to ISP CCDC device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ */
+static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
+{
+       unsigned long flags;
+       int restart = 0;
+
+       if (ccdc->output & CCDC_OUTPUT_MEMORY)
+               restart = ccdc_isr_buffer(ccdc);
+
+       spin_lock_irqsave(&ccdc->lock, flags);
+       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
+               spin_unlock_irqrestore(&ccdc->lock, flags);
+               return;
+       }
+
+       if (!ccdc->shadow_update)
+               ccdc_apply_controls(ccdc);
+       spin_unlock_irqrestore(&ccdc->lock, flags);
+
+       if (restart)
+               ccdc_enable(ccdc);
+}
+
+/*
+ * ccdc_vd1_isr - Handle VD1 event
+ * @ccdc: Pointer to ISP CCDC device.
+ */
+static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
+
+       /*
+        * Depending on the CCDC pipeline state, CCDC stopping should be
+        * handled differently. In SINGLESHOT we emulate an internal CCDC
+        * stopping because the CCDC hw works only in continuous mode.
+        * When CONTINUOUS pipeline state is used and the CCDC writes it's
+        * data to memory the CCDC and LSC are stopped immediately but
+        * without change the CCDC stopping state machine. The CCDC
+        * stopping state machine should be used only when user request
+        * for stopping is received (SINGLESHOT is an exeption).
+        */
+       switch (ccdc->state) {
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               ccdc->stopping = CCDC_STOP_REQUEST;
+               break;
+
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               if (ccdc->output & CCDC_OUTPUT_MEMORY) {
+                       if (ccdc->lsc.state != LSC_STATE_STOPPED)
+                               __ccdc_lsc_enable(ccdc, 0);
+                       __ccdc_enable(ccdc, 0);
+               }
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               break;
+       }
+
+       if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
+               goto done;
+
+       if (ccdc->lsc.request == NULL)
+               goto done;
+
+       /*
+        * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
+        * do the appropriate changes in registers
+        */
+       if (ccdc->lsc.state == LSC_STATE_RUNNING) {
+               __ccdc_lsc_enable(ccdc, 0);
+               ccdc->lsc.state = LSC_STATE_RECONFIG;
+               goto done;
+       }
+
+       /* LSC has been in STOPPED state, enable it */
+       if (ccdc->lsc.state == LSC_STATE_STOPPED)
+               ccdc_lsc_enable(ccdc);
+
+done:
+       spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
+}
+
+/*
+ * omap3isp_ccdc_isr - Configure CCDC during interframe time.
+ * @ccdc: Pointer to ISP CCDC device.
+ * @events: CCDC events
+ */
+int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
+{
+       if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
+               return 0;
+
+       if (events & IRQ0STATUS_CCDC_VD1_IRQ)
+               ccdc_vd1_isr(ccdc);
+
+       ccdc_lsc_isr(ccdc, events);
+
+       if (events & IRQ0STATUS_CCDC_VD0_IRQ)
+               ccdc_vd0_isr(ccdc);
+
+       if (events & IRQ0STATUS_HS_VS_IRQ)
+               ccdc_hs_vs_isr(ccdc);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+       struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
+
+       if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
+               return -ENODEV;
+
+       ccdc_set_outaddr(ccdc, buffer->isp_addr);
+
+       /* We now have a buffer queued on the output, restart the pipeline in
+        * on the next CCDC interrupt if running in continuous mode (or when
+        * starting the stream).
+        */
+       ccdc->underrun = 1;
+
+       return 0;
+}
+
+static const struct isp_video_operations ccdc_video_ops = {
+       .queue = ccdc_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * ccdc_ioctl - CCDC module private ioctl's
+ * @sd: ISP CCDC V4L2 subdevice
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       int ret;
+
+       switch (cmd) {
+       case VIDIOC_OMAP3ISP_CCDC_CFG:
+               mutex_lock(&ccdc->ioctl_lock);
+               ret = ccdc_config(ccdc, arg);
+               mutex_unlock(&ccdc->ioctl_lock);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
+               return -EINVAL;
+
+       return v4l2_event_subscribe(fh, sub);
+}
+
+static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                                 struct v4l2_event_subscription *sub)
+{
+       return v4l2_event_unsubscribe(fh, sub);
+}
+
+/*
+ * ccdc_set_stream - Enable/Disable streaming on the CCDC module
+ * @sd: ISP CCDC V4L2 subdevice
+ * @enable: Enable/disable stream
+ *
+ * When writing to memory, the CCDC hardware can't be enabled without a memory
+ * buffer to write to. As the s_stream operation is called in response to a
+ * STREAMON call without any buffer queued yet, just update the enabled field
+ * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
+ *
+ * When not writing to memory enable the CCDC immediately.
+ */
+static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct isp_device *isp = to_isp_device(ccdc);
+       int ret = 0;
+
+       if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISP_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+                           ISPCCDC_CFG_VDLC);
+
+               ccdc_configure(ccdc);
+
+               /* TODO: Don't configure the video port if all of its output
+                * links are inactive.
+                */
+               ccdc_config_vp(ccdc);
+               ccdc_enable_vp(ccdc, 1);
+               ccdc->error = 0;
+               ccdc_print_status(ccdc);
+       }
+
+       switch (enable) {
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               if (ccdc->output & CCDC_OUTPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+               if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
+                       ccdc_enable(ccdc);
+
+               ccdc->underrun = 0;
+               break;
+
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               if (ccdc->output & CCDC_OUTPUT_MEMORY &&
+                   ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+
+               ccdc_enable(ccdc);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               ret = ccdc_disable(ccdc);
+               if (ccdc->output & CCDC_OUTPUT_MEMORY)
+                       omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
+               omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
+               ccdc->underrun = 0;
+               break;
+       }
+
+       ccdc->state = enable;
+       return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &ccdc->formats[pad];
+}
+
+/*
+ * ccdc_try_format - Try video format on a pad
+ * @ccdc: ISP CCDC device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+               unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       const struct isp_format_info *info;
+       unsigned int width = fmt->width;
+       unsigned int height = fmt->height;
+       unsigned int i;
+
+       switch (pad) {
+       case CCDC_PAD_SINK:
+               /* TODO: If the CCDC output formatter pad is connected directly
+                * to the resizer, only YUV formats can be used.
+                */
+               for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
+                       if (fmt->code == ccdc_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(ccdc_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               /* Clamp the input size. */
+               fmt->width = clamp_t(u32, width, 32, 4096);
+               fmt->height = clamp_t(u32, height, 32, 4096);
+               break;
+
+       case CCDC_PAD_SOURCE_OF:
+               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /* The data formatter truncates the number of horizontal output
+                * pixels to a multiple of 16. To avoid clipping data, allow
+                * callers to request an output size bigger than the input size
+                * up to the nearest multiple of 16.
+                */
+               fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15);
+               fmt->width &= ~15;
+               fmt->height = clamp_t(u32, height, 32, fmt->height);
+               break;
+
+       case CCDC_PAD_SOURCE_VP:
+               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /* The video port interface truncates the data to 10 bits. */
+               info = omap3isp_video_format_info(fmt->code);
+               fmt->code = info->truncated;
+
+               /* The number of lines that can be clocked out from the video
+                * port output must be at least one line less than the number
+                * of input lines.
+                */
+               fmt->width = clamp_t(u32, width, 32, fmt->width);
+               fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
+               break;
+       }
+
+       /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
+        * stored on 2 bytes.
+        */
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * ccdc_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       switch (code->pad) {
+       case CCDC_PAD_SINK:
+               if (code->index >= ARRAY_SIZE(ccdc_fmts))
+                       return -EINVAL;
+
+               code->code = ccdc_fmts[code->index];
+               break;
+
+       case CCDC_PAD_SOURCE_OF:
+       case CCDC_PAD_SOURCE_VP:
+               /* No format conversion inside CCDC */
+               if (code->index != 0)
+                       return -EINVAL;
+
+               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK,
+                                          V4L2_SUBDEV_FORMAT_TRY);
+
+               code->code = format->code;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * ccdc_get_format - Retrieve the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * ccdc_set_format - Set the video format on a pad
+ * @sd : ISP CCDC V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == CCDC_PAD_SINK) {
+               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
+                                          fmt->which);
+               *format = fmt->format;
+               ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
+                               fmt->which);
+
+               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
+                                          fmt->which);
+               *format = fmt->format;
+               ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
+                               fmt->which);
+       }
+
+       return 0;
+}
+
+/*
+ * ccdc_init_formats - Initialize formats on all pads
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = CCDC_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       ccdc_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
+       .ioctl = ccdc_ioctl,
+       .subscribe_event = ccdc_subscribe_event,
+       .unsubscribe_event = ccdc_unsubscribe_event,
+};
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
+       .s_stream = ccdc_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
+       .enum_mbus_code = ccdc_enum_mbus_code,
+       .enum_frame_size = ccdc_enum_frame_size,
+       .get_fmt = ccdc_get_format,
+       .set_fmt = ccdc_set_format,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
+       .core = &ccdc_v4l2_core_ops,
+       .video = &ccdc_v4l2_video_ops,
+       .pad = &ccdc_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {
+       .open = ccdc_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ccdc_link_setup - Setup CCDC connections
+ * @entity: CCDC media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int ccdc_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+       struct isp_device *isp = to_isp_device(ccdc);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Read from the sensor (parallel interface), CCP2, CSI2a or
+                * CSI2c.
+                */
+               if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+                       ccdc->input = CCDC_INPUT_NONE;
+                       break;
+               }
+
+               if (ccdc->input != CCDC_INPUT_NONE)
+                       return -EBUSY;
+
+               if (remote->entity == &isp->isp_ccp2.subdev.entity)
+                       ccdc->input = CCDC_INPUT_CCP2B;
+               else if (remote->entity == &isp->isp_csi2a.subdev.entity)
+                       ccdc->input = CCDC_INPUT_CSI2A;
+               else if (remote->entity == &isp->isp_csi2c.subdev.entity)
+                       ccdc->input = CCDC_INPUT_CSI2C;
+               else
+                       ccdc->input = CCDC_INPUT_PARALLEL;
+
+               break;
+
+       /*
+        * The ISP core doesn't support pipelines with multiple video outputs.
+        * Revisit this when it will be implemented, and return -EBUSY for now.
+        */
+
+       case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Write to preview engine, histogram and H3A. When none of
+                * those links are active, the video port can be disabled.
+                */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
+                               return -EBUSY;
+                       ccdc->output |= CCDC_OUTPUT_PREVIEW;
+               } else {
+                       ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
+               }
+               break;
+
+       case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
+               /* Write to memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       ccdc->output |= CCDC_OUTPUT_MEMORY;
+               } else {
+                       ccdc->output &= ~CCDC_OUTPUT_MEMORY;
+               }
+               break;
+
+       case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Write to resizer */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
+                               return -EBUSY;
+                       ccdc->output |= CCDC_OUTPUT_RESIZER;
+               } else {
+                       ccdc->output &= ~CCDC_OUTPUT_RESIZER;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ccdc_media_ops = {
+       .link_setup = ccdc_link_setup,
+};
+
+/*
+ * ccdc_init_entities - Initialize V4L2 subdev and media entity
+ * @ccdc: ISP CCDC module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
+{
+       struct v4l2_subdev *sd = &ccdc->subdev;
+       struct media_pad *pads = ccdc->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       ccdc->input = CCDC_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &ccdc_v4l2_ops);
+       sd->internal_ops = &ccdc_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+       v4l2_set_subdevdata(sd, ccdc);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sd->nevents = OMAP3ISP_CCDC_NEVENTS;
+
+       pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
+       pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &ccdc_media_ops;
+       ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       ccdc_init_formats(sd, NULL);
+
+       ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       ccdc->video_out.ops = &ccdc_video_ops;
+       ccdc->video_out.isp = to_isp_device(ccdc);
+       ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+       ccdc->video_out.bpl_alignment = 32;
+
+       ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the CCDC subdev to the video node. */
+       ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
+                       &ccdc->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
+{
+       media_entity_cleanup(&ccdc->subdev.entity);
+
+       v4l2_device_unregister_subdev(&ccdc->subdev);
+       omap3isp_video_unregister(&ccdc->video_out);
+}
+
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+       struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video node. */
+       ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&ccdc->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap3isp_ccdc_unregister_entities(ccdc);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CCDC initialisation and cleanup
+ */
+
+/*
+ * omap3isp_ccdc_init - CCDC module initialization.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap3isp_ccdc_init(struct isp_device *isp)
+{
+       struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+       spin_lock_init(&ccdc->lock);
+       init_waitqueue_head(&ccdc->wait);
+       mutex_init(&ccdc->ioctl_lock);
+
+       ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
+
+       INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
+       ccdc->lsc.state = LSC_STATE_STOPPED;
+       INIT_LIST_HEAD(&ccdc->lsc.free_queue);
+       spin_lock_init(&ccdc->lsc.req_lock);
+
+       ccdc->syncif.ccdc_mastermode = 0;
+       ccdc->syncif.datapol = 0;
+       ccdc->syncif.datsz = 0;
+       ccdc->syncif.fldmode = 0;
+       ccdc->syncif.fldout = 0;
+       ccdc->syncif.fldpol = 0;
+       ccdc->syncif.fldstat = 0;
+       ccdc->syncif.hdpol = 0;
+       ccdc->syncif.vdpol = 0;
+
+       ccdc->clamp.oblen = 0;
+       ccdc->clamp.dcsubval = 0;
+
+       ccdc->vpcfg.pixelclk = 0;
+
+       ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
+       ccdc_apply_controls(ccdc);
+
+       return ccdc_init_entities(ccdc);
+}
+
+/*
+ * omap3isp_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ */
+void omap3isp_ccdc_cleanup(struct isp_device *isp)
+{
+       struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
+
+       /* Free LSC requests. As the CCDC is stopped there's no active request,
+        * so only the pending request and the free queue need to be handled.
+        */
+       ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
+       cancel_work_sync(&ccdc->lsc.table_work);
+       ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
+
+       if (ccdc->fpc.fpcaddr != 0)
+               iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr);
+}
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
new file mode 100644 (file)
index 0000000..d403af5
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * ispccdc.h
+ *
+ * TI OMAP3 ISP - CCDC module
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CCDC_H
+#define OMAP3_ISP_CCDC_H
+
+#include <linux/omap3isp.h>
+#include <linux/workqueue.h>
+
+#include "ispvideo.h"
+
+enum ccdc_input_entity {
+       CCDC_INPUT_NONE,
+       CCDC_INPUT_PARALLEL,
+       CCDC_INPUT_CSI2A,
+       CCDC_INPUT_CCP2B,
+       CCDC_INPUT_CSI2C
+};
+
+#define CCDC_OUTPUT_MEMORY     (1 << 0)
+#define CCDC_OUTPUT_PREVIEW    (1 << 1)
+#define CCDC_OUTPUT_RESIZER    (1 << 2)
+
+#define        OMAP3ISP_CCDC_NEVENTS   16
+
+/*
+ * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC
+ * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave.
+ * @fldstat: Field state. 0 - Odd Field, 1 - Even Field.
+ * @datsz: Data size.
+ * @fldmode: 0 - Progressive, 1 - Interlaced.
+ * @datapol: 0 - Positive, 1 - Negative.
+ * @fldpol: 0 - Positive, 1 - Negative.
+ * @hdpol: 0 - Positive, 1 - Negative.
+ * @vdpol: 0 - Positive, 1 - Negative.
+ * @fldout: 0 - Input, 1 - Output.
+ * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output.
+ * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output.
+ * @ppln: Number of pixels per line, used for HS/VS Output.
+ * @hlprf: Number of half lines per frame, used for HS/VS Output.
+ * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode.
+ */
+struct ispccdc_syncif {
+       u8 ccdc_mastermode;
+       u8 fldstat;
+       u8 datsz;
+       u8 fldmode;
+       u8 datapol;
+       u8 fldpol;
+       u8 hdpol;
+       u8 vdpol;
+       u8 fldout;
+       u8 hs_width;
+       u8 vs_width;
+       u8 ppln;
+       u8 hlprf;
+       u8 bt_r656_en;
+};
+
+/*
+ * struct ispccdc_vp - Structure for Video Port parameters
+ * @pixelclk: Input pixel clock in Hz
+ */
+struct ispccdc_vp {
+       unsigned int pixelclk;
+};
+
+enum ispccdc_lsc_state {
+       LSC_STATE_STOPPED = 0,
+       LSC_STATE_STOPPING = 1,
+       LSC_STATE_RUNNING = 2,
+       LSC_STATE_RECONFIG = 3,
+};
+
+struct ispccdc_lsc_config_req {
+       struct list_head list;
+       struct omap3isp_ccdc_lsc_config config;
+       unsigned char enable;
+       u32 table;
+       struct iovm_struct *iovm;
+};
+
+/*
+ * ispccdc_lsc - CCDC LSC parameters
+ * @update_config: Set when user changes config
+ * @request_enable: Whether LSC is requested to be enabled
+ * @config: LSC config set by user
+ * @update_table: Set when user provides a new LSC table to table_new
+ * @table_new: LSC table set by user, ISP address
+ * @table_inuse: LSC table currently in use, ISP address
+ */
+struct ispccdc_lsc {
+       enum ispccdc_lsc_state state;
+       struct work_struct table_work;
+
+       /* LSC queue of configurations */
+       spinlock_t req_lock;
+       struct ispccdc_lsc_config_req *request; /* requested configuration */
+       struct ispccdc_lsc_config_req *active;  /* active configuration */
+       struct list_head free_queue;    /* configurations for freeing */
+};
+
+#define CCDC_STOP_NOT_REQUESTED                0x00
+#define CCDC_STOP_REQUEST              0x01
+#define CCDC_STOP_EXECUTED             (0x02 | CCDC_STOP_REQUEST)
+#define CCDC_STOP_CCDC_FINISHED                0x04
+#define CCDC_STOP_LSC_FINISHED         0x08
+#define CCDC_STOP_FINISHED             \
+       (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
+
+#define CCDC_EVENT_VD1                 0x10
+#define CCDC_EVENT_VD0                 0x20
+#define CCDC_EVENT_LSC_DONE            0x40
+
+/* Sink and source CCDC pads */
+#define CCDC_PAD_SINK                  0
+#define CCDC_PAD_SOURCE_OF             1
+#define CCDC_PAD_SOURCE_VP             2
+#define CCDC_PADS_NUM                  3
+
+/*
+ * struct isp_ccdc_device - Structure for the CCDC module to store its own
+ *                         information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @input: Active input
+ * @output: Active outputs
+ * @video_out: Output video node
+ * @error: A hardware error occured during capture
+ * @alaw: A-law compression enabled (1) or disabled (0)
+ * @lpf: Low pass filter enabled (1) or disabled (0)
+ * @obclamp: Optical-black clamp enabled (1) or disabled (0)
+ * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
+ * @blcomp: Black level compensation configuration
+ * @clamp: Optical-black or digital clamp configuration
+ * @fpc: Faulty pixels correction configuration
+ * @lsc: Lens shading compensation configuration
+ * @update: Bitmask of controls to update during the next interrupt
+ * @shadow_update: Controls update in progress by userspace
+ * @syncif: Interface synchronization configuration
+ * @vpcfg: Video port configuration
+ * @underrun: A buffer underrun occured and a new buffer has been queued
+ * @state: Streaming state
+ * @lock: Serializes shadow_update with interrupt handler
+ * @wait: Wait queue used to stop the module
+ * @stopping: Stopping state
+ * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
+ */
+struct isp_ccdc_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[CCDC_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
+
+       enum ccdc_input_entity input;
+       unsigned int output;
+       struct isp_video video_out;
+       unsigned int error;
+
+       unsigned int alaw:1,
+                    lpf:1,
+                    obclamp:1,
+                    fpc_en:1;
+       struct omap3isp_ccdc_blcomp blcomp;
+       struct omap3isp_ccdc_bclamp clamp;
+       struct omap3isp_ccdc_fpc fpc;
+       struct ispccdc_lsc lsc;
+       unsigned int update;
+       unsigned int shadow_update;
+
+       struct ispccdc_syncif syncif;
+       struct ispccdc_vp vpcfg;
+
+       unsigned int underrun:1;
+       enum isp_pipeline_stream_state state;
+       spinlock_t lock;
+       wait_queue_head_t wait;
+       unsigned int stopping;
+       struct mutex ioctl_lock;
+};
+
+struct isp_device;
+
+int omap3isp_ccdc_init(struct isp_device *isp);
+void omap3isp_ccdc_cleanup(struct isp_device *isp);
+int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
+       struct v4l2_device *vdev);
+void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
+
+int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
+int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
+void omap3isp_ccdc_restore_context(struct isp_device *isp);
+void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
+       unsigned int *max_rate);
+
+#endif /* OMAP3_ISP_CCDC_H */
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c
new file mode 100644 (file)
index 0000000..0efef2e
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * ispccp2.c
+ *
+ * TI OMAP3 ISP - CCP2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccp2.h"
+
+/* Number of LCX channels */
+#define CCP2_LCx_CHANS_NUM                     3
+/* Max/Min size for CCP2 video port */
+#define ISPCCP2_DAT_START_MIN                  0
+#define ISPCCP2_DAT_START_MAX                  4095
+#define ISPCCP2_DAT_SIZE_MIN                   0
+#define ISPCCP2_DAT_SIZE_MAX                   4095
+#define ISPCCP2_VPCLK_FRACDIV                  65536
+#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12
+#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP       0x16
+/* Max/Min size for CCP2 memory channel */
+#define ISPCCP2_LCM_HSIZE_COUNT_MIN            16
+#define ISPCCP2_LCM_HSIZE_COUNT_MAX            8191
+#define ISPCCP2_LCM_HSIZE_SKIP_MIN             0
+#define ISPCCP2_LCM_HSIZE_SKIP_MAX             8191
+#define ISPCCP2_LCM_VSIZE_MIN                  1
+#define ISPCCP2_LCM_VSIZE_MAX                  8191
+#define ISPCCP2_LCM_HWORDS_MIN                 1
+#define ISPCCP2_LCM_HWORDS_MAX                 4095
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X                5
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL    0
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10    2
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8       2
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10      3
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10      3
+#define ISPCCP2_LCM_CTRL_DST_PORT_VP           0
+#define ISPCCP2_LCM_CTRL_DST_PORT_MEM          1
+
+/* Set only the required bits */
+#define BIT_SET(var, shift, mask, val)                 \
+       do {                                            \
+               var = ((var) & ~((mask) << (shift)))    \
+                       | ((val) << (shift));           \
+       } while (0)
+
+/*
+ * ccp2_print_status - Print current CCP2 module register values.
+ */
+#define CCP2_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name))
+
+static void ccp2_print_status(struct isp_ccp2_device *ccp2)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+
+       dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n");
+
+       CCP2_PRINT_REGISTER(isp, SYSCONFIG);
+       CCP2_PRINT_REGISTER(isp, SYSSTATUS);
+       CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE);
+       CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS);
+       CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE);
+       CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS);
+       CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE);
+       CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS);
+       CCP2_PRINT_REGISTER(isp, CTRL);
+       CCP2_PRINT_REGISTER(isp, LCx_CTRL(0));
+       CCP2_PRINT_REGISTER(isp, LCx_CODE(0));
+       CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0));
+       CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0));
+       CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0));
+       CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0));
+       CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0));
+       CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0));
+       CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0));
+       CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0));
+       CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0));
+       CCP2_PRINT_REGISTER(isp, LCM_CTRL);
+       CCP2_PRINT_REGISTER(isp, LCM_VSIZE);
+       CCP2_PRINT_REGISTER(isp, LCM_HSIZE);
+       CCP2_PRINT_REGISTER(isp, LCM_PREFETCH);
+       CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR);
+       CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST);
+       CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR);
+       CCP2_PRINT_REGISTER(isp, LCM_DST_OFST);
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * ccp2_reset - Reset the CCP2
+ * @ccp2: pointer to ISP CCP2 device
+ */
+static void ccp2_reset(struct isp_ccp2_device *ccp2)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       int i = 0;
+
+       /* Reset the CSI1/CCP2B and wait for reset to complete */
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG,
+                   ISPCCP2_SYSCONFIG_SOFT_RESET);
+       while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) &
+                ISPCCP2_SYSSTATUS_RESET_DONE)) {
+               udelay(10);
+               if (i++ > 10) {  /* try read 10 times */
+                       dev_warn(isp->dev,
+                               "omap3_isp: timeout waiting for ccp2 reset\n");
+                       break;
+               }
+       }
+}
+
+/*
+ * ccp2_pwr_cfg - Configure the power mode settings
+ * @ccp2: pointer to ISP CCP2 device
+ */
+static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+
+       isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART |
+                       ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ?
+                         ISPCCP2_SYSCONFIG_AUTO_IDLE : 0),
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG);
+}
+
+/*
+ * ccp2_if_enable - Enable CCP2 interface.
+ * @ccp2: pointer to ISP CCP2 device
+ * @enable: enable/disable flag
+ */
+static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+       int i;
+
+       /* Enable/Disable all the LCx channels */
+       for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
+               isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i),
+                               ISPCCP2_LCx_CTRL_CHAN_EN,
+                               enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0);
+
+       /* Enable/Disable ccp2 interface in ccp2 mode */
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+                       ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN,
+                       enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0);
+
+       /* For frame count propagation */
+       if (pipe->do_propagation) {
+               /* We may want the Frame Start IRQ from LC0 */
+               if (enable)
+                       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2,
+                                   ISPCCP2_LC01_IRQENABLE,
+                                   ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
+               else
+                       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2,
+                                   ISPCCP2_LC01_IRQENABLE,
+                                   ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
+       }
+}
+
+/*
+ * ccp2_mem_enable - Enable CCP2 memory interface.
+ * @ccp2: pointer to ISP CCP2 device
+ * @enable: enable/disable flag
+ */
+static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+
+       if (enable)
+               ccp2_if_enable(ccp2, 0);
+
+       /* Enable/Disable ccp2 interface in ccp2 mode */
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+                       ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL,
+                       ISPCCP2_LCM_CTRL_CHAN_EN,
+                       enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0);
+}
+
+/*
+ * ccp2_phyif_config - Initialize CCP2 phy interface config
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: CCP2 platform data
+ *
+ * Configure the CCP2 physical interface module from platform data.
+ *
+ * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success.
+ */
+static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
+                            const struct isp_ccp2_platform_data *pdata)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       u32 val;
+
+       /* CCP2B mode */
+       val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) |
+                           ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE;
+       /* Data/strobe physical layer */
+       BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK,
+               pdata->phy_layer);
+       BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK,
+               pdata->strobe_clk_pol);
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+
+       val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+       if (!(val & ISPCCP2_CTRL_MODE)) {
+               if (pdata->ccp2_mode)
+                       dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n");
+               if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE)
+                       /* Strobe mode requires CCP2 */
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * ccp2_vp_config - Initialize CCP2 video port interface.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @vpclk_div: Video port divisor
+ *
+ * Configure the CCP2 video port with the given clock divisor. The valid divisor
+ * values depend on the ISP revision:
+ *
+ * - revision 1.0 and 2.0      1 to 4
+ * - revision 15.0             1 to 65536
+ *
+ * The exact divisor value used might differ from the requested value, as ISP
+ * revision 15.0 represent the divisor by 65536 divided by an integer.
+ */
+static void ccp2_vp_config(struct isp_ccp2_device *ccp2,
+                          unsigned int vpclk_div)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       u32 val;
+
+       /* ISPCCP2_CTRL Video port */
+       val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+       val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */
+
+       if (isp->revision == ISP_REVISION_15_0) {
+               vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536);
+               vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U);
+               BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT,
+                       ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div);
+       } else {
+               vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4);
+               BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT,
+                       ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1);
+       }
+
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
+}
+
+/*
+ * ccp2_lcx_config - Initialize CCP2 logical channel interface.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: Pointer to ISP LCx config structure.
+ *
+ * This will analyze the parameters passed by the interface config
+ * and configure CSI1/CCP2 logical channel
+ *
+ */
+static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
+                           struct isp_interface_lcx_config *config)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       u32 val, format;
+
+       switch (config->format) {
+       case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+               format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP;
+               break;
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+       default:
+               format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP;      /* RAW10+VP */
+               break;
+       }
+       /* ISPCCP2_LCx_CTRL logical channel #0 */
+       val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0))
+                           | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */
+
+       if (isp->revision == ISP_REVISION_15_0) {
+               /* CRC */
+               BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0,
+                       ISPCCP2_LCx_CTRL_CRC_MASK,
+                       config->crc);
+               /* Format = RAW10+VP or RAW8+DPCM10+VP*/
+               BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0,
+                       ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format);
+       } else {
+               BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT,
+                       ISPCCP2_LCx_CTRL_CRC_MASK,
+                       config->crc);
+
+               BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT,
+                       ISPCCP2_LCx_CTRL_FORMAT_MASK, format);
+       }
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0));
+
+       /* ISPCCP2_DAT_START for logical channel #0 */
+       isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT,
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0));
+
+       /* ISPCCP2_DAT_SIZE for logical channel #0 */
+       isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT,
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0));
+
+       /* Enable error IRQs for logical channel #0 */
+       val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
+             ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
+
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS);
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val);
+}
+
+/*
+ * ccp2_if_configure - Configure ccp2 with data from sensor
+ * @ccp2: Pointer to ISP CCP2 device
+ *
+ * Return 0 on success or a negative error code
+ */
+static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
+{
+       const struct isp_v4l2_subdevs_group *pdata;
+       struct v4l2_mbus_framefmt *format;
+       struct media_pad *pad;
+       struct v4l2_subdev *sensor;
+       u32 lines = 0;
+       int ret;
+
+       ccp2_pwr_cfg(ccp2);
+
+       pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]);
+       sensor = media_entity_to_v4l2_subdev(pad->entity);
+       pdata = sensor->host_priv;
+
+       ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2);
+       if (ret < 0)
+               return ret;
+
+       ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1);
+
+       v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines);
+
+       format = &ccp2->formats[CCP2_PAD_SINK];
+
+       ccp2->if_cfg.data_start = lines;
+       ccp2->if_cfg.crc = pdata->bus.ccp2.crc;
+       ccp2->if_cfg.format = format->code;
+       ccp2->if_cfg.data_size = format->height;
+
+       ccp2_lcx_config(ccp2, &ccp2->if_cfg);
+
+       return 0;
+}
+
+static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+       struct isp_device *isp = to_isp_device(ccp2);
+       const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE];
+       unsigned long l3_ick = pipe->l3_ick;
+       struct v4l2_fract *timeperframe;
+       unsigned int vpclk_div = 2;
+       unsigned int value;
+       u64 bound;
+       u64 area;
+
+       /* Compute the minimum clock divisor, based on the pipeline maximum
+        * data rate. This is an absolute lower bound if we don't want SBL
+        * overflows, so round the value up.
+        */
+       vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate),
+                         vpclk_div);
+
+       /* Compute the maximum clock divisor, based on the requested frame rate.
+        * This is a soft lower bound to achieve a frame rate equal or higher
+        * than the requested value, so round the value down.
+        */
+       timeperframe = &pipe->max_timeperframe;
+
+       if (timeperframe->numerator) {
+               area = ofmt->width * ofmt->height;
+               bound = div_u64(area * timeperframe->denominator,
+                               timeperframe->numerator);
+               value = min_t(u64, bound, l3_ick);
+               vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div);
+       }
+
+       dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__,
+               vpclk_div);
+
+       return vpclk_div;
+}
+
+/*
+ * ccp2_mem_configure - Initialize CCP2 memory input/output interface
+ * @ccp2: Pointer to ISP CCP2 device
+ * @config: Pointer to ISP mem interface config structure
+ *
+ * This will analyze the parameters passed by the interface config
+ * structure, and configure the respective registers for proper
+ * CSI1/CCP2 memory input.
+ */
+static void ccp2_mem_configure(struct isp_ccp2_device *ccp2,
+                              struct isp_interface_mem_config *config)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code;
+       u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code;
+       unsigned int dpcm_decompress = 0;
+       u32 val, hwords;
+
+       if (sink_pixcode != source_pixcode &&
+           sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+               dpcm_decompress = 1;
+
+       ccp2_pwr_cfg(ccp2);
+
+       /* Hsize, Skip */
+       isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN |
+                      (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT),
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE);
+
+       /* Vsize, no. of lines */
+       isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT,
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE);
+
+       if (ccp2->video_in.bpl_padding == 0)
+               config->src_ofst = 0;
+       else
+               config->src_ofst = ccp2->video_in.bpl_value;
+
+       isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2,
+                      ISPCCP2_LCM_SRC_OFST);
+
+       /* Source and Destination formats */
+       val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 <<
+             ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT;
+
+       if (dpcm_decompress) {
+               /* source format is RAW8 */
+               val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 <<
+                      ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
+
+               /* RAW8 + DPCM10 - simple predictor */
+               val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED;
+
+               /* enable source DPCM decompression */
+               val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 <<
+                      ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT;
+       } else {
+               /* source format is RAW10 */
+               val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 <<
+                      ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
+       }
+
+       /* Burst size to 32x64 */
+       val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X <<
+              ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT;
+
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL);
+
+       /* Prefetch setup */
+       if (dpcm_decompress)
+               hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
+                         config->hsize_count) >> 3;
+       else
+               hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
+                         config->hsize_count) >> 2;
+
+       isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT,
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH);
+
+       /* Video port */
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
+                   ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE);
+       ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2));
+
+       /* Clear LCM interrupts */
+       isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ |
+                      ISPCCP2_LCM_IRQSTATUS_EOF_IRQ,
+                      OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS);
+
+       /* Enable LCM interupts */
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE,
+                   ISPCCP2_LCM_IRQSTATUS_EOF_IRQ |
+                   ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ);
+}
+
+/*
+ * ccp2_set_inaddr - Sets memory address of input frame.
+ * @ccp2: Pointer to ISP CCP2 device
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address from which the input frame is to be read.
+ */
+static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+
+       isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
+       struct isp_buffer *buffer;
+
+       buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
+       if (buffer != NULL)
+               ccp2_set_inaddr(ccp2, buffer->isp_addr);
+
+       pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+
+       if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
+               if (isp_pipeline_ready(pipe))
+                       omap3isp_pipeline_set_stream(pipe,
+                                               ISP_PIPELINE_STREAM_SINGLESHOT);
+       }
+
+       ccp2->error = 0;
+}
+
+/*
+ * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts
+ * @ccp2: Pointer to ISP CCP2 device
+ *
+ * This will handle the CCP2 interrupts
+ *
+ * Returns -EIO in case of error, or 0 on success.
+ */
+int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
+{
+       struct isp_device *isp = to_isp_device(ccp2);
+       int ret = 0;
+       static const u32 ISPCCP2_LC01_ERROR =
+               ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+               ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
+               ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
+               ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
+               ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
+               ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
+       u32 lcx_irqstatus, lcm_irqstatus;
+
+       /* First clear the interrupts */
+       lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
+                                     ISPCCP2_LC01_IRQSTATUS);
+       isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+                      ISPCCP2_LC01_IRQSTATUS);
+
+       lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
+                                     ISPCCP2_LCM_IRQSTATUS);
+       isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+                      ISPCCP2_LCM_IRQSTATUS);
+       /* Errors */
+       if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
+               ccp2->error = 1;
+               dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
+               return -EIO;
+       }
+
+       if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
+               ccp2->error = 1;
+               dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
+               ret = -EIO;
+       }
+
+       if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
+               return 0;
+
+       /* Frame number propagation */
+       if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
+               struct isp_pipeline *pipe =
+                       to_isp_pipeline(&ccp2->subdev.entity);
+               if (pipe->do_propagation)
+                       atomic_inc(&pipe->frame_number);
+       }
+
+       /* Handle queued buffers on frame end interrupts */
+       if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
+               ccp2_isr_buffer(ccp2);
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static const unsigned int ccp2_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+};
+
+/*
+ * __ccp2_get_format - helper function for getting ccp2 format
+ * @ccp2  : Pointer to ISP CCP2 device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad number
+ * @which : wanted subdev format
+ * return format structure or NULL on error
+ */
+static struct v4l2_mbus_framefmt *
+__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh,
+                    unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &ccp2->formats[pad];
+}
+
+/*
+ * ccp2_try_format - Handle try format by pad subdev method
+ * @ccp2  : Pointer to ISP CCP2 device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad num
+ * @fmt   : pointer to v4l2 mbus format structure
+ * @which : wanted subdev format
+ */
+static void ccp2_try_format(struct isp_ccp2_device *ccp2,
+                              struct v4l2_subdev_fh *fh, unsigned int pad,
+                              struct v4l2_mbus_framefmt *fmt,
+                              enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+
+       switch (pad) {
+       case CCP2_PAD_SINK:
+               if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               if (ccp2->input == CCP2_INPUT_SENSOR) {
+                       fmt->width = clamp_t(u32, fmt->width,
+                                            ISPCCP2_DAT_START_MIN,
+                                            ISPCCP2_DAT_START_MAX);
+                       fmt->height = clamp_t(u32, fmt->height,
+                                             ISPCCP2_DAT_SIZE_MIN,
+                                             ISPCCP2_DAT_SIZE_MAX);
+               } else if (ccp2->input == CCP2_INPUT_MEMORY) {
+                       fmt->width = clamp_t(u32, fmt->width,
+                                            ISPCCP2_LCM_HSIZE_COUNT_MIN,
+                                            ISPCCP2_LCM_HSIZE_COUNT_MAX);
+                       fmt->height = clamp_t(u32, fmt->height,
+                                             ISPCCP2_LCM_VSIZE_MIN,
+                                             ISPCCP2_LCM_VSIZE_MAX);
+               }
+               break;
+
+       case CCP2_PAD_SOURCE:
+               /* Source format - copy sink format and change pixel code
+                * to SGRBG10_1X10 as we don't support CCP2 write to memory.
+                * When CCP2 write to memory feature will be added this
+                * should be changed properly.
+                */
+               format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+               fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+               break;
+       }
+
+       fmt->field = V4L2_FIELD_NONE;
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+/*
+ * ccp2_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       if (code->pad == CCP2_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(ccp2_fmts))
+                       return -EINVAL;
+
+               code->code = ccp2_fmts[code->index];
+       } else {
+               if (code->index != 0)
+                       return -EINVAL;
+
+               format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK,
+                                             V4L2_SUBDEV_FORMAT_TRY);
+               code->code = format->code;
+       }
+
+       return 0;
+}
+
+static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * ccp2_get_format - Handle get format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on sucess
+ */
+static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * ccp2_set_format - Handle set format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * returns zero
+ */
+static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == CCP2_PAD_SINK) {
+               format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE,
+                                          fmt->which);
+               *format = fmt->format;
+               ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which);
+       }
+
+       return 0;
+}
+
+/*
+ * ccp2_init_formats - Initialize formats on all pads
+ * @sd: ISP CCP2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = CCP2_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       ccp2_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/*
+ * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev
+ * @sd    : pointer to v4l2 subdev structure
+ * @enable: 1 == Enable, 0 == Disable
+ * return zero
+ */
+static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+       struct isp_device *isp = to_isp_device(ccp2);
+       struct device *dev = to_device(ccp2);
+       int ret;
+
+       if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISP_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               atomic_set(&ccp2->stopping, 0);
+               ccp2->error = 0;
+       }
+
+       switch (enable) {
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               if (ccp2->phy) {
+                       ret = omap3isp_csiphy_acquire(ccp2->phy);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               ccp2_if_configure(ccp2);
+               ccp2_print_status(ccp2);
+
+               /* Enable CSI1/CCP2 interface */
+               ccp2_if_enable(ccp2, 1);
+               break;
+
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) {
+                       struct v4l2_mbus_framefmt *format;
+
+                       format = &ccp2->formats[CCP2_PAD_SINK];
+
+                       ccp2->mem_cfg.hsize_count = format->width;
+                       ccp2->mem_cfg.vsize_count = format->height;
+                       ccp2->mem_cfg.src_ofst = 0;
+
+                       ccp2_mem_configure(ccp2, &ccp2->mem_cfg);
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ);
+                       ccp2_print_status(ccp2);
+               }
+               ccp2_mem_enable(ccp2, 1);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait,
+                                             &ccp2->stopping))
+                       dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
+               if (ccp2->input == CCP2_INPUT_MEMORY) {
+                       ccp2_mem_enable(ccp2, 0);
+                       omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ);
+               } else if (ccp2->input == CCP2_INPUT_SENSOR) {
+                       /* Disable CSI1/CCP2 interface */
+                       ccp2_if_enable(ccp2, 0);
+                       if (ccp2->phy)
+                               omap3isp_csiphy_release(ccp2->phy);
+               }
+               break;
+       }
+
+       ccp2->state = enable;
+       return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = {
+       .s_stream = ccp2_s_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = {
+       .enum_mbus_code = ccp2_enum_mbus_code,
+       .enum_frame_size = ccp2_enum_frame_size,
+       .get_fmt = ccp2_get_format,
+       .set_fmt = ccp2_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops ccp2_sd_ops = {
+       .video = &ccp2_sd_video_ops,
+       .pad = &ccp2_sd_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = {
+       .open = ccp2_init_formats,
+};
+
+/* --------------------------------------------------------------------------
+ * ISP ccp2 video device node
+ */
+
+/*
+ * ccp2_video_queue - Queue video buffer.
+ * @video : Pointer to isp video structure
+ * @buffer: Pointer to isp_buffer structure
+ * return -EIO or zero on success
+ */
+static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+       struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2;
+
+       ccp2_set_inaddr(ccp2, buffer->isp_addr);
+       return 0;
+}
+
+static const struct isp_video_operations ccp2_video_ops = {
+       .queue = ccp2_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ccp2_link_setup - Setup ccp2 connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL on error or zero on success
+ */
+static int ccp2_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+               /* read from memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ccp2->input == CCP2_INPUT_SENSOR)
+                               return -EBUSY;
+                       ccp2->input = CCP2_INPUT_MEMORY;
+               } else {
+                       if (ccp2->input == CCP2_INPUT_MEMORY)
+                               ccp2->input = CCP2_INPUT_NONE;
+               }
+               break;
+
+       case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* read from sensor/phy */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ccp2->input == CCP2_INPUT_MEMORY)
+                               return -EBUSY;
+                       ccp2->input = CCP2_INPUT_SENSOR;
+               } else {
+                       if (ccp2->input == CCP2_INPUT_SENSOR)
+                               ccp2->input = CCP2_INPUT_NONE;
+               } break;
+
+       case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* write to video port/ccdc */
+               if (flags & MEDIA_LNK_FL_ENABLED)
+                       ccp2->output = CCP2_OUTPUT_CCDC;
+               else
+                       ccp2->output = CCP2_OUTPUT_NONE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ccp2_media_ops = {
+       .link_setup = ccp2_link_setup,
+};
+
+/*
+ * ccp2_init_entities - Initialize ccp2 subdev and media entity.
+ * @ccp2: Pointer to ISP CCP2 device
+ * return negative error code or zero on success
+ */
+static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
+{
+       struct v4l2_subdev *sd = &ccp2->subdev;
+       struct media_pad *pads = ccp2->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       ccp2->input = CCP2_INPUT_NONE;
+       ccp2->output = CCP2_OUTPUT_NONE;
+
+       v4l2_subdev_init(sd, &ccp2_sd_ops);
+       sd->internal_ops = &ccp2_sd_internal_ops;
+       strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+       v4l2_set_subdevdata(sd, ccp2);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &ccp2_media_ops;
+       ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       ccp2_init_formats(sd, NULL);
+
+       /*
+        * The CCP2 has weird line alignment requirements, possibly caused by
+        * DPCM8 decompression. Line length for data read from memory must be a
+        * multiple of 128 bits (16 bytes) in continuous mode (when no padding
+        * is present at end of lines). Additionally, if padding is used, the
+        * padded line length must be a multiple of 32 bytes. To simplify the
+        * implementation we use a fixed 32 bytes alignment regardless of the
+        * input format and width. If strict 128 bits alignment support is
+        * required ispvideo will need to be made aware of this special dual
+        * alignement requirements.
+        */
+       ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       ccp2->video_in.bpl_alignment = 32;
+       ccp2->video_in.bpl_max = 0xffffffe0;
+       ccp2->video_in.isp = to_isp_device(ccp2);
+       ccp2->video_in.ops = &ccp2_video_ops;
+       ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+       ret = omap3isp_video_init(&ccp2->video_in, "CCP2");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the video node to the ccp2 subdev. */
+       ret = media_entity_create_link(&ccp2->video_in.video.entity, 0,
+                                      &ccp2->subdev.entity, CCP2_PAD_SINK, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev
+ * @ccp2: Pointer to ISP CCP2 device
+ */
+void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2)
+{
+       media_entity_cleanup(&ccp2->subdev.entity);
+
+       v4l2_device_unregister_subdev(&ccp2->subdev);
+       omap3isp_video_unregister(&ccp2->video_in);
+}
+
+/*
+ * omap3isp_ccp2_register_entities - Register the subdev media entity
+ * @ccp2: Pointer to ISP CCP2 device
+ * @vdev: Pointer to v4l device
+ * return negative error code or zero on success
+ */
+
+int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
+                                   struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video nodes. */
+       ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&ccp2->video_in, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap3isp_ccp2_unregister_entities(ccp2);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP ccp2 initialisation and cleanup
+ */
+
+/*
+ * omap3isp_ccp2_cleanup - CCP2 un-initialization
+ * @isp : Pointer to ISP device
+ */
+void omap3isp_ccp2_cleanup(struct isp_device *isp)
+{
+}
+
+/*
+ * omap3isp_ccp2_init - CCP2 initialization.
+ * @isp : Pointer to ISP device
+ * return negative error code or zero on success
+ */
+int omap3isp_ccp2_init(struct isp_device *isp)
+{
+       struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
+       int ret;
+
+       init_waitqueue_head(&ccp2->wait);
+
+       /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
+        * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly
+        * configured.
+        *
+        * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
+        */
+       if (isp->revision == ISP_REVISION_15_0)
+               ccp2->phy = &isp->isp_csiphy1;
+
+       ret = ccp2_init_entities(ccp2);
+       if (ret < 0)
+               goto out;
+
+       ccp2_reset(ccp2);
+out:
+       if (ret)
+               omap3isp_ccp2_cleanup(isp);
+
+       return ret;
+}
diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h
new file mode 100644 (file)
index 0000000..5505a86
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * ispccp2.h
+ *
+ * TI OMAP3 ISP - CCP2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CCP2_H
+#define OMAP3_ISP_CCP2_H
+
+#include <linux/videodev2.h>
+
+struct isp_device;
+struct isp_csiphy;
+
+/* Sink and source ccp2 pads */
+#define CCP2_PAD_SINK                  0
+#define CCP2_PAD_SOURCE                        1
+#define CCP2_PADS_NUM                  2
+
+/* CCP2 input media entity */
+enum ccp2_input_entity {
+       CCP2_INPUT_NONE,
+       CCP2_INPUT_SENSOR,
+       CCP2_INPUT_MEMORY,
+};
+
+/* CCP2 output media entity */
+enum ccp2_output_entity {
+       CCP2_OUTPUT_NONE,
+       CCP2_OUTPUT_CCDC,
+       CCP2_OUTPUT_MEMORY,
+};
+
+
+/* Logical channel configuration */
+struct isp_interface_lcx_config {
+       int crc;
+       u32 data_start;
+       u32 data_size;
+       u32 format;
+};
+
+/* Memory channel configuration */
+struct isp_interface_mem_config {
+       u32 dst_port;
+       u32 vsize_count;
+       u32 hsize_count;
+       u32 src_ofst;
+       u32 dst_ofst;
+};
+
+/* CCP2 device */
+struct isp_ccp2_device {
+       struct v4l2_subdev subdev;
+       struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM];
+       struct media_pad pads[CCP2_PADS_NUM];
+
+       enum ccp2_input_entity input;
+       enum ccp2_output_entity output;
+       struct isp_interface_lcx_config if_cfg;
+       struct isp_interface_mem_config mem_cfg;
+       struct isp_video video_in;
+       struct isp_csiphy *phy;
+       unsigned int error;
+       enum isp_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+/* Function declarations */
+int omap3isp_ccp2_init(struct isp_device *isp);
+void omap3isp_ccp2_cleanup(struct isp_device *isp);
+int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
+                       struct v4l2_device *vdev);
+void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
+int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
+
+#endif /* OMAP3_ISP_CCP2_H */
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
new file mode 100644 (file)
index 0000000..fb503f3
--- /dev/null
@@ -0,0 +1,1317 @@
+/*
+ * ispcsi2.c
+ *
+ * TI OMAP3 ISP - CSI2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/mm.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsi2.h"
+
+/*
+ * csi2_if_enable - Enable CSI2 Receiver interface.
+ * @enable: enable flag
+ *
+ */
+static void csi2_if_enable(struct isp_device *isp,
+                          struct isp_csi2_device *csi2, u8 enable)
+{
+       struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
+
+       isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN,
+                       enable ? ISPCSI2_CTRL_IF_EN : 0);
+
+       currctrl->if_enable = enable;
+}
+
+/*
+ * csi2_recv_config - CSI2 receiver module configuration.
+ * @currctrl: isp_csi2_ctrl_cfg structure
+ *
+ */
+static void csi2_recv_config(struct isp_device *isp,
+                            struct isp_csi2_device *csi2,
+                            struct isp_csi2_ctrl_cfg *currctrl)
+{
+       u32 reg;
+
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL);
+
+       if (currctrl->frame_mode)
+               reg |= ISPCSI2_CTRL_FRAME;
+       else
+               reg &= ~ISPCSI2_CTRL_FRAME;
+
+       if (currctrl->vp_clk_enable)
+               reg |= ISPCSI2_CTRL_VP_CLK_EN;
+       else
+               reg &= ~ISPCSI2_CTRL_VP_CLK_EN;
+
+       if (currctrl->vp_only_enable)
+               reg |= ISPCSI2_CTRL_VP_ONLY_EN;
+       else
+               reg &= ~ISPCSI2_CTRL_VP_ONLY_EN;
+
+       reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
+       reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
+
+       if (currctrl->ecc_enable)
+               reg |= ISPCSI2_CTRL_ECC_EN;
+       else
+               reg &= ~ISPCSI2_CTRL_ECC_EN;
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL);
+}
+
+static const unsigned int csi2_input_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+};
+
+/* To set the format on the CSI2 requires a mapping function that takes
+ * the following inputs:
+ * - 2 different formats (at this time)
+ * - 2 destinations (mem, vp+mem) (vp only handled separately)
+ * - 2 decompression options (on, off)
+ * - 2 isp revisions (certain format must be handled differently on OMAP3630)
+ * Output should be CSI2 frame format code
+ * Array indices as follows: [format][dest][decompr][is_3630]
+ * Not all combinations are valid. 0 means invalid.
+ */
+static const u16 __csi2_fmt_map[2][2][2][2] = {
+       /* RAW10 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 },
+                       /* DPCM decompression */
+                       { 0, 0 },
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_RAW10_EXP16_VP,
+                         CSI2_PIX_FMT_RAW10_EXP16_VP },
+                       /* DPCM decompression */
+                       { 0, 0 },
+               },
+       },
+       /* RAW10 DPCM8 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 },
+                       /* DPCM decompression */
+                       { CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
+                         CSI2_USERDEF_8BIT_DATA1_DPCM10 },
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_RAW8_VP,
+                         CSI2_PIX_FMT_RAW8_VP },
+                       /* DPCM decompression */
+                       { CSI2_PIX_FMT_RAW8_DPCM10_VP,
+                         CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
+               },
+       },
+};
+
+/*
+ * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
+ * @csi2: ISP CSI2 device
+ *
+ * Returns CSI2 physical format id
+ */
+static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
+{
+       const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
+       int fmtidx, destidx, is_3630;
+
+       switch (fmt->code) {
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+               fmtidx = 0;
+               break;
+       case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+               fmtidx = 1;
+               break;
+       default:
+               WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
+                    fmt->code);
+               return 0;
+       }
+
+       if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
+           !(csi2->output & CSI2_OUTPUT_MEMORY)) {
+               /* Neither output enabled is a valid combination */
+               return CSI2_PIX_FMT_OTHERS;
+       }
+
+       /* If we need to skip frames at the beginning of the stream disable the
+        * video port to avoid sending the skipped frames to the CCDC.
+        */
+       destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
+       is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
+
+       return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630];
+}
+
+/*
+ * csi2_set_outaddr - Set memory address to save output image
+ * @csi2: Pointer to ISP CSI2a device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ */
+static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
+{
+       struct isp_device *isp = csi2->isp;
+       struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
+
+       ctx->ping_addr = addr;
+       ctx->pong_addr = addr;
+       isp_reg_writel(isp, ctx->ping_addr,
+                      csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+       isp_reg_writel(isp, ctx->pong_addr,
+                      csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
+ *                     be enabled by CSI2.
+ * @format_id: mapped format id
+ *
+ */
+static inline int is_usr_def_mapping(u32 format_id)
+{
+       return (format_id & 0x40) ? 1 : 0;
+}
+
+/*
+ * csi2_ctx_enable - Enable specified CSI2 context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @enable: enable
+ *
+ */
+static void csi2_ctx_enable(struct isp_device *isp,
+                           struct isp_csi2_device *csi2, u8 ctxnum, u8 enable)
+{
+       struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
+       unsigned int skip = 0;
+       u32 reg;
+
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+
+       if (enable) {
+               if (csi2->frame_skip)
+                       skip = csi2->frame_skip;
+               else if (csi2->output & CSI2_OUTPUT_MEMORY)
+                       skip = 1;
+
+               reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK;
+               reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK
+                   |  (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
+                   |  ISPCSI2_CTX_CTRL1_CTX_EN;
+       } else {
+               reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN;
+       }
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
+       ctx->enabled = enable;
+}
+
+/*
+ * csi2_ctx_config - CSI2 context configuration.
+ * @ctx: context configuration
+ *
+ */
+static void csi2_ctx_config(struct isp_device *isp,
+                           struct isp_csi2_device *csi2,
+                           struct isp_csi2_ctx_cfg *ctx)
+{
+       u32 reg;
+
+       /* Set up CSI2_CTx_CTRL1 */
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+       if (ctx->eof_enabled)
+               reg |= ISPCSI2_CTX_CTRL1_EOF_EN;
+       else
+               reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN;
+
+       if (ctx->eol_enabled)
+               reg |= ISPCSI2_CTX_CTRL1_EOL_EN;
+       else
+               reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN;
+
+       if (ctx->checksum_enabled)
+               reg |= ISPCSI2_CTX_CTRL1_CS_EN;
+       else
+               reg &= ~ISPCSI2_CTX_CTRL1_CS_EN;
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
+
+       /* Set up CSI2_CTx_CTRL2 */
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+       reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
+       reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+
+       reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
+       reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT;
+
+       if (ctx->dpcm_decompress) {
+               if (ctx->dpcm_predictor)
+                       reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED;
+               else
+                       reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED;
+       }
+
+       if (is_usr_def_mapping(ctx->format_id)) {
+               reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK;
+               reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
+       }
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
+
+       /* Set up CSI2_CTx_CTRL3 */
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+       reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
+       reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
+
+       /* Set up CSI2_CTx_DAT_OFST */
+       reg = isp_reg_readl(isp, csi2->regs1,
+                           ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+       reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
+       reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
+       isp_reg_writel(isp, reg, csi2->regs1,
+                      ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
+
+       isp_reg_writel(isp, ctx->ping_addr,
+                      csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
+
+       isp_reg_writel(isp, ctx->pong_addr,
+                      csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
+}
+
+/*
+ * csi2_timing_config - CSI2 timing configuration.
+ * @timing: csi2_timing_cfg structure
+ */
+static void csi2_timing_config(struct isp_device *isp,
+                              struct isp_csi2_device *csi2,
+                              struct isp_csi2_timing_cfg *timing)
+{
+       u32 reg;
+
+       reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING);
+
+       if (timing->force_rx_mode)
+               reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+       else
+               reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
+
+       if (timing->stop_state_16x)
+               reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+       else
+               reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
+
+       if (timing->stop_state_4x)
+               reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+       else
+               reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
+
+       reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum);
+       reg |= timing->stop_state_counter <<
+              ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum);
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING);
+}
+
+/*
+ * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
+ * @enable: Enable/disable CSI2 Context interrupts
+ */
+static void csi2_irq_ctx_set(struct isp_device *isp,
+                            struct isp_csi2_device *csi2, int enable)
+{
+       u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
+       int i;
+
+       if (csi2->use_fs_irq)
+               reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ;
+
+       for (i = 0; i < 8; i++) {
+               isp_reg_writel(isp, reg, csi2->regs1,
+                              ISPCSI2_CTX_IRQSTATUS(i));
+               if (enable)
+                       isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+                                   reg);
+               else
+                       isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
+                                   reg);
+       }
+}
+
+/*
+ * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
+ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
+ */
+static void csi2_irq_complexio1_set(struct isp_device *isp,
+                                   struct isp_csi2_device *csi2, int enable)
+{
+       u32 reg;
+       reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT |
+               ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER |
+               ISPCSI2_PHY_IRQENABLE_STATEULPM5 |
+               ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 |
+               ISPCSI2_PHY_IRQENABLE_ERRESC5 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 |
+               ISPCSI2_PHY_IRQENABLE_STATEULPM4 |
+               ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 |
+               ISPCSI2_PHY_IRQENABLE_ERRESC4 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 |
+               ISPCSI2_PHY_IRQENABLE_STATEULPM3 |
+               ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 |
+               ISPCSI2_PHY_IRQENABLE_ERRESC3 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 |
+               ISPCSI2_PHY_IRQENABLE_STATEULPM2 |
+               ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 |
+               ISPCSI2_PHY_IRQENABLE_ERRESC2 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 |
+               ISPCSI2_PHY_IRQENABLE_STATEULPM1 |
+               ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 |
+               ISPCSI2_PHY_IRQENABLE_ERRESC1 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 |
+               ISPCSI2_PHY_IRQENABLE_ERRSOTHS1;
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+       if (enable)
+               reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+       else
+               reg = 0;
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
+}
+
+/*
+ * csi2_irq_status_set - Enables CSI2 Status IRQs.
+ * @enable: Enable/disable CSI2 Status interrupts
+ */
+static void csi2_irq_status_set(struct isp_device *isp,
+                               struct isp_csi2_device *csi2, int enable)
+{
+       u32 reg;
+       reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+               ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+               ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
+               ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+               ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+               ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
+               ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
+               ISPCSI2_IRQSTATUS_CONTEXT(0);
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS);
+       if (enable)
+               reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE);
+       else
+               reg = 0;
+
+       isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE);
+}
+
+/*
+ * omap3isp_csi2_reset - Resets the CSI2 module.
+ *
+ * Must be called with the phy lock held.
+ *
+ * Returns 0 if successful, or -EBUSY if power command didn't respond.
+ */
+int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
+{
+       struct isp_device *isp = csi2->isp;
+       u8 soft_reset_retries = 0;
+       u32 reg;
+       int i;
+
+       if (!csi2->available)
+               return -ENODEV;
+
+       if (csi2->phy->phy_in_use)
+               return -EBUSY;
+
+       isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+                   ISPCSI2_SYSCONFIG_SOFT_RESET);
+
+       do {
+               reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) &
+                                   ISPCSI2_SYSSTATUS_RESET_DONE;
+               if (reg == ISPCSI2_SYSSTATUS_RESET_DONE)
+                       break;
+               soft_reset_retries++;
+               if (soft_reset_retries < 5)
+                       udelay(100);
+       } while (soft_reset_retries < 5);
+
+       if (soft_reset_retries == 5) {
+               printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
+               return -EBUSY;
+       }
+
+       if (isp->revision == ISP_REVISION_15_0)
+               isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG,
+                           ISPCSI2_PHY_CFG_RESET_CTRL);
+
+       i = 100;
+       do {
+               reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1)
+                   & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK;
+               if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK)
+                       break;
+               udelay(100);
+       } while (--i > 0);
+
+       if (i == 0) {
+               printk(KERN_ERR
+                      "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+               return -EBUSY;
+       }
+
+       if (isp->autoidle)
+               isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+                               ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+                               ISPCSI2_SYSCONFIG_AUTO_IDLE,
+                               ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART |
+                               ((isp->revision == ISP_REVISION_15_0) ?
+                                ISPCSI2_SYSCONFIG_AUTO_IDLE : 0));
+       else
+               isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
+                               ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+                               ISPCSI2_SYSCONFIG_AUTO_IDLE,
+                               ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO);
+
+       return 0;
+}
+
+static int csi2_configure(struct isp_csi2_device *csi2)
+{
+       const struct isp_v4l2_subdevs_group *pdata;
+       struct isp_device *isp = csi2->isp;
+       struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
+       struct v4l2_subdev *sensor;
+       struct media_pad *pad;
+
+       /*
+        * CSI2 fields that can be updated while the context has
+        * been enabled or the interface has been enabled are not
+        * updated dynamically currently. So we do not allow to
+        * reconfigure if either has been enabled
+        */
+       if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
+               return -EBUSY;
+
+       pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
+       sensor = media_entity_to_v4l2_subdev(pad->entity);
+       pdata = sensor->host_priv;
+
+       csi2->frame_skip = 0;
+       v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
+
+       csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
+       csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
+       csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
+
+       timing->ionum = 1;
+       timing->force_rx_mode = 1;
+       timing->stop_state_16x = 1;
+       timing->stop_state_4x = 1;
+       timing->stop_state_counter = 0x1FF;
+
+       /*
+        * The CSI2 receiver can't do any format conversion except DPCM
+        * decompression, so every set_format call configures both pads
+        * and enables DPCM decompression as a special case:
+        */
+       if (csi2->formats[CSI2_PAD_SINK].code !=
+           csi2->formats[CSI2_PAD_SOURCE].code)
+               csi2->dpcm_decompress = true;
+       else
+               csi2->dpcm_decompress = false;
+
+       csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
+
+       if (csi2->video_out.bpl_padding == 0)
+               csi2->contexts[0].data_offset = 0;
+       else
+               csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
+
+       /*
+        * Enable end of frame and end of line signals generation for
+        * context 0. These signals are generated from CSI2 receiver to
+        * qualify the last pixel of a frame and the last pixel of a line.
+        * Without enabling the signals CSI2 receiver writes data to memory
+        * beyond buffer size and/or data line offset is not handled correctly.
+        */
+       csi2->contexts[0].eof_enabled = 1;
+       csi2->contexts[0].eol_enabled = 1;
+
+       csi2_irq_complexio1_set(isp, csi2, 1);
+       csi2_irq_ctx_set(isp, csi2, 1);
+       csi2_irq_status_set(isp, csi2, 1);
+
+       /* Set configuration (timings, format and links) */
+       csi2_timing_config(isp, csi2, timing);
+       csi2_recv_config(isp, csi2, &csi2->ctrl);
+       csi2_ctx_config(isp, csi2, &csi2->contexts[0]);
+
+       return 0;
+}
+
+/*
+ * csi2_print_status - Prints CSI2 debug information.
+ */
+#define CSI2_PRINT_REGISTER(isp, regs, name)\
+       dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \
+               isp_reg_readl(isp, regs, ISPCSI2_##name))
+
+static void csi2_print_status(struct isp_csi2_device *csi2)
+{
+       struct isp_device *isp = csi2->isp;
+
+       if (!csi2->available)
+               return;
+
+       dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n");
+
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING);
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0));
+       CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0));
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * csi2_isr_buffer - Does buffer handling at end-of-frame
+ * when writing to memory.
+ */
+static void csi2_isr_buffer(struct isp_csi2_device *csi2)
+{
+       struct isp_device *isp = csi2->isp;
+       struct isp_buffer *buffer;
+
+       csi2_ctx_enable(isp, csi2, 0, 0);
+
+       buffer = omap3isp_video_buffer_next(&csi2->video_out, 0);
+
+       /*
+        * Let video queue operation restart engine if there is an underrun
+        * condition.
+        */
+       if (buffer == NULL)
+               return;
+
+       csi2_set_outaddr(csi2, buffer->isp_addr);
+       csi2_ctx_enable(isp, csi2, 0, 1);
+}
+
+static void csi2_isr_ctx(struct isp_csi2_device *csi2,
+                        struct isp_csi2_ctx_cfg *ctx)
+{
+       struct isp_device *isp = csi2->isp;
+       unsigned int n = ctx->ctxnum;
+       u32 status;
+
+       status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+       isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
+
+       /* Propagate frame number */
+       if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) {
+               struct isp_pipeline *pipe =
+                                    to_isp_pipeline(&csi2->subdev.entity);
+               if (pipe->do_propagation)
+                       atomic_inc(&pipe->frame_number);
+       }
+
+       if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
+               return;
+
+       /* Skip interrupts until we reach the frame skip count. The CSI2 will be
+        * automatically disabled, as the frame skip count has been programmed
+        * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
+        *
+        * It would have been nice to rely on the FRAME_NUMBER interrupt instead
+        * but it turned out that the interrupt is only generated when the CSI2
+        * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
+        * correctly and reaches 0 when data is forwarded to the video port only
+        * but no interrupt arrives). Maybe a CSI2 hardware bug.
+        */
+       if (csi2->frame_skip) {
+               csi2->frame_skip--;
+               if (csi2->frame_skip == 0) {
+                       ctx->format_id = csi2_ctx_map_format(csi2);
+                       csi2_ctx_config(isp, csi2, ctx);
+                       csi2_ctx_enable(isp, csi2, n, 1);
+               }
+               return;
+       }
+
+       if (csi2->output & CSI2_OUTPUT_MEMORY)
+               csi2_isr_buffer(csi2);
+}
+
+/*
+ * omap3isp_csi2_isr - CSI2 interrupt handling.
+ *
+ * Return -EIO on Transmission error
+ */
+int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
+{
+       u32 csi2_irqstatus, cpxio1_irqstatus;
+       struct isp_device *isp = csi2->isp;
+       int retval = 0;
+
+       if (!csi2->available)
+               return -ENODEV;
+
+       csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
+       isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
+
+       /* Failure Cases */
+       if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
+               cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1,
+                                                ISPCSI2_PHY_IRQSTATUS);
+               isp_reg_writel(isp, cpxio1_irqstatus,
+                              csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
+               dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
+                       "%x\n", cpxio1_irqstatus);
+               retval = -EIO;
+       }
+
+       if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+                             ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+                             ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+                             ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+                             ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
+               dev_dbg(isp->dev, "CSI2 Err:"
+                       " OCP:%d,"
+                       " Short_pack:%d,"
+                       " ECC:%d,"
+                       " CPXIO2:%d,"
+                       " FIFO_OVF:%d,"
+                       "\n",
+                       (csi2_irqstatus &
+                        ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
+                       (csi2_irqstatus &
+                        ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
+                       (csi2_irqstatus &
+                        ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
+                       (csi2_irqstatus &
+                        ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
+                       (csi2_irqstatus &
+                        ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
+               retval = -EIO;
+       }
+
+       if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+               return 0;
+
+       /* Successful cases */
+       if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
+               csi2_isr_ctx(csi2, &csi2->contexts[0]);
+
+       if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
+               dev_dbg(isp->dev, "CSI2: ECC correction done\n");
+
+       return retval;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+/*
+ * csi2_queue - Queues the first buffer when using memory output
+ * @video: The video node
+ * @buffer: buffer to queue
+ */
+static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
+{
+       struct isp_device *isp = video->isp;
+       struct isp_csi2_device *csi2 = &isp->isp_csi2a;
+
+       csi2_set_outaddr(csi2, buffer->isp_addr);
+
+       /*
+        * If streaming was enabled before there was a buffer queued
+        * or underrun happened in the ISR, the hardware was not enabled
+        * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set.
+        * Enable it now.
+        */
+       if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
+               /* Enable / disable context 0 and IRQs */
+               csi2_if_enable(isp, csi2, 1);
+               csi2_ctx_enable(isp, csi2, 0, 1);
+               isp_video_dmaqueue_flags_clr(&csi2->video_out);
+       }
+
+       return 0;
+}
+
+static const struct isp_video_operations csi2_ispvideo_ops = {
+       .queue = csi2_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &csi2->formats[pad];
+}
+
+static void
+csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+               unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       enum v4l2_mbus_pixelcode pixelcode;
+       struct v4l2_mbus_framefmt *format;
+       const struct isp_format_info *info;
+       unsigned int i;
+
+       switch (pad) {
+       case CSI2_PAD_SINK:
+               /* Clamp the width and height to valid range (1-8191). */
+               for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
+                       if (fmt->code == csi2_input_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(csi2_input_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               fmt->width = clamp_t(u32, fmt->width, 1, 8191);
+               fmt->height = clamp_t(u32, fmt->height, 1, 8191);
+               break;
+
+       case CSI2_PAD_SOURCE:
+               /* Source format same as sink format, except for DPCM
+                * compression.
+                */
+               pixelcode = fmt->code;
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /*
+                * Only Allow DPCM decompression, and check that the
+                * pattern is preserved
+                */
+               info = omap3isp_video_format_info(fmt->code);
+               if (info->uncompressed == pixelcode)
+                       fmt->code = pixelcode;
+               break;
+       }
+
+       /* RGB, non-interlaced */
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * csi2_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+       const struct isp_format_info *info;
+
+       if (code->pad == CSI2_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(csi2_input_fmts))
+                       return -EINVAL;
+
+               code->code = csi2_input_fmts[code->index];
+       } else {
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
+                                          V4L2_SUBDEV_FORMAT_TRY);
+               switch (code->index) {
+               case 0:
+                       /* Passthrough sink pad code */
+                       code->code = format->code;
+                       break;
+               case 1:
+                       /* Uncompressed code */
+                       info = omap3isp_video_format_info(format->code);
+                       if (info->uncompressed == format->code)
+                               return -EINVAL;
+
+                       code->code = info->uncompressed;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int csi2_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * csi2_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on sucess
+ */
+static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * csi2_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == CSI2_PAD_SINK) {
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
+                                          fmt->which);
+               *format = fmt->format;
+               csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
+       }
+
+       return 0;
+}
+
+/*
+ * csi2_init_formats - Initialize formats on all pads
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = CSI2_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       csi2_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/*
+ * csi2_set_stream - Enable/Disable streaming on the CSI2 module
+ * @sd: ISP CSI2 V4L2 subdevice
+ * @enable: ISP pipeline stream state
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct isp_device *isp = csi2->isp;
+       struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
+       struct isp_video *video_out = &csi2->video_out;
+
+       switch (enable) {
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               if (omap3isp_csiphy_acquire(csi2->phy) < 0)
+                       return -ENODEV;
+               csi2->use_fs_irq = pipe->do_propagation;
+               if (csi2->output & CSI2_OUTPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+               csi2_configure(csi2);
+               csi2_print_status(csi2);
+
+               /*
+                * When outputting to memory with no buffer available, let the
+                * buffer queue handler start the hardware. A DMA queue flag
+                * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+                * a buffer available.
+                */
+               if (csi2->output & CSI2_OUTPUT_MEMORY &&
+                   !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED))
+                       break;
+               /* Enable context 0 and IRQs */
+               atomic_set(&csi2->stopping, 0);
+               csi2_ctx_enable(isp, csi2, 0, 1);
+               csi2_if_enable(isp, csi2, 1);
+               isp_video_dmaqueue_flags_clr(video_out);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               if (csi2->state == ISP_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait,
+                                             &csi2->stopping))
+                       dev_dbg(isp->dev, "%s: module stop timeout.\n",
+                               sd->name);
+               csi2_ctx_enable(isp, csi2, 0, 0);
+               csi2_if_enable(isp, csi2, 0);
+               csi2_irq_ctx_set(isp, csi2, 0);
+               omap3isp_csiphy_release(csi2->phy);
+               isp_video_dmaqueue_flags_clr(video_out);
+               omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
+               break;
+       }
+
+       csi2->state = enable;
+       return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops csi2_video_ops = {
+       .s_stream = csi2_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
+       .enum_mbus_code = csi2_enum_mbus_code,
+       .enum_frame_size = csi2_enum_frame_size,
+       .get_fmt = csi2_get_format,
+       .set_fmt = csi2_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops csi2_ops = {
+       .video = &csi2_video_ops,
+       .pad = &csi2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+       .open = csi2_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * csi2_link_setup - Setup CSI2 connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int csi2_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+
+       /*
+        * The ISP core doesn't support pipelines with multiple video outputs.
+        * Revisit this when it will be implemented, and return -EBUSY for now.
+        */
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (csi2->output & ~CSI2_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       csi2->output |= CSI2_OUTPUT_MEMORY;
+               } else {
+                       csi2->output &= ~CSI2_OUTPUT_MEMORY;
+               }
+               break;
+
+       case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (csi2->output & ~CSI2_OUTPUT_CCDC)
+                               return -EBUSY;
+                       csi2->output |= CSI2_OUTPUT_CCDC;
+               } else {
+                       csi2->output &= ~CSI2_OUTPUT_CCDC;
+               }
+               break;
+
+       default:
+               /* Link from camera to CSI2 is fixed... */
+               return -EINVAL;
+       }
+
+       ctrl->vp_only_enable =
+               (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true;
+       ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC);
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations csi2_media_ops = {
+       .link_setup = csi2_link_setup,
+};
+
+/*
+ * csi2_init_entities - Initialize subdev and media entity.
+ * @csi2: Pointer to csi2 structure.
+ * return -ENOMEM or zero on success
+ */
+static int csi2_init_entities(struct isp_csi2_device *csi2)
+{
+       struct v4l2_subdev *sd = &csi2->subdev;
+       struct media_pad *pads = csi2->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       v4l2_subdev_init(sd, &csi2_ops);
+       sd->internal_ops = &csi2_internal_ops;
+       strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
+
+       sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+       v4l2_set_subdevdata(sd, csi2);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+       pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+       me->ops = &csi2_media_ops;
+       ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       csi2_init_formats(sd, NULL);
+
+       /* Video device node */
+       csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       csi2->video_out.ops = &csi2_ispvideo_ops;
+       csi2->video_out.bpl_alignment = 32;
+       csi2->video_out.bpl_zero_padding = 1;
+       csi2->video_out.bpl_max = 0x1ffe0;
+       csi2->video_out.isp = csi2->isp;
+       csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+       ret = omap3isp_video_init(&csi2->video_out, "CSI2a");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the CSI2 subdev to the video node. */
+       ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
+                                      &csi2->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
+{
+       media_entity_cleanup(&csi2->subdev.entity);
+
+       v4l2_device_unregister_subdev(&csi2->subdev);
+       omap3isp_video_unregister(&csi2->video_out);
+}
+
+int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
+                                   struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video nodes. */
+       ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&csi2->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap3isp_csi2_unregister_entities(csi2);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP CSI2 initialisation and cleanup
+ */
+
+/*
+ * omap3isp_csi2_cleanup - Routine for module driver cleanup
+ */
+void omap3isp_csi2_cleanup(struct isp_device *isp)
+{
+}
+
+/*
+ * omap3isp_csi2_init - Routine for module driver init
+ */
+int omap3isp_csi2_init(struct isp_device *isp)
+{
+       struct isp_csi2_device *csi2a = &isp->isp_csi2a;
+       struct isp_csi2_device *csi2c = &isp->isp_csi2c;
+       int ret;
+
+       csi2a->isp = isp;
+       csi2a->available = 1;
+       csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1;
+       csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2;
+       csi2a->phy = &isp->isp_csiphy2;
+       csi2a->state = ISP_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&csi2a->wait);
+
+       ret = csi2_init_entities(csi2a);
+       if (ret < 0)
+               goto fail;
+
+       if (isp->revision == ISP_REVISION_15_0) {
+               csi2c->isp = isp;
+               csi2c->available = 1;
+               csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1;
+               csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2;
+               csi2c->phy = &isp->isp_csiphy1;
+               csi2c->state = ISP_PIPELINE_STREAM_STOPPED;
+               init_waitqueue_head(&csi2c->wait);
+       }
+
+       return 0;
+fail:
+       omap3isp_csi2_cleanup(isp);
+       return ret;
+}
diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h
new file mode 100644 (file)
index 0000000..456fb7f
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * ispcsi2.h
+ *
+ * TI OMAP3 ISP - CSI2 module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CSI2_H
+#define OMAP3_ISP_CSI2_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+struct isp_csiphy;
+
+/* This is not an exhaustive list */
+enum isp_csi2_pix_formats {
+       CSI2_PIX_FMT_OTHERS = 0,
+       CSI2_PIX_FMT_YUV422_8BIT = 0x1e,
+       CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e,
+       CSI2_PIX_FMT_RAW10_EXP16 = 0xab,
+       CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f,
+       CSI2_PIX_FMT_RAW8 = 0x2a,
+       CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa,
+       CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a,
+       CSI2_PIX_FMT_RAW8_VP = 0x12a,
+       CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340,
+       CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0,
+       CSI2_USERDEF_8BIT_DATA1 = 0x40,
+};
+
+enum isp_csi2_irqevents {
+       OCP_ERR_IRQ = 0x4000,
+       SHORT_PACKET_IRQ = 0x2000,
+       ECC_CORRECTION_IRQ = 0x1000,
+       ECC_NO_CORRECTION_IRQ = 0x800,
+       COMPLEXIO2_ERR_IRQ = 0x400,
+       COMPLEXIO1_ERR_IRQ = 0x200,
+       FIFO_OVF_IRQ = 0x100,
+       CONTEXT7 = 0x80,
+       CONTEXT6 = 0x40,
+       CONTEXT5 = 0x20,
+       CONTEXT4 = 0x10,
+       CONTEXT3 = 0x8,
+       CONTEXT2 = 0x4,
+       CONTEXT1 = 0x2,
+       CONTEXT0 = 0x1,
+};
+
+enum isp_csi2_ctx_irqevents {
+       CTX_ECC_CORRECTION = 0x100,
+       CTX_LINE_NUMBER = 0x80,
+       CTX_FRAME_NUMBER = 0x40,
+       CTX_CS = 0x20,
+       CTX_LE = 0x8,
+       CTX_LS = 0x4,
+       CTX_FE = 0x2,
+       CTX_FS = 0x1,
+};
+
+enum isp_csi2_frame_mode {
+       ISP_CSI2_FRAME_IMMEDIATE,
+       ISP_CSI2_FRAME_AFTERFEC,
+};
+
+#define ISP_CSI2_MAX_CTX_NUM   7
+
+struct isp_csi2_ctx_cfg {
+       u8 ctxnum;              /* context number 0 - 7 */
+       u8 dpcm_decompress;
+
+       /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */
+       u8 virtual_id;
+       u16 format_id;          /* as in CSI2_CTx_CTRL2[9:0] */
+       u8 dpcm_predictor;      /* 1: simple, 0: advanced */
+
+       /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */
+       u16 alpha;
+       u16 data_offset;
+       u32 ping_addr;
+       u32 pong_addr;
+       u8 eof_enabled;
+       u8 eol_enabled;
+       u8 checksum_enabled;
+       u8 enabled;
+};
+
+struct isp_csi2_timing_cfg {
+       u8 ionum;                       /* IO1 or IO2 as in CSI2_TIMING */
+       unsigned force_rx_mode:1;
+       unsigned stop_state_16x:1;
+       unsigned stop_state_4x:1;
+       u16 stop_state_counter;
+};
+
+struct isp_csi2_ctrl_cfg {
+       bool vp_clk_enable;
+       bool vp_only_enable;
+       u8 vp_out_ctrl;
+       enum isp_csi2_frame_mode frame_mode;
+       bool ecc_enable;
+       bool if_enable;
+};
+
+#define CSI2_PAD_SINK          0
+#define CSI2_PAD_SOURCE                1
+#define CSI2_PADS_NUM          2
+
+#define CSI2_OUTPUT_CCDC       (1 << 0)
+#define CSI2_OUTPUT_MEMORY     (1 << 1)
+
+struct isp_csi2_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[CSI2_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM];
+
+       struct isp_video video_out;
+       struct isp_device *isp;
+
+       u8 available;           /* Is the IP present on the silicon? */
+
+       /* mem resources - enums as defined in enum isp_mem_resources */
+       u8 regs1;
+       u8 regs2;
+
+       u32 output; /* output to CCDC, memory or both? */
+       bool dpcm_decompress;
+       unsigned int frame_skip;
+       bool use_fs_irq;
+
+       struct isp_csiphy *phy;
+       struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1];
+       struct isp_csi2_timing_cfg timing[2];
+       struct isp_csi2_ctrl_cfg ctrl;
+       enum isp_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+int omap3isp_csi2_isr(struct isp_csi2_device *csi2);
+int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
+int omap3isp_csi2_init(struct isp_device *isp);
+void omap3isp_csi2_cleanup(struct isp_device *isp);
+void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2);
+int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
+                                   struct v4l2_device *vdev);
+#endif /* OMAP3_ISP_CSI2_H */
diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/video/omap3isp/ispcsiphy.c
new file mode 100644 (file)
index 0000000..5be37ce
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * ispcsiphy.c
+ *
+ * TI OMAP3 ISP - CSI PHY module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsiphy.h"
+
+/*
+ * csiphy_lanes_config - Configuration of CSIPHY lanes.
+ *
+ * Updates HW configuration.
+ * Called with phy->mutex taken.
+ */
+static void csiphy_lanes_config(struct isp_csiphy *phy)
+{
+       unsigned int i;
+       u32 reg;
+
+       reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
+
+       for (i = 0; i < phy->num_data_lanes; i++) {
+               reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
+                        ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
+               reg |= (phy->lanes.data[i].pol <<
+                       ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
+               reg |= (phy->lanes.data[i].pos <<
+                       ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
+       }
+
+       reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
+                ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
+       reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
+       reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
+
+       isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
+}
+
+/*
+ * csiphy_power_autoswitch_enable
+ * @enable: Sets or clears the autoswitch function enable flag.
+ */
+static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
+{
+       isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
+                       ISPCSI2_PHY_CFG_PWR_AUTO,
+                       enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
+}
+
+/*
+ * csiphy_set_power
+ * @power: Power state to be set.
+ *
+ * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
+ */
+static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
+{
+       u32 reg;
+       u8 retry_count;
+
+       isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
+                       ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
+
+       retry_count = 0;
+       do {
+               udelay(50);
+               reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
+                                   ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
+
+               if (reg != power >> 2)
+                       retry_count++;
+
+       } while ((reg != power >> 2) && (retry_count < 100));
+
+       if (retry_count == 100) {
+               printk(KERN_ERR "CSI2 CIO set power failed!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/*
+ * csiphy_dphy_config - Configure CSI2 D-PHY parameters.
+ *
+ * Called with phy->mutex taken.
+ */
+static void csiphy_dphy_config(struct isp_csiphy *phy)
+{
+       u32 reg;
+
+       /* Set up ISPCSIPHY_REG0 */
+       reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
+
+       reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
+                ISPCSIPHY_REG0_THS_SETTLE_MASK);
+       reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT;
+       reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
+
+       isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
+
+       /* Set up ISPCSIPHY_REG1 */
+       reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
+
+       reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
+                ISPCSIPHY_REG1_TCLK_MISS_MASK |
+                ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
+       reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
+       reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
+       reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
+
+       isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
+}
+
+static int csiphy_config(struct isp_csiphy *phy,
+                        struct isp_csiphy_dphy_cfg *dphy,
+                        struct isp_csiphy_lanes_cfg *lanes)
+{
+       unsigned int used_lanes = 0;
+       unsigned int i;
+
+       /* Clock and data lanes verification */
+       for (i = 0; i < phy->num_data_lanes; i++) {
+               if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
+                       return -EINVAL;
+
+               if (used_lanes & (1 << lanes->data[i].pos))
+                       return -EINVAL;
+
+               used_lanes |= 1 << lanes->data[i].pos;
+       }
+
+       if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
+               return -EINVAL;
+
+       if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
+               return -EINVAL;
+
+       mutex_lock(&phy->mutex);
+       phy->dphy = *dphy;
+       phy->lanes = *lanes;
+       mutex_unlock(&phy->mutex);
+
+       return 0;
+}
+
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
+{
+       int rval;
+
+       if (phy->vdd == NULL) {
+               dev_err(phy->isp->dev, "Power regulator for CSI PHY not "
+                       "available\n");
+               return -ENODEV;
+       }
+
+       mutex_lock(&phy->mutex);
+
+       rval = regulator_enable(phy->vdd);
+       if (rval < 0)
+               goto done;
+
+       omap3isp_csi2_reset(phy->csi2);
+
+       csiphy_dphy_config(phy);
+       csiphy_lanes_config(phy);
+
+       rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
+       if (rval) {
+               regulator_disable(phy->vdd);
+               goto done;
+       }
+
+       csiphy_power_autoswitch_enable(phy, true);
+       phy->phy_in_use = 1;
+
+done:
+       mutex_unlock(&phy->mutex);
+       return rval;
+}
+
+void omap3isp_csiphy_release(struct isp_csiphy *phy)
+{
+       mutex_lock(&phy->mutex);
+       if (phy->phy_in_use) {
+               csiphy_power_autoswitch_enable(phy, false);
+               csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
+               regulator_disable(phy->vdd);
+               phy->phy_in_use = 0;
+       }
+       mutex_unlock(&phy->mutex);
+}
+
+/*
+ * omap3isp_csiphy_init - Initialize the CSI PHY frontends
+ */
+int omap3isp_csiphy_init(struct isp_device *isp)
+{
+       struct isp_csiphy *phy1 = &isp->isp_csiphy1;
+       struct isp_csiphy *phy2 = &isp->isp_csiphy2;
+
+       isp->platform_cb.csiphy_config = csiphy_config;
+
+       phy2->isp = isp;
+       phy2->csi2 = &isp->isp_csi2a;
+       phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
+       phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
+       phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
+       mutex_init(&phy2->mutex);
+
+       if (isp->revision == ISP_REVISION_15_0) {
+               phy1->isp = isp;
+               phy1->csi2 = &isp->isp_csi2c;
+               phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
+               phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
+               phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
+               mutex_init(&phy1->mutex);
+       }
+
+       return 0;
+}
diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h
new file mode 100644 (file)
index 0000000..9596dc6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * ispcsiphy.h
+ *
+ * TI OMAP3 ISP - CSI PHY module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_CSI_PHY_H
+#define OMAP3_ISP_CSI_PHY_H
+
+struct isp_csi2_device;
+struct regulator;
+
+struct csiphy_lane {
+       u8 pos;
+       u8 pol;
+};
+
+#define ISP_CSIPHY2_NUM_DATA_LANES     2
+#define ISP_CSIPHY1_NUM_DATA_LANES     1
+
+struct isp_csiphy_lanes_cfg {
+       struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
+       struct csiphy_lane clk;
+};
+
+struct isp_csiphy_dphy_cfg {
+       u8 ths_term;
+       u8 ths_settle;
+       u8 tclk_term;
+       unsigned tclk_miss:1;
+       u8 tclk_settle;
+};
+
+struct isp_csiphy {
+       struct isp_device *isp;
+       struct mutex mutex;     /* serialize csiphy configuration */
+       u8 phy_in_use;
+       struct isp_csi2_device *csi2;
+       struct regulator *vdd;
+
+       /* mem resources - enums as defined in enum isp_mem_resources */
+       unsigned int cfg_regs;
+       unsigned int phy_regs;
+
+       u8 num_data_lanes;      /* number of CSI2 Data Lanes supported */
+       struct isp_csiphy_lanes_cfg lanes;
+       struct isp_csiphy_dphy_cfg dphy;
+};
+
+int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
+void omap3isp_csiphy_release(struct isp_csiphy *phy);
+int omap3isp_csiphy_init(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_CSI_PHY_H */
diff --git a/drivers/media/video/omap3isp/isph3a.h b/drivers/media/video/omap3isp/isph3a.h
new file mode 100644 (file)
index 0000000..fb09fd4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * isph3a.h
+ *
+ * TI OMAP3 ISP - H3A AF module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_H3A_H
+#define OMAP3_ISP_H3A_H
+
+#include <linux/omap3isp.h>
+
+/*
+ * ----------
+ * -H3A AEWB-
+ * ----------
+ */
+
+#define AEWB_PACKET_SIZE       16
+#define AEWB_SATURATION_LIMIT  0x3ff
+
+/* Flags for changed registers */
+#define PCR_CHNG               (1 << 0)
+#define AEWWIN1_CHNG           (1 << 1)
+#define AEWINSTART_CHNG                (1 << 2)
+#define AEWINBLK_CHNG          (1 << 3)
+#define AEWSUBWIN_CHNG         (1 << 4)
+#define PRV_WBDGAIN_CHNG       (1 << 5)
+#define PRV_WBGAIN_CHNG                (1 << 6)
+
+/* ISPH3A REGISTERS bits */
+#define ISPH3A_PCR_AF_EN       (1 << 0)
+#define ISPH3A_PCR_AF_ALAW_EN  (1 << 1)
+#define ISPH3A_PCR_AF_MED_EN   (1 << 2)
+#define ISPH3A_PCR_AF_BUSY     (1 << 15)
+#define ISPH3A_PCR_AEW_EN      (1 << 16)
+#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17)
+#define ISPH3A_PCR_AEW_BUSY    (1 << 18)
+#define ISPH3A_PCR_AEW_MASK    (ISPH3A_PCR_AEW_ALAW_EN | \
+                                ISPH3A_PCR_AEW_AVE2LMT_MASK)
+
+/*
+ * --------
+ * -H3A AF-
+ * --------
+ */
+
+/* Peripheral Revision */
+#define AFPID                          0x0
+
+#define AFCOEF_OFFSET                  0x00000004      /* COEF base address */
+
+/* PCR fields */
+#define AF_BUSYAF                      (1 << 15)
+#define AF_FVMODE                      (1 << 14)
+#define AF_RGBPOS                      (0x7 << 11)
+#define AF_MED_TH                      (0xFF << 3)
+#define AF_MED_EN                      (1 << 2)
+#define AF_ALAW_EN                     (1 << 1)
+#define AF_EN                          (1 << 0)
+#define AF_PCR_MASK                    (AF_FVMODE | AF_RGBPOS | AF_MED_TH | \
+                                        AF_MED_EN | AF_ALAW_EN)
+
+/* AFPAX1 fields */
+#define AF_PAXW                                (0x7F << 16)
+#define AF_PAXH                                0x7F
+
+/* AFPAX2 fields */
+#define AF_AFINCV                      (0xF << 13)
+#define AF_PAXVC                       (0x7F << 6)
+#define AF_PAXHC                       0x3F
+
+/* AFPAXSTART fields */
+#define AF_PAXSH                       (0xFFF<<16)
+#define AF_PAXSV                       0xFFF
+
+/* COEFFICIENT MASK */
+#define AF_COEF_MASK0                  0xFFF
+#define AF_COEF_MASK1                  (0xFFF<<16)
+
+/* BIT SHIFTS */
+#define AF_RGBPOS_SHIFT                        11
+#define AF_MED_TH_SHIFT                        3
+#define AF_PAXW_SHIFT                  16
+#define AF_LINE_INCR_SHIFT             13
+#define AF_VT_COUNT_SHIFT              6
+#define AF_HZ_START_SHIFT              16
+#define AF_COEF_SHIFT                  16
+
+/* Init and cleanup functions */
+int omap3isp_h3a_aewb_init(struct isp_device *isp);
+int omap3isp_h3a_af_init(struct isp_device *isp);
+
+void omap3isp_h3a_aewb_cleanup(struct isp_device *isp);
+void omap3isp_h3a_af_cleanup(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_H3A_H */
diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c
new file mode 100644 (file)
index 0000000..8068cef
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * isph3a.c
+ *
+ * TI OMAP3 ISP - H3A module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+/*
+ * h3a_aewb_update_regs - Helper function to update h3a registers.
+ */
+static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
+{
+       struct omap3isp_h3a_aewb_config *conf = priv;
+       u32 pcr;
+       u32 win1;
+       u32 start;
+       u32 blk;
+       u32 subwin;
+
+       if (aewb->state == ISPSTAT_DISABLED)
+               return;
+
+       isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
+                      OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
+
+       if (!aewb->update)
+               return;
+
+       /* Converting config metadata into reg values */
+       pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
+       pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
+
+       win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
+       win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
+       win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
+       win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
+
+       start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
+       start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
+
+       blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
+       blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
+
+       subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
+                ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
+       subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
+                 ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
+
+       isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
+       isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
+                      ISPH3A_AEWINSTART);
+       isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
+       isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
+                      ISPH3A_AEWSUBWIN);
+       isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                       ISPH3A_PCR_AEW_MASK, pcr);
+
+       aewb->update = 0;
+       aewb->config_counter += aewb->inc_config;
+       aewb->inc_config = 0;
+       aewb->buf_size = conf->buf_size;
+}
+
+static void h3a_aewb_enable(struct ispstat *aewb, int enable)
+{
+       if (enable) {
+               isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                           ISPH3A_PCR_AEW_EN);
+               /* This bit is already set if AF is enabled */
+               if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
+                       isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                                   ISPCTRL_H3A_CLK_EN);
+       } else {
+               isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                           ISPH3A_PCR_AEW_EN);
+               /* This bit can't be cleared if AF is enabled */
+               if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
+                       isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                                   ISPCTRL_H3A_CLK_EN);
+       }
+}
+
+static int h3a_aewb_busy(struct ispstat *aewb)
+{
+       return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+                                               & ISPH3A_PCR_BUSYAEAWB;
+}
+
+static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
+{
+       /* Number of configured windows + extra row for black data */
+       u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
+
+       /*
+        * Unsaturated block counts for each 8 windows.
+        * 1 extra for the last (win_count % 8) windows if win_count is not
+        * divisible by 8.
+        */
+       win_count += (win_count + 7) / 8;
+
+       return win_count * AEWB_PACKET_SIZE;
+}
+
+static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
+{
+       struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+       u32 buf_size;
+
+       if (unlikely(user_cfg->saturation_limit >
+                    OMAP3ISP_AEWB_MAX_SATURATION_LIM))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+                    user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+                    user_cfg->win_height & 0x01))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
+                    user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
+                    user_cfg->win_width & 0x01))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
+                    user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
+                    user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
+                    user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
+                    user_cfg->blk_win_height & 0x01))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+                    user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+                    user_cfg->subsample_ver_inc & 0x01))
+               return -EINVAL;
+
+       if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
+                    user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
+                    user_cfg->subsample_hor_inc & 0x01))
+               return -EINVAL;
+
+       buf_size = h3a_aewb_get_buf_size(user_cfg);
+       if (buf_size > user_cfg->buf_size)
+               user_cfg->buf_size = buf_size;
+       else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
+               user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
+
+       return 0;
+}
+
+/*
+ * h3a_aewb_set_params - Helper function to check & store user given params.
+ * @new_conf: Pointer to AE and AWB parameters struct.
+ *
+ * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
+ * program them during ISR.
+ */
+static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
+{
+       struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
+       struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
+       int update = 0;
+
+       if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
+               cur_cfg->saturation_limit = user_cfg->saturation_limit;
+               update = 1;
+       }
+       if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+               cur_cfg->alaw_enable = user_cfg->alaw_enable;
+               update = 1;
+       }
+       if (cur_cfg->win_height != user_cfg->win_height) {
+               cur_cfg->win_height = user_cfg->win_height;
+               update = 1;
+       }
+       if (cur_cfg->win_width != user_cfg->win_width) {
+               cur_cfg->win_width = user_cfg->win_width;
+               update = 1;
+       }
+       if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
+               cur_cfg->ver_win_count = user_cfg->ver_win_count;
+               update = 1;
+       }
+       if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
+               cur_cfg->hor_win_count = user_cfg->hor_win_count;
+               update = 1;
+       }
+       if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
+               cur_cfg->ver_win_start = user_cfg->ver_win_start;
+               update = 1;
+       }
+       if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
+               cur_cfg->hor_win_start = user_cfg->hor_win_start;
+               update = 1;
+       }
+       if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
+               cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
+               update = 1;
+       }
+       if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
+               cur_cfg->blk_win_height = user_cfg->blk_win_height;
+               update = 1;
+       }
+       if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
+               cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
+               update = 1;
+       }
+       if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
+               cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
+               update = 1;
+       }
+
+       if (update || !aewb->configured) {
+               aewb->inc_config++;
+               aewb->update = 1;
+               cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
+       }
+}
+
+static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+       switch (cmd) {
+       case VIDIOC_OMAP3ISP_AEWB_CFG:
+               return omap3isp_stat_config(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_REQ:
+               return omap3isp_stat_request_statistics(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_EN: {
+               unsigned long *en = arg;
+               return omap3isp_stat_enable(stat, !!*en);
+       }
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static const struct ispstat_ops h3a_aewb_ops = {
+       .validate_params        = h3a_aewb_validate_params,
+       .set_params             = h3a_aewb_set_params,
+       .setup_regs             = h3a_aewb_setup_regs,
+       .enable                 = h3a_aewb_enable,
+       .busy                   = h3a_aewb_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
+       .ioctl = h3a_aewb_ioctl,
+       .subscribe_event = omap3isp_stat_subscribe_event,
+       .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
+       .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
+       .core = &h3a_aewb_subdev_core_ops,
+       .video = &h3a_aewb_subdev_video_ops,
+};
+
+/*
+ * omap3isp_h3a_aewb_init - Module Initialisation.
+ */
+int omap3isp_h3a_aewb_init(struct isp_device *isp)
+{
+       struct ispstat *aewb = &isp->isp_aewb;
+       struct omap3isp_h3a_aewb_config *aewb_cfg;
+       struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
+       int ret;
+
+       aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
+       if (!aewb_cfg)
+               return -ENOMEM;
+
+       memset(aewb, 0, sizeof(*aewb));
+       aewb->ops = &h3a_aewb_ops;
+       aewb->priv = aewb_cfg;
+       aewb->dma_ch = -1;
+       aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
+       aewb->isp = isp;
+
+       /* Set recover state configuration */
+       aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
+       if (!aewb_recover_cfg) {
+               dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
+                                       "recover configuration.\n");
+               ret = -ENOMEM;
+               goto err_recover_alloc;
+       }
+
+       aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
+       aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+       aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
+       aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
+       aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
+       aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
+               aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
+       aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
+       aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+       aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
+
+       if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
+               dev_err(aewb->isp->dev, "AEWB: recover configuration is "
+                                       "invalid.\n");
+               ret = -EINVAL;
+               goto err_conf;
+       }
+
+       aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
+       aewb->recover_priv = aewb_recover_cfg;
+
+       ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
+       if (ret)
+               goto err_conf;
+
+       return 0;
+
+err_conf:
+       kfree(aewb_recover_cfg);
+err_recover_alloc:
+       kfree(aewb_cfg);
+
+       return ret;
+}
+
+/*
+ * omap3isp_h3a_aewb_cleanup - Module exit.
+ */
+void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
+{
+       kfree(isp->isp_aewb.priv);
+       kfree(isp->isp_aewb.recover_priv);
+       omap3isp_stat_free(&isp->isp_aewb);
+}
diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c
new file mode 100644 (file)
index 0000000..ba54d0a
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * isph3a_af.c
+ *
+ * TI OMAP3 ISP - H3A AF module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* Linux specific include files */
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include "isp.h"
+#include "isph3a.h"
+#include "ispstat.h"
+
+#define IS_OUT_OF_BOUNDS(value, min, max)              \
+       (((value) < (min)) || ((value) > (max)))
+
+static void h3a_af_setup_regs(struct ispstat *af, void *priv)
+{
+       struct omap3isp_h3a_af_config *conf = priv;
+       u32 pcr;
+       u32 pax1;
+       u32 pax2;
+       u32 paxstart;
+       u32 coef;
+       u32 base_coef_set0;
+       u32 base_coef_set1;
+       int index;
+
+       if (af->state == ISPSTAT_DISABLED)
+               return;
+
+       isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A,
+                      ISPH3A_AFBUFST);
+
+       if (!af->update)
+               return;
+
+       /* Configure Hardware Registers */
+       pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;
+       /* Set height in AFPAX1 */
+       pax1 |= (conf->paxel.height >> 1) - 1;
+       isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
+
+       /* Configure AFPAX2 Register */
+       /* Set Line Increment in AFPAX2 Register */
+       pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;
+       /* Set Vertical Count */
+       pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;
+       /* Set Horizontal Count */
+       pax2 |= (conf->paxel.h_cnt - 1);
+       isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
+
+       /* Configure PAXSTART Register */
+       /*Configure Horizontal Start */
+       paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;
+       /* Configure Vertical Start */
+       paxstart |= conf->paxel.v_start;
+       isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,
+                      ISPH3A_AFPAXSTART);
+
+       /*SetIIRSH Register */
+       isp_reg_writel(af->isp, conf->iir.h_start,
+                      OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
+
+       base_coef_set0 = ISPH3A_AFCOEF010;
+       base_coef_set1 = ISPH3A_AFCOEF110;
+       for (index = 0; index <= 8; index += 2) {
+               /*Set IIR Filter0 Coefficients */
+               coef = 0;
+               coef |= conf->iir.coeff_set0[index];
+               coef |= conf->iir.coeff_set0[index + 1] <<
+                       AF_COEF_SHIFT;
+               isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+                              base_coef_set0);
+               base_coef_set0 += AFCOEF_OFFSET;
+
+               /*Set IIR Filter1 Coefficients */
+               coef = 0;
+               coef |= conf->iir.coeff_set1[index];
+               coef |= conf->iir.coeff_set1[index + 1] <<
+                       AF_COEF_SHIFT;
+               isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
+                              base_coef_set1);
+               base_coef_set1 += AFCOEF_OFFSET;
+       }
+       /* set AFCOEF0010 Register */
+       isp_reg_writel(af->isp, conf->iir.coeff_set0[10],
+                      OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
+       /* set AFCOEF1010 Register */
+       isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
+                      OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
+
+       /* PCR Register */
+       /* Set RGB Position */
+       pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;
+       /* Set Accumulator Mode */
+       if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)
+               pcr |= AF_FVMODE;
+       /* Set A-law */
+       if (conf->alaw_enable)
+               pcr |= AF_ALAW_EN;
+       /* HMF Configurations */
+       if (conf->hmf.enable) {
+               /* Enable HMF */
+               pcr |= AF_MED_EN;
+               /* Set Median Threshold */
+               pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;
+       }
+       /* Set PCR Register */
+       isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                       AF_PCR_MASK, pcr);
+
+       af->update = 0;
+       af->config_counter += af->inc_config;
+       af->inc_config = 0;
+       af->buf_size = conf->buf_size;
+}
+
+static void h3a_af_enable(struct ispstat *af, int enable)
+{
+       if (enable) {
+               isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                           ISPH3A_PCR_AF_EN);
+               /* This bit is already set if AEWB is enabled */
+               if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
+                       isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                                   ISPCTRL_H3A_CLK_EN);
+       } else {
+               isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+                           ISPH3A_PCR_AF_EN);
+               /* This bit can't be cleared if AEWB is enabled */
+               if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
+                       isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                                   ISPCTRL_H3A_CLK_EN);
+       }
+}
+
+static int h3a_af_busy(struct ispstat *af)
+{
+       return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+                                               & ISPH3A_PCR_BUSYAF;
+}
+
+static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)
+{
+       return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;
+}
+
+/* Function to check paxel parameters */
+static int h3a_af_validate_params(struct ispstat *af, void *new_conf)
+{
+       struct omap3isp_h3a_af_config *user_cfg = new_conf;
+       struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;
+       struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;
+       int index;
+       u32 buf_size;
+
+       /* Check horizontal Count */
+       if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,
+                            OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,
+                            OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))
+               return -EINVAL;
+
+       /* Check Vertical Count */
+       if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
+                            OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,
+                            OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))
+               return -EINVAL;
+
+       if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,
+                            OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||
+           paxel_cfg->height % 2)
+               return -EINVAL;
+
+       /* Check width */
+       if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,
+                            OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||
+           paxel_cfg->width % 2)
+               return -EINVAL;
+
+       /* Check Line Increment */
+       if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
+                            OMAP3ISP_AF_PAXEL_INCREMENT_MIN,
+                            OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||
+           paxel_cfg->line_inc % 2)
+               return -EINVAL;
+
+       /* Check Horizontal Start */
+       if ((paxel_cfg->h_start < iir_cfg->h_start) ||
+           IS_OUT_OF_BOUNDS(paxel_cfg->h_start,
+                            OMAP3ISP_AF_PAXEL_HZSTART_MIN,
+                            OMAP3ISP_AF_PAXEL_HZSTART_MAX))
+               return -EINVAL;
+
+       /* Check IIR */
+       for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+               if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)
+                       return -EINVAL;
+
+               if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)
+                       return -EINVAL;
+       }
+
+       if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,
+                            OMAP3ISP_AF_IIRSH_MAX))
+               return -EINVAL;
+
+       /* Hack: If paxel size is 12, the 10th AF window may be corrupted */
+       if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&
+           (paxel_cfg->width * paxel_cfg->height == 12))
+               return -EINVAL;
+
+       buf_size = h3a_af_get_buf_size(user_cfg);
+       if (buf_size > user_cfg->buf_size)
+               /* User buf_size request wasn't enough */
+               user_cfg->buf_size = buf_size;
+       else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)
+               user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;
+
+       return 0;
+}
+
+/* Update local parameters */
+static void h3a_af_set_params(struct ispstat *af, void *new_conf)
+{
+       struct omap3isp_h3a_af_config *user_cfg = new_conf;
+       struct omap3isp_h3a_af_config *cur_cfg = af->priv;
+       int update = 0;
+       int index;
+
+       /* alaw */
+       if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
+               update = 1;
+               goto out;
+       }
+
+       /* hmf */
+       if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {
+               update = 1;
+               goto out;
+       }
+       if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {
+               update = 1;
+               goto out;
+       }
+
+       /* rgbpos */
+       if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {
+               update = 1;
+               goto out;
+       }
+
+       /* iir */
+       if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {
+               update = 1;
+               goto out;
+       }
+       for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
+               if (cur_cfg->iir.coeff_set0[index] !=
+                               user_cfg->iir.coeff_set0[index]) {
+                       update = 1;
+                       goto out;
+               }
+               if (cur_cfg->iir.coeff_set1[index] !=
+                               user_cfg->iir.coeff_set1[index]) {
+                       update = 1;
+                       goto out;
+               }
+       }
+
+       /* paxel */
+       if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||
+           (cur_cfg->paxel.height != user_cfg->paxel.height) ||
+           (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||
+           (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||
+           (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||
+           (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||
+           (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {
+               update = 1;
+               goto out;
+       }
+
+       /* af_mode */
+       if (cur_cfg->fvmode != user_cfg->fvmode)
+               update = 1;
+
+out:
+       if (update || !af->configured) {
+               memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));
+               af->inc_config++;
+               af->update = 1;
+               /*
+                * User might be asked for a bigger buffer than necessary for
+                * this configuration. In order to return the right amount of
+                * data during buffer request, let's calculate the size here
+                * instead of stick with user_cfg->buf_size.
+                */
+               cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);
+       }
+}
+
+static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+       switch (cmd) {
+       case VIDIOC_OMAP3ISP_AF_CFG:
+               return omap3isp_stat_config(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_REQ:
+               return omap3isp_stat_request_statistics(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_EN: {
+               int *en = arg;
+               return omap3isp_stat_enable(stat, !!*en);
+       }
+       }
+
+       return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops h3a_af_ops = {
+       .validate_params        = h3a_af_validate_params,
+       .set_params             = h3a_af_set_params,
+       .setup_regs             = h3a_af_setup_regs,
+       .enable                 = h3a_af_enable,
+       .busy                   = h3a_af_busy,
+};
+
+static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {
+       .ioctl = h3a_af_ioctl,
+       .subscribe_event = omap3isp_stat_subscribe_event,
+       .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {
+       .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops h3a_af_subdev_ops = {
+       .core = &h3a_af_subdev_core_ops,
+       .video = &h3a_af_subdev_video_ops,
+};
+
+/* Function to register the AF character device driver. */
+int omap3isp_h3a_af_init(struct isp_device *isp)
+{
+       struct ispstat *af = &isp->isp_af;
+       struct omap3isp_h3a_af_config *af_cfg;
+       struct omap3isp_h3a_af_config *af_recover_cfg;
+       int ret;
+
+       af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
+       if (af_cfg == NULL)
+               return -ENOMEM;
+
+       memset(af, 0, sizeof(*af));
+       af->ops = &h3a_af_ops;
+       af->priv = af_cfg;
+       af->dma_ch = -1;
+       af->event_type = V4L2_EVENT_OMAP3ISP_AF;
+       af->isp = isp;
+
+       /* Set recover state configuration */
+       af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
+       if (!af_recover_cfg) {
+               dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
+                                     "configuration.\n");
+               ret = -ENOMEM;
+               goto err_recover_alloc;
+       }
+
+       af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
+       af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;
+       af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;
+       af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;
+       af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;
+       af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;
+       if (h3a_af_validate_params(af, af_recover_cfg)) {
+               dev_err(af->isp->dev, "AF: recover configuration is "
+                                     "invalid.\n");
+               ret = -EINVAL;
+               goto err_conf;
+       }
+
+       af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
+       af->recover_priv = af_recover_cfg;
+
+       ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
+       if (ret)
+               goto err_conf;
+
+       return 0;
+
+err_conf:
+       kfree(af_recover_cfg);
+err_recover_alloc:
+       kfree(af_cfg);
+
+       return ret;
+}
+
+void omap3isp_h3a_af_cleanup(struct isp_device *isp)
+{
+       kfree(isp->isp_af.priv);
+       kfree(isp->isp_af.recover_priv);
+       omap3isp_stat_free(&isp->isp_af);
+}
diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c
new file mode 100644 (file)
index 0000000..1743856
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * isphist.c
+ *
+ * TI OMAP3 ISP - Histogram module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isphist.h"
+
+#define HIST_CONFIG_DMA        1
+
+#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
+
+/*
+ * hist_reset_mem - clear Histogram memory before start stats engine.
+ */
+static void hist_reset_mem(struct ispstat *hist)
+{
+       struct isp_device *isp = hist->isp;
+       struct omap3isp_hist_config *conf = hist->priv;
+       unsigned int i;
+
+       isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+       /*
+        * By setting it, the histogram internal buffer is being cleared at the
+        * same time it's being read. This bit must be cleared afterwards.
+        */
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+       /*
+        * We'll clear 4 words at each iteration for optimization. It avoids
+        * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
+        */
+       for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) {
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+       }
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+       hist->wait_acc_frames = conf->num_acc_frames;
+}
+
+static void hist_dma_config(struct ispstat *hist)
+{
+       hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
+       hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
+       hist->dma_config.frame_count = 1;
+       hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
+       hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
+       hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
+       hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+}
+
+/*
+ * hist_setup_regs - Helper function to update Histogram registers.
+ */
+static void hist_setup_regs(struct ispstat *hist, void *priv)
+{
+       struct isp_device *isp = hist->isp;
+       struct omap3isp_hist_config *conf = priv;
+       int c;
+       u32 cnt;
+       u32 wb_gain;
+       u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS];
+       u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS];
+
+       if (!hist->update || hist->state == ISPSTAT_DISABLED ||
+           hist->state == ISPSTAT_DISABLING)
+               return;
+
+       cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT;
+
+       wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT;
+       wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT;
+       wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT;
+       if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER)
+               wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT;
+
+       /* Regions size and position */
+       for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
+               if (c < conf->num_regions) {
+                       reg_hor[c] = conf->region[c].h_start <<
+                                    ISPHIST_REG_START_SHIFT;
+                       reg_hor[c] = conf->region[c].h_end <<
+                                    ISPHIST_REG_END_SHIFT;
+                       reg_ver[c] = conf->region[c].v_start <<
+                                    ISPHIST_REG_START_SHIFT;
+                       reg_ver[c] = conf->region[c].v_end <<
+                                    ISPHIST_REG_END_SHIFT;
+               } else {
+                       reg_hor[c] = 0;
+                       reg_ver[c] = 0;
+               }
+       }
+
+       cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT;
+       switch (conf->hist_bins) {
+       case OMAP3ISP_HIST_BINS_256:
+               cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) <<
+                       ISPHIST_CNT_SHIFT_SHIFT;
+               break;
+       case OMAP3ISP_HIST_BINS_128:
+               cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) <<
+                       ISPHIST_CNT_SHIFT_SHIFT;
+               break;
+       case OMAP3ISP_HIST_BINS_64:
+               cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) <<
+                       ISPHIST_CNT_SHIFT_SHIFT;
+               break;
+       default: /* OMAP3ISP_HIST_BINS_32 */
+               cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) <<
+                       ISPHIST_CNT_SHIFT_SHIFT;
+               break;
+       }
+
+       hist_reset_mem(hist);
+
+       isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
+       isp_reg_writel(isp, wb_gain,  OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
+       isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ);
+       isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT);
+       isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ);
+       isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT);
+       isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ);
+       isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT);
+       isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ);
+       isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT);
+
+       hist->update = 0;
+       hist->config_counter += hist->inc_config;
+       hist->inc_config = 0;
+       hist->buf_size = conf->buf_size;
+}
+
+static void hist_enable(struct ispstat *hist, int enable)
+{
+       if (enable) {
+               isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+                           ISPHIST_PCR_ENABLE);
+               isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                           ISPCTRL_HIST_CLK_EN);
+       } else {
+               isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
+                           ISPHIST_PCR_ENABLE);
+               isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+                           ISPCTRL_HIST_CLK_EN);
+       }
+}
+
+static int hist_busy(struct ispstat *hist)
+{
+       return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
+                                               & ISPHIST_PCR_BUSY;
+}
+
+static void hist_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct ispstat *hist = data;
+
+       if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
+               dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
+                       ch_status);
+               omap_stop_dma(lch);
+               hist_reset_mem(hist);
+               atomic_set(&hist->buf_err, 1);
+       }
+       isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+                   ISPHIST_CNT_CLEAR);
+
+       omap3isp_stat_dma_isr(hist);
+       if (hist->state != ISPSTAT_DISABLED)
+               omap3isp_hist_dma_done(hist->isp);
+}
+
+static int hist_buf_dma(struct ispstat *hist)
+{
+       dma_addr_t dma_addr = hist->active_buf->dma_addr;
+
+       if (unlikely(!dma_addr)) {
+               dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
+               hist_reset_mem(hist);
+               return STAT_NO_BUF;
+       }
+
+       isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+       isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+                   ISPHIST_CNT_CLEAR);
+       omap3isp_flush(hist->isp);
+       hist->dma_config.dst_start = dma_addr;
+       hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
+       omap_set_dma_params(hist->dma_ch, &hist->dma_config);
+
+       omap_start_dma(hist->dma_ch);
+
+       return STAT_BUF_WAITING_DMA;
+}
+
+static int hist_buf_pio(struct ispstat *hist)
+{
+       struct isp_device *isp = hist->isp;
+       u32 *buf = hist->active_buf->virt_addr;
+       unsigned int i;
+
+       if (!buf) {
+               dev_dbg(isp->dev, "hist: invalid PIO buffer address\n");
+               hist_reset_mem(hist);
+               return STAT_NO_BUF;
+       }
+
+       isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+       /*
+        * By setting it, the histogram internal buffer is being cleared at the
+        * same time it's being read. This bit must be cleared just after all
+        * data is acquired.
+        */
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
+
+       /*
+        * We'll read 4 times a 4-bytes-word at each iteration for
+        * optimization. It avoids 3/4 of the jumps. We also know buf_size is
+        * divisible by 16.
+        */
+       for (i = hist->buf_size / 16; i > 0; i--) {
+               *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+               *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+       }
+       isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+                   ISPHIST_CNT_CLEAR);
+
+       return STAT_BUF_DONE;
+}
+
+/*
+ * hist_buf_process - Callback from ISP driver for HIST interrupt.
+ */
+static int hist_buf_process(struct ispstat *hist)
+{
+       struct omap3isp_hist_config *user_cfg = hist->priv;
+       int ret;
+
+       if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) {
+               hist_reset_mem(hist);
+               return STAT_NO_BUF;
+       }
+
+       if (--(hist->wait_acc_frames))
+               return STAT_NO_BUF;
+
+       if (HIST_USING_DMA(hist))
+               ret = hist_buf_dma(hist);
+       else
+               ret = hist_buf_pio(hist);
+
+       hist->wait_acc_frames = user_cfg->num_acc_frames;
+
+       return ret;
+}
+
+static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
+{
+       return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions;
+}
+
+/*
+ * hist_validate_params - Helper function to check user given params.
+ * @user_cfg: Pointer to user configuration structure.
+ *
+ * Returns 0 on success configuration.
+ */
+static int hist_validate_params(struct ispstat *hist, void *new_conf)
+{
+       struct omap3isp_hist_config *user_cfg = new_conf;
+       int c;
+       u32 buf_size;
+
+       if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3)
+               return -EINVAL;
+
+       /* Regions size and position */
+
+       if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) ||
+           (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS))
+               return -EINVAL;
+
+       /* Regions */
+       for (c = 0; c < user_cfg->num_regions; c++) {
+               if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK)
+                       return -EINVAL;
+               if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK)
+                       return -EINVAL;
+               if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK)
+                       return -EINVAL;
+               if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK)
+                       return -EINVAL;
+               if (user_cfg->region[c].h_start > user_cfg->region[c].h_end)
+                       return -EINVAL;
+               if (user_cfg->region[c].v_start > user_cfg->region[c].v_end)
+                       return -EINVAL;
+       }
+
+       switch (user_cfg->num_regions) {
+       case 1:
+               if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256)
+                       return -EINVAL;
+               break;
+       case 2:
+               if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128)
+                       return -EINVAL;
+               break;
+       default: /* 3 or 4 */
+               if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64)
+                       return -EINVAL;
+               break;
+       }
+
+       buf_size = hist_get_buf_size(user_cfg);
+       if (buf_size > user_cfg->buf_size)
+               /* User's buf_size request wasn't enoght */
+               user_cfg->buf_size = buf_size;
+       else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
+               user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
+
+       return 0;
+}
+
+static int hist_comp_params(struct ispstat *hist,
+                           struct omap3isp_hist_config *user_cfg)
+{
+       struct omap3isp_hist_config *cur_cfg = hist->priv;
+       int c;
+
+       if (cur_cfg->cfa != user_cfg->cfa)
+               return 1;
+
+       if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
+               return 1;
+
+       if (cur_cfg->hist_bins != user_cfg->hist_bins)
+               return 1;
+
+       for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) {
+               if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3)
+                       break;
+               else if (cur_cfg->wg[c] != user_cfg->wg[c])
+                       return 1;
+       }
+
+       if (cur_cfg->num_regions != user_cfg->num_regions)
+               return 1;
+
+       /* Regions */
+       for (c = 0; c < user_cfg->num_regions; c++) {
+               if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start)
+                       return 1;
+               if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end)
+                       return 1;
+               if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start)
+                       return 1;
+               if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * hist_update_params - Helper function to check and store user given params.
+ * @new_conf: Pointer to user configuration structure.
+ */
+static void hist_set_params(struct ispstat *hist, void *new_conf)
+{
+       struct omap3isp_hist_config *user_cfg = new_conf;
+       struct omap3isp_hist_config *cur_cfg = hist->priv;
+
+       if (!hist->configured || hist_comp_params(hist, user_cfg)) {
+               memcpy(cur_cfg, user_cfg, sizeof(*user_cfg));
+               if (user_cfg->num_acc_frames == 0)
+                       user_cfg->num_acc_frames = 1;
+               hist->inc_config++;
+               hist->update = 1;
+               /*
+                * User might be asked for a bigger buffer than necessary for
+                * this configuration. In order to return the right amount of
+                * data during buffer request, let's calculate the size here
+                * instead of stick with user_cfg->buf_size.
+                */
+               cur_cfg->buf_size = hist_get_buf_size(cur_cfg);
+
+       }
+}
+
+static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct ispstat *stat = v4l2_get_subdevdata(sd);
+
+       switch (cmd) {
+       case VIDIOC_OMAP3ISP_HIST_CFG:
+               return omap3isp_stat_config(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_REQ:
+               return omap3isp_stat_request_statistics(stat, arg);
+       case VIDIOC_OMAP3ISP_STAT_EN: {
+               int *en = arg;
+               return omap3isp_stat_enable(stat, !!*en);
+       }
+       }
+
+       return -ENOIOCTLCMD;
+
+}
+
+static const struct ispstat_ops hist_ops = {
+       .validate_params        = hist_validate_params,
+       .set_params             = hist_set_params,
+       .setup_regs             = hist_setup_regs,
+       .enable                 = hist_enable,
+       .busy                   = hist_busy,
+       .buf_process            = hist_buf_process,
+};
+
+static const struct v4l2_subdev_core_ops hist_subdev_core_ops = {
+       .ioctl = hist_ioctl,
+       .subscribe_event = omap3isp_stat_subscribe_event,
+       .unsubscribe_event = omap3isp_stat_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_video_ops hist_subdev_video_ops = {
+       .s_stream = omap3isp_stat_s_stream,
+};
+
+static const struct v4l2_subdev_ops hist_subdev_ops = {
+       .core = &hist_subdev_core_ops,
+       .video = &hist_subdev_video_ops,
+};
+
+/*
+ * omap3isp_hist_init - Module Initialization.
+ */
+int omap3isp_hist_init(struct isp_device *isp)
+{
+       struct ispstat *hist = &isp->isp_hist;
+       struct omap3isp_hist_config *hist_cfg;
+       int ret = -1;
+
+       hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
+       if (hist_cfg == NULL)
+               return -ENOMEM;
+
+       memset(hist, 0, sizeof(*hist));
+       if (HIST_CONFIG_DMA)
+               ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
+                                      hist_dma_cb, hist, &hist->dma_ch);
+       if (ret) {
+               if (HIST_CONFIG_DMA)
+                       dev_warn(isp->dev, "hist: DMA request channel failed. "
+                                          "Using PIO only.\n");
+               hist->dma_ch = -1;
+       } else {
+               dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
+               hist_dma_config(hist);
+               omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+       }
+
+       hist->ops = &hist_ops;
+       hist->priv = hist_cfg;
+       hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
+       hist->isp = isp;
+
+       ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
+       if (ret) {
+               kfree(hist_cfg);
+               if (HIST_USING_DMA(hist))
+                       omap_free_dma(hist->dma_ch);
+       }
+
+       return ret;
+}
+
+/*
+ * omap3isp_hist_cleanup - Module cleanup.
+ */
+void omap3isp_hist_cleanup(struct isp_device *isp)
+{
+       if (HIST_USING_DMA(&isp->isp_hist))
+               omap_free_dma(isp->isp_hist.dma_ch);
+       kfree(isp->isp_hist.priv);
+       omap3isp_stat_free(&isp->isp_hist);
+}
diff --git a/drivers/media/video/omap3isp/isphist.h b/drivers/media/video/omap3isp/isphist.h
new file mode 100644 (file)
index 0000000..0b2a38e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * isphist.h
+ *
+ * TI OMAP3 ISP - Histogram module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_HIST_H
+#define OMAP3_ISP_HIST_H
+
+#include <linux/omap3isp.h>
+
+#define ISPHIST_IN_BIT_WIDTH_CCDC      10
+
+struct isp_device;
+
+int omap3isp_hist_init(struct isp_device *isp);
+void omap3isp_hist_cleanup(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_HIST */
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
new file mode 100644 (file)
index 0000000..baf9374
--- /dev/null
@@ -0,0 +1,2113 @@
+/*
+ * isppreview.c
+ *
+ * TI OMAP3 ISP driver - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "isppreview.h"
+
+/* Default values in Office Flourescent Light for RGBtoRGB Blending */
+static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
+       {       /* RGB-RGB Matrix */
+               {0x01E2, 0x0F30, 0x0FEE},
+               {0x0F9B, 0x01AC, 0x0FB9},
+               {0x0FE0, 0x0EC0, 0x0260}
+       },      /* RGB Offset */
+       {0x0000, 0x0000, 0x0000}
+};
+
+/* Default values in Office Flourescent Light for RGB to YUV Conversion*/
+static struct omap3isp_prev_csc flr_prev_csc = {
+       {       /* CSC Coef Matrix */
+               {66, 129, 25},
+               {-38, -75, 112},
+               {112, -94 , -18}
+       },      /* CSC Offset */
+       {0x0, 0x0, 0x0}
+};
+
+/* Default values in Office Flourescent Light for CFA Gradient*/
+#define FLR_CFA_GRADTHRS_HORZ  0x28
+#define FLR_CFA_GRADTHRS_VERT  0x28
+
+/* Default values in Office Flourescent Light for Chroma Suppression*/
+#define FLR_CSUP_GAIN          0x0D
+#define FLR_CSUP_THRES         0xEB
+
+/* Default values in Office Flourescent Light for Noise Filter*/
+#define FLR_NF_STRGTH          0x03
+
+/* Default values for White Balance */
+#define FLR_WBAL_DGAIN         0x100
+#define FLR_WBAL_COEF          0x20
+
+/* Default values in Office Flourescent Light for Black Adjustment*/
+#define FLR_BLKADJ_BLUE                0x0
+#define FLR_BLKADJ_GREEN       0x0
+#define FLR_BLKADJ_RED         0x0
+
+#define DEF_DETECT_CORRECT_VAL 0xe
+
+#define PREV_MIN_WIDTH         64
+#define PREV_MIN_HEIGHT                8
+#define PREV_MAX_HEIGHT                16384
+
+/*
+ * Coeficient Tables for the submodules in Preview.
+ * Array is initialised with the values from.the tables text file.
+ */
+
+/*
+ * CFA Filter Coefficient Table
+ *
+ */
+static u32 cfa_coef_table[] = {
+#include "cfa_coef_table.h"
+};
+
+/*
+ * Default Gamma Correction Table - All components
+ */
+static u32 gamma_table[] = {
+#include "gamma_table.h"
+};
+
+/*
+ * Noise Filter Threshold table
+ */
+static u32 noise_filter_table[] = {
+#include "noise_filter_table.h"
+};
+
+/*
+ * Luminance Enhancement Table
+ */
+static u32 luma_enhance_table[] = {
+#include "luma_enhance_table.h"
+};
+
+/*
+ * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
+ * @enable: 1 - Reverse the A-Law done in CCDC.
+ */
+static void
+preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+}
+
+/*
+ * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
+ * @prev -
+ * @enable: 1 - Enable, 0 - Disable
+ *
+ * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
+ * The proccess is applied for each captured frame.
+ */
+static void
+preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFCAP);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFCAP);
+}
+
+/*
+ * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
+ * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
+ *          subtracted with the pixels in the current frame.
+ *
+ * The proccess is applied for each captured frame.
+ */
+static void
+preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFEN);
+}
+
+/*
+ * preview_config_drkf_shadcomp - Configures shift value in shading comp.
+ * @scomp_shtval: 3bit value of shift used in shading compensation.
+ */
+static void
+preview_config_drkf_shadcomp(struct isp_prev_device *prev,
+                            const void *scomp_shtval)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const u32 *shtval = scomp_shtval;
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_SCOMP_SFT_MASK,
+                       *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT);
+}
+
+/*
+ * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
+ * @enable: 1 - Enables Horizontal Median Filter.
+ */
+static void
+preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_HMEDEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_HMEDEN);
+}
+
+/*
+ * preview_config_hmed - Configures the Horizontal Median Filter.
+ * @prev_hmed: Structure containing the odd and even distance between the
+ *             pixels in the image along with the filter threshold.
+ */
+static void
+preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_hmed *hmed = prev_hmed;
+
+       isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
+                      (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
+                      (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
+}
+
+/*
+ * preview_config_noisefilter - Configures the Noise Filter.
+ * @prev_nf: Structure containing the noisefilter table, strength to be used
+ *           for the noise filter and the defect correction enable flag.
+ */
+static void
+preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_nf *nf = prev_nf;
+       unsigned int i;
+
+       isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
+       isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
+               isp_reg_writel(isp, nf->table[i],
+                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+       }
+}
+
+/*
+ * preview_config_dcor - Configures the defect correction
+ * @prev_dcor: Structure containing the defect correct thresholds
+ */
+static void
+preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_dcor *dcor = prev_dcor;
+
+       isp_reg_writel(isp, dcor->detect_correct[0],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
+       isp_reg_writel(isp, dcor->detect_correct[1],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
+       isp_reg_writel(isp, dcor->detect_correct[2],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
+       isp_reg_writel(isp, dcor->detect_correct[3],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_DCCOUP,
+                       dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
+}
+
+/*
+ * preview_config_cfa - Configures the CFA Interpolation parameters.
+ * @prev_cfa: Structure containing the CFA interpolation table, CFA format
+ *            in the image, vertical and horizontal gradient threshold.
+ */
+static void
+preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_cfa *cfa = prev_cfa;
+       unsigned int i;
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_CFAFMT_MASK,
+                       cfa->format << ISPPRV_PCR_CFAFMT_SHIFT);
+
+       isp_reg_writel(isp,
+               (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
+               (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
+               OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
+
+       isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+
+       for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) {
+               isp_reg_writel(isp, cfa->table[i],
+                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+       }
+}
+
+/*
+ * preview_config_gammacorrn - Configures the Gamma Correction table values
+ * @gtable: Structure containing the table for red, blue, green gamma table.
+ */
+static void
+preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_gtables *gt = gtable;
+       unsigned int i;
+
+       isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+
+       isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+
+       isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+}
+
+/*
+ * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
+ * @ytable: Structure containing the table for Luminance Enhancement table.
+ */
+static void
+preview_config_luma_enhancement(struct isp_prev_device *prev,
+                               const void *ytable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_luma *yt = ytable;
+       unsigned int i;
+
+       isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
+               isp_reg_writel(isp, yt->table[i],
+                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+       }
+}
+
+/*
+ * preview_config_chroma_suppression - Configures the Chroma Suppression.
+ * @csup: Structure containing the threshold value for suppression
+ *        and the hypass filter enable flag.
+ */
+static void
+preview_config_chroma_suppression(struct isp_prev_device *prev,
+                                 const void *csup)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_csup *cs = csup;
+
+       isp_reg_writel(isp,
+                      cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
+                      (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
+}
+
+/*
+ * preview_enable_noisefilter - Enables/Disables the Noise Filter.
+ * @enable: 1 - Enables the Noise Filter.
+ */
+static void
+preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_NFEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_NFEN);
+}
+
+/*
+ * preview_enable_dcor - Enables/Disables the defect correction.
+ * @enable: 1 - Enables the defect correction.
+ */
+static void
+preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DCOREN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DCOREN);
+}
+
+/*
+ * preview_enable_cfa - Enable/Disable the CFA Interpolation.
+ * @enable: 1 - Enables the CFA.
+ */
+static void
+preview_enable_cfa(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_CFAEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_CFAEN);
+}
+
+/*
+ * preview_enable_gammabypass - Enables/Disables the GammaByPass
+ * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
+ *          0 - Goes through Gamma Correction. input and output is 10bit.
+ */
+static void
+preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_GAMMA_BYPASS);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_GAMMA_BYPASS);
+}
+
+/*
+ * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
+ * @enable: 1 - Enable the Luminance Enhancement.
+ */
+static void
+preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_YNENHEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_YNENHEN);
+}
+
+/*
+ * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
+ * @enable: 1 - Enable the Chrominance Suppression.
+ */
+static void
+preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SUPEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SUPEN);
+}
+
+/*
+ * preview_config_whitebalance - Configures the White Balance parameters.
+ * @prev_wbal: Structure containing the digital gain and white balance
+ *             coefficient.
+ *
+ * Coefficient matrix always with default values.
+ */
+static void
+preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_wbal *wbal = prev_wbal;
+       u32 val;
+
+       isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
+
+       val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
+       val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
+       val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
+       val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
+
+       isp_reg_writel(isp,
+                      ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
+                      ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
+                      ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
+                      ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
+                      ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
+                      ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
+                      ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
+                      ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
+                      ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
+                      ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
+                      ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
+                      ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
+                      ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
+                      ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
+                      ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
+                      ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
+}
+
+/*
+ * preview_config_blkadj - Configures the Black Adjustment parameters.
+ * @prev_blkadj: Structure containing the black adjustment towards red, green,
+ *               blue.
+ */
+static void
+preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_blkadj *blkadj = prev_blkadj;
+
+       isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
+                      (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
+                      (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
+}
+
+/*
+ * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
+ * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
+ *           offset.
+ */
+static void
+preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb;
+       u32 val;
+
+       val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
+       val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
+
+       val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
+       val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
+
+       val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
+       val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
+
+       val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
+       val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
+
+       val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
+
+       val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
+       val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
+
+       val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
+}
+
+/*
+ * Configures the RGB-YCbYCr conversion matrix
+ * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
+ *            YCbCr offset.
+ */
+static void
+preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_csc *csc = prev_csc;
+       u32 val;
+
+       val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
+       val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
+       val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
+
+       val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
+       val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
+       val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
+
+       val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
+       val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
+       val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
+
+       val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
+       val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
+       val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+       isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
+}
+
+/*
+ * preview_update_contrast - Updates the contrast.
+ * @contrast: Pointer to hold the current programmed contrast value.
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
+{
+       struct prev_params *params = &prev->params;
+
+       if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
+               params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
+               prev->update |= PREV_CONTRAST;
+       }
+}
+
+/*
+ * preview_config_contrast - Configures the Contrast.
+ * @params: Contrast value (u8 pointer, U8Q0 format).
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_config_contrast(struct isp_prev_device *prev, const void *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+                       0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
+                       *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT);
+}
+
+/*
+ * preview_update_brightness - Updates the brightness in preview module.
+ * @brightness: Pointer to hold the current programmed brightness value.
+ *
+ */
+static void
+preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
+{
+       struct prev_params *params = &prev->params;
+
+       if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
+               params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
+               prev->update |= PREV_BRIGHTNESS;
+       }
+}
+
+/*
+ * preview_config_brightness - Configures the brightness.
+ * @params: Brightness value (u8 pointer, U8Q0 format).
+ */
+static void
+preview_config_brightness(struct isp_prev_device *prev, const void *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+                       0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
+                       *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT);
+}
+
+/*
+ * preview_config_yc_range - Configures the max and min Y and C values.
+ * @yclimit: Structure containing the range of Y and C values.
+ */
+static void
+preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_yclimit *yc = yclimit;
+
+       isp_reg_writel(isp,
+                      yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+                      yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
+                      yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
+                      yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
+}
+
+/* preview parameters update structure */
+struct preview_update {
+       int cfg_bit;
+       int feature_bit;
+       void (*config)(struct isp_prev_device *, const void *);
+       void (*enable)(struct isp_prev_device *, u8);
+};
+
+static struct preview_update update_attrs[] = {
+       {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE,
+               preview_config_luma_enhancement,
+               preview_enable_luma_enhancement},
+       {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW,
+               NULL,
+               preview_enable_invalaw},
+       {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER,
+               preview_config_hmed,
+               preview_enable_hmed},
+       {OMAP3ISP_PREV_CFA, PREV_CFA,
+               preview_config_cfa,
+               preview_enable_cfa},
+       {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS,
+               preview_config_chroma_suppression,
+               preview_enable_chroma_suppression},
+       {OMAP3ISP_PREV_WB, PREV_WB,
+               preview_config_whitebalance,
+               NULL},
+       {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ,
+               preview_config_blkadj,
+               NULL},
+       {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB,
+               preview_config_rgb_blending,
+               NULL},
+       {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV,
+               preview_config_rgb_to_ycbcr,
+               NULL},
+       {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS,
+               preview_config_yc_range,
+               NULL},
+       {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR,
+               preview_config_dcor,
+               preview_enable_dcor},
+       {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS,
+               NULL,
+               preview_enable_gammabypass},
+       {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE,
+               NULL,
+               preview_enable_drkframe_capture},
+       {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT,
+               NULL,
+               preview_enable_drkframe},
+       {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING,
+               preview_config_drkf_shadcomp,
+               preview_enable_drkframe},
+       {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER,
+               preview_config_noisefilter,
+               preview_enable_noisefilter},
+       {OMAP3ISP_PREV_GAMMA, PREV_GAMMA,
+               preview_config_gammacorrn,
+               NULL},
+       {-1, PREV_CONTRAST,
+               preview_config_contrast,
+               NULL},
+       {-1, PREV_BRIGHTNESS,
+               preview_config_brightness,
+               NULL},
+};
+
+/*
+ * __preview_get_ptrs - helper function which return pointers to members
+ *                         of params and config structures.
+ * @params - pointer to preview_params structure.
+ * @param - return pointer to appropriate structure field.
+ * @configs - pointer to update config structure.
+ * @config - return pointer to appropriate structure field.
+ * @bit - for which feature to return pointers.
+ * Return size of coresponding prev_params member
+ */
+static u32
+__preview_get_ptrs(struct prev_params *params, void **param,
+                  struct omap3isp_prev_update_config *configs,
+                  void __user **config, u32 bit)
+{
+#define CHKARG(cfgs, cfg, field)                               \
+       if (cfgs && cfg) {                                      \
+               *(cfg) = (cfgs)->field;                         \
+       }
+
+       switch (bit) {
+       case PREV_HORZ_MEDIAN_FILTER:
+               *param = &params->hmed;
+               CHKARG(configs, config, hmed)
+               return sizeof(params->hmed);
+       case PREV_NOISE_FILTER:
+               *param = &params->nf;
+               CHKARG(configs, config, nf)
+               return sizeof(params->nf);
+               break;
+       case PREV_CFA:
+               *param = &params->cfa;
+               CHKARG(configs, config, cfa)
+               return sizeof(params->cfa);
+       case PREV_LUMA_ENHANCE:
+               *param = &params->luma;
+               CHKARG(configs, config, luma)
+               return sizeof(params->luma);
+       case PREV_CHROMA_SUPPRESS:
+               *param = &params->csup;
+               CHKARG(configs, config, csup)
+               return sizeof(params->csup);
+       case PREV_DEFECT_COR:
+               *param = &params->dcor;
+               CHKARG(configs, config, dcor)
+               return sizeof(params->dcor);
+       case PREV_BLKADJ:
+               *param = &params->blk_adj;
+               CHKARG(configs, config, blkadj)
+               return sizeof(params->blk_adj);
+       case PREV_YCLIMITS:
+               *param = &params->yclimit;
+               CHKARG(configs, config, yclimit)
+               return sizeof(params->yclimit);
+       case PREV_RGB2RGB:
+               *param = &params->rgb2rgb;
+               CHKARG(configs, config, rgb2rgb)
+               return sizeof(params->rgb2rgb);
+       case PREV_COLOR_CONV:
+               *param = &params->rgb2ycbcr;
+               CHKARG(configs, config, csc)
+               return sizeof(params->rgb2ycbcr);
+       case PREV_WB:
+               *param = &params->wbal;
+               CHKARG(configs, config, wbal)
+               return sizeof(params->wbal);
+       case PREV_GAMMA:
+               *param = &params->gamma;
+               CHKARG(configs, config, gamma)
+               return sizeof(params->gamma);
+       case PREV_CONTRAST:
+               *param = &params->contrast;
+               return 0;
+       case PREV_BRIGHTNESS:
+               *param = &params->brightness;
+               return 0;
+       default:
+               *param = NULL;
+               *config = NULL;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * preview_config - Copy and update local structure with userspace preview
+ *                  configuration.
+ * @prev: ISP preview engine
+ * @cfg: Configuration
+ *
+ * Return zero if success or -EFAULT if the configuration can't be copied from
+ * userspace.
+ */
+static int preview_config(struct isp_prev_device *prev,
+                         struct omap3isp_prev_update_config *cfg)
+{
+       struct prev_params *params;
+       struct preview_update *attr;
+       int i, bit, rval = 0;
+
+       params = &prev->params;
+
+       if (prev->state != ISP_PIPELINE_STREAM_STOPPED) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&prev->lock, flags);
+               prev->shadow_update = 1;
+               spin_unlock_irqrestore(&prev->lock, flags);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+               attr = &update_attrs[i];
+               bit = 0;
+
+               if (!(cfg->update & attr->cfg_bit))
+                       continue;
+
+               bit = cfg->flag & attr->cfg_bit;
+               if (bit) {
+                       void *to = NULL, __user *from = NULL;
+                       unsigned long sz = 0;
+
+                       sz = __preview_get_ptrs(params, &to, cfg, &from,
+                                                  bit);
+                       if (to && from && sz) {
+                               if (copy_from_user(to, from, sz)) {
+                                       rval = -EFAULT;
+                                       break;
+                               }
+                       }
+                       params->features |= attr->feature_bit;
+               } else {
+                       params->features &= ~attr->feature_bit;
+               }
+
+               prev->update |= attr->feature_bit;
+       }
+
+       prev->shadow_update = 0;
+       return rval;
+}
+
+/*
+ * preview_setup_hw - Setup preview registers and/or internal memory
+ * @prev: pointer to preview private structure
+ * Note: can be called from interrupt context
+ * Return none
+ */
+static void preview_setup_hw(struct isp_prev_device *prev)
+{
+       struct prev_params *params = &prev->params;
+       struct preview_update *attr;
+       int i, bit;
+       void *param_ptr;
+
+       for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
+               attr = &update_attrs[i];
+
+               if (!(prev->update & attr->feature_bit))
+                       continue;
+               bit = params->features & attr->feature_bit;
+               if (bit) {
+                       if (attr->config) {
+                               __preview_get_ptrs(params, &param_ptr, NULL,
+                                                     NULL, bit);
+                               attr->config(prev, param_ptr);
+                       }
+                       if (attr->enable)
+                               attr->enable(prev, 1);
+               } else
+                       if (attr->enable)
+                               attr->enable(prev, 0);
+
+               prev->update &= ~attr->feature_bit;
+       }
+}
+
+/*
+ * preview_config_ycpos - Configure byte layout of YUV image.
+ * @mode: Indicates the required byte layout.
+ */
+static void
+preview_config_ycpos(struct isp_prev_device *prev,
+                    enum v4l2_mbus_pixelcode pixelcode)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       enum preview_ycpos_mode mode;
+
+       switch (pixelcode) {
+       case V4L2_MBUS_FMT_YUYV8_1X16:
+               mode = YCPOS_CrYCbY;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+               mode = YCPOS_YCrYCb;
+               break;
+       default:
+               return;
+       }
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_YCPOS_CrYCbY,
+                       mode << ISPPRV_PCR_YCPOS_SHIFT);
+}
+
+/*
+ * preview_config_averager - Enable / disable / configure averager
+ * @average: Average value to be configured.
+ */
+static void preview_config_averager(struct isp_prev_device *prev, u8 average)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       int reg = 0;
+
+       if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER)
+               reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
+                     ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
+                     average;
+       else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
+               reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
+                     ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
+                     average;
+       isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+}
+
+/*
+ * preview_config_input_size - Configure the input frame size
+ *
+ * The preview engine crops several rows and columns internally depending on
+ * which processing blocks are enabled. The driver assumes all those blocks are
+ * enabled when reporting source pad formats to userspace. If this assumption is
+ * not true, rows and columns must be manually cropped at the preview engine
+ * input to avoid overflows at the end of lines and frames.
+ */
+static void preview_config_input_size(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       struct prev_params *params = &prev->params;
+       struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
+       unsigned int sph = 0;
+       unsigned int eph = format->width - 1;
+       unsigned int slv = 0;
+       unsigned int elv = format->height - 1;
+
+       if (prev->input == PREVIEW_INPUT_CCDC) {
+               sph += 2;
+               eph -= 2;
+       }
+
+       /*
+        * Median filter        4 pixels
+        * Noise filter         4 pixels, 4 lines
+        * or faulty pixels correction
+        * CFA filter           4 pixels, 4 lines in Bayer mode
+        *                                2 lines in other modes
+        * Color suppression    2 pixels
+        * or luma enhancement
+        * -------------------------------------------------------------
+        * Maximum total        14 pixels, 8 lines
+        */
+
+       if (!(params->features & PREV_CFA)) {
+               sph += 2;
+               eph -= 2;
+               slv += 2;
+               elv -= 2;
+       }
+       if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) {
+               sph += 2;
+               eph -= 2;
+               slv += 2;
+               elv -= 2;
+       }
+       if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) {
+               sph += 2;
+               eph -= 2;
+       }
+       if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)))
+               sph += 2;
+
+       isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
+       isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
+}
+
+/*
+ * preview_config_inlineoffset - Configures the Read address line offset.
+ * @prev: Preview module
+ * @offset: Line offset
+ *
+ * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
+ * However, a hardware bug requires the memory start address to be aligned on a
+ * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
+ * well.
+ */
+static void
+preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+                      ISPPRV_RADR_OFFSET);
+}
+
+/*
+ * preview_set_inaddr - Sets memory address of input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address from which the input frame is to be read.
+ */
+static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
+}
+
+/*
+ * preview_config_outlineoffset - Configures the Write address line offset.
+ * @offset: Line Offset for the preview output.
+ *
+ * The offset must be a multiple of 32 bytes.
+ */
+static void preview_config_outlineoffset(struct isp_prev_device *prev,
+                                   u32 offset)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+                      ISPPRV_WADD_OFFSET);
+}
+
+/*
+ * preview_set_outaddr - Sets the memory address to store output frame
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ *
+ * Configures the memory address to which the output frame is written.
+ */
+static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+}
+
+static void preview_adjust_bandwidth(struct isp_prev_device *prev)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+       struct isp_device *isp = to_isp_device(prev);
+       const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
+       unsigned long l3_ick = pipe->l3_ick;
+       struct v4l2_fract *timeperframe;
+       unsigned int cycles_per_frame;
+       unsigned int requests_per_frame;
+       unsigned int cycles_per_request;
+       unsigned int minimum;
+       unsigned int maximum;
+       unsigned int value;
+
+       if (prev->input != PREVIEW_INPUT_MEMORY) {
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+                           ISPSBL_SDR_REQ_PRV_EXP_MASK);
+               return;
+       }
+
+       /* Compute the minimum number of cycles per request, based on the
+        * pipeline maximum data rate. This is an absolute lower bound if we
+        * don't want SBL overflows, so round the value up.
+        */
+       cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+                                    pipe->max_rate);
+       minimum = DIV_ROUND_UP(cycles_per_request, 32);
+
+       /* Compute the maximum number of cycles per request, based on the
+        * requested frame rate. This is a soft upper bound to achieve a frame
+        * rate equal or higher than the requested value, so round the value
+        * down.
+        */
+       timeperframe = &pipe->max_timeperframe;
+
+       requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
+       cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+                                  timeperframe->denominator);
+       cycles_per_request = cycles_per_frame / requests_per_frame;
+
+       maximum = cycles_per_request / 32;
+
+       value = max(minimum, maximum);
+
+       dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+                       ISPSBL_SDR_REQ_PRV_EXP_MASK,
+                       value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_preview_busy - Gets busy state of preview module.
+ */
+int omap3isp_preview_busy(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
+               & ISPPRV_PCR_BUSY;
+}
+
+/*
+ * omap3isp_preview_restore_context - Restores the values of preview registers
+ */
+void omap3isp_preview_restore_context(struct isp_device *isp)
+{
+       isp->isp_prev.update = PREV_FEATURES_END - 1;
+       preview_setup_hw(&isp->isp_prev);
+}
+
+/*
+ * preview_print_status - Dump preview module registers to the kernel log
+ */
+#define PREV_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
+
+static void preview_print_status(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
+
+       PREV_PRINT_REGISTER(isp, PCR);
+       PREV_PRINT_REGISTER(isp, HORZ_INFO);
+       PREV_PRINT_REGISTER(isp, VERT_INFO);
+       PREV_PRINT_REGISTER(isp, RSDR_ADDR);
+       PREV_PRINT_REGISTER(isp, RADR_OFFSET);
+       PREV_PRINT_REGISTER(isp, DSDR_ADDR);
+       PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
+       PREV_PRINT_REGISTER(isp, WSDR_ADDR);
+       PREV_PRINT_REGISTER(isp, WADD_OFFSET);
+       PREV_PRINT_REGISTER(isp, AVE);
+       PREV_PRINT_REGISTER(isp, HMED);
+       PREV_PRINT_REGISTER(isp, NF);
+       PREV_PRINT_REGISTER(isp, WB_DGAIN);
+       PREV_PRINT_REGISTER(isp, WBGAIN);
+       PREV_PRINT_REGISTER(isp, WBSEL);
+       PREV_PRINT_REGISTER(isp, CFA);
+       PREV_PRINT_REGISTER(isp, BLKADJOFF);
+       PREV_PRINT_REGISTER(isp, RGB_MAT1);
+       PREV_PRINT_REGISTER(isp, RGB_MAT2);
+       PREV_PRINT_REGISTER(isp, RGB_MAT3);
+       PREV_PRINT_REGISTER(isp, RGB_MAT4);
+       PREV_PRINT_REGISTER(isp, RGB_MAT5);
+       PREV_PRINT_REGISTER(isp, RGB_OFF1);
+       PREV_PRINT_REGISTER(isp, RGB_OFF2);
+       PREV_PRINT_REGISTER(isp, CSC0);
+       PREV_PRINT_REGISTER(isp, CSC1);
+       PREV_PRINT_REGISTER(isp, CSC2);
+       PREV_PRINT_REGISTER(isp, CSC_OFFSET);
+       PREV_PRINT_REGISTER(isp, CNT_BRT);
+       PREV_PRINT_REGISTER(isp, CSUP);
+       PREV_PRINT_REGISTER(isp, SETUP_YC);
+       PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
+       PREV_PRINT_REGISTER(isp, CDC_THR0);
+       PREV_PRINT_REGISTER(isp, CDC_THR1);
+       PREV_PRINT_REGISTER(isp, CDC_THR2);
+       PREV_PRINT_REGISTER(isp, CDC_THR3);
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * preview_init_params - init image processing parameters.
+ * @prev: pointer to previewer private structure
+ * return none
+ */
+static void preview_init_params(struct isp_prev_device *prev)
+{
+       struct prev_params *params = &prev->params;
+       int i = 0;
+
+       /* Init values */
+       params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
+       params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
+       params->average = NO_AVE;
+       params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
+       memcpy(params->cfa.table, cfa_coef_table,
+              sizeof(params->cfa.table));
+       params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
+       params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
+       params->csup.gain = FLR_CSUP_GAIN;
+       params->csup.thres = FLR_CSUP_THRES;
+       params->csup.hypf_en = 0;
+       memcpy(params->luma.table, luma_enhance_table,
+              sizeof(params->luma.table));
+       params->nf.spread = FLR_NF_STRGTH;
+       memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
+       params->dcor.couplet_mode_en = 1;
+       for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
+               params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
+       memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
+       memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
+       memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
+       params->wbal.dgain = FLR_WBAL_DGAIN;
+       params->wbal.coef0 = FLR_WBAL_COEF;
+       params->wbal.coef1 = FLR_WBAL_COEF;
+       params->wbal.coef2 = FLR_WBAL_COEF;
+       params->wbal.coef3 = FLR_WBAL_COEF;
+       params->blk_adj.red = FLR_BLKADJ_RED;
+       params->blk_adj.green = FLR_BLKADJ_GREEN;
+       params->blk_adj.blue = FLR_BLKADJ_BLUE;
+       params->rgb2rgb = flr_rgb2rgb;
+       params->rgb2ycbcr = flr_prev_csc;
+       params->yclimit.minC = ISPPRV_YC_MIN;
+       params->yclimit.maxC = ISPPRV_YC_MAX;
+       params->yclimit.minY = ISPPRV_YC_MIN;
+       params->yclimit.maxY = ISPPRV_YC_MAX;
+
+       params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER
+                        | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS
+                        | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB
+                        | PREV_BRIGHTNESS | PREV_CONTRAST;
+
+       prev->update = PREV_FEATURES_END - 1;
+}
+
+/*
+ * preview_max_out_width - Handle previewer hardware ouput limitations
+ * @isp_revision : ISP revision
+ * returns maximum width output for current isp revision
+ */
+static unsigned int preview_max_out_width(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       switch (isp->revision) {
+       case ISP_REVISION_1_0:
+               return ISPPRV_MAXOUTPUT_WIDTH;
+
+       case ISP_REVISION_2_0:
+       default:
+               return ISPPRV_MAXOUTPUT_WIDTH_ES2;
+
+       case ISP_REVISION_15_0:
+               return ISPPRV_MAXOUTPUT_WIDTH_3630;
+       }
+}
+
+static void preview_configure(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       struct v4l2_mbus_framefmt *format;
+       unsigned int max_out_width;
+       unsigned int format_avg;
+
+       preview_setup_hw(prev);
+
+       if (prev->output & PREVIEW_OUTPUT_MEMORY)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SDRPORT);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SDRPORT);
+
+       if (prev->output & PREVIEW_OUTPUT_RESIZER)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_RSZPORT);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_RSZPORT);
+
+       /* PREV_PAD_SINK */
+       format = &prev->formats[PREV_PAD_SINK];
+
+       preview_adjust_bandwidth(prev);
+
+       preview_config_input_size(prev);
+
+       if (prev->input == PREVIEW_INPUT_CCDC)
+               preview_config_inlineoffset(prev, 0);
+       else
+               preview_config_inlineoffset(prev,
+                               ALIGN(format->width, 0x20) * 2);
+
+       /* PREV_PAD_SOURCE */
+       format = &prev->formats[PREV_PAD_SOURCE];
+
+       if (prev->output & PREVIEW_OUTPUT_MEMORY)
+               preview_config_outlineoffset(prev,
+                               ALIGN(format->width, 0x10) * 2);
+
+       max_out_width = preview_max_out_width(prev);
+
+       format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1);
+       preview_config_averager(prev, format_avg);
+       preview_config_ycpos(prev, format->code);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void preview_enable_oneshot(struct isp_prev_device *prev)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
+        * bit is set. As the preview engine is used in single-shot mode, we
+        * need to set PCR.SOURCE before enabling the preview engine.
+        */
+       if (prev->input == PREVIEW_INPUT_MEMORY)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SOURCE);
+
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                   ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
+}
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
+{
+       /*
+        * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+        * condition, the module was paused and now we have a buffer queued
+        * on the output again. Restart the pipeline if running in continuous
+        * mode.
+        */
+       if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+           prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+               preview_enable_oneshot(prev);
+               isp_video_dmaqueue_flags_clr(&prev->video_out);
+       }
+}
+
+static void preview_isr_buffer(struct isp_prev_device *prev)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
+       struct isp_buffer *buffer;
+       int restart = 0;
+
+       if (prev->input == PREVIEW_INPUT_MEMORY) {
+               buffer = omap3isp_video_buffer_next(&prev->video_in,
+                                                   prev->error);
+               if (buffer != NULL)
+                       preview_set_inaddr(prev, buffer->isp_addr);
+               pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+       }
+
+       if (prev->output & PREVIEW_OUTPUT_MEMORY) {
+               buffer = omap3isp_video_buffer_next(&prev->video_out,
+                                                   prev->error);
+               if (buffer != NULL) {
+                       preview_set_outaddr(prev, buffer->isp_addr);
+                       restart = 1;
+               }
+               pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+       }
+
+       switch (prev->state) {
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               if (isp_pipeline_ready(pipe))
+                       omap3isp_pipeline_set_stream(pipe,
+                                               ISP_PIPELINE_STREAM_SINGLESHOT);
+               break;
+
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               /* If an underrun occurs, the video queue operation handler will
+                * restart the preview engine. Otherwise restart it immediately.
+                */
+               if (restart)
+                       preview_enable_oneshot(prev);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+       default:
+               return;
+       }
+
+       prev->error = 0;
+}
+
+/*
+ * omap3isp_preview_isr - ISP preview engine interrupt handler
+ *
+ * Manage the preview engine video buffers and configure shadowed registers.
+ */
+void omap3isp_preview_isr(struct isp_prev_device *prev)
+{
+       unsigned long flags;
+
+       if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
+               return;
+
+       spin_lock_irqsave(&prev->lock, flags);
+       if (prev->shadow_update)
+               goto done;
+
+       preview_setup_hw(prev);
+       preview_config_input_size(prev);
+
+done:
+       spin_unlock_irqrestore(&prev->lock, flags);
+
+       if (prev->input == PREVIEW_INPUT_MEMORY ||
+           prev->output & PREVIEW_OUTPUT_MEMORY)
+               preview_isr_buffer(prev);
+       else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
+               preview_enable_oneshot(prev);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int preview_video_queue(struct isp_video *video,
+                              struct isp_buffer *buffer)
+{
+       struct isp_prev_device *prev = &video->isp->isp_prev;
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               preview_set_inaddr(prev, buffer->isp_addr);
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               preview_set_outaddr(prev, buffer->isp_addr);
+
+       return 0;
+}
+
+static const struct isp_video_operations preview_video_ops = {
+       .queue = preview_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * preview_s_ctrl - Handle set control subdev method
+ * @ctrl: pointer to v4l2 control structure
+ */
+static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct isp_prev_device *prev =
+               container_of(ctrl->handler, struct isp_prev_device, ctrls);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               preview_update_brightness(prev, ctrl->val);
+               break;
+       case V4L2_CID_CONTRAST:
+               preview_update_contrast(prev, ctrl->val);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops preview_ctrl_ops = {
+       .s_ctrl = preview_s_ctrl,
+};
+
+/*
+ * preview_ioctl - Handle preview module private ioctl's
+ * @prev: pointer to preview context structure
+ * @cmd: configuration command
+ * @arg: configuration argument
+ * return -EINVAL or zero on success
+ */
+static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+       switch (cmd) {
+       case VIDIOC_OMAP3ISP_PRV_CFG:
+               return preview_config(prev, arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+/*
+ * preview_set_stream - Enable/Disable streaming on preview subdev
+ * @sd    : pointer to v4l2 subdev structure
+ * @enable: 1 == Enable, 0 == Disable
+ * return -EINVAL or zero on sucess
+ */
+static int preview_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+       struct isp_video *video_out = &prev->video_out;
+       struct isp_device *isp = to_isp_device(prev);
+       struct device *dev = to_device(prev);
+       unsigned long flags;
+
+       if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISP_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+               preview_configure(prev);
+               atomic_set(&prev->stopping, 0);
+               prev->error = 0;
+               preview_print_status(prev);
+       }
+
+       switch (enable) {
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               if (prev->output & PREVIEW_OUTPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+               if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
+                   !(prev->output & PREVIEW_OUTPUT_MEMORY))
+                       preview_enable_oneshot(prev);
+
+               isp_video_dmaqueue_flags_clr(video_out);
+               break;
+
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               if (prev->input == PREVIEW_INPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+               if (prev->output & PREVIEW_OUTPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+
+               preview_enable_oneshot(prev);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
+                                             &prev->stopping))
+                       dev_dbg(dev, "%s: stop timeout.\n", sd->name);
+               spin_lock_irqsave(&prev->lock, flags);
+               omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
+               omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
+               omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
+               spin_unlock_irqrestore(&prev->lock, flags);
+               isp_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+
+       prev->state = enable;
+       return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
+                    unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &prev->formats[pad];
+}
+
+/* previewer format descriptions */
+static const unsigned int preview_input_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+};
+
+static const unsigned int preview_output_fmts[] = {
+       V4L2_MBUS_FMT_UYVY8_1X16,
+       V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/*
+ * preview_try_format - Handle try format by pad subdev method
+ * @prev: ISP preview device
+ * @fh : V4L2 subdev file handle
+ * @pad: pad num
+ * @fmt: pointer to v4l2 format structure
+ */
+static void preview_try_format(struct isp_prev_device *prev,
+                              struct v4l2_subdev_fh *fh, unsigned int pad,
+                              struct v4l2_mbus_framefmt *fmt,
+                              enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       unsigned int max_out_width;
+       enum v4l2_mbus_pixelcode pixelcode;
+       unsigned int i;
+
+       max_out_width = preview_max_out_width(prev);
+
+       switch (pad) {
+       case PREV_PAD_SINK:
+               /* When reading data from the CCDC, the input size has already
+                * been mangled by the CCDC output pad so it can be accepted
+                * as-is.
+                *
+                * When reading data from memory, clamp the requested width and
+                * height. The TRM doesn't specify a minimum input height, make
+                * sure we got enough lines to enable the noise filter and color
+                * filter array interpolation.
+                */
+               if (prev->input == PREVIEW_INPUT_MEMORY) {
+                       fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH,
+                                            max_out_width * 8);
+                       fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT,
+                                             PREV_MAX_HEIGHT);
+               }
+
+               fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+               for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
+                       if (fmt->code == preview_input_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(preview_input_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+               break;
+
+       case PREV_PAD_SOURCE:
+               pixelcode = fmt->code;
+               format = __preview_get_format(prev, fh, PREV_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /* The preview module output size is configurable through the
+                * input interface (horizontal and vertical cropping) and the
+                * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In
+                * spite of this, hardcode the output size to the biggest
+                * possible value for simplicity reasons.
+                */
+               switch (pixelcode) {
+               case V4L2_MBUS_FMT_YUYV8_1X16:
+               case V4L2_MBUS_FMT_UYVY8_1X16:
+                       fmt->code = pixelcode;
+                       break;
+
+               default:
+                       fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+                       break;
+               }
+
+               /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped
+                * from the left and right sides when the input source is the
+                * CCDC. This seems not to be needed in practice, investigation
+                * is required.
+                */
+               if (prev->input == PREVIEW_INPUT_CCDC)
+                       fmt->width -= 4;
+
+               /* The preview module can output a maximum of 3312 pixels
+                * horizontally due to fixed memory-line sizes. Compute the
+                * horizontal averaging factor accordingly. Note that the limit
+                * applies to the noise filter and CFA interpolation blocks, so
+                * it doesn't take cropping by further blocks into account.
+                *
+                * ES 1.0 hardware revision is limited to 1280 pixels
+                * horizontally.
+                */
+               fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1);
+
+               /* Assume that all blocks are enabled and crop pixels and lines
+                * accordingly. See preview_config_input_size() for more
+                * information.
+                */
+               fmt->width -= 14;
+               fmt->height -= 8;
+
+               fmt->colorspace = V4L2_COLORSPACE_JPEG;
+               break;
+       }
+
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * preview_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int preview_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       switch (code->pad) {
+       case PREV_PAD_SINK:
+               if (code->index >= ARRAY_SIZE(preview_input_fmts))
+                       return -EINVAL;
+
+               code->code = preview_input_fmts[code->index];
+               break;
+       case PREV_PAD_SOURCE:
+               if (code->index >= ARRAY_SIZE(preview_output_fmts))
+                       return -EINVAL;
+
+               code->code = preview_output_fmts[code->index];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int preview_enum_frame_size(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * preview_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on sucess
+ */
+static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * preview_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == PREV_PAD_SINK) {
+               format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
+                                             fmt->which);
+               *format = fmt->format;
+               preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
+                                  fmt->which);
+       }
+
+       return 0;
+}
+
+/*
+ * preview_init_formats - Initialize formats on all pads
+ * @sd: ISP preview V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int preview_init_formats(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = PREV_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       preview_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* subdev core operations */
+static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
+       .ioctl = preview_ioctl,
+};
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
+       .s_stream = preview_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
+       .enum_mbus_code = preview_enum_mbus_code,
+       .enum_frame_size = preview_enum_frame_size,
+       .get_fmt = preview_get_format,
+       .set_fmt = preview_set_format,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops preview_v4l2_ops = {
+       .core = &preview_v4l2_core_ops,
+       .video = &preview_v4l2_video_ops,
+       .pad = &preview_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = {
+       .open = preview_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * preview_link_setup - Setup previewer connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int preview_link_setup(struct media_entity *entity,
+                             const struct media_pad *local,
+                             const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+               /* read from memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (prev->input == PREVIEW_INPUT_CCDC)
+                               return -EBUSY;
+                       prev->input = PREVIEW_INPUT_MEMORY;
+               } else {
+                       if (prev->input == PREVIEW_INPUT_MEMORY)
+                               prev->input = PREVIEW_INPUT_NONE;
+               }
+               break;
+
+       case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* read from ccdc */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (prev->input == PREVIEW_INPUT_MEMORY)
+                               return -EBUSY;
+                       prev->input = PREVIEW_INPUT_CCDC;
+               } else {
+                       if (prev->input == PREVIEW_INPUT_CCDC)
+                               prev->input = PREVIEW_INPUT_NONE;
+               }
+               break;
+
+       /*
+        * The ISP core doesn't support pipelines with multiple video outputs.
+        * Revisit this when it will be implemented, and return -EBUSY for now.
+        */
+
+       case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+               /* write to memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       prev->output |= PREVIEW_OUTPUT_MEMORY;
+               } else {
+                       prev->output &= ~PREVIEW_OUTPUT_MEMORY;
+               }
+               break;
+
+       case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* write to resizer */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
+                               return -EBUSY;
+                       prev->output |= PREVIEW_OUTPUT_RESIZER;
+               } else {
+                       prev->output &= ~PREVIEW_OUTPUT_RESIZER;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations preview_media_ops = {
+       .link_setup = preview_link_setup,
+};
+
+/*
+ * review_init_entities - Initialize subdev and media entity.
+ * @prev : Pointer to preview structure
+ * return -ENOMEM or zero on success
+ */
+static int preview_init_entities(struct isp_prev_device *prev)
+{
+       struct v4l2_subdev *sd = &prev->subdev;
+       struct media_pad *pads = prev->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       prev->input = PREVIEW_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &preview_v4l2_ops);
+       sd->internal_ops = &preview_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+       v4l2_set_subdevdata(sd, prev);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       v4l2_ctrl_handler_init(&prev->ctrls, 2);
+       v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
+                         ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
+                         ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
+       v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
+                         ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
+                         ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
+       v4l2_ctrl_handler_setup(&prev->ctrls);
+       sd->ctrl_handler = &prev->ctrls;
+
+       pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &preview_media_ops;
+       ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       preview_init_formats(sd, NULL);
+
+       /* According to the OMAP34xx TRM, video buffers need to be aligned on a
+        * 32 bytes boundary. However, an undocumented hardware bug requires a
+        * 64 bytes boundary at the preview engine input.
+        */
+       prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       prev->video_in.ops = &preview_video_ops;
+       prev->video_in.isp = to_isp_device(prev);
+       prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+       prev->video_in.bpl_alignment = 64;
+       prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       prev->video_out.ops = &preview_video_ops;
+       prev->video_out.isp = to_isp_device(prev);
+       prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+       prev->video_out.bpl_alignment = 32;
+
+       ret = omap3isp_video_init(&prev->video_in, "preview");
+       if (ret < 0)
+               return ret;
+
+       ret = omap3isp_video_init(&prev->video_out, "preview");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the video nodes to the previewer subdev. */
+       ret = media_entity_create_link(&prev->video_in.video.entity, 0,
+                       &prev->subdev.entity, PREV_PAD_SINK, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
+                       &prev->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
+{
+       media_entity_cleanup(&prev->subdev.entity);
+
+       v4l2_device_unregister_subdev(&prev->subdev);
+       v4l2_ctrl_handler_free(&prev->ctrls);
+       omap3isp_video_unregister(&prev->video_in);
+       omap3isp_video_unregister(&prev->video_out);
+}
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prev,
+       struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video nodes. */
+       ret = v4l2_device_register_subdev(vdev, &prev->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&prev->video_in, vdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&prev->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap3isp_preview_unregister_entities(prev);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP previewer initialisation and cleanup
+ */
+
+void omap3isp_preview_cleanup(struct isp_device *isp)
+{
+}
+
+/*
+ * isp_preview_init - Previewer initialization.
+ * @dev : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_preview_init(struct isp_device *isp)
+{
+       struct isp_prev_device *prev = &isp->isp_prev;
+       int ret;
+
+       spin_lock_init(&prev->lock);
+       init_waitqueue_head(&prev->wait);
+       preview_init_params(prev);
+
+       ret = preview_init_entities(prev);
+       if (ret < 0)
+               goto out;
+
+out:
+       if (ret)
+               omap3isp_preview_cleanup(isp);
+
+       return ret;
+}
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
new file mode 100644 (file)
index 0000000..f2d63ca
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * isppreview.h
+ *
+ * TI OMAP3 ISP - Preview module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_PREVIEW_H
+#define OMAP3_ISP_PREVIEW_H
+
+#include <linux/omap3isp.h>
+#include <linux/types.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ispvideo.h"
+
+#define ISPPRV_BRIGHT_STEP             0x1
+#define ISPPRV_BRIGHT_DEF              0x0
+#define ISPPRV_BRIGHT_LOW              0x0
+#define ISPPRV_BRIGHT_HIGH             0xFF
+#define ISPPRV_BRIGHT_UNITS            0x1
+
+#define ISPPRV_CONTRAST_STEP           0x1
+#define ISPPRV_CONTRAST_DEF            0x10
+#define ISPPRV_CONTRAST_LOW            0x0
+#define ISPPRV_CONTRAST_HIGH           0xFF
+#define ISPPRV_CONTRAST_UNITS          0x1
+
+#define NO_AVE                         0x0
+#define AVE_2_PIX                      0x1
+#define AVE_4_PIX                      0x2
+#define AVE_8_PIX                      0x3
+
+/* Features list */
+#define PREV_LUMA_ENHANCE              OMAP3ISP_PREV_LUMAENH
+#define PREV_INVERSE_ALAW              OMAP3ISP_PREV_INVALAW
+#define PREV_HORZ_MEDIAN_FILTER                OMAP3ISP_PREV_HRZ_MED
+#define PREV_CFA                       OMAP3ISP_PREV_CFA
+#define PREV_CHROMA_SUPPRESS           OMAP3ISP_PREV_CHROMA_SUPP
+#define PREV_WB                                OMAP3ISP_PREV_WB
+#define PREV_BLKADJ                    OMAP3ISP_PREV_BLKADJ
+#define PREV_RGB2RGB                   OMAP3ISP_PREV_RGB2RGB
+#define PREV_COLOR_CONV                        OMAP3ISP_PREV_COLOR_CONV
+#define PREV_YCLIMITS                  OMAP3ISP_PREV_YC_LIMIT
+#define PREV_DEFECT_COR                        OMAP3ISP_PREV_DEFECT_COR
+#define PREV_GAMMA_BYPASS              OMAP3ISP_PREV_GAMMABYPASS
+#define PREV_DARK_FRAME_CAPTURE                OMAP3ISP_PREV_DRK_FRM_CAPTURE
+#define PREV_DARK_FRAME_SUBTRACT       OMAP3ISP_PREV_DRK_FRM_SUBTRACT
+#define PREV_LENS_SHADING              OMAP3ISP_PREV_LENS_SHADING
+#define PREV_NOISE_FILTER              OMAP3ISP_PREV_NF
+#define PREV_GAMMA                     OMAP3ISP_PREV_GAMMA
+
+#define PREV_CONTRAST                  (1 << 17)
+#define PREV_BRIGHTNESS                        (1 << 18)
+#define PREV_AVERAGER                  (1 << 19)
+#define PREV_FEATURES_END              (1 << 20)
+
+enum preview_input_entity {
+       PREVIEW_INPUT_NONE,
+       PREVIEW_INPUT_CCDC,
+       PREVIEW_INPUT_MEMORY,
+};
+
+#define PREVIEW_OUTPUT_RESIZER         (1 << 1)
+#define PREVIEW_OUTPUT_MEMORY          (1 << 2)
+
+/* Configure byte layout of YUV image */
+enum preview_ycpos_mode {
+       YCPOS_YCrYCb = 0,
+       YCPOS_YCbYCr = 1,
+       YCPOS_CbYCrY = 2,
+       YCPOS_CrYCbY = 3
+};
+
+/*
+ * struct prev_params - Structure for all configuration
+ * @features: Set of features enabled.
+ * @cfa: CFA coefficients.
+ * @csup: Chroma suppression coefficients.
+ * @luma: Luma enhancement coefficients.
+ * @nf: Noise filter coefficients.
+ * @dcor: Noise filter coefficients.
+ * @gamma: Gamma coefficients.
+ * @wbal: White Balance parameters.
+ * @blk_adj: Black adjustment parameters.
+ * @rgb2rgb: RGB blending parameters.
+ * @rgb2ycbcr: RGB to ycbcr parameters.
+ * @hmed: Horizontal median filter.
+ * @yclimit: YC limits parameters.
+ * @average: Downsampling rate for averager.
+ * @contrast: Contrast.
+ * @brightness: Brightness.
+ */
+struct prev_params {
+       u32 features;
+       struct omap3isp_prev_cfa cfa;
+       struct omap3isp_prev_csup csup;
+       struct omap3isp_prev_luma luma;
+       struct omap3isp_prev_nf nf;
+       struct omap3isp_prev_dcor dcor;
+       struct omap3isp_prev_gtables gamma;
+       struct omap3isp_prev_wbal wbal;
+       struct omap3isp_prev_blkadj blk_adj;
+       struct omap3isp_prev_rgbtorgb rgb2rgb;
+       struct omap3isp_prev_csc rgb2ycbcr;
+       struct omap3isp_prev_hmed hmed;
+       struct omap3isp_prev_yclimit yclimit;
+       u8 average;
+       u8 contrast;
+       u8 brightness;
+};
+
+/*
+ * struct isptables_update - Structure for Table Configuration.
+ * @update: Specifies which tables should be updated.
+ * @flag: Specifies which tables should be enabled.
+ * @nf: Pointer to structure for Noise Filter
+ * @lsc: Pointer to LSC gain table. (currently not used)
+ * @gamma: Pointer to gamma correction tables.
+ * @cfa: Pointer to color filter array configuration.
+ * @wbal: Pointer to colour and digital gain configuration.
+ */
+struct isptables_update {
+       u32 update;
+       u32 flag;
+       struct omap3isp_prev_nf *nf;
+       u32 *lsc;
+       struct omap3isp_prev_gtables *gamma;
+       struct omap3isp_prev_cfa *cfa;
+       struct omap3isp_prev_wbal *wbal;
+};
+
+/* Sink and source previewer pads */
+#define PREV_PAD_SINK                  0
+#define PREV_PAD_SOURCE                        1
+#define PREV_PADS_NUM                  2
+
+/*
+ * struct isp_prev_device - Structure for storing ISP Preview module information
+ * @subdev: V4L2 subdevice
+ * @pads: Media entity pads
+ * @formats: Active formats at the subdev pad
+ * @input: Module currently connected to the input pad
+ * @output: Bitmask of the active output
+ * @video_in: Input video entity
+ * @video_out: Output video entity
+ * @error: A hardware error occured during capture
+ * @params: Module configuration data
+ * @shadow_update: If set, update the hardware configured in the next interrupt
+ * @underrun: Whether the preview entity has queued buffers on the output
+ * @state: Current preview pipeline state
+ * @lock: Shadow update lock
+ * @update: Bitmask of the parameters to be updated
+ *
+ * This structure is used to store the OMAP ISP Preview module Information.
+ */
+struct isp_prev_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[PREV_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
+
+       struct v4l2_ctrl_handler ctrls;
+
+       enum preview_input_entity input;
+       unsigned int output;
+       struct isp_video video_in;
+       struct isp_video video_out;
+       unsigned int error;
+
+       struct prev_params params;
+       unsigned int shadow_update:1;
+       enum isp_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+       spinlock_t lock;
+       u32 update;
+};
+
+struct isp_device;
+
+int omap3isp_preview_init(struct isp_device *isp);
+void omap3isp_preview_cleanup(struct isp_device *isp);
+
+int omap3isp_preview_register_entities(struct isp_prev_device *prv,
+                                      struct v4l2_device *vdev);
+void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
+
+void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
+void omap3isp_preview_isr(struct isp_prev_device *prev);
+
+int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
+
+void omap3isp_preview_restore_context(struct isp_device *isp);
+
+#endif /* OMAP3_ISP_PREVIEW_H */
diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c
new file mode 100644 (file)
index 0000000..8fddc58
--- /dev/null
@@ -0,0 +1,1153 @@
+/*
+ * ispqueue.c
+ *
+ * TI OMAP3 ISP - Video buffers queue handling
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/poll.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "ispqueue.h"
+
+/* -----------------------------------------------------------------------------
+ * Video buffers management
+ */
+
+/*
+ * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP
+ *
+ * The typical operation required here is Cache Invalidation across
+ * the (user space) buffer address range. And this _must_ be done
+ * at QBUF stage (and *only* at QBUF).
+ *
+ * We try to use optimal cache invalidation function:
+ * - dmac_map_area:
+ *    - used when the number of pages are _low_.
+ *    - it becomes quite slow as the number of pages increase.
+ *       - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
+ *       - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
+ *
+ * - flush_cache_all:
+ *    - used when the number of pages are _high_.
+ *    - time taken in the range of 500-900 us.
+ *    - has a higher penalty but, as whole dcache + icache is invalidated
+ */
+/*
+ * FIXME: dmac_inv_range crashes randomly on the user space buffer
+ *        address. Fall back to flush_cache_all for now.
+ */
+#define ISP_CACHE_FLUSH_PAGES_MAX       0
+
+static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf)
+{
+       if (buf->skip_cache)
+               return;
+
+       if (buf->vbuf.m.userptr == 0 || buf->npages == 0 ||
+           buf->npages > ISP_CACHE_FLUSH_PAGES_MAX)
+               flush_cache_all();
+       else {
+               dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length,
+                             DMA_FROM_DEVICE);
+               outer_inv_range(buf->vbuf.m.userptr,
+                               buf->vbuf.m.userptr + buf->vbuf.length);
+       }
+}
+
+/*
+ * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped
+ *
+ * Lock the VMAs underlying the given buffer into memory. This avoids the
+ * userspace buffer mapping from being swapped out, making VIPT cache handling
+ * easier.
+ *
+ * Note that the pages will not be freed as the buffers have been locked to
+ * memory using by a call to get_user_pages(), but the userspace mapping could
+ * still disappear if the VMAs are not locked. This is caused by the memory
+ * management code trying to be as lock-less as possible, which results in the
+ * userspace mapping manager not finding out that the pages are locked under
+ * some conditions.
+ */
+static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock)
+{
+       struct vm_area_struct *vma;
+       unsigned long start;
+       unsigned long end;
+       int ret = 0;
+
+       if (buf->vbuf.memory == V4L2_MEMORY_MMAP)
+               return 0;
+
+       /* We can be called from workqueue context if the current task dies to
+        * unlock the VMAs. In that case there's no current memory management
+        * context so unlocking can't be performed, but the VMAs have been or
+        * are getting destroyed anyway so it doesn't really matter.
+        */
+       if (!current || !current->mm)
+               return lock ? -EINVAL : 0;
+
+       start = buf->vbuf.m.userptr;
+       end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+       down_write(&current->mm->mmap_sem);
+       spin_lock(&current->mm->page_table_lock);
+
+       do {
+               vma = find_vma(current->mm, start);
+               if (vma == NULL) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               if (lock)
+                       vma->vm_flags |= VM_LOCKED;
+               else
+                       vma->vm_flags &= ~VM_LOCKED;
+
+               start = vma->vm_end + 1;
+       } while (vma->vm_end < end);
+
+       if (lock)
+               buf->vm_flags |= VM_LOCKED;
+       else
+               buf->vm_flags &= ~VM_LOCKED;
+
+out:
+       spin_unlock(&current->mm->page_table_lock);
+       up_write(&current->mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer
+ *
+ * Iterate over the vmalloc'ed area and create a scatter list entry for every
+ * page.
+ */
+static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
+{
+       struct scatterlist *sglist;
+       unsigned int npages;
+       unsigned int i;
+       void *addr;
+
+       addr = buf->vaddr;
+       npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT;
+
+       sglist = vmalloc(npages * sizeof(*sglist));
+       if (sglist == NULL)
+               return -ENOMEM;
+
+       sg_init_table(sglist, npages);
+
+       for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
+               struct page *page = vmalloc_to_page(addr);
+
+               if (page == NULL || PageHighMem(page)) {
+                       vfree(sglist);
+                       return -EINVAL;
+               }
+
+               sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
+       }
+
+       buf->sglen = npages;
+       buf->sglist = sglist;
+
+       return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
+ *
+ * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
+ */
+static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
+{
+       struct scatterlist *sglist;
+       unsigned int offset = buf->offset;
+       unsigned int i;
+
+       sglist = vmalloc(buf->npages * sizeof(*sglist));
+       if (sglist == NULL)
+               return -ENOMEM;
+
+       sg_init_table(sglist, buf->npages);
+
+       for (i = 0; i < buf->npages; ++i) {
+               if (PageHighMem(buf->pages[i])) {
+                       vfree(sglist);
+                       return -EINVAL;
+               }
+
+               sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset,
+                           offset);
+               offset = 0;
+       }
+
+       buf->sglen = buf->npages;
+       buf->sglist = sglist;
+
+       return 0;
+}
+
+/*
+ * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
+ *
+ * Create a scatter list of physically contiguous pages starting at the buffer
+ * memory physical address.
+ */
+static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
+{
+       struct scatterlist *sglist;
+       unsigned int offset = buf->offset;
+       unsigned long pfn = buf->paddr >> PAGE_SHIFT;
+       unsigned int i;
+
+       sglist = vmalloc(buf->npages * sizeof(*sglist));
+       if (sglist == NULL)
+               return -ENOMEM;
+
+       sg_init_table(sglist, buf->npages);
+
+       for (i = 0; i < buf->npages; ++i, ++pfn) {
+               sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset,
+                           offset);
+               /* PFNMAP buffers will not get DMA-mapped, set the DMA address
+                * manually.
+                */
+               sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset;
+               offset = 0;
+       }
+
+       buf->sglen = buf->npages;
+       buf->sglist = sglist;
+
+       return 0;
+}
+
+/*
+ * isp_video_buffer_cleanup - Release pages for a userspace VMA.
+ *
+ * Release pages locked by a call isp_video_buffer_prepare_user and free the
+ * pages table.
+ */
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+       enum dma_data_direction direction;
+       unsigned int i;
+
+       if (buf->queue->ops->buffer_cleanup)
+               buf->queue->ops->buffer_cleanup(buf);
+
+       if (!(buf->vm_flags & VM_PFNMAP)) {
+               direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+                         ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+               dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen,
+                            direction);
+       }
+
+       vfree(buf->sglist);
+       buf->sglist = NULL;
+       buf->sglen = 0;
+
+       if (buf->pages != NULL) {
+               isp_video_buffer_lock_vma(buf, 0);
+
+               for (i = 0; i < buf->npages; ++i)
+                       page_cache_release(buf->pages[i]);
+
+               vfree(buf->pages);
+               buf->pages = NULL;
+       }
+
+       buf->npages = 0;
+       buf->skip_cache = false;
+}
+
+/*
+ * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory.
+ *
+ * This function creates a list of pages for a userspace VMA. The number of
+ * pages is first computed based on the buffer size, and pages are then
+ * retrieved by a call to get_user_pages.
+ *
+ * Pages are pinned to memory by get_user_pages, making them available for DMA
+ * transfers. However, due to memory management optimization, it seems the
+ * get_user_pages doesn't guarantee that the pinned pages will not be written
+ * to swap and removed from the userspace mapping(s). When this happens, a page
+ * fault can be generated when accessing those unmapped pages.
+ *
+ * If the fault is triggered by a page table walk caused by VIPT cache
+ * management operations, the page fault handler might oops if the MM semaphore
+ * is held, as it can't handle kernel page faults in that case. To fix that, a
+ * fixup entry needs to be added to the cache management code, or the userspace
+ * VMA must be locked to avoid removing pages from the userspace mapping in the
+ * first place.
+ *
+ * If the number of pages retrieved is smaller than the number required by the
+ * buffer size, the function returns -EFAULT.
+ */
+static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
+{
+       unsigned long data;
+       unsigned int first;
+       unsigned int last;
+       int ret;
+
+       data = buf->vbuf.m.userptr;
+       first = (data & PAGE_MASK) >> PAGE_SHIFT;
+       last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
+
+       buf->offset = data & ~PAGE_MASK;
+       buf->npages = last - first + 1;
+       buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
+       if (buf->pages == NULL)
+               return -ENOMEM;
+
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm, data & PAGE_MASK,
+                            buf->npages,
+                            buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+                            buf->pages, NULL);
+       up_read(&current->mm->mmap_sem);
+
+       if (ret != buf->npages) {
+               buf->npages = ret;
+               isp_video_buffer_cleanup(buf);
+               return -EFAULT;
+       }
+
+       ret = isp_video_buffer_lock_vma(buf, 1);
+       if (ret < 0)
+               isp_video_buffer_cleanup(buf);
+
+       return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer
+ *
+ * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
+ * memory and if they span a single VMA.
+ *
+ * Return 0 if the buffer is valid, or -EFAULT otherwise.
+ */
+static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
+{
+       struct vm_area_struct *vma;
+       unsigned long prev_pfn;
+       unsigned long this_pfn;
+       unsigned long start;
+       unsigned long end;
+       dma_addr_t pa;
+       int ret = -EFAULT;
+
+       start = buf->vbuf.m.userptr;
+       end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+       buf->offset = start & ~PAGE_MASK;
+       buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
+       buf->pages = NULL;
+
+       down_read(&current->mm->mmap_sem);
+       vma = find_vma(current->mm, start);
+       if (vma == NULL || vma->vm_end < end)
+               goto done;
+
+       for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
+               ret = follow_pfn(vma, start, &this_pfn);
+               if (ret)
+                       goto done;
+
+               if (prev_pfn == 0)
+                       pa = this_pfn << PAGE_SHIFT;
+               else if (this_pfn != prev_pfn + 1) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+
+               prev_pfn = this_pfn;
+       }
+
+       buf->paddr = pa + buf->offset;
+       ret = 0;
+
+done:
+       up_read(&current->mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
+ *
+ * This function locates the VMAs for the buffer's userspace address and checks
+ * that their flags match. The onlflag that we need to care for at the moment is
+ * VM_PFNMAP.
+ *
+ * The buffer vm_flags field is set to the first VMA flags.
+ *
+ * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs
+ * have incompatible flags.
+ */
+static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
+{
+       struct vm_area_struct *vma;
+       pgprot_t vm_page_prot;
+       unsigned long start;
+       unsigned long end;
+       int ret = -EFAULT;
+
+       start = buf->vbuf.m.userptr;
+       end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
+
+       down_read(&current->mm->mmap_sem);
+
+       do {
+               vma = find_vma(current->mm, start);
+               if (vma == NULL)
+                       goto done;
+
+               if (start == buf->vbuf.m.userptr) {
+                       buf->vm_flags = vma->vm_flags;
+                       vm_page_prot = vma->vm_page_prot;
+               }
+
+               if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP)
+                       goto done;
+
+               if (vm_page_prot != vma->vm_page_prot)
+                       goto done;
+
+               start = vma->vm_end + 1;
+       } while (vma->vm_end < end);
+
+       /* Skip cache management to enhance performances for non-cached or
+        * write-combining buffers.
+        */
+       if (vm_page_prot == pgprot_noncached(vm_page_prot) ||
+           vm_page_prot == pgprot_writecombine(vm_page_prot))
+               buf->skip_cache = true;
+
+       ret = 0;
+
+done:
+       up_read(&current->mm->mmap_sem);
+       return ret;
+}
+
+/*
+ * isp_video_buffer_prepare - Make a buffer ready for operation
+ *
+ * Preparing a buffer involves:
+ *
+ * - validating VMAs (userspace buffers only)
+ * - locking pages and VMAs into memory (userspace buffers only)
+ * - building page and scatter-gather lists
+ * - mapping buffers for DMA operation
+ * - performing driver-specific preparation
+ *
+ * The function must be called in userspace context with a valid mm context
+ * (this excludes cleanup paths such as sys_close when the userspace process
+ * segfaults).
+ */
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+       enum dma_data_direction direction;
+       int ret;
+
+       switch (buf->vbuf.memory) {
+       case V4L2_MEMORY_MMAP:
+               ret = isp_video_buffer_sglist_kernel(buf);
+               break;
+
+       case V4L2_MEMORY_USERPTR:
+               ret = isp_video_buffer_prepare_vm_flags(buf);
+               if (ret < 0)
+                       return ret;
+
+               if (buf->vm_flags & VM_PFNMAP) {
+                       ret = isp_video_buffer_prepare_pfnmap(buf);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = isp_video_buffer_sglist_pfnmap(buf);
+               } else {
+                       ret = isp_video_buffer_prepare_user(buf);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = isp_video_buffer_sglist_user(buf);
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (ret < 0)
+               goto done;
+
+       if (!(buf->vm_flags & VM_PFNMAP)) {
+               direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
+                         ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+               ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen,
+                                direction);
+               if (ret != buf->sglen) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+       }
+
+       if (buf->queue->ops->buffer_prepare)
+               ret = buf->queue->ops->buffer_prepare(buf);
+
+done:
+       if (ret < 0) {
+               isp_video_buffer_cleanup(buf);
+               return ret;
+       }
+
+       return ret;
+}
+
+/*
+ * isp_video_queue_query - Query the status of a given buffer
+ *
+ * Locking: must be called with the queue lock held.
+ */
+static void isp_video_buffer_query(struct isp_video_buffer *buf,
+                                  struct v4l2_buffer *vbuf)
+{
+       memcpy(vbuf, &buf->vbuf, sizeof(*vbuf));
+
+       if (buf->vma_use_count)
+               vbuf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+       switch (buf->state) {
+       case ISP_BUF_STATE_ERROR:
+               vbuf->flags |= V4L2_BUF_FLAG_ERROR;
+       case ISP_BUF_STATE_DONE:
+               vbuf->flags |= V4L2_BUF_FLAG_DONE;
+       case ISP_BUF_STATE_QUEUED:
+       case ISP_BUF_STATE_ACTIVE:
+               vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
+               break;
+       case ISP_BUF_STATE_IDLE:
+       default:
+               break;
+       }
+}
+
+/*
+ * isp_video_buffer_wait - Wait for a buffer to be ready
+ *
+ * In non-blocking mode, return immediately with 0 if the buffer is ready or
+ * -EAGAIN if the buffer is in the QUEUED or ACTIVE state.
+ *
+ * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait
+ * queue using the same condition.
+ */
+static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
+{
+       if (nonblocking) {
+               return (buf->state != ISP_BUF_STATE_QUEUED &&
+                       buf->state != ISP_BUF_STATE_ACTIVE)
+                       ? 0 : -EAGAIN;
+       }
+
+       return wait_event_interruptible(buf->wait,
+               buf->state != ISP_BUF_STATE_QUEUED &&
+               buf->state != ISP_BUF_STATE_ACTIVE);
+}
+
+/* -----------------------------------------------------------------------------
+ * Queue management
+ */
+
+/*
+ * isp_video_queue_free - Free video buffers memory
+ *
+ * Buffers can only be freed if the queue isn't streaming and if no buffer is
+ * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_free(struct isp_video_queue *queue)
+{
+       unsigned int i;
+
+       if (queue->streaming)
+               return -EBUSY;
+
+       for (i = 0; i < queue->count; ++i) {
+               if (queue->buffers[i]->vma_use_count != 0)
+                       return -EBUSY;
+       }
+
+       for (i = 0; i < queue->count; ++i) {
+               struct isp_video_buffer *buf = queue->buffers[i];
+
+               isp_video_buffer_cleanup(buf);
+
+               vfree(buf->vaddr);
+               buf->vaddr = NULL;
+
+               kfree(buf);
+               queue->buffers[i] = NULL;
+       }
+
+       INIT_LIST_HEAD(&queue->queue);
+       queue->count = 0;
+       return 0;
+}
+
+/*
+ * isp_video_queue_alloc - Allocate video buffers memory
+ *
+ * This function must be called with the queue lock held.
+ */
+static int isp_video_queue_alloc(struct isp_video_queue *queue,
+                                unsigned int nbuffers,
+                                unsigned int size, enum v4l2_memory memory)
+{
+       struct isp_video_buffer *buf;
+       unsigned int i;
+       void *mem;
+       int ret;
+
+       /* Start by freeing the buffers. */
+       ret = isp_video_queue_free(queue);
+       if (ret < 0)
+               return ret;
+
+       /* Bail out of no buffers should be allocated. */
+       if (nbuffers == 0)
+               return 0;
+
+       /* Initialize the allocated buffers. */
+       for (i = 0; i < nbuffers; ++i) {
+               buf = kzalloc(queue->bufsize, GFP_KERNEL);
+               if (buf == NULL)
+                       break;
+
+               if (memory == V4L2_MEMORY_MMAP) {
+                       /* Allocate video buffers memory for mmap mode. Align
+                        * the size to the page size.
+                        */
+                       mem = vmalloc_32_user(PAGE_ALIGN(size));
+                       if (mem == NULL) {
+                               kfree(buf);
+                               break;
+                       }
+
+                       buf->vbuf.m.offset = i * PAGE_ALIGN(size);
+                       buf->vaddr = mem;
+               }
+
+               buf->vbuf.index = i;
+               buf->vbuf.length = size;
+               buf->vbuf.type = queue->type;
+               buf->vbuf.field = V4L2_FIELD_NONE;
+               buf->vbuf.memory = memory;
+
+               buf->queue = queue;
+               init_waitqueue_head(&buf->wait);
+
+               queue->buffers[i] = buf;
+       }
+
+       if (i == 0)
+               return -ENOMEM;
+
+       queue->count = i;
+       return nbuffers;
+}
+
+/**
+ * omap3isp_video_queue_cleanup - Clean up the video buffers queue
+ * @queue: Video buffers queue
+ *
+ * Free all allocated resources and clean up the video buffers queue. The queue
+ * must not be busy (no ongoing video stream) and buffers must have been
+ * unmapped.
+ *
+ * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been
+ * unmapped.
+ */
+int omap3isp_video_queue_cleanup(struct isp_video_queue *queue)
+{
+       return isp_video_queue_free(queue);
+}
+
+/**
+ * omap3isp_video_queue_init - Initialize the video buffers queue
+ * @queue: Video buffers queue
+ * @type: V4L2 buffer type (capture or output)
+ * @ops: Driver-specific queue operations
+ * @dev: Device used for DMA operations
+ * @bufsize: Size of the driver-specific buffer structure
+ *
+ * Initialize the video buffers queue with the supplied parameters.
+ *
+ * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or
+ * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet.
+ *
+ * Buffer objects will be allocated using the given buffer size to allow room
+ * for driver-specific fields. Driver-specific buffer structures must start
+ * with a struct isp_video_buffer field. Drivers with no driver-specific buffer
+ * structure must pass the size of the isp_video_buffer structure in the bufsize
+ * parameter.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_init(struct isp_video_queue *queue,
+                             enum v4l2_buf_type type,
+                             const struct isp_video_queue_operations *ops,
+                             struct device *dev, unsigned int bufsize)
+{
+       INIT_LIST_HEAD(&queue->queue);
+       mutex_init(&queue->lock);
+       spin_lock_init(&queue->irqlock);
+
+       queue->type = type;
+       queue->ops = ops;
+       queue->dev = dev;
+       queue->bufsize = bufsize;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 operations
+ */
+
+/**
+ * omap3isp_video_queue_reqbufs - Allocate video buffers memory
+ *
+ * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It
+ * allocated video buffer objects and, for MMAP buffers, buffer memory.
+ *
+ * If the number of buffers is 0, all buffers are freed and the function returns
+ * without performing any allocation.
+ *
+ * If the number of buffers is not 0, currently allocated buffers (if any) are
+ * freed and the requested number of buffers are allocated. Depending on
+ * driver-specific requirements and on memory availability, a number of buffer
+ * smaller or bigger than requested can be allocated. This isn't considered as
+ * an error.
+ *
+ * Return 0 on success or one of the following error codes:
+ *
+ * -EINVAL if the buffer type or index are invalid
+ * -EBUSY if the queue is busy (streaming or buffers mapped)
+ * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition
+ */
+int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
+                                struct v4l2_requestbuffers *rb)
+{
+       unsigned int nbuffers = rb->count;
+       unsigned int size;
+       int ret;
+
+       if (rb->type != queue->type)
+               return -EINVAL;
+
+       queue->ops->queue_prepare(queue, &nbuffers, &size);
+       if (size == 0)
+               return -EINVAL;
+
+       nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS);
+
+       mutex_lock(&queue->lock);
+
+       ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory);
+       if (ret < 0)
+               goto done;
+
+       rb->count = ret;
+       ret = 0;
+
+done:
+       mutex_unlock(&queue->lock);
+       return ret;
+}
+
+/**
+ * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue
+ *
+ * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It
+ * returns the status of a given video buffer.
+ *
+ * Return 0 on success or -EINVAL if the buffer type or index are invalid.
+ */
+int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
+                                 struct v4l2_buffer *vbuf)
+{
+       struct isp_video_buffer *buf;
+       int ret = 0;
+
+       if (vbuf->type != queue->type)
+               return -EINVAL;
+
+       mutex_lock(&queue->lock);
+
+       if (vbuf->index >= queue->count) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       buf = queue->buffers[vbuf->index];
+       isp_video_buffer_query(buf, vbuf);
+
+done:
+       mutex_unlock(&queue->lock);
+       return ret;
+}
+
+/**
+ * omap3isp_video_queue_qbuf - Queue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_QBUF ioctl handler.
+ *
+ * The v4l2_buffer structure passed from userspace is first sanity tested. If
+ * sane, the buffer is then processed and added to the main queue and, if the
+ * queue is streaming, to the IRQ queue.
+ *
+ * Before being enqueued, USERPTR buffers are checked for address changes. If
+ * the buffer has a different userspace address, the old memory area is unlocked
+ * and the new memory area is locked.
+ */
+int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
+                             struct v4l2_buffer *vbuf)
+{
+       struct isp_video_buffer *buf;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (vbuf->type != queue->type)
+               goto done;
+
+       mutex_lock(&queue->lock);
+
+       if (vbuf->index >= queue->count)
+               goto done;
+
+       buf = queue->buffers[vbuf->index];
+
+       if (vbuf->memory != buf->vbuf.memory)
+               goto done;
+
+       if (buf->state != ISP_BUF_STATE_IDLE)
+               goto done;
+
+       if (vbuf->memory == V4L2_MEMORY_USERPTR &&
+           vbuf->m.userptr != buf->vbuf.m.userptr) {
+               isp_video_buffer_cleanup(buf);
+               buf->vbuf.m.userptr = vbuf->m.userptr;
+               buf->prepared = 0;
+       }
+
+       if (!buf->prepared) {
+               ret = isp_video_buffer_prepare(buf);
+               if (ret < 0)
+                       goto done;
+               buf->prepared = 1;
+       }
+
+       isp_video_buffer_cache_sync(buf);
+
+       buf->state = ISP_BUF_STATE_QUEUED;
+       list_add_tail(&buf->stream, &queue->queue);
+
+       if (queue->streaming) {
+               spin_lock_irqsave(&queue->irqlock, flags);
+               queue->ops->buffer_queue(buf);
+               spin_unlock_irqrestore(&queue->irqlock, flags);
+       }
+
+       ret = 0;
+
+done:
+       mutex_unlock(&queue->lock);
+       return ret;
+}
+
+/**
+ * omap3isp_video_queue_dqbuf - Dequeue a buffer
+ *
+ * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
+ *
+ * The v4l2_buffer structure passed from userspace is first sanity tested. If
+ * sane, the buffer is then processed and added to the main queue and, if the
+ * queue is streaming, to the IRQ queue.
+ *
+ * Before being enqueued, USERPTR buffers are checked for address changes. If
+ * the buffer has a different userspace address, the old memory area is unlocked
+ * and the new memory area is locked.
+ */
+int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
+                              struct v4l2_buffer *vbuf, int nonblocking)
+{
+       struct isp_video_buffer *buf;
+       int ret;
+
+       if (vbuf->type != queue->type)
+               return -EINVAL;
+
+       mutex_lock(&queue->lock);
+
+       if (list_empty(&queue->queue)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+       ret = isp_video_buffer_wait(buf, nonblocking);
+       if (ret < 0)
+               goto done;
+
+       list_del(&buf->stream);
+
+       isp_video_buffer_query(buf, vbuf);
+       buf->state = ISP_BUF_STATE_IDLE;
+       vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+done:
+       mutex_unlock(&queue->lock);
+       return ret;
+}
+
+/**
+ * omap3isp_video_queue_streamon - Start streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It
+ * starts streaming on the queue and calls the buffer_queue operation for all
+ * queued buffers.
+ *
+ * Return 0 on success.
+ */
+int omap3isp_video_queue_streamon(struct isp_video_queue *queue)
+{
+       struct isp_video_buffer *buf;
+       unsigned long flags;
+
+       mutex_lock(&queue->lock);
+
+       if (queue->streaming)
+               goto done;
+
+       queue->streaming = 1;
+
+       spin_lock_irqsave(&queue->irqlock, flags);
+       list_for_each_entry(buf, &queue->queue, stream)
+               queue->ops->buffer_queue(buf);
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+       mutex_unlock(&queue->lock);
+       return 0;
+}
+
+/**
+ * omap3isp_video_queue_streamoff - Stop streaming
+ *
+ * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It
+ * stops streaming on the queue and wakes up all the buffers.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_streamoff(struct isp_video_queue *queue)
+{
+       struct isp_video_buffer *buf;
+       unsigned long flags;
+       unsigned int i;
+
+       mutex_lock(&queue->lock);
+
+       if (!queue->streaming)
+               goto done;
+
+       queue->streaming = 0;
+
+       spin_lock_irqsave(&queue->irqlock, flags);
+       for (i = 0; i < queue->count; ++i) {
+               buf = queue->buffers[i];
+
+               if (buf->state == ISP_BUF_STATE_ACTIVE)
+                       wake_up(&buf->wait);
+
+               buf->state = ISP_BUF_STATE_IDLE;
+       }
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+
+       INIT_LIST_HEAD(&queue->queue);
+
+done:
+       mutex_unlock(&queue->lock);
+}
+
+/**
+ * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE
+ *
+ * This function is intended to be used with suspend/resume operations. It
+ * discards all 'done' buffers as they would be too old to be requested after
+ * resume.
+ *
+ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
+ * delayed works before calling this function to make sure no buffer will be
+ * touched by the driver and/or hardware.
+ */
+void omap3isp_video_queue_discard_done(struct isp_video_queue *queue)
+{
+       struct isp_video_buffer *buf;
+       unsigned int i;
+
+       mutex_lock(&queue->lock);
+
+       if (!queue->streaming)
+               goto done;
+
+       for (i = 0; i < queue->count; ++i) {
+               buf = queue->buffers[i];
+
+               if (buf->state == ISP_BUF_STATE_DONE)
+                       buf->state = ISP_BUF_STATE_ERROR;
+       }
+
+done:
+       mutex_unlock(&queue->lock);
+}
+
+static void isp_video_queue_vm_open(struct vm_area_struct *vma)
+{
+       struct isp_video_buffer *buf = vma->vm_private_data;
+
+       buf->vma_use_count++;
+}
+
+static void isp_video_queue_vm_close(struct vm_area_struct *vma)
+{
+       struct isp_video_buffer *buf = vma->vm_private_data;
+
+       buf->vma_use_count--;
+}
+
+static const struct vm_operations_struct isp_video_queue_vm_ops = {
+       .open = isp_video_queue_vm_open,
+       .close = isp_video_queue_vm_close,
+};
+
+/**
+ * omap3isp_video_queue_mmap - Map buffers to userspace
+ *
+ * This function is intended to be used as an mmap() file operation handler. It
+ * maps a buffer to userspace based on the VMA offset.
+ *
+ * Only buffers of memory type MMAP are supported.
+ */
+int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
+                        struct vm_area_struct *vma)
+{
+       struct isp_video_buffer *uninitialized_var(buf);
+       unsigned long size;
+       unsigned int i;
+       int ret = 0;
+
+       mutex_lock(&queue->lock);
+
+       for (i = 0; i < queue->count; ++i) {
+               buf = queue->buffers[i];
+               if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+
+       if (i == queue->count) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       size = vma->vm_end - vma->vm_start;
+
+       if (buf->vbuf.memory != V4L2_MEMORY_MMAP ||
+           size != PAGE_ALIGN(buf->vbuf.length)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+       if (ret < 0)
+               goto done;
+
+       vma->vm_ops = &isp_video_queue_vm_ops;
+       vma->vm_private_data = buf;
+       isp_video_queue_vm_open(vma);
+
+done:
+       mutex_unlock(&queue->lock);
+       return ret;
+}
+
+/**
+ * omap3isp_video_queue_poll - Poll video queue state
+ *
+ * This function is intended to be used as a poll() file operation handler. It
+ * polls the state of the video buffer at the front of the queue and returns an
+ * events mask.
+ *
+ * If no buffer is present at the front of the queue, POLLERR is returned.
+ */
+unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
+                                      struct file *file, poll_table *wait)
+{
+       struct isp_video_buffer *buf;
+       unsigned int mask = 0;
+
+       mutex_lock(&queue->lock);
+       if (list_empty(&queue->queue)) {
+               mask |= POLLERR;
+               goto done;
+       }
+       buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
+
+       poll_wait(file, &buf->wait, wait);
+       if (buf->state == ISP_BUF_STATE_DONE ||
+           buf->state == ISP_BUF_STATE_ERROR) {
+               if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       mask |= POLLIN | POLLRDNORM;
+               else
+                       mask |= POLLOUT | POLLWRNORM;
+       }
+
+done:
+       mutex_unlock(&queue->lock);
+       return mask;
+}
diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h
new file mode 100644 (file)
index 0000000..251de3e
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * ispqueue.h
+ *
+ * TI OMAP3 ISP - Video buffers queue handling
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_QUEUE_H
+#define OMAP3_ISP_QUEUE_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/wait.h>
+
+struct isp_video_queue;
+struct page;
+struct scatterlist;
+
+#define ISP_VIDEO_MAX_BUFFERS          16
+
+/**
+ * enum isp_video_buffer_state - ISP video buffer state
+ * @ISP_BUF_STATE_IDLE:        The buffer is under userspace control (dequeued
+ *     or not queued yet).
+ * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the
+ *     device yet.
+ * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer.
+ * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error
+ *     occured. For capture device the buffer likely contains corrupted data or
+ *     no data at all.
+ * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured.
+ *     For capture devices the buffer contains valid data.
+ */
+enum isp_video_buffer_state {
+       ISP_BUF_STATE_IDLE,
+       ISP_BUF_STATE_QUEUED,
+       ISP_BUF_STATE_ACTIVE,
+       ISP_BUF_STATE_ERROR,
+       ISP_BUF_STATE_DONE,
+};
+
+/**
+ * struct isp_video_buffer - ISP video buffer
+ * @vma_use_count: Number of times the buffer is mmap'ed to userspace
+ * @stream: List head for insertion into main queue
+ * @queue: ISP buffers queue this buffer belongs to
+ * @prepared: Whether the buffer has been prepared
+ * @skip_cache: Whether to skip cache management operations for this buffer
+ * @vaddr: Memory virtual address (for kernel buffers)
+ * @vm_flags: Buffer VMA flags (for userspace buffers)
+ * @offset: Offset inside the first page (for userspace buffers)
+ * @npages: Number of pages (for userspace buffers)
+ * @pages: Pages table (for userspace non-VM_PFNMAP buffers)
+ * @paddr: Memory physical address (for userspace VM_PFNMAP buffers)
+ * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers)
+ * @sglist: Scatter list (for non-VM_PFNMAP buffers)
+ * @vbuf: V4L2 buffer
+ * @irqlist: List head for insertion into IRQ queue
+ * @state: Current buffer state
+ * @wait: Wait queue to signal buffer completion
+ */
+struct isp_video_buffer {
+       unsigned long vma_use_count;
+       struct list_head stream;
+       struct isp_video_queue *queue;
+       unsigned int prepared:1;
+       bool skip_cache;
+
+       /* For kernel buffers. */
+       void *vaddr;
+
+       /* For userspace buffers. */
+       unsigned long vm_flags;
+       unsigned long offset;
+       unsigned int npages;
+       struct page **pages;
+       dma_addr_t paddr;
+
+       /* For all buffers except VM_PFNMAP. */
+       unsigned int sglen;
+       struct scatterlist *sglist;
+
+       /* Touched by the interrupt handler. */
+       struct v4l2_buffer vbuf;
+       struct list_head irqlist;
+       enum isp_video_buffer_state state;
+       wait_queue_head_t wait;
+};
+
+#define to_isp_video_buffer(vb)        container_of(vb, struct isp_video_buffer, vb)
+
+/**
+ * struct isp_video_queue_operations - Driver-specific operations
+ * @queue_prepare: Called before allocating buffers. Drivers should clamp the
+ *     number of buffers according to their requirements, and must return the
+ *     buffer size in bytes.
+ * @buffer_prepare: Called the first time a buffer is queued, or after changing
+ *     the userspace memory address for a USERPTR buffer, with the queue lock
+ *     held. Drivers should perform device-specific buffer preparation (such as
+ *     mapping the buffer memory in an IOMMU). This operation is optional.
+ * @buffer_queue: Called when a buffer is being added to the queue with the
+ *     queue irqlock spinlock held.
+ * @buffer_cleanup: Called before freeing buffers, or before changing the
+ *     userspace memory address for a USERPTR buffer, with the queue lock held.
+ *     Drivers must perform cleanup operations required to undo the
+ *     buffer_prepare call. This operation is optional.
+ */
+struct isp_video_queue_operations {
+       void (*queue_prepare)(struct isp_video_queue *queue,
+                             unsigned int *nbuffers, unsigned int *size);
+       int  (*buffer_prepare)(struct isp_video_buffer *buf);
+       void (*buffer_queue)(struct isp_video_buffer *buf);
+       void (*buffer_cleanup)(struct isp_video_buffer *buf);
+};
+
+/**
+ * struct isp_video_queue - ISP video buffers queue
+ * @type: Type of video buffers handled by this queue
+ * @ops: Queue operations
+ * @dev: Device used for DMA operations
+ * @bufsize: Size of a driver-specific buffer object
+ * @count: Number of currently allocated buffers
+ * @buffers: ISP video buffers
+ * @lock: Mutex to protect access to the buffers, main queue and state
+ * @irqlock: Spinlock to protect access to the IRQ queue
+ * @streaming: Queue state, indicates whether the queue is streaming
+ * @queue: List of all queued buffers
+ */
+struct isp_video_queue {
+       enum v4l2_buf_type type;
+       const struct isp_video_queue_operations *ops;
+       struct device *dev;
+       unsigned int bufsize;
+
+       unsigned int count;
+       struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS];
+       struct mutex lock;
+       spinlock_t irqlock;
+
+       unsigned int streaming:1;
+
+       struct list_head queue;
+};
+
+int omap3isp_video_queue_cleanup(struct isp_video_queue *queue);
+int omap3isp_video_queue_init(struct isp_video_queue *queue,
+                             enum v4l2_buf_type type,
+                             const struct isp_video_queue_operations *ops,
+                             struct device *dev, unsigned int bufsize);
+
+int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
+                                struct v4l2_requestbuffers *rb);
+int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
+                                 struct v4l2_buffer *vbuf);
+int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
+                             struct v4l2_buffer *vbuf);
+int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
+                              struct v4l2_buffer *vbuf, int nonblocking);
+int omap3isp_video_queue_streamon(struct isp_video_queue *queue);
+void omap3isp_video_queue_streamoff(struct isp_video_queue *queue);
+void omap3isp_video_queue_discard_done(struct isp_video_queue *queue);
+int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
+                             struct vm_area_struct *vma);
+unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
+                                      struct file *file, poll_table *wait);
+
+#endif /* OMAP3_ISP_QUEUE_H */
diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h
new file mode 100644 (file)
index 0000000..69f6af6
--- /dev/null
@@ -0,0 +1,1589 @@
+/*
+ * ispreg.h
+ *
+ * TI OMAP3 ISP - Registers definitions
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_REG_H
+#define OMAP3_ISP_REG_H
+
+#include <plat/omap34xx.h>
+
+
+#define CM_CAM_MCLK_HZ                 172800000       /* Hz */
+
+/* ISP Submodules offset */
+
+#define OMAP3ISP_REG_BASE              OMAP3430_ISP_BASE
+#define OMAP3ISP_REG(offset)           (OMAP3ISP_REG_BASE + (offset))
+
+#define OMAP3ISP_CCP2_REG_OFFSET       0x0400
+#define OMAP3ISP_CCP2_REG_BASE         (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CCP2_REG_OFFSET)
+#define OMAP3ISP_CCP2_REG(offset)      (OMAP3ISP_CCP2_REG_BASE + (offset))
+
+#define OMAP3ISP_CCDC_REG_OFFSET       0x0600
+#define OMAP3ISP_CCDC_REG_BASE         (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CCDC_REG_OFFSET)
+#define OMAP3ISP_CCDC_REG(offset)      (OMAP3ISP_CCDC_REG_BASE + (offset))
+
+#define OMAP3ISP_HIST_REG_OFFSET       0x0A00
+#define OMAP3ISP_HIST_REG_BASE         (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_HIST_REG_OFFSET)
+#define OMAP3ISP_HIST_REG(offset)      (OMAP3ISP_HIST_REG_BASE + (offset))
+
+#define OMAP3ISP_H3A_REG_OFFSET                0x0C00
+#define OMAP3ISP_H3A_REG_BASE          (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_H3A_REG_OFFSET)
+#define OMAP3ISP_H3A_REG(offset)       (OMAP3ISP_H3A_REG_BASE + (offset))
+
+#define OMAP3ISP_PREV_REG_OFFSET       0x0E00
+#define OMAP3ISP_PREV_REG_BASE         (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_PREV_REG_OFFSET)
+#define OMAP3ISP_PREV_REG(offset)      (OMAP3ISP_PREV_REG_BASE + (offset))
+
+#define OMAP3ISP_RESZ_REG_OFFSET       0x1000
+#define OMAP3ISP_RESZ_REG_BASE         (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_RESZ_REG_OFFSET)
+#define OMAP3ISP_RESZ_REG(offset)      (OMAP3ISP_RESZ_REG_BASE + (offset))
+
+#define OMAP3ISP_SBL_REG_OFFSET                0x1200
+#define OMAP3ISP_SBL_REG_BASE          (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_SBL_REG_OFFSET)
+#define OMAP3ISP_SBL_REG(offset)       (OMAP3ISP_SBL_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET        0x1800
+#define OMAP3ISP_CSI2A_REGS1_REG_BASE  (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CSI2A_REGS1_REG_OFFSET)
+#define OMAP3ISP_CSI2A_REGS1_REG(offset)                               \
+                               (OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSIPHY2_REG_OFFSET    0x1970
+#define OMAP3ISP_CSIPHY2_REG_BASE      (OMAP3ISP_REG_BASE +    \
+                                        OMAP3ISP_CSIPHY2_REG_OFFSET)
+#define OMAP3ISP_CSIPHY2_REG(offset)   (OMAP3ISP_CSIPHY2_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET        0x19C0
+#define OMAP3ISP_CSI2A_REGS2_REG_BASE  (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CSI2A_REGS2_REG_OFFSET)
+#define OMAP3ISP_CSI2A_REGS2_REG(offset)                               \
+                               (OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET        0x1C00
+#define OMAP3ISP_CSI2C_REGS1_REG_BASE  (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CSI2C_REGS1_REG_OFFSET)
+#define OMAP3ISP_CSI2C_REGS1_REG(offset)                               \
+                               (OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSIPHY1_REG_OFFSET    0x1D70
+#define OMAP3ISP_CSIPHY1_REG_BASE      (OMAP3ISP_REG_BASE +    \
+                                        OMAP3ISP_CSIPHY1_REG_OFFSET)
+#define OMAP3ISP_CSIPHY1_REG(offset)   (OMAP3ISP_CSIPHY1_REG_BASE + (offset))
+
+#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET        0x1DC0
+#define OMAP3ISP_CSI2C_REGS2_REG_BASE  (OMAP3ISP_REG_BASE +            \
+                                        OMAP3ISP_CSI2C_REGS2_REG_OFFSET)
+#define OMAP3ISP_CSI2C_REGS2_REG(offset)                               \
+                               (OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset))
+
+/* ISP module register offset */
+
+#define ISP_REVISION                   (0x000)
+#define ISP_SYSCONFIG                  (0x004)
+#define ISP_SYSSTATUS                  (0x008)
+#define ISP_IRQ0ENABLE                 (0x00C)
+#define ISP_IRQ0STATUS                 (0x010)
+#define ISP_IRQ1ENABLE                 (0x014)
+#define ISP_IRQ1STATUS                 (0x018)
+#define ISP_TCTRL_GRESET_LENGTH                (0x030)
+#define ISP_TCTRL_PSTRB_REPLAY         (0x034)
+#define ISP_CTRL                       (0x040)
+#define ISP_SECURE                     (0x044)
+#define ISP_TCTRL_CTRL                 (0x050)
+#define ISP_TCTRL_FRAME                        (0x054)
+#define ISP_TCTRL_PSTRB_DELAY          (0x058)
+#define ISP_TCTRL_STRB_DELAY           (0x05C)
+#define ISP_TCTRL_SHUT_DELAY           (0x060)
+#define ISP_TCTRL_PSTRB_LENGTH         (0x064)
+#define ISP_TCTRL_STRB_LENGTH          (0x068)
+#define ISP_TCTRL_SHUT_LENGTH          (0x06C)
+#define ISP_PING_PONG_ADDR             (0x070)
+#define ISP_PING_PONG_MEM_RANGE                (0x074)
+#define ISP_PING_PONG_BUF_SIZE         (0x078)
+
+/* CCP2 receiver registers */
+
+#define ISPCCP2_REVISION               (0x000)
+#define ISPCCP2_SYSCONFIG              (0x004)
+#define ISPCCP2_SYSCONFIG_SOFT_RESET   (1 << 1)
+#define ISPCCP2_SYSCONFIG_AUTO_IDLE            0x1
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT  12
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE  \
+       (0x0 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_NO     \
+       (0x1 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART  \
+       (0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCCP2_SYSSTATUS              (0x008)
+#define ISPCCP2_SYSSTATUS_RESET_DONE   (1 << 0)
+#define ISPCCP2_LC01_IRQENABLE         (0x00C)
+#define ISPCCP2_LC01_IRQSTATUS         (0x010)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ      (1 << 11)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ      (1 << 10)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ      (1 << 9)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ      (1 << 8)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ   (1 << 7)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ        (1 << 5)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ     (1 << 4)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ     (1 << 3)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ      (1 << 2)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ     (1 << 1)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ     (1 << 0)
+
+#define ISPCCP2_LC23_IRQENABLE         (0x014)
+#define ISPCCP2_LC23_IRQSTATUS         (0x018)
+#define ISPCCP2_LCM_IRQENABLE          (0x02C)
+#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ          (1 << 0)
+#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ     (1 << 1)
+#define ISPCCP2_LCM_IRQSTATUS          (0x030)
+#define ISPCCP2_CTRL                   (0x040)
+#define ISPCCP2_CTRL_IF_EN             (1 << 0)
+#define ISPCCP2_CTRL_PHY_SEL           (1 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_CLOCK     (0 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_STROBE    (1 << 1)
+#define ISPCCP2_CTRL_PHY_SEL_MASK      0x1
+#define ISPCCP2_CTRL_PHY_SEL_SHIFT     1
+#define ISPCCP2_CTRL_IO_OUT_SEL                (1 << 2)
+#define ISPCCP2_CTRL_MODE              (1 << 4)
+#define ISPCCP2_CTRL_VP_CLK_FORCE_ON   (1 << 9)
+#define ISPCCP2_CTRL_INV               (1 << 10)
+#define ISPCCP2_CTRL_INV_MASK          0x1
+#define ISPCCP2_CTRL_INV_SHIFT         10
+#define ISPCCP2_CTRL_VP_ONLY_EN                (1 << 11)
+#define ISPCCP2_CTRL_VP_CLK_POL                (1 << 12)
+#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT   15
+#define ISPCCP2_CTRL_VPCLK_DIV_MASK    0x1ffff /* [31:15] */
+#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */
+#define ISPCCP2_CTRL_VP_OUT_CTRL_MASK  0x3 /* 3430 bits */
+#define ISPCCP2_DBG                    (0x044)
+#define ISPCCP2_GNQ                    (0x048)
+#define ISPCCP2_LCx_CTRL(x)                    ((0x050)+0x30*(x))
+#define ISPCCP2_LCx_CTRL_CHAN_EN               (1 << 0)
+#define ISPCCP2_LCx_CTRL_CRC_EN                        (1 << 19)
+#define ISPCCP2_LCx_CTRL_CRC_MASK              0x1
+#define ISPCCP2_LCx_CTRL_CRC_SHIFT             2
+#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0                19
+#define ISPCCP2_LCx_CTRL_REGION_EN             (1 << 1)
+#define ISPCCP2_LCx_CTRL_REGION_MASK           0x1
+#define ISPCCP2_LCx_CTRL_REGION_SHIFT          1
+#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0      0x3f
+#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0     0x2
+#define ISPCCP2_LCx_CTRL_FORMAT_MASK           0x1f
+#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT          0x3
+#define ISPCCP2_LCx_CODE(x)            ((0x054)+0x30*(x))
+#define ISPCCP2_LCx_STAT_START(x)      ((0x058)+0x30*(x))
+#define ISPCCP2_LCx_STAT_SIZE(x)       ((0x05C)+0x30*(x))
+#define ISPCCP2_LCx_SOF_ADDR(x)                ((0x060)+0x30*(x))
+#define ISPCCP2_LCx_EOF_ADDR(x)                ((0x064)+0x30*(x))
+#define ISPCCP2_LCx_DAT_START(x)       ((0x068)+0x30*(x))
+#define ISPCCP2_LCx_DAT_SIZE(x)                ((0x06C)+0x30*(x))
+#define ISPCCP2_LCx_DAT_MASK           0xFFF
+#define ISPCCP2_LCx_DAT_SHIFT          16
+#define ISPCCP2_LCx_DAT_PING_ADDR(x)   ((0x070)+0x30*(x))
+#define ISPCCP2_LCx_DAT_PONG_ADDR(x)   ((0x074)+0x30*(x))
+#define ISPCCP2_LCx_DAT_OFST(x)                ((0x078)+0x30*(x))
+#define ISPCCP2_LCM_CTRL               (0x1D0)
+#define ISPCCP2_LCM_CTRL_CHAN_EN               (1 << 0)
+#define ISPCCP2_LCM_CTRL_DST_PORT              (1 << 2)
+#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT                2
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT   3
+#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK    0x11
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT      5
+#define ISPCCP2_LCM_CTRL_BURST_SIZE_MASK       0x7
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT      16
+#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK       0x7
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT     20
+#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK      0x3
+#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED         (1 << 22)
+#define ISPCCP2_LCM_CTRL_SRC_PACK              (1 << 23)
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT      24
+#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK       0x7
+#define ISPCCP2_LCM_VSIZE              (0x1D4)
+#define ISPCCP2_LCM_VSIZE_SHIFT                16
+#define ISPCCP2_LCM_HSIZE              (0x1D8)
+#define ISPCCP2_LCM_HSIZE_SHIFT                16
+#define ISPCCP2_LCM_PREFETCH           (0x1DC)
+#define ISPCCP2_LCM_PREFETCH_SHIFT     3
+#define ISPCCP2_LCM_SRC_ADDR           (0x1E0)
+#define ISPCCP2_LCM_SRC_OFST           (0x1E4)
+#define ISPCCP2_LCM_DST_ADDR           (0x1E8)
+#define ISPCCP2_LCM_DST_OFST           (0x1EC)
+
+/* CCDC module register offset */
+
+#define ISPCCDC_PID                    (0x000)
+#define ISPCCDC_PCR                    (0x004)
+#define ISPCCDC_SYN_MODE               (0x008)
+#define ISPCCDC_HD_VD_WID              (0x00C)
+#define ISPCCDC_PIX_LINES              (0x010)
+#define ISPCCDC_HORZ_INFO              (0x014)
+#define ISPCCDC_VERT_START             (0x018)
+#define ISPCCDC_VERT_LINES             (0x01C)
+#define ISPCCDC_CULLING                        (0x020)
+#define ISPCCDC_HSIZE_OFF              (0x024)
+#define ISPCCDC_SDOFST                 (0x028)
+#define ISPCCDC_SDR_ADDR               (0x02C)
+#define ISPCCDC_CLAMP                  (0x030)
+#define ISPCCDC_DCSUB                  (0x034)
+#define ISPCCDC_COLPTN                 (0x038)
+#define ISPCCDC_BLKCMP                 (0x03C)
+#define ISPCCDC_FPC                    (0x040)
+#define ISPCCDC_FPC_ADDR               (0x044)
+#define ISPCCDC_VDINT                  (0x048)
+#define ISPCCDC_ALAW                   (0x04C)
+#define ISPCCDC_REC656IF               (0x050)
+#define ISPCCDC_CFG                    (0x054)
+#define ISPCCDC_FMTCFG                 (0x058)
+#define ISPCCDC_FMT_HORZ               (0x05C)
+#define ISPCCDC_FMT_VERT               (0x060)
+#define ISPCCDC_FMT_ADDR0              (0x064)
+#define ISPCCDC_FMT_ADDR1              (0x068)
+#define ISPCCDC_FMT_ADDR2              (0x06C)
+#define ISPCCDC_FMT_ADDR3              (0x070)
+#define ISPCCDC_FMT_ADDR4              (0x074)
+#define ISPCCDC_FMT_ADDR5              (0x078)
+#define ISPCCDC_FMT_ADDR6              (0x07C)
+#define ISPCCDC_FMT_ADDR7              (0x080)
+#define ISPCCDC_PRGEVEN0               (0x084)
+#define ISPCCDC_PRGEVEN1               (0x088)
+#define ISPCCDC_PRGODD0                        (0x08C)
+#define ISPCCDC_PRGODD1                        (0x090)
+#define ISPCCDC_VP_OUT                 (0x094)
+
+#define ISPCCDC_LSC_CONFIG             (0x098)
+#define ISPCCDC_LSC_INITIAL            (0x09C)
+#define ISPCCDC_LSC_TABLE_BASE         (0x0A0)
+#define ISPCCDC_LSC_TABLE_OFFSET       (0x0A4)
+
+/* SBL */
+#define ISPSBL_PCR                     0x4
+#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF   (1 << 16)
+#define ISPSBL_PCR_H3A_AF_WBL_OVF      (1 << 17)
+#define ISPSBL_PCR_RSZ4_WBL_OVF                (1 << 18)
+#define ISPSBL_PCR_RSZ3_WBL_OVF                (1 << 19)
+#define ISPSBL_PCR_RSZ2_WBL_OVF                (1 << 20)
+#define ISPSBL_PCR_RSZ1_WBL_OVF                (1 << 21)
+#define ISPSBL_PCR_PRV_WBL_OVF         (1 << 22)
+#define ISPSBL_PCR_CCDC_WBL_OVF                (1 << 23)
+#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF   (1 << 24)
+#define ISPSBL_PCR_CSIA_WBL_OVF                (1 << 25)
+#define ISPSBL_PCR_CSIB_WBL_OVF                (1 << 26)
+#define ISPSBL_CCDC_WR_0               (0x028)
+#define ISPSBL_CCDC_WR_0_DATA_READY    (1 << 21)
+#define ISPSBL_CCDC_WR_1               (0x02C)
+#define ISPSBL_CCDC_WR_2               (0x030)
+#define ISPSBL_CCDC_WR_3               (0x034)
+
+#define ISPSBL_SDR_REQ_EXP             0xF8
+#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT  0
+#define ISPSBL_SDR_REQ_HIST_EXP_MASK   (0x3FF)
+#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT   10
+#define ISPSBL_SDR_REQ_RSZ_EXP_MASK    (0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT)
+#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT   20
+#define ISPSBL_SDR_REQ_PRV_EXP_MASK    (0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT)
+
+/* Histogram registers */
+#define ISPHIST_PID                    (0x000)
+#define ISPHIST_PCR                    (0x004)
+#define ISPHIST_CNT                    (0x008)
+#define ISPHIST_WB_GAIN                        (0x00C)
+#define ISPHIST_R0_HORZ                        (0x010)
+#define ISPHIST_R0_VERT                        (0x014)
+#define ISPHIST_R1_HORZ                        (0x018)
+#define ISPHIST_R1_VERT                        (0x01C)
+#define ISPHIST_R2_HORZ                        (0x020)
+#define ISPHIST_R2_VERT                        (0x024)
+#define ISPHIST_R3_HORZ                        (0x028)
+#define ISPHIST_R3_VERT                        (0x02C)
+#define ISPHIST_ADDR                   (0x030)
+#define ISPHIST_DATA                   (0x034)
+#define ISPHIST_RADD                   (0x038)
+#define ISPHIST_RADD_OFF               (0x03C)
+#define ISPHIST_H_V_INFO               (0x040)
+
+/* H3A module registers */
+#define ISPH3A_PID                     (0x000)
+#define ISPH3A_PCR                     (0x004)
+#define ISPH3A_AEWWIN1                 (0x04C)
+#define ISPH3A_AEWINSTART              (0x050)
+#define ISPH3A_AEWINBLK                        (0x054)
+#define ISPH3A_AEWSUBWIN               (0x058)
+#define ISPH3A_AEWBUFST                        (0x05C)
+#define ISPH3A_AFPAX1                  (0x008)
+#define ISPH3A_AFPAX2                  (0x00C)
+#define ISPH3A_AFPAXSTART              (0x010)
+#define ISPH3A_AFIIRSH                 (0x014)
+#define ISPH3A_AFBUFST                 (0x018)
+#define ISPH3A_AFCOEF010               (0x01C)
+#define ISPH3A_AFCOEF032               (0x020)
+#define ISPH3A_AFCOEF054               (0x024)
+#define ISPH3A_AFCOEF076               (0x028)
+#define ISPH3A_AFCOEF098               (0x02C)
+#define ISPH3A_AFCOEF0010              (0x030)
+#define ISPH3A_AFCOEF110               (0x034)
+#define ISPH3A_AFCOEF132               (0x038)
+#define ISPH3A_AFCOEF154               (0x03C)
+#define ISPH3A_AFCOEF176               (0x040)
+#define ISPH3A_AFCOEF198               (0x044)
+#define ISPH3A_AFCOEF1010              (0x048)
+
+#define ISPPRV_PCR                     (0x004)
+#define ISPPRV_HORZ_INFO               (0x008)
+#define ISPPRV_VERT_INFO               (0x00C)
+#define ISPPRV_RSDR_ADDR               (0x010)
+#define ISPPRV_RADR_OFFSET             (0x014)
+#define ISPPRV_DSDR_ADDR               (0x018)
+#define ISPPRV_DRKF_OFFSET             (0x01C)
+#define ISPPRV_WSDR_ADDR               (0x020)
+#define ISPPRV_WADD_OFFSET             (0x024)
+#define ISPPRV_AVE                     (0x028)
+#define ISPPRV_HMED                    (0x02C)
+#define ISPPRV_NF                      (0x030)
+#define ISPPRV_WB_DGAIN                        (0x034)
+#define ISPPRV_WBGAIN                  (0x038)
+#define ISPPRV_WBSEL                   (0x03C)
+#define ISPPRV_CFA                     (0x040)
+#define ISPPRV_BLKADJOFF               (0x044)
+#define ISPPRV_RGB_MAT1                        (0x048)
+#define ISPPRV_RGB_MAT2                        (0x04C)
+#define ISPPRV_RGB_MAT3                        (0x050)
+#define ISPPRV_RGB_MAT4                        (0x054)
+#define ISPPRV_RGB_MAT5                        (0x058)
+#define ISPPRV_RGB_OFF1                        (0x05C)
+#define ISPPRV_RGB_OFF2                        (0x060)
+#define ISPPRV_CSC0                    (0x064)
+#define ISPPRV_CSC1                    (0x068)
+#define ISPPRV_CSC2                    (0x06C)
+#define ISPPRV_CSC_OFFSET              (0x070)
+#define ISPPRV_CNT_BRT                 (0x074)
+#define ISPPRV_CSUP                    (0x078)
+#define ISPPRV_SETUP_YC                        (0x07C)
+#define ISPPRV_SET_TBL_ADDR            (0x080)
+#define ISPPRV_SET_TBL_DATA            (0x084)
+#define ISPPRV_CDC_THR0                        (0x090)
+#define ISPPRV_CDC_THR1                        (ISPPRV_CDC_THR0 + (0x4))
+#define ISPPRV_CDC_THR2                        (ISPPRV_CDC_THR0 + (0x4) * 2)
+#define ISPPRV_CDC_THR3                        (ISPPRV_CDC_THR0 + (0x4) * 3)
+
+#define ISPPRV_REDGAMMA_TABLE_ADDR     0x0000
+#define ISPPRV_GREENGAMMA_TABLE_ADDR   0x0400
+#define ISPPRV_BLUEGAMMA_TABLE_ADDR    0x0800
+#define ISPPRV_NF_TABLE_ADDR           0x0C00
+#define ISPPRV_YENH_TABLE_ADDR         0x1000
+#define ISPPRV_CFA_TABLE_ADDR          0x1400
+
+#define ISPPRV_MAXOUTPUT_WIDTH         1280
+#define ISPPRV_MAXOUTPUT_WIDTH_ES2     3300
+#define ISPPRV_MAXOUTPUT_WIDTH_3630    4096
+#define ISPRSZ_MIN_OUTPUT              64
+#define ISPRSZ_MAX_OUTPUT              3312
+
+/* Resizer module register offset */
+#define ISPRSZ_PID                     (0x000)
+#define ISPRSZ_PCR                     (0x004)
+#define ISPRSZ_CNT                     (0x008)
+#define ISPRSZ_OUT_SIZE                        (0x00C)
+#define ISPRSZ_IN_START                        (0x010)
+#define ISPRSZ_IN_SIZE                 (0x014)
+#define ISPRSZ_SDR_INADD               (0x018)
+#define ISPRSZ_SDR_INOFF               (0x01C)
+#define ISPRSZ_SDR_OUTADD              (0x020)
+#define ISPRSZ_SDR_OUTOFF              (0x024)
+#define ISPRSZ_HFILT10                 (0x028)
+#define ISPRSZ_HFILT32                 (0x02C)
+#define ISPRSZ_HFILT54                 (0x030)
+#define ISPRSZ_HFILT76                 (0x034)
+#define ISPRSZ_HFILT98                 (0x038)
+#define ISPRSZ_HFILT1110               (0x03C)
+#define ISPRSZ_HFILT1312               (0x040)
+#define ISPRSZ_HFILT1514               (0x044)
+#define ISPRSZ_HFILT1716               (0x048)
+#define ISPRSZ_HFILT1918               (0x04C)
+#define ISPRSZ_HFILT2120               (0x050)
+#define ISPRSZ_HFILT2322               (0x054)
+#define ISPRSZ_HFILT2524               (0x058)
+#define ISPRSZ_HFILT2726               (0x05C)
+#define ISPRSZ_HFILT2928               (0x060)
+#define ISPRSZ_HFILT3130               (0x064)
+#define ISPRSZ_VFILT10                 (0x068)
+#define ISPRSZ_VFILT32                 (0x06C)
+#define ISPRSZ_VFILT54                 (0x070)
+#define ISPRSZ_VFILT76                 (0x074)
+#define ISPRSZ_VFILT98                 (0x078)
+#define ISPRSZ_VFILT1110               (0x07C)
+#define ISPRSZ_VFILT1312               (0x080)
+#define ISPRSZ_VFILT1514               (0x084)
+#define ISPRSZ_VFILT1716               (0x088)
+#define ISPRSZ_VFILT1918               (0x08C)
+#define ISPRSZ_VFILT2120               (0x090)
+#define ISPRSZ_VFILT2322               (0x094)
+#define ISPRSZ_VFILT2524               (0x098)
+#define ISPRSZ_VFILT2726               (0x09C)
+#define ISPRSZ_VFILT2928               (0x0A0)
+#define ISPRSZ_VFILT3130               (0x0A4)
+#define ISPRSZ_YENH                    (0x0A8)
+
+#define ISP_INT_CLR                    0xFF113F11
+#define ISPPRV_PCR_EN                  1
+#define ISPPRV_PCR_BUSY                        (1 << 1)
+#define ISPPRV_PCR_SOURCE              (1 << 2)
+#define ISPPRV_PCR_ONESHOT             (1 << 3)
+#define ISPPRV_PCR_WIDTH               (1 << 4)
+#define ISPPRV_PCR_INVALAW             (1 << 5)
+#define ISPPRV_PCR_DRKFEN              (1 << 6)
+#define ISPPRV_PCR_DRKFCAP             (1 << 7)
+#define ISPPRV_PCR_HMEDEN              (1 << 8)
+#define ISPPRV_PCR_NFEN                        (1 << 9)
+#define ISPPRV_PCR_CFAEN               (1 << 10)
+#define ISPPRV_PCR_CFAFMT_SHIFT                11
+#define ISPPRV_PCR_CFAFMT_MASK         0x7800
+#define ISPPRV_PCR_CFAFMT_BAYER                (0 << 11)
+#define ISPPRV_PCR_CFAFMT_SONYVGA      (1 << 11)
+#define ISPPRV_PCR_CFAFMT_RGBFOVEON    (2 << 11)
+#define ISPPRV_PCR_CFAFMT_DNSPL                (3 << 11)
+#define ISPPRV_PCR_CFAFMT_HONEYCOMB    (4 << 11)
+#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11)
+#define ISPPRV_PCR_YNENHEN             (1 << 15)
+#define ISPPRV_PCR_SUPEN               (1 << 16)
+#define ISPPRV_PCR_YCPOS_SHIFT         17
+#define ISPPRV_PCR_YCPOS_YCrYCb                (0 << 17)
+#define ISPPRV_PCR_YCPOS_YCbYCr                (1 << 17)
+#define ISPPRV_PCR_YCPOS_CbYCrY                (2 << 17)
+#define ISPPRV_PCR_YCPOS_CrYCbY                (3 << 17)
+#define ISPPRV_PCR_RSZPORT             (1 << 19)
+#define ISPPRV_PCR_SDRPORT             (1 << 20)
+#define ISPPRV_PCR_SCOMP_EN            (1 << 21)
+#define ISPPRV_PCR_SCOMP_SFT_SHIFT     (22)
+#define ISPPRV_PCR_SCOMP_SFT_MASK      (7 << 22)
+#define ISPPRV_PCR_GAMMA_BYPASS                (1 << 26)
+#define ISPPRV_PCR_DCOREN              (1 << 27)
+#define ISPPRV_PCR_DCCOUP              (1 << 28)
+#define ISPPRV_PCR_DRK_FAIL            (1 << 31)
+
+#define ISPPRV_HORZ_INFO_EPH_SHIFT     0
+#define ISPPRV_HORZ_INFO_EPH_MASK      0x3fff
+#define ISPPRV_HORZ_INFO_SPH_SHIFT     16
+#define ISPPRV_HORZ_INFO_SPH_MASK      0x3fff0
+
+#define ISPPRV_VERT_INFO_ELV_SHIFT     0
+#define ISPPRV_VERT_INFO_ELV_MASK      0x3fff
+#define ISPPRV_VERT_INFO_SLV_SHIFT     16
+#define ISPPRV_VERT_INFO_SLV_MASK      0x3fff0
+
+#define ISPPRV_AVE_EVENDIST_SHIFT      2
+#define ISPPRV_AVE_EVENDIST_1          0x0
+#define ISPPRV_AVE_EVENDIST_2          0x1
+#define ISPPRV_AVE_EVENDIST_3          0x2
+#define ISPPRV_AVE_EVENDIST_4          0x3
+#define ISPPRV_AVE_ODDDIST_SHIFT       4
+#define ISPPRV_AVE_ODDDIST_1           0x0
+#define ISPPRV_AVE_ODDDIST_2           0x1
+#define ISPPRV_AVE_ODDDIST_3           0x2
+#define ISPPRV_AVE_ODDDIST_4           0x3
+
+#define ISPPRV_HMED_THRESHOLD_SHIFT    0
+#define ISPPRV_HMED_EVENDIST           (1 << 8)
+#define ISPPRV_HMED_ODDDIST            (1 << 9)
+
+#define ISPPRV_WBGAIN_COEF0_SHIFT      0
+#define ISPPRV_WBGAIN_COEF1_SHIFT      8
+#define ISPPRV_WBGAIN_COEF2_SHIFT      16
+#define ISPPRV_WBGAIN_COEF3_SHIFT      24
+
+#define ISPPRV_WBSEL_COEF0             0x0
+#define ISPPRV_WBSEL_COEF1             0x1
+#define ISPPRV_WBSEL_COEF2             0x2
+#define ISPPRV_WBSEL_COEF3             0x3
+
+#define ISPPRV_WBSEL_N0_0_SHIFT                0
+#define ISPPRV_WBSEL_N0_1_SHIFT                2
+#define ISPPRV_WBSEL_N0_2_SHIFT                4
+#define ISPPRV_WBSEL_N0_3_SHIFT                6
+#define ISPPRV_WBSEL_N1_0_SHIFT                8
+#define ISPPRV_WBSEL_N1_1_SHIFT                10
+#define ISPPRV_WBSEL_N1_2_SHIFT                12
+#define ISPPRV_WBSEL_N1_3_SHIFT                14
+#define ISPPRV_WBSEL_N2_0_SHIFT                16
+#define ISPPRV_WBSEL_N2_1_SHIFT                18
+#define ISPPRV_WBSEL_N2_2_SHIFT                20
+#define ISPPRV_WBSEL_N2_3_SHIFT                22
+#define ISPPRV_WBSEL_N3_0_SHIFT                24
+#define ISPPRV_WBSEL_N3_1_SHIFT                26
+#define ISPPRV_WBSEL_N3_2_SHIFT                28
+#define ISPPRV_WBSEL_N3_3_SHIFT                30
+
+#define ISPPRV_CFA_GRADTH_HOR_SHIFT    0
+#define ISPPRV_CFA_GRADTH_VER_SHIFT    8
+
+#define ISPPRV_BLKADJOFF_B_SHIFT       0
+#define ISPPRV_BLKADJOFF_G_SHIFT       8
+#define ISPPRV_BLKADJOFF_R_SHIFT       16
+
+#define ISPPRV_RGB_MAT1_MTX_RR_SHIFT   0
+#define ISPPRV_RGB_MAT1_MTX_GR_SHIFT   16
+
+#define ISPPRV_RGB_MAT2_MTX_BR_SHIFT   0
+#define ISPPRV_RGB_MAT2_MTX_RG_SHIFT   16
+
+#define ISPPRV_RGB_MAT3_MTX_GG_SHIFT   0
+#define ISPPRV_RGB_MAT3_MTX_BG_SHIFT   16
+
+#define ISPPRV_RGB_MAT4_MTX_RB_SHIFT   0
+#define ISPPRV_RGB_MAT4_MTX_GB_SHIFT   16
+
+#define ISPPRV_RGB_MAT5_MTX_BB_SHIFT   0
+
+#define ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT 0
+#define ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT 16
+
+#define ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT 0
+
+#define ISPPRV_CSC0_RY_SHIFT           0
+#define ISPPRV_CSC0_GY_SHIFT           10
+#define ISPPRV_CSC0_BY_SHIFT           20
+
+#define ISPPRV_CSC1_RCB_SHIFT          0
+#define ISPPRV_CSC1_GCB_SHIFT          10
+#define ISPPRV_CSC1_BCB_SHIFT          20
+
+#define ISPPRV_CSC2_RCR_SHIFT          0
+#define ISPPRV_CSC2_GCR_SHIFT          10
+#define ISPPRV_CSC2_BCR_SHIFT          20
+
+#define ISPPRV_CSC_OFFSET_CR_SHIFT     0
+#define ISPPRV_CSC_OFFSET_CB_SHIFT     8
+#define ISPPRV_CSC_OFFSET_Y_SHIFT      16
+
+#define ISPPRV_CNT_BRT_BRT_SHIFT       0
+#define ISPPRV_CNT_BRT_CNT_SHIFT       8
+
+#define ISPPRV_CONTRAST_MAX            0x10
+#define ISPPRV_CONTRAST_MIN            0xFF
+#define ISPPRV_BRIGHT_MIN              0x00
+#define ISPPRV_BRIGHT_MAX              0xFF
+
+#define ISPPRV_CSUP_CSUPG_SHIFT                0
+#define ISPPRV_CSUP_THRES_SHIFT                8
+#define ISPPRV_CSUP_HPYF_SHIFT         16
+
+#define ISPPRV_SETUP_YC_MINC_SHIFT     0
+#define ISPPRV_SETUP_YC_MAXC_SHIFT     8
+#define ISPPRV_SETUP_YC_MINY_SHIFT     16
+#define ISPPRV_SETUP_YC_MAXY_SHIFT     24
+#define ISPPRV_YC_MAX                  0xFF
+#define ISPPRV_YC_MIN                  0x0
+
+/* Define bit fields within selected registers */
+#define ISP_REVISION_SHIFT                     0
+
+#define ISP_SYSCONFIG_AUTOIDLE                 (1 << 0)
+#define ISP_SYSCONFIG_SOFTRESET                        (1 << 1)
+#define ISP_SYSCONFIG_MIDLEMODE_SHIFT          12
+#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY   0x0
+#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY       0x1
+#define ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY   0x2
+
+#define ISP_SYSSTATUS_RESETDONE                        0
+
+#define IRQ0ENABLE_CSIA_IRQ                    (1 << 0)
+#define IRQ0ENABLE_CSIC_IRQ                    (1 << 1)
+#define IRQ0ENABLE_CCP2_LCM_IRQ                        (1 << 3)
+#define IRQ0ENABLE_CCP2_LC0_IRQ                        (1 << 4)
+#define IRQ0ENABLE_CCP2_LC1_IRQ                        (1 << 5)
+#define IRQ0ENABLE_CCP2_LC2_IRQ                        (1 << 6)
+#define IRQ0ENABLE_CCP2_LC3_IRQ                        (1 << 7)
+#define IRQ0ENABLE_CSIB_IRQ                    (IRQ0ENABLE_CCP2_LCM_IRQ | \
+                                               IRQ0ENABLE_CCP2_LC0_IRQ | \
+                                               IRQ0ENABLE_CCP2_LC1_IRQ | \
+                                               IRQ0ENABLE_CCP2_LC2_IRQ | \
+                                               IRQ0ENABLE_CCP2_LC3_IRQ)
+
+#define IRQ0ENABLE_CCDC_VD0_IRQ                        (1 << 8)
+#define IRQ0ENABLE_CCDC_VD1_IRQ                        (1 << 9)
+#define IRQ0ENABLE_CCDC_VD2_IRQ                        (1 << 10)
+#define IRQ0ENABLE_CCDC_ERR_IRQ                        (1 << 11)
+#define IRQ0ENABLE_H3A_AF_DONE_IRQ             (1 << 12)
+#define IRQ0ENABLE_H3A_AWB_DONE_IRQ            (1 << 13)
+#define IRQ0ENABLE_HIST_DONE_IRQ               (1 << 16)
+#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ           (1 << 17)
+#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ      (1 << 18)
+#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ       (1 << 19)
+#define IRQ0ENABLE_PRV_DONE_IRQ                        (1 << 20)
+#define IRQ0ENABLE_RSZ_DONE_IRQ                        (1 << 24)
+#define IRQ0ENABLE_OVF_IRQ                     (1 << 25)
+#define IRQ0ENABLE_PING_IRQ                    (1 << 26)
+#define IRQ0ENABLE_PONG_IRQ                    (1 << 27)
+#define IRQ0ENABLE_MMU_ERR_IRQ                 (1 << 28)
+#define IRQ0ENABLE_OCP_ERR_IRQ                 (1 << 29)
+#define IRQ0ENABLE_SEC_ERR_IRQ                 (1 << 30)
+#define IRQ0ENABLE_HS_VS_IRQ                   (1 << 31)
+
+#define IRQ0STATUS_CSIA_IRQ                    (1 << 0)
+#define IRQ0STATUS_CSI2C_IRQ                   (1 << 1)
+#define IRQ0STATUS_CCP2_LCM_IRQ                        (1 << 3)
+#define IRQ0STATUS_CCP2_LC0_IRQ                        (1 << 4)
+#define IRQ0STATUS_CSIB_IRQ                    (IRQ0STATUS_CCP2_LCM_IRQ | \
+                                               IRQ0STATUS_CCP2_LC0_IRQ)
+
+#define IRQ0STATUS_CSIB_LC1_IRQ                        (1 << 5)
+#define IRQ0STATUS_CSIB_LC2_IRQ                        (1 << 6)
+#define IRQ0STATUS_CSIB_LC3_IRQ                        (1 << 7)
+#define IRQ0STATUS_CCDC_VD0_IRQ                        (1 << 8)
+#define IRQ0STATUS_CCDC_VD1_IRQ                        (1 << 9)
+#define IRQ0STATUS_CCDC_VD2_IRQ                        (1 << 10)
+#define IRQ0STATUS_CCDC_ERR_IRQ                        (1 << 11)
+#define IRQ0STATUS_H3A_AF_DONE_IRQ             (1 << 12)
+#define IRQ0STATUS_H3A_AWB_DONE_IRQ            (1 << 13)
+#define IRQ0STATUS_HIST_DONE_IRQ               (1 << 16)
+#define IRQ0STATUS_CCDC_LSC_DONE_IRQ           (1 << 17)
+#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ      (1 << 18)
+#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ       (1 << 19)
+#define IRQ0STATUS_PRV_DONE_IRQ                        (1 << 20)
+#define IRQ0STATUS_RSZ_DONE_IRQ                        (1 << 24)
+#define IRQ0STATUS_OVF_IRQ                     (1 << 25)
+#define IRQ0STATUS_PING_IRQ                    (1 << 26)
+#define IRQ0STATUS_PONG_IRQ                    (1 << 27)
+#define IRQ0STATUS_MMU_ERR_IRQ                 (1 << 28)
+#define IRQ0STATUS_OCP_ERR_IRQ                 (1 << 29)
+#define IRQ0STATUS_SEC_ERR_IRQ                 (1 << 30)
+#define IRQ0STATUS_HS_VS_IRQ                   (1 << 31)
+
+#define TCTRL_GRESET_LEN                       0
+
+#define TCTRL_PSTRB_REPLAY_DELAY               0
+#define TCTRL_PSTRB_REPLAY_COUNTER_SHIFT       25
+
+#define ISPCTRL_PAR_SER_CLK_SEL_PARALLEL       0x0
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIA           0x1
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIB           0x2
+#define ISPCTRL_PAR_SER_CLK_SEL_CSIC           0x3
+#define ISPCTRL_PAR_SER_CLK_SEL_MASK           0x3
+
+#define ISPCTRL_PAR_BRIDGE_SHIFT               2
+#define ISPCTRL_PAR_BRIDGE_DISABLE             (0x0 << 2)
+#define ISPCTRL_PAR_BRIDGE_LENDIAN             (0x2 << 2)
+#define ISPCTRL_PAR_BRIDGE_BENDIAN             (0x3 << 2)
+#define ISPCTRL_PAR_BRIDGE_MASK                        (0x3 << 2)
+
+#define ISPCTRL_PAR_CLK_POL_SHIFT              4
+#define ISPCTRL_PAR_CLK_POL_INV                        (1 << 4)
+#define ISPCTRL_PING_PONG_EN                   (1 << 5)
+#define ISPCTRL_SHIFT_SHIFT                    6
+#define ISPCTRL_SHIFT_0                                (0x0 << 6)
+#define ISPCTRL_SHIFT_2                                (0x1 << 6)
+#define ISPCTRL_SHIFT_4                                (0x2 << 6)
+#define ISPCTRL_SHIFT_MASK                     (0x3 << 6)
+
+#define ISPCTRL_CCDC_CLK_EN                    (1 << 8)
+#define ISPCTRL_SCMP_CLK_EN                    (1 << 9)
+#define ISPCTRL_H3A_CLK_EN                     (1 << 10)
+#define ISPCTRL_HIST_CLK_EN                    (1 << 11)
+#define ISPCTRL_PREV_CLK_EN                    (1 << 12)
+#define ISPCTRL_RSZ_CLK_EN                     (1 << 13)
+#define ISPCTRL_SYNC_DETECT_SHIFT              14
+#define ISPCTRL_SYNC_DETECT_HSFALL     (0x0 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_HSRISE     (0x1 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_VSFALL     (0x2 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_VSRISE     (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
+#define ISPCTRL_SYNC_DETECT_MASK       (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
+
+#define ISPCTRL_CCDC_RAM_EN            (1 << 16)
+#define ISPCTRL_PREV_RAM_EN            (1 << 17)
+#define ISPCTRL_SBL_RD_RAM_EN          (1 << 18)
+#define ISPCTRL_SBL_WR1_RAM_EN         (1 << 19)
+#define ISPCTRL_SBL_WR0_RAM_EN         (1 << 20)
+#define ISPCTRL_SBL_AUTOIDLE           (1 << 21)
+#define ISPCTRL_SBL_SHARED_WPORTC      (1 << 26)
+#define ISPCTRL_SBL_SHARED_RPORTA      (1 << 27)
+#define ISPCTRL_SBL_SHARED_RPORTB      (1 << 28)
+#define ISPCTRL_JPEG_FLUSH             (1 << 30)
+#define ISPCTRL_CCDC_FLUSH             (1 << 31)
+
+#define ISPSECURE_SECUREMODE           0
+
+#define ISPTCTRL_CTRL_DIV_LOW          0x0
+#define ISPTCTRL_CTRL_DIV_HIGH         0x1
+#define ISPTCTRL_CTRL_DIV_BYPASS       0x1F
+
+#define ISPTCTRL_CTRL_DIVA_SHIFT       0
+#define ISPTCTRL_CTRL_DIVA_MASK                (0x1F << ISPTCTRL_CTRL_DIVA_SHIFT)
+
+#define ISPTCTRL_CTRL_DIVB_SHIFT       5
+#define ISPTCTRL_CTRL_DIVB_MASK                (0x1F << ISPTCTRL_CTRL_DIVB_SHIFT)
+
+#define ISPTCTRL_CTRL_DIVC_SHIFT       10
+#define ISPTCTRL_CTRL_DIVC_NOCLOCK     (0x0 << 10)
+
+#define ISPTCTRL_CTRL_SHUTEN           (1 << 21)
+#define ISPTCTRL_CTRL_PSTRBEN          (1 << 22)
+#define ISPTCTRL_CTRL_STRBEN           (1 << 23)
+#define ISPTCTRL_CTRL_SHUTPOL          (1 << 24)
+#define ISPTCTRL_CTRL_STRBPSTRBPOL     (1 << 26)
+
+#define ISPTCTRL_CTRL_INSEL_SHIFT      27
+#define ISPTCTRL_CTRL_INSEL_PARALLEL   (0x0 << 27)
+#define ISPTCTRL_CTRL_INSEL_CSIA       (0x1 << 27)
+#define ISPTCTRL_CTRL_INSEL_CSIB       (0x2 << 27)
+
+#define ISPTCTRL_CTRL_GRESETEn         (1 << 29)
+#define ISPTCTRL_CTRL_GRESETPOL                (1 << 30)
+#define ISPTCTRL_CTRL_GRESETDIR                (1 << 31)
+
+#define ISPTCTRL_FRAME_SHUT_SHIFT              0
+#define ISPTCTRL_FRAME_PSTRB_SHIFT             6
+#define ISPTCTRL_FRAME_STRB_SHIFT              12
+
+#define ISPCCDC_PID_PREV_SHIFT                 0
+#define ISPCCDC_PID_CID_SHIFT                  8
+#define ISPCCDC_PID_TID_SHIFT                  16
+
+#define ISPCCDC_PCR_EN                         1
+#define ISPCCDC_PCR_BUSY                       (1 << 1)
+
+#define ISPCCDC_SYN_MODE_VDHDOUT               0x1
+#define ISPCCDC_SYN_MODE_FLDOUT                        (1 << 1)
+#define ISPCCDC_SYN_MODE_VDPOL                 (1 << 2)
+#define ISPCCDC_SYN_MODE_HDPOL                 (1 << 3)
+#define ISPCCDC_SYN_MODE_FLDPOL                        (1 << 4)
+#define ISPCCDC_SYN_MODE_EXWEN                 (1 << 5)
+#define ISPCCDC_SYN_MODE_DATAPOL               (1 << 6)
+#define ISPCCDC_SYN_MODE_FLDMODE               (1 << 7)
+#define ISPCCDC_SYN_MODE_DATSIZ_MASK           (0x7 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_8_16           (0x0 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_12             (0x4 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_11             (0x5 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_10             (0x6 << 8)
+#define ISPCCDC_SYN_MODE_DATSIZ_8              (0x7 << 8)
+#define ISPCCDC_SYN_MODE_PACK8                 (1 << 11)
+#define ISPCCDC_SYN_MODE_INPMOD_MASK           (3 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_RAW            (0 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16                (1 << 12)
+#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8         (2 << 12)
+#define ISPCCDC_SYN_MODE_LPF                   (1 << 14)
+#define ISPCCDC_SYN_MODE_FLDSTAT               (1 << 15)
+#define ISPCCDC_SYN_MODE_VDHDEN                        (1 << 16)
+#define ISPCCDC_SYN_MODE_WEN                   (1 << 17)
+#define ISPCCDC_SYN_MODE_VP2SDR                        (1 << 18)
+#define ISPCCDC_SYN_MODE_SDR2RSZ               (1 << 19)
+
+#define ISPCCDC_HD_VD_WID_VDW_SHIFT            0
+#define ISPCCDC_HD_VD_WID_HDW_SHIFT            16
+
+#define ISPCCDC_PIX_LINES_HLPRF_SHIFT          0
+#define ISPCCDC_PIX_LINES_PPLN_SHIFT           16
+
+#define ISPCCDC_HORZ_INFO_NPH_SHIFT            0
+#define ISPCCDC_HORZ_INFO_NPH_MASK             0x00007fff
+#define ISPCCDC_HORZ_INFO_SPH_SHIFT            16
+#define ISPCCDC_HORZ_INFO_SPH_MASK             0x7fff0000
+
+#define ISPCCDC_VERT_START_SLV1_SHIFT          0
+#define ISPCCDC_VERT_START_SLV0_SHIFT          16
+#define ISPCCDC_VERT_START_SLV0_MASK           0x7fff0000
+
+#define ISPCCDC_VERT_LINES_NLV_SHIFT           0
+#define ISPCCDC_VERT_LINES_NLV_MASK            0x00007fff
+
+#define ISPCCDC_CULLING_CULV_SHIFT             0
+#define ISPCCDC_CULLING_CULHODD_SHIFT          16
+#define ISPCCDC_CULLING_CULHEVN_SHIFT          24
+
+#define ISPCCDC_HSIZE_OFF_SHIFT                        0
+
+#define ISPCCDC_SDOFST_FINV                    (1 << 14)
+#define ISPCCDC_SDOFST_FOFST_1L                        0
+#define ISPCCDC_SDOFST_FOFST_4L                        (3 << 12)
+#define ISPCCDC_SDOFST_LOFST3_SHIFT            0
+#define ISPCCDC_SDOFST_LOFST2_SHIFT            3
+#define ISPCCDC_SDOFST_LOFST1_SHIFT            6
+#define ISPCCDC_SDOFST_LOFST0_SHIFT            9
+#define EVENEVEN                               1
+#define ODDEVEN                                        2
+#define EVENODD                                        3
+#define ODDODD                                 4
+
+#define ISPCCDC_CLAMP_OBGAIN_SHIFT             0
+#define ISPCCDC_CLAMP_OBST_SHIFT               10
+#define ISPCCDC_CLAMP_OBSLN_SHIFT              25
+#define ISPCCDC_CLAMP_OBSLEN_SHIFT             28
+#define ISPCCDC_CLAMP_CLAMPEN                  (1 << 31)
+
+#define ISPCCDC_COLPTN_R_Ye                    0x0
+#define ISPCCDC_COLPTN_Gr_Cy                   0x1
+#define ISPCCDC_COLPTN_Gb_G                    0x2
+#define ISPCCDC_COLPTN_B_Mg                    0x3
+#define ISPCCDC_COLPTN_CP0PLC0_SHIFT           0
+#define ISPCCDC_COLPTN_CP0PLC1_SHIFT           2
+#define ISPCCDC_COLPTN_CP0PLC2_SHIFT           4
+#define ISPCCDC_COLPTN_CP0PLC3_SHIFT           6
+#define ISPCCDC_COLPTN_CP1PLC0_SHIFT           8
+#define ISPCCDC_COLPTN_CP1PLC1_SHIFT           10
+#define ISPCCDC_COLPTN_CP1PLC2_SHIFT           12
+#define ISPCCDC_COLPTN_CP1PLC3_SHIFT           14
+#define ISPCCDC_COLPTN_CP2PLC0_SHIFT           16
+#define ISPCCDC_COLPTN_CP2PLC1_SHIFT           18
+#define ISPCCDC_COLPTN_CP2PLC2_SHIFT           20
+#define ISPCCDC_COLPTN_CP2PLC3_SHIFT           22
+#define ISPCCDC_COLPTN_CP3PLC0_SHIFT           24
+#define ISPCCDC_COLPTN_CP3PLC1_SHIFT           26
+#define ISPCCDC_COLPTN_CP3PLC2_SHIFT           28
+#define ISPCCDC_COLPTN_CP3PLC3_SHIFT           30
+
+#define ISPCCDC_BLKCMP_B_MG_SHIFT              0
+#define ISPCCDC_BLKCMP_GB_G_SHIFT              8
+#define ISPCCDC_BLKCMP_GR_CY_SHIFT             16
+#define ISPCCDC_BLKCMP_R_YE_SHIFT              24
+
+#define ISPCCDC_FPC_FPNUM_SHIFT                        0
+#define ISPCCDC_FPC_FPCEN                      (1 << 15)
+#define ISPCCDC_FPC_FPERR                      (1 << 16)
+
+#define ISPCCDC_VDINT_1_SHIFT                  0
+#define ISPCCDC_VDINT_1_MASK                   0x00007fff
+#define ISPCCDC_VDINT_0_SHIFT                  16
+#define ISPCCDC_VDINT_0_MASK                   0x7fff0000
+
+#define ISPCCDC_ALAW_GWDI_12_3                 (0x3 << 0)
+#define ISPCCDC_ALAW_GWDI_11_2                 (0x4 << 0)
+#define ISPCCDC_ALAW_GWDI_10_1                 (0x5 << 0)
+#define ISPCCDC_ALAW_GWDI_9_0                  (0x6 << 0)
+#define ISPCCDC_ALAW_CCDTBL                    (1 << 3)
+
+#define ISPCCDC_REC656IF_R656ON                        1
+#define ISPCCDC_REC656IF_ECCFVH                        (1 << 1)
+
+#define ISPCCDC_CFG_BW656                      (1 << 5)
+#define ISPCCDC_CFG_FIDMD_SHIFT                        6
+#define ISPCCDC_CFG_WENLOG                     (1 << 8)
+#define ISPCCDC_CFG_WENLOG_AND                 (0 << 8)
+#define ISPCCDC_CFG_WENLOG_OR                  (1 << 8)
+#define ISPCCDC_CFG_Y8POS                      (1 << 11)
+#define ISPCCDC_CFG_BSWD                       (1 << 12)
+#define ISPCCDC_CFG_MSBINVI                    (1 << 13)
+#define ISPCCDC_CFG_VDLC                       (1 << 15)
+
+#define ISPCCDC_FMTCFG_FMTEN                   0x1
+#define ISPCCDC_FMTCFG_LNALT                   (1 << 1)
+#define ISPCCDC_FMTCFG_LNUM_SHIFT              2
+#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT          4
+#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT         8
+#define ISPCCDC_FMTCFG_VPIN_MASK               0x00007000
+#define ISPCCDC_FMTCFG_VPIN_12_3               (0x3 << 12)
+#define ISPCCDC_FMTCFG_VPIN_11_2               (0x4 << 12)
+#define ISPCCDC_FMTCFG_VPIN_10_1               (0x5 << 12)
+#define ISPCCDC_FMTCFG_VPIN_9_0                        (0x6 << 12)
+#define ISPCCDC_FMTCFG_VPEN                    (1 << 15)
+
+#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK           0x003f0000
+#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT          16
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2            (0x0 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3            (0x1 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4            (0x2 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5            (0x3 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6            (0x4 << 16)
+
+#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT          0
+#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT          16
+
+#define ISPCCDC_FMT_VERT_FMTLNV_SHIFT          0
+#define ISPCCDC_FMT_VERT_FMTSLV_SHIFT          16
+
+#define ISPCCDC_FMT_HORZ_FMTSPH_MASK           0x1fff0000
+#define ISPCCDC_FMT_HORZ_FMTLNH_MASK           0x00001fff
+
+#define ISPCCDC_FMT_VERT_FMTSLV_MASK           0x1fff0000
+#define ISPCCDC_FMT_VERT_FMTLNV_MASK           0x00001fff
+
+#define ISPCCDC_VP_OUT_HORZ_ST_SHIFT           0
+#define ISPCCDC_VP_OUT_HORZ_NUM_SHIFT          4
+#define ISPCCDC_VP_OUT_VERT_NUM_SHIFT          17
+
+#define ISPRSZ_PID_PREV_SHIFT                  0
+#define ISPRSZ_PID_CID_SHIFT                   8
+#define ISPRSZ_PID_TID_SHIFT                   16
+
+#define ISPRSZ_PCR_ENABLE                      (1 << 0)
+#define ISPRSZ_PCR_BUSY                                (1 << 1)
+#define ISPRSZ_PCR_ONESHOT                     (1 << 2)
+
+#define ISPRSZ_CNT_HRSZ_SHIFT                  0
+#define ISPRSZ_CNT_HRSZ_MASK                   \
+       (0x3FF << ISPRSZ_CNT_HRSZ_SHIFT)
+#define ISPRSZ_CNT_VRSZ_SHIFT                  10
+#define ISPRSZ_CNT_VRSZ_MASK                   \
+       (0x3FF << ISPRSZ_CNT_VRSZ_SHIFT)
+#define ISPRSZ_CNT_HSTPH_SHIFT                 20
+#define ISPRSZ_CNT_HSTPH_MASK                  (0x7 << ISPRSZ_CNT_HSTPH_SHIFT)
+#define ISPRSZ_CNT_VSTPH_SHIFT                 23
+#define ISPRSZ_CNT_VSTPH_MASK                  (0x7 << ISPRSZ_CNT_VSTPH_SHIFT)
+#define ISPRSZ_CNT_YCPOS                       (1 << 26)
+#define ISPRSZ_CNT_INPTYP                      (1 << 27)
+#define ISPRSZ_CNT_INPSRC                      (1 << 28)
+#define ISPRSZ_CNT_CBILIN                      (1 << 29)
+
+#define ISPRSZ_OUT_SIZE_HORZ_SHIFT             0
+#define ISPRSZ_OUT_SIZE_HORZ_MASK              \
+       (0xFFF << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
+#define ISPRSZ_OUT_SIZE_VERT_SHIFT             16
+#define ISPRSZ_OUT_SIZE_VERT_MASK              \
+       (0xFFF << ISPRSZ_OUT_SIZE_VERT_SHIFT)
+
+#define ISPRSZ_IN_START_HORZ_ST_SHIFT          0
+#define ISPRSZ_IN_START_HORZ_ST_MASK           \
+       (0x1FFF << ISPRSZ_IN_START_HORZ_ST_SHIFT)
+#define ISPRSZ_IN_START_VERT_ST_SHIFT          16
+#define ISPRSZ_IN_START_VERT_ST_MASK           \
+       (0x1FFF << ISPRSZ_IN_START_VERT_ST_SHIFT)
+
+#define ISPRSZ_IN_SIZE_HORZ_SHIFT              0
+#define ISPRSZ_IN_SIZE_HORZ_MASK               \
+       (0x1FFF << ISPRSZ_IN_SIZE_HORZ_SHIFT)
+#define ISPRSZ_IN_SIZE_VERT_SHIFT              16
+#define ISPRSZ_IN_SIZE_VERT_MASK               \
+       (0x1FFF << ISPRSZ_IN_SIZE_VERT_SHIFT)
+
+#define ISPRSZ_SDR_INADD_ADDR_SHIFT            0
+#define ISPRSZ_SDR_INADD_ADDR_MASK             0xFFFFFFFF
+
+#define ISPRSZ_SDR_INOFF_OFFSET_SHIFT          0
+#define ISPRSZ_SDR_INOFF_OFFSET_MASK           \
+       (0xFFFF << ISPRSZ_SDR_INOFF_OFFSET_SHIFT)
+
+#define ISPRSZ_SDR_OUTADD_ADDR_SHIFT           0
+#define ISPRSZ_SDR_OUTADD_ADDR_MASK            0xFFFFFFFF
+
+
+#define ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT         0
+#define ISPRSZ_SDR_OUTOFF_OFFSET_MASK          \
+       (0xFFFF << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT)
+
+#define ISPRSZ_HFILT_COEF0_SHIFT               0
+#define ISPRSZ_HFILT_COEF0_MASK                        \
+       (0x3FF << ISPRSZ_HFILT_COEF0_SHIFT)
+#define ISPRSZ_HFILT_COEF1_SHIFT               16
+#define ISPRSZ_HFILT_COEF1_MASK                        \
+       (0x3FF << ISPRSZ_HFILT_COEF1_SHIFT)
+
+#define ISPRSZ_HFILT32_COEF2_SHIFT             0
+#define ISPRSZ_HFILT32_COEF2_MASK              0x3FF
+#define ISPRSZ_HFILT32_COEF3_SHIFT             16
+#define ISPRSZ_HFILT32_COEF3_MASK              0x3FF0000
+
+#define ISPRSZ_HFILT54_COEF4_SHIFT             0
+#define ISPRSZ_HFILT54_COEF4_MASK              0x3FF
+#define ISPRSZ_HFILT54_COEF5_SHIFT             16
+#define ISPRSZ_HFILT54_COEF5_MASK              0x3FF0000
+
+#define ISPRSZ_HFILT76_COEFF6_SHIFT            0
+#define ISPRSZ_HFILT76_COEFF6_MASK             0x3FF
+#define ISPRSZ_HFILT76_COEFF7_SHIFT            16
+#define ISPRSZ_HFILT76_COEFF7_MASK             0x3FF0000
+
+#define ISPRSZ_HFILT98_COEFF8_SHIFT            0
+#define ISPRSZ_HFILT98_COEFF8_MASK             0x3FF
+#define ISPRSZ_HFILT98_COEFF9_SHIFT            16
+#define ISPRSZ_HFILT98_COEFF9_MASK             0x3FF0000
+
+#define ISPRSZ_HFILT1110_COEF10_SHIFT          0
+#define ISPRSZ_HFILT1110_COEF10_MASK           0x3FF
+#define ISPRSZ_HFILT1110_COEF11_SHIFT          16
+#define ISPRSZ_HFILT1110_COEF11_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT1312_COEFF12_SHIFT         0
+#define ISPRSZ_HFILT1312_COEFF12_MASK          0x3FF
+#define ISPRSZ_HFILT1312_COEFF13_SHIFT         16
+#define ISPRSZ_HFILT1312_COEFF13_MASK          0x3FF0000
+
+#define ISPRSZ_HFILT1514_COEFF14_SHIFT         0
+#define ISPRSZ_HFILT1514_COEFF14_MASK          0x3FF
+#define ISPRSZ_HFILT1514_COEFF15_SHIFT         16
+#define ISPRSZ_HFILT1514_COEFF15_MASK          0x3FF0000
+
+#define ISPRSZ_HFILT1716_COEF16_SHIFT          0
+#define ISPRSZ_HFILT1716_COEF16_MASK           0x3FF
+#define ISPRSZ_HFILT1716_COEF17_SHIFT          16
+#define ISPRSZ_HFILT1716_COEF17_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT1918_COEF18_SHIFT          0
+#define ISPRSZ_HFILT1918_COEF18_MASK           0x3FF
+#define ISPRSZ_HFILT1918_COEF19_SHIFT          16
+#define ISPRSZ_HFILT1918_COEF19_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT2120_COEF20_SHIFT          0
+#define ISPRSZ_HFILT2120_COEF20_MASK           0x3FF
+#define ISPRSZ_HFILT2120_COEF21_SHIFT          16
+#define ISPRSZ_HFILT2120_COEF21_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT2322_COEF22_SHIFT          0
+#define ISPRSZ_HFILT2322_COEF22_MASK           0x3FF
+#define ISPRSZ_HFILT2322_COEF23_SHIFT          16
+#define ISPRSZ_HFILT2322_COEF23_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT2524_COEF24_SHIFT          0
+#define ISPRSZ_HFILT2524_COEF24_MASK           0x3FF
+#define ISPRSZ_HFILT2524_COEF25_SHIFT          16
+#define ISPRSZ_HFILT2524_COEF25_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT2726_COEF26_SHIFT          0
+#define ISPRSZ_HFILT2726_COEF26_MASK           0x3FF
+#define ISPRSZ_HFILT2726_COEF27_SHIFT          16
+#define ISPRSZ_HFILT2726_COEF27_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT2928_COEF28_SHIFT          0
+#define ISPRSZ_HFILT2928_COEF28_MASK           0x3FF
+#define ISPRSZ_HFILT2928_COEF29_SHIFT          16
+#define ISPRSZ_HFILT2928_COEF29_MASK           0x3FF0000
+
+#define ISPRSZ_HFILT3130_COEF30_SHIFT          0
+#define ISPRSZ_HFILT3130_COEF30_MASK           0x3FF
+#define ISPRSZ_HFILT3130_COEF31_SHIFT          16
+#define ISPRSZ_HFILT3130_COEF31_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT_COEF0_SHIFT               0
+#define ISPRSZ_VFILT_COEF0_MASK                        \
+       (0x3FF << ISPRSZ_VFILT_COEF0_SHIFT)
+#define ISPRSZ_VFILT_COEF1_SHIFT               16
+#define ISPRSZ_VFILT_COEF1_MASK                        \
+       (0x3FF << ISPRSZ_VFILT_COEF1_SHIFT)
+
+#define ISPRSZ_VFILT10_COEF0_SHIFT             0
+#define ISPRSZ_VFILT10_COEF0_MASK              0x3FF
+#define ISPRSZ_VFILT10_COEF1_SHIFT             16
+#define ISPRSZ_VFILT10_COEF1_MASK              0x3FF0000
+
+#define ISPRSZ_VFILT32_COEF2_SHIFT             0
+#define ISPRSZ_VFILT32_COEF2_MASK              0x3FF
+#define ISPRSZ_VFILT32_COEF3_SHIFT             16
+#define ISPRSZ_VFILT32_COEF3_MASK              0x3FF0000
+
+#define ISPRSZ_VFILT54_COEF4_SHIFT             0
+#define ISPRSZ_VFILT54_COEF4_MASK              0x3FF
+#define ISPRSZ_VFILT54_COEF5_SHIFT             16
+#define ISPRSZ_VFILT54_COEF5_MASK              0x3FF0000
+
+#define ISPRSZ_VFILT76_COEFF6_SHIFT            0
+#define ISPRSZ_VFILT76_COEFF6_MASK             0x3FF
+#define ISPRSZ_VFILT76_COEFF7_SHIFT            16
+#define ISPRSZ_VFILT76_COEFF7_MASK             0x3FF0000
+
+#define ISPRSZ_VFILT98_COEFF8_SHIFT            0
+#define ISPRSZ_VFILT98_COEFF8_MASK             0x3FF
+#define ISPRSZ_VFILT98_COEFF9_SHIFT            16
+#define ISPRSZ_VFILT98_COEFF9_MASK             0x3FF0000
+
+#define ISPRSZ_VFILT1110_COEF10_SHIFT          0
+#define ISPRSZ_VFILT1110_COEF10_MASK           0x3FF
+#define ISPRSZ_VFILT1110_COEF11_SHIFT          16
+#define ISPRSZ_VFILT1110_COEF11_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT1312_COEFF12_SHIFT         0
+#define ISPRSZ_VFILT1312_COEFF12_MASK          0x3FF
+#define ISPRSZ_VFILT1312_COEFF13_SHIFT         16
+#define ISPRSZ_VFILT1312_COEFF13_MASK          0x3FF0000
+
+#define ISPRSZ_VFILT1514_COEFF14_SHIFT         0
+#define ISPRSZ_VFILT1514_COEFF14_MASK          0x3FF
+#define ISPRSZ_VFILT1514_COEFF15_SHIFT         16
+#define ISPRSZ_VFILT1514_COEFF15_MASK          0x3FF0000
+
+#define ISPRSZ_VFILT1716_COEF16_SHIFT          0
+#define ISPRSZ_VFILT1716_COEF16_MASK           0x3FF
+#define ISPRSZ_VFILT1716_COEF17_SHIFT          16
+#define ISPRSZ_VFILT1716_COEF17_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT1918_COEF18_SHIFT          0
+#define ISPRSZ_VFILT1918_COEF18_MASK           0x3FF
+#define ISPRSZ_VFILT1918_COEF19_SHIFT          16
+#define ISPRSZ_VFILT1918_COEF19_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT2120_COEF20_SHIFT          0
+#define ISPRSZ_VFILT2120_COEF20_MASK           0x3FF
+#define ISPRSZ_VFILT2120_COEF21_SHIFT          16
+#define ISPRSZ_VFILT2120_COEF21_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT2322_COEF22_SHIFT          0
+#define ISPRSZ_VFILT2322_COEF22_MASK           0x3FF
+#define ISPRSZ_VFILT2322_COEF23_SHIFT          16
+#define ISPRSZ_VFILT2322_COEF23_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT2524_COEF24_SHIFT          0
+#define ISPRSZ_VFILT2524_COEF24_MASK           0x3FF
+#define ISPRSZ_VFILT2524_COEF25_SHIFT          16
+#define ISPRSZ_VFILT2524_COEF25_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT2726_COEF26_SHIFT          0
+#define ISPRSZ_VFILT2726_COEF26_MASK           0x3FF
+#define ISPRSZ_VFILT2726_COEF27_SHIFT          16
+#define ISPRSZ_VFILT2726_COEF27_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT2928_COEF28_SHIFT          0
+#define ISPRSZ_VFILT2928_COEF28_MASK           0x3FF
+#define ISPRSZ_VFILT2928_COEF29_SHIFT          16
+#define ISPRSZ_VFILT2928_COEF29_MASK           0x3FF0000
+
+#define ISPRSZ_VFILT3130_COEF30_SHIFT          0
+#define ISPRSZ_VFILT3130_COEF30_MASK           0x3FF
+#define ISPRSZ_VFILT3130_COEF31_SHIFT          16
+#define ISPRSZ_VFILT3130_COEF31_MASK           0x3FF0000
+
+#define ISPRSZ_YENH_CORE_SHIFT                 0
+#define ISPRSZ_YENH_CORE_MASK                  \
+       (0xFF << ISPRSZ_YENH_CORE_SHIFT)
+#define ISPRSZ_YENH_SLOP_SHIFT                 8
+#define ISPRSZ_YENH_SLOP_MASK                  \
+       (0xF << ISPRSZ_YENH_SLOP_SHIFT)
+#define ISPRSZ_YENH_GAIN_SHIFT                 12
+#define ISPRSZ_YENH_GAIN_MASK                  \
+       (0xF << ISPRSZ_YENH_GAIN_SHIFT)
+#define ISPRSZ_YENH_ALGO_SHIFT                 16
+#define ISPRSZ_YENH_ALGO_MASK                  \
+       (0x3 << ISPRSZ_YENH_ALGO_SHIFT)
+
+#define ISPH3A_PCR_AEW_ALAW_EN_SHIFT           1
+#define ISPH3A_PCR_AF_MED_TH_SHIFT             3
+#define ISPH3A_PCR_AF_RGBPOS_SHIFT             11
+#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT           22
+#define ISPH3A_PCR_AEW_AVE2LMT_MASK            0xFFC00000
+#define ISPH3A_PCR_BUSYAF                      (1 << 15)
+#define ISPH3A_PCR_BUSYAEAWB                   (1 << 18)
+
+#define ISPH3A_AEWWIN1_WINHC_SHIFT             0
+#define ISPH3A_AEWWIN1_WINHC_MASK              0x3F
+#define ISPH3A_AEWWIN1_WINVC_SHIFT             6
+#define ISPH3A_AEWWIN1_WINVC_MASK              0x1FC0
+#define ISPH3A_AEWWIN1_WINW_SHIFT              13
+#define ISPH3A_AEWWIN1_WINW_MASK               0xFE000
+#define ISPH3A_AEWWIN1_WINH_SHIFT              24
+#define ISPH3A_AEWWIN1_WINH_MASK               0x7F000000
+
+#define ISPH3A_AEWINSTART_WINSH_SHIFT          0
+#define ISPH3A_AEWINSTART_WINSH_MASK           0x0FFF
+#define ISPH3A_AEWINSTART_WINSV_SHIFT          16
+#define ISPH3A_AEWINSTART_WINSV_MASK           0x0FFF0000
+
+#define ISPH3A_AEWINBLK_WINH_SHIFT             0
+#define ISPH3A_AEWINBLK_WINH_MASK              0x7F
+#define ISPH3A_AEWINBLK_WINSV_SHIFT            16
+#define ISPH3A_AEWINBLK_WINSV_MASK             0x0FFF0000
+
+#define ISPH3A_AEWSUBWIN_AEWINCH_SHIFT         0
+#define ISPH3A_AEWSUBWIN_AEWINCH_MASK          0x0F
+#define ISPH3A_AEWSUBWIN_AEWINCV_SHIFT         8
+#define ISPH3A_AEWSUBWIN_AEWINCV_MASK          0x0F00
+
+#define ISPHIST_PCR_ENABLE_SHIFT       0
+#define ISPHIST_PCR_ENABLE_MASK                0x01
+#define ISPHIST_PCR_ENABLE             (1 << ISPHIST_PCR_ENABLE_SHIFT)
+#define ISPHIST_PCR_BUSY               0x02
+
+#define ISPHIST_CNT_DATASIZE_SHIFT     8
+#define ISPHIST_CNT_DATASIZE_MASK      0x0100
+#define ISPHIST_CNT_CLEAR_SHIFT                7
+#define ISPHIST_CNT_CLEAR_MASK         0x080
+#define ISPHIST_CNT_CLEAR              (1 << ISPHIST_CNT_CLEAR_SHIFT)
+#define ISPHIST_CNT_CFA_SHIFT          6
+#define ISPHIST_CNT_CFA_MASK           0x040
+#define ISPHIST_CNT_BINS_SHIFT         4
+#define ISPHIST_CNT_BINS_MASK          0x030
+#define ISPHIST_CNT_SOURCE_SHIFT       3
+#define ISPHIST_CNT_SOURCE_MASK                0x08
+#define ISPHIST_CNT_SHIFT_SHIFT                0
+#define ISPHIST_CNT_SHIFT_MASK         0x07
+
+#define ISPHIST_WB_GAIN_WG00_SHIFT     24
+#define ISPHIST_WB_GAIN_WG00_MASK      0xFF000000
+#define ISPHIST_WB_GAIN_WG01_SHIFT     16
+#define ISPHIST_WB_GAIN_WG01_MASK      0xFF0000
+#define ISPHIST_WB_GAIN_WG02_SHIFT     8
+#define ISPHIST_WB_GAIN_WG02_MASK      0xFF00
+#define ISPHIST_WB_GAIN_WG03_SHIFT     0
+#define ISPHIST_WB_GAIN_WG03_MASK      0xFF
+
+#define ISPHIST_REG_START_END_MASK             0x3FFF
+#define ISPHIST_REG_START_SHIFT                        16
+#define ISPHIST_REG_END_SHIFT                  0
+#define ISPHIST_REG_START_MASK                 (ISPHIST_REG_START_END_MASK << \
+                                                ISPHIST_REG_START_SHIFT)
+#define ISPHIST_REG_END_MASK                   (ISPHIST_REG_START_END_MASK << \
+                                                ISPHIST_REG_END_SHIFT)
+
+#define ISPHIST_REG_MASK                       (ISPHIST_REG_START_MASK | \
+                                                ISPHIST_REG_END_MASK)
+
+#define ISPHIST_ADDR_SHIFT                     0
+#define ISPHIST_ADDR_MASK                      0x3FF
+
+#define ISPHIST_DATA_SHIFT                     0
+#define ISPHIST_DATA_MASK                      0xFFFFF
+
+#define ISPHIST_RADD_SHIFT                     0
+#define ISPHIST_RADD_MASK                      0xFFFFFFFF
+
+#define ISPHIST_RADD_OFF_SHIFT                 0
+#define ISPHIST_RADD_OFF_MASK                  0xFFFF
+
+#define ISPHIST_HV_INFO_HSIZE_SHIFT            16
+#define ISPHIST_HV_INFO_HSIZE_MASK             0x3FFF0000
+#define ISPHIST_HV_INFO_VSIZE_SHIFT            0
+#define ISPHIST_HV_INFO_VSIZE_MASK             0x3FFF
+
+#define ISPHIST_HV_INFO_MASK                   0x3FFF3FFF
+
+#define ISPCCDC_LSC_ENABLE                     1
+#define ISPCCDC_LSC_BUSY                       (1 << 7)
+#define ISPCCDC_LSC_GAIN_MODE_N_MASK           0x700
+#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT          8
+#define ISPCCDC_LSC_GAIN_MODE_M_MASK           0x3800
+#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT          12
+#define ISPCCDC_LSC_GAIN_FORMAT_MASK           0xE
+#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT          1
+#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK     (1<<6)
+
+#define ISPCCDC_LSC_INITIAL_X_MASK             0x3F
+#define ISPCCDC_LSC_INITIAL_X_SHIFT            0
+#define ISPCCDC_LSC_INITIAL_Y_MASK             0x3F0000
+#define ISPCCDC_LSC_INITIAL_Y_SHIFT            16
+
+/* -----------------------------------------------------------------------------
+ * CSI2 receiver registers (ES2.0)
+ */
+
+#define ISPCSI2_REVISION                       (0x000)
+#define ISPCSI2_SYSCONFIG                      (0x010)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT  12
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK   \
+       (0x3 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_FORCE  \
+       (0x0 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO     \
+       (0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART  \
+       (0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
+#define ISPCSI2_SYSCONFIG_SOFT_RESET           (1 << 1)
+#define ISPCSI2_SYSCONFIG_AUTO_IDLE            (1 << 0)
+
+#define ISPCSI2_SYSSTATUS                      (0x014)
+#define ISPCSI2_SYSSTATUS_RESET_DONE           (1 << 0)
+
+#define ISPCSI2_IRQSTATUS                      (0x018)
+#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ          (1 << 14)
+#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ     (1 << 13)
+#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ   (1 << 12)
+#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ        (1 << 11)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ   (1 << 10)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ   (1 << 9)
+#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ         (1 << 8)
+#define ISPCSI2_IRQSTATUS_CONTEXT(n)           (1 << (n))
+
+#define ISPCSI2_IRQENABLE                      (0x01c)
+#define ISPCSI2_CTRL                           (0x040)
+#define ISPCSI2_CTRL_VP_CLK_EN                 (1 << 15)
+#define ISPCSI2_CTRL_VP_ONLY_EN                        (1 << 11)
+#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT         8
+#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK          \
+       (3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT)
+#define ISPCSI2_CTRL_DBG_EN                    (1 << 7)
+#define ISPCSI2_CTRL_BURST_SIZE_SHIFT          5
+#define ISPCSI2_CTRL_BURST_SIZE_MASK           \
+       (3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT)
+#define ISPCSI2_CTRL_FRAME                     (1 << 3)
+#define ISPCSI2_CTRL_ECC_EN                    (1 << 2)
+#define ISPCSI2_CTRL_SECURE                    (1 << 1)
+#define ISPCSI2_CTRL_IF_EN                     (1 << 0)
+
+#define ISPCSI2_DBG_H                          (0x044)
+#define ISPCSI2_GNQ                            (0x048)
+#define ISPCSI2_PHY_CFG                                (0x050)
+#define ISPCSI2_PHY_CFG_RESET_CTRL             (1 << 30)
+#define ISPCSI2_PHY_CFG_RESET_DONE             (1 << 29)
+#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT          27
+#define ISPCSI2_PHY_CFG_PWR_CMD_MASK           \
+       (0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_OFF            \
+       (0x0 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_ON             \
+       (0x1 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_CMD_ULPW           \
+       (0x2 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT       25
+#define ISPCSI2_PHY_CFG_PWR_STATUS_MASK                \
+       (0x3 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_OFF         \
+       (0x0 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_ON          \
+       (0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW                \
+       (0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
+#define ISPCSI2_PHY_CFG_PWR_AUTO               (1 << 24)
+
+#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)      (3 + ((n) * 4))
+#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n)       \
+       (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POL_PN(n)         \
+       (0x0 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POL_NP(n)         \
+       (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
+
+#define ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n) ((n) * 4)
+#define ISPCSI2_PHY_CFG_DATA_POSITION_MASK(n)  \
+       (0x7 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_NC(n)    \
+       (0x0 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_1(n)     \
+       (0x1 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_2(n)     \
+       (0x2 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_3(n)     \
+       (0x3 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_4(n)     \
+       (0x4 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+#define ISPCSI2_PHY_CFG_DATA_POSITION_5(n)     \
+       (0x5 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
+
+#define ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT                3
+#define ISPCSI2_PHY_CFG_CLOCK_POL_MASK         \
+       (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POL_PN           \
+       (0x0 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POL_NP           \
+       (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
+
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT   0
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK    \
+       (0x7 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_1       \
+       (0x1 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_2       \
+       (0x2 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_3       \
+       (0x3 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_4       \
+       (0x4 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+#define ISPCSI2_PHY_CFG_CLOCK_POSITION_5       \
+       (0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
+
+#define ISPCSI2_PHY_IRQSTATUS                  (0x054)
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26)
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER        (1 << 25)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5       (1 << 24)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4       (1 << 23)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3       (1 << 22)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2       (1 << 21)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1       (1 << 20)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5      (1 << 19)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4      (1 << 18)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3      (1 << 17)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2      (1 << 16)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1      (1 << 15)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC5          (1 << 14)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC4          (1 << 13)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC3          (1 << 12)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC2          (1 << 11)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC1          (1 << 10)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5    (1 << 9)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4    (1 << 8)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3    (1 << 7)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2    (1 << 6)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1    (1 << 5)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5                (1 << 4)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4                (1 << 3)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3                (1 << 2)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2                (1 << 1)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1                1
+
+#define ISPCSI2_SHORT_PACKET                   (0x05c)
+#define ISPCSI2_PHY_IRQENABLE                  (0x060)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER        (1 << 25)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM5       (1 << 24)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM4       (1 << 23)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM3       (1 << 22)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM2       (1 << 21)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM1       (1 << 20)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5      (1 << 19)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4      (1 << 18)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3      (1 << 17)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2      (1 << 16)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1      (1 << 15)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC5          (1 << 14)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC4          (1 << 13)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC3          (1 << 12)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC2          (1 << 11)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC1          (1 << 10)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5    (1 << 9)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4    (1 << 8)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3    (1 << 7)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2    (1 << 6)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1    (1 << 5)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5                (1 << 4)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4                (1 << 3)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3                (1 << 2)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2                (1 << 1)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1                (1 << 0)
+
+#define ISPCSI2_DBG_P                          (0x068)
+#define ISPCSI2_TIMING                         (0x06c)
+#define ISPCSI2_TIMING_FORCE_RX_MODE_IO(n)     (1 << ((16 * ((n) - 1)) + 15))
+#define ISPCSI2_TIMING_STOP_STATE_X16_IO(n)    (1 << ((16 * ((n) - 1)) + 14))
+#define ISPCSI2_TIMING_STOP_STATE_X4_IO(n)     (1 << ((16 * ((n) - 1)) + 13))
+#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n)  (16 * ((n) - 1))
+#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(n)   \
+       (0x1fff << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n))
+
+#define ISPCSI2_CTX_CTRL1(n)                   ((0x070) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT          8
+#define ISPCSI2_CTX_CTRL1_COUNT_MASK           \
+       (0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
+#define ISPCSI2_CTX_CTRL1_EOF_EN               (1 << 7)
+#define ISPCSI2_CTX_CTRL1_EOL_EN               (1 << 6)
+#define ISPCSI2_CTX_CTRL1_CS_EN                        (1 << 5)
+#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK         (1 << 4)
+#define ISPCSI2_CTX_CTRL1_PING_PONG            (1 << 3)
+#define ISPCSI2_CTX_CTRL1_CTX_EN               (1 << 0)
+
+#define ISPCSI2_CTX_CTRL2(n)                   ((0x074) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT   13
+#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK    \
+       (0x3 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT)
+#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT     11
+#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK      \
+       (0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT)
+#define ISPCSI2_CTX_CTRL2_DPCM_PRED            (1 << 10)
+#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT         0
+#define ISPCSI2_CTX_CTRL2_FORMAT_MASK          \
+       (0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT)
+#define ISPCSI2_CTX_CTRL2_FRAME_SHIFT          16
+#define ISPCSI2_CTX_CTRL2_FRAME_MASK           \
+       (0xffff << ISPCSI2_CTX_CTRL2_FRAME_SHIFT)
+
+#define ISPCSI2_CTX_DAT_OFST(n)                        ((0x078) + 0x20 * (n))
+#define ISPCSI2_CTX_DAT_OFST_OFST_SHIFT                0
+#define ISPCSI2_CTX_DAT_OFST_OFST_MASK         \
+       (0x1ffe0 << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT)
+
+#define ISPCSI2_CTX_DAT_PING_ADDR(n)           ((0x07c) + 0x20 * (n))
+#define ISPCSI2_CTX_DAT_PONG_ADDR(n)           ((0x080) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQENABLE(n)               ((0x084) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ       (1 << 8)
+#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ  (1 << 7)
+#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6)
+#define ISPCSI2_CTX_IRQENABLE_CS_IRQ           (1 << 5)
+#define ISPCSI2_CTX_IRQENABLE_LE_IRQ           (1 << 3)
+#define ISPCSI2_CTX_IRQENABLE_LS_IRQ           (1 << 2)
+#define ISPCSI2_CTX_IRQENABLE_FE_IRQ           (1 << 1)
+#define ISPCSI2_CTX_IRQENABLE_FS_IRQ           (1 << 0)
+
+#define ISPCSI2_CTX_IRQSTATUS(n)               ((0x088) + 0x20 * (n))
+#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ       (1 << 8)
+#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ  (1 << 7)
+#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6)
+#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ           (1 << 5)
+#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ           (1 << 3)
+#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ           (1 << 2)
+#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ           (1 << 1)
+#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ           (1 << 0)
+
+#define ISPCSI2_CTX_CTRL3(n)                   ((0x08c) + 0x20 * (n))
+#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT          5
+#define ISPCSI2_CTX_CTRL3_ALPHA_MASK           \
+       (0x3fff << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT)
+
+/* This instance is for OMAP3630 only */
+#define ISPCSI2_CTX_TRANSCODEH(n)              (0x000 + 0x8 * (n))
+#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT    16
+#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_MASK     \
+       (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEH_HSKIP_SHIFT     0
+#define ISPCSI2_CTX_TRANSCODEH_HSKIP_MASK      \
+       (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEV(n)              (0x004 + 0x8 * (n))
+#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT    16
+#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_MASK     \
+       (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
+#define ISPCSI2_CTX_TRANSCODEV_VSKIP_SHIFT     0
+#define ISPCSI2_CTX_TRANSCODEV_VSKIP_MASK      \
+       (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
+
+/* -----------------------------------------------------------------------------
+ * CSI PHY registers
+ */
+
+#define ISPCSIPHY_REG0                         (0x000)
+#define ISPCSIPHY_REG0_THS_TERM_SHIFT          8
+#define ISPCSIPHY_REG0_THS_TERM_MASK           \
+       (0xff << ISPCSIPHY_REG0_THS_TERM_SHIFT)
+#define ISPCSIPHY_REG0_THS_SETTLE_SHIFT                0
+#define ISPCSIPHY_REG0_THS_SETTLE_MASK         \
+       (0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT)
+
+#define ISPCSIPHY_REG1                                 (0x004)
+#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK              (1 << 29)
+/* This field is for OMAP3630 only */
+#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS      (1 << 25)
+#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT                 18
+#define ISPCSIPHY_REG1_TCLK_TERM_MASK                  \
+       (0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT)
+#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_SHIFT      10
+#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_MASK       \
+       (0xff << ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN)
+/* This field is for OMAP3430 only */
+#define ISPCSIPHY_REG1_TCLK_MISS_SHIFT                 8
+#define ISPCSIPHY_REG1_TCLK_MISS_MASK                  \
+       (0x3 << ISPCSIPHY_REG1_TCLK_MISS_SHIFT)
+/* This field is for OMAP3630 only */
+#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT                8
+#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_MASK         \
+       (0x3 << ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT)
+#define ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT               0
+#define ISPCSIPHY_REG1_TCLK_SETTLE_MASK                        \
+       (0xff << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT)
+
+/* This register is for OMAP3630 only */
+#define ISPCSIPHY_REG2                                 (0x008)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT    30
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK     \
+       (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT    28
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK     \
+       (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT    26
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK     \
+       (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT)
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT    24
+#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK     \
+       (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT)
+#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT         0
+#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK          \
+       (0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT)
+
+#endif /* OMAP3_ISP_REG_H */
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
new file mode 100644 (file)
index 0000000..75d39b1
--- /dev/null
@@ -0,0 +1,1693 @@
+/*
+ * ispresizer.c
+ *
+ * TI OMAP3 ISP - Resizer module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispresizer.h"
+
+/*
+ * Resizer Constants
+ */
+#define MIN_RESIZE_VALUE               64
+#define MID_RESIZE_VALUE               512
+#define MAX_RESIZE_VALUE               1024
+
+#define MIN_IN_WIDTH                   32
+#define MIN_IN_HEIGHT                  32
+#define MAX_IN_WIDTH_MEMORY_MODE       4095
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
+#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
+#define MAX_IN_HEIGHT                  4095
+
+#define MIN_OUT_WIDTH                  16
+#define MIN_OUT_HEIGHT                 2
+#define MAX_OUT_HEIGHT                 4095
+
+/*
+ * Resizer Use Constraints
+ * "TRM ES3.1, table 12-46"
+ */
+#define MAX_4TAP_OUT_WIDTH_ES1         1280
+#define MAX_7TAP_OUT_WIDTH_ES1         640
+#define MAX_4TAP_OUT_WIDTH_ES2         3312
+#define MAX_7TAP_OUT_WIDTH_ES2         1650
+#define MAX_4TAP_OUT_WIDTH_3630                4096
+#define MAX_7TAP_OUT_WIDTH_3630                2048
+
+/*
+ * Constants for ratio calculation
+ */
+#define RESIZE_DIVISOR                 256
+#define DEFAULT_PHASE                  1
+
+/*
+ * Default (and only) configuration of filter coefficients.
+ * 7-tap mode is for scale factors 0.25x to 0.5x.
+ * 4-tap mode is for scale factors 0.5x to 4.0x.
+ * There shouldn't be any reason to recalculate these, EVER.
+ */
+static const struct isprsz_coef filter_coefs = {
+       /* For 8-phase 4-tap horizontal filter: */
+       {
+               0x0000, 0x0100, 0x0000, 0x0000,
+               0x03FA, 0x00F6, 0x0010, 0x0000,
+               0x03F9, 0x00DB, 0x002C, 0x0000,
+               0x03FB, 0x00B3, 0x0053, 0x03FF,
+               0x03FD, 0x0082, 0x0084, 0x03FD,
+               0x03FF, 0x0053, 0x00B3, 0x03FB,
+               0x0000, 0x002C, 0x00DB, 0x03F9,
+               0x0000, 0x0010, 0x00F6, 0x03FA
+       },
+       /* For 8-phase 4-tap vertical filter: */
+       {
+               0x0000, 0x0100, 0x0000, 0x0000,
+               0x03FA, 0x00F6, 0x0010, 0x0000,
+               0x03F9, 0x00DB, 0x002C, 0x0000,
+               0x03FB, 0x00B3, 0x0053, 0x03FF,
+               0x03FD, 0x0082, 0x0084, 0x03FD,
+               0x03FF, 0x0053, 0x00B3, 0x03FB,
+               0x0000, 0x002C, 0x00DB, 0x03F9,
+               0x0000, 0x0010, 0x00F6, 0x03FA
+       },
+       /* For 4-phase 7-tap horizontal filter: */
+       #define DUMMY 0
+       {
+               0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+               0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+               0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+               0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+       },
+       /* For 4-phase 7-tap vertical filter: */
+       {
+               0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
+               0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
+               0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
+               0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
+       }
+       /*
+        * The dummy padding is required in 7-tap mode because of how the
+        * registers are arranged physically.
+        */
+       #undef DUMMY
+};
+
+/*
+ * __resizer_get_format - helper function for getting resizer format
+ * @res   : pointer to resizer private structure
+ * @pad   : pad number
+ * @fh    : V4L2 subdev file handle
+ * @which : wanted subdev format
+ * return zero
+ */
+static struct v4l2_mbus_framefmt *
+__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+                    unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &res->formats[pad];
+}
+
+/*
+ * __resizer_get_crop - helper function for getting resizer crop rectangle
+ * @res   : pointer to resizer private structure
+ * @fh    : V4L2 subdev file handle
+ * @which : wanted subdev crop rectangle
+ */
+static struct v4l2_rect *
+__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
+                  enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
+       else
+               return &res->crop.request;
+}
+
+/*
+ * resizer_set_filters - Set resizer filters
+ * @res: Device context.
+ * @h_coeff: horizontal coefficient
+ * @v_coeff: vertical coefficient
+ * Return none
+ */
+static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
+                               const u16 *v_coeff)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
+       int i;
+
+       startaddr_h = ISPRSZ_HFILT10;
+       startaddr_v = ISPRSZ_VFILT10;
+
+       for (i = 0; i < COEFF_CNT; i += 2) {
+               tmp_h = h_coeff[i] |
+                       (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
+               tmp_v = v_coeff[i] |
+                       (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
+               isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
+               isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
+               startaddr_h += 4;
+               startaddr_v += 4;
+       }
+}
+
+/*
+ * resizer_set_bilinear - Chrominance horizontal algorithm select
+ * @res: Device context.
+ * @type: Filtering interpolation type.
+ *
+ * Filtering that is same as luminance processing is
+ * intended only for downsampling, and bilinear interpolation
+ * is intended only for upsampling.
+ */
+static void resizer_set_bilinear(struct isp_res_device *res,
+                                enum resizer_chroma_algo type)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       if (type == RSZ_BILINEAR)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_CBILIN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_CBILIN);
+}
+
+/*
+ * resizer_set_ycpos - Luminance and chrominance order
+ * @res: Device context.
+ * @order: order type.
+ */
+static void resizer_set_ycpos(struct isp_res_device *res,
+                             enum v4l2_mbus_pixelcode pixelcode)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       switch (pixelcode) {
+       case V4L2_MBUS_FMT_YUYV8_1X16:
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_YCPOS);
+               break;
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_YCPOS);
+               break;
+       default:
+               return;
+       }
+}
+
+/*
+ * resizer_set_phase - Setup horizontal and vertical starting phase
+ * @res: Device context.
+ * @h_phase: horizontal phase parameters.
+ * @v_phase: vertical phase parameters.
+ *
+ * Horizontal and vertical phase range is 0 to 7
+ */
+static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
+                             u32 v_phase)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 rgval = 0;
+
+       rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+             ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
+       rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
+       rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
+
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+}
+
+/*
+ * resizer_set_luma - Setup luminance enhancer parameters
+ * @res: Device context.
+ * @luma: Structure for luminance enhancer parameters.
+ *
+ * Algorithm select:
+ *  0x0: Disable
+ *  0x1: [-1  2 -1]/2 high-pass filter
+ *  0x2: [-1 -2  6 -2 -1]/4 high-pass filter
+ *
+ * Maximum gain:
+ *  The data is coded in U4Q4 representation.
+ *
+ * Slope:
+ *  The data is coded in U4Q4 representation.
+ *
+ * Coring offset:
+ *  The data is coded in U8Q0 representation.
+ *
+ * The new luminance value is computed as:
+ *  Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
+ */
+static void resizer_set_luma(struct isp_res_device *res,
+                            struct resizer_luma_yenh *luma)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 rgval = 0;
+
+       rgval  = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
+                 & ISPRSZ_YENH_ALGO_MASK;
+       rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
+                 & ISPRSZ_YENH_GAIN_MASK;
+       rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
+                 & ISPRSZ_YENH_SLOP_MASK;
+       rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
+                 & ISPRSZ_YENH_CORE_MASK;
+
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
+}
+
+/*
+ * resizer_set_source - Input source select
+ * @res: Device context.
+ * @source: Input source type
+ *
+ * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
+ * Preview/CCDC engine, otherwise from memory.
+ */
+static void resizer_set_source(struct isp_res_device *res,
+                              enum resizer_input_entity source)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       if (source == RESIZER_INPUT_MEMORY)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_INPSRC);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_INPSRC);
+}
+
+/*
+ * resizer_set_ratio - Setup horizontal and vertical resizing value
+ * @res: Device context.
+ * @ratio: Structure for ratio parameters.
+ *
+ * Resizing range from 64 to 1024
+ */
+static void resizer_set_ratio(struct isp_res_device *res,
+                             const struct resizer_ratio *ratio)
+{
+       struct isp_device *isp = to_isp_device(res);
+       const u16 *h_filter, *v_filter;
+       u32 rgval = 0;
+
+       rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+                             ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
+       rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
+                 & ISPRSZ_CNT_HRSZ_MASK;
+       rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
+                 & ISPRSZ_CNT_VRSZ_MASK;
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
+
+       /* prepare horizontal filter coefficients */
+       if (ratio->horz > MID_RESIZE_VALUE)
+               h_filter = &filter_coefs.h_filter_coef_7tap[0];
+       else
+               h_filter = &filter_coefs.h_filter_coef_4tap[0];
+
+       /* prepare vertical filter coefficients */
+       if (ratio->vert > MID_RESIZE_VALUE)
+               v_filter = &filter_coefs.v_filter_coef_7tap[0];
+       else
+               v_filter = &filter_coefs.v_filter_coef_4tap[0];
+
+       resizer_set_filters(res, h_filter, v_filter);
+}
+
+/*
+ * resizer_set_dst_size - Setup the output height and width
+ * @res: Device context.
+ * @width: Output width.
+ * @height: Output height.
+ *
+ * Width :
+ *  The value must be EVEN.
+ *
+ * Height:
+ *  The number of bytes written to SDRAM must be
+ *  a multiple of 16-bytes if the vertical resizing factor
+ *  is greater than 1x (upsizing)
+ */
+static void resizer_set_output_size(struct isp_res_device *res,
+                                   u32 width, u32 height)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 rgval = 0;
+
+       dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
+       rgval  = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
+                & ISPRSZ_OUT_SIZE_HORZ_MASK;
+       rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
+                & ISPRSZ_OUT_SIZE_VERT_MASK;
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
+}
+
+/*
+ * resizer_set_output_offset - Setup memory offset for the output lines.
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
+ * the SDRAM line offset must be set on a 256-byte boundary
+ */
+static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+}
+
+/*
+ * resizer_set_start - Setup vertical and horizontal start position
+ * @res: Device context.
+ * @left: Horizontal start position.
+ * @top: Vertical start position.
+ *
+ * Vertical start line:
+ *  This field makes sense only when the resizer obtains its input
+ *  from the preview engine/CCDC
+ *
+ * Horizontal start pixel:
+ *  Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
+ *  When the resizer gets its input from SDRAM, this field must be set
+ *  to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
+ */
+static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 rgval = 0;
+
+       rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
+               & ISPRSZ_IN_START_HORZ_ST_MASK;
+       rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
+                & ISPRSZ_IN_START_VERT_ST_MASK;
+
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+}
+
+/*
+ * resizer_set_input_size - Setup the input size
+ * @res: Device context.
+ * @width: The range is 0 to 4095 pixels
+ * @height: The range is 0 to 4095 lines
+ */
+static void resizer_set_input_size(struct isp_res_device *res,
+                                  u32 width, u32 height)
+{
+       struct isp_device *isp = to_isp_device(res);
+       u32 rgval = 0;
+
+       dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
+
+       rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
+               & ISPRSZ_IN_SIZE_HORZ_MASK;
+       rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
+                & ISPRSZ_IN_SIZE_VERT_MASK;
+
+       isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
+}
+
+/*
+ * resizer_set_src_offs - Setup the memory offset for the input lines
+ * @res: Device context.
+ * @offset: Memory offset.
+ *
+ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
+ * boundary; the 5 LSBs are read-only. This field must be programmed to be
+ * 0x0 if the resizer input is from preview engine/CCDC.
+ */
+static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
+}
+
+/*
+ * resizer_set_intype - Input type select
+ * @res: Device context.
+ * @type: Pixel format type.
+ */
+static void resizer_set_intype(struct isp_res_device *res,
+                              enum resizer_colors_type type)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       if (type == RSZ_COLOR8)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_INPTYP);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+                           ISPRSZ_CNT_INPTYP);
+}
+
+/*
+ * __resizer_set_inaddr - Helper function for set input address
+ * @res : pointer to resizer private data structure
+ * @addr: input address
+ * return none
+ */
+static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+}
+
+/*
+ * The data rate at the horizontal resizer output must not exceed half the
+ * functional clock or 100 MP/s, whichever is lower. According to the TRM
+ * there's no similar requirement for the vertical resizer output. However
+ * experience showed that vertical upscaling by 4 leads to SBL overflows (with
+ * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
+ * output data rate to the functional clock or 200 MP/s, whichever is lower,
+ * seems to get rid of SBL overflows.
+ *
+ * The maximum data rate at the output of the horizontal resizer can thus be
+ * computed with
+ *
+ * max intermediate rate <= L3 clock * input height / output height
+ * max intermediate rate <= L3 clock / 2
+ *
+ * The maximum data rate at the resizer input is then
+ *
+ * max input rate <= max intermediate rate * input width / output width
+ *
+ * where the input width and height are the resizer input crop rectangle size.
+ * The TRM doesn't clearly explain if that's a maximum instant data rate or a
+ * maximum average data rate.
+ */
+void omap3isp_resizer_max_rate(struct isp_res_device *res,
+                              unsigned int *max_rate)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+       const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
+       unsigned long limit = min(pipe->l3_ick, 200000000UL);
+       unsigned long clock;
+
+       clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
+       clock = min(clock, limit / 2);
+       *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
+}
+
+/*
+ * When the resizer processes images from memory, the driver must slow down read
+ * requests on the input to at least comply with the internal data rate
+ * requirements. If the application real-time requirements can cope with slower
+ * processing, the resizer can be slowed down even more to put less pressure on
+ * the overall system.
+ *
+ * When the resizer processes images on the fly (either from the CCDC or the
+ * preview module), the same data rate requirements apply but they can't be
+ * enforced at the resizer level. The image input module (sensor, CCP2 or
+ * preview module) must not provide image data faster than the resizer can
+ * process.
+ *
+ * For live image pipelines, the data rate is set by the frame format, size and
+ * rate. The sensor output frame rate must not exceed the maximum resizer data
+ * rate.
+ *
+ * The resizer slows down read requests by inserting wait cycles in the SBL
+ * requests. The maximum number of 256-byte requests per second can be computed
+ * as (the data rate is multiplied by 2 to convert from pixels per second to
+ * bytes per second)
+ *
+ * request per second = data rate * 2 / 256
+ * cycles per request = cycles per second / requests per second
+ *
+ * The number of cycles per second is controlled by the L3 clock, leading to
+ *
+ * cycles per request = L3 frequency / 2 * 256 / data rate
+ */
+static void resizer_adjust_bandwidth(struct isp_res_device *res)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+       struct isp_device *isp = to_isp_device(res);
+       unsigned long l3_ick = pipe->l3_ick;
+       struct v4l2_fract *timeperframe;
+       unsigned int cycles_per_frame;
+       unsigned int requests_per_frame;
+       unsigned int cycles_per_request;
+       unsigned int granularity;
+       unsigned int minimum;
+       unsigned int maximum;
+       unsigned int value;
+
+       if (res->input != RESIZER_INPUT_MEMORY) {
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+                           ISPSBL_SDR_REQ_RSZ_EXP_MASK);
+               return;
+       }
+
+       switch (isp->revision) {
+       case ISP_REVISION_1_0:
+       case ISP_REVISION_2_0:
+       default:
+               granularity = 1024;
+               break;
+
+       case ISP_REVISION_15_0:
+               granularity = 32;
+               break;
+       }
+
+       /* Compute the minimum number of cycles per request, based on the
+        * pipeline maximum data rate. This is an absolute lower bound if we
+        * don't want SBL overflows, so round the value up.
+        */
+       cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
+                                    pipe->max_rate);
+       minimum = DIV_ROUND_UP(cycles_per_request, granularity);
+
+       /* Compute the maximum number of cycles per request, based on the
+        * requested frame rate. This is a soft upper bound to achieve a frame
+        * rate equal or higher than the requested value, so round the value
+        * down.
+        */
+       timeperframe = &pipe->max_timeperframe;
+
+       requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
+                          * res->crop.active.height;
+       cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
+                                  timeperframe->denominator);
+       cycles_per_request = cycles_per_frame / requests_per_frame;
+
+       maximum = cycles_per_request / granularity;
+
+       value = max(minimum, maximum);
+
+       dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
+                       ISPSBL_SDR_REQ_RSZ_EXP_MASK,
+                       value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
+}
+
+/*
+ * omap3isp_resizer_busy - Checks if ISP resizer is busy.
+ *
+ * Returns busy field from ISPRSZ_PCR register.
+ */
+int omap3isp_resizer_busy(struct isp_res_device *res)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+                            ISPRSZ_PCR_BUSY;
+}
+
+/*
+ * resizer_set_inaddr - Sets the memory address of the input frame.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ */
+static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
+{
+       res->addr_base = addr;
+
+       /* This will handle crop settings in stream off state */
+       if (res->crop_offset)
+               addr += res->crop_offset & ~0x1f;
+
+       __resizer_set_inaddr(res, addr);
+}
+
+/*
+ * Configures the memory address to which the output frame is written.
+ * @addr: 32bit memory address aligned on 32byte boundary.
+ * Note: For SBL efficiency reasons the address should be on a 256-byte
+ * boundary.
+ */
+static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       /*
+        * Set output address. This needs to be in its own function
+        * because it changes often.
+        */
+       isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
+                      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+}
+
+/*
+ * resizer_print_status - Prints the values of the resizer module registers.
+ */
+#define RSZ_PRINT_REGISTER(isp, name)\
+       dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
+               isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
+
+static void resizer_print_status(struct isp_res_device *res)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
+
+       RSZ_PRINT_REGISTER(isp, PCR);
+       RSZ_PRINT_REGISTER(isp, CNT);
+       RSZ_PRINT_REGISTER(isp, OUT_SIZE);
+       RSZ_PRINT_REGISTER(isp, IN_START);
+       RSZ_PRINT_REGISTER(isp, IN_SIZE);
+       RSZ_PRINT_REGISTER(isp, SDR_INADD);
+       RSZ_PRINT_REGISTER(isp, SDR_INOFF);
+       RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
+       RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
+       RSZ_PRINT_REGISTER(isp, YENH);
+
+       dev_dbg(isp->dev, "--------------------------------------------\n");
+}
+
+/*
+ * resizer_calc_ratios - Helper function for calculate resizer ratios
+ * @res: pointer to resizer private data structure
+ * @input: input frame size
+ * @output: output frame size
+ * @ratio : return calculated ratios
+ * return none
+ *
+ * The resizer uses a polyphase sample rate converter. The upsampling filter
+ * has a fixed number of phases that depend on the resizing ratio. As the ratio
+ * computation depends on the number of phases, we need to compute a first
+ * approximation and then refine it.
+ *
+ * The input/output/ratio relationship is given by the OMAP34xx TRM:
+ *
+ * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
+ *     iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
+ *     ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
+ * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
+ *     iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
+ *     ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
+ *
+ * iw and ih are the input width and height after cropping. Those equations need
+ * to be satisfied exactly for the resizer to work correctly.
+ *
+ * Reverting the equations, we can compute the resizing ratios with
+ *
+ * - 8-phase, 4-tap mode
+ *     hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
+ *     vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
+ * - 4-phase, 7-tap mode
+ *     hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
+ *     vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
+ *
+ * The ratios are integer values, and must be rounded down to ensure that the
+ * cropped input size is not bigger than the uncropped input size. As the ratio
+ * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
+ * 7-tap mode equations to compute a ratio approximation.
+ *
+ * We first clamp the output size according to the hardware capabilitie to avoid
+ * auto-cropping the input more than required to satisfy the TRM equations. The
+ * minimum output size is achieved with a scaling factor of 1024. It is thus
+ * computed using the 7-tap equations.
+ *
+ *     min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
+ *     min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
+ *
+ * Similarly, the maximum output size is achieved with a scaling factor of 64
+ * and computed using the 4-tap equations.
+ *
+ *     max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
+ *     max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
+ *
+ * The additional +255 term compensates for the round down operation performed
+ * by the TRM equations when shifting the value right by 8 bits.
+ *
+ * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
+ * the maximum value guarantees that the ratio value will never be smaller than
+ * the minimum, but it could still slightly exceed the maximum. Clamping the
+ * ratio will thus result in a resizing factor slightly larger than the
+ * requested value.
+ *
+ * To accomodate that, and make sure the TRM equations are satisfied exactly, we
+ * compute the input crop rectangle as the last step.
+ *
+ * As if the situation wasn't complex enough, the maximum output width depends
+ * on the vertical resizing ratio.  Fortunately, the output height doesn't
+ * depend on the horizontal resizing ratio. We can then start by computing the
+ * output height and the vertical ratio, and then move to computing the output
+ * width and the horizontal ratio.
+ */
+static void resizer_calc_ratios(struct isp_res_device *res,
+                               struct v4l2_rect *input,
+                               struct v4l2_mbus_framefmt *output,
+                               struct resizer_ratio *ratio)
+{
+       struct isp_device *isp = to_isp_device(res);
+       const unsigned int spv = DEFAULT_PHASE;
+       const unsigned int sph = DEFAULT_PHASE;
+       unsigned int upscaled_width;
+       unsigned int upscaled_height;
+       unsigned int min_width;
+       unsigned int min_height;
+       unsigned int max_width;
+       unsigned int max_height;
+       unsigned int width_alignment;
+
+       /*
+        * Clamp the output height based on the hardware capabilities and
+        * compute the vertical resizing ratio.
+        */
+       min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
+       min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
+       max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
+       max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
+       output->height = clamp(output->height, min_height, max_height);
+
+       ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
+                   / (output->height - 1);
+       ratio->vert = clamp_t(unsigned int, ratio->vert,
+                             MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+       if (ratio->vert <= MID_RESIZE_VALUE) {
+               upscaled_height = (output->height - 1) * ratio->vert
+                               + 32 * spv + 16;
+               input->height = (upscaled_height >> 8) + 4;
+       } else {
+               upscaled_height = (output->height - 1) * ratio->vert
+                               + 64 * spv + 32;
+               input->height = (upscaled_height >> 8) + 7;
+       }
+
+       /*
+        * Compute the minimum and maximum output widths based on the hardware
+        * capabilities. The maximum depends on the vertical resizing ratio.
+        */
+       min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
+       min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
+
+       if (ratio->vert <= MID_RESIZE_VALUE) {
+               switch (isp->revision) {
+               case ISP_REVISION_1_0:
+                       max_width = MAX_4TAP_OUT_WIDTH_ES1;
+                       break;
+
+               case ISP_REVISION_2_0:
+               default:
+                       max_width = MAX_4TAP_OUT_WIDTH_ES2;
+                       break;
+
+               case ISP_REVISION_15_0:
+                       max_width = MAX_4TAP_OUT_WIDTH_3630;
+                       break;
+               }
+       } else {
+               switch (isp->revision) {
+               case ISP_REVISION_1_0:
+                       max_width = MAX_7TAP_OUT_WIDTH_ES1;
+                       break;
+
+               case ISP_REVISION_2_0:
+               default:
+                       max_width = MAX_7TAP_OUT_WIDTH_ES2;
+                       break;
+
+               case ISP_REVISION_15_0:
+                       max_width = MAX_7TAP_OUT_WIDTH_3630;
+                       break;
+               }
+       }
+       max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
+                       + 1, max_width);
+
+       /*
+        * The output width must be even, and must be a multiple of 16 bytes
+        * when upscaling vertically. Clamp the output width to the valid range.
+        * Take the alignment into account (the maximum width in 7-tap mode on
+        * ES2 isn't a multiple of 8) and align the result up to make sure it
+        * won't be smaller than the minimum.
+        */
+       width_alignment = ratio->vert < 256 ? 8 : 2;
+       output->width = clamp(output->width, min_width,
+                             max_width & ~(width_alignment - 1));
+       output->width = ALIGN(output->width, width_alignment);
+
+       ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
+                   / (output->width - 1);
+       ratio->horz = clamp_t(unsigned int, ratio->horz,
+                             MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
+
+       if (ratio->horz <= MID_RESIZE_VALUE) {
+               upscaled_width = (output->width - 1) * ratio->horz
+                              + 32 * sph + 16;
+               input->width = (upscaled_width >> 8) + 7;
+       } else {
+               upscaled_width = (output->width - 1) * ratio->horz
+                              + 64 * sph + 32;
+               input->width = (upscaled_width >> 8) + 7;
+       }
+}
+
+/*
+ * resizer_set_crop_params - Setup hardware with cropping parameters
+ * @res : resizer private structure
+ * @crop_rect : current crop rectangle
+ * @ratio : resizer ratios
+ * return none
+ */
+static void resizer_set_crop_params(struct isp_res_device *res,
+                                   const struct v4l2_mbus_framefmt *input,
+                                   const struct v4l2_mbus_framefmt *output)
+{
+       resizer_set_ratio(res, &res->ratio);
+
+       /* Set chrominance horizontal algorithm */
+       if (res->ratio.horz >= RESIZE_DIVISOR)
+               resizer_set_bilinear(res, RSZ_THE_SAME);
+       else
+               resizer_set_bilinear(res, RSZ_BILINEAR);
+
+       resizer_adjust_bandwidth(res);
+
+       if (res->input == RESIZER_INPUT_MEMORY) {
+               /* Calculate additional offset for crop */
+               res->crop_offset = (res->crop.active.top * input->width +
+                                   res->crop.active.left) * 2;
+               /*
+                * Write lowest 4 bits of horizontal pixel offset (in pixels),
+                * vertical start must be 0.
+                */
+               resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
+
+               /*
+                * Set start (read) address for cropping, in bytes.
+                * Lowest 5 bits must be zero.
+                */
+               __resizer_set_inaddr(res,
+                               res->addr_base + (res->crop_offset & ~0x1f));
+       } else {
+               /*
+                * Set vertical start line and horizontal starting pixel.
+                * If the input is from CCDC/PREV, horizontal start field is
+                * in bytes (twice number of pixels).
+                */
+               resizer_set_start(res, res->crop.active.left * 2,
+                                 res->crop.active.top);
+               /* Input address and offset must be 0 for preview/ccdc input */
+               __resizer_set_inaddr(res, 0);
+               resizer_set_input_offset(res, 0);
+       }
+
+       /* Set the input size */
+       resizer_set_input_size(res, res->crop.active.width,
+                              res->crop.active.height);
+}
+
+static void resizer_configure(struct isp_res_device *res)
+{
+       struct v4l2_mbus_framefmt *informat, *outformat;
+       struct resizer_luma_yenh luma = {0, 0, 0, 0};
+
+       resizer_set_source(res, res->input);
+
+       informat = &res->formats[RESZ_PAD_SINK];
+       outformat = &res->formats[RESZ_PAD_SOURCE];
+
+       /* RESZ_PAD_SINK */
+       if (res->input == RESIZER_INPUT_VP)
+               resizer_set_input_offset(res, 0);
+       else
+               resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
+
+       /* YUV422 interleaved, default phase, no luma enhancement */
+       resizer_set_intype(res, RSZ_YUV422);
+       resizer_set_ycpos(res, informat->code);
+       resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
+       resizer_set_luma(res, &luma);
+
+       /* RESZ_PAD_SOURCE */
+       resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
+       resizer_set_output_size(res, outformat->width, outformat->height);
+
+       resizer_set_crop_params(res, informat, outformat);
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void resizer_enable_oneshot(struct isp_res_device *res)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
+                   ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
+}
+
+void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
+{
+       /*
+        * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
+        * condition, the module was paused and now we have a buffer queued
+        * on the output again. Restart the pipeline if running in continuous
+        * mode.
+        */
+       if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+           res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+               resizer_enable_oneshot(res);
+               isp_video_dmaqueue_flags_clr(&res->video_out);
+       }
+}
+
+static void resizer_isr_buffer(struct isp_res_device *res)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
+       struct isp_buffer *buffer;
+       int restart = 0;
+
+       if (res->state == ISP_PIPELINE_STREAM_STOPPED)
+               return;
+
+       /* Complete the output buffer and, if reading from memory, the input
+        * buffer.
+        */
+       buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
+       if (buffer != NULL) {
+               resizer_set_outaddr(res, buffer->isp_addr);
+               restart = 1;
+       }
+
+       pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
+
+       if (res->input == RESIZER_INPUT_MEMORY) {
+               buffer = omap3isp_video_buffer_next(&res->video_in, 0);
+               if (buffer != NULL)
+                       resizer_set_inaddr(res, buffer->isp_addr);
+               pipe->state |= ISP_PIPELINE_IDLE_INPUT;
+       }
+
+       if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
+               if (isp_pipeline_ready(pipe))
+                       omap3isp_pipeline_set_stream(pipe,
+                                               ISP_PIPELINE_STREAM_SINGLESHOT);
+       } else {
+               /* If an underrun occurs, the video queue operation handler will
+                * restart the resizer. Otherwise restart it immediately.
+                */
+               if (restart)
+                       resizer_enable_oneshot(res);
+       }
+
+       res->error = 0;
+}
+
+/*
+ * omap3isp_resizer_isr - ISP resizer interrupt handler
+ *
+ * Manage the resizer video buffers and configure shadowed and busy-locked
+ * registers.
+ */
+void omap3isp_resizer_isr(struct isp_res_device *res)
+{
+       struct v4l2_mbus_framefmt *informat, *outformat;
+
+       if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
+               return;
+
+       if (res->applycrop) {
+               outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
+                                             V4L2_SUBDEV_FORMAT_ACTIVE);
+               informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
+                                             V4L2_SUBDEV_FORMAT_ACTIVE);
+               resizer_set_crop_params(res, informat, outformat);
+               res->applycrop = 0;
+       }
+
+       resizer_isr_buffer(res);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int resizer_video_queue(struct isp_video *video,
+                              struct isp_buffer *buffer)
+{
+       struct isp_res_device *res = &video->isp->isp_res;
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               resizer_set_inaddr(res, buffer->isp_addr);
+
+       /*
+        * We now have a buffer queued on the output. Despite what the
+        * TRM says, the resizer can't be restarted immediately.
+        * Enabling it in one shot mode in the middle of a frame (or at
+        * least asynchronously to the frame) results in the output
+        * being shifted randomly left/right and up/down, as if the
+        * hardware didn't synchronize itself to the beginning of the
+        * frame correctly.
+        *
+        * Restart the resizer on the next sync interrupt if running in
+        * continuous mode or when starting the stream.
+        */
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               resizer_set_outaddr(res, buffer->isp_addr);
+
+       return 0;
+}
+
+static const struct isp_video_operations resizer_video_ops = {
+       .queue = resizer_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * resizer_set_stream - Enable/Disable streaming on resizer subdev
+ * @sd: ISP resizer V4L2 subdev
+ * @enable: 1 == Enable, 0 == Disable
+ *
+ * The resizer hardware can't be enabled without a memory buffer to write to.
+ * As the s_stream operation is called in response to a STREAMON call without
+ * any buffer queued yet, just update the state field and return immediately.
+ * The resizer will be enabled in resizer_video_queue().
+ */
+static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct isp_video *video_out = &res->video_out;
+       struct isp_device *isp = to_isp_device(res);
+       struct device *dev = to_device(res);
+
+       if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISP_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+               resizer_configure(res);
+               res->error = 0;
+               resizer_print_status(res);
+       }
+
+       switch (enable) {
+       case ISP_PIPELINE_STREAM_CONTINUOUS:
+               omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+               if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
+                       resizer_enable_oneshot(res);
+                       isp_video_dmaqueue_flags_clr(video_out);
+               }
+               break;
+
+       case ISP_PIPELINE_STREAM_SINGLESHOT:
+               if (res->input == RESIZER_INPUT_MEMORY)
+                       omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
+               omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
+
+               resizer_enable_oneshot(res);
+               break;
+
+       case ISP_PIPELINE_STREAM_STOPPED:
+               if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
+                                             &res->stopping))
+                       dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
+               omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
+                               OMAP3_ISP_SBL_RESIZER_WRITE);
+               omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
+               isp_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+
+       res->state = enable;
+       return 0;
+}
+
+/*
+ * resizer_g_crop - handle get crop subdev operation
+ * @sd : pointer to v4l2 subdev structure
+ * @pad : subdev pad
+ * @crop : pointer to crop structure
+ * @which : active or try format
+ * return zero
+ */
+static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_crop *crop)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+       struct resizer_ratio ratio;
+
+       /* Only sink pad has crop capability */
+       if (crop->pad != RESZ_PAD_SINK)
+               return -EINVAL;
+
+       format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
+       crop->rect = *__resizer_get_crop(res, fh, crop->which);
+       resizer_calc_ratios(res, &crop->rect, format, &ratio);
+
+       return 0;
+}
+
+/*
+ * resizer_try_crop - mangles crop parameters.
+ */
+static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
+                            const struct v4l2_mbus_framefmt *source,
+                            struct v4l2_rect *crop)
+{
+       const unsigned int spv = DEFAULT_PHASE;
+       const unsigned int sph = DEFAULT_PHASE;
+
+       /* Crop rectangle is constrained to the output size so that zoom ratio
+        * cannot exceed +/-4.0.
+        */
+       unsigned int min_width =
+               ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
+       unsigned int min_height =
+               ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
+       unsigned int max_width =
+               ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
+       unsigned int max_height =
+               ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
+
+       crop->width = clamp_t(u32, crop->width, min_width, max_width);
+       crop->height = clamp_t(u32, crop->height, min_height, max_height);
+
+       /* Crop can not go beyond of the input rectangle */
+       crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
+       crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
+                             sink->width - crop->left);
+       crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
+       crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
+                              sink->height - crop->top);
+}
+
+/*
+ * resizer_s_crop - handle set crop subdev operation
+ * @sd : pointer to v4l2 subdev structure
+ * @pad : subdev pad
+ * @crop : pointer to crop structure
+ * @which : active or try format
+ * return -EINVAL or zero when succeed
+ */
+static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_crop *crop)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct isp_device *isp = to_isp_device(res);
+       struct v4l2_mbus_framefmt *format_sink, *format_source;
+       struct resizer_ratio ratio;
+
+       /* Only sink pad has crop capability */
+       if (crop->pad != RESZ_PAD_SINK)
+               return -EINVAL;
+
+       format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+                                          crop->which);
+       format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+                                            crop->which);
+
+       dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
+               crop->rect.left, crop->rect.top, crop->rect.width,
+               crop->rect.height, crop->which);
+
+       dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
+               format_sink->width, format_sink->height,
+               format_source->width, format_source->height);
+
+       resizer_try_crop(format_sink, format_source, &crop->rect);
+       *__resizer_get_crop(res, fh, crop->which) = crop->rect;
+       resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
+
+       if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
+               return 0;
+
+       res->ratio = ratio;
+       res->crop.active = crop->rect;
+
+       /*
+        * s_crop can be called while streaming is on. In this case
+        * the crop values will be set in the next IRQ.
+        */
+       if (res->state != ISP_PIPELINE_STREAM_STOPPED)
+               res->applycrop = 1;
+
+       return 0;
+}
+
+/* resizer pixel formats */
+static const unsigned int resizer_formats[] = {
+       V4L2_MBUS_FMT_UYVY8_1X16,
+       V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+static unsigned int resizer_max_in_width(struct isp_res_device *res)
+{
+       struct isp_device *isp = to_isp_device(res);
+
+       if (res->input == RESIZER_INPUT_MEMORY) {
+               return MAX_IN_WIDTH_MEMORY_MODE;
+       } else {
+               if (isp->revision == ISP_REVISION_1_0)
+                       return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
+               else
+                       return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
+       }
+}
+
+/*
+ * resizer_try_format - Handle try format by pad subdev method
+ * @res   : ISP resizer device
+ * @fh    : V4L2 subdev file handle
+ * @pad   : pad num
+ * @fmt   : pointer to v4l2 format structure
+ * @which : wanted subdev format
+ */
+static void resizer_try_format(struct isp_res_device *res,
+                              struct v4l2_subdev_fh *fh, unsigned int pad,
+                              struct v4l2_mbus_framefmt *fmt,
+                              enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       struct resizer_ratio ratio;
+       struct v4l2_rect crop;
+
+       switch (pad) {
+       case RESZ_PAD_SINK:
+               if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
+                   fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
+                       fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+
+               fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
+                                    resizer_max_in_width(res));
+               fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
+                                     MAX_IN_HEIGHT);
+               break;
+
+       case RESZ_PAD_SOURCE:
+               format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
+               fmt->code = format->code;
+
+               crop = *__resizer_get_crop(res, fh, which);
+               resizer_calc_ratios(res, &crop, fmt, &ratio);
+               break;
+       }
+
+       fmt->colorspace = V4L2_COLORSPACE_JPEG;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * resizer_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       if (code->pad == RESZ_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(resizer_formats))
+                       return -EINVAL;
+
+               code->code = resizer_formats[code->index];
+       } else {
+               if (code->index != 0)
+                       return -EINVAL;
+
+               format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+                                             V4L2_SUBDEV_FORMAT_TRY);
+               code->code = format->code;
+       }
+
+       return 0;
+}
+
+static int resizer_enum_frame_size(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * resizer_get_format - Handle get format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on sucess
+ */
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * resizer_set_format - Handle set format by pads subdev method
+ * @sd    : pointer to v4l2 subdev structure
+ * @fh    : V4L2 subdev file handle
+ * @fmt   : pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
+
+       format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       if (fmt->pad == RESZ_PAD_SINK) {
+               /* reset crop rectangle */
+               crop = __resizer_get_crop(res, fh, fmt->which);
+               crop->left = 0;
+               crop->top = 0;
+               crop->width = fmt->format.width;
+               crop->height = fmt->format.height;
+
+               /* Propagate the format from sink to source */
+               format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+                                             fmt->which);
+               *format = fmt->format;
+               resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
+                                  fmt->which);
+       }
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               /* Compute and store the active crop rectangle and resizer
+                * ratios. format already points to the source pad active
+                * format.
+                */
+               res->crop.active = res->crop.request;
+               resizer_calc_ratios(res, &res->crop.active, format,
+                                      &res->ratio);
+       }
+
+       return 0;
+}
+
+/*
+ * resizer_init_formats - Initialize formats on all pads
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int resizer_init_formats(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = RESZ_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       resizer_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
+       .s_stream = resizer_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
+       .enum_mbus_code = resizer_enum_mbus_code,
+       .enum_frame_size = resizer_enum_frame_size,
+       .get_fmt = resizer_get_format,
+       .set_fmt = resizer_set_format,
+       .get_crop = resizer_g_crop,
+       .set_crop = resizer_s_crop,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops resizer_v4l2_ops = {
+       .video = &resizer_v4l2_video_ops,
+       .pad = &resizer_v4l2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
+       .open = resizer_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * resizer_link_setup - Setup resizer connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int resizer_link_setup(struct media_entity *entity,
+                             const struct media_pad *local,
+                             const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
+               /* read from memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (res->input == RESIZER_INPUT_VP)
+                               return -EBUSY;
+                       res->input = RESIZER_INPUT_MEMORY;
+               } else {
+                       if (res->input == RESIZER_INPUT_MEMORY)
+                               res->input = RESIZER_INPUT_NONE;
+               }
+               break;
+
+       case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* read from ccdc or previewer */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (res->input == RESIZER_INPUT_MEMORY)
+                               return -EBUSY;
+                       res->input = RESIZER_INPUT_VP;
+               } else {
+                       if (res->input == RESIZER_INPUT_VP)
+                               res->input = RESIZER_INPUT_NONE;
+               }
+               break;
+
+       case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+               /* resizer always write to memory */
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations resizer_media_ops = {
+       .link_setup = resizer_link_setup,
+};
+
+/*
+ * resizer_init_entities - Initialize resizer subdev and media entity.
+ * @res : Pointer to resizer device structure
+ * return -ENOMEM or zero on success
+ */
+static int resizer_init_entities(struct isp_res_device *res)
+{
+       struct v4l2_subdev *sd = &res->subdev;
+       struct media_pad *pads = res->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       res->input = RESIZER_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &resizer_v4l2_ops);
+       sd->internal_ops = &resizer_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
+       v4l2_set_subdevdata(sd, res);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &resizer_media_ops;
+       ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       resizer_init_formats(sd, NULL);
+
+       res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       res->video_in.ops = &resizer_video_ops;
+       res->video_in.isp = to_isp_device(res);
+       res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+       res->video_in.bpl_alignment = 32;
+       res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       res->video_out.ops = &resizer_video_ops;
+       res->video_out.isp = to_isp_device(res);
+       res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
+       res->video_out.bpl_alignment = 32;
+
+       ret = omap3isp_video_init(&res->video_in, "resizer");
+       if (ret < 0)
+               return ret;
+
+       ret = omap3isp_video_init(&res->video_out, "resizer");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the video nodes to the resizer subdev. */
+       ret = media_entity_create_link(&res->video_in.video.entity, 0,
+                       &res->subdev.entity, RESZ_PAD_SINK, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
+                       &res->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
+{
+       media_entity_cleanup(&res->subdev.entity);
+
+       v4l2_device_unregister_subdev(&res->subdev);
+       omap3isp_video_unregister(&res->video_in);
+       omap3isp_video_unregister(&res->video_out);
+}
+
+int omap3isp_resizer_register_entities(struct isp_res_device *res,
+                                      struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video nodes. */
+       ret = v4l2_device_register_subdev(vdev, &res->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&res->video_in, vdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap3isp_video_register(&res->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap3isp_resizer_unregister_entities(res);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP resizer initialization and cleanup
+ */
+
+void omap3isp_resizer_cleanup(struct isp_device *isp)
+{
+}
+
+/*
+ * isp_resizer_init - Resizer initialization.
+ * @isp : Pointer to ISP device
+ * return -ENOMEM or zero on success
+ */
+int omap3isp_resizer_init(struct isp_device *isp)
+{
+       struct isp_res_device *res = &isp->isp_res;
+       int ret;
+
+       init_waitqueue_head(&res->wait);
+       atomic_set(&res->stopping, 0);
+       ret = resizer_init_entities(res);
+       if (ret < 0)
+               goto out;
+
+out:
+       if (ret)
+               omap3isp_resizer_cleanup(isp);
+
+       return ret;
+}
diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h
new file mode 100644 (file)
index 0000000..76abc2e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * ispresizer.h
+ *
+ * TI OMAP3 ISP - Resizer module
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_RESIZER_H
+#define OMAP3_ISP_RESIZER_H
+
+#include <linux/types.h>
+
+/*
+ * Constants for filter coefficents count
+ */
+#define COEFF_CNT              32
+
+/*
+ * struct isprsz_coef - Structure for resizer filter coeffcients.
+ * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap
+ *                     mode (.5x-4x)
+ * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap
+ *                     mode (.5x-4x)
+ * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap
+ *                     mode (.25x-.5x)
+ * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap
+ *                     mode (.25x-.5x)
+ */
+struct isprsz_coef {
+       u16 h_filter_coef_4tap[32];
+       u16 v_filter_coef_4tap[32];
+       /* Every 8th value is a dummy value in the following arrays: */
+       u16 h_filter_coef_7tap[32];
+       u16 v_filter_coef_7tap[32];
+};
+
+/* Chrominance horizontal algorithm */
+enum resizer_chroma_algo {
+       RSZ_THE_SAME = 0,       /* Chrominance the same as Luminance */
+       RSZ_BILINEAR = 1,       /* Chrominance uses bilinear interpolation */
+};
+
+/* Resizer input type select */
+enum resizer_colors_type {
+       RSZ_YUV422 = 0,         /* YUV422 color is interleaved */
+       RSZ_COLOR8 = 1,         /* Color separate data on 8 bits */
+};
+
+/*
+ * Structure for horizontal and vertical resizing value
+ */
+struct resizer_ratio {
+       u32 horz;
+       u32 vert;
+};
+
+/*
+ * Structure for luminance enhancer parameters.
+ */
+struct resizer_luma_yenh {
+       u8 algo;                /* algorithm select. */
+       u8 gain;                /* maximum gain. */
+       u8 slope;               /* slope. */
+       u8 core;                /* core offset. */
+};
+
+enum resizer_input_entity {
+       RESIZER_INPUT_NONE,
+       RESIZER_INPUT_VP,       /* input video port - prev or ccdc */
+       RESIZER_INPUT_MEMORY,
+};
+
+/* Sink and source resizer pads */
+#define RESZ_PAD_SINK                  0
+#define RESZ_PAD_SOURCE                        1
+#define RESZ_PADS_NUM                  2
+
+/*
+ * struct isp_res_device - OMAP3 ISP resizer module
+ * @crop.request: Crop rectangle requested by the user
+ * @crop.active: Active crop rectangle (based on hardware requirements)
+ */
+struct isp_res_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[RESZ_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM];
+
+       enum resizer_input_entity input;
+       struct isp_video video_in;
+       struct isp_video video_out;
+       unsigned int error;
+
+       u32 addr_base;   /* stored source buffer address in memory mode */
+       u32 crop_offset; /* additional offset for crop in memory mode */
+       struct resizer_ratio ratio;
+       int pm_state;
+       unsigned int applycrop:1;
+       enum isp_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+
+       struct {
+               struct v4l2_rect request;
+               struct v4l2_rect active;
+       } crop;
+};
+
+struct isp_device;
+
+int omap3isp_resizer_init(struct isp_device *isp);
+void omap3isp_resizer_cleanup(struct isp_device *isp);
+
+int omap3isp_resizer_register_entities(struct isp_res_device *res,
+                                      struct v4l2_device *vdev);
+void omap3isp_resizer_unregister_entities(struct isp_res_device *res);
+void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res);
+void omap3isp_resizer_isr(struct isp_res_device *isp_res);
+
+void omap3isp_resizer_max_rate(struct isp_res_device *res,
+                              unsigned int *max_rate);
+
+void omap3isp_resizer_suspend(struct isp_res_device *isp_res);
+
+void omap3isp_resizer_resume(struct isp_res_device *isp_res);
+
+int omap3isp_resizer_busy(struct isp_res_device *isp_res);
+
+#endif /* OMAP3_ISP_RESIZER_H */
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c
new file mode 100644 (file)
index 0000000..b44cb68
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ * ispstat.c
+ *
+ * TI OMAP3 ISP - Statistics core
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+
+#define IS_COHERENT_BUF(stat)  ((stat)->dma_ch >= 0)
+
+/*
+ * MAGIC_SIZE must always be the greatest common divisor of
+ * AEWB_PACKET_SIZE and AF_PAXEL_SIZE.
+ */
+#define MAGIC_SIZE             16
+#define MAGIC_NUM              0x55
+
+/* HACK: AF module seems to be writing one more paxel data than it should. */
+#define AF_EXTRA_DATA          OMAP3ISP_AF_PAXEL_SIZE
+
+/*
+ * HACK: H3A modules go to an invalid state after have a SBL overflow. It makes
+ * the next buffer to start to be written in the same point where the overflow
+ * occurred instead of the configured address. The only known way to make it to
+ * go back to a valid state is having a valid buffer processing. Of course it
+ * requires at least a doubled buffer size to avoid an access to invalid memory
+ * region. But it does not fix everything. It may happen more than one
+ * consecutive SBL overflows. In that case, it might be unpredictable how many
+ * buffers the allocated memory should fit. For that case, a recover
+ * configuration was created. It produces the minimum buffer size for each H3A
+ * module and decrease the change for more SBL overflows. This recover state
+ * will be enabled every time a SBL overflow occur. As the output buffer size
+ * isn't big, it's possible to have an extra size able to fit many recover
+ * buffers making it extreamily unlikely to have an access to invalid memory
+ * region.
+ */
+#define NUM_H3A_RECOVER_BUFS   10
+
+/*
+ * HACK: Because of HW issues the generic layer sometimes need to have
+ * different behaviour for different statistic modules.
+ */
+#define IS_H3A_AF(stat)                ((stat) == &(stat)->isp->isp_af)
+#define IS_H3A_AEWB(stat)      ((stat) == &(stat)->isp->isp_aewb)
+#define IS_H3A(stat)           (IS_H3A_AF(stat) || IS_H3A_AEWB(stat))
+
+static void __isp_stat_buf_sync_magic(struct ispstat *stat,
+                                     struct ispstat_buffer *buf,
+                                     u32 buf_size, enum dma_data_direction dir,
+                                     void (*dma_sync)(struct device *,
+                                       dma_addr_t, unsigned long, size_t,
+                                       enum dma_data_direction))
+{
+       struct device *dev = stat->isp->dev;
+       struct page *pg;
+       dma_addr_t dma_addr;
+       u32 offset;
+
+       /* Initial magic words */
+       pg = vmalloc_to_page(buf->virt_addr);
+       dma_addr = pfn_to_dma(dev, page_to_pfn(pg));
+       dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir);
+
+       /* Final magic words */
+       pg = vmalloc_to_page(buf->virt_addr + buf_size);
+       dma_addr = pfn_to_dma(dev, page_to_pfn(pg));
+       offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK;
+       dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir);
+}
+
+static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat,
+                                              struct ispstat_buffer *buf,
+                                              u32 buf_size,
+                                              enum dma_data_direction dir)
+{
+       if (IS_COHERENT_BUF(stat))
+               return;
+
+       __isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
+                                 dma_sync_single_range_for_device);
+}
+
+static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat,
+                                           struct ispstat_buffer *buf,
+                                           u32 buf_size,
+                                           enum dma_data_direction dir)
+{
+       if (IS_COHERENT_BUF(stat))
+               return;
+
+       __isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
+                                 dma_sync_single_range_for_cpu);
+}
+
+static int isp_stat_buf_check_magic(struct ispstat *stat,
+                                   struct ispstat_buffer *buf)
+{
+       const u32 buf_size = IS_H3A_AF(stat) ?
+                            buf->buf_size + AF_EXTRA_DATA : buf->buf_size;
+       u8 *w;
+       u8 *end;
+       int ret = -EINVAL;
+
+       isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
+
+       /* Checking initial magic numbers. They shouldn't be here anymore. */
+       for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++)
+               if (likely(*w != MAGIC_NUM))
+                       ret = 0;
+
+       if (ret) {
+               dev_dbg(stat->isp->dev, "%s: beginning magic check does not "
+                                       "match.\n", stat->subdev.name);
+               return ret;
+       }
+
+       /* Checking magic numbers at the end. They must be still here. */
+       for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE;
+            w < end; w++) {
+               if (unlikely(*w != MAGIC_NUM)) {
+                       dev_dbg(stat->isp->dev, "%s: endding magic check does "
+                               "not match.\n", stat->subdev.name);
+                       return -EINVAL;
+               }
+       }
+
+       isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
+                                          DMA_FROM_DEVICE);
+
+       return 0;
+}
+
+static void isp_stat_buf_insert_magic(struct ispstat *stat,
+                                     struct ispstat_buffer *buf)
+{
+       const u32 buf_size = IS_H3A_AF(stat) ?
+                            stat->buf_size + AF_EXTRA_DATA : stat->buf_size;
+
+       isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
+
+       /*
+        * Inserting MAGIC_NUM at the beginning and end of the buffer.
+        * buf->buf_size is set only after the buffer is queued. For now the
+        * right buf_size for the current configuration is pointed by
+        * stat->buf_size.
+        */
+       memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE);
+       memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE);
+
+       isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
+                                          DMA_BIDIRECTIONAL);
+}
+
+static void isp_stat_buf_sync_for_device(struct ispstat *stat,
+                                        struct ispstat_buffer *buf)
+{
+       if (IS_COHERENT_BUF(stat))
+               return;
+
+       dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl,
+                              buf->iovm->sgt->nents, DMA_FROM_DEVICE);
+}
+
+static void isp_stat_buf_sync_for_cpu(struct ispstat *stat,
+                                     struct ispstat_buffer *buf)
+{
+       if (IS_COHERENT_BUF(stat))
+               return;
+
+       dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl,
+                           buf->iovm->sgt->nents, DMA_FROM_DEVICE);
+}
+
+static void isp_stat_buf_clear(struct ispstat *stat)
+{
+       int i;
+
+       for (i = 0; i < STAT_MAX_BUFS; i++)
+               stat->buf[i].empty = 1;
+}
+
+static struct ispstat_buffer *
+__isp_stat_buf_find(struct ispstat *stat, int look_empty)
+{
+       struct ispstat_buffer *found = NULL;
+       int i;
+
+       for (i = 0; i < STAT_MAX_BUFS; i++) {
+               struct ispstat_buffer *curr = &stat->buf[i];
+
+               /*
+                * Don't select the buffer which is being copied to
+                * userspace or used by the module.
+                */
+               if (curr == stat->locked_buf || curr == stat->active_buf)
+                       continue;
+
+               /* Don't select uninitialised buffers if it's not required */
+               if (!look_empty && curr->empty)
+                       continue;
+
+               /* Pick uninitialised buffer over anything else if look_empty */
+               if (curr->empty) {
+                       found = curr;
+                       break;
+               }
+
+               /* Choose the oldest buffer */
+               if (!found ||
+                   (s32)curr->frame_number - (s32)found->frame_number < 0)
+                       found = curr;
+       }
+
+       return found;
+}
+
+static inline struct ispstat_buffer *
+isp_stat_buf_find_oldest(struct ispstat *stat)
+{
+       return __isp_stat_buf_find(stat, 0);
+}
+
+static inline struct ispstat_buffer *
+isp_stat_buf_find_oldest_or_empty(struct ispstat *stat)
+{
+       return __isp_stat_buf_find(stat, 1);
+}
+
+static int isp_stat_buf_queue(struct ispstat *stat)
+{
+       if (!stat->active_buf)
+               return STAT_NO_BUF;
+
+       do_gettimeofday(&stat->active_buf->ts);
+
+       stat->active_buf->buf_size = stat->buf_size;
+       if (isp_stat_buf_check_magic(stat, stat->active_buf)) {
+               dev_dbg(stat->isp->dev, "%s: data wasn't properly written.\n",
+                       stat->subdev.name);
+               return STAT_NO_BUF;
+       }
+       stat->active_buf->config_counter = stat->config_counter;
+       stat->active_buf->frame_number = stat->frame_number;
+       stat->active_buf->empty = 0;
+       stat->active_buf = NULL;
+
+       return STAT_BUF_DONE;
+}
+
+/* Get next free buffer to write the statistics to and mark it active. */
+static void isp_stat_buf_next(struct ispstat *stat)
+{
+       if (unlikely(stat->active_buf))
+               /* Overwriting unused active buffer */
+               dev_dbg(stat->isp->dev, "%s: new buffer requested without "
+                                       "queuing active one.\n",
+                                       stat->subdev.name);
+       else
+               stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat);
+}
+
+static void isp_stat_buf_release(struct ispstat *stat)
+{
+       unsigned long flags;
+
+       isp_stat_buf_sync_for_device(stat, stat->locked_buf);
+       spin_lock_irqsave(&stat->isp->stat_lock, flags);
+       stat->locked_buf = NULL;
+       spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+}
+
+/* Get buffer to userspace. */
+static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat,
+                                              struct omap3isp_stat_data *data)
+{
+       int rval = 0;
+       unsigned long flags;
+       struct ispstat_buffer *buf;
+
+       spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+       while (1) {
+               buf = isp_stat_buf_find_oldest(stat);
+               if (!buf) {
+                       spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+                       dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n",
+                               stat->subdev.name);
+                       return ERR_PTR(-EBUSY);
+               }
+               if (isp_stat_buf_check_magic(stat, buf)) {
+                       dev_dbg(stat->isp->dev, "%s: current buffer has "
+                               "corrupted data\n.", stat->subdev.name);
+                       /* Mark empty because it doesn't have valid data. */
+                       buf->empty = 1;
+               } else {
+                       /* Buffer isn't corrupted. */
+                       break;
+               }
+       }
+
+       stat->locked_buf = buf;
+
+       spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+       if (buf->buf_size > data->buf_size) {
+               dev_warn(stat->isp->dev, "%s: userspace's buffer size is "
+                                        "not enough.\n", stat->subdev.name);
+               isp_stat_buf_release(stat);
+               return ERR_PTR(-EINVAL);
+       }
+
+       isp_stat_buf_sync_for_cpu(stat, buf);
+
+       rval = copy_to_user(data->buf,
+                           buf->virt_addr,
+                           buf->buf_size);
+
+       if (rval) {
+               dev_info(stat->isp->dev,
+                        "%s: failed copying %d bytes of stat data\n",
+                        stat->subdev.name, rval);
+               buf = ERR_PTR(-EFAULT);
+               isp_stat_buf_release(stat);
+       }
+
+       return buf;
+}
+
+static void isp_stat_bufs_free(struct ispstat *stat)
+{
+       struct isp_device *isp = stat->isp;
+       int i;
+
+       for (i = 0; i < STAT_MAX_BUFS; i++) {
+               struct ispstat_buffer *buf = &stat->buf[i];
+
+               if (!IS_COHERENT_BUF(stat)) {
+                       if (IS_ERR_OR_NULL((void *)buf->iommu_addr))
+                               continue;
+                       if (buf->iovm)
+                               dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl,
+                                            buf->iovm->sgt->nents,
+                                            DMA_FROM_DEVICE);
+                       iommu_vfree(isp->iommu, buf->iommu_addr);
+               } else {
+                       if (!buf->virt_addr)
+                               continue;
+                       dma_free_coherent(stat->isp->dev, stat->buf_alloc_size,
+                                         buf->virt_addr, buf->dma_addr);
+               }
+               buf->iommu_addr = 0;
+               buf->iovm = NULL;
+               buf->dma_addr = 0;
+               buf->virt_addr = NULL;
+               buf->empty = 1;
+       }
+
+       dev_dbg(stat->isp->dev, "%s: all buffers were freed.\n",
+               stat->subdev.name);
+
+       stat->buf_alloc_size = 0;
+       stat->active_buf = NULL;
+}
+
+static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
+{
+       struct isp_device *isp = stat->isp;
+       int i;
+
+       stat->buf_alloc_size = size;
+
+       for (i = 0; i < STAT_MAX_BUFS; i++) {
+               struct ispstat_buffer *buf = &stat->buf[i];
+               struct iovm_struct *iovm;
+
+               WARN_ON(buf->dma_addr);
+               buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
+                                               IOMMU_FLAG);
+               if (IS_ERR((void *)buf->iommu_addr)) {
+                       dev_err(stat->isp->dev,
+                                "%s: Can't acquire memory for "
+                                "buffer %d\n", stat->subdev.name, i);
+                       isp_stat_bufs_free(stat);
+                       return -ENOMEM;
+               }
+
+               iovm = find_iovm_area(isp->iommu, buf->iommu_addr);
+               if (!iovm ||
+                   !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents,
+                               DMA_FROM_DEVICE)) {
+                       isp_stat_bufs_free(stat);
+                       return -ENOMEM;
+               }
+               buf->iovm = iovm;
+
+               buf->virt_addr = da_to_va(stat->isp->iommu,
+                                         (u32)buf->iommu_addr);
+               buf->empty = 1;
+               dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
+                       "iommu_addr=0x%08lx virt_addr=0x%08lx",
+                       stat->subdev.name, i, buf->iommu_addr,
+                       (unsigned long)buf->virt_addr);
+       }
+
+       return 0;
+}
+
+static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size)
+{
+       int i;
+
+       stat->buf_alloc_size = size;
+
+       for (i = 0; i < STAT_MAX_BUFS; i++) {
+               struct ispstat_buffer *buf = &stat->buf[i];
+
+               WARN_ON(buf->iommu_addr);
+               buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size,
+                                       &buf->dma_addr, GFP_KERNEL | GFP_DMA);
+
+               if (!buf->virt_addr || !buf->dma_addr) {
+                       dev_info(stat->isp->dev,
+                                "%s: Can't acquire memory for "
+                                "DMA buffer %d\n", stat->subdev.name, i);
+                       isp_stat_bufs_free(stat);
+                       return -ENOMEM;
+               }
+               buf->empty = 1;
+
+               dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
+                       "dma_addr=0x%08lx virt_addr=0x%08lx\n",
+                       stat->subdev.name, i, (unsigned long)buf->dma_addr,
+                       (unsigned long)buf->virt_addr);
+       }
+
+       return 0;
+}
+
+static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+       BUG_ON(stat->locked_buf != NULL);
+
+       /* Are the old buffers big enough? */
+       if (stat->buf_alloc_size >= size) {
+               spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+               return 0;
+       }
+
+       if (stat->state != ISPSTAT_DISABLED || stat->buf_processing) {
+               dev_info(stat->isp->dev,
+                        "%s: trying to allocate memory when busy\n",
+                        stat->subdev.name);
+               spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+               return -EBUSY;
+       }
+
+       spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+       isp_stat_bufs_free(stat);
+
+       if (IS_COHERENT_BUF(stat))
+               return isp_stat_bufs_alloc_dma(stat, size);
+       else
+               return isp_stat_bufs_alloc_iommu(stat, size);
+}
+
+static void isp_stat_queue_event(struct ispstat *stat, int err)
+{
+       struct video_device *vdev = &stat->subdev.devnode;
+       struct v4l2_event event;
+       struct omap3isp_stat_event_status *status = (void *)event.u.data;
+
+       memset(&event, 0, sizeof(event));
+       if (!err) {
+               status->frame_number = stat->frame_number;
+               status->config_counter = stat->config_counter;
+       } else {
+               status->buf_err = 1;
+       }
+       event.type = stat->event_type;
+       v4l2_event_queue(vdev, &event);
+}
+
+
+/*
+ * omap3isp_stat_request_statistics - Request statistics.
+ * @data: Pointer to return statistics data.
+ *
+ * Returns 0 if successful.
+ */
+int omap3isp_stat_request_statistics(struct ispstat *stat,
+                                    struct omap3isp_stat_data *data)
+{
+       struct ispstat_buffer *buf;
+
+       if (stat->state != ISPSTAT_ENABLED) {
+               dev_dbg(stat->isp->dev, "%s: engine not enabled.\n",
+                       stat->subdev.name);
+               return -EINVAL;
+       }
+
+       mutex_lock(&stat->ioctl_lock);
+       buf = isp_stat_buf_get(stat, data);
+       if (IS_ERR(buf)) {
+               mutex_unlock(&stat->ioctl_lock);
+               return PTR_ERR(buf);
+       }
+
+       data->ts = buf->ts;
+       data->config_counter = buf->config_counter;
+       data->frame_number = buf->frame_number;
+       data->buf_size = buf->buf_size;
+
+       buf->empty = 1;
+       isp_stat_buf_release(stat);
+       mutex_unlock(&stat->ioctl_lock);
+
+       return 0;
+}
+
+/*
+ * omap3isp_stat_config - Receives new statistic engine configuration.
+ * @new_conf: Pointer to config structure.
+ *
+ * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if
+ * was unable to allocate memory for the buffer, or other errors if parameters
+ * are invalid.
+ */
+int omap3isp_stat_config(struct ispstat *stat, void *new_conf)
+{
+       int ret;
+       unsigned long irqflags;
+       struct ispstat_generic_config *user_cfg = new_conf;
+       u32 buf_size = user_cfg->buf_size;
+
+       if (!new_conf) {
+               dev_dbg(stat->isp->dev, "%s: configuration is NULL\n",
+                       stat->subdev.name);
+               return -EINVAL;
+       }
+
+       mutex_lock(&stat->ioctl_lock);
+
+       dev_dbg(stat->isp->dev, "%s: configuring module with buffer "
+               "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size);
+
+       ret = stat->ops->validate_params(stat, new_conf);
+       if (ret) {
+               mutex_unlock(&stat->ioctl_lock);
+               dev_dbg(stat->isp->dev, "%s: configuration values are "
+                                       "invalid.\n", stat->subdev.name);
+               return ret;
+       }
+
+       if (buf_size != user_cfg->buf_size)
+               dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size "
+                       "request to 0x%08lx\n", stat->subdev.name,
+                       (unsigned long)user_cfg->buf_size);
+
+       /*
+        * Hack: H3A modules may need a doubled buffer size to avoid access
+        * to a invalid memory address after a SBL overflow.
+        * The buffer size is always PAGE_ALIGNED.
+        * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be
+        * inserted at the end to data integrity check purpose.
+        * Hack 3: AF module writes one paxel data more than it should, so
+        * the buffer allocation must consider it to avoid invalid memory
+        * access.
+        * Hack 4: H3A need to allocate extra space for the recover state.
+        */
+       if (IS_H3A(stat)) {
+               buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE;
+               if (IS_H3A_AF(stat))
+                       /*
+                        * Adding one extra paxel data size for each recover
+                        * buffer + 2 regular ones.
+                        */
+                       buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2);
+               if (stat->recover_priv) {
+                       struct ispstat_generic_config *recover_cfg =
+                               stat->recover_priv;
+                       buf_size += recover_cfg->buf_size *
+                                   NUM_H3A_RECOVER_BUFS;
+               }
+               buf_size = PAGE_ALIGN(buf_size);
+       } else { /* Histogram */
+               buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE);
+       }
+
+       ret = isp_stat_bufs_alloc(stat, buf_size);
+       if (ret) {
+               mutex_unlock(&stat->ioctl_lock);
+               return ret;
+       }
+
+       spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+       stat->ops->set_params(stat, new_conf);
+       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+
+       /*
+        * Returning the right future config_counter for this setup, so
+        * userspace can *know* when it has been applied.
+        */
+       user_cfg->config_counter = stat->config_counter + stat->inc_config;
+
+       /* Module has a valid configuration. */
+       stat->configured = 1;
+       dev_dbg(stat->isp->dev, "%s: module has been successfully "
+               "configured.\n", stat->subdev.name);
+
+       mutex_unlock(&stat->ioctl_lock);
+
+       return 0;
+}
+
+/*
+ * isp_stat_buf_process - Process statistic buffers.
+ * @buf_state: points out if buffer is ready to be processed. It's necessary
+ *            because histogram needs to copy the data from internal memory
+ *            before be able to process the buffer.
+ */
+static int isp_stat_buf_process(struct ispstat *stat, int buf_state)
+{
+       int ret = STAT_NO_BUF;
+
+       if (!atomic_add_unless(&stat->buf_err, -1, 0) &&
+           buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) {
+               ret = isp_stat_buf_queue(stat);
+               isp_stat_buf_next(stat);
+       }
+
+       return ret;
+}
+
+int omap3isp_stat_pcr_busy(struct ispstat *stat)
+{
+       return stat->ops->busy(stat);
+}
+
+int omap3isp_stat_busy(struct ispstat *stat)
+{
+       return omap3isp_stat_pcr_busy(stat) | stat->buf_processing |
+               (stat->state != ISPSTAT_DISABLED);
+}
+
+/*
+ * isp_stat_pcr_enable - Disables/Enables statistic engines.
+ * @pcr_enable: 0/1 - Disables/Enables the engine.
+ *
+ * Must be called from ISP driver when the module is idle and synchronized
+ * with CCDC.
+ */
+static void isp_stat_pcr_enable(struct ispstat *stat, u8 pcr_enable)
+{
+       if ((stat->state != ISPSTAT_ENABLING &&
+            stat->state != ISPSTAT_ENABLED) && pcr_enable)
+               /* Userspace has disabled the module. Aborting. */
+               return;
+
+       stat->ops->enable(stat, pcr_enable);
+       if (stat->state == ISPSTAT_DISABLING && !pcr_enable)
+               stat->state = ISPSTAT_DISABLED;
+       else if (stat->state == ISPSTAT_ENABLING && pcr_enable)
+               stat->state = ISPSTAT_ENABLED;
+}
+
+void omap3isp_stat_suspend(struct ispstat *stat)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&stat->isp->stat_lock, flags);
+
+       if (stat->state != ISPSTAT_DISABLED)
+               stat->ops->enable(stat, 0);
+       if (stat->state == ISPSTAT_ENABLED)
+               stat->state = ISPSTAT_SUSPENDED;
+
+       spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+}
+
+void omap3isp_stat_resume(struct ispstat *stat)
+{
+       /* Module will be re-enabled with its pipeline */
+       if (stat->state == ISPSTAT_SUSPENDED)
+               stat->state = ISPSTAT_ENABLING;
+}
+
+static void isp_stat_try_enable(struct ispstat *stat)
+{
+       unsigned long irqflags;
+
+       if (stat->priv == NULL)
+               /* driver wasn't initialised */
+               return;
+
+       spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+       if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing &&
+           stat->buf_alloc_size) {
+               /*
+                * Userspace's requested to enable the engine but it wasn't yet.
+                * Let's do that now.
+                */
+               stat->update = 1;
+               isp_stat_buf_next(stat);
+               stat->ops->setup_regs(stat, stat->priv);
+               isp_stat_buf_insert_magic(stat, stat->active_buf);
+
+               /*
+                * H3A module has some hw issues which forces the driver to
+                * ignore next buffers even if it was disabled in the meantime.
+                * On the other hand, Histogram shouldn't ignore buffers anymore
+                * if it's being enabled.
+                */
+               if (!IS_H3A(stat))
+                       atomic_set(&stat->buf_err, 0);
+
+               isp_stat_pcr_enable(stat, 1);
+               spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+               dev_dbg(stat->isp->dev, "%s: module is enabled.\n",
+                       stat->subdev.name);
+       } else {
+               spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+       }
+}
+
+void omap3isp_stat_isr_frame_sync(struct ispstat *stat)
+{
+       isp_stat_try_enable(stat);
+}
+
+void omap3isp_stat_sbl_overflow(struct ispstat *stat)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+       /*
+        * Due to a H3A hw issue which prevents the next buffer to start from
+        * the correct memory address, 2 buffers must be ignored.
+        */
+       atomic_set(&stat->buf_err, 2);
+
+       /*
+        * If more than one SBL overflow happen in a row, H3A module may access
+        * invalid memory region.
+        * stat->sbl_ovl_recover is set to tell to the driver to temporarily use
+        * a soft configuration which helps to avoid consecutive overflows.
+        */
+       if (stat->recover_priv)
+               stat->sbl_ovl_recover = 1;
+       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+}
+
+/*
+ * omap3isp_stat_enable - Disable/Enable statistic engine as soon as possible
+ * @enable: 0/1 - Disables/Enables the engine.
+ *
+ * Client should configure all the module registers before this.
+ * This function can be called from a userspace request.
+ */
+int omap3isp_stat_enable(struct ispstat *stat, u8 enable)
+{
+       unsigned long irqflags;
+
+       dev_dbg(stat->isp->dev, "%s: user wants to %s module.\n",
+               stat->subdev.name, enable ? "enable" : "disable");
+
+       /* Prevent enabling while configuring */
+       mutex_lock(&stat->ioctl_lock);
+
+       spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+
+       if (!stat->configured && enable) {
+               spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+               mutex_unlock(&stat->ioctl_lock);
+               dev_dbg(stat->isp->dev, "%s: cannot enable module as it's "
+                       "never been successfully configured so far.\n",
+                       stat->subdev.name);
+               return -EINVAL;
+       }
+
+       if (enable) {
+               if (stat->state == ISPSTAT_DISABLING)
+                       /* Previous disabling request wasn't done yet */
+                       stat->state = ISPSTAT_ENABLED;
+               else if (stat->state == ISPSTAT_DISABLED)
+                       /* Module is now being enabled */
+                       stat->state = ISPSTAT_ENABLING;
+       } else {
+               if (stat->state == ISPSTAT_ENABLING) {
+                       /* Previous enabling request wasn't done yet */
+                       stat->state = ISPSTAT_DISABLED;
+               } else if (stat->state == ISPSTAT_ENABLED) {
+                       /* Module is now being disabled */
+                       stat->state = ISPSTAT_DISABLING;
+                       isp_stat_buf_clear(stat);
+               }
+       }
+
+       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+       mutex_unlock(&stat->ioctl_lock);
+
+       return 0;
+}
+
+int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct ispstat *stat = v4l2_get_subdevdata(subdev);
+
+       if (enable) {
+               /*
+                * Only set enable PCR bit if the module was previously
+                * enabled through ioct.
+                */
+               isp_stat_try_enable(stat);
+       } else {
+               unsigned long flags;
+               /* Disable PCR bit and config enable field */
+               omap3isp_stat_enable(stat, 0);
+               spin_lock_irqsave(&stat->isp->stat_lock, flags);
+               stat->ops->enable(stat, 0);
+               spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
+
+               /*
+                * If module isn't busy, a new interrupt may come or not to
+                * set the state to DISABLED. As Histogram needs to read its
+                * internal memory to clear it, let interrupt handler
+                * responsible of changing state to DISABLED. If the last
+                * interrupt is coming, it's still safe as the handler will
+                * ignore the second time when state is already set to DISABLED.
+                * It's necessary to synchronize Histogram with streamoff, once
+                * the module may be considered idle before last SDMA transfer
+                * starts if we return here.
+                */
+               if (!omap3isp_stat_pcr_busy(stat))
+                       omap3isp_stat_isr(stat);
+
+               dev_dbg(stat->isp->dev, "%s: module is being disabled\n",
+                       stat->subdev.name);
+       }
+
+       return 0;
+}
+
+/*
+ * __stat_isr - Interrupt handler for statistic drivers
+ */
+static void __stat_isr(struct ispstat *stat, int from_dma)
+{
+       int ret = STAT_BUF_DONE;
+       int buf_processing;
+       unsigned long irqflags;
+       struct isp_pipeline *pipe;
+
+       /*
+        * stat->buf_processing must be set before disable module. It's
+        * necessary to not inform too early the buffers aren't busy in case
+        * of SDMA is going to be used.
+        */
+       spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+       if (stat->state == ISPSTAT_DISABLED) {
+               spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+               return;
+       }
+       buf_processing = stat->buf_processing;
+       stat->buf_processing = 1;
+       stat->ops->enable(stat, 0);
+
+       if (buf_processing && !from_dma) {
+               if (stat->state == ISPSTAT_ENABLED) {
+                       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+                       dev_err(stat->isp->dev,
+                               "%s: interrupt occurred when module was still "
+                               "processing a buffer.\n", stat->subdev.name);
+                       ret = STAT_NO_BUF;
+                       goto out;
+               } else {
+                       /*
+                        * Interrupt handler was called from streamoff when
+                        * the module wasn't busy anymore to ensure it is being
+                        * disabled after process last buffer. If such buffer
+                        * processing has already started, no need to do
+                        * anything else.
+                        */
+                       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+                       return;
+               }
+       }
+       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+
+       /* If it's busy we can't process this buffer anymore */
+       if (!omap3isp_stat_pcr_busy(stat)) {
+               if (!from_dma && stat->ops->buf_process)
+                       /* Module still need to copy data to buffer. */
+                       ret = stat->ops->buf_process(stat);
+               if (ret == STAT_BUF_WAITING_DMA)
+                       /* Buffer is not ready yet */
+                       return;
+
+               spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
+
+               /*
+                * Histogram needs to read its internal memory to clear it
+                * before be disabled. For that reason, common statistic layer
+                * can return only after call stat's buf_process() operator.
+                */
+               if (stat->state == ISPSTAT_DISABLING) {
+                       stat->state = ISPSTAT_DISABLED;
+                       spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+                       stat->buf_processing = 0;
+                       return;
+               }
+               pipe = to_isp_pipeline(&stat->subdev.entity);
+               stat->frame_number = atomic_read(&pipe->frame_number);
+
+               /*
+                * Before this point, 'ret' stores the buffer's status if it's
+                * ready to be processed. Afterwards, it holds the status if
+                * it was processed successfully.
+                */
+               ret = isp_stat_buf_process(stat, ret);
+
+               if (likely(!stat->sbl_ovl_recover)) {
+                       stat->ops->setup_regs(stat, stat->priv);
+               } else {
+                       /*
+                        * Using recover config to increase the chance to have
+                        * a good buffer processing and make the H3A module to
+                        * go back to a valid state.
+                        */
+                       stat->update = 1;
+                       stat->ops->setup_regs(stat, stat->recover_priv);
+                       stat->sbl_ovl_recover = 0;
+
+                       /*
+                        * Set 'update' in case of the module needs to use
+                        * regular configuration after next buffer.
+                        */
+                       stat->update = 1;
+               }
+
+               isp_stat_buf_insert_magic(stat, stat->active_buf);
+
+               /*
+                * Hack: H3A modules may access invalid memory address or send
+                * corrupted data to userspace if more than 1 SBL overflow
+                * happens in a row without re-writing its buffer's start memory
+                * address in the meantime. Such situation is avoided if the
+                * module is not immediately re-enabled when the ISR misses the
+                * timing to process the buffer and to setup the registers.
+                * Because of that, pcr_enable(1) was moved to inside this 'if'
+                * block. But the next interruption will still happen as during
+                * pcr_enable(0) the module was busy.
+                */
+               isp_stat_pcr_enable(stat, 1);
+               spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
+       } else {
+               /*
+                * If a SBL overflow occurs and the H3A driver misses the timing
+                * to process the buffer, stat->buf_err is set and won't be
+                * cleared now. So the next buffer will be correctly ignored.
+                * It's necessary due to a hw issue which makes the next H3A
+                * buffer to start from the memory address where the previous
+                * one stopped, instead of start where it was configured to.
+                * Do not "stat->buf_err = 0" here.
+                */
+
+               if (stat->ops->buf_process)
+                       /*
+                        * Driver may need to erase current data prior to
+                        * process a new buffer. If it misses the timing, the
+                        * next buffer might be wrong. So should be ignored.
+                        * It happens only for Histogram.
+                        */
+                       atomic_set(&stat->buf_err, 1);
+
+               ret = STAT_NO_BUF;
+               dev_dbg(stat->isp->dev, "%s: cannot process buffer, "
+                                       "device is busy.\n", stat->subdev.name);
+       }
+
+out:
+       stat->buf_processing = 0;
+       isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
+}
+
+void omap3isp_stat_isr(struct ispstat *stat)
+{
+       __stat_isr(stat, 0);
+}
+
+void omap3isp_stat_dma_isr(struct ispstat *stat)
+{
+       __stat_isr(stat, 1);
+}
+
+static int isp_stat_init_entities(struct ispstat *stat, const char *name,
+                                 const struct v4l2_subdev_ops *sd_ops)
+{
+       struct v4l2_subdev *subdev = &stat->subdev;
+       struct media_entity *me = &subdev->entity;
+
+       v4l2_subdev_init(subdev, sd_ops);
+       snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
+       subdev->grp_id = 1 << 16;       /* group ID for isp subdevs */
+       subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+       subdev->nevents = STAT_NEVENTS;
+       v4l2_set_subdevdata(subdev, stat);
+
+       stat->pad.flags = MEDIA_PAD_FL_SINK;
+       me->ops = NULL;
+
+       return media_entity_init(me, 1, &stat->pad, 0);
+}
+
+int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
+                                 struct v4l2_fh *fh,
+                                 struct v4l2_event_subscription *sub)
+{
+       struct ispstat *stat = v4l2_get_subdevdata(subdev);
+
+       if (sub->type != stat->event_type)
+               return -EINVAL;
+
+       return v4l2_event_subscribe(fh, sub);
+}
+
+int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
+                                   struct v4l2_fh *fh,
+                                   struct v4l2_event_subscription *sub)
+{
+       return v4l2_event_unsubscribe(fh, sub);
+}
+
+void omap3isp_stat_unregister_entities(struct ispstat *stat)
+{
+       media_entity_cleanup(&stat->subdev.entity);
+       v4l2_device_unregister_subdev(&stat->subdev);
+}
+
+int omap3isp_stat_register_entities(struct ispstat *stat,
+                                   struct v4l2_device *vdev)
+{
+       return v4l2_device_register_subdev(vdev, &stat->subdev);
+}
+
+int omap3isp_stat_init(struct ispstat *stat, const char *name,
+                      const struct v4l2_subdev_ops *sd_ops)
+{
+       stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL);
+       if (!stat->buf)
+               return -ENOMEM;
+       isp_stat_buf_clear(stat);
+       mutex_init(&stat->ioctl_lock);
+       atomic_set(&stat->buf_err, 0);
+
+       return isp_stat_init_entities(stat, name, sd_ops);
+}
+
+void omap3isp_stat_free(struct ispstat *stat)
+{
+       isp_stat_bufs_free(stat);
+       kfree(stat->buf);
+}
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h
new file mode 100644 (file)
index 0000000..820950c
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * ispstat.h
+ *
+ * TI OMAP3 ISP - Statistics core
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc
+ *
+ * Contacts: David Cohen <dacohen@gmail.com>
+ *          Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_STAT_H
+#define OMAP3_ISP_STAT_H
+
+#include <linux/types.h>
+#include <linux/omap3isp.h>
+#include <plat/dma.h>
+#include <media/v4l2-event.h>
+
+#include "isp.h"
+#include "ispvideo.h"
+
+#define STAT_MAX_BUFS          5
+#define STAT_NEVENTS           8
+
+#define STAT_BUF_DONE          0       /* Buffer is ready */
+#define STAT_NO_BUF            1       /* An error has occurred */
+#define STAT_BUF_WAITING_DMA   2       /* Histogram only: DMA is running */
+
+struct ispstat;
+
+struct ispstat_buffer {
+       unsigned long iommu_addr;
+       struct iovm_struct *iovm;
+       void *virt_addr;
+       dma_addr_t dma_addr;
+       struct timeval ts;
+       u32 buf_size;
+       u32 frame_number;
+       u16 config_counter;
+       u8 empty;
+};
+
+struct ispstat_ops {
+       /*
+        * Validate new params configuration.
+        * new_conf->buf_size value must be changed to the exact buffer size
+        * necessary for the new configuration if it's smaller.
+        */
+       int (*validate_params)(struct ispstat *stat, void *new_conf);
+
+       /*
+        * Save new params configuration.
+        * stat->priv->buf_size value must be set to the exact buffer size for
+        * the new configuration.
+        * stat->update is set to 1 if new configuration is different than
+        * current one.
+        */
+       void (*set_params)(struct ispstat *stat, void *new_conf);
+
+       /* Apply stored configuration. */
+       void (*setup_regs)(struct ispstat *stat, void *priv);
+
+       /* Enable/Disable module. */
+       void (*enable)(struct ispstat *stat, int enable);
+
+       /* Verify is module is busy. */
+       int (*busy)(struct ispstat *stat);
+
+       /* Used for specific operations during generic buf process task. */
+       int (*buf_process)(struct ispstat *stat);
+};
+
+enum ispstat_state_t {
+       ISPSTAT_DISABLED = 0,
+       ISPSTAT_DISABLING,
+       ISPSTAT_ENABLED,
+       ISPSTAT_ENABLING,
+       ISPSTAT_SUSPENDED,
+};
+
+struct ispstat {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;   /* sink pad */
+
+       /* Control */
+       unsigned configured:1;
+       unsigned update:1;
+       unsigned buf_processing:1;
+       unsigned sbl_ovl_recover:1;
+       u8 inc_config;
+       atomic_t buf_err;
+       enum ispstat_state_t state;     /* enabling/disabling state */
+       struct omap_dma_channel_params dma_config;
+       struct isp_device *isp;
+       void *priv;             /* pointer to priv config struct */
+       void *recover_priv;     /* pointer to recover priv configuration */
+       struct mutex ioctl_lock; /* serialize private ioctl */
+
+       const struct ispstat_ops *ops;
+
+       /* Buffer */
+       u8 wait_acc_frames;
+       u16 config_counter;
+       u32 frame_number;
+       u32 buf_size;
+       u32 buf_alloc_size;
+       int dma_ch;
+       unsigned long event_type;
+       struct ispstat_buffer *buf;
+       struct ispstat_buffer *active_buf;
+       struct ispstat_buffer *locked_buf;
+};
+
+struct ispstat_generic_config {
+       /*
+        * Fields must be in the same order as in:
+        *  - isph3a_aewb_config
+        *  - isph3a_af_config
+        *  - isphist_config
+        */
+       u32 buf_size;
+       u16 config_counter;
+};
+
+int omap3isp_stat_config(struct ispstat *stat, void *new_conf);
+int omap3isp_stat_request_statistics(struct ispstat *stat,
+                                    struct omap3isp_stat_data *data);
+int omap3isp_stat_init(struct ispstat *stat, const char *name,
+                      const struct v4l2_subdev_ops *sd_ops);
+void omap3isp_stat_free(struct ispstat *stat);
+int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
+                                 struct v4l2_fh *fh,
+                                 struct v4l2_event_subscription *sub);
+int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
+                                   struct v4l2_fh *fh,
+                                   struct v4l2_event_subscription *sub);
+int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable);
+
+int omap3isp_stat_busy(struct ispstat *stat);
+int omap3isp_stat_pcr_busy(struct ispstat *stat);
+void omap3isp_stat_suspend(struct ispstat *stat);
+void omap3isp_stat_resume(struct ispstat *stat);
+int omap3isp_stat_enable(struct ispstat *stat, u8 enable);
+void omap3isp_stat_sbl_overflow(struct ispstat *stat);
+void omap3isp_stat_isr(struct ispstat *stat);
+void omap3isp_stat_isr_frame_sync(struct ispstat *stat);
+void omap3isp_stat_dma_isr(struct ispstat *stat);
+int omap3isp_stat_register_entities(struct ispstat *stat,
+                                   struct v4l2_device *vdev);
+void omap3isp_stat_unregister_entities(struct ispstat *stat);
+
+#endif /* OMAP3_ISP_STAT_H */
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
new file mode 100644 (file)
index 0000000..a0bb5db
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * ispvideo.c
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/clk.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+#include <plat/omap-pm.h>
+
+#include "ispvideo.h"
+#include "isp.h"
+
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+static struct isp_format_info formats[] = {
+       { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, },
+       { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+       { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
+         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, },
+       { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
+         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, },
+       { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
+         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, },
+       { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
+         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, },
+       { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
+         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, },
+       { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
+         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, },
+       { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
+         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, },
+       { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
+         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, },
+       { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
+         V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, },
+       { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
+         V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, },
+};
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].code == code)
+                       return &formats[i];
+       }
+
+       return NULL;
+}
+
+/*
+ * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
+ * @video: ISP video instance
+ * @mbus: v4l2_mbus_framefmt format (input)
+ * @pix: v4l2_pix_format format (output)
+ *
+ * Fill the output pix structure with information from the input mbus format.
+ * The bytesperline and sizeimage fields are computed from the requested bytes
+ * per line value in the pix format and information from the video instance.
+ *
+ * Return the number of padding bytes at end of line.
+ */
+static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
+                                         const struct v4l2_mbus_framefmt *mbus,
+                                         struct v4l2_pix_format *pix)
+{
+       unsigned int bpl = pix->bytesperline;
+       unsigned int min_bpl;
+       unsigned int i;
+
+       memset(pix, 0, sizeof(*pix));
+       pix->width = mbus->width;
+       pix->height = mbus->height;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].code == mbus->code)
+                       break;
+       }
+
+       if (WARN_ON(i == ARRAY_SIZE(formats)))
+               return 0;
+
+       min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
+
+       /* Clamp the requested bytes per line value. If the maximum bytes per
+        * line value is zero, the module doesn't support user configurable line
+        * sizes. Override the requested value with the minimum in that case.
+        */
+       if (video->bpl_max)
+               bpl = clamp(bpl, min_bpl, video->bpl_max);
+       else
+               bpl = min_bpl;
+
+       if (!video->bpl_zero_padding || bpl != min_bpl)
+               bpl = ALIGN(bpl, video->bpl_alignment);
+
+       pix->pixelformat = formats[i].pixelformat;
+       pix->bytesperline = bpl;
+       pix->sizeimage = pix->bytesperline * pix->height;
+       pix->colorspace = mbus->colorspace;
+       pix->field = mbus->field;
+
+       return bpl - min_bpl;
+}
+
+static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
+                                 struct v4l2_mbus_framefmt *mbus)
+{
+       unsigned int i;
+
+       memset(mbus, 0, sizeof(*mbus));
+       mbus->width = pix->width;
+       mbus->height = pix->height;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].pixelformat == pix->pixelformat)
+                       break;
+       }
+
+       if (WARN_ON(i == ARRAY_SIZE(formats)))
+               return;
+
+       mbus->code = formats[i].code;
+       mbus->colorspace = pix->colorspace;
+       mbus->field = pix->field;
+}
+
+static struct v4l2_subdev *
+isp_video_remote_subdev(struct isp_video *video, u32 *pad)
+{
+       struct media_pad *remote;
+
+       remote = media_entity_remote_source(&video->pad);
+
+       if (remote == NULL ||
+           media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+               return NULL;
+
+       if (pad)
+               *pad = remote->index;
+
+       return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* Return a pointer to the ISP video instance at the far end of the pipeline. */
+static struct isp_video *
+isp_video_far_end(struct isp_video *video)
+{
+       struct media_entity_graph graph;
+       struct media_entity *entity = &video->video.entity;
+       struct media_device *mdev = entity->parent;
+       struct isp_video *far_end = NULL;
+
+       mutex_lock(&mdev->graph_mutex);
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               if (entity == &video->video.entity)
+                       continue;
+
+               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+                       continue;
+
+               far_end = to_isp_video(media_entity_to_video_device(entity));
+               if (far_end->type != video->type)
+                       break;
+
+               far_end = NULL;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
+       return far_end;
+}
+
+/*
+ * Validate a pipeline by checking both ends of all links for format
+ * discrepancies.
+ *
+ * Compute the minimum time per frame value as the maximum of time per frame
+ * limits reported by every block in the pipeline.
+ *
+ * Return 0 if all formats match, or -EPIPE if at least one link is found with
+ * different formats on its two ends.
+ */
+static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
+{
+       struct isp_device *isp = pipe->output->isp;
+       struct v4l2_subdev_format fmt_source;
+       struct v4l2_subdev_format fmt_sink;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       pipe->max_rate = pipe->l3_ick;
+
+       subdev = isp_video_remote_subdev(pipe->output, NULL);
+       if (subdev == NULL)
+               return -EPIPE;
+
+       while (1) {
+               /* Retrieve the sink format */
+               pad = &subdev->entity.pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               fmt_sink.pad = pad->index;
+               fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+               ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return -EPIPE;
+
+               /* Update the maximum frame rate */
+               if (subdev == &isp->isp_res.subdev)
+                       omap3isp_resizer_max_rate(&isp->isp_res,
+                                                 &pipe->max_rate);
+
+               /* Check ccdc maximum data rate when data comes from sensor
+                * TODO: Include ccdc rate in pipe->max_rate and compare the
+                *       total pipe rate with the input data rate from sensor.
+                */
+               if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
+                       unsigned int rate = UINT_MAX;
+
+                       omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+                       if (isp->isp_ccdc.vpcfg.pixelclk > rate)
+                               return -ENOSPC;
+               }
+
+               /* Retrieve the source format */
+               pad = media_entity_remote_source(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+               fmt_source.pad = pad->index;
+               fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+               ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return -EPIPE;
+
+               /* Check if the two ends match */
+               if (fmt_source.format.code != fmt_sink.format.code ||
+                   fmt_source.format.width != fmt_sink.format.width ||
+                   fmt_source.format.height != fmt_sink.format.height)
+                       return -EPIPE;
+       }
+
+       return 0;
+}
+
+static int
+__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
+{
+       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       subdev = isp_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+
+       fmt.pad = pad;
+       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+       if (ret == -ENOIOCTLCMD)
+               ret = -EINVAL;
+
+       mutex_unlock(&video->mutex);
+
+       if (ret)
+               return ret;
+
+       format->type = video->type;
+       return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+}
+
+static int
+isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
+{
+       struct v4l2_format format;
+       int ret;
+
+       memcpy(&format, &vfh->format, sizeof(format));
+       ret = __isp_video_get_format(video, &format);
+       if (ret < 0)
+               return ret;
+
+       if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
+           vfh->format.fmt.pix.height != format.fmt.pix.height ||
+           vfh->format.fmt.pix.width != format.fmt.pix.width ||
+           vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
+           vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
+               return -EINVAL;
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * IOMMU management
+ */
+
+#define IOMMU_FLAG     (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
+/*
+ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @sglist: Pointer to source Scatter gather list to allocate.
+ * @sglen: Number of elements of the scatter-gatter list.
+ *
+ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
+ * we ran out of memory.
+ */
+static dma_addr_t
+ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
+{
+       struct sg_table *sgt;
+       u32 da;
+
+       sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+       if (sgt == NULL)
+               return -ENOMEM;
+
+       sgt->sgl = (struct scatterlist *)sglist;
+       sgt->nents = sglen;
+       sgt->orig_nents = sglen;
+
+       da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
+       if (IS_ERR_VALUE(da))
+               kfree(sgt);
+
+       return da;
+}
+
+/*
+ * ispmmu_vunmap - Unmap a device address from the ISP MMU
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @da: Device address generated from a ispmmu_vmap call.
+ */
+static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
+{
+       struct sg_table *sgt;
+
+       sgt = iommu_vunmap(isp->iommu, (u32)da);
+       kfree(sgt);
+}
+
+/* -----------------------------------------------------------------------------
+ * Video queue operations
+ */
+
+static void isp_video_queue_prepare(struct isp_video_queue *queue,
+                                   unsigned int *nbuffers, unsigned int *size)
+{
+       struct isp_video_fh *vfh =
+               container_of(queue, struct isp_video_fh, queue);
+       struct isp_video *video = vfh->video;
+
+       *size = vfh->format.fmt.pix.sizeimage;
+       if (*size == 0)
+               return;
+
+       *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
+}
+
+static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
+{
+       struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+       struct isp_buffer *buffer = to_isp_buffer(buf);
+       struct isp_video *video = vfh->video;
+
+       if (buffer->isp_addr) {
+               ispmmu_vunmap(video->isp, buffer->isp_addr);
+               buffer->isp_addr = 0;
+       }
+}
+
+static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
+{
+       struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+       struct isp_buffer *buffer = to_isp_buffer(buf);
+       struct isp_video *video = vfh->video;
+       unsigned long addr;
+
+       addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
+       if (IS_ERR_VALUE(addr))
+               return -EIO;
+
+       if (!IS_ALIGNED(addr, 32)) {
+               dev_dbg(video->isp->dev, "Buffer address must be "
+                       "aligned to 32 bytes boundary.\n");
+               ispmmu_vunmap(video->isp, buffer->isp_addr);
+               return -EINVAL;
+       }
+
+       buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
+       buffer->isp_addr = addr;
+       return 0;
+}
+
+/*
+ * isp_video_buffer_queue - Add buffer to streaming queue
+ * @buf: Video buffer
+ *
+ * In memory-to-memory mode, start streaming on the pipeline if buffers are
+ * queued on both the input and the output, if the pipeline isn't already busy.
+ * If the pipeline is busy, it will be restarted in the output module interrupt
+ * handler.
+ */
+static void isp_video_buffer_queue(struct isp_video_buffer *buf)
+{
+       struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
+       struct isp_buffer *buffer = to_isp_buffer(buf);
+       struct isp_video *video = vfh->video;
+       struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+       enum isp_pipeline_state state;
+       unsigned long flags;
+       unsigned int empty;
+       unsigned int start;
+
+       empty = list_empty(&video->dmaqueue);
+       list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
+
+       if (empty) {
+               if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       state = ISP_PIPELINE_QUEUE_OUTPUT;
+               else
+                       state = ISP_PIPELINE_QUEUE_INPUT;
+
+               spin_lock_irqsave(&pipe->lock, flags);
+               pipe->state |= state;
+               video->ops->queue(video, buffer);
+               video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+
+               start = isp_pipeline_ready(pipe);
+               if (start)
+                       pipe->state |= ISP_PIPELINE_STREAM;
+               spin_unlock_irqrestore(&pipe->lock, flags);
+
+               if (start)
+                       omap3isp_pipeline_set_stream(pipe,
+                                               ISP_PIPELINE_STREAM_SINGLESHOT);
+       }
+}
+
+static const struct isp_video_queue_operations isp_video_queue_ops = {
+       .queue_prepare = &isp_video_queue_prepare,
+       .buffer_prepare = &isp_video_buffer_prepare,
+       .buffer_queue = &isp_video_buffer_queue,
+       .buffer_cleanup = &isp_video_buffer_cleanup,
+};
+
+/*
+ * omap3isp_video_buffer_next - Complete the current buffer and return the next
+ * @video: ISP video object
+ * @error: Whether an error occured during capture
+ *
+ * Remove the current video buffer from the DMA queue and fill its timestamp,
+ * field count and state fields before waking up its completion handler.
+ *
+ * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0)
+ * or VIDEOBUF_ERROR otherwise (@error is non-zero).
+ *
+ * The DMA queue is expected to contain at least one buffer.
+ *
+ * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
+ * empty.
+ */
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
+                                             unsigned int error)
+{
+       struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+       struct isp_video_queue *queue = video->queue;
+       enum isp_pipeline_state state;
+       struct isp_video_buffer *buf;
+       unsigned long flags;
+       struct timespec ts;
+
+       spin_lock_irqsave(&queue->irqlock, flags);
+       if (WARN_ON(list_empty(&video->dmaqueue))) {
+               spin_unlock_irqrestore(&queue->irqlock, flags);
+               return NULL;
+       }
+
+       buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+                              irqlist);
+       list_del(&buf->irqlist);
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+
+       ktime_get_ts(&ts);
+       buf->vbuf.timestamp.tv_sec = ts.tv_sec;
+       buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+       /* Do frame number propagation only if this is the output video node.
+        * Frame number either comes from the CSI receivers or it gets
+        * incremented here if H3A is not active.
+        * Note: There is no guarantee that the output buffer will finish
+        * first, so the input number might lag behind by 1 in some cases.
+        */
+       if (video == pipe->output && !pipe->do_propagation)
+               buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
+       else
+               buf->vbuf.sequence = atomic_read(&pipe->frame_number);
+
+       buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;
+
+       wake_up(&buf->wait);
+
+       if (list_empty(&video->dmaqueue)) {
+               if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       state = ISP_PIPELINE_QUEUE_OUTPUT
+                             | ISP_PIPELINE_STREAM;
+               else
+                       state = ISP_PIPELINE_QUEUE_INPUT
+                             | ISP_PIPELINE_STREAM;
+
+               spin_lock_irqsave(&pipe->lock, flags);
+               pipe->state &= ~state;
+               if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
+                       video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+               spin_unlock_irqrestore(&pipe->lock, flags);
+               return NULL;
+       }
+
+       if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
+               spin_lock_irqsave(&pipe->lock, flags);
+               pipe->state &= ~ISP_PIPELINE_STREAM;
+               spin_unlock_irqrestore(&pipe->lock, flags);
+       }
+
+       buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
+                              irqlist);
+       buf->state = ISP_BUF_STATE_ACTIVE;
+       return to_isp_buffer(buf);
+}
+
+/*
+ * omap3isp_video_resume - Perform resume operation on the buffers
+ * @video: ISP video object
+ * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise
+ *
+ * This function is intended to be used on suspend/resume scenario. It
+ * requests video queue layer to discard buffers marked as DONE if it's in
+ * continuous mode and requests ISP modules to queue again the ACTIVE buffer
+ * if there's any.
+ */
+void omap3isp_video_resume(struct isp_video *video, int continuous)
+{
+       struct isp_buffer *buf = NULL;
+
+       if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               omap3isp_video_queue_discard_done(video->queue);
+
+       if (!list_empty(&video->dmaqueue)) {
+               buf = list_first_entry(&video->dmaqueue,
+                                      struct isp_buffer, buffer.irqlist);
+               video->ops->queue(video, buf);
+               video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
+       } else {
+               if (continuous)
+                       video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+       struct isp_video *video = video_drvdata(file);
+
+       strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, video->video.name, sizeof(cap->card));
+       strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+       cap->version = ISP_VIDEO_DRIVER_VERSION;
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       else
+               cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int
+isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       *format = vfh->format;
+       mutex_unlock(&video->mutex);
+
+       return 0;
+}
+
+static int
+isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_mbus_framefmt fmt;
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+
+       /* Fill the bytesperline and sizeimage fields by converting to media bus
+        * format and back to pixel format.
+        */
+       isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
+       isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
+
+       vfh->format = *format;
+
+       mutex_unlock(&video->mutex);
+       return 0;
+}
+
+static int
+isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       subdev = isp_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
+
+       fmt.pad = pad;
+       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+       if (ret)
+               return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+       isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+       return 0;
+}
+
+static int
+isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       subdev = isp_video_remote_subdev(video, NULL);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
+       mutex_unlock(&video->mutex);
+
+       return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_subdev_format format;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       subdev = isp_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       /* Try the get crop operation first and fallback to get format if not
+        * implemented.
+        */
+       ret = v4l2_subdev_call(subdev, video, g_crop, crop);
+       if (ret != -ENOIOCTLCMD)
+               return ret;
+
+       format.pad = pad;
+       format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
+       if (ret < 0)
+               return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+       crop->c.left = 0;
+       crop->c.top = 0;
+       crop->c.width = format.format.width;
+       crop->c.height = format.format.height;
+
+       return 0;
+}
+
+static int
+isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       subdev = isp_video_remote_subdev(video, NULL);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       ret = v4l2_subdev_call(subdev, video, s_crop, crop);
+       mutex_unlock(&video->mutex);
+
+       return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+static int
+isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+
+       if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+           video->type != a->type)
+               return -EINVAL;
+
+       memset(a, 0, sizeof(*a));
+       a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       a->parm.output.timeperframe = vfh->timeperframe;
+
+       return 0;
+}
+
+static int
+isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+
+       if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+           video->type != a->type)
+               return -EINVAL;
+
+       if (a->parm.output.timeperframe.denominator == 0)
+               a->parm.output.timeperframe.denominator = 1;
+
+       vfh->timeperframe = a->parm.output.timeperframe;
+
+       return 0;
+}
+
+static int
+isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+       return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
+}
+
+static int
+isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+       return omap3isp_video_queue_querybuf(&vfh->queue, b);
+}
+
+static int
+isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+       return omap3isp_video_queue_qbuf(&vfh->queue, b);
+}
+
+static int
+isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+
+       return omap3isp_video_queue_dqbuf(&vfh->queue, b,
+                                         file->f_flags & O_NONBLOCK);
+}
+
+/*
+ * Stream management
+ *
+ * Every ISP pipeline has a single input and a single output. The input can be
+ * either a sensor or a video node. The output is always a video node.
+ *
+ * As every pipeline has an output video node, the ISP video objects at the
+ * pipeline output stores the pipeline state. It tracks the streaming state of
+ * both the input and output, as well as the availability of buffers.
+ *
+ * In sensor-to-memory mode, frames are always available at the pipeline input.
+ * Starting the sensor usually requires I2C transfers and must be done in
+ * interruptible context. The pipeline is started and stopped synchronously
+ * to the stream on/off commands. All modules in the pipeline will get their
+ * subdev set stream handler called. The module at the end of the pipeline must
+ * delay starting the hardware until buffers are available at its output.
+ *
+ * In memory-to-memory mode, starting/stopping the stream requires
+ * synchronization between the input and output. ISP modules can't be stopped
+ * in the middle of a frame, and at least some of the modules seem to become
+ * busy as soon as they're started, even if they don't receive a frame start
+ * event. For that reason frames need to be processed in single-shot mode. The
+ * driver needs to wait until a frame is completely processed and written to
+ * memory before restarting the pipeline for the next frame. Pipelined
+ * processing might be possible but requires more testing.
+ *
+ * Stream start must be delayed until buffers are available at both the input
+ * and output. The pipeline must be started in the videobuf queue callback with
+ * the buffers queue spinlock held. The modules subdev set stream operation must
+ * not sleep.
+ */
+static int
+isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       enum isp_pipeline_state state;
+       struct isp_pipeline *pipe;
+       struct isp_video *far_end;
+       unsigned long flags;
+       int ret;
+
+       if (type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->stream_lock);
+
+       if (video->streaming) {
+               mutex_unlock(&video->stream_lock);
+               return -EBUSY;
+       }
+
+       /* Start streaming on the pipeline. No link touching an entity in the
+        * pipeline can be activated or deactivated once streaming is started.
+        */
+       pipe = video->video.entity.pipe
+            ? to_isp_pipeline(&video->video.entity) : &video->pipe;
+       media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+
+       /* Verify that the currently configured format matches the output of
+        * the connected subdev.
+        */
+       ret = isp_video_check_format(video, vfh);
+       if (ret < 0)
+               goto error;
+
+       video->bpl_padding = ret;
+       video->bpl_value = vfh->format.fmt.pix.bytesperline;
+
+       /* Find the ISP video node connected at the far end of the pipeline and
+        * update the pipeline.
+        */
+       far_end = isp_video_far_end(video);
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
+               pipe->input = far_end;
+               pipe->output = video;
+       } else {
+               if (far_end == NULL) {
+                       ret = -EPIPE;
+                       goto error;
+               }
+
+               state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
+               pipe->input = video;
+               pipe->output = far_end;
+       }
+
+       if (video->isp->pdata->set_constraints)
+               video->isp->pdata->set_constraints(video->isp, true);
+       pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+
+       /* Validate the pipeline and update its state. */
+       ret = isp_video_validate_pipeline(pipe);
+       if (ret < 0)
+               goto error;
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~ISP_PIPELINE_STREAM;
+       pipe->state |= state;
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       /* Set the maximum time per frame as the value requested by userspace.
+        * This is a soft limit that can be overridden if the hardware doesn't
+        * support the request limit.
+        */
+       if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               pipe->max_timeperframe = vfh->timeperframe;
+
+       video->queue = &vfh->queue;
+       INIT_LIST_HEAD(&video->dmaqueue);
+       atomic_set(&pipe->frame_number, -1);
+
+       ret = omap3isp_video_queue_streamon(&vfh->queue);
+       if (ret < 0)
+               goto error;
+
+       /* In sensor-to-memory mode, the stream can be started synchronously
+        * to the stream on command. In memory-to-memory mode, it will be
+        * started when buffers are queued on both the input and output.
+        */
+       if (pipe->input == NULL) {
+               ret = omap3isp_pipeline_set_stream(pipe,
+                                             ISP_PIPELINE_STREAM_CONTINUOUS);
+               if (ret < 0)
+                       goto error;
+               spin_lock_irqsave(&video->queue->irqlock, flags);
+               if (list_empty(&video->dmaqueue))
+                       video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
+               spin_unlock_irqrestore(&video->queue->irqlock, flags);
+       }
+
+error:
+       if (ret < 0) {
+               omap3isp_video_queue_streamoff(&vfh->queue);
+               if (video->isp->pdata->set_constraints)
+                       video->isp->pdata->set_constraints(video->isp, false);
+               media_entity_pipeline_stop(&video->video.entity);
+               video->queue = NULL;
+       }
+
+       if (!ret)
+               video->streaming = 1;
+
+       mutex_unlock(&video->stream_lock);
+       return ret;
+}
+
+static int
+isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(fh);
+       struct isp_video *video = video_drvdata(file);
+       struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
+       enum isp_pipeline_state state;
+       unsigned int streaming;
+       unsigned long flags;
+
+       if (type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->stream_lock);
+
+       /* Make sure we're not streaming yet. */
+       mutex_lock(&vfh->queue.lock);
+       streaming = vfh->queue.streaming;
+       mutex_unlock(&vfh->queue.lock);
+
+       if (!streaming)
+               goto done;
+
+       /* Update the pipeline state. */
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               state = ISP_PIPELINE_STREAM_OUTPUT
+                     | ISP_PIPELINE_QUEUE_OUTPUT;
+       else
+               state = ISP_PIPELINE_STREAM_INPUT
+                     | ISP_PIPELINE_QUEUE_INPUT;
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~state;
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       /* Stop the stream. */
+       omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
+       omap3isp_video_queue_streamoff(&vfh->queue);
+       video->queue = NULL;
+       video->streaming = 0;
+
+       if (video->isp->pdata->set_constraints)
+               video->isp->pdata->set_constraints(video->isp, false);
+       media_entity_pipeline_stop(&video->video.entity);
+
+done:
+       mutex_unlock(&video->stream_lock);
+       return 0;
+}
+
+static int
+isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
+{
+       if (input->index > 0)
+               return -EINVAL;
+
+       strlcpy(input->name, "camera", sizeof(input->name));
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int
+isp_video_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       *input = 0;
+
+       return 0;
+}
+
+static int
+isp_video_s_input(struct file *file, void *fh, unsigned int input)
+{
+       return input == 0 ? 0 : -EINVAL;
+}
+
+static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
+       .vidioc_querycap                = isp_video_querycap,
+       .vidioc_g_fmt_vid_cap           = isp_video_get_format,
+       .vidioc_s_fmt_vid_cap           = isp_video_set_format,
+       .vidioc_try_fmt_vid_cap         = isp_video_try_format,
+       .vidioc_g_fmt_vid_out           = isp_video_get_format,
+       .vidioc_s_fmt_vid_out           = isp_video_set_format,
+       .vidioc_try_fmt_vid_out         = isp_video_try_format,
+       .vidioc_cropcap                 = isp_video_cropcap,
+       .vidioc_g_crop                  = isp_video_get_crop,
+       .vidioc_s_crop                  = isp_video_set_crop,
+       .vidioc_g_parm                  = isp_video_get_param,
+       .vidioc_s_parm                  = isp_video_set_param,
+       .vidioc_reqbufs                 = isp_video_reqbufs,
+       .vidioc_querybuf                = isp_video_querybuf,
+       .vidioc_qbuf                    = isp_video_qbuf,
+       .vidioc_dqbuf                   = isp_video_dqbuf,
+       .vidioc_streamon                = isp_video_streamon,
+       .vidioc_streamoff               = isp_video_streamoff,
+       .vidioc_enum_input              = isp_video_enum_input,
+       .vidioc_g_input                 = isp_video_g_input,
+       .vidioc_s_input                 = isp_video_s_input,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int isp_video_open(struct file *file)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct isp_video_fh *handle;
+       int ret = 0;
+
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       if (handle == NULL)
+               return -ENOMEM;
+
+       v4l2_fh_init(&handle->vfh, &video->video);
+       v4l2_fh_add(&handle->vfh);
+
+       /* If this is the first user, initialise the pipeline. */
+       if (omap3isp_get(video->isp) == NULL) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
+       if (ret < 0) {
+               omap3isp_put(video->isp);
+               goto done;
+       }
+
+       omap3isp_video_queue_init(&handle->queue, video->type,
+                                 &isp_video_queue_ops, video->isp->dev,
+                                 sizeof(struct isp_buffer));
+
+       memset(&handle->format, 0, sizeof(handle->format));
+       handle->format.type = video->type;
+       handle->timeperframe.denominator = 1;
+
+       handle->video = video;
+       file->private_data = &handle->vfh;
+
+done:
+       if (ret < 0) {
+               v4l2_fh_del(&handle->vfh);
+               kfree(handle);
+       }
+
+       return ret;
+}
+
+static int isp_video_release(struct file *file)
+{
+       struct isp_video *video = video_drvdata(file);
+       struct v4l2_fh *vfh = file->private_data;
+       struct isp_video_fh *handle = to_isp_video_fh(vfh);
+
+       /* Disable streaming and free the buffers queue resources. */
+       isp_video_streamoff(file, vfh, video->type);
+
+       mutex_lock(&handle->queue.lock);
+       omap3isp_video_queue_cleanup(&handle->queue);
+       mutex_unlock(&handle->queue.lock);
+
+       omap3isp_pipeline_pm_use(&video->video.entity, 0);
+
+       /* Release the file handle. */
+       v4l2_fh_del(vfh);
+       kfree(handle);
+       file->private_data = NULL;
+
+       omap3isp_put(video->isp);
+
+       return 0;
+}
+
+static unsigned int isp_video_poll(struct file *file, poll_table *wait)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+       struct isp_video_queue *queue = &vfh->queue;
+
+       return omap3isp_video_queue_poll(queue, file, wait);
+}
+
+static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
+
+       return omap3isp_video_queue_mmap(&vfh->queue, vma);
+}
+
+static struct v4l2_file_operations isp_video_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = video_ioctl2,
+       .open = isp_video_open,
+       .release = isp_video_release,
+       .poll = isp_video_poll,
+       .mmap = isp_video_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * ISP video core
+ */
+
+static const struct isp_video_operations isp_video_dummy_ops = {
+};
+
+int omap3isp_video_init(struct isp_video *video, const char *name)
+{
+       const char *direction;
+       int ret;
+
+       switch (video->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               direction = "output";
+               video->pad.flags = MEDIA_PAD_FL_SINK;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               direction = "input";
+               video->pad.flags = MEDIA_PAD_FL_SOURCE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&video->mutex);
+       atomic_set(&video->active, 0);
+
+       spin_lock_init(&video->pipe.lock);
+       mutex_init(&video->stream_lock);
+
+       /* Initialize the video device. */
+       if (video->ops == NULL)
+               video->ops = &isp_video_dummy_ops;
+
+       video->video.fops = &isp_video_fops;
+       snprintf(video->video.name, sizeof(video->video.name),
+                "OMAP3 ISP %s %s", name, direction);
+       video->video.vfl_type = VFL_TYPE_GRABBER;
+       video->video.release = video_device_release_empty;
+       video->video.ioctl_ops = &isp_video_ioctl_ops;
+       video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
+
+       video_set_drvdata(&video->video, video);
+
+       return 0;
+}
+
+int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
+{
+       int ret;
+
+       video->video.v4l2_dev = vdev;
+
+       ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+       if (ret < 0)
+               printk(KERN_ERR "%s: could not register video device (%d)\n",
+                       __func__, ret);
+
+       return ret;
+}
+
+void omap3isp_video_unregister(struct isp_video *video)
+{
+       if (video_is_registered(&video->video)) {
+               media_entity_cleanup(&video->video.entity);
+               video_unregister_device(&video->video);
+       }
+}
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
new file mode 100644 (file)
index 0000000..524a1ac
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * ispvideo.h
+ *
+ * TI OMAP3 ISP - Generic video node
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_VIDEO_H
+#define OMAP3_ISP_VIDEO_H
+
+#include <linux/v4l2-mediabus.h>
+#include <linux/version.h>
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include "ispqueue.h"
+
+#define ISP_VIDEO_DRIVER_NAME          "ispvideo"
+#define ISP_VIDEO_DRIVER_VERSION       KERNEL_VERSION(0, 0, 1)
+
+struct isp_device;
+struct isp_video;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+
+/*
+ * struct isp_format_info - ISP media bus format information
+ * @code: V4L2 media bus format code
+ * @truncated: V4L2 media bus format code for the same format truncated to 10
+ *     bits. Identical to @code if the format is 10 bits wide or less.
+ * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
+ *     format. Identical to @code if the format is not DPCM compressed.
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @bpp: Bits per pixel
+ */
+struct isp_format_info {
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_mbus_pixelcode truncated;
+       enum v4l2_mbus_pixelcode uncompressed;
+       u32 pixelformat;
+       unsigned int bpp;
+};
+
+enum isp_pipeline_stream_state {
+       ISP_PIPELINE_STREAM_STOPPED = 0,
+       ISP_PIPELINE_STREAM_CONTINUOUS = 1,
+       ISP_PIPELINE_STREAM_SINGLESHOT = 2,
+};
+
+enum isp_pipeline_state {
+       /* The stream has been started on the input video node. */
+       ISP_PIPELINE_STREAM_INPUT = 1,
+       /* The stream has been started on the output video node. */
+       ISP_PIPELINE_STREAM_OUTPUT = 2,
+       /* At least one buffer is queued on the input video node. */
+       ISP_PIPELINE_QUEUE_INPUT = 4,
+       /* At least one buffer is queued on the output video node. */
+       ISP_PIPELINE_QUEUE_OUTPUT = 8,
+       /* The input entity is idle, ready to be started. */
+       ISP_PIPELINE_IDLE_INPUT = 16,
+       /* The output entity is idle, ready to be started. */
+       ISP_PIPELINE_IDLE_OUTPUT = 32,
+       /* The pipeline is currently streaming. */
+       ISP_PIPELINE_STREAM = 64,
+};
+
+struct isp_pipeline {
+       struct media_pipeline pipe;
+       spinlock_t lock;                /* Pipeline state and queue flags */
+       unsigned int state;
+       enum isp_pipeline_stream_state stream_state;
+       struct isp_video *input;
+       struct isp_video *output;
+       unsigned long l3_ick;
+       unsigned int max_rate;
+       atomic_t frame_number;
+       bool do_propagation; /* of frame number */
+       struct v4l2_fract max_timeperframe;
+};
+
+#define to_isp_pipeline(__e) \
+       container_of((__e)->pipe, struct isp_pipeline, pipe)
+
+static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
+{
+       return pipe->state == (ISP_PIPELINE_STREAM_INPUT |
+                              ISP_PIPELINE_STREAM_OUTPUT |
+                              ISP_PIPELINE_QUEUE_INPUT |
+                              ISP_PIPELINE_QUEUE_OUTPUT |
+                              ISP_PIPELINE_IDLE_INPUT |
+                              ISP_PIPELINE_IDLE_OUTPUT);
+}
+
+/*
+ * struct isp_buffer - ISP buffer
+ * @buffer: ISP video buffer
+ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
+ */
+struct isp_buffer {
+       struct isp_video_buffer buffer;
+       dma_addr_t isp_addr;
+};
+
+#define to_isp_buffer(buf)     container_of(buf, struct isp_buffer, buffer)
+
+enum isp_video_dmaqueue_flags {
+       /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */
+       ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
+       /* Set when queuing buffer to an empty DMA queue */
+       ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
+};
+
+#define isp_video_dmaqueue_flags_clr(video)    \
+                       ({ (video)->dmaqueue_flags = 0; })
+
+/*
+ * struct isp_video_operations - ISP video operations
+ * @queue:     Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
+ *             if there was no buffer previously queued.
+ */
+struct isp_video_operations {
+       int(*queue)(struct isp_video *video, struct isp_buffer *buffer);
+};
+
+struct isp_video {
+       struct video_device video;
+       enum v4l2_buf_type type;
+       struct media_pad pad;
+
+       struct mutex mutex;             /* format and crop settings */
+       atomic_t active;
+
+       struct isp_device *isp;
+
+       unsigned int capture_mem;
+       unsigned int bpl_alignment;     /* alignment value */
+       unsigned int bpl_zero_padding;  /* whether the alignment is optional */
+       unsigned int bpl_max;           /* maximum bytes per line value */
+       unsigned int bpl_value;         /* bytes per line value */
+       unsigned int bpl_padding;       /* padding at end of line */
+
+       /* Entity video node streaming */
+       unsigned int streaming:1;
+
+       /* Pipeline state */
+       struct isp_pipeline pipe;
+       struct mutex stream_lock;       /* pipeline and stream states */
+
+       /* Video buffers queue */
+       struct isp_video_queue *queue;
+       struct list_head dmaqueue;
+       enum isp_video_dmaqueue_flags dmaqueue_flags;
+
+       const struct isp_video_operations *ops;
+};
+
+#define to_isp_video(vdev)     container_of(vdev, struct isp_video, video)
+
+struct isp_video_fh {
+       struct v4l2_fh vfh;
+       struct isp_video *video;
+       struct isp_video_queue queue;
+       struct v4l2_format format;
+       struct v4l2_fract timeperframe;
+};
+
+#define to_isp_video_fh(fh)    container_of(fh, struct isp_video_fh, vfh)
+#define isp_video_queue_to_isp_video_fh(q) \
+                               container_of(q, struct isp_video_fh, queue)
+
+int omap3isp_video_init(struct isp_video *video, const char *name);
+int omap3isp_video_register(struct isp_video *video,
+                           struct v4l2_device *vdev);
+void omap3isp_video_unregister(struct isp_video *video);
+struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
+                                             unsigned int error);
+void omap3isp_video_resume(struct isp_video *video, int continuous);
+struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
+
+const struct isp_format_info *
+omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
+
+#endif /* OMAP3_ISP_VIDEO_H */
diff --git a/drivers/media/video/omap3isp/luma_enhance_table.h b/drivers/media/video/omap3isp/luma_enhance_table.h
new file mode 100644 (file)
index 0000000..098b45e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * luma_enhance_table.h
+ *
+ * TI OMAP3 ISP - Luminance enhancement table
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552,
+1047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503,
+1044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311,
+1036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096,
+1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096,
+1028096, 1028100, 1032196, 1036292, 1040388, 1044484,       0,       0,
+      0,       5,    5125,   10245,   15365,   20485,   25605,   30720,
+  30720,   30720,   30720,   30720,   30720,   30720,   30720,   30720,
+  30720,   30720,   31743,   30719,   29695,   28671,   27647,   26623,
+  25599,   24575,   23551,   22527,   21503,   20479,   19455,   18431,
+  17407,   16383,   15359,   14335,   13311,   12287,   11263,   10239,
+   9215,    8191,    7167,    6143,    5119,    4095,    3071,    1024,
+   1024,    1024,    1024,    1024,    1024,    1024,    1024,    1024,
+   1024,    1024,    1024,    1024,    1024,    1024,    1024,    1024
diff --git a/drivers/media/video/omap3isp/noise_filter_table.h b/drivers/media/video/omap3isp/noise_filter_table.h
new file mode 100644 (file)
index 0000000..d50451a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * noise_filter_table.h
+ *
+ * TI OMAP3 ISP - Noise filter table
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
index cf93de98806894f36ff0a4504efe88d9658f06bf..fe8e3ebd9ce4c1687752c56143e131fbf6c3b208 100644 (file)
@@ -207,7 +207,7 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = {
        V4L2_MBUS_FMT_YVYU8_2X8,
        V4L2_MBUS_FMT_VYUY8_2X8,
        V4L2_MBUS_FMT_SBGGR8_1X8,
-       V4L2_MBUS_FMT_GREY8_1X8,
+       V4L2_MBUS_FMT_Y8_1X8,
 };
 
 static const struct v4l2_queryctrl ov6650_controls[] = {
@@ -800,7 +800,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 
        /* select color matrix configuration for given color encoding */
        switch (code) {
-       case V4L2_MBUS_FMT_GREY8_1X8:
+       case V4L2_MBUS_FMT_Y8_1X8:
                dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
                coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
                coma_set |= COMA_BW;
@@ -846,7 +846,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
        }
        priv->code = code;
 
-       if (code == V4L2_MBUS_FMT_GREY8_1X8 ||
+       if (code == V4L2_MBUS_FMT_Y8_1X8 ||
                        code == V4L2_MBUS_FMT_SBGGR8_1X8) {
                coml_mask = COML_ONE_CHANNEL;
                coml_set = 0;
@@ -936,8 +936,8 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd,
 
        switch (mf->code) {
        case V4L2_MBUS_FMT_Y10_1X10:
-               mf->code = V4L2_MBUS_FMT_GREY8_1X8;
-       case V4L2_MBUS_FMT_GREY8_1X8:
+               mf->code = V4L2_MBUS_FMT_Y8_1X8;
+       case V4L2_MBUS_FMT_Y8_1X8:
        case V4L2_MBUS_FMT_YVYU8_2X8:
        case V4L2_MBUS_FMT_YUYV8_2X8:
        case V4L2_MBUS_FMT_VYUY8_2X8:
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c
new file mode 100644 (file)
index 0000000..4d4ee4f
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * OmniVision OV9740 Camera Driver
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Based on ov9640 camera driver.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#define to_ov9740(sd)          container_of(sd, struct ov9740_priv, subdev)
+
+/* General Status Registers */
+#define OV9740_MODEL_ID_HI             0x0000
+#define OV9740_MODEL_ID_LO             0x0001
+#define OV9740_REVISION_NUMBER         0x0002
+#define OV9740_MANUFACTURER_ID         0x0003
+#define OV9740_SMIA_VERSION            0x0004
+
+/* General Setup Registers */
+#define OV9740_MODE_SELECT             0x0100
+#define OV9740_IMAGE_ORT               0x0101
+#define OV9740_SOFTWARE_RESET          0x0103
+#define OV9740_GRP_PARAM_HOLD          0x0104
+#define OV9740_MSK_CORRUP_FM           0x0105
+
+/* Timing Setting */
+#define OV9740_FRM_LENGTH_LN_HI                0x0340 /* VTS */
+#define OV9740_FRM_LENGTH_LN_LO                0x0341 /* VTS */
+#define OV9740_LN_LENGTH_PCK_HI                0x0342 /* HTS */
+#define OV9740_LN_LENGTH_PCK_LO                0x0343 /* HTS */
+#define OV9740_X_ADDR_START_HI         0x0344
+#define OV9740_X_ADDR_START_LO         0x0345
+#define OV9740_Y_ADDR_START_HI         0x0346
+#define OV9740_Y_ADDR_START_LO         0x0347
+#define OV9740_X_ADDR_END_HI           0x0348
+#define OV9740_X_ADDR_END_LO           0x0349
+#define OV9740_Y_ADDR_END_HI           0x034A
+#define OV9740_Y_ADDR_END_LO           0x034B
+#define OV9740_X_OUTPUT_SIZE_HI                0x034C
+#define OV9740_X_OUTPUT_SIZE_LO                0x034D
+#define OV9740_Y_OUTPUT_SIZE_HI                0x034E
+#define OV9740_Y_OUTPUT_SIZE_LO                0x034F
+
+/* IO Control Registers */
+#define OV9740_IO_CREL00               0x3002
+#define OV9740_IO_CREL01               0x3004
+#define OV9740_IO_CREL02               0x3005
+#define OV9740_IO_OUTPUT_SEL01         0x3026
+#define OV9740_IO_OUTPUT_SEL02         0x3027
+
+/* AWB Registers */
+#define OV9740_AWB_MANUAL_CTRL         0x3406
+
+/* Analog Control Registers */
+#define OV9740_ANALOG_CTRL01           0x3601
+#define OV9740_ANALOG_CTRL02           0x3602
+#define OV9740_ANALOG_CTRL03           0x3603
+#define OV9740_ANALOG_CTRL04           0x3604
+#define OV9740_ANALOG_CTRL10           0x3610
+#define OV9740_ANALOG_CTRL12           0x3612
+#define OV9740_ANALOG_CTRL20           0x3620
+#define OV9740_ANALOG_CTRL21           0x3621
+#define OV9740_ANALOG_CTRL22           0x3622
+#define OV9740_ANALOG_CTRL30           0x3630
+#define OV9740_ANALOG_CTRL31           0x3631
+#define OV9740_ANALOG_CTRL32           0x3632
+#define OV9740_ANALOG_CTRL33           0x3633
+
+/* Sensor Control */
+#define OV9740_SENSOR_CTRL03           0x3703
+#define OV9740_SENSOR_CTRL04           0x3704
+#define OV9740_SENSOR_CTRL05           0x3705
+#define OV9740_SENSOR_CTRL07           0x3707
+
+/* Timing Control */
+#define OV9740_TIMING_CTRL17           0x3817
+#define OV9740_TIMING_CTRL19           0x3819
+#define OV9740_TIMING_CTRL33           0x3833
+#define OV9740_TIMING_CTRL35           0x3835
+
+/* Banding Filter */
+#define OV9740_AEC_MAXEXPO_60_H                0x3A02
+#define OV9740_AEC_MAXEXPO_60_L                0x3A03
+#define OV9740_AEC_B50_STEP_HI         0x3A08
+#define OV9740_AEC_B50_STEP_LO         0x3A09
+#define OV9740_AEC_B60_STEP_HI         0x3A0A
+#define OV9740_AEC_B60_STEP_LO         0x3A0B
+#define OV9740_AEC_CTRL0D              0x3A0D
+#define OV9740_AEC_CTRL0E              0x3A0E
+#define OV9740_AEC_MAXEXPO_50_H                0x3A14
+#define OV9740_AEC_MAXEXPO_50_L                0x3A15
+
+/* AEC/AGC Control */
+#define OV9740_AEC_ENABLE              0x3503
+#define OV9740_GAIN_CEILING_01         0x3A18
+#define OV9740_GAIN_CEILING_02         0x3A19
+#define OV9740_AEC_HI_THRESHOLD                0x3A11
+#define OV9740_AEC_3A1A                        0x3A1A
+#define OV9740_AEC_CTRL1B_WPT2         0x3A1B
+#define OV9740_AEC_CTRL0F_WPT          0x3A0F
+#define OV9740_AEC_CTRL10_BPT          0x3A10
+#define OV9740_AEC_CTRL1E_BPT2         0x3A1E
+#define OV9740_AEC_LO_THRESHOLD                0x3A1F
+
+/* BLC Control */
+#define OV9740_BLC_AUTO_ENABLE         0x4002
+#define OV9740_BLC_MODE                        0x4005
+
+/* VFIFO */
+#define OV9740_VFIFO_READ_START_HI     0x4608
+#define OV9740_VFIFO_READ_START_LO     0x4609
+
+/* DVP Control */
+#define OV9740_DVP_VSYNC_CTRL02                0x4702
+#define OV9740_DVP_VSYNC_MODE          0x4704
+#define OV9740_DVP_VSYNC_CTRL06                0x4706
+
+/* PLL Setting */
+#define OV9740_PLL_MODE_CTRL01         0x3104
+#define OV9740_PRE_PLL_CLK_DIV         0x0305
+#define OV9740_PLL_MULTIPLIER          0x0307
+#define OV9740_VT_SYS_CLK_DIV          0x0303
+#define OV9740_VT_PIX_CLK_DIV          0x0301
+#define OV9740_PLL_CTRL3010            0x3010
+#define OV9740_VFIFO_CTRL00            0x460E
+
+/* ISP Control */
+#define OV9740_ISP_CTRL00              0x5000
+#define OV9740_ISP_CTRL01              0x5001
+#define OV9740_ISP_CTRL03              0x5003
+#define OV9740_ISP_CTRL05              0x5005
+#define OV9740_ISP_CTRL12              0x5012
+#define OV9740_ISP_CTRL19              0x5019
+#define OV9740_ISP_CTRL1A              0x501A
+#define OV9740_ISP_CTRL1E              0x501E
+#define OV9740_ISP_CTRL1F              0x501F
+#define OV9740_ISP_CTRL20              0x5020
+#define OV9740_ISP_CTRL21              0x5021
+
+/* AWB */
+#define OV9740_AWB_CTRL00              0x5180
+#define OV9740_AWB_CTRL01              0x5181
+#define OV9740_AWB_CTRL02              0x5182
+#define OV9740_AWB_CTRL03              0x5183
+#define OV9740_AWB_ADV_CTRL01          0x5184
+#define OV9740_AWB_ADV_CTRL02          0x5185
+#define OV9740_AWB_ADV_CTRL03          0x5186
+#define OV9740_AWB_ADV_CTRL04          0x5187
+#define OV9740_AWB_ADV_CTRL05          0x5188
+#define OV9740_AWB_ADV_CTRL06          0x5189
+#define OV9740_AWB_ADV_CTRL07          0x518A
+#define OV9740_AWB_ADV_CTRL08          0x518B
+#define OV9740_AWB_ADV_CTRL09          0x518C
+#define OV9740_AWB_ADV_CTRL10          0x518D
+#define OV9740_AWB_ADV_CTRL11          0x518E
+#define OV9740_AWB_CTRL0F              0x518F
+#define OV9740_AWB_CTRL10              0x5190
+#define OV9740_AWB_CTRL11              0x5191
+#define OV9740_AWB_CTRL12              0x5192
+#define OV9740_AWB_CTRL13              0x5193
+#define OV9740_AWB_CTRL14              0x5194
+
+/* MIPI Control */
+#define OV9740_MIPI_CTRL00             0x4800
+#define OV9740_MIPI_3837               0x3837
+#define OV9740_MIPI_CTRL01             0x4801
+#define OV9740_MIPI_CTRL03             0x4803
+#define OV9740_MIPI_CTRL05             0x4805
+#define OV9740_VFIFO_RD_CTRL           0x4601
+#define OV9740_MIPI_CTRL_3012          0x3012
+#define OV9740_SC_CMMM_MIPI_CTR                0x3014
+
+/* supported resolutions */
+enum {
+       OV9740_VGA,
+       OV9740_720P,
+};
+
+struct ov9740_resolution {
+       unsigned int width;
+       unsigned int height;
+};
+
+static struct ov9740_resolution ov9740_resolutions[] = {
+       [OV9740_VGA] = {
+               .width  = 640,
+               .height = 480,
+       },
+       [OV9740_720P] = {
+               .width  = 1280,
+               .height = 720,
+       },
+};
+
+/* Misc. structures */
+struct ov9740_reg {
+       u16                             reg;
+       u8                              val;
+};
+
+struct ov9740_priv {
+       struct v4l2_subdev              subdev;
+
+       int                             ident;
+       u16                             model;
+       u8                              revision;
+       u8                              manid;
+       u8                              smiaver;
+
+       bool                            flag_vflip;
+       bool                            flag_hflip;
+};
+
+static const struct ov9740_reg ov9740_defaults[] = {
+       /* Banding Filter */
+       { OV9740_AEC_B50_STEP_HI,       0x00 },
+       { OV9740_AEC_B50_STEP_LO,       0xe8 },
+       { OV9740_AEC_CTRL0E,            0x03 },
+       { OV9740_AEC_MAXEXPO_50_H,      0x15 },
+       { OV9740_AEC_MAXEXPO_50_L,      0xc6 },
+       { OV9740_AEC_B60_STEP_HI,       0x00 },
+       { OV9740_AEC_B60_STEP_LO,       0xc0 },
+       { OV9740_AEC_CTRL0D,            0x04 },
+       { OV9740_AEC_MAXEXPO_60_H,      0x18 },
+       { OV9740_AEC_MAXEXPO_60_L,      0x20 },
+
+       /* LC */
+       { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
+       { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
+
+       /* Un-documented OV9740 registers */
+       { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
+       { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
+       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580A, 0x0e }, { 0x580B, 0x16 },
+       { 0x580C, 0x06 }, { 0x580D, 0x02 }, { 0x580E, 0x00 }, { 0x580F, 0x00 },
+       { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
+       { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
+       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581A, 0x07 }, { 0x581B, 0x08 },
+       { 0x581C, 0x0b }, { 0x581D, 0x14 }, { 0x581E, 0x28 }, { 0x581F, 0x23 },
+       { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
+       { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
+       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582A, 0x8f }, { 0x582B, 0x9e },
+       { 0x582C, 0x8f }, { 0x582D, 0x9f }, { 0x582E, 0x4f }, { 0x582F, 0x87 },
+       { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
+       { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
+       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583A, 0x9f }, { 0x583B, 0x7f },
+       { 0x583C, 0x5f },
+
+       /* Y Gamma */
+       { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
+       { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
+       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548A, 0xa4 }, { 0x548B, 0xb1 },
+       { 0x548C, 0xc6 }, { 0x548D, 0xd8 }, { 0x548E, 0xe9 },
+
+       /* UV Gamma */
+       { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
+       { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
+       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549A, 0x02 }, { 0x549B, 0xeb },
+       { 0x549C, 0x02 }, { 0x549D, 0xa0 }, { 0x549E, 0x02 }, { 0x549F, 0x67 },
+       { 0x54A0, 0x02 }, { 0x54A1, 0x3b }, { 0x54A2, 0x02 }, { 0x54A3, 0x18 },
+       { 0x54A4, 0x01 }, { 0x54A5, 0xe7 }, { 0x54A6, 0x01 }, { 0x54A7, 0xc3 },
+       { 0x54A8, 0x01 }, { 0x54A9, 0x94 }, { 0x54AA, 0x01 }, { 0x54AB, 0x72 },
+       { 0x54AC, 0x01 }, { 0x54AD, 0x57 },
+
+       /* AWB */
+       { OV9740_AWB_CTRL00,            0xf0 },
+       { OV9740_AWB_CTRL01,            0x00 },
+       { OV9740_AWB_CTRL02,            0x41 },
+       { OV9740_AWB_CTRL03,            0x42 },
+       { OV9740_AWB_ADV_CTRL01,        0x8a },
+       { OV9740_AWB_ADV_CTRL02,        0x61 },
+       { OV9740_AWB_ADV_CTRL03,        0xce },
+       { OV9740_AWB_ADV_CTRL04,        0xa8 },
+       { OV9740_AWB_ADV_CTRL05,        0x17 },
+       { OV9740_AWB_ADV_CTRL06,        0x1f },
+       { OV9740_AWB_ADV_CTRL07,        0x27 },
+       { OV9740_AWB_ADV_CTRL08,        0x41 },
+       { OV9740_AWB_ADV_CTRL09,        0x34 },
+       { OV9740_AWB_ADV_CTRL10,        0xf0 },
+       { OV9740_AWB_ADV_CTRL11,        0x10 },
+       { OV9740_AWB_CTRL0F,            0xff },
+       { OV9740_AWB_CTRL10,            0x00 },
+       { OV9740_AWB_CTRL11,            0xff },
+       { OV9740_AWB_CTRL12,            0x00 },
+       { OV9740_AWB_CTRL13,            0xff },
+       { OV9740_AWB_CTRL14,            0x00 },
+
+       /* CIP */
+       { 0x530D, 0x12 },
+
+       /* CMX */
+       { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
+       { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
+       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538A, 0x00 }, { 0x538B, 0x20 },
+       { 0x538C, 0x00 }, { 0x538D, 0x00 }, { 0x538E, 0x00 }, { 0x538F, 0x16 },
+       { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
+       { 0x5394, 0x18 },
+
+       /* 50/60 Detection */
+       { 0x3C0A, 0x9c }, { 0x3C0B, 0x3f },
+
+       /* Output Select */
+       { OV9740_IO_OUTPUT_SEL01,       0x00 },
+       { OV9740_IO_OUTPUT_SEL02,       0x00 },
+       { OV9740_IO_CREL00,             0x00 },
+       { OV9740_IO_CREL01,             0x00 },
+       { OV9740_IO_CREL02,             0x00 },
+
+       /* AWB Control */
+       { OV9740_AWB_MANUAL_CTRL,       0x00 },
+
+       /* Analog Control */
+       { OV9740_ANALOG_CTRL03,         0xaa },
+       { OV9740_ANALOG_CTRL32,         0x2f },
+       { OV9740_ANALOG_CTRL20,         0x66 },
+       { OV9740_ANALOG_CTRL21,         0xc0 },
+       { OV9740_ANALOG_CTRL31,         0x52 },
+       { OV9740_ANALOG_CTRL33,         0x50 },
+       { OV9740_ANALOG_CTRL30,         0xca },
+       { OV9740_ANALOG_CTRL04,         0x0c },
+       { OV9740_ANALOG_CTRL01,         0x40 },
+       { OV9740_ANALOG_CTRL02,         0x16 },
+       { OV9740_ANALOG_CTRL10,         0xa1 },
+       { OV9740_ANALOG_CTRL12,         0x24 },
+       { OV9740_ANALOG_CTRL22,         0x9f },
+
+       /* Sensor Control */
+       { OV9740_SENSOR_CTRL03,         0x42 },
+       { OV9740_SENSOR_CTRL04,         0x10 },
+       { OV9740_SENSOR_CTRL05,         0x45 },
+       { OV9740_SENSOR_CTRL07,         0x14 },
+
+       /* Timing Control */
+       { OV9740_TIMING_CTRL33,         0x04 },
+       { OV9740_TIMING_CTRL35,         0x02 },
+       { OV9740_TIMING_CTRL19,         0x6e },
+       { OV9740_TIMING_CTRL17,         0x94 },
+
+       /* AEC/AGC Control */
+       { OV9740_AEC_ENABLE,            0x10 },
+       { OV9740_GAIN_CEILING_01,       0x00 },
+       { OV9740_GAIN_CEILING_02,       0x7f },
+       { OV9740_AEC_HI_THRESHOLD,      0xa0 },
+       { OV9740_AEC_3A1A,              0x05 },
+       { OV9740_AEC_CTRL1B_WPT2,       0x50 },
+       { OV9740_AEC_CTRL0F_WPT,        0x50 },
+       { OV9740_AEC_CTRL10_BPT,        0x4c },
+       { OV9740_AEC_CTRL1E_BPT2,       0x4c },
+       { OV9740_AEC_LO_THRESHOLD,      0x26 },
+
+       /* BLC Control */
+       { OV9740_BLC_AUTO_ENABLE,       0x45 },
+       { OV9740_BLC_MODE,              0x18 },
+
+       /* DVP Control */
+       { OV9740_DVP_VSYNC_CTRL02,      0x04 },
+       { OV9740_DVP_VSYNC_MODE,        0x00 },
+       { OV9740_DVP_VSYNC_CTRL06,      0x08 },
+
+       /* PLL Setting */
+       { OV9740_PLL_MODE_CTRL01,       0x20 },
+       { OV9740_PRE_PLL_CLK_DIV,       0x03 },
+       { OV9740_PLL_MULTIPLIER,        0x4c },
+       { OV9740_VT_SYS_CLK_DIV,        0x01 },
+       { OV9740_VT_PIX_CLK_DIV,        0x08 },
+       { OV9740_PLL_CTRL3010,          0x01 },
+       { OV9740_VFIFO_CTRL00,          0x82 },
+
+       /* Timing Setting */
+       /* VTS */
+       { OV9740_FRM_LENGTH_LN_HI,      0x03 },
+       { OV9740_FRM_LENGTH_LN_LO,      0x07 },
+       /* HTS */
+       { OV9740_LN_LENGTH_PCK_HI,      0x06 },
+       { OV9740_LN_LENGTH_PCK_LO,      0x62 },
+
+       /* MIPI Control */
+       { OV9740_MIPI_CTRL00,           0x44 },
+       { OV9740_MIPI_3837,             0x01 },
+       { OV9740_MIPI_CTRL01,           0x0f },
+       { OV9740_MIPI_CTRL03,           0x05 },
+       { OV9740_MIPI_CTRL05,           0x10 },
+       { OV9740_VFIFO_RD_CTRL,         0x16 },
+       { OV9740_MIPI_CTRL_3012,        0x70 },
+       { OV9740_SC_CMMM_MIPI_CTR,      0x01 },
+};
+
+static const struct ov9740_reg ov9740_regs_vga[] = {
+       { OV9740_X_ADDR_START_HI,       0x00 },
+       { OV9740_X_ADDR_START_LO,       0xa0 },
+       { OV9740_Y_ADDR_START_HI,       0x00 },
+       { OV9740_Y_ADDR_START_LO,       0x00 },
+       { OV9740_X_ADDR_END_HI,         0x04 },
+       { OV9740_X_ADDR_END_LO,         0x63 },
+       { OV9740_Y_ADDR_END_HI,         0x02 },
+       { OV9740_Y_ADDR_END_LO,         0xd3 },
+       { OV9740_X_OUTPUT_SIZE_HI,      0x02 },
+       { OV9740_X_OUTPUT_SIZE_LO,      0x80 },
+       { OV9740_Y_OUTPUT_SIZE_HI,      0x01 },
+       { OV9740_Y_OUTPUT_SIZE_LO,      0xe0 },
+       { OV9740_ISP_CTRL1E,            0x03 },
+       { OV9740_ISP_CTRL1F,            0xc0 },
+       { OV9740_ISP_CTRL20,            0x02 },
+       { OV9740_ISP_CTRL21,            0xd0 },
+       { OV9740_VFIFO_READ_START_HI,   0x01 },
+       { OV9740_VFIFO_READ_START_LO,   0x40 },
+       { OV9740_ISP_CTRL00,            0xff },
+       { OV9740_ISP_CTRL01,            0xff },
+       { OV9740_ISP_CTRL03,            0xff },
+};
+
+static const struct ov9740_reg ov9740_regs_720p[] = {
+       { OV9740_X_ADDR_START_HI,       0x00 },
+       { OV9740_X_ADDR_START_LO,       0x00 },
+       { OV9740_Y_ADDR_START_HI,       0x00 },
+       { OV9740_Y_ADDR_START_LO,       0x00 },
+       { OV9740_X_ADDR_END_HI,         0x05 },
+       { OV9740_X_ADDR_END_LO,         0x03 },
+       { OV9740_Y_ADDR_END_HI,         0x02 },
+       { OV9740_Y_ADDR_END_LO,         0xd3 },
+       { OV9740_X_OUTPUT_SIZE_HI,      0x05 },
+       { OV9740_X_OUTPUT_SIZE_LO,      0x00 },
+       { OV9740_Y_OUTPUT_SIZE_HI,      0x02 },
+       { OV9740_Y_OUTPUT_SIZE_LO,      0xd0 },
+       { OV9740_ISP_CTRL1E,            0x05 },
+       { OV9740_ISP_CTRL1F,            0x00 },
+       { OV9740_ISP_CTRL20,            0x02 },
+       { OV9740_ISP_CTRL21,            0xd0 },
+       { OV9740_VFIFO_READ_START_HI,   0x02 },
+       { OV9740_VFIFO_READ_START_LO,   0x30 },
+       { OV9740_ISP_CTRL00,            0xff },
+       { OV9740_ISP_CTRL01,            0xef },
+       { OV9740_ISP_CTRL03,            0xff },
+};
+
+static enum v4l2_mbus_pixelcode ov9740_codes[] = {
+       V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+static const struct v4l2_queryctrl ov9740_controls[] = {
+       {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Vertically",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+       {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Horizontally",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       },
+};
+
+/* read a register */
+static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = client->addr,
+                       .flags  = 0,
+                       .len    = 2,
+                       .buf    = (u8 *)&reg,
+               },
+               {
+                       .addr   = client->addr,
+                       .flags  = I2C_M_RD,
+                       .len    = 1,
+                       .buf    = val,
+               },
+       };
+
+       reg = swab16(reg);
+
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* write a register */
+static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+       struct i2c_msg msg;
+       struct {
+               u16 reg;
+               u8 val;
+       } __packed buf;
+       int ret;
+
+       reg = swab16(reg);
+
+       buf.reg = reg;
+       buf.val = val;
+
+       msg.addr        = client->addr;
+       msg.flags       = 0;
+       msg.len         = 3;
+       msg.buf         = (u8 *)&buf;
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
+{
+       u8 val;
+       int ret;
+
+       ret = ov9740_reg_read(client, reg, &val);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "[Read]-Modify-Write of register %02x failed!\n", reg);
+               return ret;
+       }
+
+       val |= set;
+       val &= ~unset;
+
+       ret = ov9740_reg_write(client, reg, val);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "Read-Modify-[Write] of register %02x failed!\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ov9740_reg_write_array(struct i2c_client *client,
+                                 const struct ov9740_reg *regarray,
+                                 int regarraylen)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < regarraylen; i++) {
+               ret = ov9740_reg_write(client,
+                                      regarray[i].reg, regarray[i].val);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       int ret;
+
+       /* Program orientation register. */
+       if (priv->flag_vflip)
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
+       else
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
+       if (ret < 0)
+               return ret;
+
+       if (priv->flag_hflip)
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
+       else
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
+       if (ret < 0)
+               return ret;
+
+       if (enable) {
+               dev_dbg(&client->dev, "Enabling Streaming\n");
+               /* Start Streaming */
+               ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
+
+       } else {
+               dev_dbg(&client->dev, "Disabling Streaming\n");
+               /* Software Reset */
+               ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
+               if (!ret)
+                       /* Setting Streaming to Standby */
+                       ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
+                                              0x00);
+       }
+
+       return ret;
+}
+
+/* Alter bus settings on camera side */
+static int ov9740_set_bus_param(struct soc_camera_device *icd,
+                               unsigned long flags)
+{
+       return 0;
+}
+
+/* Request bus settings on camera side */
+static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd)
+{
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+/* Get status of additional camera capabilities */
+static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               ctrl->value = priv->flag_vflip;
+               break;
+       case V4L2_CID_HFLIP:
+               ctrl->value = priv->flag_hflip;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               priv->flag_vflip = ctrl->value;
+               break;
+       case V4L2_CID_HFLIP:
+               priv->flag_hflip = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Get chip identification */
+static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       id->ident = priv->ident;
+       id->revision = priv->revision;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 2;
+
+       ret = ov9740_reg_read(client, reg->reg, &val);
+       if (ret)
+               return ret;
+
+       reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ov9740_resolutions); i++)
+               if ((ov9740_resolutions[i].width >= *width) &&
+                   (ov9740_resolutions[i].height >= *height)) {
+                       *width = ov9740_resolutions[i].width;
+                       *height = ov9740_resolutions[i].height;
+                       return;
+               }
+
+       *width = ov9740_resolutions[OV9740_720P].width;
+       *height = ov9740_resolutions[OV9740_720P].height;
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width)
+{
+       int ret;
+
+       /* select register configuration for given resolution */
+       if (width == ov9740_resolutions[OV9740_VGA].width) {
+               dev_dbg(&client->dev, "Setting image size to 640x480\n");
+               ret = ov9740_reg_write_array(client, ov9740_regs_vga,
+                                            ARRAY_SIZE(ov9740_regs_vga));
+       } else if (width == ov9740_resolutions[OV9740_720P].width) {
+               dev_dbg(&client->dev, "Setting image size to 1280x720\n");
+               ret = ov9740_reg_write_array(client, ov9740_regs_720p,
+                                            ARRAY_SIZE(ov9740_regs_720p));
+       } else {
+               dev_err(&client->dev, "Failed to select resolution!\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/* set the format we will capture in */
+static int ov9740_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       enum v4l2_colorspace cspace;
+       enum v4l2_mbus_pixelcode code = mf->code;
+       int ret;
+
+       ov9740_res_roundup(&mf->width, &mf->height);
+
+       switch (code) {
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               cspace = V4L2_COLORSPACE_SRGB;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = ov9740_reg_write_array(client, ov9740_defaults,
+                                    ARRAY_SIZE(ov9740_defaults));
+       if (ret < 0)
+               return ret;
+
+       ret = ov9740_set_res(client, mf->width);
+       if (ret < 0)
+               return ret;
+
+       mf->code        = code;
+       mf->colorspace  = cspace;
+
+       return ret;
+}
+
+static int ov9740_try_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *mf)
+{
+       ov9740_res_roundup(&mf->width, &mf->height);
+
+       mf->field = V4L2_FIELD_NONE;
+       mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+       mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+       return 0;
+}
+
+static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(ov9740_codes))
+               return -EINVAL;
+
+       *code = ov9740_codes[index];
+
+       return 0;
+}
+
+static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       a->bounds.left          = 0;
+       a->bounds.top           = 0;
+       a->bounds.width         = ov9740_resolutions[OV9740_720P].width;
+       a->bounds.height        = ov9740_resolutions[OV9740_720P].height;
+       a->defrect              = a->bounds;
+       a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       a->c.left               = 0;
+       a->c.top                = 0;
+       a->c.width              = ov9740_resolutions[OV9740_720P].width;
+       a->c.height             = ov9740_resolutions[OV9740_720P].height;
+       a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       return 0;
+}
+
+static int ov9740_video_probe(struct soc_camera_device *icd,
+                             struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       u8 modelhi, modello;
+       int ret;
+
+       /*
+        * We must have a parent by now. And it cannot be a wrong one.
+        * So this entire test is completely redundant.
+        */
+       if (!icd->dev.parent ||
+           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
+               dev_err(&client->dev, "Parent missing or invalid!\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+       ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
+       if (ret < 0)
+               goto err;
+
+       ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
+       if (ret < 0)
+               goto err;
+
+       priv->model = (modelhi << 8) | modello;
+
+       ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
+       if (ret < 0)
+               goto err;
+
+       ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
+       if (ret < 0)
+               goto err;
+
+       ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
+       if (ret < 0)
+               goto err;
+
+       if (priv->model != 0x9740) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       priv->ident = V4L2_IDENT_OV9740;
+
+       dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
+                "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
+                priv->model, priv->revision, priv->manid, priv->smiaver);
+
+err:
+       return ret;
+}
+
+static struct soc_camera_ops ov9740_ops = {
+       .set_bus_param          = ov9740_set_bus_param,
+       .query_bus_param        = ov9740_query_bus_param,
+       .controls               = ov9740_controls,
+       .num_controls           = ARRAY_SIZE(ov9740_controls),
+};
+
+static struct v4l2_subdev_core_ops ov9740_core_ops = {
+       .g_ctrl                 = ov9740_g_ctrl,
+       .s_ctrl                 = ov9740_s_ctrl,
+       .g_chip_ident           = ov9740_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register             = ov9740_get_register,
+       .s_register             = ov9740_set_register,
+#endif
+
+};
+
+static struct v4l2_subdev_video_ops ov9740_video_ops = {
+       .s_stream               = ov9740_s_stream,
+       .s_mbus_fmt             = ov9740_s_fmt,
+       .try_mbus_fmt           = ov9740_try_fmt,
+       .enum_mbus_fmt          = ov9740_enum_fmt,
+       .cropcap                = ov9740_cropcap,
+       .g_crop                 = ov9740_g_crop,
+};
+
+static struct v4l2_subdev_ops ov9740_subdev_ops = {
+       .core                   = &ov9740_core_ops,
+       .video                  = &ov9740_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9740_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov9740_priv *priv;
+       struct soc_camera_device *icd   = client->dev.platform_data;
+       struct soc_camera_link *icl;
+       int ret;
+
+       if (!icd) {
+               dev_err(&client->dev, "Missing soc-camera data!\n");
+               return -EINVAL;
+       }
+
+       icl = to_soc_camera_link(icd);
+       if (!icl) {
+               dev_err(&client->dev, "Missing platform_data for driver\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&client->dev, "Failed to allocate private data!\n");
+               return -ENOMEM;
+       }
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
+
+       icd->ops = &ov9740_ops;
+
+       ret = ov9740_video_probe(icd, client);
+       if (ret < 0) {
+               icd->ops = NULL;
+               kfree(priv);
+       }
+
+       return ret;
+}
+
+static int ov9740_remove(struct i2c_client *client)
+{
+       struct ov9740_priv *priv = i2c_get_clientdata(client);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id ov9740_id[] = {
+       { "ov9740", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov9740_id);
+
+static struct i2c_driver ov9740_i2c_driver = {
+       .driver = {
+               .name = "ov9740",
+       },
+       .probe    = ov9740_probe,
+       .remove   = ov9740_remove,
+       .id_table = ov9740_id,
+};
+
+static int __init ov9740_module_init(void)
+{
+       return i2c_add_driver(&ov9740_i2c_driver);
+}
+
+static void __exit ov9740_module_exit(void)
+{
+       i2c_del_driver(&ov9740_i2c_driver);
+}
+
+module_init(ov9740_module_init);
+module_exit(ov9740_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
+MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index 2222da8d0ca67cf97985388a6d42e1428e9d4c8e..c514d0b9ffdc6262df50bff0bfe342aea2ead1b6 100644 (file)
@@ -99,9 +99,27 @@ static const struct routing_scheme routing_defgv = {
        .cnt = ARRAY_SIZE(routing_schemegv),
 };
 
+/* Specific to grabster av400 device */
+static const struct routing_scheme_item routing_schemeav400[] = {
+       [PVR2_CVAL_INPUT_COMPOSITE] = {
+               .vid = CX25840_COMPOSITE1,
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+       [PVR2_CVAL_INPUT_SVIDEO] = {
+               .vid = (CX25840_SVIDEO_LUMA2|CX25840_SVIDEO_CHROMA4),
+               .aud = CX25840_AUDIO_SERIAL,
+       },
+};
+
+static const struct routing_scheme routing_defav400 = {
+       .def = routing_schemeav400,
+       .cnt = ARRAY_SIZE(routing_schemeav400),
+};
+
 static const struct routing_scheme *routing_schemes[] = {
        [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0,
        [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv,
+       [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400,
 };
 
 void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
index 3092abfd66a21e69113728127ad9aaf9e64d79c1..e799331389b1b7dc3e92af6a15e8ef7469d5a89e 100644 (file)
@@ -156,6 +156,28 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = {
 
 
 
+/*------------------------------------------------------------------------*/
+/* Terratec Grabster AV400 */
+
+static const struct pvr2_device_client_desc pvr2_cli_av400[] = {
+       { .module_id = PVR2_CLIENT_ID_CX25840 },
+};
+
+static const struct pvr2_device_desc pvr2_device_av400 = {
+               .description = "Terratec Grabster AV400",
+               .shortname = "av400",
+               .flag_is_experimental = 1,
+               .client_table.lst = pvr2_cli_av400,
+               .client_table.cnt = ARRAY_SIZE(pvr2_cli_av400),
+               .flag_has_cx25840 = !0,
+               .flag_has_analogtuner = 0,
+               .flag_has_composite = !0,
+               .flag_has_svideo = !0,
+               .signal_routing_scheme = PVR2_ROUTING_SCHEME_AV400,
+};
+
+
+
 /*------------------------------------------------------------------------*/
 /* OnAir Creator */
 
@@ -517,6 +539,8 @@ struct usb_device_id pvr2_device_table[] = {
          .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
        { USB_DEVICE(0x2040, 0x7501),
          .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
+       { USB_DEVICE(0x0ccd, 0x0039),
+         .driver_info = (kernel_ulong_t)&pvr2_device_av400},
        { }
 };
 
index 66ad516bdfd97070380b1592d14be35ea978acc0..9d0dd08f57f8ccc4b360424e4a53ad45883c07a1 100644 (file)
@@ -499,31 +499,35 @@ static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
        return 0;
 }
 
-static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width)
 {
        struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
-       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       int stat, bleftend, cleft;
+
+       stat = pvr2_hdw_check_cropcap(cptr->hdw);
        if (stat != 0) {
                return stat;
        }
-       *val = 0;
-       if (cap->bounds.width > cptr->hdw->cropl_val) {
-               *val = cap->bounds.width - cptr->hdw->cropl_val;
-       }
+       bleftend = cap->bounds.left+cap->bounds.width;
+       cleft = cptr->hdw->cropl_val;
+
+       *width = cleft < bleftend ? bleftend-cleft : 0;
        return 0;
 }
 
-static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height)
 {
        struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
-       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       int stat, btopend, ctop;
+
+       stat = pvr2_hdw_check_cropcap(cptr->hdw);
        if (stat != 0) {
                return stat;
        }
-       *val = 0;
-       if (cap->bounds.height > cptr->hdw->cropt_val) {
-               *val = cap->bounds.height - cptr->hdw->cropt_val;
-       }
+       btopend = cap->bounds.top+cap->bounds.height;
+       ctop = cptr->hdw->cropt_val;
+
+       *height = ctop < btopend ? btopend-ctop : 0;
        return 0;
 }
 
@@ -1114,6 +1118,7 @@ static const struct pvr2_ctl_info control_defs[] = {
                .internal_id = PVR2_CID_CROPW,
                .default_value = 720,
                DEFREF(cropw),
+               DEFINT(0, 864),
                .get_max_value = ctrl_cropw_max_get,
                .get_def_value = ctrl_get_cropcapdw,
        }, {
@@ -1122,6 +1127,7 @@ static const struct pvr2_ctl_info control_defs[] = {
                .internal_id = PVR2_CID_CROPH,
                .default_value = 480,
                DEFREF(croph),
+               DEFINT(0, 576),
                .get_max_value = ctrl_croph_max_get,
                .get_def_value = ctrl_get_cropcapdh,
        }, {
@@ -2027,6 +2033,8 @@ static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw)
                   hdw->decoder_client_id);
        memset(&fmt, 0, sizeof(fmt));
        fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       fmt.fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+       fmt.fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
        v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
                             vbi, s_sliced_fmt, &fmt.fmt.sliced);
 }
@@ -2842,15 +2850,23 @@ static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
                        PVR2_TRACE_ERROR_LEGS,
                        "WARNING: Failed to identify any viable standards");
        }
+
+       /* Set up the dynamic control for this standard */
        hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
-       hdw->std_enum_names[0] = "none";
-       for (idx = 0; idx < std_cnt; idx++) {
-               hdw->std_enum_names[idx+1] =
-                       newstd[idx].name;
-       }
-       // Set up the dynamic control for this standard
-       hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names;
-       hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+       if (hdw->std_enum_names) {
+               hdw->std_enum_names[0] = "none";
+               for (idx = 0; idx < std_cnt; idx++)
+                       hdw->std_enum_names[idx+1] = newstd[idx].name;
+               hdw->std_info_enum.def.type_enum.value_names =
+                                               hdw->std_enum_names;
+               hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+       } else {
+               pvr2_trace(
+                       PVR2_TRACE_ERROR_LEGS,
+                       "WARNING: Failed to alloc memory for names");
+               hdw->std_info_enum.def.type_enum.value_names = NULL;
+               hdw->std_info_enum.def.type_enum.count = 0;
+       }
        hdw->std_defs = newstd;
        hdw->std_enum_cnt = std_cnt+1;
        hdw->std_enum_cur = 0;
@@ -3165,6 +3181,19 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
        struct pvr2_ctrl *cptr;
        int disruptive_change;
 
+       if (hdw->input_dirty && hdw->state_pathway_ok &&
+           (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
+             PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
+            hdw->pathway_state)) {
+               /* Change of mode being asked for... */
+               hdw->state_pathway_ok = 0;
+               trace_stbit("state_pathway_ok", hdw->state_pathway_ok);
+       }
+       if (!hdw->state_pathway_ok) {
+               /* Can't commit anything until pathway is ok. */
+               return 0;
+       }
+
        /* Handle some required side effects when the video standard is
           changed.... */
        if (hdw->std_dirty) {
@@ -3199,18 +3228,6 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                }
        }
 
-       if (hdw->input_dirty && hdw->state_pathway_ok &&
-           (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
-             PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
-            hdw->pathway_state)) {
-               /* Change of mode being asked for... */
-               hdw->state_pathway_ok = 0;
-               trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
-       }
-       if (!hdw->state_pathway_ok) {
-               /* Can't commit anything until pathway is ok. */
-               return 0;
-       }
        /* The broadcast decoder can only scale down, so if
         * res_*_dirty && crop window < output format ==> enlarge crop.
         *
@@ -5159,8 +5176,7 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
           using v4l2-subdev - therefore we can't support that AT ALL right
           now.  (Of course, no sub-drivers seem to implement it either.
           But now it's a a chicken and egg problem...) */
-       v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner,
-                            &hdw->tuner_signal_info);
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp);
        pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll"
                   " type=%u strength=%u audio=0x%x cap=0x%x"
                   " low=%u hi=%u",
index 451ecd485f97c6c1fb318f1d5fa66e71260705d7..e72d5103e778c7d774eb4214e17950df5f0a8656 100644 (file)
@@ -578,7 +578,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
        switch (hdw->ir_scheme_active) {
        case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
        case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
-               init_data->ir_codes              = RC_MAP_HAUPPAUGE_NEW;
+               init_data->ir_codes              = RC_MAP_HAUPPAUGE;
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
                init_data->type                  = RC_TYPE_RC5;
                init_data->name                  = hdw->hdw_desc->description;
@@ -593,7 +593,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
                break;
        case PVR2_IR_SCHEME_ZILOG:     /* HVR-1950 style */
        case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
-               init_data->ir_codes              = RC_MAP_HAUPPAUGE_NEW;
+               init_data->ir_codes              = RC_MAP_HAUPPAUGE;
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
                init_data->type                  = RC_TYPE_RC5;
                init_data->name                  = hdw->hdw_desc->description;
index 281806b2df6263cf901594fc5cb8dec817d54c5e..6ef1335b2858a54bb17707579453f091a1f9d976 100644 (file)
@@ -324,36 +324,45 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
        }
        sfp->item_last = cip;
 
+       sysfs_attr_init(&cip->attr_name.attr);
        cip->attr_name.attr.name = "name";
        cip->attr_name.attr.mode = S_IRUGO;
        cip->attr_name.show = show_name;
 
+       sysfs_attr_init(&cip->attr_type.attr);
        cip->attr_type.attr.name = "type";
        cip->attr_type.attr.mode = S_IRUGO;
        cip->attr_type.show = show_type;
 
+       sysfs_attr_init(&cip->attr_min.attr);
        cip->attr_min.attr.name = "min_val";
        cip->attr_min.attr.mode = S_IRUGO;
        cip->attr_min.show = show_min;
 
+       sysfs_attr_init(&cip->attr_max.attr);
        cip->attr_max.attr.name = "max_val";
        cip->attr_max.attr.mode = S_IRUGO;
        cip->attr_max.show = show_max;
 
+       sysfs_attr_init(&cip->attr_def.attr);
        cip->attr_def.attr.name = "def_val";
        cip->attr_def.attr.mode = S_IRUGO;
        cip->attr_def.show = show_def;
 
+       sysfs_attr_init(&cip->attr_val.attr);
        cip->attr_val.attr.name = "cur_val";
        cip->attr_val.attr.mode = S_IRUGO;
 
+       sysfs_attr_init(&cip->attr_custom.attr);
        cip->attr_custom.attr.name = "custom_val";
        cip->attr_custom.attr.mode = S_IRUGO;
 
+       sysfs_attr_init(&cip->attr_enum.attr);
        cip->attr_enum.attr.name = "enum_val";
        cip->attr_enum.attr.mode = S_IRUGO;
        cip->attr_enum.show = show_enum;
 
+       sysfs_attr_init(&cip->attr_bits.attr);
        cip->attr_bits.attr.name = "bit_val";
        cip->attr_bits.attr.mode = S_IRUGO;
        cip->attr_bits.show = show_bits;
index 58617fc656c2147176ffd3c82856598b1a01820b..38761142a4d94235e595897e35ca1cd053acabbf 100644 (file)
@@ -795,12 +795,10 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        case VIDIOC_S_CROP:
        {
                struct v4l2_crop *crop = (struct v4l2_crop *)arg;
-               struct v4l2_cropcap cap;
                if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                        ret = -EINVAL;
                        break;
                }
-               cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                ret = pvr2_ctrl_set_value(
                        pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
                        crop->c.left);
index bd1519a4ecb474ba62dbc3bb55ff49d922e0f727..780af5f81642f87ece0d11158a2ead78c70f2bb8 100644 (file)
@@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file);
 static ssize_t pwc_video_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
-static long  pwc_video_ioctl(struct file *file,
-                           unsigned int ioctlnr, unsigned long arg);
 static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
 
 static const struct v4l2_file_operations pwc_fops = {
@@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = {
        .read =         pwc_video_read,
        .poll =         pwc_video_poll,
        .mmap =         pwc_video_mmap,
-       .unlocked_ioctl = pwc_video_ioctl,
+       .unlocked_ioctl = video_ioctl2,
 };
 static struct video_device pwc_template = {
        .name =         "Philips Webcam",       /* Filled in later */
@@ -1098,7 +1096,6 @@ static int pwc_video_open(struct file *file)
                return -EBUSY;
        }
 
-       mutex_lock(&pdev->modlock);
        pwc_construct(pdev); /* set min/max sizes correct */
        if (!pdev->usb_init) {
                PWC_DEBUG_OPEN("Doing first time initialization.\n");
@@ -1130,7 +1127,6 @@ static int pwc_video_open(struct file *file)
        if (i < 0) {
                PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
                pwc_free_buffers(pdev);
-               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1171,7 +1167,6 @@ static int pwc_video_open(struct file *file)
        if (i) {
                PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
                pwc_free_buffers(pdev);
-               mutex_unlock(&pdev->modlock);
                return i;
        }
 
@@ -1181,7 +1176,6 @@ static int pwc_video_open(struct file *file)
 
        pdev->vopen++;
        file->private_data = vdev;
-       mutex_unlock(&pdev->modlock);
        PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
 }
@@ -1210,7 +1204,6 @@ static int pwc_video_close(struct file *file)
        PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
        pdev = video_get_drvdata(vdev);
-       mutex_lock(&pdev->modlock);
        if (pdev->vopen == 0)
                PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
@@ -1248,7 +1241,6 @@ static int pwc_video_close(struct file *file)
                        if (device_hint[hint].pdev == pdev)
                                device_hint[hint].pdev = NULL;
        }
-       mutex_unlock(&pdev->modlock);
 
        return 0;
 }
@@ -1283,7 +1275,6 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
        if (pdev == NULL)
                return -EFAULT;
 
-       mutex_lock(&pdev->modlock);
        if (pdev->error_status) {
                rv = -pdev->error_status; /* Something happened, report what. */
                goto err_out;
@@ -1318,8 +1309,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
                                rv = -ERESTARTSYS;
                                goto err_out;
                        }
+                       mutex_unlock(&pdev->modlock);
                        schedule();
                        set_current_state(TASK_INTERRUPTIBLE);
+                       mutex_lock(&pdev->modlock);
                }
                remove_wait_queue(&pdev->frameq, &wait);
                set_current_state(TASK_RUNNING);
@@ -1352,10 +1345,8 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
                pdev->image_read_pos = 0;
                pwc_next_image(pdev);
        }
-       mutex_unlock(&pdev->modlock);
        return count;
 err_out:
-       mutex_unlock(&pdev->modlock);
        return rv;
 }
 
@@ -1372,9 +1363,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
                return -EFAULT;
 
        /* Start the stream (if not already started) */
-       mutex_lock(&pdev->modlock);
        ret = pwc_isoc_init(pdev);
-       mutex_unlock(&pdev->modlock);
        if (ret)
                return ret;
 
@@ -1387,25 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
        return 0;
 }
 
-static long pwc_video_ioctl(struct file *file,
-                          unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       long r = -ENODEV;
-
-       if (!vdev)
-               goto out;
-       pdev = video_get_drvdata(vdev);
-
-       mutex_lock(&pdev->modlock);
-       if (!pdev->unplugged)
-               r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
-       mutex_unlock(&pdev->modlock);
-out:
-       return r;
-}
-
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct video_device *vdev = file->private_data;
@@ -1754,6 +1724,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
        pdev->vdev->parent = &intf->dev;
+       pdev->vdev->lock = &pdev->modlock;
+       pdev->vdev->ioctl_ops = &pwc_ioctl_ops;
        strcpy(pdev->vdev->name, name);
        video_set_drvdata(pdev->vdev, pdev);
 
index 8ca4d22b4384f0f496397f9d6307dd01d2ff9a59..aa87e462a958aec8025fb99c60772dd97039e66a 100644 (file)
@@ -341,604 +341,555 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 
 }
 
-long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 {
        struct video_device *vdev = video_devdata(file);
-       struct pwc_device *pdev;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = video_get_drvdata(vdev);
-       if (pdev == NULL)
-               return -EFAULT;
+       struct pwc_device *pdev = video_drvdata(file);
+
+       strcpy(cap->driver, PWC_NAME);
+       strlcpy(cap->card, vdev->name, sizeof(cap->card));
+       usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->version = PWC_VERSION_CODE;
+       cap->capabilities =
+               V4L2_CAP_VIDEO_CAPTURE  |
+               V4L2_CAP_STREAMING      |
+               V4L2_CAP_READWRITE;
+       return 0;
+}
 
-#ifdef CONFIG_USB_PWC_DEBUG
-       if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
-               v4l_printk_ioctl(cmd);
-               printk("\n");
-       }
-#endif
-
-
-       switch (cmd) {
-               /* V4L2 Layer */
-               case VIDIOC_QUERYCAP:
-               {
-                   struct v4l2_capability *cap = arg;
-
-                   PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
-                                      "try to use the v4l2 layer\n");
-                   strcpy(cap->driver,PWC_NAME);
-                   strlcpy(cap->card, vdev->name, sizeof(cap->card));
-                   usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
-                   cap->version = PWC_VERSION_CODE;
-                   cap->capabilities =
-                       V4L2_CAP_VIDEO_CAPTURE  |
-                       V4L2_CAP_STREAMING      |
-                       V4L2_CAP_READWRITE;
-                   return 0;
-               }
+static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+       if (i->index)   /* Only one INPUT is supported */
+               return -EINVAL;
 
-               case VIDIOC_ENUMINPUT:
-               {
-                   struct v4l2_input *i = arg;
+       strcpy(i->name, "usb");
+       return 0;
+}
 
-                   if ( i->index )     /* Only one INPUT is supported */
-                         return -EINVAL;
+static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
 
-                   memset(i, 0, sizeof(struct v4l2_input));
-                   strcpy(i->name, "usb");
-                   return 0;
-               }
+static int pwc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       return i ? -EINVAL : 0;
+}
 
-               case VIDIOC_G_INPUT:
-               {
-                   int *i = arg;
-                   *i = 0;     /* Only one INPUT is supported */
-                   return 0;
-               }
-               case VIDIOC_S_INPUT:
-               {
-                       int *i = arg;
+static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+{
+       int i;
 
-                       if ( *i ) {     /* Only one INPUT is supported */
-                               PWC_DEBUG_IOCTL("Only one input source is"\
-                                       " supported with this webcam.\n");
-                               return -EINVAL;
-                       }
+       for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
+               if (pwc_controls[i].id == c->id) {
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+                       memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));
                        return 0;
                }
+       }
+       return -EINVAL;
+}
 
-               /* TODO: */
-               case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *c = arg;
-                       int i;
-
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
-                       for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
-                               if (pwc_controls[i].id == c->id) {
-                                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
-                                       memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
-                                       return 0;
-                               }
-                       }
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+       int ret;
 
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               c->value = pwc_get_brightness(pdev);
+               if (c->value < 0)
                        return -EINVAL;
-               }
-               case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *c = arg;
-                       int ret;
-
-                       switch (c->id)
-                       {
-                               case V4L2_CID_BRIGHTNESS:
-                                       c->value = pwc_get_brightness(pdev);
-                                       if (c->value<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_CONTRAST:
-                                       c->value = pwc_get_contrast(pdev);
-                                       if (c->value<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_SATURATION:
-                                       ret = pwc_get_saturation(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_GAMMA:
-                                       c->value = pwc_get_gamma(pdev);
-                                       if (c->value<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_RED_BALANCE:
-                                       ret = pwc_get_red_gain(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       c->value >>= 8;
-                                       return 0;
-                               case V4L2_CID_BLUE_BALANCE:
-                                       ret = pwc_get_blue_gain(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       c->value >>= 8;
-                                       return 0;
-                               case V4L2_CID_AUTO_WHITE_BALANCE:
-                                       ret = pwc_get_awb(pdev);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       c->value = (ret == PWC_WB_MANUAL)?0:1;
-                                       return 0;
-                               case V4L2_CID_GAIN:
-                                       ret = pwc_get_agc(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       c->value >>= 8;
-                                       return 0;
-                               case V4L2_CID_AUTOGAIN:
-                                       ret = pwc_get_agc(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       c->value = (c->value < 0)?1:0;
-                                       return 0;
-                               case V4L2_CID_EXPOSURE:
-                                       ret = pwc_get_shutter_speed(pdev, &c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_COLOUR_MODE:
-                                       ret = pwc_get_colour_mode(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
-                                       ret = pwc_get_contour(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       c->value=(c->value == -1?1:0);
-                                       return 0;
-                               case V4L2_CID_PRIVATE_CONTOUR:
-                                       ret = pwc_get_contour(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       c->value >>= 10;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_BACKLIGHT:
-                                       ret = pwc_get_backlight(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_FLICKERLESS:
-                                       ret = pwc_get_flicker(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       c->value=(c->value?1:0);
-                                       return 0;
-                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
-                                       ret = pwc_get_dynamic_noise(pdev, &c->value);
-                                       if (ret < 0)
-                                               return -EINVAL;
-                                       return 0;
-
-                               case V4L2_CID_PRIVATE_SAVE_USER:
-                               case V4L2_CID_PRIVATE_RESTORE_USER:
-                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
-                                       return -EINVAL;
-                       }
+               return 0;
+       case V4L2_CID_CONTRAST:
+               c->value = pwc_get_contrast(pdev);
+               if (c->value < 0)
                        return -EINVAL;
-               }
-               case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *c = arg;
-                       int ret;
-
-                       switch (c->id)
-                       {
-                               case V4L2_CID_BRIGHTNESS:
-                                       c->value <<= 9;
-                                       ret = pwc_set_brightness(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_CONTRAST:
-                                       c->value <<= 10;
-                                       ret = pwc_set_contrast(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_SATURATION:
-                                       ret = pwc_set_saturation(pdev, c->value);
-                                       if (ret<0)
-                                         return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_GAMMA:
-                                       c->value <<= 11;
-                                       ret = pwc_set_gamma(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_RED_BALANCE:
-                                       c->value <<= 8;
-                                       ret = pwc_set_red_gain(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_BLUE_BALANCE:
-                                       c->value <<= 8;
-                                       ret = pwc_set_blue_gain(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_AUTO_WHITE_BALANCE:
-                                       c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
-                                       ret = pwc_set_awb(pdev, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_EXPOSURE:
-                                       c->value <<= 8;
-                                       ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_AUTOGAIN:
-                                       /* autogain off means nothing without a gain */
-                                       if (c->value == 0)
-                                               return 0;
-                                       ret = pwc_set_agc(pdev, c->value, 0);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_GAIN:
-                                       c->value <<= 8;
-                                       ret = pwc_set_agc(pdev, 0, c->value);
-                                       if (ret<0)
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_SAVE_USER:
-                                       if (pwc_save_user(pdev))
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_RESTORE_USER:
-                                       if (pwc_restore_user(pdev))
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
-                                       if (pwc_restore_factory(pdev))
-                                               return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_COLOUR_MODE:
-                                       ret = pwc_set_colour_mode(pdev, c->value);
-                                       if (ret < 0)
-                                         return -EINVAL;
-                                       return 0;
-                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
-                                 c->value=(c->value == 1)?-1:0;
-                                 ret = pwc_set_contour(pdev, c->value);
-                                 if (ret < 0)
-                                   return -EINVAL;
-                                 return 0;
-                               case V4L2_CID_PRIVATE_CONTOUR:
-                                 c->value <<= 10;
-                                 ret = pwc_set_contour(pdev, c->value);
-                                 if (ret < 0)
-                                   return -EINVAL;
-                                 return 0;
-                               case V4L2_CID_PRIVATE_BACKLIGHT:
-                                 ret = pwc_set_backlight(pdev, c->value);
-                                 if (ret < 0)
-                                   return -EINVAL;
-                                 return 0;
-                               case V4L2_CID_PRIVATE_FLICKERLESS:
-                                 ret = pwc_set_flicker(pdev, c->value);
-                                 if (ret < 0)
-                                   return -EINVAL;
-                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
-                                 ret = pwc_set_dynamic_noise(pdev, c->value);
-                                 if (ret < 0)
-                                   return -EINVAL;
-                                 return 0;
-
-                       }
+               return 0;
+       case V4L2_CID_SATURATION:
+               ret = pwc_get_saturation(pdev, &c->value);
+               if (ret < 0)
                        return -EINVAL;
-               }
+               return 0;
+       case V4L2_CID_GAMMA:
+               c->value = pwc_get_gamma(pdev);
+               if (c->value < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               ret = pwc_get_red_gain(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value >>= 8;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               ret = pwc_get_blue_gain(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value >>= 8;
+               return 0;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret = pwc_get_awb(pdev);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value = (ret == PWC_WB_MANUAL) ? 0 : 1;
+               return 0;
+       case V4L2_CID_GAIN:
+               ret = pwc_get_agc(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value >>= 8;
+               return 0;
+       case V4L2_CID_AUTOGAIN:
+               ret = pwc_get_agc(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value = (c->value < 0) ? 1 : 0;
+               return 0;
+       case V4L2_CID_EXPOSURE:
+               ret = pwc_get_shutter_speed(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_COLOUR_MODE:
+               ret = pwc_get_colour_mode(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_AUTOCONTOUR:
+               ret = pwc_get_contour(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value = (c->value == -1 ? 1 : 0);
+               return 0;
+       case V4L2_CID_PRIVATE_CONTOUR:
+               ret = pwc_get_contour(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value >>= 10;
+               return 0;
+       case V4L2_CID_PRIVATE_BACKLIGHT:
+               ret = pwc_get_backlight(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_FLICKERLESS:
+               ret = pwc_get_flicker(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               c->value = (c->value ? 1 : 0);
+               return 0;
+       case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+               ret = pwc_get_dynamic_noise(pdev, &c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
 
-               case VIDIOC_ENUM_FMT:
-               {
-                       struct v4l2_fmtdesc *f = arg;
-                       int index;
-
-                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                             return -EINVAL;
-
-                       /* We only support two format: the raw format, and YUV */
-                       index = f->index;
-                       memset(f,0,sizeof(struct v4l2_fmtdesc));
-                       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       f->index = index;
-                       switch(index)
-                       {
-                               case 0:
-                                       /* RAW format */
-                                       f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
-                                       f->flags = V4L2_FMT_FLAG_COMPRESSED;
-                                       strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
-                                       break;
-                               case 1:
-                                       f->pixelformat = V4L2_PIX_FMT_YUV420;
-                                       strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
-                                       break;
-                               default:
-                                       return -EINVAL;
-                       }
-                       return 0;
-               }
+       case V4L2_CID_PRIVATE_SAVE_USER:
+       case V4L2_CID_PRIVATE_RESTORE_USER:
+       case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+               return -EINVAL;
+       }
+       return -EINVAL;
+}
 
-               case VIDIOC_G_FMT:
-               {
-                       struct v4l2_format *f = arg;
+static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+       int ret;
+
+       switch (c->id) {
+       case V4L2_CID_BRIGHTNESS:
+               c->value <<= 9;
+               ret = pwc_set_brightness(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_CONTRAST:
+               c->value <<= 10;
+               ret = pwc_set_contrast(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_SATURATION:
+               ret = pwc_set_saturation(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_GAMMA:
+               c->value <<= 11;
+               ret = pwc_set_gamma(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               c->value <<= 8;
+               ret = pwc_set_red_gain(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               c->value <<= 8;
+               ret = pwc_set_blue_gain(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO;
+               ret = pwc_set_awb(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_EXPOSURE:
+               c->value <<= 8;
+               ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_AUTOGAIN:
+               /* autogain off means nothing without a gain */
+               if (c->value == 0)
+                       return 0;
+               ret = pwc_set_agc(pdev, c->value, 0);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_GAIN:
+               c->value <<= 8;
+               ret = pwc_set_agc(pdev, 0, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_SAVE_USER:
+               if (pwc_save_user(pdev))
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_RESTORE_USER:
+               if (pwc_restore_user(pdev))
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+               if (pwc_restore_factory(pdev))
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_COLOUR_MODE:
+               ret = pwc_set_colour_mode(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_AUTOCONTOUR:
+               c->value = (c->value == 1) ? -1 : 0;
+               ret = pwc_set_contour(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_CONTOUR:
+               c->value <<= 10;
+               ret = pwc_set_contour(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_BACKLIGHT:
+               ret = pwc_set_backlight(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
+       case V4L2_CID_PRIVATE_FLICKERLESS:
+               ret = pwc_set_flicker(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+       case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+               ret = pwc_set_dynamic_noise(pdev, c->value);
+               if (ret < 0)
+                       return -EINVAL;
+               return 0;
 
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
-                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                             return -EINVAL;
+       }
+       return -EINVAL;
+}
 
-                       pwc_vidioc_fill_fmt(pdev, f);
+static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+
+       /* We only support two format: the raw format, and YUV */
+       switch (f->index) {
+       case 0:
+               /* RAW format */
+               f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
+               f->flags = V4L2_FMT_FLAG_COMPRESSED;
+               strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description));
+               break;
+       case 1:
+               f->pixelformat = V4L2_PIX_FMT_YUV420;
+               strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description));
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
 
-                       return 0;
-               }
+static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct pwc_device *pdev = video_drvdata(file);
 
-               case VIDIOC_TRY_FMT:
-                       return pwc_vidioc_try_fmt(pdev, arg);
+       PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
+                       pdev->image.x, pdev->image.y);
+       pwc_vidioc_fill_fmt(pdev, f);
+       return 0;
+}
 
-               case VIDIOC_S_FMT:
-                       return pwc_vidioc_set_fmt(pdev, arg);
+static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct pwc_device *pdev = video_drvdata(file);
 
-               case VIDIOC_G_STD:
-               {
-                       v4l2_std_id *std = arg;
-                       *std = V4L2_STD_UNKNOWN;
-                       return 0;
-               }
+       return pwc_vidioc_try_fmt(pdev, f);
+}
 
-               case VIDIOC_S_STD:
-               {
-                       v4l2_std_id *std = arg;
-                       if (*std != V4L2_STD_UNKNOWN)
-                               return -EINVAL;
-                       return 0;
-               }
+static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct pwc_device *pdev = video_drvdata(file);
 
-               case VIDIOC_ENUMSTD:
-               {
-                       struct v4l2_standard *std = arg;
-                       if (std->index != 0)
-                               return -EINVAL;
-                       std->id = V4L2_STD_UNKNOWN;
-                       strlcpy(std->name, "webcam", sizeof(std->name));
-                       return 0;
-               }
+       return pwc_vidioc_set_fmt(pdev, f);
+}
 
-               case VIDIOC_REQBUFS:
-               {
-                       struct v4l2_requestbuffers *rb = arg;
-                       int nbuffers;
+static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
+{
+       int nbuffers;
 
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
-                       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-                       if (rb->memory != V4L2_MEMORY_MMAP)
-                               return -EINVAL;
+       PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
+       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (rb->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
 
-                       nbuffers = rb->count;
-                       if (nbuffers < 2)
-                               nbuffers = 2;
-                       else if (nbuffers > pwc_mbufs)
-                               nbuffers = pwc_mbufs;
-                       /* Force to use our # of buffers */
-                       rb->count = pwc_mbufs;
-                       return 0;
-               }
+       nbuffers = rb->count;
+       if (nbuffers < 2)
+               nbuffers = 2;
+       else if (nbuffers > pwc_mbufs)
+               nbuffers = pwc_mbufs;
+       /* Force to use our # of buffers */
+       rb->count = pwc_mbufs;
+       return 0;
+}
 
-               case VIDIOC_QUERYBUF:
-               {
-                       struct v4l2_buffer *buf = arg;
-                       int index;
+static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+       int index;
 
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
-                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
-                               return -EINVAL;
-                       }
-                       if (buf->memory != V4L2_MEMORY_MMAP) {
-                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
-                               return -EINVAL;
-                       }
-                       index = buf->index;
-                       if (index < 0 || index >= pwc_mbufs) {
-                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
-                               return -EINVAL;
-                       }
+       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+               return -EINVAL;
+       }
+       index = buf->index;
+       if (index < 0 || index >= pwc_mbufs) {
+               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+               return -EINVAL;
+       }
 
-                       memset(buf, 0, sizeof(struct v4l2_buffer));
-                       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                       buf->index = index;
-                       buf->m.offset = index * pdev->len_per_image;
-                       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
-                       else
-                               buf->bytesused = pdev->view.size;
-                       buf->field = V4L2_FIELD_NONE;
-                       buf->memory = V4L2_MEMORY_MMAP;
-                       //buf->flags = V4L2_BUF_FLAG_MAPPED;
-                       buf->length = pdev->len_per_image;
-
-                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
-                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
-                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+       buf->m.offset = index * pdev->len_per_image;
+       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
+               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+       else
+               buf->bytesused = pdev->view.size;
+       buf->field = V4L2_FIELD_NONE;
+       buf->memory = V4L2_MEMORY_MMAP;
+       /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
+       buf->length = pdev->len_per_image;
 
-                       return 0;
-               }
+       PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index);
+       PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset);
+       PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused);
 
-               case VIDIOC_QBUF:
-               {
-                       struct v4l2_buffer *buf = arg;
+       return 0;
+}
 
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
-                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
-                       if (buf->memory != V4L2_MEMORY_MMAP)
-                               return -EINVAL;
-                       if (buf->index >= pwc_mbufs)
-                               return -EINVAL;
+static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (buf->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+       if (buf->index >= pwc_mbufs)
+               return -EINVAL;
 
-                       buf->flags |= V4L2_BUF_FLAG_QUEUED;
-                       buf->flags &= ~V4L2_BUF_FLAG_DONE;
+       buf->flags |= V4L2_BUF_FLAG_QUEUED;
+       buf->flags &= ~V4L2_BUF_FLAG_DONE;
 
-                       return 0;
-               }
+       return 0;
+}
 
-               case VIDIOC_DQBUF:
-               {
-                       struct v4l2_buffer *buf = arg;
-                       int ret;
+static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct pwc_device *pdev = video_drvdata(file);
+       int ret;
 
-                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
 
-                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                               return -EINVAL;
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
-                       /* Add ourselves to the frame wait-queue.
-
-                          FIXME: needs auditing for safety.
-                          QUESTION: In what respect? I think that using the
-                                    frameq is safe now.
-                        */
-                       add_wait_queue(&pdev->frameq, &wait);
-                       while (pdev->full_frames == NULL) {
-                               if (pdev->error_status) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -pdev->error_status;
-                               }
+       add_wait_queue(&pdev->frameq, &wait);
+       while (pdev->full_frames == NULL) {
+               if (pdev->error_status) {
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+                       return -pdev->error_status;
+               }
 
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -ERESTARTSYS;
-                               }
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
+               if (signal_pending(current)) {
                        remove_wait_queue(&pdev->frameq, &wait);
                        set_current_state(TASK_RUNNING);
+                       return -ERESTARTSYS;
+               }
+               mutex_unlock(&pdev->modlock);
+               schedule();
+               set_current_state(TASK_INTERRUPTIBLE);
+               mutex_lock(&pdev->modlock);
+       }
+       remove_wait_queue(&pdev->frameq, &wait);
+       set_current_state(TASK_RUNNING);
 
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
-                       /* Decompress data in pdev->images[pdev->fill_image] */
-                       ret = pwc_handle_frame(pdev);
-                       if (ret)
-                               return -EFAULT;
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
-
-                       buf->index = pdev->fill_image;
-                       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
-                       else
-                               buf->bytesused = pdev->view.size;
-                       buf->flags = V4L2_BUF_FLAG_MAPPED;
-                       buf->field = V4L2_FIELD_NONE;
-                       do_gettimeofday(&buf->timestamp);
-                       buf->sequence = 0;
-                       buf->memory = V4L2_MEMORY_MMAP;
-                       buf->m.offset = pdev->fill_image * pdev->len_per_image;
-                       buf->length = pdev->len_per_image;
-                       pwc_next_image(pdev);
-
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
-                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
-                       return 0;
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+       /* Decompress data in pdev->images[pdev->fill_image] */
+       ret = pwc_handle_frame(pdev);
+       if (ret)
+               return -EFAULT;
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+       buf->index = pdev->fill_image;
+       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
+               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+       else
+               buf->bytesused = pdev->view.size;
+       buf->flags = V4L2_BUF_FLAG_MAPPED;
+       buf->field = V4L2_FIELD_NONE;
+       do_gettimeofday(&buf->timestamp);
+       buf->sequence = 0;
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->m.offset = pdev->fill_image * pdev->len_per_image;
+       buf->length = pdev->len_per_image;
+       pwc_next_image(pdev);
+
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index);
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length);
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset);
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused);
+       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+       return 0;
 
-               }
+}
 
-               case VIDIOC_STREAMON:
-               {
-                       return pwc_isoc_init(pdev);
-               }
+static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct pwc_device *pdev = video_drvdata(file);
 
-               case VIDIOC_STREAMOFF:
-               {
-                       pwc_isoc_cleanup(pdev);
-                       return 0;
-               }
+       return pwc_isoc_init(pdev);
+}
 
-               case VIDIOC_ENUM_FRAMESIZES:
-               {
-                       struct v4l2_frmsizeenum *fsize = arg;
-                       unsigned int i = 0, index = fsize->index;
-
-                       if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
-                               for (i = 0; i < PSZ_MAX; i++) {
-                                       if (pdev->image_mask & (1UL << i)) {
-                                               if (!index--) {
-                                                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-                                                       fsize->discrete.width = pwc_image_sizes[i].x;
-                                                       fsize->discrete.height = pwc_image_sizes[i].y;
-                                                       return 0;
-                                               }
-                                       }
-                               }
-                       } else if (fsize->index == 0 &&
-                                  ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
-                                   (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
-
-                               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-                               fsize->discrete.width = pdev->abs_max.x;
-                               fsize->discrete.height = pdev->abs_max.y;
-                               return 0;
-                       }
-                       return -EINVAL;
-               }
+static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct pwc_device *pdev = video_drvdata(file);
 
-               case VIDIOC_ENUM_FRAMEINTERVALS:
-               {
-                       struct v4l2_frmivalenum *fival = arg;
-                       int size = -1;
-                       unsigned int i;
-
-                       for (i = 0; i < PSZ_MAX; i++) {
-                               if (pwc_image_sizes[i].x == fival->width &&
-                                   pwc_image_sizes[i].y == fival->height) {
-                                       size = i;
-                                       break;
+       pwc_isoc_cleanup(pdev);
+       return 0;
+}
+
+static int pwc_enum_framesizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+       unsigned int i = 0, index = fsize->index;
+
+       if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
+               for (i = 0; i < PSZ_MAX; i++) {
+                       if (pdev->image_mask & (1UL << i)) {
+                               if (!index--) {
+                                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+                                       fsize->discrete.width = pwc_image_sizes[i].x;
+                                       fsize->discrete.height = pwc_image_sizes[i].y;
+                                       return 0;
                                }
                        }
+               }
+       } else if (fsize->index == 0 &&
+                       ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
+                        (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
+
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete.width = pdev->abs_max.x;
+               fsize->discrete.height = pdev->abs_max.y;
+               return 0;
+       }
+       return -EINVAL;
+}
 
-                       /* TODO: Support raw format */
-                       if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
-                               return -EINVAL;
-                       }
+static int pwc_enum_frameintervals(struct file *file, void *fh,
+                                          struct v4l2_frmivalenum *fival)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+       int size = -1;
+       unsigned int i;
+
+       for (i = 0; i < PSZ_MAX; i++) {
+               if (pwc_image_sizes[i].x == fival->width &&
+                               pwc_image_sizes[i].y == fival->height) {
+                       size = i;
+                       break;
+               }
+       }
 
-                       i = pwc_get_fps(pdev, fival->index, size);
-                       if (!i)
-                               return -EINVAL;
+       /* TODO: Support raw format */
+       if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
+               return -EINVAL;
 
-                       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
-                       fival->discrete.numerator = 1;
-                       fival->discrete.denominator = i;
+       i = pwc_get_fps(pdev, fival->index, size);
+       if (!i)
+               return -EINVAL;
 
-                       return 0;
-               }
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete.numerator = 1;
+       fival->discrete.denominator = i;
 
-               default:
-                       return pwc_ioctl(pdev, cmd, arg);
-       } /* ..switch */
        return 0;
 }
 
+static long pwc_default(struct file *file, void *fh, bool valid_prio,
+                       int cmd, void *arg)
+{
+       struct pwc_device *pdev = video_drvdata(file);
+
+       return pwc_ioctl(pdev, cmd, arg);
+}
+
+const struct v4l2_ioctl_ops pwc_ioctl_ops = {
+       .vidioc_querycap                    = pwc_querycap,
+       .vidioc_enum_input                  = pwc_enum_input,
+       .vidioc_g_input                     = pwc_g_input,
+       .vidioc_s_input                     = pwc_s_input,
+       .vidioc_enum_fmt_vid_cap            = pwc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap               = pwc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap               = pwc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap             = pwc_try_fmt_vid_cap,
+       .vidioc_queryctrl                   = pwc_queryctrl,
+       .vidioc_g_ctrl                      = pwc_g_ctrl,
+       .vidioc_s_ctrl                      = pwc_s_ctrl,
+       .vidioc_reqbufs                     = pwc_reqbufs,
+       .vidioc_querybuf                    = pwc_querybuf,
+       .vidioc_qbuf                        = pwc_qbuf,
+       .vidioc_dqbuf                       = pwc_dqbuf,
+       .vidioc_streamon                    = pwc_streamon,
+       .vidioc_streamoff                   = pwc_streamoff,
+       .vidioc_enum_framesizes             = pwc_enum_framesizes,
+       .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
+       .vidioc_default             = pwc_default,
+};
+
+
 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index 16bbc6df9b075a82c4ec03b9f3553c2c22a80da5..e947766337d63d9233ed333539705e677f81a742 100644 (file)
@@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
 /* Private ioctl()s; see pwc-ioctl.h */
 extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
 
-/** Functions in pwc-v4l.c */
-extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
+extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
index 2f500809f53d9b418dd2d3117ce44ef7706d0287..95f8b4e11e46f71773b9f8f2556a06be094e9510 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-mem2mem.h>
-#include <media/videobuf-core.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
 
 #include "fimc-core.h"
 
 static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
-                                           struct s3c_fimc_isp_info *isp_info)
+                                           struct s5p_fimc_isp_info *isp_info)
 {
        struct i2c_adapter *i2c_adap;
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
@@ -86,19 +86,19 @@ static void fimc_subdev_unregister(struct fimc_dev *fimc)
 static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
 {
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
-       struct s3c_platform_fimc *pdata = fimc->pdata;
-       struct s3c_fimc_isp_info *isp_info;
+       struct s5p_platform_fimc *pdata = fimc->pdata;
+       struct s5p_fimc_isp_info *isp_info;
        struct v4l2_subdev *sd;
        int i;
 
-       for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
-               isp_info = pdata->isp_info[i];
+       for (i = 0; i < pdata->num_clients; ++i) {
+               isp_info = &pdata->isp_info[i];
 
-               if (!isp_info || (index >= 0 && i != index))
+               if (index >= 0 && i != index)
                        continue;
 
                sd = fimc_subdev_register(fimc, isp_info);
-               if (sd) {
+               if (!IS_ERR_OR_NULL(sd)) {
                        vid_cap->sd = sd;
                        vid_cap->input_index = i;
 
@@ -113,60 +113,42 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
        return -ENODEV;
 }
 
-static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
+static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index)
 {
-       struct s3c_fimc_isp_info *isp_info;
+       struct s5p_fimc_isp_info *isp_info;
+       struct s5p_platform_fimc *pdata = fimc->pdata;
        int ret;
 
-       ret = fimc_subdev_attach(fimc, index);
-       if (ret)
-               return ret;
+       if (index >= pdata->num_clients)
+               return -EINVAL;
 
-       isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
-       ret = fimc_hw_set_camera_polarity(fimc, isp_info);
-       if (!ret) {
-               ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
-                                      s_power, 1);
-               if (!ret)
-                       return ret;
-       }
+       isp_info = &pdata->isp_info[index];
 
-       fimc_subdev_unregister(fimc);
-       err("ISP initialization failed: %d", ret);
-       return ret;
-}
+       if (isp_info->clk_frequency)
+               clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency);
 
-/*
- * At least one buffer on the pending_buf_q queue is required.
- * Locking: The caller holds fimc->slock spinlock.
- */
-int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
-                            struct fimc_vid_buffer *fimc_vb)
-{
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       struct fimc_ctx *ctx = cap->ctx;
-       int ret = 0;
+       ret = clk_enable(fimc->clock[CLK_CAM]);
+       if (ret)
+               return ret;
 
-       BUG_ON(!fimc || !fimc_vb);
+       ret = fimc_subdev_attach(fimc, index);
+       if (ret)
+               return ret;
 
-       ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
-                               &fimc_vb->paddr);
+       ret = fimc_hw_set_camera_polarity(fimc, isp_info);
        if (ret)
                return ret;
 
-       if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
-               fimc_pending_queue_add(cap, fimc_vb);
-       } else {
-               /* Setup the buffer directly for processing. */
-               int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
-               fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
+       ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1);
+       if (!ret)
+               return ret;
+
+       /* enabling power failed so unregister subdev */
+       fimc_subdev_unregister(fimc);
 
-               fimc_vb->index = cap->buf_index;
-               active_queue_add(cap, fimc_vb);
+       v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n",
+                ret);
 
-               if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
-                       cap->buf_index = 0;
-       }
        return ret;
 }
 
@@ -174,7 +156,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
 {
        unsigned long flags;
        struct fimc_vid_cap *cap;
-       int ret;
+       struct fimc_vid_buffer *buf;
 
        cap = &fimc->vid_cap;
 
@@ -187,24 +169,224 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
        spin_unlock_irqrestore(&fimc->slock, flags);
 
        wait_event_timeout(fimc->irq_queue,
-                          test_bit(ST_CAPT_SHUT, &fimc->state),
+                          !test_bit(ST_CAPT_SHUT, &fimc->state),
                           FIMC_SHUTDOWN_TIMEOUT);
 
-       ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
-       if (ret)
-               v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
+       v4l2_subdev_call(cap->sd, video, s_stream, 0);
 
        spin_lock_irqsave(&fimc->slock, flags);
        fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
-                       1 << ST_CAPT_STREAM);
+                        1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM);
 
        fimc->vid_cap.active_buf_cnt = 0;
+
+       /* Release buffers that were enqueued in the driver by videobuf2. */
+       while (!list_empty(&cap->pending_buf_q)) {
+               buf = pending_queue_pop(cap);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       while (!list_empty(&cap->active_buf_q)) {
+               buf = active_queue_pop(cap);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
        spin_unlock_irqrestore(&fimc->slock, flags);
 
        dbg("state: 0x%lx", fimc->state);
        return 0;
 }
 
+static int start_streaming(struct vb2_queue *q)
+{
+       struct fimc_ctx *ctx = q->drv_priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct s5p_fimc_isp_info *isp_info;
+       int ret;
+
+       fimc_hw_reset(fimc);
+
+       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
+       if (ret && ret != -ENOIOCTLCMD)
+               return ret;
+
+       ret = fimc_prepare_config(ctx, ctx->state);
+       if (ret)
+               return ret;
+
+       isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index];
+       fimc_hw_set_camera_type(fimc, isp_info);
+       fimc_hw_set_camera_source(fimc, isp_info);
+       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+       if (ctx->state & FIMC_PARAMS) {
+               ret = fimc_set_scaler_info(ctx);
+               if (ret) {
+                       err("Scaler setup error");
+                       return ret;
+               }
+               fimc_hw_set_input_path(ctx);
+               fimc_hw_set_prescaler(ctx);
+               fimc_hw_set_mainscaler(ctx);
+               fimc_hw_set_target_format(ctx);
+               fimc_hw_set_rotation(ctx);
+               fimc_hw_set_effect(ctx);
+       }
+
+       fimc_hw_set_output_path(ctx);
+       fimc_hw_set_out_dma(ctx);
+
+       INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
+       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+       fimc->vid_cap.active_buf_cnt = 0;
+       fimc->vid_cap.frame_count = 0;
+       fimc->vid_cap.buf_index = 0;
+
+       set_bit(ST_CAPT_PEND, &fimc->state);
+
+       return 0;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+       struct fimc_ctx *ctx = q->drv_priv;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+
+       if (!fimc_capture_active(fimc))
+               return -EINVAL;
+
+       return fimc_stop_capture(fimc);
+}
+
+static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
+{
+       if (!fr || plane >= fr->fmt->memplanes)
+               return 0;
+
+       dbg("%s: w: %d. h: %d. depth[%d]: %d",
+           __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]);
+
+       return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8;
+
+}
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+                      unsigned int *num_planes, unsigned long sizes[],
+                      void *allocators[])
+{
+       struct fimc_ctx *ctx = vq->drv_priv;
+       struct fimc_fmt *fmt = ctx->d_frame.fmt;
+       int i;
+
+       if (!fmt)
+               return -EINVAL;
+
+       *num_planes = fmt->memplanes;
+
+       dbg("%s, buffer count=%d, plane count=%d",
+           __func__, *num_buffers, *num_planes);
+
+       for (i = 0; i < fmt->memplanes; i++) {
+               sizes[i] = get_plane_size(&ctx->d_frame, i);
+               dbg("plane: %u, plane_size: %lu", i, sizes[i]);
+               allocators[i] = ctx->fimc_dev->alloc_ctx;
+       }
+
+       return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+       /* TODO: */
+       return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct fimc_ctx *ctx = vq->drv_priv;
+       struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
+       int i;
+
+       if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return -EINVAL;
+
+       for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) {
+               unsigned long size = get_plane_size(&ctx->d_frame, i);
+
+               if (vb2_plane_size(vb, i) < size) {
+                       v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n",
+                                vb2_plane_size(vb, i), size);
+                       return -EINVAL;
+               }
+
+               vb2_set_plane_payload(vb, i, size);
+       }
+
+       return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       struct fimc_vid_buffer *buf
+               = container_of(vb, struct fimc_vid_buffer, vb);
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       unsigned long flags;
+       int min_bufs;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr);
+
+       if (!test_bit(ST_CAPT_STREAM, &fimc->state)
+            && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
+               /* Setup the buffer directly for processing. */
+               int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :
+                               vid_cap->buf_index;
+
+               fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id);
+               buf->index = vid_cap->buf_index;
+               active_queue_add(vid_cap, buf);
+
+               if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS)
+                       vid_cap->buf_index = 0;
+       } else {
+               fimc_pending_queue_add(vid_cap, buf);
+       }
+
+       min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;
+
+       if (vid_cap->active_buf_cnt >= min_bufs &&
+           !test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+               fimc_activate_capture(ctx);
+
+       spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_lock(&ctx->fimc_dev->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_unlock(&ctx->fimc_dev->lock);
+}
+
+static struct vb2_ops fimc_capture_qops = {
+       .queue_setup            = queue_setup,
+       .buf_prepare            = buffer_prepare,
+       .buf_queue              = buffer_queue,
+       .buf_init               = buffer_init,
+       .wait_prepare           = fimc_unlock,
+       .wait_finish            = fimc_lock,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+};
+
 static int fimc_capture_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
@@ -216,44 +398,36 @@ static int fimc_capture_open(struct file *file)
        if (fimc_m2m_active(fimc))
                return -EBUSY;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        if (++fimc->vid_cap.refcnt == 1) {
-               ret = fimc_isp_subdev_init(fimc, -1);
+               ret = fimc_isp_subdev_init(fimc, 0);
                if (ret) {
                        fimc->vid_cap.refcnt--;
-                       ret = -EIO;
+                       return -EIO;
                }
        }
 
        file->private_data = fimc->vid_cap.ctx;
 
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return 0;
 }
 
 static int fimc_capture_close(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
        if (--fimc->vid_cap.refcnt == 0) {
                fimc_stop_capture(fimc);
-
-               videobuf_stop(&fimc->vid_cap.vbq);
-               videobuf_mmap_free(&fimc->vid_cap.vbq);
+               vb2_queue_release(&fimc->vid_cap.vbq);
 
                v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+
                v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+               clk_disable(fimc->clock[CLK_CAM]);
                fimc_subdev_unregister(fimc);
        }
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -262,32 +436,16 @@ static unsigned int fimc_capture_poll(struct file *file,
 {
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       int ret;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return POLLERR;
 
-       ret = videobuf_poll_stream(file, &cap->vbq, wait);
-       mutex_unlock(&fimc->lock);
-
-       return ret;
+       return vb2_poll(&fimc->vid_cap.vbq, file, wait);
 }
 
 static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       int ret;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
 
-       ret = videobuf_mmap_mapper(&cap->vbq, vma);
-       mutex_unlock(&fimc->lock);
-
-       return ret;
+       return vb2_mmap(&fimc->vid_cap.vbq, vma);
 }
 
 /* video device file operations */
@@ -310,7 +468,8 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
        cap->version = KERNEL_VERSION(1, 0, 0);
-       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_VIDEO_CAPTURE_MPLANE;
 
        return 0;
 }
@@ -351,57 +510,52 @@ static int sync_capture_fmt(struct fimc_ctx *ctx)
        return 0;
 }
 
-static int fimc_cap_s_fmt(struct file *file, void *priv,
-                            struct v4l2_format *f)
+static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
+                                struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *frame;
-       struct v4l2_pix_format *pix;
+       struct v4l2_pix_format_mplane *pix;
        int ret;
+       int i;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
 
-       ret = fimc_vidioc_try_fmt(file, priv, f);
+       ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
        if (ret)
                return ret;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       if (fimc_capture_active(fimc)) {
-               ret = -EBUSY;
-               goto sf_unlock;
-       }
+       if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
+               return -EBUSY;
 
        frame = &ctx->d_frame;
 
-       pix = &f->fmt.pix;
+       pix = &f->fmt.pix_mp;
        frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
        if (!frame->fmt) {
                err("fimc target format not found\n");
-               ret = -EINVAL;
-               goto sf_unlock;
+               return -EINVAL;
        }
 
+       for (i = 0; i < frame->fmt->colplanes; i++)
+               frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+
        /* Output DMA frame pixel size and offsets. */
-       frame->f_width  = pix->bytesperline * 8 / frame->fmt->depth;
+       frame->f_width = pix->plane_fmt[0].bytesperline * 8
+                       / frame->fmt->depth[0];
        frame->f_height = pix->height;
        frame->width    = pix->width;
        frame->height   = pix->height;
        frame->o_width  = pix->width;
        frame->o_height = pix->height;
-       frame->size     = (pix->width * pix->height * frame->fmt->depth) >> 3;
        frame->offs_h   = 0;
        frame->offs_v   = 0;
 
-       ret = sync_capture_fmt(ctx);
-
        ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
 
-sf_unlock:
-       mutex_unlock(&fimc->lock);
+       ret = sync_capture_fmt(ctx);
        return ret;
 }
 
@@ -409,15 +563,13 @@ static int fimc_cap_enum_input(struct file *file, void *priv,
                                     struct v4l2_input *i)
 {
        struct fimc_ctx *ctx = priv;
-       struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
-       struct s3c_fimc_isp_info *isp_info;
+       struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata;
+       struct s5p_fimc_isp_info *isp_info;
 
-       if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
+       if (i->index >= pldata->num_clients)
                return -EINVAL;
 
-       isp_info = pldata->isp_info[i->index];
-       if (isp_info == NULL)
-               return -EINVAL;
+       isp_info = &pldata->isp_info[i->index];
 
        i->type = V4L2_INPUT_TYPE_CAMERA;
        strncpy(i->name, isp_info->board_info->type, 32);
@@ -429,34 +581,27 @@ static int fimc_cap_s_input(struct file *file, void *priv,
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct s3c_platform_fimc *pdata = fimc->pdata;
-       int ret;
+       struct s5p_platform_fimc *pdata = fimc->pdata;
 
        if (fimc_capture_active(ctx->fimc_dev))
                return -EBUSY;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
+       if (i >= pdata->num_clients)
+               return -EINVAL;
 
-       if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
-               ret = -EINVAL;
-               goto si_unlock;
-       }
 
        if (fimc->vid_cap.sd) {
-               ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+               int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
                if (ret)
                        err("s_power failed: %d", ret);
+
+               clk_disable(fimc->clock[CLK_CAM]);
        }
 
        /* Release the attached sensor subdevice. */
        fimc_subdev_unregister(fimc);
 
-       ret = fimc_isp_subdev_init(fimc, i);
-
-si_unlock:
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return fimc_isp_subdev_init(fimc, i);
 }
 
 static int fimc_cap_g_input(struct file *file, void *priv,
@@ -470,66 +615,20 @@ static int fimc_cap_g_input(struct file *file, void *priv,
 }
 
 static int fimc_cap_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type type)
+                            enum v4l2_buf_type type)
 {
-       struct s3c_fimc_isp_info *isp_info;
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret = -EBUSY;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
 
        if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
-               goto s_unlock;
+               return -EBUSY;
 
        if (!(ctx->state & FIMC_DST_FMT)) {
                v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
-               ret = -EINVAL;
-               goto s_unlock;
-       }
-
-       ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
-       if (ret && ret != -ENOIOCTLCMD)
-               goto s_unlock;
-
-       ret = fimc_prepare_config(ctx, ctx->state);
-       if (ret)
-               goto s_unlock;
-
-       isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
-       fimc_hw_set_camera_type(fimc, isp_info);
-       fimc_hw_set_camera_source(fimc, isp_info);
-       fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
-
-       if (ctx->state & FIMC_PARAMS) {
-               ret = fimc_set_scaler_info(ctx);
-               if (ret) {
-                       err("Scaler setup error");
-                       goto s_unlock;
-               }
-               fimc_hw_set_input_path(ctx);
-               fimc_hw_set_scaler(ctx);
-               fimc_hw_set_target_format(ctx);
-               fimc_hw_set_rotation(ctx);
-               fimc_hw_set_effect(ctx);
+               return -EINVAL;
        }
 
-       fimc_hw_set_output_path(ctx);
-       fimc_hw_set_out_dma(ctx);
-
-       INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
-       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
-       fimc->vid_cap.active_buf_cnt = 0;
-       fimc->vid_cap.frame_count = 0;
-       fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc);
-
-       set_bit(ST_CAPT_PEND, &fimc->state);
-       ret = videobuf_streamon(&fimc->vid_cap.vbq);
-
-s_unlock:
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return vb2_streamon(&fimc->vid_cap.vbq, type);
 }
 
 static int fimc_cap_streamoff(struct file *file, void *priv,
@@ -537,46 +636,22 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&fimc->slock, flags);
-       if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
-               spin_unlock_irqrestore(&fimc->slock, flags);
-               dbg("state: 0x%lx", fimc->state);
-               return -EINVAL;
-       }
-       spin_unlock_irqrestore(&fimc->slock, flags);
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       fimc_stop_capture(fimc);
-       ret = videobuf_streamoff(&cap->vbq);
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return vb2_streamoff(&fimc->vid_cap.vbq, type);
 }
 
 static int fimc_cap_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *reqbufs)
+                           struct v4l2_requestbuffers *reqbufs)
 {
        struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
        int ret;
 
-       if (fimc_capture_active(ctx->fimc_dev))
-               return -EBUSY;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       ret = videobuf_reqbufs(&cap->vbq, reqbufs);
+       ret = vb2_reqbufs(&cap->vbq, reqbufs);
        if (!ret)
                cap->reqbufs_count = reqbufs->count;
 
-       mutex_unlock(&fimc->lock);
        return ret;
 }
 
@@ -586,43 +661,23 @@ static int fimc_cap_querybuf(struct file *file, void *priv,
        struct fimc_ctx *ctx = priv;
        struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
 
-       if (fimc_capture_active(ctx->fimc_dev))
-               return -EBUSY;
-
-       return videobuf_querybuf(&cap->vbq, buf);
+       return vb2_querybuf(&cap->vbq, buf);
 }
 
 static int fimc_cap_qbuf(struct file *file, void *priv,
                          struct v4l2_buffer *buf)
 {
        struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       int ret;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       ret = videobuf_qbuf(&cap->vbq, buf);
-
-       mutex_unlock(&fimc->lock);
-       return ret;
+       struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+       return vb2_qbuf(&cap->vbq, buf);
 }
 
 static int fimc_cap_dqbuf(struct file *file, void *priv,
                           struct v4l2_buffer *buf)
 {
        struct fimc_ctx *ctx = priv;
-       int ret;
-
-       if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
-               return -ERESTARTSYS;
-
-       ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
+       return vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
                file->f_flags & O_NONBLOCK);
-
-       mutex_unlock(&ctx->fimc_dev->lock);
-       return ret;
 }
 
 static int fimc_cap_s_ctrl(struct file *file, void *priv,
@@ -631,9 +686,6 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv,
        struct fimc_ctx *ctx = priv;
        int ret = -EINVAL;
 
-       if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
-               return -ERESTARTSYS;
-
        /* Allow any controls but 90/270 rotation while streaming */
        if (!fimc_capture_active(ctx->fimc_dev) ||
            ctrl->id != V4L2_CID_ROTATE ||
@@ -648,8 +700,6 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv,
        if (ret == -EINVAL)
                ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
                                       core, s_ctrl, ctrl);
-
-       mutex_unlock(&ctx->fimc_dev->lock);
        return ret;
 }
 
@@ -658,22 +708,18 @@ static int fimc_cap_cropcap(struct file *file, void *fh,
 {
        struct fimc_frame *f;
        struct fimc_ctx *ctx = fh;
-       struct fimc_dev *fimc = ctx->fimc_dev;
 
-       if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                return -EINVAL;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        f = &ctx->s_frame;
+
        cr->bounds.left         = 0;
        cr->bounds.top          = 0;
        cr->bounds.width        = f->o_width;
        cr->bounds.height       = f->o_height;
        cr->defrect             = cr->bounds;
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -681,19 +727,14 @@ static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
        struct fimc_frame *f;
        struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
 
        f = &ctx->s_frame;
+
        cr->c.left      = f->offs_h;
        cr->c.top       = f->offs_v;
        cr->c.width     = f->width;
        cr->c.height    = f->height;
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -712,41 +753,38 @@ static int fimc_cap_s_crop(struct file *file, void *fh,
        if (ret)
                return ret;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        if (!(ctx->state & FIMC_DST_FMT)) {
                v4l2_err(&fimc->vid_cap.v4l2_dev,
                         "Capture color format not set\n");
-               goto sc_unlock;
+               return -EINVAL; /* TODO: make sure this is the right value */
        }
 
        f = &ctx->s_frame;
        /* Check for the pixel scaling ratio when cropping input image. */
-       ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+       ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
+                                     ctx->d_frame.width, ctx->d_frame.height,
+                                     ctx->rotation);
        if (ret) {
-               v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
-       } else {
-               ret = 0;
-               f->offs_h = cr->c.left;
-               f->offs_v = cr->c.top;
-               f->width  = cr->c.width;
-               f->height = cr->c.height;
+               v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n");
+               return ret;
        }
 
-sc_unlock:
-       mutex_unlock(&fimc->lock);
-       return ret;
+       f->offs_h = cr->c.left;
+       f->offs_v = cr->c.top;
+       f->width  = cr->c.width;
+       f->height = cr->c.height;
+
+       return 0;
 }
 
 
 static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_querycap                = fimc_vidioc_querycap_capture,
 
-       .vidioc_enum_fmt_vid_cap        = fimc_vidioc_enum_fmt,
-       .vidioc_try_fmt_vid_cap         = fimc_vidioc_try_fmt,
-       .vidioc_s_fmt_vid_cap           = fimc_cap_s_fmt,
-       .vidioc_g_fmt_vid_cap           = fimc_vidioc_g_fmt,
+       .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane,
+       .vidioc_try_fmt_vid_cap_mplane  = fimc_vidioc_try_fmt_mplane,
+       .vidioc_s_fmt_vid_cap_mplane    = fimc_cap_s_fmt_mplane,
+       .vidioc_g_fmt_vid_cap_mplane    = fimc_vidioc_g_fmt_mplane,
 
        .vidioc_reqbufs                 = fimc_cap_reqbufs,
        .vidioc_querybuf                = fimc_cap_querybuf,
@@ -770,6 +808,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_g_input                 = fimc_cap_g_input,
 };
 
+/* fimc->lock must be already initialized */
 int fimc_register_capture_device(struct fimc_dev *fimc)
 {
        struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
@@ -777,6 +816,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        struct fimc_vid_cap *vid_cap;
        struct fimc_ctx *ctx;
        struct v4l2_format f;
+       struct fimc_frame *fr;
+       struct vb2_queue *q;
        int ret;
 
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
@@ -788,8 +829,12 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        ctx->out_path    = FIMC_DMA;
        ctx->state       = FIMC_CTX_CAP;
 
-       f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
-       ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
+       /* Default format of the output frames */
+       f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
+       fr = &ctx->d_frame;
+       fr->fmt = find_format(&f, FMT_FLAGS_M2M);
+       fr->width = fr->f_width = fr->o_width = 640;
+       fr->height = fr->f_height = fr->o_height = 480;
 
        if (!v4l2_dev->name[0])
                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
@@ -812,6 +857,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        vfd->ioctl_ops  = &fimc_capture_ioctl_ops;
        vfd->minor      = -1;
        vfd->release    = video_device_release;
+       vfd->lock       = &fimc->lock;
        video_set_drvdata(vfd, fimc);
 
        vid_cap = &fimc->vid_cap;
@@ -819,7 +865,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        vid_cap->active_buf_cnt = 0;
        vid_cap->reqbufs_count  = 0;
        vid_cap->refcnt = 0;
-       /* The default color format for image sensor. */
+       /* Default color format for image sensor */
        vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
 
        INIT_LIST_HEAD(&vid_cap->pending_buf_q);
@@ -827,10 +873,16 @@ int fimc_register_capture_device(struct fimc_dev *fimc)
        spin_lock_init(&ctx->slock);
        vid_cap->ctx = ctx;
 
-       videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
-               vid_cap->v4l2_dev.dev, &fimc->irqlock,
-               V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
-               sizeof(struct fimc_vid_buffer), (void *)ctx, NULL);
+       q = &fimc->vid_cap.vbq;
+       memset(q, 0, sizeof(*q));
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR;
+       q->drv_priv = fimc->vid_cap.ctx;
+       q->ops = &fimc_capture_qops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->buf_struct_size = sizeof(struct fimc_vid_buffer);
+
+       vb2_queue_init(q);
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
        if (ret) {
index 817aa66627f64959c6ad0c0e5da3a850862530a0..6c919b38a3d89c17c33d4cd5d4beee2252f23929 100644 (file)
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <media/v4l2-ioctl.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
 
 #include "fimc-core.h"
 
-static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" };
+static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
+       "sclk_fimc", "fimc", "sclk_cam"
+};
 
 static struct fimc_fmt fimc_formats[] = {
        {
-               .name   = "RGB565",
-               .fourcc = V4L2_PIX_FMT_RGB565X,
-               .depth  = 16,
-               .color  = S5P_FIMC_RGB565,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "RGB565",
+               .fourcc         = V4L2_PIX_FMT_RGB565X,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_RGB565,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_BE,
+               .flags          = FMT_FLAGS_M2M,
+       }, {
+               .name           = "BGR666",
+               .fourcc         = V4L2_PIX_FMT_BGR666,
+               .depth          = { 32 },
+               .color          = S5P_FIMC_RGB666,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .flags          = FMT_FLAGS_M2M,
+       }, {
+               .name           = "XRGB-8-8-8-8, 32 bpp",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .depth          = { 32 },
+               .color          = S5P_FIMC_RGB888,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .flags          = FMT_FLAGS_M2M,
+       }, {
+               .name           = "YUV 4:2:2 packed, YCbYCr",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_YCBYCR422,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
-               .name   = "BGR666",
-               .fourcc = V4L2_PIX_FMT_BGR666,
-               .depth  = 32,
-               .color  = S5P_FIMC_RGB666,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:2 packed, CbYCrY",
+               .fourcc         = V4L2_PIX_FMT_UYVY,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_CBYCRY422,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
+               .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
-               .name = "XRGB-8-8-8-8, 32 bpp",
-               .fourcc = V4L2_PIX_FMT_RGB32,
-               .depth = 32,
-               .color  = S5P_FIMC_RGB888,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:2 packed, CrYCbY",
+               .fourcc         = V4L2_PIX_FMT_VYUY,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_CRYCBY422,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_VYUY8_2X8,
+               .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
-               .name   = "YUV 4:2:2 packed, YCbYCr",
-               .fourcc = V4L2_PIX_FMT_YUYV,
-               .depth  = 16,
-               .color  = S5P_FIMC_YCBYCR422,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
-               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+               .name           = "YUV 4:2:2 packed, YCrYCb",
+               .fourcc         = V4L2_PIX_FMT_YVYU,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_YCRYCB422,
+               .memplanes      = 1,
+               .colplanes      = 1,
+               .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
+               .flags          = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
        }, {
-               .name   = "YUV 4:2:2 packed, CbYCrY",
-               .fourcc = V4L2_PIX_FMT_UYVY,
-               .depth  = 16,
-               .color  = S5P_FIMC_CBYCRY422,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
-               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+               .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
+               .fourcc         = V4L2_PIX_FMT_YUV422P,
+               .depth          = { 12 },
+               .color          = S5P_FIMC_YCBYCR422,
+               .memplanes      = 1,
+               .colplanes      = 3,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:2 packed, CrYCbY",
-               .fourcc = V4L2_PIX_FMT_VYUY,
-               .depth  = 16,
-               .color  = S5P_FIMC_CRYCBY422,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
-               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+               .name           = "YUV 4:2:2 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV16,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_YCBYCR422,
+               .memplanes      = 1,
+               .colplanes      = 2,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:2 packed, YCrYCb",
-               .fourcc = V4L2_PIX_FMT_YVYU,
-               .depth  = 16,
-               .color  = S5P_FIMC_YCRYCB422,
-               .buff_cnt = 1,
-               .planes_cnt = 1,
-               .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
-               .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+               .name           = "YUV 4:2:2 planar, Y/CrCb",
+               .fourcc         = V4L2_PIX_FMT_NV61,
+               .depth          = { 16 },
+               .color          = S5P_FIMC_YCRYCB422,
+               .memplanes      = 1,
+               .colplanes      = 2,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:2 planar, Y/Cb/Cr",
-               .fourcc = V4L2_PIX_FMT_YUV422P,
-               .depth  = 12,
-               .color  = S5P_FIMC_YCBCR422,
-               .buff_cnt = 1,
-               .planes_cnt = 3,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:0 planar, YCbCr",
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+               .depth          = { 12 },
+               .color          = S5P_FIMC_YCBCR420,
+               .memplanes      = 1,
+               .colplanes      = 3,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:2 planar, Y/CbCr",
-               .fourcc = V4L2_PIX_FMT_NV16,
-               .depth  = 16,
-               .color  = S5P_FIMC_YCBCR422,
-               .buff_cnt = 1,
-               .planes_cnt = 2,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:0 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .depth          = { 12 },
+               .color          = S5P_FIMC_YCBCR420,
+               .memplanes      = 1,
+               .colplanes      = 2,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:2 planar, Y/CrCb",
-               .fourcc = V4L2_PIX_FMT_NV61,
-               .depth  = 16,
-               .color  = S5P_FIMC_RGB565,
-               .buff_cnt = 1,
-               .planes_cnt = 2,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV12M,
+               .color          = S5P_FIMC_YCBCR420,
+               .depth          = { 8, 4 },
+               .memplanes      = 2,
+               .colplanes      = 2,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:0 planar, YCbCr",
-               .fourcc = V4L2_PIX_FMT_YUV420,
-               .depth  = 12,
-               .color  = S5P_FIMC_YCBCR420,
-               .buff_cnt = 1,
-               .planes_cnt = 3,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+               .fourcc         = V4L2_PIX_FMT_YUV420M,
+               .color          = S5P_FIMC_YCBCR420,
+               .depth          = { 8, 2, 2 },
+               .memplanes      = 3,
+               .colplanes      = 3,
+               .flags          = FMT_FLAGS_M2M,
        }, {
-               .name   = "YUV 4:2:0 planar, Y/CbCr",
-               .fourcc = V4L2_PIX_FMT_NV12,
-               .depth  = 12,
-               .color  = S5P_FIMC_YCBCR420,
-               .buff_cnt = 1,
-               .planes_cnt = 2,
-               .flags = FMT_FLAGS_M2M,
+               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
+               .fourcc         = V4L2_PIX_FMT_NV12MT,
+               .color          = S5P_FIMC_YCBCR420,
+               .depth          = { 8, 4 },
+               .memplanes      = 2,
+               .colplanes      = 2,
+               .flags          = FMT_FLAGS_M2M,
        },
 };
 
@@ -173,24 +200,21 @@ static struct v4l2_queryctrl *get_ctrl(int id)
        return NULL;
 }
 
-int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
+int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot)
 {
-       if (r->width > f->width) {
-               if (f->width > (r->width * SCALER_MAX_HRATIO))
-                       return -EINVAL;
-       } else {
-               if ((f->width * SCALER_MAX_HRATIO) < r->width)
-                       return -EINVAL;
-       }
+       int tx, ty;
 
-       if (r->height > f->height) {
-               if (f->height > (r->height * SCALER_MAX_VRATIO))
-                       return -EINVAL;
+       if (rot == 90 || rot == 270) {
+               ty = dw;
+               tx = dh;
        } else {
-               if ((f->height * SCALER_MAX_VRATIO) < r->height)
-                       return -EINVAL;
+               tx = dw;
+               ty = dh;
        }
 
+       if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty))
+               return -EINVAL;
+
        return 0;
 }
 
@@ -221,6 +245,7 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
        struct fimc_scaler *sc = &ctx->scaler;
        struct fimc_frame *s_frame = &ctx->s_frame;
        struct fimc_frame *d_frame = &ctx->d_frame;
+       struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
        int tx, ty, sx, sy;
        int ret;
 
@@ -259,8 +284,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
        sc->pre_dst_width = sx / sc->pre_hratio;
        sc->pre_dst_height = sy / sc->pre_vratio;
 
-       sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
-       sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
+       if (variant->has_mainscaler_ext) {
+               sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
+               sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
+       } else {
+               sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
+               sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
+
+       }
 
        sc->scaleup_h = (tx >= sx) ? 1 : 0;
        sc->scaleup_v = (ty >= sy) ? 1 : 0;
@@ -276,14 +307,65 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
        return 0;
 }
 
-static void fimc_capture_handler(struct fimc_dev *fimc)
+static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
+{
+       struct vb2_buffer *src_vb, *dst_vb;
+       struct fimc_dev *fimc = ctx->fimc_dev;
+
+       if (!ctx || !ctx->m2m_ctx)
+               return;
+
+       src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+       if (src_vb && dst_vb) {
+               v4l2_m2m_buf_done(src_vb, vb_state);
+               v4l2_m2m_buf_done(dst_vb, vb_state);
+               v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+       }
+}
+
+/* Complete the transaction which has been scheduled for execution. */
+static void fimc_m2m_shutdown(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret;
+
+       if (!fimc_m2m_pending(fimc))
+               return;
+
+       fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx);
+
+       ret = wait_event_timeout(fimc->irq_queue,
+                          !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
+                          FIMC_SHUTDOWN_TIMEOUT);
+       /*
+        * In case of a timeout the buffers are not released in the interrupt
+        * handler so return them here with the error flag set, if there are
+        * any on the queue.
+        */
+       if (ret == 0)
+               fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+       struct fimc_ctx *ctx = q->drv_priv;
+
+       fimc_m2m_shutdown(ctx);
+
+       return 0;
+}
+
+static void fimc_capture_irq_handler(struct fimc_dev *fimc)
 {
        struct fimc_vid_cap *cap = &fimc->vid_cap;
-       struct fimc_vid_buffer *v_buf = NULL;
+       struct fimc_vid_buffer *v_buf;
 
-       if (!list_empty(&cap->active_buf_q)) {
+       if (!list_empty(&cap->active_buf_q) &&
+           test_bit(ST_CAPT_RUN, &fimc->state)) {
                v_buf = active_queue_pop(cap);
-               fimc_buf_finish(fimc, v_buf);
+               vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
        }
 
        if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
@@ -297,13 +379,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc)
                fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
                v_buf->index = cap->buf_index;
 
-               dbg("hw ptr: %d, sw ptr: %d",
-                   fimc_hw_get_frame_index(fimc), cap->buf_index);
-
-               spin_lock(&fimc->irqlock);
-               v_buf->vb.state = VIDEOBUF_ACTIVE;
-               spin_unlock(&fimc->irqlock);
-
                /* Move the buffer to the capture active queue */
                active_queue_add(cap, v_buf);
 
@@ -312,77 +387,79 @@ static void fimc_capture_handler(struct fimc_dev *fimc)
 
                if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
                        cap->buf_index = 0;
+       }
 
-       } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
-                  cap->active_buf_cnt <= 1) {
-               fimc_deactivate_capture(fimc);
+       if (cap->active_buf_cnt == 0) {
+               clear_bit(ST_CAPT_RUN, &fimc->state);
+
+               if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+                       cap->buf_index = 0;
+       } else {
+               set_bit(ST_CAPT_RUN, &fimc->state);
        }
 
-       dbg("frame: %d, active_buf_cnt= %d",
+       dbg("frame: %d, active_buf_cnt: %d",
            fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
 }
 
 static irqreturn_t fimc_isr(int irq, void *priv)
 {
-       struct fimc_vid_buffer *src_buf, *dst_buf;
-       struct fimc_ctx *ctx;
        struct fimc_dev *fimc = priv;
+       struct fimc_vid_cap *cap = &fimc->vid_cap;
+       struct fimc_ctx *ctx;
 
-       BUG_ON(!fimc);
        fimc_hw_clear_irq(fimc);
 
-       spin_lock(&fimc->slock);
-
        if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
                ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
-               if (!ctx || !ctx->m2m_ctx)
-                       goto isr_unlock;
-               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-               if (src_buf && dst_buf) {
-                       spin_lock(&fimc->irqlock);
-                       src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
-                       wake_up(&src_buf->vb.done);
-                       wake_up(&dst_buf->vb.done);
-                       spin_unlock(&fimc->irqlock);
-                       v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+               if (ctx != NULL) {
+                       fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
+
+                       spin_lock(&ctx->slock);
+                       if (ctx->state & FIMC_CTX_SHUT) {
+                               ctx->state &= ~FIMC_CTX_SHUT;
+                               wake_up(&fimc->irq_queue);
+                       }
+                       spin_unlock(&ctx->slock);
                }
-               goto isr_unlock;
 
+               return IRQ_HANDLED;
        }
 
-       if (test_bit(ST_CAPT_RUN, &fimc->state))
-               fimc_capture_handler(fimc);
+       spin_lock(&fimc->slock);
 
-       if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
-               set_bit(ST_CAPT_RUN, &fimc->state);
-               wake_up(&fimc->irq_queue);
+       if (test_bit(ST_CAPT_PEND, &fimc->state)) {
+               fimc_capture_irq_handler(fimc);
+
+               if (cap->active_buf_cnt == 1) {
+                       fimc_deactivate_capture(fimc);
+                       clear_bit(ST_CAPT_STREAM, &fimc->state);
+               }
        }
 
-isr_unlock:
        spin_unlock(&fimc->slock);
        return IRQ_HANDLED;
 }
 
-/* The color format (planes_cnt, buff_cnt) must be already configured. */
-int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+/* The color format (colplanes, memplanes) must be already configured. */
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
                      struct fimc_frame *frame, struct fimc_addr *paddr)
 {
        int ret = 0;
        u32 pix_size;
 
-       if (buf == NULL || frame == NULL)
+       if (vb == NULL || frame == NULL)
                return -EINVAL;
 
        pix_size = frame->width * frame->height;
 
-       dbg("buff_cnt= %d, planes_cnt= %d, frame->size= %d, pix_size= %d",
-               frame->fmt->buff_cnt, frame->fmt->planes_cnt,
-               frame->size, pix_size);
+       dbg("memplanes= %d, colplanes= %d, pix_size= %d",
+               frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
+
+       paddr->y = vb2_dma_contig_plane_paddr(vb, 0);
 
-       if (frame->fmt->buff_cnt == 1) {
-               paddr->y = videobuf_to_dma_contig(&buf->vb);
-               switch (frame->fmt->planes_cnt) {
+       if (frame->fmt->memplanes == 1) {
+               switch (frame->fmt->colplanes) {
                case 1:
                        paddr->cb = 0;
                        paddr->cr = 0;
@@ -405,6 +482,12 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
                default:
                        return -EINVAL;
                }
+       } else {
+               if (frame->fmt->memplanes >= 2)
+                       paddr->cb = vb2_dma_contig_plane_paddr(vb, 1);
+
+               if (frame->fmt->memplanes == 3)
+                       paddr->cr = vb2_dma_contig_plane_paddr(vb, 2);
        }
 
        dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
@@ -423,34 +506,34 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx)
        /* Set order for 1 plane input formats. */
        switch (ctx->s_frame.fmt->color) {
        case S5P_FIMC_YCRYCB422:
-               ctx->in_order_1p = S5P_FIMC_IN_YCRYCB;
+               ctx->in_order_1p = S5P_MSCTRL_ORDER422_CBYCRY;
                break;
        case S5P_FIMC_CBYCRY422:
-               ctx->in_order_1p = S5P_FIMC_IN_CBYCRY;
+               ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCRYCB;
                break;
        case S5P_FIMC_CRYCBY422:
-               ctx->in_order_1p = S5P_FIMC_IN_CRYCBY;
+               ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCBYCR;
                break;
        case S5P_FIMC_YCBYCR422:
        default:
-               ctx->in_order_1p = S5P_FIMC_IN_YCBYCR;
+               ctx->in_order_1p = S5P_MSCTRL_ORDER422_CRYCBY;
                break;
        }
        dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
 
        switch (ctx->d_frame.fmt->color) {
        case S5P_FIMC_YCRYCB422:
-               ctx->out_order_1p = S5P_FIMC_OUT_YCRYCB;
+               ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CBYCRY;
                break;
        case S5P_FIMC_CBYCRY422:
-               ctx->out_order_1p = S5P_FIMC_OUT_CBYCRY;
+               ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCRYCB;
                break;
        case S5P_FIMC_CRYCBY422:
-               ctx->out_order_1p = S5P_FIMC_OUT_CRYCBY;
+               ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCBYCR;
                break;
        case S5P_FIMC_YCBYCR422:
        default:
-               ctx->out_order_1p = S5P_FIMC_OUT_YCBYCR;
+               ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CRYCBY;
                break;
        }
        dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
@@ -459,10 +542,14 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx)
 static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 {
        struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+       u32 i, depth = 0;
+
+       for (i = 0; i < f->fmt->colplanes; i++)
+               depth += f->fmt->depth[i];
 
        f->dma_offset.y_h = f->offs_h;
        if (!variant->pix_hoff)
-               f->dma_offset.y_h *= (f->fmt->depth >> 3);
+               f->dma_offset.y_h *= (depth >> 3);
 
        f->dma_offset.y_v = f->offs_v;
 
@@ -473,7 +560,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
        f->dma_offset.cr_v = f->offs_v;
 
        if (!variant->pix_hoff) {
-               if (f->fmt->planes_cnt == 3) {
+               if (f->fmt->colplanes == 3) {
                        f->dma_offset.cb_h >>= 1;
                        f->dma_offset.cr_h >>= 1;
                }
@@ -499,7 +586,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
 {
        struct fimc_frame *s_frame, *d_frame;
-       struct fimc_vid_buffer *buf = NULL;
+       struct vb2_buffer *vb = NULL;
        int ret = 0;
 
        s_frame = &ctx->s_frame;
@@ -522,15 +609,15 @@ int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
        ctx->scaler.enabled = 1;
 
        if (flags & FIMC_SRC_ADDR) {
-               buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-               ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr);
+               vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+               ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr);
                if (ret)
                        return ret;
        }
 
        if (flags & FIMC_DST_ADDR) {
-               buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-               ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr);
+               vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+               ret = fimc_prepare_addr(ctx, vb, d_frame, &d_frame->paddr);
        }
 
        return ret;
@@ -553,26 +640,28 @@ static void fimc_dma_run(void *priv)
 
        ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
        ret = fimc_prepare_config(ctx, ctx->state);
-       if (ret) {
-               err("Wrong parameters");
+       if (ret)
                goto dma_unlock;
-       }
+
        /* Reconfigure hardware if the context has changed. */
        if (fimc->m2m.ctx != ctx) {
                ctx->state |= FIMC_PARAMS;
                fimc->m2m.ctx = ctx;
        }
 
+       spin_lock(&fimc->slock);
        fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
 
        if (ctx->state & FIMC_PARAMS) {
                fimc_hw_set_input_path(ctx);
                fimc_hw_set_in_dma(ctx);
-               if (fimc_set_scaler_info(ctx)) {
-                       err("Scaler setup error");
+               ret = fimc_set_scaler_info(ctx);
+               if (ret) {
+                       spin_unlock(&fimc->slock);
                        goto dma_unlock;
                }
-               fimc_hw_set_scaler(ctx);
+               fimc_hw_set_prescaler(ctx);
+               fimc_hw_set_mainscaler(ctx);
                fimc_hw_set_target_format(ctx);
                fimc_hw_set_rotation(ctx);
                fimc_hw_set_effect(ctx);
@@ -587,8 +676,10 @@ static void fimc_dma_run(void *priv)
 
        fimc_activate_capture(ctx);
 
-       ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
+       ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
+                      FIMC_SRC_FMT | FIMC_DST_FMT);
        fimc_hw_activate_input_dma(fimc, true);
+       spin_unlock(&fimc->slock);
 
 dma_unlock:
        spin_unlock_irqrestore(&ctx->slock, flags);
@@ -596,109 +687,84 @@ dma_unlock:
 
 static void fimc_job_abort(void *priv)
 {
-       /* Nothing done in job_abort. */
+       fimc_m2m_shutdown(priv);
 }
 
-static void fimc_buf_release(struct videobuf_queue *vq,
-                                   struct videobuf_buffer *vb)
+static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
+                           unsigned int *num_planes, unsigned long sizes[],
+                           void *allocators[])
 {
-       videobuf_dma_contig_free(vq, vb);
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+       struct fimc_frame *f;
+       int i;
 
-static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
-                               unsigned int *size)
-{
-       struct fimc_ctx *ctx = vq->priv_data;
-       struct fimc_frame *frame;
+       f = ctx_get_frame(ctx, vq->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
 
-       frame = ctx_get_frame(ctx, vq->type);
-       if (IS_ERR(frame))
-               return PTR_ERR(frame);
+       /*
+        * Return number of non-contigous planes (plane buffers)
+        * depending on the configured color format.
+        */
+       if (f->fmt)
+               *num_planes = f->fmt->memplanes;
+
+       for (i = 0; i < f->fmt->memplanes; i++) {
+               sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3;
+               allocators[i] = ctx->fimc_dev->alloc_ctx;
+       }
+
+       if (*num_buffers == 0)
+               *num_buffers = 1;
 
-       *size = (frame->width * frame->height * frame->fmt->depth) >> 3;
-       if (0 == *count)
-               *count = 1;
        return 0;
 }
 
-static int fimc_buf_prepare(struct videobuf_queue *vq,
-               struct videobuf_buffer *vb, enum v4l2_field field)
+static int fimc_buf_prepare(struct vb2_buffer *vb)
 {
-       struct fimc_ctx *ctx = vq->priv_data;
-       struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
        struct fimc_frame *frame;
-       int ret;
+       int i;
 
-       frame = ctx_get_frame(ctx, vq->type);
+       frame = ctx_get_frame(ctx, vb->vb2_queue->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       if (vb->baddr) {
-               if (vb->bsize < frame->size) {
-                       v4l2_err(v4l2_dev,
-                               "User-provided buffer too small (%d < %d)\n",
-                                vb->bsize, frame->size);
-                       WARN_ON(1);
-                       return -EINVAL;
-               }
-       } else if (vb->state != VIDEOBUF_NEEDS_INIT
-                  && vb->bsize < frame->size) {
-               return -EINVAL;
-       }
-
-       vb->width       = frame->width;
-       vb->height      = frame->height;
-       vb->bytesperline = (frame->width * frame->fmt->depth) >> 3;
-       vb->size        = frame->size;
-       vb->field       = field;
-
-       if (VIDEOBUF_NEEDS_INIT == vb->state) {
-               ret = videobuf_iolock(vq, vb, NULL);
-               if (ret) {
-                       v4l2_err(v4l2_dev, "Iolock failed\n");
-                       fimc_buf_release(vq, vb);
-                       return ret;
-               }
-       }
-       vb->state = VIDEOBUF_PREPARED;
+       for (i = 0; i < frame->fmt->memplanes; i++)
+               vb2_set_plane_payload(vb, i, frame->payload[i]);
 
        return 0;
 }
 
-static void fimc_buf_queue(struct videobuf_queue *vq,
-                                 struct videobuf_buffer *vb)
+static void fimc_buf_queue(struct vb2_buffer *vb)
 {
-       struct fimc_ctx *ctx = vq->priv_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
-       unsigned long flags;
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 
        dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
 
-       if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
-       } else if (ctx->state & FIMC_CTX_CAP) {
-               spin_lock_irqsave(&fimc->slock, flags);
-               fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
+       if (ctx->m2m_ctx)
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
 
-               dbg("fimc->cap.active_buf_cnt: %d",
-                   fimc->vid_cap.active_buf_cnt);
+static void fimc_lock(struct vb2_queue *vq)
+{
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_lock(&ctx->fimc_dev->lock);
+}
 
-               if (cap->active_buf_cnt >= cap->reqbufs_count ||
-                  cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
-                       if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
-                               fimc_activate_capture(ctx);
-               }
-               spin_unlock_irqrestore(&fimc->slock, flags);
-       }
+static void fimc_unlock(struct vb2_queue *vq)
+{
+       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_unlock(&ctx->fimc_dev->lock);
 }
 
-struct videobuf_queue_ops fimc_qops = {
-       .buf_setup      = fimc_buf_setup,
-       .buf_prepare    = fimc_buf_prepare,
-       .buf_queue      = fimc_buf_queue,
-       .buf_release    = fimc_buf_release,
+struct vb2_ops fimc_qops = {
+       .queue_setup     = fimc_queue_setup,
+       .buf_prepare     = fimc_buf_prepare,
+       .buf_queue       = fimc_buf_queue,
+       .wait_prepare    = fimc_unlock,
+       .wait_finish     = fimc_lock,
+       .stop_streaming  = stop_streaming,
 };
 
 static int fimc_m2m_querycap(struct file *file, void *priv,
@@ -712,12 +778,13 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
        cap->bus_info[0] = 0;
        cap->version = KERNEL_VERSION(1, 0, 0);
        cap->capabilities = V4L2_CAP_STREAMING |
-               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
+               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+               V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
 
        return 0;
 }
 
-int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
                                struct v4l2_fmtdesc *f)
 {
        struct fimc_fmt *fmt;
@@ -732,25 +799,39 @@ int fimc_vidioc_enum_fmt(struct file *file, void *priv,
        return 0;
 }
 
-int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv,
+                            struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *frame;
+       struct v4l2_pix_format_mplane *pixm;
+       int i;
 
        frame = ctx_get_frame(ctx, f->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
+       pixm = &f->fmt.pix_mp;
+
+       pixm->width             = frame->width;
+       pixm->height            = frame->height;
+       pixm->field             = V4L2_FIELD_NONE;
+       pixm->pixelformat       = frame->fmt->fourcc;
+       pixm->colorspace        = V4L2_COLORSPACE_JPEG;
+       pixm->num_planes        = frame->fmt->memplanes;
+
+       for (i = 0; i < pixm->num_planes; ++i) {
+               int bpl = frame->o_width;
 
-       f->fmt.pix.width        = frame->width;
-       f->fmt.pix.height       = frame->height;
-       f->fmt.pix.field        = V4L2_FIELD_NONE;
-       f->fmt.pix.pixelformat  = frame->fmt->fourcc;
+               if (frame->fmt->colplanes == 1) /* packed formats */
+                       bpl = (bpl * frame->fmt->depth[0]) / 8;
+
+               pixm->plane_fmt[i].bytesperline = bpl;
+
+               pixm->plane_fmt[i].sizeimage = (frame->o_width *
+                       frame->o_height * frame->fmt->depth[i]) / 8;
+       }
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -785,42 +866,40 @@ struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
 }
 
 
-int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
+                              struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct samsung_fimc_variant *variant = fimc->variant;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
        struct fimc_fmt *fmt;
        u32 max_width, mod_x, mod_y, mask;
-       int ret = -EINVAL, is_output = 0;
+       int i, is_output = 0;
+
 
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-               if (ctx->state & FIMC_CTX_CAP)
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx))
                        return -EINVAL;
                is_output = 1;
-       } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                return -EINVAL;
        }
 
-       dbg("w: %d, h: %d, bpl: %d",
-           pix->width, pix->height, pix->bytesperline);
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
+       dbg("w: %d, h: %d", pix->width, pix->height);
 
        mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
        fmt = find_format(f, mask);
        if (!fmt) {
                v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
                         pix->pixelformat);
-               goto tf_out;
+               return -EINVAL;
        }
 
        if (pix->field == V4L2_FIELD_ANY)
                pix->field = V4L2_FIELD_NONE;
        else if (V4L2_FIELD_NONE != pix->field)
-               goto tf_out;
+               return -EINVAL;
 
        if (is_output) {
                max_width = variant->pix_limit->scaler_dis_w;
@@ -834,7 +913,7 @@ int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
                mod_x = 6; /* 64 x 32 pixels tile */
                mod_y = 5;
        } else {
-               if (fimc->id == 1 && fimc->variant->pix_hoff)
+               if (fimc->id == 1 && variant->pix_hoff)
                        mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
                else
                        mod_y = mod_x;
@@ -845,74 +924,72 @@ int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
        v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
                &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
 
-       if (pix->bytesperline == 0 ||
-           (pix->bytesperline * 8 / fmt->depth) > pix->width)
-               pix->bytesperline = (pix->width * fmt->depth) >> 3;
+       pix->num_planes = fmt->memplanes;
+       pix->colorspace = V4L2_COLORSPACE_JPEG;
 
-       if (pix->sizeimage == 0)
-               pix->sizeimage = pix->height * pix->bytesperline;
+       for (i = 0; i < pix->num_planes; ++i) {
+               int bpl = pix->plane_fmt[i].bytesperline;
 
-       dbg("w: %d, h: %d, bpl: %d, depth: %d",
-           pix->width, pix->height, pix->bytesperline, fmt->depth);
+               dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
+                   i, bpl, fmt->depth[i], pix->width, pix->height);
 
-       ret = 0;
+               if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
+                       bpl = (pix->width * fmt->depth[0]) >> 3;
 
-tf_out:
-       mutex_unlock(&fimc->lock);
-       return ret;
+               if (!pix->plane_fmt[i].sizeimage)
+                       pix->plane_fmt[i].sizeimage = pix->height * bpl;
+
+               pix->plane_fmt[i].bytesperline = bpl;
+
+               dbg("[%d]: bpl: %d, sizeimage: %d",
+                   i, pix->plane_fmt[i].bytesperline,
+                   pix->plane_fmt[i].sizeimage);
+       }
+
+       return 0;
 }
 
-static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv,
+                                struct v4l2_format *f)
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev;
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
        struct fimc_frame *frame;
-       struct v4l2_pix_format *pix;
-       unsigned long flags;
-       int ret = 0;
+       struct v4l2_pix_format_mplane *pix;
+       int i, ret = 0;
 
-       ret = fimc_vidioc_try_fmt(file, priv, f);
+       ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
        if (ret)
                return ret;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-       mutex_lock(&vq->vb_lock);
 
-       if (videobuf_queue_is_busy(vq)) {
-               v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type);
-               ret = -EBUSY;
-               goto sf_out;
+       if (vb2_is_streaming(vq)) {
+               v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type);
+               return -EBUSY;
        }
 
-       spin_lock_irqsave(&ctx->slock, flags);
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                frame = &ctx->s_frame;
-               ctx->state |= FIMC_SRC_FMT;
-       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                frame = &ctx->d_frame;
-               ctx->state |= FIMC_DST_FMT;
        } else {
-               spin_unlock_irqrestore(&ctx->slock, flags);
-               v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+               v4l2_err(&fimc->m2m.v4l2_dev,
                         "Wrong buffer/video queue type (%d)\n", f->type);
-               ret = -EINVAL;
-               goto sf_out;
+               return -EINVAL;
        }
-       spin_unlock_irqrestore(&ctx->slock, flags);
 
-       pix = &f->fmt.pix;
+       pix = &f->fmt.pix_mp;
        frame->fmt = find_format(f, FMT_FLAGS_M2M);
-       if (!frame->fmt) {
-               ret = -EINVAL;
-               goto sf_out;
-       }
+       if (!frame->fmt)
+               return -EINVAL;
 
-       frame->f_width  = pix->bytesperline * 8 / frame->fmt->depth;
+       for (i = 0; i < frame->fmt->colplanes; i++)
+               frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height;
+
+       frame->f_width  = pix->plane_fmt[0].bytesperline * 8 /
+               frame->fmt->depth[0];
        frame->f_height = pix->height;
        frame->width    = pix->width;
        frame->height   = pix->height;
@@ -920,19 +997,15 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
        frame->o_height = pix->height;
        frame->offs_h   = 0;
        frame->offs_v   = 0;
-       frame->size     = (pix->width * pix->height * frame->fmt->depth) >> 3;
-       vq->field       = pix->field;
 
-       spin_lock_irqsave(&ctx->slock, flags);
-       ctx->state |= FIMC_PARAMS;
-       spin_unlock_irqrestore(&ctx->slock, flags);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
+       else
+               fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
 
        dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
 
-sf_out:
-       mutex_unlock(&vq->vb_lock);
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return 0;
 }
 
 static int fimc_m2m_reqbufs(struct file *file, void *priv,
@@ -968,6 +1041,15 @@ static int fimc_m2m_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type type)
 {
        struct fimc_ctx *ctx = priv;
+
+       /* The source and target color format need to be set */
+       if (V4L2_TYPE_IS_OUTPUT(type)) {
+               if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
+                       return -EINVAL;
+       } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
+               return -EINVAL;
+       }
+
        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 }
 
@@ -991,12 +1073,9 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv,
                return 0;
        }
 
-       if (ctx->state & FIMC_CTX_CAP) {
-               if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
-                       return -ERESTARTSYS;
-               ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+       if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
+               return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
                                        core, queryctrl, qc);
-               mutex_unlock(&ctx->fimc_dev->lock);
        }
        return ret;
 }
@@ -1006,10 +1085,6 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct fimc_ctx *ctx = priv;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret = 0;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
@@ -1022,19 +1097,17 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv,
                ctrl->value = ctx->rotation;
                break;
        default:
-               if (ctx->state & FIMC_CTX_CAP) {
-                       ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
-                                      g_ctrl, ctrl);
+               if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
+                       return v4l2_subdev_call(fimc->vid_cap.sd, core,
+                                               g_ctrl, ctrl);
                } else {
-                       v4l2_err(&fimc->m2m.v4l2_dev,
-                                "Invalid control\n");
-                       ret = -EINVAL;
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
+                       return -EINVAL;
                }
        }
        dbg("ctrl->value= %d", ctrl->value);
 
-       mutex_unlock(&fimc->lock);
-       return ret;
+       return 0;
 }
 
 int check_ctrl_val(struct fimc_ctx *ctx,  struct v4l2_control *ctrl)
@@ -1058,16 +1131,7 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
 {
        struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       unsigned long flags;
-
-       if (ctx->rotation != 0 &&
-           (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
-               v4l2_err(&fimc->m2m.v4l2_dev,
-                        "Simultaneous flip and rotation is not supported\n");
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&ctx->slock, flags);
+       int ret = 0;
 
        switch (ctrl->id) {
        case V4L2_CID_HFLIP:
@@ -1085,29 +1149,36 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
                break;
 
        case V4L2_CID_ROTATE:
+               if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+                       ret = fimc_check_scaler_ratio(ctx->s_frame.width,
+                                       ctx->s_frame.height, ctx->d_frame.width,
+                                       ctx->d_frame.height, ctrl->value);
+               }
+
+               if (ret) {
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
+                       return -EINVAL;
+               }
+
                /* Check for the output rotator availability */
                if ((ctrl->value == 90 || ctrl->value == 270) &&
-                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
-                       spin_unlock_irqrestore(&ctx->slock, flags);
+                   (ctx->in_path == FIMC_DMA && !variant->has_out_rot))
                        return -EINVAL;
-               } else {
-                       ctx->rotation = ctrl->value;
-               }
+               ctx->rotation = ctrl->value;
                break;
 
        default:
-               spin_unlock_irqrestore(&ctx->slock, flags);
                v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
                return -EINVAL;
        }
-       ctx->state |= FIMC_PARAMS;
-       spin_unlock_irqrestore(&ctx->slock, flags);
+
+       fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
 
        return 0;
 }
 
 static int fimc_m2m_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
+                          struct v4l2_control *ctrl)
 {
        struct fimc_ctx *ctx = priv;
        int ret = 0;
@@ -1125,22 +1196,17 @@ static int fimc_m2m_cropcap(struct file *file, void *fh,
 {
        struct fimc_frame *frame;
        struct fimc_ctx *ctx = fh;
-       struct fimc_dev *fimc = ctx->fimc_dev;
 
        frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        cr->bounds.left         = 0;
        cr->bounds.top          = 0;
        cr->bounds.width        = frame->f_width;
        cr->bounds.height       = frame->f_height;
        cr->defrect             = cr->bounds;
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -1148,21 +1214,16 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
        struct fimc_frame *frame;
        struct fimc_ctx *ctx = file->private_data;
-       struct fimc_dev *fimc = ctx->fimc_dev;
 
        frame = ctx_get_frame(ctx, cr->type);
        if (IS_ERR(frame))
                return PTR_ERR(frame);
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
        cr->c.left = frame->offs_h;
        cr->c.top = frame->offs_v;
        cr->c.width = frame->width;
        cr->c.height = frame->height;
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -1170,7 +1231,9 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
 {
        struct fimc_dev *fimc = ctx->fimc_dev;
        struct fimc_frame *f;
-       u32 min_size, halign;
+       u32 min_size, halign, depth = 0;
+       bool is_capture_ctx;
+       int i;
 
        if (cr->c.top < 0 || cr->c.left < 0) {
                v4l2_err(&fimc->m2m.v4l2_dev,
@@ -1178,10 +1241,12 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
                return -EINVAL;
        }
 
-       if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame;
-       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-                ctx->state & FIMC_CTX_M2M)
+       is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx);
+
+       if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame;
+       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+                !is_capture_ctx)
                f = &ctx->s_frame;
        else
                return -EINVAL;
@@ -1189,21 +1254,24 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
        min_size = (f == &ctx->s_frame) ?
                fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
 
-       if (ctx->state & FIMC_CTX_M2M) {
+       /* Get pixel alignment constraints. */
+       if (is_capture_ctx) {
+               min_size = 16;
+               halign = 4;
+       } else {
                if (fimc->id == 1 && fimc->variant->pix_hoff)
                        halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
                else
                        halign = ffs(min_size) - 1;
-       /* there are more strict aligment requirements at camera interface */
-       } else {
-               min_size = 16;
-               halign = 4;
        }
 
+       for (i = 0; i < f->fmt->colplanes; i++)
+               depth += f->fmt->depth[i];
+
        v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
                              ffs(min_size) - 1,
                              &cr->c.height, min_size, f->o_height,
-                             halign, 64/(ALIGN(f->fmt->depth, 8)));
+                             halign, 64/(ALIGN(depth, 8)));
 
        /* adjust left/top if cropping rectangle is out of bounds */
        if (cr->c.left + cr->c.width > f->o_width)
@@ -1212,8 +1280,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
                cr->c.top = f->o_height - cr->c.height;
 
        cr->c.left = round_down(cr->c.left, min_size);
-       cr->c.top  = round_down(cr->c.top,
-                               ctx->state & FIMC_CTX_M2M ? 8 : 16);
+       cr->c.top  = round_down(cr->c.top, is_capture_ctx ? 16 : 8);
 
        dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
            cr->c.left, cr->c.top, cr->c.width, cr->c.height,
@@ -1222,12 +1289,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
        return 0;
 }
 
-
 static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 {
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
-       unsigned long flags;
        struct fimc_frame *f;
        int ret;
 
@@ -1235,52 +1300,52 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
        if (ret)
                return ret;
 
-       f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+       f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
                &ctx->s_frame : &ctx->d_frame;
 
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       spin_lock_irqsave(&ctx->slock, flags);
-       if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
-               /* Check to see if scaling ratio is within supported range */
-               if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
-                       ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
-               else
-                       ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
+       /* Check to see if scaling ratio is within supported range */
+       if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+               if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+                       ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
+                                                     ctx->d_frame.width,
+                                                     ctx->d_frame.height,
+                                                     ctx->rotation);
+               } else {
+                       ret = fimc_check_scaler_ratio(ctx->s_frame.width,
+                                                     ctx->s_frame.height,
+                                                     cr->c.width, cr->c.height,
+                                                     ctx->rotation);
+               }
                if (ret) {
-                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
-                       ret = -EINVAL;
-                       goto scr_unlock;
+                       v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n");
+                       return -EINVAL;
                }
        }
-       ctx->state |= FIMC_PARAMS;
 
        f->offs_h = cr->c.left;
        f->offs_v = cr->c.top;
        f->width  = cr->c.width;
        f->height = cr->c.height;
 
-scr_unlock:
-       spin_unlock_irqrestore(&ctx->slock, flags);
-       mutex_unlock(&fimc->lock);
+       fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
+
        return 0;
 }
 
 static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_querycap                = fimc_m2m_querycap,
 
-       .vidioc_enum_fmt_vid_cap        = fimc_vidioc_enum_fmt,
-       .vidioc_enum_fmt_vid_out        = fimc_vidioc_enum_fmt,
+       .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane,
+       .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane,
 
-       .vidioc_g_fmt_vid_cap           = fimc_vidioc_g_fmt,
-       .vidioc_g_fmt_vid_out           = fimc_vidioc_g_fmt,
+       .vidioc_g_fmt_vid_cap_mplane    = fimc_vidioc_g_fmt_mplane,
+       .vidioc_g_fmt_vid_out_mplane    = fimc_vidioc_g_fmt_mplane,
 
-       .vidioc_try_fmt_vid_cap         = fimc_vidioc_try_fmt,
-       .vidioc_try_fmt_vid_out         = fimc_vidioc_try_fmt,
+       .vidioc_try_fmt_vid_cap_mplane  = fimc_vidioc_try_fmt_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = fimc_vidioc_try_fmt_mplane,
 
-       .vidioc_s_fmt_vid_cap           = fimc_m2m_s_fmt,
-       .vidioc_s_fmt_vid_out           = fimc_m2m_s_fmt,
+       .vidioc_s_fmt_vid_cap_mplane    = fimc_m2m_s_fmt_mplane,
+       .vidioc_s_fmt_vid_out_mplane    = fimc_m2m_s_fmt_mplane,
 
        .vidioc_reqbufs                 = fimc_m2m_reqbufs,
        .vidioc_querybuf                = fimc_m2m_querybuf,
@@ -1301,26 +1366,39 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
 
 };
 
-static void queue_init(void *priv, struct videobuf_queue *vq,
-                      enum v4l2_buf_type type)
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
 {
        struct fimc_ctx *ctx = priv;
-       struct fimc_dev *fimc = ctx->fimc_dev;
+       int ret;
+
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       src_vq->drv_priv = ctx;
+       src_vq->ops = &fimc_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
 
-       videobuf_queue_dma_contig_init(vq, &fimc_qops,
-               &fimc->pdev->dev,
-               &fimc->irqlock, type, V4L2_FIELD_NONE,
-               sizeof(struct fimc_vid_buffer), priv, NULL);
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       dst_vq->drv_priv = ctx;
+       dst_vq->ops = &fimc_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+       return vb2_queue_init(dst_vq);
 }
 
 static int fimc_m2m_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
        struct fimc_ctx *ctx = NULL;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
 
        dbg("pid: %d, state: 0x%lx, refcnt: %d",
                task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
@@ -1329,19 +1407,15 @@ static int fimc_m2m_open(struct file *file)
         * Return if the corresponding video capture node
         * is already opened.
         */
-       if (fimc->vid_cap.refcnt > 0) {
-               err = -EBUSY;
-               goto err_unlock;
-       }
+       if (fimc->vid_cap.refcnt > 0)
+               return -EBUSY;
 
        fimc->m2m.refcnt++;
        set_bit(ST_OUTDMA_RUN, &fimc->state);
 
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-       if (!ctx) {
-               err = -ENOMEM;
-               goto err_unlock;
-       }
+       if (!ctx)
+               return -ENOMEM;
 
        file->private_data = ctx;
        ctx->fimc_dev = fimc;
@@ -1355,15 +1429,14 @@ static int fimc_m2m_open(struct file *file)
        ctx->out_path = FIMC_DMA;
        spin_lock_init(&ctx->slock);
 
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, fimc->m2m.m2m_dev, queue_init);
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
        if (IS_ERR(ctx->m2m_ctx)) {
-               err = PTR_ERR(ctx->m2m_ctx);
+               int err = PTR_ERR(ctx->m2m_ctx);
                kfree(ctx);
+               return err;
        }
 
-err_unlock:
-       mutex_unlock(&fimc->lock);
-       return err;
+       return 0;
 }
 
 static int fimc_m2m_release(struct file *file)
@@ -1371,8 +1444,6 @@ static int fimc_m2m_release(struct file *file)
        struct fimc_ctx *ctx = file->private_data;
        struct fimc_dev *fimc = ctx->fimc_dev;
 
-       mutex_lock(&fimc->lock);
-
        dbg("pid: %d, state: 0x%lx, refcnt= %d",
                task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
 
@@ -1381,7 +1452,6 @@ static int fimc_m2m_release(struct file *file)
        if (--fimc->m2m.refcnt <= 0)
                clear_bit(ST_OUTDMA_RUN, &fimc->state);
 
-       mutex_unlock(&fimc->lock);
        return 0;
 }
 
@@ -1415,7 +1485,6 @@ static struct v4l2_m2m_ops m2m_ops = {
        .job_abort      = fimc_job_abort,
 };
 
-
 static int fimc_register_m2m_device(struct fimc_dev *fimc)
 {
        struct video_device *vfd;
@@ -1448,6 +1517,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc)
        vfd->ioctl_ops  = &fimc_m2m_ioctl_ops;
        vfd->minor      = -1;
        vfd->release    = video_device_release;
+       vfd->lock       = &fimc->lock;
 
        snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev));
 
@@ -1496,7 +1566,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
 static void fimc_clk_release(struct fimc_dev *fimc)
 {
        int i;
-       for (i = 0; i < NUM_FIMC_CLOCKS; i++) {
+       for (i = 0; i < fimc->num_clocks; i++) {
                if (fimc->clock[i]) {
                        clk_disable(fimc->clock[i]);
                        clk_put(fimc->clock[i]);
@@ -1507,15 +1577,16 @@ static void fimc_clk_release(struct fimc_dev *fimc)
 static int fimc_clk_get(struct fimc_dev *fimc)
 {
        int i;
-       for (i = 0; i < NUM_FIMC_CLOCKS; i++) {
-               fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clock_name[i]);
-               if (IS_ERR(fimc->clock[i])) {
-                       dev_err(&fimc->pdev->dev,
-                               "failed to get fimc clock: %s\n",
-                               fimc_clock_name[i]);
-                       return -ENXIO;
+       for (i = 0; i < fimc->num_clocks; i++) {
+               fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
+
+               if (!IS_ERR_OR_NULL(fimc->clock[i])) {
+                       clk_enable(fimc->clock[i]);
+                       continue;
                }
-               clk_enable(fimc->clock[i]);
+               dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n",
+                       fimc_clocks[i]);
+               return -ENXIO;
        }
        return 0;
 }
@@ -1525,7 +1596,9 @@ static int fimc_probe(struct platform_device *pdev)
        struct fimc_dev *fimc;
        struct resource *res;
        struct samsung_fimc_driverdata *drv_data;
+       struct s5p_platform_fimc *pdata;
        int ret = 0;
+       int cap_input_index = -1;
 
        dev_dbg(&pdev->dev, "%s():\n", __func__);
 
@@ -1545,10 +1618,10 @@ static int fimc_probe(struct platform_device *pdev)
        fimc->id = pdev->id;
        fimc->variant = drv_data->variant[fimc->id];
        fimc->pdev = pdev;
-       fimc->pdata = pdev->dev.platform_data;
+       pdata = pdev->dev.platform_data;
+       fimc->pdata = pdata;
        fimc->state = ST_IDLE;
 
-       spin_lock_init(&fimc->irqlock);
        init_waitqueue_head(&fimc->irq_queue);
        spin_lock_init(&fimc->slock);
 
@@ -1576,10 +1649,18 @@ static int fimc_probe(struct platform_device *pdev)
                goto err_req_region;
        }
 
+       fimc->num_clocks = MAX_FIMC_CLOCKS - 1;
+
+       /* Check if a video capture node needs to be registered. */
+       if (pdata && pdata->num_clients > 0) {
+               cap_input_index = 0;
+               fimc->num_clocks++;
+       }
+
        ret = fimc_clk_get(fimc);
        if (ret)
                goto err_regs_unmap;
-       clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
+       clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -1597,24 +1678,24 @@ static int fimc_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
+       /* Initialize contiguous memory allocator */
+       fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev);
+       if (IS_ERR(fimc->alloc_ctx)) {
+               ret = PTR_ERR(fimc->alloc_ctx);
+               goto err_irq;
+       }
+
        ret = fimc_register_m2m_device(fimc);
        if (ret)
                goto err_irq;
 
        /* At least one camera sensor is required to register capture node */
-       if (fimc->pdata) {
-               int i;
-               for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
-                       if (fimc->pdata->isp_info[i])
-                               break;
-
-               if (i < FIMC_MAX_CAMIF_CLIENTS) {
-                       ret = fimc_register_capture_device(fimc);
-                       if (ret)
-                               goto err_m2m;
-               }
+       if (cap_input_index >= 0) {
+               ret = fimc_register_capture_device(fimc);
+               if (ret)
+                       goto err_m2m;
+               clk_disable(fimc->clock[CLK_CAM]);
        }
-
        /*
         * Exclude the additional output DMA address registers by masking
         * them out on HW revisions that provide extended capabilites.
@@ -1656,6 +1737,9 @@ static int __devexit fimc_remove(struct platform_device *pdev)
        fimc_unregister_capture_device(fimc);
 
        fimc_clk_release(fimc);
+
+       vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+
        iounmap(fimc->regs);
        release_resource(fimc->regs_res);
        kfree(fimc->regs_res);
@@ -1726,6 +1810,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
        .pix_hoff        = 1,
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
+       .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 1,
@@ -1747,6 +1832,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
        .has_inp_rot     = 1,
        .has_out_rot     = 1,
        .has_cistatus2   = 1,
+       .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 1,
@@ -1757,6 +1843,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
 static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
        .pix_hoff        = 1,
        .has_cistatus2   = 1,
+       .has_mainscaler_ext = 1,
        .min_inp_pixsize = 16,
        .min_out_pixsize = 16,
        .hor_offs_align  = 1,
index 4f047d35f8ad9333ce3b4768836685b3d5f2f411..3beb1e5320ce71ef674b5f810d8014ec454c8d68 100644 (file)
 /*#define DEBUG*/
 
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
-#include <media/videobuf-core.h>
+#include <linux/io.h>
+#include <media/videobuf2-core.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-mediabus.h>
-#include <media/s3c_fimc.h>
+#include <media/s5p_fimc.h>
 
 #include "regs-fimc.h"
 
 #define err(fmt, args...) \
        printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
 
-#ifdef DEBUG
 #define dbg(fmt, args...) \
-       printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
-#else
-#define dbg(fmt, args...)
-#endif
+       pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args)
 
 /* Time to wait for next frame VSYNC interrupt while stopping operation. */
 #define FIMC_SHUTDOWN_TIMEOUT  ((100*HZ)/1000)
-#define NUM_FIMC_CLOCKS                2
+#define MAX_FIMC_CLOCKS                3
 #define MODULE_NAME            "s5p-fimc"
 #define FIMC_MAX_DEVS          4
 #define FIMC_MAX_OUT_BUFS      4
 #define SCALER_MAX_VRATIO      64
 #define DMA_MIN_SIZE           8
 
-/* FIMC device state flags */
+/* indices to the clocks array */
+enum {
+       CLK_BUS,
+       CLK_GATE,
+       CLK_CAM,
+};
+
 enum fimc_dev_flags {
        /* for m2m node */
        ST_IDLE,
@@ -63,20 +67,6 @@ enum fimc_dev_flags {
 #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
 #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
 
-#define fimc_capture_active(dev) \
-       (test_bit(ST_CAPT_RUN, &(dev)->state) || \
-        test_bit(ST_CAPT_PEND, &(dev)->state))
-
-#define fimc_capture_streaming(dev) \
-       test_bit(ST_CAPT_STREAM, &(dev)->state)
-
-#define fimc_buf_finish(dev, vid_buf) do { \
-       spin_lock(&(dev)->irqlock); \
-       (vid_buf)->vb.state = VIDEOBUF_DONE; \
-       spin_unlock(&(dev)->irqlock); \
-       wake_up(&(vid_buf)->vb.done); \
-} while (0)
-
 enum fimc_datapath {
        FIMC_CAMERA,
        FIMC_DMA,
@@ -90,7 +80,6 @@ enum fimc_color_fmt {
        S5P_FIMC_RGB888,
        S5P_FIMC_RGB30_LOCAL,
        S5P_FIMC_YCBCR420 = 0x20,
-       S5P_FIMC_YCBCR422,
        S5P_FIMC_YCBYCR422,
        S5P_FIMC_YCRYCB422,
        S5P_FIMC_CBYCRY422,
@@ -100,18 +89,6 @@ enum fimc_color_fmt {
 
 #define fimc_fmt_is_rgb(x) ((x) & 0x10)
 
-/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */
-#define        S5P_FIMC_OUT_CRYCBY     S5P_CIOCTRL_ORDER422_CRYCBY
-#define        S5P_FIMC_OUT_CBYCRY     S5P_CIOCTRL_ORDER422_YCRYCB
-#define        S5P_FIMC_OUT_YCRYCB     S5P_CIOCTRL_ORDER422_CBYCRY
-#define        S5P_FIMC_OUT_YCBYCR     S5P_CIOCTRL_ORDER422_YCBYCR
-
-/* Input Y/Cb/Cr components order for 1 plane YCbCr 4:2:2 color formats. */
-#define        S5P_FIMC_IN_CRYCBY      S5P_MSCTRL_ORDER422_CRYCBY
-#define        S5P_FIMC_IN_CBYCRY      S5P_MSCTRL_ORDER422_YCRYCB
-#define        S5P_FIMC_IN_YCRYCB      S5P_MSCTRL_ORDER422_CBYCRY
-#define        S5P_FIMC_IN_YCBYCR      S5P_MSCTRL_ORDER422_YCBYCR
-
 /* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */
 #define        S5P_FIMC_LSB_CRCB       S5P_CIOCTRL_ORDER422_2P_LSB_CRCB
 
@@ -131,6 +108,7 @@ enum fimc_color_fmt {
 #define        FIMC_DST_FMT            (1 << 4)
 #define        FIMC_CTX_M2M            (1 << 5)
 #define        FIMC_CTX_CAP            (1 << 6)
+#define        FIMC_CTX_SHUT           (1 << 7)
 
 /* Image conversion flags */
 #define        FIMC_IN_DMA_ACCESS_TILED        (1 << 0)
@@ -157,18 +135,18 @@ enum fimc_color_fmt {
  * @name: format description
  * @fourcc: the fourcc code for this format, 0 if not applicable
  * @color: the corresponding fimc_color_fmt
- * @depth: driver's private 'number of bits per pixel'
- * @buff_cnt: number of physically non-contiguous data planes
- * @planes_cnt: number of physically contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @memplanes: number of physically non-contiguous data planes
+ * @colplanes: number of physically contiguous data planes
  */
 struct fimc_fmt {
        enum v4l2_mbus_pixelcode mbus_code;
        char    *name;
        u32     fourcc;
        u32     color;
-       u16     buff_cnt;
-       u16     planes_cnt;
-       u16     depth;
+       u16     memplanes;
+       u16     colplanes;
+       u8      depth[VIDEO_MAX_PLANES];
        u16     flags;
 #define FMT_FLAGS_CAM  (1 << 0)
 #define FMT_FLAGS_M2M  (1 << 1)
@@ -260,7 +238,8 @@ struct fimc_addr {
  * @index: buffer index for the output DMA engine
  */
 struct fimc_vid_buffer {
-       struct videobuf_buffer  vb;
+       struct vb2_buffer       vb;
+       struct list_head        list;
        struct fimc_addr        paddr;
        int                     index;
 };
@@ -277,7 +256,7 @@ struct fimc_vid_buffer {
  * @height:    image pixel weight
  * @paddr:     image frame buffer physical addresses
  * @buf_cnt:   number of buffers depending on a color format
- * @size:      image size in bytes
+ * @payload:   image size in bytes (w x h x bpp)
  * @color:     color format
  * @dma_offset:        DMA offset in bytes
  */
@@ -290,7 +269,7 @@ struct fimc_frame {
        u32     offs_v;
        u32     width;
        u32     height;
-       u32     size;
+       unsigned long           payload[VIDEO_MAX_PLANES];
        struct fimc_addr        paddr;
        struct fimc_dma_offset  dma_offset;
        struct fimc_fmt         *fmt;
@@ -331,13 +310,14 @@ struct fimc_m2m_device {
  */
 struct fimc_vid_cap {
        struct fimc_ctx                 *ctx;
+       struct vb2_alloc_ctx            *alloc_ctx;
        struct video_device             *vfd;
        struct v4l2_device              v4l2_dev;
-       struct v4l2_subdev              *sd;
+       struct v4l2_subdev              *sd;;
        struct v4l2_mbus_framefmt       fmt;
        struct list_head                pending_buf_q;
        struct list_head                active_buf_q;
-       struct videobuf_queue           vbq;
+       struct vb2_queue                vbq;
        int                             active_buf_cnt;
        int                             buf_index;
        unsigned int                    frame_count;
@@ -372,6 +352,8 @@ struct fimc_pix_limit {
  * @has_inp_rot: set if has input rotator
  * @has_out_rot: set if has output rotator
  * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
+ * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register
+ *                      are present in this IP revision
  * @pix_limit: pixel size constraints for the scaler
  * @min_inp_pixsize: minimum input pixel size
  * @min_out_pixsize: minimum output pixel size
@@ -383,6 +365,7 @@ struct samsung_fimc_variant {
        unsigned int    has_inp_rot:1;
        unsigned int    has_out_rot:1;
        unsigned int    has_cistatus2:1;
+       unsigned int    has_mainscaler_ext:1;
        struct fimc_pix_limit *pix_limit;
        u16             min_inp_pixsize;
        u16             min_out_pixsize;
@@ -412,12 +395,12 @@ struct fimc_ctx;
  * @lock:      the mutex protecting this data structure
  * @pdev:      pointer to the FIMC platform device
  * @pdata:     pointer to the device platform data
- * @id:                FIMC device index (0..2)
+ * @id:                FIMC device index (0..FIMC_MAX_DEVS)
+ * @num_clocks: the number of clocks managed by this device instance
  * @clock[]:   the clocks required for FIMC operation
  * @regs:      the mapped hardware registers
  * @regs_res:  the resource claimed for IO registers
  * @irq:       interrupt number of the FIMC subdevice
- * @irqlock:   spinlock protecting videobuffer queue
  * @irq_queue:
  * @m2m:       memory-to-memory V4L2 device information
  * @vid_cap:   camera capture device information
@@ -427,18 +410,19 @@ struct fimc_dev {
        spinlock_t                      slock;
        struct mutex                    lock;
        struct platform_device          *pdev;
-       struct s3c_platform_fimc        *pdata;
+       struct s5p_platform_fimc        *pdata;
        struct samsung_fimc_variant     *variant;
-       int                             id;
-       struct clk                      *clock[NUM_FIMC_CLOCKS];
+       u16                             id;
+       u16                             num_clocks;
+       struct clk                      *clock[MAX_FIMC_CLOCKS];
        void __iomem                    *regs;
        struct resource                 *regs_res;
        int                             irq;
-       spinlock_t                      irqlock;
        wait_queue_head_t               irq_queue;
        struct fimc_m2m_device          m2m;
        struct fimc_vid_cap             vid_cap;
        unsigned long                   state;
+       struct vb2_alloc_ctx            *alloc_ctx;
 };
 
 /**
@@ -482,11 +466,41 @@ struct fimc_ctx {
        struct v4l2_m2m_ctx     *m2m_ctx;
 };
 
-extern struct videobuf_queue_ops fimc_qops;
+static inline bool fimc_capture_active(struct fimc_dev *fimc)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&fimc->slock, flags);
+       ret = !!(fimc->state & (1 << ST_CAPT_RUN) ||
+                fimc->state & (1 << ST_CAPT_PEND));
+       spin_unlock_irqrestore(&fimc->slock, flags);
+       return ret;
+}
+
+static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->slock, flags);
+       ctx->state |= state;
+       spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ctx->slock, flags);
+       ret = (ctx->state & mask) == mask;
+       spin_unlock_irqrestore(&ctx->slock, flags);
+       return ret;
+}
 
 static inline int tiled_fmt(struct fimc_fmt *fmt)
 {
-       return 0;
+       return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
 }
 
 static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
@@ -542,12 +556,12 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
 {
        struct fimc_frame *frame;
 
-       if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
-               if (ctx->state & FIMC_CTX_M2M)
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
+               if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx))
                        frame = &ctx->s_frame;
                else
                        return ERR_PTR(-EINVAL);
-       } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
+       } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
                frame = &ctx->d_frame;
        } else {
                v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
@@ -581,7 +595,8 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx);
 void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
 void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
 void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
-void fimc_hw_set_scaler(struct fimc_ctx *ctx);
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
 void fimc_hw_en_capture(struct fimc_ctx *ctx);
 void fimc_hw_set_effect(struct fimc_ctx *ctx);
 void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
@@ -589,23 +604,23 @@ void fimc_hw_set_input_path(struct fimc_ctx *ctx);
 void fimc_hw_set_output_path(struct fimc_ctx *ctx);
 void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
 void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
-                             int index);
+                            int index);
 int fimc_hw_set_camera_source(struct fimc_dev *fimc,
-                             struct s3c_fimc_isp_info *cam);
+                             struct s5p_fimc_isp_info *cam);
 int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
 int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
-                               struct s3c_fimc_isp_info *cam);
+                               struct s5p_fimc_isp_info *cam);
 int fimc_hw_set_camera_type(struct fimc_dev *fimc,
-                           struct s3c_fimc_isp_info *cam);
+                           struct s5p_fimc_isp_info *cam);
 
 /* -----------------------------------------------------*/
 /* fimc-core.c */
-int fimc_vidioc_enum_fmt(struct file *file, void *priv,
-                     struct v4l2_fmtdesc *f);
-int fimc_vidioc_g_fmt(struct file *file, void *priv,
-                     struct v4l2_format *f);
-int fimc_vidioc_try_fmt(struct file *file, void *priv,
-                       struct v4l2_format *f);
+int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
+                               struct v4l2_fmtdesc *f);
+int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv,
+                            struct v4l2_format *f);
+int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv,
+                              struct v4l2_format *f);
 int fimc_vidioc_queryctrl(struct file *file, void *priv,
                          struct v4l2_queryctrl *qc);
 int fimc_vidioc_g_ctrl(struct file *file, void *priv,
@@ -619,10 +634,10 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
 struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
                                  unsigned int mask);
 
-int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
+int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot);
 int fimc_set_scaler_info(struct fimc_ctx *ctx);
 int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
-int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
                      struct fimc_frame *frame, struct fimc_addr *paddr);
 
 /* -----------------------------------------------------*/
@@ -649,28 +664,27 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
 }
 
 /*
- * Add video buffer to the active buffers queue.
- * The caller holds irqlock spinlock.
+ * Add buf to the capture active buffers queue.
+ * Locking: Need to be called with fimc_dev::slock held.
  */
 static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
-                                        struct fimc_vid_buffer *buf)
+                                   struct fimc_vid_buffer *buf)
 {
-       buf->vb.state = VIDEOBUF_ACTIVE;
-       list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
+       list_add_tail(&buf->list, &vid_cap->active_buf_q);
        vid_cap->active_buf_cnt++;
 }
 
 /*
  * Pop a video buffer from the capture active buffers queue
- * Locking: Need to be called with dev->slock held.
+ * Locking: Need to be called with fimc_dev::slock held.
  */
 static inline struct fimc_vid_buffer *
 active_queue_pop(struct fimc_vid_cap *vid_cap)
 {
        struct fimc_vid_buffer *buf;
        buf = list_entry(vid_cap->active_buf_q.next,
-                        struct fimc_vid_buffer, vb.queue);
-       list_del(&buf->vb.queue);
+                        struct fimc_vid_buffer, list);
+       list_del(&buf->list);
        vid_cap->active_buf_cnt--;
        return buf;
 }
@@ -679,8 +693,7 @@ active_queue_pop(struct fimc_vid_cap *vid_cap)
 static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
                                          struct fimc_vid_buffer *buf)
 {
-       buf->vb.state = VIDEOBUF_QUEUED;
-       list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
+       list_add_tail(&buf->list, &vid_cap->pending_buf_q);
 }
 
 /* Add video buffer to the capture pending buffers queue */
@@ -689,10 +702,9 @@ pending_queue_pop(struct fimc_vid_cap *vid_cap)
 {
        struct fimc_vid_buffer *buf;
        buf = list_entry(vid_cap->pending_buf_q.next,
-                       struct fimc_vid_buffer, vb.queue);
-       list_del(&buf->vb.queue);
+                       struct fimc_vid_buffer, list);
+       list_del(&buf->list);
        return buf;
 }
 
-
 #endif /* FIMC_CORE_H_ */
index 511631a2e5c3332d22163fc291f1c9e6867a167d..4d929a3945217bf432f94704c0adc3c9d43fbde8 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <mach/map.h>
-#include <media/s3c_fimc.h>
+#include <media/s5p_fimc.h>
 
 #include "fimc-core.h"
 
@@ -37,11 +37,11 @@ void fimc_hw_reset(struct fimc_dev *dev)
        writel(cfg, dev->regs + S5P_CIGCTRL);
 }
 
-static u32 fimc_hw_get_in_flip(u32 ctx_flip)
+static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
 {
        u32 flip = S5P_MSCTRL_FLIP_NORMAL;
 
-       switch (ctx_flip) {
+       switch (ctx->flip) {
        case FLIP_X_AXIS:
                flip = S5P_MSCTRL_FLIP_X_MIRROR;
                break;
@@ -51,16 +51,20 @@ static u32 fimc_hw_get_in_flip(u32 ctx_flip)
        case FLIP_XY_AXIS:
                flip = S5P_MSCTRL_FLIP_180;
                break;
+       default:
+               break;
        }
+       if (ctx->rotation <= 90)
+               return flip;
 
-       return flip;
+       return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180;
 }
 
-static u32 fimc_hw_get_target_flip(u32 ctx_flip)
+static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
 {
        u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
 
-       switch (ctx_flip) {
+       switch (ctx->flip) {
        case FLIP_X_AXIS:
                flip = S5P_CITRGFMT_FLIP_X_MIRROR;
                break;
@@ -70,11 +74,13 @@ static u32 fimc_hw_get_target_flip(u32 ctx_flip)
        case FLIP_XY_AXIS:
                flip = S5P_CITRGFMT_FLIP_180;
                break;
-       case FLIP_NONE:
+       default:
                break;
-
        }
-       return flip;
+       if (ctx->rotation <= 90)
+               return flip;
+
+       return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180;
 }
 
 void fimc_hw_set_rotation(struct fimc_ctx *ctx)
@@ -84,10 +90,7 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx)
 
        cfg = readl(dev->regs + S5P_CITRGFMT);
        cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
-                 S5P_CITRGFMT_FLIP_180);
-
-       flip = readl(dev->regs + S5P_MSCTRL);
-       flip &= ~S5P_MSCTRL_FLIP_MASK;
+                S5P_CITRGFMT_FLIP_180);
 
        /*
         * The input and output rotator cannot work simultaneously.
@@ -95,26 +98,22 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx)
         * in direct fifo output mode.
         */
        if (ctx->rotation == 90 || ctx->rotation == 270) {
-               if (ctx->out_path == FIMC_LCDFIFO) {
-                       cfg |= S5P_CITRGFMT_INROT90;
-                       if (ctx->rotation == 270)
-                               flip |= S5P_MSCTRL_FLIP_180;
-               } else {
-                       cfg |= S5P_CITRGFMT_OUTROT90;
-                       if (ctx->rotation == 270)
-                               cfg |= S5P_CITRGFMT_FLIP_180;
-               }
-       } else if (ctx->rotation == 180) {
                if (ctx->out_path == FIMC_LCDFIFO)
-                       flip |= S5P_MSCTRL_FLIP_180;
+                       cfg |= S5P_CITRGFMT_INROT90;
                else
-                       cfg |= S5P_CITRGFMT_FLIP_180;
+                       cfg |= S5P_CITRGFMT_OUTROT90;
        }
-       if (ctx->rotation == 180 || ctx->rotation == 270)
-               writel(flip, dev->regs + S5P_MSCTRL);
 
-       cfg |= fimc_hw_get_target_flip(ctx->flip);
-       writel(cfg, dev->regs + S5P_CITRGFMT);
+       if (ctx->out_path == FIMC_DMA) {
+               cfg |= fimc_hw_get_target_flip(ctx);
+               writel(cfg, dev->regs + S5P_CITRGFMT);
+       } else {
+               /* LCD FIFO path */
+               flip = readl(dev->regs + S5P_MSCTRL);
+               flip &= ~S5P_MSCTRL_FLIP_MASK;
+               flip |= fimc_hw_get_in_flip(ctx);
+               writel(flip, dev->regs + S5P_MSCTRL);
+       }
 }
 
 void fimc_hw_set_target_format(struct fimc_ctx *ctx)
@@ -131,19 +130,14 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
                  S5P_CITRGFMT_VSIZE_MASK);
 
        switch (frame->fmt->color) {
-       case S5P_FIMC_RGB565:
-       case S5P_FIMC_RGB666:
-       case S5P_FIMC_RGB888:
+       case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
                cfg |= S5P_CITRGFMT_RGB;
                break;
        case S5P_FIMC_YCBCR420:
                cfg |= S5P_CITRGFMT_YCBCR420;
                break;
-       case S5P_FIMC_YCBYCR422:
-       case S5P_FIMC_YCRYCB422:
-       case S5P_FIMC_CBYCRY422:
-       case S5P_FIMC_CRYCBY422:
-               if (frame->fmt->planes_cnt == 1)
+       case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+               if (frame->fmt->colplanes == 1)
                        cfg |= S5P_CITRGFMT_YCBCR422_1P;
                else
                        cfg |= S5P_CITRGFMT_YCBCR422;
@@ -219,11 +213,11 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
        cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
                 S5P_CIOCTRL_YCBCR_PLANE_MASK);
 
-       if (frame->fmt->planes_cnt == 1)
+       if (frame->fmt->colplanes == 1)
                cfg |= ctx->out_order_1p;
-       else if (frame->fmt->planes_cnt == 2)
+       else if (frame->fmt->colplanes == 2)
                cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
-       else if (frame->fmt->planes_cnt == 3)
+       else if (frame->fmt->colplanes == 3)
                cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
 
        writel(cfg, dev->regs + S5P_CIOCTRL);
@@ -249,7 +243,7 @@ void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
        writel(cfg, dev->regs + S5P_CIOCTRL);
 }
 
-static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev =  ctx->fimc_dev;
        struct fimc_scaler *sc = &ctx->scaler;
@@ -267,7 +261,7 @@ static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
        writel(cfg, dev->regs + S5P_CISCPREDST);
 }
 
-void fimc_hw_set_scaler(struct fimc_ctx *ctx)
+static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
 {
        struct fimc_dev *dev = ctx->fimc_dev;
        struct fimc_scaler *sc = &ctx->scaler;
@@ -275,8 +269,6 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
        struct fimc_frame *dst_frame = &ctx->d_frame;
        u32 cfg = 0;
 
-       fimc_hw_set_prescaler(ctx);
-
        if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
                cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
 
@@ -316,13 +308,42 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx)
                        cfg |= S5P_CISCCTRL_INTERLACE;
        }
 
+       writel(cfg, dev->regs + S5P_CISCCTRL);
+}
+
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
+{
+       struct fimc_dev *dev = ctx->fimc_dev;
+       struct samsung_fimc_variant *variant = dev->variant;
+       struct fimc_scaler *sc = &ctx->scaler;
+       u32 cfg;
+
        dbg("main_hratio= 0x%X  main_vratio= 0x%X",
                sc->main_hratio, sc->main_vratio);
 
-       cfg |= S5P_CISCCTRL_SC_HORRATIO(sc->main_hratio);
-       cfg |= S5P_CISCCTRL_SC_VERRATIO(sc->main_vratio);
+       fimc_hw_set_scaler(ctx);
 
-       writel(cfg, dev->regs + S5P_CISCCTRL);
+       cfg = readl(dev->regs + S5P_CISCCTRL);
+
+       if (variant->has_mainscaler_ext) {
+               cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
+               cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
+               cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
+               writel(cfg, dev->regs + S5P_CISCCTRL);
+
+               cfg = readl(dev->regs + S5P_CIEXTEN);
+
+               cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK |
+                        S5P_CIEXTEN_MHRATIO_EXT_MASK);
+               cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
+               cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
+               writel(cfg, dev->regs + S5P_CIEXTEN);
+       } else {
+               cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
+               cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio);
+               cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio);
+               writel(cfg, dev->regs + S5P_CISCCTRL);
+       }
 }
 
 void fimc_hw_en_capture(struct fimc_ctx *ctx)
@@ -410,41 +431,37 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
 
        /* Set the input DMA to process single frame only. */
        cfg = readl(dev->regs + S5P_MSCTRL);
-       cfg &= ~(S5P_MSCTRL_FLIP_MASK
-               | S5P_MSCTRL_INFORMAT_MASK
+       cfg &= ~(S5P_MSCTRL_INFORMAT_MASK
                | S5P_MSCTRL_IN_BURST_COUNT_MASK
                | S5P_MSCTRL_INPUT_MASK
                | S5P_MSCTRL_C_INT_IN_MASK
                | S5P_MSCTRL_2P_IN_ORDER_MASK);
 
-       cfg |= (S5P_MSCTRL_FRAME_COUNT(1) | S5P_MSCTRL_INPUT_MEMORY);
+       cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4)
+               | S5P_MSCTRL_INPUT_MEMORY
+               | S5P_MSCTRL_FIFO_CTRL_FULL);
 
        switch (frame->fmt->color) {
-       case S5P_FIMC_RGB565:
-       case S5P_FIMC_RGB666:
-       case S5P_FIMC_RGB888:
+       case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
                cfg |= S5P_MSCTRL_INFORMAT_RGB;
                break;
        case S5P_FIMC_YCBCR420:
                cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
 
-               if (frame->fmt->planes_cnt == 2)
+               if (frame->fmt->colplanes == 2)
                        cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
                else
                        cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
 
                break;
-       case S5P_FIMC_YCBYCR422:
-       case S5P_FIMC_YCRYCB422:
-       case S5P_FIMC_CBYCRY422:
-       case S5P_FIMC_CRYCBY422:
-               if (frame->fmt->planes_cnt == 1) {
+       case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+               if (frame->fmt->colplanes == 1) {
                        cfg |= ctx->in_order_1p
                                | S5P_MSCTRL_INFORMAT_YCBCR422_1P;
                } else {
                        cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
 
-                       if (frame->fmt->planes_cnt == 2)
+                       if (frame->fmt->colplanes == 2)
                                cfg |= ctx->in_order_2p
                                        | S5P_MSCTRL_C_INT_IN_2PLANE;
                        else
@@ -455,13 +472,6 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
                break;
        }
 
-       /*
-        * Input DMA flip mode (and rotation).
-        * Do not allow simultaneous rotation and flipping.
-        */
-       if (!ctx->rotation && ctx->out_path == FIMC_LCDFIFO)
-               cfg |= fimc_hw_get_in_flip(ctx->flip);
-
        writel(cfg, dev->regs + S5P_MSCTRL);
 
        /* Input/output DMA linear/tiled mode. */
@@ -532,7 +542,7 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
 }
 
 int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
-                               struct s3c_fimc_isp_info *cam)
+                               struct s5p_fimc_isp_info *cam)
 {
        u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
 
@@ -557,41 +567,46 @@ int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
 }
 
 int fimc_hw_set_camera_source(struct fimc_dev *fimc,
-                             struct s3c_fimc_isp_info *cam)
+                             struct s5p_fimc_isp_info *cam)
 {
        struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
        u32 cfg = 0;
+       u32 bus_width;
+       int i;
+
+       static const struct {
+               u32 pixelcode;
+               u32 cisrcfmt;
+               u16 bus_width;
+       } pix_desc[] = {
+               { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 },
+               { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 },
+               { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 },
+               { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 },
+               /* TODO: Add pixel codes for 16-bit bus width */
+       };
 
        if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+               for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
+                       if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) {
+                               cfg = pix_desc[i].cisrcfmt;
+                               bus_width = pix_desc[i].bus_width;
+                               break;
+                       }
+               }
 
-               switch (fimc->vid_cap.fmt.code) {
-               case V4L2_MBUS_FMT_YUYV8_2X8:
-                       cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
-                       break;
-               case V4L2_MBUS_FMT_YVYU8_2X8:
-                       cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
-                       break;
-               case V4L2_MBUS_FMT_VYUY8_2X8:
-                       cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
-                       break;
-               case V4L2_MBUS_FMT_UYVY8_2X8:
-                       cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
-                       break;
-               default:
-                       err("camera image format not supported: %d",
-                           fimc->vid_cap.fmt.code);
+               if (i == ARRAY_SIZE(pix_desc)) {
+                       v4l2_err(&fimc->vid_cap.v4l2_dev,
+                                "Camera color format not supported: %d\n",
+                                fimc->vid_cap.fmt.code);
                        return -EINVAL;
                }
 
                if (cam->bus_type == FIMC_ITU_601) {
-                       if (cam->bus_width == 8) {
+                       if (bus_width == 8)
                                cfg |= S5P_CISRCFMT_ITU601_8BIT;
-                       } else if (cam->bus_width == 16) {
+                       else if (bus_width == 16)
                                cfg |= S5P_CISRCFMT_ITU601_16BIT;
-                       } else {
-                               err("invalid bus width: %d", cam->bus_width);
-                               return -EINVAL;
-                       }
                } /* else defaults to ITU-R BT.656 8-bit */
        }
 
@@ -624,7 +639,7 @@ int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
 }
 
 int fimc_hw_set_camera_type(struct fimc_dev *fimc,
-                           struct s3c_fimc_isp_info *cam)
+                           struct s5p_fimc_isp_info *cam)
 {
        u32 cfg, tmp;
        struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
@@ -650,10 +665,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
                            vid_cap->fmt.code);
                        return -EINVAL;
                }
-               writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
+               tmp |= (cam->csi_data_align == 32) << 8;
+
+               writel(tmp, fimc->regs + S5P_CSIIMGFMT);
 
        } else if (cam->bus_type == FIMC_ITU_601 ||
-                 cam->bus_type == FIMC_ITU_656) {
+                  cam->bus_type == FIMC_ITU_656) {
                if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
                        cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
        } else if (cam->bus_type == FIMC_LCD_WB) {
index 57e33f84fcfa5fa4a4fd35d7eb9998e75ac1d003..0fea3e635d76bd19c487dc81bb89307bd4684011 100644 (file)
@@ -98,8 +98,8 @@
 #define S5P_CIOCTRL                    0x4c
 #define S5P_CIOCTRL_ORDER422_MASK      (3 << 0)
 #define S5P_CIOCTRL_ORDER422_CRYCBY    (0 << 0)
-#define S5P_CIOCTRL_ORDER422_YCRYCB    (1 << 0)
-#define S5P_CIOCTRL_ORDER422_CBYCRY    (2 << 0)
+#define S5P_CIOCTRL_ORDER422_CBYCRY    (1 << 0)
+#define S5P_CIOCTRL_ORDER422_YCRYCB    (2 << 0)
 #define S5P_CIOCTRL_ORDER422_YCBYCR    (3 << 0)
 #define S5P_CIOCTRL_LASTIRQ_ENABLE     (1 << 2)
 #define S5P_CIOCTRL_YCBCR_3PLANE       (0 << 3)
 #define S5P_CISCCTRL_OUTRGB_FMT_MASK   (3 << 11)
 #define S5P_CISCCTRL_RGB_EXT           (1 << 10)
 #define S5P_CISCCTRL_ONE2ONE           (1 << 9)
-#define S5P_CISCCTRL_SC_HORRATIO(x)    ((x) << 16)
-#define S5P_CISCCTRL_SC_VERRATIO(x)    ((x) << 0)
+#define S5P_CISCCTRL_MHRATIO(x)                ((x) << 16)
+#define S5P_CISCCTRL_MVRATIO(x)                ((x) << 0)
+#define S5P_CISCCTRL_MHRATIO_MASK      (0x1ff << 16)
+#define S5P_CISCCTRL_MVRATIO_MASK      (0x1ff << 0)
+#define S5P_CISCCTRL_MHRATIO_EXT(x)    (((x) >> 6) << 16)
+#define S5P_CISCCTRL_MVRATIO_EXT(x)    (((x) >> 6) << 0)
 
 /* Target area */
 #define S5P_CITAREA                    0x5c
 
 /* Input DMA control */
 #define S5P_MSCTRL                     0xfc
-#define S5P_MSCTRL_IN_BURST_COUNT_MASK (3 << 24)
+#define S5P_MSCTRL_IN_BURST_COUNT_MASK (0xF << 24)
 #define S5P_MSCTRL_2P_IN_ORDER_MASK    (3 << 16)
 #define S5P_MSCTRL_2P_IN_ORDER_SHIFT   16
 #define S5P_MSCTRL_C_INT_IN_3PLANE     (0 << 15)
 #define S5P_MSCTRL_FLIP_X_MIRROR       (1 << 13)
 #define S5P_MSCTRL_FLIP_Y_MIRROR       (2 << 13)
 #define S5P_MSCTRL_FLIP_180            (3 << 13)
+#define S5P_MSCTRL_FIFO_CTRL_FULL      (1 << 12)
 #define S5P_MSCTRL_ORDER422_SHIFT      4
-#define S5P_MSCTRL_ORDER422_CRYCBY     (0 << 4)
-#define S5P_MSCTRL_ORDER422_YCRYCB     (1 << 4)
-#define S5P_MSCTRL_ORDER422_CBYCRY     (2 << 4)
-#define S5P_MSCTRL_ORDER422_YCBYCR     (3 << 4)
+#define S5P_MSCTRL_ORDER422_YCBYCR     (0 << 4)
+#define S5P_MSCTRL_ORDER422_CBYCRY     (1 << 4)
+#define S5P_MSCTRL_ORDER422_YCRYCB     (2 << 4)
+#define S5P_MSCTRL_ORDER422_CRYCBY     (3 << 4)
 #define S5P_MSCTRL_ORDER422_MASK       (3 << 4)
 #define S5P_MSCTRL_INPUT_EXTCAM                (0 << 3)
 #define S5P_MSCTRL_INPUT_MEMORY                (1 << 3)
 #define S5P_MSCTRL_INFORMAT_RGB                (3 << 1)
 #define S5P_MSCTRL_INFORMAT_MASK       (3 << 1)
 #define S5P_MSCTRL_ENVID               (1 << 0)
-#define S5P_MSCTRL_FRAME_COUNT(x)      ((x) << 24)
+#define S5P_MSCTRL_IN_BURST_COUNT(x)   ((x) << 24)
 
 /* Output DMA Y/Cb/Cr offset */
 #define S5P_CIOYOFF                    0x168
 
 /* Real output DMA image size (extension register) */
 #define S5P_CIEXTEN                    0x188
+#define S5P_CIEXTEN_MHRATIO_EXT(x)     (((x) & 0x3f) << 10)
+#define S5P_CIEXTEN_MVRATIO_EXT(x)     ((x) & 0x3f)
+#define S5P_CIEXTEN_MHRATIO_EXT_MASK   (0x3f << 10)
+#define S5P_CIEXTEN_MVRATIO_EXT_MASK   0x3f
 
 #define S5P_CIDMAPARAM                 0x18c
 #define S5P_CIDMAPARAM_R_LINEAR                (0 << 29)
index 7913f93979b8ccfe2e5f81f0aedb3704872f1166..99664205ef4e962abecbc448d4c7521bd47770cf 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
 MODULE_AUTHOR("Pauline Middelink");
@@ -53,15 +54,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct saa7110 {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        u8 reg[SAA7110_NR_REG];
 
        v4l2_std_id norm;
        int input;
        int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 
        wait_queue_head_t wq;
 };
@@ -71,6 +69,11 @@ static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
        return container_of(sd, struct saa7110, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
+}
+
 /* ----------------------------------------------------------------------- */
 /* I2C support functions                                                  */
 /* ----------------------------------------------------------------------- */
@@ -326,73 +329,22 @@ static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-               return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct saa7110 *decoder = to_saa7110(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = decoder->bright;
-               break;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = decoder->contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               ctrl->value = decoder->sat;
-               break;
-       case V4L2_CID_HUE:
-               ctrl->value = decoder->hue;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct saa7110 *decoder = to_saa7110(sd);
+       struct v4l2_subdev *sd = to_sd(ctrl);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               if (decoder->bright != ctrl->value) {
-                       decoder->bright = ctrl->value;
-                       saa7110_write(sd, 0x19, decoder->bright);
-               }
+               saa7110_write(sd, 0x19, ctrl->val);
                break;
        case V4L2_CID_CONTRAST:
-               if (decoder->contrast != ctrl->value) {
-                       decoder->contrast = ctrl->value;
-                       saa7110_write(sd, 0x13, decoder->contrast);
-               }
+               saa7110_write(sd, 0x13, ctrl->val);
                break;
        case V4L2_CID_SATURATION:
-               if (decoder->sat != ctrl->value) {
-                       decoder->sat = ctrl->value;
-                       saa7110_write(sd, 0x12, decoder->sat);
-               }
+               saa7110_write(sd, 0x12, ctrl->val);
                break;
        case V4L2_CID_HUE:
-               if (decoder->hue != ctrl->value) {
-                       decoder->hue = ctrl->value;
-                       saa7110_write(sd, 0x07, decoder->hue);
-               }
+               saa7110_write(sd, 0x07, ctrl->val);
                break;
        default:
                return -EINVAL;
@@ -409,11 +361,19 @@ static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
+       .s_ctrl = saa7110_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops saa7110_core_ops = {
        .g_chip_ident = saa7110_g_chip_ident,
-       .g_ctrl = saa7110_g_ctrl,
-       .s_ctrl = saa7110_s_ctrl,
-       .queryctrl = saa7110_queryctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = saa7110_s_std,
 };
 
@@ -454,10 +414,25 @@ static int saa7110_probe(struct i2c_client *client,
        decoder->norm = V4L2_STD_PAL;
        decoder->input = 0;
        decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
+       v4l2_ctrl_handler_init(&decoder->hdl, 2);
+       v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+               V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+               V4L2_CID_CONTRAST, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+               V4L2_CID_SATURATION, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+               V4L2_CID_HUE, -128, 127, 1, 0);
+       sd->ctrl_handler = &decoder->hdl;
+       if (decoder->hdl.error) {
+               int err = decoder->hdl.error;
+
+               v4l2_ctrl_handler_free(&decoder->hdl);
+               kfree(decoder);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&decoder->hdl);
+
        init_waitqueue_head(&decoder->wq);
 
        rv = saa7110_write_block(sd, initseq, sizeof(initseq));
@@ -490,9 +465,11 @@ static int saa7110_probe(struct i2c_client *client,
 static int saa7110_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct saa7110 *decoder = to_saa7110(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_saa7110(sd));
+       v4l2_ctrl_handler_free(&decoder->hdl);
+       kfree(decoder);
        return 0;
 }
 
index 380f1b28cfcc1f2f41a354b31579a518c5f886db..39fc0187a747c22bb9b2dbee2ff298bfc8974787 100644 (file)
@@ -28,6 +28,7 @@ config VIDEO_SAA7134_RC
        bool "Philips SAA7134 Remote Controller support"
        depends on RC_CORE
        depends on VIDEO_SAA7134
+       depends on !(RC_CORE=m && VIDEO_SAA7134=y)
        default y
        ---help---
          Enables Remote Controller support on saa7134 driver.
index deb8fcf4aa49550fb251407a092774a4284f9d32..61c6007c8ea63eafce840f12f5ab7cf73c0d7999 100644 (file)
@@ -3620,6 +3620,38 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = 0,
                },
        },
+       [SAA7134_BOARD_ENCORE_ENLTV_FM3] = {
+               .name           = "Encore ENLTV-FM 3",
+               .audio_clock    = 0x02187de7,
+               .tuner_type     = TUNER_TENA_TNF_5337,
+               .radio_type     = TUNER_TEA5767,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x60,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+                       .gpio = 0x43000,
+               },
+       },
        [SAA7134_BOARD_CINERGY_HT_PCI] = {
                .name           = "Terratec Cinergy HT PCI",
                .audio_clock    = 0x00187de7,
@@ -6385,6 +6417,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1a7f,
                .subdevice    = 0x2008,
                .driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM53,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1a7f,
+               .subdevice    = 0x2108,
+               .driver_data  = SAA7134_BOARD_ENCORE_ENLTV_FM3,
        }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -7102,6 +7140,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
        case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+       case SAA7134_BOARD_ENCORE_ENLTV_FM3:
        case SAA7134_BOARD_10MOONSTVMASTER3:
        case SAA7134_BOARD_BEHOLD_401:
        case SAA7134_BOARD_BEHOLD_403:
@@ -7294,9 +7333,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 static void saa7134_tuner_setup(struct saa7134_dev *dev)
 {
        struct tuner_setup tun_setup;
-       unsigned int mode_mask = T_RADIO     |
-                                T_ANALOG_TV |
-                                T_DIGITAL_TV;
+       unsigned int mode_mask = T_RADIO | T_ANALOG_TV;
 
        memset(&tun_setup, 0, sizeof(tun_setup));
        tun_setup.tuner_callback = saa7134_tuner_callback;
index 6abeecff6da7b5d7bbaa5856a464b981eb90c8f0..41f836fc93ec3adf4e2cdfc909220904244771b4 100644 (file)
@@ -752,19 +752,28 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
        return 0;
 }
 
-static void __devinit must_configure_manually(void)
+static void __devinit must_configure_manually(int has_eeprom)
 {
        unsigned int i,p;
 
-       printk(KERN_WARNING
-              "saa7134: <rant>\n"
-              "saa7134:  Congratulations!  Your TV card vendor saved a few\n"
-              "saa7134:  cents for a eeprom, thus your pci board has no\n"
-              "saa7134:  subsystem ID and I can't identify it automatically\n"
-              "saa7134: </rant>\n"
-              "saa7134: I feel better now.  Ok, here are the good news:\n"
-              "saa7134: You can use the card=<nr> insmod option to specify\n"
-              "saa7134: which board do you have.  The list:\n");
+       if (!has_eeprom)
+               printk(KERN_WARNING
+                      "saa7134: <rant>\n"
+                      "saa7134:  Congratulations!  Your TV card vendor saved a few\n"
+                      "saa7134:  cents for a eeprom, thus your pci board has no\n"
+                      "saa7134:  subsystem ID and I can't identify it automatically\n"
+                      "saa7134: </rant>\n"
+                      "saa7134: I feel better now.  Ok, here are the good news:\n"
+                      "saa7134: You can use the card=<nr> insmod option to specify\n"
+                      "saa7134: which board do you have.  The list:\n");
+       else
+               printk(KERN_WARNING
+                      "saa7134: Board is currently unknown. You might try to use the card=<nr>\n"
+                      "saa7134: insmod option to specify which board do you have, but this is\n"
+                      "saa7134: somewhat risky, as might damage your card. It is better to ask\n"
+                      "saa7134: for support at linux-media@vger.kernel.org.\n"
+                      "saa7134: The supported cards are:\n");
+
        for (i = 0; i < saa7134_bcount; i++) {
                printk(KERN_WARNING "saa7134:   card=%d -> %-40.40s",
                       i,saa7134_boards[i].name);
@@ -936,8 +945,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        if (card[dev->nr] >= 0 &&
            card[dev->nr] < saa7134_bcount)
                dev->board = card[dev->nr];
-       if (SAA7134_BOARD_NOAUTO == dev->board) {
-               must_configure_manually();
+       if (SAA7134_BOARD_UNKNOWN == dev->board)
+               must_configure_manually(0);
+       else if (SAA7134_BOARD_NOAUTO == dev->board) {
+               must_configure_manually(1);
                dev->board = SAA7134_BOARD_UNKNOWN;
        }
        dev->autodetected = card[dev->nr] != dev->board;
index 6b8459c7728e472c1d927a2a066e7cc77fcebd2a..18294db38a01ace446d4ccb908d431dfcea99a2c 100644 (file)
@@ -373,6 +373,10 @@ static int empress_queryctrl(struct file *file, void *priv,
        static const u32 mpeg_ctrls[] = {
                V4L2_CID_MPEG_CLASS,
                V4L2_CID_MPEG_STREAM_TYPE,
+               V4L2_CID_MPEG_STREAM_PID_PMT,
+               V4L2_CID_MPEG_STREAM_PID_AUDIO,
+               V4L2_CID_MPEG_STREAM_PID_VIDEO,
+               V4L2_CID_MPEG_STREAM_PID_PCR,
                V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
                V4L2_CID_MPEG_AUDIO_ENCODING,
                V4L2_CID_MPEG_AUDIO_L2_BITRATE,
index dc646e65edb7bdf3fd77e12423c166316e11e863..be1c2a2de27cfa2fb4a3f53bbcf4f23054dd0764 100644 (file)
@@ -414,6 +414,41 @@ static int __saa7134_ir_start(void *priv)
        if (ir->running)
                return 0;
 
+       /* Moved here from saa7134_input_init1() because the latter
+        * is not called on device resume */
+       switch (dev->board) {
+       case SAA7134_BOARD_MD2819:
+       case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+       case SAA7134_BOARD_AVERMEDIA_305:
+       case SAA7134_BOARD_AVERMEDIA_307:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+       case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+       case SAA7134_BOARD_AVERMEDIA_M102:
+       case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+               /* Without this we won't receive key up events */
+               saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
+               saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+               break;
+       case SAA7134_BOARD_AVERMEDIA_777:
+       case SAA7134_BOARD_AVERMEDIA_A16AR:
+               /* Without this we won't receive key up events */
+               saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+               saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+               break;
+       case SAA7134_BOARD_AVERMEDIA_A16D:
+               /* Without this we won't receive key up events */
+               saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+               saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+               break;
+       case SAA7134_BOARD_GOTVIEW_7135:
+               saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
+               break;
+       }
+
        ir->running = true;
        ir->active = false;
 
@@ -548,9 +583,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
                polling      = 50; // ms
-               /* Set GPIO pin2 to high to enable the IR controller */
-               saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
-               saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+               /* GPIO stuff moved to __saa7134_ir_start() */
                break;
        case SAA7134_BOARD_AVERMEDIA_M135A:
                ir_codes     = RC_MAP_AVERMEDIA_M135A;
@@ -572,18 +605,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; // ms
-               /* Without this we won't receive key up events */
-               saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
-               saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+               /* GPIO stuff moved to __saa7134_ir_start() */
                break;
        case SAA7134_BOARD_AVERMEDIA_A16D:
                ir_codes     = RC_MAP_AVERMEDIA_A16D;
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; /* ms */
-               /* Without this we won't receive key up events */
-               saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
-               saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+               /* GPIO stuff moved to __saa7134_ir_start() */
                break;
        case SAA7134_BOARD_KWORLD_TERMINATOR:
                ir_codes     = RC_MAP_PIXELVIEW;
@@ -635,7 +664,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x0003CC;
                mask_keydown = 0x000010;
                polling      = 5; /* ms */
-               saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
+               /* GPIO stuff moved to __saa7134_ir_start() */
                break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -681,6 +710,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+       case SAA7134_BOARD_ENCORE_ENLTV_FM3:
                ir_codes     = RC_MAP_ENCORE_ENLTV_FM53;
                mask_keydown = 0x0040000;       /* Enable GPIO18 line on both edges */
                mask_keyup   = 0x0040000;
@@ -863,7 +893,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                dev->init_data.name = "HVR 1110";
                dev->init_data.get_key = get_key_hvr1110;
-               dev->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
+               dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
                info.addr = 0x71;
                break;
        case SAA7134_BOARD_BEHOLD_607FM_MK3:
index 5b0a347b0b8f1ac0cf5e8927506d8747e83cfb84..f96cd5d761f937990030f1d0dbe42cec9910a22b 100644 (file)
@@ -327,6 +327,7 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
 #define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
 #define SAA7134_BOARD_VIDEOMATE_M1F         183
+#define SAA7134_BOARD_ENCORE_ENLTV_FM3      184
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
index bd86d970f4c205de528ea39ec3d0778a248f0553..8a98ab68239e10ee5f1155f4fa31e678b58f7e48 100644 (file)
@@ -743,7 +743,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
 int saa7164_api_initialize_dif(struct saa7164_port *port)
 {
        struct saa7164_dev *dev = port->dev;
-       struct saa7164_port *p = 0;
+       struct saa7164_port *p = NULL;
        int ret = -EINVAL;
        u32 std = 0;
 
@@ -926,9 +926,9 @@ int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
 
 int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
 {
-       struct saa7164_port *tsport = 0;
-       struct saa7164_port *encport = 0;
-       struct saa7164_port *vbiport = 0;
+       struct saa7164_port *tsport = NULL;
+       struct saa7164_port *encport = NULL;
+       struct saa7164_port *vbiport = NULL;
        u32 idx, next_offset;
        int i;
        struct tmComResDescrHeader *hdr, *t;
@@ -1340,7 +1340,7 @@ int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
 
        /* Allocate enough storage for all of the descs */
        buf = kzalloc(buflen, GFP_KERNEL);
-       if (buf == NULL)
+       if (!buf)
                return SAA_ERR_NO_RESOURCES;
 
        /* Retrieve them */
index ddd25211c9e81b3a44ccb208d51412c062e75782..66696fa8341d1d1b646565d6802f99b1d33e0898 100644 (file)
@@ -93,7 +93,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
        u32 len)
 {
        struct tmHWStreamParameters *params = &port->hw_streamingparams;
-       struct saa7164_buffer *buf = 0;
+       struct saa7164_buffer *buf = NULL;
        struct saa7164_dev *dev = port->dev;
        int i;
 
@@ -103,7 +103,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
        }
 
        buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL);
-       if (buf == NULL) {
+       if (!buf) {
                log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__);
                goto ret;
        }
@@ -157,7 +157,7 @@ fail2:
 fail1:
        kfree(buf);
 
-       buf = 0;
+       buf = NULL;
 ret:
        return buf;
 }
@@ -289,14 +289,14 @@ struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev,
        struct saa7164_user_buffer *buf;
 
        buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
-       if (buf == 0)
-               return 0;
+       if (!buf)
+               return NULL;
 
        buf->data = kzalloc(len, GFP_KERNEL);
 
-       if (buf->data == 0) {
+       if (!buf->data) {
                kfree(buf);
-               return 0;
+               return NULL;
        }
 
        buf->actual_size = len;
@@ -315,7 +315,7 @@ void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
                return;
 
        kfree(buf->data);
-       buf->data = 0;
+       buf->data = NULL;
 
        kfree(buf);
 }
index b2b0d97101d091d306926206ea9fcf17c2ae0bfa..466e1b02f91f42c38c9a8af77d0eb1f9794c55f5 100644 (file)
@@ -158,7 +158,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
                return SAA_ERR_BAD_PARAMETER;
        }
 
-       if ((msg->size > 0) && (buf == 0)) {
+       if ((msg->size > 0) && (buf == NULL)) {
                printk(KERN_ERR "%s() Missing message buffer\n", __func__);
                return SAA_ERR_BAD_PARAMETER;
        }
@@ -315,7 +315,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
 
        saa7164_bus_verify(dev);
 
-       if (msg == 0)
+       if (msg == NULL)
                return ret;
 
        if (msg->size > dev->bus.m_wMaxReqSize) {
@@ -324,7 +324,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
                return ret;
        }
 
-       if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) {
+       if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) {
                printk(KERN_ERR
                        "%s() Missing msg buf, size should be %d bytes\n",
                        __func__, msg->size);
@@ -392,7 +392,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
 
                printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__);
                saa7164_bus_dumpmsg(dev, msg, buf);
-               saa7164_bus_dumpmsg(dev, &msg_tmp, 0);
+               saa7164_bus_dumpmsg(dev, &msg_tmp, NULL);
                ret = SAA_ERR_INVALID_COMMAND;
                goto out;
        }
index a97ae17b36c2ca3f52a422f9a8e647ece56e4900..6a4c217ed3a7632bf332026cf557a9041cff9759 100644 (file)
@@ -84,7 +84,7 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev)
 {
        int ret = SAA_OK, i = 0;
        u32 timeout;
-       wait_queue_head_t *q = 0;
+       wait_queue_head_t *q = NULL;
        u8 tmp[512];
        dprintk(DBGLVL_CMD, "%s()\n", __func__);
 
@@ -137,7 +137,7 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
        int loop = 1;
        int ret;
        u32 timeout;
-       wait_queue_head_t *q = 0;
+       wait_queue_head_t *q = NULL;
        u8 tmp[512];
        dprintk(DBGLVL_CMD, "%s()\n", __func__);
 
@@ -261,7 +261,7 @@ out:
  */
 int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
 {
-       wait_queue_head_t *q = 0;
+       wait_queue_head_t *q = NULL;
        int ret = SAA_BUS_TIMEOUT;
        unsigned long stamp;
        int r;
@@ -357,7 +357,7 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
                "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id,
                command, controlselector);
 
-       if ((size == 0) || (buf == 0)) {
+       if ((size == 0) || (buf == NULL)) {
                printk(KERN_ERR "%s() Invalid param\n", __func__);
                return SAA_ERR_BAD_PARAMETER;
        }
@@ -538,7 +538,7 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
 
                        /* Invalid */
                        dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__);
-                       ret = saa7164_bus_get(dev, presponse_t, 0, 0);
+                       ret = saa7164_bus_get(dev, presponse_t, NULL, 0);
                        if (ret != SAA_OK) {
                                printk(KERN_ERR "get failed\n");
                                return ret;
index 58af67f2278bc5b2cf9b045752fdf08e7b3838b1..b813aec1e456cd46a807c5e86790cf8d2e2e0a0f 100644 (file)
@@ -277,8 +277,8 @@ static void saa7164_histogram_print(struct saa7164_port *port,
 static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
 {
        struct saa7164_dev *dev = port->dev;
-       struct saa7164_buffer *buf = 0;
-       struct saa7164_user_buffer *ubuf = 0;
+       struct saa7164_buffer *buf = NULL;
+       struct saa7164_user_buffer *ubuf = NULL;
        struct list_head *c, *n;
        int i = 0;
        u8 __iomem *p;
@@ -649,7 +649,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
        u32 intid, intstat[INT_SIZE/4];
        int i, handled = 0, bit;
 
-       if (dev == 0) {
+       if (dev == NULL) {
                printk(KERN_ERR "%s() No device specified\n", __func__);
                handled = 0;
                goto out;
@@ -945,7 +945,7 @@ static int get_resources(struct saa7164_dev *dev)
 
 static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
 {
-       struct saa7164_port *port = 0;
+       struct saa7164_port *port = NULL;
 
        if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
                BUG();
index b305a01b3bdec6c7875b6d4aad7d6a513c9b9dcf..f65eab63ca871fb634be16d0f17a0457ee1d933c 100644 (file)
@@ -309,8 +309,8 @@ static int dvb_register(struct saa7164_port *port)
 
        port->hw_streamingparams.pitch = 188;
        port->hw_streamingparams.linethreshold = 0;
-       port->hw_streamingparams.pagetablelistvirt = 0;
-       port->hw_streamingparams.pagetablelistphys = 0;
+       port->hw_streamingparams.pagetablelistvirt = NULL;
+       port->hw_streamingparams.pagetablelistphys = NULL;
        port->hw_streamingparams.numpagetables = 2 +
                ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
 
index 1838408cd5cb2635c64bf2ccee7e766cb90bd3aa..f9d5946988323c5e125c7d1a8bb70de9a34e8a8e 100644 (file)
@@ -152,8 +152,8 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
        /* Init and establish defaults */
        params->bitspersample = 8;
        params->linethreshold = 0;
-       params->pagetablelistvirt = 0;
-       params->pagetablelistphys = 0;
+       params->pagetablelistvirt = NULL;
+       params->pagetablelistphys = NULL;
        params->numpagetableentries = port->hwcfg.buffercount;
 
        /* Allocate the PCI resources, buffers (hard) */
@@ -1108,7 +1108,7 @@ static int fops_release(struct file *file)
 
 struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
 {
-       struct saa7164_user_buffer *ubuf = 0;
+       struct saa7164_user_buffer *ubuf = NULL;
        struct saa7164_dev *dev = port->dev;
        u32 crc;
 
@@ -1443,7 +1443,7 @@ int saa7164_encoder_register(struct saa7164_port *port)
        port->v4l_device = saa7164_encoder_alloc(port,
                dev->pci, &saa7164_mpeg_template, "mpeg");
 
-       if (port->v4l_device == NULL) {
+       if (!port->v4l_device) {
                printk(KERN_INFO "%s: can't allocate mpeg device\n",
                        dev->name);
                result = -ENOMEM;
index ebed6f786a23750a69d17df841924563b66a9123..b369300cce0695eae159acd664d31de0e6dd6d70 100644 (file)
@@ -88,7 +88,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
                "%s(image=%p, size=%d, flags=0x%x, dst=%p, dstsize=0x%x)\n",
                __func__, src, srcsize, dlflags, dst, dstsize);
 
-       if ((src == 0) || (dst == 0)) {
+       if ((src == NULL) || (dst == NULL)) {
                ret = -EIO;
                goto out;
        }
index 8abbe6d661e452149ae9e73cf517d3e85659adcd..9e5b01c29cf5fa7509c9affa0b8b7f5b7280d4b3 100644 (file)
@@ -123,8 +123,8 @@ static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
                ((params->numberoflines * params->pitch) / PAGE_SIZE);
        params->bitspersample = 8;
        params->linethreshold = 0;
-       params->pagetablelistvirt = 0;
-       params->pagetablelistphys = 0;
+       params->pagetablelistvirt = NULL;
+       params->pagetablelistphys = NULL;
        params->numpagetableentries = port->hwcfg.buffercount;
 
        /* Allocate the PCI resources, buffers (hard) */
@@ -1054,7 +1054,7 @@ static int fops_release(struct file *file)
 
 struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
 {
-       struct saa7164_user_buffer *ubuf = 0;
+       struct saa7164_user_buffer *ubuf = NULL;
        struct saa7164_dev *dev = port->dev;
        u32 crc;
 
@@ -1334,7 +1334,7 @@ int saa7164_vbi_register(struct saa7164_port *port)
        port->v4l_device = saa7164_vbi_alloc(port,
                dev->pci, &saa7164_vbi_template, "vbi");
 
-       if (port->v4l_device == NULL) {
+       if (!port->v4l_device) {
                printk(KERN_INFO "%s: can't allocate vbi device\n",
                        dev->name);
                result = -ENOMEM;
index 954222bc3458d6d2dde208953f99bcb6e2ec7b4b..3fe54bf41142d025437859ea71dbd0765bc67d0c 100644 (file)
@@ -38,7 +38,7 @@
 #include <media/v4l2-dev.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/v4l2-mediabus.h>
 #include <media/soc_mediabus.h>
 
@@ -87,7 +87,8 @@
 
 /* per video frame buffer */
 struct sh_mobile_ceu_buffer {
-       struct videobuf_buffer vb; /* v4l buffer must be first */
+       struct vb2_buffer vb; /* v4l buffer must be first */
+       struct list_head queue;
        enum v4l2_mbus_pixelcode code;
 };
 
@@ -99,16 +100,17 @@ struct sh_mobile_ceu_dev {
        void __iomem *base;
        unsigned long video_limit;
 
-       /* lock used to protect videobuf */
-       spinlock_t lock;
+       spinlock_t lock;                /* Protects video buffer lists */
        struct list_head capture;
-       struct videobuf_buffer *active;
+       struct vb2_buffer *active;
+       struct vb2_alloc_ctx *alloc_ctx;
 
        struct sh_mobile_ceu_info *pdata;
 
        u32 cflcr;
 
        enum v4l2_field field;
+       int sequence;
 
        unsigned int image_mode:1;
        unsigned int is_16bit:1;
@@ -133,6 +135,11 @@ struct sh_mobile_ceu_cam {
        enum v4l2_mbus_pixelcode code;
 };
 
+static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb)
+{
+       return container_of(vb, struct sh_mobile_ceu_buffer, vb);
+}
+
 static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
 {
        unsigned long flags;
@@ -205,11 +212,11 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
 /*
  *  Videobuf operations
  */
-static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
-                                       unsigned int *count,
-                                       unsigned int *size)
+static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
+                       unsigned int *count, unsigned int *num_planes,
+                       unsigned long sizes[], void *alloc_ctxs[])
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
@@ -218,39 +225,25 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq,
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       *size = bytes_per_line * icd->user_height;
+       *num_planes = 1;
+
+       pcdev->sequence = 0;
+       sizes[0] = bytes_per_line * icd->user_height;
+       alloc_ctxs[0] = pcdev->alloc_ctx;
 
-       if (0 == *count)
+       if (!*count)
                *count = 2;
 
        if (pcdev->video_limit) {
-               if (PAGE_ALIGN(*size) * *count > pcdev->video_limit)
-                       *count = pcdev->video_limit / PAGE_ALIGN(*size);
+               if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit)
+                       *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
        }
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->dev.parent, "count=%d, size=%lu\n", *count, sizes[0]);
 
        return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq,
-                       struct sh_mobile_ceu_buffer *buf)
-{
-       struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
-
-       dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
-               &buf->vb, buf->vb.baddr, buf->vb.bsize);
-
-       if (in_interrupt())
-               BUG();
-
-       videobuf_waiton(vq, &buf->vb, 0, 0);
-       videobuf_dma_contig_free(vq, &buf->vb);
-       dev_dbg(dev, "%s freed\n", __func__);
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
 #define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
 #define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
 #define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
@@ -309,7 +302,8 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
                bottom2 = CDBCR;
        }
 
-       phys_addr_top = videobuf_to_dma_contig(pcdev->active);
+       phys_addr_top = vb2_dma_contig_plane_paddr(pcdev->active, 0);
+
        ceu_write(pcdev, top1, phys_addr_top);
        if (V4L2_FIELD_NONE != pcdev->field) {
                phys_addr_bottom = phys_addr_top + icd->user_width;
@@ -330,87 +324,67 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
                }
        }
 
-       pcdev->active->state = VIDEOBUF_ACTIVE;
        ceu_write(pcdev, CAPSR, 0x1); /* start capture */
 
        return ret;
 }
 
-static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
-                                         struct videobuf_buffer *vb,
-                                         enum v4l2_field field)
+static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
        struct sh_mobile_ceu_buffer *buf;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
-       int ret;
+       unsigned long size;
 
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       buf = container_of(vb, struct sh_mobile_ceu_buffer, vb);
+       buf = to_ceu_vb(vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        /* Added list head initialization on alloc */
-       WARN_ON(!list_empty(&vb->queue));
+       WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);
 
 #ifdef DEBUG
        /*
         * This can be useful if you want to see if we actually fill
         * the buffer with something
         */
-       memset((void *)vb->baddr, 0xaa, vb->bsize);
+       if (vb2_plane_vaddr(vb, 0))
+               memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
        BUG_ON(NULL == icd->current_fmt);
 
-       if (buf->code   != icd->current_fmt->code ||
-           vb->width   != icd->user_width ||
-           vb->height  != icd->user_height ||
-           vb->field   != field) {
-               buf->code       = icd->current_fmt->code;
-               vb->width       = icd->user_width;
-               vb->height      = icd->user_height;
-               vb->field       = field;
-               vb->state       = VIDEOBUF_NEEDS_INIT;
-       }
+       size = icd->user_height * bytes_per_line;
 
-       vb->size = vb->height * bytes_per_line;
-       if (0 != vb->baddr && vb->bsize < vb->size) {
-               ret = -EINVAL;
-               goto out;
+       if (vb2_plane_size(vb, 0) < size) {
+               dev_err(icd->dev.parent, "Buffer too small (%lu < %lu)\n",
+                       vb2_plane_size(vb, 0), size);
+               return -ENOBUFS;
        }
 
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               ret = videobuf_iolock(vq, vb, NULL);
-               if (ret)
-                       goto fail;
-               vb->state = VIDEOBUF_PREPARED;
-       }
+       vb2_set_plane_payload(vb, 0, size);
 
        return 0;
-fail:
-       free_buffer(vq, buf);
-out:
-       return ret;
 }
 
-/* Called under spinlock_irqsave(&pcdev->lock, ...) */
-static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
-                                        struct videobuf_buffer *vb)
+static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
+       unsigned long flags;
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-       vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &pcdev->capture);
+       spin_lock_irqsave(&pcdev->lock, flags);
+       list_add_tail(&buf->queue, &pcdev->capture);
 
        if (!pcdev->active) {
                /*
@@ -421,13 +395,14 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
                pcdev->active = vb;
                sh_mobile_ceu_capture(pcdev);
        }
+       spin_unlock_irqrestore(&pcdev->lock, flags);
 }
 
-static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
-                                          struct videobuf_buffer *vb)
+static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        unsigned long flags;
 
@@ -439,53 +414,60 @@ static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq,
                pcdev->active = NULL;
        }
 
-       if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
-           !list_empty(&vb->queue)) {
-               vb->state = VIDEOBUF_ERROR;
-               list_del_init(&vb->queue);
-       }
+       /* Doesn't hurt also if the list is empty */
+       list_del_init(&buf->queue);
 
        spin_unlock_irqrestore(&pcdev->lock, flags);
+}
 
-       free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb));
+static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
+{
+       /* This is for locking debugging only */
+       INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
+       return 0;
 }
 
-static struct videobuf_queue_ops sh_mobile_ceu_videobuf_ops = {
-       .buf_setup      = sh_mobile_ceu_videobuf_setup,
-       .buf_prepare    = sh_mobile_ceu_videobuf_prepare,
-       .buf_queue      = sh_mobile_ceu_videobuf_queue,
-       .buf_release    = sh_mobile_ceu_videobuf_release,
+static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
+       .queue_setup    = sh_mobile_ceu_videobuf_setup,
+       .buf_prepare    = sh_mobile_ceu_videobuf_prepare,
+       .buf_queue      = sh_mobile_ceu_videobuf_queue,
+       .buf_cleanup    = sh_mobile_ceu_videobuf_release,
+       .buf_init       = sh_mobile_ceu_videobuf_init,
+       .wait_prepare   = soc_camera_unlock,
+       .wait_finish    = soc_camera_lock,
 };
 
 static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
 {
        struct sh_mobile_ceu_dev *pcdev = data;
-       struct videobuf_buffer *vb;
-       unsigned long flags;
+       struct vb2_buffer *vb;
+       int ret;
 
-       spin_lock_irqsave(&pcdev->lock, flags);
+       spin_lock(&pcdev->lock);
 
        vb = pcdev->active;
        if (!vb)
                /* Stale interrupt from a released buffer */
                goto out;
 
-       list_del_init(&vb->queue);
+       list_del_init(&to_ceu_vb(vb)->queue);
 
        if (!list_empty(&pcdev->capture))
-               pcdev->active = list_entry(pcdev->capture.next,
-                                          struct videobuf_buffer, queue);
+               pcdev->active = &list_entry(pcdev->capture.next,
+                                           struct sh_mobile_ceu_buffer, queue)->vb;
        else
                pcdev->active = NULL;
 
-       vb->state = (sh_mobile_ceu_capture(pcdev) < 0) ?
-               VIDEOBUF_ERROR : VIDEOBUF_DONE;
-       do_gettimeofday(&vb->ts);
-       vb->field_count++;
-       wake_up(&vb->done);
+       ret = sh_mobile_ceu_capture(pcdev);
+       do_gettimeofday(&vb->v4l2_buf.timestamp);
+       if (!ret) {
+               vb->v4l2_buf.field = pcdev->field;
+               vb->v4l2_buf.sequence = pcdev->sequence++;
+       }
+       vb2_buffer_done(vb, ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 
 out:
-       spin_unlock_irqrestore(&pcdev->lock, flags);
+       spin_unlock(&pcdev->lock);
 
        return IRQ_HANDLED;
 }
@@ -529,9 +511,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
        /* make sure active buffer is canceled */
        spin_lock_irqsave(&pcdev->lock, flags);
        if (pcdev->active) {
-               list_del(&pcdev->active->queue);
-               pcdev->active->state = VIDEOBUF_ERROR;
-               wake_up_all(&pcdev->active->done);
+               list_del_init(&to_ceu_vb(pcdev->active)->queue);
+               vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
                pcdev->active = NULL;
        }
        spin_unlock_irqrestore(&pcdev->lock, flags);
@@ -686,6 +667,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
                ceu_write(pcdev, CAPSR, capsr);
 }
 
+/* Capture is not running, no interrupts, no locking needed */
 static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
                                       __u32 pixfmt)
 {
@@ -1364,7 +1346,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
        struct device *dev = icd->dev.parent;
        struct v4l2_mbus_framefmt mf;
        unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v,
-               out_width, out_height, scale_h, scale_v;
+               out_width, out_height;
        int interm_width, interm_height;
        u32 capsr, cflcr;
        int ret;
@@ -1422,10 +1404,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
        scale_ceu_h     = calc_scale(interm_width, &out_width);
        scale_ceu_v     = calc_scale(interm_height, &out_height);
 
-       /* Calculate camera scales */
-       scale_h         = calc_generic_scale(cam_rect->width, out_width);
-       scale_v         = calc_generic_scale(cam_rect->height, out_height);
-
        dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v);
 
        /* Apply CEU scales. */
@@ -1437,8 +1415,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
 
        icd->user_width  = out_width;
        icd->user_height = out_height;
-       cam->ceu_left    = scale_down(rect->left - cam_rect->left, scale_h) & ~1;
-       cam->ceu_top     = scale_down(rect->top - cam_rect->top, scale_v) & ~1;
+       cam->ceu_left    = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1;
+       cam->ceu_top     = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1;
 
        /* 6. Use CEU cropping to crop to the new window. */
        sh_mobile_ceu_set_rect(icd);
@@ -1449,7 +1427,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
                icd->user_width, icd->user_height,
                cam->ceu_left, cam->ceu_top);
 
-       /* Restore capture */
+       /* Restore capture. The CE bit can be cleared by the hardware */
        if (pcdev->active)
                capsr |= 1;
        capture_restore(pcdev, capsr);
@@ -1726,43 +1704,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        return ret;
 }
 
-static int sh_mobile_ceu_reqbufs(struct soc_camera_device *icd,
-                                struct v4l2_requestbuffers *p)
-{
-       int i;
-
-       /*
-        * This is for locking debugging only. I removed spinlocks and now I
-        * check whether .prepare is ever called on a linked buffer, or whether
-        * a dma IRQ can occur for an in-work or unlinked buffer. Until now
-        * it hadn't triggered
-        */
-       for (i = 0; i < p->count; i++) {
-               struct sh_mobile_ceu_buffer *buf;
-
-               buf = container_of(icd->vb_vidq.bufs[i],
-                                  struct sh_mobile_ceu_buffer, vb);
-               INIT_LIST_HEAD(&buf->vb.queue);
-       }
-
-       return 0;
-}
-
 static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct sh_mobile_ceu_buffer *buf;
-
-       buf = list_entry(icd->vb_vidq.stream.next,
-                        struct sh_mobile_ceu_buffer, vb.stream);
-
-       poll_wait(file, &buf->vb.done, pt);
 
-       if (buf->vb.state == VIDEOBUF_DONE ||
-           buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-
-       return 0;
+       return vb2_poll(&icd->vb2_vidq, file, pt);
 }
 
 static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
@@ -1774,19 +1720,17 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
-                                       struct soc_camera_device *icd)
+static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
+                                      struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct sh_mobile_ceu_dev *pcdev = ici->priv;
-
-       videobuf_queue_dma_contig_init(q,
-                                      &sh_mobile_ceu_videobuf_ops,
-                                      icd->dev.parent, &pcdev->lock,
-                                      V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                      pcdev->field,
-                                      sizeof(struct sh_mobile_ceu_buffer),
-                                      icd, &icd->video_lock);
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR;
+       q->drv_priv = icd;
+       q->ops = &sh_mobile_ceu_videobuf_ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer);
+
+       return vb2_queue_init(q);
 }
 
 static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
@@ -1850,11 +1794,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .try_fmt        = sh_mobile_ceu_try_fmt,
        .set_ctrl       = sh_mobile_ceu_set_ctrl,
        .get_ctrl       = sh_mobile_ceu_get_ctrl,
-       .reqbufs        = sh_mobile_ceu_reqbufs,
        .poll           = sh_mobile_ceu_poll,
        .querycap       = sh_mobile_ceu_querycap,
        .set_bus_param  = sh_mobile_ceu_set_bus_param,
-       .init_videobuf  = sh_mobile_ceu_init_videobuf,
+       .init_videobuf2 = sh_mobile_ceu_init_videobuf,
        .controls       = sh_mobile_ceu_controls,
        .num_controls   = ARRAY_SIZE(sh_mobile_ceu_controls),
 };
@@ -2005,12 +1948,20 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                }
        }
 
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               err = PTR_ERR(pcdev->alloc_ctx);
+               goto exit_module_put;
+       }
+
        err = soc_camera_host_register(&pcdev->ici);
        if (err)
-               goto exit_module_put;
+               goto exit_free_ctx;
 
        return 0;
 
+exit_free_ctx:
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
 exit_module_put:
        if (csi2 && csi2->driver)
                module_put(csi2->driver->owner);
@@ -2041,6 +1992,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
        if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
                dma_release_declared_memory(&pdev->dev);
        iounmap(pcdev->base);
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
        if (csi2 && csi2->driver)
                module_put(csi2->driver->owner);
        kfree(pcdev);
index 84a6468193183369e1fda6537479d9496c518ce4..dd1b81b1442bcbaa194f9f4830140e184a3d84af 100644 (file)
@@ -56,7 +56,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
                switch (mf->code) {
                case V4L2_MBUS_FMT_UYVY8_2X8:           /* YUV422 */
                case V4L2_MBUS_FMT_YUYV8_1_5X8:         /* YUV420 */
-               case V4L2_MBUS_FMT_GREY8_1X8:           /* RAW8 */
+               case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
                case V4L2_MBUS_FMT_SBGGR8_1X8:
                case V4L2_MBUS_FMT_SGRBG8_1X8:
                        break;
@@ -67,7 +67,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
                break;
        case SH_CSI2I:
                switch (mf->code) {
-               case V4L2_MBUS_FMT_GREY8_1X8:           /* RAW8 */
+               case V4L2_MBUS_FMT_Y8_1X8:              /* RAW8 */
                case V4L2_MBUS_FMT_SBGGR8_1X8:
                case V4L2_MBUS_FMT_SGRBG8_1X8:
                case V4L2_MBUS_FMT_SBGGR10_1X10:        /* RAW10 */
@@ -111,7 +111,7 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
        case V4L2_MBUS_FMT_RGB565_2X8_BE:
                tmp |= 0x22;    /* RGB565 */
                break;
-       case V4L2_MBUS_FMT_GREY8_1X8:
+       case V4L2_MBUS_FMT_Y8_1X8:
        case V4L2_MBUS_FMT_SBGGR8_1X8:
        case V4L2_MBUS_FMT_SGRBG8_1X8:
                tmp |= 0x2a;    /* RAW8 */
index 84984f64b234a7cb013470793984ebc6ff5e6688..ce56a1cdbf0a6bf1065f75a7de5e322416e5e4b5 100644 (file)
@@ -1430,9 +1430,9 @@ static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
                   sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
 static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
                   sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green);
+static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue);
+static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red);
 static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
 
 
index a66811b43710a690c2a5d7ee77967ce40af1a6d4..46284489e4eb8b89e96e354e4defca8bd1710ebd 100644 (file)
@@ -34,6 +34,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
 #include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
 #include <media/soc_mediabus.h>
 
 /* Default to VGA resolution */
@@ -143,6 +144,10 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
 
        WARN_ON(priv != file->private_data);
 
+       /* Only single-plane capture is supported so far */
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        /* limit format to hardware capabilities */
        return ici->ops->try_fmt(icd, f);
 }
@@ -191,6 +196,15 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
        return v4l2_subdev_call(sd, core, s_std, *a);
 }
 
+static int soc_camera_enum_fsizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
+       struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+
+       return ici->ops->enum_fsizes(icd, fsize);
+}
+
 static int soc_camera_reqbufs(struct file *file, void *priv,
                              struct v4l2_requestbuffers *p)
 {
@@ -203,11 +217,16 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
        if (icd->streamer && icd->streamer != file)
                return -EBUSY;
 
-       ret = videobuf_reqbufs(&icd->vb_vidq, p);
-       if (ret < 0)
-               return ret;
+       if (ici->ops->init_videobuf) {
+               ret = videobuf_reqbufs(&icd->vb_vidq, p);
+               if (ret < 0)
+                       return ret;
+
+               ret = ici->ops->reqbufs(icd, p);
+       } else {
+               ret = vb2_reqbufs(&icd->vb2_vidq, p);
+       }
 
-       ret = ici->ops->reqbufs(icd, p);
        if (!ret && !icd->streamer)
                icd->streamer = file;
 
@@ -218,36 +237,48 @@ static int soc_camera_querybuf(struct file *file, void *priv,
                               struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
-       return videobuf_querybuf(&icd->vb_vidq, p);
+       if (ici->ops->init_videobuf)
+               return videobuf_querybuf(&icd->vb_vidq, p);
+       else
+               return vb2_querybuf(&icd->vb2_vidq, p);
 }
 
 static int soc_camera_qbuf(struct file *file, void *priv,
                           struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
        if (icd->streamer != file)
                return -EBUSY;
 
-       return videobuf_qbuf(&icd->vb_vidq, p);
+       if (ici->ops->init_videobuf)
+               return videobuf_qbuf(&icd->vb_vidq, p);
+       else
+               return vb2_qbuf(&icd->vb2_vidq, p);
 }
 
 static int soc_camera_dqbuf(struct file *file, void *priv,
                            struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
        if (icd->streamer != file)
                return -EBUSY;
 
-       return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
+       if (ici->ops->init_videobuf)
+               return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
+       else
+               return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
 /* Always entered with .video_lock held */
@@ -362,13 +393,12 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
 
        icd->user_width         = pix->width;
        icd->user_height        = pix->height;
+       icd->bytesperline       = pix->bytesperline;
+       icd->sizeimage          = pix->sizeimage;
        icd->colorspace         = pix->colorspace;
-       icd->vb_vidq.field      =
-               icd->field      = pix->field;
-
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
-                        f->type);
+       icd->field              = pix->field;
+       if (ici->ops->init_videobuf)
+               icd->vb_vidq.field = pix->field;
 
        dev_dbg(&icd->dev, "set width: %d height: %d\n",
                icd->user_width, icd->user_height);
@@ -444,7 +474,13 @@ static int soc_camera_open(struct file *file)
                if (ret < 0)
                        goto esfmt;
 
-               ici->ops->init_videobuf(&icd->vb_vidq, icd);
+               if (ici->ops->init_videobuf) {
+                       ici->ops->init_videobuf(&icd->vb_vidq, icd);
+               } else {
+                       ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd);
+                       if (ret < 0)
+                               goto einitvb;
+               }
        }
 
        file->private_data = icd;
@@ -456,6 +492,7 @@ static int soc_camera_open(struct file *file)
         * First four errors are entered with the .video_lock held
         * and use_count == 1
         */
+einitvb:
 esfmt:
        pm_runtime_disable(&icd->vdev->dev);
 eresume:
@@ -482,6 +519,8 @@ static int soc_camera_close(struct file *file)
                pm_runtime_disable(&icd->vdev->dev);
 
                ici->ops->remove(icd);
+               if (ici->ops->init_videobuf2)
+                       vb2_queue_release(&icd->vb2_vidq);
 
                soc_camera_power_set(icd, icl, 0);
        }
@@ -510,6 +549,7 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
 static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        int err;
 
        dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
@@ -517,7 +557,10 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
        if (icd->streamer != file)
                return -EBUSY;
 
-       err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
+       if (ici->ops->init_videobuf)
+               err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
+       else
+               err = vb2_mmap(&icd->vb2_vidq, vma);
 
        dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -535,7 +578,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
        if (icd->streamer != file)
                return -EBUSY;
 
-       if (list_empty(&icd->vb_vidq.stream)) {
+       if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
                dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
                return POLLERR;
        }
@@ -543,6 +586,20 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
        return ici->ops->poll(file, pt);
 }
 
+void soc_camera_lock(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+       mutex_lock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_lock);
+
+void soc_camera_unlock(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = vb2_get_drv_priv(vq);
+       mutex_unlock(&icd->video_lock);
+}
+EXPORT_SYMBOL(soc_camera_unlock);
+
 static struct v4l2_file_operations soc_camera_fops = {
        .owner          = THIS_MODULE,
        .open           = soc_camera_open,
@@ -561,6 +618,11 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
 
        WARN_ON(priv != file->private_data);
 
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_warn(&icd->dev, "Wrong buf-type %d\n", f->type);
+               return -EINVAL;
+       }
+
        if (icd->streamer && icd->streamer != file)
                return -EBUSY;
 
@@ -604,16 +666,16 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
 
        WARN_ON(priv != file->private_data);
 
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
        pix->width              = icd->user_width;
        pix->height             = icd->user_height;
-       pix->field              = icd->vb_vidq.field;
+       pix->bytesperline       = icd->bytesperline;
+       pix->sizeimage          = icd->sizeimage;
+       pix->field              = icd->field;
        pix->pixelformat        = icd->current_fmt->host_fmt->fourcc;
-       pix->bytesperline       = soc_mbus_bytes_per_line(pix->width,
-                                               icd->current_fmt->host_fmt);
        pix->colorspace         = icd->colorspace;
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage          = pix->height * pix->bytesperline;
        dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
                icd->current_fmt->host_fmt->fourcc);
        return 0;
@@ -635,6 +697,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
                               enum v4l2_buf_type i)
 {
        struct soc_camera_device *icd = file->private_data;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -646,10 +709,14 @@ static int soc_camera_streamon(struct file *file, void *priv,
        if (icd->streamer != file)
                return -EBUSY;
 
-       v4l2_subdev_call(sd, video, s_stream, 1);
-
        /* This calls buf_queue from host driver's videobuf_queue_ops */
-       ret = videobuf_streamon(&icd->vb_vidq);
+       if (ici->ops->init_videobuf)
+               ret = videobuf_streamon(&icd->vb_vidq);
+       else
+               ret = vb2_streamon(&icd->vb2_vidq, i);
+
+       if (!ret)
+               v4l2_subdev_call(sd, video, s_stream, 1);
 
        return ret;
 }
@@ -659,6 +726,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 {
        struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -672,7 +740,10 @@ static int soc_camera_streamoff(struct file *file, void *priv,
         * This calls buf_release from host driver's videobuf_queue_ops for all
         * remaining buffers. When the last buffer is freed, stop capture
         */
-       videobuf_streamoff(&icd->vb_vidq);
+       if (ici->ops->init_videobuf)
+               videobuf_streamoff(&icd->vb_vidq);
+       else
+               vb2_streamoff(&icd->vb2_vidq, i);
 
        v4l2_subdev_call(sd, video, s_stream, 0);
 
@@ -1175,6 +1246,31 @@ static int default_s_parm(struct soc_camera_device *icd,
        return v4l2_subdev_call(sd, video, s_parm, parm);
 }
 
+static int default_enum_fsizes(struct soc_camera_device *icd,
+                         struct v4l2_frmsizeenum *fsize)
+{
+       int ret;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       __u32 pixfmt = fsize->pixel_format;
+       struct v4l2_frmsizeenum fsize_mbus = *fsize;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate)
+               return -EINVAL;
+       /* map xlate-code to pixel_format, sensor only handle xlate-code*/
+       fsize_mbus.pixel_format = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus);
+       if (ret < 0)
+               return ret;
+
+       *fsize = fsize_mbus;
+       fsize->pixel_format = pixfmt;
+
+       return 0;
+}
+
 static void soc_camera_device_init(struct device *dev, void *pdata)
 {
        dev->platform_data      = pdata;
@@ -1192,8 +1288,9 @@ int soc_camera_host_register(struct soc_camera_host *ici)
            !ici->ops->set_fmt ||
            !ici->ops->set_bus_param ||
            !ici->ops->querycap ||
-           !ici->ops->init_videobuf ||
-           !ici->ops->reqbufs ||
+           ((!ici->ops->init_videobuf ||
+             !ici->ops->reqbufs) &&
+            !ici->ops->init_videobuf2) ||
            !ici->ops->add ||
            !ici->ops->remove ||
            !ici->ops->poll ||
@@ -1210,6 +1307,8 @@ int soc_camera_host_register(struct soc_camera_host *ici)
                ici->ops->set_parm = default_s_parm;
        if (!ici->ops->get_parm)
                ici->ops->get_parm = default_g_parm;
+       if (!ici->ops->enum_fsizes)
+               ici->ops->enum_fsizes = default_enum_fsizes;
 
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {
@@ -1317,6 +1416,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_g_input          = soc_camera_g_input,
        .vidioc_s_input          = soc_camera_s_input,
        .vidioc_s_std            = soc_camera_s_std,
+       .vidioc_enum_framesizes  = soc_camera_enum_fsizes,
        .vidioc_reqbufs          = soc_camera_reqbufs,
        .vidioc_try_fmt_vid_cap  = soc_camera_try_fmt_vid_cap,
        .vidioc_querybuf         = soc_camera_querybuf,
index 91391214c682d46f52bae13eb53a3c7f37f2f347..ed77aa055b633713f696cacb4612857cfa18c308 100644 (file)
@@ -88,7 +88,7 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
                .packing                = SOC_MBUS_PACKING_EXTEND16,
                .order                  = SOC_MBUS_ORDER_LE,
        },
-       [MBUS_IDX(GREY8_1X8)] = {
+       [MBUS_IDX(Y8_1X8)] = {
                .fourcc                 = V4L2_PIX_FMT_GREY,
                .name                   = "Grey",
                .bits_per_sample        = 8,
@@ -132,6 +132,20 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
        },
 };
 
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf)
+{
+       switch (mf->packing) {
+       case SOC_MBUS_PACKING_NONE:
+       case SOC_MBUS_PACKING_EXTEND16:
+               return 1;
+       case SOC_MBUS_PACKING_2X8_PADHI:
+       case SOC_MBUS_PACKING_2X8_PADLO:
+               return 2;
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
+
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
 {
        switch (mf->packing) {
index fc611ebeb82c3a550b3d2425c58927813dfb448d..84d4c7c83435caa355971c1bd0536d27253e0bd3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
+#include <linux/mfd/core.h>
 #include <linux/scatterlist.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
@@ -790,7 +791,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
 {
        int err;
        struct timblogiw *lw = NULL;
-       struct timb_video_platform_data *pdata = pdev->dev.platform_data;
+       struct timb_video_platform_data *pdata = mfd_get_data(pdev);
 
        if (!pdata) {
                dev_err(&pdev->dev, "No platform data\n");
index df33a1d188bbf1224716961cca57e79bd1afd17e..a794ae62aebfc5689b8bc542919e535444fb84d6 100644 (file)
@@ -764,10 +764,8 @@ static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix)
        }
        ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
                                vid_resol, &cmd_status);
-       if (ret || cmd_status) {
-               mutex_unlock(&pd->lock);
+       if (ret || cmd_status)
                return -EBUSY;
-       }
 
        pix_def->pixelformat = pix->pixelformat; /* save it */
        pix->height = (context->tvnormid & V4L2_STD_525_60) ?  480 : 576;
index dfc4dd7c509731575392a491ba6f7994e2d1b55e..286ec7e7062abd692583f9ebb52d71bebbbbe904 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -41,7 +42,7 @@ MODULE_LICENSE("GPL");
 
 struct tlv320aic23b_state {
        struct v4l2_subdev sd;
-       u8 muted;
+       struct v4l2_ctrl_handler hdl;
 };
 
 static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
@@ -49,6 +50,11 @@ static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
        return container_of(sd, struct tlv320aic23b_state, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct tlv320aic23b_state, hdl)->sd;
+}
+
 static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -85,44 +91,44 @@ static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        return 0;
 }
 
-static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct tlv320aic23b_state *state = to_state(sd);
-
-       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-               return -EINVAL;
-       ctrl->value = state->muted;
-       return 0;
-}
-
-static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tlv320aic23b_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct tlv320aic23b_state *state = to_state(sd);
-
-       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-               return -EINVAL;
-       state->muted = ctrl->value;
-       tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
-       /* set gain on both channels to +3.0 dB */
-       if (!state->muted)
-               tlv320aic23b_write(sd, 0, 0x119);
-       return 0;
+       struct v4l2_subdev *sd = to_sd(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
+               /* set gain on both channels to +3.0 dB */
+               if (!ctrl->val)
+                       tlv320aic23b_write(sd, 0, 0x119);
+               return 0;
+       }
+       return -EINVAL;
 }
 
 static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
 {
        struct tlv320aic23b_state *state = to_state(sd);
 
-       v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active");
+       v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = {
+       .s_ctrl = tlv320aic23b_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
        .log_status = tlv320aic23b_log_status,
-       .g_ctrl = tlv320aic23b_g_ctrl,
-       .s_ctrl = tlv320aic23b_s_ctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
@@ -161,7 +167,6 @@ static int tlv320aic23b_probe(struct i2c_client *client,
                return -ENOMEM;
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
-       state->muted = 0;
 
        /* Initialize tlv320aic23b */
 
@@ -177,15 +182,30 @@ static int tlv320aic23b_probe(struct i2c_client *client,
        tlv320aic23b_write(sd, 8, 0x000);
        /* activate digital interface */
        tlv320aic23b_write(sd, 9, 0x001);
+
+       v4l2_ctrl_handler_init(&state->hdl, 1);
+       v4l2_ctrl_new_std(&state->hdl, &tlv320aic23b_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       sd->ctrl_handler = &state->hdl;
+       if (state->hdl.error) {
+               int err = state->hdl.error;
+
+               v4l2_ctrl_handler_free(&state->hdl);
+               kfree(state);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&state->hdl);
        return 0;
 }
 
 static int tlv320aic23b_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct tlv320aic23b_state *state = to_state(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
+       v4l2_ctrl_handler_free(&state->hdl);
+       kfree(state);
        return 0;
 }
 
index 1cec1224913f4c64f3a68b7a9de9d4a635d5d66a..9363ed91a4cbda40a91ce2e1bf3958e9da097283 100644 (file)
@@ -1,7 +1,17 @@
 /*
- *
  * i2c tv tuner chip device driver
  * core core, i.e. kernel interfaces, registering and so on
+ *
+ * Copyright(c) by Ralph Metzler, Gerd Knorr, Gunther Mayer
+ *
+ * Copyright(c) 2005-2011 by Mauro Carvalho Chehab
+ *     - Added support for a separate Radio tuner
+ *     - Major rework and cleanups at the code
+ *
+ * This driver supports many devices and the idea is to let the driver
+ * detect which device is present. So rather than listing all supported
+ * devices here, we pretend to support a single, fake device type that will
+ * handle both radio and analog TV tuning.
  */
 
 #include <linux/module.h>
 
 #define UNSET (-1U)
 
-#define PREFIX t->i2c->driver->driver.name
+#define PREFIX (t->i2c->driver->driver.name)
+
+/*
+ * Driver modprobe parameters
+ */
+
+/* insmod options used at init time => read/only */
+static unsigned int addr;
+static unsigned int no_autodetect;
+static unsigned int show_i2c;
+
+module_param(addr, int, 0444);
+module_param(no_autodetect, int, 0444);
+module_param(show_i2c, int, 0444);
+
+/* insmod options used at runtime => read/write */
+static int tuner_debug;
+static unsigned int tv_range[2] = { 44, 958 };
+static unsigned int radio_range[2] = { 65, 108 };
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+module_param_named(debug, tuner_debug, int, 0644);
+module_param_array(tv_range, int, NULL, 0644);
+module_param_array(radio_range, int, NULL, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+
+/*
+ * Static vars
+ */
+
+static LIST_HEAD(tuner_list);
+static const struct v4l2_subdev_ops tuner_ops;
+
+/*
+ * Debug macros
+ */
+
+#define tuner_warn(fmt, arg...) do {                   \
+       printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_info(fmt, arg...) do {                   \
+       printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,    \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_err(fmt, arg...) do {                    \
+       printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,     \
+              i2c_adapter_id(t->i2c->adapter),         \
+              t->i2c->addr, ##arg);                    \
+        } while (0)
+
+#define tuner_dbg(fmt, arg...) do {                            \
+       if (tuner_debug)                                        \
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,   \
+                      i2c_adapter_id(t->i2c->adapter),         \
+                      t->i2c->addr, ##arg);                    \
+        } while (0)
+
+/*
+ * Internal struct used inside the driver
+ */
+
+struct tuner {
+       /* device */
+       struct dvb_frontend fe;
+       struct i2c_client   *i2c;
+       struct v4l2_subdev  sd;
+       struct list_head    list;
+
+       /* keep track of the current settings */
+       v4l2_std_id         std;
+       unsigned int        tv_freq;
+       unsigned int        radio_freq;
+       unsigned int        audmode;
+
+       enum v4l2_tuner_type mode;
+       unsigned int        mode_mask; /* Combination of allowable modes */
+
+       bool                standby;    /* Standby mode */
+
+       unsigned int        type; /* chip type id */
+       unsigned int        config;
+       const char          *name;
+};
+
+/*
+ * Function prototypes
+ */
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq);
+static void set_radio_freq(struct i2c_client *c, unsigned int freq);
+
+/*
+ * tuner attach/detach logic
+ */
 
-/** This macro allows us to probe dynamically, avoiding static links */
+/* This macro allows us to probe dynamically, avoiding static links */
 #ifdef CONFIG_MEDIA_ATTACH
 #define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
        int __r = -EINVAL; \
@@ -74,92 +186,15 @@ static void tuner_detach(struct dvb_frontend *fe)
 }
 #endif
 
-struct tuner {
-       /* device */
-       struct dvb_frontend fe;
-       struct i2c_client   *i2c;
-       struct v4l2_subdev  sd;
-       struct list_head    list;
-       unsigned int        using_v4l2:1;
-
-       /* keep track of the current settings */
-       v4l2_std_id         std;
-       unsigned int        tv_freq;
-       unsigned int        radio_freq;
-       unsigned int        audmode;
-
-       unsigned int        mode;
-       unsigned int        mode_mask; /* Combination of allowable modes */
-
-       unsigned int        type; /* chip type id */
-       unsigned int        config;
-       const char          *name;
-};
 
 static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
 {
        return container_of(sd, struct tuner, sd);
 }
 
-
-/* insmod options used at init time => read/only */
-static unsigned int addr;
-static unsigned int no_autodetect;
-static unsigned int show_i2c;
-
-/* insmod options used at runtime => read/write */
-static int tuner_debug;
-
-#define tuner_warn(fmt, arg...) do {                   \
-       printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
-              i2c_adapter_id(t->i2c->adapter),         \
-              t->i2c->addr, ##arg);                    \
-        } while (0)
-
-#define tuner_info(fmt, arg...) do {                   \
-       printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,    \
-              i2c_adapter_id(t->i2c->adapter),         \
-              t->i2c->addr, ##arg);                    \
-        } while (0)
-
-#define tuner_err(fmt, arg...) do {                    \
-       printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,     \
-              i2c_adapter_id(t->i2c->adapter),         \
-              t->i2c->addr, ##arg);                    \
-        } while (0)
-
-#define tuner_dbg(fmt, arg...) do {                            \
-       if (tuner_debug)                                        \
-               printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,   \
-                      i2c_adapter_id(t->i2c->adapter),         \
-                      t->i2c->addr, ##arg);                    \
-        } while (0)
-
-/* ------------------------------------------------------------------------ */
-
-static unsigned int tv_range[2] = { 44, 958 };
-static unsigned int radio_range[2] = { 65, 108 };
-
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-
-module_param(addr, int, 0444);
-module_param(no_autodetect, int, 0444);
-module_param(show_i2c, int, 0444);
-module_param_named(debug,tuner_debug, int, 0644);
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-module_param_array(tv_range, int, NULL, 0644);
-module_param_array(radio_range, int, NULL, 0644);
-
-MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-/* ---------------------------------------------------------------------- */
+/*
+ * struct analog_demod_ops callbacks
+ */
 
 static void fe_set_params(struct dvb_frontend *fe,
                          struct analog_parameters *params)
@@ -215,102 +250,25 @@ static struct analog_demod_ops tuner_analog_ops = {
        .tuner_status   = tuner_status
 };
 
-/* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-       struct tuner *t = to_tuner(i2c_get_clientdata(c));
-       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-
-       struct analog_parameters params = {
-               .mode      = t->mode,
-               .audmode   = t->audmode,
-               .std       = t->std
-       };
-
-       if (t->type == UNSET) {
-               tuner_warn ("tuner type not set\n");
-               return;
-       }
-       if (NULL == analog_ops->set_params) {
-               tuner_warn ("Tuner has no way to set tv freq\n");
-               return;
-       }
-       if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
-               tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
-                          freq / 16, freq % 16 * 100 / 16, tv_range[0],
-                          tv_range[1]);
-               /* V4L2 spec: if the freq is not possible then the closest
-                  possible value should be selected */
-               if (freq < tv_range[0] * 16)
-                       freq = tv_range[0] * 16;
-               else
-                       freq = tv_range[1] * 16;
-       }
-       params.frequency = freq;
-
-       analog_ops->set_params(&t->fe, &params);
-}
-
-static void set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-       struct tuner *t = to_tuner(i2c_get_clientdata(c));
-       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-
-       struct analog_parameters params = {
-               .mode      = t->mode,
-               .audmode   = t->audmode,
-               .std       = t->std
-       };
-
-       if (t->type == UNSET) {
-               tuner_warn ("tuner type not set\n");
-               return;
-       }
-       if (NULL == analog_ops->set_params) {
-               tuner_warn ("tuner has no way to set radio frequency\n");
-               return;
-       }
-       if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
-               tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
-                          freq / 16000, freq % 16000 * 100 / 16000,
-                          radio_range[0], radio_range[1]);
-               /* V4L2 spec: if the freq is not possible then the closest
-                  possible value should be selected */
-               if (freq < radio_range[0] * 16000)
-                       freq = radio_range[0] * 16000;
-               else
-                       freq = radio_range[1] * 16000;
-       }
-       params.frequency = freq;
-
-       analog_ops->set_params(&t->fe, &params);
-}
-
-static void set_freq(struct i2c_client *c, unsigned long freq)
-{
-       struct tuner *t = to_tuner(i2c_get_clientdata(c));
-
-       switch (t->mode) {
-       case V4L2_TUNER_RADIO:
-               tuner_dbg("radio freq set to %lu.%02lu\n",
-                         freq / 16000, freq % 16000 * 100 / 16000);
-               set_radio_freq(c, freq);
-               t->radio_freq = freq;
-               break;
-       case V4L2_TUNER_ANALOG_TV:
-       case V4L2_TUNER_DIGITAL_TV:
-               tuner_dbg("tv freq set to %lu.%02lu\n",
-                         freq / 16, freq % 16 * 100 / 16);
-               set_tv_freq(c, freq);
-               t->tv_freq = freq;
-               break;
-       default:
-               tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
-       }
-}
-
-static struct xc5000_config xc5000_cfg;
+/*
+ * Functions to select between radio and TV and tuner probe/remove functions
+ */
 
+/**
+ * set_type - Sets the tuner type for a given device
+ *
+ * @c:                 i2c_client descriptoy
+ * @type:              type of the tuner (e. g. tuner number)
+ * @new_mode_mask:     Indicates if tuner supports TV and/or Radio
+ * @new_config:                an optional parameter ranging from 0-255 used by
+                       a few tuners to adjust an internal parameter,
+                       like LNA mode
+ * @tuner_callback:    an optional function to be called when switching
+ *                     to analog mode
+ *
+ * This function applys the tuner config to tuner specified
+ * by tun_setup structure. It contains several per-tuner initialization "magic"
+ */
 static void set_type(struct i2c_client *c, unsigned int type,
                     unsigned int new_mode_mask, unsigned int new_config,
                     int (*tuner_callback) (void *dev, int component, int cmd, int arg))
@@ -322,7 +280,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
        int tune_now = 1;
 
        if (type == UNSET || type == TUNER_ABSENT) {
-               tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
+               tuner_dbg("tuner 0x%02x: Tuner type absent\n", c->addr);
                return;
        }
 
@@ -334,15 +292,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->fe.callback = tuner_callback;
        }
 
-       if (t->mode == T_UNINITIALIZED) {
-               tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
-
-               return;
-       }
-
-       /* discard private data, in case set_type() was previously called */
-       tuner_detach(&t->fe);
-       t->fe.analog_demod_priv = NULL;
+       /* discard private data, in case set_type() was previously called */
+       tuner_detach(&t->fe);
+       t->fe.analog_demod_priv = NULL;
 
        switch (t->type) {
        case TUNER_MT2032:
@@ -414,9 +366,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
                break;
        case TUNER_XC5000:
        {
-               xc5000_cfg.i2c_address    = t->i2c->addr;
-               /* if_khz will be set when the digital dvb_attach() occurs */
-               xc5000_cfg.if_khz         = 0;
+               struct xc5000_config xc5000_cfg = {
+                       .i2c_address = t->i2c->addr,
+                       /* if_khz will be set at dvb_attach() */
+                       .if_khz   = 0,
+               };
+
                if (!dvb_attach(xc5000_attach,
                                &t->fe, t->i2c->adapter, &xc5000_cfg))
                        goto attach_failed;
@@ -459,8 +414,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 
        tuner_dbg("type set to %s\n", t->name);
 
-       if (t->mode_mask == T_UNINITIALIZED)
-               t->mode_mask = new_mode_mask;
+       t->mode_mask = new_mode_mask;
 
        /* Some tuners require more initialization setup before use,
           such as firmware download or device calibration.
@@ -468,9 +422,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
           FIXME: better to move set_freq to the tuner code. This is needed
           on analog tuners for PLL to properly work
         */
-       if (tune_now)
-               set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
-                           t->radio_freq : t->tv_freq);
+       if (tune_now) {
+               if (V4L2_TUNER_RADIO == t->mode)
+                       set_radio_freq(c, t->radio_freq);
+               else
+                       set_tv_freq(c, t->tv_freq);
+       }
 
        tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
                  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
@@ -480,86 +437,426 @@ static void set_type(struct i2c_client *c, unsigned int type,
 attach_failed:
        tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
        t->type = TUNER_ABSENT;
-       t->mode_mask = T_UNINITIALIZED;
 
        return;
 }
 
-/*
- * This function apply tuner config to tuner specified
- * by tun_setup structure. I addr is unset, then admin status
- * and tun addr status is more precise then current status,
- * it's applied. Otherwise status and type are applied only to
- * tuner with exactly the same addr.
-*/
-
-static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
+/**
+ * tuner_s_type_addr - Sets the tuner type for a device
+ *
+ * @sd:                subdev descriptor
+ * @tun_setup: type to be associated to a given tuner i2c address
+ *
+ * This function applys the tuner config to tuner specified
+ * by tun_setup structure.
+ * If tuner I2C address is UNSET, then it will only set the device
+ * if the tuner supports the mode specified in the call.
+ * If the address is specified, the change will be applied only if
+ * tuner I2C address matches.
+ * The call can change the tuner number and the tuner mode.
+ */
+static int tuner_s_type_addr(struct v4l2_subdev *sd,
+                            struct tuner_setup *tun_setup)
 {
-       struct tuner *t = to_tuner(i2c_get_clientdata(c));
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
 
-       if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
-               (t->mode_mask & tun_setup->mode_mask))) ||
-               (tun_setup->addr == c->addr)) {
-                       set_type(c, tun_setup->type, tun_setup->mode_mask,
-                                tun_setup->config, tun_setup->tuner_callback);
+       tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
+                       tun_setup->type,
+                       tun_setup->addr,
+                       tun_setup->mode_mask,
+                       tun_setup->config);
+
+       if ((t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
+           (t->mode_mask & tun_setup->mode_mask))) ||
+           (tun_setup->addr == c->addr)) {
+               set_type(c, tun_setup->type, tun_setup->mode_mask,
+                        tun_setup->config, tun_setup->tuner_callback);
        } else
                tuner_dbg("set addr discarded for type %i, mask %x. "
                          "Asked to change tuner at addr 0x%02x, with mask %x\n",
                          t->type, t->mode_mask,
                          tun_setup->addr, tun_setup->mode_mask);
+
+       return 0;
 }
 
-static inline int check_mode(struct tuner *t, char *cmd)
+/**
+ * tuner_s_config - Sets tuner configuration
+ *
+ * @sd:                subdev descriptor
+ * @cfg:       tuner configuration
+ *
+ * Calls tuner set_config() private function to set some tuner-internal
+ * parameters
+ */
+static int tuner_s_config(struct v4l2_subdev *sd,
+                         const struct v4l2_priv_tun_config *cfg)
 {
-       if ((1 << t->mode & t->mode_mask) == 0) {
-               return -EINVAL;
+       struct tuner *t = to_tuner(sd);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       if (t->type != cfg->tuner)
+               return 0;
+
+       if (analog_ops->set_config) {
+               analog_ops->set_config(&t->fe, cfg->priv);
+               return 0;
        }
 
-       switch (t->mode) {
-       case V4L2_TUNER_RADIO:
-               tuner_dbg("Cmd %s accepted for radio\n", cmd);
-               break;
-       case V4L2_TUNER_ANALOG_TV:
-               tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
-               break;
-       case V4L2_TUNER_DIGITAL_TV:
-               tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
-               break;
+       tuner_dbg("Tuner frontend module has no way to set config\n");
+       return 0;
+}
+
+/**
+ * tuner_lookup - Seek for tuner adapters
+ *
+ * @adap:      i2c_adapter struct
+ * @radio:     pointer to be filled if the adapter is radio
+ * @tv:                pointer to be filled if the adapter is TV
+ *
+ * Search for existing radio and/or TV tuners on the given I2C adapter,
+ * discarding demod-only adapters (tda9887).
+ *
+ * Note that when this function is called from tuner_probe you can be
+ * certain no other devices will be added/deleted at the same time, I2C
+ * core protects against that.
+ */
+static void tuner_lookup(struct i2c_adapter *adap,
+               struct tuner **radio, struct tuner **tv)
+{
+       struct tuner *pos;
+
+       *radio = NULL;
+       *tv = NULL;
+
+       list_for_each_entry(pos, &tuner_list, list) {
+               int mode_mask;
+
+               if (pos->i2c->adapter != adap ||
+                   strcmp(pos->i2c->driver->driver.name, "tuner"))
+                       continue;
+
+               mode_mask = pos->mode_mask;
+               if (*radio == NULL && mode_mask == T_RADIO)
+                       *radio = pos;
+               /* Note: currently TDA9887 is the only demod-only
+                  device. If other devices appear then we need to
+                  make this test more general. */
+               else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
+                        (pos->mode_mask & T_ANALOG_TV))
+                       *tv = pos;
+       }
+}
+
+/**
+ *tuner_probe - Probes the existing tuners on an I2C bus
+ *
+ * @client:    i2c_client descriptor
+ * @id:                not used
+ *
+ * This routine probes for tuners at the expected I2C addresses. On most
+ * cases, if a device answers to a given I2C address, it assumes that the
+ * device is a tuner. On a few cases, however, an additional logic is needed
+ * to double check if the device is really a tuner, or to identify the tuner
+ * type, like on tea5767/5761 devices.
+ *
+ * During client attach, set_type is called by adapter's attach_inform callback.
+ * set_type must then be completed by tuner_probe.
+ */
+static int tuner_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct tuner *t;
+       struct tuner *radio;
+       struct tuner *tv;
+
+       t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
+       if (NULL == t)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
+       t->i2c = client;
+       t->name = "(tuner unset)";
+       t->type = UNSET;
+       t->audmode = V4L2_TUNER_MODE_STEREO;
+       t->standby = 1;
+       t->radio_freq = 87.5 * 16000;   /* Initial freq range */
+       t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */
+
+       if (show_i2c) {
+               unsigned char buffer[16];
+               int i, rc;
+
+               memset(buffer, 0, sizeof(buffer));
+               rc = i2c_master_recv(client, buffer, sizeof(buffer));
+               tuner_info("I2C RECV = ");
+               for (i = 0; i < rc; i++)
+                       printk(KERN_CONT "%02x ", buffer[i]);
+               printk("\n");
+       }
+
+       /* autodetection code based on the i2c addr */
+       if (!no_autodetect) {
+               switch (client->addr) {
+               case 0x10:
+                       if (tuner_symbol_probe(tea5761_autodetection,
+                                              t->i2c->adapter,
+                                              t->i2c->addr) >= 0) {
+                               t->type = TUNER_TEA5761;
+                               t->mode_mask = T_RADIO;
+                               tuner_lookup(t->i2c->adapter, &radio, &tv);
+                               if (tv)
+                                       tv->mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       kfree(t);
+                       return -ENODEV;
+               case 0x42:
+               case 0x43:
+               case 0x4a:
+               case 0x4b:
+                       /* If chip is not tda8290, don't register.
+                          since it can be tda9887*/
+                       if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
+                                              t->i2c->addr) >= 0) {
+                               tuner_dbg("tda829x detected\n");
+                       } else {
+                               /* Default is being tda9887 */
+                               t->type = TUNER_TDA9887;
+                               t->mode_mask = T_RADIO | T_ANALOG_TV;
+                               goto register_client;
+                       }
+                       break;
+               case 0x60:
+                       if (tuner_symbol_probe(tea5767_autodetection,
+                                              t->i2c->adapter, t->i2c->addr)
+                                       >= 0) {
+                               t->type = TUNER_TEA5767;
+                               t->mode_mask = T_RADIO;
+                               /* Sets freq to FM range */
+                               tuner_lookup(t->i2c->adapter, &radio, &tv);
+                               if (tv)
+                                       tv->mode_mask &= ~T_RADIO;
+
+                               goto register_client;
+                       }
+                       break;
+               }
        }
+
+       /* Initializes only the first TV tuner on this adapter. Why only the
+          first? Because there are some devices (notably the ones with TI
+          tuners) that have more than one i2c address for the *same* device.
+          Experience shows that, except for just one case, the first
+          address is the right one. The exception is a Russian tuner
+          (ACORP_Y878F). So, the desired behavior is just to enable the
+          first found TV tuner. */
+       tuner_lookup(t->i2c->adapter, &radio, &tv);
+       if (tv == NULL) {
+               t->mode_mask = T_ANALOG_TV;
+               if (radio == NULL)
+                       t->mode_mask |= T_RADIO;
+               tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
+       }
+
+       /* Should be just before return */
+register_client:
+       /* Sets a default mode */
+       if (t->mode_mask & T_ANALOG_TV)
+               t->mode = V4L2_TUNER_ANALOG_TV;
+       else
+               t->mode = V4L2_TUNER_RADIO;
+       set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
+       list_add_tail(&t->list, &tuner_list);
+
+       tuner_info("Tuner %d found with type(s)%s%s.\n",
+                  t->type,
+                  t->mode_mask & T_RADIO ? " Radio" : "",
+                  t->mode_mask & T_ANALOG_TV ? " TV" : "");
+       return 0;
+}
+
+/**
+ * tuner_remove - detaches a tuner
+ *
+ * @client:    i2c_client descriptor
+ */
+
+static int tuner_remove(struct i2c_client *client)
+{
+       struct tuner *t = to_tuner(i2c_get_clientdata(client));
+
+       v4l2_device_unregister_subdev(&t->sd);
+       tuner_detach(&t->fe);
+       t->fe.analog_demod_priv = NULL;
+
+       list_del(&t->list);
+       kfree(t);
        return 0;
 }
 
-/* get more precise norm info from insmod option */
+/*
+ * Functions to switch between Radio and TV
+ *
+ * A few cards have a separate I2C tuner for radio. Those routines
+ * take care of switching between TV/Radio mode, filtering only the
+ * commands that apply to the Radio or TV tuner.
+ */
+
+/**
+ * check_mode - Verify if tuner supports the requested mode
+ * @t: a pointer to the module's internal struct_tuner
+ *
+ * This function checks if the tuner is capable of tuning analog TV,
+ * digital TV or radio, depending on what the caller wants. If the
+ * tuner can't support that mode, it returns -EINVAL. Otherwise, it
+ * returns 0.
+ * This function is needed for boards that have a separate tuner for
+ * radio (like devices with tea5767).
+ */
+static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode)
+{
+       if ((1 << mode & t->mode_mask) == 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * set_mode_freq - Switch tuner to other mode.
+ * @client:    struct i2c_client pointer
+ * @t:         a pointer to the module's internal struct_tuner
+ * @mode:      enum v4l2_type (radio or TV)
+ * @freq:      frequency to set (0 means to use the previous one)
+ *
+ * If tuner doesn't support the needed mode (radio or TV), prints a
+ * debug message and returns -EINVAL, changing its state to standby.
+ * Otherwise, changes the state and sets frequency to the last value, if
+ * the tuner can sleep or if it supports both Radio and TV.
+ */
+static int set_mode_freq(struct i2c_client *client, struct tuner *t,
+                        enum v4l2_tuner_type mode, unsigned int freq)
+{
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       if (mode != t->mode) {
+               if (check_mode(t, mode) == -EINVAL) {
+                       tuner_dbg("Tuner doesn't support mode %d. "
+                                 "Putting tuner to sleep\n", mode);
+                       t->standby = true;
+                       if (analog_ops->standby)
+                               analog_ops->standby(&t->fe);
+                       return -EINVAL;
+               }
+               t->mode = mode;
+               tuner_dbg("Changing to mode %d\n", mode);
+       }
+       if (t->mode == V4L2_TUNER_RADIO) {
+               if (freq)
+                       t->radio_freq = freq;
+               set_radio_freq(client, t->radio_freq);
+       } else {
+               if (freq)
+                       t->tv_freq = freq;
+               set_tv_freq(client, t->tv_freq);
+       }
+
+       return 0;
+}
+
+/*
+ * Functions that are specific for TV mode
+ */
+
+/**
+ * set_tv_freq - Set tuner frequency,  freq in Units of 62.5 kHz = 1/16MHz
+ *
+ * @c: i2c_client descriptor
+ * @freq: frequency
+ */
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       struct analog_parameters params = {
+               .mode      = t->mode,
+               .audmode   = t->audmode,
+               .std       = t->std
+       };
+
+       if (t->type == UNSET) {
+               tuner_warn("tuner type not set\n");
+               return;
+       }
+       if (NULL == analog_ops->set_params) {
+               tuner_warn("Tuner has no way to set tv freq\n");
+               return;
+       }
+       if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
+               tuner_dbg("TV freq (%d.%02d) out of range (%d-%d)\n",
+                          freq / 16, freq % 16 * 100 / 16, tv_range[0],
+                          tv_range[1]);
+               /* V4L2 spec: if the freq is not possible then the closest
+                  possible value should be selected */
+               if (freq < tv_range[0] * 16)
+                       freq = tv_range[0] * 16;
+               else
+                       freq = tv_range[1] * 16;
+       }
+       params.frequency = freq;
+       tuner_dbg("tv freq set to %d.%02d\n",
+                       freq / 16, freq % 16 * 100 / 16);
+       t->tv_freq = freq;
+       t->standby = false;
+
+       analog_ops->set_params(&t->fe, &params);
+}
+
+/**
+ * tuner_fixup_std - force a given video standard variant
+ *
+ * @t: tuner internal struct
+ *
+ * A few devices or drivers have problem to detect some standard variations.
+ * On other operational systems, the drivers generally have a per-country
+ * code, and some logic to apply per-country hacks. V4L2 API doesn't provide
+ * such hacks. Instead, it relies on a proper video standard selection from
+ * the userspace application. However, as some apps are buggy, not allowing
+ * to distinguish all video standard variations, a modprobe parameter can
+ * be used to force a video standard match.
+ */
 static int tuner_fixup_std(struct tuner *t)
 {
        if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
                switch (pal[0]) {
                case '6':
-                       tuner_dbg ("insmod fixup: PAL => PAL-60\n");
+                       tuner_dbg("insmod fixup: PAL => PAL-60\n");
                        t->std = V4L2_STD_PAL_60;
                        break;
                case 'b':
                case 'B':
                case 'g':
                case 'G':
-                       tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
+                       tuner_dbg("insmod fixup: PAL => PAL-BG\n");
                        t->std = V4L2_STD_PAL_BG;
                        break;
                case 'i':
                case 'I':
-                       tuner_dbg ("insmod fixup: PAL => PAL-I\n");
+                       tuner_dbg("insmod fixup: PAL => PAL-I\n");
                        t->std = V4L2_STD_PAL_I;
                        break;
                case 'd':
                case 'D':
                case 'k':
                case 'K':
-                       tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
+                       tuner_dbg("insmod fixup: PAL => PAL-DK\n");
                        t->std = V4L2_STD_PAL_DK;
                        break;
                case 'M':
                case 'm':
-                       tuner_dbg ("insmod fixup: PAL => PAL-M\n");
+                       tuner_dbg("insmod fixup: PAL => PAL-M\n");
                        t->std = V4L2_STD_PAL_M;
                        break;
                case 'N':
@@ -568,7 +865,7 @@ static int tuner_fixup_std(struct tuner *t)
                                tuner_dbg("insmod fixup: PAL => PAL-Nc\n");
                                t->std = V4L2_STD_PAL_Nc;
                        } else {
-                               tuner_dbg ("insmod fixup: PAL => PAL-N\n");
+                               tuner_dbg("insmod fixup: PAL => PAL-N\n");
                                t->std = V4L2_STD_PAL_N;
                        }
                        break;
@@ -576,7 +873,7 @@ static int tuner_fixup_std(struct tuner *t)
                        /* default parameter, do nothing */
                        break;
                default:
-                       tuner_warn ("pal= argument not recognised\n");
+                       tuner_warn("pal= argument not recognised\n");
                        break;
                }
        }
@@ -589,22 +886,24 @@ static int tuner_fixup_std(struct tuner *t)
                case 'h':
                case 'H':
                        tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n");
-                       t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+                       t->std = V4L2_STD_SECAM_B |
+                                V4L2_STD_SECAM_G |
+                                V4L2_STD_SECAM_H;
                        break;
                case 'd':
                case 'D':
                case 'k':
                case 'K':
-                       tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
+                       tuner_dbg("insmod fixup: SECAM => SECAM-DK\n");
                        t->std = V4L2_STD_SECAM_DK;
                        break;
                case 'l':
                case 'L':
-                       if ((secam[1]=='C')||(secam[1]=='c')) {
-                               tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
+                       if ((secam[1] == 'C') || (secam[1] == 'c')) {
+                               tuner_dbg("insmod fixup: SECAM => SECAM-L'\n");
                                t->std = V4L2_STD_SECAM_LC;
                        } else {
-                               tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
+                               tuner_dbg("insmod fixup: SECAM => SECAM-L\n");
                                t->std = V4L2_STD_SECAM_L;
                        }
                        break;
@@ -612,7 +911,7 @@ static int tuner_fixup_std(struct tuner *t)
                        /* default parameter, do nothing */
                        break;
                default:
-                       tuner_warn ("secam= argument not recognised\n");
+                       tuner_warn("secam= argument not recognised\n");
                        break;
                }
        }
@@ -642,9 +941,69 @@ static int tuner_fixup_std(struct tuner *t)
                        break;
                }
        }
-       return 0;
+       return 0;
+}
+
+/*
+ * Functions that are specific for Radio mode
+ */
+
+/**
+ * set_radio_freq - Set tuner frequency,  freq in Units of 62.5 Hz  = 1/16kHz
+ *
+ * @c: i2c_client descriptor
+ * @freq: frequency
+ */
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       struct analog_parameters params = {
+               .mode      = t->mode,
+               .audmode   = t->audmode,
+               .std       = t->std
+       };
+
+       if (t->type == UNSET) {
+               tuner_warn("tuner type not set\n");
+               return;
+       }
+       if (NULL == analog_ops->set_params) {
+               tuner_warn("tuner has no way to set radio frequency\n");
+               return;
+       }
+       if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
+               tuner_dbg("radio freq (%d.%02d) out of range (%d-%d)\n",
+                          freq / 16000, freq % 16000 * 100 / 16000,
+                          radio_range[0], radio_range[1]);
+               /* V4L2 spec: if the freq is not possible then the closest
+                  possible value should be selected */
+               if (freq < radio_range[0] * 16000)
+                       freq = radio_range[0] * 16000;
+               else
+                       freq = radio_range[1] * 16000;
+       }
+       params.frequency = freq;
+       tuner_dbg("radio freq set to %d.%02d\n",
+                       freq / 16000, freq % 16000 * 100 / 16000);
+       t->radio_freq = freq;
+       t->standby = false;
+
+       analog_ops->set_params(&t->fe, &params);
 }
 
+/*
+ * Debug function for reporting tuner status to userspace
+ */
+
+/**
+ * tuner_status - Dumps the current tuner status at dmesg
+ * @fe: pointer to struct dvb_frontend
+ *
+ * This callback is used only for driver debug purposes, answering to
+ * VIDIOC_LOG_STATUS. No changes should happen on this call.
+ */
 static void tuner_status(struct dvb_frontend *fe)
 {
        struct tuner *t = fe->analog_demod_priv;
@@ -654,10 +1013,16 @@ static void tuner_status(struct dvb_frontend *fe)
        const char *p;
 
        switch (t->mode) {
-               case V4L2_TUNER_RADIO:      p = "radio"; break;
-               case V4L2_TUNER_ANALOG_TV:  p = "analog TV"; break;
-               case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break;
-               default: p = "undefined"; break;
+       case V4L2_TUNER_RADIO:
+               p = "radio";
+               break;
+       case V4L2_TUNER_DIGITAL_TV:
+               p = "digital TV";
+               break;
+       case V4L2_TUNER_ANALOG_TV:
+       default:
+               p = "analog TV";
+               break;
        }
        if (t->mode == V4L2_TUNER_RADIO) {
                freq = t->radio_freq / 16000;
@@ -666,11 +1031,12 @@ static void tuner_status(struct dvb_frontend *fe)
                freq = t->tv_freq / 16;
                freq_fraction = (t->tv_freq % 16) * 100 / 16;
        }
-       tuner_info("Tuner mode:      %s\n", p);
+       tuner_info("Tuner mode:      %s%s\n", p,
+                  t->standby ? " on standby mode" : "");
        tuner_info("Frequency:       %lu.%02lu MHz\n", freq, freq_fraction);
        tuner_info("Standard:        0x%08lx\n", (unsigned long)t->std);
        if (t->mode != V4L2_TUNER_RADIO)
-              return;
+               return;
        if (fe_tuner_ops->get_status) {
                u32 tuner_status;
 
@@ -683,132 +1049,58 @@ static void tuner_status(struct dvb_frontend *fe)
        if (analog_ops->has_signal)
                tuner_info("Signal strength: %d\n",
                           analog_ops->has_signal(fe));
-       if (analog_ops->is_stereo)
-               tuner_info("Stereo:          %s\n",
-                          analog_ops->is_stereo(fe) ? "yes" : "no");
 }
 
-/* ---------------------------------------------------------------------- */
-
 /*
- * Switch tuner to other mode. If tuner support both tv and radio,
- * set another frequency to some value (This is needed for some pal
- * tuners to avoid locking). Otherwise, just put second tuner in
- * standby mode.
+ * Function to splicitly change mode to radio. Probably not needed anymore
  */
 
-static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
-{
-       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-
-       if (mode == t->mode)
-               return 0;
-
-       t->mode = mode;
-
-       if (check_mode(t, cmd) == -EINVAL) {
-               tuner_dbg("Tuner doesn't support this mode. "
-                         "Putting tuner to sleep\n");
-               t->mode = T_STANDBY;
-               if (analog_ops->standby)
-                       analog_ops->standby(&t->fe);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-#define switch_v4l2()  if (!t->using_v4l2) \
-                           tuner_dbg("switching to v4l2\n"); \
-                       t->using_v4l2 = 1;
-
-static inline int check_v4l2(struct tuner *t)
-{
-       /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for
-          TV, v4l1 for radio), until that is fixed this code is disabled.
-          Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2)
-          first. */
-       return 0;
-}
-
-static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type)
-{
-       struct tuner *t = to_tuner(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
-                       type->type,
-                       type->addr,
-                       type->mode_mask,
-                       type->config);
-
-       set_addr(client, type);
-       return 0;
-}
-
 static int tuner_s_radio(struct v4l2_subdev *sd)
 {
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL)
+       if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL)
                return 0;
-       if (t->radio_freq)
-               set_freq(client, t->radio_freq);
        return 0;
 }
 
+/*
+ * Tuner callbacks to handle userspace ioctl's
+ */
+
+/**
+ * tuner_s_power - controls the power state of the tuner
+ * @sd: pointer to struct v4l2_subdev
+ * @on: a zero value puts the tuner to sleep
+ */
 static int tuner_s_power(struct v4l2_subdev *sd, int on)
 {
        struct tuner *t = to_tuner(sd);
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
+       /* FIXME: Why this function don't wake the tuner if on != 0 ? */
        if (on)
                return 0;
 
        tuner_dbg("Putting tuner to sleep\n");
-
-       if (check_mode(t, "s_power") == -EINVAL)
-               return 0;
-       t->mode = T_STANDBY;
+       t->standby = true;
        if (analog_ops->standby)
                analog_ops->standby(&t->fe);
        return 0;
 }
 
-static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
-{
-       struct tuner *t = to_tuner(sd);
-       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
-
-       if (t->type != cfg->tuner)
-               return 0;
-
-       if (analog_ops->set_config) {
-               analog_ops->set_config(&t->fe, cfg->priv);
-               return 0;
-       }
-
-       tuner_dbg("Tuner frontend module has no way to set config\n");
-       return 0;
-}
-
-/* --- v4l ioctls --- */
-/* take care: bttv does userspace copying, we'll get a
-   kernel pointer here... */
 static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "s_std") == -EINVAL)
+       if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL)
                return 0;
 
-       switch_v4l2();
-
        t->std = std;
        tuner_fixup_std(t);
-       if (t->tv_freq)
-               set_freq(client, t->tv_freq);
+
        return 0;
 }
 
@@ -817,10 +1109,8 @@ static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (set_mode(client, t, f->type, "s_frequency") == -EINVAL)
+       if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL)
                return 0;
-       switch_v4l2();
-       set_freq(client, f->frequency);
 
        return 0;
 }
@@ -830,21 +1120,20 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
        struct tuner *t = to_tuner(sd);
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
-       if (check_mode(t, "g_frequency") == -EINVAL)
+       if (check_mode(t, f->type) == -EINVAL)
                return 0;
-       switch_v4l2();
        f->type = t->mode;
-       if (fe_tuner_ops->get_frequency) {
+       if (fe_tuner_ops->get_frequency && !t->standby) {
                u32 abs_freq;
 
                fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
                f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
                        DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
                        DIV_ROUND_CLOSEST(abs_freq, 62500);
-               return 0;
+       } else {
+               f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+                       t->radio_freq : t->tv_freq;
        }
-       f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
-               t->radio_freq : t->tv_freq;
        return 0;
 }
 
@@ -854,10 +1143,8 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
-       if (check_mode(t, "g_tuner") == -EINVAL)
+       if (check_mode(t, vt->type) == -EINVAL)
                return 0;
-       switch_v4l2();
-
        vt->type = t->mode;
        if (analog_ops->get_afc)
                vt->afc = analog_ops->get_afc(&t->fe);
@@ -870,8 +1157,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        }
 
        /* radio mode */
-       vt->rxsubchans =
-               V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
        if (fe_tuner_ops->get_status) {
                u32 tuner_status;
 
@@ -880,21 +1166,14 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
                        (tuner_status & TUNER_STATUS_STEREO) ?
                        V4L2_TUNER_SUB_STEREO :
                        V4L2_TUNER_SUB_MONO;
-       } else {
-               if (analog_ops->is_stereo) {
-                       vt->rxsubchans =
-                               analog_ops->is_stereo(&t->fe) ?
-                               V4L2_TUNER_SUB_STEREO :
-                               V4L2_TUNER_SUB_MONO;
-               }
        }
        if (analog_ops->has_signal)
                vt->signal = analog_ops->has_signal(&t->fe);
-       vt->capability |=
-               V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+       vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
        vt->audmode = t->audmode;
        vt->rangelow = radio_range[0] * 16000;
        vt->rangehigh = radio_range[1] * 16000;
+
        return 0;
 }
 
@@ -903,16 +1182,12 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        struct tuner *t = to_tuner(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (check_mode(t, "s_tuner") == -EINVAL)
+       if (set_mode_freq(client, t, vt->type, 0) == -EINVAL)
                return 0;
 
-       switch_v4l2();
+       if (t->mode == V4L2_TUNER_RADIO)
+               t->audmode = vt->audmode;
 
-       /* do nothing unless we're a radio tuner */
-       if (t->mode != V4L2_TUNER_RADIO)
-               return 0;
-       t->audmode = vt->audmode;
-       set_radio_freq(client, t->radio_freq);
        return 0;
 }
 
@@ -929,9 +1204,13 @@ static int tuner_log_status(struct v4l2_subdev *sd)
 static int tuner_suspend(struct i2c_client *c, pm_message_t state)
 {
        struct tuner *t = to_tuner(i2c_get_clientdata(c));
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        tuner_dbg("suspend\n");
-       /* FIXME: power down ??? */
+
+       if (!t->standby && analog_ops->standby)
+               analog_ops->standby(&t->fe);
+
        return 0;
 }
 
@@ -940,13 +1219,10 @@ static int tuner_resume(struct i2c_client *c)
        struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
        tuner_dbg("resume\n");
-       if (V4L2_TUNER_RADIO == t->mode) {
-               if (t->radio_freq)
-                       set_freq(c, t->radio_freq);
-       } else {
-               if (t->tv_freq)
-                       set_freq(c, t->tv_freq);
-       }
+
+       if (!t->standby)
+               set_mode_freq(c, t, t->type, 0);
+
        return 0;
 }
 
@@ -964,7 +1240,9 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
        return -ENOIOCTLCMD;
 }
 
-/* ----------------------------------------------------------------------- */
+/*
+ * Callback structs
+ */
 
 static const struct v4l2_subdev_core_ops tuner_core_ops = {
        .log_status = tuner_log_status,
@@ -987,183 +1265,10 @@ static const struct v4l2_subdev_ops tuner_ops = {
        .tuner = &tuner_tuner_ops,
 };
 
-/* ---------------------------------------------------------------------- */
-
-static LIST_HEAD(tuner_list);
-
-/* Search for existing radio and/or TV tuners on the given I2C adapter.
-   Note that when this function is called from tuner_probe you can be
-   certain no other devices will be added/deleted at the same time, I2C
-   core protects against that. */
-static void tuner_lookup(struct i2c_adapter *adap,
-               struct tuner **radio, struct tuner **tv)
-{
-       struct tuner *pos;
-
-       *radio = NULL;
-       *tv = NULL;
-
-       list_for_each_entry(pos, &tuner_list, list) {
-               int mode_mask;
-
-               if (pos->i2c->adapter != adap ||
-                   strcmp(pos->i2c->driver->driver.name, "tuner"))
-                       continue;
-
-               mode_mask = pos->mode_mask & ~T_STANDBY;
-               if (*radio == NULL && mode_mask == T_RADIO)
-                       *radio = pos;
-               /* Note: currently TDA9887 is the only demod-only
-                  device. If other devices appear then we need to
-                  make this test more general. */
-               else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
-                        (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
-                       *tv = pos;
-       }
-}
-
-/* During client attach, set_type is called by adapter's attach_inform callback.
-   set_type must then be completed by tuner_probe.
+/*
+ * I2C structs and module init functions
  */
-static int tuner_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
-{
-       struct tuner *t;
-       struct tuner *radio;
-       struct tuner *tv;
-
-       t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
-       if (NULL == t)
-               return -ENOMEM;
-       v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
-       t->i2c = client;
-       t->name = "(tuner unset)";
-       t->type = UNSET;
-       t->audmode = V4L2_TUNER_MODE_STEREO;
-       t->mode_mask = T_UNINITIALIZED;
-
-       if (show_i2c) {
-               unsigned char buffer[16];
-               int i, rc;
-
-               memset(buffer, 0, sizeof(buffer));
-               rc = i2c_master_recv(client, buffer, sizeof(buffer));
-               tuner_info("I2C RECV = ");
-               for (i = 0; i < rc; i++)
-                       printk(KERN_CONT "%02x ", buffer[i]);
-               printk("\n");
-       }
-
-       /* autodetection code based on the i2c addr */
-       if (!no_autodetect) {
-               switch (client->addr) {
-               case 0x10:
-                       if (tuner_symbol_probe(tea5761_autodetection,
-                                              t->i2c->adapter,
-                                              t->i2c->addr) >= 0) {
-                               t->type = TUNER_TEA5761;
-                               t->mode_mask = T_RADIO;
-                               t->mode = T_STANDBY;
-                               /* Sets freq to FM range */
-                               t->radio_freq = 87.5 * 16000;
-                               tuner_lookup(t->i2c->adapter, &radio, &tv);
-                               if (tv)
-                                       tv->mode_mask &= ~T_RADIO;
-
-                               goto register_client;
-                       }
-                       kfree(t);
-                       return -ENODEV;
-               case 0x42:
-               case 0x43:
-               case 0x4a:
-               case 0x4b:
-                       /* If chip is not tda8290, don't register.
-                          since it can be tda9887*/
-                       if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
-                                              t->i2c->addr) >= 0) {
-                               tuner_dbg("tda829x detected\n");
-                       } else {
-                               /* Default is being tda9887 */
-                               t->type = TUNER_TDA9887;
-                               t->mode_mask = T_RADIO | T_ANALOG_TV |
-                                              T_DIGITAL_TV;
-                               t->mode = T_STANDBY;
-                               goto register_client;
-                       }
-                       break;
-               case 0x60:
-                       if (tuner_symbol_probe(tea5767_autodetection,
-                                              t->i2c->adapter, t->i2c->addr)
-                                       >= 0) {
-                               t->type = TUNER_TEA5767;
-                               t->mode_mask = T_RADIO;
-                               t->mode = T_STANDBY;
-                               /* Sets freq to FM range */
-                               t->radio_freq = 87.5 * 16000;
-                               tuner_lookup(t->i2c->adapter, &radio, &tv);
-                               if (tv)
-                                       tv->mode_mask &= ~T_RADIO;
-
-                               goto register_client;
-                       }
-                       break;
-               }
-       }
-
-       /* Initializes only the first TV tuner on this adapter. Why only the
-          first? Because there are some devices (notably the ones with TI
-          tuners) that have more than one i2c address for the *same* device.
-          Experience shows that, except for just one case, the first
-          address is the right one. The exception is a Russian tuner
-          (ACORP_Y878F). So, the desired behavior is just to enable the
-          first found TV tuner. */
-       tuner_lookup(t->i2c->adapter, &radio, &tv);
-       if (tv == NULL) {
-               t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
-               if (radio == NULL)
-                       t->mode_mask |= T_RADIO;
-               tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
-               t->tv_freq = 400 * 16; /* Sets freq to VHF High */
-               t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-       }
 
-       /* Should be just before return */
-register_client:
-       tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
-                      client->adapter->name);
-
-       /* Sets a default mode */
-       if (t->mode_mask & T_ANALOG_TV) {
-               t->mode = V4L2_TUNER_ANALOG_TV;
-       } else  if (t->mode_mask & T_RADIO) {
-               t->mode = V4L2_TUNER_RADIO;
-       } else {
-               t->mode = V4L2_TUNER_DIGITAL_TV;
-       }
-       set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);
-       list_add_tail(&t->list, &tuner_list);
-       return 0;
-}
-
-static int tuner_remove(struct i2c_client *client)
-{
-       struct tuner *t = to_tuner(i2c_get_clientdata(client));
-
-       v4l2_device_unregister_subdev(&t->sd);
-       tuner_detach(&t->fe);
-       t->fe.analog_demod_priv = NULL;
-
-       list_del(&t->list);
-       kfree(t);
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* This driver supports many devices and the idea is to let the driver
-   detect which device is present. So rather than listing all supported
-   devices here, we pretend to support a single, fake device type. */
 static const struct i2c_device_id tuner_id[] = {
        { "tuner", }, /* autodetect */
        { }
@@ -1196,10 +1301,6 @@ static __exit void exit_tuner(void)
 module_init(init_tuner);
 module_exit(exit_tuner);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
index 45bcf0358a1d20a002f0a82ef964a7c85663d42a..9b3e828b0775fc6e4bd1f1b3077128d49f40545f 100644 (file)
@@ -37,6 +37,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tvp514x.h>
 
 #include "tvp514x_regs.h"
@@ -97,6 +98,7 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
  */
 struct tvp514x_decoder {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
        const struct tvp514x_platform_data *pdata;
 
@@ -238,6 +240,11 @@ static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
        return container_of(sd, struct tvp514x_decoder, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd;
+}
+
 
 /**
  * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
@@ -718,214 +725,55 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
        return 0;
 }
 
-/**
- * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @qctrl: standard V4L2 v4l2_queryctrl structure
- *
- * If the requested control is supported, returns the control information.
- * Otherwise, returns -EINVAL if the control is not supported.
- */
-static int
-tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
-{
-       int err = -EINVAL;
-
-       if (qctrl == NULL)
-               return err;
-
-       switch (qctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               /* Brightness supported is (0-255), */
-               err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
-               break;
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-               /**
-                * Saturation and Contrast supported is -
-                *      Contrast: 0 - 255 (Default - 128)
-                *      Saturation: 0 - 255 (Default - 128)
-                */
-               err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
-               break;
-       case V4L2_CID_HUE:
-               /* Hue Supported is -
-                *      Hue - -180 - +180 (Default - 0, Step - +180)
-                */
-               err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
-               break;
-       case V4L2_CID_AUTOGAIN:
-               /**
-                * Auto Gain supported is -
-                *      0 - 1 (Default - 1)
-                */
-               err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
-               break;
-       default:
-               v4l2_err(sd, "invalid control id %d\n", qctrl->id);
-               return err;
-       }
-
-       v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n",
-                       qctrl->name, qctrl->minimum, qctrl->maximum,
-                       qctrl->default_value);
-
-       return err;
-}
-
-/**
- * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @ctrl: pointer to v4l2_control structure
- *
- * If the requested control is supported, returns the control's current
- * value from the decoder. Otherwise, returns -EINVAL if the control is not
- * supported.
- */
-static int
-tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct tvp514x_decoder *decoder = to_decoder(sd);
-
-       if (ctrl == NULL)
-               return -EINVAL;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
-               break;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
-               break;
-       case V4L2_CID_SATURATION:
-               ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
-               break;
-       case V4L2_CID_HUE:
-               ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
-               if (ctrl->value == 0x7F)
-                       ctrl->value = 180;
-               else if (ctrl->value == 0x80)
-                       ctrl->value = -180;
-               else
-                       ctrl->value = 0;
-
-               break;
-       case V4L2_CID_AUTOGAIN:
-               ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
-               if ((ctrl->value & 0x3) == 3)
-                       ctrl->value = 1;
-               else
-                       ctrl->value = 0;
-
-               break;
-       default:
-               v4l2_err(sd, "invalid control id %d\n", ctrl->id);
-               return -EINVAL;
-       }
-
-       v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n",
-                       ctrl->id, ctrl->value);
-       return 0;
-}
-
 /**
  * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @ctrl: pointer to v4l2_control structure
+ * @ctrl: pointer to v4l2_ctrl structure
  *
  * If the requested control is supported, sets the control's current
  * value in HW. Otherwise, returns -EINVAL if the control is not supported.
  */
-static int
-tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct v4l2_subdev *sd = to_sd(ctrl);
        struct tvp514x_decoder *decoder = to_decoder(sd);
        int err = -EINVAL, value;
 
-       if (ctrl == NULL)
-               return err;
-
-       value = ctrl->value;
+       value = ctrl->val;
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               if (ctrl->value < 0 || ctrl->value > 255) {
-                       v4l2_err(sd, "invalid brightness setting %d\n",
-                                       ctrl->value);
-                       return -ERANGE;
-               }
-               err = tvp514x_write_reg(sd, REG_BRIGHTNESS,
-                               value);
-               if (err)
-                       return err;
-
-               decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
+               err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value);
+               if (!err)
+                       decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
                break;
        case V4L2_CID_CONTRAST:
-               if (ctrl->value < 0 || ctrl->value > 255) {
-                       v4l2_err(sd, "invalid contrast setting %d\n",
-                                       ctrl->value);
-                       return -ERANGE;
-               }
                err = tvp514x_write_reg(sd, REG_CONTRAST, value);
-               if (err)
-                       return err;
-
-               decoder->tvp514x_regs[REG_CONTRAST].val = value;
+               if (!err)
+                       decoder->tvp514x_regs[REG_CONTRAST].val = value;
                break;
        case V4L2_CID_SATURATION:
-               if (ctrl->value < 0 || ctrl->value > 255) {
-                       v4l2_err(sd, "invalid saturation setting %d\n",
-                                       ctrl->value);
-                       return -ERANGE;
-               }
                err = tvp514x_write_reg(sd, REG_SATURATION, value);
-               if (err)
-                       return err;
-
-               decoder->tvp514x_regs[REG_SATURATION].val = value;
+               if (!err)
+                       decoder->tvp514x_regs[REG_SATURATION].val = value;
                break;
        case V4L2_CID_HUE:
                if (value == 180)
                        value = 0x7F;
                else if (value == -180)
                        value = 0x80;
-               else if (value == 0)
-                       value = 0;
-               else {
-                       v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
-                       return -ERANGE;
-               }
                err = tvp514x_write_reg(sd, REG_HUE, value);
-               if (err)
-                       return err;
-
-               decoder->tvp514x_regs[REG_HUE].val = value;
+               if (!err)
+                       decoder->tvp514x_regs[REG_HUE].val = value;
                break;
        case V4L2_CID_AUTOGAIN:
-               if (value == 1)
-                       value = 0x0F;
-               else if (value == 0)
-                       value = 0x0C;
-               else {
-                       v4l2_err(sd, "invalid auto gain setting %d\n",
-                                       ctrl->value);
-                       return -ERANGE;
-               }
-               err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value);
-               if (err)
-                       return err;
-
-               decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
+               err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c);
+               if (!err)
+                       decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
                break;
-       default:
-               v4l2_err(sd, "invalid control id %d\n", ctrl->id);
-               return err;
        }
 
        v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
-                       ctrl->id, ctrl->value);
-
+                       ctrl->id, ctrl->val);
        return err;
 }
 
@@ -1104,10 +952,18 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
        return err;
 }
 
-static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
-       .queryctrl = tvp514x_queryctrl,
-       .g_ctrl = tvp514x_g_ctrl,
+static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
        .s_ctrl = tvp514x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = tvp514x_s_std,
 };
 
@@ -1190,6 +1046,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
        sd = &decoder->sd;
        v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
 
+       v4l2_ctrl_handler_init(&decoder->hdl, 5);
+       v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+               V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+               V4L2_CID_CONTRAST, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+               V4L2_CID_SATURATION, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+               V4L2_CID_HUE, -180, 180, 180, 0);
+       v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+               V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       sd->ctrl_handler = &decoder->hdl;
+       if (decoder->hdl.error) {
+               int err = decoder->hdl.error;
+
+               v4l2_ctrl_handler_free(&decoder->hdl);
+               kfree(decoder);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&decoder->hdl);
+
        v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
 
        return 0;
@@ -1209,6 +1086,7 @@ static int tvp514x_remove(struct i2c_client *client)
        struct tvp514x_decoder *decoder = to_decoder(sd);
 
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&decoder->hdl);
        kfree(decoder);
        return 0;
 }
index 58927664d3ea17250027e354fb5e5fa8aaa1d775..e927d25e0d35b431a38140340cfcfac7dd57f572 100644 (file)
@@ -12,6 +12,7 @@
 #include <media/v4l2-device.h>
 #include <media/tvp5150.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #include "tvp5150_reg.h"
 
@@ -24,58 +25,14 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
-/* supported controls */
-static struct v4l2_queryctrl tvp5150_qctrl[] = {
-       {
-               .id = V4L2_CID_BRIGHTNESS,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Brightness",
-               .minimum = 0,
-               .maximum = 255,
-               .step = 1,
-               .default_value = 128,
-               .flags = 0,
-       }, {
-               .id = V4L2_CID_CONTRAST,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Contrast",
-               .minimum = 0,
-               .maximum = 255,
-               .step = 0x1,
-               .default_value = 128,
-               .flags = 0,
-       }, {
-                .id = V4L2_CID_SATURATION,
-                .type = V4L2_CTRL_TYPE_INTEGER,
-                .name = "Saturation",
-                .minimum = 0,
-                .maximum = 255,
-                .step = 0x1,
-                .default_value = 128,
-                .flags = 0,
-       }, {
-               .id = V4L2_CID_HUE,
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "Hue",
-               .minimum = -128,
-               .maximum = 127,
-               .step = 0x1,
-               .default_value = 0,
-               .flags = 0,
-       }
-};
-
 struct tvp5150 {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
 
        v4l2_std_id norm;       /* Current set standard */
        u32 input;
        u32 output;
        int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
 static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
@@ -83,6 +40,11 @@ static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
        return container_of(sd, struct tvp5150, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
+}
+
 static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
 {
        struct i2c_client *c = v4l2_get_subdevdata(sd);
@@ -775,27 +737,6 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
-       u8 msb_id, lsb_id, msb_rom, lsb_rom;
-
-       msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
-       lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
-       msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
-       lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
-
-       if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
-               v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);
-
-               /* ITU-T BT.656.4 timing */
-               tvp5150_write(sd, TVP5150_REV_SELECT, 0);
-       } else {
-               if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
-                       v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
-               } else {
-                       v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
-                                       msb_id, lsb_id);
-                       v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
-               }
-       }
 
        /* Initializes TVP5150 to its default values */
        tvp5150_write_inittab(sd, tvp5150_init_default);
@@ -810,64 +751,28 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
        tvp5150_write_inittab(sd, tvp5150_init_enable);
 
        /* Initialize image preferences */
-       tvp5150_write(sd, TVP5150_BRIGHT_CTL, decoder->bright);
-       tvp5150_write(sd, TVP5150_CONTRAST_CTL, decoder->contrast);
-       tvp5150_write(sd, TVP5150_SATURATION_CTL, decoder->contrast);
-       tvp5150_write(sd, TVP5150_HUE_CTL, decoder->hue);
+       v4l2_ctrl_handler_setup(&decoder->hdl);
 
        tvp5150_set_std(sd, decoder->norm);
        return 0;
 };
 
-static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       v4l2_dbg(1, debug, sd, "g_ctrl called\n");
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = tvp5150_read(sd, TVP5150_BRIGHT_CTL);
-               return 0;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = tvp5150_read(sd, TVP5150_CONTRAST_CTL);
-               return 0;
-       case V4L2_CID_SATURATION:
-               ctrl->value = tvp5150_read(sd, TVP5150_SATURATION_CTL);
-               return 0;
-       case V4L2_CID_HUE:
-               ctrl->value = tvp5150_read(sd, TVP5150_HUE_CTL);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       u8 i, n;
-       n = ARRAY_SIZE(tvp5150_qctrl);
-
-       for (i = 0; i < n; i++) {
-               if (ctrl->id != tvp5150_qctrl[i].id)
-                       continue;
-               if (ctrl->value < tvp5150_qctrl[i].minimum ||
-                   ctrl->value > tvp5150_qctrl[i].maximum)
-                       return -ERANGE;
-               v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
-                                       ctrl->id, ctrl->value);
-               break;
-       }
+       struct v4l2_subdev *sd = to_sd(ctrl);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
                return 0;
        case V4L2_CID_CONTRAST:
-               tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
                return 0;
        case V4L2_CID_SATURATION:
-               tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
                return 0;
        case V4L2_CID_HUE:
-               tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
                return 0;
        }
        return -EINVAL;
@@ -995,29 +900,21 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        return 0;
 }
 
-static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       v4l2_dbg(1, debug, sd, "queryctrl called\n");
-
-       for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
-               if (qc->id && qc->id == tvp5150_qctrl[i].id) {
-                       memcpy(qc, &(tvp5150_qctrl[i]),
-                              sizeof(*qc));
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
+       .s_ctrl = tvp5150_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
        .log_status = tvp5150_log_status,
-       .g_ctrl = tvp5150_g_ctrl,
-       .s_ctrl = tvp5150_s_ctrl,
-       .queryctrl = tvp5150_queryctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = tvp5150_s_std,
        .reset = tvp5150_reset,
        .g_chip_ident = tvp5150_g_chip_ident,
@@ -1059,6 +956,7 @@ static int tvp5150_probe(struct i2c_client *c,
 {
        struct tvp5150 *core;
        struct v4l2_subdev *sd;
+       u8 msb_id, lsb_id, msb_rom, lsb_rom;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(c->adapter,
@@ -1074,13 +972,48 @@ static int tvp5150_probe(struct i2c_client *c,
        v4l_info(c, "chip found @ 0x%02x (%s)\n",
                 c->addr << 1, c->adapter->name);
 
+       msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
+       lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
+       msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
+       lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
+
+       if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
+               v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);
+
+               /* ITU-T BT.656.4 timing */
+               tvp5150_write(sd, TVP5150_REV_SELECT, 0);
+       } else {
+               if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
+                       v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
+               } else {
+                       v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
+                                       msb_id, lsb_id);
+                       v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
+               }
+       }
+
        core->norm = V4L2_STD_ALL;      /* Default is autodetect */
        core->input = TVP5150_COMPOSITE1;
        core->enable = 1;
-       core->bright = 128;
-       core->contrast = 128;
-       core->hue = 0;
-       core->sat = 128;
+
+       v4l2_ctrl_handler_init(&core->hdl, 4);
+       v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       sd->ctrl_handler = &core->hdl;
+       if (core->hdl.error) {
+               int err = core->hdl.error;
+
+               v4l2_ctrl_handler_free(&core->hdl);
+               kfree(core);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&core->hdl);
 
        if (debug > 1)
                tvp5150_log_status(sd);
@@ -1090,12 +1023,14 @@ static int tvp5150_probe(struct i2c_client *c,
 static int tvp5150_remove(struct i2c_client *c)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(c);
+       struct tvp5150 *decoder = to_tvp5150(sd);
 
        v4l2_dbg(1, debug, sd,
                "tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
                c->addr << 1);
 
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&decoder->hdl);
        kfree(to_tvp5150(sd));
        return 0;
 }
index c799e4eb6fcd1ac6710e9a13c896c25d163c268f..b799851bf3d0be20abfd593a6cf98d8b131e49ab 100644 (file)
@@ -32,6 +32,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
 #include "tvp7002_reg.h"
 
 MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
@@ -421,13 +422,13 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
 /* Device definition */
 struct tvp7002 {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        const struct tvp7002_config *pdata;
 
        int ver;
        int streaming;
 
        const struct tvp7002_preset_definition *current_preset;
-       u8 gain;
 };
 
 /*
@@ -441,6 +442,11 @@ static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd)
        return container_of(sd, struct tvp7002, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct tvp7002, hdl)->sd;
+}
+
 /*
  * tvp7002_read - Read a value from a register in an TVP7002
  * @sd: ptr to v4l2_subdev struct
@@ -605,79 +611,26 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
        return -EINVAL;
 }
 
-/*
- * tvp7002_g_ctrl() - Get a control
- * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_control struct
- *
- * Get a control for a TVP7002 decoder device.
- * Returns zero when successful or -EINVAL if register access fails.
- */
-static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct tvp7002 *device = to_tvp7002(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               ctrl->value = device->gain;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
 /*
  * tvp7002_s_ctrl() - Set a control
- * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_control struct
+ * @ctrl: ptr to v4l2_ctrl struct
  *
  * Set a control in TVP7002 decoder device.
  * Returns zero when successful or -EINVAL if register access fails.
  */
-static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct tvp7002 *device = to_tvp7002(sd);
+       struct v4l2_subdev *sd = to_sd(ctrl);
        int error = 0;
 
        switch (ctrl->id) {
        case V4L2_CID_GAIN:
-               tvp7002_write_err(sd, TVP7002_R_FINE_GAIN,
-                                               ctrl->value & 0xff, &error);
-               tvp7002_write_err(sd, TVP7002_G_FINE_GAIN,
-                                               ctrl->value & 0xff, &error);
-               tvp7002_write_err(sd, TVP7002_B_FINE_GAIN,
-                                               ctrl->value & 0xff, &error);
-
-               if (error < 0)
-                       return error;
-
-               /* Set only after knowing there is no error */
-               device->gain = ctrl->value & 0xff;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-/*
- * tvp7002_queryctrl() - Query a control
- * @sd: ptr to v4l2_subdev struct
- * @qc: ptr to v4l2_queryctrl struct
- *
- * Query a control of a TVP7002 decoder device.
- * Returns zero when successful or -EINVAL if register read fails.
- */
-static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_GAIN:
-               /*
-                * Gain is supported [0-255, default=0, step=1]
-                */
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
-       default:
-               return -EINVAL;
+               tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, ctrl->val, &error);
+               tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, ctrl->val, &error);
+               tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, ctrl->val, &error);
+               return error;
        }
+       return -EINVAL;
 }
 
 /*
@@ -924,7 +877,7 @@ static int tvp7002_log_status(struct v4l2_subdev *sd)
                                        device->streaming ? "yes" : "no");
 
        /* Print the current value of the gain control */
-       v4l2_info(sd, "Gain: %u\n", device->gain);
+       v4l2_ctrl_handler_log_status(&device->hdl, sd->name);
 
        return 0;
 }
@@ -946,13 +899,21 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
        return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
 }
 
+static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
+       .s_ctrl = tvp7002_s_ctrl,
+};
+
 /* V4L2 core operation handlers */
 static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
        .g_chip_ident = tvp7002_g_chip_ident,
        .log_status = tvp7002_log_status,
-       .g_ctrl = tvp7002_g_ctrl,
-       .s_ctrl = tvp7002_s_ctrl,
-       .queryctrl = tvp7002_queryctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = tvp7002_g_register,
        .s_register = tvp7002_s_register,
@@ -977,12 +938,6 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
        .video = &tvp7002_video_ops,
 };
 
-static struct tvp7002 tvp7002_dev = {
-       .streaming = 0,
-       .current_preset = tvp7002_presets,
-       .gain = 0,
-};
-
 /*
  * tvp7002_probe - Probe a TVP7002 device
  * @c: ptr to i2c_client struct
@@ -1013,14 +968,14 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
                return -ENODEV;
        }
 
-       device = kmalloc(sizeof(struct tvp7002), GFP_KERNEL);
+       device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL);
 
        if (!device)
                return -ENOMEM;
 
-       *device = tvp7002_dev;
        sd = &device->sd;
        device->pdata = c->dev.platform_data;
+       device->current_preset = tvp7002_presets;
 
        /* Tell v4l2 the device is ready */
        v4l2_i2c_subdev_init(sd, c, &tvp7002_ops);
@@ -1060,6 +1015,19 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
        preset.preset = device->current_preset->preset;
        error = tvp7002_s_dv_preset(sd, &preset);
 
+       v4l2_ctrl_handler_init(&device->hdl, 1);
+       v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 255, 1, 0);
+       sd->ctrl_handler = &device->hdl;
+       if (device->hdl.error) {
+               int err = device->hdl.error;
+
+               v4l2_ctrl_handler_free(&device->hdl);
+               kfree(device);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&device->hdl);
+
 found_error:
        if (error < 0)
                kfree(device);
@@ -1083,6 +1051,7 @@ static int tvp7002_remove(struct i2c_client *c)
                                "on address 0x%x\n", c->addr);
 
        v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(&device->hdl);
        kfree(device);
        return 0;
 }
index a1e9dfb52f6986fc189279f1b3d03e6927124a61..6459b8cba22384f88a04e28fb3e7cb6964d9d882 100644 (file)
@@ -1264,6 +1264,14 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
 
                break;
 
+       case UVC_OTT_VENDOR_SPECIFIC:
+       case UVC_OTT_DISPLAY:
+       case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+               if (uvc_trace_param & UVC_TRACE_PROBE)
+                       printk(" OT %d", entity->id);
+
+               break;
+
        case UVC_TT_STREAMING:
                if (UVC_ENTITY_IS_ITERM(entity)) {
                        if (uvc_trace_param & UVC_TRACE_PROBE)
index 5673d673504b838f510966c31c46c078da032bdd..545c0294813d9bb9a9293e61792236d396b1bbc3 100644 (file)
@@ -89,15 +89,19 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
 static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
        struct uvc_streaming_control *ctrl)
 {
-       struct uvc_format *format;
+       struct uvc_format *format = NULL;
        struct uvc_frame *frame = NULL;
        unsigned int i;
 
-       if (ctrl->bFormatIndex <= 0 ||
-           ctrl->bFormatIndex > stream->nformats)
-               return;
+       for (i = 0; i < stream->nformats; ++i) {
+               if (stream->format[i].index == ctrl->bFormatIndex) {
+                       format = &stream->format[i];
+                       break;
+               }
+       }
 
-       format = &stream->format[ctrl->bFormatIndex - 1];
+       if (format == NULL)
+               return;
 
        for (i = 0; i < format->nframes; ++i) {
                if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
index 810eef43c216b86e153ad5b08fe8a432f2609986..06b9f9f82013c33b1c61e812038aa3bd660469ad 100644 (file)
@@ -59,7 +59,6 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/div64.h>
-#define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
@@ -81,69 +80,6 @@ MODULE_LICENSE("GPL");
  *  Video Standard Operations (contributed by Michael Schimek)
  */
 
-
-/* ----------------------------------------------------------------- */
-/* priority handling                                                 */
-
-#define V4L2_PRIO_VALID(val) (val == V4L2_PRIORITY_BACKGROUND   || \
-                             val == V4L2_PRIORITY_INTERACTIVE  || \
-                             val == V4L2_PRIORITY_RECORD)
-
-void v4l2_prio_init(struct v4l2_prio_state *global)
-{
-       memset(global, 0, sizeof(*global));
-}
-EXPORT_SYMBOL(v4l2_prio_init);
-
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
-                    enum v4l2_priority new)
-{
-       if (!V4L2_PRIO_VALID(new))
-               return -EINVAL;
-       if (*local == new)
-               return 0;
-
-       atomic_inc(&global->prios[new]);
-       if (V4L2_PRIO_VALID(*local))
-               atomic_dec(&global->prios[*local]);
-       *local = new;
-       return 0;
-}
-EXPORT_SYMBOL(v4l2_prio_change);
-
-void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
-{
-       v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
-}
-EXPORT_SYMBOL(v4l2_prio_open);
-
-void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
-{
-       if (V4L2_PRIO_VALID(local))
-               atomic_dec(&global->prios[local]);
-}
-EXPORT_SYMBOL(v4l2_prio_close);
-
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
-{
-       if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0)
-               return V4L2_PRIORITY_RECORD;
-       if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0)
-               return V4L2_PRIORITY_INTERACTIVE;
-       if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0)
-               return V4L2_PRIORITY_BACKGROUND;
-       return V4L2_PRIORITY_UNSET;
-}
-EXPORT_SYMBOL(v4l2_prio_max);
-
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
-{
-       return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
-}
-EXPORT_SYMBOL(v4l2_prio_check);
-
-/* ----------------------------------------------------------------- */
-
 /* Helper functions for control handling                            */
 
 /* Check for correctness of the ctrl's value based on the data from
index dc82eb83c1d4de590a33eb9b9c90ee61a9069e21..7c2694738b312db94557c0e342e97872124adc8d 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/compat.h>
-#define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <media/v4l2-ioctl.h>
@@ -97,6 +96,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
        return 0;
 }
 
+static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+                               struct v4l2_pix_format_mplane __user *up)
+{
+       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+               return -EFAULT;
+       return 0;
+}
+
 static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
 {
        if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
@@ -104,6 +111,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
        return 0;
 }
 
+static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+                               struct v4l2_pix_format_mplane __user *up)
+{
+       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+               return -EFAULT;
+       return 0;
+}
+
 static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
 {
        if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
@@ -136,6 +151,7 @@ struct v4l2_format32 {
        enum v4l2_buf_type type;
        union {
                struct v4l2_pix_format  pix;
+               struct v4l2_pix_format_mplane   pix_mp;
                struct v4l2_window32    win;
                struct v4l2_vbi_format  vbi;
                struct v4l2_sliced_vbi_format   sliced;
@@ -152,6 +168,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+                                                 &up->fmt.pix_mp);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -181,6 +201,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+                                                 &up->fmt.pix_mp);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -232,6 +256,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
        return 0;
 }
 
+struct v4l2_plane32 {
+       __u32                   bytesused;
+       __u32                   length;
+       union {
+               __u32           mem_offset;
+               compat_long_t   userptr;
+       } m;
+       __u32                   data_offset;
+       __u32                   reserved[11];
+};
+
 struct v4l2_buffer32 {
        __u32                   index;
        enum v4l2_buf_type      type;
@@ -247,14 +282,64 @@ struct v4l2_buffer32 {
        union {
                __u32           offset;
                compat_long_t   userptr;
+               compat_caddr_t  planes;
        } m;
        __u32                   length;
        __u32                   input;
        __u32                   reserved;
 };
 
+static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+                               enum v4l2_memory memory)
+{
+       void __user *up_pln;
+       compat_long_t p;
+
+       if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+               copy_in_user(&up->data_offset, &up32->data_offset,
+                               sizeof(__u32)))
+               return -EFAULT;
+
+       if (memory == V4L2_MEMORY_USERPTR) {
+               if (get_user(p, &up32->m.userptr))
+                       return -EFAULT;
+               up_pln = compat_ptr(p);
+               if (put_user((unsigned long)up_pln, &up->m.userptr))
+                       return -EFAULT;
+       } else {
+               if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+                                       sizeof(__u32)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+                               enum v4l2_memory memory)
+{
+       if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+               copy_in_user(&up32->data_offset, &up->data_offset,
+                               sizeof(__u32)))
+               return -EFAULT;
+
+       /* For MMAP, driver might've set up the offset, so copy it back.
+        * USERPTR stays the same (was userspace-provided), so no copying. */
+       if (memory == V4L2_MEMORY_MMAP)
+               if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+                                       sizeof(__u32)))
+                       return -EFAULT;
+
+       return 0;
+}
+
 static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
 {
+       struct v4l2_plane32 __user *uplane32;
+       struct v4l2_plane __user *uplane;
+       compat_caddr_t p;
+       int num_planes;
+       int ret;
 
        if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
                get_user(kp->index, &up->index) ||
@@ -263,33 +348,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                get_user(kp->memory, &up->memory) ||
                get_user(kp->input, &up->input))
                        return -EFAULT;
-       switch (kp->memory) {
-       case V4L2_MEMORY_MMAP:
-               if (get_user(kp->length, &up->length) ||
-                       get_user(kp->m.offset, &up->m.offset))
+
+       if (V4L2_TYPE_IS_OUTPUT(kp->type))
+               if (get_user(kp->bytesused, &up->bytesused) ||
+                       get_user(kp->field, &up->field) ||
+                       get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+                       get_user(kp->timestamp.tv_usec,
+                                       &up->timestamp.tv_usec))
                        return -EFAULT;
-               break;
-       case V4L2_MEMORY_USERPTR:
-               {
-               compat_long_t tmp;
 
-               if (get_user(kp->length, &up->length) ||
-                   get_user(tmp, &up->m.userptr))
+       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+               if (get_user(kp->length, &up->length))
                        return -EFAULT;
 
-               kp->m.userptr = (unsigned long)compat_ptr(tmp);
+               num_planes = kp->length;
+               if (num_planes == 0) {
+                       kp->m.planes = NULL;
+                       /* num_planes == 0 is legal, e.g. when userspace doesn't
+                        * need planes array on DQBUF*/
+                       return 0;
                }
-               break;
-       case V4L2_MEMORY_OVERLAY:
-               if (get_user(kp->m.offset, &up->m.offset))
+
+               if (get_user(p, &up->m.planes))
                        return -EFAULT;
-               break;
+
+               uplane32 = compat_ptr(p);
+               if (!access_ok(VERIFY_READ, uplane32,
+                               num_planes * sizeof(struct v4l2_plane32)))
+                       return -EFAULT;
+
+               /* We don't really care if userspace decides to kill itself
+                * by passing a very big num_planes value */
+               uplane = compat_alloc_user_space(num_planes *
+                                               sizeof(struct v4l2_plane));
+               kp->m.planes = uplane;
+
+               while (--num_planes >= 0) {
+                       ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+                       if (ret)
+                               return ret;
+                       ++uplane;
+                       ++uplane32;
+               }
+       } else {
+               switch (kp->memory) {
+               case V4L2_MEMORY_MMAP:
+                       if (get_user(kp->length, &up->length) ||
+                               get_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+               case V4L2_MEMORY_USERPTR:
+                       {
+                       compat_long_t tmp;
+
+                       if (get_user(kp->length, &up->length) ||
+                           get_user(tmp, &up->m.userptr))
+                               return -EFAULT;
+
+                       kp->m.userptr = (unsigned long)compat_ptr(tmp);
+                       }
+                       break;
+               case V4L2_MEMORY_OVERLAY:
+                       if (get_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+               }
        }
+
        return 0;
 }
 
 static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
 {
+       struct v4l2_plane32 __user *uplane32;
+       struct v4l2_plane __user *uplane;
+       compat_caddr_t p;
+       int num_planes;
+       int ret;
+
        if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
                put_user(kp->index, &up->index) ||
                put_user(kp->type, &up->type) ||
@@ -297,22 +433,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                put_user(kp->memory, &up->memory) ||
                put_user(kp->input, &up->input))
                        return -EFAULT;
-       switch (kp->memory) {
-       case V4L2_MEMORY_MMAP:
-               if (put_user(kp->length, &up->length) ||
-                       put_user(kp->m.offset, &up->m.offset))
-                       return -EFAULT;
-               break;
-       case V4L2_MEMORY_USERPTR:
-               if (put_user(kp->length, &up->length) ||
-                       put_user(kp->m.userptr, &up->m.userptr))
-                       return -EFAULT;
-               break;
-       case V4L2_MEMORY_OVERLAY:
-               if (put_user(kp->m.offset, &up->m.offset))
-                       return -EFAULT;
-               break;
-       }
+
        if (put_user(kp->bytesused, &up->bytesused) ||
                put_user(kp->field, &up->field) ||
                put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
@@ -321,6 +442,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                put_user(kp->sequence, &up->sequence) ||
                put_user(kp->reserved, &up->reserved))
                        return -EFAULT;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+               num_planes = kp->length;
+               if (num_planes == 0)
+                       return 0;
+
+               uplane = kp->m.planes;
+               if (get_user(p, &up->m.planes))
+                       return -EFAULT;
+               uplane32 = compat_ptr(p);
+
+               while (--num_planes >= 0) {
+                       ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+                       if (ret)
+                               return ret;
+                       ++uplane;
+                       ++uplane32;
+               }
+       } else {
+               switch (kp->memory) {
+               case V4L2_MEMORY_MMAP:
+                       if (put_user(kp->length, &up->length) ||
+                               put_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+               case V4L2_MEMORY_USERPTR:
+                       if (put_user(kp->length, &up->length) ||
+                               put_user(kp->m.userptr, &up->m.userptr))
+                               return -EFAULT;
+                       break;
+               case V4L2_MEMORY_OVERLAY:
+                       if (put_user(kp->m.offset, &up->m.offset))
+                               return -EFAULT;
+                       break;
+               }
+       }
+
        return 0;
 }
 
@@ -442,12 +600,13 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
+       if (!access_ok(VERIFY_READ, ucontrols,
+                       n * sizeof(struct v4l2_ext_control32)))
                return -EFAULT;
        kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
        kp->controls = kcontrols;
        while (--n >= 0) {
-               if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
+               if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
                        return -EFAULT;
                if (ctrl_is_pointer(kcontrols->id)) {
                        void __user *s;
@@ -483,7 +642,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
+       if (!access_ok(VERIFY_WRITE, ucontrols,
+                       n * sizeof(struct v4l2_ext_control32)))
                return -EFAULT;
 
        while (--n >= 0) {
@@ -517,9 +677,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
 
 #define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
-#ifdef __OLD_VIDIOC_
-#define VIDIOC_OVERLAY32_OLD   _IOWR('V', 14, s32)
-#endif
 #define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
 #define VIDIOC_STREAMOFF32     _IOW ('V', 19, s32)
 #define VIDIOC_G_INPUT32       _IOR ('V', 38, s32)
@@ -559,9 +716,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
-#ifdef __OLD_VIDIOC_
-       case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
-#endif
        case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
        case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
        case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
@@ -695,14 +849,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
                return ret;
 
        switch (cmd) {
-#ifdef __OLD_VIDIOC_
-       case VIDIOC_OVERLAY32_OLD:
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_G_AUDIO_OLD:
-       case VIDIOC_G_AUDOUT_OLD:
-       case VIDIOC_CROPCAP_OLD:
-#endif
        case VIDIOC_QUERYCAP:
        case VIDIOC_RESERVED:
        case VIDIOC_ENUM_FMT:
index ef66d2af0c57c8adea19be12ad78e2b1c754883b..2412f08527aa8e014a440971b7ade207ecd1b233 100644 (file)
@@ -1364,6 +1364,8 @@ EXPORT_SYMBOL(v4l2_queryctrl);
 
 int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
+       if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL)
+               return -EINVAL;
        return v4l2_queryctrl(sd->ctrl_handler, qc);
 }
 EXPORT_SYMBOL(v4l2_subdev_queryctrl);
index 341764a3a990e4cfb4c815aa7f41658ec92d82dd..498e6742579e76bb400f79af9dac37d1d7fe10b4 100644 (file)
@@ -143,6 +143,7 @@ static inline void video_put(struct video_device *vdev)
 static void v4l2_device_release(struct device *cd)
 {
        struct video_device *vdev = to_video_device(cd);
+       struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
 
        mutex_lock(&videodev_lock);
        if (video_device[vdev->minor] != vdev) {
@@ -169,6 +170,10 @@ static void v4l2_device_release(struct device *cd)
        /* Release video_device and perform other
           cleanups as needed. */
        vdev->release(vdev);
+
+       /* Decrease v4l2_device refcount */
+       if (v4l2_dev)
+               v4l2_device_put(v4l2_dev);
 }
 
 static struct class video_class = {
@@ -182,6 +187,70 @@ struct video_device *video_devdata(struct file *file)
 }
 EXPORT_SYMBOL(video_devdata);
 
+
+/* Priority handling */
+
+static inline bool prio_is_valid(enum v4l2_priority prio)
+{
+       return prio == V4L2_PRIORITY_BACKGROUND ||
+              prio == V4L2_PRIORITY_INTERACTIVE ||
+              prio == V4L2_PRIORITY_RECORD;
+}
+
+void v4l2_prio_init(struct v4l2_prio_state *global)
+{
+       memset(global, 0, sizeof(*global));
+}
+EXPORT_SYMBOL(v4l2_prio_init);
+
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+                    enum v4l2_priority new)
+{
+       if (!prio_is_valid(new))
+               return -EINVAL;
+       if (*local == new)
+               return 0;
+
+       atomic_inc(&global->prios[new]);
+       if (prio_is_valid(*local))
+               atomic_dec(&global->prios[*local]);
+       *local = new;
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_prio_change);
+
+void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
+{
+       v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
+}
+EXPORT_SYMBOL(v4l2_prio_open);
+
+void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
+{
+       if (prio_is_valid(local))
+               atomic_dec(&global->prios[local]);
+}
+EXPORT_SYMBOL(v4l2_prio_close);
+
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
+{
+       if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0)
+               return V4L2_PRIORITY_RECORD;
+       if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0)
+               return V4L2_PRIORITY_INTERACTIVE;
+       if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0)
+               return V4L2_PRIORITY_BACKGROUND;
+       return V4L2_PRIORITY_UNSET;
+}
+EXPORT_SYMBOL(v4l2_prio_max);
+
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
+{
+       return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
+}
+EXPORT_SYMBOL(v4l2_prio_check);
+
+
 static ssize_t v4l2_read(struct file *filp, char __user *buf,
                size_t sz, loff_t *off)
 {
@@ -303,6 +372,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
 static int v4l2_open(struct inode *inode, struct file *filp)
 {
        struct video_device *vdev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity *entity = NULL;
+#endif
        int ret = 0;
 
        /* Check if the video device is available */
@@ -316,6 +388,16 @@ static int v4l2_open(struct inode *inode, struct file *filp)
        /* and increase the device refcount */
        video_get(vdev);
        mutex_unlock(&videodev_lock);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+               entity = media_entity_get(&vdev->entity);
+               if (!entity) {
+                       ret = -EBUSY;
+                       video_put(vdev);
+                       return ret;
+               }
+       }
+#endif
        if (vdev->fops->open) {
                if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
                        ret = -ERESTARTSYS;
@@ -331,8 +413,13 @@ static int v4l2_open(struct inode *inode, struct file *filp)
 
 err:
        /* decrease the refcount in case of an error */
-       if (ret)
+       if (ret) {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+               if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+                       media_entity_put(entity);
+#endif
                video_put(vdev);
+       }
        return ret;
 }
 
@@ -349,7 +436,10 @@ static int v4l2_release(struct inode *inode, struct file *filp)
                if (vdev->lock)
                        mutex_unlock(vdev->lock);
        }
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+               media_entity_put(&vdev->entity);
+#endif
        /* decrease the refcount unconditionally since the release()
           return value is ignored. */
        video_put(vdev);
@@ -408,13 +498,14 @@ static int get_index(struct video_device *vdev)
 }
 
 /**
- *     video_register_device - register video4linux devices
+ *     __video_register_device - register video4linux devices
  *     @vdev: video device structure we want to register
  *     @type: type of device to register
  *     @nr:   which device node number (0 == /dev/video0, 1 == /dev/video1, ...
  *             -1 == first free)
  *     @warn_if_nr_in_use: warn if the desired device node number
  *            was already in use and another number was chosen instead.
+ *     @owner: module that owns the video device node
  *
  *     The registration code assigns minor numbers and device node numbers
  *     based on the requested type and registers the new device node with
@@ -435,9 +526,11 @@ static int get_index(struct video_device *vdev)
  *     %VFL_TYPE_VBI - Vertical blank data (undecoded)
  *
  *     %VFL_TYPE_RADIO - A radio card
+ *
+ *     %VFL_TYPE_SUBDEV - A subdevice
  */
-static int __video_register_device(struct video_device *vdev, int type, int nr,
-               int warn_if_nr_in_use)
+int __video_register_device(struct video_device *vdev, int type, int nr,
+               int warn_if_nr_in_use, struct module *owner)
 {
        int i = 0;
        int ret;
@@ -469,6 +562,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
        case VFL_TYPE_RADIO:
                name_base = "radio";
                break;
+       case VFL_TYPE_SUBDEV:
+               name_base = "v4l-subdev";
+               break;
        default:
                printk(KERN_ERR "%s called with unknown type: %d\n",
                       __func__, type);
@@ -482,6 +578,10 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
                        vdev->parent = vdev->v4l2_dev->dev;
                if (vdev->ctrl_handler == NULL)
                        vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+               /* If the prio state pointer is NULL, then use the v4l2_device
+                  prio state. */
+               if (vdev->prio == NULL)
+                       vdev->prio = &vdev->v4l2_dev->prio;
        }
 
        /* Part 2: find a free minor, device node number and device index. */
@@ -552,7 +652,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
                goto cleanup;
        }
        vdev->cdev->ops = &v4l2_fops;
-       vdev->cdev->owner = vdev->fops->owner;
+       vdev->cdev->owner = owner;
        ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
        if (ret < 0) {
                printk(KERN_ERR "%s: cdev_add failed\n", __func__);
@@ -580,11 +680,31 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
                printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
                        name_base, nr, video_device_node_name(vdev));
 
-       /* Part 5: Activate this minor. The char device can now be used. */
+       /* Increase v4l2_device refcount */
+       if (vdev->v4l2_dev)
+               v4l2_device_get(vdev->v4l2_dev);
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       /* Part 5: Register the entity. */
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
+               vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+               vdev->entity.name = vdev->name;
+               vdev->entity.v4l.major = VIDEO_MAJOR;
+               vdev->entity.v4l.minor = vdev->minor;
+               ret = media_device_register_entity(vdev->v4l2_dev->mdev,
+                       &vdev->entity);
+               if (ret < 0)
+                       printk(KERN_WARNING
+                              "%s: media_device_register_entity failed\n",
+                              __func__);
+       }
+#endif
+       /* Part 6: Activate this minor. The char device can now be used. */
        set_bit(V4L2_FL_REGISTERED, &vdev->flags);
        mutex_lock(&videodev_lock);
        video_device[vdev->minor] = vdev;
        mutex_unlock(&videodev_lock);
+
        return 0;
 
 cleanup:
@@ -597,18 +717,7 @@ cleanup:
        vdev->minor = -1;
        return ret;
 }
-
-int video_register_device(struct video_device *vdev, int type, int nr)
-{
-       return __video_register_device(vdev, type, nr, 1);
-}
-EXPORT_SYMBOL(video_register_device);
-
-int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
-{
-       return __video_register_device(vdev, type, nr, 0);
-}
-EXPORT_SYMBOL(video_register_device_no_warn);
+EXPORT_SYMBOL(__video_register_device);
 
 /**
  *     video_unregister_device - unregister a video4linux device
@@ -623,6 +732,11 @@ void video_unregister_device(struct video_device *vdev)
        if (!vdev || !video_is_registered(vdev))
                return;
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
+               media_device_unregister_entity(&vdev->entity);
+#endif
+
        mutex_lock(&videodev_lock);
        /* This must be in a critical section to prevent a race with v4l2_open.
         * Once this bit has been cleared video_get may never be called again.
index ce64fe16bc604137d3522af06931ab562983865c..5aeaf876ba9b2ca4a04221e41fd4cf2bfbd7c0e1 100644 (file)
@@ -36,6 +36,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
        INIT_LIST_HEAD(&v4l2_dev->subdevs);
        spin_lock_init(&v4l2_dev->lock);
        mutex_init(&v4l2_dev->ioctl_lock);
+       v4l2_prio_init(&v4l2_dev->prio);
+       kref_init(&v4l2_dev->ref);
        v4l2_dev->dev = dev;
        if (dev == NULL) {
                /* If dev == NULL, then name must be filled in by the caller */
@@ -47,13 +49,27 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
        if (!v4l2_dev->name[0])
                snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
                        dev->driver->name, dev_name(dev));
-       if (dev_get_drvdata(dev))
-               v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
-       dev_set_drvdata(dev, v4l2_dev);
+       if (!dev_get_drvdata(dev))
+               dev_set_drvdata(dev, v4l2_dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
+static void v4l2_device_release(struct kref *ref)
+{
+       struct v4l2_device *v4l2_dev =
+               container_of(ref, struct v4l2_device, ref);
+
+       if (v4l2_dev->release)
+               v4l2_dev->release(v4l2_dev);
+}
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev)
+{
+       return kref_put(&v4l2_dev->ref, v4l2_device_release);
+}
+EXPORT_SYMBOL_GPL(v4l2_device_put);
+
 int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
                                                atomic_t *instance)
 {
@@ -72,10 +88,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name);
 
 void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
 {
-       if (v4l2_dev->dev) {
+       if (v4l2_dev->dev == NULL)
+               return;
+
+       if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
                dev_set_drvdata(v4l2_dev->dev, NULL);
-               v4l2_dev->dev = NULL;
-       }
+       v4l2_dev->dev = NULL;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
 
@@ -117,23 +135,30 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
 int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
-                                               struct v4l2_subdev *sd)
+                               struct v4l2_subdev *sd)
 {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity *entity = &sd->entity;
+#endif
        int err;
 
        /* Check for valid input */
        if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
                return -EINVAL;
+
        /* Warn if we apparently re-register a subdev */
        WARN_ON(sd->v4l2_dev != NULL);
+
        if (!try_module_get(sd->owner))
                return -ENODEV;
+
        sd->v4l2_dev = v4l2_dev;
        if (sd->internal_ops && sd->internal_ops->registered) {
                err = sd->internal_ops->registered(sd);
                if (err)
                        return err;
        }
+
        /* This just returns 0 if either of the two args is NULL */
        err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
        if (err) {
@@ -141,24 +166,82 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
                        sd->internal_ops->unregistered(sd);
                return err;
        }
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       /* Register the entity. */
+       if (v4l2_dev->mdev) {
+               err = media_device_register_entity(v4l2_dev->mdev, entity);
+               if (err < 0) {
+                       if (sd->internal_ops && sd->internal_ops->unregistered)
+                               sd->internal_ops->unregistered(sd);
+                       module_put(sd->owner);
+                       return err;
+               }
+       }
+#endif
+
        spin_lock(&v4l2_dev->lock);
        list_add_tail(&sd->list, &v4l2_dev->subdevs);
        spin_unlock(&v4l2_dev->lock);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
 
+int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
+{
+       struct video_device *vdev;
+       struct v4l2_subdev *sd;
+       int err;
+
+       /* Register a device node for every subdev marked with the
+        * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+        */
+       list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
+               if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+                       continue;
+
+               vdev = &sd->devnode;
+               strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+               vdev->v4l2_dev = v4l2_dev;
+               vdev->fops = &v4l2_subdev_fops;
+               vdev->release = video_device_release_empty;
+               err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+                                             sd->owner);
+               if (err < 0)
+                       return err;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+               sd->entity.v4l.major = VIDEO_MAJOR;
+               sd->entity.v4l.minor = vdev->minor;
+#endif
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
+
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 {
+       struct v4l2_device *v4l2_dev;
+
        /* return if it isn't registered */
        if (sd == NULL || sd->v4l2_dev == NULL)
                return;
-       spin_lock(&sd->v4l2_dev->lock);
+
+       v4l2_dev = sd->v4l2_dev;
+
+       spin_lock(&v4l2_dev->lock);
        list_del(&sd->list);
-       spin_unlock(&sd->v4l2_dev->lock);
+       spin_unlock(&v4l2_dev->lock);
+
        if (sd->internal_ops && sd->internal_ops->unregistered)
                sd->internal_ops->unregistered(sd);
        sd->v4l2_dev = NULL;
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (v4l2_dev->mdev)
+               media_device_unregister_entity(&sd->entity);
+#endif
+       video_unregister_device(&sd->devnode);
        module_put(sd->owner);
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
index d78f184f40c5e67d5a9fc5a009daf156453c5d0d..717f71e6370e564deb08371fb2b72bf326ee3bad 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/slab.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
@@ -33,6 +34,7 @@ int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
        fh->vdev = vdev;
        INIT_LIST_HEAD(&fh->list);
        set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags);
+       fh->prio = V4L2_PRIORITY_UNSET;
 
        /*
         * fh->events only needs to be initialized if the driver
@@ -51,12 +53,28 @@ void v4l2_fh_add(struct v4l2_fh *fh)
 {
        unsigned long flags;
 
+       if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags))
+               v4l2_prio_open(fh->vdev->prio, &fh->prio);
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
        list_add(&fh->list, &fh->vdev->fh_list);
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_add);
 
+int v4l2_fh_open(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+
+       filp->private_data = fh;
+       if (fh == NULL)
+               return -ENOMEM;
+       v4l2_fh_init(fh, vdev);
+       v4l2_fh_add(fh);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_open);
+
 void v4l2_fh_del(struct v4l2_fh *fh)
 {
        unsigned long flags;
@@ -64,6 +82,8 @@ void v4l2_fh_del(struct v4l2_fh *fh)
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
        list_del_init(&fh->list);
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+       if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags))
+               v4l2_prio_close(fh->vdev->prio, fh->prio);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_del);
 
@@ -77,3 +97,30 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
        v4l2_event_free(fh);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_exit);
+
+int v4l2_fh_release(struct file *filp)
+{
+       struct v4l2_fh *fh = filp->private_data;
+
+       if (fh) {
+               v4l2_fh_del(fh);
+               v4l2_fh_exit(fh);
+               kfree(fh);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_release);
+
+int v4l2_fh_is_singular(struct v4l2_fh *fh)
+{
+       unsigned long flags;
+       int is_singular;
+
+       if (fh == NULL || fh->vdev == NULL)
+               return 0;
+       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+       is_singular = list_is_singular(&fh->list);
+       spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+       return is_singular;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_is_singular);
index f51327ef675734c1274669e4ff36f37f82d55b8b..a01ed39e6c168a292a1994b9ef7e440687525c72 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 
-#define __OLD_VIDIOC_ /* To allow fixing old calls */
 #include <linux/videodev2.h>
 
 #include <media/v4l2-common.h>
@@ -25,6 +24,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 
 #define dbgarg(cmd, fmt, arg...) \
@@ -165,6 +165,8 @@ const char *v4l2_type_names[] = {
        [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
        [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
        [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",
+       [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",
+       [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane",
 };
 EXPORT_SYMBOL(v4l2_type_names);
 
@@ -293,153 +295,37 @@ void v4l_printk_ioctl(unsigned int cmd)
 }
 EXPORT_SYMBOL(v4l_printk_ioctl);
 
-/*
- * helper function -- handles userspace copying for ioctl arguments
- */
-
-#ifdef __OLD_VIDIOC_
-static unsigned int
-video_fix_command(unsigned int cmd)
-{
-       switch (cmd) {
-       case VIDIOC_OVERLAY_OLD:
-               cmd = VIDIOC_OVERLAY;
-               break;
-       case VIDIOC_S_PARM_OLD:
-               cmd = VIDIOC_S_PARM;
-               break;
-       case VIDIOC_S_CTRL_OLD:
-               cmd = VIDIOC_S_CTRL;
-               break;
-       case VIDIOC_G_AUDIO_OLD:
-               cmd = VIDIOC_G_AUDIO;
-               break;
-       case VIDIOC_G_AUDOUT_OLD:
-               cmd = VIDIOC_G_AUDOUT;
-               break;
-       case VIDIOC_CROPCAP_OLD:
-               cmd = VIDIOC_CROPCAP;
-               break;
-       }
-       return cmd;
-}
-#endif
-
-/*
- * Obsolete usercopy function - Should be removed soon
- */
-long
-video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
-               v4l2_kioctl func)
-{
-       char    sbuf[128];
-       void    *mbuf = NULL;
-       void    *parg = NULL;
-       long    err  = -EINVAL;
-       int     is_ext_ctrl;
-       size_t  ctrls_size = 0;
-       void __user *user_ptr = NULL;
-
-#ifdef __OLD_VIDIOC_
-       cmd = video_fix_command(cmd);
-#endif
-       is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
-                      cmd == VIDIOC_TRY_EXT_CTRLS);
-
-       /*  Copy arguments into temp kernel buffer  */
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:
-               parg = NULL;
-               break;
-       case _IOC_READ:
-       case _IOC_WRITE:
-       case (_IOC_WRITE | _IOC_READ):
-               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-                       parg = sbuf;
-               } else {
-                       /* too big to allocate from stack */
-                       mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
-                       if (NULL == mbuf)
-                               return -ENOMEM;
-                       parg = mbuf;
-               }
-
-               err = -EFAULT;
-               if (_IOC_DIR(cmd) & _IOC_WRITE)
-                       if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-                               goto out;
-               break;
-       }
-       if (is_ext_ctrl) {
-               struct v4l2_ext_controls *p = parg;
-
-               /* In case of an error, tell the caller that it wasn't
-                  a specific control that caused it. */
-               p->error_idx = p->count;
-               user_ptr = (void __user *)p->controls;
-               if (p->count) {
-                       ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
-                       /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
-                       mbuf = kmalloc(ctrls_size, GFP_KERNEL);
-                       err = -ENOMEM;
-                       if (NULL == mbuf)
-                               goto out_ext_ctrl;
-                       err = -EFAULT;
-                       if (copy_from_user(mbuf, user_ptr, ctrls_size))
-                               goto out_ext_ctrl;
-                       p->controls = mbuf;
-               }
-       }
-
-       /* call driver */
-       err = func(file, cmd, parg);
-       if (err == -ENOIOCTLCMD)
-               err = -EINVAL;
-       if (is_ext_ctrl) {
-               struct v4l2_ext_controls *p = parg;
-
-               p->controls = (void *)user_ptr;
-               if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
-                       err = -EFAULT;
-               goto out_ext_ctrl;
-       }
-       if (err < 0)
-               goto out;
-
-out_ext_ctrl:
-       /*  Copy results into user buffer  */
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_READ:
-       case (_IOC_WRITE | _IOC_READ):
-               if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-                       err = -EFAULT;
-               break;
-       }
-
-out:
-       kfree(mbuf);
-       return err;
-}
-EXPORT_SYMBOL(video_usercopy);
-
 static void dbgbuf(unsigned int cmd, struct video_device *vfd,
                                        struct v4l2_buffer *p)
 {
        struct v4l2_timecode *tc = &p->timecode;
+       struct v4l2_plane *plane;
+       int i;
 
        dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
-               "bytesused=%d, flags=0x%08d, "
-               "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",
+               "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n",
                        p->timestamp.tv_sec / 3600,
                        (int)(p->timestamp.tv_sec / 60) % 60,
                        (int)(p->timestamp.tv_sec % 60),
                        (long)p->timestamp.tv_usec,
                        p->index,
                        prt_names(p->type, v4l2_type_names),
-                       p->bytesused, p->flags,
-                       p->field, p->sequence,
-                       prt_names(p->memory, v4l2_memory_names),
-                       p->m.userptr, p->length);
+                       p->flags, p->field, p->sequence,
+                       prt_names(p->memory, v4l2_memory_names));
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) {
+               for (i = 0; i < p->length; ++i) {
+                       plane = &p->m.planes[i];
+                       dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x "
+                               "offset/userptr=0x%08lx, length=%d\n",
+                               i, plane->bytesused, plane->data_offset,
+                               plane->m.userptr, plane->length);
+               }
+       } else {
+               dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n",
+                       p->bytesused, p->m.userptr, p->length);
+       }
+
        dbgarg2("timecode=%02d:%02d:%02d type=%d, "
                "flags=0x%08d, frames=%d, userbits=0x%08x\n",
                        tc->hours, tc->minutes, tc->seconds,
@@ -467,6 +353,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd,
                fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
 };
 
+static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd,
+                                           struct v4l2_pix_format_mplane *fmt)
+{
+       int i;
+
+       dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "
+               "colorspace=%d, num_planes=%d\n",
+               fmt->width, fmt->height,
+               (fmt->pixelformat & 0xff),
+               (fmt->pixelformat >>  8) & 0xff,
+               (fmt->pixelformat >> 16) & 0xff,
+               (fmt->pixelformat >> 24) & 0xff,
+               prt_names(fmt->field, v4l2_field_names),
+               fmt->colorspace, fmt->num_planes);
+
+       for (i = 0; i < fmt->num_planes; ++i)
+               dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i,
+                       fmt->plane_fmt[i].bytesperline,
+                       fmt->plane_fmt[i].sizeimage);
+}
+
 static inline void v4l_print_ext_ctrls(unsigned int cmd,
        struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals)
 {
@@ -520,7 +427,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 
        switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (ops->vidioc_g_fmt_vid_cap)
+               if (ops->vidioc_g_fmt_vid_cap ||
+                               ops->vidioc_g_fmt_vid_cap_mplane)
+                       return 0;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               if (ops->vidioc_g_fmt_vid_cap_mplane)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
@@ -528,7 +440,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               if (ops->vidioc_g_fmt_vid_out)
+               if (ops->vidioc_g_fmt_vid_out ||
+                               ops->vidioc_g_fmt_vid_out_mplane)
+                       return 0;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               if (ops->vidioc_g_fmt_vid_out_mplane)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
@@ -559,12 +476,72 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
        return -EINVAL;
 }
 
+/**
+ * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane
+ * equivalent
+ */
+static int fmt_sp_to_mp(const struct v4l2_format *f_sp,
+                       struct v4l2_format *f_mp)
+{
+       struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
+       const struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+
+       if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       else
+               return -EINVAL;
+
+       pix_mp->width = pix->width;
+       pix_mp->height = pix->height;
+       pix_mp->pixelformat = pix->pixelformat;
+       pix_mp->field = pix->field;
+       pix_mp->colorspace = pix->colorspace;
+       pix_mp->num_planes = 1;
+       pix_mp->plane_fmt[0].sizeimage = pix->sizeimage;
+       pix_mp->plane_fmt[0].bytesperline = pix->bytesperline;
+
+       return 0;
+}
+
+/**
+ * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar
+ * equivalent
+ */
+static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
+                       struct v4l2_format *f_sp)
+{
+       const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
+       struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+
+       if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       else
+               return -EINVAL;
+
+       pix->width = pix_mp->width;
+       pix->height = pix_mp->height;
+       pix->pixelformat = pix_mp->pixelformat;
+       pix->field = pix_mp->field;
+       pix->colorspace = pix_mp->colorspace;
+       pix->sizeimage = pix_mp->plane_fmt[0].sizeimage;
+       pix->bytesperline = pix_mp->plane_fmt[0].bytesperline;
+
+       return 0;
+}
+
 static long __video_do_ioctl(struct file *file,
                unsigned int cmd, void *arg)
 {
        struct video_device *vfd = video_devdata(file);
        const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
        void *fh = file->private_data;
+       struct v4l2_fh *vfh = NULL;
+       struct v4l2_format f_copy;
+       int use_fh_prio = 0;
        long ret = -EINVAL;
 
        if (ops == NULL) {
@@ -579,6 +556,45 @@ static long __video_do_ioctl(struct file *file,
                printk(KERN_CONT "\n");
        }
 
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+               vfh = file->private_data;
+               use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+       }
+
+       if (use_fh_prio) {
+               switch (cmd) {
+               case VIDIOC_S_CTRL:
+               case VIDIOC_S_STD:
+               case VIDIOC_S_INPUT:
+               case VIDIOC_S_OUTPUT:
+               case VIDIOC_S_TUNER:
+               case VIDIOC_S_FREQUENCY:
+               case VIDIOC_S_FMT:
+               case VIDIOC_S_CROP:
+               case VIDIOC_S_AUDIO:
+               case VIDIOC_S_AUDOUT:
+               case VIDIOC_S_EXT_CTRLS:
+               case VIDIOC_S_FBUF:
+               case VIDIOC_S_PRIORITY:
+               case VIDIOC_S_DV_PRESET:
+               case VIDIOC_S_DV_TIMINGS:
+               case VIDIOC_S_JPEGCOMP:
+               case VIDIOC_S_MODULATOR:
+               case VIDIOC_S_PARM:
+               case VIDIOC_S_HW_FREQ_SEEK:
+               case VIDIOC_ENCODER_CMD:
+               case VIDIOC_OVERLAY:
+               case VIDIOC_REQBUFS:
+               case VIDIOC_STREAMON:
+               case VIDIOC_STREAMOFF:
+                       ret = v4l2_prio_check(vfd->prio, vfh->prio);
+                       if (ret)
+                               goto exit_prio;
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
        switch (cmd) {
 
        /* --- capabilities ------------------------------------------ */
@@ -605,9 +621,12 @@ static long __video_do_ioctl(struct file *file,
        {
                enum v4l2_priority *p = arg;
 
-               if (!ops->vidioc_g_priority)
-                       break;
-               ret = ops->vidioc_g_priority(file, fh, p);
+               if (ops->vidioc_g_priority) {
+                       ret = ops->vidioc_g_priority(file, fh, p);
+               } else if (use_fh_prio) {
+                       *p = v4l2_prio_max(&vfd->v4l2_dev->prio);
+                       ret = 0;
+               }
                if (!ret)
                        dbgarg(cmd, "priority is %d\n", *p);
                break;
@@ -616,10 +635,13 @@ static long __video_do_ioctl(struct file *file,
        {
                enum v4l2_priority *p = arg;
 
-               if (!ops->vidioc_s_priority)
-                       break;
+               if (!ops->vidioc_s_priority && !use_fh_prio)
+                               break;
                dbgarg(cmd, "setting priority to %d\n", *p);
-               ret = ops->vidioc_s_priority(file, fh, *p);
+               if (ops->vidioc_s_priority)
+                       ret = ops->vidioc_s_priority(file, fh, *p);
+               else
+                       ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p);
                break;
        }
 
@@ -633,6 +655,11 @@ static long __video_do_ioctl(struct file *file,
                        if (ops->vidioc_enum_fmt_vid_cap)
                                ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+                       if (ops->vidioc_enum_fmt_vid_cap_mplane)
+                               ret = ops->vidioc_enum_fmt_vid_cap_mplane(file,
+                                                                       fh, f);
+                       break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        if (ops->vidioc_enum_fmt_vid_overlay)
                                ret = ops->vidioc_enum_fmt_vid_overlay(file,
@@ -642,6 +669,11 @@ static long __video_do_ioctl(struct file *file,
                        if (ops->vidioc_enum_fmt_vid_out)
                                ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+                       if (ops->vidioc_enum_fmt_vid_out_mplane)
+                               ret = ops->vidioc_enum_fmt_vid_out_mplane(file,
+                                                                       fh, f);
+                       break;
                case V4L2_BUF_TYPE_PRIVATE:
                        if (ops->vidioc_enum_fmt_type_private)
                                ret = ops->vidioc_enum_fmt_type_private(file,
@@ -670,22 +702,90 @@ static long __video_do_ioctl(struct file *file,
 
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-                       if (ops->vidioc_g_fmt_vid_cap)
+                       if (ops->vidioc_g_fmt_vid_cap) {
                                ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);
+                       } else if (ops->vidioc_g_fmt_vid_cap_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh,
+                                                                      &f_copy);
+                               if (ret)
+                                       break;
+
+                               /* Driver is currently in multi-planar format,
+                                * we can't return it in single-planar API*/
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       ret = -EBUSY;
+                                       break;
+                               }
+
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+                       if (ops->vidioc_g_fmt_vid_cap_mplane) {
+                               ret = ops->vidioc_g_fmt_vid_cap_mplane(file,
+                                                                       fh, f);
+                       } else if (ops->vidioc_g_fmt_vid_cap) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_g_fmt_vid_cap(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_sp_to_mp(&f_copy, f);
+                       }
+                       if (!ret)
+                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        if (ops->vidioc_g_fmt_vid_overlay)
                                ret = ops->vidioc_g_fmt_vid_overlay(file,
                                                                    fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-                       if (ops->vidioc_g_fmt_vid_out)
+                       if (ops->vidioc_g_fmt_vid_out) {
                                ret = ops->vidioc_g_fmt_vid_out(file, fh, f);
+                       } else if (ops->vidioc_g_fmt_vid_out_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh,
+                                                                       &f_copy);
+                               if (ret)
+                                       break;
+
+                               /* Driver is currently in multi-planar format,
+                                * we can't return it in single-planar API*/
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       ret = -EBUSY;
+                                       break;
+                               }
+
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+                       if (ops->vidioc_g_fmt_vid_out_mplane) {
+                               ret = ops->vidioc_g_fmt_vid_out_mplane(file,
+                                                                       fh, f);
+                       } else if (ops->vidioc_g_fmt_vid_out) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_g_fmt_vid_out(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_sp_to_mp(&f_copy, f);
+                       }
+                       if (!ret)
+                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                        if (ops->vidioc_g_fmt_vid_out_overlay)
                                ret = ops->vidioc_g_fmt_vid_out_overlay(file,
@@ -729,8 +829,44 @@ static long __video_do_ioctl(struct file *file,
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_cap)
+                       if (ops->vidioc_s_fmt_vid_cap) {
                                ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
+                       } else if (ops->vidioc_s_fmt_vid_cap_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh,
+                                                                       &f_copy);
+                               if (ret)
+                                       break;
+
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       /* Drivers shouldn't adjust from 1-plane
+                                        * to more than 1-plane formats */
+                                       ret = -EBUSY;
+                                       WARN_ON(1);
+                                       break;
+                               }
+
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+                       v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       if (ops->vidioc_s_fmt_vid_cap_mplane) {
+                               ret = ops->vidioc_s_fmt_vid_cap_mplane(file,
+                                                                       fh, f);
+                       } else if (ops->vidioc_s_fmt_vid_cap &&
+                                       f->fmt.pix_mp.num_planes == 1) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_s_fmt_vid_cap(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_sp_to_mp(&f_copy, f);
+                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
@@ -741,8 +877,44 @@ static long __video_do_ioctl(struct file *file,
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
-                       if (ops->vidioc_s_fmt_vid_out)
+                       if (ops->vidioc_s_fmt_vid_out) {
                                ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
+                       } else if (ops->vidioc_s_fmt_vid_out_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh,
+                                                                       &f_copy);
+                               if (ret)
+                                       break;
+
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       /* Drivers shouldn't adjust from 1-plane
+                                        * to more than 1-plane formats */
+                                       ret = -EBUSY;
+                                       WARN_ON(1);
+                                       break;
+                               }
+
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
+                       break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+                       v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       if (ops->vidioc_s_fmt_vid_out_mplane) {
+                               ret = ops->vidioc_s_fmt_vid_out_mplane(file,
+                                                                       fh, f);
+                       } else if (ops->vidioc_s_fmt_vid_out &&
+                                       f->fmt.pix_mp.num_planes == 1) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_s_fmt_vid_out(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
@@ -791,11 +963,47 @@ static long __video_do_ioctl(struct file *file,
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_cap)
+                       if (ops->vidioc_try_fmt_vid_cap) {
                                ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);
+                       } else if (ops->vidioc_try_fmt_vid_cap_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       /* Drivers shouldn't adjust from 1-plane
+                                        * to more than 1-plane formats */
+                                       ret = -EBUSY;
+                                       WARN_ON(1);
+                                       break;
+                               }
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+                       if (ops->vidioc_try_fmt_vid_cap_mplane) {
+                               ret = ops->vidioc_try_fmt_vid_cap_mplane(file,
+                                                                        fh, f);
+                       } else if (ops->vidioc_try_fmt_vid_cap &&
+                                       f->fmt.pix_mp.num_planes == 1) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_try_fmt_vid_cap(file,
+                                                                 fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_sp_to_mp(&f_copy, f);
+                       }
+                       if (!ret)
+                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_try_fmt_vid_overlay)
@@ -804,11 +1012,47 @@ static long __video_do_ioctl(struct file *file,
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        CLEAR_AFTER_FIELD(f, fmt.pix);
-                       if (ops->vidioc_try_fmt_vid_out)
+                       if (ops->vidioc_try_fmt_vid_out) {
                                ret = ops->vidioc_try_fmt_vid_out(file, fh, f);
+                       } else if (ops->vidioc_try_fmt_vid_out_mplane) {
+                               if (fmt_sp_to_mp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_try_fmt_vid_out_mplane(file,
+                                                               fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               if (f_copy.fmt.pix_mp.num_planes > 1) {
+                                       /* Drivers shouldn't adjust from 1-plane
+                                        * to more than 1-plane formats */
+                                       ret = -EBUSY;
+                                       WARN_ON(1);
+                                       break;
+                               }
+                               ret = fmt_mp_to_sp(&f_copy, f);
+                       }
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix_mp);
+                       if (ops->vidioc_try_fmt_vid_out_mplane) {
+                               ret = ops->vidioc_try_fmt_vid_out_mplane(file,
+                                                                        fh, f);
+                       } else if (ops->vidioc_try_fmt_vid_out &&
+                                       f->fmt.pix_mp.num_planes == 1) {
+                               if (fmt_mp_to_sp(f, &f_copy))
+                                       break;
+                               ret = ops->vidioc_try_fmt_vid_out(file,
+                                                                 fh, &f_copy);
+                               if (ret)
+                                       break;
+
+                               ret = fmt_sp_to_mp(&f_copy, f);
+                       }
+                       if (!ret)
+                               v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp);
+                       break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                        CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_try_fmt_vid_out_overlay)
@@ -1942,13 +2186,18 @@ static long __video_do_ioctl(struct file *file,
        }
        default:
        {
+               bool valid_prio = true;
+
                if (!ops->vidioc_default)
                        break;
-               ret = ops->vidioc_default(file, fh, cmd, arg);
+               if (use_fh_prio)
+                       valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0;
+               ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg);
                break;
        }
        } /* switch */
 
+exit_prio:
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
                if (ret < 0) {
                        v4l_print_ioctl(vfd->name, cmd);
@@ -1973,7 +2222,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
        switch (cmd) {
                CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
                CMDINSIZE(G_FMT,                format,         type);
-               CMDINSIZE(QUERYBUF,             buffer,         type);
+               CMDINSIZE(QUERYBUF,             buffer,         length);
                CMDINSIZE(G_PARM,               streamparm,     type);
                CMDINSIZE(ENUMSTD,              standard,       index);
                CMDINSIZE(ENUMINPUT,            input,          index);
@@ -1998,22 +2247,61 @@ static unsigned long cmd_input_size(unsigned int cmd)
        }
 }
 
-long video_ioctl2(struct file *file,
-              unsigned int cmd, unsigned long arg)
+static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
+                           void * __user *user_ptr, void ***kernel_ptr)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF: {
+               struct v4l2_buffer *buf = parg;
+
+               if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) {
+                       if (buf->length > VIDEO_MAX_PLANES) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       *user_ptr = (void __user *)buf->m.planes;
+                       *kernel_ptr = (void **)&buf->m.planes;
+                       *array_size = sizeof(struct v4l2_plane) * buf->length;
+                       ret = 1;
+               }
+               break;
+       }
+
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS: {
+               struct v4l2_ext_controls *ctrls = parg;
+
+               if (ctrls->count != 0) {
+                       *user_ptr = (void __user *)ctrls->controls;
+                       *kernel_ptr = (void **)&ctrls->controls;
+                       *array_size = sizeof(struct v4l2_ext_control)
+                                   * ctrls->count;
+                       ret = 1;
+               }
+               break;
+       }
+       }
+
+       return ret;
+}
+
+long
+video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+              v4l2_kioctl func)
 {
        char    sbuf[128];
        void    *mbuf = NULL;
        void    *parg = (void *)arg;
        long    err  = -EINVAL;
-       int     is_ext_ctrl;
-       size_t  ctrls_size = 0;
+       bool    has_array_args;
+       size_t  array_size = 0;
        void __user *user_ptr = NULL;
-
-#ifdef __OLD_VIDIOC_
-       cmd = video_fix_command(cmd);
-#endif
-       is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
-                      cmd == VIDIOC_TRY_EXT_CTRLS);
+       void    **kernel_ptr = NULL;
 
        /*  Copy arguments into temp kernel buffer  */
        if (_IOC_DIR(cmd) != _IOC_NONE) {
@@ -2043,43 +2331,43 @@ long video_ioctl2(struct file *file,
                }
        }
 
-       if (is_ext_ctrl) {
-               struct v4l2_ext_controls *p = parg;
+       err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
+       if (err < 0)
+               goto out;
+       has_array_args = err;
 
-               /* In case of an error, tell the caller that it wasn't
-                  a specific control that caused it. */
-               p->error_idx = p->count;
-               user_ptr = (void __user *)p->controls;
-               if (p->count) {
-                       ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
-                       /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
-                       mbuf = kmalloc(ctrls_size, GFP_KERNEL);
-                       err = -ENOMEM;
-                       if (NULL == mbuf)
-                               goto out_ext_ctrl;
-                       err = -EFAULT;
-                       if (copy_from_user(mbuf, user_ptr, ctrls_size))
-                               goto out_ext_ctrl;
-                       p->controls = mbuf;
-               }
+       if (has_array_args) {
+               /*
+                * When adding new types of array args, make sure that the
+                * parent argument to ioctl (which contains the pointer to the
+                * array) fits into sbuf (so that mbuf will still remain
+                * unused up to here).
+                */
+               mbuf = kmalloc(array_size, GFP_KERNEL);
+               err = -ENOMEM;
+               if (NULL == mbuf)
+                       goto out_array_args;
+               err = -EFAULT;
+               if (copy_from_user(mbuf, user_ptr, array_size))
+                       goto out_array_args;
+               *kernel_ptr = mbuf;
        }
 
        /* Handles IOCTL */
-       err = __video_do_ioctl(file, cmd, parg);
+       err = func(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -EINVAL;
-       if (is_ext_ctrl) {
-               struct v4l2_ext_controls *p = parg;
 
-               p->controls = (void *)user_ptr;
-               if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+       if (has_array_args) {
+               *kernel_ptr = user_ptr;
+               if (copy_to_user(user_ptr, mbuf, array_size))
                        err = -EFAULT;
-               goto out_ext_ctrl;
+               goto out_array_args;
        }
        if (err < 0)
                goto out;
 
-out_ext_ctrl:
+out_array_args:
        /*  Copy results into user buffer  */
        switch (_IOC_DIR(cmd)) {
        case _IOC_READ:
@@ -2093,4 +2381,11 @@ out:
        kfree(mbuf);
        return err;
 }
+EXPORT_SYMBOL(video_usercopy);
+
+long video_ioctl2(struct file *file,
+              unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(file, cmd, arg, __video_do_ioctl);
+}
 EXPORT_SYMBOL(video_ioctl2);
index ac832a28e18ee7bcc30f097417d3c88a52232075..3b15bf5892a803b4da4e7eb8af7e6a20d83a7455 100644 (file)
@@ -5,7 +5,7 @@
  * source and destination.
  *
  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- * Pawel Osciak, <p.osciak@samsung.com>
+ * Pawel Osciak, <pawel@osciak.com>
  * Marek Szyprowski, <m.szyprowski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-#include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
 #include <media/v4l2-mem2mem.h>
 
 MODULE_DESCRIPTION("Mem to mem device framework for videobuf");
-MODULE_AUTHOR("Pawel Osciak, <p.osciak@samsung.com>");
+MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
 MODULE_LICENSE("GPL");
 
 static bool debug;
@@ -65,21 +65,16 @@ struct v4l2_m2m_dev {
 static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
                                                enum v4l2_buf_type type)
 {
-       switch (type) {
-       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               return &m2m_ctx->cap_q_ctx;
-       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+       if (V4L2_TYPE_IS_OUTPUT(type))
                return &m2m_ctx->out_q_ctx;
-       default:
-               printk(KERN_ERR "Invalid buffer type\n");
-               return NULL;
-       }
+       else
+               return &m2m_ctx->cap_q_ctx;
 }
 
 /**
- * v4l2_m2m_get_vq() - return videobuf_queue for the given type
+ * v4l2_m2m_get_vq() - return vb2_queue for the given type
  */
-struct videobuf_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
+struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
                                       enum v4l2_buf_type type)
 {
        struct v4l2_m2m_queue_ctx *q_ctx;
@@ -95,27 +90,20 @@ EXPORT_SYMBOL(v4l2_m2m_get_vq);
 /**
  * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers
  */
-void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type)
+void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx)
 {
-       struct v4l2_m2m_queue_ctx *q_ctx;
-       struct videobuf_buffer *vb = NULL;
+       struct v4l2_m2m_buffer *b = NULL;
        unsigned long flags;
 
-       q_ctx = get_queue_ctx(m2m_ctx, type);
-       if (!q_ctx)
-               return NULL;
-
-       spin_lock_irqsave(q_ctx->q.irqlock, flags);
+       spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
 
        if (list_empty(&q_ctx->rdy_queue))
                goto end;
 
-       vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, queue);
-       vb->state = VIDEOBUF_ACTIVE;
-
+       b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list);
 end:
-       spin_unlock_irqrestore(q_ctx->q.irqlock, flags);
-       return vb;
+       spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
+       return &b->vb;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf);
 
@@ -123,26 +111,21 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf);
  * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and
  * return it
  */
-void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type)
+void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx)
 {
-       struct v4l2_m2m_queue_ctx *q_ctx;
-       struct videobuf_buffer *vb = NULL;
+       struct v4l2_m2m_buffer *b = NULL;
        unsigned long flags;
 
-       q_ctx = get_queue_ctx(m2m_ctx, type);
-       if (!q_ctx)
-               return NULL;
-
-       spin_lock_irqsave(q_ctx->q.irqlock, flags);
+       spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
        if (!list_empty(&q_ctx->rdy_queue)) {
-               vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer,
-                               queue);
-               list_del(&vb->queue);
+               b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer,
+                               list);
+               list_del(&b->list);
                q_ctx->num_rdy--;
        }
-       spin_unlock_irqrestore(q_ctx->q.irqlock, flags);
+       spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
 
-       return vb;
+       return &b->vb;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove);
 
@@ -235,20 +218,20 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
                return;
        }
 
-       spin_lock_irqsave(m2m_ctx->out_q_ctx.q.irqlock, flags);
+       spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
        if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) {
-               spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+               spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("No input buffers available\n");
                return;
        }
        if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) {
-               spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+               spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
                dprintk("No output buffers available\n");
                return;
        }
-       spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags);
+       spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
 
        if (m2m_dev->m2m_ops->job_ready
                && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
@@ -291,6 +274,7 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
 
        list_del(&m2m_dev->curr_ctx->queue);
        m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+       wake_up(&m2m_dev->curr_ctx->finished);
        m2m_dev->curr_ctx = NULL;
 
        spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
@@ -309,10 +293,10 @@ EXPORT_SYMBOL(v4l2_m2m_job_finish);
 int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                     struct v4l2_requestbuffers *reqbufs)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type);
-       return videobuf_reqbufs(vq, reqbufs);
+       return vb2_reqbufs(vq, reqbufs);
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs);
 
@@ -324,15 +308,22 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs);
 int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                      struct v4l2_buffer *buf)
 {
-       struct videobuf_queue *vq;
-       int ret;
+       struct vb2_queue *vq;
+       int ret = 0;
+       unsigned int i;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-       ret = videobuf_querybuf(vq, buf);
-
-       if (buf->memory == V4L2_MEMORY_MMAP
-           && vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               buf->m.offset += DST_QUEUE_OFF_BASE;
+       ret = vb2_querybuf(vq, buf);
+
+       /* Adjust MMAP memory offsets for the CAPTURE queue */
+       if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) {
+               if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) {
+                       for (i = 0; i < buf->length; ++i)
+                               buf->m.planes[i].m.mem_offset
+                                       += DST_QUEUE_OFF_BASE;
+               } else {
+                       buf->m.offset += DST_QUEUE_OFF_BASE;
+               }
        }
 
        return ret;
@@ -346,11 +337,11 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
 int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                  struct v4l2_buffer *buf)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
        int ret;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-       ret = videobuf_qbuf(vq, buf);
+       ret = vb2_qbuf(vq, buf);
        if (!ret)
                v4l2_m2m_try_schedule(m2m_ctx);
 
@@ -365,10 +356,10 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
 int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                   struct v4l2_buffer *buf)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-       return videobuf_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+       return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
 
@@ -378,11 +369,11 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf);
 int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                      enum v4l2_buf_type type)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
        int ret;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, type);
-       ret = videobuf_streamon(vq);
+       ret = vb2_streamon(vq, type);
        if (!ret)
                v4l2_m2m_try_schedule(m2m_ctx);
 
@@ -396,10 +387,10 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamon);
 int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                       enum v4l2_buf_type type)
 {
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
 
        vq = v4l2_m2m_get_vq(m2m_ctx, type);
-       return videobuf_streamoff(vq);
+       return vb2_streamoff(vq, type);
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
 
@@ -414,44 +405,53 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
 unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                           struct poll_table_struct *wait)
 {
-       struct videobuf_queue *src_q, *dst_q;
-       struct videobuf_buffer *src_vb = NULL, *dst_vb = NULL;
+       struct vb2_queue *src_q, *dst_q;
+       struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
        unsigned int rc = 0;
+       unsigned long flags;
 
        src_q = v4l2_m2m_get_src_vq(m2m_ctx);
        dst_q = v4l2_m2m_get_dst_vq(m2m_ctx);
 
-       videobuf_queue_lock(src_q);
-       videobuf_queue_lock(dst_q);
-
-       if (src_q->streaming && !list_empty(&src_q->stream))
-               src_vb = list_first_entry(&src_q->stream,
-                                         struct videobuf_buffer, stream);
-       if (dst_q->streaming && !list_empty(&dst_q->stream))
-               dst_vb = list_first_entry(&dst_q->stream,
-                                         struct videobuf_buffer, stream);
-
-       if (!src_vb && !dst_vb) {
+       /*
+        * There has to be at least one buffer queued on each queued_list, which
+        * means either in driver already or waiting for driver to claim it
+        * and start processing.
+        */
+       if ((!src_q->streaming || list_empty(&src_q->queued_list))
+               && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
                rc = POLLERR;
                goto end;
        }
 
-       if (src_vb) {
-               poll_wait(file, &src_vb->done, wait);
-               if (src_vb->state == VIDEOBUF_DONE
-                   || src_vb->state == VIDEOBUF_ERROR)
-                       rc |= POLLOUT | POLLWRNORM;
-       }
-       if (dst_vb) {
-               poll_wait(file, &dst_vb->done, wait);
-               if (dst_vb->state == VIDEOBUF_DONE
-                   || dst_vb->state == VIDEOBUF_ERROR)
-                       rc |= POLLIN | POLLRDNORM;
-       }
+       if (m2m_ctx->m2m_dev->m2m_ops->unlock)
+               m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv);
+
+       poll_wait(file, &src_q->done_wq, wait);
+       poll_wait(file, &dst_q->done_wq, wait);
+
+       if (m2m_ctx->m2m_dev->m2m_ops->lock)
+               m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv);
+
+       spin_lock_irqsave(&src_q->done_lock, flags);
+       if (!list_empty(&src_q->done_list))
+               src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
+                                               done_entry);
+       if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
+                       || src_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLOUT | POLLWRNORM;
+       spin_unlock_irqrestore(&src_q->done_lock, flags);
+
+       spin_lock_irqsave(&dst_q->done_lock, flags);
+       if (!list_empty(&dst_q->done_list))
+               dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
+                                               done_entry);
+       if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
+                       || dst_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLIN | POLLRDNORM;
+       spin_unlock_irqrestore(&dst_q->done_lock, flags);
 
 end:
-       videobuf_queue_unlock(dst_q);
-       videobuf_queue_unlock(src_q);
        return rc;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
@@ -470,7 +470,7 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                         struct vm_area_struct *vma)
 {
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       struct videobuf_queue *vq;
+       struct vb2_queue *vq;
 
        if (offset < DST_QUEUE_OFF_BASE) {
                vq = v4l2_m2m_get_src_vq(m2m_ctx);
@@ -479,7 +479,7 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
        }
 
-       return videobuf_mmap_mapper(vq, vma);
+       return vb2_mmap(vq, vma);
 }
 EXPORT_SYMBOL(v4l2_m2m_mmap);
 
@@ -531,36 +531,41 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_release);
  *
  * Usually called from driver's open() function.
  */
-struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(void *priv, struct v4l2_m2m_dev *m2m_dev,
-                       void (*vq_init)(void *priv, struct videobuf_queue *,
-                                       enum v4l2_buf_type))
+struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
+               void *drv_priv,
+               int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq))
 {
        struct v4l2_m2m_ctx *m2m_ctx;
        struct v4l2_m2m_queue_ctx *out_q_ctx, *cap_q_ctx;
-
-       if (!vq_init)
-               return ERR_PTR(-EINVAL);
+       int ret;
 
        m2m_ctx = kzalloc(sizeof *m2m_ctx, GFP_KERNEL);
        if (!m2m_ctx)
                return ERR_PTR(-ENOMEM);
 
-       m2m_ctx->priv = priv;
+       m2m_ctx->priv = drv_priv;
        m2m_ctx->m2m_dev = m2m_dev;
+       init_waitqueue_head(&m2m_ctx->finished);
 
-       out_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       cap_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       out_q_ctx = &m2m_ctx->out_q_ctx;
+       cap_q_ctx = &m2m_ctx->cap_q_ctx;
 
        INIT_LIST_HEAD(&out_q_ctx->rdy_queue);
        INIT_LIST_HEAD(&cap_q_ctx->rdy_queue);
+       spin_lock_init(&out_q_ctx->rdy_spinlock);
+       spin_lock_init(&cap_q_ctx->rdy_spinlock);
 
        INIT_LIST_HEAD(&m2m_ctx->queue);
 
-       vq_init(priv, &out_q_ctx->q, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       vq_init(priv, &cap_q_ctx->q, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       out_q_ctx->q.priv_data = cap_q_ctx->q.priv_data = priv;
+       ret = queue_init(drv_priv, &out_q_ctx->q, &cap_q_ctx->q);
+
+       if (ret)
+               goto err;
 
        return m2m_ctx;
+err:
+       kfree(m2m_ctx);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init);
 
@@ -572,7 +577,6 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init);
 void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
 {
        struct v4l2_m2m_dev *m2m_dev;
-       struct videobuf_buffer *vb;
        unsigned long flags;
 
        m2m_dev = m2m_ctx->m2m_dev;
@@ -582,10 +586,7 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
                m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
                dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
-               vb = v4l2_m2m_next_dst_buf(m2m_ctx);
-               BUG_ON(NULL == vb);
-               wait_event(vb->done, vb->state != VIDEOBUF_ACTIVE
-                                    && vb->state != VIDEOBUF_QUEUED);
+               wait_event(m2m_ctx->finished, !(m2m_ctx->job_flags & TRANS_RUNNING));
        } else if (m2m_ctx->job_flags & TRANS_QUEUED) {
                list_del(&m2m_ctx->queue);
                m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
@@ -597,11 +598,8 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
                spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
        }
 
-       videobuf_stop(&m2m_ctx->cap_q_ctx.q);
-       videobuf_stop(&m2m_ctx->out_q_ctx.q);
-
-       videobuf_mmap_free(&m2m_ctx->cap_q_ctx.q);
-       videobuf_mmap_free(&m2m_ctx->out_q_ctx.q);
+       vb2_queue_release(&m2m_ctx->cap_q_ctx.q);
+       vb2_queue_release(&m2m_ctx->out_q_ctx.q);
 
        kfree(m2m_ctx);
 }
@@ -611,23 +609,21 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release);
  * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list.
  *
  * Call from buf_queue(), videobuf_queue_ops callback.
- *
- * Locking: Caller holds q->irqlock (taken by videobuf before calling buf_queue
- * callback in the driver).
  */
-void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct videobuf_queue *vq,
-                       struct videobuf_buffer *vb)
+void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb)
 {
+       struct v4l2_m2m_buffer *b = container_of(vb, struct v4l2_m2m_buffer, vb);
        struct v4l2_m2m_queue_ctx *q_ctx;
+       unsigned long flags;
 
-       q_ctx = get_queue_ctx(m2m_ctx, vq->type);
+       q_ctx = get_queue_ctx(m2m_ctx, vb->vb2_queue->type);
        if (!q_ctx)
                return;
 
-       list_add_tail(&vb->queue, &q_ctx->rdy_queue);
+       spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
+       list_add_tail(&b->list, &q_ctx->rdy_queue);
        q_ctx->num_rdy++;
-
-       vb->state = VIDEOBUF_QUEUED;
+       spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
 
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
new file mode 100644 (file)
index 0000000..0b80644
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * V4L2 sub-device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *         Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+
+static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
+{
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+       /* Allocate try format and crop in the same memory block */
+       fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
+                             * sd->entity.num_pads, GFP_KERNEL);
+       if (fh->try_fmt == NULL)
+               return -ENOMEM;
+
+       fh->try_crop = (struct v4l2_rect *)
+               (fh->try_fmt + sd->entity.num_pads);
+#endif
+       return 0;
+}
+
+static void subdev_fh_free(struct v4l2_subdev_fh *fh)
+{
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+       kfree(fh->try_fmt);
+       fh->try_fmt = NULL;
+       fh->try_crop = NULL;
+#endif
+}
+
+static int subdev_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+       struct v4l2_subdev_fh *subdev_fh;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity *entity = NULL;
+#endif
+       int ret;
+
+       subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
+       if (subdev_fh == NULL)
+               return -ENOMEM;
+
+       ret = subdev_fh_init(subdev_fh, sd);
+       if (ret) {
+               kfree(subdev_fh);
+               return ret;
+       }
+
+       ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
+       if (ret)
+               goto err;
+
+       if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
+               ret = v4l2_event_init(&subdev_fh->vfh);
+               if (ret)
+                       goto err;
+
+               ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
+               if (ret)
+                       goto err;
+       }
+
+       v4l2_fh_add(&subdev_fh->vfh);
+       file->private_data = &subdev_fh->vfh;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (sd->v4l2_dev->mdev) {
+               entity = media_entity_get(&sd->entity);
+               if (!entity) {
+                       ret = -EBUSY;
+                       goto err;
+               }
+       }
+#endif
+
+       if (sd->internal_ops && sd->internal_ops->open) {
+               ret = sd->internal_ops->open(sd, subdev_fh);
+               if (ret < 0)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (entity)
+               media_entity_put(entity);
+#endif
+       v4l2_fh_del(&subdev_fh->vfh);
+       v4l2_fh_exit(&subdev_fh->vfh);
+       subdev_fh_free(subdev_fh);
+       kfree(subdev_fh);
+
+       return ret;
+}
+
+static int subdev_close(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+       struct v4l2_fh *vfh = file->private_data;
+       struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+
+       if (sd->internal_ops && sd->internal_ops->close)
+               sd->internal_ops->close(sd, subdev_fh);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       if (sd->v4l2_dev->mdev)
+               media_entity_put(&sd->entity);
+#endif
+       v4l2_fh_del(vfh);
+       v4l2_fh_exit(vfh);
+       subdev_fh_free(subdev_fh);
+       kfree(subdev_fh);
+       file->private_data = NULL;
+
+       return 0;
+}
+
+static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+       struct v4l2_fh *vfh = file->private_data;
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+       struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+#endif
+
+       switch (cmd) {
+       case VIDIOC_QUERYCTRL:
+               return v4l2_subdev_queryctrl(sd, arg);
+
+       case VIDIOC_QUERYMENU:
+               return v4l2_subdev_querymenu(sd, arg);
+
+       case VIDIOC_G_CTRL:
+               return v4l2_subdev_g_ctrl(sd, arg);
+
+       case VIDIOC_S_CTRL:
+               return v4l2_subdev_s_ctrl(sd, arg);
+
+       case VIDIOC_G_EXT_CTRLS:
+               return v4l2_subdev_g_ext_ctrls(sd, arg);
+
+       case VIDIOC_S_EXT_CTRLS:
+               return v4l2_subdev_s_ext_ctrls(sd, arg);
+
+       case VIDIOC_TRY_EXT_CTRLS:
+               return v4l2_subdev_try_ext_ctrls(sd, arg);
+
+       case VIDIOC_DQEVENT:
+               if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+                       return -ENOIOCTLCMD;
+
+               return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+       case VIDIOC_SUBSCRIBE_EVENT:
+               return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+       case VIDIOC_UNSUBSCRIBE_EVENT:
+               return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+       case VIDIOC_SUBDEV_G_FMT: {
+               struct v4l2_subdev_format *format = arg;
+
+               if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
+                   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+                       return -EINVAL;
+
+               if (format->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format);
+       }
+
+       case VIDIOC_SUBDEV_S_FMT: {
+               struct v4l2_subdev_format *format = arg;
+
+               if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
+                   format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+                       return -EINVAL;
+
+               if (format->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
+       }
+
+       case VIDIOC_SUBDEV_G_CROP: {
+               struct v4l2_subdev_crop *crop = arg;
+
+               if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+                   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+                       return -EINVAL;
+
+               if (crop->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+       }
+
+       case VIDIOC_SUBDEV_S_CROP: {
+               struct v4l2_subdev_crop *crop = arg;
+
+               if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+                   crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+                       return -EINVAL;
+
+               if (crop->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+       }
+
+       case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
+               struct v4l2_subdev_mbus_code_enum *code = arg;
+
+               if (code->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh,
+                                       code);
+       }
+
+       case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
+               struct v4l2_subdev_frame_size_enum *fse = arg;
+
+               if (fse->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
+                                       fse);
+       }
+
+       case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
+               return v4l2_subdev_call(sd, video, g_frame_interval, arg);
+
+       case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
+               return v4l2_subdev_call(sd, video, s_frame_interval, arg);
+
+       case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
+               struct v4l2_subdev_frame_interval_enum *fie = arg;
+
+               if (fie->pad >= sd->entity.num_pads)
+                       return -EINVAL;
+
+               return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
+                                       fie);
+       }
+#endif
+       default:
+               return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+       }
+
+       return 0;
+}
+
+static long subdev_ioctl(struct file *file, unsigned int cmd,
+       unsigned long arg)
+{
+       return video_usercopy(file, cmd, arg, subdev_do_ioctl);
+}
+
+static unsigned int subdev_poll(struct file *file, poll_table *wait)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+       struct v4l2_fh *fh = file->private_data;
+
+       if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+               return POLLERR;
+
+       poll_wait(file, &fh->events->wait, wait);
+
+       if (v4l2_event_pending(fh))
+               return POLLPRI;
+
+       return 0;
+}
+
+const struct v4l2_file_operations v4l2_subdev_fops = {
+       .owner = THIS_MODULE,
+       .open = subdev_open,
+       .unlocked_ioctl = subdev_ioctl,
+       .release = subdev_close,
+       .poll = subdev_poll,
+};
+
+void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+{
+       INIT_LIST_HEAD(&sd->list);
+       BUG_ON(!ops);
+       sd->ops = ops;
+       sd->v4l2_dev = NULL;
+       sd->flags = 0;
+       sd->name[0] = '\0';
+       sd->grp_id = 0;
+       sd->dev_priv = NULL;
+       sd->host_priv = NULL;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       sd->entity.name = sd->name;
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+#endif
+}
+EXPORT_SYMBOL(v4l2_subdev_init);
index 2f973cd5640869c9c62bc0d7b2885ae12b8f0b19..8c780c2d937be5b02d174c04d35d5f97815ac2e1 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
 #include <linux/via_i2c.h>
+#include <asm/olpc.h>
 
 #include "via-camera.h"
 
@@ -38,14 +39,12 @@ MODULE_PARM_DESC(flip_image,
                "If set, the sensor will be instructed to flip the image "
                "vertically.");
 
-#ifdef CONFIG_OLPC_XO_1_5
 static int override_serial;
 module_param(override_serial, bool, 0444);
 MODULE_PARM_DESC(override_serial,
                "The camera driver will normally refuse to load if "
                "the XO 1.5 serial port is enabled.  Set this option "
-               "to force the issue.");
-#endif
+               "to force-enable the camera.");
 
 /*
  * Basic window sizes.
@@ -1246,6 +1245,62 @@ static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
 /*
  * Power management.
  */
+#ifdef CONFIG_PM
+
+static int viacam_suspend(void *priv)
+{
+       struct via_camera *cam = priv;
+       enum viacam_opstate state = cam->opstate;
+
+       if (cam->opstate != S_IDLE) {
+               viacam_stop_engine(cam);
+               cam->opstate = state; /* So resume restarts */
+       }
+
+       return 0;
+}
+
+static int viacam_resume(void *priv)
+{
+       struct via_camera *cam = priv;
+       int ret = 0;
+
+       /*
+        * Get back to a reasonable operating state.
+        */
+       via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+       via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+       viacam_int_disable(cam);
+       set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       /*
+        * Make sure the sensor's power state is correct
+        */
+       if (cam->users > 0)
+               via_sensor_power_up(cam);
+       else
+               via_sensor_power_down(cam);
+       /*
+        * If it was operating, try to restart it.
+        */
+       if (cam->opstate != S_IDLE) {
+               mutex_lock(&cam->lock);
+               ret = viacam_configure_sensor(cam);
+               if (!ret)
+                       ret = viacam_config_controller(cam);
+               mutex_unlock(&cam->lock);
+               if (!ret)
+                       viacam_start_engine(cam);
+       }
+
+       return ret;
+}
+
+static struct viafb_pm_hooks viacam_pm_hooks = {
+       .suspend = viacam_suspend,
+       .resume = viacam_resume
+};
+
+#endif /* CONFIG_PM */
 
 /*
  * Setup stuff.
@@ -1261,6 +1316,37 @@ static struct video_device viacam_v4l_template = {
        .release        = video_device_release_empty, /* Check this */
 };
 
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera. They also get grumpy if we break the
+ * serial port and keep them from using it.  So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit bool viacam_serial_is_enabled(void)
+{
+       struct pci_bus *pbus = pci_find_bus(0, 0);
+       u8 cbyte;
+
+       pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+                       VIACAM_SERIAL_CREG, &cbyte);
+       if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+               return false; /* Not enabled */
+       if (override_serial == 0) {
+               printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+                               "refusing to load.\n");
+               printk(KERN_NOTICE "Specify override_serial=1 to force " \
+                               "module loading.\n");
+               return true;
+       }
+       printk(KERN_NOTICE "Via camera: overriding serial port\n");
+       pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+                       VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+       return false;
+}
 
 static __devinit int viacam_probe(struct platform_device *pdev)
 {
@@ -1292,6 +1378,10 @@ static __devinit int viacam_probe(struct platform_device *pdev)
                printk(KERN_ERR "viacam: No I/O memory, so no pictures\n");
                return -ENOMEM;
        }
+
+       if (machine_is_olpc() && viacam_serial_is_enabled())
+               return -EBUSY;
+
        /*
         * Basic structure initialization.
         */
@@ -1369,6 +1459,14 @@ static __devinit int viacam_probe(struct platform_device *pdev)
                goto out_irq;
        video_set_drvdata(&cam->vdev, cam);
 
+#ifdef CONFIG_PM
+       /*
+        * Hook into PM events
+        */
+       viacam_pm_hooks.private = cam;
+       viafb_pm_register(&viacam_pm_hooks);
+#endif
+
        /* Power the sensor down until somebody opens the device */
        via_sensor_power_down(cam);
        return 0;
@@ -1395,7 +1493,6 @@ static __devexit int viacam_remove(struct platform_device *pdev)
        return 0;
 }
 
-
 static struct platform_driver viacam_driver = {
        .driver = {
                .name = "viafb-camera",
@@ -1404,50 +1501,8 @@ static struct platform_driver viacam_driver = {
        .remove = viacam_remove,
 };
 
-
-#ifdef CONFIG_OLPC_XO_1_5
-/*
- * The OLPC folks put the serial port on the same pin as
- * the camera. They also get grumpy if we break the
- * serial port and keep them from using it.  So we have
- * to check the serial enable bit and not step on it.
- */
-#define VIACAM_SERIAL_DEVFN 0x88
-#define VIACAM_SERIAL_CREG 0x46
-#define VIACAM_SERIAL_BIT 0x40
-
-static __devinit int viacam_check_serial_port(void)
-{
-       struct pci_bus *pbus = pci_find_bus(0, 0);
-       u8 cbyte;
-
-       pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
-                       VIACAM_SERIAL_CREG, &cbyte);
-       if ((cbyte & VIACAM_SERIAL_BIT) == 0)
-               return 0; /* Not enabled */
-       if (override_serial == 0) {
-               printk(KERN_NOTICE "Via camera: serial port is enabled, " \
-                               "refusing to load.\n");
-               printk(KERN_NOTICE "Specify override_serial=1 to force " \
-                               "module loading.\n");
-               return -EBUSY;
-       }
-       printk(KERN_NOTICE "Via camera: overriding serial port\n");
-       pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
-                       VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
-       return 0;
-}
-#endif
-
-
-
-
 static int viacam_init(void)
 {
-#ifdef CONFIG_OLPC_XO_1_5
-       if (viacam_check_serial_port())
-               return -EBUSY;
-#endif
        return platform_driver_register(&viacam_driver);
 }
 module_init(viacam_init);
index c9691115f2d26787fa9d85ae98382539d78a8a98..c4742fc15529a97cf4472dde06717f9ef7d31233 100644 (file)
@@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        retval = remap_pfn_range(vma, vma->vm_start,
-                                mem->dma_handle >> PAGE_SHIFT,
+                                PFN_DOWN(virt_to_phys(mem->vaddr)),
                                 size, vma->vm_page_prot);
        if (retval) {
                dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
new file mode 100644 (file)
index 0000000..6698c77
--- /dev/null
@@ -0,0 +1,1819 @@
+/*
+ * videobuf2-core.c - V4L2 driver helper framework
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.com>
+ *        Marek Szyprowski <m.szyprowski@samsung.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.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <media/videobuf2-core.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...)                                    \
+       do {                                                            \
+               if (debug >= level)                                     \
+                       printk(KERN_DEBUG "vb2: " fmt, ## arg);         \
+       } while (0)
+
+#define call_memop(q, plane, op, args...)                              \
+       (((q)->mem_ops->op) ?                                           \
+               ((q)->mem_ops->op(args)) : 0)
+
+#define call_qop(q, op, args...)                                       \
+       (((q)->ops->op) ? ((q)->ops->op(args)) : 0)
+
+/**
+ * __vb2_buf_mem_alloc() - allocate video memory for the given buffer
+ */
+static int __vb2_buf_mem_alloc(struct vb2_buffer *vb,
+                               unsigned long *plane_sizes)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       void *mem_priv;
+       int plane;
+
+       /* Allocate memory for all planes in this buffer */
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane],
+                                       plane_sizes[plane]);
+               if (!mem_priv)
+                       goto free;
+
+               /* Associate allocator private data with this plane */
+               vb->planes[plane].mem_priv = mem_priv;
+               vb->v4l2_planes[plane].length = plane_sizes[plane];
+       }
+
+       return 0;
+free:
+       /* Free already allocated memory if one of the allocations failed */
+       for (; plane > 0; --plane)
+               call_memop(q, plane, put, vb->planes[plane - 1].mem_priv);
+
+       return -ENOMEM;
+}
+
+/**
+ * __vb2_buf_mem_free() - free memory of the given buffer
+ */
+static void __vb2_buf_mem_free(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       unsigned int plane;
+
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               call_memop(q, plane, put, vb->planes[plane].mem_priv);
+               vb->planes[plane].mem_priv = NULL;
+               dprintk(3, "Freed plane %d of buffer %d\n",
+                               plane, vb->v4l2_buf.index);
+       }
+}
+
+/**
+ * __vb2_buf_userptr_put() - release userspace memory associated with
+ * a USERPTR buffer
+ */
+static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       unsigned int plane;
+
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               void *mem_priv = vb->planes[plane].mem_priv;
+
+               if (mem_priv) {
+                       call_memop(q, plane, put_userptr, mem_priv);
+                       vb->planes[plane].mem_priv = NULL;
+               }
+       }
+}
+
+/**
+ * __setup_offsets() - setup unique offsets ("cookies") for every plane in
+ * every buffer on the queue
+ */
+static void __setup_offsets(struct vb2_queue *q)
+{
+       unsigned int buffer, plane;
+       struct vb2_buffer *vb;
+       unsigned long off = 0;
+
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               vb = q->bufs[buffer];
+               if (!vb)
+                       continue;
+
+               for (plane = 0; plane < vb->num_planes; ++plane) {
+                       vb->v4l2_planes[plane].m.mem_offset = off;
+
+                       dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
+                                       buffer, plane, off);
+
+                       off += vb->v4l2_planes[plane].length;
+                       off = PAGE_ALIGN(off);
+               }
+       }
+}
+
+/**
+ * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
+ * video buffer memory for all buffers/planes on the queue and initializes the
+ * queue
+ *
+ * Returns the number of buffers successfully allocated.
+ */
+static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
+                            unsigned int num_buffers, unsigned int num_planes,
+                            unsigned long plane_sizes[])
+{
+       unsigned int buffer;
+       struct vb2_buffer *vb;
+       int ret;
+
+       for (buffer = 0; buffer < num_buffers; ++buffer) {
+               /* Allocate videobuf buffer structures */
+               vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
+               if (!vb) {
+                       dprintk(1, "Memory alloc for buffer struct failed\n");
+                       break;
+               }
+
+               /* Length stores number of planes for multiplanar buffers */
+               if (V4L2_TYPE_IS_MULTIPLANAR(q->type))
+                       vb->v4l2_buf.length = num_planes;
+
+               vb->state = VB2_BUF_STATE_DEQUEUED;
+               vb->vb2_queue = q;
+               vb->num_planes = num_planes;
+               vb->v4l2_buf.index = buffer;
+               vb->v4l2_buf.type = q->type;
+               vb->v4l2_buf.memory = memory;
+
+               /* Allocate video buffer memory for the MMAP type */
+               if (memory == V4L2_MEMORY_MMAP) {
+                       ret = __vb2_buf_mem_alloc(vb, plane_sizes);
+                       if (ret) {
+                               dprintk(1, "Failed allocating memory for "
+                                               "buffer %d\n", buffer);
+                               kfree(vb);
+                               break;
+                       }
+                       /*
+                        * Call the driver-provided buffer initialization
+                        * callback, if given. An error in initialization
+                        * results in queue setup failure.
+                        */
+                       ret = call_qop(q, buf_init, vb);
+                       if (ret) {
+                               dprintk(1, "Buffer %d %p initialization"
+                                       " failed\n", buffer, vb);
+                               __vb2_buf_mem_free(vb);
+                               kfree(vb);
+                               break;
+                       }
+               }
+
+               q->bufs[buffer] = vb;
+       }
+
+       q->num_buffers = buffer;
+
+       __setup_offsets(q);
+
+       dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
+                       q->num_buffers, num_planes);
+
+       return buffer;
+}
+
+/**
+ * __vb2_free_mem() - release all video buffer memory for a given queue
+ */
+static void __vb2_free_mem(struct vb2_queue *q)
+{
+       unsigned int buffer;
+       struct vb2_buffer *vb;
+
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               vb = q->bufs[buffer];
+               if (!vb)
+                       continue;
+
+               /* Free MMAP buffers or release USERPTR buffers */
+               if (q->memory == V4L2_MEMORY_MMAP)
+                       __vb2_buf_mem_free(vb);
+               else
+                       __vb2_buf_userptr_put(vb);
+       }
+}
+
+/**
+ * __vb2_queue_free() - free the queue - video memory and related information
+ * and return the queue to an uninitialized state. Might be called even if the
+ * queue has already been freed.
+ */
+static void __vb2_queue_free(struct vb2_queue *q)
+{
+       unsigned int buffer;
+
+       /* Call driver-provided cleanup function for each buffer, if provided */
+       if (q->ops->buf_cleanup) {
+               for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+                       if (NULL == q->bufs[buffer])
+                               continue;
+                       q->ops->buf_cleanup(q->bufs[buffer]);
+               }
+       }
+
+       /* Release video buffer memory */
+       __vb2_free_mem(q);
+
+       /* Free videobuf buffers */
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               kfree(q->bufs[buffer]);
+               q->bufs[buffer] = NULL;
+       }
+
+       q->num_buffers = 0;
+       q->memory = 0;
+}
+
+/**
+ * __verify_planes_array() - verify that the planes array passed in struct
+ * v4l2_buffer from userspace can be safely used
+ */
+static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+       /* Is memory for copying plane information present? */
+       if (NULL == b->m.planes) {
+               dprintk(1, "Multi-planar buffer passed but "
+                          "planes array not provided\n");
+               return -EINVAL;
+       }
+
+       if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) {
+               dprintk(1, "Incorrect planes array length, "
+                          "expected %d, got %d\n", vb->num_planes, b->length);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
+ * returned to userspace
+ */
+static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       int ret = 0;
+
+       /* Copy back data such as timestamp, input, etc. */
+       memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
+       b->input = vb->v4l2_buf.input;
+       b->reserved = vb->v4l2_buf.reserved;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
+               ret = __verify_planes_array(vb, b);
+               if (ret)
+                       return ret;
+
+               /*
+                * Fill in plane-related data if userspace provided an array
+                * for it. The memory and size is verified above.
+                */
+               memcpy(b->m.planes, vb->v4l2_planes,
+                       b->length * sizeof(struct v4l2_plane));
+       } else {
+               /*
+                * We use length and offset in v4l2_planes array even for
+                * single-planar buffers, but userspace does not.
+                */
+               b->length = vb->v4l2_planes[0].length;
+               b->bytesused = vb->v4l2_planes[0].bytesused;
+               if (q->memory == V4L2_MEMORY_MMAP)
+                       b->m.offset = vb->v4l2_planes[0].m.mem_offset;
+               else if (q->memory == V4L2_MEMORY_USERPTR)
+                       b->m.userptr = vb->v4l2_planes[0].m.userptr;
+       }
+
+       b->flags = 0;
+
+       switch (vb->state) {
+       case VB2_BUF_STATE_QUEUED:
+       case VB2_BUF_STATE_ACTIVE:
+               b->flags |= V4L2_BUF_FLAG_QUEUED;
+               break;
+       case VB2_BUF_STATE_ERROR:
+               b->flags |= V4L2_BUF_FLAG_ERROR;
+               /* fall through */
+       case VB2_BUF_STATE_DONE:
+               b->flags |= V4L2_BUF_FLAG_DONE;
+               break;
+       case VB2_BUF_STATE_DEQUEUED:
+               /* nothing */
+               break;
+       }
+
+       if (vb->num_planes_mapped == vb->num_planes)
+               b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+       return ret;
+}
+
+/**
+ * vb2_querybuf() - query video buffer information
+ * @q:         videobuf queue
+ * @b:         buffer struct passed from userspace to vidioc_querybuf handler
+ *             in driver
+ *
+ * Should be called from vidioc_querybuf ioctl handler in driver.
+ * This function will verify the passed v4l2_buffer structure and fill the
+ * relevant information for the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_querybuf handler in driver.
+ */
+int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+       struct vb2_buffer *vb;
+
+       if (b->type != q->type) {
+               dprintk(1, "querybuf: wrong buffer type\n");
+               return -EINVAL;
+       }
+
+       if (b->index >= q->num_buffers) {
+               dprintk(1, "querybuf: buffer index out of range\n");
+               return -EINVAL;
+       }
+       vb = q->bufs[b->index];
+
+       return __fill_v4l2_buffer(vb, b);
+}
+EXPORT_SYMBOL(vb2_querybuf);
+
+/**
+ * __verify_userptr_ops() - verify that all memory operations required for
+ * USERPTR queue type have been provided
+ */
+static int __verify_userptr_ops(struct vb2_queue *q)
+{
+       if (!(q->io_modes & VB2_USERPTR) || !q->mem_ops->get_userptr ||
+           !q->mem_ops->put_userptr)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * __verify_mmap_ops() - verify that all memory operations required for
+ * MMAP queue type have been provided
+ */
+static int __verify_mmap_ops(struct vb2_queue *q)
+{
+       if (!(q->io_modes & VB2_MMAP) || !q->mem_ops->alloc ||
+           !q->mem_ops->put || !q->mem_ops->mmap)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * __buffers_in_use() - return true if any buffers on the queue are in use and
+ * the queue cannot be freed (by the means of REQBUFS(0)) call
+ */
+static bool __buffers_in_use(struct vb2_queue *q)
+{
+       unsigned int buffer, plane;
+       struct vb2_buffer *vb;
+
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               vb = q->bufs[buffer];
+               for (plane = 0; plane < vb->num_planes; ++plane) {
+                       /*
+                        * If num_users() has not been provided, call_memop
+                        * will return 0, apparently nobody cares about this
+                        * case anyway. If num_users() returns more than 1,
+                        * we are not the only user of the plane's memory.
+                        */
+                       if (call_memop(q, plane, num_users,
+                                       vb->planes[plane].mem_priv) > 1)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+/**
+ * vb2_reqbufs() - Initiate streaming
+ * @q:         videobuf2 queue
+ * @req:       struct passed from userspace to vidioc_reqbufs handler in driver
+ *
+ * Should be called from vidioc_reqbufs ioctl handler of a driver.
+ * This function:
+ * 1) verifies streaming parameters passed from the userspace,
+ * 2) sets up the queue,
+ * 3) negotiates number of buffers and planes per buffer with the driver
+ *    to be used during streaming,
+ * 4) allocates internal buffer structures (struct vb2_buffer), according to
+ *    the agreed parameters,
+ * 5) for MMAP memory type, allocates actual video memory, using the
+ *    memory handling/allocation routines provided during queue initialization
+ *
+ * If req->count is 0, all the memory will be freed instead.
+ * If the queue has been allocated previously (by a previous vb2_reqbufs) call
+ * and the queue is not busy, memory will be reallocated.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_reqbufs handler in driver.
+ */
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+{
+       unsigned int num_buffers, num_planes;
+       unsigned long plane_sizes[VIDEO_MAX_PLANES];
+       int ret = 0;
+
+       if (q->fileio) {
+               dprintk(1, "reqbufs: file io in progress\n");
+               return -EBUSY;
+       }
+
+       if (req->memory != V4L2_MEMORY_MMAP
+                       && req->memory != V4L2_MEMORY_USERPTR) {
+               dprintk(1, "reqbufs: unsupported memory type\n");
+               return -EINVAL;
+       }
+
+       if (req->type != q->type) {
+               dprintk(1, "reqbufs: requested type is incorrect\n");
+               return -EINVAL;
+       }
+
+       if (q->streaming) {
+               dprintk(1, "reqbufs: streaming active\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Make sure all the required memory ops for given memory type
+        * are available.
+        */
+       if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
+               dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
+               return -EINVAL;
+       }
+
+       if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
+               dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
+               return -EINVAL;
+       }
+
+       /*
+        * If the same number of buffers and memory access method is requested
+        * then return immediately.
+        */
+       if (q->memory == req->memory && req->count == q->num_buffers)
+               return 0;
+
+       if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
+               /*
+                * We already have buffers allocated, so first check if they
+                * are not in use and can be freed.
+                */
+               if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
+                       dprintk(1, "reqbufs: memory in use, cannot free\n");
+                       return -EBUSY;
+               }
+
+               __vb2_queue_free(q);
+
+               /*
+                * In case of REQBUFS(0) return immediately without calling
+                * driver's queue_setup() callback and allocating resources.
+                */
+               if (req->count == 0)
+                       return 0;
+       }
+
+       /*
+        * Make sure the requested values and current defaults are sane.
+        */
+       num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
+       memset(plane_sizes, 0, sizeof(plane_sizes));
+       memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
+
+       /*
+        * Ask the driver how many buffers and planes per buffer it requires.
+        * Driver also sets the size and allocator context for each plane.
+        */
+       ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
+                      plane_sizes, q->alloc_ctx);
+       if (ret)
+               return ret;
+
+       /* Finally, allocate buffers and video memory */
+       ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes,
+                               plane_sizes);
+       if (ret < 0) {
+               dprintk(1, "Memory allocation failed with error: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Check if driver can handle the allocated number of buffers.
+        */
+       if (ret < num_buffers) {
+               unsigned int orig_num_buffers;
+
+               orig_num_buffers = num_buffers = ret;
+               ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
+                              plane_sizes, q->alloc_ctx);
+               if (ret)
+                       goto free_mem;
+
+               if (orig_num_buffers < num_buffers) {
+                       ret = -ENOMEM;
+                       goto free_mem;
+               }
+
+               /*
+                * Ok, driver accepted smaller number of buffers.
+                */
+               ret = num_buffers;
+       }
+
+       q->memory = req->memory;
+
+       /*
+        * Return the number of successfully allocated buffers
+        * to the userspace.
+        */
+       req->count = ret;
+
+       return 0;
+
+free_mem:
+       __vb2_queue_free(q);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_reqbufs);
+
+/**
+ * vb2_plane_vaddr() - Return a kernel virtual address of a given plane
+ * @vb:                vb2_buffer to which the plane in question belongs to
+ * @plane_no:  plane number for which the address is to be returned
+ *
+ * This function returns a kernel virtual address of a given plane if
+ * such a mapping exist, NULL otherwise.
+ */
+void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+
+       if (plane_no > vb->num_planes)
+               return NULL;
+
+       return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv);
+
+}
+EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
+
+/**
+ * vb2_plane_cookie() - Return allocator specific cookie for the given plane
+ * @vb:                vb2_buffer to which the plane in question belongs to
+ * @plane_no:  plane number for which the cookie is to be returned
+ *
+ * This function returns an allocator specific cookie for a given plane if
+ * available, NULL otherwise. The allocator should provide some simple static
+ * inline function, which would convert this cookie to the allocator specific
+ * type that can be used directly by the driver to access the buffer. This can
+ * be for example physical address, pointer to scatter list or IOMMU mapping.
+ */
+void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+
+       if (plane_no > vb->num_planes)
+               return NULL;
+
+       return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv);
+}
+EXPORT_SYMBOL_GPL(vb2_plane_cookie);
+
+/**
+ * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished
+ * @vb:                vb2_buffer returned from the driver
+ * @state:     either VB2_BUF_STATE_DONE if the operation finished successfully
+ *             or VB2_BUF_STATE_ERROR if the operation finished with an error
+ *
+ * This function should be called by the driver after a hardware operation on
+ * a buffer is finished and the buffer may be returned to userspace. The driver
+ * cannot use this buffer anymore until it is queued back to it by videobuf
+ * by the means of buf_queue callback. Only buffers previously queued to the
+ * driver by buf_queue can be passed to this function.
+ */
+void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       unsigned long flags;
+
+       if (vb->state != VB2_BUF_STATE_ACTIVE)
+               return;
+
+       if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR)
+               return;
+
+       dprintk(4, "Done processing on buffer %d, state: %d\n",
+                       vb->v4l2_buf.index, vb->state);
+
+       /* Add the buffer to the done buffers list */
+       spin_lock_irqsave(&q->done_lock, flags);
+       vb->state = state;
+       list_add_tail(&vb->done_entry, &q->done_list);
+       atomic_dec(&q->queued_count);
+       spin_unlock_irqrestore(&q->done_lock, flags);
+
+       /* Inform any processes that may be waiting for buffers */
+       wake_up(&q->done_wq);
+}
+EXPORT_SYMBOL_GPL(vb2_buffer_done);
+
+/**
+ * __fill_vb2_buffer() - fill a vb2_buffer with information provided in
+ * a v4l2_buffer by the userspace
+ */
+static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b,
+                               struct v4l2_plane *v4l2_planes)
+{
+       unsigned int plane;
+       int ret;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+               /*
+                * Verify that the userspace gave us a valid array for
+                * plane information.
+                */
+               ret = __verify_planes_array(vb, b);
+               if (ret)
+                       return ret;
+
+               /* Fill in driver-provided information for OUTPUT types */
+               if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+                       /*
+                        * Will have to go up to b->length when API starts
+                        * accepting variable number of planes.
+                        */
+                       for (plane = 0; plane < vb->num_planes; ++plane) {
+                               v4l2_planes[plane].bytesused =
+                                       b->m.planes[plane].bytesused;
+                               v4l2_planes[plane].data_offset =
+                                       b->m.planes[plane].data_offset;
+                       }
+               }
+
+               if (b->memory == V4L2_MEMORY_USERPTR) {
+                       for (plane = 0; plane < vb->num_planes; ++plane) {
+                               v4l2_planes[plane].m.userptr =
+                                       b->m.planes[plane].m.userptr;
+                               v4l2_planes[plane].length =
+                                       b->m.planes[plane].length;
+                       }
+               }
+       } else {
+               /*
+                * Single-planar buffers do not use planes array,
+                * so fill in relevant v4l2_buffer struct fields instead.
+                * In videobuf we use our internal V4l2_planes struct for
+                * single-planar buffers as well, for simplicity.
+                */
+               if (V4L2_TYPE_IS_OUTPUT(b->type))
+                       v4l2_planes[0].bytesused = b->bytesused;
+
+               if (b->memory == V4L2_MEMORY_USERPTR) {
+                       v4l2_planes[0].m.userptr = b->m.userptr;
+                       v4l2_planes[0].length = b->length;
+               }
+       }
+
+       vb->v4l2_buf.field = b->field;
+       vb->v4l2_buf.timestamp = b->timestamp;
+
+       return 0;
+}
+
+/**
+ * __qbuf_userptr() - handle qbuf of a USERPTR buffer
+ */
+static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+       struct v4l2_plane planes[VIDEO_MAX_PLANES];
+       struct vb2_queue *q = vb->vb2_queue;
+       void *mem_priv;
+       unsigned int plane;
+       int ret;
+       int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+
+       /* Verify and copy relevant information provided by the userspace */
+       ret = __fill_vb2_buffer(vb, b, planes);
+       if (ret)
+               return ret;
+
+       for (plane = 0; plane < vb->num_planes; ++plane) {
+               /* Skip the plane if already verified */
+               if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr
+                   && vb->v4l2_planes[plane].length == planes[plane].length)
+                       continue;
+
+               dprintk(3, "qbuf: userspace address for plane %d changed, "
+                               "reacquiring memory\n", plane);
+
+               /* Release previously acquired memory if present */
+               if (vb->planes[plane].mem_priv)
+                       call_memop(q, plane, put_userptr,
+                                       vb->planes[plane].mem_priv);
+
+               vb->planes[plane].mem_priv = NULL;
+
+               /* Acquire each plane's memory */
+               if (q->mem_ops->get_userptr) {
+                       mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane],
+                                                       planes[plane].m.userptr,
+                                                       planes[plane].length,
+                                                       write);
+                       if (IS_ERR(mem_priv)) {
+                               dprintk(1, "qbuf: failed acquiring userspace "
+                                               "memory for plane %d\n", plane);
+                               ret = PTR_ERR(mem_priv);
+                               goto err;
+                       }
+                       vb->planes[plane].mem_priv = mem_priv;
+               }
+       }
+
+       /*
+        * Call driver-specific initialization on the newly acquired buffer,
+        * if provided.
+        */
+       ret = call_qop(q, buf_init, vb);
+       if (ret) {
+               dprintk(1, "qbuf: buffer initialization failed\n");
+               goto err;
+       }
+
+       /*
+        * Now that everything is in order, copy relevant information
+        * provided by userspace.
+        */
+       for (plane = 0; plane < vb->num_planes; ++plane)
+               vb->v4l2_planes[plane] = planes[plane];
+
+       return 0;
+err:
+       /* In case of errors, release planes that were already acquired */
+       for (; plane > 0; --plane) {
+               call_memop(q, plane, put_userptr,
+                               vb->planes[plane - 1].mem_priv);
+               vb->planes[plane - 1].mem_priv = NULL;
+       }
+
+       return ret;
+}
+
+/**
+ * __qbuf_mmap() - handle qbuf of an MMAP buffer
+ */
+static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b)
+{
+       return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
+}
+
+/**
+ * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
+ */
+static void __enqueue_in_driver(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+
+       vb->state = VB2_BUF_STATE_ACTIVE;
+       atomic_inc(&q->queued_count);
+       q->ops->buf_queue(vb);
+}
+
+/**
+ * vb2_qbuf() - Queue a buffer from userspace
+ * @q:         videobuf2 queue
+ * @b:         buffer structure passed from userspace to vidioc_qbuf handler
+ *             in driver
+ *
+ * Should be called from vidioc_qbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_prepare callback in the driver (if provided), in which
+ *    driver-specific buffer initialization can be performed,
+ * 3) if streaming is on, queues the buffer in driver by the means of buf_queue
+ *    callback for processing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_qbuf handler in driver.
+ */
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+       struct vb2_buffer *vb;
+       int ret = 0;
+
+       if (q->fileio) {
+               dprintk(1, "qbuf: file io in progress\n");
+               return -EBUSY;
+       }
+
+       if (b->type != q->type) {
+               dprintk(1, "qbuf: invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       if (b->index >= q->num_buffers) {
+               dprintk(1, "qbuf: buffer index out of range\n");
+               return -EINVAL;
+       }
+
+       vb = q->bufs[b->index];
+       if (NULL == vb) {
+               /* Should never happen */
+               dprintk(1, "qbuf: buffer is NULL\n");
+               return -EINVAL;
+       }
+
+       if (b->memory != q->memory) {
+               dprintk(1, "qbuf: invalid memory type\n");
+               return -EINVAL;
+       }
+
+       if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+               dprintk(1, "qbuf: buffer already in use\n");
+               return -EINVAL;
+       }
+
+       if (q->memory == V4L2_MEMORY_MMAP)
+               ret = __qbuf_mmap(vb, b);
+       else if (q->memory == V4L2_MEMORY_USERPTR)
+               ret = __qbuf_userptr(vb, b);
+       else {
+               WARN(1, "Invalid queue type\n");
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       ret = call_qop(q, buf_prepare, vb);
+       if (ret) {
+               dprintk(1, "qbuf: buffer preparation failed\n");
+               return ret;
+       }
+
+       /*
+        * Add to the queued buffers list, a buffer will stay on it until
+        * dequeued in dqbuf.
+        */
+       list_add_tail(&vb->queued_entry, &q->queued_list);
+       vb->state = VB2_BUF_STATE_QUEUED;
+
+       /*
+        * If already streaming, give the buffer to driver for processing.
+        * If not, the buffer will be given to driver on next streamon.
+        */
+       if (q->streaming)
+               __enqueue_in_driver(vb);
+
+       dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf);
+
+/**
+ * __vb2_wait_for_done_vb() - wait for a buffer to become available
+ * for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
+{
+       /*
+        * All operations on vb_done_list are performed under done_lock
+        * spinlock protection. However, buffers may be removed from
+        * it and returned to userspace only while holding both driver's
+        * lock and the done_lock spinlock. Thus we can be sure that as
+        * long as we hold the driver's lock, the list will remain not
+        * empty if list_empty() check succeeds.
+        */
+
+       for (;;) {
+               int ret;
+
+               if (!q->streaming) {
+                       dprintk(1, "Streaming off, will not wait for buffers\n");
+                       return -EINVAL;
+               }
+
+               if (!list_empty(&q->done_list)) {
+                       /*
+                        * Found a buffer that we were waiting for.
+                        */
+                       break;
+               }
+
+               if (nonblocking) {
+                       dprintk(1, "Nonblocking and no buffers to dequeue, "
+                                                               "will not wait\n");
+                       return -EAGAIN;
+               }
+
+               /*
+                * We are streaming and blocking, wait for another buffer to
+                * become ready or for streamoff. Driver's lock is released to
+                * allow streamoff or qbuf to be called while waiting.
+                */
+               call_qop(q, wait_prepare, q);
+
+               /*
+                * All locks have been released, it is safe to sleep now.
+                */
+               dprintk(3, "Will sleep waiting for buffers\n");
+               ret = wait_event_interruptible(q->done_wq,
+                               !list_empty(&q->done_list) || !q->streaming);
+
+               /*
+                * We need to reevaluate both conditions again after reacquiring
+                * the locks or return an error if one occurred.
+                */
+               call_qop(q, wait_finish, q);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/**
+ * __vb2_get_done_vb() - get a buffer ready for dequeuing
+ *
+ * Will sleep if required for nonblocking == false.
+ */
+static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
+                               int nonblocking)
+{
+       unsigned long flags;
+       int ret;
+
+       /*
+        * Wait for at least one buffer to become available on the done_list.
+        */
+       ret = __vb2_wait_for_done_vb(q, nonblocking);
+       if (ret)
+               return ret;
+
+       /*
+        * Driver's lock has been held since we last verified that done_list
+        * is not empty, so no need for another list_empty(done_list) check.
+        */
+       spin_lock_irqsave(&q->done_lock, flags);
+       *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
+       list_del(&(*vb)->done_entry);
+       spin_unlock_irqrestore(&q->done_lock, flags);
+
+       return 0;
+}
+
+/**
+ * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2
+ * @q:         videobuf2 queue
+ *
+ * This function will wait until all buffers that have been given to the driver
+ * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call
+ * wait_prepare, wait_finish pair. It is intended to be called with all locks
+ * taken, for example from stop_streaming() callback.
+ */
+int vb2_wait_for_all_buffers(struct vb2_queue *q)
+{
+       if (!q->streaming) {
+               dprintk(1, "Streaming off, will not wait for buffers\n");
+               return -EINVAL;
+       }
+
+       wait_event(q->done_wq, !atomic_read(&q->queued_count));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
+
+/**
+ * vb2_dqbuf() - Dequeue a buffer to the userspace
+ * @q:         videobuf2 queue
+ * @b:         buffer structure passed from userspace to vidioc_dqbuf handler
+ *             in driver
+ * @nonblocking: if true, this call will not sleep waiting for a buffer if no
+ *              buffers ready for dequeuing are present. Normally the driver
+ *              would be passing (file->f_flags & O_NONBLOCK) here
+ *
+ * Should be called from vidioc_dqbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_finish callback in the driver (if provided), in which
+ *    driver can perform any additional operations that may be required before
+ *    returning the buffer to userspace, such as cache sync,
+ * 3) the buffer struct members are filled with relevant information for
+ *    the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_dqbuf handler in driver.
+ */
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+       struct vb2_buffer *vb = NULL;
+       int ret;
+
+       if (q->fileio) {
+               dprintk(1, "dqbuf: file io in progress\n");
+               return -EBUSY;
+       }
+
+       if (b->type != q->type) {
+               dprintk(1, "dqbuf: invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       ret = __vb2_get_done_vb(q, &vb, nonblocking);
+       if (ret < 0) {
+               dprintk(1, "dqbuf: error getting next done buffer\n");
+               return ret;
+       }
+
+       ret = call_qop(q, buf_finish, vb);
+       if (ret) {
+               dprintk(1, "dqbuf: buffer finish failed\n");
+               return ret;
+       }
+
+       switch (vb->state) {
+       case VB2_BUF_STATE_DONE:
+               dprintk(3, "dqbuf: Returning done buffer\n");
+               break;
+       case VB2_BUF_STATE_ERROR:
+               dprintk(3, "dqbuf: Returning done buffer with errors\n");
+               break;
+       default:
+               dprintk(1, "dqbuf: Invalid buffer state\n");
+               return -EINVAL;
+       }
+
+       /* Fill buffer information for the userspace */
+       __fill_v4l2_buffer(vb, b);
+       /* Remove from videobuf queue */
+       list_del(&vb->queued_entry);
+
+       dprintk(1, "dqbuf of buffer %d, with state %d\n",
+                       vb->v4l2_buf.index, vb->state);
+
+       vb->state = VB2_BUF_STATE_DEQUEUED;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_dqbuf);
+
+/**
+ * vb2_streamon - start streaming
+ * @q:         videobuf2 queue
+ * @type:      type argument passed from userspace to vidioc_streamon handler
+ *
+ * Should be called from vidioc_streamon handler of a driver.
+ * This function:
+ * 1) verifies current state
+ * 2) starts streaming and passes any previously queued buffers to the driver
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamon handler in the driver.
+ */
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+       struct vb2_buffer *vb;
+       int ret;
+
+       if (q->fileio) {
+               dprintk(1, "streamon: file io in progress\n");
+               return -EBUSY;
+       }
+
+       if (type != q->type) {
+               dprintk(1, "streamon: invalid stream type\n");
+               return -EINVAL;
+       }
+
+       if (q->streaming) {
+               dprintk(1, "streamon: already streaming\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Cannot start streaming on an OUTPUT device if no buffers have
+        * been queued yet.
+        */
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               if (list_empty(&q->queued_list)) {
+                       dprintk(1, "streamon: no output buffers queued\n");
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Let driver notice that streaming state has been enabled.
+        */
+       ret = call_qop(q, start_streaming, q);
+       if (ret) {
+               dprintk(1, "streamon: driver refused to start streaming\n");
+               return ret;
+       }
+
+       q->streaming = 1;
+
+       /*
+        * If any buffers were queued before streamon,
+        * we can now pass them to driver for processing.
+        */
+       list_for_each_entry(vb, &q->queued_list, queued_entry)
+               __enqueue_in_driver(vb);
+
+       dprintk(3, "Streamon successful\n");
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_streamon);
+
+/**
+ * __vb2_queue_cancel() - cancel and stop (pause) streaming
+ *
+ * Removes all queued buffers from driver's queue and all buffers queued by
+ * userspace from videobuf's queue. Returns to state after reqbufs.
+ */
+static void __vb2_queue_cancel(struct vb2_queue *q)
+{
+       unsigned int i;
+
+       /*
+        * Tell driver to stop all transactions and release all queued
+        * buffers.
+        */
+       if (q->streaming)
+               call_qop(q, stop_streaming, q);
+       q->streaming = 0;
+
+       /*
+        * Remove all buffers from videobuf's list...
+        */
+       INIT_LIST_HEAD(&q->queued_list);
+       /*
+        * ...and done list; userspace will not receive any buffers it
+        * has not already dequeued before initiating cancel.
+        */
+       INIT_LIST_HEAD(&q->done_list);
+       wake_up_all(&q->done_wq);
+
+       /*
+        * Reinitialize all buffers for next use.
+        */
+       for (i = 0; i < q->num_buffers; ++i)
+               q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
+}
+
+/**
+ * vb2_streamoff - stop streaming
+ * @q:         videobuf2 queue
+ * @type:      type argument passed from userspace to vidioc_streamoff handler
+ *
+ * Should be called from vidioc_streamoff handler of a driver.
+ * This function:
+ * 1) verifies current state,
+ * 2) stop streaming and dequeues any queued buffers, including those previously
+ *    passed to the driver (after waiting for the driver to finish).
+ *
+ * This call can be used for pausing playback.
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamoff handler in the driver
+ */
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+       if (q->fileio) {
+               dprintk(1, "streamoff: file io in progress\n");
+               return -EBUSY;
+       }
+
+       if (type != q->type) {
+               dprintk(1, "streamoff: invalid stream type\n");
+               return -EINVAL;
+       }
+
+       if (!q->streaming) {
+               dprintk(1, "streamoff: not streaming\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Cancel will pause streaming and remove all buffers from the driver
+        * and videobuf, effectively returning control over them to userspace.
+        */
+       __vb2_queue_cancel(q);
+
+       dprintk(3, "Streamoff successful\n");
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_streamoff);
+
+/**
+ * __find_plane_by_offset() - find plane associated with the given offset off
+ */
+static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
+                       unsigned int *_buffer, unsigned int *_plane)
+{
+       struct vb2_buffer *vb;
+       unsigned int buffer, plane;
+
+       /*
+        * Go over all buffers and their planes, comparing the given offset
+        * with an offset assigned to each plane. If a match is found,
+        * return its buffer and plane numbers.
+        */
+       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
+               vb = q->bufs[buffer];
+
+               for (plane = 0; plane < vb->num_planes; ++plane) {
+                       if (vb->v4l2_planes[plane].m.mem_offset == off) {
+                               *_buffer = buffer;
+                               *_plane = plane;
+                               return 0;
+                       }
+               }
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vb2_mmap() - map video buffers into application address space
+ * @q:         videobuf2 queue
+ * @vma:       vma passed to the mmap file operation handler in the driver
+ *
+ * Should be called from mmap file operation handler of a driver.
+ * This function maps one plane of one of the available video buffers to
+ * userspace. To map whole video memory allocated on reqbufs, this function
+ * has to be called once per each plane per each buffer previously allocated.
+ *
+ * When the userspace application calls mmap, it passes to it an offset returned
+ * to it earlier by the means of vidioc_querybuf handler. That offset acts as
+ * a "cookie", which is then used to identify the plane to be mapped.
+ * This function finds a plane with a matching offset and a mapping is performed
+ * by the means of a provided memory operation.
+ *
+ * The return values from this function are intended to be directly returned
+ * from the mmap handler in driver.
+ */
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
+{
+       unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+       struct vb2_plane *vb_plane;
+       struct vb2_buffer *vb;
+       unsigned int buffer, plane;
+       int ret;
+
+       if (q->memory != V4L2_MEMORY_MMAP) {
+               dprintk(1, "Queue is not currently set up for mmap\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Check memory area access mode.
+        */
+       if (!(vma->vm_flags & VM_SHARED)) {
+               dprintk(1, "Invalid vma flags, VM_SHARED needed\n");
+               return -EINVAL;
+       }
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               if (!(vma->vm_flags & VM_WRITE)) {
+                       dprintk(1, "Invalid vma flags, VM_WRITE needed\n");
+                       return -EINVAL;
+               }
+       } else {
+               if (!(vma->vm_flags & VM_READ)) {
+                       dprintk(1, "Invalid vma flags, VM_READ needed\n");
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * Find the plane corresponding to the offset passed by userspace.
+        */
+       ret = __find_plane_by_offset(q, off, &buffer, &plane);
+       if (ret)
+               return ret;
+
+       vb = q->bufs[buffer];
+       vb_plane = &vb->planes[plane];
+
+       ret = q->mem_ops->mmap(vb_plane->mem_priv, vma);
+       if (ret)
+               return ret;
+
+       vb_plane->mapped = 1;
+       vb->num_planes_mapped++;
+
+       dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_mmap);
+
+static int __vb2_init_fileio(struct vb2_queue *q, int read);
+static int __vb2_cleanup_fileio(struct vb2_queue *q);
+
+/**
+ * vb2_poll() - implements poll userspace operation
+ * @q:         videobuf2 queue
+ * @file:      file argument passed to the poll file operation handler
+ * @wait:      wait argument passed to the poll file operation handler
+ *
+ * This function implements poll file operation handler for a driver.
+ * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
+ * be informed that the file descriptor of a video device is available for
+ * reading.
+ * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
+ * will be reported as available for writing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from poll handler in driver.
+ */
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
+{
+       unsigned long flags;
+       unsigned int ret;
+       struct vb2_buffer *vb = NULL;
+
+       /*
+        * Start file I/O emulator only if streaming API has not been used yet.
+        */
+       if (q->num_buffers == 0 && q->fileio == NULL) {
+               if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) {
+                       ret = __vb2_init_fileio(q, 1);
+                       if (ret)
+                               return POLLERR;
+               }
+               if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) {
+                       ret = __vb2_init_fileio(q, 0);
+                       if (ret)
+                               return POLLERR;
+                       /*
+                        * Write to OUTPUT queue can be done immediately.
+                        */
+                       return POLLOUT | POLLWRNORM;
+               }
+       }
+
+       /*
+        * There is nothing to wait for if no buffers have already been queued.
+        */
+       if (list_empty(&q->queued_list))
+               return POLLERR;
+
+       poll_wait(file, &q->done_wq, wait);
+
+       /*
+        * Take first buffer available for dequeuing.
+        */
+       spin_lock_irqsave(&q->done_lock, flags);
+       if (!list_empty(&q->done_list))
+               vb = list_first_entry(&q->done_list, struct vb2_buffer,
+                                       done_entry);
+       spin_unlock_irqrestore(&q->done_lock, flags);
+
+       if (vb && (vb->state == VB2_BUF_STATE_DONE
+                       || vb->state == VB2_BUF_STATE_ERROR)) {
+               return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM :
+                       POLLIN | POLLRDNORM;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_poll);
+
+/**
+ * vb2_queue_init() - initialize a videobuf2 queue
+ * @q:         videobuf2 queue; this structure should be allocated in driver
+ *
+ * The vb2_queue structure should be allocated by the driver. The driver is
+ * responsible of clearing it's content and setting initial values for some
+ * required entries before calling this function.
+ * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
+ * to the struct vb2_queue description in include/media/videobuf2-core.h
+ * for more information.
+ */
+int vb2_queue_init(struct vb2_queue *q)
+{
+       BUG_ON(!q);
+       BUG_ON(!q->ops);
+       BUG_ON(!q->mem_ops);
+       BUG_ON(!q->type);
+       BUG_ON(!q->io_modes);
+
+       BUG_ON(!q->ops->queue_setup);
+       BUG_ON(!q->ops->buf_queue);
+
+       INIT_LIST_HEAD(&q->queued_list);
+       INIT_LIST_HEAD(&q->done_list);
+       spin_lock_init(&q->done_lock);
+       init_waitqueue_head(&q->done_wq);
+
+       if (q->buf_struct_size == 0)
+               q->buf_struct_size = sizeof(struct vb2_buffer);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_init);
+
+/**
+ * vb2_queue_release() - stop streaming, release the queue and free memory
+ * @q:         videobuf2 queue
+ *
+ * This function stops streaming and performs necessary clean ups, including
+ * freeing video buffer memory. The driver is responsible for freeing
+ * the vb2_queue structure itself.
+ */
+void vb2_queue_release(struct vb2_queue *q)
+{
+       __vb2_cleanup_fileio(q);
+       __vb2_queue_cancel(q);
+       __vb2_queue_free(q);
+}
+EXPORT_SYMBOL_GPL(vb2_queue_release);
+
+/**
+ * struct vb2_fileio_buf - buffer context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. This structure is used for
+ * tracking context related to the buffers.
+ */
+struct vb2_fileio_buf {
+       void *vaddr;
+       unsigned int size;
+       unsigned int pos;
+       unsigned int queued:1;
+};
+
+/**
+ * struct vb2_fileio_data - queue context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. For proper operation it required
+ * this structure to save the driver state between each call of the read
+ * or write function.
+ */
+struct vb2_fileio_data {
+       struct v4l2_requestbuffers req;
+       struct v4l2_buffer b;
+       struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
+       unsigned int index;
+       unsigned int q_count;
+       unsigned int dq_count;
+       unsigned int flags;
+};
+
+/**
+ * __vb2_init_fileio() - initialize file io emulator
+ * @q:         videobuf2 queue
+ * @read:      mode selector (1 means read, 0 means write)
+ */
+static int __vb2_init_fileio(struct vb2_queue *q, int read)
+{
+       struct vb2_fileio_data *fileio;
+       int i, ret;
+       unsigned int count = 0;
+
+       /*
+        * Sanity check
+        */
+       if ((read && !(q->io_modes & VB2_READ)) ||
+          (!read && !(q->io_modes & VB2_WRITE)))
+               BUG();
+
+       /*
+        * Check if device supports mapping buffers to kernel virtual space.
+        */
+       if (!q->mem_ops->vaddr)
+               return -EBUSY;
+
+       /*
+        * Check if streaming api has not been already activated.
+        */
+       if (q->streaming || q->num_buffers > 0)
+               return -EBUSY;
+
+       /*
+        * Start with count 1, driver can increase it in queue_setup()
+        */
+       count = 1;
+
+       dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n",
+               (read) ? "read" : "write", count, q->io_flags);
+
+       fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
+       if (fileio == NULL)
+               return -ENOMEM;
+
+       fileio->flags = q->io_flags;
+
+       /*
+        * Request buffers and use MMAP type to force driver
+        * to allocate buffers by itself.
+        */
+       fileio->req.count = count;
+       fileio->req.memory = V4L2_MEMORY_MMAP;
+       fileio->req.type = q->type;
+       ret = vb2_reqbufs(q, &fileio->req);
+       if (ret)
+               goto err_kfree;
+
+       /*
+        * Check if plane_count is correct
+        * (multiplane buffers are not supported).
+        */
+       if (q->bufs[0]->num_planes != 1) {
+               fileio->req.count = 0;
+               ret = -EBUSY;
+               goto err_reqbufs;
+       }
+
+       /*
+        * Get kernel address of each buffer.
+        */
+       for (i = 0; i < q->num_buffers; i++) {
+               fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+               if (fileio->bufs[i].vaddr == NULL)
+                       goto err_reqbufs;
+               fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+       }
+
+       /*
+        * Read mode requires pre queuing of all buffers.
+        */
+       if (read) {
+               /*
+                * Queue all buffers.
+                */
+               for (i = 0; i < q->num_buffers; i++) {
+                       struct v4l2_buffer *b = &fileio->b;
+                       memset(b, 0, sizeof(*b));
+                       b->type = q->type;
+                       b->memory = q->memory;
+                       b->index = i;
+                       ret = vb2_qbuf(q, b);
+                       if (ret)
+                               goto err_reqbufs;
+                       fileio->bufs[i].queued = 1;
+               }
+
+               /*
+                * Start streaming.
+                */
+               ret = vb2_streamon(q, q->type);
+               if (ret)
+                       goto err_reqbufs;
+       }
+
+       q->fileio = fileio;
+
+       return ret;
+
+err_reqbufs:
+       vb2_reqbufs(q, &fileio->req);
+
+err_kfree:
+       kfree(fileio);
+       return ret;
+}
+
+/**
+ * __vb2_cleanup_fileio() - free resourced used by file io emulator
+ * @q:         videobuf2 queue
+ */
+static int __vb2_cleanup_fileio(struct vb2_queue *q)
+{
+       struct vb2_fileio_data *fileio = q->fileio;
+
+       if (fileio) {
+               /*
+                * Hack fileio context to enable direct calls to vb2 ioctl
+                * interface.
+                */
+               q->fileio = NULL;
+
+               vb2_streamoff(q, q->type);
+               fileio->req.count = 0;
+               vb2_reqbufs(q, &fileio->req);
+               kfree(fileio);
+               dprintk(3, "file io emulator closed\n");
+       }
+       return 0;
+}
+
+/**
+ * __vb2_perform_fileio() - perform a single file io (read or write) operation
+ * @q:         videobuf2 queue
+ * @data:      pointed to target userspace buffer
+ * @count:     number of bytes to read or write
+ * @ppos:      file handle position tracking pointer
+ * @nonblock:  mode selector (1 means blocking calls, 0 means nonblocking)
+ * @read:      access mode selector (1 means read, 0 means write)
+ */
+static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblock, int read)
+{
+       struct vb2_fileio_data *fileio;
+       struct vb2_fileio_buf *buf;
+       int ret, index;
+
+       dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n",
+               read ? "read" : "write", (long)*ppos, count,
+               nonblock ? "non" : "");
+
+       if (!data)
+               return -EINVAL;
+
+       /*
+        * Initialize emulator on first call.
+        */
+       if (!q->fileio) {
+               ret = __vb2_init_fileio(q, read);
+               dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+               if (ret)
+                       return ret;
+       }
+       fileio = q->fileio;
+
+       /*
+        * Hack fileio context to enable direct calls to vb2 ioctl interface.
+        * The pointer will be restored before returning from this function.
+        */
+       q->fileio = NULL;
+
+       index = fileio->index;
+       buf = &fileio->bufs[index];
+
+       /*
+        * Check if we need to dequeue the buffer.
+        */
+       if (buf->queued) {
+               struct vb2_buffer *vb;
+
+               /*
+                * Call vb2_dqbuf to get buffer back.
+                */
+               memset(&fileio->b, 0, sizeof(fileio->b));
+               fileio->b.type = q->type;
+               fileio->b.memory = q->memory;
+               fileio->b.index = index;
+               ret = vb2_dqbuf(q, &fileio->b, nonblock);
+               dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+               if (ret)
+                       goto end;
+               fileio->dq_count += 1;
+
+               /*
+                * Get number of bytes filled by the driver
+                */
+               vb = q->bufs[index];
+               buf->size = vb2_get_plane_payload(vb, 0);
+               buf->queued = 0;
+       }
+
+       /*
+        * Limit count on last few bytes of the buffer.
+        */
+       if (buf->pos + count > buf->size) {
+               count = buf->size - buf->pos;
+               dprintk(5, "reducing read count: %zd\n", count);
+       }
+
+       /*
+        * Transfer data to userspace.
+        */
+       dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n",
+               count, index, buf->pos);
+       if (read)
+               ret = copy_to_user(data, buf->vaddr + buf->pos, count);
+       else
+               ret = copy_from_user(buf->vaddr + buf->pos, data, count);
+       if (ret) {
+               dprintk(3, "file io: error copying data\n");
+               ret = -EFAULT;
+               goto end;
+       }
+
+       /*
+        * Update counters.
+        */
+       buf->pos += count;
+       *ppos += count;
+
+       /*
+        * Queue next buffer if required.
+        */
+       if (buf->pos == buf->size ||
+          (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) {
+               /*
+                * Check if this is the last buffer to read.
+                */
+               if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
+                   fileio->dq_count == 1) {
+                       dprintk(3, "file io: read limit reached\n");
+                       /*
+                        * Restore fileio pointer and release the context.
+                        */
+                       q->fileio = fileio;
+                       return __vb2_cleanup_fileio(q);
+               }
+
+               /*
+                * Call vb2_qbuf and give buffer to the driver.
+                */
+               memset(&fileio->b, 0, sizeof(fileio->b));
+               fileio->b.type = q->type;
+               fileio->b.memory = q->memory;
+               fileio->b.index = index;
+               fileio->b.bytesused = buf->pos;
+               ret = vb2_qbuf(q, &fileio->b);
+               dprintk(5, "file io: vb2_dbuf result: %d\n", ret);
+               if (ret)
+                       goto end;
+
+               /*
+                * Buffer has been queued, update the status
+                */
+               buf->pos = 0;
+               buf->queued = 1;
+               buf->size = q->bufs[0]->v4l2_planes[0].length;
+               fileio->q_count += 1;
+
+               /*
+                * Switch to the next buffer
+                */
+               fileio->index = (index + 1) % q->num_buffers;
+
+               /*
+                * Start streaming if required.
+                */
+               if (!read && !q->streaming) {
+                       ret = vb2_streamon(q, q->type);
+                       if (ret)
+                               goto end;
+               }
+       }
+
+       /*
+        * Return proper number of bytes processed.
+        */
+       if (ret == 0)
+               ret = count;
+end:
+       /*
+        * Restore the fileio context and block vb2 ioctl interface.
+        */
+       q->fileio = fileio;
+       return ret;
+}
+
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblocking)
+{
+       return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
+}
+EXPORT_SYMBOL_GPL(vb2_read);
+
+size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblocking)
+{
+       return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0);
+}
+EXPORT_SYMBOL_GPL(vb2_write);
+
+MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
new file mode 100644 (file)
index 0000000..58205d5
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_dc_conf {
+       struct device           *dev;
+};
+
+struct vb2_dc_buf {
+       struct vb2_dc_conf              *conf;
+       void                            *vaddr;
+       dma_addr_t                      paddr;
+       unsigned long                   size;
+       struct vm_area_struct           *vma;
+       atomic_t                        refcount;
+       struct vb2_vmarea_handler       handler;
+};
+
+static void vb2_dma_contig_put(void *buf_priv);
+
+static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
+{
+       struct vb2_dc_conf *conf = alloc_ctx;
+       struct vb2_dc_buf *buf;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+
+       buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr,
+                                       GFP_KERNEL);
+       if (!buf->vaddr) {
+               dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
+                       buf->size);
+               kfree(buf);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       buf->conf = conf;
+       buf->size = size;
+
+       buf->handler.refcount = &buf->refcount;
+       buf->handler.put = vb2_dma_contig_put;
+       buf->handler.arg = buf;
+
+       atomic_inc(&buf->refcount);
+
+       return buf;
+}
+
+static void vb2_dma_contig_put(void *buf_priv)
+{
+       struct vb2_dc_buf *buf = buf_priv;
+
+       if (atomic_dec_and_test(&buf->refcount)) {
+               dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
+                                 buf->paddr);
+               kfree(buf);
+       }
+}
+
+static void *vb2_dma_contig_cookie(void *buf_priv)
+{
+       struct vb2_dc_buf *buf = buf_priv;
+
+       return &buf->paddr;
+}
+
+static void *vb2_dma_contig_vaddr(void *buf_priv)
+{
+       struct vb2_dc_buf *buf = buf_priv;
+       if (!buf)
+               return 0;
+
+       return buf->vaddr;
+}
+
+static unsigned int vb2_dma_contig_num_users(void *buf_priv)
+{
+       struct vb2_dc_buf *buf = buf_priv;
+
+       return atomic_read(&buf->refcount);
+}
+
+static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+       struct vb2_dc_buf *buf = buf_priv;
+
+       if (!buf) {
+               printk(KERN_ERR "No buffer to map\n");
+               return -EINVAL;
+       }
+
+       return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
+                                 &vb2_common_vm_ops, &buf->handler);
+}
+
+static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
+                                       unsigned long size, int write)
+{
+       struct vb2_dc_buf *buf;
+       struct vm_area_struct *vma;
+       dma_addr_t paddr = 0;
+       int ret;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+
+       ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
+       if (ret) {
+               printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
+                               vaddr);
+               kfree(buf);
+               return ERR_PTR(ret);
+       }
+
+       buf->size = size;
+       buf->paddr = paddr;
+       buf->vma = vma;
+
+       return buf;
+}
+
+static void vb2_dma_contig_put_userptr(void *mem_priv)
+{
+       struct vb2_dc_buf *buf = mem_priv;
+
+       if (!buf)
+               return;
+
+       vb2_put_vma(buf->vma);
+       kfree(buf);
+}
+
+const struct vb2_mem_ops vb2_dma_contig_memops = {
+       .alloc          = vb2_dma_contig_alloc,
+       .put            = vb2_dma_contig_put,
+       .cookie         = vb2_dma_contig_cookie,
+       .vaddr          = vb2_dma_contig_vaddr,
+       .mmap           = vb2_dma_contig_mmap,
+       .get_userptr    = vb2_dma_contig_get_userptr,
+       .put_userptr    = vb2_dma_contig_put_userptr,
+       .num_users      = vb2_dma_contig_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
+
+void *vb2_dma_contig_init_ctx(struct device *dev)
+{
+       struct vb2_dc_conf *conf;
+
+       conf = kzalloc(sizeof *conf, GFP_KERNEL);
+       if (!conf)
+               return ERR_PTR(-ENOMEM);
+
+       conf->dev = dev;
+
+       return conf;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
+
+void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
+{
+       kfree(alloc_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
+
+MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c
new file mode 100644 (file)
index 0000000..b2d9485
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * videobuf2-dma-sg.c - dma scatter/gather memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.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.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+#include <media/videobuf2-dma-sg.h>
+
+struct vb2_dma_sg_buf {
+       void                            *vaddr;
+       struct page                     **pages;
+       int                             write;
+       int                             offset;
+       struct vb2_dma_sg_desc          sg_desc;
+       atomic_t                        refcount;
+       struct vb2_vmarea_handler       handler;
+};
+
+static void vb2_dma_sg_put(void *buf_priv);
+
+static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
+{
+       struct vb2_dma_sg_buf *buf;
+       int i;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->vaddr = NULL;
+       buf->write = 0;
+       buf->offset = 0;
+       buf->sg_desc.size = size;
+       buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+       buf->sg_desc.sglist = vmalloc(buf->sg_desc.num_pages *
+                                     sizeof(*buf->sg_desc.sglist));
+       if (!buf->sg_desc.sglist)
+               goto fail_sglist_alloc;
+       memset(buf->sg_desc.sglist, 0, buf->sg_desc.num_pages *
+              sizeof(*buf->sg_desc.sglist));
+       sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
+
+       buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
+                            GFP_KERNEL);
+       if (!buf->pages)
+               goto fail_pages_array_alloc;
+
+       for (i = 0; i < buf->sg_desc.num_pages; ++i) {
+               buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (NULL == buf->pages[i])
+                       goto fail_pages_alloc;
+               sg_set_page(&buf->sg_desc.sglist[i],
+                           buf->pages[i], PAGE_SIZE, 0);
+       }
+
+       buf->handler.refcount = &buf->refcount;
+       buf->handler.put = vb2_dma_sg_put;
+       buf->handler.arg = buf;
+
+       atomic_inc(&buf->refcount);
+
+       printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n",
+               __func__, buf->sg_desc.num_pages);
+
+       if (!buf->vaddr)
+               buf->vaddr = vm_map_ram(buf->pages,
+                                       buf->sg_desc.num_pages,
+                                       -1,
+                                       PAGE_KERNEL);
+       return buf;
+
+fail_pages_alloc:
+       while (--i >= 0)
+               __free_page(buf->pages[i]);
+       kfree(buf->pages);
+
+fail_pages_array_alloc:
+       vfree(buf->sg_desc.sglist);
+
+fail_sglist_alloc:
+       kfree(buf);
+       return NULL;
+}
+
+static void vb2_dma_sg_put(void *buf_priv)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+       int i = buf->sg_desc.num_pages;
+
+       if (atomic_dec_and_test(&buf->refcount)) {
+               printk(KERN_DEBUG "%s: Freeing buffer of %d pages\n", __func__,
+                       buf->sg_desc.num_pages);
+               if (buf->vaddr)
+                       vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
+               vfree(buf->sg_desc.sglist);
+               while (--i >= 0)
+                       __free_page(buf->pages[i]);
+               kfree(buf->pages);
+               kfree(buf);
+       }
+}
+
+static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
+                                   unsigned long size, int write)
+{
+       struct vb2_dma_sg_buf *buf;
+       unsigned long first, last;
+       int num_pages_from_user, i;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->vaddr = NULL;
+       buf->write = write;
+       buf->offset = vaddr & ~PAGE_MASK;
+       buf->sg_desc.size = size;
+
+       first = (vaddr           & PAGE_MASK) >> PAGE_SHIFT;
+       last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
+       buf->sg_desc.num_pages = last - first + 1;
+
+       buf->sg_desc.sglist = vmalloc(
+               buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
+       if (!buf->sg_desc.sglist)
+               goto userptr_fail_sglist_alloc;
+
+       memset(buf->sg_desc.sglist, 0,
+               buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
+       sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
+
+       buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
+                            GFP_KERNEL);
+       if (!buf->pages)
+               goto userptr_fail_pages_array_alloc;
+
+       down_read(&current->mm->mmap_sem);
+       num_pages_from_user = get_user_pages(current, current->mm,
+                                            vaddr & PAGE_MASK,
+                                            buf->sg_desc.num_pages,
+                                            write,
+                                            1, /* force */
+                                            buf->pages,
+                                            NULL);
+       up_read(&current->mm->mmap_sem);
+       if (num_pages_from_user != buf->sg_desc.num_pages)
+               goto userptr_fail_get_user_pages;
+
+       sg_set_page(&buf->sg_desc.sglist[0], buf->pages[0],
+                   PAGE_SIZE - buf->offset, buf->offset);
+       size -= PAGE_SIZE - buf->offset;
+       for (i = 1; i < buf->sg_desc.num_pages; ++i) {
+               sg_set_page(&buf->sg_desc.sglist[i], buf->pages[i],
+                           min_t(size_t, PAGE_SIZE, size), 0);
+               size -= min_t(size_t, PAGE_SIZE, size);
+       }
+       return buf;
+
+userptr_fail_get_user_pages:
+       printk(KERN_DEBUG "get_user_pages requested/got: %d/%d]\n",
+              num_pages_from_user, buf->sg_desc.num_pages);
+       while (--num_pages_from_user >= 0)
+               put_page(buf->pages[num_pages_from_user]);
+       kfree(buf->pages);
+
+userptr_fail_pages_array_alloc:
+       vfree(buf->sg_desc.sglist);
+
+userptr_fail_sglist_alloc:
+       kfree(buf);
+       return NULL;
+}
+
+/*
+ * @put_userptr: inform the allocator that a USERPTR buffer will no longer
+ *              be used
+ */
+static void vb2_dma_sg_put_userptr(void *buf_priv)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+       int i = buf->sg_desc.num_pages;
+
+       printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n",
+              __func__, buf->sg_desc.num_pages);
+       if (buf->vaddr)
+               vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
+       while (--i >= 0) {
+               if (buf->write)
+                       set_page_dirty_lock(buf->pages[i]);
+               put_page(buf->pages[i]);
+       }
+       vfree(buf->sg_desc.sglist);
+       kfree(buf->pages);
+       kfree(buf);
+}
+
+static void *vb2_dma_sg_vaddr(void *buf_priv)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+
+       BUG_ON(!buf);
+
+       if (!buf->vaddr)
+               buf->vaddr = vm_map_ram(buf->pages,
+                                       buf->sg_desc.num_pages,
+                                       -1,
+                                       PAGE_KERNEL);
+
+       /* add offset in case userptr is not page-aligned */
+       return buf->vaddr + buf->offset;
+}
+
+static unsigned int vb2_dma_sg_num_users(void *buf_priv)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+
+       return atomic_read(&buf->refcount);
+}
+
+static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+       unsigned long uaddr = vma->vm_start;
+       unsigned long usize = vma->vm_end - vma->vm_start;
+       int i = 0;
+
+       if (!buf) {
+               printk(KERN_ERR "No memory to map\n");
+               return -EINVAL;
+       }
+
+       do {
+               int ret;
+
+               ret = vm_insert_page(vma, uaddr, buf->pages[i++]);
+               if (ret) {
+                       printk(KERN_ERR "Remapping memory, error: %d\n", ret);
+                       return ret;
+               }
+
+               uaddr += PAGE_SIZE;
+               usize -= PAGE_SIZE;
+       } while (usize > 0);
+
+
+       /*
+        * Use common vm_area operations to track buffer refcount.
+        */
+       vma->vm_private_data    = &buf->handler;
+       vma->vm_ops             = &vb2_common_vm_ops;
+
+       vma->vm_ops->open(vma);
+
+       return 0;
+}
+
+static void *vb2_dma_sg_cookie(void *buf_priv)
+{
+       struct vb2_dma_sg_buf *buf = buf_priv;
+
+       return &buf->sg_desc;
+}
+
+const struct vb2_mem_ops vb2_dma_sg_memops = {
+       .alloc          = vb2_dma_sg_alloc,
+       .put            = vb2_dma_sg_put,
+       .get_userptr    = vb2_dma_sg_get_userptr,
+       .put_userptr    = vb2_dma_sg_put_userptr,
+       .vaddr          = vb2_dma_sg_vaddr,
+       .mmap           = vb2_dma_sg_mmap,
+       .num_users      = vb2_dma_sg_num_users,
+       .cookie         = vb2_dma_sg_cookie,
+};
+EXPORT_SYMBOL_GPL(vb2_dma_sg_memops);
+
+MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2");
+MODULE_AUTHOR("Andrzej Pietrasiewicz");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c
new file mode 100644 (file)
index 0000000..5370a3a
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * videobuf2-memops.c - generic memory handling routines for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.com>
+ *        Marek Szyprowski <m.szyprowski@samsung.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.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+/**
+ * vb2_get_vma() - acquire and lock the virtual memory area
+ * @vma:       given virtual memory area
+ *
+ * This function attempts to acquire an area mapped in the userspace for
+ * the duration of a hardware operation. The area is "locked" by performing
+ * the same set of operation that are done when process calls fork() and
+ * memory areas are duplicated.
+ *
+ * Returns a copy of a virtual memory region on success or NULL.
+ */
+struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
+{
+       struct vm_area_struct *vma_copy;
+
+       vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
+       if (vma_copy == NULL)
+               return NULL;
+
+       if (vma->vm_ops && vma->vm_ops->open)
+               vma->vm_ops->open(vma);
+
+       if (vma->vm_file)
+               get_file(vma->vm_file);
+
+       memcpy(vma_copy, vma, sizeof(*vma));
+
+       vma_copy->vm_mm = NULL;
+       vma_copy->vm_next = NULL;
+       vma_copy->vm_prev = NULL;
+
+       return vma_copy;
+}
+
+/**
+ * vb2_put_userptr() - release a userspace virtual memory area
+ * @vma:       virtual memory region associated with the area to be released
+ *
+ * This function releases the previously acquired memory area after a hardware
+ * operation.
+ */
+void vb2_put_vma(struct vm_area_struct *vma)
+{
+       if (!vma)
+               return;
+
+       if (vma->vm_file)
+               fput(vma->vm_file);
+
+       if (vma->vm_ops && vma->vm_ops->close)
+               vma->vm_ops->close(vma);
+
+       kfree(vma);
+}
+EXPORT_SYMBOL_GPL(vb2_put_vma);
+
+/**
+ * vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory
+ * @vaddr:     starting virtual address of the area to be verified
+ * @size:      size of the area
+ * @res_paddr: will return physical address for the given vaddr
+ * @res_vma:   will return locked copy of struct vm_area for the given area
+ *
+ * This function will go through memory area of size @size mapped at @vaddr and
+ * verify that the underlying physical pages are contiguous. If they are
+ * contiguous the virtual memory area is locked and a @res_vma is filled with
+ * the copy and @res_pa set to the physical address of the buffer.
+ *
+ * Returns 0 on success.
+ */
+int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
+                          struct vm_area_struct **res_vma, dma_addr_t *res_pa)
+{
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       unsigned long offset, start, end;
+       unsigned long this_pfn, prev_pfn;
+       dma_addr_t pa = 0;
+       int ret = -EFAULT;
+
+       start = vaddr;
+       offset = start & ~PAGE_MASK;
+       end = start + size;
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, start);
+
+       if (vma == NULL || vma->vm_end < end)
+               goto done;
+
+       for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
+               ret = follow_pfn(vma, start, &this_pfn);
+               if (ret)
+                       goto done;
+
+               if (prev_pfn == 0)
+                       pa = this_pfn << PAGE_SHIFT;
+               else if (this_pfn != prev_pfn + 1) {
+                       ret = -EFAULT;
+                       goto done;
+               }
+               prev_pfn = this_pfn;
+       }
+
+       /*
+        * Memory is contigous, lock vma and return to the caller
+        */
+       *res_vma = vb2_get_vma(vma);
+       if (*res_vma == NULL) {
+               ret = -ENOMEM;
+               goto done;
+       }
+       *res_pa = pa + offset;
+       ret = 0;
+
+done:
+       up_read(&mm->mmap_sem);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_get_contig_userptr);
+
+/**
+ * vb2_mmap_pfn_range() - map physical pages to userspace
+ * @vma:       virtual memory region for the mapping
+ * @paddr:     starting physical address of the memory to be mapped
+ * @size:      size of the memory to be mapped
+ * @vm_ops:    vm operations to be assigned to the created area
+ * @priv:      private data to be associated with the area
+ *
+ * Returns 0 on success.
+ */
+int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+                               unsigned long size,
+                               const struct vm_operations_struct *vm_ops,
+                               void *priv)
+{
+       int ret;
+
+       size = min_t(unsigned long, vma->vm_end - vma->vm_start, size);
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT,
+                               size, vma->vm_page_prot);
+       if (ret) {
+               printk(KERN_ERR "Remapping memory failed, error: %d\n", ret);
+               return ret;
+       }
+
+       vma->vm_flags           |= VM_DONTEXPAND | VM_RESERVED;
+       vma->vm_private_data    = priv;
+       vma->vm_ops             = vm_ops;
+
+       vma->vm_ops->open(vma);
+
+       printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+                       __func__, paddr, vma->vm_start, size);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_mmap_pfn_range);
+
+/**
+ * vb2_common_vm_open() - increase refcount of the vma
+ * @vma:       virtual memory region for the mapping
+ *
+ * This function adds another user to the provided vma. It expects
+ * struct vb2_vmarea_handler pointer in vma->vm_private_data.
+ */
+static void vb2_common_vm_open(struct vm_area_struct *vma)
+{
+       struct vb2_vmarea_handler *h = vma->vm_private_data;
+
+       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+              __func__, h, atomic_read(h->refcount), vma->vm_start,
+              vma->vm_end);
+
+       atomic_inc(h->refcount);
+}
+
+/**
+ * vb2_common_vm_close() - decrease refcount of the vma
+ * @vma:       virtual memory region for the mapping
+ *
+ * This function releases the user from the provided vma. It expects
+ * struct vb2_vmarea_handler pointer in vma->vm_private_data.
+ */
+static void vb2_common_vm_close(struct vm_area_struct *vma)
+{
+       struct vb2_vmarea_handler *h = vma->vm_private_data;
+
+       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+              __func__, h, atomic_read(h->refcount), vma->vm_start,
+              vma->vm_end);
+
+       h->put(h->arg);
+}
+
+/**
+ * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped
+ * video buffers
+ */
+const struct vm_operations_struct vb2_common_vm_ops = {
+       .open = vb2_common_vm_open,
+       .close = vb2_common_vm_close,
+};
+EXPORT_SYMBOL_GPL(vb2_common_vm_ops);
+
+MODULE_DESCRIPTION("common memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c
new file mode 100644 (file)
index 0000000..a3a8842
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_vmalloc_buf {
+       void                            *vaddr;
+       unsigned long                   size;
+       atomic_t                        refcount;
+       struct vb2_vmarea_handler       handler;
+};
+
+static void vb2_vmalloc_put(void *buf_priv);
+
+static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
+{
+       struct vb2_vmalloc_buf *buf;
+
+       buf = kzalloc(sizeof *buf, GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->size = size;
+       buf->vaddr = vmalloc_user(buf->size);
+       buf->handler.refcount = &buf->refcount;
+       buf->handler.put = vb2_vmalloc_put;
+       buf->handler.arg = buf;
+
+       if (!buf->vaddr) {
+               printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
+               kfree(buf);
+               return NULL;
+       }
+
+       atomic_inc(&buf->refcount);
+       printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
+                       buf->size, buf->vaddr);
+
+       return buf;
+}
+
+static void vb2_vmalloc_put(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+
+       if (atomic_dec_and_test(&buf->refcount)) {
+               printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
+                       __func__, buf->vaddr);
+               vfree(buf->vaddr);
+               kfree(buf);
+       }
+}
+
+static void *vb2_vmalloc_vaddr(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+
+       BUG_ON(!buf);
+
+       if (!buf->vaddr) {
+               printk(KERN_ERR "Address of an unallocated plane requested\n");
+               return NULL;
+       }
+
+       return buf->vaddr;
+}
+
+static unsigned int vb2_vmalloc_num_users(void *buf_priv)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+       return atomic_read(&buf->refcount);
+}
+
+static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+       struct vb2_vmalloc_buf *buf = buf_priv;
+       int ret;
+
+       if (!buf) {
+               printk(KERN_ERR "No memory to map\n");
+               return -EINVAL;
+       }
+
+       ret = remap_vmalloc_range(vma, buf->vaddr, 0);
+       if (ret) {
+               printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Make sure that vm_areas for 2 buffers won't be merged together
+        */
+       vma->vm_flags           |= VM_DONTEXPAND;
+
+       /*
+        * Use common vm_area operations to track buffer refcount.
+        */
+       vma->vm_private_data    = &buf->handler;
+       vma->vm_ops             = &vb2_common_vm_ops;
+
+       vma->vm_ops->open(vma);
+
+       return 0;
+}
+
+const struct vb2_mem_ops vb2_vmalloc_memops = {
+       .alloc          = vb2_vmalloc_alloc,
+       .put            = vb2_vmalloc_put,
+       .vaddr          = vb2_vmalloc_vaddr,
+       .mmap           = vb2_vmalloc_mmap,
+       .num_users      = vb2_vmalloc_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
+
+MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
+MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
+MODULE_LICENSE("GPL");
index c49c39386bd045f9f00dee5a63f9b50f841c1421..2238a613d664b7b9edebdaef4b0a58195888955c 100644 (file)
@@ -7,6 +7,9 @@
  *      John Sokol <sokol--a.t--videotechnology.com>
  *      http://v4l.videotechnology.com/
  *
+ *      Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski
+ *      Copyright (c) 2010 Samsung Electronics
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the BSD Licence, GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/kthread.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
 #include <linux/freezer.h>
-#endif
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
 #include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
@@ -42,7 +45,7 @@
 #define MAX_HEIGHT 1200
 
 #define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 7
+#define VIVI_MINOR_VERSION 8
 #define VIVI_RELEASE 0
 #define VIVI_VERSION \
        KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
@@ -133,16 +136,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f)
        return &formats[k];
 }
 
-struct sg_to_addr {
-       int pos;
-       struct scatterlist *sg;
-};
-
 /* buffer for one video frame */
 struct vivi_buffer {
        /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer vb;
-
+       struct vb2_buffer       vb;
+       struct list_head        list;
        struct vivi_fmt        *fmt;
 };
 
@@ -162,13 +160,20 @@ static LIST_HEAD(vivi_devlist);
 struct vivi_dev {
        struct list_head           vivi_devlist;
        struct v4l2_device         v4l2_dev;
+       struct v4l2_ctrl_handler   ctrl_handler;
 
        /* controls */
-       int                        brightness;
-       int                        contrast;
-       int                        saturation;
-       int                        hue;
-       int                        volume;
+       struct v4l2_ctrl           *brightness;
+       struct v4l2_ctrl           *contrast;
+       struct v4l2_ctrl           *saturation;
+       struct v4l2_ctrl           *hue;
+       struct v4l2_ctrl           *volume;
+       struct v4l2_ctrl           *button;
+       struct v4l2_ctrl           *boolean;
+       struct v4l2_ctrl           *int32;
+       struct v4l2_ctrl           *int64;
+       struct v4l2_ctrl           *menu;
+       struct v4l2_ctrl           *string;
 
        spinlock_t                 slock;
        struct mutex               mutex;
@@ -181,6 +186,7 @@ struct vivi_dev {
        /* Several counters */
        unsigned                   ms;
        unsigned long              jiffies;
+       unsigned                   button_pressed;
 
        int                        mv_count;    /* Controls bars movement */
 
@@ -190,9 +196,10 @@ struct vivi_dev {
        /* video capture */
        struct vivi_fmt            *fmt;
        unsigned int               width, height;
-       struct videobuf_queue      vb_vidq;
+       struct vb2_queue           vb_vidq;
+       enum v4l2_field            field;
+       unsigned int               field_count;
 
-       unsigned long              generating;
        u8                         bars[9][3];
        u8                         line[MAX_WIDTH * 4];
 };
@@ -443,10 +450,10 @@ static void gen_text(struct vivi_dev *dev, char *basep,
 
 static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-       int hmax = buf->vb.height;
-       int wmax = buf->vb.width;
+       int wmax = dev->width;
+       int hmax = dev->height;
        struct timeval ts;
-       void *vbuf = videobuf_to_vmalloc(&buf->vb);
+       void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
        unsigned ms;
        char str[100];
        int h, line = 1;
@@ -472,22 +479,38 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                        dev->width, dev->height, dev->input);
        gen_text(dev, vbuf, line++ * 16, 16, str);
 
+       mutex_lock(&dev->ctrl_handler.lock);
        snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-                       dev->brightness,
-                       dev->contrast,
-                       dev->saturation,
-                       dev->hue);
+                       dev->brightness->cur.val,
+                       dev->contrast->cur.val,
+                       dev->saturation->cur.val,
+                       dev->hue->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " volume %3d ", dev->volume);
+       snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
+       snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
+                       dev->int32->cur.val,
+                       dev->int64->cur.val64);
+       gen_text(dev, vbuf, line++ * 16, 16, str);
+       snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+                       dev->boolean->cur.val,
+                       dev->menu->qmenu[dev->menu->cur.val],
+                       dev->string->cur.string);
+       mutex_unlock(&dev->ctrl_handler.lock);
+       gen_text(dev, vbuf, line++ * 16, 16, str);
+       if (dev->button_pressed) {
+               dev->button_pressed--;
+               snprintf(str, sizeof(str), " button pressed!");
+               gen_text(dev, vbuf, line++ * 16, 16, str);
+       }
 
        dev->mv_count += 2;
 
-       /* Advice that buffer was filled */
-       buf->vb.field_count++;
+       buf->vb.v4l2_buf.field = dev->field;
+       dev->field_count++;
+       buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
        do_gettimeofday(&ts);
-       buf->vb.ts = ts;
-       buf->vb.state = VIDEOBUF_DONE;
+       buf->vb.v4l2_buf.timestamp = ts;
 }
 
 static void vivi_thread_tick(struct vivi_dev *dev)
@@ -504,23 +527,17 @@ static void vivi_thread_tick(struct vivi_dev *dev)
                goto unlock;
        }
 
-       buf = list_entry(dma_q->active.next,
-                        struct vivi_buffer, vb.queue);
+       buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+       list_del(&buf->list);
 
-       /* Nobody is waiting on this buffer, return */
-       if (!waitqueue_active(&buf->vb.done))
-               goto unlock;
-
-       list_del(&buf->vb.queue);
-
-       do_gettimeofday(&buf->vb.ts);
+       do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
 
        /* Fill buffer */
        vivi_fillbuff(dev, buf);
        dprintk(dev, 1, "filled buffer %p\n", buf);
 
-       wake_up(&buf->vb.done);
-       dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+       dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
 unlock:
        spin_unlock_irqrestore(&dev->slock, flags);
 }
@@ -571,17 +588,12 @@ static int vivi_thread(void *data)
        return 0;
 }
 
-static void vivi_start_generating(struct file *file)
+static int vivi_start_generating(struct vivi_dev *dev)
 {
-       struct vivi_dev *dev = video_drvdata(file);
        struct vivi_dmaqueue *dma_q = &dev->vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       if (test_and_set_bit(0, &dev->generating))
-               return;
-       file->private_data = dev;
-
        /* Resets frame counters */
        dev->ms = 0;
        dev->mv_count = 0;
@@ -593,146 +605,200 @@ static void vivi_start_generating(struct file *file)
 
        if (IS_ERR(dma_q->kthread)) {
                v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
-               clear_bit(0, &dev->generating);
-               return;
+               return PTR_ERR(dma_q->kthread);
        }
        /* Wakes thread */
        wake_up_interruptible(&dma_q->wq);
 
        dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
 }
 
-static void vivi_stop_generating(struct file *file)
+static void vivi_stop_generating(struct vivi_dev *dev)
 {
-       struct vivi_dev *dev = video_drvdata(file);
        struct vivi_dmaqueue *dma_q = &dev->vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       if (!file->private_data)
-               return;
-       if (!test_and_clear_bit(0, &dev->generating))
-               return;
-
        /* shutdown control thread */
        if (dma_q->kthread) {
                kthread_stop(dma_q->kthread);
                dma_q->kthread = NULL;
        }
-       videobuf_stop(&dev->vb_vidq);
-       videobuf_mmap_free(&dev->vb_vidq);
-}
 
-static int vivi_is_generating(struct vivi_dev *dev)
-{
-       return test_bit(0, &dev->generating);
+       /*
+        * Typical driver might need to wait here until dma engine stops.
+        * In this case we can abort imiedetly, so it's just a noop.
+        */
+
+       /* Release all active buffers */
+       while (!list_empty(&dma_q->active)) {
+               struct vivi_buffer *buf;
+               buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
+       }
 }
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       unsigned long size;
+
+       size = dev->width * dev->height * 2;
+
+       if (0 == *nbuffers)
+               *nbuffers = 32;
 
-       *size = dev->width * dev->height * 2;
+       while (size * *nbuffers > vid_limit * 1024 * 1024)
+               (*nbuffers)--;
 
-       if (0 == *count)
-               *count = 32;
+       *nplanes = 1;
 
-       while (*size * *count > vid_limit * 1024 * 1024)
-               (*count)--;
+       sizes[0] = size;
 
-       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
-               *count, *size);
+       /*
+        * videobuf2-vmalloc allocator is context-less so no need to set
+        * alloc_ctxs array.
+        */
+
+       dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__,
+               *nbuffers, size);
 
        return 0;
 }
 
-static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static int buffer_init(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+       BUG_ON(NULL == dev->fmt);
 
-       dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+       /*
+        * This callback is called once per buffer, after its allocation.
+        *
+        * Vivi does not allow changing format during streaming, but it is
+        * possible to do so when streaming is paused (i.e. in streamoff state).
+        * Buffers however are not freed when going into streamoff and so
+        * buffer size verification has to be done in buffer_prepare, on each
+        * qbuf.
+        * It would be best to move verification code here to buf_init and
+        * s_fmt though.
+        */
 
-       videobuf_vmalloc_free(&buf->vb);
-       dprintk(dev, 1, "free_buffer: freed\n");
-       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       return 0;
 }
 
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
-                                               enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
-       int rc;
+       unsigned long size;
 
-       dprintk(dev, 1, "%s, field=%d\n", __func__, field);
+       dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
 
        BUG_ON(NULL == dev->fmt);
 
+       /*
+        * Theses properties only change when queue is idle, see s_fmt.
+        * The below checks should not be performed here, on each
+        * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+        * should thus be moved to buffer_init and s_fmt.
+        */
        if (dev->width  < 48 || dev->width  > MAX_WIDTH ||
            dev->height < 32 || dev->height > MAX_HEIGHT)
                return -EINVAL;
 
-       buf->vb.size = dev->width * dev->height * 2;
-       if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+       size = dev->width * dev->height * 2;
+       if (vb2_plane_size(vb, 0) < size) {
+               dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
                return -EINVAL;
+       }
 
-       /* These properties only change when queue is idle, see s_fmt */
-       buf->fmt       = dev->fmt;
-       buf->vb.width  = dev->width;
-       buf->vb.height = dev->height;
-       buf->vb.field  = field;
+       vb2_set_plane_payload(&buf->vb, 0, size);
+
+       buf->fmt = dev->fmt;
 
        precalculate_bars(dev);
        precalculate_line(dev);
 
-       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-               rc = videobuf_iolock(vq, &buf->vb, NULL);
-               if (rc < 0)
-                       goto fail;
-       }
+       return 0;
+}
 
-       buf->vb.state = VIDEOBUF_PREPARED;
+static int buffer_finish(struct vb2_buffer *vb)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       dprintk(dev, 1, "%s\n", __func__);
        return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+       dprintk(dev, 1, "%s\n", __func__);
 
-fail:
-       free_buffer(vq, buf);
-       return rc;
 }
 
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
 {
-       struct vivi_dev *dev = vq->priv_data;
+       struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
        struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
        struct vivi_dmaqueue *vidq = &dev->vidq;
+       unsigned long flags = 0;
 
        dprintk(dev, 1, "%s\n", __func__);
 
-       buf->vb.state = VIDEOBUF_QUEUED;
-       list_add_tail(&buf->vb.queue, &vidq->active);
+       spin_lock_irqsave(&dev->slock, flags);
+       list_add_tail(&buf->list, &vidq->active);
+       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
-static void buffer_release(struct videobuf_queue *vq,
-                          struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *vq)
 {
-       struct vivi_dev *dev = vq->priv_data;
-       struct vivi_buffer *buf  = container_of(vb, struct vivi_buffer, vb);
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       dprintk(dev, 1, "%s\n", __func__);
+       return vivi_start_generating(dev);
+}
 
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
        dprintk(dev, 1, "%s\n", __func__);
+       vivi_stop_generating(dev);
+       return 0;
+}
 
-       free_buffer(vq, buf);
+static void vivi_lock(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       mutex_lock(&dev->mutex);
 }
 
-static struct videobuf_queue_ops vivi_video_qops = {
-       .buf_setup      = buffer_setup,
-       .buf_prepare    = buffer_prepare,
-       .buf_queue      = buffer_queue,
-       .buf_release    = buffer_release,
+static void vivi_unlock(struct vb2_queue *vq)
+{
+       struct vivi_dev *dev = vb2_get_drv_priv(vq);
+       mutex_unlock(&dev->mutex);
+}
+
+
+static struct vb2_ops vivi_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_finish             = buffer_finish,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = vivi_unlock,
+       .wait_finish            = vivi_lock,
 };
 
 /* ------------------------------------------------------------------
@@ -774,7 +840,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width        = dev->width;
        f->fmt.pix.height       = dev->height;
-       f->fmt.pix.field        = dev->vb_vidq.field;
+       f->fmt.pix.field        = dev->field;
        f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -820,82 +886,60 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
        struct vivi_dev *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_vidq;
 
        int ret = vidioc_try_fmt_vid_cap(file, priv, f);
        if (ret < 0)
                return ret;
 
-       if (vivi_is_generating(dev)) {
+       if (vb2_is_streaming(q)) {
                dprintk(dev, 1, "%s device busy\n", __func__);
-               ret = -EBUSY;
-               goto out;
+               return -EBUSY;
        }
 
        dev->fmt = get_format(f);
        dev->width = f->fmt.pix.width;
        dev->height = f->fmt.pix.height;
-       dev->vb_vidq.field = f->fmt.pix.field;
-       ret = 0;
-out:
-       return ret;
+       dev->field = f->fmt.pix.field;
+
+       return 0;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_reqbufs(&dev->vb_vidq, p);
+       return vb2_reqbufs(&dev->vb_vidq, p);
 }
 
 static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_querybuf(&dev->vb_vidq, p);
+       return vb2_querybuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_qbuf(&dev->vb_vidq, p);
+       return vb2_qbuf(&dev->vb_vidq, p);
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct vivi_dev *dev = video_drvdata(file);
-
-       return videobuf_dqbuf(&dev->vb_vidq, p,
-                               file->f_flags & O_NONBLOCK);
+       return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       int ret;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       ret = videobuf_streamon(&dev->vb_vidq);
-       if (ret)
-               return ret;
-
-       vivi_start_generating(file);
-       return 0;
+       return vb2_streamon(&dev->vb_vidq, i);
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       int ret;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       ret = videobuf_streamoff(&dev->vb_vidq);
-       if (!ret)
-               vivi_stop_generating(file);
-       return ret;
+       return vb2_streamoff(&dev->vb_vidq, i);
 }
 
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
@@ -938,80 +982,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 }
 
 /* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
-                           struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
-       case V4L2_CID_CONTRAST:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
-       case V4L2_CID_SATURATION:
-               return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-       }
-       return -EINVAL;
-}
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
+static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct vivi_dev *dev = video_drvdata(file);
+       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
 
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = dev->volume;
-               return 0;
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = dev->brightness;
-               return 0;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = dev->contrast;
-               return 0;
-       case V4L2_CID_SATURATION:
-               ctrl->value = dev->saturation;
-               return 0;
-       case V4L2_CID_HUE:
-               ctrl->value = dev->hue;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-       struct v4l2_queryctrl qc;
-       int err;
-
-       qc.id = ctrl->id;
-       err = vidioc_queryctrl(file, priv, &qc);
-       if (err < 0)
-               return err;
-       if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
-               return -ERANGE;
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               dev->volume = ctrl->value;
-               return 0;
-       case V4L2_CID_BRIGHTNESS:
-               dev->brightness = ctrl->value;
-               return 0;
-       case V4L2_CID_CONTRAST:
-               dev->contrast = ctrl->value;
-               return 0;
-       case V4L2_CID_SATURATION:
-               dev->saturation = ctrl->value;
-               return 0;
-       case V4L2_CID_HUE:
-               dev->hue = ctrl->value;
-               return 0;
-       }
-       return -EINVAL;
+       if (ctrl == dev->button)
+               dev->button_pressed = 30;
+       return 0;
 }
 
 /* ------------------------------------------------------------------
@@ -1023,21 +1001,19 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct vivi_dev *dev = video_drvdata(file);
 
-       vivi_start_generating(file);
-       return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
-                                       file->f_flags & O_NONBLOCK);
+       dprintk(dev, 1, "read called\n");
+       return vb2_read(&dev->vb_vidq, data, count, ppos,
+                      file->f_flags & O_NONBLOCK);
 }
 
 static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct vivi_dev *dev = video_drvdata(file);
-       struct videobuf_queue *q = &dev->vb_vidq;
+       struct vb2_queue *q = &dev->vb_vidq;
 
        dprintk(dev, 1, "%s\n", __func__);
-
-       vivi_start_generating(file);
-       return videobuf_poll_stream(file, q, wait);
+       return vb2_poll(q, file, wait);
 }
 
 static int vivi_close(struct file *file)
@@ -1045,11 +1021,12 @@ static int vivi_close(struct file *file)
        struct video_device  *vdev = video_devdata(file);
        struct vivi_dev *dev = video_drvdata(file);
 
-       vivi_stop_generating(file);
+       dprintk(dev, 1, "close called (dev=%s), file %p\n",
+               video_device_node_name(vdev), file);
 
-       dprintk(dev, 1, "close called (dev=%s)\n",
-               video_device_node_name(vdev));
-       return 0;
+       if (v4l2_fh_is_singular_file(file))
+               vb2_queue_release(&dev->vb_vidq);
+       return v4l2_fh_release(file);
 }
 
 static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1059,8 +1036,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 
        dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-       ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
-
+       ret = vb2_mmap(&dev->vb_vidq, vma);
        dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
@@ -1068,8 +1044,82 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
        return ret;
 }
 
+static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+       .s_ctrl = vivi_s_ctrl,
+};
+
+#define VIVI_CID_CUSTOM_BASE   (V4L2_CID_USER_BASE | 0xf000)
+
+static const struct v4l2_ctrl_config vivi_ctrl_button = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 0,
+       .name = "Button",
+       .type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 1,
+       .name = "Boolean",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 2,
+       .name = "Integer 32 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0x80000000,
+       .max = 0x7fffffff,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 3,
+       .name = "Integer 64 Bits",
+       .type = V4L2_CTRL_TYPE_INTEGER64,
+};
+
+static const char * const vivi_ctrl_menu_strings[] = {
+       "Menu Item 0 (Skipped)",
+       "Menu Item 1",
+       "Menu Item 2 (Skipped)",
+       "Menu Item 3",
+       "Menu Item 4",
+       "Menu Item 5 (Skipped)",
+       NULL,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_menu = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 4,
+       .name = "Menu",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 1,
+       .max = 4,
+       .def = 3,
+       .menu_skip_mask = 0x04,
+       .qmenu = vivi_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 5,
+       .name = "String",
+       .type = V4L2_CTRL_TYPE_STRING,
+       .min = 2,
+       .max = 4,
+       .step = 1,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
        .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
        .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
@@ -1093,9 +1143,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
-       .vidioc_queryctrl     = vidioc_queryctrl,
-       .vidioc_g_ctrl        = vidioc_g_ctrl,
-       .vidioc_s_ctrl        = vidioc_s_ctrl,
 };
 
 static struct video_device vivi_template = {
@@ -1126,6 +1173,7 @@ static int vivi_release(void)
                        video_device_node_name(dev->vfd));
                video_unregister_device(dev->vfd);
                v4l2_device_unregister(&dev->v4l2_dev);
+               v4l2_ctrl_handler_free(&dev->ctrl_handler);
                kfree(dev);
        }
 
@@ -1136,6 +1184,8 @@ static int __init vivi_create_instance(int inst)
 {
        struct vivi_dev *dev;
        struct video_device *vfd;
+       struct v4l2_ctrl_handler *hdl;
+       struct vb2_queue *q;
        int ret;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1151,20 +1201,46 @@ static int __init vivi_create_instance(int inst)
        dev->fmt = &formats[0];
        dev->width = 640;
        dev->height = 480;
-       dev->volume = 200;
-       dev->brightness = 127;
-       dev->contrast = 16;
-       dev->saturation = 127;
-       dev->hue = 0;
+       hdl = &dev->ctrl_handler;
+       v4l2_ctrl_handler_init(hdl, 11);
+       dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+       dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+       dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 255, 1, 16);
+       dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 255, 1, 127);
+       dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
+       dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
+       dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
+       dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
+       dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
+       dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+       if (hdl->error) {
+               ret = hdl->error;
+               goto unreg_dev;
+       }
+       dev->v4l2_dev.ctrl_handler = hdl;
 
        /* initialize locks */
        spin_lock_init(&dev->slock);
-       mutex_init(&dev->mutex);
 
-       videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
-                       NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                       V4L2_FIELD_INTERLACED,
-                       sizeof(struct vivi_buffer), dev, &dev->mutex);
+       /* initialize queue */
+       q = &dev->vb_vidq;
+       memset(q, 0, sizeof(dev->vb_vidq));
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct vivi_buffer);
+       q->ops = &vivi_video_qops;
+       q->mem_ops = &vb2_vmalloc_memops;
+
+       vb2_queue_init(q);
+
+       mutex_init(&dev->mutex);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
@@ -1178,6 +1254,12 @@ static int __init vivi_create_instance(int inst)
        *vfd = vivi_template;
        vfd->debug = debug;
        vfd->v4l2_dev = &dev->v4l2_dev;
+       set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+
+       /*
+        * Provide a mutex to v4l2 core. It will be used to protect
+        * all fops and v4l2 ioctls.
+        */
        vfd->lock = &dev->mutex;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
@@ -1200,6 +1282,7 @@ static int __init vivi_create_instance(int inst)
 rel_vdev:
        video_device_release(vfd);
 unreg_dev:
+       v4l2_ctrl_handler_free(hdl);
        v4l2_device_unregister(&dev->v4l2_dev);
 free_dev:
        kfree(dev);
index 91a01b3cdf8ccd6b6aa74450cb245465ef6c8f6e..75301d10a8389f4854e1dd7da7cf7735008b7db8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
 MODULE_AUTHOR("Laurent Pinchart");
@@ -44,16 +45,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct vpx3220 {
        struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
        unsigned char reg[255];
 
        v4l2_std_id norm;
        int ident;
        int input;
        int enable;
-       int bright;
-       int contrast;
-       int hue;
-       int sat;
 };
 
 static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
@@ -61,6 +59,11 @@ static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
        return container_of(sd, struct vpx3220, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
+}
+
 static char *inputs[] = { "internal", "composite", "svideo" };
 
 /* ----------------------------------------------------------------------- */
@@ -417,88 +420,26 @@ static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-               v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-               break;
-
-       case V4L2_CID_CONTRAST:
-               v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
-               break;
-
-       case V4L2_CID_SATURATION:
-               v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
-               break;
-
-       case V4L2_CID_HUE:
-               v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct vpx3220 *decoder = to_vpx3220(sd);
+       struct v4l2_subdev *sd = to_sd(ctrl);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = decoder->bright;
-               break;
+               vpx3220_write(sd, 0xe6, ctrl->val);
+               return 0;
        case V4L2_CID_CONTRAST:
-               ctrl->value = decoder->contrast;
-               break;
+               /* Bit 7 and 8 is for noise shaping */
+               vpx3220_write(sd, 0xe7, ctrl->val + 192);
+               return 0;
        case V4L2_CID_SATURATION:
-               ctrl->value = decoder->sat;
-               break;
+               vpx3220_fp_write(sd, 0xa0, ctrl->val);
+               return 0;
        case V4L2_CID_HUE:
-               ctrl->value = decoder->hue;
-               break;
-       default:
-               return -EINVAL;
+               vpx3220_fp_write(sd, 0x1c, ctrl->val);
+               return 0;
        }
-       return 0;
-}
-
-static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct vpx3220 *decoder = to_vpx3220(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               if (decoder->bright != ctrl->value) {
-                       decoder->bright = ctrl->value;
-                       vpx3220_write(sd, 0xe6, decoder->bright);
-               }
-               break;
-       case V4L2_CID_CONTRAST:
-               if (decoder->contrast != ctrl->value) {
-                       /* Bit 7 and 8 is for noise shaping */
-                       decoder->contrast = ctrl->value;
-                       vpx3220_write(sd, 0xe7, decoder->contrast + 192);
-               }
-               break;
-       case V4L2_CID_SATURATION:
-               if (decoder->sat != ctrl->value) {
-                       decoder->sat = ctrl->value;
-                       vpx3220_fp_write(sd, 0xa0, decoder->sat);
-               }
-               break;
-       case V4L2_CID_HUE:
-               if (decoder->hue != ctrl->value) {
-                       decoder->hue = ctrl->value;
-                       vpx3220_fp_write(sd, 0x1c, decoder->hue);
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
+       return -EINVAL;
 }
 
 static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
@@ -511,12 +452,20 @@ static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
+       .s_ctrl = vpx3220_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
        .g_chip_ident = vpx3220_g_chip_ident,
        .init = vpx3220_init,
-       .g_ctrl = vpx3220_g_ctrl,
-       .s_ctrl = vpx3220_s_ctrl,
-       .queryctrl = vpx3220_queryctrl,
+       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+       .g_ctrl = v4l2_subdev_g_ctrl,
+       .s_ctrl = v4l2_subdev_s_ctrl,
+       .queryctrl = v4l2_subdev_queryctrl,
+       .querymenu = v4l2_subdev_querymenu,
        .s_std = vpx3220_s_std,
 };
 
@@ -558,10 +507,24 @@ static int vpx3220_probe(struct i2c_client *client,
        decoder->norm = V4L2_STD_PAL;
        decoder->input = 0;
        decoder->enable = 1;
-       decoder->bright = 32768;
-       decoder->contrast = 32768;
-       decoder->hue = 32768;
-       decoder->sat = 32768;
+       v4l2_ctrl_handler_init(&decoder->hdl, 4);
+       v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+               V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+               V4L2_CID_CONTRAST, 0, 63, 1, 32);
+       v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+               V4L2_CID_SATURATION, 0, 4095, 1, 2048);
+       v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+               V4L2_CID_HUE, -512, 511, 1, 0);
+       sd->ctrl_handler = &decoder->hdl;
+       if (decoder->hdl.error) {
+               int err = decoder->hdl.error;
+
+               v4l2_ctrl_handler_free(&decoder->hdl);
+               kfree(decoder);
+               return err;
+       }
+       v4l2_ctrl_handler_setup(&decoder->hdl);
 
        ver = i2c_smbus_read_byte_data(client, 0x00);
        pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
@@ -599,9 +562,11 @@ static int vpx3220_probe(struct i2c_client *client,
 static int vpx3220_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct vpx3220 *decoder = to_vpx3220(sd);
 
        v4l2_device_unregister_subdev(sd);
-       kfree(to_vpx3220(sd));
+       v4l2_ctrl_handler_free(&decoder->hdl);
+       kfree(decoder);
        return 0;
 }
 
index fe8ef6419f831f36d52347ff275d8c96d4dc8c5f..9cedb1e69b5871e9cd6d97d01bf8a5f97bb34ed8 100644 (file)
@@ -35,6 +35,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-ctrls.h>
+#include <media/wm8775.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -50,10 +51,16 @@ enum {
        TOT_REGS
 };
 
+#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
+#define ALC_EN 0x100  /* R17: ALC enable */
+
 struct wm8775_state {
        struct v4l2_subdev sd;
        struct v4l2_ctrl_handler hdl;
        struct v4l2_ctrl *mute;
+       struct v4l2_ctrl *vol;
+       struct v4l2_ctrl *bal;
+       struct v4l2_ctrl *loud;
        u8 input;               /* Last selected input (0-0xf) */
 };
 
@@ -85,6 +92,30 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
        return -1;
 }
 
+static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
+{
+       struct wm8775_state *state = to_state(sd);
+       u8 vol_l, vol_r;
+       int muted = 0 != state->mute->val;
+       u16 volume = (u16)state->vol->val;
+       u16 balance = (u16)state->bal->val;
+
+       /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
+       vol_l = (min(65536 - balance, 32768) * volume) >> 23;
+       vol_r = (min(balance, (u16)32768) * volume) >> 23;
+
+       /* Mute */
+       if (muted || quietly)
+               wm8775_write(sd, R21, 0x0c0 | state->input);
+
+       wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
+       wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
+
+       /* Un-mute */
+       if (!muted)
+               wm8775_write(sd, R21, state->input);
+}
+
 static int wm8775_s_routing(struct v4l2_subdev *sd,
                            u32 input, u32 output, u32 config)
 {
@@ -102,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
        state->input = input;
        if (!v4l2_ctrl_g_ctrl(state->mute))
                return 0;
-       wm8775_write(sd, R21, 0x0c0);
-       wm8775_write(sd, R14, 0x1d4);
-       wm8775_write(sd, R15, 0x1d4);
-       wm8775_write(sd, R21, 0x100 + state->input);
+       if (!v4l2_ctrl_g_ctrl(state->vol))
+               return 0;
+       if (!v4l2_ctrl_g_ctrl(state->bal))
+               return 0;
+       wm8775_set_audio(sd, 1);
        return 0;
 }
 
 static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
-       struct wm8775_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               wm8775_write(sd, R21, 0x0c0);
-               wm8775_write(sd, R14, 0x1d4);
-               wm8775_write(sd, R15, 0x1d4);
-               if (!ctrl->val)
-                       wm8775_write(sd, R21, 0x100 + state->input);
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+               wm8775_set_audio(sd, 0);
+               return 0;
+       case V4L2_CID_AUDIO_LOUDNESS:
+               wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
                return 0;
        }
        return -EINVAL;
@@ -144,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
 
 static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
 {
-       struct wm8775_state *state = to_state(sd);
-
-       /* If I remove this, then it can happen that I have no
-          sound the first time I tune from static to a valid channel.
-          It's difficult to reproduce and is almost certainly related
-          to the zero cross detect circuit. */
-       wm8775_write(sd, R21, 0x0c0);
-       wm8775_write(sd, R14, 0x1d4);
-       wm8775_write(sd, R15, 0x1d4);
-       wm8775_write(sd, R21, 0x100 + state->input);
+       wm8775_set_audio(sd, 0);
        return 0;
 }
 
@@ -203,6 +226,13 @@ static int wm8775_probe(struct i2c_client *client,
 {
        struct wm8775_state *state;
        struct v4l2_subdev *sd;
+       int err;
+       bool is_nova_s = false;
+
+       if (client->dev.platform_data) {
+               struct wm8775_platform_data *data = client->dev.platform_data;
+               is_nova_s = data->is_nova_s;
+       }
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -218,13 +248,18 @@ static int wm8775_probe(struct i2c_client *client,
        v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
        state->input = 2;
 
-       v4l2_ctrl_handler_init(&state->hdl, 1);
+       v4l2_ctrl_handler_init(&state->hdl, 4);
        state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
                        V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
+       state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
+       state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+                       V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
        sd->ctrl_handler = &state->hdl;
-       if (state->hdl.error) {
-               int err = state->hdl.error;
-
+       err = state->hdl.error;
+       if (err) {
                v4l2_ctrl_handler_free(&state->hdl);
                kfree(state);
                return err;
@@ -236,29 +271,44 @@ static int wm8775_probe(struct i2c_client *client,
        wm8775_write(sd, R23, 0x000);
        /* Disable zero cross detect timeout */
        wm8775_write(sd, R7, 0x000);
-       /* Left justified, 24-bit mode */
+       /* HPF enable, left justified, 24-bit (Philips) mode */
        wm8775_write(sd, R11, 0x021);
        /* Master mode, clock ratio 256fs */
        wm8775_write(sd, R12, 0x102);
        /* Powered up */
        wm8775_write(sd, R13, 0x000);
-       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(sd, R14, 0x1d4);
-       /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(sd, R15, 0x1d4);
-       /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
-       wm8775_write(sd, R16, 0x1bf);
-       /* Enable gain control, use zero cross detection,
-          ALC hold time 42.6 ms */
-       wm8775_write(sd, R17, 0x185);
+
+       if (!is_nova_s) {
+               /* ADC gain +2.5dB, enable zero cross */
+               wm8775_write(sd, R14, 0x1d4);
+               /* ADC gain +2.5dB, enable zero cross */
+               wm8775_write(sd, R15, 0x1d4);
+               /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+               wm8775_write(sd, R16, 0x1bf);
+               /* Enable gain control, use zero cross detection,
+                  ALC hold time 42.6 ms */
+               wm8775_write(sd, R17, 0x185);
+       } else {
+               /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
+               wm8775_write(sd, R16, 0x1bb);
+               /* Set ALC mode and hold time */
+               wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
+       }
        /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
        wm8775_write(sd, R18, 0x0a2);
        /* Enable noise gate, threshold -72dBfs */
        wm8775_write(sd, R19, 0x005);
-       /* Transient window 4ms, lower PGA gain limit -1dB */
-       wm8775_write(sd, R20, 0x07a);
-       /* LRBOTH = 1, use input 2. */
-       wm8775_write(sd, R21, 0x102);
+       if (!is_nova_s) {
+               /* Transient window 4ms, lower PGA gain limit -1dB */
+               wm8775_write(sd, R20, 0x07a);
+               /* LRBOTH = 1, use input 2. */
+               wm8775_write(sd, R21, 0x102);
+       } else {
+               /* Transient window 4ms, ALC min gain -5dB  */
+               wm8775_write(sd, R20, 0x0fb);
+
+               wm8775_set_audio(sd, 1);      /* set volume/mute/mux */
+       }
        return 0;
 }
 
index dc160fb435150ceeab480513919086a896077d29..98623590c7fe048d727f477f1f6d6ecf42d91ed2 100644 (file)
@@ -2,9 +2,7 @@
 # Makefile for the kernel MemoryStick device drivers.
 #
 
-ifeq ($(CONFIG_MEMSTICK_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
+subdir-ccflags-$(CONFIG_MEMSTICK_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_MEMSTICK)         += core/
 obj-$(CONFIG_MEMSTICK)         += host/
index 8b2b5293877e0f1fd7da1766765f72d46d6bf24f..ecd0299377386fee7e062a87c9209a5ad36f22f1 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for the kernel MemoryStick core.
 #
 
-ifeq ($(CONFIG_MEMSTICK_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MEMSTICK)         += memstick.o
 
 obj-$(CONFIG_MSPRO_BLOCK)      += mspro_block.o
index 4ce5c8dffb6878e1a073538c3e2eed261c1ab457..cc0997a0517137052c138ed90bd4516594b8e5dc 100644 (file)
@@ -30,3 +30,15 @@ config MEMSTICK_JMICRON_38X
 
           To compile this driver as a module, choose M here: the
          module will be called jmb38x_ms.
+
+config MEMSTICK_R592
+       tristate "Ricoh R5C592 MemoryStick interface support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && PCI
+
+       help
+         Say Y here if you want to be able to access MemoryStick cards with
+         the Ricoh R5C592 MemoryStick card reader (which is part of 5 in one
+               multifunction reader)
+
+         To compile this driver as a module, choose M here: the module will
+         be called r592.
index 12530e4311d31143dcab38c1405d92b02418c8de..31ba8d378e4660d7a91d61a2ff38adef8f000c1f 100644 (file)
@@ -2,9 +2,6 @@
 # Makefile for MemoryStick host controller drivers
 #
 
-ifeq ($(CONFIG_MEMSTICK_DEBUG),y)
-       EXTRA_CFLAGS                    += -DDEBUG
-endif
-
 obj-$(CONFIG_MEMSTICK_TIFM_MS)         += tifm_ms.o
 obj-$(CONFIG_MEMSTICK_JMICRON_38X)     += jmb38x_ms.o
+obj-$(CONFIG_MEMSTICK_R592)            += r592.o
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
new file mode 100644 (file)
index 0000000..767406c
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2010 - Maxim Levitsky
+ * driver for Ricoh memstick readers
+ *
+ * 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/module.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <asm/byteorder.h>
+#include <linux/swab.h>
+#include "r592.h"
+
+static int enable_dma = 1;
+static int debug;
+
+static const char *tpc_names[] = {
+       "MS_TPC_READ_MG_STATUS",
+       "MS_TPC_READ_LONG_DATA",
+       "MS_TPC_READ_SHORT_DATA",
+       "MS_TPC_READ_REG",
+       "MS_TPC_READ_QUAD_DATA",
+       "INVALID",
+       "MS_TPC_GET_INT",
+       "MS_TPC_SET_RW_REG_ADRS",
+       "MS_TPC_EX_SET_CMD",
+       "MS_TPC_WRITE_QUAD_DATA",
+       "MS_TPC_WRITE_REG",
+       "MS_TPC_WRITE_SHORT_DATA",
+       "MS_TPC_WRITE_LONG_DATA",
+       "MS_TPC_SET_CMD",
+};
+
+/**
+ * memstick_debug_get_tpc_name - debug helper that returns string for
+ * a TPC number
+ */
+const char *memstick_debug_get_tpc_name(int tpc)
+{
+       return tpc_names[tpc-1];
+}
+EXPORT_SYMBOL(memstick_debug_get_tpc_name);
+
+
+/* Read a register*/
+static inline u32 r592_read_reg(struct r592_device *dev, int address)
+{
+       u32 value = readl(dev->mmio + address);
+       dbg_reg("reg #%02d == 0x%08x", address, value);
+       return value;
+}
+
+/* Write a register */
+static inline void r592_write_reg(struct r592_device *dev,
+                                                       int address, u32 value)
+{
+       dbg_reg("reg #%02d <- 0x%08x", address, value);
+       writel(value, dev->mmio + address);
+}
+
+/* Reads a big endian DWORD register */
+static inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address)
+{
+       u32 value = __raw_readl(dev->mmio + address);
+       dbg_reg("reg #%02d == 0x%08x", address, value);
+       return be32_to_cpu(value);
+}
+
+/* Writes a big endian DWORD register */
+static inline void r592_write_reg_raw_be(struct r592_device *dev,
+                                                       int address, u32 value)
+{
+       dbg_reg("reg #%02d <- 0x%08x", address, value);
+       __raw_writel(cpu_to_be32(value), dev->mmio + address);
+}
+
+/* Set specific bits in a register (little endian) */
+static inline void r592_set_reg_mask(struct r592_device *dev,
+                                                       int address, u32 mask)
+{
+       u32 reg = readl(dev->mmio + address);
+       dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg);
+       writel(reg | mask , dev->mmio + address);
+}
+
+/* Clear specific bits in a register (little endian) */
+static inline void r592_clear_reg_mask(struct r592_device *dev,
+                                               int address, u32 mask)
+{
+       u32 reg = readl(dev->mmio + address);
+       dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)",
+                                               address, ~mask, reg, mask);
+       writel(reg & ~mask, dev->mmio + address);
+}
+
+
+/* Wait for status bits while checking for errors */
+static int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+       u32 reg = r592_read_reg(dev, R592_STATUS);
+
+       if ((reg & mask) == wanted_mask)
+               return 0;
+
+       while (time_before(jiffies, timeout)) {
+
+               reg = r592_read_reg(dev, R592_STATUS);
+
+               if ((reg & mask) == wanted_mask)
+                       return 0;
+
+               if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))
+                       return -EIO;
+
+               cpu_relax();
+       }
+       return -ETIME;
+}
+
+
+/* Enable/disable device */
+static int r592_enable_device(struct r592_device *dev, bool enable)
+{
+       dbg("%sabling the device", enable ? "en" : "dis");
+
+       if (enable) {
+
+               /* Power up the card */
+               r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1);
+
+               /* Perform a reset */
+               r592_set_reg_mask(dev, R592_IO, R592_IO_RESET);
+
+               msleep(100);
+       } else
+               /* Power down the card */
+               r592_write_reg(dev, R592_POWER, 0);
+
+       return 0;
+}
+
+/* Set serial/parallel mode */
+static int r592_set_mode(struct r592_device *dev, bool parallel_mode)
+{
+       if (!parallel_mode) {
+               dbg("switching to serial mode");
+
+               /* Set serial mode */
+               r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL);
+
+               r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20);
+
+       } else {
+               dbg("switching to parallel mode");
+
+               /* This setting should be set _before_ switch TPC */
+               r592_set_reg_mask(dev, R592_POWER, R592_POWER_20);
+
+               r592_clear_reg_mask(dev, R592_IO,
+                       R592_IO_SERIAL1 | R592_IO_SERIAL2);
+
+               /* Set the parallel mode now */
+               r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL);
+       }
+
+       dev->parallel_mode = parallel_mode;
+       return 0;
+}
+
+/* Perform a controller reset without powering down the card */
+static void r592_host_reset(struct r592_device *dev)
+{
+       r592_set_reg_mask(dev, R592_IO, R592_IO_RESET);
+       msleep(100);
+       r592_set_mode(dev, dev->parallel_mode);
+}
+
+/* Disable all hardware interrupts */
+static void r592_clear_interrupts(struct r592_device *dev)
+{
+       /* Disable & ACK all interrupts */
+       r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK);
+       r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK);
+}
+
+/* Tests if there is an CRC error */
+static int r592_test_io_error(struct r592_device *dev)
+{
+       if (!(r592_read_reg(dev, R592_STATUS) &
+               (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)))
+               return 0;
+
+       return -EIO;
+}
+
+/* Ensure that FIFO is ready for use */
+static int r592_test_fifo_empty(struct r592_device *dev)
+{
+       if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY)
+               return 0;
+
+       dbg("FIFO not ready, trying to reset the device");
+       r592_host_reset(dev);
+
+       if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY)
+               return 0;
+
+       message("FIFO still not ready, giving up");
+       return -EIO;
+}
+
+/* Activates the DMA transfer from to FIFO */
+static void r592_start_dma(struct r592_device *dev, bool is_write)
+{
+       unsigned long flags;
+       u32 reg;
+       spin_lock_irqsave(&dev->irq_lock, flags);
+
+       /* Ack interrupts (just in case) + enable them */
+       r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK);
+       r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK);
+
+       /* Set DMA address */
+       r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg));
+
+       /* Enable the DMA */
+       reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS);
+       reg |= R592_FIFO_DMA_SETTINGS_EN;
+
+       if (!is_write)
+               reg |= R592_FIFO_DMA_SETTINGS_DIR;
+       else
+               reg &= ~R592_FIFO_DMA_SETTINGS_DIR;
+       r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg);
+
+       spin_unlock_irqrestore(&dev->irq_lock, flags);
+}
+
+/* Cleanups DMA related settings */
+static void r592_stop_dma(struct r592_device *dev, int error)
+{
+       r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS,
+               R592_FIFO_DMA_SETTINGS_EN);
+
+       /* This is only a precation */
+       r592_write_reg(dev, R592_FIFO_DMA,
+                       dev->dummy_dma_page_physical_address);
+
+       r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK);
+       r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK);
+       dev->dma_error = error;
+}
+
+/* Test if hardware supports DMA */
+static void r592_check_dma(struct r592_device *dev)
+{
+       dev->dma_capable = enable_dma &&
+               (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) &
+                       R592_FIFO_DMA_SETTINGS_CAP);
+}
+
+/* Transfers fifo contents in/out using DMA */
+static int r592_transfer_fifo_dma(struct r592_device *dev)
+{
+       int len, sg_count;
+       bool is_write;
+
+       if (!dev->dma_capable || !dev->req->long_data)
+               return -EINVAL;
+
+       len = dev->req->sg.length;
+       is_write = dev->req->data_dir == WRITE;
+
+       if (len != R592_LFIFO_SIZE)
+               return -EINVAL;
+
+       dbg_verbose("doing dma transfer");
+
+       dev->dma_error = 0;
+       INIT_COMPLETION(dev->dma_done);
+
+       /* TODO: hidden assumption about nenth beeing always 1 */
+       sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ?
+               PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+       if (sg_count != 1 ||
+                       (sg_dma_len(&dev->req->sg) < dev->req->sg.length)) {
+               message("problem in dma_map_sg");
+               return -EIO;
+       }
+
+       r592_start_dma(dev, is_write);
+
+       /* Wait for DMA completion */
+       if (!wait_for_completion_timeout(
+                       &dev->dma_done, msecs_to_jiffies(1000))) {
+               message("DMA timeout");
+               r592_stop_dma(dev, -ETIMEDOUT);
+       }
+
+       dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ?
+               PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+
+       return dev->dma_error;
+}
+
+/*
+ * Writes the FIFO in 4 byte chunks.
+ * If length isn't 4 byte aligned, rest of the data if put to a fifo
+ * to be written later
+ * Use r592_flush_fifo_write to flush that fifo when writing for the
+ * last time
+ */
+static void r592_write_fifo_pio(struct r592_device *dev,
+                                       unsigned char *buffer, int len)
+{
+       /* flush spill from former write */
+       if (!kfifo_is_empty(&dev->pio_fifo)) {
+
+               u8 tmp[4] = {0};
+               int copy_len = kfifo_in(&dev->pio_fifo, buffer, len);
+
+               if (!kfifo_is_full(&dev->pio_fifo))
+                       return;
+               len -= copy_len;
+               buffer += copy_len;
+
+               copy_len = kfifo_out(&dev->pio_fifo, tmp, 4);
+               WARN_ON(copy_len != 4);
+               r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp);
+       }
+
+       WARN_ON(!kfifo_is_empty(&dev->pio_fifo));
+
+       /* write full dwords */
+       while (len >= 4) {
+               r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
+               buffer += 4;
+               len -= 4;
+       }
+
+       /* put remaining bytes to the spill */
+       if (len)
+               kfifo_in(&dev->pio_fifo, buffer, len);
+}
+
+/* Flushes the temporary FIFO used to make aligned DWORD writes */
+static void r592_flush_fifo_write(struct r592_device *dev)
+{
+       u8 buffer[4] = { 0 };
+       int len;
+
+       if (kfifo_is_empty(&dev->pio_fifo))
+               return;
+
+       len = kfifo_out(&dev->pio_fifo, buffer, 4);
+       r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
+}
+
+/*
+ * Read a fifo in 4 bytes chunks.
+ * If input doesn't fit the buffer, it places bytes of last dword in spill
+ * buffer, so that they don't get lost on last read, just throw these away.
+ */
+static void r592_read_fifo_pio(struct r592_device *dev,
+                                               unsigned char *buffer, int len)
+{
+       u8 tmp[4];
+
+       /* Read from last spill */
+       if (!kfifo_is_empty(&dev->pio_fifo)) {
+               int bytes_copied =
+                       kfifo_out(&dev->pio_fifo, buffer, min(4, len));
+               buffer += bytes_copied;
+               len -= bytes_copied;
+
+               if (!kfifo_is_empty(&dev->pio_fifo))
+                       return;
+       }
+
+       /* Reads dwords from FIFO */
+       while (len >= 4) {
+               *(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO);
+               buffer += 4;
+               len -= 4;
+       }
+
+       if (len) {
+               *(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO);
+               kfifo_in(&dev->pio_fifo, tmp, 4);
+               len -= kfifo_out(&dev->pio_fifo, buffer, len);
+       }
+
+       WARN_ON(len);
+       return;
+}
+
+/* Transfers actual data using PIO. */
+static int r592_transfer_fifo_pio(struct r592_device *dev)
+{
+       unsigned long flags;
+
+       bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS;
+       struct sg_mapping_iter miter;
+
+       kfifo_reset(&dev->pio_fifo);
+
+       if (!dev->req->long_data) {
+               if (is_write) {
+                       r592_write_fifo_pio(dev, dev->req->data,
+                                                       dev->req->data_len);
+                       r592_flush_fifo_write(dev);
+               } else
+                       r592_read_fifo_pio(dev, dev->req->data,
+                                                       dev->req->data_len);
+               return 0;
+       }
+
+       local_irq_save(flags);
+       sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC |
+               (is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG));
+
+       /* Do the transfer fifo<->memory*/
+       while (sg_miter_next(&miter))
+               if (is_write)
+                       r592_write_fifo_pio(dev, miter.addr, miter.length);
+               else
+                       r592_read_fifo_pio(dev, miter.addr, miter.length);
+
+
+       /* Write last few non aligned bytes*/
+       if (is_write)
+               r592_flush_fifo_write(dev);
+
+       sg_miter_stop(&miter);
+       local_irq_restore(flags);
+       return 0;
+}
+
+/* Executes one TPC (data is read/written from small or large fifo) */
+static void r592_execute_tpc(struct r592_device *dev)
+{
+       bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS;
+       int len, error;
+       u32 status, reg;
+
+       if (!dev->req) {
+               message("BUG: tpc execution without request!");
+               return;
+       }
+
+       len = dev->req->long_data ?
+               dev->req->sg.length : dev->req->data_len;
+
+       /* Ensure that FIFO can hold the input data */
+       if (len > R592_LFIFO_SIZE) {
+               message("IO: hardware doesn't support TPCs longer that 512");
+               error = -ENOSYS;
+               goto out;
+       }
+
+       if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) {
+               dbg("IO: refusing to send TPC because card is absent");
+               error = -ENODEV;
+               goto out;
+       }
+
+       dbg("IO: executing %s LEN=%d",
+                       memstick_debug_get_tpc_name(dev->req->tpc), len);
+
+       /* Set IO direction */
+       if (is_write)
+               r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION);
+       else
+               r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION);
+
+
+       error = r592_test_fifo_empty(dev);
+       if (error)
+               goto out;
+
+       /* Transfer write data */
+       if (is_write) {
+               error = r592_transfer_fifo_dma(dev);
+               if (error == -EINVAL)
+                       error = r592_transfer_fifo_pio(dev);
+       }
+
+       if (error)
+               goto out;
+
+       /* Trigger the TPC */
+       reg = (len << R592_TPC_EXEC_LEN_SHIFT) |
+               (dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) |
+                       R592_TPC_EXEC_BIG_FIFO;
+
+       r592_write_reg(dev, R592_TPC_EXEC, reg);
+
+       /* Wait for TPC completion */
+       status = R592_STATUS_RDY;
+       if (dev->req->need_card_int)
+               status |= R592_STATUS_CED;
+
+       error = r592_wait_status(dev, status, status);
+       if (error) {
+               message("card didn't respond");
+               goto out;
+       }
+
+       /* Test IO errors */
+       error = r592_test_io_error(dev);
+       if (error) {
+               dbg("IO error");
+               goto out;
+       }
+
+       /* Read data from FIFO */
+       if (!is_write) {
+               error = r592_transfer_fifo_dma(dev);
+               if (error == -EINVAL)
+                       error = r592_transfer_fifo_pio(dev);
+       }
+
+       /* read INT reg. This can be shortened with shifts, but that way
+               its more readable */
+       if (dev->parallel_mode && dev->req->need_card_int) {
+
+               dev->req->int_reg = 0;
+               status = r592_read_reg(dev, R592_STATUS);
+
+               if (status & R592_STATUS_P_CMDNACK)
+                       dev->req->int_reg |= MEMSTICK_INT_CMDNAK;
+               if (status & R592_STATUS_P_BREQ)
+                       dev->req->int_reg |= MEMSTICK_INT_BREQ;
+               if (status & R592_STATUS_P_INTERR)
+                       dev->req->int_reg |= MEMSTICK_INT_ERR;
+               if (status & R592_STATUS_P_CED)
+                       dev->req->int_reg |= MEMSTICK_INT_CED;
+       }
+
+       if (error)
+               dbg("FIFO read error");
+out:
+       dev->req->error = error;
+       r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED);
+       return;
+}
+
+/* Main request processing thread */
+static int r592_process_thread(void *data)
+{
+       int error;
+       struct r592_device *dev = (struct r592_device *)data;
+       unsigned long flags;
+
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&dev->io_thread_lock, flags);
+               set_current_state(TASK_INTERRUPTIBLE);
+               error = memstick_next_req(dev->host, &dev->req);
+               spin_unlock_irqrestore(&dev->io_thread_lock, flags);
+
+               if (error) {
+                       if (error == -ENXIO || error == -EAGAIN) {
+                               dbg_verbose("IO: done IO, sleeping");
+                       } else {
+                               dbg("IO: unknown error from "
+                                       "memstick_next_req %d", error);
+                       }
+
+                       if (kthread_should_stop())
+                               set_current_state(TASK_RUNNING);
+
+                       schedule();
+               } else {
+                       set_current_state(TASK_RUNNING);
+                       r592_execute_tpc(dev);
+               }
+       }
+       return 0;
+}
+
+/* Reprogram chip to detect change in card state */
+/* eg, if card is detected, arm it to detect removal, and vice versa */
+static void r592_update_card_detect(struct r592_device *dev)
+{
+       u32 reg = r592_read_reg(dev, R592_REG_MSC);
+       bool card_detected = reg & R592_REG_MSC_PRSNT;
+
+       dbg("update card detect. card state: %s", card_detected ?
+               "present" : "absent");
+
+       reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16);
+
+       if (card_detected)
+               reg |= (R592_REG_MSC_IRQ_REMOVE << 16);
+       else
+               reg |= (R592_REG_MSC_IRQ_INSERT << 16);
+
+       r592_write_reg(dev, R592_REG_MSC, reg);
+}
+
+/* Timer routine that fires 1 second after last card detection event, */
+static void r592_detect_timer(long unsigned int data)
+{
+       struct r592_device *dev = (struct r592_device *)data;
+       r592_update_card_detect(dev);
+       memstick_detect_change(dev->host);
+}
+
+/* Interrupt handler */
+static irqreturn_t r592_irq(int irq, void *data)
+{
+       struct r592_device *dev = (struct r592_device *)data;
+       irqreturn_t ret = IRQ_NONE;
+       u32 reg;
+       u16 irq_enable, irq_status;
+       unsigned long flags;
+       int error;
+
+       spin_lock_irqsave(&dev->irq_lock, flags);
+
+       reg = r592_read_reg(dev, R592_REG_MSC);
+       irq_enable = reg >> 16;
+       irq_status = reg & 0xFFFF;
+
+       /* Ack the interrupts */
+       reg &= ~irq_status;
+       r592_write_reg(dev, R592_REG_MSC, reg);
+
+       /* Get the IRQ status minus bits that aren't enabled */
+       irq_status &= (irq_enable);
+
+       /* Due to limitation of memstick core, we don't look at bits that
+               indicate that card was removed/inserted and/or present */
+       if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) {
+
+               bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT;
+               ret = IRQ_HANDLED;
+
+               message("IRQ: card %s", card_was_added ? "added" : "removed");
+
+               mod_timer(&dev->detect_timer,
+                       jiffies + msecs_to_jiffies(card_was_added ? 500 : 50));
+       }
+
+       if (irq_status &
+               (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) {
+               ret = IRQ_HANDLED;
+
+               if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) {
+                       message("IRQ: DMA error");
+                       error = -EIO;
+               } else {
+                       dbg_verbose("IRQ: dma done");
+                       error = 0;
+               }
+
+               r592_stop_dma(dev, error);
+               complete(&dev->dma_done);
+       }
+
+       spin_unlock_irqrestore(&dev->irq_lock, flags);
+       return ret;
+}
+
+/* External inteface: set settings */
+static int r592_set_param(struct memstick_host *host,
+                       enum memstick_param param, int value)
+{
+       struct r592_device *dev = memstick_priv(host);
+
+       switch (param) {
+       case MEMSTICK_POWER:
+               switch (value) {
+               case MEMSTICK_POWER_ON:
+                       return r592_enable_device(dev, true);
+               case MEMSTICK_POWER_OFF:
+                       return r592_enable_device(dev, false);
+               default:
+                       return -EINVAL;
+               }
+       case MEMSTICK_INTERFACE:
+               switch (value) {
+               case MEMSTICK_SERIAL:
+                       return r592_set_mode(dev, 0);
+               case MEMSTICK_PAR4:
+                       return r592_set_mode(dev, 1);
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+/* External interface: submit requests */
+static void r592_submit_req(struct memstick_host *host)
+{
+       struct r592_device *dev = memstick_priv(host);
+       unsigned long flags;
+
+       if (dev->req)
+               return;
+
+       spin_lock_irqsave(&dev->io_thread_lock, flags);
+       if (wake_up_process(dev->io_thread))
+               dbg_verbose("IO thread woken to process requests");
+       spin_unlock_irqrestore(&dev->io_thread_lock, flags);
+}
+
+static const struct pci_device_id r592_pci_id_tbl[] = {
+
+       { PCI_VDEVICE(RICOH, 0x0592), },
+       { },
+};
+
+/* Main entry */
+static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       int error = -ENOMEM;
+       struct memstick_host *host;
+       struct r592_device *dev;
+
+       /* Allocate memory */
+       host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev);
+       if (!host)
+               goto error1;
+
+       dev = memstick_priv(host);
+       dev->host = host;
+       dev->pci_dev = pdev;
+       pci_set_drvdata(pdev, dev);
+
+       /* pci initialization */
+       error = pci_enable_device(pdev);
+       if (error)
+               goto error2;
+
+       pci_set_master(pdev);
+       error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (error)
+               goto error3;
+
+       error = pci_request_regions(pdev, DRV_NAME);
+       if (error)
+               goto error3;
+
+       dev->mmio = pci_ioremap_bar(pdev, 0);
+       if (!dev->mmio)
+               goto error4;
+
+       dev->irq = pdev->irq;
+       spin_lock_init(&dev->irq_lock);
+       spin_lock_init(&dev->io_thread_lock);
+       init_completion(&dev->dma_done);
+       INIT_KFIFO(dev->pio_fifo);
+       setup_timer(&dev->detect_timer,
+               r592_detect_timer, (long unsigned int)dev);
+
+       /* Host initialization */
+       host->caps = MEMSTICK_CAP_PAR4;
+       host->request = r592_submit_req;
+       host->set_param = r592_set_param;
+       r592_check_dma(dev);
+
+       dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io");
+       if (IS_ERR(dev->io_thread)) {
+               error = PTR_ERR(dev->io_thread);
+               goto error5;
+       }
+
+       /* This is just a precation, so don't fail */
+       dev->dummy_dma_page = pci_alloc_consistent(pdev, PAGE_SIZE,
+               &dev->dummy_dma_page_physical_address);
+       r592_stop_dma(dev , 0);
+
+       if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
+                         DRV_NAME, dev))
+               goto error6;
+
+       r592_update_card_detect(dev);
+       if (memstick_add_host(host))
+               goto error7;
+
+       message("driver succesfully loaded");
+       return 0;
+error7:
+       free_irq(dev->irq, dev);
+error6:
+       if (dev->dummy_dma_page)
+               pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page,
+                       dev->dummy_dma_page_physical_address);
+
+       kthread_stop(dev->io_thread);
+error5:
+       iounmap(dev->mmio);
+error4:
+       pci_release_regions(pdev);
+error3:
+       pci_disable_device(pdev);
+error2:
+       memstick_free_host(host);
+error1:
+       return error;
+}
+
+static void r592_remove(struct pci_dev *pdev)
+{
+       int error = 0;
+       struct r592_device *dev = pci_get_drvdata(pdev);
+
+       /* Stop the processing thread.
+       That ensures that we won't take any more requests */
+       kthread_stop(dev->io_thread);
+
+       r592_enable_device(dev, false);
+
+       while (!error && dev->req) {
+               dev->req->error = -ETIME;
+               error = memstick_next_req(dev->host, &dev->req);
+       }
+       memstick_remove_host(dev->host);
+
+       free_irq(dev->irq, dev);
+       iounmap(dev->mmio);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       memstick_free_host(dev->host);
+
+       if (dev->dummy_dma_page)
+               pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page,
+                       dev->dummy_dma_page_physical_address);
+}
+
+#ifdef CONFIG_PM
+static int r592_suspend(struct device *core_dev)
+{
+       struct pci_dev *pdev = to_pci_dev(core_dev);
+       struct r592_device *dev = pci_get_drvdata(pdev);
+
+       r592_clear_interrupts(dev);
+       memstick_suspend_host(dev->host);
+       del_timer_sync(&dev->detect_timer);
+       return 0;
+}
+
+static int r592_resume(struct device *core_dev)
+{
+       struct pci_dev *pdev = to_pci_dev(core_dev);
+       struct r592_device *dev = pci_get_drvdata(pdev);
+
+       r592_clear_interrupts(dev);
+       r592_enable_device(dev, false);
+       memstick_resume_host(dev->host);
+       r592_update_card_detect(dev);
+       return 0;
+}
+
+SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume);
+#endif
+
+MODULE_DEVICE_TABLE(pci, r592_pci_id_tbl);
+
+static struct pci_driver r852_pci_driver = {
+       .name           = DRV_NAME,
+       .id_table       = r592_pci_id_tbl,
+       .probe          = r592_probe,
+       .remove         = r592_remove,
+#ifdef CONFIG_PM
+       .driver.pm      = &r592_pm_ops,
+#endif
+};
+
+static __init int r592_module_init(void)
+{
+       return pci_register_driver(&r852_pci_driver);
+}
+
+static void __exit r592_module_exit(void)
+{
+       pci_unregister_driver(&r852_pci_driver);
+}
+
+module_init(r592_module_init);
+module_exit(r592_module_exit);
+
+module_param(enable_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-3)");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+MODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver");
diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h
new file mode 100644 (file)
index 0000000..eee264e
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 - Maxim Levitsky
+ * driver for Ricoh memstick readers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef R592_H
+
+#include <linux/memstick.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/ctype.h>
+
+/* write to this reg (number,len) triggers TPC execution */
+#define R592_TPC_EXEC                  0x00
+#define R592_TPC_EXEC_LEN_SHIFT                16              /* Bits 16..25 are TPC len */
+#define R592_TPC_EXEC_BIG_FIFO         (1 << 26)       /* If bit 26 is set, large fifo is used (reg 48) */
+#define R592_TPC_EXEC_TPC_SHIFT                28              /* Bits 28..31 are the TPC number */
+
+
+/* Window for small TPC fifo (big endian)*/
+/* reads and writes always are done in  8 byte chunks */
+/* Not used in driver, because large fifo does better job */
+#define R592_SFIFO                     0x08
+
+
+/* Status register (ms int, small fifo, IO)*/
+#define R592_STATUS                    0x10
+                                                       /* Parallel INT bits */
+#define R592_STATUS_P_CMDNACK          (1 << 16)       /* INT reg: NACK (parallel mode) */
+#define R592_STATUS_P_BREQ             (1 << 17)       /* INT reg: card ready (parallel mode)*/
+#define R592_STATUS_P_INTERR           (1 << 18)       /* INT reg: int error (parallel mode)*/
+#define R592_STATUS_P_CED              (1 << 19)       /* INT reg: command done (parallel mode) */
+
+                                                       /* Fifo status */
+#define R592_STATUS_SFIFO_FULL         (1 << 20)       /* Small Fifo almost full (last chunk is written) */
+#define R592_STATUS_SFIFO_EMPTY                (1 << 21)       /* Small Fifo empty */
+
+                                                       /* Error detection via CRC */
+#define R592_STATUS_SEND_ERR           (1 << 24)       /* Send failed */
+#define R592_STATUS_RECV_ERR           (1 << 25)       /* Recieve failed */
+
+                                                       /* Card state */
+#define R592_STATUS_RDY                        (1 << 28)       /* RDY signal recieved */
+#define R592_STATUS_CED                        (1 << 29)       /* INT: Command done (serial mode)*/
+#define R592_STATUS_SFIFO_INPUT                (1 << 30)       /* Small fifo recieved data*/
+
+#define R592_SFIFO_SIZE                        32              /* total size of small fifo is 32 bytes */
+#define R592_SFIFO_PACKET              8               /* packet size of small fifo */
+
+/* IO control */
+#define R592_IO                                0x18
+#define        R592_IO_16                      (1 << 16)       /* Set by default, can be cleared */
+#define        R592_IO_18                      (1 << 18)       /* Set by default, can be cleared */
+#define        R592_IO_SERIAL1                 (1 << 20)       /* Set by default, can be cleared, (cleared on parallel) */
+#define        R592_IO_22                      (1 << 22)       /* Set by default, can be cleared */
+#define R592_IO_DIRECTION              (1 << 24)       /* TPC direction (1 write 0 read) */
+#define        R592_IO_26                      (1 << 26)       /* Set by default, can be cleared */
+#define        R592_IO_SERIAL2                 (1 << 30)       /* Set by default, can be cleared (cleared on parallel), serial doesn't work if unset */
+#define R592_IO_RESET                  (1 << 31)       /* Reset, sets defaults*/
+
+
+/* Turns hardware on/off */
+#define R592_POWER                     0x20            /* bits 0-7 writeable */
+#define R592_POWER_0                   (1 << 0)        /* set on start, cleared on stop - must be set*/
+#define R592_POWER_1                   (1 << 1)        /* set on start, cleared on stop - must be set*/
+#define R592_POWER_3                   (1 << 3)        /* must be clear */
+#define R592_POWER_20                  (1 << 5)        /* set before switch to parallel */
+
+/* IO mode*/
+#define R592_IO_MODE                   0x24
+#define R592_IO_MODE_SERIAL            1
+#define R592_IO_MODE_PARALLEL          3
+
+
+/* IRQ,card detection,large fifo (first word irq status, second enable) */
+/* IRQs are ACKed by clearing the bits */
+#define R592_REG_MSC                   0x28
+#define R592_REG_MSC_PRSNT             (1 << 1)        /* card present (only status)*/
+#define R592_REG_MSC_IRQ_INSERT                (1 << 8)        /* detect insert / card insered */
+#define R592_REG_MSC_IRQ_REMOVE                (1 << 9)        /* detect removal / card removed */
+#define R592_REG_MSC_FIFO_EMPTY                (1 << 10)       /* fifo is empty */
+#define R592_REG_MSC_FIFO_DMA_DONE     (1 << 11)       /* dma enable / dma done */
+
+#define R592_REG_MSC_FIFO_USER_ORN     (1 << 12)       /* set if software reads empty fifo (if R592_REG_MSC_FIFO_EMPTY is set) */
+#define R592_REG_MSC_FIFO_MISMATH      (1 << 13)       /* set if amount of data in fifo doesn't match amount in TPC */
+#define R592_REG_MSC_FIFO_DMA_ERR      (1 << 14)       /* IO failure */
+#define R592_REG_MSC_LED               (1 << 15)       /* clear to turn led off (only status)*/
+
+#define DMA_IRQ_ACK_MASK \
+       (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)
+
+#define DMA_IRQ_EN_MASK (DMA_IRQ_ACK_MASK << 16)
+
+#define IRQ_ALL_ACK_MASK 0x00007F00
+#define IRQ_ALL_EN_MASK (IRQ_ALL_ACK_MASK << 16)
+
+/* DMA address for large FIFO read/writes*/
+#define R592_FIFO_DMA                  0x2C
+
+/* PIO access to large FIFO (512 bytes) (big endian)*/
+#define R592_FIFO_PIO                  0x30
+#define R592_LFIFO_SIZE                        512             /* large fifo size */
+
+
+/* large FIFO DMA settings */
+#define R592_FIFO_DMA_SETTINGS         0x34
+#define R592_FIFO_DMA_SETTINGS_EN      (1 << 0)        /* DMA enabled */
+#define R592_FIFO_DMA_SETTINGS_DIR     (1 << 1)        /* Dma direction (1 read, 0 write) */
+#define R592_FIFO_DMA_SETTINGS_CAP     (1 << 24)       /* Dma is aviable */
+
+/* Maybe just an delay */
+/* Bits 17..19 are just number */
+/* bit 16 is set, then bit 20 is waited */
+/* time to wait is about 50 spins * 2 ^ (bits 17..19) */
+/* seems to be possible just to ignore */
+/* Probably debug register */
+#define R592_REG38                     0x38
+#define R592_REG38_CHANGE              (1 << 16)       /* Start bit */
+#define R592_REG38_DONE                        (1 << 20)       /* HW set this after the delay */
+#define R592_REG38_SHIFT               17
+
+/* Debug register, written (0xABCDEF00) when error happens - not used*/
+#define R592_REG_3C                    0x3C
+
+struct r592_device {
+       struct pci_dev *pci_dev;
+       struct memstick_host    *host;          /* host backpointer */
+       struct memstick_request *req;           /* current request */
+
+       /* Registers, IRQ */
+       void __iomem *mmio;
+       int irq;
+       spinlock_t irq_lock;
+       spinlock_t io_thread_lock;
+       struct timer_list detect_timer;
+
+       struct task_struct *io_thread;
+       bool parallel_mode;
+
+       DECLARE_KFIFO(pio_fifo, u8, sizeof(u32));
+
+       /* DMA area */
+       int dma_capable;
+       int dma_error;
+       struct completion dma_done;
+       void *dummy_dma_page;
+       dma_addr_t dummy_dma_page_physical_address;
+
+};
+
+#define DRV_NAME "r592"
+
+
+#define message(format, ...) \
+       printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
+
+#define __dbg(level, format, ...) \
+       do { \
+               if (debug >= level) \
+                       printk(KERN_DEBUG DRV_NAME \
+                               ": " format "\n", ## __VA_ARGS__); \
+       } while (0)
+
+
+#define dbg(format, ...)               __dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)       __dbg(2, format, ## __VA_ARGS__)
+#define dbg_reg(format, ...)           __dbg(3, format, ## __VA_ARGS__)
+
+#endif
index 95c9532cb07ca693cd39a6f37a49c9debe3db9d6..d182a24b31955cbf1c9b3fe0c4353d7f962ad968 100644 (file)
@@ -2,7 +2,7 @@
 
 # enable verbose logging
 # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
-#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
+#ccflags-y := -DMPT_DEBUG_VERBOSE
 
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
index ae7cad1858987f489b3b0b24a3dcaff64d143dd6..47ec5bc0ed2167b080652ade6b47804dbab49ee0 100644 (file)
@@ -695,20 +695,22 @@ static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
 };
 
 /**
- *     i2o_block_media_changed - Have we seen a media change?
+ *     i2o_block_check_events - Have we seen a media change?
  *     @disk: gendisk which should be verified
+ *     @clearing: events being cleared
  *
  *     Verifies if the media has changed.
  *
  *     Returns 1 if the media was changed or 0 otherwise.
  */
-static int i2o_block_media_changed(struct gendisk *disk)
+static unsigned int i2o_block_check_events(struct gendisk *disk,
+                                          unsigned int clearing)
 {
        struct i2o_block_device *p = disk->private_data;
 
        if (p->media_change_flag) {
                p->media_change_flag = 0;
-               return 1;
+               return DISK_EVENT_MEDIA_CHANGE;
        }
        return 0;
 }
@@ -895,11 +897,7 @@ static void i2o_block_request_fn(struct request_queue *q)
 {
        struct request *req;
 
-       while (!blk_queue_plugged(q)) {
-               req = blk_peek_request(q);
-               if (!req)
-                       break;
-
+       while ((req = blk_peek_request(q)) != NULL) {
                if (req->cmd_type == REQ_TYPE_FS) {
                        struct i2o_block_delayed_request *dreq;
                        struct i2o_block_request *ireq = req->special;
@@ -950,7 +948,7 @@ static const struct block_device_operations i2o_block_fops = {
        .ioctl = i2o_block_ioctl,
        .compat_ioctl = i2o_block_ioctl,
        .getgeo = i2o_block_getgeo,
-       .media_changed = i2o_block_media_changed
+       .check_events = i2o_block_check_events,
 };
 
 /**
@@ -1002,6 +1000,7 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
        gd->major = I2O_MAJOR;
        gd->queue = queue;
        gd->fops = &i2o_block_fops;
+       gd->events = DISK_EVENT_MEDIA_CHANGE;
        gd->private_data = dev;
 
        dev->gd = gd;
index 793300c554b4210eb44011b5a991119c4155b589..9c511c1604a5f09c4051172eca8c2b95bbf691df 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
+#include <linux/regulator/machine.h>
 
 #define INT_STATUS_NUM                 3
 
-char pm860x_backlight_name[][MFD_NAME_SIZE] = {
-       "backlight-0",
-       "backlight-1",
-       "backlight-2",
+static struct resource bk_resources[] __initdata = {
+       {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
+       {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
+       {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
 };
-EXPORT_SYMBOL(pm860x_backlight_name);
-
-char pm860x_led_name[][MFD_NAME_SIZE] = {
-       "led0-red",
-       "led0-green",
-       "led0-blue",
-       "led1-red",
-       "led1-green",
-       "led1-blue",
-};
-EXPORT_SYMBOL(pm860x_led_name);
-
-#define PM8606_BACKLIGHT_RESOURCE(_i, _x)              \
-{                                                      \
-       .name   = pm860x_backlight_name[_i],            \
-       .start  = PM8606_##_x,                          \
-       .end    = PM8606_##_x,                          \
-       .flags  = IORESOURCE_IO,                        \
-}
 
-static struct resource backlight_resources[] = {
-       PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A),
-       PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A),
-       PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A),
+static struct resource led_resources[] __initdata = {
+       {PM8606_LED1_RED,   PM8606_LED1_RED,   "led0-red",   IORESOURCE_IO,},
+       {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
+       {PM8606_LED1_BLUE,  PM8606_LED1_BLUE,  "led0-blue",  IORESOURCE_IO,},
+       {PM8606_LED2_RED,   PM8606_LED2_RED,   "led1-red",   IORESOURCE_IO,},
+       {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
+       {PM8606_LED2_BLUE,  PM8606_LED2_BLUE,  "led1-blue",  IORESOURCE_IO,},
 };
 
-#define PM8606_BACKLIGHT_DEVS(_i)                      \
-{                                                      \
-       .name           = "88pm860x-backlight",         \
-       .num_resources  = 1,                            \
-       .resources      = &backlight_resources[_i],     \
-       .id             = _i,                           \
-}
-
-static struct mfd_cell backlight_devs[] = {
-       PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1),
-       PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2),
-       PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3),
+static struct resource regulator_resources[] __initdata = {
+       {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
+       {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
+       {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
+       {PM8607_ID_LDO1,  PM8607_ID_LDO1,  "ldo-01", IORESOURCE_IO,},
+       {PM8607_ID_LDO2,  PM8607_ID_LDO2,  "ldo-02", IORESOURCE_IO,},
+       {PM8607_ID_LDO3,  PM8607_ID_LDO3,  "ldo-03", IORESOURCE_IO,},
+       {PM8607_ID_LDO4,  PM8607_ID_LDO4,  "ldo-04", IORESOURCE_IO,},
+       {PM8607_ID_LDO5,  PM8607_ID_LDO5,  "ldo-05", IORESOURCE_IO,},
+       {PM8607_ID_LDO6,  PM8607_ID_LDO6,  "ldo-06", IORESOURCE_IO,},
+       {PM8607_ID_LDO7,  PM8607_ID_LDO7,  "ldo-07", IORESOURCE_IO,},
+       {PM8607_ID_LDO8,  PM8607_ID_LDO8,  "ldo-08", IORESOURCE_IO,},
+       {PM8607_ID_LDO9,  PM8607_ID_LDO9,  "ldo-09", IORESOURCE_IO,},
+       {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
+       {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
+       {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
+       {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
+       {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
+       {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
 };
 
-#define PM8606_LED_RESOURCE(_i, _x)                    \
-{                                                      \
-       .name   = pm860x_led_name[_i],                  \
-       .start  = PM8606_##_x,                          \
-       .end    = PM8606_##_x,                          \
-       .flags  = IORESOURCE_IO,                        \
-}
-
-static struct resource led_resources[] = {
-       PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B),
-       PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C),
-       PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D),
-       PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B),
-       PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C),
-       PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D),
+static struct resource touch_resources[] __initdata = {
+       {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
 };
 
-#define PM8606_LED_DEVS(_i)                            \
-{                                                      \
-       .name           = "88pm860x-led",               \
-       .num_resources  = 1,                            \
-       .resources      = &led_resources[_i],           \
-       .id             = _i,                           \
-}
-
-static struct mfd_cell led_devs[] = {
-       PM8606_LED_DEVS(PM8606_LED1_RED),
-       PM8606_LED_DEVS(PM8606_LED1_GREEN),
-       PM8606_LED_DEVS(PM8606_LED1_BLUE),
-       PM8606_LED_DEVS(PM8606_LED2_RED),
-       PM8606_LED_DEVS(PM8606_LED2_GREEN),
-       PM8606_LED_DEVS(PM8606_LED2_BLUE),
+static struct resource onkey_resources[] __initdata = {
+       {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
 };
 
-static struct resource touch_resources[] = {
-       {
-               .start  = PM8607_IRQ_PEN,
-               .end    = PM8607_IRQ_PEN,
-               .flags  = IORESOURCE_IRQ,
-       },
+static struct resource codec_resources[] __initdata = {
+       /* Headset microphone insertion or removal */
+       {PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
+       /* Hook-switch press or release */
+       {PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
+       /* Headset insertion or removal */
+       {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
+       /* Audio short */
+       {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
 };
 
-static struct mfd_cell touch_devs[] = {
-       {
-               .name           = "88pm860x-touch",
-               .num_resources  = 1,
-               .resources      = &touch_resources[0],
-       },
+static struct resource battery_resources[] __initdata = {
+       {PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
+       {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
 };
 
-#define PM8607_REG_RESOURCE(_start, _end)              \
-{                                                      \
-       .start  = PM8607_##_start,                      \
-       .end    = PM8607_##_end,                        \
-       .flags  = IORESOURCE_IO,                        \
-}
-
-static struct resource power_supply_resources[] = {
-       {
-               .name           = "88pm860x-power",
-               .start          = PM8607_IRQ_CHG,
-               .end            = PM8607_IRQ_CHG,
-               .flags          = IORESOURCE_IRQ,
-       },
+static struct resource charger_resources[] __initdata = {
+       {PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
+       {PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",       IORESOURCE_IRQ,},
+       {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout",    IORESOURCE_IRQ,},
+       {PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature", IORESOURCE_IRQ,},
+       {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
+       {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
 };
 
-static struct mfd_cell power_devs[] = {
-       {
-               .name           = "88pm860x-power",
-               .num_resources  = 1,
-               .resources      = &power_supply_resources[0],
-               .id             = -1,
-       },
+static struct mfd_cell bk_devs[] __initdata = {
+       {"88pm860x-backlight", 0,},
+       {"88pm860x-backlight", 1,},
+       {"88pm860x-backlight", 2,},
 };
 
-static struct resource onkey_resources[] = {
-       {
-               .name           = "88pm860x-onkey",
-               .start          = PM8607_IRQ_ONKEY,
-               .end            = PM8607_IRQ_ONKEY,
-               .flags          = IORESOURCE_IRQ,
-       },
+static struct mfd_cell led_devs[] __initdata = {
+       {"88pm860x-led", 0,},
+       {"88pm860x-led", 1,},
+       {"88pm860x-led", 2,},
+       {"88pm860x-led", 3,},
+       {"88pm860x-led", 4,},
+       {"88pm860x-led", 5,},
 };
 
-static struct mfd_cell onkey_devs[] = {
-       {
-               .name           = "88pm860x-onkey",
-               .num_resources  = 1,
-               .resources      = &onkey_resources[0],
-               .id             = -1,
-       },
+static struct mfd_cell regulator_devs[] __initdata = {
+       {"88pm860x-regulator", 0,},
+       {"88pm860x-regulator", 1,},
+       {"88pm860x-regulator", 2,},
+       {"88pm860x-regulator", 3,},
+       {"88pm860x-regulator", 4,},
+       {"88pm860x-regulator", 5,},
+       {"88pm860x-regulator", 6,},
+       {"88pm860x-regulator", 7,},
+       {"88pm860x-regulator", 8,},
+       {"88pm860x-regulator", 9,},
+       {"88pm860x-regulator", 10,},
+       {"88pm860x-regulator", 11,},
+       {"88pm860x-regulator", 12,},
+       {"88pm860x-regulator", 13,},
+       {"88pm860x-regulator", 14,},
+       {"88pm860x-regulator", 15,},
+       {"88pm860x-regulator", 16,},
+       {"88pm860x-regulator", 17,},
 };
 
-static struct resource codec_resources[] = {
-       {
-               /* Headset microphone insertion or removal */
-               .name           = "micin",
-               .start          = PM8607_IRQ_MICIN,
-               .end            = PM8607_IRQ_MICIN,
-               .flags          = IORESOURCE_IRQ,
-       }, {
-               /* Hook-switch press or release */
-               .name           = "hook",
-               .start          = PM8607_IRQ_HOOK,
-               .end            = PM8607_IRQ_HOOK,
-               .flags          = IORESOURCE_IRQ,
-       }, {
-               /* Headset insertion or removal */
-               .name           = "headset",
-               .start          = PM8607_IRQ_HEADSET,
-               .end            = PM8607_IRQ_HEADSET,
-               .flags          = IORESOURCE_IRQ,
-       }, {
-               /* Audio short */
-               .name           = "audio-short",
-               .start          = PM8607_IRQ_AUDIO_SHORT,
-               .end            = PM8607_IRQ_AUDIO_SHORT,
-               .flags          = IORESOURCE_IRQ,
-       },
+static struct mfd_cell touch_devs[] __initdata = {
+       {"88pm860x-touch", -1,},
 };
 
-static struct mfd_cell codec_devs[] = {
-       {
-               .name           = "88pm860x-codec",
-               .num_resources  = ARRAY_SIZE(codec_resources),
-               .resources      = &codec_resources[0],
-               .id             = -1,
-       },
+static struct mfd_cell onkey_devs[] __initdata = {
+       {"88pm860x-onkey", -1,},
 };
 
-static struct resource regulator_resources[] = {
-       PM8607_REG_RESOURCE(BUCK1, BUCK1),
-       PM8607_REG_RESOURCE(BUCK2, BUCK2),
-       PM8607_REG_RESOURCE(BUCK3, BUCK3),
-       PM8607_REG_RESOURCE(LDO1,  LDO1),
-       PM8607_REG_RESOURCE(LDO2,  LDO2),
-       PM8607_REG_RESOURCE(LDO3,  LDO3),
-       PM8607_REG_RESOURCE(LDO4,  LDO4),
-       PM8607_REG_RESOURCE(LDO5,  LDO5),
-       PM8607_REG_RESOURCE(LDO6,  LDO6),
-       PM8607_REG_RESOURCE(LDO7,  LDO7),
-       PM8607_REG_RESOURCE(LDO8,  LDO8),
-       PM8607_REG_RESOURCE(LDO9,  LDO9),
-       PM8607_REG_RESOURCE(LDO10, LDO10),
-       PM8607_REG_RESOURCE(LDO12, LDO12),
-       PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET),
-       PM8607_REG_RESOURCE(LDO14, LDO14),
+static struct mfd_cell codec_devs[] __initdata = {
+       {"88pm860x-codec", -1,},
 };
 
-#define PM8607_REG_DEVS(_id)                                           \
-{                                                                      \
-       .name           = "88pm860x-regulator",                         \
-       .num_resources  = 1,                                            \
-       .resources      = &regulator_resources[PM8607_ID_##_id],        \
-       .id             = PM8607_ID_##_id,                              \
-}
-
-static struct mfd_cell regulator_devs[] = {
-       PM8607_REG_DEVS(BUCK1),
-       PM8607_REG_DEVS(BUCK2),
-       PM8607_REG_DEVS(BUCK3),
-       PM8607_REG_DEVS(LDO1),
-       PM8607_REG_DEVS(LDO2),
-       PM8607_REG_DEVS(LDO3),
-       PM8607_REG_DEVS(LDO4),
-       PM8607_REG_DEVS(LDO5),
-       PM8607_REG_DEVS(LDO6),
-       PM8607_REG_DEVS(LDO7),
-       PM8607_REG_DEVS(LDO8),
-       PM8607_REG_DEVS(LDO9),
-       PM8607_REG_DEVS(LDO10),
-       PM8607_REG_DEVS(LDO12),
-       PM8607_REG_DEVS(LDO13),
-       PM8607_REG_DEVS(LDO14),
+static struct mfd_cell power_devs[] = {
+       {"88pm860x-battery", -1,},
+       {"88pm860x-charger", -1,},
 };
 
+static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
+static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
+static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
+static struct pm860x_touch_pdata touch_pdata;
+static struct pm860x_power_pdata power_pdata;
+
 struct pm860x_irq_data {
        int     reg;
        int     mask_reg;
@@ -595,37 +503,212 @@ static void device_irq_exit(struct pm860x_chip *chip)
                free_irq(chip->core_irq, chip);
 }
 
-static void __devinit device_8606_init(struct pm860x_chip *chip,
-                                      struct i2c_client *i2c,
-                                      struct pm860x_platform_data *pdata)
+static void __devinit device_bk_init(struct pm860x_chip *chip,
+                                    struct i2c_client *i2c,
+                                    struct pm860x_platform_data *pdata)
 {
        int ret;
+       int i, j, id;
+
+       if ((pdata == NULL) || (pdata->backlight == NULL))
+               return;
+
+       if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
+               pdata->num_backlights = ARRAY_SIZE(bk_devs);
+
+       for (i = 0; i < pdata->num_backlights; i++) {
+               memcpy(&bk_pdata[i], &pdata->backlight[i],
+                       sizeof(struct pm860x_backlight_pdata));
+               bk_devs[i].mfd_data = &bk_pdata[i];
+
+               for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
+                       id = bk_resources[j].start;
+                       if (bk_pdata[i].flags != id)
+                               continue;
+
+                       bk_devs[i].num_resources = 1;
+                       bk_devs[i].resources = &bk_resources[j];
+                       ret = mfd_add_devices(chip->dev, 0,
+                                             &bk_devs[i], 1,
+                                             &bk_resources[j], 0);
+                       if (ret < 0) {
+                               dev_err(chip->dev, "Failed to add "
+                                       "backlight subdev\n");
+                               return;
+                       }
+               }
+       }
+}
 
-       if (pdata && pdata->backlight) {
-               ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
-                                     ARRAY_SIZE(backlight_devs),
-                                     &backlight_resources[0], 0);
-               if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add backlight "
-                               "subdev\n");
-                       goto out_dev;
+static void __devinit device_led_init(struct pm860x_chip *chip,
+                                     struct i2c_client *i2c,
+                                     struct pm860x_platform_data *pdata)
+{
+       int ret;
+       int i, j, id;
+
+       if ((pdata == NULL) || (pdata->led == NULL))
+               return;
+
+       if (pdata->num_leds > ARRAY_SIZE(led_devs))
+               pdata->num_leds = ARRAY_SIZE(led_devs);
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               memcpy(&led_pdata[i], &pdata->led[i],
+                       sizeof(struct pm860x_led_pdata));
+               led_devs[i].mfd_data = &led_pdata[i];
+
+               for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
+                       id = led_resources[j].start;
+                       if (led_pdata[i].flags != id)
+                               continue;
+
+                       led_devs[i].num_resources = 1;
+                       led_devs[i].resources = &led_resources[j],
+                       ret = mfd_add_devices(chip->dev, 0,
+                                             &led_devs[i], 1,
+                                             &led_resources[j], 0);
+                       if (ret < 0) {
+                               dev_err(chip->dev, "Failed to add "
+                                       "led subdev\n");
+                               return;
+                       }
                }
        }
+}
 
-       if (pdata && pdata->led) {
-               ret = mfd_add_devices(chip->dev, 0, &led_devs[0],
-                                     ARRAY_SIZE(led_devs),
-                                     &led_resources[0], 0);
+static void __devinit device_regulator_init(struct pm860x_chip *chip,
+                                           struct i2c_client *i2c,
+                                           struct pm860x_platform_data *pdata)
+{
+       struct regulator_init_data *initdata;
+       int ret;
+       int i, j;
+
+       if ((pdata == NULL) || (pdata->regulator == NULL))
+               return;
+
+       if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
+               pdata->num_regulators = ARRAY_SIZE(regulator_devs);
+
+       for (i = 0, j = -1; i < pdata->num_regulators; i++) {
+               initdata = &pdata->regulator[i];
+               if (strstr(initdata->constraints.name, "BUCK")) {
+                       sscanf(initdata->constraints.name, "BUCK%d", &j);
+                       /* BUCK1 ~ BUCK3 */
+                       if ((j < 1) || (j > 3)) {
+                               dev_err(chip->dev, "Failed to add constraint "
+                                       "(%s)\n", initdata->constraints.name);
+                               goto out;
+                       }
+                       j = (j - 1) + PM8607_ID_BUCK1;
+               }
+               if (strstr(initdata->constraints.name, "LDO")) {
+                       sscanf(initdata->constraints.name, "LDO%d", &j);
+                       /* LDO1 ~ LDO15 */
+                       if ((j < 1) || (j > 15)) {
+                               dev_err(chip->dev, "Failed to add constraint "
+                                       "(%s)\n", initdata->constraints.name);
+                               goto out;
+                       }
+                       j = (j - 1) + PM8607_ID_LDO1;
+               }
+               if (j == -1) {
+                       dev_err(chip->dev, "Failed to add constraint (%s)\n",
+                               initdata->constraints.name);
+                       goto out;
+               }
+               memcpy(&regulator_pdata[i], &pdata->regulator[i],
+                       sizeof(struct regulator_init_data));
+               regulator_devs[i].mfd_data = &regulator_pdata[i];
+               regulator_devs[i].num_resources = 1;
+               regulator_devs[i].resources = &regulator_resources[j];
+
+               ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
+                                     &regulator_resources[j], 0);
                if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add led "
-                               "subdev\n");
-                       goto out_dev;
+                       dev_err(chip->dev, "Failed to add regulator subdev\n");
+                       goto out;
                }
        }
+out:
        return;
-out_dev:
-       mfd_remove_devices(chip->dev);
-       device_irq_exit(chip);
+}
+
+static void __devinit device_touch_init(struct pm860x_chip *chip,
+                                       struct i2c_client *i2c,
+                                       struct pm860x_platform_data *pdata)
+{
+       int ret;
+
+       if ((pdata == NULL) || (pdata->touch == NULL))
+               return;
+
+       memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
+       touch_devs[0].mfd_data = &touch_pdata;
+       touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
+       touch_devs[0].resources = &touch_resources[0];
+       ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
+                             ARRAY_SIZE(touch_devs), &touch_resources[0],
+                             chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add touch subdev\n");
+}
+
+static void __devinit device_power_init(struct pm860x_chip *chip,
+                                       struct i2c_client *i2c,
+                                       struct pm860x_platform_data *pdata)
+{
+       int ret;
+
+       if ((pdata == NULL) || (pdata->power == NULL))
+               return;
+
+       memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
+       power_devs[0].mfd_data = &power_pdata;
+       power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
+       power_devs[0].resources = &battery_resources[0],
+       ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
+                             &battery_resources[0], chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add battery subdev\n");
+
+       power_devs[1].mfd_data = &power_pdata;
+       power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
+       power_devs[1].resources = &charger_resources[0],
+       ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
+                             &charger_resources[0], chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add charger subdev\n");
+}
+
+static void __devinit device_onkey_init(struct pm860x_chip *chip,
+                                       struct i2c_client *i2c,
+                                       struct pm860x_platform_data *pdata)
+{
+       int ret;
+
+       onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
+       onkey_devs[0].resources = &onkey_resources[0],
+       ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+                             ARRAY_SIZE(onkey_devs), &onkey_resources[0],
+                             chip->irq_base);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add onkey subdev\n");
+}
+
+static void __devinit device_codec_init(struct pm860x_chip *chip,
+                                       struct i2c_client *i2c,
+                                       struct pm860x_platform_data *pdata)
+{
+       int ret;
+
+       codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
+       codec_devs[0].resources = &codec_resources[0],
+       ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
+                             ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
+       if (ret < 0)
+               dev_err(chip->dev, "Failed to add codec subdev\n");
 }
 
 static void __devinit device_8607_init(struct pm860x_chip *chip,
@@ -683,55 +766,11 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
        if (ret < 0)
                goto out;
 
-       ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
-                             ARRAY_SIZE(regulator_devs),
-                             &regulator_resources[0], 0);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to add regulator subdev\n");
-               goto out_dev;
-       }
-
-       if (pdata && pdata->touch) {
-               ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
-                                     ARRAY_SIZE(touch_devs),
-                                     &touch_resources[0], 0);
-               if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add touch "
-                               "subdev\n");
-                       goto out_dev;
-               }
-       }
-
-       if (pdata && pdata->power) {
-               ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
-                                     ARRAY_SIZE(power_devs),
-                                     &power_supply_resources[0], 0);
-               if (ret < 0) {
-                       dev_err(chip->dev, "Failed to add power supply "
-                               "subdev\n");
-                       goto out_dev;
-               }
-       }
-
-       ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
-                             ARRAY_SIZE(onkey_devs),
-                             &onkey_resources[0], 0);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to add onkey subdev\n");
-               goto out_dev;
-       }
-
-       ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
-                             ARRAY_SIZE(codec_devs),
-                             &codec_resources[0], 0);
-       if (ret < 0) {
-               dev_err(chip->dev, "Failed to add codec subdev\n");
-               goto out_dev;
-       }
-       return;
-out_dev:
-       mfd_remove_devices(chip->dev);
-       device_irq_exit(chip);
+       device_regulator_init(chip, i2c, pdata);
+       device_onkey_init(chip, i2c, pdata);
+       device_touch_init(chip, i2c, pdata);
+       device_power_init(chip, i2c, pdata);
+       device_codec_init(chip, i2c, pdata);
 out:
        return;
 }
@@ -743,7 +782,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 
        switch (chip->id) {
        case CHIP_PM8606:
-               device_8606_init(chip, chip->client, pdata);
+               device_bk_init(chip, chip->client, pdata);
+               device_led_init(chip, chip->client, pdata);
                break;
        case CHIP_PM8607:
                device_8607_init(chip, chip->client, pdata);
@@ -753,7 +793,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
        if (chip->companion) {
                switch (chip->id) {
                case CHIP_PM8607:
-                       device_8606_init(chip, chip->companion, pdata);
+                       device_bk_init(chip, chip->companion, pdata);
+                       device_led_init(chip, chip->companion, pdata);
                        break;
                case CHIP_PM8606:
                        device_8607_init(chip, chip->companion, pdata);
index bc02e6b21608be1ee4a0fcf4e52e3e6e7f383982..e017dc88622ada48f145457585e5fc376a6d155e 100644 (file)
@@ -126,6 +126,109 @@ out:
 }
 EXPORT_SYMBOL(pm860x_set_bits);
 
+int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char zero = 0;
+       unsigned char data;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       pm860x_write_device(i2c, 0xFA, 0, &zero);
+       pm860x_write_device(i2c, 0xFB, 0, &zero);
+       pm860x_write_device(i2c, 0xFF, 0, &zero);
+       ret = pm860x_read_device(i2c, reg, 1, &data);
+       if (ret >= 0)
+               ret = (int)data;
+       pm860x_write_device(i2c, 0xFE, 0, &zero);
+       pm860x_write_device(i2c, 0xFC, 0, &zero);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm860x_page_reg_read);
+
+int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
+                         unsigned char data)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char zero;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       pm860x_write_device(i2c, 0xFA, 0, &zero);
+       pm860x_write_device(i2c, 0xFB, 0, &zero);
+       pm860x_write_device(i2c, 0xFF, 0, &zero);
+       ret = pm860x_write_device(i2c, reg, 1, &data);
+       pm860x_write_device(i2c, 0xFE, 0, &zero);
+       pm860x_write_device(i2c, 0xFC, 0, &zero);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm860x_page_reg_write);
+
+int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
+                         int count, unsigned char *buf)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char zero = 0;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       pm860x_write_device(i2c, 0xFA, 0, &zero);
+       pm860x_write_device(i2c, 0xFB, 0, &zero);
+       pm860x_write_device(i2c, 0xFF, 0, &zero);
+       ret = pm860x_read_device(i2c, reg, count, buf);
+       pm860x_write_device(i2c, 0xFE, 0, &zero);
+       pm860x_write_device(i2c, 0xFC, 0, &zero);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm860x_page_bulk_read);
+
+int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
+                          int count, unsigned char *buf)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char zero = 0;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       pm860x_write_device(i2c, 0xFA, 0, &zero);
+       pm860x_write_device(i2c, 0xFB, 0, &zero);
+       pm860x_write_device(i2c, 0xFF, 0, &zero);
+       ret = pm860x_write_device(i2c, reg, count, buf);
+       pm860x_write_device(i2c, 0xFE, 0, &zero);
+       pm860x_write_device(i2c, 0xFC, 0, &zero);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm860x_page_bulk_write);
+
+int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
+                        unsigned char mask, unsigned char data)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char zero;
+       unsigned char value;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       pm860x_write_device(i2c, 0xFA, 0, &zero);
+       pm860x_write_device(i2c, 0xFB, 0, &zero);
+       pm860x_write_device(i2c, 0xFF, 0, &zero);
+       ret = pm860x_read_device(i2c, reg, 1, &value);
+       if (ret < 0)
+               goto out;
+       value &= ~mask;
+       value |= data;
+       ret = pm860x_write_device(i2c, reg, 1, &value);
+out:
+       pm860x_write_device(i2c, 0xFE, 0, &zero);
+       pm860x_write_device(i2c, 0xFC, 0, &zero);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm860x_page_set_bits);
 
 static const struct i2c_device_id pm860x_id_table[] = {
        { "88PM860x", 0 },
index fdca643249e1743c5030e081ca525ccac8f7255a..a9a1af49281eea983265c3084c6a1f8bed1585a9 100644 (file)
@@ -129,6 +129,17 @@ config UCB1400_CORE
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_core.
 
+config TPS6105X
+       tristate "TPS61050/61052 Boost Converters"
+       depends on I2C
+       select REGULATOR
+       select REGULATOR_FIXED_VOLTAGE
+       help
+         This option enables a driver for the TP61050/TPS61052
+         high-power "white LED driver". This boost converter is
+         sometimes used for other things than white LEDs, and
+         also contains a GPIO pin.
+
 config TPS65010
        tristate "TPS6501x Power Management chips"
        depends on I2C && GPIOLIB
@@ -178,6 +189,16 @@ config TWL4030_CORE
          high speed USB OTG transceiver, an audio codec (on most
          versions) and many other features.
 
+config TWL4030_MADC
+       tristate "Texas Instruments TWL4030 MADC"
+       depends on TWL4030_CORE
+       help
+       This driver provides support for triton TWL4030-MADC. The
+       driver supports both RT and SW conversion methods.
+
+       This driver can be built as a module. If so it will be
+       named twl4030-madc
+
 config TWL4030_POWER
        bool "Support power resources on TWL4030 family chips"
        depends on TWL4030_CORE && ARM
@@ -304,6 +325,18 @@ config MFD_MAX8925
          accessing the device, additional drivers must be enabled in order
          to use the functionality of the device.
 
+config MFD_MAX8997
+       bool "Maxim Semiconductor MAX8997/8966 PMIC Support"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       help
+         Say yes here to support for Maxim Semiconductor MAX8998/8966.
+         This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
+         MUIC controls on chip.
+         This driver provides common support for accessing the device;
+         additional drivers must be enabled in order to use the functionality
+         of the device.
+
 config MFD_MAX8998
        bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
        depends on I2C=y && GENERIC_HARDIRQS
@@ -534,6 +567,13 @@ config AB8500_DEBUG
          Select this option if you want debug information using the debug
          filesystem, debugfs.
 
+config AB8500_GPADC
+       bool "AB8500 GPADC driver"
+       depends on AB8500_CORE && REGULATOR_AB8500
+       default y
+       help
+         AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage
+
 config AB3550_CORE
         bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions"
        select MFD_CORE
@@ -626,7 +666,7 @@ config MFD_VX855
          and/or vx855_gpio drivers for this to do anything useful.
 
 config MFD_WL1273_CORE
-       tristate
+       tristate "Support for TI WL1273 FM radio."
        depends on I2C
        select MFD_CORE
        default n
index f0e25cad762ed5e24e7c7cb36099261fc3bbdd7e..47f5709f3828c48d1b85e894e241341291dccf6f 100644 (file)
@@ -33,11 +33,13 @@ obj-$(CONFIG_MFD_WM8350)    += wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
 obj-$(CONFIG_MFD_WM8994)       += wm8994-core.o wm8994-irq.o
 
+obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
+obj-$(CONFIG_TWL4030_MADC)      += twl4030-madc.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_TWL4030_CODEC)    += twl4030-codec.o
 obj-$(CONFIG_TWL6030_PWM)      += twl6030-pwm.o
@@ -61,6 +63,7 @@ obj-$(CONFIG_UCB1400_CORE)    += ucb1400_core.o
 obj-$(CONFIG_PMIC_DA903X)      += da903x.o
 max8925-objs                   := max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)      += max8925.o
+obj-$(CONFIG_MFD_MAX8997)      += max8997.o
 obj-$(CONFIG_MFD_MAX8998)      += max8998.o max8998-irq.o
 
 pcf50633-objs                  := pcf50633-core.o pcf50633-irq.o
@@ -71,9 +74,10 @@ obj-$(CONFIG_ABX500_CORE)    += abx500-core.o
 obj-$(CONFIG_AB3100_CORE)      += ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)       += ab3100-otp.o
 obj-$(CONFIG_AB3550_CORE)      += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o
+obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o ab8500-sysctrl.o
 obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
 obj-$(CONFIG_AB8500_DEBUG)     += ab8500-debugfs.o
+obj-$(CONFIG_AB8500_GPADC)     += ab8500-gpadc.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)     += adp5520.o
 obj-$(CONFIG_LPC_SCH)          += lpc_sch.o
index 4193af5f2743904238962f440483eca992d20680..a751927047ac967b6111359c3d8942253382be12 100644 (file)
@@ -613,7 +613,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
        ab3100_get_priv.ab3100 = ab3100;
        ab3100_get_priv.mode = false;
        ab3100_get_reg_file = debugfs_create_file("get_reg",
-                               S_IWUGO, ab3100_dir, &ab3100_get_priv,
+                               S_IWUSR, ab3100_dir, &ab3100_get_priv,
                                &ab3100_get_set_reg_fops);
        if (!ab3100_get_reg_file) {
                err = -ENOMEM;
@@ -623,7 +623,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100)
        ab3100_set_priv.ab3100 = ab3100;
        ab3100_set_priv.mode = true;
        ab3100_set_reg_file = debugfs_create_file("set_reg",
-                               S_IWUGO, ab3100_dir, &ab3100_set_priv,
+                               S_IWUSR, ab3100_dir, &ab3100_set_priv,
                                &ab3100_get_set_reg_fops);
        if (!ab3100_set_reg_file) {
                err = -ENOMEM;
@@ -949,10 +949,8 @@ static int __devinit ab3100_probe(struct i2c_client *client,
                goto exit_no_ops;
 
        /* Set up and register the platform devices. */
-       for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
-               ab3100_devs[i].platform_data = ab3100_plf_data;
-               ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data);
-       }
+       for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
+               ab3100_devs[i].mfd_data = ab3100_plf_data;
 
        err = mfd_add_devices(&client->dev, 0, ab3100_devs,
                ARRAY_SIZE(ab3100_devs), NULL, 0);
index 5fbca346b998d4a5316790306bc60c32fb8eb623..c12d042852269a6ebaeff0e132d316ef2b0a6d0e 100644 (file)
@@ -1053,17 +1053,17 @@ static inline void ab3550_setup_debugfs(struct ab3550 *ab)
                goto exit_destroy_dir;
 
        ab3550_bank_file = debugfs_create_file("register-bank",
-               (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops);
+               (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_bank_fops);
        if (!ab3550_bank_file)
                goto exit_destroy_reg;
 
        ab3550_address_file = debugfs_create_file("register-address",
-               (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops);
+               (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_address_fops);
        if (!ab3550_address_file)
                goto exit_destroy_bank;
 
        ab3550_val_file = debugfs_create_file("register-value",
-               (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops);
+               (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_val_fops);
        if (!ab3550_val_file)
                goto exit_destroy_address;
 
@@ -1320,10 +1320,8 @@ static int __init ab3550_probe(struct i2c_client *client,
                goto exit_no_ops;
 
        /* Set up and register the platform devices. */
-       for (i = 0; i < AB3550_NUM_DEVICES; i++) {
-               ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
-               ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i];
-       }
+       for (i = 0; i < AB3550_NUM_DEVICES; i++)
+               ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
 
        err = mfd_add_devices(&client->dev, 0, ab3550_devs,
                ARRAY_SIZE(ab3550_devs), NULL,
index b6887014d687bbe03c608f029fa5d4f2634b93ad..6e185b272d00890a20a2fff6b6e2f846b00cc753 100644 (file)
@@ -4,7 +4,7 @@
  * License Terms: GNU General Public License v2
  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
  * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- * Changes: Mattias Wallin <mattias.wallin@stericsson.com>
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com>
  */
 
 #include <linux/kernel.h>
@@ -90,6 +90,7 @@
 #define AB8500_IT_MASK24_REG           0x57
 
 #define AB8500_REV_REG                 0x80
+#define AB8500_SWITCH_OFF_STATUS       0x00
 
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
@@ -652,10 +653,38 @@ static ssize_t show_chip_id(struct device *dev,
        return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
 }
 
+/*
+ * ab8500 has switched off due to (SWITCH_OFF_STATUS):
+ * 0x01 Swoff bit programming
+ * 0x02 Thermal protection activation
+ * 0x04 Vbat lower then BattOk falling threshold
+ * 0x08 Watchdog expired
+ * 0x10 Non presence of 32kHz clock
+ * 0x20 Battery level lower than power on reset threshold
+ * 0x40 Power on key 1 pressed longer than 10 seconds
+ * 0x80 DB8500 thermal shutdown
+ */
+static ssize_t show_switch_off_status(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int ret;
+       u8 value;
+       struct ab8500 *ab8500;
+
+       ab8500 = dev_get_drvdata(dev);
+       ret = get_register_interruptible(ab8500, AB8500_RTC,
+               AB8500_SWITCH_OFF_STATUS, &value);
+       if (ret < 0)
+               return ret;
+       return sprintf(buf, "%#x\n", value);
+}
+
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 
 static struct attribute *ab8500_sysfs_entries[] = {
        &dev_attr_chip_id.attr,
+       &dev_attr_switch_off_status.attr,
        NULL,
 };
 
@@ -686,9 +715,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
         * 0x10 - Cut 1.0
         * 0x11 - Cut 1.1
         * 0x20 - Cut 2.0
+        * 0x30 - Cut 3.0
         */
-       if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
-               ab8500->revision = value;
+       if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 ||
+               value == 0x30) {
                dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
        } else {
                dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
@@ -696,6 +726,24 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        }
        ab8500->chip_id = value;
 
+       /*
+        * ab8500 has switched off due to (SWITCH_OFF_STATUS):
+        * 0x01 Swoff bit programming
+        * 0x02 Thermal protection activation
+        * 0x04 Vbat lower then BattOk falling threshold
+        * 0x08 Watchdog expired
+        * 0x10 Non presence of 32kHz clock
+        * 0x20 Battery level lower than power on reset threshold
+        * 0x40 Power on key 1 pressed longer than 10 seconds
+        * 0x80 DB8500 thermal shutdown
+        */
+
+       ret = get_register_interruptible(ab8500, AB8500_RTC,
+               AB8500_SWITCH_OFF_STATUS, &value);
+       if (ret < 0)
+               return ret;
+       dev_info(ab8500->dev, "switch off status: %#x", value);
+
        if (plat && plat->init)
                plat->init(ab8500);
 
@@ -764,6 +812,6 @@ int __devexit ab8500_exit(struct ab8500 *ab8500)
        return 0;
 }
 
-MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent");
+MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
 MODULE_DESCRIPTION("AB8500 MFD core");
 MODULE_LICENSE("GPL v2");
index 3c1541ae722321f43b27a01294e553a6d4bcdf58..64748e42ac039c101431782547194834cd4ca69b 100644 (file)
@@ -585,18 +585,18 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf)
                goto exit_destroy_dir;
 
        ab8500_bank_file = debugfs_create_file("register-bank",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
        if (!ab8500_bank_file)
                goto exit_destroy_reg;
 
        ab8500_address_file = debugfs_create_file("register-address",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
                &ab8500_address_fops);
        if (!ab8500_address_file)
                goto exit_destroy_bank;
 
        ab8500_val_file = debugfs_create_file("register-value",
-               (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+               (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
        if (!ab8500_val_file)
                goto exit_destroy_address;
 
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
new file mode 100644 (file)
index 0000000..bc93b2e
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ * Author: Johan Palsson <johan.palsson@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500/gpadc.h>
+
+/*
+ * GPADC register offsets
+ * Bank : 0x0A
+ */
+#define AB8500_GPADC_CTRL1_REG         0x00
+#define AB8500_GPADC_CTRL2_REG         0x01
+#define AB8500_GPADC_CTRL3_REG         0x02
+#define AB8500_GPADC_AUTO_TIMER_REG    0x03
+#define AB8500_GPADC_STAT_REG          0x04
+#define AB8500_GPADC_MANDATAL_REG      0x05
+#define AB8500_GPADC_MANDATAH_REG      0x06
+#define AB8500_GPADC_AUTODATAL_REG     0x07
+#define AB8500_GPADC_AUTODATAH_REG     0x08
+#define AB8500_GPADC_MUX_CTRL_REG      0x09
+
+/*
+ * OTP register offsets
+ * Bank : 0x15
+ */
+#define AB8500_GPADC_CAL_1             0x0F
+#define AB8500_GPADC_CAL_2             0x10
+#define AB8500_GPADC_CAL_3             0x11
+#define AB8500_GPADC_CAL_4             0x12
+#define AB8500_GPADC_CAL_5             0x13
+#define AB8500_GPADC_CAL_6             0x14
+#define AB8500_GPADC_CAL_7             0x15
+
+/* gpadc constants */
+#define EN_VINTCORE12                  0x04
+#define EN_VTVOUT                      0x02
+#define EN_GPADC                       0x01
+#define DIS_GPADC                      0x00
+#define SW_AVG_16                      0x60
+#define ADC_SW_CONV                    0x04
+#define EN_ICHAR                       0x80
+#define EN_BUF                         0x40
+#define DIS_ZERO                       0x00
+#define GPADC_BUSY                     0x01
+
+/* GPADC constants from AB8500 spec, UM0836 */
+#define ADC_RESOLUTION                 1024
+#define ADC_CH_BTEMP_MIN               0
+#define ADC_CH_BTEMP_MAX               1350
+#define ADC_CH_DIETEMP_MIN             0
+#define ADC_CH_DIETEMP_MAX             1350
+#define ADC_CH_CHG_V_MIN               0
+#define ADC_CH_CHG_V_MAX               20030
+#define ADC_CH_ACCDET2_MIN             0
+#define ADC_CH_ACCDET2_MAX             2500
+#define ADC_CH_VBAT_MIN                        2300
+#define ADC_CH_VBAT_MAX                        4800
+#define ADC_CH_CHG_I_MIN               0
+#define ADC_CH_CHG_I_MAX               1500
+#define ADC_CH_BKBAT_MIN               0
+#define ADC_CH_BKBAT_MAX               3200
+
+/* This is used to not lose precision when dividing to get gain and offset */
+#define CALIB_SCALE                    1000
+
+enum cal_channels {
+       ADC_INPUT_VMAIN = 0,
+       ADC_INPUT_BTEMP,
+       ADC_INPUT_VBAT,
+       NBR_CAL_INPUTS,
+};
+
+/**
+ * struct adc_cal_data - Table for storing gain and offset for the calibrated
+ * ADC channels
+ * @gain:              Gain of the ADC channel
+ * @offset:            Offset of the ADC channel
+ */
+struct adc_cal_data {
+       u64 gain;
+       u64 offset;
+};
+
+/**
+ * struct ab8500_gpadc - AB8500 GPADC device information
+ * @dev:                       pointer to the struct device
+ * @node:                      a list of AB8500 GPADCs, hence prepared for
+                               reentrance
+ * @ab8500_gpadc_complete:     pointer to the struct completion, to indicate
+ *                             the completion of gpadc conversion
+ * @ab8500_gpadc_lock:         structure of type mutex
+ * @regu:                      pointer to the struct regulator
+ * @irq:                       interrupt number that is used by gpadc
+ * @cal_data                   array of ADC calibration data structs
+ */
+struct ab8500_gpadc {
+       struct device *dev;
+       struct list_head node;
+       struct completion ab8500_gpadc_complete;
+       struct mutex ab8500_gpadc_lock;
+       struct regulator *regu;
+       int irq;
+       struct adc_cal_data cal_data[NBR_CAL_INPUTS];
+};
+
+static LIST_HEAD(ab8500_gpadc_list);
+
+/**
+ * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC
+ * (i.e. the first GPADC in the instance list)
+ */
+struct ab8500_gpadc *ab8500_gpadc_get(char *name)
+{
+       struct ab8500_gpadc *gpadc;
+
+       list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
+               if (!strcmp(name, dev_name(gpadc->dev)))
+                   return gpadc;
+       }
+
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(ab8500_gpadc_get);
+
+static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input,
+       int ad_value)
+{
+       int res;
+
+       switch (input) {
+       case MAIN_CHARGER_V:
+               /* For some reason we don't have calibrated data */
+               if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) {
+                       res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX -
+                               ADC_CH_CHG_V_MIN) * ad_value /
+                               ADC_RESOLUTION;
+                       break;
+               }
+               /* Here we can use the calibrated data */
+               res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain +
+                       gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE;
+               break;
+
+       case BAT_CTRL:
+       case BTEMP_BALL:
+       case ACC_DETECT1:
+       case ADC_AUX1:
+       case ADC_AUX2:
+               /* For some reason we don't have calibrated data */
+               if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) {
+                       res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX -
+                               ADC_CH_BTEMP_MIN) * ad_value /
+                               ADC_RESOLUTION;
+                       break;
+               }
+               /* Here we can use the calibrated data */
+               res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain +
+                       gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE;
+               break;
+
+       case MAIN_BAT_V:
+               /* For some reason we don't have calibrated data */
+               if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) {
+                       res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX -
+                               ADC_CH_VBAT_MIN) * ad_value /
+                               ADC_RESOLUTION;
+                       break;
+               }
+               /* Here we can use the calibrated data */
+               res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain +
+                       gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE;
+               break;
+
+       case DIE_TEMP:
+               res = ADC_CH_DIETEMP_MIN +
+                       (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value /
+                       ADC_RESOLUTION;
+               break;
+
+       case ACC_DETECT2:
+               res = ADC_CH_ACCDET2_MIN +
+                       (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value /
+                       ADC_RESOLUTION;
+               break;
+
+       case VBUS_V:
+               res = ADC_CH_CHG_V_MIN +
+                       (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value /
+                       ADC_RESOLUTION;
+               break;
+
+       case MAIN_CHARGER_C:
+       case USB_CHARGER_C:
+               res = ADC_CH_CHG_I_MIN +
+                       (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value /
+                       ADC_RESOLUTION;
+               break;
+
+       case BK_BAT_V:
+               res = ADC_CH_BKBAT_MIN +
+                       (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value /
+                       ADC_RESOLUTION;
+               break;
+
+       default:
+               dev_err(gpadc->dev,
+                       "unknown channel, not possible to convert\n");
+               res = -EINVAL;
+               break;
+
+       }
+       return res;
+}
+
+/**
+ * ab8500_gpadc_convert() - gpadc conversion
+ * @input:     analog input to be converted to digital data
+ *
+ * This function converts the selected analog i/p to digital
+ * data.
+ */
+int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
+{
+       int ret;
+       u16 data = 0;
+       int looplimit = 0;
+       u8 val, low_data, high_data;
+
+       if (!gpadc)
+               return -ENODEV;
+
+       mutex_lock(&gpadc->ab8500_gpadc_lock);
+       /* Enable VTVout LDO this is required for GPADC */
+       regulator_enable(gpadc->regu);
+
+       /* Check if ADC is not busy, lock and proceed */
+       do {
+               ret = abx500_get_register_interruptible(gpadc->dev,
+                       AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
+               if (ret < 0)
+                       goto out;
+               if (!(val & GPADC_BUSY))
+                       break;
+               msleep(10);
+       } while (++looplimit < 10);
+       if (looplimit >= 10 && (val & GPADC_BUSY)) {
+               dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Enable GPADC */
+       ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+               AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
+       if (ret < 0) {
+               dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
+               goto out;
+       }
+       /* Select the input source and set average samples to 16 */
+       ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
+               AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
+       if (ret < 0) {
+               dev_err(gpadc->dev,
+                       "gpadc_conversion: set avg samples failed\n");
+               goto out;
+       }
+       /*
+        * Enable ADC, buffering, select rising edge and enable ADC path
+        * charging current sense if it needed
+        */
+       switch (input) {
+       case MAIN_CHARGER_C:
+       case USB_CHARGER_C:
+               ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+                       AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+                       EN_BUF | EN_ICHAR,
+                       EN_BUF | EN_ICHAR);
+               break;
+       default:
+               ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+                       AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
+               break;
+       }
+       if (ret < 0) {
+               dev_err(gpadc->dev,
+                       "gpadc_conversion: select falling edge failed\n");
+               goto out;
+       }
+       ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+               AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
+       if (ret < 0) {
+               dev_err(gpadc->dev,
+                       "gpadc_conversion: start s/w conversion failed\n");
+               goto out;
+       }
+       /* wait for completion of conversion */
+       if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) {
+               dev_err(gpadc->dev,
+                       "timeout: didnt recieve GPADC conversion interrupt\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Read the converted RAW data */
+       ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
+               AB8500_GPADC_MANDATAL_REG, &low_data);
+       if (ret < 0) {
+               dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
+               goto out;
+       }
+
+       ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
+               AB8500_GPADC_MANDATAH_REG, &high_data);
+       if (ret < 0) {
+               dev_err(gpadc->dev,
+                       "gpadc_conversion: read high data failed\n");
+               goto out;
+       }
+
+       data = (high_data << 8) | low_data;
+       /* Disable GPADC */
+       ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
+               AB8500_GPADC_CTRL1_REG, DIS_GPADC);
+       if (ret < 0) {
+               dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n");
+               goto out;
+       }
+       /* Disable VTVout LDO this is required for GPADC */
+       regulator_disable(gpadc->regu);
+       mutex_unlock(&gpadc->ab8500_gpadc_lock);
+       ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data);
+       return ret;
+
+out:
+       /*
+        * It has shown to be needed to turn off the GPADC if an error occurs,
+        * otherwise we might have problem when waiting for the busy bit in the
+        * GPADC status register to go low. In V1.1 there wait_for_completion
+        * seems to timeout when waiting for an interrupt.. Not seen in V2.0
+        */
+       (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
+               AB8500_GPADC_CTRL1_REG, DIS_GPADC);
+       regulator_disable(gpadc->regu);
+       mutex_unlock(&gpadc->ab8500_gpadc_lock);
+       dev_err(gpadc->dev,
+               "gpadc_conversion: Failed to AD convert channel %d\n", input);
+       return ret;
+}
+EXPORT_SYMBOL(ab8500_gpadc_convert);
+
+/**
+ * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
+ * @irq:       irq number
+ * @data:      pointer to the data passed during request irq
+ *
+ * This is a interrupt service routine for s/w gpadc conversion completion.
+ * Notifies the gpadc completion is completed and the converted raw value
+ * can be read from the registers.
+ * Returns IRQ status(IRQ_HANDLED)
+ */
+static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
+{
+       struct ab8500_gpadc *gpadc = _gpadc;
+
+       complete(&gpadc->ab8500_gpadc_complete);
+
+       return IRQ_HANDLED;
+}
+
+static int otp_cal_regs[] = {
+       AB8500_GPADC_CAL_1,
+       AB8500_GPADC_CAL_2,
+       AB8500_GPADC_CAL_3,
+       AB8500_GPADC_CAL_4,
+       AB8500_GPADC_CAL_5,
+       AB8500_GPADC_CAL_6,
+       AB8500_GPADC_CAL_7,
+};
+
+static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
+{
+       int i;
+       int ret[ARRAY_SIZE(otp_cal_regs)];
+       u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)];
+
+       int vmain_high, vmain_low;
+       int btemp_high, btemp_low;
+       int vbat_high, vbat_low;
+
+       /* First we read all OTP registers and store the error code */
+       for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) {
+               ret[i] = abx500_get_register_interruptible(gpadc->dev,
+                       AB8500_OTP_EMUL, otp_cal_regs[i],  &gpadc_cal[i]);
+               if (ret[i] < 0)
+                       dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n",
+                               __func__, otp_cal_regs[i]);
+       }
+
+       /*
+        * The ADC calibration data is stored in OTP registers.
+        * The layout of the calibration data is outlined below and a more
+        * detailed description can be found in UM0836
+        *
+        * vm_h/l = vmain_high/low
+        * bt_h/l = btemp_high/low
+        * vb_h/l = vbat_high/low
+        *
+        * Data bits:
+        * | 7     | 6     | 5     | 4     | 3     | 2     | 1     | 0
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * |                                               | vm_h9 | vm_h8
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * |               | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
+        * |.......|.......|.......|.......|.......|.......|.......|.......
+        *
+        *
+        * Ideal output ADC codes corresponding to injected input voltages
+        * during manufacturing is:
+        *
+        * vmain_high: Vin = 19500mV / ADC ideal code = 997
+        * vmain_low:  Vin = 315mV   / ADC ideal code = 16
+        * btemp_high: Vin = 1300mV  / ADC ideal code = 985
+        * btemp_low:  Vin = 21mV    / ADC ideal code = 16
+        * vbat_high:  Vin = 4700mV  / ADC ideal code = 982
+        * vbat_low:   Vin = 2380mV  / ADC ideal code = 33
+        */
+
+       /* Calculate gain and offset for VMAIN if all reads succeeded */
+       if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
+               vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
+                       ((gpadc_cal[1] & 0x3F) << 2) |
+                       ((gpadc_cal[2] & 0xC0) >> 6));
+
+               vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+
+               gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
+                       (19500 - 315) / (vmain_high - vmain_low);
+
+               gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 -
+                       (CALIB_SCALE * (19500 - 315) /
+                        (vmain_high - vmain_low)) * vmain_high;
+       } else {
+               gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+       }
+
+       /* Calculate gain and offset for BTEMP if all reads succeeded */
+       if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) {
+               btemp_high = (((gpadc_cal[2] & 0x01) << 9) |
+                       (gpadc_cal[3] << 1) |
+                       ((gpadc_cal[4] & 0x80) >> 7));
+
+               btemp_low = ((gpadc_cal[4] & 0x7C) >> 2);
+
+               gpadc->cal_data[ADC_INPUT_BTEMP].gain =
+                       CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low);
+
+               gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 -
+                       (CALIB_SCALE * (1300 - 21) /
+                       (btemp_high - btemp_low)) * btemp_high;
+       } else {
+               gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0;
+       }
+
+       /* Calculate gain and offset for VBAT if all reads succeeded */
+       if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) {
+               vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]);
+               vbat_low = ((gpadc_cal[6] & 0xFC) >> 2);
+
+               gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE *
+                       (4700 - 2380) / (vbat_high - vbat_low);
+
+               gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 -
+                       (CALIB_SCALE * (4700 - 2380) /
+                       (vbat_high - vbat_low)) * vbat_high;
+       } else {
+               gpadc->cal_data[ADC_INPUT_VBAT].gain = 0;
+       }
+
+       dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n",
+               gpadc->cal_data[ADC_INPUT_VMAIN].gain,
+               gpadc->cal_data[ADC_INPUT_VMAIN].offset);
+
+       dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n",
+               gpadc->cal_data[ADC_INPUT_BTEMP].gain,
+               gpadc->cal_data[ADC_INPUT_BTEMP].offset);
+
+       dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n",
+               gpadc->cal_data[ADC_INPUT_VBAT].gain,
+               gpadc->cal_data[ADC_INPUT_VBAT].offset);
+}
+
+static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct ab8500_gpadc *gpadc;
+
+       gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
+       if (!gpadc) {
+               dev_err(&pdev->dev, "Error: No memory\n");
+               return -ENOMEM;
+       }
+
+       gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
+       if (gpadc->irq < 0) {
+               dev_err(gpadc->dev, "failed to get platform irq-%d\n",
+                       gpadc->irq);
+               ret = gpadc->irq;
+               goto fail;
+       }
+
+       gpadc->dev = &pdev->dev;
+       mutex_init(&gpadc->ab8500_gpadc_lock);
+
+       /* Initialize completion used to notify completion of conversion */
+       init_completion(&gpadc->ab8500_gpadc_complete);
+
+       /* Register interrupt  - SwAdcComplete */
+       ret = request_threaded_irq(gpadc->irq, NULL,
+               ab8500_bm_gpswadcconvend_handler,
+               IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc);
+       if (ret < 0) {
+               dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
+                       gpadc->irq);
+               goto fail;
+       }
+
+       /* VTVout LDO used to power up ab8500-GPADC */
+       gpadc->regu = regulator_get(&pdev->dev, "vddadc");
+       if (IS_ERR(gpadc->regu)) {
+               ret = PTR_ERR(gpadc->regu);
+               dev_err(gpadc->dev, "failed to get vtvout LDO\n");
+               goto fail_irq;
+       }
+       ab8500_gpadc_read_calibration_data(gpadc);
+       list_add_tail(&gpadc->node, &ab8500_gpadc_list);
+       dev_dbg(gpadc->dev, "probe success\n");
+       return 0;
+fail_irq:
+       free_irq(gpadc->irq, gpadc);
+fail:
+       kfree(gpadc);
+       gpadc = NULL;
+       return ret;
+}
+
+static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
+{
+       struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev);
+
+       /* remove this gpadc entry from the list */
+       list_del(&gpadc->node);
+       /* remove interrupt  - completion of Sw ADC conversion */
+       free_irq(gpadc->irq, gpadc);
+       /* disable VTVout LDO that is being used by GPADC */
+       regulator_put(gpadc->regu);
+       kfree(gpadc);
+       gpadc = NULL;
+       return 0;
+}
+
+static struct platform_driver ab8500_gpadc_driver = {
+       .probe = ab8500_gpadc_probe,
+       .remove = __devexit_p(ab8500_gpadc_remove),
+       .driver = {
+               .name = "ab8500-gpadc",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init ab8500_gpadc_init(void)
+{
+       return platform_driver_register(&ab8500_gpadc_driver);
+}
+
+static void __exit ab8500_gpadc_exit(void)
+{
+       platform_driver_unregister(&ab8500_gpadc_driver);
+}
+
+subsys_initcall_sync(ab8500_gpadc_init);
+module_exit(ab8500_gpadc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson");
+MODULE_ALIAS("platform:ab8500_gpadc");
+MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
new file mode 100644 (file)
index 0000000..3921859
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/ab8500/sysctrl.h>
+
+static struct device *sysctrl_dev;
+
+static inline bool valid_bank(u8 bank)
+{
+       return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
+               (bank == AB8500_SYS_CTRL2_BLOCK));
+}
+
+int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+       u8 bank;
+
+       if (sysctrl_dev == NULL)
+               return -EAGAIN;
+
+       bank = (reg >> 8);
+       if (!valid_bank(bank))
+               return -EINVAL;
+
+       return abx500_get_register_interruptible(sysctrl_dev, bank,
+               (u8)(reg & 0xFF), value);
+}
+
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+       u8 bank;
+
+       if (sysctrl_dev == NULL)
+               return -EAGAIN;
+
+       bank = (reg >> 8);
+       if (!valid_bank(bank))
+               return -EINVAL;
+
+       return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
+               (u8)(reg & 0xFF), mask, value);
+}
+
+static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev)
+{
+       sysctrl_dev = &pdev->dev;
+       return 0;
+}
+
+static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev)
+{
+       sysctrl_dev = NULL;
+       return 0;
+}
+
+static struct platform_driver ab8500_sysctrl_driver = {
+       .driver = {
+               .name = "ab8500-sysctrl",
+               .owner = THIS_MODULE,
+       },
+       .probe = ab8500_sysctrl_probe,
+       .remove = __devexit_p(ab8500_sysctrl_remove),
+};
+
+static int __init ab8500_sysctrl_init(void)
+{
+       return platform_driver_register(&ab8500_sysctrl_driver);
+}
+subsys_initcall(ab8500_sysctrl_init);
+
+MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
+MODULE_DESCRIPTION("AB8500 system control driver");
+MODULE_LICENSE("GPL v2");
index 3122139b430022d819b532ba90d4d7dbccf69c96..f1d88483112cac13565cce2a8f88d3092c9d516c 100644 (file)
@@ -321,27 +321,27 @@ static int __devexit adp5520_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int adp5520_suspend(struct i2c_client *client,
-                                pm_message_t state)
+static int adp5520_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
 
        adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
        return 0;
 }
 
-static int adp5520_resume(struct i2c_client *client)
+static int adp5520_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
 
        adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY);
        return 0;
 }
-#else
-#define adp5520_suspend        NULL
-#define adp5520_resume NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume);
+
 static const struct i2c_device_id adp5520_id[] = {
        { "pmic-adp5520", ID_ADP5520 },
        { "pmic-adp5501", ID_ADP5501 },
@@ -353,11 +353,10 @@ static struct i2c_driver adp5520_driver = {
        .driver = {
                .name   = "adp5520",
                .owner  = THIS_MODULE,
+               .pm     = &adp5520_pm,
        },
        .probe          = adp5520_probe,
        .remove         = __devexit_p(adp5520_remove),
-       .suspend        = adp5520_suspend,
-       .resume         = adp5520_resume,
        .id_table       = adp5520_id,
 };
 
index c45e6305b26f464025430e0ce6c77df93ae09af3..0241f08fc00d63cfde562a96c7d7a43818bbf9e0 100644 (file)
@@ -682,7 +682,7 @@ static struct mfd_cell asic3_cell_ds1wm = {
        .name          = "ds1wm",
        .enable        = ds1wm_enable,
        .disable       = ds1wm_disable,
-       .driver_data   = &ds1wm_pdata,
+       .mfd_data      = &ds1wm_pdata,
        .num_resources = ARRAY_SIZE(ds1wm_resources),
        .resources     = ds1wm_resources,
 };
@@ -783,7 +783,7 @@ static struct mfd_cell asic3_cell_mmc = {
        .name          = "tmio-mmc",
        .enable        = asic3_mmc_enable,
        .disable       = asic3_mmc_disable,
-       .driver_data   = &asic3_mmc_data,
+       .mfd_data      = &asic3_mmc_data,
        .num_resources = ARRAY_SIZE(asic3_mmc_resources),
        .resources     = asic3_mmc_resources,
 };
@@ -810,9 +810,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
        ds1wm_resources[0].start >>= asic->bus_shift;
        ds1wm_resources[0].end   >>= asic->bus_shift;
 
-       asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
-       asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
-
        /* MMC */
        asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
                                 mem_sdio->start, 0x400 >> asic->bus_shift);
@@ -824,9 +821,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
        asic3_mmc_resources[0].start >>= asic->bus_shift;
        asic3_mmc_resources[0].end   >>= asic->bus_shift;
 
-       asic3_cell_mmc.platform_data = &asic3_cell_mmc;
-       asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
-
        ret = mfd_add_devices(&pdev->dev, pdev->id,
                        &asic3_cell_ds1wm, 1, mem, asic->irq_base);
        if (ret < 0)
index 59ca6f151e788cc901a218bddde8ae28715fc85c..886a068710652613e195b54ed433c86f6c664bef 100644 (file)
@@ -39,6 +39,37 @@ enum cs5535_mfd_bars {
        NR_BARS,
 };
 
+static int cs5535_mfd_res_enable(struct platform_device *pdev)
+{
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
+               return -EIO;
+       }
+
+       if (!request_region(res->start, resource_size(res), DRV_NAME)) {
+               dev_err(&pdev->dev, "can't request region\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int cs5535_mfd_res_disable(struct platform_device *pdev)
+{
+       struct resource *res;
+       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "can't fetch device resource info\n");
+               return -EIO;
+       }
+
+       release_region(res->start, resource_size(res));
+       return 0;
+}
+
 static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
 
 static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
@@ -65,12 +96,18 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
                .name = "cs5535-pms",
                .num_resources = 1,
                .resources = &cs5535_mfd_resources[PMS_BAR],
+
+               .enable = cs5535_mfd_res_enable,
+               .disable = cs5535_mfd_res_disable,
        },
        {
                .id = ACPI_BAR,
                .name = "cs5535-acpi",
                .num_resources = 1,
                .resources = &cs5535_mfd_resources[ACPI_BAR],
+
+               .enable = cs5535_mfd_res_enable,
+               .disable = cs5535_mfd_res_disable,
        },
 };
 
index fdd8a1b8bc67dc972fd8d215eab00361e46f728d..414783b048490b7a03a021781c79acd29d32367c 100644 (file)
@@ -119,12 +119,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
        /* Voice codec interface client */
        cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
        cell->name = "davinci-vcif";
-       cell->driver_data = davinci_vc;
+       cell->mfd_data = davinci_vc;
 
        /* Voice codec CQ93VC client */
        cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
        cell->name = "cq93vc-codec";
-       cell->driver_data = davinci_vc;
+       cell->mfd_data = davinci_vc;
 
        ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
                              DAVINCI_VC_CELLS, NULL, 0);
index 7bc752272dc1db9465132c2731d83afc446bdc85..fb9770b39a3253edcc92a83a3e77fb020b72b93f 100644 (file)
@@ -117,7 +117,7 @@ static struct mfd_cell ds1wm_cell __initdata = {
        .name          = "ds1wm",
        .enable        = ds1wm_enable,
        .disable       = ds1wm_disable,
-       .driver_data   = &ds1wm_pdata,
+       .mfd_data      = &ds1wm_pdata,
        .num_resources = 2,
        .resources     = ds1wm_resources,
 };
@@ -165,8 +165,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
                ds1wm_pdata.clock_rate = pdata->clock_rate;
                /* the first 5 PASIC3 registers control the DS1WM */
                ds1wm_resources[0].end = (5 << asic->bus_shift) - 1;
-               ds1wm_cell.platform_data = &ds1wm_cell;
-               ds1wm_cell.data_size = sizeof(ds1wm_cell);
                ret = mfd_add_devices(&pdev->dev, pdev->id,
                                &ds1wm_cell, 1, r, irq);
                if (ret < 0)
@@ -174,9 +172,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
        }
 
        if (pdata && pdata->led_pdata) {
-               led_cell.driver_data = pdata->led_pdata;
-               led_cell.platform_data = &led_cell;
-               led_cell.data_size = sizeof(ds1wm_cell);
                ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
                if (ret < 0)
                        dev_warn(dev, "failed to register LED device\n");
index 36a166bcdb08845b782b1ddb8d2fa0a423ff1815..fc4191137e9069f20cfd4c87ac76987e8eec3435 100644 (file)
@@ -86,8 +86,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
 
        /* Add platform data */
        pdata->modno = modno;
-       cell->platform_data = pdata;
-       cell->data_size = sizeof(*pdata);
+       cell->mfd_data = pdata;
 
        /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
        res->flags = IORESOURCE_MEM;
index 0cc59795f6004df02380608d28f300f85e07435a..aa518b9beaf5c4e7ebb9059ddbd8f62d55916c84 100644 (file)
@@ -232,8 +232,6 @@ const struct mfd_cell jz4740_adc_cells[] = {
                .name = "jz4740-hwmon",
                .num_resources = ARRAY_SIZE(jz4740_hwmon_resources),
                .resources = jz4740_hwmon_resources,
-               .platform_data = (void *)&jz4740_adc_cells[0],
-               .data_size = sizeof(struct mfd_cell),
 
                .enable = jz4740_adc_cell_enable,
                .disable = jz4740_adc_cell_disable,
@@ -243,8 +241,6 @@ const struct mfd_cell jz4740_adc_cells[] = {
                .name = "jz4740-battery",
                .num_resources = ARRAY_SIZE(jz4740_battery_resources),
                .resources = jz4740_battery_resources,
-               .platform_data = (void *)&jz4740_adc_cells[1],
-               .data_size = sizeof(struct mfd_cell),
 
                .enable = jz4740_adc_cell_enable,
                .disable = jz4740_adc_cell_disable,
index 51b2f6065a0bf713c6d5625451c2f32b29a11e87..ea3f52c07ef7fd3436cee6a078f011961bdb92eb 100644 (file)
@@ -61,6 +61,7 @@ static struct mfd_cell lpc_sch_cells[] = {
 
 static struct pci_device_id lpc_sch_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
@@ -70,6 +71,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
 {
        unsigned int base_addr_cfg;
        unsigned short base_addr;
+       int i;
 
        pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
        if (!(base_addr_cfg & (1 << 31))) {
@@ -99,7 +101,10 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
        gpio_sch_resource.start = base_addr;
        gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
 
-       return mfd_add_devices(&dev->dev, -1,
+       for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
+               lpc_sch_cells[i].id = id->device;
+
+       return mfd_add_devices(&dev->dev, 0,
                        lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
 }
 
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
new file mode 100644 (file)
index 0000000..5d1fca0
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * max8997.c - mfd core driver for the Maxim 8966 and 8997
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@smasung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8998.c
+ */
+
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+#define I2C_ADDR_PMIC  (0xCC >> 1)
+#define I2C_ADDR_MUIC  (0x4A >> 1)
+#define I2C_ADDR_BATTERY       (0x6C >> 1)
+#define I2C_ADDR_RTC   (0x0C >> 1)
+#define I2C_ADDR_HAPTIC        (0x90 >> 1)
+
+static struct mfd_cell max8997_devs[] = {
+       { .name = "max8997-pmic", },
+       { .name = "max8997-rtc", },
+       { .name = "max8997-battery", },
+       { .name = "max8997-haptic", },
+       { .name = "max8997-muic", },
+       { .name = "max8997-flash", },
+};
+
+int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&max8997->iolock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       mutex_unlock(&max8997->iolock);
+       if (ret < 0)
+               return ret;
+
+       ret &= 0xff;
+       *dest = ret;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max8997_read_reg);
+
+int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&max8997->iolock);
+       ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf);
+       mutex_unlock(&max8997->iolock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max8997_bulk_read);
+
+int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&max8997->iolock);
+       ret = i2c_smbus_write_byte_data(i2c, reg, value);
+       mutex_unlock(&max8997->iolock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(max8997_write_reg);
+
+int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&max8997->iolock);
+       ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf);
+       mutex_unlock(&max8997->iolock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(max8997_bulk_write);
+
+int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int ret;
+
+       mutex_lock(&max8997->iolock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       if (ret >= 0) {
+               u8 old_val = ret & 0xff;
+               u8 new_val = (val & mask) | (old_val & (~mask));
+               ret = i2c_smbus_write_byte_data(i2c, reg, new_val);
+       }
+       mutex_unlock(&max8997->iolock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(max8997_update_reg);
+
+static int max8997_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct max8997_dev *max8997;
+       struct max8997_platform_data *pdata = i2c->dev.platform_data;
+       int ret = 0;
+
+       max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL);
+       if (max8997 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, max8997);
+       max8997->dev = &i2c->dev;
+       max8997->i2c = i2c;
+       max8997->type = id->driver_data;
+
+       if (!pdata)
+               goto err;
+
+       max8997->wakeup = pdata->wakeup;
+
+       mutex_init(&max8997->iolock);
+
+       max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
+       i2c_set_clientdata(max8997->rtc, max8997);
+       max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
+       i2c_set_clientdata(max8997->haptic, max8997);
+       max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
+       i2c_set_clientdata(max8997->muic, max8997);
+
+       pm_runtime_set_active(max8997->dev);
+
+       mfd_add_devices(max8997->dev, -1, max8997_devs,
+                       ARRAY_SIZE(max8997_devs),
+                       NULL, 0);
+
+       /*
+        * TODO: enable others (flash, muic, rtc, battery, ...) and
+        * check the return value
+        */
+
+       if (ret < 0)
+               goto err_mfd;
+
+       return ret;
+
+err_mfd:
+       mfd_remove_devices(max8997->dev);
+       i2c_unregister_device(max8997->muic);
+       i2c_unregister_device(max8997->haptic);
+       i2c_unregister_device(max8997->rtc);
+err:
+       kfree(max8997);
+       return ret;
+}
+
+static int max8997_i2c_remove(struct i2c_client *i2c)
+{
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(max8997->dev);
+       i2c_unregister_device(max8997->muic);
+       i2c_unregister_device(max8997->haptic);
+       i2c_unregister_device(max8997->rtc);
+       kfree(max8997);
+
+       return 0;
+}
+
+static const struct i2c_device_id max8997_i2c_id[] = {
+       { "max8997", TYPE_MAX8997 },
+       { "max8966", TYPE_MAX8966 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
+
+u8 max8997_dumpaddr_pmic[] = {
+       MAX8997_REG_INT1MSK,
+       MAX8997_REG_INT2MSK,
+       MAX8997_REG_INT3MSK,
+       MAX8997_REG_INT4MSK,
+       MAX8997_REG_MAINCON1,
+       MAX8997_REG_MAINCON2,
+       MAX8997_REG_BUCKRAMP,
+       MAX8997_REG_BUCK1CTRL,
+       MAX8997_REG_BUCK1DVS1,
+       MAX8997_REG_BUCK1DVS2,
+       MAX8997_REG_BUCK1DVS3,
+       MAX8997_REG_BUCK1DVS4,
+       MAX8997_REG_BUCK1DVS5,
+       MAX8997_REG_BUCK1DVS6,
+       MAX8997_REG_BUCK1DVS7,
+       MAX8997_REG_BUCK1DVS8,
+       MAX8997_REG_BUCK2CTRL,
+       MAX8997_REG_BUCK2DVS1,
+       MAX8997_REG_BUCK2DVS2,
+       MAX8997_REG_BUCK2DVS3,
+       MAX8997_REG_BUCK2DVS4,
+       MAX8997_REG_BUCK2DVS5,
+       MAX8997_REG_BUCK2DVS6,
+       MAX8997_REG_BUCK2DVS7,
+       MAX8997_REG_BUCK2DVS8,
+       MAX8997_REG_BUCK3CTRL,
+       MAX8997_REG_BUCK3DVS,
+       MAX8997_REG_BUCK4CTRL,
+       MAX8997_REG_BUCK4DVS,
+       MAX8997_REG_BUCK5CTRL,
+       MAX8997_REG_BUCK5DVS1,
+       MAX8997_REG_BUCK5DVS2,
+       MAX8997_REG_BUCK5DVS3,
+       MAX8997_REG_BUCK5DVS4,
+       MAX8997_REG_BUCK5DVS5,
+       MAX8997_REG_BUCK5DVS6,
+       MAX8997_REG_BUCK5DVS7,
+       MAX8997_REG_BUCK5DVS8,
+       MAX8997_REG_BUCK6CTRL,
+       MAX8997_REG_BUCK6BPSKIPCTRL,
+       MAX8997_REG_BUCK7CTRL,
+       MAX8997_REG_BUCK7DVS,
+       MAX8997_REG_LDO1CTRL,
+       MAX8997_REG_LDO2CTRL,
+       MAX8997_REG_LDO3CTRL,
+       MAX8997_REG_LDO4CTRL,
+       MAX8997_REG_LDO5CTRL,
+       MAX8997_REG_LDO6CTRL,
+       MAX8997_REG_LDO7CTRL,
+       MAX8997_REG_LDO8CTRL,
+       MAX8997_REG_LDO9CTRL,
+       MAX8997_REG_LDO10CTRL,
+       MAX8997_REG_LDO11CTRL,
+       MAX8997_REG_LDO12CTRL,
+       MAX8997_REG_LDO13CTRL,
+       MAX8997_REG_LDO14CTRL,
+       MAX8997_REG_LDO15CTRL,
+       MAX8997_REG_LDO16CTRL,
+       MAX8997_REG_LDO17CTRL,
+       MAX8997_REG_LDO18CTRL,
+       MAX8997_REG_LDO21CTRL,
+       MAX8997_REG_MBCCTRL1,
+       MAX8997_REG_MBCCTRL2,
+       MAX8997_REG_MBCCTRL3,
+       MAX8997_REG_MBCCTRL4,
+       MAX8997_REG_MBCCTRL5,
+       MAX8997_REG_MBCCTRL6,
+       MAX8997_REG_OTPCGHCVS,
+       MAX8997_REG_SAFEOUTCTRL,
+       MAX8997_REG_LBCNFG1,
+       MAX8997_REG_LBCNFG2,
+       MAX8997_REG_BBCCTRL,
+
+       MAX8997_REG_FLASH1_CUR,
+       MAX8997_REG_FLASH2_CUR,
+       MAX8997_REG_MOVIE_CUR,
+       MAX8997_REG_GSMB_CUR,
+       MAX8997_REG_BOOST_CNTL,
+       MAX8997_REG_LEN_CNTL,
+       MAX8997_REG_FLASH_CNTL,
+       MAX8997_REG_WDT_CNTL,
+       MAX8997_REG_MAXFLASH1,
+       MAX8997_REG_MAXFLASH2,
+       MAX8997_REG_FLASHSTATUSMASK,
+
+       MAX8997_REG_GPIOCNTL1,
+       MAX8997_REG_GPIOCNTL2,
+       MAX8997_REG_GPIOCNTL3,
+       MAX8997_REG_GPIOCNTL4,
+       MAX8997_REG_GPIOCNTL5,
+       MAX8997_REG_GPIOCNTL6,
+       MAX8997_REG_GPIOCNTL7,
+       MAX8997_REG_GPIOCNTL8,
+       MAX8997_REG_GPIOCNTL9,
+       MAX8997_REG_GPIOCNTL10,
+       MAX8997_REG_GPIOCNTL11,
+       MAX8997_REG_GPIOCNTL12,
+
+       MAX8997_REG_LDO1CONFIG,
+       MAX8997_REG_LDO2CONFIG,
+       MAX8997_REG_LDO3CONFIG,
+       MAX8997_REG_LDO4CONFIG,
+       MAX8997_REG_LDO5CONFIG,
+       MAX8997_REG_LDO6CONFIG,
+       MAX8997_REG_LDO7CONFIG,
+       MAX8997_REG_LDO8CONFIG,
+       MAX8997_REG_LDO9CONFIG,
+       MAX8997_REG_LDO10CONFIG,
+       MAX8997_REG_LDO11CONFIG,
+       MAX8997_REG_LDO12CONFIG,
+       MAX8997_REG_LDO13CONFIG,
+       MAX8997_REG_LDO14CONFIG,
+       MAX8997_REG_LDO15CONFIG,
+       MAX8997_REG_LDO16CONFIG,
+       MAX8997_REG_LDO17CONFIG,
+       MAX8997_REG_LDO18CONFIG,
+       MAX8997_REG_LDO21CONFIG,
+
+       MAX8997_REG_DVSOKTIMER1,
+       MAX8997_REG_DVSOKTIMER2,
+       MAX8997_REG_DVSOKTIMER4,
+       MAX8997_REG_DVSOKTIMER5,
+};
+
+u8 max8997_dumpaddr_muic[] = {
+       MAX8997_MUIC_REG_INTMASK1,
+       MAX8997_MUIC_REG_INTMASK2,
+       MAX8997_MUIC_REG_INTMASK3,
+       MAX8997_MUIC_REG_CDETCTRL,
+       MAX8997_MUIC_REG_CONTROL1,
+       MAX8997_MUIC_REG_CONTROL2,
+       MAX8997_MUIC_REG_CONTROL3,
+};
+
+u8 max8997_dumpaddr_haptic[] = {
+       MAX8997_HAPTIC_REG_CONF1,
+       MAX8997_HAPTIC_REG_CONF2,
+       MAX8997_HAPTIC_REG_DRVCONF,
+       MAX8997_HAPTIC_REG_CYCLECONF1,
+       MAX8997_HAPTIC_REG_CYCLECONF2,
+       MAX8997_HAPTIC_REG_SIGCONF1,
+       MAX8997_HAPTIC_REG_SIGCONF2,
+       MAX8997_HAPTIC_REG_SIGCONF3,
+       MAX8997_HAPTIC_REG_SIGCONF4,
+       MAX8997_HAPTIC_REG_SIGDC1,
+       MAX8997_HAPTIC_REG_SIGDC2,
+       MAX8997_HAPTIC_REG_SIGPWMDC1,
+       MAX8997_HAPTIC_REG_SIGPWMDC2,
+       MAX8997_HAPTIC_REG_SIGPWMDC3,
+       MAX8997_HAPTIC_REG_SIGPWMDC4,
+};
+
+static int max8997_freeze(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
+               max8997_read_reg(i2c, max8997_dumpaddr_pmic[i],
+                               &max8997->reg_dump[i]);
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
+               max8997_read_reg(i2c, max8997_dumpaddr_muic[i],
+                               &max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
+               max8997_read_reg(i2c, max8997_dumpaddr_haptic[i],
+                               &max8997->reg_dump[i + MAX8997_REG_PMIC_END +
+                               MAX8997_MUIC_REG_END]);
+
+       return 0;
+}
+
+static int max8997_restore(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
+               max8997_write_reg(i2c, max8997_dumpaddr_pmic[i],
+                               max8997->reg_dump[i]);
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
+               max8997_write_reg(i2c, max8997_dumpaddr_muic[i],
+                               max8997->reg_dump[i + MAX8997_REG_PMIC_END]);
+
+       for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
+               max8997_write_reg(i2c, max8997_dumpaddr_haptic[i],
+                               max8997->reg_dump[i + MAX8997_REG_PMIC_END +
+                               MAX8997_MUIC_REG_END]);
+
+       return 0;
+}
+
+const struct dev_pm_ops max8997_pm = {
+       .freeze = max8997_freeze,
+       .restore = max8997_restore,
+};
+
+static struct i2c_driver max8997_i2c_driver = {
+       .driver = {
+                  .name = "max8997",
+                  .owner = THIS_MODULE,
+                  .pm = &max8997_pm,
+       },
+       .probe = max8997_i2c_probe,
+       .remove = max8997_i2c_remove,
+       .id_table = max8997_i2c_id,
+};
+
+static int __init max8997_i2c_init(void)
+{
+       return i2c_add_driver(&max8997_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max8997_i2c_init);
+
+static void __exit max8997_i2c_exit(void)
+{
+       i2c_del_driver(&max8997_i2c_driver);
+}
+module_exit(max8997_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
index bbfe867326027f514b00645da907f5e31e96fabc..c00214257da28c97e80e27c30cedf3ac86ac7cfe 100644 (file)
@@ -233,7 +233,7 @@ struct max8998_reg_dump {
        u8      val;
 };
 #define SAVE_ITEM(x)   { .addr = (x), .val = 0x0, }
-struct max8998_reg_dump max8998_dump[] = {
+static struct max8998_reg_dump max8998_dump[] = {
        SAVE_ITEM(MAX8998_REG_IRQM1),
        SAVE_ITEM(MAX8998_REG_IRQM2),
        SAVE_ITEM(MAX8998_REG_IRQM3),
@@ -298,7 +298,7 @@ static int max8998_restore(struct device *dev)
        return 0;
 }
 
-const struct dev_pm_ops max8998_pm = {
+static const struct dev_pm_ops max8998_pm = {
        .suspend = max8998_suspend,
        .resume = max8998_resume,
        .freeze = max8998_freeze,
index b9fcaf0004da79142414ef54d53f866122df1a1e..668634e89e81e1e616bbdab7562db258de72c8a0 100644 (file)
@@ -683,14 +683,13 @@ out:
 EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
 
 static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
-               const char *format, void *pdata, size_t pdata_size)
+               const char *format, void *pdata)
 {
        char buf[30];
        const char *name = mc13xxx_get_chipname(mc13xxx);
 
        struct mfd_cell cell = {
-               .platform_data = pdata,
-               .data_size = pdata_size,
+               .mfd_data = pdata,
        };
 
        /* there is no asnprintf in the kernel :-( */
@@ -706,7 +705,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
 
 static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
 {
-       return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
+       return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
 }
 
 static int mc13xxx_probe(struct spi_device *spi)
@@ -764,13 +763,8 @@ err_revision:
                mc13xxx_add_subdevice(mc13xxx, "%s-codec");
 
        if (pdata->flags & MC13XXX_USE_REGULATOR) {
-               struct mc13xxx_regulator_platform_data regulator_pdata = {
-                       .num_regulators = pdata->num_regulators,
-                       .regulators = pdata->regulators,
-               };
-
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-                               &regulator_pdata, sizeof(regulator_pdata));
+                               &pdata->regulators);
        }
 
        if (pdata->flags & MC13XXX_USE_RTC)
@@ -779,10 +773,8 @@ err_revision:
        if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
                mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 
-       if (pdata->flags & MC13XXX_USE_LED) {
-               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
-                                       pdata->leds, sizeof(*pdata->leds));
-       }
+       if (pdata->flags & MC13XXX_USE_LED)
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
 
        return 0;
 }
@@ -811,6 +803,7 @@ static const struct spi_device_id mc13xxx_device_id[] = {
                /* sentinel */
        }
 };
+MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
 
 static struct spi_driver mc13xxx_driver = {
        .id_table = mc13xxx_device_id,
index d83ad0f141af3ef7bc26d8322e508a46351d8cf9..79eda0264fb277176a2141338d9d4aa8682ea3b7 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
+int mfd_cell_enable(struct platform_device *pdev)
+{
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       int err = 0;
+
+       /* only call enable hook if the cell wasn't previously enabled */
+       if (atomic_inc_return(cell->usage_count) == 1)
+               err = cell->enable(pdev);
+
+       /* if the enable hook failed, decrement counter to allow retries */
+       if (err)
+               atomic_dec(cell->usage_count);
+
+       return err;
+}
+EXPORT_SYMBOL(mfd_cell_enable);
+
+int mfd_cell_disable(struct platform_device *pdev)
+{
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       int err = 0;
+
+       /* only disable if no other clients are using it */
+       if (atomic_dec_return(cell->usage_count) == 0)
+               err = cell->disable(pdev);
+
+       /* if the disable hook failed, increment to allow retries */
+       if (err)
+               atomic_inc(cell->usage_count);
+
+       /* sanity check; did someone call disable too many times? */
+       WARN_ON(atomic_read(cell->usage_count) < 0);
+
+       return err;
+}
+EXPORT_SYMBOL(mfd_cell_disable);
+
 static int mfd_add_device(struct device *parent, int id,
                          const struct mfd_cell *cell,
                          struct resource *mem_base,
@@ -37,14 +74,10 @@ static int mfd_add_device(struct device *parent, int id,
                goto fail_device;
 
        pdev->dev.parent = parent;
-       platform_set_drvdata(pdev, cell->driver_data);
 
-       if (cell->data_size) {
-               ret = platform_device_add_data(pdev,
-                                       cell->platform_data, cell->data_size);
-               if (ret)
-                       goto fail_res;
-       }
+       ret = platform_device_add_data(pdev, cell, sizeof(*cell));
+       if (ret)
+               goto fail_res;
 
        for (r = 0; r < cell->num_resources; r++) {
                res[r].name = cell->resources[r].name;
@@ -100,14 +133,22 @@ fail_alloc:
 }
 
 int mfd_add_devices(struct device *parent, int id,
-                   const struct mfd_cell *cells, int n_devs,
+                   struct mfd_cell *cells, int n_devs,
                    struct resource *mem_base,
                    int irq_base)
 {
        int i;
        int ret = 0;
+       atomic_t *cnts;
+
+       /* initialize reference counting for all cells */
+       cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+       if (!cnts)
+               return -ENOMEM;
 
        for (i = 0; i < n_devs; i++) {
+               atomic_set(&cnts[i], 0);
+               cells[i].usage_count = &cnts[i];
                ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base);
                if (ret)
                        break;
@@ -120,17 +161,89 @@ int mfd_add_devices(struct device *parent, int id,
 }
 EXPORT_SYMBOL(mfd_add_devices);
 
-static int mfd_remove_devices_fn(struct device *dev, void *unused)
+static int mfd_remove_devices_fn(struct device *dev, void *c)
 {
-       platform_device_unregister(to_platform_device(dev));
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
+       atomic_t **usage_count = c;
+
+       /* find the base address of usage_count pointers (for freeing) */
+       if (!*usage_count || (cell->usage_count < *usage_count))
+               *usage_count = cell->usage_count;
+
+       platform_device_unregister(pdev);
        return 0;
 }
 
 void mfd_remove_devices(struct device *parent)
 {
-       device_for_each_child(parent, NULL, mfd_remove_devices_fn);
+       atomic_t *cnts = NULL;
+
+       device_for_each_child(parent, &cnts, mfd_remove_devices_fn);
+       kfree(cnts);
 }
 EXPORT_SYMBOL(mfd_remove_devices);
 
+static int add_shared_platform_device(const char *cell, const char *name)
+{
+       struct mfd_cell cell_entry;
+       struct device *dev;
+       struct platform_device *pdev;
+       int err;
+
+       /* check if we've already registered a device (don't fail if we have) */
+       if (bus_find_device_by_name(&platform_bus_type, NULL, name))
+               return 0;
+
+       /* fetch the parent cell's device (should already be registered!) */
+       dev = bus_find_device_by_name(&platform_bus_type, NULL, cell);
+       if (!dev) {
+               printk(KERN_ERR "failed to find device for cell %s\n", cell);
+               return -ENODEV;
+       }
+       pdev = to_platform_device(dev);
+       memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry));
+
+       WARN_ON(!cell_entry.enable);
+
+       cell_entry.name = name;
+       err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0);
+       if (err)
+               dev_err(dev, "MFD add devices failed: %d\n", err);
+       return err;
+}
+
+int mfd_shared_platform_driver_register(struct platform_driver *drv,
+               const char *cellname)
+{
+       int err;
+
+       err = add_shared_platform_device(cellname, drv->driver.name);
+       if (err)
+               printk(KERN_ERR "failed to add platform device %s\n",
+                               drv->driver.name);
+
+       err = platform_driver_register(drv);
+       if (err)
+               printk(KERN_ERR "failed to add platform driver %s\n",
+                               drv->driver.name);
+
+       return err;
+}
+EXPORT_SYMBOL(mfd_shared_platform_driver_register);
+
+void mfd_shared_platform_driver_unregister(struct platform_driver *drv)
+{
+       struct device *dev;
+
+       dev = bus_find_device_by_name(&platform_bus_type, NULL,
+                       drv->driver.name);
+       if (dev)
+               platform_device_unregister(to_platform_device(dev));
+
+       platform_driver_unregister(drv);
+}
+EXPORT_SYMBOL(mfd_shared_platform_driver_unregister);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
index 501ce13b693ea8b105d9fe1c06d4be7e27140943..c1306ed43e3c10cf0c7f69a95dabcf0ecdbc6bd0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/pcf50633/core.h>
@@ -230,27 +231,26 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
        }
 }
 
-#ifdef CONFIG_PM
-static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pcf50633_suspend(struct device *dev)
 {
-       struct pcf50633 *pcf;
-       pcf = i2c_get_clientdata(client);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pcf50633 *pcf = i2c_get_clientdata(client);
 
        return pcf50633_irq_suspend(pcf);
 }
 
-static int pcf50633_resume(struct i2c_client *client)
+static int pcf50633_resume(struct device *dev)
 {
-       struct pcf50633 *pcf;
-       pcf = i2c_get_clientdata(client);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pcf50633 *pcf = i2c_get_clientdata(client);
 
        return pcf50633_irq_resume(pcf);
 }
-#else
-#define pcf50633_suspend NULL
-#define pcf50633_resume NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
+
 static int __devinit pcf50633_probe(struct i2c_client *client,
                                const struct i2c_device_id *ids)
 {
@@ -360,16 +360,16 @@ static struct i2c_device_id pcf50633_id_table[] = {
        {"pcf50633", 0x73},
        {/* end of list */}
 };
+MODULE_DEVICE_TABLE(i2c, pcf50633_id_table);
 
 static struct i2c_driver pcf50633_driver = {
        .driver = {
                .name   = "pcf50633",
+               .pm     = &pcf50633_pm,
        },
        .id_table = pcf50633_id_table,
        .probe = pcf50633_probe,
        .remove = __devexit_p(pcf50633_remove),
-       .suspend = pcf50633_suspend,
-       .resume = pcf50633_resume,
 };
 
 static int __init pcf50633_init(void)
index 50922975bda381d520072a02273eb5a0477d5806..193c940225b5bc45bec2fe3a9ce7204e79ef464d 100644 (file)
@@ -61,12 +61,12 @@ static struct mfd_cell rdc321x_sb_cells[] = {
                .name           = "rdc321x-wdt",
                .resources      = rdc321x_wdt_resource,
                .num_resources  = ARRAY_SIZE(rdc321x_wdt_resource),
-               .driver_data    = &rdc321x_wdt_pdata,
+               .mfd_data       = &rdc321x_wdt_pdata,
        }, {
                .name           = "rdc321x-gpio",
                .resources      = rdc321x_gpio_resources,
                .num_resources  = ARRAY_SIZE(rdc321x_gpio_resources),
-               .driver_data    = &rdc321x_gpio_pdata,
+               .mfd_data       = &rdc321x_gpio_pdata,
        },
 };
 
index 0a7df44a93c042461ee567a7ba029da6c21ac55a..53a63024bf114fb03301a0a23a3211f537d42c98 100644 (file)
@@ -146,9 +146,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
-       priv->cell_mmc.driver_data = mmc_data;
-       priv->cell_mmc.platform_data = &priv->cell_mmc;
-       priv->cell_mmc.data_size = sizeof(priv->cell_mmc);
+       priv->cell_mmc.mfd_data = mmc_data;
 
        platform_set_drvdata(pdev, priv);
 
index 5de3a760ea1ef946075c1de485a645bb8121ae0d..df3702c1756df9aae08dcfbbf1bde345d7520172 100644 (file)
@@ -133,10 +133,10 @@ static unsigned long decode_div(unsigned long pll2, unsigned long val,
 
 static void sm501_dump_clk(struct sm501_devdata *sm)
 {
-       unsigned long misct = readl(sm->regs + SM501_MISC_TIMING);
-       unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
-       unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
-       unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING);
+       unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
+       unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
+       unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
        unsigned long sdclk0, sdclk1;
        unsigned long pll2 = 0;
 
@@ -193,29 +193,29 @@ static void sm501_dump_regs(struct sm501_devdata *sm)
        void __iomem *regs = sm->regs;
 
        dev_info(sm->dev, "System Control   %08x\n",
-                       readl(regs + SM501_SYSTEM_CONTROL));
+                       smc501_readl(regs + SM501_SYSTEM_CONTROL));
        dev_info(sm->dev, "Misc Control     %08x\n",
-                       readl(regs + SM501_MISC_CONTROL));
+                       smc501_readl(regs + SM501_MISC_CONTROL));
        dev_info(sm->dev, "GPIO Control Low %08x\n",
-                       readl(regs + SM501_GPIO31_0_CONTROL));
+                       smc501_readl(regs + SM501_GPIO31_0_CONTROL));
        dev_info(sm->dev, "GPIO Control Hi  %08x\n",
-                       readl(regs + SM501_GPIO63_32_CONTROL));
+                       smc501_readl(regs + SM501_GPIO63_32_CONTROL));
        dev_info(sm->dev, "DRAM Control     %08x\n",
-                       readl(regs + SM501_DRAM_CONTROL));
+                       smc501_readl(regs + SM501_DRAM_CONTROL));
        dev_info(sm->dev, "Arbitration Ctrl %08x\n",
-                       readl(regs + SM501_ARBTRTN_CONTROL));
+                       smc501_readl(regs + SM501_ARBTRTN_CONTROL));
        dev_info(sm->dev, "Misc Timing      %08x\n",
-                       readl(regs + SM501_MISC_TIMING));
+                       smc501_readl(regs + SM501_MISC_TIMING));
 }
 
 static void sm501_dump_gate(struct sm501_devdata *sm)
 {
        dev_info(sm->dev, "CurrentGate      %08x\n",
-                       readl(sm->regs + SM501_CURRENT_GATE));
+                       smc501_readl(sm->regs + SM501_CURRENT_GATE));
        dev_info(sm->dev, "CurrentClock     %08x\n",
-                       readl(sm->regs + SM501_CURRENT_CLOCK));
+                       smc501_readl(sm->regs + SM501_CURRENT_CLOCK));
        dev_info(sm->dev, "PowerModeControl %08x\n",
-                       readl(sm->regs + SM501_POWER_MODE_CONTROL));
+                       smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL));
 }
 
 #else
@@ -231,7 +231,7 @@ static inline void sm501_dump_clk(struct sm501_devdata *sm) { }
 
 static void sm501_sync_regs(struct sm501_devdata *sm)
 {
-       readl(sm->regs);
+       smc501_readl(sm->regs);
 }
 
 static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay)
@@ -261,11 +261,11 @@ int sm501_misc_control(struct device *dev,
 
        spin_lock_irqsave(&sm->reg_lock, save);
 
-       misc = readl(sm->regs + SM501_MISC_CONTROL);
+       misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
        to = (misc & ~clear) | set;
 
        if (to != misc) {
-               writel(to, sm->regs + SM501_MISC_CONTROL);
+               smc501_writel(to, sm->regs + SM501_MISC_CONTROL);
                sm501_sync_regs(sm);
 
                dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc);
@@ -294,11 +294,11 @@ unsigned long sm501_modify_reg(struct device *dev,
 
        spin_lock_irqsave(&sm->reg_lock, save);
 
-       data = readl(sm->regs + reg);
+       data = smc501_readl(sm->regs + reg);
        data |= set;
        data &= ~clear;
 
-       writel(data, sm->regs + reg);
+       smc501_writel(data, sm->regs + reg);
        sm501_sync_regs(sm);
 
        spin_unlock_irqrestore(&sm->reg_lock, save);
@@ -322,9 +322,9 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
 
        mutex_lock(&sm->clock_lock);
 
-       mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
-       gate = readl(sm->regs + SM501_CURRENT_GATE);
-       clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+       mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
+       clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
 
        mode &= 3;              /* get current power mode */
 
@@ -356,14 +356,14 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
 
        switch (mode) {
        case 1:
-               writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
-               writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+               smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+               smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
                mode = 0;
                break;
        case 2:
        case 0:
-               writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
-               writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+               smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+               smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
                mode = 1;
                break;
 
@@ -372,7 +372,7 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
                goto already;
        }
 
-       writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+       smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
        sm501_sync_regs(sm);
 
        dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
@@ -519,9 +519,9 @@ unsigned long sm501_set_clock(struct device *dev,
                              unsigned long req_freq)
 {
        struct sm501_devdata *sm = dev_get_drvdata(dev);
-       unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
-       unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE);
-       unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+       unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
+       unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
        unsigned char reg;
        unsigned int pll_reg = 0;
        unsigned long sm501_freq; /* the actual frequency achieved */
@@ -592,9 +592,9 @@ unsigned long sm501_set_clock(struct device *dev,
 
        mutex_lock(&sm->clock_lock);
 
-       mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
-       gate = readl(sm->regs + SM501_CURRENT_GATE);
-       clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+       mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
+       gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
+       clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
 
        clock = clock & ~(0xFF << clksrc);
        clock |= reg<<clksrc;
@@ -603,14 +603,14 @@ unsigned long sm501_set_clock(struct device *dev,
 
        switch (mode) {
        case 1:
-               writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
-               writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+               smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+               smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
                mode = 0;
                break;
        case 2:
        case 0:
-               writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
-               writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+               smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+               smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
                mode = 1;
                break;
 
@@ -619,10 +619,11 @@ unsigned long sm501_set_clock(struct device *dev,
                return -1;
        }
 
-       writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+       smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
 
        if (pll_reg)
-               writel(pll_reg, sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL);
+               smc501_writel(pll_reg,
+                               sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL);
 
        sm501_sync_regs(sm);
 
@@ -902,7 +903,7 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
        struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip);
        unsigned long result;
 
-       result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
+       result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
        result >>= offset;
 
        return result & 1UL;
@@ -915,13 +916,13 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
 
        /* check and modify if this pin is not set as gpio. */
 
-       if (readl(smchip->control) & bit) {
+       if (smc501_readl(smchip->control) & bit) {
                dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev,
                         "changing mode of gpio, bit %08lx\n", bit);
 
-               ctrl = readl(smchip->control);
+               ctrl = smc501_readl(smchip->control);
                ctrl &= ~bit;
-               writel(ctrl, smchip->control);
+               smc501_writel(ctrl, smchip->control);
 
                sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio));
        }
@@ -942,10 +943,10 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        spin_lock_irqsave(&smgpio->lock, save);
 
-       val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
+       val = smc501_readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
        if (value)
                val |= bit;
-       writel(val, regs);
+       smc501_writel(val, regs);
 
        sm501_sync_regs(sm501_gpio_to_dev(smgpio));
        sm501_gpio_ensure_gpio(smchip, bit);
@@ -967,8 +968,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&smgpio->lock, save);
 
-       ddr = readl(regs + SM501_GPIO_DDR_LOW);
-       writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
+       ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
+       smc501_writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
 
        sm501_sync_regs(sm501_gpio_to_dev(smgpio));
        sm501_gpio_ensure_gpio(smchip, bit);
@@ -994,18 +995,18 @@ static int sm501_gpio_output(struct gpio_chip *chip,
 
        spin_lock_irqsave(&smgpio->lock, save);
 
-       val = readl(regs + SM501_GPIO_DATA_LOW);
+       val = smc501_readl(regs + SM501_GPIO_DATA_LOW);
        if (value)
                val |= bit;
        else
                val &= ~bit;
-       writel(val, regs);
+       smc501_writel(val, regs);
 
-       ddr = readl(regs + SM501_GPIO_DDR_LOW);
-       writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
+       ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
+       smc501_writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
 
        sm501_sync_regs(sm501_gpio_to_dev(smgpio));
-       writel(val, regs + SM501_GPIO_DATA_LOW);
+       smc501_writel(val, regs + SM501_GPIO_DATA_LOW);
 
        sm501_sync_regs(sm501_gpio_to_dev(smgpio));
        spin_unlock_irqrestore(&smgpio->lock, save);
@@ -1231,7 +1232,7 @@ static ssize_t sm501_dbg_regs(struct device *dev,
 
        for (reg = 0x00; reg < 0x70; reg += 4) {
                ret = sprintf(ptr, "%08x = %08x\n",
-                             reg, readl(sm->regs + reg));
+                             reg, smc501_readl(sm->regs + reg));
                ptr += ret;
        }
 
@@ -1255,10 +1256,10 @@ static inline void sm501_init_reg(struct sm501_devdata *sm,
 {
        unsigned long tmp;
 
-       tmp = readl(sm->regs + reg);
+       tmp = smc501_readl(sm->regs + reg);
        tmp &= ~r->mask;
        tmp |= r->set;
-       writel(tmp, sm->regs + reg);
+       smc501_writel(tmp, sm->regs + reg);
 }
 
 /* sm501_init_regs
@@ -1299,7 +1300,7 @@ static void sm501_init_regs(struct sm501_devdata *sm,
 
 static int sm501_check_clocks(struct sm501_devdata *sm)
 {
-       unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK);
+       unsigned long pwrmode = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
        unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC);
        unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC);
 
@@ -1334,7 +1335,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
 
        INIT_LIST_HEAD(&sm->devices);
 
-       devid = readl(sm->regs + SM501_DEVICEID);
+       devid = smc501_readl(sm->regs + SM501_DEVICEID);
 
        if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) {
                dev_err(sm->dev, "incorrect device id %08lx\n", devid);
@@ -1342,9 +1343,9 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
        }
 
        /* disable irqs */
-       writel(0, sm->regs + SM501_IRQ_MASK);
+       smc501_writel(0, sm->regs + SM501_IRQ_MASK);
 
-       dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
+       dramctrl = smc501_readl(sm->regs + SM501_DRAM_CONTROL);
        mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
 
        dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n",
@@ -1376,7 +1377,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
                        sm501_register_gpio(sm);
        }
 
-       if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
+       if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
                if (!sm501_gpio_isregistered(sm))
                        dev_err(sm->dev, "no gpio available for i2c gpio.\n");
                else
@@ -1421,6 +1422,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev)
 
        sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
        sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
        if (sm->io_res == NULL || sm->mem_res == NULL) {
                dev_err(&dev->dev, "failed to get IO resource\n");
                ret = -ENOENT;
@@ -1489,7 +1491,7 @@ static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state)
        struct sm501_devdata *sm = platform_get_drvdata(pdev);
 
        sm->in_suspend = 1;
-       sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL);
+       sm->pm_misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
 
        sm501_dump_regs(sm);
 
@@ -1513,9 +1515,9 @@ static int sm501_plat_resume(struct platform_device *pdev)
 
        /* check to see if we are in the same state as when suspended */
 
-       if (readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
+       if (smc501_readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
                dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n");
-               writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
+               smc501_writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
 
                /* our suspend causes the controller state to change,
                 * either by something attempting setup, power loss,
@@ -1734,10 +1736,16 @@ static struct pci_driver sm501_pci_driver = {
 
 MODULE_ALIAS("platform:sm501");
 
+static struct of_device_id __devinitdata of_sm501_match_tbl[] = {
+       { .compatible = "smi,sm501", },
+       { /* end */ }
+};
+
 static struct platform_driver sm501_plat_driver = {
        .driver         = {
                .name   = "sm501",
                .owner  = THIS_MODULE,
+               .of_match_table = of_sm501_match_tbl,
        },
        .probe          = sm501_plat_probe,
        .remove         = sm501_plat_remove,
index 9caeb4ac6ea6c2b1fa72eb63a8c678fefef28b14..af57fc706a4cedf49043309c93d6f5cc47ca7e10 100644 (file)
@@ -170,7 +170,7 @@ static struct mfd_cell t7l66xb_cells[] = {
                .name = "tmio-mmc",
                .enable = t7l66xb_mmc_enable,
                .disable = t7l66xb_mmc_disable,
-               .driver_data = &t7166xb_mmc_data,
+               .mfd_data = &t7166xb_mmc_data,
                .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
                .resources = t7l66xb_mmc_resources,
        },
@@ -383,16 +383,7 @@ static int t7l66xb_probe(struct platform_device *dev)
 
        t7l66xb_attach_irq(dev);
 
-       t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data;
-       t7l66xb_cells[T7L66XB_CELL_NAND].platform_data =
-               &t7l66xb_cells[T7L66XB_CELL_NAND];
-       t7l66xb_cells[T7L66XB_CELL_NAND].data_size =
-               sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]);
-
-       t7l66xb_cells[T7L66XB_CELL_MMC].platform_data =
-               &t7l66xb_cells[T7L66XB_CELL_MMC];
-       t7l66xb_cells[T7L66XB_CELL_MMC].data_size =
-               sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]);
+       t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
 
        ret = mfd_add_devices(&dev->dev, dev->id,
                              t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
index 6315f63f017dd820266f4aee6abfe3352b38e334..b006f7cee9521673acf6e65e9b599dfc98d73a26 100644 (file)
@@ -131,7 +131,7 @@ static struct mfd_cell tc6387xb_cells[] = {
                .name = "tmio-mmc",
                .enable = tc6387xb_mmc_enable,
                .disable = tc6387xb_mmc_disable,
-               .driver_data = &tc6387xb_mmc_data,
+               .mfd_data = &tc6387xb_mmc_data,
                .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
                .resources = tc6387xb_mmc_resources,
        },
@@ -190,11 +190,6 @@ static int __devinit tc6387xb_probe(struct platform_device *dev)
 
        printk(KERN_INFO "Toshiba tc6387xb initialised\n");
 
-       tc6387xb_cells[TC6387XB_CELL_MMC].platform_data =
-               &tc6387xb_cells[TC6387XB_CELL_MMC];
-       tc6387xb_cells[TC6387XB_CELL_MMC].data_size =
-               sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]);
-
        ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
                              ARRAY_SIZE(tc6387xb_cells), iomem, irq);
 
index 9a238633a54d4b7e0c594e04a5b6c35738b03e3b..3d62ded86a8fe478a386ae96c41d88e3d81a368d 100644 (file)
@@ -393,7 +393,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
                .name = "tmio-mmc",
                .enable = tc6393xb_mmc_enable,
                .resume = tc6393xb_mmc_resume,
-               .driver_data = &tc6393xb_mmc_data,
+               .mfd_data = &tc6393xb_mmc_data,
                .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
                .resources = tc6393xb_mmc_resources,
        },
@@ -693,27 +693,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
                        goto err_setup;
        }
 
-       tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data;
-       tc6393xb_cells[TC6393XB_CELL_NAND].platform_data =
-               &tc6393xb_cells[TC6393XB_CELL_NAND];
-       tc6393xb_cells[TC6393XB_CELL_NAND].data_size =
-               sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]);
-
-       tc6393xb_cells[TC6393XB_CELL_MMC].platform_data =
-               &tc6393xb_cells[TC6393XB_CELL_MMC];
-       tc6393xb_cells[TC6393XB_CELL_MMC].data_size =
-               sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]);
-
-       tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data =
-               &tc6393xb_cells[TC6393XB_CELL_OHCI];
-       tc6393xb_cells[TC6393XB_CELL_OHCI].data_size =
-               sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]);
-
-       tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data;
-       tc6393xb_cells[TC6393XB_CELL_FB].platform_data =
-               &tc6393xb_cells[TC6393XB_CELL_FB];
-       tc6393xb_cells[TC6393XB_CELL_FB].data_size =
-               sizeof(tc6393xb_cells[TC6393XB_CELL_FB]);
+       tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
+       tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
 
        ret = mfd_add_devices(&dev->dev, dev->id,
                        tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
index 6ad8a7f8d390770124b23b0f5c225bf365c345f8..94c6c8afad12e5abe9e0728b833db5c70f0d23aa 100644 (file)
@@ -384,8 +384,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .platform_data = &timb_dma_platform_data,
-               .data_size = sizeof(timb_dma_platform_data),
+               .mfd_data = &timb_dma_platform_data,
        },
        {
                .name = "timb-uart",
@@ -396,43 +395,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .platform_data = &timberdale_xiic_platform_data,
-               .data_size = sizeof(timberdale_xiic_platform_data),
+               .mfd_data = &timberdale_xiic_platform_data,
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .platform_data = &timberdale_gpio_platform_data,
-               .data_size = sizeof(timberdale_gpio_platform_data),
+               .mfd_data = &timberdale_gpio_platform_data,
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .platform_data = &timberdale_video_platform_data,
-               .data_size = sizeof(timberdale_video_platform_data),
+               .mfd_data = &timberdale_video_platform_data,
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .platform_data = &timberdale_radio_platform_data,
-               .data_size = sizeof(timberdale_radio_platform_data),
+               .mfd_data = &timberdale_radio_platform_data,
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .platform_data = &timberdale_xspi_platform_data,
-               .data_size = sizeof(timberdale_xspi_platform_data),
+               .mfd_data = &timberdale_xspi_platform_data,
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .platform_data = &timberdale_ks8842_platform_data,
-               .data_size = sizeof(timberdale_ks8842_platform_data)
+               .mfd_data = &timberdale_ks8842_platform_data,
        },
 };
 
@@ -441,8 +434,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .platform_data = &timb_dma_platform_data,
-               .data_size = sizeof(timb_dma_platform_data),
+               .mfd_data = &timb_dma_platform_data,
        },
        {
                .name = "timb-uart",
@@ -458,15 +450,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .platform_data = &timberdale_xiic_platform_data,
-               .data_size = sizeof(timberdale_xiic_platform_data),
+               .mfd_data = &timberdale_xiic_platform_data,
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .platform_data = &timberdale_gpio_platform_data,
-               .data_size = sizeof(timberdale_gpio_platform_data),
+               .mfd_data = &timberdale_gpio_platform_data,
        },
        {
                .name = "timb-mlogicore",
@@ -477,29 +467,25 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .platform_data = &timberdale_video_platform_data,
-               .data_size = sizeof(timberdale_video_platform_data),
+               .mfd_data = &timberdale_video_platform_data,
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .platform_data = &timberdale_radio_platform_data,
-               .data_size = sizeof(timberdale_radio_platform_data),
+               .mfd_data = &timberdale_radio_platform_data,
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .platform_data = &timberdale_xspi_platform_data,
-               .data_size = sizeof(timberdale_xspi_platform_data),
+               .mfd_data = &timberdale_xspi_platform_data,
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .platform_data = &timberdale_ks8842_platform_data,
-               .data_size = sizeof(timberdale_ks8842_platform_data)
+               .mfd_data = &timberdale_ks8842_platform_data,
        },
 };
 
@@ -508,8 +494,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .platform_data = &timb_dma_platform_data,
-               .data_size = sizeof(timb_dma_platform_data),
+               .mfd_data = &timb_dma_platform_data,
        },
        {
                .name = "timb-uart",
@@ -520,36 +505,31 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
                .name = "xiic-i2c",
                .num_resources = ARRAY_SIZE(timberdale_xiic_resources),
                .resources = timberdale_xiic_resources,
-               .platform_data = &timberdale_xiic_platform_data,
-               .data_size = sizeof(timberdale_xiic_platform_data),
+               .mfd_data = &timberdale_xiic_platform_data,
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .platform_data = &timberdale_gpio_platform_data,
-               .data_size = sizeof(timberdale_gpio_platform_data),
+               .mfd_data = &timberdale_gpio_platform_data,
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .platform_data = &timberdale_video_platform_data,
-               .data_size = sizeof(timberdale_video_platform_data),
+               .mfd_data = &timberdale_video_platform_data,
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .platform_data = &timberdale_radio_platform_data,
-               .data_size = sizeof(timberdale_radio_platform_data),
+               .mfd_data = &timberdale_radio_platform_data,
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .platform_data = &timberdale_xspi_platform_data,
-               .data_size = sizeof(timberdale_xspi_platform_data),
+               .mfd_data = &timberdale_xspi_platform_data,
        },
 };
 
@@ -558,8 +538,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
                .name = "timb-dma",
                .num_resources = ARRAY_SIZE(timberdale_dma_resources),
                .resources = timberdale_dma_resources,
-               .platform_data = &timb_dma_platform_data,
-               .data_size = sizeof(timb_dma_platform_data),
+               .mfd_data = &timb_dma_platform_data,
        },
        {
                .name = "timb-uart",
@@ -570,43 +549,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
                .name = "ocores-i2c",
                .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
                .resources = timberdale_ocores_resources,
-               .platform_data = &timberdale_ocores_platform_data,
-               .data_size = sizeof(timberdale_ocores_platform_data),
+               .mfd_data = &timberdale_ocores_platform_data,
        },
        {
                .name = "timb-gpio",
                .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
                .resources = timberdale_gpio_resources,
-               .platform_data = &timberdale_gpio_platform_data,
-               .data_size = sizeof(timberdale_gpio_platform_data),
+               .mfd_data = &timberdale_gpio_platform_data,
        },
        {
                .name = "timb-video",
                .num_resources = ARRAY_SIZE(timberdale_video_resources),
                .resources = timberdale_video_resources,
-               .platform_data = &timberdale_video_platform_data,
-               .data_size = sizeof(timberdale_video_platform_data),
+               .mfd_data = &timberdale_video_platform_data,
        },
        {
                .name = "timb-radio",
                .num_resources = ARRAY_SIZE(timberdale_radio_resources),
                .resources = timberdale_radio_resources,
-               .platform_data = &timberdale_radio_platform_data,
-               .data_size = sizeof(timberdale_radio_platform_data),
+               .mfd_data = &timberdale_radio_platform_data,
        },
        {
                .name = "xilinx_spi",
                .num_resources = ARRAY_SIZE(timberdale_spi_resources),
                .resources = timberdale_spi_resources,
-               .platform_data = &timberdale_xspi_platform_data,
-               .data_size = sizeof(timberdale_xspi_platform_data),
+               .mfd_data = &timberdale_xspi_platform_data,
        },
        {
                .name = "ks8842",
                .num_resources = ARRAY_SIZE(timberdale_eth_resources),
                .resources = timberdale_eth_resources,
-               .platform_data = &timberdale_ks8842_platform_data,
-               .data_size = sizeof(timberdale_ks8842_platform_data)
+               .mfd_data = &timberdale_ks8842_platform_data,
        },
 };
 
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c
new file mode 100644 (file)
index 0000000..46d8205
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Core driver for TPS61050/61052 boost converters, used for while LED
+ * driving, audio power amplification, white LED flash, and generic
+ * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in)
+ * and a flash synchronization pin to synchronize flash events when used as
+ * flashgun.
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps6105x.h>
+
+int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
+{
+       int ret;
+
+       ret = mutex_lock_interruptible(&tps6105x->lock);
+       if (ret)
+               return ret;
+       ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
+       mutex_unlock(&tps6105x->lock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(tps6105x_set);
+
+int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
+{
+       int ret;
+
+       ret = mutex_lock_interruptible(&tps6105x->lock);
+       if (ret)
+               return ret;
+       ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
+       mutex_unlock(&tps6105x->lock);
+       if (ret < 0)
+               return ret;
+
+       *buf = ret;
+       return 0;
+}
+EXPORT_SYMBOL(tps6105x_get);
+
+/*
+ * Masks off the bits in the mask and sets the bits in the bitvalues
+ * parameter in one atomic operation
+ */
+int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
+                         u8 bitmask, u8 bitvalues)
+{
+       int ret;
+       u8 regval;
+
+       ret = mutex_lock_interruptible(&tps6105x->lock);
+       if (ret)
+               return ret;
+       ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
+       if (ret < 0)
+               goto fail;
+       regval = ret;
+       regval = (~bitmask & regval) | (bitmask & bitvalues);
+       ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
+fail:
+       mutex_unlock(&tps6105x->lock);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(tps6105x_mask_and_set);
+
+static int __devinit tps6105x_startup(struct tps6105x *tps6105x)
+{
+       int ret;
+       u8 regval;
+
+       ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
+       if (ret)
+               return ret;
+       switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
+       case TPS6105X_REG0_MODE_SHUTDOWN:
+               dev_info(&tps6105x->client->dev,
+                        "TPS6105x found in SHUTDOWN mode\n");
+               break;
+       case TPS6105X_REG0_MODE_TORCH:
+               dev_info(&tps6105x->client->dev,
+                        "TPS6105x found in TORCH mode\n");
+               break;
+       case TPS6105X_REG0_MODE_TORCH_FLASH:
+               dev_info(&tps6105x->client->dev,
+                        "TPS6105x found in FLASH mode\n");
+               break;
+       case TPS6105X_REG0_MODE_VOLTAGE:
+               dev_info(&tps6105x->client->dev,
+                        "TPS6105x found in VOLTAGE mode\n");
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * MFD cells - we have one cell which is selected operation
+ * mode, and we always have a GPIO cell.
+ */
+static struct mfd_cell tps6105x_cells[] = {
+       {
+               /* name will be runtime assigned */
+               .id = -1,
+       },
+       {
+               .name = "tps6105x-gpio",
+               .id = -1,
+       },
+};
+
+static int __devinit tps6105x_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct tps6105x                 *tps6105x;
+       struct tps6105x_platform_data   *pdata;
+       int ret;
+       int i;
+
+       tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL);
+       if (!tps6105x)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, tps6105x);
+       tps6105x->client = client;
+       pdata = client->dev.platform_data;
+       tps6105x->pdata = pdata;
+       mutex_init(&tps6105x->lock);
+
+       ret = tps6105x_startup(tps6105x);
+       if (ret) {
+               dev_err(&client->dev, "chip initialization failed\n");
+               goto fail;
+       }
+
+       /* Remove warning texts when you implement new cell drivers */
+       switch (pdata->mode) {
+       case TPS6105X_MODE_SHUTDOWN:
+               dev_info(&client->dev,
+                        "present, not used for anything, only GPIO\n");
+               break;
+       case TPS6105X_MODE_TORCH:
+               tps6105x_cells[0].name = "tps6105x-leds";
+               dev_warn(&client->dev,
+                        "torch mode is unsupported\n");
+               break;
+       case TPS6105X_MODE_TORCH_FLASH:
+               tps6105x_cells[0].name = "tps6105x-flash";
+               dev_warn(&client->dev,
+                        "flash mode is unsupported\n");
+               break;
+       case TPS6105X_MODE_VOLTAGE:
+               tps6105x_cells[0].name ="tps6105x-regulator";
+               break;
+       default:
+               break;
+       }
+
+       /* Set up and register the platform devices. */
+       for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
+               /* One state holder for all drivers, this is simple */
+               tps6105x_cells[i].mfd_data = tps6105x;
+       }
+
+       ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
+               ARRAY_SIZE(tps6105x_cells), NULL, 0);
+       if (ret)
+               goto fail;
+
+       return 0;
+
+fail:
+       kfree(tps6105x);
+       return ret;
+}
+
+static int __devexit tps6105x_remove(struct i2c_client *client)
+{
+       struct tps6105x *tps6105x = i2c_get_clientdata(client);
+
+       mfd_remove_devices(&client->dev);
+
+       /* Put chip in shutdown mode */
+       tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+               TPS6105X_REG0_MODE_MASK,
+               TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
+
+       kfree(tps6105x);
+       return 0;
+}
+
+static const struct i2c_device_id tps6105x_id[] = {
+       { "tps61050", 0 },
+       { "tps61052", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tps6105x_id);
+
+static struct i2c_driver tps6105x_driver = {
+       .driver = {
+               .name   = "tps6105x",
+       },
+       .probe          = tps6105x_probe,
+       .remove         = __devexit_p(tps6105x_remove),
+       .id_table       = tps6105x_id,
+};
+
+static int __init tps6105x_init(void)
+{
+       return i2c_add_driver(&tps6105x_driver);
+}
+subsys_initcall(tps6105x_init);
+
+static void __exit tps6105x_exit(void)
+{
+       i2c_del_driver(&tps6105x_driver);
+}
+module_exit(tps6105x_exit);
+
+MODULE_AUTHOR("Linus Walleij");
+MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver");
+MODULE_LICENSE("GPL v2");
index e9018d1394ee7d8a6044c1c252a2f6d38f8470c3..0aa9186aec1961cb19d8a6b35ae027c07ffb3a04 100644 (file)
@@ -288,12 +288,10 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
        return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
 }
 
-static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
+static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
 {
-       int ret;
-
        if (!gpio_base)
-               return;
+               return 0;
 
        tps6586x->gpio.owner            = THIS_MODULE;
        tps6586x->gpio.label            = tps6586x->client->name;
@@ -307,9 +305,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
        tps6586x->gpio.set              = tps6586x_gpio_set;
        tps6586x->gpio.get              = tps6586x_gpio_get;
 
-       ret = gpiochip_add(&tps6586x->gpio);
-       if (ret)
-               dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
+       return gpiochip_add(&tps6586x->gpio);
 }
 
 static int __remove_subdev(struct device *dev, void *unused)
@@ -517,17 +513,28 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
                }
        }
 
+       ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base);
+       if (ret) {
+               dev_err(&client->dev, "GPIO registration failed: %d\n", ret);
+               goto err_gpio_init;
+       }
+
        ret = tps6586x_add_subdevs(tps6586x, pdata);
        if (ret) {
                dev_err(&client->dev, "add devices failed: %d\n", ret);
                goto err_add_devs;
        }
 
-       tps6586x_gpio_init(tps6586x, pdata->gpio_base);
-
        return 0;
 
 err_add_devs:
+       if (pdata->gpio_base) {
+               ret = gpiochip_remove(&tps6586x->gpio);
+               if (ret)
+                       dev_err(&client->dev, "Can't remove gpio chip: %d\n",
+                               ret);
+       }
+err_gpio_init:
        if (client->irq)
                free_irq(client->irq, tps6586x);
 err_irq_init:
@@ -587,4 +594,3 @@ module_exit(tps6586x_exit);
 MODULE_DESCRIPTION("TPS6586X core driver");
 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 MODULE_LICENSE("GPL");
-
index a35fa7dcbf53b6778696aa81d5a82a3d145ab148..960b5bed7f5237afdd769583db90908ed7a45fca 100644 (file)
@@ -721,13 +721,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        }
 
-       if (twl_has_watchdog()) {
+       if (twl_has_watchdog() && twl_class_is_4030()) {
                child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
-       if (twl_has_pwrbutton()) {
+       if (twl_has_pwrbutton() && twl_class_is_4030()) {
                child = add_child(1, "twl4030_pwrbutton",
                                NULL, 0, true, pdata->irq_base + 8 + 0, 0);
                if (IS_ERR(child))
@@ -864,6 +864,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
                if (IS_ERR(child))
                        return PTR_ERR(child);
+
+               child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
        }
 
        if (twl_has_bci() && pdata->bci &&
index 9a4b196d6deb64751d8e4981bb81de8074f5e231..c02fded316c9f1ce1ee8fd2343b1bfb476399a9f 100644 (file)
@@ -208,15 +208,13 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
        if (pdata->audio) {
                cell = &codec->cells[childs];
                cell->name = "twl4030-codec";
-               cell->platform_data = pdata->audio;
-               cell->data_size = sizeof(*pdata->audio);
+               cell->mfd_data = pdata->audio;
                childs++;
        }
        if (pdata->vibra) {
                cell = &codec->cells[childs];
                cell->name = "twl4030-vibra";
-               cell->platform_data = pdata->vibra;
-               cell->data_size = sizeof(*pdata->vibra);
+               cell->mfd_data = pdata->vibra;
                childs++;
        }
 
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
new file mode 100644 (file)
index 0000000..3941ddc
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ *
+ * TWL4030 MADC module driver-This driver monitors the real time
+ * conversion of analog signals like battery temperature,
+ * battery type, battery level etc.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * Based on twl4030-madc.c
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * Amit Kucheria <amit.kucheria@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/i2c/twl.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/err.h>
+
+/*
+ * struct twl4030_madc_data - a container for madc info
+ * @dev - pointer to device structure for madc
+ * @lock - mutex protecting this data structure
+ * @requests - Array of request struct corresponding to SW1, SW2 and RT
+ * @imr - Interrupt mask register of MADC
+ * @isr - Interrupt status register of MADC
+ */
+struct twl4030_madc_data {
+       struct device *dev;
+       struct mutex lock;      /* mutex protecting this data structure */
+       struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
+       int imr;
+       int isr;
+};
+
+static struct twl4030_madc_data *twl4030_madc;
+
+struct twl4030_prescale_divider_ratios {
+       s16 numerator;
+       s16 denominator;
+};
+
+static const struct twl4030_prescale_divider_ratios
+twl4030_divider_ratios[16] = {
+       {1, 1},         /* CHANNEL 0 No Prescaler */
+       {1, 1},         /* CHANNEL 1 No Prescaler */
+       {6, 10},        /* CHANNEL 2 */
+       {6, 10},        /* CHANNEL 3 */
+       {6, 10},        /* CHANNEL 4 */
+       {6, 10},        /* CHANNEL 5 */
+       {6, 10},        /* CHANNEL 6 */
+       {6, 10},        /* CHANNEL 7 */
+       {3, 14},        /* CHANNEL 8 */
+       {1, 3},         /* CHANNEL 9 */
+       {1, 1},         /* CHANNEL 10 No Prescaler */
+       {15, 100},      /* CHANNEL 11 */
+       {1, 4},         /* CHANNEL 12 */
+       {1, 1},         /* CHANNEL 13 Reserved channels */
+       {1, 1},         /* CHANNEL 14 Reseved channels */
+       {5, 11},        /* CHANNEL 15 */
+};
+
+
+/*
+ * Conversion table from -3 to 55 degree Celcius
+ */
+static int therm_tbl[] = {
+30800, 29500,  28300,  27100,
+26000, 24900,  23900,  22900,  22000,  21100,  20300,  19400,  18700,  17900,
+17200, 16500,  15900,  15300,  14700,  14100,  13600,  13100,  12600,  12100,
+11600, 11200,  10800,  10400,  10000,  9630,   9280,   8950,   8620,   8310,
+8020,  7730,   7460,   7200,   6950,   6710,   6470,   6250,   6040,   5830,
+5640,  5450,   5260,   5090,   4920,   4760,   4600,   4450,   4310,   4170,
+4040,  3910,   3790,   3670,   3550
+};
+
+/*
+ * Structure containing the registers
+ * of different conversion methods supported by MADC.
+ * Hardware or RT real time conversion request initiated by external host
+ * processor for RT Signal conversions.
+ * External host processors can also request for non RT conversions
+ * SW1 and SW2 software conversions also called asynchronous or GPC request.
+ */
+static
+const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
+       [TWL4030_MADC_RT] = {
+                            .sel = TWL4030_MADC_RTSELECT_LSB,
+                            .avg = TWL4030_MADC_RTAVERAGE_LSB,
+                            .rbase = TWL4030_MADC_RTCH0_LSB,
+                            },
+       [TWL4030_MADC_SW1] = {
+                             .sel = TWL4030_MADC_SW1SELECT_LSB,
+                             .avg = TWL4030_MADC_SW1AVERAGE_LSB,
+                             .rbase = TWL4030_MADC_GPCH0_LSB,
+                             .ctrl = TWL4030_MADC_CTRL_SW1,
+                             },
+       [TWL4030_MADC_SW2] = {
+                             .sel = TWL4030_MADC_SW2SELECT_LSB,
+                             .avg = TWL4030_MADC_SW2AVERAGE_LSB,
+                             .rbase = TWL4030_MADC_GPCH0_LSB,
+                             .ctrl = TWL4030_MADC_CTRL_SW2,
+                             },
+};
+
+/*
+ * Function to read a particular channel value.
+ * @madc - pointer to struct twl4030_madc_data
+ * @reg - lsb of ADC Channel
+ * If the i2c read fails it returns an error else returns 0.
+ */
+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
+{
+       u8 msb, lsb;
+       int ret;
+       /*
+        * For each ADC channel, we have MSB and LSB register pair. MSB address
+        * is always LSB address+1. reg parameter is the address of LSB register
+        */
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
+       if (ret) {
+               dev_err(madc->dev, "unable to read MSB register 0x%X\n",
+                       reg + 1);
+               return ret;
+       }
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
+       if (ret) {
+               dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
+               return ret;
+       }
+
+       return (int)(((msb << 8) | lsb) >> 6);
+}
+
+/*
+ * Return battery temperature
+ * Or < 0 on failure.
+ */
+static int twl4030battery_temperature(int raw_volt)
+{
+       u8 val;
+       int temp, curr, volt, res, ret;
+
+       volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
+       /* Getting and calculating the supply current in micro ampers */
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+               REG_BCICTL2);
+       if (ret < 0)
+               return ret;
+       curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
+       /* Getting and calculating the thermistor resistance in ohms */
+       res = volt * 1000 / curr;
+       /* calculating temperature */
+       for (temp = 58; temp >= 0; temp--) {
+               int actual = therm_tbl[temp];
+
+               if ((actual - res) >= 0)
+                       break;
+       }
+
+       return temp + 1;
+}
+
+static int twl4030battery_current(int raw_volt)
+{
+       int ret;
+       u8 val;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+               TWL4030_BCI_BCICTL1);
+       if (ret)
+               return ret;
+       if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
+               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
+       else /* slope of 0.88 mV/mA */
+               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
+}
+/*
+ * Function to read channel values
+ * @madc - pointer to twl4030_madc_data struct
+ * @reg_base - Base address of the first channel
+ * @Channels - 16 bit bitmap. If the bit is set, channel value is read
+ * @buf - The channel values are stored here. if read fails error
+ * value is stored
+ * Returns the number of successfully read channels.
+ */
+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
+                                     u8 reg_base, unsigned
+                                               long channels, int *buf)
+{
+       int count = 0, count_req = 0, i;
+       u8 reg;
+
+       for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
+               reg = reg_base + 2 * i;
+               buf[i] = twl4030_madc_channel_raw_read(madc, reg);
+               if (buf[i] < 0) {
+                       dev_err(madc->dev,
+                               "Unable to read register 0x%X\n", reg);
+                       count_req++;
+                       continue;
+               }
+               switch (i) {
+               case 10:
+                       buf[i] = twl4030battery_current(buf[i]);
+                       if (buf[i] < 0) {
+                               dev_err(madc->dev, "err reading current\n");
+                               count_req++;
+                       } else {
+                               count++;
+                               buf[i] = buf[i] - 750;
+                       }
+                       break;
+               case 1:
+                       buf[i] = twl4030battery_temperature(buf[i]);
+                       if (buf[i] < 0) {
+                               dev_err(madc->dev, "err reading temperature\n");
+                               count_req++;
+                       } else {
+                               buf[i] -= 3;
+                               count++;
+                       }
+                       break;
+               default:
+                       count++;
+                       /* Analog Input (V) = conv_result * step_size / R
+                        * conv_result = decimal value of 10-bit conversion
+                        *               result
+                        * step size = 1.5 / (2 ^ 10 -1)
+                        * R = Prescaler ratio for input channels.
+                        * Result given in mV hence multiplied by 1000.
+                        */
+                       buf[i] = (buf[i] * 3 * 1000 *
+                                twl4030_divider_ratios[i].denominator)
+                               / (2 * 1023 *
+                               twl4030_divider_ratios[i].numerator);
+               }
+       }
+       if (count_req)
+               dev_err(madc->dev, "%d channel conversion failed\n", count_req);
+
+       return count;
+}
+
+/*
+ * Enables irq.
+ * @madc - pointer to twl4030_madc_data struct
+ * @id - irq number to be enabled
+ * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
+ * corresponding to RT, SW1, SW2 conversion requests.
+ * If the i2c read fails it returns an error else returns 0.
+ */
+static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
+{
+       u8 val;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               return ret;
+       }
+       val &= ~(1 << id);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev,
+                       "unable to write imr register 0x%X\n", madc->imr);
+               return ret;
+
+       }
+
+       return 0;
+}
+
+/*
+ * Disables irq.
+ * @madc - pointer to twl4030_madc_data struct
+ * @id - irq number to be disabled
+ * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
+ * corresponding to RT, SW1, SW2 conversion requests.
+ * Returns error if i2c read/write fails.
+ */
+static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
+{
+       u8 val;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               return ret;
+       }
+       val |= (1 << id);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev,
+                       "unable to write imr register 0x%X\n", madc->imr);
+               return ret;
+       }
+
+       return 0;
+}
+
+static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
+{
+       struct twl4030_madc_data *madc = _madc;
+       const struct twl4030_madc_conversion_method *method;
+       u8 isr_val, imr_val;
+       int i, len, ret;
+       struct twl4030_madc_request *r;
+
+       mutex_lock(&madc->lock);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read isr register 0x%X\n",
+                       madc->isr);
+               goto err_i2c;
+       }
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               goto err_i2c;
+       }
+       isr_val &= ~imr_val;
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               if (!(isr_val & (1 << i)))
+                       continue;
+               ret = twl4030_madc_disable_irq(madc, i);
+               if (ret < 0)
+                       dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
+               madc->requests[i].result_pending = 1;
+       }
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               r = &madc->requests[i];
+               /* No pending results for this method, move to next one */
+               if (!r->result_pending)
+                       continue;
+               method = &twl4030_conversion_methods[r->method];
+               /* Read results */
+               len = twl4030_madc_read_channels(madc, method->rbase,
+                                                r->channels, r->rbuf);
+               /* Return results to caller */
+               if (r->func_cb != NULL) {
+                       r->func_cb(len, r->channels, r->rbuf);
+                       r->func_cb = NULL;
+               }
+               /* Free request */
+               r->result_pending = 0;
+               r->active = 0;
+       }
+       mutex_unlock(&madc->lock);
+
+       return IRQ_HANDLED;
+
+err_i2c:
+       /*
+        * In case of error check whichever request is active
+        * and service the same.
+        */
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               r = &madc->requests[i];
+               if (r->active == 0)
+                       continue;
+               method = &twl4030_conversion_methods[r->method];
+               /* Read results */
+               len = twl4030_madc_read_channels(madc, method->rbase,
+                                                r->channels, r->rbuf);
+               /* Return results to caller */
+               if (r->func_cb != NULL) {
+                       r->func_cb(len, r->channels, r->rbuf);
+                       r->func_cb = NULL;
+               }
+               /* Free request */
+               r->result_pending = 0;
+               r->active = 0;
+       }
+       mutex_unlock(&madc->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+                               struct twl4030_madc_request *req)
+{
+       struct twl4030_madc_request *p;
+       int ret;
+
+       p = &madc->requests[req->method];
+       memcpy(p, req, sizeof(*req));
+       ret = twl4030_madc_enable_irq(madc, req->method);
+       if (ret < 0) {
+               dev_err(madc->dev, "enable irq failed!!\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Function which enables the madc conversion
+ * by writing to the control register.
+ * @madc - pointer to twl4030_madc_data struct
+ * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
+ * corresponding to RT SW1 or SW2 conversion methods.
+ * Returns 0 if succeeds else a negative error value
+ */
+static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+                                        int conv_method)
+{
+       const struct twl4030_madc_conversion_method *method;
+       int ret = 0;
+       method = &twl4030_conversion_methods[conv_method];
+       switch (conv_method) {
+       case TWL4030_MADC_SW1:
+       case TWL4030_MADC_SW2:
+               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
+                                      TWL4030_MADC_SW_START, method->ctrl);
+               if (ret) {
+                       dev_err(madc->dev,
+                               "unable to write ctrl register 0x%X\n",
+                               method->ctrl);
+                       return ret;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * Function that waits for conversion to be ready
+ * @madc - pointer to twl4030_madc_data struct
+ * @timeout_ms - timeout value in milliseconds
+ * @status_reg - ctrl register
+ * returns 0 if succeeds else a negative error value
+ */
+static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
+                                             unsigned int timeout_ms,
+                                             u8 status_reg)
+{
+       unsigned long timeout;
+       int ret;
+
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       do {
+               u8 reg;
+
+               ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
+               if (ret) {
+                       dev_err(madc->dev,
+                               "unable to read status register 0x%X\n",
+                               status_reg);
+                       return ret;
+               }
+               if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
+                       return 0;
+               usleep_range(500, 2000);
+       } while (!time_after(jiffies, timeout));
+       dev_err(madc->dev, "conversion timeout!\n");
+
+       return -EAGAIN;
+}
+
+/*
+ * An exported function which can be called from other kernel drivers.
+ * @req twl4030_madc_request structure
+ * req->rbuf will be filled with read values of channels based on the
+ * channel index. If a particular channel reading fails there will
+ * be a negative error value in the corresponding array element.
+ * returns 0 if succeeds else error value
+ */
+int twl4030_madc_conversion(struct twl4030_madc_request *req)
+{
+       const struct twl4030_madc_conversion_method *method;
+       u8 ch_msb, ch_lsb;
+       int ret;
+
+       if (!req)
+               return -EINVAL;
+       mutex_lock(&twl4030_madc->lock);
+       if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
+               ret = -EINVAL;
+               goto out;
+       }
+       /* Do we have a conversion request ongoing */
+       if (twl4030_madc->requests[req->method].active) {
+               ret = -EBUSY;
+               goto out;
+       }
+       ch_msb = (req->channels >> 8) & 0xff;
+       ch_lsb = req->channels & 0xff;
+       method = &twl4030_conversion_methods[req->method];
+       /* Select channels to be converted */
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
+       if (ret) {
+               dev_err(twl4030_madc->dev,
+                       "unable to write sel register 0x%X\n", method->sel + 1);
+               return ret;
+       }
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
+       if (ret) {
+               dev_err(twl4030_madc->dev,
+                       "unable to write sel register 0x%X\n", method->sel + 1);
+               return ret;
+       }
+       /* Select averaging for all channels if do_avg is set */
+       if (req->do_avg) {
+               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
+                                      ch_msb, method->avg + 1);
+               if (ret) {
+                       dev_err(twl4030_madc->dev,
+                               "unable to write avg register 0x%X\n",
+                               method->avg + 1);
+                       return ret;
+               }
+               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
+                                      ch_lsb, method->avg);
+               if (ret) {
+                       dev_err(twl4030_madc->dev,
+                               "unable to write sel reg 0x%X\n",
+                               method->sel + 1);
+                       return ret;
+               }
+       }
+       if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
+               ret = twl4030_madc_set_irq(twl4030_madc, req);
+               if (ret < 0)
+                       goto out;
+               ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
+               if (ret < 0)
+                       goto out;
+               twl4030_madc->requests[req->method].active = 1;
+               ret = 0;
+               goto out;
+       }
+       /* With RT method we should not be here anymore */
+       if (req->method == TWL4030_MADC_RT) {
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
+       if (ret < 0)
+               goto out;
+       twl4030_madc->requests[req->method].active = 1;
+       /* Wait until conversion is ready (ctrl register returns EOC) */
+       ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
+       if (ret) {
+               twl4030_madc->requests[req->method].active = 0;
+               goto out;
+       }
+       ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
+                                        req->channels, req->rbuf);
+       twl4030_madc->requests[req->method].active = 0;
+
+out:
+       mutex_unlock(&twl4030_madc->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
+
+/*
+ * Return channel value
+ * Or < 0 on failure.
+ */
+int twl4030_get_madc_conversion(int channel_no)
+{
+       struct twl4030_madc_request req;
+       int temp = 0;
+       int ret;
+
+       req.channels = (1 << channel_no);
+       req.method = TWL4030_MADC_SW2;
+       req.active = 0;
+       req.func_cb = NULL;
+       ret = twl4030_madc_conversion(&req);
+       if (ret < 0)
+               return ret;
+       if (req.rbuf[channel_no] > 0)
+               temp = req.rbuf[channel_no];
+
+       return temp;
+}
+EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
+
+/*
+ * Function to enable or disable bias current for
+ * main battery type reading or temperature sensing
+ * @madc - pointer to twl4030_madc_data struct
+ * @chan - can be one of the two values
+ * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
+ * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
+ * sensing
+ * @on - enable or disable chan.
+ */
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+                                             int chan, int on)
+{
+       int ret;
+       u8 regval;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
+                       TWL4030_BCI_BCICTL1);
+               return ret;
+       }
+       if (on)
+               regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+       else
+               regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+                              regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Function that sets MADC software power on bit to enable MADC
+ * @madc - pointer to twl4030_madc_data struct
+ * @on - Enable or disable MADC software powen on bit.
+ * returns error if i2c read/write fails else 0
+ */
+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
+{
+       u8 regval;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_MADC_CTRL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
+                       TWL4030_MADC_CTRL1);
+               return ret;
+       }
+       if (on)
+               regval |= TWL4030_MADC_MADCON;
+       else
+               regval &= ~TWL4030_MADC_MADCON;
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
+                       TWL4030_MADC_CTRL1);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize MADC and request for threaded irq
+ */
+static int __devinit twl4030_madc_probe(struct platform_device *pdev)
+{
+       struct twl4030_madc_data *madc;
+       struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+       u8 regval;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "platform_data not available\n");
+               return -EINVAL;
+       }
+       madc = kzalloc(sizeof(*madc), GFP_KERNEL);
+       if (!madc)
+               return -ENOMEM;
+
+       /*
+        * Phoenix provides 2 interrupt lines. The first one is connected to
+        * the OMAP. The other one can be connected to the other processor such
+        * as modem. Hence two separate ISR and IMR registers.
+        */
+       madc->imr = (pdata->irq_line == 1) ?
+           TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+       madc->isr = (pdata->irq_line == 1) ?
+           TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+       ret = twl4030_madc_set_power(madc, 1);
+       if (ret < 0)
+               goto err_power;
+       ret = twl4030_madc_set_current_generator(madc, 0, 1);
+       if (ret < 0)
+               goto err_current_generator;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               goto err_i2c;
+       }
+       regval |= TWL4030_BCI_MESBAT;
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+                              regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               goto err_i2c;
+       }
+       platform_set_drvdata(pdev, madc);
+       mutex_init(&madc->lock);
+       ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
+                                  twl4030_madc_threaded_irq_handler,
+                                  IRQF_TRIGGER_RISING, "twl4030_madc", madc);
+       if (ret) {
+               dev_dbg(&pdev->dev, "could not request irq\n");
+               goto err_irq;
+       }
+       twl4030_madc = madc;
+       return 0;
+err_irq:
+       platform_set_drvdata(pdev, NULL);
+err_i2c:
+       twl4030_madc_set_current_generator(madc, 0, 0);
+err_current_generator:
+       twl4030_madc_set_power(madc, 0);
+err_power:
+       kfree(madc);
+
+       return ret;
+}
+
+static int __devexit twl4030_madc_remove(struct platform_device *pdev)
+{
+       struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+
+       free_irq(platform_get_irq(pdev, 0), madc);
+       platform_set_drvdata(pdev, NULL);
+       twl4030_madc_set_current_generator(madc, 0, 0);
+       twl4030_madc_set_power(madc, 0);
+       kfree(madc);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_madc_driver = {
+       .probe = twl4030_madc_probe,
+       .remove = __exit_p(twl4030_madc_remove),
+       .driver = {
+                  .name = "twl4030_madc",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+static int __init twl4030_madc_init(void)
+{
+       return platform_driver_register(&twl4030_madc_driver);
+}
+
+module_init(twl4030_madc_init);
+
+static void __exit twl4030_madc_exit(void)
+{
+       platform_driver_unregister(&twl4030_madc_driver);
+}
+
+module_exit(twl4030_madc_exit);
+
+MODULE_DESCRIPTION("TWL4030 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("J Keerthy");
+MODULE_ALIAS("platform:twl4030_madc");
index 92b85e28a15ee7edaca835fcc2755ba0eb181c0b..38ffbd50a0d27bc24cbc9826c5dae1e95a54b560 100644 (file)
@@ -60,6 +60,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x
        input_report_abs(idev, ABS_X, x);
        input_report_abs(idev, ABS_Y, y);
        input_report_abs(idev, ABS_PRESSURE, pressure);
+       input_report_key(idev, BTN_TOUCH, 1);
        input_sync(idev);
 }
 
@@ -68,6 +69,7 @@ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
        struct input_dev *idev = ts->idev;
 
        input_report_abs(idev, ABS_PRESSURE, 0);
+       input_report_key(idev, BTN_TOUCH, 0);
        input_sync(idev);
 }
 
@@ -384,7 +386,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        idev->open       = ucb1x00_ts_open;
        idev->close      = ucb1x00_ts_close;
 
-       __set_bit(EV_ABS, idev->evbit);
+       idev->evbit[0]   = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
+       idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
        input_set_drvdata(idev, ts);
 
index 348052aa5dbfac31b3bb8496d6d2f35ac164c454..d698703dbd462c73b7267d9cd1a37a55bdd99d60 100644 (file)
@@ -122,6 +122,7 @@ static struct pci_device_id vx855_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
        { 0, }
 };
+MODULE_DEVICE_TABLE(pci, vx855_pci_tbl);
 
 static struct pci_driver vx855_pci_driver = {
        .name           = "vx855",
index d2ecc2435736a015a006e279f93d61e0007560e8..f76f6c798046434baeb0dddea523de6b05158d0a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MFD driver for wl1273 FM radio and audio codec submodules.
  *
- * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Nokia Corporation
  * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,145 @@ static struct i2c_device_id wl1273_driver_id_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
 
+static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
+{
+       struct i2c_client *client = core->client;
+       u8 b[2];
+       int r;
+
+       r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
+       if (r != 2) {
+               dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
+               return -EREMOTEIO;
+       }
+
+       *value = (u16)b[0] << 8 | b[1];
+
+       return 0;
+}
+
+static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
+{
+       struct i2c_client *client = core->client;
+       u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
+       int r;
+
+       r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
+       if (r) {
+               dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
+               return r;
+       }
+
+       return 0;
+}
+
+static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
+{
+       struct i2c_client *client = core->client;
+       struct i2c_msg msg;
+       int r;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.buf = data;
+       msg.len = len;
+
+       r = i2c_transfer(client->adapter, &msg, 1);
+       if (r != 1) {
+               dev_err(&client->dev, "%s: write error.\n", __func__);
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+/**
+ * wl1273_fm_set_audio() -     Set audio mode.
+ * @core:                      A pointer to the device struct.
+ * @new_mode:                  The new audio mode.
+ *
+ * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
+ */
+static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
+{
+       int r = 0;
+
+       if (core->mode == WL1273_MODE_OFF ||
+           core->mode == WL1273_MODE_SUSPENDED)
+               return -EPERM;
+
+       if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
+               r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
+                                       WL1273_PCM_DEF_MODE);
+               if (r)
+                       goto out;
+
+               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+                                       core->i2s_mode);
+               if (r)
+                       goto out;
+
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+                                       WL1273_AUDIO_ENABLE_I2S);
+               if (r)
+                       goto out;
+
+       } else if (core->mode == WL1273_MODE_RX &&
+                  new_mode == WL1273_AUDIO_ANALOG) {
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+                                       WL1273_AUDIO_ENABLE_ANALOG);
+               if (r)
+                       goto out;
+
+       } else if (core->mode == WL1273_MODE_TX &&
+                  new_mode == WL1273_AUDIO_DIGITAL) {
+               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+                                       core->i2s_mode);
+               if (r)
+                       goto out;
+
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+                                       WL1273_AUDIO_IO_SET_I2S);
+               if (r)
+                       goto out;
+
+       } else if (core->mode == WL1273_MODE_TX &&
+                  new_mode == WL1273_AUDIO_ANALOG) {
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+                                       WL1273_AUDIO_IO_SET_ANALOG);
+               if (r)
+                       goto out;
+       }
+
+       core->audio_mode = new_mode;
+out:
+       return r;
+}
+
+/**
+ * wl1273_fm_set_volume() -    Set volume.
+ * @core:                      A pointer to the device struct.
+ * @volume:                    The new volume value.
+ */
+static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
+{
+       u16 val;
+       int r;
+
+       if (volume > WL1273_MAX_VOLUME)
+               return -EINVAL;
+
+       if (core->volume == volume)
+               return 0;
+
+       r = wl1273_fm_write_cmd(core, WL1273_VOLUME_SET, volume);
+       if (r)
+               return r;
+
+       core->volume = volume;
+       return 0;
+}
+
 static int wl1273_core_remove(struct i2c_client *client)
 {
        struct wl1273_core *core = i2c_get_clientdata(client);
@@ -38,7 +177,6 @@ static int wl1273_core_remove(struct i2c_client *client)
        dev_dbg(&client->dev, "%s\n", __func__);
 
        mfd_remove_devices(&client->dev);
-       i2c_set_clientdata(client, NULL);
        kfree(core);
 
        return 0;
@@ -79,17 +217,21 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
 
        cell = &core->cells[children];
        cell->name = "wl1273_fm_radio";
-       cell->platform_data = &core;
-       cell->data_size = sizeof(core);
+       cell->mfd_data = &core;
        children++;
 
+       core->read = wl1273_fm_read_reg;
+       core->write = wl1273_fm_write_cmd;
+       core->write_data = wl1273_fm_write_data;
+       core->set_audio = wl1273_fm_set_audio;
+       core->set_volume = wl1273_fm_set_volume;
+
        if (pdata->children & WL1273_CODEC_CHILD) {
                cell = &core->cells[children];
 
                dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
                cell->name = "wl1273-codec";
-               cell->platform_data = &core;
-               cell->data_size = sizeof(core);
+               cell->mfd_data = &core;
                children++;
        }
 
@@ -104,7 +246,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
        return 0;
 
 err:
-       i2c_set_clientdata(client, NULL);
        pdata->free_resources();
        kfree(core);
 
index 3853fa8e7cc267dd4496a1e9101c79fc6f2c9082..a06cbc739716c25c57ae872f90c2ba9cc6fa506d 100644 (file)
@@ -51,17 +51,25 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
                                   int bytes, void *src)
 {
        struct i2c_client *i2c = wm831x->control_data;
-       unsigned char msg[bytes + 2];
+       struct i2c_msg xfer[2];
        int ret;
 
        reg = cpu_to_be16(reg);
-       memcpy(&msg[0], &reg, 2);
-       memcpy(&msg[2], src, bytes);
 
-       ret = i2c_master_send(i2c, msg, bytes + 2);
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 2;
+       xfer[0].buf = (char *)&reg;
+
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_NOSTART;
+       xfer[1].len = bytes;
+       xfer[1].buf = (char *)src;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
        if (ret < 0)
                return ret;
-       if (ret < bytes + 2)
+       if (ret != 2)
                return -EIO;
 
        return 0;
index f7192d438aabf17f209ec9959aaa7f7db98078d4..a5cd17e18d09d93ec582d36f19478c66259e71d2 100644 (file)
 
 #include <linux/delay.h>
 
-/*
- * Since generic IRQs don't currently support interrupt controllers on
- * interrupt driven buses we don't use genirq but instead provide an
- * interface that looks very much like the standard ones.  This leads
- * to some bodges, including storing interrupt handler information in
- * the static irq_data table we use to look up the data for individual
- * interrupts, but hopefully won't last too long.
- */
-
 struct wm831x_irq_data {
        int primary;
        int reg;
@@ -361,6 +352,10 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
                /* If there's been a change in the mask write it back
                 * to the hardware. */
                if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) {
+                       dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n",
+                               WM831X_INTERRUPT_STATUS_1_MASK + i,
+                               wm831x->irq_masks_cur[i]);
+
                        wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i];
                        wm831x_reg_write(wm831x,
                                         WM831X_INTERRUPT_STATUS_1_MASK + i,
@@ -371,7 +366,7 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
        mutex_unlock(&wm831x->irq_lock);
 }
 
-static void wm831x_irq_unmask(struct irq_data *data)
+static void wm831x_irq_enable(struct irq_data *data)
 {
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
        struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
@@ -380,7 +375,7 @@ static void wm831x_irq_unmask(struct irq_data *data)
        wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
 
-static void wm831x_irq_mask(struct irq_data *data)
+static void wm831x_irq_disable(struct irq_data *data)
 {
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
        struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
@@ -426,8 +421,8 @@ static struct irq_chip wm831x_irq_chip = {
        .name                   = "wm831x",
        .irq_bus_lock           = wm831x_irq_lock,
        .irq_bus_sync_unlock    = wm831x_irq_sync_unlock,
-       .irq_mask               = wm831x_irq_mask,
-       .irq_unmask             = wm831x_irq_unmask,
+       .irq_disable            = wm831x_irq_disable,
+       .irq_enable             = wm831x_irq_enable,
        .irq_set_type           = wm831x_irq_set_type,
 };
 
@@ -449,6 +444,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                goto out;
        }
 
+       /* The touch interrupts are visible in the primary register as
+        * an optimisation; open code this to avoid complicating the
+        * main handling loop and so we can also skip iterating the
+        * descriptors.
+        */
+       if (primary & WM831X_TCHPD_INT)
+               handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
+       if (primary & WM831X_TCHDATA_INT)
+               handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
+       if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
+               goto out;
+
        for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
                int offset = wm831x_irqs[i].reg - 1;
 
@@ -481,6 +488,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
        }
 
 out:
+       /* Touchscreen interrupts are handled specially in the driver */
+       status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
+
        for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
                if (status_regs[i])
                        wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
@@ -517,6 +527,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                return 0;
        }
 
+       if (pdata->irq_cmos)
+               i = 0;
+       else
+               i = WM831X_IRQ_OD;
+
+       wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG,
+                       WM831X_IRQ_OD, i);
+
        /* Try to flag /IRQ as a wake source; there are a number of
         * unconditional wake sources in the PMIC so this isn't
         * conditional but we don't actually care *too* much if it
index 0a8f772be88c88aff35e731a7eef5ae607eefcdb..eed8e4f7a5a14c6c724097567f1b817419dba3a9 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/pm.h>
 #include <linux/spi/spi.h>
 
 #include <linux/mfd/wm831x/core.h>
@@ -113,22 +114,27 @@ static int __devexit wm831x_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m)
+static int wm831x_spi_suspend(struct device *dev)
 {
-       struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
+       struct wm831x *wm831x = dev_get_drvdata(dev);
 
        return wm831x_device_suspend(wm831x);
 }
 
+static const struct dev_pm_ops wm831x_spi_pm = {
+       .freeze = wm831x_spi_suspend,
+       .suspend = wm831x_spi_suspend,
+};
+
 static struct spi_driver wm8310_spi_driver = {
        .driver = {
                .name   = "wm8310",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8311_spi_driver = {
@@ -136,10 +142,10 @@ static struct spi_driver wm8311_spi_driver = {
                .name   = "wm8311",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8312_spi_driver = {
@@ -147,10 +153,10 @@ static struct spi_driver wm8312_spi_driver = {
                .name   = "wm8312",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8320_spi_driver = {
@@ -158,10 +164,10 @@ static struct spi_driver wm8320_spi_driver = {
                .name   = "wm8320",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8321_spi_driver = {
@@ -169,10 +175,10 @@ static struct spi_driver wm8321_spi_driver = {
                .name   = "wm8321",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8325_spi_driver = {
@@ -180,10 +186,10 @@ static struct spi_driver wm8325_spi_driver = {
                .name   = "wm8325",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static struct spi_driver wm8326_spi_driver = {
@@ -191,10 +197,10 @@ static struct spi_driver wm8326_spi_driver = {
                .name   = "wm8326",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &wm831x_spi_pm,
        },
        .probe          = wm831x_spi_probe,
        .remove         = __devexit_p(wm831x_spi_remove),
-       .suspend        = wm831x_spi_suspend,
 };
 
 static int __init wm831x_spi_init(void)
index 1bfef4846b07b0d98138c87509872937b2c29e6f..3a6e78cb038458936e4679483ba564ac98f25936 100644 (file)
@@ -245,7 +245,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
 {
        struct mfd_cell cell = {
                .name = "wm8400-codec",
-               .driver_data = wm8400,
+               .mfd_data = wm8400,
        };
 
        return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
index f4016a075fd611000f8f6f1059deb8631722a211..e198d40292e7f5cb9c1ed5e78c4d3f41e30f1bc5 100644 (file)
@@ -40,10 +40,8 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
                return ret;
 
        for (i = 0; i < bytes / 2; i++) {
-               buf[i] = be16_to_cpu(buf[i]);
-
                dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n",
-                        buf[i], reg + i, reg + i);
+                        be16_to_cpu(buf[i]), reg + i, reg + i);
        }
 
        return 0;
@@ -69,7 +67,7 @@ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg)
        if (ret < 0)
                return ret;
        else
-               return val;
+               return be16_to_cpu(val);
 }
 EXPORT_SYMBOL_GPL(wm8994_reg_read);
 
@@ -79,7 +77,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read);
  * @wm8994: Device to read from
  * @reg: First register
  * @count: Number of registers
- * @buf: Buffer to fill.
+ * @buf: Buffer to fill.  The data will be returned big endian.
  */
 int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
                     int count, u16 *buf)
@@ -97,9 +95,9 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
 EXPORT_SYMBOL_GPL(wm8994_bulk_read);
 
 static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
-                       int bytes, void *src)
+                       int bytes, const void *src)
 {
-       u16 *buf = src;
+       const u16 *buf = src;
        int i;
 
        BUG_ON(bytes % 2);
@@ -107,9 +105,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
 
        for (i = 0; i < bytes / 2; i++) {
                dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n",
-                        buf[i], reg + i, reg + i);
-
-               buf[i] = cpu_to_be16(buf[i]);
+                        be16_to_cpu(buf[i]), reg + i, reg + i);
        }
 
        return wm8994->write_dev(wm8994, reg, bytes, src);
@@ -127,6 +123,8 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
 {
        int ret;
 
+       val = cpu_to_be16(val);
+
        mutex_lock(&wm8994->io_lock);
 
        ret = wm8994_write(wm8994, reg, 2, &val);
@@ -137,6 +135,29 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg,
 }
 EXPORT_SYMBOL_GPL(wm8994_reg_write);
 
+/**
+ * wm8994_bulk_write: Write multiple WM8994 registers
+ *
+ * @wm8994: Device to write to
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to write from.  Data must be big-endian formatted.
+ */
+int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
+                     int count, const u16 *buf)
+{
+       int ret;
+
+       mutex_lock(&wm8994->io_lock);
+
+       ret = wm8994_write(wm8994, reg, count * 2, buf);
+
+       mutex_unlock(&wm8994->io_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8994_bulk_write);
+
 /**
  * wm8994_set_bits: Set the value of a bitfield in a WM8994 register
  *
@@ -157,9 +178,13 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
        if (ret < 0)
                goto out;
 
+       r = be16_to_cpu(r);
+
        r &= ~mask;
        r |= val;
 
+       r = cpu_to_be16(r);
+
        ret = wm8994_write(wm8994, reg, 2, &r);
 
 out:
@@ -271,6 +296,11 @@ static int wm8994_suspend(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to save LDO registers: %d\n", ret);
 
+       /* Explicitly put the device into reset in case regulators
+        * don't get disabled in order to ensure consistent restart.
+        */
+       wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994);
+
        wm8994->suspended = true;
 
        ret = regulator_bulk_disable(wm8994->num_supplies,
@@ -552,25 +582,29 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg,
        return 0;
 }
 
-/* Currently we allocate the write buffer on the stack; this is OK for
- * small writes - if we need to do large writes this will need to be
- * revised.
- */
 static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg,
-                                  int bytes, void *src)
+                                  int bytes, const void *src)
 {
        struct i2c_client *i2c = wm8994->control_data;
-       unsigned char msg[bytes + 2];
+       struct i2c_msg xfer[2];
        int ret;
 
        reg = cpu_to_be16(reg);
-       memcpy(&msg[0], &reg, 2);
-       memcpy(&msg[2], src, bytes);
 
-       ret = i2c_master_send(i2c, msg, bytes + 2);
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 2;
+       xfer[0].buf = (char *)&reg;
+
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_NOSTART;
+       xfer[1].len = bytes;
+       xfer[1].buf = (char *)src;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
        if (ret < 0)
                return ret;
-       if (ret < bytes + 2)
+       if (ret != 2)
                return -EIO;
 
        return 0;
@@ -612,7 +646,8 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
 
-UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume,
+                           NULL);
 
 static struct i2c_driver wm8994_i2c_driver = {
        .driver = {
index 29e8faf9c01c79f37dada4b1d0581d92f4e49e90..1e3bf4a2ff8ef7dbfdd0caab962559c6fe5ed3c3 100644 (file)
@@ -182,7 +182,7 @@ static void wm8994_irq_sync_unlock(struct irq_data *data)
        mutex_unlock(&wm8994->irq_lock);
 }
 
-static void wm8994_irq_unmask(struct irq_data *data)
+static void wm8994_irq_enable(struct irq_data *data)
 {
        struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
        struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
@@ -191,7 +191,7 @@ static void wm8994_irq_unmask(struct irq_data *data)
        wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
 
-static void wm8994_irq_mask(struct irq_data *data)
+static void wm8994_irq_disable(struct irq_data *data)
 {
        struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
        struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
@@ -204,8 +204,8 @@ static struct irq_chip wm8994_irq_chip = {
        .name                   = "wm8994",
        .irq_bus_lock           = wm8994_irq_lock,
        .irq_bus_sync_unlock    = wm8994_irq_sync_unlock,
-       .irq_mask               = wm8994_irq_mask,
-       .irq_unmask             = wm8994_irq_unmask,
+       .irq_disable            = wm8994_irq_disable,
+       .irq_enable             = wm8994_irq_enable,
 };
 
 /* The processing of the primary interrupt occurs in a thread so that
@@ -225,9 +225,11 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
                return IRQ_NONE;
        }
 
-       /* Apply masking */
-       for (i = 0; i < WM8994_NUM_IRQ_REGS; i++)
+       /* Bit swap and apply masking */
+       for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
+               status[i] = be16_to_cpu(status[i]);
                status[i] &= ~wm8994->irq_masks_cur[i];
+       }
 
        /* Report */
        for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
index b7d5ef234ac942f00358abdf700ee2ed21770c5f..4e007c6a4b446695c01980450f3d6b6eb4548bf0 100644 (file)
@@ -2,6 +2,14 @@
 # Misc strange devices
 #
 
+# This one has to live outside of the MISC_DEVICES conditional,
+# because it may be selected by drivers/platform/x86/hp_accel.
+config SENSORS_LIS3LV02D
+       tristate
+       depends on INPUT
+       select INPUT_POLLDEV
+       default n
+
 menuconfig MISC_DEVICES
        bool "Misc devices"
        ---help---
@@ -394,6 +402,16 @@ config DS1682
          This driver can also be built as a module.  If so, the module
          will be called ds1682.
 
+config SPEAR13XX_PCIE_GADGET
+       bool "PCIe gadget support for SPEAr13XX platform"
+       depends on ARCH_SPEAR13XX
+       default n
+       help
+        This option enables gadget support for PCIe controller. If
+        board file defines any controller as PCIe endpoint then a sysfs
+        entry will be created for that controller. User can use these
+        sysfs node to configure PCIe EP as per his requirements.
+
 config TI_DAC7512
        tristate "Texas Instruments DAC7512"
        depends on SPI && SYSFS
@@ -462,5 +480,6 @@ source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
 source "drivers/misc/iwmc3200top/Kconfig"
 source "drivers/misc/ti-st/Kconfig"
+source "drivers/misc/lis3lv02d/Kconfig"
 
 endif # MISC_DEVICES
index 98009cc20cb9c6c887a200bfe96c85948a311be5..f5468602961f85ec578b62530e71c9af39d36080 100644 (file)
@@ -37,8 +37,10 @@ obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-$(CONFIG_HMC6352)          += hmc6352.o
 obj-y                          += eeprom/
 obj-y                          += cb710/
+obj-$(CONFIG_SPEAR13XX_PCIE_GADGET)    += spear13xx_pcie_gadget.o
 obj-$(CONFIG_VMWARE_BALLOON)   += vmw_balloon.o
 obj-$(CONFIG_ARM_CHARLCD)      += arm-charlcd.o
 obj-$(CONFIG_PCH_PHUB)         += pch_phub.o
 obj-y                          += ti-st/
 obj-$(CONFIG_AB8500_PWM)       += ab8500-pwm.o
+obj-y                          += lis3lv02d/
index 644d4cd071cc58eb2afc02d09b53bab2f5a3ff38..81db7811cf68ca349b6778ca5a8bff99db535f3e 100644 (file)
@@ -245,9 +245,8 @@ static int apds9802als_probe(struct i2c_client *client,
        als_set_default_config(client);
        mutex_init(&data->mutex);
 
+       pm_runtime_set_active(&client->dev);
        pm_runtime_enable(&client->dev);
-       pm_runtime_get(&client->dev);
-       pm_runtime_put(&client->dev);
 
        return res;
 als_error1:
@@ -255,12 +254,19 @@ als_error1:
        return res;
 }
 
-static int apds9802als_remove(struct i2c_client *client)
+static int __devexit apds9802als_remove(struct i2c_client *client)
 {
        struct als_data *data = i2c_get_clientdata(client);
 
+       pm_runtime_get_sync(&client->dev);
+
        als_set_power_state(client, false);
        sysfs_remove_group(&client->dev.kobj, &m_als_gr);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+
        kfree(data);
        return 0;
 }
@@ -275,9 +281,6 @@ static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
 static int apds9802als_resume(struct i2c_client *client)
 {
        als_set_default_config(client);
-
-       pm_runtime_get(&client->dev);
-       pm_runtime_put(&client->dev);
        return 0;
 }
 
@@ -323,7 +326,7 @@ static struct i2c_driver apds9802als_driver = {
                .pm = APDS9802ALS_PM_OPS,
        },
        .probe = apds9802als_probe,
-       .remove = apds9802als_remove,
+       .remove = __devexit_p(apds9802als_remove),
        .suspend = apds9802als_suspend,
        .resume = apds9802als_resume,
        .id_table = apds9802als_id,
index 3891124001f28331946b284a22564e15b029ce6a..a844810b50f68a6a88e12ed7a427862a044efc48 100644 (file)
@@ -75,7 +75,7 @@ out:
        return tc;
 
 fail_ioremap:
-       release_resource(r);
+       release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE);
 fail:
        tc = NULL;
        goto out;
@@ -95,7 +95,7 @@ void atmel_tc_free(struct atmel_tc *tc)
        spin_lock(&tc_list_lock);
        if (tc->regs) {
                iounmap(tc->regs);
-               release_resource(tc->iomem);
+               release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE);
                tc->regs = NULL;
                tc->iomem = NULL;
        }
index d5f3a3fd231931508948a9b0227aae2a3648a96f..d07cd67c951c58ac88f3cf070127c795d3f4beae 100644 (file)
@@ -196,10 +196,11 @@ static int __devexit bh1780_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg)
+static int bh1780_suspend(struct device *dev)
 {
        struct bh1780_data *ddata;
        int state, ret;
+       struct i2c_client *client = to_i2c_client(dev);
 
        ddata = i2c_get_clientdata(client);
        state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL");
@@ -217,14 +218,14 @@ static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int bh1780_resume(struct i2c_client *client)
+static int bh1780_resume(struct device *dev)
 {
        struct bh1780_data *ddata;
        int state, ret;
+       struct i2c_client *client = to_i2c_client(dev);
 
        ddata = i2c_get_clientdata(client);
        state = ddata->power_state;
-
        ret = bh1780_write(ddata, BH1780_REG_CONTROL, state,
                                "CONTROL");
 
@@ -233,9 +234,10 @@ static int bh1780_resume(struct i2c_client *client)
 
        return 0;
 }
+static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume);
+#define BH1780_PMOPS (&bh1780_pm)
 #else
-#define bh1780_suspend NULL
-#define bh1780_resume NULL
+#define BH1780_PMOPS NULL
 #endif /* CONFIG_PM */
 
 static const struct i2c_device_id bh1780_id[] = {
@@ -247,11 +249,10 @@ static struct i2c_driver bh1780_driver = {
        .probe          = bh1780_probe,
        .remove         = bh1780_remove,
        .id_table       = bh1780_id,
-       .suspend        = bh1780_suspend,
-       .resume         = bh1780_resume,
        .driver = {
-               .name = "bh1780"
-       },
+               .name = "bh1780",
+               .pm     = BH1780_PMOPS,
+},
 };
 
 static int __init bh1780_init(void)
index b6e1c9a6679edd11ae94738775b813ecf34632df..ecd276ad6b193452dec2e3ed993d04ca68ac2415 100644 (file)
@@ -402,7 +402,7 @@ exit:
        return status;
 }
 
-static int bmp085_probe(struct i2c_client *client,
+static int __devinit bmp085_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct bmp085_data *data;
@@ -438,7 +438,7 @@ exit:
        return err;
 }
 
-static int bmp085_remove(struct i2c_client *client)
+static int __devexit bmp085_remove(struct i2c_client *client)
 {
        sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group);
        kfree(i2c_get_clientdata(client));
@@ -458,7 +458,7 @@ static struct i2c_driver bmp085_driver = {
        },
        .id_table       = bmp085_id,
        .probe          = bmp085_probe,
-       .remove         = bmp085_remove,
+       .remove         = __devexit_p(bmp085_remove),
 
        .detect         = bmp085_detect,
        .address_list   = normal_i2c
index 7b80cbf1a609b75f710d9b308a45e66d2bd9deef..467c8e9ca3c94d6b7f54998133a70ec5c88a9403 100644 (file)
@@ -1,6 +1,4 @@
-ifeq ($(CONFIG_CB710_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
+ccflags-$(CONFIG_CB710_DEBUG)  := -DDEBUG
 
 obj-$(CONFIG_CB710_CORE)       += cb710.o
 
index 46b3439673e9036ed9f46e4a275819c7e45da061..16d7179e2f9b8dd5005a2a62952abb6c10e20f2f 100644 (file)
@@ -249,11 +249,11 @@ static ssize_t ep93xx_pwm_set_invert(struct device *dev,
 
 static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL);
 static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL);
-static DEVICE_ATTR(freq, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(freq, S_IWUSR | S_IRUGO,
                   ep93xx_pwm_get_freq, ep93xx_pwm_set_freq);
-static DEVICE_ATTR(duty_percent, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(duty_percent, S_IWUSR | S_IRUGO,
                   ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent);
-static DEVICE_ATTR(invert, S_IWUGO | S_IRUGO,
+static DEVICE_ATTR(invert, S_IWUSR | S_IRUGO,
                   ep93xx_pwm_get_invert, ep93xx_pwm_set_invert);
 
 static struct attribute *ep93xx_pwm_attrs[] = {
index 234bfcaf209917996697362a4aa6ca64a3a7f2ef..ca938fc8a8d6d20361b98e157c959cd62e6ed6a4 100644 (file)
@@ -75,7 +75,7 @@ static ssize_t compass_heading_data_show(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        unsigned char i2c_data[2];
-       unsigned int ret;
+       int ret;
 
        mutex_lock(&compass_mutex);
        ret = compass_command(client, 'A');
@@ -86,7 +86,7 @@ static ssize_t compass_heading_data_show(struct device *dev,
        msleep(10); /* sending 'A' cmd we need to wait for 7-10 millisecs */
        ret = i2c_master_recv(client, i2c_data, 2);
        mutex_unlock(&compass_mutex);
-       if (ret != 1) {
+       if (ret < 0) {
                dev_warn(dev, "i2c read data cmd failed\n");
                return ret;
        }
diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig
new file mode 100644 (file)
index 0000000..8f474e6
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# STMicroelectonics LIS3LV02D and similar accelerometers
+#
+
+config SENSORS_LIS3_SPI
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
+       depends on !ACPI && SPI_MASTER && INPUT
+       select SENSORS_LIS3LV02D
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer connected
+         via SPI. The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the laptop to act as a pinball machine-esque joystick.
+
+         This driver can also be built as modules.  If so, the core module
+         will be called lis3lv02d and a specific module for the SPI transport
+         is called lis3lv02d_spi.
+
+config SENSORS_LIS3_I2C
+       tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
+       depends on I2C && INPUT
+       select SENSORS_LIS3LV02D
+       default n
+       help
+         This driver provides support for the LIS3LV02Dx accelerometer connected
+         via I2C. The accelerometer data is readable via
+         /sys/devices/platform/lis3lv02d.
+
+         This driver also provides an absolute input class device, allowing
+         the device to act as a pinball machine-esque joystick.
+
+         This driver can also be built as modules.  If so, the core module
+         will be called lis3lv02d and a specific module for the I2C transport
+         is called lis3lv02d_i2c.
diff --git a/drivers/misc/lis3lv02d/Makefile b/drivers/misc/lis3lv02d/Makefile
new file mode 100644 (file)
index 0000000..4bf58b1
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# STMicroelectonics LIS3LV02D and similar accelerometers
+#
+
+obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o
+obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o
+obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
new file mode 100644 (file)
index 0000000..b928bc1
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver
+ *
+ *  Copyright (C) 2007-2008 Yan Burman
+ *  Copyright (C) 2008 Eric Piel
+ *  Copyright (C) 2008-2009 Pavel Machek
+ *
+ *  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
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input-polldev.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/freezer.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pm_runtime.h>
+#include <linux/atomic.h>
+#include "lis3lv02d.h"
+
+#define DRIVER_NAME     "lis3lv02d"
+
+/* joystick device poll interval in milliseconds */
+#define MDPS_POLL_INTERVAL 50
+#define MDPS_POLL_MIN     0
+#define MDPS_POLL_MAX     2000
+
+#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
+
+#define SELFTEST_OK           0
+#define SELFTEST_FAIL         -1
+#define SELFTEST_IRQ          -2
+
+#define IRQ_LINE0             0
+#define IRQ_LINE1             1
+
+/*
+ * The sensor can also generate interrupts (DRDY) but it's pretty pointless
+ * because they are generated even if the data do not change. So it's better
+ * to keep the interrupt for the free-fall event. The values are updated at
+ * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
+ * some low processor, we poll the sensor only at 20Hz... enough for the
+ * joystick.
+ */
+
+#define LIS3_PWRON_DELAY_WAI_12B       (5000)
+#define LIS3_PWRON_DELAY_WAI_8B                (3000)
+
+/*
+ * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG
+ * LIS302D spec says: 18 mG / digit
+ * LIS3_ACCURACY is used to increase accuracy of the intermediate
+ * calculation results.
+ */
+#define LIS3_ACCURACY                  1024
+/* Sensitivity values for -2G +2G scale */
+#define LIS3_SENSITIVITY_12B           ((LIS3_ACCURACY * 1000) / 1024)
+#define LIS3_SENSITIVITY_8B            (18 * LIS3_ACCURACY)
+
+#define LIS3_DEFAULT_FUZZ_12B          3
+#define LIS3_DEFAULT_FLAT_12B          3
+#define LIS3_DEFAULT_FUZZ_8B           1
+#define LIS3_DEFAULT_FLAT_8B           1
+
+struct lis3lv02d lis3_dev = {
+       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
+};
+EXPORT_SYMBOL_GPL(lis3_dev);
+
+/* just like param_set_int() but does sanity-check so that it won't point
+ * over the axis array size
+ */
+static int param_set_axis(const char *val, const struct kernel_param *kp)
+{
+       int ret = param_set_int(val, kp);
+       if (!ret) {
+               int val = *(int *)kp->arg;
+               if (val < 0)
+                       val = -val;
+               if (!val || val > 3)
+                       return -EINVAL;
+       }
+       return ret;
+}
+
+static struct kernel_param_ops param_ops_axis = {
+       .set = param_set_axis,
+       .get = param_get_int,
+};
+
+module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
+MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
+
+static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
+{
+       s8 lo;
+       if (lis3->read(lis3, reg, &lo) < 0)
+               return 0;
+
+       return lo;
+}
+
+static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
+{
+       u8 lo, hi;
+
+       lis3->read(lis3, reg - 1, &lo);
+       lis3->read(lis3, reg, &hi);
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       return (s16)((hi << 8) | lo);
+}
+
+/**
+ * lis3lv02d_get_axis - For the given axis, give the value converted
+ * @axis:      1,2,3 - can also be negative
+ * @hw_values: raw values returned by the hardware
+ *
+ * Returns the converted value.
+ */
+static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
+{
+       if (axis > 0)
+               return hw_values[axis - 1];
+       else
+               return -hw_values[-axis - 1];
+}
+
+/**
+ * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
+ * @lis3: pointer to the device struct
+ * @x:    where to store the X axis value
+ * @y:    where to store the Y axis value
+ * @z:    where to store the Z axis value
+ *
+ * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
+ */
+static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
+{
+       int position[3];
+       int i;
+
+       if (lis3->blkread) {
+               if (lis3_dev.whoami == WAI_12B) {
+                       u16 data[3];
+                       lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
+                       for (i = 0; i < 3; i++)
+                               position[i] = (s16)le16_to_cpu(data[i]);
+               } else {
+                       u8 data[5];
+                       /* Data: x, dummy, y, dummy, z */
+                       lis3->blkread(lis3, OUTX, 5, data);
+                       for (i = 0; i < 3; i++)
+                               position[i] = (s8)data[i * 2];
+               }
+       } else {
+               position[0] = lis3->read_data(lis3, OUTX);
+               position[1] = lis3->read_data(lis3, OUTY);
+               position[2] = lis3->read_data(lis3, OUTZ);
+       }
+
+       for (i = 0; i < 3; i++)
+               position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
+
+       *x = lis3lv02d_get_axis(lis3->ac.x, position);
+       *y = lis3lv02d_get_axis(lis3->ac.y, position);
+       *z = lis3lv02d_get_axis(lis3->ac.z, position);
+}
+
+/* conversion btw sampling rate and the register values */
+static int lis3_12_rates[4] = {40, 160, 640, 2560};
+static int lis3_8_rates[2] = {100, 400};
+static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
+
+/* ODR is Output Data Rate */
+static int lis3lv02d_get_odr(void)
+{
+       u8 ctrl;
+       int shift;
+
+       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
+       ctrl &= lis3_dev.odr_mask;
+       shift = ffs(lis3_dev.odr_mask) - 1;
+       return lis3_dev.odrs[(ctrl >> shift)];
+}
+
+static int lis3lv02d_set_odr(int rate)
+{
+       u8 ctrl;
+       int i, len, shift;
+
+       if (!rate)
+               return -EINVAL;
+
+       lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
+       ctrl &= ~lis3_dev.odr_mask;
+       len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
+       shift = ffs(lis3_dev.odr_mask) - 1;
+
+       for (i = 0; i < len; i++)
+               if (lis3_dev.odrs[i] == rate) {
+                       lis3_dev.write(&lis3_dev, CTRL_REG1,
+                                       ctrl | (i << shift));
+                       return 0;
+               }
+       return -EINVAL;
+}
+
+static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
+{
+       u8 ctlreg, reg;
+       s16 x, y, z;
+       u8 selftest;
+       int ret;
+       u8 ctrl_reg_data;
+       unsigned char irq_cfg;
+
+       mutex_lock(&lis3->mutex);
+
+       irq_cfg = lis3->irq_cfg;
+       if (lis3_dev.whoami == WAI_8B) {
+               lis3->data_ready_count[IRQ_LINE0] = 0;
+               lis3->data_ready_count[IRQ_LINE1] = 0;
+
+               /* Change interrupt cfg to data ready for selftest */
+               atomic_inc(&lis3_dev.wake_thread);
+               lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
+               lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
+               lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
+                               ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
+                               (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
+       }
+
+       if (lis3_dev.whoami == WAI_3DC) {
+               ctlreg = CTRL_REG4;
+               selftest = CTRL4_ST0;
+       } else {
+               ctlreg = CTRL_REG1;
+               if (lis3_dev.whoami == WAI_12B)
+                       selftest = CTRL1_ST;
+               else
+                       selftest = CTRL1_STP;
+       }
+
+       lis3->read(lis3, ctlreg, &reg);
+       lis3->write(lis3, ctlreg, (reg | selftest));
+       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+
+       /* Read directly to avoid axis remap */
+       x = lis3->read_data(lis3, OUTX);
+       y = lis3->read_data(lis3, OUTY);
+       z = lis3->read_data(lis3, OUTZ);
+
+       /* back to normal settings */
+       lis3->write(lis3, ctlreg, reg);
+       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+
+       results[0] = x - lis3->read_data(lis3, OUTX);
+       results[1] = y - lis3->read_data(lis3, OUTY);
+       results[2] = z - lis3->read_data(lis3, OUTZ);
+
+       ret = 0;
+
+       if (lis3_dev.whoami == WAI_8B) {
+               /* Restore original interrupt configuration */
+               atomic_dec(&lis3_dev.wake_thread);
+               lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
+               lis3->irq_cfg = irq_cfg;
+
+               if ((irq_cfg & LIS3_IRQ1_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE0] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+
+               if ((irq_cfg & LIS3_IRQ2_MASK) &&
+                       lis3->data_ready_count[IRQ_LINE1] < 2) {
+                       ret = SELFTEST_IRQ;
+                       goto fail;
+               }
+       }
+
+       if (lis3->pdata) {
+               int i;
+               for (i = 0; i < 3; i++) {
+                       /* Check against selftest acceptance limits */
+                       if ((results[i] < lis3->pdata->st_min_limits[i]) ||
+                           (results[i] > lis3->pdata->st_max_limits[i])) {
+                               ret = SELFTEST_FAIL;
+                               goto fail;
+                       }
+               }
+       }
+
+       /* test passed */
+fail:
+       mutex_unlock(&lis3->mutex);
+       return ret;
+}
+
+/*
+ * Order of registers in the list affects to order of the restore process.
+ * Perhaps it is a good idea to set interrupt enable register as a last one
+ * after all other configurations
+ */
+static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
+                              FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
+                              CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
+                              CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
+                              CTRL_REG1, CTRL_REG2, CTRL_REG3};
+
+static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
+                              FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
+                              DD_THSE_L, DD_THSE_H,
+                              CTRL_REG1, CTRL_REG3, CTRL_REG2};
+
+static inline void lis3_context_save(struct lis3lv02d *lis3)
+{
+       int i;
+       for (i = 0; i < lis3->regs_size; i++)
+               lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
+       lis3->regs_stored = true;
+}
+
+static inline void lis3_context_restore(struct lis3lv02d *lis3)
+{
+       int i;
+       if (lis3->regs_stored)
+               for (i = 0; i < lis3->regs_size; i++)
+                       lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
+}
+
+void lis3lv02d_poweroff(struct lis3lv02d *lis3)
+{
+       if (lis3->reg_ctrl)
+               lis3_context_save(lis3);
+       /* disable X,Y,Z axis and power down */
+       lis3->write(lis3, CTRL_REG1, 0x00);
+       if (lis3->reg_ctrl)
+               lis3->reg_ctrl(lis3, LIS3_REG_OFF);
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
+
+void lis3lv02d_poweron(struct lis3lv02d *lis3)
+{
+       u8 reg;
+
+       lis3->init(lis3);
+
+       /*
+        * Common configuration
+        * BDU: (12 bits sensors only) LSB and MSB values are not updated until
+        *      both have been read. So the value read will always be correct.
+        * Set BOOT bit to refresh factory tuning values.
+        */
+       lis3->read(lis3, CTRL_REG2, &reg);
+       if (lis3->whoami ==  WAI_12B)
+               reg |= CTRL2_BDU | CTRL2_BOOT;
+       else
+               reg |= CTRL2_BOOT_8B;
+       lis3->write(lis3, CTRL_REG2, reg);
+
+       /* LIS3 power on delay is quite long */
+       msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+
+       if (lis3->reg_ctrl)
+               lis3_context_restore(lis3);
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
+
+
+static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
+{
+       int x, y, z;
+
+       mutex_lock(&lis3_dev.mutex);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       input_report_abs(pidev->input, ABS_X, x);
+       input_report_abs(pidev->input, ABS_Y, y);
+       input_report_abs(pidev->input, ABS_Z, z);
+       input_sync(pidev->input);
+       mutex_unlock(&lis3_dev.mutex);
+}
+
+static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
+{
+       if (lis3_dev.pm_dev)
+               pm_runtime_get_sync(lis3_dev.pm_dev);
+
+       if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
+               atomic_set(&lis3_dev.wake_thread, 1);
+       /*
+        * Update coordinates for the case where poll interval is 0 and
+        * the chip in running purely under interrupt control
+        */
+       lis3lv02d_joystick_poll(pidev);
+}
+
+static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
+{
+       atomic_set(&lis3_dev.wake_thread, 0);
+       if (lis3_dev.pm_dev)
+               pm_runtime_put(lis3_dev.pm_dev);
+}
+
+static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
+{
+       if (!test_bit(0, &lis3_dev.misc_opened))
+               goto out;
+
+       /*
+        * Be careful: on some HP laptops the bios force DD when on battery and
+        * the lid is closed. This leads to interrupts as soon as a little move
+        * is done.
+        */
+       atomic_inc(&lis3_dev.count);
+
+       wake_up_interruptible(&lis3_dev.misc_wait);
+       kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
+out:
+       if (atomic_read(&lis3_dev.wake_thread))
+               return IRQ_WAKE_THREAD;
+       return IRQ_HANDLED;
+}
+
+static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3)
+{
+       struct input_dev *dev = lis3->idev->input;
+       u8 click_src;
+
+       mutex_lock(&lis3->mutex);
+       lis3->read(lis3, CLICK_SRC, &click_src);
+
+       if (click_src & CLICK_SINGLE_X) {
+               input_report_key(dev, lis3->mapped_btns[0], 1);
+               input_report_key(dev, lis3->mapped_btns[0], 0);
+       }
+
+       if (click_src & CLICK_SINGLE_Y) {
+               input_report_key(dev, lis3->mapped_btns[1], 1);
+               input_report_key(dev, lis3->mapped_btns[1], 0);
+       }
+
+       if (click_src & CLICK_SINGLE_Z) {
+               input_report_key(dev, lis3->mapped_btns[2], 1);
+               input_report_key(dev, lis3->mapped_btns[2], 0);
+       }
+       input_sync(dev);
+       mutex_unlock(&lis3->mutex);
+}
+
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
+{
+       int dummy;
+
+       /* Dummy read to ack interrupt */
+       lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
+       lis3->data_ready_count[index]++;
+}
+
+static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
+{
+       struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
+
+       if (irq_cfg == LIS3_IRQ1_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE0);
+       else
+               lis3lv02d_joystick_poll(lis3->idev);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
+{
+       struct lis3lv02d *lis3 = data;
+       u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
+
+       if (irq_cfg == LIS3_IRQ2_CLICK)
+               lis302dl_interrupt_handle_click(lis3);
+       else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
+               lis302dl_data_ready(lis3, IRQ_LINE1);
+       else
+               lis3lv02d_joystick_poll(lis3->idev);
+
+       return IRQ_HANDLED;
+}
+
+static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &lis3_dev.misc_opened))
+               return -EBUSY; /* already open */
+
+       if (lis3_dev.pm_dev)
+               pm_runtime_get_sync(lis3_dev.pm_dev);
+
+       atomic_set(&lis3_dev.count, 0);
+       return 0;
+}
+
+static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
+{
+       fasync_helper(-1, file, 0, &lis3_dev.async_queue);
+       clear_bit(0, &lis3_dev.misc_opened); /* release the device */
+       if (lis3_dev.pm_dev)
+               pm_runtime_put(lis3_dev.pm_dev);
+       return 0;
+}
+
+static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       u32 data;
+       unsigned char byte_data;
+       ssize_t retval = 1;
+
+       if (count < 1)
+               return -EINVAL;
+
+       add_wait_queue(&lis3_dev.misc_wait, &wait);
+       while (true) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               data = atomic_xchg(&lis3_dev.count, 0);
+               if (data)
+                       break;
+
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               }
+
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+
+               schedule();
+       }
+
+       if (data < 255)
+               byte_data = data;
+       else
+               byte_data = 255;
+
+       /* make sure we are not going into copy_to_user() with
+        * TASK_INTERRUPTIBLE state */
+       set_current_state(TASK_RUNNING);
+       if (copy_to_user(buf, &byte_data, sizeof(byte_data)))
+               retval = -EFAULT;
+
+out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&lis3_dev.misc_wait, &wait);
+
+       return retval;
+}
+
+static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &lis3_dev.misc_wait, wait);
+       if (atomic_read(&lis3_dev.count))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
+{
+       return fasync_helper(fd, file, on, &lis3_dev.async_queue);
+}
+
+static const struct file_operations lis3lv02d_misc_fops = {
+       .owner   = THIS_MODULE,
+       .llseek  = no_llseek,
+       .read    = lis3lv02d_misc_read,
+       .open    = lis3lv02d_misc_open,
+       .release = lis3lv02d_misc_release,
+       .poll    = lis3lv02d_misc_poll,
+       .fasync  = lis3lv02d_misc_fasync,
+};
+
+static struct miscdevice lis3lv02d_misc_device = {
+       .minor   = MISC_DYNAMIC_MINOR,
+       .name    = "freefall",
+       .fops    = &lis3lv02d_misc_fops,
+};
+
+int lis3lv02d_joystick_enable(void)
+{
+       struct input_dev *input_dev;
+       int err;
+       int max_val, fuzz, flat;
+       int btns[] = {BTN_X, BTN_Y, BTN_Z};
+
+       if (lis3_dev.idev)
+               return -EINVAL;
+
+       lis3_dev.idev = input_allocate_polled_device();
+       if (!lis3_dev.idev)
+               return -ENOMEM;
+
+       lis3_dev.idev->poll = lis3lv02d_joystick_poll;
+       lis3_dev.idev->open = lis3lv02d_joystick_open;
+       lis3_dev.idev->close = lis3lv02d_joystick_close;
+       lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
+       lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
+       lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
+       input_dev = lis3_dev.idev->input;
+
+       input_dev->name       = "ST LIS3LV02DL Accelerometer";
+       input_dev->phys       = DRIVER_NAME "/input0";
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor  = 0;
+       input_dev->dev.parent = &lis3_dev.pdev->dev;
+
+       set_bit(EV_ABS, input_dev->evbit);
+       max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
+       if (lis3_dev.whoami == WAI_12B) {
+               fuzz = LIS3_DEFAULT_FUZZ_12B;
+               flat = LIS3_DEFAULT_FLAT_12B;
+       } else {
+               fuzz = LIS3_DEFAULT_FUZZ_8B;
+               flat = LIS3_DEFAULT_FLAT_8B;
+       }
+       fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
+       flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+
+       input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
+       input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
+       input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
+
+       lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
+       lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
+       lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
+
+       err = input_register_polled_device(lis3_dev.idev);
+       if (err) {
+               input_free_polled_device(lis3_dev.idev);
+               lis3_dev.idev = NULL;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
+
+void lis3lv02d_joystick_disable(void)
+{
+       if (lis3_dev.irq)
+               free_irq(lis3_dev.irq, &lis3_dev);
+       if (lis3_dev.pdata && lis3_dev.pdata->irq2)
+               free_irq(lis3_dev.pdata->irq2, &lis3_dev);
+
+       if (!lis3_dev.idev)
+               return;
+
+       if (lis3_dev.irq)
+               misc_deregister(&lis3lv02d_misc_device);
+       input_unregister_polled_device(lis3_dev.idev);
+       input_free_polled_device(lis3_dev.idev);
+       lis3_dev.idev = NULL;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
+
+/* Sysfs stuff */
+static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
+{
+       /*
+        * SYSFS functions are fast visitors so put-call
+        * immediately after the get-call. However, keep
+        * chip running for a while and schedule delayed
+        * suspend. This way periodic sysfs calls doesn't
+        * suffer from relatively long power up time.
+        */
+
+       if (lis3->pm_dev) {
+               pm_runtime_get_sync(lis3->pm_dev);
+               pm_runtime_put_noidle(lis3->pm_dev);
+               pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
+       }
+}
+
+static ssize_t lis3lv02d_selftest_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       s16 values[3];
+
+       static const char ok[] = "OK";
+       static const char fail[] = "FAIL";
+       static const char irq[] = "FAIL_IRQ";
+       const char *res;
+
+       lis3lv02d_sysfs_poweron(&lis3_dev);
+       switch (lis3lv02d_selftest(&lis3_dev, values)) {
+       case SELFTEST_FAIL:
+               res = fail;
+               break;
+       case SELFTEST_IRQ:
+               res = irq;
+               break;
+       case SELFTEST_OK:
+       default:
+               res = ok;
+               break;
+       }
+       return sprintf(buf, "%s %d %d %d\n", res,
+               values[0], values[1], values[2]);
+}
+
+static ssize_t lis3lv02d_position_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int x, y, z;
+
+       lis3lv02d_sysfs_poweron(&lis3_dev);
+       mutex_lock(&lis3_dev.mutex);
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       mutex_unlock(&lis3_dev.mutex);
+       return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t lis3lv02d_rate_show(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       lis3lv02d_sysfs_poweron(&lis3_dev);
+       return sprintf(buf, "%d\n", lis3lv02d_get_odr());
+}
+
+static ssize_t lis3lv02d_rate_set(struct device *dev,
+                               struct device_attribute *attr, const char *buf,
+                               size_t count)
+{
+       unsigned long rate;
+
+       if (strict_strtoul(buf, 0, &rate))
+               return -EINVAL;
+
+       lis3lv02d_sysfs_poweron(&lis3_dev);
+       if (lis3lv02d_set_odr(rate))
+               return -EINVAL;
+
+       return count;
+}
+
+static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
+static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
+static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
+                                           lis3lv02d_rate_set);
+
+static struct attribute *lis3lv02d_attributes[] = {
+       &dev_attr_selftest.attr,
+       &dev_attr_position.attr,
+       &dev_attr_rate.attr,
+       NULL
+};
+
+static struct attribute_group lis3lv02d_attribute_group = {
+       .attrs = lis3lv02d_attributes
+};
+
+
+static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
+{
+       lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(lis3->pdev))
+               return PTR_ERR(lis3->pdev);
+
+       return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
+}
+
+int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
+{
+       sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
+       platform_device_unregister(lis3->pdev);
+       if (lis3->pm_dev) {
+               /* Barrier after the sysfs remove */
+               pm_runtime_barrier(lis3->pm_dev);
+
+               /* SYSFS may have left chip running. Turn off if necessary */
+               if (!pm_runtime_suspended(lis3->pm_dev))
+                       lis3lv02d_poweroff(&lis3_dev);
+
+               pm_runtime_disable(lis3->pm_dev);
+               pm_runtime_set_suspended(lis3->pm_dev);
+       }
+       kfree(lis3->reg_cache);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
+
+static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
+                               struct lis3lv02d_platform_data *p)
+{
+       int err;
+       int ctrl2 = p->hipass_ctrl;
+
+       if (p->click_flags) {
+               dev->write(dev, CLICK_CFG, p->click_flags);
+               dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
+               dev->write(dev, CLICK_LATENCY, p->click_latency);
+               dev->write(dev, CLICK_WINDOW, p->click_window);
+               dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
+               dev->write(dev, CLICK_THSY_X,
+                       (p->click_thresh_x & 0xf) |
+                       (p->click_thresh_y << 4));
+
+               if (dev->idev) {
+                       struct input_dev *input_dev = lis3_dev.idev->input;
+                       input_set_capability(input_dev, EV_KEY, BTN_X);
+                       input_set_capability(input_dev, EV_KEY, BTN_Y);
+                       input_set_capability(input_dev, EV_KEY, BTN_Z);
+               }
+       }
+
+       if (p->wakeup_flags) {
+               dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
+               dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
+               /* pdata value + 1 to keep this backward compatible*/
+               dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
+               ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
+       }
+
+       if (p->wakeup_flags2) {
+               dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
+               dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
+               /* pdata value + 1 to keep this backward compatible*/
+               dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
+               ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
+       }
+       /* Configure hipass filters */
+       dev->write(dev, CTRL_REG2, ctrl2);
+
+       if (p->irq2) {
+               err = request_threaded_irq(p->irq2,
+                                       NULL,
+                                       lis302dl_interrupt_thread2_8b,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+                                       (p->irq_flags2 & IRQF_TRIGGER_MASK),
+                                       DRIVER_NAME, &lis3_dev);
+               if (err < 0)
+                       pr_err("No second IRQ. Limited functionality\n");
+       }
+}
+
+/*
+ * Initialise the accelerometer and the various subsystems.
+ * Should be rather independent of the bus system.
+ */
+int lis3lv02d_init_device(struct lis3lv02d *dev)
+{
+       int err;
+       irq_handler_t thread_fn;
+       int irq_flags = 0;
+
+       dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
+
+       switch (dev->whoami) {
+       case WAI_12B:
+               pr_info("12 bits sensor found\n");
+               dev->read_data = lis3lv02d_read_12;
+               dev->mdps_max_val = 2048;
+               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
+               dev->odrs = lis3_12_rates;
+               dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
+               dev->scale = LIS3_SENSITIVITY_12B;
+               dev->regs = lis3_wai12_regs;
+               dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
+               break;
+       case WAI_8B:
+               pr_info("8 bits sensor found\n");
+               dev->read_data = lis3lv02d_read_8;
+               dev->mdps_max_val = 128;
+               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+               dev->odrs = lis3_8_rates;
+               dev->odr_mask = CTRL1_DR;
+               dev->scale = LIS3_SENSITIVITY_8B;
+               dev->regs = lis3_wai8_regs;
+               dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+               break;
+       case WAI_3DC:
+               pr_info("8 bits 3DC sensor found\n");
+               dev->read_data = lis3lv02d_read_8;
+               dev->mdps_max_val = 128;
+               dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+               dev->odrs = lis3_3dc_rates;
+               dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+               dev->scale = LIS3_SENSITIVITY_8B;
+               break;
+       default:
+               pr_err("unknown sensor type 0x%X\n", dev->whoami);
+               return -EINVAL;
+       }
+
+       dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+                                    sizeof(lis3_wai12_regs)), GFP_KERNEL);
+
+       if (dev->reg_cache == NULL) {
+               printk(KERN_ERR DRIVER_NAME "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->mutex);
+       atomic_set(&dev->wake_thread, 0);
+
+       lis3lv02d_add_fs(dev);
+       lis3lv02d_poweron(dev);
+
+       if (dev->pm_dev) {
+               pm_runtime_set_active(dev->pm_dev);
+               pm_runtime_enable(dev->pm_dev);
+       }
+
+       if (lis3lv02d_joystick_enable())
+               pr_err("joystick initialization failed\n");
+
+       /* passing in platform specific data is purely optional and only
+        * used by the SPI transport layer at the moment */
+       if (dev->pdata) {
+               struct lis3lv02d_platform_data *p = dev->pdata;
+
+               if (dev->whoami == WAI_8B)
+                       lis3lv02d_8b_configure(dev, p);
+
+               irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
+
+               dev->irq_cfg = p->irq_cfg;
+               if (p->irq_cfg)
+                       dev->write(dev, CTRL_REG3, p->irq_cfg);
+
+               if (p->default_rate)
+                       lis3lv02d_set_odr(p->default_rate);
+       }
+
+       /* bail if we did not get an IRQ from the bus layer */
+       if (!dev->irq) {
+               pr_debug("No IRQ. Disabling /dev/freefall\n");
+               goto out;
+       }
+
+       /*
+        * The sensor can generate interrupts for free-fall and direction
+        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
+        * the things simple and _fast_ we activate it only for free-fall, so
+        * no need to read register (very slow with ACPI). For the same reason,
+        * we forbid shared interrupts.
+        *
+        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
+        * io-apic is not configurable (and generates a warning) but I keep it
+        * in case of support for other hardware.
+        */
+       if (dev->pdata && dev->whoami == WAI_8B)
+               thread_fn = lis302dl_interrupt_thread1_8b;
+       else
+               thread_fn = NULL;
+
+       err = request_threaded_irq(dev->irq, lis302dl_interrupt,
+                               thread_fn,
+                               IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+                               irq_flags,
+                               DRIVER_NAME, &lis3_dev);
+
+       if (err < 0) {
+               pr_err("Cannot get IRQ\n");
+               goto out;
+       }
+
+       if (misc_register(&lis3lv02d_misc_device))
+               pr_err("misc_register failed\n");
+out:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
+
+MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
+MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
new file mode 100644 (file)
index 0000000..a193958
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ *  lis3lv02d.h - ST LIS3LV02DL accelerometer driver
+ *
+ *  Copyright (C) 2007-2008 Yan Burman
+ *  Copyright (C) 2008-2009 Eric Piel
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/regulator/consumer.h>
+
+/*
+ * This driver tries to support the "digital" accelerometer chips from
+ * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
+ * LIS35DE, or LIS202DL. They are very similar in terms of programming, with
+ * almost the same registers. In addition to differing on physical properties,
+ * they differ on the number of axes (2/3), precision (8/12 bits), and special
+ * features (freefall detection, click...). Unfortunately, not all the
+ * differences can be probed via a register.
+ * They can be connected either via IĀ²C or SPI.
+ */
+
+#include <linux/lis3lv02d.h>
+
+enum lis3_reg {
+       WHO_AM_I        = 0x0F,
+       OFFSET_X        = 0x16,
+       OFFSET_Y        = 0x17,
+       OFFSET_Z        = 0x18,
+       GAIN_X          = 0x19,
+       GAIN_Y          = 0x1A,
+       GAIN_Z          = 0x1B,
+       CTRL_REG1       = 0x20,
+       CTRL_REG2       = 0x21,
+       CTRL_REG3       = 0x22,
+       CTRL_REG4       = 0x23,
+       HP_FILTER_RESET = 0x23,
+       STATUS_REG      = 0x27,
+       OUTX_L          = 0x28,
+       OUTX_H          = 0x29,
+       OUTX            = 0x29,
+       OUTY_L          = 0x2A,
+       OUTY_H          = 0x2B,
+       OUTY            = 0x2B,
+       OUTZ_L          = 0x2C,
+       OUTZ_H          = 0x2D,
+       OUTZ            = 0x2D,
+};
+
+enum lis302d_reg {
+       FF_WU_CFG_1     = 0x30,
+       FF_WU_SRC_1     = 0x31,
+       FF_WU_THS_1     = 0x32,
+       FF_WU_DURATION_1 = 0x33,
+       FF_WU_CFG_2     = 0x34,
+       FF_WU_SRC_2     = 0x35,
+       FF_WU_THS_2     = 0x36,
+       FF_WU_DURATION_2 = 0x37,
+       CLICK_CFG       = 0x38,
+       CLICK_SRC       = 0x39,
+       CLICK_THSY_X    = 0x3B,
+       CLICK_THSZ      = 0x3C,
+       CLICK_TIMELIMIT = 0x3D,
+       CLICK_LATENCY   = 0x3E,
+       CLICK_WINDOW    = 0x3F,
+};
+
+enum lis3lv02d_reg {
+       FF_WU_CFG       = 0x30,
+       FF_WU_SRC       = 0x31,
+       FF_WU_ACK       = 0x32,
+       FF_WU_THS_L     = 0x34,
+       FF_WU_THS_H     = 0x35,
+       FF_WU_DURATION  = 0x36,
+       DD_CFG          = 0x38,
+       DD_SRC          = 0x39,
+       DD_ACK          = 0x3A,
+       DD_THSI_L       = 0x3C,
+       DD_THSI_H       = 0x3D,
+       DD_THSE_L       = 0x3E,
+       DD_THSE_H       = 0x3F,
+};
+
+enum lis3_who_am_i {
+       WAI_3DC         = 0x33, /* 8 bits: LIS3DC, HP3DC */
+       WAI_12B         = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
+       WAI_8B          = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
+       WAI_6B          = 0x52, /* 6 bits: LIS331DLF - not supported */
+};
+
+enum lis3lv02d_ctrl1_12b {
+       CTRL1_Xen       = 0x01,
+       CTRL1_Yen       = 0x02,
+       CTRL1_Zen       = 0x04,
+       CTRL1_ST        = 0x08,
+       CTRL1_DF0       = 0x10,
+       CTRL1_DF1       = 0x20,
+       CTRL1_PD0       = 0x40,
+       CTRL1_PD1       = 0x80,
+};
+
+/* Delta to ctrl1_12b version */
+enum lis3lv02d_ctrl1_8b {
+       CTRL1_STM       = 0x08,
+       CTRL1_STP       = 0x10,
+       CTRL1_FS        = 0x20,
+       CTRL1_PD        = 0x40,
+       CTRL1_DR        = 0x80,
+};
+
+enum lis3lv02d_ctrl1_3dc {
+       CTRL1_ODR0      = 0x10,
+       CTRL1_ODR1      = 0x20,
+       CTRL1_ODR2      = 0x40,
+       CTRL1_ODR3      = 0x80,
+};
+
+enum lis3lv02d_ctrl2 {
+       CTRL2_DAS       = 0x01,
+       CTRL2_SIM       = 0x02,
+       CTRL2_DRDY      = 0x04,
+       CTRL2_IEN       = 0x08,
+       CTRL2_BOOT      = 0x10,
+       CTRL2_BLE       = 0x20,
+       CTRL2_BDU       = 0x40, /* Block Data Update */
+       CTRL2_FS        = 0x80, /* Full Scale selection */
+};
+
+enum lis3lv02d_ctrl4_3dc {
+       CTRL4_SIM       = 0x01,
+       CTRL4_ST0       = 0x02,
+       CTRL4_ST1       = 0x04,
+       CTRL4_FS0       = 0x10,
+       CTRL4_FS1       = 0x20,
+};
+
+enum lis302d_ctrl2 {
+       HP_FF_WU2       = 0x08,
+       HP_FF_WU1       = 0x04,
+       CTRL2_BOOT_8B   = 0x40,
+};
+
+enum lis3lv02d_ctrl3 {
+       CTRL3_CFS0      = 0x01,
+       CTRL3_CFS1      = 0x02,
+       CTRL3_FDS       = 0x10,
+       CTRL3_HPFF      = 0x20,
+       CTRL3_HPDD      = 0x40,
+       CTRL3_ECK       = 0x80,
+};
+
+enum lis3lv02d_status_reg {
+       STATUS_XDA      = 0x01,
+       STATUS_YDA      = 0x02,
+       STATUS_ZDA      = 0x04,
+       STATUS_XYZDA    = 0x08,
+       STATUS_XOR      = 0x10,
+       STATUS_YOR      = 0x20,
+       STATUS_ZOR      = 0x40,
+       STATUS_XYZOR    = 0x80,
+};
+
+enum lis3lv02d_ff_wu_cfg {
+       FF_WU_CFG_XLIE  = 0x01,
+       FF_WU_CFG_XHIE  = 0x02,
+       FF_WU_CFG_YLIE  = 0x04,
+       FF_WU_CFG_YHIE  = 0x08,
+       FF_WU_CFG_ZLIE  = 0x10,
+       FF_WU_CFG_ZHIE  = 0x20,
+       FF_WU_CFG_LIR   = 0x40,
+       FF_WU_CFG_AOI   = 0x80,
+};
+
+enum lis3lv02d_ff_wu_src {
+       FF_WU_SRC_XL    = 0x01,
+       FF_WU_SRC_XH    = 0x02,
+       FF_WU_SRC_YL    = 0x04,
+       FF_WU_SRC_YH    = 0x08,
+       FF_WU_SRC_ZL    = 0x10,
+       FF_WU_SRC_ZH    = 0x20,
+       FF_WU_SRC_IA    = 0x40,
+};
+
+enum lis3lv02d_dd_cfg {
+       DD_CFG_XLIE     = 0x01,
+       DD_CFG_XHIE     = 0x02,
+       DD_CFG_YLIE     = 0x04,
+       DD_CFG_YHIE     = 0x08,
+       DD_CFG_ZLIE     = 0x10,
+       DD_CFG_ZHIE     = 0x20,
+       DD_CFG_LIR      = 0x40,
+       DD_CFG_IEND     = 0x80,
+};
+
+enum lis3lv02d_dd_src {
+       DD_SRC_XL       = 0x01,
+       DD_SRC_XH       = 0x02,
+       DD_SRC_YL       = 0x04,
+       DD_SRC_YH       = 0x08,
+       DD_SRC_ZL       = 0x10,
+       DD_SRC_ZH       = 0x20,
+       DD_SRC_IA       = 0x40,
+};
+
+enum lis3lv02d_click_src_8b {
+       CLICK_SINGLE_X  = 0x01,
+       CLICK_DOUBLE_X  = 0x02,
+       CLICK_SINGLE_Y  = 0x04,
+       CLICK_DOUBLE_Y  = 0x08,
+       CLICK_SINGLE_Z  = 0x10,
+       CLICK_DOUBLE_Z  = 0x20,
+       CLICK_IA        = 0x40,
+};
+
+enum lis3lv02d_reg_state {
+       LIS3_REG_OFF    = 0x00,
+       LIS3_REG_ON     = 0x01,
+};
+
+union axis_conversion {
+       struct {
+               int x, y, z;
+       };
+       int as_array[3];
+
+};
+
+struct lis3lv02d {
+       void                    *bus_priv; /* used by the bus layer only */
+       struct device           *pm_dev; /* for pm_runtime purposes */
+       int (*init) (struct lis3lv02d *lis3);
+       int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
+       int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
+       int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
+       int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
+
+       int                     *odrs;     /* Supported output data rates */
+       u8                      *regs;     /* Regs to store / restore */
+       int                     regs_size;
+       u8                      *reg_cache;
+       bool                    regs_stored;
+       u8                      odr_mask;  /* ODR bit mask */
+       u8                      whoami;    /* indicates measurement precision */
+       s16 (*read_data) (struct lis3lv02d *lis3, int reg);
+       int                     mdps_max_val;
+       int                     pwron_delay;
+       int                     scale; /*
+                                       * relationship between 1 LBS and mG
+                                       * (1/1000th of earth gravity)
+                                       */
+
+       struct input_polled_dev *idev;     /* input device */
+       struct platform_device  *pdev;     /* platform device */
+       struct regulator_bulk_data regulators[2];
+       atomic_t                count;     /* interrupt count after last read */
+       union axis_conversion   ac;        /* hw -> logical axis */
+       int                     mapped_btns[3];
+
+       u32                     irq;       /* IRQ number */
+       struct fasync_struct    *async_queue; /* queue for the misc device */
+       wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
+       unsigned long           misc_opened; /* bit0: whether the device is open */
+       int                     data_ready_count[2];
+       atomic_t                wake_thread;
+       unsigned char           irq_cfg;
+
+       struct lis3lv02d_platform_data *pdata;  /* for passing board config */
+       struct mutex            mutex;     /* Serialize poll and selftest */
+};
+
+int lis3lv02d_init_device(struct lis3lv02d *lis3);
+int lis3lv02d_joystick_enable(void);
+void lis3lv02d_joystick_disable(void);
+void lis3lv02d_poweroff(struct lis3lv02d *lis3);
+void lis3lv02d_poweron(struct lis3lv02d *lis3);
+int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
+
+extern struct lis3lv02d lis3_dev;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
new file mode 100644 (file)
index 0000000..b20dfb4
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * drivers/hwmon/lis3lv02d_i2c.c
+ *
+ * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer.
+ * Driver is based on corresponding SPI driver written by Daniel Mack
+ * (lis3lv02d_spi.c (C) 2009 Daniel Mack <daniel@caiaq.de> ).
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include "lis3lv02d.h"
+
+#define DRV_NAME       "lis3lv02d_i2c"
+
+static const char reg_vdd[]    = "Vdd";
+static const char reg_vdd_io[] = "Vdd_IO";
+
+static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
+{
+       int ret;
+       if (state == LIS3_REG_OFF) {
+               ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
+                                       lis3->regulators);
+       } else {
+               ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
+                                       lis3->regulators);
+               /* Chip needs time to wakeup. Not mentioned in datasheet */
+               usleep_range(10000, 20000);
+       }
+       return ret;
+}
+
+static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       return i2c_smbus_write_byte_data(c, reg, value);
+}
+
+static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       *v = i2c_smbus_read_byte_data(c, reg);
+       return 0;
+}
+
+static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
+                               u8 *v)
+{
+       struct i2c_client *c = lis3->bus_priv;
+       reg |= (1 << 7); /* 7th bit enables address auto incrementation */
+       return i2c_smbus_read_i2c_block_data(c, reg, len, v);
+}
+
+static int lis3_i2c_init(struct lis3lv02d *lis3)
+{
+       u8 reg;
+       int ret;
+
+       if (lis3->reg_ctrl)
+               lis3_reg_ctrl(lis3, LIS3_REG_ON);
+
+       lis3->read(lis3, WHO_AM_I, &reg);
+       if (reg != lis3->whoami)
+               printk(KERN_ERR "lis3: power on failure\n");
+
+       /* power up the device */
+       ret = lis3->read(lis3, CTRL_REG1, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+       return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+/* Default axis mapping but it can be overwritten by platform data */
+static union axis_conversion lis3lv02d_axis_map =
+       { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
+
+static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+       if (pdata) {
+               /* Regulator control is optional */
+               if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
+                       lis3_dev.reg_ctrl = lis3_reg_ctrl;
+
+               if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
+                       (i2c_check_functionality(client->adapter,
+                                               I2C_FUNC_SMBUS_I2C_BLOCK)))
+                       lis3_dev.blkread  = lis3_i2c_blockread;
+
+               if (pdata->axis_x)
+                       lis3lv02d_axis_map.x = pdata->axis_x;
+
+               if (pdata->axis_y)
+                       lis3lv02d_axis_map.y = pdata->axis_y;
+
+               if (pdata->axis_z)
+                       lis3lv02d_axis_map.z = pdata->axis_z;
+
+               if (pdata->setup_resources)
+                       ret = pdata->setup_resources();
+
+               if (ret)
+                       goto fail;
+       }
+
+       if (lis3_dev.reg_ctrl) {
+               lis3_dev.regulators[0].supply = reg_vdd;
+               lis3_dev.regulators[1].supply = reg_vdd_io;
+               ret = regulator_bulk_get(&client->dev,
+                                       ARRAY_SIZE(lis3_dev.regulators),
+                                       lis3_dev.regulators);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       lis3_dev.pdata    = pdata;
+       lis3_dev.bus_priv = client;
+       lis3_dev.init     = lis3_i2c_init;
+       lis3_dev.read     = lis3_i2c_read;
+       lis3_dev.write    = lis3_i2c_write;
+       lis3_dev.irq      = client->irq;
+       lis3_dev.ac       = lis3lv02d_axis_map;
+       lis3_dev.pm_dev   = &client->dev;
+
+       i2c_set_clientdata(client, &lis3_dev);
+
+       /* Provide power over the init call */
+       if (lis3_dev.reg_ctrl)
+               lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
+
+       ret = lis3lv02d_init_device(&lis3_dev);
+
+       if (lis3_dev.reg_ctrl)
+               lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
+
+       if (ret == 0)
+               return 0;
+fail:
+       if (pdata && pdata->release_resources)
+               pdata->release_resources();
+       return ret;
+}
+
+static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
+{
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+       struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+
+       if (pdata && pdata->release_resources)
+               pdata->release_resources();
+
+       lis3lv02d_joystick_disable();
+       lis3lv02d_remove_fs(&lis3_dev);
+
+       if (lis3_dev.reg_ctrl)
+               regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
+                               lis3_dev.regulators);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int lis3lv02d_i2c_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+               lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static int lis3lv02d_i2c_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       /*
+        * pm_runtime documentation says that devices should always
+        * be powered on at resume. Pm_runtime turns them off after system
+        * wide resume is complete.
+        */
+       if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
+               pm_runtime_suspended(dev))
+               lis3lv02d_poweron(lis3);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int lis3_i2c_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       lis3lv02d_poweroff(lis3);
+       return 0;
+}
+
+static int lis3_i2c_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+       lis3lv02d_poweron(lis3);
+       return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct i2c_device_id lis3lv02d_id[] = {
+       {"lis3lv02d", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
+
+static const struct dev_pm_ops lis3_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
+                               lis3lv02d_i2c_resume)
+       SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
+                          lis3_i2c_runtime_resume,
+                          NULL)
+};
+
+static struct i2c_driver lis3lv02d_i2c_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &lis3_pm_ops,
+       },
+       .probe  = lis3lv02d_i2c_probe,
+       .remove = __devexit_p(lis3lv02d_i2c_remove),
+       .id_table = lis3lv02d_id,
+};
+
+static int __init lis3lv02d_init(void)
+{
+       return i2c_add_driver(&lis3lv02d_i2c_driver);
+}
+
+static void __exit lis3lv02d_exit(void)
+{
+       i2c_del_driver(&lis3lv02d_i2c_driver);
+}
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("lis3lv02d I2C interface");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init);
+module_exit(lis3lv02d_exit);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
new file mode 100644 (file)
index 0000000..c1f8a8f
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * lis3lv02d_spi - SPI glue layer for lis3lv02d
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/pm.h>
+
+#include "lis3lv02d.h"
+
+#define DRV_NAME       "lis3lv02d_spi"
+#define LIS3_SPI_READ  0x80
+
+static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v)
+{
+       struct spi_device *spi = lis3->bus_priv;
+       int ret = spi_w8r8(spi, reg | LIS3_SPI_READ);
+       if (ret < 0)
+               return -EINVAL;
+
+       *v = (u8) ret;
+       return 0;
+}
+
+static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val)
+{
+       u8 tmp[2] = { reg, val };
+       struct spi_device *spi = lis3->bus_priv;
+       return spi_write(spi, tmp, sizeof(tmp));
+}
+
+static int lis3_spi_init(struct lis3lv02d *lis3)
+{
+       u8 reg;
+       int ret;
+
+       /* power up the device */
+       ret = lis3->read(lis3, CTRL_REG1, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+       return lis3->write(lis3, CTRL_REG1, reg);
+}
+
+static union axis_conversion lis3lv02d_axis_normal =
+       { .as_array = { 1, 2, 3 } };
+
+static int __devinit lis302dl_spi_probe(struct spi_device *spi)
+{
+       int ret;
+
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       lis3_dev.bus_priv       = spi;
+       lis3_dev.init           = lis3_spi_init;
+       lis3_dev.read           = lis3_spi_read;
+       lis3_dev.write          = lis3_spi_write;
+       lis3_dev.irq            = spi->irq;
+       lis3_dev.ac             = lis3lv02d_axis_normal;
+       lis3_dev.pdata          = spi->dev.platform_data;
+       spi_set_drvdata(spi, &lis3_dev);
+
+       return lis3lv02d_init_device(&lis3_dev);
+}
+
+static int __devexit lis302dl_spi_remove(struct spi_device *spi)
+{
+       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(lis3);
+
+       return lis3lv02d_remove_fs(&lis3_dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int lis3lv02d_spi_suspend(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
+
+       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+               lis3lv02d_poweroff(&lis3_dev);
+
+       return 0;
+}
+
+static int lis3lv02d_spi_resume(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct lis3lv02d *lis3 = spi_get_drvdata(spi);
+
+       if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+               lis3lv02d_poweron(lis3);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend,
+                        lis3lv02d_spi_resume);
+
+static struct spi_driver lis302dl_spi_driver = {
+       .driver  = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &lis3lv02d_spi_pm,
+       },
+       .probe  = lis302dl_spi_probe,
+       .remove = __devexit_p(lis302dl_spi_remove),
+};
+
+static int __init lis302dl_init(void)
+{
+       return spi_register_driver(&lis302dl_spi_driver);
+}
+
+static void __exit lis302dl_exit(void)
+{
+       spi_unregister_driver(&lis302dl_spi_driver);
+}
+
+module_init(lis302dl_init);
+module_exit(lis302dl_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("lis3lv02d SPI glue layer");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:" DRV_NAME);
index 380ba806495d33f2638130b9c67785f7289aac1d..a19cb710a2462a7dc2f72ca06cd5aab9f7609aa4 100644 (file)
@@ -735,6 +735,7 @@ static struct pci_device_id pch_phub_pcidev_id[] = {
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2,  },
        { }
 };
+MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id);
 
 static struct pci_driver pch_phub_driver = {
        .name = "pch_phub",
index 7c4c306dfa8a464073b74b8c1358c72ed1f0d12d..0003a1d56f7f63123411de0388e2221abc997193 100644 (file)
@@ -1,6 +1,4 @@
-ifdef CONFIG_SGI_GRU_DEBUG
-  EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_SGI_GRU_DEBUG)        := -DDEBUG
 
 obj-$(CONFIG_SGI_GRU) := gru.o
 gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o grukdump.o
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
new file mode 100644 (file)
index 0000000..ec3b8c9
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * drivers/misc/spear13xx_pcie_gadget.c
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Pratyush Anand<pratyush.anand@st.com>
+ *
+ * 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/clk.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pci_regs.h>
+#include <linux/configfs.h>
+#include <mach/pcie.h>
+#include <mach/misc_regs.h>
+
+#define IN0_MEM_SIZE   (200 * 1024 * 1024 - 1)
+/* In current implementation address translation is done using IN0 only.
+ * So IN1 start address and IN0 end address has been kept same
+*/
+#define IN1_MEM_SIZE   (0 * 1024 * 1024 - 1)
+#define IN_IO_SIZE     (20 * 1024 * 1024 - 1)
+#define IN_CFG0_SIZE   (12 * 1024 * 1024 - 1)
+#define IN_CFG1_SIZE   (12 * 1024 * 1024 - 1)
+#define IN_MSG_SIZE    (12 * 1024 * 1024 - 1)
+/* Keep default BAR size as 4K*/
+/* AORAM would be mapped by default*/
+#define INBOUND_ADDR_MASK      (SPEAR13XX_SYSRAM1_SIZE - 1)
+
+#define INT_TYPE_NO_INT        0
+#define INT_TYPE_INTX  1
+#define INT_TYPE_MSI   2
+struct spear_pcie_gadget_config {
+       void __iomem *base;
+       void __iomem *va_app_base;
+       void __iomem *va_dbi_base;
+       char int_type[10];
+       ulong requested_msi;
+       ulong configured_msi;
+       ulong bar0_size;
+       ulong bar0_rw_offset;
+       void __iomem *va_bar0_address;
+};
+
+struct pcie_gadget_target {
+       struct configfs_subsystem subsys;
+       struct spear_pcie_gadget_config config;
+};
+
+struct pcie_gadget_target_attr {
+       struct configfs_attribute       attr;
+       ssize_t         (*show)(struct spear_pcie_gadget_config *config,
+                                               char *buf);
+       ssize_t         (*store)(struct spear_pcie_gadget_config *config,
+                                                const char *buf,
+                                                size_t count);
+};
+
+static void enable_dbi_access(struct pcie_app_reg __iomem *app_reg)
+{
+       /* Enable DBI access */
+       writel(readl(&app_reg->slv_armisc) | (1 << AXI_OP_DBI_ACCESS_ID),
+                       &app_reg->slv_armisc);
+       writel(readl(&app_reg->slv_awmisc) | (1 << AXI_OP_DBI_ACCESS_ID),
+                       &app_reg->slv_awmisc);
+
+}
+
+static void disable_dbi_access(struct pcie_app_reg __iomem *app_reg)
+{
+       /* disable DBI access */
+       writel(readl(&app_reg->slv_armisc) & ~(1 << AXI_OP_DBI_ACCESS_ID),
+                       &app_reg->slv_armisc);
+       writel(readl(&app_reg->slv_awmisc) & ~(1 << AXI_OP_DBI_ACCESS_ID),
+                       &app_reg->slv_awmisc);
+
+}
+
+static void spear_dbi_read_reg(struct spear_pcie_gadget_config *config,
+               int where, int size, u32 *val)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       ulong va_address;
+
+       /* Enable DBI access */
+       enable_dbi_access(app_reg);
+
+       va_address = (ulong)config->va_dbi_base + (where & ~0x3);
+
+       *val = readl(va_address);
+
+       if (size == 1)
+               *val = (*val >> (8 * (where & 3))) & 0xff;
+       else if (size == 2)
+               *val = (*val >> (8 * (where & 3))) & 0xffff;
+
+       /* Disable DBI access */
+       disable_dbi_access(app_reg);
+}
+
+static void spear_dbi_write_reg(struct spear_pcie_gadget_config *config,
+               int where, int size, u32 val)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       ulong va_address;
+
+       /* Enable DBI access */
+       enable_dbi_access(app_reg);
+
+       va_address = (ulong)config->va_dbi_base + (where & ~0x3);
+
+       if (size == 4)
+               writel(val, va_address);
+       else if (size == 2)
+               writew(val, va_address + (where & 2));
+       else if (size == 1)
+               writeb(val, va_address + (where & 3));
+
+       /* Disable DBI access */
+       disable_dbi_access(app_reg);
+}
+
+#define PCI_FIND_CAP_TTL       48
+
+static int pci_find_own_next_cap_ttl(struct spear_pcie_gadget_config *config,
+               u32 pos, int cap, int *ttl)
+{
+       u32 id;
+
+       while ((*ttl)--) {
+               spear_dbi_read_reg(config, pos, 1, &pos);
+               if (pos < 0x40)
+                       break;
+               pos &= ~3;
+               spear_dbi_read_reg(config, pos + PCI_CAP_LIST_ID, 1, &id);
+               if (id == 0xff)
+                       break;
+               if (id == cap)
+                       return pos;
+               pos += PCI_CAP_LIST_NEXT;
+       }
+       return 0;
+}
+
+static int pci_find_own_next_cap(struct spear_pcie_gadget_config *config,
+                       u32 pos, int cap)
+{
+       int ttl = PCI_FIND_CAP_TTL;
+
+       return pci_find_own_next_cap_ttl(config, pos, cap, &ttl);
+}
+
+static int pci_find_own_cap_start(struct spear_pcie_gadget_config *config,
+                               u8 hdr_type)
+{
+       u32 status;
+
+       spear_dbi_read_reg(config, PCI_STATUS, 2, &status);
+       if (!(status & PCI_STATUS_CAP_LIST))
+               return 0;
+
+       switch (hdr_type) {
+       case PCI_HEADER_TYPE_NORMAL:
+       case PCI_HEADER_TYPE_BRIDGE:
+               return PCI_CAPABILITY_LIST;
+       case PCI_HEADER_TYPE_CARDBUS:
+               return PCI_CB_CAPABILITY_LIST;
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+/*
+ * Tell if a device supports a given PCI capability.
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it. Possible values for @cap:
+ *
+ * %PCI_CAP_ID_PM      Power Management
+ * %PCI_CAP_ID_AGP     Accelerated Graphics Port
+ * %PCI_CAP_ID_VPD     Vital Product Data
+ * %PCI_CAP_ID_SLOTID  Slot Identification
+ * %PCI_CAP_ID_MSI     Message Signalled Interrupts
+ * %PCI_CAP_ID_CHSWP   CompactPCI HotSwap
+ * %PCI_CAP_ID_PCIX    PCI-X
+ * %PCI_CAP_ID_EXP     PCI Express
+ */
+static int pci_find_own_capability(struct spear_pcie_gadget_config *config,
+               int cap)
+{
+       u32 pos;
+       u32 hdr_type;
+
+       spear_dbi_read_reg(config, PCI_HEADER_TYPE, 1, &hdr_type);
+
+       pos = pci_find_own_cap_start(config, hdr_type);
+       if (pos)
+               pos = pci_find_own_next_cap(config, pos, cap);
+
+       return pos;
+}
+
+static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id)
+{
+       return 0;
+}
+
+/*
+ * configfs interfaces show/store functions
+ */
+static ssize_t pcie_gadget_show_link(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+
+       if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID))
+               return sprintf(buf, "UP");
+       else
+               return sprintf(buf, "DOWN");
+}
+
+static ssize_t pcie_gadget_store_link(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+
+       if (sysfs_streq(buf, "UP"))
+               writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID),
+                       &app_reg->app_ctrl_0);
+       else if (sysfs_streq(buf, "DOWN"))
+               writel(readl(&app_reg->app_ctrl_0)
+                               & ~(1 << APP_LTSSM_ENABLE_ID),
+                               &app_reg->app_ctrl_0);
+       else
+               return -EINVAL;
+       return count;
+}
+
+static ssize_t pcie_gadget_show_int_type(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       return sprintf(buf, "%s", config->int_type);
+}
+
+static ssize_t pcie_gadget_store_int_type(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       u32 cap, vec, flags;
+       ulong vector;
+
+       if (sysfs_streq(buf, "INTA"))
+               spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1);
+
+       else if (sysfs_streq(buf, "MSI")) {
+               vector = config->requested_msi;
+               vec = 0;
+               while (vector > 1) {
+                       vector /= 2;
+                       vec++;
+               }
+               spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 0);
+               cap = pci_find_own_capability(config, PCI_CAP_ID_MSI);
+               spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags);
+               flags &= ~PCI_MSI_FLAGS_QMASK;
+               flags |= vec << 1;
+               spear_dbi_write_reg(config, cap + PCI_MSI_FLAGS, 1, flags);
+       } else
+               return -EINVAL;
+
+       strcpy(config->int_type, buf);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_no_of_msi(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       u32 cap, vec, flags;
+       ulong vector;
+
+       if ((readl(&app_reg->msg_status) & (1 << CFG_MSI_EN_ID))
+                       != (1 << CFG_MSI_EN_ID))
+               vector = 0;
+       else {
+               cap = pci_find_own_capability(config, PCI_CAP_ID_MSI);
+               spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags);
+               flags &= ~PCI_MSI_FLAGS_QSIZE;
+               vec = flags >> 4;
+               vector = 1;
+               while (vec--)
+                       vector *= 2;
+       }
+       config->configured_msi = vector;
+
+       return sprintf(buf, "%lu", vector);
+}
+
+static ssize_t pcie_gadget_store_no_of_msi(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       if (strict_strtoul(buf, 0, &config->requested_msi))
+               return -EINVAL;
+       if (config->requested_msi > 32)
+               config->requested_msi = 32;
+
+       return count;
+}
+
+static ssize_t pcie_gadget_store_inta(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       ulong en;
+
+       if (strict_strtoul(buf, 0, &en))
+               return -EINVAL;
+
+       if (en)
+               writel(readl(&app_reg->app_ctrl_0) | (1 << SYS_INT_ID),
+                               &app_reg->app_ctrl_0);
+       else
+               writel(readl(&app_reg->app_ctrl_0) & ~(1 << SYS_INT_ID),
+                               &app_reg->app_ctrl_0);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_store_send_msi(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       ulong vector;
+       u32 ven_msi;
+
+       if (strict_strtoul(buf, 0, &vector))
+               return -EINVAL;
+
+       if (!config->configured_msi)
+               return -EINVAL;
+
+       if (vector >= config->configured_msi)
+               return -EINVAL;
+
+       ven_msi = readl(&app_reg->ven_msi_1);
+       ven_msi &= ~VEN_MSI_FUN_NUM_MASK;
+       ven_msi |= 0 << VEN_MSI_FUN_NUM_ID;
+       ven_msi &= ~VEN_MSI_TC_MASK;
+       ven_msi |= 0 << VEN_MSI_TC_ID;
+       ven_msi &= ~VEN_MSI_VECTOR_MASK;
+       ven_msi |= vector << VEN_MSI_VECTOR_ID;
+
+       /* generating interrupt for msi vector */
+       ven_msi |= VEN_MSI_REQ_EN;
+       writel(ven_msi, &app_reg->ven_msi_1);
+       udelay(1);
+       ven_msi &= ~VEN_MSI_REQ_EN;
+       writel(ven_msi, &app_reg->ven_msi_1);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_vendor_id(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       u32 id;
+
+       spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id);
+
+       return sprintf(buf, "%x", id);
+}
+
+static ssize_t pcie_gadget_store_vendor_id(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       ulong id;
+
+       if (strict_strtoul(buf, 0, &id))
+               return -EINVAL;
+
+       spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_device_id(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       u32 id;
+
+       spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id);
+
+       return sprintf(buf, "%x", id);
+}
+
+static ssize_t pcie_gadget_store_device_id(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       ulong id;
+
+       if (strict_strtoul(buf, 0, &id))
+               return -EINVAL;
+
+       spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_bar0_size(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       return sprintf(buf, "%lx", config->bar0_size);
+}
+
+static ssize_t pcie_gadget_store_bar0_size(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       ulong size;
+       u32 pos, pos1;
+       u32 no_of_bit = 0;
+
+       if (strict_strtoul(buf, 0, &size))
+               return -EINVAL;
+       /* min bar size is 256 */
+       if (size <= 0x100)
+               size = 0x100;
+       /* max bar size is 1MB*/
+       else if (size >= 0x100000)
+               size = 0x100000;
+       else {
+               pos = 0;
+               pos1 = 0;
+               while (pos < 21) {
+                       pos = find_next_bit((ulong *)&size, 21, pos);
+                       if (pos != 21)
+                               pos1 = pos + 1;
+                       pos++;
+                       no_of_bit++;
+               }
+               if (no_of_bit == 2)
+                       pos1--;
+
+               size = 1 << pos1;
+       }
+       config->bar0_size = size;
+       spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, size - 1);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_bar0_address(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+
+       u32 address = readl(&app_reg->pim0_mem_addr_start);
+
+       return sprintf(buf, "%x", address);
+}
+
+static ssize_t pcie_gadget_store_bar0_address(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+       ulong address;
+
+       if (strict_strtoul(buf, 0, &address))
+               return -EINVAL;
+
+       address &= ~(config->bar0_size - 1);
+       if (config->va_bar0_address)
+               iounmap(config->va_bar0_address);
+       config->va_bar0_address = ioremap(address, config->bar0_size);
+       if (!config->va_bar0_address)
+               return -ENOMEM;
+
+       writel(address, &app_reg->pim0_mem_addr_start);
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_bar0_rw_offset(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       return sprintf(buf, "%lx", config->bar0_rw_offset);
+}
+
+static ssize_t pcie_gadget_store_bar0_rw_offset(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       ulong offset;
+
+       if (strict_strtoul(buf, 0, &offset))
+               return -EINVAL;
+
+       if (offset % 4)
+               return -EINVAL;
+
+       config->bar0_rw_offset = offset;
+
+       return count;
+}
+
+static ssize_t pcie_gadget_show_bar0_data(
+               struct spear_pcie_gadget_config *config,
+               char *buf)
+{
+       ulong data;
+
+       if (!config->va_bar0_address)
+               return -ENOMEM;
+
+       data = readl((ulong)config->va_bar0_address + config->bar0_rw_offset);
+
+       return sprintf(buf, "%lx", data);
+}
+
+static ssize_t pcie_gadget_store_bar0_data(
+               struct spear_pcie_gadget_config *config,
+               const char *buf, size_t count)
+{
+       ulong data;
+
+       if (strict_strtoul(buf, 0, &data))
+               return -EINVAL;
+
+       if (!config->va_bar0_address)
+               return -ENOMEM;
+
+       writel(data, (ulong)config->va_bar0_address + config->bar0_rw_offset);
+
+       return count;
+}
+
+/*
+ * Attribute definitions.
+ */
+
+#define PCIE_GADGET_TARGET_ATTR_RO(_name)                              \
+static struct pcie_gadget_target_attr pcie_gadget_target_##_name =     \
+       __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL)
+
+#define PCIE_GADGET_TARGET_ATTR_WO(_name)                              \
+static struct pcie_gadget_target_attr pcie_gadget_target_##_name =     \
+       __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name)
+
+#define PCIE_GADGET_TARGET_ATTR_RW(_name)                              \
+static struct pcie_gadget_target_attr pcie_gadget_target_##_name =     \
+       __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \
+                       pcie_gadget_store_##_name)
+PCIE_GADGET_TARGET_ATTR_RW(link);
+PCIE_GADGET_TARGET_ATTR_RW(int_type);
+PCIE_GADGET_TARGET_ATTR_RW(no_of_msi);
+PCIE_GADGET_TARGET_ATTR_WO(inta);
+PCIE_GADGET_TARGET_ATTR_WO(send_msi);
+PCIE_GADGET_TARGET_ATTR_RW(vendor_id);
+PCIE_GADGET_TARGET_ATTR_RW(device_id);
+PCIE_GADGET_TARGET_ATTR_RW(bar0_size);
+PCIE_GADGET_TARGET_ATTR_RW(bar0_address);
+PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset);
+PCIE_GADGET_TARGET_ATTR_RW(bar0_data);
+
+static struct configfs_attribute *pcie_gadget_target_attrs[] = {
+       &pcie_gadget_target_link.attr,
+       &pcie_gadget_target_int_type.attr,
+       &pcie_gadget_target_no_of_msi.attr,
+       &pcie_gadget_target_inta.attr,
+       &pcie_gadget_target_send_msi.attr,
+       &pcie_gadget_target_vendor_id.attr,
+       &pcie_gadget_target_device_id.attr,
+       &pcie_gadget_target_bar0_size.attr,
+       &pcie_gadget_target_bar0_address.attr,
+       &pcie_gadget_target_bar0_rw_offset.attr,
+       &pcie_gadget_target_bar0_data.attr,
+       NULL,
+};
+
+static struct pcie_gadget_target *to_target(struct config_item *item)
+{
+       return item ?
+               container_of(to_configfs_subsystem(to_config_group(item)),
+                               struct pcie_gadget_target, subsys) : NULL;
+}
+
+/*
+ * Item operations and type for pcie_gadget_target.
+ */
+
+static ssize_t pcie_gadget_target_attr_show(struct config_item *item,
+                                          struct configfs_attribute *attr,
+                                          char *buf)
+{
+       ssize_t ret = -EINVAL;
+       struct pcie_gadget_target *target = to_target(item);
+       struct pcie_gadget_target_attr *t_attr =
+               container_of(attr, struct pcie_gadget_target_attr, attr);
+
+       if (t_attr->show)
+               ret = t_attr->show(&target->config, buf);
+       return ret;
+}
+
+static ssize_t pcie_gadget_target_attr_store(struct config_item *item,
+                                       struct configfs_attribute *attr,
+                                       const char *buf,
+                                       size_t count)
+{
+       ssize_t ret = -EINVAL;
+       struct pcie_gadget_target *target = to_target(item);
+       struct pcie_gadget_target_attr *t_attr =
+               container_of(attr, struct pcie_gadget_target_attr, attr);
+
+       if (t_attr->store)
+               ret = t_attr->store(&target->config, buf, count);
+       return ret;
+}
+
+static struct configfs_item_operations pcie_gadget_target_item_ops = {
+       .show_attribute         = pcie_gadget_target_attr_show,
+       .store_attribute        = pcie_gadget_target_attr_store,
+};
+
+static struct config_item_type pcie_gadget_target_type = {
+       .ct_attrs               = pcie_gadget_target_attrs,
+       .ct_item_ops            = &pcie_gadget_target_item_ops,
+       .ct_owner               = THIS_MODULE,
+};
+
+static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config)
+{
+       struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+
+       /*setup registers for outbound translation */
+
+       writel(config->base, &app_reg->in0_mem_addr_start);
+       writel(app_reg->in0_mem_addr_start + IN0_MEM_SIZE,
+                       &app_reg->in0_mem_addr_limit);
+       writel(app_reg->in0_mem_addr_limit + 1, &app_reg->in1_mem_addr_start);
+       writel(app_reg->in1_mem_addr_start + IN1_MEM_SIZE,
+                       &app_reg->in1_mem_addr_limit);
+       writel(app_reg->in1_mem_addr_limit + 1, &app_reg->in_io_addr_start);
+       writel(app_reg->in_io_addr_start + IN_IO_SIZE,
+                       &app_reg->in_io_addr_limit);
+       writel(app_reg->in_io_addr_limit + 1, &app_reg->in_cfg0_addr_start);
+       writel(app_reg->in_cfg0_addr_start + IN_CFG0_SIZE,
+                       &app_reg->in_cfg0_addr_limit);
+       writel(app_reg->in_cfg0_addr_limit + 1, &app_reg->in_cfg1_addr_start);
+       writel(app_reg->in_cfg1_addr_start + IN_CFG1_SIZE,
+                       &app_reg->in_cfg1_addr_limit);
+       writel(app_reg->in_cfg1_addr_limit + 1, &app_reg->in_msg_addr_start);
+       writel(app_reg->in_msg_addr_start + IN_MSG_SIZE,
+                       &app_reg->in_msg_addr_limit);
+
+       writel(app_reg->in0_mem_addr_start, &app_reg->pom0_mem_addr_start);
+       writel(app_reg->in1_mem_addr_start, &app_reg->pom1_mem_addr_start);
+       writel(app_reg->in_io_addr_start, &app_reg->pom_io_addr_start);
+
+       /*setup registers for inbound translation */
+
+       /* Keep AORAM mapped at BAR0 as default */
+       config->bar0_size = INBOUND_ADDR_MASK + 1;
+       spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, INBOUND_ADDR_MASK);
+       spear_dbi_write_reg(config, PCI_BASE_ADDRESS_0, 4, 0xC);
+       config->va_bar0_address = ioremap(SPEAR13XX_SYSRAM1_BASE,
+                       config->bar0_size);
+
+       writel(SPEAR13XX_SYSRAM1_BASE, &app_reg->pim0_mem_addr_start);
+       writel(0, &app_reg->pim1_mem_addr_start);
+       writel(INBOUND_ADDR_MASK + 1, &app_reg->mem0_addr_offset_limit);
+
+       writel(0x0, &app_reg->pim_io_addr_start);
+       writel(0x0, &app_reg->pim_io_addr_start);
+       writel(0x0, &app_reg->pim_rom_addr_start);
+
+       writel(DEVICE_TYPE_EP | (1 << MISCTRL_EN_ID)
+                       | ((u32)1 << REG_TRANSLATION_ENABLE),
+                       &app_reg->app_ctrl_0);
+       /* disable all rx interrupts */
+       writel(0, &app_reg->int_mask);
+
+       /* Select INTA as default*/
+       spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1);
+}
+
+static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev)
+{
+       struct resource *res0, *res1;
+       unsigned int status = 0;
+       int irq;
+       struct clk *clk;
+       static struct pcie_gadget_target *target;
+       struct spear_pcie_gadget_config *config;
+       struct config_item              *cg_item;
+       struct configfs_subsystem *subsys;
+
+       /* get resource for application registers*/
+
+       res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res0) {
+               dev_err(&pdev->dev, "no resource defined\n");
+               return -EBUSY;
+       }
+       if (!request_mem_region(res0->start, resource_size(res0),
+                               pdev->name)) {
+               dev_err(&pdev->dev, "pcie gadget region already claimed\n");
+               return -EBUSY;
+       }
+       /* get resource for dbi registers*/
+
+       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res1) {
+               dev_err(&pdev->dev, "no resource defined\n");
+               goto err_rel_res0;
+       }
+       if (!request_mem_region(res1->start, resource_size(res1),
+                               pdev->name)) {
+               dev_err(&pdev->dev, "pcie gadget region already claimed\n");
+               goto err_rel_res0;
+       }
+
+       target = kzalloc(sizeof(*target), GFP_KERNEL);
+       if (!target) {
+               dev_err(&pdev->dev, "out of memory\n");
+               status = -ENOMEM;
+               goto err_rel_res;
+       }
+
+       cg_item = &target->subsys.su_group.cg_item;
+       sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id);
+       cg_item->ci_type        = &pcie_gadget_target_type;
+       config = &target->config;
+       config->va_app_base = (void __iomem *)ioremap(res0->start,
+                       resource_size(res0));
+       if (!config->va_app_base) {
+               dev_err(&pdev->dev, "ioremap fail\n");
+               status = -ENOMEM;
+               goto err_kzalloc;
+       }
+
+       config->base = (void __iomem *)res1->start;
+
+       config->va_dbi_base = (void __iomem *)ioremap(res1->start,
+                       resource_size(res1));
+       if (!config->va_dbi_base) {
+               dev_err(&pdev->dev, "ioremap fail\n");
+               status = -ENOMEM;
+               goto err_iounmap_app;
+       }
+
+       dev_set_drvdata(&pdev->dev, target);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no update irq?\n");
+               status = irq;
+               goto err_iounmap;
+       }
+
+       status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL);
+       if (status) {
+               dev_err(&pdev->dev, "pcie gadget interrupt IRQ%d already \
+                               claimed\n", irq);
+               goto err_iounmap;
+       }
+
+       /* Register configfs hooks */
+       subsys = &target->subsys;
+       config_group_init(&subsys->su_group);
+       mutex_init(&subsys->su_mutex);
+       status = configfs_register_subsystem(subsys);
+       if (status)
+               goto err_irq;
+
+       /*
+        * init basic pcie application registers
+        * do not enable clock if it is PCIE0.Ideally , all controller should
+        * have been independent from others with respect to clock. But PCIE1
+        * and 2 depends on PCIE0.So PCIE0 clk is provided during board init.
+        */
+       if (pdev->id == 1) {
+               /*
+                * Ideally CFG Clock should have been also enabled here. But
+                * it is done currently during board init routne
+                */
+               clk = clk_get_sys("pcie1", NULL);
+               if (IS_ERR(clk)) {
+                       pr_err("%s:couldn't get clk for pcie1\n", __func__);
+                       goto err_irq;
+               }
+               if (clk_enable(clk)) {
+                       pr_err("%s:couldn't enable clk for pcie1\n", __func__);
+                       goto err_irq;
+               }
+       } else if (pdev->id == 2) {
+               /*
+                * Ideally CFG Clock should have been also enabled here. But
+                * it is done currently during board init routne
+                */
+               clk = clk_get_sys("pcie2", NULL);
+               if (IS_ERR(clk)) {
+                       pr_err("%s:couldn't get clk for pcie2\n", __func__);
+                       goto err_irq;
+               }
+               if (clk_enable(clk)) {
+                       pr_err("%s:couldn't enable clk for pcie2\n", __func__);
+                       goto err_irq;
+               }
+       }
+       spear13xx_pcie_device_init(config);
+
+       return 0;
+err_irq:
+       free_irq(irq, NULL);
+err_iounmap:
+       iounmap(config->va_dbi_base);
+err_iounmap_app:
+       iounmap(config->va_app_base);
+err_kzalloc:
+       kfree(config);
+err_rel_res:
+       release_mem_region(res1->start, resource_size(res1));
+err_rel_res0:
+       release_mem_region(res0->start, resource_size(res0));
+       return status;
+}
+
+static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev)
+{
+       struct resource *res0, *res1;
+       static struct pcie_gadget_target *target;
+       struct spear_pcie_gadget_config *config;
+       int irq;
+
+       res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       irq = platform_get_irq(pdev, 0);
+       target = dev_get_drvdata(&pdev->dev);
+       config = &target->config;
+
+       free_irq(irq, NULL);
+       iounmap(config->va_dbi_base);
+       iounmap(config->va_app_base);
+       release_mem_region(res1->start, resource_size(res1));
+       release_mem_region(res0->start, resource_size(res0));
+       configfs_unregister_subsystem(&target->subsys);
+       kfree(target);
+
+       return 0;
+}
+
+static void spear_pcie_gadget_shutdown(struct platform_device *pdev)
+{
+}
+
+static struct platform_driver spear_pcie_gadget_driver = {
+       .probe = spear_pcie_gadget_probe,
+       .remove = spear_pcie_gadget_remove,
+       .shutdown = spear_pcie_gadget_shutdown,
+       .driver = {
+               .name = "pcie-gadget-spear",
+               .bus = &platform_bus_type
+       },
+};
+
+static int __init spear_pcie_gadget_init(void)
+{
+       return platform_driver_register(&spear_pcie_gadget_driver);
+}
+module_init(spear_pcie_gadget_init);
+
+static void __exit spear_pcie_gadget_exit(void)
+{
+       platform_driver_unregister(&spear_pcie_gadget_driver);
+}
+module_exit(spear_pcie_gadget_exit);
+
+MODULE_ALIAS("pcie-gadget-spear");
+MODULE_AUTHOR("Pratyush Anand");
+MODULE_LICENSE("GPL");
index 2a876c4099cd3d1054e39217424ba85f34772780..3b1f783bf924fccc2168aea37b9a1056d5095dd6 100644 (file)
@@ -58,12 +58,11 @@ config SDIO_UART
 
 config MMC_TEST
        tristate "MMC host test driver"
-       default n
        help
          Development driver that performs a series of reads and writes
          to a memory card in order to expose certain well known bugs
          in host controllers. The tests are executed by writing to the
-         "test" file in sysfs under each card. Note that whatever is
+         "test" file in debugfs under each card. Note that whatever is
          on your card will be overwritten by these tests.
 
          This driver is only of interest to those developing or
index bfc8a8ae55df209458b52e0cb6bfcb1b6f79d989..61d233a7c1180e4b9fea129104ad60f631e60de2 100644 (file)
@@ -621,6 +621,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        md->disk->private_data = md;
        md->disk->queue = md->queue.queue;
        md->disk->driverfs_dev = &card->dev;
+       set_disk_ro(md->disk, md->read_only);
 
        /*
         * As discussed on lkml, GENHD_FL_REMOVABLE should:
index 21adc27f413281ec5e6d6f0e699a1a12f3b4ce9f..5ec8eddfcf6e6e4db69633c71875005c44812688 100644 (file)
@@ -88,6 +88,7 @@ struct mmc_test_area {
  * @sectors: amount of sectors to check in one group
  * @ts: time values of transfer
  * @rate: calculated transfer rate
+ * @iops: I/O operations per second (times 100)
  */
 struct mmc_test_transfer_result {
        struct list_head link;
@@ -95,6 +96,7 @@ struct mmc_test_transfer_result {
        unsigned int sectors;
        struct timespec ts;
        unsigned int rate;
+       unsigned int iops;
 };
 
 /**
@@ -226,9 +228,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
 
                if (!busy && mmc_test_busy(&cmd)) {
                        busy = 1;
-                       printk(KERN_INFO "%s: Warning: Host did not "
-                               "wait for busy state to end.\n",
-                               mmc_hostname(test->card->host));
+                       if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+                               printk(KERN_INFO "%s: Warning: Host did not "
+                                       "wait for busy state to end.\n",
+                                       mmc_hostname(test->card->host));
                }
        } while (mmc_test_busy(&cmd));
 
@@ -494,7 +497,7 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
  */
 static void mmc_test_save_transfer_result(struct mmc_test_card *test,
        unsigned int count, unsigned int sectors, struct timespec ts,
-       unsigned int rate)
+       unsigned int rate, unsigned int iops)
 {
        struct mmc_test_transfer_result *tr;
 
@@ -509,6 +512,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test,
        tr->sectors = sectors;
        tr->ts = ts;
        tr->rate = rate;
+       tr->iops = iops;
 
        list_add_tail(&tr->link, &test->gr->tr_lst);
 }
@@ -519,20 +523,22 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test,
 static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
                                struct timespec *ts1, struct timespec *ts2)
 {
-       unsigned int rate, sectors = bytes >> 9;
+       unsigned int rate, iops, sectors = bytes >> 9;
        struct timespec ts;
 
        ts = timespec_sub(*ts2, *ts1);
 
        rate = mmc_test_rate(bytes, &ts);
+       iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */
 
        printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
-                        "seconds (%u kB/s, %u KiB/s)\n",
+                        "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n",
                         mmc_hostname(test->card->host), sectors, sectors >> 1,
                         (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
-                        (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+                        (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024,
+                        iops / 100, iops % 100);
 
-       mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
+       mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops);
 }
 
 /*
@@ -542,22 +548,24 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
                                    unsigned int count, struct timespec *ts1,
                                    struct timespec *ts2)
 {
-       unsigned int rate, sectors = bytes >> 9;
+       unsigned int rate, iops, sectors = bytes >> 9;
        uint64_t tot = bytes * count;
        struct timespec ts;
 
        ts = timespec_sub(*ts2, *ts1);
 
        rate = mmc_test_rate(tot, &ts);
+       iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */
 
        printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
-                        "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
+                        "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
+                        "%u.%02u IOPS)\n",
                         mmc_hostname(test->card->host), count, sectors, count,
                         sectors >> 1, (sectors & 1 ? ".5" : ""),
                         (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
-                        rate / 1000, rate / 1024);
+                        rate / 1000, rate / 1024, iops / 100, iops % 100);
 
-       mmc_test_save_transfer_result(test, count, sectors, ts, rate);
+       mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
 }
 
 /*
@@ -1425,28 +1433,29 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test)
 }
 
 /*
- * Initialize an area for testing large transfers.  The size of the area is the
- * preferred erase size which is a good size for optimal transfer speed.  Note
- * that is typically 4MiB for modern cards.  The test area is set to the middle
- * of the card because cards may have different charateristics at the front
- * (for FAT file system optimization).  Optionally, the area is erased (if the
- * card supports it) which may improve write performance.  Optionally, the area
- * is filled with data for subsequent read tests.
+ * Initialize an area for testing large transfers.  The test area is set to the
+ * middle of the card because cards may have different charateristics at the
+ * front (for FAT file system optimization).  Optionally, the area is erased
+ * (if the card supports it) which may improve write performance.  Optionally,
+ * the area is filled with data for subsequent read tests.
  */
 static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
 {
        struct mmc_test_area *t = &test->area;
-       unsigned long min_sz = 64 * 1024;
+       unsigned long min_sz = 64 * 1024, sz;
        int ret;
 
        ret = mmc_test_set_blksize(test, 512);
        if (ret)
                return ret;
 
-       if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9)
-               t->max_sz = TEST_AREA_MAX_SIZE;
-       else
-               t->max_sz = (unsigned long)test->card->pref_erase << 9;
+       /* Make the test area size about 4MiB */
+       sz = (unsigned long)test->card->pref_erase << 9;
+       t->max_sz = sz;
+       while (t->max_sz < 4 * 1024 * 1024)
+               t->max_sz += sz;
+       while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz)
+               t->max_sz -= sz;
 
        t->max_segs = test->card->host->max_segs;
        t->max_seg_sz = test->card->host->max_seg_size;
@@ -1766,6 +1775,188 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
        return 0;
 }
 
+static unsigned int rnd_next = 1;
+
+static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
+{
+       uint64_t r;
+
+       rnd_next = rnd_next * 1103515245 + 12345;
+       r = (rnd_next >> 16) & 0x7fff;
+       return (r * rnd_cnt) >> 15;
+}
+
+static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
+                            unsigned long sz)
+{
+       unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea;
+       unsigned int ssz;
+       struct timespec ts1, ts2, ts;
+       int ret;
+
+       ssz = sz >> 9;
+
+       rnd_addr = mmc_test_capacity(test->card) / 4;
+       range1 = rnd_addr / test->card->pref_erase;
+       range2 = range1 / ssz;
+
+       getnstimeofday(&ts1);
+       for (cnt = 0; cnt < UINT_MAX; cnt++) {
+               getnstimeofday(&ts2);
+               ts = timespec_sub(ts2, ts1);
+               if (ts.tv_sec >= 10)
+                       break;
+               ea = mmc_test_rnd_num(range1);
+               if (ea == last_ea)
+                       ea -= 1;
+               last_ea = ea;
+               dev_addr = rnd_addr + test->card->pref_erase * ea +
+                          ssz * mmc_test_rnd_num(range2);
+               ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0);
+               if (ret)
+                       return ret;
+       }
+       if (print)
+               mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+       return 0;
+}
+
+static int mmc_test_random_perf(struct mmc_test_card *test, int write)
+{
+       unsigned int next;
+       unsigned long sz;
+       int ret;
+
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+               /*
+                * When writing, try to get more consistent results by running
+                * the test twice with exactly the same I/O but outputting the
+                * results only for the 2nd run.
+                */
+               if (write) {
+                       next = rnd_next;
+                       ret = mmc_test_rnd_perf(test, write, 0, sz);
+                       if (ret)
+                               return ret;
+                       rnd_next = next;
+               }
+               ret = mmc_test_rnd_perf(test, write, 1, sz);
+               if (ret)
+                       return ret;
+       }
+       sz = test->area.max_tfr;
+       if (write) {
+               next = rnd_next;
+               ret = mmc_test_rnd_perf(test, write, 0, sz);
+               if (ret)
+                       return ret;
+               rnd_next = next;
+       }
+       return mmc_test_rnd_perf(test, write, 1, sz);
+}
+
+/*
+ * Random read performance by transfer size.
+ */
+static int mmc_test_random_read_perf(struct mmc_test_card *test)
+{
+       return mmc_test_random_perf(test, 0);
+}
+
+/*
+ * Random write performance by transfer size.
+ */
+static int mmc_test_random_write_perf(struct mmc_test_card *test)
+{
+       return mmc_test_random_perf(test, 1);
+}
+
+static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
+                            unsigned int tot_sz, int max_scatter)
+{
+       unsigned int dev_addr, i, cnt, sz, ssz;
+       struct timespec ts1, ts2, ts;
+       int ret;
+
+       sz = test->area.max_tfr;
+       /*
+        * In the case of a maximally scattered transfer, the maximum transfer
+        * size is further limited by using PAGE_SIZE segments.
+        */
+       if (max_scatter) {
+               struct mmc_test_area *t = &test->area;
+               unsigned long max_tfr;
+
+               if (t->max_seg_sz >= PAGE_SIZE)
+                       max_tfr = t->max_segs * PAGE_SIZE;
+               else
+                       max_tfr = t->max_segs * t->max_seg_sz;
+               if (sz > max_tfr)
+                       sz = max_tfr;
+       }
+
+       ssz = sz >> 9;
+       dev_addr = mmc_test_capacity(test->card) / 4;
+       if (tot_sz > dev_addr << 9)
+               tot_sz = dev_addr << 9;
+       cnt = tot_sz / sz;
+       dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+
+       getnstimeofday(&ts1);
+       for (i = 0; i < cnt; i++) {
+               ret = mmc_test_area_io(test, sz, dev_addr, write,
+                                      max_scatter, 0);
+               if (ret)
+                       return ret;
+               dev_addr += ssz;
+       }
+       getnstimeofday(&ts2);
+
+       ts = timespec_sub(ts2, ts1);
+       mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+
+       return 0;
+}
+
+static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write)
+{
+       int ret, i;
+
+       for (i = 0; i < 10; i++) {
+               ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1);
+               if (ret)
+                       return ret;
+       }
+       for (i = 0; i < 5; i++) {
+               ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1);
+               if (ret)
+                       return ret;
+       }
+       for (i = 0; i < 3; i++) {
+               ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+/*
+ * Large sequential read performance.
+ */
+static int mmc_test_large_seq_read_perf(struct mmc_test_card *test)
+{
+       return mmc_test_large_seq_perf(test, 0);
+}
+
+/*
+ * Large sequential write performance.
+ */
+static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
+{
+       return mmc_test_large_seq_perf(test, 1);
+}
+
 static const struct mmc_test_case mmc_test_cases[] = {
        {
                .name = "Basic write (no data verification)",
@@ -2005,6 +2196,34 @@ static const struct mmc_test_case mmc_test_cases[] = {
                .cleanup = mmc_test_area_cleanup,
        },
 
+       {
+               .name = "Random read performance by transfer size",
+               .prepare = mmc_test_area_prepare,
+               .run = mmc_test_random_read_perf,
+               .cleanup = mmc_test_area_cleanup,
+       },
+
+       {
+               .name = "Random write performance by transfer size",
+               .prepare = mmc_test_area_prepare,
+               .run = mmc_test_random_write_perf,
+               .cleanup = mmc_test_area_cleanup,
+       },
+
+       {
+               .name = "Large sequential read into scattered pages",
+               .prepare = mmc_test_area_prepare,
+               .run = mmc_test_large_seq_read_perf,
+               .cleanup = mmc_test_area_cleanup,
+       },
+
+       {
+               .name = "Large sequential write from scattered pages",
+               .prepare = mmc_test_area_prepare,
+               .run = mmc_test_large_seq_write_perf,
+               .cleanup = mmc_test_area_cleanup,
+       },
+
 };
 
 static DEFINE_MUTEX(mmc_test_lock);
@@ -2148,11 +2367,11 @@ static int mtf_test_show(struct seq_file *sf, void *data)
                seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
 
                list_for_each_entry(tr, &gr->tr_lst, link) {
-                       seq_printf(sf, "%u %d %lu.%09lu %u\n",
+                       seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n",
                                tr->count, tr->sectors,
                                (unsigned long)tr->ts.tv_sec,
                                (unsigned long)tr->ts.tv_nsec,
-                               tr->rate);
+                               tr->rate, tr->iops / 100, tr->iops % 100);
                }
        }
 
index 4e42d030e09724324e9eb6ec475103dff83a86af..2ae727568df92b9edeaf330ea46751d6e0493474 100644 (file)
@@ -55,8 +55,7 @@ static int mmc_queue_thread(void *d)
 
                spin_lock_irq(q->queue_lock);
                set_current_state(TASK_INTERRUPTIBLE);
-               if (!blk_queue_plugged(q))
-                       req = blk_fetch_request(q);
+               req = blk_fetch_request(q);
                mq->req = req;
                spin_unlock_irq(q->queue_lock);
 
index 86b479119332686192ad73bee576c0fce8f1d0ed..639501970b412c7315c4d516da44aa9bf930a203 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_MMC)               += mmc_core.o
 mmc_core-y                     := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
-                                  sdio_cis.o sdio_io.o sdio_irq.o
+                                  sdio_cis.o sdio_io.o sdio_irq.o \
+                                  quirks.o
 
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
index 150b5f3cd401a7c8549e9e15910a1107b713986e..1f453acc8682b8f828b4f6c9574f2b0f6e1ff7f9 100644 (file)
@@ -167,8 +167,6 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 
        WARN_ON(!host->claimed);
 
-       led_trigger_event(host->led, LED_FULL);
-
        mrq->cmd->error = 0;
        mrq->cmd->mrq = mrq;
        if (mrq->data) {
@@ -194,6 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
                }
        }
        mmc_host_clk_ungate(host);
+       led_trigger_event(host->led, LED_FULL);
        host->ops->request(host, mrq);
 }
 
@@ -528,7 +527,14 @@ int mmc_try_claim_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_try_claim_host);
 
-static void mmc_do_release_host(struct mmc_host *host)
+/**
+ *     mmc_do_release_host - release a claimed host
+ *     @host: mmc host to release
+ *
+ *     If you successfully claimed a host, this function will
+ *     release it again.
+ */
+void mmc_do_release_host(struct mmc_host *host)
 {
        unsigned long flags;
 
@@ -543,6 +549,7 @@ static void mmc_do_release_host(struct mmc_host *host)
                wake_up(&host->wq);
        }
 }
+EXPORT_SYMBOL(mmc_do_release_host);
 
 void mmc_host_deeper_disable(struct work_struct *work)
 {
@@ -1002,6 +1009,13 @@ static void mmc_power_off(struct mmc_host *host)
 {
        host->ios.clock = 0;
        host->ios.vdd = 0;
+
+       /*
+        * Reset ocr mask to be the highest possible voltage supported for
+        * this mmc host. This value will be used at next power up.
+        */
+       host->ocr = 1 << (fls(host->ocr_avail) - 1);
+
        if (!mmc_host_is_spi(host)) {
                host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
                host->ios.chip_select = MMC_CS_DONTCARE;
@@ -1495,6 +1509,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
                mmc_hostname(host), __func__, host->f_init);
 #endif
        mmc_power_up(host);
+
+       /*
+        * sdio_reset sends CMD52 to reset card.  Since we do not know
+        * if the card is being re-initialized, just send it.  CMD52
+        * should be ignored by SD/eMMC cards.
+        */
        sdio_reset(host);
        mmc_go_idle(host);
 
index ca1fdde29df6c9a90f7c1a931588048f5e3425e6..20b1c0831eac8f01e0bd8234d547f37618bd1494 100644 (file)
@@ -61,6 +61,8 @@ int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
 
+void mmc_fixup_device(struct mmc_card *card);
+
 /* Module parameters */
 extern int use_spi_crc;
 
index b3ac6c5bc5c6289b39299e715d0feb01170b22bb..461e6a17fb90e8526d96054f2ec90f44a85e70c3 100644 (file)
@@ -160,10 +160,7 @@ static bool mmc_host_may_gate_card(struct mmc_card *card)
         * gate the clock, because there is somebody out there that may still
         * be using it.
         */
-       if (mmc_card_sdio(card))
-               return false;
-
-       return true;
+       return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
 }
 
 /**
index 16006ef153fe081c2f0f0a09cd4443ce7f3c49a1..14e95f39a7bf3fec3dff6c45048a40c7a67fcd80 100644 (file)
@@ -302,6 +302,44 @@ static int mmc_read_ext_csd(struct mmc_card *card)
        }
 
        if (card->ext_csd.rev >= 4) {
+               /*
+                * Enhanced area feature support -- check whether the eMMC
+                * card has the Enhanced area enabled.  If so, export enhanced
+                * area offset and size to user by adding sysfs interface.
+                */
+               if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
+                               (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
+                       u8 hc_erase_grp_sz =
+                               ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+                       u8 hc_wp_grp_sz =
+                               ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+                       card->ext_csd.enhanced_area_en = 1;
+                       /*
+                        * calculate the enhanced data area offset, in bytes
+                        */
+                       card->ext_csd.enhanced_area_offset =
+                               (ext_csd[139] << 24) + (ext_csd[138] << 16) +
+                               (ext_csd[137] << 8) + ext_csd[136];
+                       if (mmc_card_blockaddr(card))
+                               card->ext_csd.enhanced_area_offset <<= 9;
+                       /*
+                        * calculate the enhanced data area size, in kilobytes
+                        */
+                       card->ext_csd.enhanced_area_size =
+                               (ext_csd[142] << 16) + (ext_csd[141] << 8) +
+                               ext_csd[140];
+                       card->ext_csd.enhanced_area_size *=
+                               (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
+                       card->ext_csd.enhanced_area_size <<= 9;
+               } else {
+                       /*
+                        * If the enhanced area is not enabled, disable these
+                        * device attributes.
+                        */
+                       card->ext_csd.enhanced_area_offset = -EINVAL;
+                       card->ext_csd.enhanced_area_size = -EINVAL;
+               }
                card->ext_csd.sec_trim_mult =
                        ext_csd[EXT_CSD_SEC_TRIM_MULT];
                card->ext_csd.sec_erase_mult =
@@ -336,6 +374,9 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
 MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
 MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
 MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
+MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
+               card->ext_csd.enhanced_area_offset);
+MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
 
 static struct attribute *mmc_std_attrs[] = {
        &dev_attr_cid.attr,
@@ -349,6 +390,8 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_oemid.attr,
        &dev_attr_serial.attr,
+       &dev_attr_enhanced_area_offset.attr,
+       &dev_attr_enhanced_area_size.attr,
        NULL,
 };
 
@@ -378,6 +421,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        int err, ddr = 0;
        u32 cid[4];
        unsigned int max_dtr;
+       u32 rocr;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -391,7 +435,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        mmc_go_idle(host);
 
        /* The extra bit indicates that we support high capacity */
-       err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
+       err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
        if (err)
                goto err;
 
@@ -479,10 +523,50 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                err = mmc_read_ext_csd(card);
                if (err)
                        goto free_card;
+
+               /* If doing byte addressing, check if required to do sector
+                * addressing.  Handle the case of <2GB cards needing sector
+                * addressing.  See section 8.1 JEDEC Standard JED84-A441;
+                * ocr register has bit 30 set for sector addressing.
+                */
+               if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30)))
+                       mmc_card_set_blockaddr(card);
+
                /* Erase size depends on CSD and Extended CSD */
                mmc_set_erase_size(card);
        }
 
+       /*
+        * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
+        * bit.  This bit will be lost everytime after a reset or power off.
+        */
+       if (card->ext_csd.enhanced_area_en) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_ERASE_GROUP_DEF, 1);
+
+               if (err && err != -EBADMSG)
+                       goto free_card;
+
+               if (err) {
+                       err = 0;
+                       /*
+                        * Just disable enhanced area off & sz
+                        * will try to enable ERASE_GROUP_DEF
+                        * during next time reinit
+                        */
+                       card->ext_csd.enhanced_area_offset = -EINVAL;
+                       card->ext_csd.enhanced_area_size = -EINVAL;
+               } else {
+                       card->ext_csd.erase_group_def = 1;
+                       /*
+                        * enable ERASE_GRP_DEF successfully.
+                        * This will affect the erase size, so
+                        * here need to reset erase size
+                        */
+                       mmc_set_erase_size(card);
+               }
+       }
+
        /*
         * Activate high speed (if supported)
         */
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
new file mode 100644 (file)
index 0000000..11118b7
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  This file contains work-arounds for many known sdio hardware
+ *  bugs.
+ *
+ *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
+ *  Inspired from pci fixup code:
+ *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mmc/card.h>
+#include <linux/mod_devicetable.h>
+
+/*
+ *  The world is not perfect and supplies us with broken mmc/sdio devices.
+ *  For at least a part of these bugs we need a work-around
+ */
+
+struct mmc_fixup {
+       u16 vendor, device;     /* You can use SDIO_ANY_ID here of course */
+       void (*vendor_fixup)(struct mmc_card *card, int data);
+       int data;
+};
+
+/*
+ * This hook just adds a quirk unconditionnally
+ */
+static void __maybe_unused add_quirk(struct mmc_card *card, int data)
+{
+       card->quirks |= data;
+}
+
+/*
+ * This hook just removes a quirk unconditionnally
+ */
+static void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+{
+       card->quirks &= ~data;
+}
+
+/*
+ * This hook just adds a quirk for all sdio devices
+ */
+static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
+{
+       if (mmc_card_sdio(card))
+               card->quirks |= data;
+}
+
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI              0x0097
+#endif
+
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271       0x4076
+#endif
+
+static const struct mmc_fixup mmc_fixup_methods[] = {
+       /* by default sdio devices are considered CLK_GATING broken */
+       /* good cards will be whitelisted as they are tested */
+       { SDIO_ANY_ID, SDIO_ANY_ID,
+               add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING },
+       { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+               remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING },
+       { 0 }
+};
+
+void mmc_fixup_device(struct mmc_card *card)
+{
+       const struct mmc_fixup *f;
+
+       for (f = mmc_fixup_methods; f->vendor_fixup; f++) {
+               if ((f->vendor == card->cis.vendor
+                    || f->vendor == (u16) SDIO_ANY_ID) &&
+                   (f->device == card->cis.device
+                    || f->device == (u16) SDIO_ANY_ID)) {
+                       dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
+                       f->vendor_fixup(card, f->data);
+               }
+       }
+}
+EXPORT_SYMBOL(mmc_fixup_device);
index d18c32bca99bae78fe3b0f04d22c2f124ce86cb5..6dac89fe0535ad02b272e5fbe658627d0263fd29 100644 (file)
@@ -21,6 +21,7 @@
 #include "core.h"
 #include "bus.h"
 #include "mmc_ops.h"
+#include "sd.h"
 #include "sd_ops.h"
 
 static const unsigned int tran_exp[] = {
index ebc62ad4cc567b7aee3313835050770dd1ff14f0..db0f0b44d684617b006b7eaa787e07fd0cd1017b 100644 (file)
@@ -395,6 +395,14 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
                if (err)
                        goto remove;
 
+               /*
+                * Update oldcard with the new RCA received from the SDIO
+                * device -- we're doing this so that it's updated in the
+                * "card" struct when oldcard overwrites that later.
+                */
+               if (oldcard)
+                       oldcard->rca = card->rca;
+
                mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
        }
 
@@ -458,6 +466,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 
                card = oldcard;
        }
+       mmc_fixup_device(card);
 
        if (card->type == MMC_TYPE_SD_COMBO) {
                err = mmc_sd_setup_card(host, card, oldcard != NULL);
index 54f91321749a526b07d78ca96739968731386d27..1a21c6427a19769c84cb31018c7d745ea5517164 100644 (file)
@@ -311,7 +311,7 @@ config MMC_MSM
 
 config MMC_MXC
        tristate "Freescale i.MX2/3 Multimedia Card Interface support"
-       depends on ARCH_MXC
+       depends on MACH_MX21 || MACH_MX27 || ARCH_MX31
        help
          This selects the Freescale i.MX2/3 Multimedia card Interface.
          If you have a i.MX platform with a Multimedia Card slot,
@@ -319,6 +319,15 @@ config MMC_MXC
 
          If unsure, say N.
 
+config MMC_MXS
+       tristate "Freescale MXS Multimedia Card Interface support"
+       depends on ARCH_MXS && MXS_DMA
+       help
+         This selects the Freescale SSP MMC controller found on MXS based
+         platforms like mx23/28.
+
+         If unsure, say N.
+
 config MMC_TIFM_SD
        tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
        depends on EXPERIMENTAL && PCI
index e834fb223e9a80f7a84615b2a2a95d26348e808d..30aa6867745f442ddbba5bfe219a5881bd8ef053 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_MMC_ARMMMCI)       += mmci.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
 obj-$(CONFIG_MMC_IMX)          += imxmmc.o
 obj-$(CONFIG_MMC_MXC)          += mxcmmc.o
+obj-$(CONFIG_MMC_MXS)          += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
 obj-$(CONFIG_MMC_SDHCI_PXA)    += sdhci-pxa.o
index ad2a7a032cdf02478a80cd87055abce9648e31ca..80bc9a5c25cc3ef3f6bd7656c03e5d2da00ee0c7 100644 (file)
@@ -578,7 +578,8 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
        struct mmc_data                 *data = host->data;
 
        if (data)
-               dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+               dma_unmap_sg(host->dma.chan->device->dev,
+                            data->sg, data->sg_len,
                             ((data->flags & MMC_DATA_WRITE)
                              ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
 }
@@ -588,7 +589,7 @@ static void atmci_stop_dma(struct atmel_mci *host)
        struct dma_chan *chan = host->data_chan;
 
        if (chan) {
-         chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dmaengine_terminate_all(chan);
                atmci_dma_cleanup(host);
        } else {
                /* Data transfer was stopped by the interrupt handler */
@@ -684,11 +685,11 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
        else
                direction = DMA_TO_DEVICE;
 
-       sglen = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, direction);
-       if (sglen != data->sg_len)
-               goto unmap_exit;
+       sglen = dma_map_sg(chan->device->dev, data->sg,
+                          data->sg_len, direction);
+
        desc = chan->device->device_prep_slave_sg(chan,
-                       data->sg, data->sg_len, direction,
+                       data->sg, sglen, direction,
                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc)
                goto unmap_exit;
@@ -699,7 +700,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
 
        return 0;
 unmap_exit:
-       dma_unmap_sg(&host->pdev->dev, data->sg, sglen, direction);
+       dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
        return -ENOMEM;
 }
 
@@ -709,8 +710,8 @@ static void atmci_submit_data(struct atmel_mci *host)
        struct dma_async_tx_descriptor  *desc = host->dma.data_desc;
 
        if (chan) {
-               desc->tx_submit(desc);
-               chan->device->device_issue_pending(chan);
+               dmaengine_submit(desc);
+               dma_async_issue_pending(chan);
        }
 }
 
index 66b4ce587f4bdb13bf3ff5de67f289f5f3a9d580..ce2a47b71dd6a0fe8b73d5eefb616607d04fe731 100644 (file)
@@ -205,7 +205,7 @@ static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask)
                        "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n",
                        limit, mask, e, x);
 #endif
-       return 0;
+       return err;
 }
 
 static void cb710_mmc_set_transfer_size(struct cb710_slot *slot,
index 2fcc82577c1b156c08102270903b5b28ef2c430f..5a614069cb00b67122d053635897e769972adb0d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
 #include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
 
 #include "dw_mmc.h"
 
@@ -562,7 +563,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
                             SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
 
                /* enable clock */
-               mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE);
+               mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE |
+                          SDMMC_CLKEN_LOW_PWR);
 
                /* inform CIU */
                mci_send_cmd(slot,
@@ -661,6 +663,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       u32 regs;
 
        /* set default 1 bit mode */
        slot->ctype = SDMMC_CTYPE_1BIT;
@@ -672,6 +675,16 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        case MMC_BUS_WIDTH_4:
                slot->ctype = SDMMC_CTYPE_4BIT;
                break;
+       case MMC_BUS_WIDTH_8:
+               slot->ctype = SDMMC_CTYPE_8BIT;
+               break;
+       }
+
+       /* DDR mode set */
+       if (ios->ddr) {
+               regs = mci_readl(slot->host, UHS_REG);
+               regs |= (0x1 << slot->id) << 16;
+               mci_writel(slot->host, UHS_REG, regs);
        }
 
        if (ios->clock) {
@@ -717,7 +730,9 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        struct dw_mci_board *brd = slot->host->pdata;
 
        /* Use platform get_cd function, else try onboard card detect */
-       if (brd->get_cd)
+       if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
+               present = 1;
+       else if (brd->get_cd)
                present = !brd->get_cd(slot->id);
        else
                present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
@@ -1019,13 +1034,10 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
        struct mmc_data *data = host->data;
        int shift = host->data_shift;
        u32 status;
-       unsigned int nbytes = 0, len, old_len, count = 0;
+       unsigned int nbytes = 0, len;
 
        do {
                len = SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift;
-               if (count == 0)
-                       old_len = len;
-
                if (offset + len <= sg->length) {
                        host->pull_data(host, (void *)(buf + offset), len);
 
@@ -1070,7 +1082,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
                        tasklet_schedule(&host->tasklet);
                        return;
                }
-               count++;
        } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
        len = SDMMC_GET_FCNT(mci_readl(host, STATUS));
        host->pio_offset = offset;
@@ -1395,7 +1406,11 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->setpower)
                host->pdata->setpower(id, 0);
 
-       mmc->caps = 0;
+       if (host->pdata->caps)
+               mmc->caps = host->pdata->caps;
+       else
+               mmc->caps = 0;
+
        if (host->pdata->get_bus_wd)
                if (host->pdata->get_bus_wd(slot->id) >= 4)
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
@@ -1426,6 +1441,13 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        }
 #endif /* CONFIG_MMC_DW_IDMAC */
 
+       host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+       if (IS_ERR(host->vmmc)) {
+               printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc));
+               host->vmmc = NULL;
+       } else
+               regulator_enable(host->vmmc);
+
        if (dw_mci_get_cd(mmc))
                set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
        else
@@ -1441,6 +1463,12 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        /* Card initially undetected */
        slot->last_detect_state = 0;
 
+       /*
+        * Card may have been plugged in prior to boot so we
+        * need to run the detect tasklet
+        */
+       tasklet_schedule(&host->card_tasklet);
+
        return 0;
 }
 
@@ -1619,8 +1647,9 @@ static int dw_mci_probe(struct platform_device *pdev)
         */
        fifo_size = mci_readl(host, FIFOTH);
        fifo_size = (fifo_size >> 16) & 0x7ff;
-       mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
-                                 ((fifo_size/2) << 0)));
+       host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+                       ((fifo_size/2) << 0));
+       mci_writel(host, FIFOTH, host->fifoth_val);
 
        /* disable clock to CIU */
        mci_writel(host, CLKENA, 0);
@@ -1683,6 +1712,12 @@ err_dmaunmap:
                          host->sg_cpu, host->sg_dma);
        iounmap(host->regs);
 
+       if (host->vmmc) {
+               regulator_disable(host->vmmc);
+               regulator_put(host->vmmc);
+       }
+
+
 err_freehost:
        kfree(host);
        return ret;
@@ -1714,6 +1749,11 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
 
+       if (host->vmmc) {
+               regulator_disable(host->vmmc);
+               regulator_put(host->vmmc);
+       }
+
        iounmap(host->regs);
 
        kfree(host);
@@ -1729,6 +1769,9 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
+       if (host->vmmc)
+               regulator_enable(host->vmmc);
+
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
                if (!slot)
@@ -1744,6 +1787,9 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
                }
        }
 
+       if (host->vmmc)
+               regulator_disable(host->vmmc);
+
        return 0;
 }
 
@@ -1752,6 +1798,23 @@ static int dw_mci_resume(struct platform_device *pdev)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
+       if (host->dma_ops->init)
+               host->dma_ops->init(host);
+
+       if (!mci_wait_reset(&pdev->dev, host)) {
+               ret = -ENODEV;
+               return ret;
+       }
+
+       /* Restore the old value at FIFOTH register */
+       mci_writel(host, FIFOTH, host->fifoth_val);
+
+       mci_writel(host, RINTSTS, 0xFFFFFFFF);
+       mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
+                  SDMMC_INT_TXDR | SDMMC_INT_RXDR |
+                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
                if (!slot)
index 5dd55a75233d912f9a9be9d6f82de04a76eff93d..23c662af5616f3a741e14e685b43ec5c5dcc66e7 100644 (file)
@@ -43,6 +43,7 @@
 #define SDMMC_USRID            0x068
 #define SDMMC_VERID            0x06c
 #define SDMMC_HCON             0x070
+#define SDMMC_UHS_REG          0x074
 #define SDMMC_BMOD             0x080
 #define SDMMC_PLDMND           0x084
 #define SDMMC_DBADDR           0x088
@@ -51,7 +52,6 @@
 #define SDMMC_DSCADDR          0x094
 #define SDMMC_BUFADDR          0x098
 #define SDMMC_DATA             0x100
-#define SDMMC_DATA_ADR         0x100
 
 /* shift bit field */
 #define _SBF(f, v)             ((v) << (f))
index 97c9b3638d57ea81aef3917c042b0067234fa31b..a4c865a5286b2cde603898fd7e4a669e429855f1 100644 (file)
@@ -267,14 +267,6 @@ msmsdcc_dma_complete_tlet(unsigned long data)
        dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
                     host->dma.dir);
 
-       if (host->curr.user_pages) {
-               struct scatterlist *sg = host->dma.sg;
-               int i;
-
-               for (i = 0; i < host->dma.num_ents; i++)
-                       flush_dcache_page(sg_page(sg++));
-       }
-
        host->dma.sg = NULL;
        host->dma.busy = 0;
 
index 4428594261c52cbc42b5e265e1e26ab52c947820..cc20e025932593db93deb84d3e27f05bf9ed89c0 100644 (file)
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 #include <mach/mmc.h>
 
-#ifdef CONFIG_ARCH_MX2
-#include <mach/dma-mx1-mx2.h>
-#define HAS_DMA
-#endif
+#include <mach/dma.h>
 
 #define DRIVER_NAME "mxc-mmc"
 
@@ -118,7 +116,8 @@ struct mxcmci_host {
        void __iomem            *base;
        int                     irq;
        int                     detect_irq;
-       int                     dma;
+       struct dma_chan         *dma;
+       struct dma_async_tx_descriptor *desc;
        int                     do_dma;
        int                     default_irq_mask;
        int                     use_sdio;
@@ -129,7 +128,6 @@ struct mxcmci_host {
        struct mmc_command      *cmd;
        struct mmc_data         *data;
 
-       unsigned int            dma_nents;
        unsigned int            datasize;
        unsigned int            dma_dir;
 
@@ -144,6 +142,11 @@ struct mxcmci_host {
        spinlock_t              lock;
 
        struct regulator        *vcc;
+
+       int                     burstlen;
+       int                     dmareq;
+       struct dma_slave_config dma_slave_config;
+       struct imx_dma_data     dma_data;
 };
 
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -206,17 +209,16 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 
        writew(0xff, host->base + MMC_REG_RES_TO);
 }
+static int mxcmci_setup_dma(struct mmc_host *mmc);
 
 static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 {
        unsigned int nob = data->blocks;
        unsigned int blksz = data->blksz;
        unsigned int datasize = nob * blksz;
-#ifdef HAS_DMA
        struct scatterlist *sg;
-       int i;
-       int ret;
-#endif
+       int i, nents;
+
        if (data->flags & MMC_DATA_STREAM)
                nob = 0xffff;
 
@@ -227,7 +229,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
        writew(blksz, host->base + MMC_REG_BLK_LEN);
        host->datasize = datasize;
 
-#ifdef HAS_DMA
+       if (!mxcmci_use_dma(host))
+               return 0;
+
        for_each_sg(data->sg, sg, data->sg_len, i) {
                if (sg->offset & 3 || sg->length & 3) {
                        host->do_dma = 0;
@@ -235,34 +239,30 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
                }
        }
 
-       if (data->flags & MMC_DATA_READ) {
+       if (data->flags & MMC_DATA_READ)
                host->dma_dir = DMA_FROM_DEVICE;
-               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                            data->sg_len,  host->dma_dir);
-
-               ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
-                               datasize,
-                               host->res->start + MMC_REG_BUFFER_ACCESS,
-                               DMA_MODE_READ);
-       } else {
+       else
                host->dma_dir = DMA_TO_DEVICE;
-               host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                            data->sg_len,  host->dma_dir);
 
-               ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents,
-                               datasize,
-                               host->res->start + MMC_REG_BUFFER_ACCESS,
-                               DMA_MODE_WRITE);
-       }
+       nents = dma_map_sg(host->dma->device->dev, data->sg,
+                                    data->sg_len,  host->dma_dir);
+       if (nents != data->sg_len)
+               return -EINVAL;
+
+       host->desc = host->dma->device->device_prep_slave_sg(host->dma,
+               data->sg, data->sg_len, host->dma_dir,
+               DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
-       if (ret) {
-               dev_err(mmc_dev(host->mmc), "failed to setup DMA : %d\n", ret);
-               return ret;
+       if (!host->desc) {
+               dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
+                               host->dma_dir);
+               host->do_dma = 0;
+               return 0; /* Fall back to PIO */
        }
        wmb();
 
-       imx_dma_enable(host->dma);
-#endif /* HAS_DMA */
+       dmaengine_submit(host->desc);
+
        return 0;
 }
 
@@ -337,13 +337,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
        struct mmc_data *data = host->data;
        int data_error;
 
-#ifdef HAS_DMA
        if (mxcmci_use_dma(host)) {
-               imx_dma_disable(host->dma);
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
+               dmaengine_terminate_all(host->dma);
+               dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
                                host->dma_dir);
        }
-#endif
 
        if (stat & STATUS_ERR_MASK) {
                dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
@@ -545,7 +543,6 @@ static void mxcmci_datawork(struct work_struct *work)
        }
 }
 
-#ifdef HAS_DMA
 static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
 {
        struct mmc_data *data = host->data;
@@ -568,7 +565,6 @@ static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
                mxcmci_finish_request(host, host->req);
        }
 }
-#endif /* HAS_DMA */
 
 static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
 {
@@ -606,12 +602,10 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
        sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
        spin_unlock_irqrestore(&host->lock, flags);
 
-#ifdef HAS_DMA
        if (mxcmci_use_dma(host) &&
            (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
                writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
                        host->base + MMC_REG_STATUS);
-#endif
 
        if (sdio_irq) {
                writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
@@ -621,14 +615,14 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
        if (stat & STATUS_END_CMD_RESP)
                mxcmci_cmd_done(host, stat);
 
-#ifdef HAS_DMA
        if (mxcmci_use_dma(host) &&
                  (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
                mxcmci_data_done(host, stat);
-#endif
+
        if (host->default_irq_mask &&
                  (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
                mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+
        return IRQ_HANDLED;
 }
 
@@ -642,9 +636,10 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
 
        host->req = req;
        host->cmdat &= ~CMD_DAT_CONT_INIT;
-#ifdef HAS_DMA
-       host->do_dma = 1;
-#endif
+
+       if (host->dma)
+               host->do_dma = 1;
+
        if (req->data) {
                error = mxcmci_setup_data(host, req->data);
                if (error) {
@@ -660,6 +655,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
        }
 
        error = mxcmci_start_cmd(host, req->cmd, cmdat);
+
 out:
        if (error)
                mxcmci_finish_request(host, req);
@@ -698,22 +694,46 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
                        prescaler, divider, clk_in, clk_ios);
 }
 
+static int mxcmci_setup_dma(struct mmc_host *mmc)
+{
+       struct mxcmci_host *host = mmc_priv(mmc);
+       struct dma_slave_config *config = &host->dma_slave_config;
+
+       config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
+       config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
+       config->dst_addr_width = 4;
+       config->src_addr_width = 4;
+       config->dst_maxburst = host->burstlen;
+       config->src_maxburst = host->burstlen;
+
+       return dmaengine_slave_config(host->dma, config);
+}
+
 static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct mxcmci_host *host = mmc_priv(mmc);
-#ifdef HAS_DMA
-       unsigned int blen;
+       int burstlen, ret;
+
        /*
         * use burstlen of 64 in 4 bit mode (--> reg value  0)
         * use burstlen of 16 in 1 bit mode (--> reg value 16)
         */
        if (ios->bus_width == MMC_BUS_WIDTH_4)
-               blen = 0;
+               burstlen = 64;
        else
-               blen = 16;
+               burstlen = 16;
+
+       if (mxcmci_use_dma(host) && burstlen != host->burstlen) {
+               host->burstlen = burstlen;
+               ret = mxcmci_setup_dma(mmc);
+               if (ret) {
+                       dev_err(mmc_dev(host->mmc),
+                               "failed to config DMA channel. Falling back to PIO\n");
+                       dma_release_channel(host->dma);
+                       host->do_dma = 0;
+               }
+       }
 
-       imx_dma_config_burstlen(host->dma, blen);
-#endif
        if (ios->bus_width == MMC_BUS_WIDTH_4)
                host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
        else
@@ -794,6 +814,18 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card)
                host->caps |= MMC_CAP_4_BIT_DATA;
 }
 
+static bool filter(struct dma_chan *chan, void *param)
+{
+       struct mxcmci_host *host = param;
+
+       if (!imx_dma_is_general_purpose(chan))
+               return false;
+
+       chan->private = &host->dma_data;
+
+       return true;
+}
+
 static const struct mmc_host_ops mxcmci_ops = {
        .request                = mxcmci_request,
        .set_ios                = mxcmci_set_ios,
@@ -808,6 +840,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        struct mxcmci_host *host = NULL;
        struct resource *iores, *r;
        int ret = 0, irq;
+       dma_cap_mask_t mask;
 
        printk(KERN_INFO "i.MX SDHC driver\n");
 
@@ -883,29 +916,23 @@ static int mxcmci_probe(struct platform_device *pdev)
 
        writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
 
-#ifdef HAS_DMA
-       host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
-       if (host->dma < 0) {
-               dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
-               ret = -EBUSY;
-               goto out_clk_put;
-       }
-
        r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!r) {
-               ret = -EINVAL;
-               goto out_free_dma;
+       if (r) {
+               host->dmareq = r->start;
+               host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
+               host->dma_data.priority = DMA_PRIO_LOW;
+               host->dma_data.dma_request = host->dmareq;
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               host->dma = dma_request_channel(mask, filter, host);
+               if (host->dma)
+                       mmc->max_seg_size = dma_get_max_seg_size(
+                                       host->dma->device->dev);
        }
 
-       ret = imx_dma_config_channel(host->dma,
-                                    IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
-                                    IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-                                    r->start, 0);
-       if (ret) {
-               dev_err(mmc_dev(host->mmc), "failed to config DMA channel\n");
-               goto out_free_dma;
-       }
-#endif
+       if (!host->dma)
+               dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n");
+
        INIT_WORK(&host->datawork, mxcmci_datawork);
 
        ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host);
@@ -928,9 +955,8 @@ static int mxcmci_probe(struct platform_device *pdev)
 out_free_irq:
        free_irq(host->irq, host);
 out_free_dma:
-#ifdef HAS_DMA
-       imx_dma_free(host->dma);
-#endif
+       if (host->dma)
+               dma_release_channel(host->dma);
 out_clk_put:
        clk_disable(host->clk);
        clk_put(host->clk);
@@ -960,9 +986,10 @@ static int mxcmci_remove(struct platform_device *pdev)
 
        free_irq(host->irq, host);
        iounmap(host->base);
-#ifdef HAS_DMA
-       imx_dma_free(host->dma);
-#endif
+
+       if (host->dma)
+               dma_release_channel(host->dma);
+
        clk_disable(host->clk);
        clk_put(host->clk);
 
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
new file mode 100644 (file)
index 0000000..99d39a6
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * Portions copyright (C) 2003 Russell King, PXA MMCI Driver
+ * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver
+ *
+ * Copyright 2008 Embedded Alley Solutions, Inc.
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/highmem.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/mxs.h>
+#include <mach/common.h>
+#include <mach/dma.h>
+#include <mach/mmc.h>
+
+#define DRIVER_NAME    "mxs-mmc"
+
+/* card detect polling timeout */
+#define MXS_MMC_DETECT_TIMEOUT                 (HZ/2)
+
+#define SSP_VERSION_LATEST     4
+#define ssp_is_old()           (host->version < SSP_VERSION_LATEST)
+
+/* SSP registers */
+#define HW_SSP_CTRL0                           0x000
+#define  BM_SSP_CTRL0_RUN                      (1 << 29)
+#define  BM_SSP_CTRL0_SDIO_IRQ_CHECK           (1 << 28)
+#define  BM_SSP_CTRL0_IGNORE_CRC               (1 << 26)
+#define  BM_SSP_CTRL0_READ                     (1 << 25)
+#define  BM_SSP_CTRL0_DATA_XFER                        (1 << 24)
+#define  BP_SSP_CTRL0_BUS_WIDTH                        (22)
+#define  BM_SSP_CTRL0_BUS_WIDTH                        (0x3 << 22)
+#define  BM_SSP_CTRL0_WAIT_FOR_IRQ             (1 << 21)
+#define  BM_SSP_CTRL0_LONG_RESP                        (1 << 19)
+#define  BM_SSP_CTRL0_GET_RESP                 (1 << 17)
+#define  BM_SSP_CTRL0_ENABLE                   (1 << 16)
+#define  BP_SSP_CTRL0_XFER_COUNT               (0)
+#define  BM_SSP_CTRL0_XFER_COUNT               (0xffff)
+#define HW_SSP_CMD0                            0x010
+#define  BM_SSP_CMD0_DBL_DATA_RATE_EN          (1 << 25)
+#define  BM_SSP_CMD0_SLOW_CLKING_EN            (1 << 22)
+#define  BM_SSP_CMD0_CONT_CLKING_EN            (1 << 21)
+#define  BM_SSP_CMD0_APPEND_8CYC               (1 << 20)
+#define  BP_SSP_CMD0_BLOCK_SIZE                        (16)
+#define  BM_SSP_CMD0_BLOCK_SIZE                        (0xf << 16)
+#define  BP_SSP_CMD0_BLOCK_COUNT               (8)
+#define  BM_SSP_CMD0_BLOCK_COUNT               (0xff << 8)
+#define  BP_SSP_CMD0_CMD                       (0)
+#define  BM_SSP_CMD0_CMD                       (0xff)
+#define HW_SSP_CMD1                            0x020
+#define HW_SSP_XFER_SIZE                       0x030
+#define HW_SSP_BLOCK_SIZE                      0x040
+#define  BP_SSP_BLOCK_SIZE_BLOCK_COUNT         (4)
+#define  BM_SSP_BLOCK_SIZE_BLOCK_COUNT         (0xffffff << 4)
+#define  BP_SSP_BLOCK_SIZE_BLOCK_SIZE          (0)
+#define  BM_SSP_BLOCK_SIZE_BLOCK_SIZE          (0xf)
+#define HW_SSP_TIMING                          (ssp_is_old() ? 0x050 : 0x070)
+#define  BP_SSP_TIMING_TIMEOUT                 (16)
+#define  BM_SSP_TIMING_TIMEOUT                 (0xffff << 16)
+#define  BP_SSP_TIMING_CLOCK_DIVIDE            (8)
+#define  BM_SSP_TIMING_CLOCK_DIVIDE            (0xff << 8)
+#define  BP_SSP_TIMING_CLOCK_RATE              (0)
+#define  BM_SSP_TIMING_CLOCK_RATE              (0xff)
+#define HW_SSP_CTRL1                           (ssp_is_old() ? 0x060 : 0x080)
+#define  BM_SSP_CTRL1_SDIO_IRQ                 (1 << 31)
+#define  BM_SSP_CTRL1_SDIO_IRQ_EN              (1 << 30)
+#define  BM_SSP_CTRL1_RESP_ERR_IRQ             (1 << 29)
+#define  BM_SSP_CTRL1_RESP_ERR_IRQ_EN          (1 << 28)
+#define  BM_SSP_CTRL1_RESP_TIMEOUT_IRQ         (1 << 27)
+#define  BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN      (1 << 26)
+#define  BM_SSP_CTRL1_DATA_TIMEOUT_IRQ         (1 << 25)
+#define  BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN      (1 << 24)
+#define  BM_SSP_CTRL1_DATA_CRC_IRQ             (1 << 23)
+#define  BM_SSP_CTRL1_DATA_CRC_IRQ_EN          (1 << 22)
+#define  BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ                (1 << 21)
+#define  BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN     (1 << 20)
+#define  BM_SSP_CTRL1_RECV_TIMEOUT_IRQ         (1 << 17)
+#define  BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN      (1 << 16)
+#define  BM_SSP_CTRL1_FIFO_OVERRUN_IRQ         (1 << 15)
+#define  BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN      (1 << 14)
+#define  BM_SSP_CTRL1_DMA_ENABLE               (1 << 13)
+#define  BM_SSP_CTRL1_POLARITY                 (1 << 9)
+#define  BP_SSP_CTRL1_WORD_LENGTH              (4)
+#define  BM_SSP_CTRL1_WORD_LENGTH              (0xf << 4)
+#define  BP_SSP_CTRL1_SSP_MODE                 (0)
+#define  BM_SSP_CTRL1_SSP_MODE                 (0xf)
+#define HW_SSP_SDRESP0                         (ssp_is_old() ? 0x080 : 0x0a0)
+#define HW_SSP_SDRESP1                         (ssp_is_old() ? 0x090 : 0x0b0)
+#define HW_SSP_SDRESP2                         (ssp_is_old() ? 0x0a0 : 0x0c0)
+#define HW_SSP_SDRESP3                         (ssp_is_old() ? 0x0b0 : 0x0d0)
+#define HW_SSP_STATUS                          (ssp_is_old() ? 0x0c0 : 0x100)
+#define  BM_SSP_STATUS_CARD_DETECT             (1 << 28)
+#define  BM_SSP_STATUS_SDIO_IRQ                        (1 << 17)
+#define HW_SSP_VERSION                         (cpu_is_mx23() ? 0x110 : 0x130)
+#define  BP_SSP_VERSION_MAJOR                  (24)
+
+#define BF_SSP(value, field)   (((value) << BP_SSP_##field) & BM_SSP_##field)
+
+#define MXS_MMC_IRQ_BITS       (BM_SSP_CTRL1_SDIO_IRQ          | \
+                                BM_SSP_CTRL1_RESP_ERR_IRQ      | \
+                                BM_SSP_CTRL1_RESP_TIMEOUT_IRQ  | \
+                                BM_SSP_CTRL1_DATA_TIMEOUT_IRQ  | \
+                                BM_SSP_CTRL1_DATA_CRC_IRQ      | \
+                                BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \
+                                BM_SSP_CTRL1_RECV_TIMEOUT_IRQ  | \
+                                BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
+
+#define SSP_PIO_NUM    3
+
+struct mxs_mmc_host {
+       struct mmc_host                 *mmc;
+       struct mmc_request              *mrq;
+       struct mmc_command              *cmd;
+       struct mmc_data                 *data;
+
+       void __iomem                    *base;
+       int                             irq;
+       struct resource                 *res;
+       struct resource                 *dma_res;
+       struct clk                      *clk;
+       unsigned int                    clk_rate;
+
+       struct dma_chan                 *dmach;
+       struct mxs_dma_data             dma_data;
+       unsigned int                    dma_dir;
+       u32                             ssp_pio_words[SSP_PIO_NUM];
+
+       unsigned int                    version;
+       unsigned char                   bus_width;
+       spinlock_t                      lock;
+       int                             sdio_irq_en;
+};
+
+static int mxs_mmc_get_ro(struct mmc_host *mmc)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       struct mxs_mmc_platform_data *pdata =
+               mmc_dev(host->mmc)->platform_data;
+
+       if (!pdata)
+               return -EFAULT;
+
+       if (!gpio_is_valid(pdata->wp_gpio))
+               return -EINVAL;
+
+       return gpio_get_value(pdata->wp_gpio);
+}
+
+static int mxs_mmc_get_cd(struct mmc_host *mmc)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+
+       return !(readl(host->base + HW_SSP_STATUS) &
+                BM_SSP_STATUS_CARD_DETECT);
+}
+
+static void mxs_mmc_reset(struct mxs_mmc_host *host)
+{
+       u32 ctrl0, ctrl1;
+
+       mxs_reset_block(host->base);
+
+       ctrl0 = BM_SSP_CTRL0_IGNORE_CRC;
+       ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) |
+               BF_SSP(0x7, CTRL1_WORD_LENGTH) |
+               BM_SSP_CTRL1_DMA_ENABLE |
+               BM_SSP_CTRL1_POLARITY |
+               BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
+               BM_SSP_CTRL1_DATA_CRC_IRQ_EN |
+               BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
+               BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
+               BM_SSP_CTRL1_RESP_ERR_IRQ_EN;
+
+       writel(BF_SSP(0xffff, TIMING_TIMEOUT) |
+              BF_SSP(2, TIMING_CLOCK_DIVIDE) |
+              BF_SSP(0, TIMING_CLOCK_RATE),
+              host->base + HW_SSP_TIMING);
+
+       if (host->sdio_irq_en) {
+               ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
+               ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN;
+       }
+
+       writel(ctrl0, host->base + HW_SSP_CTRL0);
+       writel(ctrl1, host->base + HW_SSP_CTRL1);
+}
+
+static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
+                             struct mmc_command *cmd);
+
+static void mxs_mmc_request_done(struct mxs_mmc_host *host)
+{
+       struct mmc_command *cmd = host->cmd;
+       struct mmc_data *data = host->data;
+       struct mmc_request *mrq = host->mrq;
+
+       if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) {
+               if (mmc_resp_type(cmd) & MMC_RSP_136) {
+                       cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0);
+                       cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1);
+                       cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2);
+                       cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3);
+               } else {
+                       cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0);
+               }
+       }
+
+       if (data) {
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+                            data->sg_len, host->dma_dir);
+               /*
+                * If there was an error on any block, we mark all
+                * data blocks as being in error.
+                */
+               if (!data->error)
+                       data->bytes_xfered = data->blocks * data->blksz;
+               else
+                       data->bytes_xfered = 0;
+
+               host->data = NULL;
+               if (mrq->stop) {
+                       mxs_mmc_start_cmd(host, mrq->stop);
+                       return;
+               }
+       }
+
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
+static void mxs_mmc_dma_irq_callback(void *param)
+{
+       struct mxs_mmc_host *host = param;
+
+       mxs_mmc_request_done(host);
+}
+
+static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
+{
+       struct mxs_mmc_host *host = dev_id;
+       struct mmc_command *cmd = host->cmd;
+       struct mmc_data *data = host->data;
+       u32 stat;
+
+       spin_lock(&host->lock);
+
+       stat = readl(host->base + HW_SSP_CTRL1);
+       writel(stat & MXS_MMC_IRQ_BITS,
+              host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR);
+
+       if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN))
+               mmc_signal_sdio_irq(host->mmc);
+
+       spin_unlock(&host->lock);
+
+       if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ)
+               cmd->error = -ETIMEDOUT;
+       else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ)
+               cmd->error = -EIO;
+
+       if (data) {
+               if (stat & (BM_SSP_CTRL1_DATA_TIMEOUT_IRQ |
+                           BM_SSP_CTRL1_RECV_TIMEOUT_IRQ))
+                       data->error = -ETIMEDOUT;
+               else if (stat & BM_SSP_CTRL1_DATA_CRC_IRQ)
+                       data->error = -EILSEQ;
+               else if (stat & (BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ |
+                                BM_SSP_CTRL1_FIFO_OVERRUN_IRQ))
+                       data->error = -EIO;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
+       struct mxs_mmc_host *host, unsigned int append)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct mmc_data *data = host->data;
+       struct scatterlist * sgl;
+       unsigned int sg_len;
+
+       if (data) {
+               /* data */
+               dma_map_sg(mmc_dev(host->mmc), data->sg,
+                          data->sg_len, host->dma_dir);
+               sgl = data->sg;
+               sg_len = data->sg_len;
+       } else {
+               /* pio */
+               sgl = (struct scatterlist *) host->ssp_pio_words;
+               sg_len = SSP_PIO_NUM;
+       }
+
+       desc = host->dmach->device->device_prep_slave_sg(host->dmach,
+                               sgl, sg_len, host->dma_dir, append);
+       if (desc) {
+               desc->callback = mxs_mmc_dma_irq_callback;
+               desc->callback_param = host;
+       } else {
+               if (data)
+                       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+                                    data->sg_len, host->dma_dir);
+       }
+
+       return desc;
+}
+
+static void mxs_mmc_bc(struct mxs_mmc_host *host)
+{
+       struct mmc_command *cmd = host->cmd;
+       struct dma_async_tx_descriptor *desc;
+       u32 ctrl0, cmd0, cmd1;
+
+       ctrl0 = BM_SSP_CTRL0_ENABLE | BM_SSP_CTRL0_IGNORE_CRC;
+       cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC;
+       cmd1 = cmd->arg;
+
+       if (host->sdio_irq_en) {
+               ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
+               cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
+       }
+
+       host->ssp_pio_words[0] = ctrl0;
+       host->ssp_pio_words[1] = cmd0;
+       host->ssp_pio_words[2] = cmd1;
+       host->dma_dir = DMA_NONE;
+       desc = mxs_mmc_prep_dma(host, 0);
+       if (!desc)
+               goto out;
+
+       dmaengine_submit(desc);
+       return;
+
+out:
+       dev_warn(mmc_dev(host->mmc),
+                "%s: failed to prep dma\n", __func__);
+}
+
+static void mxs_mmc_ac(struct mxs_mmc_host *host)
+{
+       struct mmc_command *cmd = host->cmd;
+       struct dma_async_tx_descriptor *desc;
+       u32 ignore_crc, get_resp, long_resp;
+       u32 ctrl0, cmd0, cmd1;
+
+       ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ?
+                       0 : BM_SSP_CTRL0_IGNORE_CRC;
+       get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ?
+                       BM_SSP_CTRL0_GET_RESP : 0;
+       long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ?
+                       BM_SSP_CTRL0_LONG_RESP : 0;
+
+       ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp;
+       cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
+       cmd1 = cmd->arg;
+
+       if (host->sdio_irq_en) {
+               ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
+               cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
+       }
+
+       host->ssp_pio_words[0] = ctrl0;
+       host->ssp_pio_words[1] = cmd0;
+       host->ssp_pio_words[2] = cmd1;
+       host->dma_dir = DMA_NONE;
+       desc = mxs_mmc_prep_dma(host, 0);
+       if (!desc)
+               goto out;
+
+       dmaengine_submit(desc);
+       return;
+
+out:
+       dev_warn(mmc_dev(host->mmc),
+                "%s: failed to prep dma\n", __func__);
+}
+
+static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns)
+{
+       const unsigned int ssp_timeout_mul = 4096;
+       /*
+        * Calculate ticks in ms since ns are large numbers
+        * and might overflow
+        */
+       const unsigned int clock_per_ms = clock_rate / 1000;
+       const unsigned int ms = ns / 1000;
+       const unsigned int ticks = ms * clock_per_ms;
+       const unsigned int ssp_ticks = ticks / ssp_timeout_mul;
+
+       WARN_ON(ssp_ticks == 0);
+       return ssp_ticks;
+}
+
+static void mxs_mmc_adtc(struct mxs_mmc_host *host)
+{
+       struct mmc_command *cmd = host->cmd;
+       struct mmc_data *data = cmd->data;
+       struct dma_async_tx_descriptor *desc;
+       struct scatterlist *sgl = data->sg, *sg;
+       unsigned int sg_len = data->sg_len;
+       int i;
+
+       unsigned short dma_data_dir, timeout;
+       unsigned int data_size = 0, log2_blksz;
+       unsigned int blocks = data->blocks;
+
+       u32 ignore_crc, get_resp, long_resp, read;
+       u32 ctrl0, cmd0, cmd1, val;
+
+       ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ?
+                       0 : BM_SSP_CTRL0_IGNORE_CRC;
+       get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ?
+                       BM_SSP_CTRL0_GET_RESP : 0;
+       long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ?
+                       BM_SSP_CTRL0_LONG_RESP : 0;
+
+       if (data->flags & MMC_DATA_WRITE) {
+               dma_data_dir = DMA_TO_DEVICE;
+               read = 0;
+       } else {
+               dma_data_dir = DMA_FROM_DEVICE;
+               read = BM_SSP_CTRL0_READ;
+       }
+
+       ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) |
+               ignore_crc | get_resp | long_resp |
+               BM_SSP_CTRL0_DATA_XFER | read |
+               BM_SSP_CTRL0_WAIT_FOR_IRQ |
+               BM_SSP_CTRL0_ENABLE;
+
+       cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
+
+       /* get logarithm to base 2 of block size for setting register */
+       log2_blksz = ilog2(data->blksz);
+
+       /*
+        * take special care of the case that data size from data->sg
+        * is not equal to blocks x blksz
+        */
+       for_each_sg(sgl, sg, sg_len, i)
+               data_size += sg->length;
+
+       if (data_size != data->blocks * data->blksz)
+               blocks = 1;
+
+       /* xfer count, block size and count need to be set differently */
+       if (ssp_is_old()) {
+               ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT);
+               cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) |
+                       BF_SSP(blocks - 1, CMD0_BLOCK_COUNT);
+       } else {
+               writel(data_size, host->base + HW_SSP_XFER_SIZE);
+               writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) |
+                      BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT),
+                      host->base + HW_SSP_BLOCK_SIZE);
+       }
+
+       if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
+           (cmd->opcode == SD_IO_RW_EXTENDED))
+               cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
+
+       cmd1 = cmd->arg;
+
+       if (host->sdio_irq_en) {
+               ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
+               cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
+       }
+
+       /* set the timeout count */
+       timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns);
+       val = readl(host->base + HW_SSP_TIMING);
+       val &= ~(BM_SSP_TIMING_TIMEOUT);
+       val |= BF_SSP(timeout, TIMING_TIMEOUT);
+       writel(val, host->base + HW_SSP_TIMING);
+
+       /* pio */
+       host->ssp_pio_words[0] = ctrl0;
+       host->ssp_pio_words[1] = cmd0;
+       host->ssp_pio_words[2] = cmd1;
+       host->dma_dir = DMA_NONE;
+       desc = mxs_mmc_prep_dma(host, 0);
+       if (!desc)
+               goto out;
+
+       /* append data sg */
+       WARN_ON(host->data != NULL);
+       host->data = data;
+       host->dma_dir = dma_data_dir;
+       desc = mxs_mmc_prep_dma(host, 1);
+       if (!desc)
+               goto out;
+
+       dmaengine_submit(desc);
+       return;
+out:
+       dev_warn(mmc_dev(host->mmc),
+                "%s: failed to prep dma\n", __func__);
+}
+
+static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
+                             struct mmc_command *cmd)
+{
+       host->cmd = cmd;
+
+       switch (mmc_cmd_type(cmd)) {
+       case MMC_CMD_BC:
+               mxs_mmc_bc(host);
+               break;
+       case MMC_CMD_BCR:
+               mxs_mmc_ac(host);
+               break;
+       case MMC_CMD_AC:
+               mxs_mmc_ac(host);
+               break;
+       case MMC_CMD_ADTC:
+               mxs_mmc_adtc(host);
+               break;
+       default:
+               dev_warn(mmc_dev(host->mmc),
+                        "%s: unknown MMC command\n", __func__);
+               break;
+       }
+}
+
+static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq != NULL);
+       host->mrq = mrq;
+       mxs_mmc_start_cmd(host, mrq->cmd);
+}
+
+static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate)
+{
+       unsigned int ssp_rate, bit_rate;
+       u32 div1, div2;
+       u32 val;
+
+       ssp_rate = clk_get_rate(host->clk);
+
+       for (div1 = 2; div1 < 254; div1 += 2) {
+               div2 = ssp_rate / rate / div1;
+               if (div2 < 0x100)
+                       break;
+       }
+
+       if (div1 >= 254) {
+               dev_err(mmc_dev(host->mmc),
+                       "%s: cannot set clock to %d\n", __func__, rate);
+               return;
+       }
+
+       if (div2 == 0)
+               bit_rate = ssp_rate / div1;
+       else
+               bit_rate = ssp_rate / div1 / div2;
+
+       val = readl(host->base + HW_SSP_TIMING);
+       val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
+       val |= BF_SSP(div1, TIMING_CLOCK_DIVIDE);
+       val |= BF_SSP(div2 - 1, TIMING_CLOCK_RATE);
+       writel(val, host->base + HW_SSP_TIMING);
+
+       host->clk_rate = bit_rate;
+
+       dev_dbg(mmc_dev(host->mmc),
+               "%s: div1 %d, div2 %d, ssp %d, bit %d, rate %d\n",
+               __func__, div1, div2, ssp_rate, bit_rate, rate);
+}
+
+static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+
+       if (ios->bus_width == MMC_BUS_WIDTH_8)
+               host->bus_width = 2;
+       else if (ios->bus_width == MMC_BUS_WIDTH_4)
+               host->bus_width = 1;
+       else
+               host->bus_width = 0;
+
+       if (ios->clock)
+               mxs_mmc_set_clk_rate(host, ios->clock);
+}
+
+static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       host->sdio_irq_en = enable;
+
+       if (enable) {
+               writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
+                      host->base + HW_SSP_CTRL0 + MXS_SET_ADDR);
+               writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
+                      host->base + HW_SSP_CTRL1 + MXS_SET_ADDR);
+
+               if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ)
+                       mmc_signal_sdio_irq(host->mmc);
+
+       } else {
+               writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
+                      host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR);
+               writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
+                      host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR);
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops mxs_mmc_ops = {
+       .request = mxs_mmc_request,
+       .get_ro = mxs_mmc_get_ro,
+       .get_cd = mxs_mmc_get_cd,
+       .set_ios = mxs_mmc_set_ios,
+       .enable_sdio_irq = mxs_mmc_enable_sdio_irq,
+};
+
+static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param)
+{
+       struct mxs_mmc_host *host = param;
+
+       if (!mxs_dma_is_apbh(chan))
+               return false;
+
+       if (chan->chan_id != host->dma_res->start)
+               return false;
+
+       chan->private = &host->dma_data;
+
+       return true;
+}
+
+static int mxs_mmc_probe(struct platform_device *pdev)
+{
+       struct mxs_mmc_host *host;
+       struct mmc_host *mmc;
+       struct resource *iores, *dmares, *r;
+       struct mxs_mmc_platform_data *pdata;
+       int ret = 0, irq_err, irq_dma;
+       dma_cap_mask_t mask;
+
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       irq_err = platform_get_irq(pdev, 0);
+       irq_dma = platform_get_irq(pdev, 1);
+       if (!iores || !dmares || irq_err < 0 || irq_dma < 0)
+               return -EINVAL;
+
+       r = request_mem_region(iores->start, resource_size(iores), pdev->name);
+       if (!r)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto out_release_mem;
+       }
+
+       host = mmc_priv(mmc);
+       host->base = ioremap(r->start, resource_size(r));
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto out_mmc_free;
+       }
+
+       /* only major verion does matter */
+       host->version = readl(host->base + HW_SSP_VERSION) >>
+                       BP_SSP_VERSION_MAJOR;
+
+       host->mmc = mmc;
+       host->res = r;
+       host->dma_res = dmares;
+       host->irq = irq_err;
+       host->sdio_irq_en = 0;
+
+       host->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
+               goto out_iounmap;
+       }
+       clk_enable(host->clk);
+
+       mxs_mmc_reset(host);
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       host->dma_data.chan_irq = irq_dma;
+       host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host);
+       if (!host->dmach) {
+               dev_err(mmc_dev(host->mmc),
+                       "%s: failed to request dma\n", __func__);
+               goto out_clk_put;
+       }
+
+       /* set mmc core parameters */
+       mmc->ops = &mxs_mmc_ops;
+       mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
+                   MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
+
+       pdata = mmc_dev(host->mmc)->platform_data;
+       if (pdata) {
+               if (pdata->flags & SLOTF_8_BIT_CAPABLE)
+                       mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+               if (pdata->flags & SLOTF_4_BIT_CAPABLE)
+                       mmc->caps |= MMC_CAP_4_BIT_DATA;
+       }
+
+       mmc->f_min = 400000;
+       mmc->f_max = 288000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+       mmc->max_segs = 52;
+       mmc->max_blk_size = 1 << 0xf;
+       mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff;
+       mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff;
+       mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev);
+
+       platform_set_drvdata(pdev, mmc);
+
+       ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host);
+       if (ret)
+               goto out_free_dma;
+
+       spin_lock_init(&host->lock);
+
+       ret = mmc_add_host(mmc);
+       if (ret)
+               goto out_free_irq;
+
+       dev_info(mmc_dev(host->mmc), "initialized\n");
+
+       return 0;
+
+out_free_irq:
+       free_irq(host->irq, host);
+out_free_dma:
+       if (host->dmach)
+               dma_release_channel(host->dmach);
+out_clk_put:
+       clk_disable(host->clk);
+       clk_put(host->clk);
+out_iounmap:
+       iounmap(host->base);
+out_mmc_free:
+       mmc_free_host(mmc);
+out_release_mem:
+       release_mem_region(iores->start, resource_size(iores));
+       return ret;
+}
+
+static int mxs_mmc_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       struct resource *res = host->res;
+
+       mmc_remove_host(mmc);
+
+       free_irq(host->irq, host);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (host->dmach)
+               dma_release_channel(host->dmach);
+
+       clk_disable(host->clk);
+       clk_put(host->clk);
+
+       iounmap(host->base);
+
+       mmc_free_host(mmc);
+
+       release_mem_region(res->start, resource_size(res));
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxs_mmc_suspend(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       int ret = 0;
+
+       ret = mmc_suspend_host(mmc);
+
+       clk_disable(host->clk);
+
+       return ret;
+}
+
+static int mxs_mmc_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct mxs_mmc_host *host = mmc_priv(mmc);
+       int ret = 0;
+
+       clk_enable(host->clk);
+
+       ret = mmc_resume_host(mmc);
+
+       return ret;
+}
+
+static const struct dev_pm_ops mxs_mmc_pm_ops = {
+       .suspend        = mxs_mmc_suspend,
+       .resume         = mxs_mmc_resume,
+};
+#endif
+
+static struct platform_driver mxs_mmc_driver = {
+       .probe          = mxs_mmc_probe,
+       .remove         = mxs_mmc_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &mxs_mmc_pm_ops,
+#endif
+       },
+};
+
+static int __init mxs_mmc_init(void)
+{
+       return platform_driver_register(&mxs_mmc_driver);
+}
+
+static void __exit mxs_mmc_exit(void)
+{
+       platform_driver_unregister(&mxs_mmc_driver);
+}
+
+module_init(mxs_mmc_init);
+module_exit(mxs_mmc_exit);
+
+MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_LICENSE("GPL");
index 379d2ffe4c871f66805a92a4f04f113d39dac6b6..2e032f0e8cf47e45730d99e8f9554c688eb756b1 100644 (file)
@@ -1417,7 +1417,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
        if (res == NULL || irq < 0)
                return -ENXIO;
 
-       res = request_mem_region(res->start, res->end - res->start + 1,
+       res = request_mem_region(res->start, resource_size(res),
                                 pdev->name);
        if (res == NULL)
                return -EBUSY;
@@ -1457,7 +1457,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
 
        host->irq = irq;
        host->phys_base = host->mem_res->start;
-       host->virt_base = ioremap(res->start, res->end - res->start + 1);
+       host->virt_base = ioremap(res->start, resource_size(res));
        if (!host->virt_base)
                goto err_ioremap;
 
@@ -1514,7 +1514,7 @@ err_free_mmc_host:
 err_ioremap:
        kfree(host);
 err_free_mem_region:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
index 158c0ee53b2cca163e28d74a66ff64e1152cff2d..259ece047afcd6057bff748f7850d15430ae2136 100644 (file)
@@ -2047,8 +2047,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        res->start += pdata->reg_offset;
        res->end += pdata->reg_offset;
-       res = request_mem_region(res->start, res->end - res->start + 1,
-                                                       pdev->name);
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
        if (res == NULL)
                return -EBUSY;
 
@@ -2287,7 +2286,7 @@ err1:
 err_alloc:
        omap_hsmmc_gpio_free(pdata);
 err:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
@@ -2324,7 +2323,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
-               release_mem_region(res->start, res->end - res->start + 1);
+               release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 9b82910b9dbb3ec01ab07a0ff2f19f6ec59a9ed7..3b5248567973dc794d2cf1c8232317d118f1727a 100644 (file)
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-pltfm.h>
 #include <mach/hardware.h>
+#include <mach/esdhc.h>
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
@@ -30,6 +32,39 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
        writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
 }
 
+static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
+{
+       /* fake CARD_PRESENT flag on mx25/35 */
+       u32 val = readl(host->ioaddr + reg);
+
+       if (unlikely(reg == SDHCI_PRESENT_STATE)) {
+               struct esdhc_platform_data *boarddata =
+                               host->mmc->parent->platform_data;
+
+               if (boarddata && gpio_is_valid(boarddata->cd_gpio)
+                               && gpio_get_value(boarddata->cd_gpio))
+                       /* no card, if a valid gpio says so... */
+                       val &= SDHCI_CARD_PRESENT;
+               else
+                       /* ... in all other cases assume card is present */
+                       val |= SDHCI_CARD_PRESENT;
+       }
+
+       return val;
+}
+
+static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
+{
+       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE))
+               /*
+                * these interrupts won't work with a custom card_detect gpio
+                * (only applied to mx25/35)
+                */
+               val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+       writel(val, host->ioaddr + reg);
+}
+
 static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
 {
        if (unlikely(reg == SDHCI_HOST_VERSION))
@@ -100,10 +135,39 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+               return gpio_get_value(boarddata->wp_gpio);
+       else
+               return -ENOSYS;
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+       .read_w = esdhc_readw_le,
+       .write_w = esdhc_writew_le,
+       .write_b = esdhc_writeb_le,
+       .set_clock = esdhc_set_clock,
+       .get_max_clock = esdhc_pltfm_get_max_clock,
+       .get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+static irqreturn_t cd_irq(int irq, void *data)
+{
+       struct sdhci_host *sdhost = (struct sdhci_host *)data;
+
+       tasklet_schedule(&sdhost->card_tasklet);
+       return IRQ_HANDLED;
+};
+
 static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
        struct clk *clk;
+       int err;
 
        clk = clk_get(mmc_dev(host->mmc), NULL);
        if (IS_ERR(clk)) {
@@ -116,32 +180,78 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
        if (cpu_is_mx35() || cpu_is_mx51())
                host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
-       /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */
-       if (cpu_is_mx25() || cpu_is_mx35())
+       if (cpu_is_mx25() || cpu_is_mx35()) {
+               /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
                host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+               /* write_protect can't be routed to controller, use gpio */
+               sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
+       }
+
+       if (boarddata) {
+               err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+               if (err) {
+                       dev_warn(mmc_dev(host->mmc),
+                               "no write-protect pin available!\n");
+                       boarddata->wp_gpio = err;
+               }
+
+               err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+               if (err) {
+                       dev_warn(mmc_dev(host->mmc),
+                               "no card-detect pin available!\n");
+                       goto no_card_detect_pin;
+               }
+
+               /* i.MX5x has issues to be researched */
+               if (!cpu_is_mx25() && !cpu_is_mx35())
+                       goto not_supported;
+
+               err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+                                IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                                mmc_hostname(host->mmc), host);
+               if (err) {
+                       dev_warn(mmc_dev(host->mmc), "request irq error\n");
+                       goto no_card_detect_irq;
+               }
+
+               sdhci_esdhc_ops.write_l = esdhc_writel_le;
+               sdhci_esdhc_ops.read_l = esdhc_readl_le;
+               /* Now we have a working card_detect again */
+               host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+       }
+
+       return 0;
 
+ no_card_detect_irq:
+       gpio_free(boarddata->cd_gpio);
+ no_card_detect_pin:
+       boarddata->cd_gpio = err;
+ not_supported:
        return 0;
 }
 
 static void esdhc_pltfm_exit(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+               gpio_free(boarddata->wp_gpio);
+
+       if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+               gpio_free(boarddata->cd_gpio);
+
+               if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
+                       free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+       }
 
        clk_disable(pltfm_host->clk);
        clk_put(pltfm_host->clk);
 }
 
-static struct sdhci_ops sdhci_esdhc_ops = {
-       .read_w = esdhc_readw_le,
-       .write_w = esdhc_writew_le,
-       .write_b = esdhc_writeb_le,
-       .set_clock = esdhc_set_clock,
-       .get_max_clock = esdhc_pltfm_get_max_clock,
-       .get_min_clock = esdhc_pltfm_get_min_clock,
-};
-
 struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA,
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+                       | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
        /* ADMA has issues. Might be fixable */
        .ops = &sdhci_esdhc_ops,
        .init = esdhc_pltfm_init,
index afaf1bc4913a3930794a9cae674d79b9da1f88f3..c55aae828aac1eb450657da0dac9eafdfd427d4e 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #define ESDHC_DEFAULT_QUIRKS   (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
-                               SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
                                SDHCI_QUIRK_NO_BUSY_IRQ | \
                                SDHCI_QUIRK_NONSTANDARD_CLOCK | \
                                SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
index fcd0e1fcba44635b450409318b10c30562fc8a42..08161f690ae872320c9799e48774bc5b714eea2a 100644 (file)
@@ -73,7 +73,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 }
 
 struct sdhci_of_data sdhci_esdhc = {
-       .quirks = ESDHC_DEFAULT_QUIRKS,
+       /* card detection could be handled via GPIO */
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
        .ops = {
                .read_l = sdhci_be32bs_readl,
                .read_w = esdhc_readw,
index 0dc905b20eee122543b9365cdecdfe1185307730..2f8d46854acd0fb5430ec22ac15ed439ec3b8710 100644 (file)
@@ -546,6 +546,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_ricoh_mmc,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = 0xe823,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_ricoh_mmc,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_ENE,
                .device         = PCI_DEVICE_ID_ENE_CB712_SD,
@@ -900,9 +908,6 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
 {
        struct sdhci_pci_slot *slot;
        struct sdhci_host *host;
-
-       resource_size_t addr;
-
        int ret;
 
        if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
@@ -949,7 +954,6 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                goto free;
        }
 
-       addr = pci_resource_start(pdev, bar);
        host->ioaddr = pci_ioremap_bar(pdev, bar);
        if (!host->ioaddr) {
                dev_err(&pdev->dev, "failed to remap registers\n");
index 5309ab95aada9a39914300833b1be38f4ec07ad9..69e3ee321eb59ad593290706e091d359e5912db6 100644 (file)
@@ -499,6 +499,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
         * SDHCI block, or a missing configuration that needs to be set. */
        host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
 
+       /* This host supports the Auto CMD12 */
+       host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+
        if (pdata->cd_type == S3C_SDHCI_CD_NONE ||
            pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
index 4823ee94a63fe2f363eb4b40ce4cbf7656cbad81..f7e1f964395fd5bb46264e98c0e474046204293b 100644 (file)
@@ -169,7 +169,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
                if (rc) {
                        dev_err(mmc_dev(host->mmc),
                                "failed to allocate wp gpio\n");
-                       goto out_cd;
+                       goto out_irq;
                }
                tegra_gpio_enable(plat->wp_gpio);
                gpio_direction_input(plat->wp_gpio);
@@ -195,6 +195,9 @@ out_wp:
                gpio_free(plat->wp_gpio);
        }
 
+out_irq:
+       if (gpio_is_valid(plat->cd_gpio))
+               free_irq(gpio_to_irq(plat->cd_gpio), host);
 out_cd:
        if (gpio_is_valid(plat->cd_gpio)) {
                tegra_gpio_disable(plat->cd_gpio);
@@ -225,6 +228,7 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
        }
 
        if (gpio_is_valid(plat->cd_gpio)) {
+               free_irq(gpio_to_irq(plat->cd_gpio), host);
                tegra_gpio_disable(plat->cd_gpio);
                gpio_free(plat->cd_gpio);
        }
index 12884c270171d2e81e5a87c2854e0005cdf085cb..af97015a2fc7f57b216992a2032869f40cbf5e59 100644 (file)
@@ -169,7 +169,7 @@ struct sh_mmcif_host {
        struct dma_chan         *chan_rx;
        struct dma_chan         *chan_tx;
        struct completion       dma_complete;
-       unsigned int            dma_sglen;
+       bool                    dma_active;
 };
 
 static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
@@ -194,10 +194,12 @@ static void mmcif_dma_complete(void *arg)
                return;
 
        if (host->data->flags & MMC_DATA_READ)
-               dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+               dma_unmap_sg(host->chan_rx->device->dev,
+                            host->data->sg, host->data->sg_len,
                             DMA_FROM_DEVICE);
        else
-               dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen,
+               dma_unmap_sg(host->chan_tx->device->dev,
+                            host->data->sg, host->data->sg_len,
                             DMA_TO_DEVICE);
 
        complete(&host->dma_complete);
@@ -211,9 +213,10 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_FROM_DEVICE);
+       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+                        DMA_FROM_DEVICE);
        if (ret > 0) {
-               host->dma_sglen = ret;
+               host->dma_active = true;
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
                        DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        }
@@ -221,14 +224,9 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
        if (desc) {
                desc->callback = mmcif_dma_complete;
                desc->callback_param = host;
-               cookie = desc->tx_submit(desc);
-               if (cookie < 0) {
-                       desc = NULL;
-                       ret = cookie;
-               } else {
-                       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
-                       chan->device->device_issue_pending(chan);
-               }
+               cookie = dmaengine_submit(desc);
+               sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
+               dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
                __func__, host->data->sg_len, ret, cookie);
@@ -238,7 +236,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
                if (ret >= 0)
                        ret = -EIO;
                host->chan_rx = NULL;
-               host->dma_sglen = 0;
+               host->dma_active = false;
                dma_release_channel(chan);
                /* Free the Tx channel too */
                chan = host->chan_tx;
@@ -263,9 +261,10 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_TO_DEVICE);
+       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+                        DMA_TO_DEVICE);
        if (ret > 0) {
-               host->dma_sglen = ret;
+               host->dma_active = true;
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
                        DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        }
@@ -273,14 +272,9 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
        if (desc) {
                desc->callback = mmcif_dma_complete;
                desc->callback_param = host;
-               cookie = desc->tx_submit(desc);
-               if (cookie < 0) {
-                       desc = NULL;
-                       ret = cookie;
-               } else {
-                       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN);
-                       chan->device->device_issue_pending(chan);
-               }
+               cookie = dmaengine_submit(desc);
+               sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN);
+               dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
                __func__, host->data->sg_len, ret, cookie);
@@ -290,7 +284,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
                if (ret >= 0)
                        ret = -EIO;
                host->chan_tx = NULL;
-               host->dma_sglen = 0;
+               host->dma_active = false;
                dma_release_channel(chan);
                /* Free the Rx channel too */
                chan = host->chan_rx;
@@ -317,7 +311,7 @@ static bool sh_mmcif_filter(struct dma_chan *chan, void *arg)
 static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
                                 struct sh_mmcif_plat_data *pdata)
 {
-       host->dma_sglen = 0;
+       host->dma_active = false;
 
        /* We can only either use DMA for both Tx and Rx or not use it at all */
        if (pdata->dma) {
@@ -364,7 +358,7 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
                dma_release_channel(chan);
        }
 
-       host->dma_sglen = 0;
+       host->dma_active = false;
 }
 
 static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
@@ -753,7 +747,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        }
        sh_mmcif_get_response(host, cmd);
        if (host->data) {
-               if (!host->dma_sglen) {
+               if (!host->dma_active) {
                        ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
                } else {
                        long time =
@@ -765,7 +759,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
                                ret = time;
                        sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
                                        BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
-                       host->dma_sglen = 0;
+                       host->dma_active = false;
                }
                if (ret < 0)
                        mrq->data->bytes_xfered = 0;
@@ -850,15 +844,15 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct sh_mmcif_host *host = mmc_priv(mmc);
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
 
-       if (ios->power_mode == MMC_POWER_OFF) {
+       if (ios->power_mode == MMC_POWER_UP) {
+               if (p->set_pwr)
+                       p->set_pwr(host->pd, ios->power_mode);
+       } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* clock stop */
                sh_mmcif_clock_control(host, 0);
-               if (p->down_pwr)
+               if (ios->power_mode == MMC_POWER_OFF && p->down_pwr)
                        p->down_pwr(host->pd);
                return;
-       } else if (ios->power_mode == MMC_POWER_UP) {
-               if (p->set_pwr)
-                       p->set_pwr(host->pd, ios->power_mode);
        }
 
        if (ios->clock)
index e3c6ef20839193462150eadb2cfea55b0234a7d3..ab1adeabdd224f43e78fec6cbe01dfb1c13f4f45 100644 (file)
@@ -152,7 +152,6 @@ struct tmio_mmc_host {
        struct tasklet_struct   dma_complete;
        struct tasklet_struct   dma_issue;
 #ifdef CONFIG_TMIO_MMC_DMA
-       unsigned int            dma_sglen;
        u8                      bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN)));
        struct scatterlist      bounce_sg;
 #endif
@@ -220,44 +219,48 @@ static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
        return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
 }
 
-static void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags)
+static void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt)
 {
-       kunmap_atomic(virt, KM_BIO_SRC_IRQ);
+       kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
        local_irq_restore(*flags);
 }
 
 #ifdef CONFIG_MMC_DEBUG
 
-#define STATUS_TO_TEXT(a) \
+#define STATUS_TO_TEXT(a, status, i) \
        do { \
-               if (status & TMIO_STAT_##a) \
+               if (status & TMIO_STAT_##a) { \
+                       if (i++) \
+                               printk(" | "); \
                        printk(#a); \
+               } \
        } while (0)
 
 void pr_debug_status(u32 status)
 {
+       int i = 0;
        printk(KERN_DEBUG "status: %08x = ", status);
-       STATUS_TO_TEXT(CARD_REMOVE);
-       STATUS_TO_TEXT(CARD_INSERT);
-       STATUS_TO_TEXT(SIGSTATE);
-       STATUS_TO_TEXT(WRPROTECT);
-       STATUS_TO_TEXT(CARD_REMOVE_A);
-       STATUS_TO_TEXT(CARD_INSERT_A);
-       STATUS_TO_TEXT(SIGSTATE_A);
-       STATUS_TO_TEXT(CMD_IDX_ERR);
-       STATUS_TO_TEXT(STOPBIT_ERR);
-       STATUS_TO_TEXT(ILL_FUNC);
-       STATUS_TO_TEXT(CMD_BUSY);
-       STATUS_TO_TEXT(CMDRESPEND);
-       STATUS_TO_TEXT(DATAEND);
-       STATUS_TO_TEXT(CRCFAIL);
-       STATUS_TO_TEXT(DATATIMEOUT);
-       STATUS_TO_TEXT(CMDTIMEOUT);
-       STATUS_TO_TEXT(RXOVERFLOW);
-       STATUS_TO_TEXT(TXUNDERRUN);
-       STATUS_TO_TEXT(RXRDY);
-       STATUS_TO_TEXT(TXRQ);
-       STATUS_TO_TEXT(ILL_ACCESS);
+       STATUS_TO_TEXT(CARD_REMOVE, status, i);
+       STATUS_TO_TEXT(CARD_INSERT, status, i);
+       STATUS_TO_TEXT(SIGSTATE, status, i);
+       STATUS_TO_TEXT(WRPROTECT, status, i);
+       STATUS_TO_TEXT(CARD_REMOVE_A, status, i);
+       STATUS_TO_TEXT(CARD_INSERT_A, status, i);
+       STATUS_TO_TEXT(SIGSTATE_A, status, i);
+       STATUS_TO_TEXT(CMD_IDX_ERR, status, i);
+       STATUS_TO_TEXT(STOPBIT_ERR, status, i);
+       STATUS_TO_TEXT(ILL_FUNC, status, i);
+       STATUS_TO_TEXT(CMD_BUSY, status, i);
+       STATUS_TO_TEXT(CMDRESPEND, status, i);
+       STATUS_TO_TEXT(DATAEND, status, i);
+       STATUS_TO_TEXT(CRCFAIL, status, i);
+       STATUS_TO_TEXT(DATATIMEOUT, status, i);
+       STATUS_TO_TEXT(CMDTIMEOUT, status, i);
+       STATUS_TO_TEXT(RXOVERFLOW, status, i);
+       STATUS_TO_TEXT(TXUNDERRUN, status, i);
+       STATUS_TO_TEXT(RXRDY, status, i);
+       STATUS_TO_TEXT(TXRQ, status, i);
+       STATUS_TO_TEXT(ILL_ACCESS, status, i);
        printk("\n");
 }
 
@@ -300,8 +303,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
 
 static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
 {
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
 
        /*
         * Testing on sh-mobile showed that SDIO IRQs are unmasked when
@@ -324,8 +326,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
 
 static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
 {
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
 
        sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
                sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@@ -507,7 +508,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
 
        host->sg_off += count;
 
-       tmio_mmc_kunmap_atomic(sg_virt, &flags);
+       tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
 
        if (host->sg_off == host->sg_ptr->length)
                tmio_mmc_next_sg(host);
@@ -666,8 +667,7 @@ out:
 static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 {
        struct tmio_mmc_host *host = devid;
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
        unsigned int ireg, irq_mask, status;
        unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
 
@@ -767,7 +767,7 @@ static void tmio_check_bounce_buffer(struct tmio_mmc_host *host)
                unsigned long flags;
                void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
                memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
-               tmio_mmc_kunmap_atomic(sg_vaddr, &flags);
+               tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
        }
 }
 
@@ -796,8 +796,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_rx;
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
        dma_cookie_t cookie;
        int ret, i;
        bool aligned = true, multiple = true;
@@ -825,23 +824,16 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
                sg = host->sg_ptr;
        }
 
-       ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE);
-       if (ret > 0) {
-               host->dma_sglen = ret;
+       ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
+       if (ret > 0)
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
                        DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       }
 
        if (desc) {
                desc->callback = tmio_dma_complete;
                desc->callback_param = host;
-               cookie = desc->tx_submit(desc);
-               if (cookie < 0) {
-                       desc = NULL;
-                       ret = cookie;
-               } else {
-                       chan->device->device_issue_pending(chan);
-               }
+               cookie = dmaengine_submit(desc);
+               dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
                __func__, host->sg_len, ret, cookie, host->mrq);
@@ -873,8 +865,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
        struct scatterlist *sg = host->sg_ptr, *sg_tmp;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_tx;
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
        dma_cookie_t cookie;
        int ret, i;
        bool aligned = true, multiple = true;
@@ -901,26 +892,20 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
                void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
                sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
                memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
-               tmio_mmc_kunmap_atomic(sg_vaddr, &flags);
+               tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
                host->sg_ptr = &host->bounce_sg;
                sg = host->sg_ptr;
        }
 
-       ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE);
-       if (ret > 0) {
-               host->dma_sglen = ret;
+       ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
+       if (ret > 0)
                desc = chan->device->device_prep_slave_sg(chan, sg, ret,
                        DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       }
 
        if (desc) {
                desc->callback = tmio_dma_complete;
                desc->callback_param = host;
-               cookie = desc->tx_submit(desc);
-               if (cookie < 0) {
-                       desc = NULL;
-                       ret = cookie;
-               }
+               cookie = dmaengine_submit(desc);
        }
        dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
                __func__, host->sg_len, ret, cookie, host->mrq);
@@ -964,7 +949,7 @@ static void tmio_issue_tasklet_fn(unsigned long priv)
        struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
        struct dma_chan *chan = host->chan_tx;
 
-       chan->device->device_issue_pending(chan);
+       dma_async_issue_pending(chan);
 }
 
 static void tmio_tasklet_fn(unsigned long arg)
@@ -978,10 +963,12 @@ static void tmio_tasklet_fn(unsigned long arg)
                goto out;
 
        if (host->data->flags & MMC_DATA_READ)
-               dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen,
+               dma_unmap_sg(host->chan_rx->device->dev,
+                            host->sg_ptr, host->sg_len,
                             DMA_FROM_DEVICE);
        else
-               dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen,
+               dma_unmap_sg(host->chan_tx->device->dev,
+                            host->sg_ptr, host->sg_len,
                             DMA_TO_DEVICE);
 
        tmio_mmc_do_data_irq(host);
@@ -1071,8 +1058,7 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host)
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        struct mmc_data *data)
 {
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
 
        pr_debug("setup data transfer: blocksize %08x  nr_blocks %d\n",
                 data->blksz, data->blocks);
@@ -1177,8 +1163,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
 
        return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
                (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1;
@@ -1187,8 +1172,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
 static int tmio_mmc_get_cd(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       struct mfd_cell *cell = host->pdev->dev.platform_data;
-       struct tmio_mmc_data *pdata = cell->driver_data;
+       struct tmio_mmc_data *pdata = mfd_get_data(host->pdev);
 
        if (!pdata->get_cd)
                return -ENOSYS;
@@ -1207,7 +1191,7 @@ static const struct mmc_host_ops tmio_mmc_ops = {
 #ifdef CONFIG_PM
 static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
@@ -1222,7 +1206,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 
 static int tmio_mmc_resume(struct platform_device *dev)
 {
-       struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret = 0;
 
@@ -1245,7 +1229,7 @@ out:
 
 static int __devinit tmio_mmc_probe(struct platform_device *dev)
 {
-       struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct tmio_mmc_data *pdata;
        struct resource *res_ctl;
        struct tmio_mmc_host *host;
@@ -1260,7 +1244,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev)
        if (!res_ctl)
                goto out;
 
-       pdata = cell->driver_data;
+       pdata = mfd_get_data(dev);
        if (!pdata || !pdata->hclk)
                goto out;
 
@@ -1360,7 +1344,7 @@ out:
 
 static int __devexit tmio_mmc_remove(struct platform_device *dev)
 {
-       struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct mmc_host *mmc = platform_get_drvdata(dev);
 
        platform_set_drvdata(dev, NULL);
index 9ed84ddb478060358cce983c0996b6268b1edd93..8c5b4881ccd6068fc766fd6e0ae77dbbe2669664 100644 (file)
@@ -802,12 +802,9 @@ static const struct mmc_host_ops via_sdc_ops = {
 
 static void via_reset_pcictrl(struct via_crdr_mmc_host *host)
 {
-       void __iomem *addrbase;
        unsigned long flags;
        u8 gatt;
 
-       addrbase = host->pcictrl_mmiobase;
-
        spin_lock_irqsave(&host->lock, flags);
 
        via_save_pcictrlreg(host);
index 3041d1f7ae3fc4ed3f6e00a3a4f0d444cdb69ce0..38fb16771f8554969231cdde5779a064476b93dc 100644 (file)
@@ -319,7 +319,7 @@ static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf,
 
 static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
 {
-       struct mfd_cell *cell = dev_get_platdata(&dev->dev);
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        int ret;
 
        if (cell->enable) {
@@ -363,7 +363,7 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
 
 static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 {
-       struct mfd_cell *cell = dev_get_platdata(&dev->dev);
+       const struct mfd_cell *cell = mfd_get_cell(dev);
 
        tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
        if (cell->disable)
@@ -372,8 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 
 static int tmio_probe(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev_get_platdata(&dev->dev);
-       struct tmio_nand_data *data = cell->driver_data;
+       struct tmio_nand_data *data = mfd_get_data(dev);
        struct resource *fcr = platform_get_resource(dev,
                        IORESOURCE_MEM, 0);
        struct resource *ccr = platform_get_resource(dev,
@@ -516,7 +515,7 @@ static int tmio_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int tmio_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct mfd_cell *cell = dev_get_platdata(&dev->dev);
+       const struct mfd_cell *cell = mfd_get_cell(dev);
 
        if (cell->suspend)
                cell->suspend(dev);
@@ -527,7 +526,7 @@ static int tmio_suspend(struct platform_device *dev, pm_message_t state)
 
 static int tmio_resume(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev_get_platdata(&dev->dev);
+       const struct mfd_cell *cell = mfd_get_cell(dev);
 
        /* FIXME - is this required or merely another attack of the broken
         * SHARP platform? Looks suspicious.
index aaa6e1e83b297f6bbbc96e660fb9048d9125dab2..eededf94f5a6c591d003fcd9838e8a06af15f3d4 100644 (file)
@@ -1345,7 +1345,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
        if (!(ubi_chk_flags & UBI_CHK_IO))
                return 0;
 
-       buf1 = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
        if (!buf1) {
                ubi_err("cannot allocate memory to check writes");
                return 0;
@@ -1409,7 +1409,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
        if (!(ubi_chk_flags & UBI_CHK_IO))
                return 0;
 
-       buf = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubi_err("cannot allocate memory to check for 0xFFs");
                return 0;
index b38d987da67d9c810d069ec9303313aa2978243d..9560b9d624bd56b1bef99b972b3f2d7931819977 100644 (file)
@@ -1,6 +1,4 @@
-ifeq ($(CONFIG_CAIF_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG
 
 # Serial interface
 obj-$(CONFIG_CAIF_TTY) += caif_serial.o
index 366f5cc050ae0c85a35dca366bda26f6f8b841ab..102b16c6cc97711543cfecacaa224799cf4e4d6b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 
 #include <linux/netdevice.h>
 #include <linux/can.h>
@@ -1643,7 +1644,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
        struct device *dev;
        int ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = mfd_get_data(pdev);
        if (!pdata)
                return -ENXIO;
 
index 928b2b83cef509080c30eccd6c4d1c4cfe76fd58..efd44afeae83f7c359629f9561b3288504d7bef8 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
@@ -1145,7 +1146,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
        struct resource *iomem;
        struct net_device *netdev;
        struct ks8842_adapter *adapter;
-       struct ks8842_platform_data *pdata = pdev->dev.platform_data;
+       struct ks8842_platform_data *pdata = mfd_get_data(pdev);
        u16 id;
        unsigned i;
 
index 05c5671749aa9c40adc7f8bc16fa0f6a5b039b46..62fa7eec5f0c448be487ed78bc4da11eaaa4a751 100644 (file)
@@ -1204,6 +1204,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
                }
        }
 
+       /* Allow large DMA segments, up to the firmware limit of 1 GB */
+       dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
+
        priv = kzalloc(sizeof *priv, GFP_KERNEL);
        if (!priv) {
                dev_err(&pdev->dev, "Device struct alloc failed, "
index 43583309a65db6ec7053c182b479cb4e13c4471d..31e9407a07394e6bdeaf976afe59b012160e2c9b 100644 (file)
@@ -129,7 +129,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
 
        state->strm.next_in   = NULL;
        state->w_size         = w_size;
-       state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
+       state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
        if (state->strm.workspace == NULL)
                goto out_free;
 
index 44150f2f7bfd6b206b17e0a64064d5996d0033ea..26afbaae23f0d1fb7acbf65c030d92fcfd2ebda0 100644 (file)
@@ -382,7 +382,7 @@ static void rionet_remove(struct rio_dev *rdev)
        struct rionet_peer *peer, *tmp;
 
        free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
-                                       __ilog2(sizeof(void *)) + 4 : 0);
+                                       __fls(sizeof(void *)) + 4 : 0);
        unregister_netdev(ndev);
        free_netdev(ndev);
 
@@ -450,7 +450,7 @@ static int rionet_setup_netdev(struct rio_mport *mport)
        }
 
        rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
-                       mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0);
+                       mport->sys_size ? __fls(sizeof(void *)) + 4 : 0);
        if (!rionet_active) {
                rc = -ENOMEM;
                goto out;
@@ -571,5 +571,5 @@ static void __exit rionet_exit(void)
        rio_unregister_driver(&rionet_driver);
 }
 
-module_init(rionet_init);
+late_initcall(rionet_init);
 module_exit(rionet_exit);
index cb23580fcffa5894d1f10db8dce271575c7a1781..b0be0234abf6a3bc8a1060434a2b5c6af88112f5 100644 (file)
@@ -17,4 +17,4 @@ skfp-objs :=  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
 #   projects. To keep the source common for all those drivers (and
 #   thus simplify fixes to it), please do not clean it up!
 
-EXTRA_CFLAGS += -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes 
+ccflags-y := -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes
index dabdcfed4efd1fc8b96d02635fa0ea40f19037fb..609710d64eb5c196a506a33ae2d832aa1cb5d7bb 100644 (file)
@@ -14,4 +14,4 @@ lmc-objs := lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o
 # -DDEBUG \
 # -DLMC_PACKET_LOG
 
-EXTRA_CFLAGS += -I. $(DBGDEF)
+ccflags-y := -I. $(DBGDEF)
index 30acd39d76a2892de5a684b9b716201c74b9da1f..2c8f71f0ed456e5718e322350339ff8b55556d0a 100644 (file)
@@ -30,9 +30,9 @@
 
 /* Following defines can be used to remove unneeded parts of the driver, e.g.,
  * to limit the size of the kernel module. Definitions can be added here in
- * hostap_config.h or they can be added to make command with EXTRA_CFLAGS,
+ * hostap_config.h or they can be added to make command with ccflags-y,
  * e.g.,
- * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
+ * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
  */
 
 /* Do not include debug messages into the driver */
index 1907eafb9b16b72aea2502869b420dbe87dbe8b5..5728a918e508ba9bf9636ac98f615b25fcd48c28 100644 (file)
@@ -5,7 +5,5 @@ zd1211rw-objs := zd_chip.o zd_mac.o \
                zd_rf_al7230b.o zd_rf_uw2453.o \
                zd_rf.o zd_usb.o
 
-ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_ZD1211RW_DEBUG) := -DDEBUG
 
index 710b53bfac6d9478b86aed67e537bc06ee1cbc6d..632ebae7f17a4444f7aa3ad193bdbce0212c6c09 100644 (file)
@@ -496,6 +496,9 @@ EXPORT_SYMBOL(of_find_node_with_property);
 const struct of_device_id *of_match_node(const struct of_device_id *matches,
                                         const struct device_node *node)
 {
+       if (!matches)
+               return NULL;
+
        while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
                int match = 1;
                if (matches->name[0])
index af824e7e03678b04520433180950858bb5ed2e35..c9db49c10f452b925eeb859599591d08fdc9fcb2 100644 (file)
@@ -139,12 +139,13 @@ static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
 /**
  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
  * @blob: The parent device tree blob
+ * @mem: Memory chunk to use for allocating device nodes and properties
  * @p: pointer to node in flat tree
  * @dad: Parent struct device_node
  * @allnextpp: pointer to ->allnext from last allocated device_node
  * @fpsize: Size of the node path up at the current depth.
  */
-unsigned long unflatten_dt_node(struct boot_param_header *blob,
+static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                                unsigned long mem,
                                unsigned long *p,
                                struct device_node *dad,
@@ -230,6 +231,7 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob,
                }
                kref_init(&np->kref);
        }
+       /* process properties */
        while (1) {
                u32 sz, noff;
                char *pname;
@@ -351,7 +353,7 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob,
  * @dt_alloc: An allocator that provides a virtual address to memory
  * for the resulting tree
  */
-void __unflatten_device_tree(struct boot_param_header *blob,
+static void __unflatten_device_tree(struct boot_param_header *blob,
                             struct device_node **mynodes,
                             void * (*dt_alloc)(u64 size, u64 align))
 {
index 1ce4c45c4ab2a12e431172a236fd26c1b96409ce..63d3cb73bdb9ac31b46efa252d0075e5c6c16c0a 100644 (file)
@@ -210,13 +210,16 @@ struct platform_device *of_platform_device_create(struct device_node *np,
 EXPORT_SYMBOL(of_platform_device_create);
 
 /**
- * of_platform_bus_create - Create an OF device for a bus node and all its
- * children. Optionally recursively instantiate matching busses.
+ * of_platform_bus_create() - Create a device for a node and its children.
  * @bus: device node of the bus to instantiate
- * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
- * disallow recursive creation of child busses
+ * @matches: match table for bus nodes
+ * disallow recursive creation of child buses
+ * @parent: parent for new device, or NULL for top level.
+ *
+ * Creates a platform_device for the provided device_node, and optionally
+ * recursively create devices for all the child nodes.
  */
-static int of_platform_bus_create(const struct device_node *bus,
+static int of_platform_bus_create(struct device_node *bus,
                                  const struct of_device_id *matches,
                                  struct device *parent)
 {
@@ -224,18 +227,13 @@ static int of_platform_bus_create(const struct device_node *bus,
        struct platform_device *dev;
        int rc = 0;
 
+       dev = of_platform_device_create(bus, NULL, parent);
+       if (!dev || !of_match_node(matches, bus))
+               return 0;
+
        for_each_child_of_node(bus, child) {
                pr_debug("   create child: %s\n", child->full_name);
-               dev = of_platform_device_create(child, NULL, parent);
-               if (dev == NULL)
-                       continue;
-
-               if (!of_match_node(matches, child))
-                       continue;
-               if (rc == 0) {
-                       pr_debug("   and sub busses\n");
-                       rc = of_platform_bus_create(child, matches, &dev->dev);
-               }
+               rc = of_platform_bus_create(child, matches, &dev->dev);
                if (rc) {
                        of_node_put(child);
                        break;
@@ -245,9 +243,9 @@ static int of_platform_bus_create(const struct device_node *bus,
 }
 
 /**
- * of_platform_bus_probe - Probe the device-tree for platform busses
+ * of_platform_bus_probe() - Probe the device-tree for platform buses
  * @root: parent of the first level to probe or NULL for the root of the tree
- * @matches: match table, NULL to use the default
+ * @matches: match table for bus nodes
  * @parent: parent to hook devices from, NULL for toplevel
  *
  * Note that children of the provided root are not instantiated as devices
@@ -258,50 +256,26 @@ int of_platform_bus_probe(struct device_node *root,
                          struct device *parent)
 {
        struct device_node *child;
-       struct platform_device *dev;
        int rc = 0;
 
-       if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE))
-               return -EINVAL;
-       if (root == NULL)
-               root = of_find_node_by_path("/");
-       else
-               of_node_get(root);
-       if (root == NULL)
+       root = root ? of_node_get(root) : of_find_node_by_path("/");
+       if (!root)
                return -EINVAL;
 
        pr_debug("of_platform_bus_probe()\n");
        pr_debug(" starting at: %s\n", root->full_name);
 
-       /* Do a self check of bus type, if there's a match, create
-        * children
-        */
+       /* Do a self check of bus type, if there's a match, create children */
        if (of_match_node(matches, root)) {
-               pr_debug(" root match, create all sub devices\n");
-               dev = of_platform_device_create(root, NULL, parent);
-               if (dev == NULL)
-                       goto bail;
-
-               pr_debug(" create all sub busses\n");
-               rc = of_platform_bus_create(root, matches, &dev->dev);
-               goto bail;
-       }
-       for_each_child_of_node(root, child) {
+               rc = of_platform_bus_create(root, matches, parent);
+       } else for_each_child_of_node(root, child) {
                if (!of_match_node(matches, child))
                        continue;
-
-               pr_debug("  match: %s\n", child->full_name);
-               dev = of_platform_device_create(child, NULL, parent);
-               if (dev == NULL)
-                       continue;
-
-               rc = of_platform_bus_create(child, matches, &dev->dev);
-               if (rc) {
-                       of_node_put(child);
+               rc = of_platform_bus_create(child, matches, parent);
+               if (rc)
                        break;
-               }
        }
- bail:
+
        of_node_put(root);
        return rc;
 }
index 9383063d2b16896bfcc740855221c5eccfbf0570..bcd5d54b7d4d2b3cfc938acf6141cc65bb4ec8ec 100644 (file)
@@ -296,25 +296,25 @@ static struct pci_port_ops dino_port_ops = {
        .outl   = dino_out32
 };
 
-static void dino_mask_irq(unsigned int irq)
+static void dino_mask_irq(struct irq_data *d)
 {
-       struct dino_device *dino_dev = get_irq_chip_data(irq);
-       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
+       struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
+       int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
 
-       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
+       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq);
 
        /* Clear the matching bit in the IMR register */
        dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq));
        __raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR);
 }
 
-static void dino_unmask_irq(unsigned int irq)
+static void dino_unmask_irq(struct irq_data *d)
 {
-       struct dino_device *dino_dev = get_irq_chip_data(irq);
-       int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
+       struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
+       int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
        u32 tmp;
 
-       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq);
+       DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq);
 
        /*
        ** clear pending IRQ bits
@@ -346,9 +346,9 @@ static void dino_unmask_irq(unsigned int irq)
 }
 
 static struct irq_chip dino_interrupt_type = {
-       .name   = "GSC-PCI",
-       .unmask = dino_unmask_irq,
-       .mask   = dino_mask_irq,
+       .name           = "GSC-PCI",
+       .irq_unmask     = dino_unmask_irq,
+       .irq_mask       = dino_mask_irq,
 };
 
 
index e860038b0b841952f29021a5fa752f6d9ee4ea3e..deeec32a5803c30834469819102f7efac98342ed 100644 (file)
@@ -144,8 +144,9 @@ static unsigned int eisa_irq_level __read_mostly; /* default to edge triggered *
 
 
 /* called by free irq */
-static void eisa_mask_irq(unsigned int irq)
+static void eisa_mask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long flags;
 
        EISA_DBG("disable irq %d\n", irq);
@@ -164,8 +165,9 @@ static void eisa_mask_irq(unsigned int irq)
 }
 
 /* called by request irq */
-static void eisa_unmask_irq(unsigned int irq)
+static void eisa_unmask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long flags;
        EISA_DBG("enable irq %d\n", irq);
                
@@ -183,9 +185,9 @@ static void eisa_unmask_irq(unsigned int irq)
 }
 
 static struct irq_chip eisa_interrupt_type = {
-       .name   =       "EISA",
-       .unmask =       eisa_unmask_irq,
-       .mask   =       eisa_mask_irq,
+       .name           =       "EISA",
+       .irq_unmask     =       eisa_unmask_irq,
+       .irq_mask       =       eisa_mask_irq,
 };
 
 static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
index 772b1939ac218a2b9fc936ce57bc567761f050fc..ef31080cf5912323d31284fd3ddb2b0036158aea 100644 (file)
@@ -105,13 +105,13 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
        return NO_IRQ;
 }
 
-static void gsc_asic_mask_irq(unsigned int irq)
+static void gsc_asic_mask_irq(struct irq_data *d)
 {
-       struct gsc_asic *irq_dev = get_irq_chip_data(irq);
-       int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
+       struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d);
+       int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32);
        u32 imr;
 
-       DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
+       DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq,
                        irq_dev->name, imr);
 
        /* Disable the IRQ line by clearing the bit in the IMR */
@@ -120,13 +120,13 @@ static void gsc_asic_mask_irq(unsigned int irq)
        gsc_writel(imr, irq_dev->hpa + OFFSET_IMR);
 }
 
-static void gsc_asic_unmask_irq(unsigned int irq)
+static void gsc_asic_unmask_irq(struct irq_data *d)
 {
-       struct gsc_asic *irq_dev = get_irq_chip_data(irq);
-       int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
+       struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d);
+       int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32);
        u32 imr;
 
-       DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq,
+       DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq,
                        irq_dev->name, imr);
 
        /* Enable the IRQ line by setting the bit in the IMR */
@@ -140,9 +140,9 @@ static void gsc_asic_unmask_irq(unsigned int irq)
 }
 
 static struct irq_chip gsc_asic_interrupt_type = {
-       .name   =       "GSC-ASIC",
-       .unmask =       gsc_asic_unmask_irq,
-       .mask   =       gsc_asic_mask_irq,
+       .name           =       "GSC-ASIC",
+       .irq_unmask     =       gsc_asic_unmask_irq,
+       .irq_mask       =       gsc_asic_mask_irq,
 };
 
 int gsc_assign_irq(struct irq_chip *type, void *data)
index 0327894bf2355c23d3e2b3daae80c8a2cadf7aeb..95930d016235ae3a39fdfe71e1b409291d21d370 100644 (file)
@@ -615,10 +615,10 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
 }
 
 
-static void iosapic_mask_irq(unsigned int irq)
+static void iosapic_mask_irq(struct irq_data *d)
 {
        unsigned long flags;
-       struct vector_info *vi = get_irq_chip_data(irq);
+       struct vector_info *vi = irq_data_get_irq_chip_data(d);
        u32 d0, d1;
 
        spin_lock_irqsave(&iosapic_lock, flags);
@@ -628,9 +628,9 @@ static void iosapic_mask_irq(unsigned int irq)
        spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
-static void iosapic_unmask_irq(unsigned int irq)
+static void iosapic_unmask_irq(struct irq_data *d)
 {
-       struct vector_info *vi = get_irq_chip_data(irq);
+       struct vector_info *vi = irq_data_get_irq_chip_data(d);
        u32 d0, d1;
 
        /* data is initialized by fixup_irq */
@@ -666,34 +666,34 @@ printk("\n");
         * enables their IRQ. It can lead to "interesting" race conditions
         * in the driver initialization sequence.
         */
-       DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq,
+       DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", d->irq,
                        vi->eoi_addr, vi->eoi_data);
        iosapic_eoi(vi->eoi_addr, vi->eoi_data);
 }
 
-static void iosapic_eoi_irq(unsigned int irq)
+static void iosapic_eoi_irq(struct irq_data *d)
 {
-       struct vector_info *vi = get_irq_chip_data(irq);
+       struct vector_info *vi = irq_data_get_irq_chip_data(d);
 
        iosapic_eoi(vi->eoi_addr, vi->eoi_data);
-       cpu_eoi_irq(irq);
+       cpu_eoi_irq(d);
 }
 
 #ifdef CONFIG_SMP
-static int iosapic_set_affinity_irq(unsigned int irq,
-                                    const struct cpumask *dest)
+static int iosapic_set_affinity_irq(struct irq_data *d,
+                                   const struct cpumask *dest, bool force)
 {
-       struct vector_info *vi = get_irq_chip_data(irq);
+       struct vector_info *vi = irq_data_get_irq_chip_data(d);
        u32 d0, d1, dummy_d0;
        unsigned long flags;
        int dest_cpu;
 
-       dest_cpu = cpu_check_affinity(irq, dest);
+       dest_cpu = cpu_check_affinity(d, dest);
        if (dest_cpu < 0)
                return -1;
 
-       cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu));
-       vi->txn_addr = txn_affinity_addr(irq, dest_cpu);
+       cpumask_copy(d->affinity, cpumask_of(dest_cpu));
+       vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu);
 
        spin_lock_irqsave(&iosapic_lock, flags);
        /* d1 contains the destination CPU, so only want to set that
@@ -708,13 +708,13 @@ static int iosapic_set_affinity_irq(unsigned int irq,
 #endif
 
 static struct irq_chip iosapic_interrupt_type = {
-       .name   =       "IO-SAPIC-level",
-       .unmask =       iosapic_unmask_irq,
-       .mask   =       iosapic_mask_irq,
-       .ack    =       cpu_ack_irq,
-       .eoi    =       iosapic_eoi_irq,
+       .name           =       "IO-SAPIC-level",
+       .irq_unmask     =       iosapic_unmask_irq,
+       .irq_mask       =       iosapic_mask_irq,
+       .irq_ack        =       cpu_ack_irq,
+       .irq_eoi        =       iosapic_eoi_irq,
 #ifdef CONFIG_SMP
-       .set_affinity = iosapic_set_affinity_irq,
+       .irq_set_affinity =     iosapic_set_affinity_irq,
 #endif
 };
 
index 28241532c0fd1b56c7f6bfa50d788c5fef1e9e3a..a4d8ff66a63901833ec06a6eb69830d6246d0d8e 100644 (file)
@@ -286,8 +286,9 @@ superio_init(struct pci_dev *pcidev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);
 
-static void superio_mask_irq(unsigned int irq)
+static void superio_mask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        u8 r8;
 
        if ((irq < 1) || (irq == 2) || (irq > 7)) {
@@ -303,8 +304,9 @@ static void superio_mask_irq(unsigned int irq)
        outb (r8,IC_PIC1+1);
 }
 
-static void superio_unmask_irq(unsigned int irq)
+static void superio_unmask_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        u8 r8;
 
        if ((irq < 1) || (irq == 2) || (irq > 7)) {
@@ -320,9 +322,9 @@ static void superio_unmask_irq(unsigned int irq)
 }
 
 static struct irq_chip superio_interrupt_type = {
-       .name   =       SUPERIO,
-       .unmask =       superio_unmask_irq,
-       .mask   =       superio_mask_irq,
+       .name           =       SUPERIO,
+       .irq_unmask     =       superio_unmask_irq,
+       .irq_mask       =       superio_mask_irq,
 };
 
 #ifdef DEBUG_SUPERIO_INIT
index 6fe0772e0e7de2432d9353d8871b3bc5e8ba04ee..7c3b18e78cee148d889a8a63ccc2fd4785eab81a 100644 (file)
@@ -293,19 +293,11 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable)
        }
 
        if (enable) {
-               if (!dev->wakeup.run_wake_count++) {
-                       acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
-                       acpi_enable_gpe(dev->wakeup.gpe_device,
-                                       dev->wakeup.gpe_number);
-               }
-       } else if (dev->wakeup.run_wake_count > 0) {
-               if (!--dev->wakeup.run_wake_count) {
-                       acpi_disable_gpe(dev->wakeup.gpe_device,
-                                        dev->wakeup.gpe_number);
-                       acpi_disable_wakeup_device_power(dev);
-               }
+               acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0);
+               acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
        } else {
-               error = -EALREADY;
+               acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number);
+               acpi_disable_wakeup_device_power(dev);
        }
 
        return error;
index c85438a367d530e6db996ce79c66767e5aa84cb7..a8a277a2e0d05ad414d64d347dbfd7517538673c 100644 (file)
@@ -369,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj,
        u8 *data = (u8*) buf;
 
        /* Several chips lock up trying to read undefined config space */
-       if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) {
+       if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) {
                size = dev->cfg_size;
        } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                size = 128;
index b714d787bdddeb8306324dada56412c6eef2ac68..2472e7177b4b5af6ddc813913fb193c47fef984d 100644 (file)
@@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        if (!__pci_complete_power_transition(dev, state))
                error = 0;
+       /*
+        * When aspm_policy is "powersave" this call ensures
+        * that ASPM is configured.
+        */
+       if (!error && dev->bus->self)
+               pcie_aspm_powersave_config_link(dev->bus->self);
 
        return error;
 }
index 80c11d1314999c77f9666dd6f892610b90e07bd0..3eb77080366a21db38065493a5a29d241d4320cc 100644 (file)
                                        PCI_ERR_UNC_UNX_COMP|           \
                                        PCI_ERR_UNC_MALF_TLP)
 
-struct header_log_regs {
-       unsigned int dw0;
-       unsigned int dw1;
-       unsigned int dw2;
-       unsigned int dw3;
-};
-
 #define AER_MAX_MULTI_ERR_DEVICES      5       /* Not likely to have more */
 struct aer_err_info {
        struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
@@ -59,7 +52,7 @@ struct aer_err_info {
 
        unsigned int status;            /* COR/UNCOR Error Status */
        unsigned int mask;              /* COR/UNCOR Error Mask */
-       struct header_log_regs tlp;     /* TLP Header */
+       struct aer_header_log_regs tlp; /* TLP Header */
 };
 
 struct aer_err_source {
index 9d3e4c8d0184202ce58177d88b2d6ac9454c20d2..b07a42e0b350f9c84207df510272ef6926430a70 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/pm.h>
 #include <linux/suspend.h>
+#include <linux/cper.h>
 
 #include "aerdrv.h"
 
        (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \
        AER_TRANSACTION_LAYER_ERROR)
 
-#define AER_PR(info, pdev, fmt, args...)                               \
-       printk("%s%s %s: " fmt, (info->severity == AER_CORRECTABLE) ?   \
-               KERN_WARNING : KERN_ERR, dev_driver_string(&pdev->dev), \
-               dev_name(&pdev->dev), ## args)
-
 /*
  * AER error strings
  */
-static char *aer_error_severity_string[] = {
+static const char *aer_error_severity_string[] = {
        "Uncorrected (Non-Fatal)",
        "Uncorrected (Fatal)",
        "Corrected"
 };
 
-static char *aer_error_layer[] = {
+static const char *aer_error_layer[] = {
        "Physical Layer",
        "Data Link Layer",
        "Transaction Layer"
 };
-static char *aer_correctable_error_string[] = {
-       "Receiver Error        ",       /* Bit Position 0       */
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       "Bad TLP               ",       /* Bit Position 6       */
-       "Bad DLLP              ",       /* Bit Position 7       */
-       "RELAY_NUM Rollover    ",       /* Bit Position 8       */
-       NULL,
-       NULL,
-       NULL,
-       "Replay Timer Timeout  ",       /* Bit Position 12      */
-       "Advisory Non-Fatal    ",       /* Bit Position 13      */
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
+
+static const char *aer_correctable_error_string[] = {
+       "Receiver Error",               /* Bit Position 0       */
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
+       "Bad TLP",                      /* Bit Position 6       */
+       "Bad DLLP",                     /* Bit Position 7       */
+       "RELAY_NUM Rollover",           /* Bit Position 8       */
        NULL,
        NULL,
        NULL,
+       "Replay Timer Timeout",         /* Bit Position 12      */
+       "Advisory Non-Fatal",           /* Bit Position 13      */
 };
 
-static char *aer_uncorrectable_error_string[] = {
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       "Data Link Protocol    ",       /* Bit Position 4       */
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       "Poisoned TLP          ",       /* Bit Position 12      */
-       "Flow Control Protocol ",       /* Bit Position 13      */
-       "Completion Timeout    ",       /* Bit Position 14      */
-       "Completer Abort       ",       /* Bit Position 15      */
-       "Unexpected Completion ",       /* Bit Position 16      */
-       "Receiver Overflow     ",       /* Bit Position 17      */
-       "Malformed TLP         ",       /* Bit Position 18      */
-       "ECRC                  ",       /* Bit Position 19      */
-       "Unsupported Request   ",       /* Bit Position 20      */
+static const char *aer_uncorrectable_error_string[] = {
        NULL,
        NULL,
        NULL,
        NULL,
+       "Data Link Protocol",           /* Bit Position 4       */
        NULL,
        NULL,
        NULL,
@@ -144,19 +103,29 @@ static char *aer_uncorrectable_error_string[] = {
        NULL,
        NULL,
        NULL,
+       "Poisoned TLP",                 /* Bit Position 12      */
+       "Flow Control Protocol",        /* Bit Position 13      */
+       "Completion Timeout",           /* Bit Position 14      */
+       "Completer Abort",              /* Bit Position 15      */
+       "Unexpected Completion",        /* Bit Position 16      */
+       "Receiver Overflow",            /* Bit Position 17      */
+       "Malformed TLP",                /* Bit Position 18      */
+       "ECRC",                         /* Bit Position 19      */
+       "Unsupported Request",          /* Bit Position 20      */
 };
 
-static char *aer_agent_string[] = {
+static const char *aer_agent_string[] = {
        "Receiver ID",
        "Requester ID",
        "Completer ID",
        "Transmitter ID"
 };
 
-static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev)
+static void __aer_print_error(const char *prefix,
+                             struct aer_err_info *info)
 {
        int i, status;
-       char *errmsg = NULL;
+       const char *errmsg = NULL;
 
        status = (info->status & ~info->mask);
 
@@ -165,15 +134,17 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev)
                        continue;
 
                if (info->severity == AER_CORRECTABLE)
-                       errmsg = aer_correctable_error_string[i];
+                       errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ?
+                               aer_correctable_error_string[i] : NULL;
                else
-                       errmsg = aer_uncorrectable_error_string[i];
+                       errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ?
+                               aer_uncorrectable_error_string[i] : NULL;
 
                if (errmsg)
-                       AER_PR(info, dev, "   [%2d] %s%s\n", i, errmsg,
+                       printk("%s""   [%2d] %-22s%s\n", prefix, i, errmsg,
                                info->first_error == i ? " (First)" : "");
                else
-                       AER_PR(info, dev, "   [%2d] Unknown Error Bit%s\n", i,
+                       printk("%s""   [%2d] Unknown Error Bit%s\n", prefix, i,
                                info->first_error == i ? " (First)" : "");
        }
 }
@@ -181,11 +152,15 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev)
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 {
        int id = ((dev->bus->number << 8) | dev->devfn);
+       char prefix[44];
+
+       snprintf(prefix, sizeof(prefix), "%s%s %s: ",
+                (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR,
+                dev_driver_string(&dev->dev), dev_name(&dev->dev));
 
        if (info->status == 0) {
-               AER_PR(info, dev,
-                       "PCIe Bus Error: severity=%s, type=Unaccessible, "
-                       "id=%04x(Unregistered Agent ID)\n",
+               printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, "
+                       "id=%04x(Unregistered Agent ID)\n", prefix,
                        aer_error_severity_string[info->severity], id);
        } else {
                int layer, agent;
@@ -193,23 +168,22 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
                layer = AER_GET_LAYER_ERROR(info->severity, info->status);
                agent = AER_GET_AGENT(info->severity, info->status);
 
-               AER_PR(info, dev,
-                       "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
-                       aer_error_severity_string[info->severity],
+               printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
+                       prefix, aer_error_severity_string[info->severity],
                        aer_error_layer[layer], id, aer_agent_string[agent]);
 
-               AER_PR(info, dev,
-                       "  device [%04x:%04x] error status/mask=%08x/%08x\n",
-                       dev->vendor, dev->device, info->status, info->mask);
+               printk("%s""  device [%04x:%04x] error status/mask=%08x/%08x\n",
+                       prefix, dev->vendor, dev->device,
+                       info->status, info->mask);
 
-               __aer_print_error(info, dev);
+               __aer_print_error(prefix, info);
 
                if (info->tlp_header_valid) {
                        unsigned char *tlp = (unsigned char *) &info->tlp;
-                       AER_PR(info, dev, "  TLP Header:"
+                       printk("%s""  TLP Header:"
                                " %02x%02x%02x%02x %02x%02x%02x%02x"
                                " %02x%02x%02x%02x %02x%02x%02x%02x\n",
-                               *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+                               prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
                                *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
                                *(tlp + 11), *(tlp + 10), *(tlp + 9),
                                *(tlp + 8), *(tlp + 15), *(tlp + 14),
@@ -218,8 +192,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
        }
 
        if (info->id && info->error_dev_num > 1 && info->id == id)
-               AER_PR(info, dev,
-                       "  Error of this Agent(%04x) is reported first\n", id);
+               printk("%s""  Error of this Agent(%04x) is reported first\n",
+                       prefix, id);
 }
 
 void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
@@ -228,3 +202,61 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
                info->multi_error_valid ? "Multiple " : "",
                aer_error_severity_string[info->severity], info->id);
 }
+
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+static int cper_severity_to_aer(int cper_severity)
+{
+       switch (cper_severity) {
+       case CPER_SEV_RECOVERABLE:
+               return AER_NONFATAL;
+       case CPER_SEV_FATAL:
+               return AER_FATAL;
+       default:
+               return AER_CORRECTABLE;
+       }
+}
+
+void cper_print_aer(const char *prefix, int cper_severity,
+                   struct aer_capability_regs *aer)
+{
+       int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
+       u32 status, mask;
+       const char **status_strs;
+
+       aer_severity = cper_severity_to_aer(cper_severity);
+       if (aer_severity == AER_CORRECTABLE) {
+               status = aer->cor_status;
+               mask = aer->cor_mask;
+               status_strs = aer_correctable_error_string;
+               status_strs_size = ARRAY_SIZE(aer_correctable_error_string);
+       } else {
+               status = aer->uncor_status;
+               mask = aer->uncor_mask;
+               status_strs = aer_uncorrectable_error_string;
+               status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string);
+               tlp_header_valid = status & AER_LOG_TLP_MASKS;
+       }
+       layer = AER_GET_LAYER_ERROR(aer_severity, status);
+       agent = AER_GET_AGENT(aer_severity, status);
+       printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n",
+              prefix, status, mask);
+       cper_print_bits(prefix, status, status_strs, status_strs_size);
+       printk("%s""aer_layer=%s, aer_agent=%s\n", prefix,
+              aer_error_layer[layer], aer_agent_string[agent]);
+       if (aer_severity != AER_CORRECTABLE)
+               printk("%s""aer_uncor_severity: 0x%08x\n",
+                      prefix, aer->uncor_severity);
+       if (tlp_header_valid) {
+               const unsigned char *tlp;
+               tlp = (const unsigned char *)&aer->header_log;
+               printk("%s""aer_tlp_header:"
+                       " %02x%02x%02x%02x %02x%02x%02x%02x"
+                       " %02x%02x%02x%02x %02x%02x%02x%02x\n",
+                       prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+                       *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
+                       *(tlp + 11), *(tlp + 10), *(tlp + 9),
+                       *(tlp + 8), *(tlp + 15), *(tlp + 14),
+                       *(tlp + 13), *(tlp + 12));
+       }
+}
+#endif
index 3188cd96b3386c2992d2b3df1d5a7bb0e363c266..eee09f756ec95a18832199801924aa2775da2195 100644 (file)
@@ -69,6 +69,7 @@ struct pcie_link_state {
 };
 
 static int aspm_disabled, aspm_force, aspm_clear_state;
+static bool aspm_support_enabled = true;
 static DEFINE_MUTEX(aspm_lock);
 static LIST_HEAD(link_list);
 
@@ -707,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
        up_read(&pci_bus_sem);
 }
 
+void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+       struct pcie_link_state *link = pdev->link_state;
+
+       if (aspm_disabled || !pci_is_pcie(pdev) || !link)
+               return;
+
+       if (aspm_policy != POLICY_POWERSAVE)
+               return;
+
+       if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
+           (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+               return;
+
+       down_read(&pci_bus_sem);
+       mutex_lock(&aspm_lock);
+       pcie_config_aspm_path(link);
+       pcie_set_clkpm(link, policy_to_clkpm_state(link));
+       mutex_unlock(&aspm_lock);
+       up_read(&pci_bus_sem);
+}
+
 /*
  * pci_disable_link_state - disable pci device's link state, so the link will
  * never enter specific states
@@ -747,6 +770,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp)
        int i;
        struct pcie_link_state *link;
 
+       if (aspm_disabled)
+               return -EPERM;
        for (i = 0; i < ARRAY_SIZE(policy_str); i++)
                if (!strncmp(val, policy_str[i], strlen(policy_str[i])))
                        break;
@@ -801,6 +826,8 @@ static ssize_t link_state_store(struct device *dev,
        struct pcie_link_state *link, *root = pdev->link_state->root;
        u32 val = buf[0] - '0', state = 0;
 
+       if (aspm_disabled)
+               return -EPERM;
        if (n < 1 || val > 3)
                return -EINVAL;
 
@@ -896,6 +923,7 @@ static int __init pcie_aspm_disable(char *str)
 {
        if (!strcmp(str, "off")) {
                aspm_disabled = 1;
+               aspm_support_enabled = false;
                printk(KERN_INFO "PCIe ASPM is disabled\n");
        } else if (!strcmp(str, "force")) {
                aspm_force = 1;
@@ -930,3 +958,8 @@ int pcie_aspm_enabled(void)
 }
 EXPORT_SYMBOL(pcie_aspm_enabled);
 
+bool pcie_aspm_support_enabled(void)
+{
+       return aspm_support_enabled;
+}
+EXPORT_SYMBOL(pcie_aspm_support_enabled);
index 5130d0d22390bba5266fdfb18a10cb7aa2dccb7d..595654a1a6a6eec86e8011f1efe667bf318bf257 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/pcieport_if.h>
 #include <linux/aer.h>
-#include <linux/pci-aspm.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -356,10 +355,8 @@ int pcie_port_device_register(struct pci_dev *dev)
 
        /* Get and check PCI Express port services */
        capabilities = get_port_device_capability(dev);
-       if (!capabilities) {
-               pcie_no_aspm();
+       if (!capabilities)
                return 0;
-       }
 
        pci_set_master(dev);
        /*
index a59af5b24f0ac9d9f0e4ea7c88cc2ad00ddddbb0..222dfb737b11a699d559c12c23e26a7577ab99de 100644 (file)
@@ -138,6 +138,24 @@ config TC1100_WMI
          This is a driver for the WMI extensions (wireless and bluetooth power
          control) of the HP Compaq TC1100 tablet.
 
+config HP_ACCEL
+       tristate "HP laptop accelerometer"
+       depends on INPUT && ACPI
+       select SENSORS_LIS3LV02D
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         This driver provides support for the "Mobile Data Protection System 3D"
+         or "3D DriveGuard" feature of HP laptops. On such systems the driver
+         should load automatically (via ACPI alias).
+
+         Support for a led indicating disk protection will be provided as
+         hp::hddprotect. For more information on the feature, refer to
+         Documentation/hwmon/lis3lv02d.
+
+         To compile this driver as a module, choose M here: the module will
+         be called hp_accel.
+
 config HP_WMI
        tristate "HP WMI extras"
        depends on ACPI_WMI
index 4ec4ff8f918240e657153d7bdd0a11202ba8d498..299aefb3e74ce222b0a146703b601fe73b1f933d 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_DELL_LAPTOP)     += dell-laptop.o
 obj-$(CONFIG_DELL_WMI)         += dell-wmi.o
 obj-$(CONFIG_ACER_WMI)         += acer-wmi.o
 obj-$(CONFIG_ACERHDF)          += acerhdf.o
+obj-$(CONFIG_HP_ACCEL)         += hp_accel.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
 obj-$(CONFIG_SONY_LAPTOP)      += sony-laptop.o
index ad3d099bf5c14c3431d9035ba21694bf1f561627..c9784705f6ac41ca63666b6d330cfb651c080b0b 100644 (file)
@@ -1031,6 +1031,7 @@ static int __devinit acer_backlight_init(struct device *dev)
        struct backlight_device *bd;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = max_brightness;
        bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
                                       &props);
index f3aa6a7fdab60c71448b85bb6eeb68a3f8c1cc7f..5a6f7d7575d61605e92c8e6bbf826ed9c2fcc6d2 100644 (file)
@@ -667,6 +667,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.max_brightness = 15;
+       props.type = BACKLIGHT_PLATFORM;
 
        bd = backlight_device_register(ASUS_LAPTOP_FILE,
                                       &asus->platform_device->dev, asus,
index fe495939c30745f4ea279a33fbb5a2e64467dada..f503607c0645b015e46fdc963f22fa6e3ba8725c 100644 (file)
@@ -1507,6 +1507,7 @@ static int __init asus_acpi_init(void)
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = 15;
        asus_backlight_device = backlight_device_register("asus", NULL, NULL,
                                                          &asus_backlight_data,
index 911135425224b4e8aab137d9b696500c794aaa71..94f93b621d7b67474808fb6c33cdf81248ca3936 100644 (file)
@@ -564,6 +564,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi)
                return -ENOMEM;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = 7;
        ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
                                             acpi->handle, &cmpc_bl_ops,
index 034572b980c99cb102e0aad04719bf6279baa75a..eb95878fa58335aa3a22bea204be4ecb28746046 100644 (file)
@@ -970,6 +970,7 @@ static int __init compal_init(void)
        if (!acpi_video_backlight_support()) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = BACKLIGHT_LEVEL_MAX;
                compalbl_device = backlight_device_register(DRIVER_NAME,
                                                            NULL, NULL,
index ad24ef36f9f73958edf966213bf6fc8d580a7a84..de301aa8e5c3799620ff5a06372b5e1942c2dab2 100644 (file)
@@ -671,6 +671,7 @@ static int __init dell_init(void)
        if (max_intensity) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = max_intensity;
                dell_backlight_device = backlight_device_register("dell_backlight",
                                                                  &platform_device->dev,
index 49d9ad708f8959f3f39602ca3b262f4f934630d7..6605beac0d0e5e570b0b0e7baf6edf6abbd03f73 100644 (file)
@@ -1147,6 +1147,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
        struct backlight_device *bd;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = 15;
        bd = backlight_device_register(EEEPC_LAPTOP_FILE,
                                       &eeepc->platform_device->dev, eeepc,
index 95e3b0948e9c2a508fcf920b0ad861b841376785..493054c2dbe15ec114922ce6446ad5f75b21beaa 100644 (file)
@@ -1128,6 +1128,7 @@ static int __init fujitsu_init(void)
 
                memset(&props, 0, sizeof(struct backlight_properties));
                max_brightness = fujitsu->max_brightness;
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = max_brightness - 1;
                fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
                                                               NULL, NULL,
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
new file mode 100644 (file)
index 0000000..1b52d00
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS
+ *
+ *  Copyright (C) 2007-2008 Yan Burman
+ *  Copyright (C) 2008 Eric Piel
+ *  Copyright (C) 2008-2009 Pavel Machek
+ *
+ *  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
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/freezer.h>
+#include <linux/uaccess.h>
+#include <linux/leds.h>
+#include <linux/atomic.h>
+#include <acpi/acpi_drivers.h>
+#include "../../misc/lis3lv02d/lis3lv02d.h"
+
+#define DRIVER_NAME     "hp_accel"
+#define ACPI_MDPS_CLASS "accelerometer"
+
+/* Delayed LEDs infrastructure ------------------------------------ */
+
+/* Special LED class that can defer work */
+struct delayed_led_classdev {
+       struct led_classdev led_classdev;
+       struct work_struct work;
+       enum led_brightness new_brightness;
+
+       unsigned int led;               /* For driver */
+       void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value);
+};
+
+static inline void delayed_set_status_worker(struct work_struct *work)
+{
+       struct delayed_led_classdev *data =
+                       container_of(work, struct delayed_led_classdev, work);
+
+       data->set_brightness(data, data->new_brightness);
+}
+
+static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
+                             enum led_brightness brightness)
+{
+       struct delayed_led_classdev *data = container_of(led_cdev,
+                            struct delayed_led_classdev, led_classdev);
+       data->new_brightness = brightness;
+       schedule_work(&data->work);
+}
+
+/* HP-specific accelerometer driver ------------------------------------ */
+
+/* For automatic insertion of the module */
+static struct acpi_device_id lis3lv02d_device_ids[] = {
+       {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
+
+
+/**
+ * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
+ * @lis3: pointer to the device struct
+ *
+ * Returns 0 on success.
+ */
+int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
+{
+       struct acpi_device *dev = lis3->bus_priv;
+       if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
+                                NULL, NULL) != AE_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * lis3lv02d_acpi_read - ACPI ALRD method: read a register
+ * @lis3: pointer to the device struct
+ * @reg:    the register to read
+ * @ret:    result of the operation
+ *
+ * Returns 0 on success.
+ */
+int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
+{
+       struct acpi_device *dev = lis3->bus_priv;
+       union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+       struct acpi_object_list args = { 1, &arg0 };
+       unsigned long long lret;
+       acpi_status status;
+
+       arg0.integer.value = reg;
+
+       status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret);
+       *ret = lret;
+       return (status != AE_OK) ? -EINVAL : 0;
+}
+
+/**
+ * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
+ * @lis3: pointer to the device struct
+ * @reg:    the register to write to
+ * @val:    the value to write
+ *
+ * Returns 0 on success.
+ */
+int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
+{
+       struct acpi_device *dev = lis3->bus_priv;
+       unsigned long long ret; /* Not used when writting */
+       union acpi_object in_obj[2];
+       struct acpi_object_list args = { 2, in_obj };
+
+       in_obj[0].type          = ACPI_TYPE_INTEGER;
+       in_obj[0].integer.value = reg;
+       in_obj[1].type          = ACPI_TYPE_INTEGER;
+       in_obj[1].integer.value = val;
+
+       if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
+{
+       lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
+       pr_info("hardware type %s found\n", dmi->ident);
+
+       return 1;
+}
+
+/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
+ * If the value is negative, the opposite of the hw value is used. */
+#define DEFINE_CONV(name, x, y, z)                           \
+       static union axis_conversion lis3lv02d_axis_##name = \
+               { .as_array = { x, y, z } }
+DEFINE_CONV(normal, 1, 2, 3);
+DEFINE_CONV(y_inverted, 1, -2, 3);
+DEFINE_CONV(x_inverted, -1, 2, 3);
+DEFINE_CONV(z_inverted, 1, 2, -3);
+DEFINE_CONV(xy_swap, 2, 1, 3);
+DEFINE_CONV(xy_rotated_left, -2, 1, 3);
+DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
+DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
+DEFINE_CONV(xy_rotated_right, 2, -1, 3);
+DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
+
+#define AXIS_DMI_MATCH(_ident, _name, _axis) {         \
+       .ident = _ident,                                \
+       .callback = lis3lv02d_dmi_matched,              \
+       .matches = {                                    \
+               DMI_MATCH(DMI_PRODUCT_NAME, _name)      \
+       },                                              \
+       .driver_data = &lis3lv02d_axis_##_axis          \
+}
+
+#define AXIS_DMI_MATCH2(_ident, _class1, _name1,       \
+                               _class2, _name2,        \
+                               _axis) {                \
+       .ident = _ident,                                \
+       .callback = lis3lv02d_dmi_matched,              \
+       .matches = {                                    \
+               DMI_MATCH(DMI_##_class1, _name1),       \
+               DMI_MATCH(DMI_##_class2, _name2),       \
+       },                                              \
+       .driver_data = &lis3lv02d_axis_##_axis          \
+}
+static struct dmi_system_id lis3lv02d_dmi_ids[] = {
+       /* product names are truncated to match all kinds of a same model */
+       AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
+       AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
+       AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
+       AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
+       AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
+       AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
+       AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
+       AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
+       AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
+       AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
+       AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd),
+       AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap),
+       AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
+       AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
+       AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
+       AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
+       AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap),
+       /* Intel-based HP Pavilion dv5 */
+       AXIS_DMI_MATCH2("HPDV5_I",
+                       PRODUCT_NAME, "HP Pavilion dv5",
+                       BOARD_NAME, "3603",
+                       x_inverted),
+       /* AMD-based HP Pavilion dv5 */
+       AXIS_DMI_MATCH2("HPDV5_A",
+                       PRODUCT_NAME, "HP Pavilion dv5",
+                       BOARD_NAME, "3600",
+                       y_inverted),
+       AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted),
+       AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted),
+       AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
+       AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
+       AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
+       AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
+       AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
+       AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
+       AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
+       { NULL, }
+/* Laptop models without axis info (yet):
+ * "NC6910" "HP Compaq 6910"
+ * "NC2400" "HP Compaq nc2400"
+ * "NX74x0" "HP Compaq nx74"
+ * "NX6325" "HP Compaq nx6325"
+ * "NC4400" "HP Compaq nc4400"
+ */
+};
+
+static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
+{
+       struct acpi_device *dev = lis3_dev.bus_priv;
+       unsigned long long ret; /* Not used when writing */
+       union acpi_object in_obj[1];
+       struct acpi_object_list args = { 1, in_obj };
+
+       in_obj[0].type          = ACPI_TYPE_INTEGER;
+       in_obj[0].integer.value = !!value;
+
+       acpi_evaluate_integer(dev->handle, "ALED", &args, &ret);
+}
+
+static struct delayed_led_classdev hpled_led = {
+       .led_classdev = {
+               .name                   = "hp::hddprotect",
+               .default_trigger        = "none",
+               .brightness_set         = delayed_sysfs_set,
+               .flags                  = LED_CORE_SUSPENDRESUME,
+       },
+       .set_brightness = hpled_set,
+};
+
+static acpi_status
+lis3lv02d_get_resource(struct acpi_resource *resource, void *context)
+{
+       if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
+               struct acpi_resource_extended_irq *irq;
+               u32 *device_irq = context;
+
+               irq = &resource->data.extended_irq;
+               *device_irq = irq->interrupts[0];
+       }
+
+       return AE_OK;
+}
+
+static void lis3lv02d_enum_resources(struct acpi_device *device)
+{
+       acpi_status status;
+
+       status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+                                       lis3lv02d_get_resource, &lis3_dev.irq);
+       if (ACPI_FAILURE(status))
+               printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
+}
+
+static int lis3lv02d_add(struct acpi_device *device)
+{
+       int ret;
+
+       if (!device)
+               return -EINVAL;
+
+       lis3_dev.bus_priv = device;
+       lis3_dev.init = lis3lv02d_acpi_init;
+       lis3_dev.read = lis3lv02d_acpi_read;
+       lis3_dev.write = lis3lv02d_acpi_write;
+       strcpy(acpi_device_name(device), DRIVER_NAME);
+       strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
+       device->driver_data = &lis3_dev;
+
+       /* obtain IRQ number of our device from ACPI */
+       lis3lv02d_enum_resources(device);
+
+       /* If possible use a "standard" axes order */
+       if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
+               pr_info("Using custom axes %d,%d,%d\n",
+                       lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+       } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+               pr_info("laptop model unknown, using default axes configuration\n");
+               lis3_dev.ac = lis3lv02d_axis_normal;
+       }
+
+       /* call the core layer do its init */
+       ret = lis3lv02d_init_device(&lis3_dev);
+       if (ret)
+               return ret;
+
+       INIT_WORK(&hpled_led.work, delayed_set_status_worker);
+       ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+       if (ret) {
+               lis3lv02d_joystick_disable();
+               lis3lv02d_poweroff(&lis3_dev);
+               flush_work(&hpled_led.work);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int lis3lv02d_remove(struct acpi_device *device, int type)
+{
+       if (!device)
+               return -EINVAL;
+
+       lis3lv02d_joystick_disable();
+       lis3lv02d_poweroff(&lis3_dev);
+
+       led_classdev_unregister(&hpled_led.led_classdev);
+       flush_work(&hpled_led.work);
+
+       return lis3lv02d_remove_fs(&lis3_dev);
+}
+
+
+#ifdef CONFIG_PM
+static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
+{
+       /* make sure the device is off when we suspend */
+       lis3lv02d_poweroff(&lis3_dev);
+       return 0;
+}
+
+static int lis3lv02d_resume(struct acpi_device *device)
+{
+       lis3lv02d_poweron(&lis3_dev);
+       return 0;
+}
+#else
+#define lis3lv02d_suspend NULL
+#define lis3lv02d_resume NULL
+#endif
+
+/* For the HP MDPS aka 3D Driveguard */
+static struct acpi_driver lis3lv02d_driver = {
+       .name  = DRIVER_NAME,
+       .class = ACPI_MDPS_CLASS,
+       .ids   = lis3lv02d_device_ids,
+       .ops = {
+               .add     = lis3lv02d_add,
+               .remove  = lis3lv02d_remove,
+               .suspend = lis3lv02d_suspend,
+               .resume  = lis3lv02d_resume,
+       }
+};
+
+static int __init lis3lv02d_init_module(void)
+{
+       int ret;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       ret = acpi_bus_register_driver(&lis3lv02d_driver);
+       if (ret < 0)
+               return ret;
+
+       pr_info("driver loaded\n");
+
+       return 0;
+}
+
+static void __exit lis3lv02d_exit_module(void)
+{
+       acpi_bus_unregister_driver(&lis3lv02d_driver);
+}
+
+MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED.");
+MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init_module);
+module_exit(lis3lv02d_exit_module);
index 7e9bb6df9d394659deeef7dba46090bc06d129bb..142d38579314837085930228752ed92adfaf4b0e 100644 (file)
@@ -804,6 +804,7 @@ static int __init msi_init(void)
        } else {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = MSI_LCD_LEVEL_MAX - 1;
                msibl_device = backlight_device_register("msi-laptop-bl", NULL,
                                                         NULL, &msibl_ops,
index 35278ad7e628412754e9d8bcc1281cfbfd38c178..d5419c9ec07a39e34ebc49d7698d39cb933a0da9 100644 (file)
@@ -254,6 +254,7 @@ static int __init msi_wmi_init(void)
        if (!acpi_video_backlight_support()) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
                backlight = backlight_device_register(DRV_NAME, NULL, NULL,
                                                      &msi_backlight_ops,
index cc1e0ba104d749603957d0017d6f1a364b38cc0b..05be30ee158b54e4e7a3d8344b2476c62fef6c78 100644 (file)
@@ -602,6 +602,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
        }
        /* initialize backlight */
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
        pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
                                                   &pcc_backlight_ops, &props);
index 5e83370b0812975c780630ca0782ef0cfbaac306..13d8d63bcca9ef7cf307860a72f9b94c06466ed8 100644 (file)
@@ -1305,8 +1305,9 @@ static int sony_nc_add(struct acpi_device *device)
                       "controlled by ACPI video driver\n");
        } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
                                                &handle))) {
-                                                       struct backlight_properties props;
+               struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
+               props.type = BACKLIGHT_PLATFORM;
                props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
                sony_backlight_device = backlight_device_register("sony", NULL,
                                                                  NULL,
index eb9922385ef8ff59c0148a2c764d747a07516685..947bdcaa0ce9b624b858ca786c7dffaff410056f 100644 (file)
@@ -6307,6 +6307,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                return 1;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = bright_maxlvl;
        props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
        ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME,
index 209cced786c60628b87455b6be7b60c977257c00..63f42a22e10240a32d58c6f4bd1ce7ddc87428b6 100644 (file)
@@ -1018,6 +1018,7 @@ static int __init toshiba_acpi_init(void)
                create_toshiba_proc_entries();
        }
 
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
        toshiba_backlight_device = backlight_device_register("toshiba",
                                                             &toshiba_acpi.p_dev->dev,
index 19bc73695475078a2b3a419e9ccfb9c4a4979882..fa4e0a5db3f8a15ccfd2981f52d09c8b165b7945 100644 (file)
@@ -142,7 +142,9 @@ void __pnp_remove_device(struct pnp_dev *dev);
 int pnp_check_port(struct pnp_dev *dev, struct resource *res);
 int pnp_check_mem(struct pnp_dev *dev, struct resource *res);
 int pnp_check_irq(struct pnp_dev *dev, struct resource *res);
+#ifdef CONFIG_ISA_DMA_API
 int pnp_check_dma(struct pnp_dev *dev, struct resource *res);
+#endif
 
 char *pnp_resource_type_name(struct resource *res);
 void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
index 0a15664eef1c65f2c9670f24ab03af0a604122c6..ed9ce507149ab87efe8692b24379a82ab728184c 100644 (file)
@@ -171,6 +171,7 @@ __add:
        return 0;
 }
 
+#ifdef CONFIG_ISA_DMA_API
 static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
 {
        struct resource *res, local_res;
@@ -210,6 +211,7 @@ __add:
        pnp_add_dma_resource(dev, res->start, res->flags);
        return 0;
 }
+#endif /* CONFIG_ISA_DMA_API */
 
 void pnp_init_resources(struct pnp_dev *dev)
 {
@@ -234,7 +236,8 @@ static void pnp_clean_resource_table(struct pnp_dev *dev)
 static int pnp_assign_resources(struct pnp_dev *dev, int set)
 {
        struct pnp_option *option;
-       int nport = 0, nmem = 0, nirq = 0, ndma = 0;
+       int nport = 0, nmem = 0, nirq = 0;
+       int ndma __maybe_unused = 0;
        int ret = 0;
 
        pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
@@ -256,9 +259,11 @@ static int pnp_assign_resources(struct pnp_dev *dev, int set)
                case IORESOURCE_IRQ:
                        ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
                        break;
+#ifdef CONFIG_ISA_DMA_API
                case IORESOURCE_DMA:
                        ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
                        break;
+#endif
                default:
                        ret = -EINVAL;
                        break;
index a925e6b63d72cff9953672c285210de80c3c488e..b0ecacbe53b191147f4146510ce32b25ab48de70 100644 (file)
@@ -409,9 +409,9 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
        return 1;
 }
 
+#ifdef CONFIG_ISA_DMA_API
 int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
 {
-#ifndef CONFIG_IA64
        int i;
        struct pnp_dev *tdev;
        struct resource *tres;
@@ -466,11 +466,8 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
        }
 
        return 1;
-#else
-       /* IA64 does not have legacy DMA */
-       return 0;
-#endif
 }
+#endif /* CONFIG_ISA_DMA_API */
 
 unsigned long pnp_resource_type(struct resource *res)
 {
index 61bf5d724139c80a93fd86350dd7ebb46f9eb8c0..52a462fc6b84467f3aafca8d09cf5630b7d500bd 100644 (file)
@@ -117,10 +117,24 @@ config BATTERY_BQ20Z75
 
 config BATTERY_BQ27x00
        tristate "BQ27x00 battery driver"
+       help
+         Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.
+
+config BATTERY_BQ27X00_I2C
+       bool "BQ27200/BQ27500 support"
+       depends on BATTERY_BQ27x00
        depends on I2C
+       default y
        help
          Say Y here to enable support for batteries with BQ27x00 (I2C) chips.
 
+config BATTERY_BQ27X00_PLATFORM
+       bool "BQ27000 support"
+       depends on BATTERY_BQ27x00
+       default y
+       help
+         Say Y here to enable support for batteries with BQ27000 (HDQ) chips.
+
 config BATTERY_DA9030
        tristate "DA9030 battery driver"
        depends on PMIC_DA903X
index 492da27e1a47ed8960bd76e7626225e7fe0510f8..506585e31a5bee12ff53e3d7b3604f11d9d70902 100644 (file)
 #include <linux/power_supply.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/power/bq20z75.h>
 
 enum {
        REG_MANUFACTURER_DATA,
@@ -38,11 +42,22 @@ enum {
        REG_CYCLE_COUNT,
        REG_SERIAL_NUMBER,
        REG_REMAINING_CAPACITY,
+       REG_REMAINING_CAPACITY_CHARGE,
        REG_FULL_CHARGE_CAPACITY,
+       REG_FULL_CHARGE_CAPACITY_CHARGE,
        REG_DESIGN_CAPACITY,
+       REG_DESIGN_CAPACITY_CHARGE,
        REG_DESIGN_VOLTAGE,
 };
 
+/* Battery Mode defines */
+#define BATTERY_MODE_OFFSET            0x03
+#define BATTERY_MODE_MASK              0x8000
+enum bq20z75_battery_mode {
+       BATTERY_MODE_AMPS,
+       BATTERY_MODE_WATTS
+};
+
 /* manufacturer access defines */
 #define MANUFACTURER_ACCESS_STATUS     0x0006
 #define MANUFACTURER_ACCESS_SLEEP      0x0011
@@ -78,8 +93,12 @@ static const struct bq20z75_device_data {
                BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
        [REG_REMAINING_CAPACITY] =
                BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
+       [REG_REMAINING_CAPACITY_CHARGE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
        [REG_FULL_CHARGE_CAPACITY] =
                BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
+       [REG_FULL_CHARGE_CAPACITY_CHARGE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
        [REG_TIME_TO_EMPTY] =
                BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
                        65535),
@@ -93,6 +112,9 @@ static const struct bq20z75_device_data {
        [REG_DESIGN_CAPACITY] =
                BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
                        65535),
+       [REG_DESIGN_CAPACITY_CHARGE] =
+               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0,
+                       65535),
        [REG_DESIGN_VOLTAGE] =
                BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
                        65535),
@@ -117,39 +139,72 @@ static enum power_supply_property bq20z75_properties[] = {
        POWER_SUPPLY_PROP_ENERGY_NOW,
        POWER_SUPPLY_PROP_ENERGY_FULL,
        POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
 struct bq20z75_info {
-       struct i2c_client       *client;
-       struct power_supply     power_supply;
+       struct i2c_client               *client;
+       struct power_supply             power_supply;
+       struct bq20z75_platform_data    *pdata;
+       bool                            is_present;
+       bool                            gpio_detect;
+       bool                            enable_detection;
+       int                             irq;
 };
 
 static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
 {
-       s32 ret;
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
+       s32 ret = 0;
+       int retries = 1;
+
+       if (bq20z75_device->pdata)
+               retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
+
+       while (retries > 0) {
+               ret = i2c_smbus_read_word_data(client, address);
+               if (ret >= 0)
+                       break;
+               retries--;
+       }
 
-       ret = i2c_smbus_read_word_data(client, address);
        if (ret < 0) {
-               dev_err(&client->dev,
+               dev_dbg(&client->dev,
                        "%s: i2c read at address 0x%x failed\n",
                        __func__, address);
                return ret;
        }
+
        return le16_to_cpu(ret);
 }
 
 static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
        u16 value)
 {
-       s32 ret;
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
+       s32 ret = 0;
+       int retries = 1;
+
+       if (bq20z75_device->pdata)
+               retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
+
+       while (retries > 0) {
+               ret = i2c_smbus_write_word_data(client, address,
+                       le16_to_cpu(value));
+               if (ret >= 0)
+                       break;
+               retries--;
+       }
 
-       ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value));
        if (ret < 0) {
-               dev_err(&client->dev,
+               dev_dbg(&client->dev,
                        "%s: i2c write to address 0x%x failed\n",
                        __func__, address);
                return ret;
        }
+
        return 0;
 }
 
@@ -158,6 +213,19 @@ static int bq20z75_get_battery_presence_and_health(
        union power_supply_propval *val)
 {
        s32 ret;
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
+
+       if (psp == POWER_SUPPLY_PROP_PRESENT &&
+               bq20z75_device->gpio_detect) {
+               ret = gpio_get_value(
+                       bq20z75_device->pdata->battery_detect);
+               if (ret == bq20z75_device->pdata->battery_detect_present)
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               bq20z75_device->is_present = val->intval;
+               return ret;
+       }
 
        /* Write to ManufacturerAccess with
         * ManufacturerAccess command and then
@@ -165,9 +233,11 @@ static int bq20z75_get_battery_presence_and_health(
        ret = bq20z75_write_word_data(client,
                bq20z75_data[REG_MANUFACTURER_DATA].addr,
                MANUFACTURER_ACCESS_STATUS);
-       if (ret < 0)
+       if (ret < 0) {
+               if (psp == POWER_SUPPLY_PROP_PRESENT)
+                       val->intval = 0; /* battery removed */
                return ret;
-
+       }
 
        ret = bq20z75_read_word_data(client,
                bq20z75_data[REG_MANUFACTURER_DATA].addr);
@@ -248,30 +318,39 @@ static void  bq20z75_unit_adjustment(struct i2c_client *client,
 {
 #define BASE_UNIT_CONVERSION           1000
 #define BATTERY_MODE_CAP_MULT_WATT     (10 * BASE_UNIT_CONVERSION)
-#define TIME_UNIT_CONVERSION           600
-#define TEMP_KELVIN_TO_CELCIUS         2731
+#define TIME_UNIT_CONVERSION           60
+#define TEMP_KELVIN_TO_CELSIUS         2731
        switch (psp) {
        case POWER_SUPPLY_PROP_ENERGY_NOW:
        case POWER_SUPPLY_PROP_ENERGY_FULL:
        case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+               /* bq20z75 provides energy in units of 10mWh.
+                * Convert to ĀµWh
+                */
                val->intval *= BATTERY_MODE_CAP_MULT_WATT;
                break;
 
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
        case POWER_SUPPLY_PROP_CURRENT_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
                val->intval *= BASE_UNIT_CONVERSION;
                break;
 
        case POWER_SUPPLY_PROP_TEMP:
-               /* bq20z75 provides battery tempreture in 0.1Ā°K
-                * so convert it to 0.1Ā°C */
-               val->intval -= TEMP_KELVIN_TO_CELCIUS;
-               val->intval *= 10;
+               /* bq20z75 provides battery temperature in 0.1K
+                * so convert it to 0.1Ā°C
+                */
+               val->intval -= TEMP_KELVIN_TO_CELSIUS;
                break;
 
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
        case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+               /* bq20z75 provides time to empty and time to full in minutes.
+                * Convert to seconds
+                */
                val->intval *= TIME_UNIT_CONVERSION;
                break;
 
@@ -281,11 +360,44 @@ static void  bq20z75_unit_adjustment(struct i2c_client *client,
        }
 }
 
+static enum bq20z75_battery_mode
+bq20z75_set_battery_mode(struct i2c_client *client,
+       enum bq20z75_battery_mode mode)
+{
+       int ret, original_val;
+
+       original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET);
+       if (original_val < 0)
+               return original_val;
+
+       if ((original_val & BATTERY_MODE_MASK) == mode)
+               return mode;
+
+       if (mode == BATTERY_MODE_AMPS)
+               ret = original_val & ~BATTERY_MODE_MASK;
+       else
+               ret = original_val | BATTERY_MODE_MASK;
+
+       ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret);
+       if (ret < 0)
+               return ret;
+
+       return original_val & BATTERY_MODE_MASK;
+}
+
 static int bq20z75_get_battery_capacity(struct i2c_client *client,
        int reg_offset, enum power_supply_property psp,
        union power_supply_propval *val)
 {
        s32 ret;
+       enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS;
+
+       if (power_supply_is_amp_property(psp))
+               mode = BATTERY_MODE_AMPS;
+
+       mode = bq20z75_set_battery_mode(client, mode);
+       if (mode < 0)
+               return mode;
 
        ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
        if (ret < 0)
@@ -298,6 +410,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client,
        } else
                val->intval = ret;
 
+       ret = bq20z75_set_battery_mode(client, mode);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
@@ -318,12 +434,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client,
        return 0;
 }
 
+static int bq20z75_get_property_index(struct i2c_client *client,
+       enum power_supply_property psp)
+{
+       int count;
+       for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++)
+               if (psp == bq20z75_data[count].psp)
+                       return count;
+
+       dev_warn(&client->dev,
+               "%s: Invalid Property - %d\n", __func__, psp);
+
+       return -EINVAL;
+}
+
 static int bq20z75_get_property(struct power_supply *psy,
        enum power_supply_property psp,
        union power_supply_propval *val)
 {
-       int count;
-       int ret;
+       int ret = 0;
        struct bq20z75_info *bq20z75_device = container_of(psy,
                                struct bq20z75_info, power_supply);
        struct i2c_client *client = bq20z75_device->client;
@@ -332,8 +461,8 @@ static int bq20z75_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_PRESENT:
        case POWER_SUPPLY_PROP_HEALTH:
                ret = bq20z75_get_battery_presence_and_health(client, psp, val);
-               if (ret)
-                       return ret;
+               if (psp == POWER_SUPPLY_PROP_PRESENT)
+                       return 0;
                break;
 
        case POWER_SUPPLY_PROP_TECHNOLOGY:
@@ -343,22 +472,19 @@ static int bq20z75_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_ENERGY_NOW:
        case POWER_SUPPLY_PROP_ENERGY_FULL:
        case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
        case POWER_SUPPLY_PROP_CAPACITY:
-               for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
-                       if (psp == bq20z75_data[count].psp)
-                               break;
-               }
-
-               ret = bq20z75_get_battery_capacity(client, count, psp, val);
-               if (ret)
-                       return ret;
+               ret = bq20z75_get_property_index(client, psp);
+               if (ret < 0)
+                       break;
 
+               ret = bq20z75_get_battery_capacity(client, ret, psp, val);
                break;
 
        case POWER_SUPPLY_PROP_SERIAL_NUMBER:
                ret = bq20z75_get_battery_serial_number(client, val);
-               if (ret)
-                       return ret;
                break;
 
        case POWER_SUPPLY_PROP_STATUS:
@@ -369,15 +495,11 @@ static int bq20z75_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
        case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
        case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-               for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) {
-                       if (psp == bq20z75_data[count].psp)
-                               break;
-               }
-
-               ret = bq20z75_get_battery_property(client, count, psp, val);
-               if (ret)
-                       return ret;
+               ret = bq20z75_get_property_index(client, psp);
+               if (ret < 0)
+                       break;
 
+               ret = bq20z75_get_battery_property(client, ret, psp, val);
                break;
 
        default:
@@ -386,26 +508,58 @@ static int bq20z75_get_property(struct power_supply *psy,
                return -EINVAL;
        }
 
-       /* Convert units to match requirements for power supply class */
-       bq20z75_unit_adjustment(client, psp, val);
+       if (!bq20z75_device->enable_detection)
+               goto done;
+
+       if (!bq20z75_device->gpio_detect &&
+               bq20z75_device->is_present != (ret >= 0)) {
+               bq20z75_device->is_present = (ret >= 0);
+               power_supply_changed(&bq20z75_device->power_supply);
+       }
+
+done:
+       if (!ret) {
+               /* Convert units to match requirements for power supply class */
+               bq20z75_unit_adjustment(client, psp, val);
+       }
 
        dev_dbg(&client->dev,
-               "%s: property = %d, value = %d\n", __func__, psp, val->intval);
+               "%s: property = %d, value = %x\n", __func__, psp, val->intval);
+
+       if (ret && bq20z75_device->is_present)
+               return ret;
+
+       /* battery not present, so return NODATA for properties */
+       if (ret)
+               return -ENODATA;
 
        return 0;
 }
 
-static int bq20z75_probe(struct i2c_client *client,
+static irqreturn_t bq20z75_irq(int irq, void *devid)
+{
+       struct power_supply *battery = devid;
+
+       power_supply_changed(battery);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit bq20z75_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
        struct bq20z75_info *bq20z75_device;
+       struct bq20z75_platform_data *pdata = client->dev.platform_data;
        int rc;
+       int irq;
 
        bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
        if (!bq20z75_device)
                return -ENOMEM;
 
        bq20z75_device->client = client;
+       bq20z75_device->enable_detection = false;
+       bq20z75_device->gpio_detect = false;
        bq20z75_device->power_supply.name = "battery";
        bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
        bq20z75_device->power_supply.properties = bq20z75_properties;
@@ -413,26 +567,86 @@ static int bq20z75_probe(struct i2c_client *client,
                ARRAY_SIZE(bq20z75_properties);
        bq20z75_device->power_supply.get_property = bq20z75_get_property;
 
+       if (pdata) {
+               bq20z75_device->gpio_detect =
+                       gpio_is_valid(pdata->battery_detect);
+               bq20z75_device->pdata = pdata;
+       }
+
        i2c_set_clientdata(client, bq20z75_device);
 
+       if (!bq20z75_device->gpio_detect)
+               goto skip_gpio;
+
+       rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
+       if (rc) {
+               dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
+               bq20z75_device->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       rc = gpio_direction_input(pdata->battery_detect);
+       if (rc) {
+               dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
+               gpio_free(pdata->battery_detect);
+               bq20z75_device->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       irq = gpio_to_irq(pdata->battery_detect);
+       if (irq <= 0) {
+               dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
+               gpio_free(pdata->battery_detect);
+               bq20z75_device->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       rc = request_irq(irq, bq20z75_irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               dev_name(&client->dev), &bq20z75_device->power_supply);
+       if (rc) {
+               dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
+               gpio_free(pdata->battery_detect);
+               bq20z75_device->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       bq20z75_device->irq = irq;
+
+skip_gpio:
+
        rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
        if (rc) {
                dev_err(&client->dev,
                        "%s: Failed to register power supply\n", __func__);
-               kfree(bq20z75_device);
-               return rc;
+               goto exit_psupply;
        }
 
        dev_info(&client->dev,
                "%s: battery gas gauge device registered\n", client->name);
 
        return 0;
+
+exit_psupply:
+       if (bq20z75_device->irq)
+               free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
+       if (bq20z75_device->gpio_detect)
+               gpio_free(pdata->battery_detect);
+
+       kfree(bq20z75_device);
+
+       return rc;
 }
 
-static int bq20z75_remove(struct i2c_client *client)
+static int __devexit bq20z75_remove(struct i2c_client *client)
 {
        struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
 
+       if (bq20z75_device->irq)
+               free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
+       if (bq20z75_device->gpio_detect)
+               gpio_free(bq20z75_device->pdata->battery_detect);
+
        power_supply_unregister(&bq20z75_device->power_supply);
        kfree(bq20z75_device);
        bq20z75_device = NULL;
@@ -444,13 +658,14 @@ static int bq20z75_remove(struct i2c_client *client)
 static int bq20z75_suspend(struct i2c_client *client,
        pm_message_t state)
 {
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
        s32 ret;
 
        /* write to manufacturer access with sleep command */
        ret = bq20z75_write_word_data(client,
                bq20z75_data[REG_MANUFACTURER_DATA].addr,
                MANUFACTURER_ACCESS_SLEEP);
-       if (ret < 0)
+       if (bq20z75_device->is_present && ret < 0)
                return ret;
 
        return 0;
@@ -465,10 +680,11 @@ static const struct i2c_device_id bq20z75_id[] = {
        { "bq20z75", 0 },
        {}
 };
+MODULE_DEVICE_TABLE(i2c, bq20z75_id);
 
 static struct i2c_driver bq20z75_battery_driver = {
        .probe          = bq20z75_probe,
-       .remove         = bq20z75_remove,
+       .remove         = __devexit_p(bq20z75_remove),
        .suspend        = bq20z75_suspend,
        .resume         = bq20z75_resume,
        .id_table       = bq20z75_id,
index eff0273d4030d71a745f109a25754be52eaa1d8e..59e68dbd028b31e4bf8e17f5e33bc19e0deb7492 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
  * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
  *
  * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
  *
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  */
+
+/*
+ * Datasheets:
+ * http://focus.ti.com/docs/prod/folders/print/bq27000.html
+ * http://focus.ti.com/docs/prod/folders/print/bq27500.html
+ */
+
 #include <linux/module.h>
 #include <linux/param.h>
 #include <linux/jiffies.h>
@@ -27,7 +35,9 @@
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 
-#define DRIVER_VERSION                 "1.1.0"
+#include <linux/power/bq27x00_battery.h>
+
+#define DRIVER_VERSION                 "1.2.0"
 
 #define BQ27x00_REG_TEMP               0x06
 #define BQ27x00_REG_VOLT               0x08
 #define BQ27x00_REG_TTE                        0x16
 #define BQ27x00_REG_TTF                        0x18
 #define BQ27x00_REG_TTECP              0x26
+#define BQ27x00_REG_NAC                        0x0C /* Nominal available capaciy */
+#define BQ27x00_REG_LMD                        0x12 /* Last measured discharge */
+#define BQ27x00_REG_CYCT               0x2A /* Cycle count total */
+#define BQ27x00_REG_AE                 0x22 /* Available enery */
 
 #define BQ27000_REG_RSOC               0x0B /* Relative State-of-Charge */
+#define BQ27000_REG_ILMD               0x76 /* Initial last measured discharge */
 #define BQ27000_FLAG_CHGS              BIT(7)
+#define BQ27000_FLAG_FC                        BIT(5)
 
-#define BQ27500_REG_SOC                        0x2c
+#define BQ27500_REG_SOC                        0x2C
+#define BQ27500_REG_DCAP               0x3C /* Design capacity */
 #define BQ27500_FLAG_DSC               BIT(0)
 #define BQ27500_FLAG_FC                        BIT(9)
 
-/* If the system has several batteries we need a different name for each
- * of them...
- */
-static DEFINE_IDR(battery_id);
-static DEFINE_MUTEX(battery_mutex);
+#define BQ27000_RS                     20 /* Resistor sense */
 
 struct bq27x00_device_info;
 struct bq27x00_access_methods {
-       int (*read)(u8 reg, int *rt_value, int b_single,
-               struct bq27x00_device_info *di);
+       int (*read)(struct bq27x00_device_info *di, u8 reg, bool single);
 };
 
 enum bq27x00_chip { BQ27000, BQ27500 };
 
+struct bq27x00_reg_cache {
+       int temperature;
+       int time_to_empty;
+       int time_to_empty_avg;
+       int time_to_full;
+       int charge_full;
+       int charge_counter;
+       int capacity;
+       int flags;
+
+       int current_now;
+};
+
 struct bq27x00_device_info {
        struct device           *dev;
        int                     id;
-       struct bq27x00_access_methods   *bus;
-       struct power_supply     bat;
        enum bq27x00_chip       chip;
 
-       struct i2c_client       *client;
+       struct bq27x00_reg_cache cache;
+       int charge_design_full;
+
+       unsigned long last_update;
+       struct delayed_work work;
+
+       struct power_supply     bat;
+
+       struct bq27x00_access_methods bus;
+
+       struct mutex lock;
 };
 
 static enum power_supply_property bq27x00_battery_props[] = {
@@ -78,164 +111,328 @@ static enum power_supply_property bq27x00_battery_props[] = {
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+       POWER_SUPPLY_PROP_CHARGE_COUNTER,
+       POWER_SUPPLY_PROP_ENERGY_NOW,
 };
 
+static unsigned int poll_interval = 360;
+module_param(poll_interval, uint, 0644);
+MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \
+                               "0 disables polling");
+
 /*
  * Common code for BQ27x00 devices
  */
 
-static int bq27x00_read(u8 reg, int *rt_value, int b_single,
-                       struct bq27x00_device_info *di)
+static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
+               bool single)
 {
-       return di->bus->read(reg, rt_value, b_single, di);
+       return di->bus.read(di, reg, single);
 }
 
 /*
- * Return the battery temperature in tenths of degree Celsius
+ * Return the battery Relative State-of-Charge
  * Or < 0 if something fails.
  */
-static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
 {
-       int ret;
-       int temp = 0;
+       int rsoc;
 
-       ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
-       if (ret) {
-               dev_err(di->dev, "error reading temperature\n");
-               return ret;
+       if (di->chip == BQ27500)
+               rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
+       else
+               rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
+
+       if (rsoc < 0)
+               dev_err(di->dev, "error reading relative State-of-Charge\n");
+
+       return rsoc;
+}
+
+/*
+ * Return a battery charge value in ĀµAh
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
+{
+       int charge;
+
+       charge = bq27x00_read(di, reg, false);
+       if (charge < 0) {
+               dev_err(di->dev, "error reading nominal available capacity\n");
+               return charge;
        }
 
        if (di->chip == BQ27500)
-               return temp - 2731;
+               charge *= 1000;
        else
-               return ((temp >> 2) - 273) * 10;
+               charge = charge * 3570 / BQ27000_RS;
+
+       return charge;
 }
 
 /*
- * Return the battery Voltage in milivolts
+ * Return the battery Nominal available capaciy in ĀµAh
  * Or < 0 if something fails.
  */
-static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di)
 {
-       int ret;
-       int volt = 0;
+       return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC);
+}
 
-       ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
-       if (ret) {
-               dev_err(di->dev, "error reading voltage\n");
-               return ret;
+/*
+ * Return the battery Last measured discharge in ĀµAh
+ * Or < 0 if something fails.
+ */
+static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di)
+{
+       return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD);
+}
+
+/*
+ * Return the battery Initial last measured discharge in ĀµAh
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
+{
+       int ilmd;
+
+       if (di->chip == BQ27500)
+               ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
+       else
+               ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
+
+       if (ilmd < 0) {
+               dev_err(di->dev, "error reading initial last measured discharge\n");
+               return ilmd;
        }
 
-       return volt * 1000;
+       if (di->chip == BQ27500)
+               ilmd *= 1000;
+       else
+               ilmd = ilmd * 256 * 3570 / BQ27000_RS;
+
+       return ilmd;
 }
 
 /*
- * Return the battery average current
- * Note that current can be negative signed as well
- * Or 0 if something fails.
+ * Return the battery Cycle count total
+ * Or < 0 if something fails.
  */
-static int bq27x00_battery_current(struct bq27x00_device_info *di)
+static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di)
 {
-       int ret;
-       int curr = 0;
-       int flags = 0;
+       int cyct;
 
-       ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
-       if (ret) {
-               dev_err(di->dev, "error reading current\n");
-               return 0;
+       cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false);
+       if (cyct < 0)
+               dev_err(di->dev, "error reading cycle count total\n");
+
+       return cyct;
+}
+
+/*
+ * Read a time register.
+ * Return < 0 if something fails.
+ */
+static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
+{
+       int tval;
+
+       tval = bq27x00_read(di, reg, false);
+       if (tval < 0) {
+               dev_err(di->dev, "error reading register %02x: %d\n", reg, tval);
+               return tval;
        }
 
-       if (di->chip == BQ27500) {
-               /* bq27500 returns signed value */
-               curr = (int)(s16)curr;
-       } else {
-               ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
-               if (ret < 0) {
-                       dev_err(di->dev, "error reading flags\n");
-                       return 0;
-               }
-               if (flags & BQ27000_FLAG_CHGS) {
-                       dev_dbg(di->dev, "negative current!\n");
-                       curr = -curr;
-               }
+       if (tval == 65535)
+               return -ENODATA;
+
+       return tval * 60;
+}
+
+static void bq27x00_update(struct bq27x00_device_info *di)
+{
+       struct bq27x00_reg_cache cache = {0, };
+       bool is_bq27500 = di->chip == BQ27500;
+
+       cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500);
+       if (cache.flags >= 0) {
+               cache.capacity = bq27x00_battery_read_rsoc(di);
+               cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false);
+               cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
+               cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
+               cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
+               cache.charge_full = bq27x00_battery_read_lmd(di);
+               cache.charge_counter = bq27x00_battery_read_cyct(di);
+
+               if (!is_bq27500)
+                       cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
+
+               /* We only have to read charge design full once */
+               if (di->charge_design_full <= 0)
+                       di->charge_design_full = bq27x00_battery_read_ilmd(di);
+       }
+
+       /* Ignore current_now which is a snapshot of the current battery state
+        * and is likely to be different even between two consecutive reads */
+       if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) {
+               di->cache = cache;
+               power_supply_changed(&di->bat);
        }
 
-       return curr * 1000;
+       di->last_update = jiffies;
+}
+
+static void bq27x00_battery_poll(struct work_struct *work)
+{
+       struct bq27x00_device_info *di =
+               container_of(work, struct bq27x00_device_info, work.work);
+
+       bq27x00_update(di);
+
+       if (poll_interval > 0) {
+               /* The timer does not have to be accurate. */
+               set_timer_slack(&di->work.timer, poll_interval * HZ / 4);
+               schedule_delayed_work(&di->work, poll_interval * HZ);
+       }
 }
 
+
 /*
- * Return the battery Relative State-of-Charge
+ * Return the battery temperature in tenths of degree Celsius
  * Or < 0 if something fails.
  */
-static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di,
+       union power_supply_propval *val)
 {
-       int ret;
-       int rsoc = 0;
+       if (di->cache.temperature < 0)
+               return di->cache.temperature;
 
        if (di->chip == BQ27500)
-               ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di);
+               val->intval = di->cache.temperature - 2731;
        else
-               ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di);
-       if (ret) {
-               dev_err(di->dev, "error reading relative State-of-Charge\n");
-               return ret;
+               val->intval = ((di->cache.temperature * 5) - 5463) / 2;
+
+       return 0;
+}
+
+/*
+ * Return the battery average current in ĀµA
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di,
+       union power_supply_propval *val)
+{
+       int curr;
+
+       if (di->chip == BQ27500)
+           curr = bq27x00_read(di, BQ27x00_REG_AI, false);
+       else
+           curr = di->cache.current_now;
+
+       if (curr < 0)
+               return curr;
+
+       if (di->chip == BQ27500) {
+               /* bq27500 returns signed value */
+               val->intval = (int)((s16)curr) * 1000;
+       } else {
+               if (di->cache.flags & BQ27000_FLAG_CHGS) {
+                       dev_dbg(di->dev, "negative current!\n");
+                       curr = -curr;
+               }
+
+               val->intval = curr * 3570 / BQ27000_RS;
        }
 
-       return rsoc;
+       return 0;
 }
 
 static int bq27x00_battery_status(struct bq27x00_device_info *di,
-                                 union power_supply_propval *val)
+       union power_supply_propval *val)
 {
-       int flags = 0;
        int status;
-       int ret;
-
-       ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
-       if (ret < 0) {
-               dev_err(di->dev, "error reading flags\n");
-               return ret;
-       }
 
        if (di->chip == BQ27500) {
-               if (flags & BQ27500_FLAG_FC)
+               if (di->cache.flags & BQ27500_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
-               else if (flags & BQ27500_FLAG_DSC)
+               else if (di->cache.flags & BQ27500_FLAG_DSC)
                        status = POWER_SUPPLY_STATUS_DISCHARGING;
                else
                        status = POWER_SUPPLY_STATUS_CHARGING;
        } else {
-               if (flags & BQ27000_FLAG_CHGS)
+               if (di->cache.flags & BQ27000_FLAG_FC)
+                       status = POWER_SUPPLY_STATUS_FULL;
+               else if (di->cache.flags & BQ27000_FLAG_CHGS)
                        status = POWER_SUPPLY_STATUS_CHARGING;
+               else if (power_supply_am_i_supplied(&di->bat))
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
                else
                        status = POWER_SUPPLY_STATUS_DISCHARGING;
        }
 
        val->intval = status;
+
        return 0;
 }
 
 /*
- * Read a time register.
- * Return < 0 if something fails.
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
  */
-static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
-                               union power_supply_propval *val)
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
+       union power_supply_propval *val)
 {
-       int tval = 0;
-       int ret;
+       int volt;
 
-       ret = bq27x00_read(reg, &tval, 0, di);
-       if (ret) {
-               dev_err(di->dev, "error reading register %02x\n", reg);
-               return ret;
+       volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
+       if (volt < 0)
+               return volt;
+
+       val->intval = volt * 1000;
+
+       return 0;
+}
+
+/*
+ * Return the battery Available energy in ĀµWh
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_energy(struct bq27x00_device_info *di,
+       union power_supply_propval *val)
+{
+       int ae;
+
+       ae = bq27x00_read(di, BQ27x00_REG_AE, false);
+       if (ae < 0) {
+               dev_err(di->dev, "error reading available energy\n");
+               return ae;
        }
 
-       if (tval == 65535)
-               return -ENODATA;
+       if (di->chip == BQ27500)
+               ae *= 1000;
+       else
+               ae = ae * 29200 / BQ27000_RS;
+
+       val->intval = ae;
+
+       return 0;
+}
+
+
+static int bq27x00_simple_value(int value,
+       union power_supply_propval *val)
+{
+       if (value < 0)
+               return value;
+
+       val->intval = value;
 
-       val->intval = tval * 60;
        return 0;
 }
 
@@ -249,33 +446,61 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
        int ret = 0;
        struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
 
+       mutex_lock(&di->lock);
+       if (time_is_before_jiffies(di->last_update + 5 * HZ)) {
+               cancel_delayed_work_sync(&di->work);
+               bq27x00_battery_poll(&di->work.work);
+       }
+       mutex_unlock(&di->lock);
+
+       if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
+               return -ENODEV;
+
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                ret = bq27x00_battery_status(di, val);
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               ret = bq27x00_battery_voltage(di, val);
+               break;
        case POWER_SUPPLY_PROP_PRESENT:
-               val->intval = bq27x00_battery_voltage(di);
-               if (psp == POWER_SUPPLY_PROP_PRESENT)
-                       val->intval = val->intval <= 0 ? 0 : 1;
+               val->intval = di->cache.flags < 0 ? 0 : 1;
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
-               val->intval = bq27x00_battery_current(di);
+               ret = bq27x00_battery_current(di, val);
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               val->intval = bq27x00_battery_rsoc(di);
+               ret = bq27x00_simple_value(di->cache.capacity, val);
                break;
        case POWER_SUPPLY_PROP_TEMP:
-               val->intval = bq27x00_battery_temperature(di);
+               ret = bq27x00_battery_temperature(di, val);
                break;
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
-               ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val);
+               ret = bq27x00_simple_value(di->cache.time_to_empty, val);
                break;
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
-               ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val);
+               ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val);
                break;
        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
-               ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val);
+               ret = bq27x00_simple_value(di->cache.time_to_full, val);
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val);
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               ret = bq27x00_simple_value(di->cache.charge_full, val);
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+               ret = bq27x00_simple_value(di->charge_design_full, val);
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+               ret = bq27x00_simple_value(di->cache.charge_counter, val);
+               break;
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+               ret = bq27x00_battery_energy(di, val);
                break;
        default:
                return -EINVAL;
@@ -284,56 +509,91 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
        return ret;
 }
 
-static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+static void bq27x00_external_power_changed(struct power_supply *psy)
 {
+       struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+       cancel_delayed_work_sync(&di->work);
+       schedule_delayed_work(&di->work, 0);
+}
+
+static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+       int ret;
+
        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        di->bat.properties = bq27x00_battery_props;
        di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
        di->bat.get_property = bq27x00_battery_get_property;
-       di->bat.external_power_changed = NULL;
+       di->bat.external_power_changed = bq27x00_external_power_changed;
+
+       INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll);
+       mutex_init(&di->lock);
+
+       ret = power_supply_register(di->dev, &di->bat);
+       if (ret) {
+               dev_err(di->dev, "failed to register battery: %d\n", ret);
+               return ret;
+       }
+
+       dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
+
+       bq27x00_update(di);
+
+       return 0;
 }
 
-/*
- * i2c specific code
+static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
+{
+       cancel_delayed_work_sync(&di->work);
+
+       power_supply_unregister(&di->bat);
+
+       mutex_destroy(&di->lock);
+}
+
+
+/* i2c specific code */
+#ifdef CONFIG_BATTERY_BQ27X00_I2C
+
+/* If the system has several batteries we need a different name for each
+ * of them...
  */
+static DEFINE_IDR(battery_id);
+static DEFINE_MUTEX(battery_mutex);
 
-static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single,
-                       struct bq27x00_device_info *di)
+static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single)
 {
-       struct i2c_client *client = di->client;
-       struct i2c_msg msg[1];
+       struct i2c_client *client = to_i2c_client(di->dev);
+       struct i2c_msg msg[2];
        unsigned char data[2];
-       int err;
+       int ret;
 
        if (!client->adapter)
                return -ENODEV;
 
-       msg->addr = client->addr;
-       msg->flags = 0;
-       msg->len = 1;
-       msg->buf = data;
-
-       data[0] = reg;
-       err = i2c_transfer(client->adapter, msg, 1);
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].buf = &reg;
+       msg[0].len = sizeof(reg);
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+       if (single)
+               msg[1].len = 1;
+       else
+               msg[1].len = 2;
 
-       if (err >= 0) {
-               if (!b_single)
-                       msg->len = 2;
-               else
-                       msg->len = 1;
+       ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+       if (ret < 0)
+               return ret;
 
-               msg->flags = I2C_M_RD;
-               err = i2c_transfer(client->adapter, msg, 1);
-               if (err >= 0) {
-                       if (!b_single)
-                               *rt_value = get_unaligned_le16(data);
-                       else
-                               *rt_value = data[0];
+       if (!single)
+               ret = get_unaligned_le16(data);
+       else
+               ret = data[0];
 
-                       return 0;
-               }
-       }
-       return err;
+       return ret;
 }
 
 static int bq27x00_battery_probe(struct i2c_client *client,
@@ -341,7 +601,6 @@ static int bq27x00_battery_probe(struct i2c_client *client,
 {
        char *name;
        struct bq27x00_device_info *di;
-       struct bq27x00_access_methods *bus;
        int num;
        int retval = 0;
 
@@ -368,38 +627,20 @@ static int bq27x00_battery_probe(struct i2c_client *client,
                retval = -ENOMEM;
                goto batt_failed_2;
        }
+
        di->id = num;
+       di->dev = &client->dev;
        di->chip = id->driver_data;
+       di->bat.name = name;
+       di->bus.read = &bq27x00_read_i2c;
 
-       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-       if (!bus) {
-               dev_err(&client->dev, "failed to allocate access method "
-                                       "data\n");
-               retval = -ENOMEM;
+       if (bq27x00_powersupply_init(di))
                goto batt_failed_3;
-       }
 
        i2c_set_clientdata(client, di);
-       di->dev = &client->dev;
-       di->bat.name = name;
-       bus->read = &bq27x00_read_i2c;
-       di->bus = bus;
-       di->client = client;
-
-       bq27x00_powersupply_init(di);
-
-       retval = power_supply_register(&client->dev, &di->bat);
-       if (retval) {
-               dev_err(&client->dev, "failed to register battery\n");
-               goto batt_failed_4;
-       }
-
-       dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 
        return 0;
 
-batt_failed_4:
-       kfree(bus);
 batt_failed_3:
        kfree(di);
 batt_failed_2:
@@ -416,9 +657,8 @@ static int bq27x00_battery_remove(struct i2c_client *client)
 {
        struct bq27x00_device_info *di = i2c_get_clientdata(client);
 
-       power_supply_unregister(&di->bat);
+       bq27x00_powersupply_unregister(di);
 
-       kfree(di->bus);
        kfree(di->bat.name);
 
        mutex_lock(&battery_mutex);
@@ -430,15 +670,12 @@ static int bq27x00_battery_remove(struct i2c_client *client)
        return 0;
 }
 
-/*
- * Module stuff
- */
-
 static const struct i2c_device_id bq27x00_id[] = {
        { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */
        { "bq27500", BQ27500 },
        {},
 };
+MODULE_DEVICE_TABLE(i2c, bq27x00_id);
 
 static struct i2c_driver bq27x00_battery_driver = {
        .driver = {
@@ -449,13 +686,164 @@ static struct i2c_driver bq27x00_battery_driver = {
        .id_table = bq27x00_id,
 };
 
+static inline int bq27x00_battery_i2c_init(void)
+{
+       int ret = i2c_add_driver(&bq27x00_battery_driver);
+       if (ret)
+               printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n");
+
+       return ret;
+}
+
+static inline void bq27x00_battery_i2c_exit(void)
+{
+       i2c_del_driver(&bq27x00_battery_driver);
+}
+
+#else
+
+static inline int bq27x00_battery_i2c_init(void) { return 0; }
+static inline void bq27x00_battery_i2c_exit(void) {};
+
+#endif
+
+/* platform specific code */
+#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
+
+static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg,
+                       bool single)
+{
+       struct device *dev = di->dev;
+       struct bq27000_platform_data *pdata = dev->platform_data;
+       unsigned int timeout = 3;
+       int upper, lower;
+       int temp;
+
+       if (!single) {
+               /* Make sure the value has not changed in between reading the
+                * lower and the upper part */
+               upper = pdata->read(dev, reg + 1);
+               do {
+                       temp = upper;
+                       if (upper < 0)
+                               return upper;
+
+                       lower = pdata->read(dev, reg);
+                       if (lower < 0)
+                               return lower;
+
+                       upper = pdata->read(dev, reg + 1);
+               } while (temp != upper && --timeout);
+
+               if (timeout == 0)
+                       return -EIO;
+
+               return (upper << 8) | lower;
+       }
+
+       return pdata->read(dev, reg);
+}
+
+static int __devinit bq27000_battery_probe(struct platform_device *pdev)
+{
+       struct bq27x00_device_info *di;
+       struct bq27000_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform_data supplied\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->read) {
+               dev_err(&pdev->dev, "no hdq read callback supplied\n");
+               return -EINVAL;
+       }
+
+       di = kzalloc(sizeof(*di), GFP_KERNEL);
+       if (!di) {
+               dev_err(&pdev->dev, "failed to allocate device info data\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, di);
+
+       di->dev = &pdev->dev;
+       di->chip = BQ27000;
+
+       di->bat.name = pdata->name ?: dev_name(&pdev->dev);
+       di->bus.read = &bq27000_read_platform;
+
+       ret = bq27x00_powersupply_init(di);
+       if (ret)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       platform_set_drvdata(pdev, NULL);
+       kfree(di);
+
+       return ret;
+}
+
+static int __devexit bq27000_battery_remove(struct platform_device *pdev)
+{
+       struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+       bq27x00_powersupply_unregister(di);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(di);
+
+       return 0;
+}
+
+static struct platform_driver bq27000_battery_driver = {
+       .probe  = bq27000_battery_probe,
+       .remove = __devexit_p(bq27000_battery_remove),
+       .driver = {
+               .name = "bq27000-battery",
+               .owner = THIS_MODULE,
+       },
+};
+
+static inline int bq27x00_battery_platform_init(void)
+{
+       int ret = platform_driver_register(&bq27000_battery_driver);
+       if (ret)
+               printk(KERN_ERR "Unable to register BQ27000 platform driver\n");
+
+       return ret;
+}
+
+static inline void bq27x00_battery_platform_exit(void)
+{
+       platform_driver_unregister(&bq27000_battery_driver);
+}
+
+#else
+
+static inline int bq27x00_battery_platform_init(void) { return 0; }
+static inline void bq27x00_battery_platform_exit(void) {};
+
+#endif
+
+/*
+ * Module stuff
+ */
+
 static int __init bq27x00_battery_init(void)
 {
        int ret;
 
-       ret = i2c_add_driver(&bq27x00_battery_driver);
+       ret = bq27x00_battery_i2c_init();
        if (ret)
-               printk(KERN_ERR "Unable to register BQ27x00 driver\n");
+               return ret;
+
+       ret = bq27x00_battery_platform_init();
+       if (ret)
+               bq27x00_battery_i2c_exit();
 
        return ret;
 }
@@ -463,7 +851,8 @@ module_init(bq27x00_battery_init);
 
 static void __exit bq27x00_battery_exit(void)
 {
-       i2c_del_driver(&bq27x00_battery_driver);
+       bq27x00_battery_platform_exit();
+       bq27x00_battery_i2c_exit();
 }
 module_exit(bq27x00_battery_exit);
 
index 6957e8af64490d006d383b7ce253bd7faddca0f4..4d2dc4fa2888fe2953b4b7c10a1aa53648b1f298 100644 (file)
@@ -393,6 +393,7 @@ static const struct i2c_device_id ds278x_id[] = {
        {"ds2786", DS2786},
        {},
 };
+MODULE_DEVICE_TABLE(i2c, ds278x_id);
 
 static struct i2c_driver ds278x_battery_driver = {
        .driver         = {
index 02414db6a94c151208bab6ff51917765cc074db1..763f894ed18815d5e54f9cd1359d42eab03f44ea 100644 (file)
@@ -39,7 +39,7 @@ struct jz_battery {
        int irq;
        int charge_irq;
 
-       struct mfd_cell *cell;
+       const struct mfd_cell *cell;
 
        int status;
        long voltage;
@@ -258,7 +258,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       jz_battery->cell = pdev->dev.platform_data;
+       jz_battery->cell = mfd_get_cell(pdev);
 
        jz_battery->irq = platform_get_irq(pdev, 0);
        if (jz_battery->irq < 0) {
index 970f7335d3a7f67bade76d6fad08eb954427a949..329b46b2327d4110eaea4438f87f2570f2587e88 100644 (file)
@@ -171,6 +171,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        dev_set_drvdata(dev, psy);
        psy->dev = dev;
 
+       INIT_WORK(&psy->changed_work, power_supply_changed_work);
+
        rc = kobject_set_name(&dev->kobj, "%s", psy->name);
        if (rc)
                goto kobject_set_name_failed;
@@ -179,8 +181,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        if (rc)
                goto device_add_failed;
 
-       INIT_WORK(&psy->changed_work, power_supply_changed_work);
-
        rc = power_supply_create_triggers(psy);
        if (rc)
                goto create_triggers_failed;
index 031a554837f78d2958b2c3368268c27466251837..da25eb94e5c6487907fc4fecb175b73059a8677a 100644 (file)
@@ -21,6 +21,8 @@
 static void power_supply_update_bat_leds(struct power_supply *psy)
 {
        union power_supply_propval status;
+       unsigned long delay_on = 0;
+       unsigned long delay_off = 0;
 
        if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
                return;
@@ -32,16 +34,22 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
                led_trigger_event(psy->charging_full_trig, LED_FULL);
                led_trigger_event(psy->charging_trig, LED_OFF);
                led_trigger_event(psy->full_trig, LED_FULL);
+               led_trigger_event(psy->charging_blink_full_solid_trig,
+                       LED_FULL);
                break;
        case POWER_SUPPLY_STATUS_CHARGING:
                led_trigger_event(psy->charging_full_trig, LED_FULL);
                led_trigger_event(psy->charging_trig, LED_FULL);
                led_trigger_event(psy->full_trig, LED_OFF);
+               led_trigger_blink(psy->charging_blink_full_solid_trig,
+                       &delay_on, &delay_off);
                break;
        default:
                led_trigger_event(psy->charging_full_trig, LED_OFF);
                led_trigger_event(psy->charging_trig, LED_OFF);
                led_trigger_event(psy->full_trig, LED_OFF);
+               led_trigger_event(psy->charging_blink_full_solid_trig,
+                       LED_OFF);
                break;
        }
 }
@@ -64,15 +72,24 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
        if (!psy->full_trig_name)
                goto full_failed;
 
+       psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
+               "%s-charging-blink-full-solid", psy->name);
+       if (!psy->charging_blink_full_solid_trig_name)
+               goto charging_blink_full_solid_failed;
+
        led_trigger_register_simple(psy->charging_full_trig_name,
                                    &psy->charging_full_trig);
        led_trigger_register_simple(psy->charging_trig_name,
                                    &psy->charging_trig);
        led_trigger_register_simple(psy->full_trig_name,
                                    &psy->full_trig);
+       led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
+                                   &psy->charging_blink_full_solid_trig);
 
        goto success;
 
+charging_blink_full_solid_failed:
+       kfree(psy->full_trig_name);
 full_failed:
        kfree(psy->charging_trig_name);
 charging_failed:
@@ -88,6 +105,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
        led_trigger_unregister_simple(psy->charging_full_trig);
        led_trigger_unregister_simple(psy->charging_trig);
        led_trigger_unregister_simple(psy->full_trig);
+       led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
+       kfree(psy->charging_blink_full_solid_trig_name);
        kfree(psy->full_trig_name);
        kfree(psy->charging_trig_name);
        kfree(psy->charging_full_trig_name);
index cd1f90754a3a301ebdbdd71da8bac4ad8265a580..605514afc29f20029032ef2ab94cc1b006e8ffa3 100644 (file)
@@ -270,7 +270,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
                attr = &power_supply_attrs[psy->properties[j]];
 
                ret = power_supply_show_property(dev, attr, prop_buf);
-               if (ret == -ENODEV) {
+               if (ret == -ENODEV || ret == -ENODATA) {
                        /* When a battery is absent, we expect -ENODEV. Don't abort;
                           send the uevent with at least the the PRESENT=0 property */
                        ret = 0;
index 4255f2358b138beb96305e832d778bef9ab15285..d36c289aaef52e1246029dd97f07f8f9d061f2f8 100644 (file)
@@ -406,8 +406,8 @@ static int s3c_adc_bat_resume(struct platform_device *pdev)
        return 0;
 }
 #else
-#define s3c_adc_battery_suspend NULL
-#define s3c_adc_battery_resume NULL
+#define s3c_adc_bat_suspend NULL
+#define s3c_adc_bat_resume NULL
 #endif
 
 static struct platform_driver s3c_adc_bat_driver = {
index ff1f42398a2edf42509152deae3cb721079ba221..92c16e1677bd7db5d796a34d64e5bd3b29428c7b 100644 (file)
@@ -71,8 +71,11 @@ struct twl4030_bci {
        struct power_supply     usb;
        struct otg_transceiver  *transceiver;
        struct notifier_block   otg_nb;
+       struct work_struct      work;
        int                     irq_chg;
        int                     irq_bci;
+
+       unsigned long           event;
 };
 
 /*
@@ -258,14 +261,11 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
-                              void *priv)
+static void twl4030_bci_usb_work(struct work_struct *data)
 {
-       struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+       struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work);
 
-       dev_dbg(bci->dev, "OTG notify %lu\n", val);
-
-       switch (val) {
+       switch (bci->event) {
        case USB_EVENT_VBUS:
        case USB_EVENT_CHARGER:
                twl4030_charger_enable_usb(bci, true);
@@ -274,6 +274,17 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
                twl4030_charger_enable_usb(bci, false);
                break;
        }
+}
+
+static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
+                              void *priv)
+{
+       struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+
+       dev_dbg(bci->dev, "OTG notify %lu\n", val);
+
+       bci->event = val;
+       schedule_work(&bci->work);
 
        return NOTIFY_OK;
 }
@@ -466,6 +477,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
                goto fail_bci_irq;
        }
 
+       INIT_WORK(&bci->work, twl4030_bci_usb_work);
+
        bci->transceiver = otg_get_transceiver();
        if (bci->transceiver != NULL) {
                bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
index e5ed52d719376e41c35de6c1368c8723af532f89..2a9ab89f83b8af99264495663516694fc2afee25 100644 (file)
@@ -134,6 +134,8 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props)
        enum power_supply_property *prop;
        struct z2_battery_info *info = charger->info;
 
+       if (info->charge_gpio >= 0)
+               props++;        /* POWER_SUPPLY_PROP_STATUS */
        if (info->batt_tech >= 0)
                props++;        /* POWER_SUPPLY_PROP_TECHNOLOGY */
        if (info->batt_I2C_reg >= 0)
@@ -293,6 +295,7 @@ static const struct i2c_device_id z2_batt_id[] = {
        { "aer915", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, z2_batt_id);
 
 static struct i2c_driver z2_batt_driver = {
        .driver = {
index 42517da07049e38e04da56a0ce4cdb78a87795eb..4feb7e9e71ee6c14fb8ce8585437ccd3d7dde24c 100644 (file)
@@ -6,6 +6,4 @@ obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
 obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
 obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
 
-ifeq ($(CONFIG_PPS_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
index b93af3ebb5baa1ece794b9054ca0fbf84563f20e..dcd39fba6ddd1c61a69aa99c7ad4e9f6285252fa 100644 (file)
@@ -216,11 +216,6 @@ static void parport_attach(struct parport *port)
 
        hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        device.timer.function = hrtimer_event;
-#ifdef CONFIG_PREEMPT_RT
-       /* hrtimer interrupt will run in the interrupt context with this */
-       device.timer.irqsafe = 1;
-#endif
-
        hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS);
 
        return;
index b6139fe187bfe7389f1b30970dc03c16660ca161..89b8eca825b55f28dc6a29afa8eabed91730bd3e 100644 (file)
@@ -5,6 +5,4 @@ obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
 
 obj-$(CONFIG_RAPIDIO)          += switches/
 
-ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+subdir-ccflags-$(CONFIG_RAPIDIO_DEBUG) := -DDEBUG
index a50391b6ba2a95b8afcc6d397a90c068c5f9bc36..3a59d5f018d39126f575d1c31b241812e85359ef 100644 (file)
@@ -517,7 +517,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
        return rdev;
 
 cleanup:
-       if (rswitch->route_table)
+       if (rio_is_switch(rdev))
                kfree(rswitch->route_table);
 
        kfree(rdev);
index 1269fbd2decad1a9898329f84addb5bb2720392d..4dbe360989be8b3ed1b156e7f61aeaafb5b68fff 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/rio.h>
 #include <linux/rio_drv.h>
 #include <linux/stat.h>
+#include <linux/capability.h>
 
 #include "rio.h"
 
@@ -33,6 +34,8 @@ rio_config_attr(device_rev, "0x%08x\n");
 rio_config_attr(asm_did, "0x%04x\n");
 rio_config_attr(asm_vid, "0x%04x\n");
 rio_config_attr(asm_rev, "0x%04x\n");
+rio_config_attr(destid, "0x%04x\n");
+rio_config_attr(hopcount, "0x%02x\n");
 
 static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -52,6 +55,35 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
        return (str - buf);
 }
 
+static ssize_t lprev_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct rio_dev *rdev = to_rio_dev(dev);
+
+       return sprintf(buf, "%s\n",
+                       (rdev->prev) ? rio_name(rdev->prev) : "root");
+}
+
+static ssize_t lnext_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct rio_dev *rdev = to_rio_dev(dev);
+       char *str = buf;
+       int i;
+
+       if (rdev->pef & RIO_PEF_SWITCH) {
+               for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
+                       if (rdev->rswitch->nextdev[i])
+                               str += sprintf(str, "%s\n",
+                                       rio_name(rdev->rswitch->nextdev[i]));
+                       else
+                               str += sprintf(str, "null\n");
+               }
+       }
+
+       return str - buf;
+}
+
 struct device_attribute rio_dev_attrs[] = {
        __ATTR_RO(did),
        __ATTR_RO(vid),
@@ -59,10 +91,14 @@ struct device_attribute rio_dev_attrs[] = {
        __ATTR_RO(asm_did),
        __ATTR_RO(asm_vid),
        __ATTR_RO(asm_rev),
+       __ATTR_RO(lprev),
+       __ATTR_RO(destid),
        __ATTR_NULL,
 };
 
 static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
+static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL);
+static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL);
 
 static ssize_t
 rio_read_config(struct file *filp, struct kobject *kobj,
@@ -218,7 +254,9 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
        err = device_create_bin_file(&rdev->dev, &rio_config_attr);
 
        if (!err && (rdev->pef & RIO_PEF_SWITCH)) {
-               err = device_create_file(&rdev->dev, &dev_attr_routes);
+               err |= device_create_file(&rdev->dev, &dev_attr_routes);
+               err |= device_create_file(&rdev->dev, &dev_attr_lnext);
+               err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
                if (!err && rdev->rswitch->sw_sysfs)
                        err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
        }
@@ -241,6 +279,8 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
        device_remove_bin_file(&rdev->dev, &rio_config_attr);
        if (rdev->pef & RIO_PEF_SWITCH) {
                device_remove_file(&rdev->dev, &dev_attr_routes);
+               device_remove_file(&rdev->dev, &dev_attr_lnext);
+               device_remove_file(&rdev->dev, &dev_attr_hopcount);
                if (rdev->rswitch->sw_sysfs)
                        rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
        }
index cc2a3b74d0f081fd4ae1d5cac09a297850e93bec..c29719cacbca00e108203361a25ee70cb5c8017f 100644 (file)
@@ -32,6 +32,7 @@
 #include "rio.h"
 
 static LIST_HEAD(rio_mports);
+static unsigned char next_portid;
 
 /**
  * rio_local_get_device_id - Get the base/extended device id for a port
@@ -68,9 +69,13 @@ int rio_request_inb_mbox(struct rio_mport *mport,
                         void (*minb) (struct rio_mport * mport, void *dev_id, int mbox,
                                       int slot))
 {
-       int rc = 0;
+       int rc = -ENOSYS;
+       struct resource *res;
 
-       struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+       if (mport->ops->open_inb_mbox == NULL)
+               goto out;
+
+       res = kmalloc(sizeof(struct resource), GFP_KERNEL);
 
        if (res) {
                rio_init_mbox_res(res, mbox, mbox);
@@ -88,7 +93,7 @@ int rio_request_inb_mbox(struct rio_mport *mport,
                /* Hook the inbound message callback */
                mport->inb_msg[mbox].mcback = minb;
 
-               rc = rio_open_inb_mbox(mport, dev_id, mbox, entries);
+               rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries);
        } else
                rc = -ENOMEM;
 
@@ -106,10 +111,13 @@ int rio_request_inb_mbox(struct rio_mport *mport,
  */
 int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
 {
-       rio_close_inb_mbox(mport, mbox);
+       if (mport->ops->close_inb_mbox) {
+               mport->ops->close_inb_mbox(mport, mbox);
 
-       /* Release the mailbox resource */
-       return release_resource(mport->inb_msg[mbox].res);
+               /* Release the mailbox resource */
+               return release_resource(mport->inb_msg[mbox].res);
+       } else
+               return -ENOSYS;
 }
 
 /**
@@ -129,9 +137,13 @@ int rio_request_outb_mbox(struct rio_mport *mport,
                          int entries,
                          void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot))
 {
-       int rc = 0;
+       int rc = -ENOSYS;
+       struct resource *res;
 
-       struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL);
+       if (mport->ops->open_outb_mbox == NULL)
+               goto out;
+
+       res = kmalloc(sizeof(struct resource), GFP_KERNEL);
 
        if (res) {
                rio_init_mbox_res(res, mbox, mbox);
@@ -149,7 +161,7 @@ int rio_request_outb_mbox(struct rio_mport *mport,
                /* Hook the inbound message callback */
                mport->outb_msg[mbox].mcback = moutb;
 
-               rc = rio_open_outb_mbox(mport, dev_id, mbox, entries);
+               rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries);
        } else
                rc = -ENOMEM;
 
@@ -167,10 +179,13 @@ int rio_request_outb_mbox(struct rio_mport *mport,
  */
 int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
 {
-       rio_close_outb_mbox(mport, mbox);
+       if (mport->ops->close_outb_mbox) {
+               mport->ops->close_outb_mbox(mport, mbox);
 
-       /* Release the mailbox resource */
-       return release_resource(mport->outb_msg[mbox].res);
+               /* Release the mailbox resource */
+               return release_resource(mport->outb_msg[mbox].res);
+       } else
+               return -ENOSYS;
 }
 
 /**
@@ -1120,36 +1135,51 @@ static int __devinit rio_init(void)
        return 0;
 }
 
-device_initcall(rio_init);
-
 int __devinit rio_init_mports(void)
 {
-       int rc = 0;
        struct rio_mport *port;
 
        list_for_each_entry(port, &rio_mports, node) {
-               if (!request_mem_region(port->iores.start,
-                                       resource_size(&port->iores),
-                                       port->name)) {
-                       printk(KERN_ERR
-                              "RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
-                              (u64)port->iores.start, (u64)port->iores.end);
-                       rc = -ENOMEM;
-                       goto out;
-               }
-
                if (port->host_deviceid >= 0)
                        rio_enum_mport(port);
                else
                        rio_disc_mport(port);
        }
 
-      out:
-       return rc;
+       rio_init();
+
+       return 0;
 }
 
+device_initcall_sync(rio_init_mports);
+
+static int hdids[RIO_MAX_MPORTS + 1];
+
+static int rio_get_hdid(int index)
+{
+       if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS)
+               return -1;
+
+       return hdids[index + 1];
+}
+
+static int rio_hdid_setup(char *str)
+{
+       (void)get_options(str, ARRAY_SIZE(hdids), hdids);
+       return 1;
+}
+
+__setup("riohdid=", rio_hdid_setup);
+
 void rio_register_mport(struct rio_mport *port)
 {
+       if (next_portid >= RIO_MAX_MPORTS) {
+               pr_err("RIO: reached specified max number of mports\n");
+               return;
+       }
+
+       port->id = next_portid++;
+       port->host_deviceid = rio_get_hdid(port->id);
        list_add_tail(&port->node, &rio_mports);
 }
 
index 48d67a6b98c89febb63780c598ad394f2fb15bc8..c4d3acc3c71560f63b605b410072ace4828c81a5 100644 (file)
@@ -7,7 +7,3 @@ obj-$(CONFIG_RAPIDIO_CPS_XX)    += idtcps.o
 obj-$(CONFIG_RAPIDIO_TSI568)   += tsi568.o
 obj-$(CONFIG_RAPIDIO_TSI500)   += tsi500.o
 obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
-
-ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
index dd6308499bd4c0d400ba3c4ac979e5dd2ff97b72..859251250b55bb400d548924711e665ebb26b5f2 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
 
 struct pm8607_regulator_info {
@@ -394,47 +395,48 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = {
        PM8607_LDO(14,        LDO14, 0, 4, SUPPLIES_EN12, 6),
 };
 
-static inline struct pm8607_regulator_info *find_regulator_info(int id)
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
 {
-       struct pm8607_regulator_info *info;
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm8607_regulator_info *info = NULL;
+       struct regulator_init_data *pdata;
+       struct mfd_cell *cell;
        int i;
 
+       cell = pdev->dev.platform_data;
+       if (cell == NULL)
+               return -ENODEV;
+       pdata = cell->mfd_data;
+       if (pdata == NULL)
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
                info = &pm8607_regulator_info[i];
-               if (info->desc.id == id)
-                       return info;
+               if (!strcmp(info->desc.name, pdata->constraints.name))
+                       break;
        }
-       return NULL;
-}
-
-static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
-{
-       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct pm860x_platform_data *pdata = chip->dev->platform_data;
-       struct pm8607_regulator_info *info = NULL;
-
-       info = find_regulator_info(pdev->id);
-       if (info == NULL) {
-               dev_err(&pdev->dev, "invalid regulator ID specified\n");
+       if (i > ARRAY_SIZE(pm8607_regulator_info)) {
+               dev_err(&pdev->dev, "Failed to find regulator %s\n",
+                       pdata->constraints.name);
                return -EINVAL;
        }
 
        info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
        info->chip = chip;
 
+       /* check DVC ramp slope double */
+       if (!strcmp(info->desc.name, "BUCK3"))
+               if (info->chip->buck3_double)
+                       info->slope_double = 1;
+
        info->regulator = regulator_register(&info->desc, &pdev->dev,
-                                            pdata->regulator[pdev->id], info);
+                                            pdata, info);
        if (IS_ERR(info->regulator)) {
                dev_err(&pdev->dev, "failed to register regulator %s\n",
                        info->desc.name);
                return PTR_ERR(info->regulator);
        }
 
-       /* check DVC ramp slope double */
-       if (info->desc.id == PM8607_ID_BUCK3)
-               if (info->chip->buck3_double)
-                       info->slope_double = 1;
-
        platform_set_drvdata(pdev, info);
        return 0;
 }
index e1d943619ab80b53d7bb69b41851d9703d1bd436..de75f67f4cc3768012007331ac76aa2e28b9e475 100644 (file)
@@ -108,6 +108,15 @@ config REGULATOR_MAX8952
          via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
          modes ranging from 0.77V to 1.40V by 0.01V steps.
 
+config REGULATOR_MAX8997
+       tristate "Maxim 8997/8966 regulator"
+       depends on MFD_MAX8997
+       help
+         This driver controls a Maxim 8997/8966 regulator
+         via I2C bus. The provided regulator is suitable for S5PC110,
+         S5PV210, and Exynos-4 chips to control VCC_CORE and
+         VCC_USIM voltages.
+
 config REGULATOR_MAX8998
        tristate "Maxim 8998 voltage regulator"
        depends on MFD_MAX8998
@@ -214,6 +223,15 @@ config REGULATOR_AB3100
         AB3100 analog baseband dealing with power regulators
         for the system.
 
+config REGULATOR_TPS6105X
+       tristate "TI TPS6105X Power regulators"
+       depends on TPS6105X
+       default y if TPS6105X
+       help
+         This driver supports TPS61050/TPS61052 voltage regulator chips.
+         It is a single boost converter primarily for white LEDs and
+         audio amplifiers.
+
 config REGULATOR_TPS65023
        tristate "TI TPS65023 Power regulators"
        depends on I2C
index 0b5e88c2b8d75f9f455a88f98350d4a188c48041..d72a427567786eade1a87fb05c2a83284757ba01 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_REGULATOR_MAX8649)       += max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
 obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
+obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
@@ -33,7 +34,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
-
+obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
index ed6feaf9398ddda5ee123d7eb11674419133c3d5..2dec589a89087e8340b1f074c42c7baa866e4c3b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/core.h>
 
 /* LDO registers and some handy masking definitions for AB3100 */
 #define AB3100_LDO_A           0x40
@@ -576,7 +577,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
 
 static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
 {
-       struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+       struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
        int err = 0;
        u8 data;
        int i;
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
new file mode 100644 (file)
index 0000000..01ef7e9
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ * max8997.c - Regulator driver for the Maxim 8997/8966
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@smasung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8998.c
+ */
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+struct max8997_data {
+       struct device *dev;
+       struct max8997_dev *iodev;
+       int num_regulators;
+       struct regulator_dev **rdev;
+       int ramp_delay; /* in mV/us */
+
+       u8 buck1_vol[8];
+       u8 buck2_vol[8];
+       u8 buck5_vol[8];
+       int buck125_gpioindex;
+
+       u8 saved_states[MAX8997_REG_MAX];
+};
+
+static inline void max8997_set_gpio(struct max8997_data *max8997)
+{
+       struct max8997_platform_data *pdata =
+               dev_get_platdata(max8997->iodev->dev);
+       int set3 = (max8997->buck125_gpioindex) & 0x1;
+       int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1;
+       int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1;
+
+       gpio_set_value(pdata->buck125_gpios[0], set1);
+       gpio_set_value(pdata->buck125_gpios[1], set2);
+       gpio_set_value(pdata->buck125_gpios[2], set3);
+}
+
+struct voltage_map_desc {
+       int min;
+       int max;
+       int step;
+       unsigned int n_bits;
+};
+
+/* Voltage maps in mV */
+static const struct voltage_map_desc ldo_voltage_map_desc = {
+       .min = 800,     .max = 3950,    .step = 50,     .n_bits = 6,
+}; /* LDO1 ~ 18, 21 all */
+
+static const struct voltage_map_desc buck1245_voltage_map_desc = {
+       .min = 650,     .max = 2225,    .step = 25,     .n_bits = 6,
+}; /* Buck1, 2, 4, 5 */
+
+static const struct voltage_map_desc buck37_voltage_map_desc = {
+       .min = 750,     .max = 3900,    .step = 50,     .n_bits = 6,
+}; /* Buck3, 7 */
+
+/* current map in mA */
+static const struct voltage_map_desc charger_current_map_desc = {
+       .min = 200,     .max = 950,     .step = 50,     .n_bits = 4,
+};
+
+static const struct voltage_map_desc topoff_current_map_desc = {
+       .min = 50,      .max = 200,     .step = 10,     .n_bits = 4,
+};
+
+static const struct voltage_map_desc *reg_voltage_map[] = {
+       [MAX8997_LDO1] = &ldo_voltage_map_desc,
+       [MAX8997_LDO2] = &ldo_voltage_map_desc,
+       [MAX8997_LDO3] = &ldo_voltage_map_desc,
+       [MAX8997_LDO4] = &ldo_voltage_map_desc,
+       [MAX8997_LDO5] = &ldo_voltage_map_desc,
+       [MAX8997_LDO6] = &ldo_voltage_map_desc,
+       [MAX8997_LDO7] = &ldo_voltage_map_desc,
+       [MAX8997_LDO8] = &ldo_voltage_map_desc,
+       [MAX8997_LDO9] = &ldo_voltage_map_desc,
+       [MAX8997_LDO10] = &ldo_voltage_map_desc,
+       [MAX8997_LDO11] = &ldo_voltage_map_desc,
+       [MAX8997_LDO12] = &ldo_voltage_map_desc,
+       [MAX8997_LDO13] = &ldo_voltage_map_desc,
+       [MAX8997_LDO14] = &ldo_voltage_map_desc,
+       [MAX8997_LDO15] = &ldo_voltage_map_desc,
+       [MAX8997_LDO16] = &ldo_voltage_map_desc,
+       [MAX8997_LDO17] = &ldo_voltage_map_desc,
+       [MAX8997_LDO18] = &ldo_voltage_map_desc,
+       [MAX8997_LDO21] = &ldo_voltage_map_desc,
+       [MAX8997_BUCK1] = &buck1245_voltage_map_desc,
+       [MAX8997_BUCK2] = &buck1245_voltage_map_desc,
+       [MAX8997_BUCK3] = &buck37_voltage_map_desc,
+       [MAX8997_BUCK4] = &buck1245_voltage_map_desc,
+       [MAX8997_BUCK5] = &buck1245_voltage_map_desc,
+       [MAX8997_BUCK6] = NULL,
+       [MAX8997_BUCK7] = &buck37_voltage_map_desc,
+       [MAX8997_EN32KHZ_AP] = NULL,
+       [MAX8997_EN32KHZ_CP] = NULL,
+       [MAX8997_ENVICHG] = NULL,
+       [MAX8997_ESAFEOUT1] = NULL,
+       [MAX8997_ESAFEOUT2] = NULL,
+       [MAX8997_CHARGER_CV] = NULL,
+       [MAX8997_CHARGER] = &charger_current_map_desc,
+       [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
+};
+
+static inline int max8997_get_rid(struct regulator_dev *rdev)
+{
+       return rdev_get_id(rdev);
+}
+
+static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
+               unsigned int selector)
+{
+       int rid = max8997_get_rid(rdev);
+
+       if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
+               switch (selector) {
+               case 0:
+                       return 4850000;
+               case 1:
+                       return 4900000;
+               case 2:
+                       return 4950000;
+               case 3:
+                       return 3300000;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
+               unsigned int selector)
+{
+       int rid = max8997_get_rid(rdev);
+
+       if (rid != MAX8997_CHARGER_CV)
+               goto err;
+
+       switch (selector) {
+       case 0x00:
+               return 4200000;
+       case 0x01 ... 0x0E:
+               return 4000000 + 20000 * (selector - 0x01);
+       case 0x0F:
+               return 4350000;
+       default:
+               return -EINVAL;
+       }
+err:
+       return -EINVAL;
+}
+
+static int max8997_list_voltage(struct regulator_dev *rdev,
+               unsigned int selector)
+{
+       const struct voltage_map_desc *desc;
+       int rid = max8997_get_rid(rdev);
+       int val;
+
+       if (rid >= ARRAY_SIZE(reg_voltage_map) ||
+                       rid < 0)
+               return -EINVAL;
+
+       desc = reg_voltage_map[rid];
+       if (desc == NULL)
+               return -EINVAL;
+
+       val = desc->min + desc->step * selector;
+       if (val > desc->max)
+               return -EINVAL;
+
+       return val * 1000;
+}
+
+static int max8997_get_enable_register(struct regulator_dev *rdev,
+               int *reg, int *mask, int *pattern)
+{
+       int rid = max8997_get_rid(rdev);
+
+       switch (rid) {
+       case MAX8997_LDO1 ... MAX8997_LDO21:
+               *reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
+               *mask = 0xC0;
+               *pattern = 0xC0;
+               break;
+       case MAX8997_BUCK1:
+               *reg = MAX8997_REG_BUCK1CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK2:
+               *reg = MAX8997_REG_BUCK2CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK3:
+               *reg = MAX8997_REG_BUCK3CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK4:
+               *reg = MAX8997_REG_BUCK4CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK5:
+               *reg = MAX8997_REG_BUCK5CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK6:
+               *reg = MAX8997_REG_BUCK6CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_BUCK7:
+               *reg = MAX8997_REG_BUCK7CTRL;
+               *mask = 0x01;
+               *pattern = 0x01;
+               break;
+       case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP:
+               *reg = MAX8997_REG_MAINCON1;
+               *mask = 0x01 << (rid - MAX8997_EN32KHZ_AP);
+               *pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP);
+               break;
+       case MAX8997_ENVICHG:
+               *reg = MAX8997_REG_MBCCTRL1;
+               *mask = 0x80;
+               *pattern = 0x80;
+               break;
+       case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2:
+               *reg = MAX8997_REG_SAFEOUTCTRL;
+               *mask = 0x40 << (rid - MAX8997_ESAFEOUT1);
+               *pattern = 0x40 << (rid - MAX8997_ESAFEOUT1);
+               break;
+       case MAX8997_CHARGER:
+               *reg = MAX8997_REG_MBCCTRL2;
+               *mask = 0x40;
+               *pattern = 0x40;
+               break;
+       default:
+               /* Not controllable or not exists */
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+static int max8997_reg_is_enabled(struct regulator_dev *rdev)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int ret, reg, mask, pattern;
+       u8 val;
+
+       ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+       if (ret == -EINVAL)
+               return 1; /* "not controllable" */
+       else if (ret)
+               return ret;
+
+       ret = max8997_read_reg(i2c, reg, &val);
+       if (ret)
+               return ret;
+
+       return (val & mask) == pattern;
+}
+
+static int max8997_reg_enable(struct regulator_dev *rdev)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int ret, reg, mask, pattern;
+
+       ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+       if (ret)
+               return ret;
+
+       return max8997_update_reg(i2c, reg, pattern, mask);
+}
+
+static int max8997_reg_disable(struct regulator_dev *rdev)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int ret, reg, mask, pattern;
+
+       ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+       if (ret)
+               return ret;
+
+       return max8997_update_reg(i2c, reg, ~pattern, mask);
+}
+
+static int max8997_get_voltage_register(struct regulator_dev *rdev,
+               int *_reg, int *_shift, int *_mask)
+{
+       int rid = max8997_get_rid(rdev);
+       int reg, shift = 0, mask = 0x3f;
+
+       switch (rid) {
+       case MAX8997_LDO1 ... MAX8997_LDO21:
+               reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
+               break;
+       case MAX8997_BUCK1:
+               reg = MAX8997_REG_BUCK1DVS1;
+               break;
+       case MAX8997_BUCK2:
+               reg = MAX8997_REG_BUCK2DVS1;
+               break;
+       case MAX8997_BUCK3:
+               reg = MAX8997_REG_BUCK3DVS;
+               break;
+       case MAX8997_BUCK4:
+               reg = MAX8997_REG_BUCK4DVS;
+               break;
+       case MAX8997_BUCK5:
+               reg = MAX8997_REG_BUCK5DVS1;
+               break;
+       case MAX8997_BUCK7:
+               reg = MAX8997_REG_BUCK7DVS;
+               break;
+       case MAX8997_ESAFEOUT1 ...  MAX8997_ESAFEOUT2:
+               reg = MAX8997_REG_SAFEOUTCTRL;
+               shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0;
+               mask = 0x3;
+               break;
+       case MAX8997_CHARGER_CV:
+               reg = MAX8997_REG_MBCCTRL3;
+               shift = 0;
+               mask = 0xf;
+               break;
+       case MAX8997_CHARGER:
+               reg = MAX8997_REG_MBCCTRL4;
+               shift = 0;
+               mask = 0xf;
+               break;
+       case MAX8997_CHARGER_TOPOFF:
+               reg = MAX8997_REG_MBCCTRL5;
+               shift = 0;
+               mask = 0xf;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       *_reg = reg;
+       *_shift = shift;
+       *_mask = mask;
+
+       return 0;
+}
+
+static int max8997_get_voltage(struct regulator_dev *rdev)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct max8997_platform_data *pdata =
+               dev_get_platdata(max8997->iodev->dev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int reg, shift, mask, ret;
+       int rid = max8997_get_rid(rdev);
+       u8 val;
+
+       ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+       if (ret)
+               return ret;
+
+       if ((rid == MAX8997_BUCK1 && pdata->buck1_gpiodvs) ||
+                       (rid == MAX8997_BUCK2 && pdata->buck2_gpiodvs) ||
+                       (rid == MAX8997_BUCK5 && pdata->buck5_gpiodvs))
+               reg += max8997->buck125_gpioindex;
+
+       ret = max8997_read_reg(i2c, reg, &val);
+       if (ret)
+               return ret;
+
+       val >>= shift;
+       val &= mask;
+
+       if (rdev->desc && rdev->desc->ops && rdev->desc->ops->list_voltage)
+               return rdev->desc->ops->list_voltage(rdev, val);
+
+       /*
+        * max8997_list_voltage returns value for any rdev with voltage_map,
+        * which works for "CHARGER" and "CHARGER TOPOFF" that do not have
+        * list_voltage ops (they are current regulators).
+        */
+       return max8997_list_voltage(rdev, val);
+}
+
+static inline int max8997_get_voltage_proper_val(
+               const struct voltage_map_desc *desc,
+               int min_vol, int max_vol)
+{
+       int i = 0;
+
+       if (desc == NULL)
+               return -EINVAL;
+
+       if (max_vol < desc->min || min_vol > desc->max)
+               return -EINVAL;
+
+       while (desc->min + desc->step * i < min_vol &&
+                       desc->min + desc->step * i < desc->max)
+               i++;
+
+       if (desc->min + desc->step * i > max_vol)
+               return -EINVAL;
+
+       if (i >= (1 << desc->n_bits))
+               return -EINVAL;
+
+       return i;
+}
+
+static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev,
+               int min_uV, int max_uV, unsigned *selector)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int rid = max8997_get_rid(rdev);
+       int lb, ub;
+       int reg, shift = 0, mask, ret = 0;
+       u8 val = 0x0;
+
+       if (rid != MAX8997_CHARGER_CV)
+               return -EINVAL;
+
+       ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+       if (ret)
+               return ret;
+
+       if (max_uV < 4000000 || min_uV > 4350000)
+               return -EINVAL;
+
+       if (min_uV <= 4000000) {
+               if (max_uV >= 4000000)
+                       return -EINVAL;
+               else
+                       val = 0x1;
+       } else if (min_uV <= 4200000 && max_uV >= 4200000)
+               val = 0x0;
+       else {
+               lb = (min_uV - 4000001) / 20000 + 2;
+               ub = (max_uV - 4000000) / 20000 + 1;
+
+               if (lb > ub)
+                       return -EINVAL;
+
+               if (lb < 0xf)
+                       val = lb;
+               else {
+                       if (ub >= 0xf)
+                               val = 0xf;
+                       else
+                               return -EINVAL;
+               }
+       }
+
+       *selector = val;
+
+       ret = max8997_update_reg(i2c, reg, val << shift, mask);
+
+       return ret;
+}
+
+/*
+ * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF
+ * BUCK1, 2, and 5 are available if they are not controlled by gpio
+ */
+static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
+               int min_uV, int max_uV, unsigned *selector)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+       const struct voltage_map_desc *desc;
+       int rid = max8997_get_rid(rdev);
+       int reg, shift = 0, mask, ret;
+       int i;
+       u8 org;
+
+       switch (rid) {
+       case MAX8997_LDO1 ... MAX8997_LDO21:
+               break;
+       case MAX8997_BUCK1 ... MAX8997_BUCK5:
+               break;
+       case MAX8997_BUCK6:
+               return -EINVAL;
+       case MAX8997_BUCK7:
+               break;
+       case MAX8997_CHARGER:
+               break;
+       case MAX8997_CHARGER_TOPOFF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       desc = reg_voltage_map[rid];
+
+       i = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
+       if (i < 0)
+               return i;
+
+       ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+       if (ret)
+               return ret;
+
+       max8997_read_reg(i2c, reg, &org);
+       org = (org & mask) >> shift;
+
+       ret = max8997_update_reg(i2c, reg, i << shift, mask << shift);
+       *selector = i;
+
+       if (rid == MAX8997_BUCK1 || rid == MAX8997_BUCK2 ||
+                       rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) {
+               /* If the voltage is increasing */
+               if (org < i)
+                       udelay(desc->step * (i - org) / max8997->ramp_delay);
+       }
+
+       return ret;
+}
+
+/*
+ * Assess the damage on the voltage setting of BUCK1,2,5 by the change.
+ *
+ * When GPIO-DVS mode is used for multiple bucks, changing the voltage value
+ * of one of the bucks may affect that of another buck, which is the side
+ * effect of the change (set_voltage). This function examines the GPIO-DVS
+ * configurations and checks whether such side-effect exists.
+ */
+static int max8997_assess_side_effect(struct regulator_dev *rdev,
+               u8 new_val, int *best)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct max8997_platform_data *pdata =
+               dev_get_platdata(max8997->iodev->dev);
+       int rid = max8997_get_rid(rdev);
+       u8 *buckx_val[3];
+       bool buckx_gpiodvs[3];
+       int side_effect[8];
+       int min_side_effect = INT_MAX;
+       int i;
+
+       *best = -1;
+
+       switch (rid) {
+       case MAX8997_BUCK1:
+               rid = 0;
+               break;
+       case MAX8997_BUCK2:
+               rid = 1;
+               break;
+       case MAX8997_BUCK5:
+               rid = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       buckx_val[0] = max8997->buck1_vol;
+       buckx_val[1] = max8997->buck2_vol;
+       buckx_val[2] = max8997->buck5_vol;
+       buckx_gpiodvs[0] = pdata->buck1_gpiodvs;
+       buckx_gpiodvs[1] = pdata->buck2_gpiodvs;
+       buckx_gpiodvs[2] = pdata->buck5_gpiodvs;
+
+       for (i = 0; i < 8; i++) {
+               int others;
+
+               if (new_val != (buckx_val[rid])[i]) {
+                       side_effect[i] = -1;
+                       continue;
+               }
+
+               side_effect[i] = 0;
+               for (others = 0; others < 3; others++) {
+                       int diff;
+
+                       if (others == rid)
+                               continue;
+                       if (buckx_gpiodvs[others] == false)
+                               continue; /* Not affected */
+                       diff = (buckx_val[others])[i] -
+                               (buckx_val[others])[max8997->buck125_gpioindex];
+                       if (diff > 0)
+                               side_effect[i] += diff;
+                       else if (diff < 0)
+                               side_effect[i] -= diff;
+               }
+               if (side_effect[i] == 0) {
+                       *best = i;
+                       return 0; /* NO SIDE EFFECT! Use This! */
+               }
+               if (side_effect[i] < min_side_effect) {
+                       min_side_effect = side_effect[i];
+                       *best = i;
+               }
+       }
+
+       if (*best == -1)
+               return -EINVAL;
+
+       return side_effect[*best];
+}
+
+/*
+ * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls
+ * max8997_set_voltage_ldobuck to do the job.
+ */
+static int max8997_set_voltage_buck(struct regulator_dev *rdev,
+               int min_uV, int max_uV, unsigned *selector)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct max8997_platform_data *pdata =
+               dev_get_platdata(max8997->iodev->dev);
+       int rid = max8997_get_rid(rdev);
+       const struct voltage_map_desc *desc;
+       int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
+       bool gpio_dvs_mode = false;
+       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+
+       if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7)
+               return -EINVAL;
+
+       switch (rid) {
+       case MAX8997_BUCK1:
+               if (pdata->buck1_gpiodvs)
+                       gpio_dvs_mode = true;
+               break;
+       case MAX8997_BUCK2:
+               if (pdata->buck2_gpiodvs)
+                       gpio_dvs_mode = true;
+               break;
+       case MAX8997_BUCK5:
+               if (pdata->buck5_gpiodvs)
+                       gpio_dvs_mode = true;
+               break;
+       }
+
+       if (!gpio_dvs_mode)
+               return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV,
+                                               selector);
+
+       desc = reg_voltage_map[rid];
+       new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
+       if (new_val < 0)
+               return new_val;
+
+       tmp_dmg = INT_MAX;
+       tmp_idx = -1;
+       tmp_val = -1;
+       do {
+               damage = max8997_assess_side_effect(rdev, new_val, &new_idx);
+               if (damage == 0)
+                       goto out;
+
+               if (tmp_dmg > damage) {
+                       tmp_idx = new_idx;
+                       tmp_val = new_val;
+                       tmp_dmg = damage;
+               }
+
+               new_val++;
+       } while (desc->min + desc->step + new_val <= desc->max);
+
+       new_idx = tmp_idx;
+       new_val = tmp_val;
+
+       if (pdata->ignore_gpiodvs_side_effect == false)
+               return -EINVAL;
+
+       dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:"
+                       " %d -> %d\n", max8997->buck125_gpioindex, tmp_idx);
+
+out:
+       if (new_idx < 0 || new_val < 0)
+               return -EINVAL;
+
+       max8997->buck125_gpioindex = new_idx;
+       max8997_set_gpio(max8997);
+       *selector = new_val;
+
+       return 0;
+}
+
+static const int safeoutvolt[] = {
+       3300000,
+       4850000,
+       4900000,
+       4950000,
+};
+
+/* For SAFEOUT1 and SAFEOUT2 */
+static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
+               int min_uV, int max_uV, unsigned *selector)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int rid = max8997_get_rid(rdev);
+       int reg, shift = 0, mask, ret;
+       int i = 0;
+       u8 val;
+
+       if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
+               if (min_uV <= safeoutvolt[i] &&
+                               max_uV >= safeoutvolt[i])
+                       break;
+       }
+
+       if (i >= ARRAY_SIZE(safeoutvolt))
+               return -EINVAL;
+
+       if (i == 0)
+               val = 0x3;
+       else
+               val = i - 1;
+
+       ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+       if (ret)
+               return ret;
+
+       ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
+       *selector = val;
+
+       return ret;
+}
+
+static int max8997_reg_enable_suspend(struct regulator_dev *rdev)
+{
+       return 0;
+}
+
+static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
+{
+       struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+       struct i2c_client *i2c = max8997->iodev->i2c;
+       int ret, reg, mask, pattern;
+       int rid = max8997_get_rid(rdev);
+
+       ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+       if (ret)
+               return ret;
+
+       max8997_read_reg(i2c, reg, &max8997->saved_states[rid]);
+
+       if (rid == MAX8997_LDO1 ||
+                       rid == MAX8997_LDO10 ||
+                       rid == MAX8997_LDO21) {
+               dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n",
+                               rdev->desc->name);
+               return max8997_update_reg(i2c, reg, 0x40, mask);
+       }
+
+       dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n",
+                       rdev->desc->name, max8997->saved_states[rid] & mask,
+                       (~pattern) & mask);
+       return max8997_update_reg(i2c, reg, ~pattern, mask);
+}
+
+static struct regulator_ops max8997_ldo_ops = {
+       .list_voltage           = max8997_list_voltage,
+       .is_enabled             = max8997_reg_is_enabled,
+       .enable                 = max8997_reg_enable,
+       .disable                = max8997_reg_disable,
+       .get_voltage            = max8997_get_voltage,
+       .set_voltage            = max8997_set_voltage_ldobuck,
+       .set_suspend_enable     = max8997_reg_enable_suspend,
+       .set_suspend_disable    = max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_buck_ops = {
+       .list_voltage           = max8997_list_voltage,
+       .is_enabled             = max8997_reg_is_enabled,
+       .enable                 = max8997_reg_enable,
+       .disable                = max8997_reg_disable,
+       .get_voltage            = max8997_get_voltage,
+       .set_voltage            = max8997_set_voltage_buck,
+       .set_suspend_enable     = max8997_reg_enable_suspend,
+       .set_suspend_disable    = max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_fixedvolt_ops = {
+       .list_voltage           = max8997_list_voltage,
+       .is_enabled             = max8997_reg_is_enabled,
+       .enable                 = max8997_reg_enable,
+       .disable                = max8997_reg_disable,
+       .set_suspend_enable     = max8997_reg_enable_suspend,
+       .set_suspend_disable    = max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_safeout_ops = {
+       .list_voltage           = max8997_list_voltage_safeout,
+       .is_enabled             = max8997_reg_is_enabled,
+       .enable                 = max8997_reg_enable,
+       .disable                = max8997_reg_disable,
+       .get_voltage            = max8997_get_voltage,
+       .set_voltage            = max8997_set_voltage_safeout,
+       .set_suspend_enable     = max8997_reg_enable_suspend,
+       .set_suspend_disable    = max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_fixedstate_ops = {
+       .list_voltage           = max8997_list_voltage_charger_cv,
+       .get_voltage            = max8997_get_voltage,
+       .set_voltage            = max8997_set_voltage_charger_cv,
+};
+
+static int max8997_set_voltage_ldobuck_wrap(struct regulator_dev *rdev,
+               int min_uV, int max_uV)
+{
+       unsigned dummy;
+
+       return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, &dummy);
+}
+
+
+static struct regulator_ops max8997_charger_ops = {
+       .is_enabled             = max8997_reg_is_enabled,
+       .enable                 = max8997_reg_enable,
+       .disable                = max8997_reg_disable,
+       .get_current_limit      = max8997_get_voltage,
+       .set_current_limit      = max8997_set_voltage_ldobuck_wrap,
+};
+
+static struct regulator_ops max8997_charger_fixedstate_ops = {
+       .is_enabled             = max8997_reg_is_enabled,
+       .get_current_limit      = max8997_get_voltage,
+       .set_current_limit      = max8997_set_voltage_ldobuck_wrap,
+};
+
+#define regulator_desc_ldo(num)                {       \
+       .name           = "LDO"#num,            \
+       .id             = MAX8997_LDO##num,     \
+       .ops            = &max8997_ldo_ops,     \
+       .type           = REGULATOR_VOLTAGE,    \
+       .owner          = THIS_MODULE,          \
+}
+#define regulator_desc_buck(num)               {       \
+       .name           = "BUCK"#num,           \
+       .id             = MAX8997_BUCK##num,    \
+       .ops            = &max8997_buck_ops,    \
+       .type           = REGULATOR_VOLTAGE,    \
+       .owner          = THIS_MODULE,          \
+}
+
+static struct regulator_desc regulators[] = {
+       regulator_desc_ldo(1),
+       regulator_desc_ldo(2),
+       regulator_desc_ldo(3),
+       regulator_desc_ldo(4),
+       regulator_desc_ldo(5),
+       regulator_desc_ldo(6),
+       regulator_desc_ldo(7),
+       regulator_desc_ldo(8),
+       regulator_desc_ldo(9),
+       regulator_desc_ldo(10),
+       regulator_desc_ldo(11),
+       regulator_desc_ldo(12),
+       regulator_desc_ldo(13),
+       regulator_desc_ldo(14),
+       regulator_desc_ldo(15),
+       regulator_desc_ldo(16),
+       regulator_desc_ldo(17),
+       regulator_desc_ldo(18),
+       regulator_desc_ldo(21),
+       regulator_desc_buck(1),
+       regulator_desc_buck(2),
+       regulator_desc_buck(3),
+       regulator_desc_buck(4),
+       regulator_desc_buck(5),
+       {
+               .name   = "BUCK6",
+               .id     = MAX8997_BUCK6,
+               .ops    = &max8997_fixedvolt_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner  = THIS_MODULE,
+       },
+       regulator_desc_buck(7),
+       {
+               .name   = "EN32KHz AP",
+               .id     = MAX8997_EN32KHZ_AP,
+               .ops    = &max8997_fixedvolt_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner  = THIS_MODULE,
+       }, {
+               .name   = "EN32KHz CP",
+               .id     = MAX8997_EN32KHZ_CP,
+               .ops    = &max8997_fixedvolt_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner  = THIS_MODULE,
+       }, {
+               .name   = "ENVICHG",
+               .id     = MAX8997_ENVICHG,
+               .ops    = &max8997_fixedvolt_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner  = THIS_MODULE,
+       }, {
+               .name   = "ESAFEOUT1",
+               .id     = MAX8997_ESAFEOUT1,
+               .ops    = &max8997_safeout_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner   = THIS_MODULE,
+       }, {
+               .name   = "ESAFEOUT2",
+               .id     = MAX8997_ESAFEOUT2,
+               .ops    = &max8997_safeout_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner   = THIS_MODULE,
+       }, {
+               .name   = "CHARGER CV",
+               .id     = MAX8997_CHARGER_CV,
+               .ops    = &max8997_fixedstate_ops,
+               .type   = REGULATOR_VOLTAGE,
+               .owner   = THIS_MODULE,
+       }, {
+               .name   = "CHARGER",
+               .id     = MAX8997_CHARGER,
+               .ops    = &max8997_charger_ops,
+               .type   = REGULATOR_CURRENT,
+               .owner   = THIS_MODULE,
+       }, {
+               .name   = "CHARGER TOPOFF",
+               .id     = MAX8997_CHARGER_TOPOFF,
+               .ops    = &max8997_charger_fixedstate_ops,
+               .type   = REGULATOR_CURRENT,
+               .owner   = THIS_MODULE,
+       },
+};
+
+static __devinit int max8997_pmic_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct regulator_dev **rdev;
+       struct max8997_data *max8997;
+       struct i2c_client *i2c;
+       int i, ret, size;
+       u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
+
+       if (!pdata) {
+               dev_err(pdev->dev.parent, "No platform init data supplied.\n");
+               return -ENODEV;
+       }
+
+       max8997 = kzalloc(sizeof(struct max8997_data), GFP_KERNEL);
+       if (!max8997)
+               return -ENOMEM;
+
+       size = sizeof(struct regulator_dev *) * pdata->num_regulators;
+       max8997->rdev = kzalloc(size, GFP_KERNEL);
+       if (!max8997->rdev) {
+               kfree(max8997);
+               return -ENOMEM;
+       }
+
+       rdev = max8997->rdev;
+       max8997->dev = &pdev->dev;
+       max8997->iodev = iodev;
+       max8997->num_regulators = pdata->num_regulators;
+       platform_set_drvdata(pdev, max8997);
+       i2c = max8997->iodev->i2c;
+
+       max8997->buck125_gpioindex = pdata->buck125_default_idx;
+
+       for (i = 0; i < 8; i++) {
+               max8997->buck1_vol[i] = ret =
+                       max8997_get_voltage_proper_val(
+                                       &buck1245_voltage_map_desc,
+                                       pdata->buck1_voltage[i] / 1000,
+                                       pdata->buck1_voltage[i] / 1000 +
+                                       buck1245_voltage_map_desc.step);
+               if (ret < 0)
+                       goto err_alloc;
+
+               max8997->buck2_vol[i] = ret =
+                       max8997_get_voltage_proper_val(
+                                       &buck1245_voltage_map_desc,
+                                       pdata->buck2_voltage[i] / 1000,
+                                       pdata->buck2_voltage[i] / 1000 +
+                                       buck1245_voltage_map_desc.step);
+               if (ret < 0)
+                       goto err_alloc;
+
+               max8997->buck5_vol[i] = ret =
+                       max8997_get_voltage_proper_val(
+                                       &buck1245_voltage_map_desc,
+                                       pdata->buck5_voltage[i] / 1000,
+                                       pdata->buck5_voltage[i] / 1000 +
+                                       buck1245_voltage_map_desc.step);
+               if (ret < 0)
+                       goto err_alloc;
+
+               if (max_buck1 < max8997->buck1_vol[i])
+                       max_buck1 = max8997->buck1_vol[i];
+               if (max_buck2 < max8997->buck2_vol[i])
+                       max_buck2 = max8997->buck2_vol[i];
+               if (max_buck5 < max8997->buck5_vol[i])
+                       max_buck5 = max8997->buck5_vol[i];
+       }
+
+       /* For the safety, set max voltage before setting up */
+       for (i = 0; i < 8; i++) {
+               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+                               max_buck1, 0x3f);
+               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+                               max_buck2, 0x3f);
+               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+                               max_buck5, 0x3f);
+       }
+
+       /*
+        * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them.
+        * If at least one of them cares, set gpios.
+        */
+       if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
+                       pdata->buck5_gpiodvs) {
+               bool gpio1set = false, gpio2set = false;
+
+               if (!gpio_is_valid(pdata->buck125_gpios[0]) ||
+                               !gpio_is_valid(pdata->buck125_gpios[1]) ||
+                               !gpio_is_valid(pdata->buck125_gpios[2])) {
+                       dev_err(&pdev->dev, "GPIO NOT VALID\n");
+                       ret = -EINVAL;
+                       goto err_alloc;
+               }
+
+               ret = gpio_request(pdata->buck125_gpios[0],
+                               "MAX8997 SET1");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                                       " on SET1\n");
+               else if (ret)
+                       goto err_alloc;
+               else
+                       gpio1set = true;
+
+               ret = gpio_request(pdata->buck125_gpios[1],
+                               "MAX8997 SET2");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                                       " on SET2\n");
+               else if (ret) {
+                       if (gpio1set)
+                               gpio_free(pdata->buck125_gpios[0]);
+                       goto err_alloc;
+               } else
+                       gpio2set = true;
+
+               ret = gpio_request(pdata->buck125_gpios[2],
+                               "MAX8997 SET3");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                                       " on SET3\n");
+               else if (ret) {
+                       if (gpio1set)
+                               gpio_free(pdata->buck125_gpios[0]);
+                       if (gpio2set)
+                               gpio_free(pdata->buck125_gpios[1]);
+                       goto err_alloc;
+               }
+
+               gpio_direction_output(pdata->buck125_gpios[0],
+                               (max8997->buck125_gpioindex >> 2)
+                               & 0x1); /* SET1 */
+               gpio_direction_output(pdata->buck125_gpios[1],
+                               (max8997->buck125_gpioindex >> 1)
+                               & 0x1); /* SET2 */
+               gpio_direction_output(pdata->buck125_gpios[2],
+                               (max8997->buck125_gpioindex >> 0)
+                               & 0x1); /* SET3 */
+               ret = 0;
+       }
+
+       /* DVS-GPIO disabled */
+       max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ?
+                       (1 << 1) : (0 << 1), 1 << 1);
+       max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ?
+                       (1 << 1) : (0 << 1), 1 << 1);
+       max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ?
+                       (1 << 1) : (0 << 1), 1 << 1);
+
+       /* Initialize all the DVS related BUCK registers */
+       for (i = 0; i < 8; i++) {
+               max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+                               max8997->buck1_vol[i],
+                               0x3f);
+               max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+                               max8997->buck2_vol[i],
+                               0x3f);
+               max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+                               max8997->buck5_vol[i],
+                               0x3f);
+       }
+
+       for (i = 0; i < pdata->num_regulators; i++) {
+               const struct voltage_map_desc *desc;
+               int id = pdata->regulators[i].id;
+
+               desc = reg_voltage_map[id];
+               if (desc)
+                       regulators[id].n_voltages =
+                               (desc->max - desc->min) / desc->step + 1;
+               else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
+                       regulators[id].n_voltages = 4;
+               else if (id == MAX8997_CHARGER_CV)
+                       regulators[id].n_voltages = 16;
+
+               rdev[i] = regulator_register(&regulators[id], max8997->dev,
+                               pdata->regulators[i].initdata, max8997);
+               if (IS_ERR(rdev[i])) {
+                       ret = PTR_ERR(rdev[i]);
+                       dev_err(max8997->dev, "regulator init failed for %d\n",
+                                       id);
+                       rdev[i] = NULL;
+                       goto err;
+               }
+       }
+
+       /* Misc Settings */
+       max8997->ramp_delay = 10; /* set 10mV/us, which is the default */
+       max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9);
+
+       return 0;
+err:
+       for (i = 0; i < max8997->num_regulators; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+err_alloc:
+       kfree(max8997->rdev);
+       kfree(max8997);
+
+       return ret;
+}
+
+static int __devexit max8997_pmic_remove(struct platform_device *pdev)
+{
+       struct max8997_data *max8997 = platform_get_drvdata(pdev);
+       struct regulator_dev **rdev = max8997->rdev;
+       int i;
+
+       for (i = 0; i < max8997->num_regulators; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+
+       kfree(max8997->rdev);
+       kfree(max8997);
+
+       return 0;
+}
+
+static const struct platform_device_id max8997_pmic_id[] = {
+       { "max8997-pmic", 0},
+       { },
+};
+
+static struct platform_driver max8997_pmic_driver = {
+       .driver = {
+               .name = "max8997-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = max8997_pmic_probe,
+       .remove = __devexit_p(max8997_pmic_remove),
+       .id_table = max8997_pmic_id,
+};
+
+static int __init max8997_pmic_init(void)
+{
+       return platform_driver_register(&max8997_pmic_driver);
+}
+subsys_initcall(max8997_pmic_init);
+
+static void __exit max8997_pmic_cleanup(void)
+{
+       platform_driver_unregister(&max8997_pmic_driver);
+}
+module_exit(max8997_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
index 3e5d0c3b4e53134e84fa1ce2b5b32413de9b9a65..23249cb0a8bdcc6be50b0ccb52e89f5e3cf5fa36 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
+#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -336,8 +337,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv;
        struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
-       struct mc13783_regulator_platform_data *pdata =
-               dev_get_platdata(&pdev->dev);
+       struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
        struct mc13783_regulator_init_data *init_data;
        int i, ret;
 
@@ -381,8 +381,7 @@ err:
 static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-       struct mc13783_regulator_platform_data *pdata =
-               dev_get_platdata(&pdev->dev);
+       struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
        int i;
 
        platform_set_drvdata(pdev, NULL);
index 1b8f7398a4a8f9709a17d17463be54afcbda9ae4..6f15168e5ed494e04cbc4d38a9589bdc0847c97c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
+#include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -520,8 +521,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv;
        struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
-       struct mc13xxx_regulator_platform_data *pdata =
-               dev_get_platdata(&pdev->dev);
+       struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
        struct mc13xxx_regulator_init_data *init_data;
        int i, ret;
        u32 val;
@@ -595,8 +595,7 @@ err_free:
 static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
 {
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
-       struct mc13xxx_regulator_platform_data *pdata =
-               dev_get_platdata(&pdev->dev);
+       struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
        int i;
 
        platform_set_drvdata(pdev, NULL);
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
new file mode 100644 (file)
index 0000000..1661499
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Driver for TPS61050/61052 boost converters, typically used for white LEDs
+ * or audio amplifiers.
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps6105x.h>
+
+static const int tps6105x_voltages[] = {
+       4500000,
+       5000000,
+       5250000,
+       5000000, /* There is an additional 5V */
+};
+
+static int tps6105x_regulator_enable(struct regulator_dev *rdev)
+{
+       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+       int ret;
+
+       /* Activate voltage mode */
+       ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+               TPS6105X_REG0_MODE_MASK,
+               TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int tps6105x_regulator_disable(struct regulator_dev *rdev)
+{
+       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+       int ret;
+
+       /* Set into shutdown mode */
+       ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+               TPS6105X_REG0_MODE_MASK,
+               TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
+{
+       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+       u8 regval;
+       int ret;
+
+       ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
+       if (ret)
+               return ret;
+       regval &= TPS6105X_REG0_MODE_MASK;
+       regval >>= TPS6105X_REG0_MODE_SHIFT;
+
+       if (regval == TPS6105X_REG0_MODE_VOLTAGE)
+               return 1;
+
+       return 0;
+}
+
+static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+       u8 regval;
+       int ret;
+
+       ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
+       if (ret)
+               return ret;
+
+       regval &= TPS6105X_REG0_VOLTAGE_MASK;
+       regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
+       return (int) regval;
+}
+
+static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
+                                             unsigned selector)
+{
+       struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+                                   TPS6105X_REG0_VOLTAGE_MASK,
+                                   selector << TPS6105X_REG0_VOLTAGE_SHIFT);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
+                                          unsigned selector)
+{
+       if (selector >= ARRAY_SIZE(tps6105x_voltages))
+               return -EINVAL;
+
+       return tps6105x_voltages[selector];
+}
+
+static struct regulator_ops tps6105x_regulator_ops = {
+       .enable         = tps6105x_regulator_enable,
+       .disable        = tps6105x_regulator_disable,
+       .is_enabled     = tps6105x_regulator_is_enabled,
+       .get_voltage_sel = tps6105x_regulator_get_voltage_sel,
+       .set_voltage_sel = tps6105x_regulator_set_voltage_sel,
+       .list_voltage   = tps6105x_regulator_list_voltage,
+};
+
+static struct regulator_desc tps6105x_regulator_desc = {
+       .name           = "tps6105x-boost",
+       .ops            = &tps6105x_regulator_ops,
+       .type           = REGULATOR_VOLTAGE,
+       .id             = 0,
+       .owner          = THIS_MODULE,
+       .n_voltages     = ARRAY_SIZE(tps6105x_voltages),
+};
+
+/*
+ * Registers the chip as a voltage regulator
+ */
+static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
+{
+       struct tps6105x *tps6105x = mfd_get_data(pdev);
+       struct tps6105x_platform_data *pdata = tps6105x->pdata;
+       int ret;
+
+       /* This instance is not set for regulator mode so bail out */
+       if (pdata->mode != TPS6105X_MODE_VOLTAGE) {
+               dev_info(&pdev->dev,
+                        "chip not in voltage mode mode, exit probe \n");
+               return 0;
+       }
+
+       /* Register regulator with framework */
+       tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
+                                            &tps6105x->client->dev,
+                                            pdata->regulator_data, tps6105x);
+       if (IS_ERR(tps6105x->regulator)) {
+               ret = PTR_ERR(tps6105x->regulator);
+               dev_err(&tps6105x->client->dev,
+                       "failed to register regulator\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
+{
+       struct tps6105x *tps6105x = platform_get_drvdata(pdev);
+       regulator_unregister(tps6105x->regulator);
+       return 0;
+}
+
+static struct platform_driver tps6105x_regulator_driver = {
+       .driver = {
+               .name  = "tps6105x-regulator",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps6105x_regulator_probe,
+       .remove = __devexit_p(tps6105x_regulator_remove),
+};
+
+static __init int tps6105x_regulator_init(void)
+{
+       return platform_driver_register(&tps6105x_regulator_driver);
+}
+subsys_initcall(tps6105x_regulator_init);
+
+static __exit void tps6105x_regulator_exit(void)
+{
+       platform_driver_unregister(&tps6105x_regulator_driver);
+}
+module_exit(tps6105x_regulator_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("TPS6105x regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps6105x-regulator");
index bd332cf1cc3f9fc390f637457c16763cca30d19c..6a292852a3583899a1d1c1a2c3236e76aea6d118 100644 (file)
@@ -475,6 +475,13 @@ static struct regulator_ops twlfixed_ops = {
        .get_status     = twlreg_get_status,
 };
 
+static struct regulator_ops twl6030_fixed_resource = {
+       .enable         = twlreg_enable,
+       .disable        = twlreg_disable,
+       .is_enabled     = twlreg_is_enabled,
+       .get_status     = twlreg_get_status,
+};
+
 /*----------------------------------------------------------------------*/
 
 #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
@@ -538,6 +545,20 @@ static struct regulator_ops twlfixed_ops = {
                }, \
        }
 
+#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \
+       .base = offset, \
+       .id = num, \
+       .delay = turnon_delay, \
+       .remap = remap_conf, \
+       .desc = { \
+               .name = #label, \
+               .id = TWL6030_REG_##label, \
+               .ops = &twl6030_fixed_resource, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               }, \
+       }
+
 /*
  * We list regulators here if systems need some level of
  * software control over them after boot.
@@ -577,7 +598,8 @@ static struct twlreg_info twl_regs[] = {
        TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
        TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
        TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
-       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21)
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21),
+       TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21),
 };
 
 static int __devinit twlreg_probe(struct platform_device *pdev)
index 4941cade319f5cef06d508d0b1f1354d951c1034..e1878877399c42418e5b8d626337c285e3d9b12a 100644 (file)
@@ -985,4 +985,14 @@ config RTC_DRV_LPC32XX
          This driver can also be buillt as a module. If so, the module
          will be called rtc-lpc32xx.
 
+config RTC_DRV_TEGRA
+       tristate "NVIDIA Tegra Internal RTC driver"
+       depends on RTC_CLASS && ARCH_TEGRA
+       help
+         If you say yes here you get support for the
+         Tegra 200 series internal RTC module.
+
+         This drive can also be built as a module. If so, the module
+         will be called rtc-tegra.
+
 endif # RTC_CLASS
index 2afdaf3ff98660f53c72a189503786ebeac0a27c..ca91c3c42e98f6f7effa5ce95463f26e11d34a74 100644 (file)
@@ -2,9 +2,7 @@
 # Makefile for RTC class/drivers.
 #
 
-ifeq ($(CONFIG_RTC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
+ccflags-$(CONFIG_RTC_DEBUG)    := -DDEBUG
 
 obj-$(CONFIG_RTC_LIB)          += rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
@@ -93,6 +91,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE)        += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_STMP)     += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_TEGRA)    += rtc-tegra.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
index d834a63ec4b0ec9b5c035e480e969f6722a82c7c..e6e71deb188f7cc91a6512584724df883f307a27 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/bcd.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 
 #define DS1374_REG_TOD0                0x00 /* Time of Day */
 #define DS1374_REG_TOD1                0x01
@@ -409,32 +410,38 @@ static int __devexit ds1374_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int ds1374_suspend(struct i2c_client *client, pm_message_t state)
+static int ds1374_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        if (client->irq >= 0 && device_may_wakeup(&client->dev))
                enable_irq_wake(client->irq);
        return 0;
 }
 
-static int ds1374_resume(struct i2c_client *client)
+static int ds1374_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        if (client->irq >= 0 && device_may_wakeup(&client->dev))
                disable_irq_wake(client->irq);
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
+
+#define DS1374_PM (&ds1374_pm)
 #else
-#define ds1374_suspend NULL
-#define ds1374_resume  NULL
+#define DS1374_PM NULL
 #endif
 
 static struct i2c_driver ds1374_driver = {
        .driver = {
                .name = "rtc-ds1374",
                .owner = THIS_MODULE,
+               .pm = DS1374_PM,
        },
        .probe = ds1374_probe,
-       .suspend = ds1374_suspend,
-       .resume = ds1374_resume,
        .remove = __devexit_p(ds1374_remove),
        .id_table = ds1374_id,
 };
index 3fffd708711f52fd646692b068fd3d8e8aef0655..fbabc773dded52eb6ee17e3f6c92b589bef0d189 100644 (file)
@@ -468,7 +468,7 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj,
 static struct bin_attribute ds1511_nvram_attr = {
        .attr = {
                .name = "nvram",
-               .mode = S_IRUGO | S_IWUGO,
+               .mode = S_IRUGO | S_IWUSR,
        },
        .size = DS1511_RAM_MAX,
        .read = ds1511_nvram_read,
index 468200c38ecbf4116e0abf1873aec8f0e65e85fd..da8beb8cae51931162aebe3802cddc45067e8f96 100644 (file)
@@ -39,6 +39,8 @@
 #define ISL1208_REG_SR_BAT     (1<<1)  /* battery */
 #define ISL1208_REG_SR_RTCF    (1<<0)  /* rtc fail */
 #define ISL1208_REG_INT 0x08
+#define ISL1208_REG_INT_ALME   (1<<6)   /* alarm enable */
+#define ISL1208_REG_INT_IM     (1<<7)   /* interrupt/alarm mode */
 #define ISL1208_REG_09  0x09   /* reserved */
 #define ISL1208_REG_ATR 0x0a
 #define ISL1208_REG_DTR 0x0b
@@ -201,6 +203,30 @@ isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
                                    ISL1208_USR_SECTION_LEN);
 }
 
+static int
+isl1208_rtc_toggle_alarm(struct i2c_client *client, int enable)
+{
+       int icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT);
+
+       if (icr < 0) {
+               dev_err(&client->dev, "%s: reading INT failed\n", __func__);
+               return icr;
+       }
+
+       if (enable)
+               icr |= ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM;
+       else
+               icr &= ~(ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM);
+
+       icr = i2c_smbus_write_byte_data(client, ISL1208_REG_INT, icr);
+       if (icr < 0) {
+               dev_err(&client->dev, "%s: writing INT failed\n", __func__);
+               return icr;
+       }
+
+       return 0;
+}
+
 static int
 isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
 {
@@ -288,9 +314,8 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
 {
        struct rtc_time *const tm = &alarm->time;
        u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
-       int sr;
+       int icr, yr, sr = isl1208_i2c_get_sr(client);
 
-       sr = isl1208_i2c_get_sr(client);
        if (sr < 0) {
                dev_err(&client->dev, "%s: reading SR failed\n", __func__);
                return sr;
@@ -313,6 +338,73 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
                bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1;
        tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03);
 
+       /* The alarm doesn't store the year so get it from the rtc section */
+       yr = i2c_smbus_read_byte_data(client, ISL1208_REG_YR);
+       if (yr < 0) {
+               dev_err(&client->dev, "%s: reading RTC YR failed\n", __func__);
+               return yr;
+       }
+       tm->tm_year = bcd2bin(yr) + 100;
+
+       icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT);
+       if (icr < 0) {
+               dev_err(&client->dev, "%s: reading INT failed\n", __func__);
+               return icr;
+       }
+       alarm->enabled = !!(icr & ISL1208_REG_INT_ALME);
+
+       return 0;
+}
+
+static int
+isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
+{
+       struct rtc_time *alarm_tm = &alarm->time;
+       u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
+       const int offs = ISL1208_REG_SCA;
+       unsigned long rtc_secs, alarm_secs;
+       struct rtc_time rtc_tm;
+       int err, enable;
+
+       err = isl1208_i2c_read_time(client, &rtc_tm);
+       if (err)
+               return err;
+       err = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+       if (err)
+               return err;
+       err = rtc_tm_to_time(alarm_tm, &alarm_secs);
+       if (err)
+               return err;
+
+       /* If the alarm time is before the current time disable the alarm */
+       if (!alarm->enabled || alarm_secs <= rtc_secs)
+               enable = 0x00;
+       else
+               enable = 0x80;
+
+       /* Program the alarm and enable it for each setting */
+       regs[ISL1208_REG_SCA - offs] = bin2bcd(alarm_tm->tm_sec) | enable;
+       regs[ISL1208_REG_MNA - offs] = bin2bcd(alarm_tm->tm_min) | enable;
+       regs[ISL1208_REG_HRA - offs] = bin2bcd(alarm_tm->tm_hour) |
+               ISL1208_REG_HR_MIL | enable;
+
+       regs[ISL1208_REG_DTA - offs] = bin2bcd(alarm_tm->tm_mday) | enable;
+       regs[ISL1208_REG_MOA - offs] = bin2bcd(alarm_tm->tm_mon + 1) | enable;
+       regs[ISL1208_REG_DWA - offs] = bin2bcd(alarm_tm->tm_wday & 7) | enable;
+
+       /* write ALARM registers */
+       err = isl1208_i2c_set_regs(client, offs, regs,
+                                 ISL1208_ALARM_SECTION_LEN);
+       if (err < 0) {
+               dev_err(&client->dev, "%s: writing ALARM section failed\n",
+                       __func__);
+               return err;
+       }
+
+       err = isl1208_rtc_toggle_alarm(client, enable);
+       if (err)
+               return err;
+
        return 0;
 }
 
@@ -391,12 +483,63 @@ isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
 }
 
+static int
+isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm);
+}
+
+static irqreturn_t
+isl1208_rtc_interrupt(int irq, void *data)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+       struct i2c_client *client = data;
+       int handled = 0, sr, err;
+
+       /*
+        * I2C reads get NAK'ed if we read straight away after an interrupt?
+        * Using a mdelay/msleep didn't seem to help either, so we work around
+        * this by continually trying to read the register for a short time.
+        */
+       while (1) {
+               sr = isl1208_i2c_get_sr(client);
+               if (sr >= 0)
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       dev_err(&client->dev, "%s: reading SR failed\n",
+                               __func__);
+                       return sr;
+               }
+       }
+
+       if (sr & ISL1208_REG_SR_ALM) {
+               dev_dbg(&client->dev, "alarm!\n");
+
+               /* Clear the alarm */
+               sr &= ~ISL1208_REG_SR_ALM;
+               sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
+               if (sr < 0)
+                       dev_err(&client->dev, "%s: writing SR failed\n",
+                               __func__);
+               else
+                       handled = 1;
+
+               /* Disable the alarm */
+               err = isl1208_rtc_toggle_alarm(client, 0);
+               if (err)
+                       return err;
+       }
+
+       return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
 static const struct rtc_class_ops isl1208_rtc_ops = {
        .proc = isl1208_rtc_proc,
        .read_time = isl1208_rtc_read_time,
        .set_time = isl1208_rtc_set_time,
        .read_alarm = isl1208_rtc_read_alarm,
-       /*.set_alarm    = isl1208_rtc_set_alarm, */
+       .set_alarm = isl1208_rtc_set_alarm,
 };
 
 /* sysfs interface */
@@ -488,11 +631,29 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
        dev_info(&client->dev,
                 "chip found, driver version " DRV_VERSION "\n");
 
+       if (client->irq > 0) {
+               rc = request_threaded_irq(client->irq, NULL,
+                                         isl1208_rtc_interrupt,
+                                         IRQF_SHARED,
+                                         isl1208_driver.driver.name, client);
+               if (!rc) {
+                       device_init_wakeup(&client->dev, 1);
+                       enable_irq_wake(client->irq);
+               } else {
+                       dev_err(&client->dev,
+                               "Unable to request irq %d, no alarm support\n",
+                               client->irq);
+                       client->irq = 0;
+               }
+       }
+
        rtc = rtc_device_register(isl1208_driver.driver.name,
                                  &client->dev, &isl1208_rtc_ops,
                                  THIS_MODULE);
-       if (IS_ERR(rtc))
-               return PTR_ERR(rtc);
+       if (IS_ERR(rtc)) {
+               rc = PTR_ERR(rtc);
+               goto exit_free_irq;
+       }
 
        i2c_set_clientdata(client, rtc);
 
@@ -514,6 +675,9 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 exit_unregister:
        rtc_device_unregister(rtc);
+exit_free_irq:
+       if (client->irq)
+               free_irq(client->irq, client);
 
        return rc;
 }
@@ -525,6 +689,8 @@ isl1208_remove(struct i2c_client *client)
 
        sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
        rtc_device_unregister(rtc);
+       if (client->irq)
+               free_irq(client->irq, client);
 
        return 0;
 }
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
new file mode 100644 (file)
index 0000000..2fc31aa
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * An RTC driver for the NVIDIA Tegra 200 series internal RTC.
+ *
+ * Copyright (c) 2010, NVIDIA 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
+#define TEGRA_RTC_REG_BUSY                     0x004
+#define TEGRA_RTC_REG_SECONDS                  0x008
+/* when msec is read, the seconds are buffered into shadow seconds. */
+#define TEGRA_RTC_REG_SHADOW_SECONDS           0x00c
+#define TEGRA_RTC_REG_MILLI_SECONDS            0x010
+#define TEGRA_RTC_REG_SECONDS_ALARM0           0x014
+#define TEGRA_RTC_REG_SECONDS_ALARM1           0x018
+#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0     0x01c
+#define TEGRA_RTC_REG_INTR_MASK                        0x028
+/* write 1 bits to clear status bits */
+#define TEGRA_RTC_REG_INTR_STATUS              0x02c
+
+/* bits in INTR_MASK */
+#define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM     (1<<4)
+#define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM      (1<<3)
+#define TEGRA_RTC_INTR_MASK_MSEC_ALARM         (1<<2)
+#define TEGRA_RTC_INTR_MASK_SEC_ALARM1         (1<<1)
+#define TEGRA_RTC_INTR_MASK_SEC_ALARM0         (1<<0)
+
+/* bits in INTR_STATUS */
+#define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM   (1<<4)
+#define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM    (1<<3)
+#define TEGRA_RTC_INTR_STATUS_MSEC_ALARM       (1<<2)
+#define TEGRA_RTC_INTR_STATUS_SEC_ALARM1       (1<<1)
+#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0       (1<<0)
+
+struct tegra_rtc_info {
+       struct platform_device  *pdev;
+       struct rtc_device       *rtc_dev;
+       void __iomem            *rtc_base; /* NULL if not initialized. */
+       int                     tegra_rtc_irq; /* alarm and periodic irq */
+       spinlock_t              tegra_rtc_lock;
+};
+
+/* RTC hardware is busy when it is updating its values over AHB once
+ * every eight 32kHz clocks (~250uS).
+ * outside of these updates the CPU is free to write.
+ * CPU is always free to read.
+ */
+static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info)
+{
+       return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1;
+}
+
+/* Wait for hardware to be ready for writing.
+ * This function tries to maximize the amount of time before the next update.
+ * It does this by waiting for the RTC to become busy with its periodic update,
+ * then returning once the RTC first becomes not busy.
+ * This periodic update (where the seconds and milliseconds are copied to the
+ * AHB side) occurs every eight 32kHz clocks (~250uS).
+ * The behavior of this function allows us to make some assumptions without
+ * introducing a race, because 250uS is plenty of time to read/write a value.
+ */
+static int tegra_rtc_wait_while_busy(struct device *dev)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+
+       int retries = 500; /* ~490 us is the worst case, ~250 us is best. */
+
+       /* first wait for the RTC to become busy. this is when it
+        * posts its updated seconds+msec registers to AHB side. */
+       while (tegra_rtc_check_busy(info)) {
+               if (!retries--)
+                       goto retry_failed;
+               udelay(1);
+       }
+
+       /* now we have about 250 us to manipulate registers */
+       return 0;
+
+retry_failed:
+       dev_err(dev, "write failed:retry count exceeded.\n");
+       return -ETIMEDOUT;
+}
+
+static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned long sec, msec;
+       unsigned long sl_irq_flags;
+
+       /* RTC hardware copies seconds to shadow seconds when a read
+        * of milliseconds occurs. use a lock to keep other threads out. */
+       spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+
+       msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS);
+       sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS);
+
+       spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+
+       rtc_time_to_tm(sec, tm);
+
+       dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n",
+               sec,
+               tm->tm_mon + 1,
+               tm->tm_mday,
+               tm->tm_year + 1900,
+               tm->tm_hour,
+               tm->tm_min,
+               tm->tm_sec
+       );
+
+       return 0;
+}
+
+static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned long sec;
+       int ret;
+
+       /* convert tm to seconds. */
+       ret = rtc_valid_tm(tm);
+       if (ret)
+               return ret;
+
+       rtc_tm_to_time(tm, &sec);
+
+       dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n",
+               sec,
+               tm->tm_mon+1,
+               tm->tm_mday,
+               tm->tm_year+1900,
+               tm->tm_hour,
+               tm->tm_min,
+               tm->tm_sec
+       );
+
+       /* seconds only written if wait succeeded. */
+       ret = tegra_rtc_wait_while_busy(dev);
+       if (!ret)
+               writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS);
+
+       dev_vdbg(dev, "time read back as %d\n",
+               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS));
+
+       return ret;
+}
+
+static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned long sec;
+       unsigned tmp;
+
+       sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+
+       if (sec == 0) {
+               /* alarm is disabled. */
+               alarm->enabled = 0;
+               alarm->time.tm_mon = -1;
+               alarm->time.tm_mday = -1;
+               alarm->time.tm_year = -1;
+               alarm->time.tm_hour = -1;
+               alarm->time.tm_min = -1;
+               alarm->time.tm_sec = -1;
+       } else {
+               /* alarm is enabled. */
+               alarm->enabled = 1;
+               rtc_time_to_tm(sec, &alarm->time);
+       }
+
+       tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0;
+
+       return 0;
+}
+
+static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned status;
+       unsigned long sl_irq_flags;
+
+       tegra_rtc_wait_while_busy(dev);
+       spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+
+       /* read the original value, and OR in the flag. */
+       status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+       if (enabled)
+               status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */
+       else
+               status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */
+
+       writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+
+       spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+
+       return 0;
+}
+
+static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned long sec;
+
+       if (alarm->enabled)
+               rtc_tm_to_time(&alarm->time, &sec);
+       else
+               sec = 0;
+
+       tegra_rtc_wait_while_busy(dev);
+       writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+       dev_vdbg(dev, "alarm read back as %d\n",
+               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+
+       /* if successfully written and alarm is enabled ... */
+       if (sec) {
+               tegra_rtc_alarm_irq_enable(dev, 1);
+
+               dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n",
+                       sec,
+                       alarm->time.tm_mon+1,
+                       alarm->time.tm_mday,
+                       alarm->time.tm_year+1900,
+                       alarm->time.tm_hour,
+                       alarm->time.tm_min,
+                       alarm->time.tm_sec);
+       } else {
+               /* disable alarm if 0 or write error. */
+               dev_vdbg(dev, "alarm disabled\n");
+               tegra_rtc_alarm_irq_enable(dev, 0);
+       }
+
+       return 0;
+}
+
+static int tegra_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+       if (!dev || !dev->driver)
+               return 0;
+
+       return seq_printf(seq, "name\t\t: %s\n", dev_name(dev));
+}
+
+static irqreturn_t tegra_rtc_irq_handler(int irq, void *data)
+{
+       struct device *dev = data;
+       struct tegra_rtc_info *info = dev_get_drvdata(dev);
+       unsigned long events = 0;
+       unsigned status;
+       unsigned long sl_irq_flags;
+
+       status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       if (status) {
+               /* clear the interrupt masks and status on any irq. */
+               tegra_rtc_wait_while_busy(dev);
+               spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags);
+               writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+               writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+               spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags);
+       }
+
+       /* check if Alarm */
+       if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0))
+               events |= RTC_IRQF | RTC_AF;
+
+       /* check if Periodic */
+       if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM))
+               events |= RTC_IRQF | RTC_PF;
+
+       rtc_update_irq(info->rtc_dev, 1, events);
+
+       return IRQ_HANDLED;
+}
+
+static struct rtc_class_ops tegra_rtc_ops = {
+       .read_time      = tegra_rtc_read_time,
+       .set_time       = tegra_rtc_set_time,
+       .read_alarm     = tegra_rtc_read_alarm,
+       .set_alarm      = tegra_rtc_set_alarm,
+       .proc           = tegra_rtc_proc,
+       .alarm_irq_enable = tegra_rtc_alarm_irq_enable,
+};
+
+static int __devinit tegra_rtc_probe(struct platform_device *pdev)
+{
+       struct tegra_rtc_info *info;
+       struct resource *res;
+       int ret;
+
+       info = kzalloc(sizeof(struct tegra_rtc_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Unable to allocate resources for device.\n");
+               ret = -EBUSY;
+               goto err_free_info;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_err(&pdev->dev,
+                       "Unable to request mem region for device.\n");
+               ret = -EBUSY;
+               goto err_free_info;
+       }
+
+       info->tegra_rtc_irq = platform_get_irq(pdev, 0);
+       if (info->tegra_rtc_irq <= 0) {
+               ret = -EBUSY;
+               goto err_release_mem_region;
+       }
+
+       info->rtc_base = ioremap_nocache(res->start, resource_size(res));
+       if (!info->rtc_base) {
+               dev_err(&pdev->dev, "Unable to grab IOs for device.\n");
+               ret = -EBUSY;
+               goto err_release_mem_region;
+       }
+
+       /* set context info. */
+       info->pdev = pdev;
+       info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock);
+
+       platform_set_drvdata(pdev, info);
+
+       /* clear out the hardware. */
+       writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0);
+       writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       info->rtc_dev = rtc_device_register(
+               pdev->name, &pdev->dev, &tegra_rtc_ops, THIS_MODULE);
+       if (IS_ERR(info->rtc_dev)) {
+               ret = PTR_ERR(info->rtc_dev);
+               info->rtc_dev = NULL;
+               dev_err(&pdev->dev,
+                       "Unable to register device (err=%d).\n",
+                       ret);
+               goto err_iounmap;
+       }
+
+       ret = request_irq(info->tegra_rtc_irq, tegra_rtc_irq_handler,
+               IRQF_TRIGGER_HIGH, "rtc alarm", &pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Unable to request interrupt for device (err=%d).\n",
+                       ret);
+               goto err_dev_unreg;
+       }
+
+       dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
+
+       return 0;
+
+err_dev_unreg:
+       rtc_device_unregister(info->rtc_dev);
+err_iounmap:
+       iounmap(info->rtc_base);
+err_release_mem_region:
+       release_mem_region(res->start, resource_size(res));
+err_free_info:
+       kfree(info);
+
+       return ret;
+}
+
+static int __devexit tegra_rtc_remove(struct platform_device *pdev)
+{
+       struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EBUSY;
+
+       free_irq(info->tegra_rtc_irq, &pdev->dev);
+       rtc_device_unregister(info->rtc_dev);
+       iounmap(info->rtc_base);
+       release_mem_region(res->start, resource_size(res));
+       kfree(info);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+       tegra_rtc_wait_while_busy(dev);
+
+       /* only use ALARM0 as a wake source. */
+       writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS);
+       writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0,
+               info->rtc_base + TEGRA_RTC_REG_INTR_MASK);
+
+       dev_vdbg(dev, "alarm sec = %d\n",
+               readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0));
+
+       dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n",
+               device_may_wakeup(dev), info->tegra_rtc_irq);
+
+       /* leave the alarms on as a wake source. */
+       if (device_may_wakeup(dev))
+               enable_irq_wake(info->tegra_rtc_irq);
+
+       return 0;
+}
+
+static int tegra_rtc_resume(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+       dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
+               device_may_wakeup(dev));
+       /* alarms were left on as a wake source, turn them off. */
+       if (device_may_wakeup(dev))
+               disable_irq_wake(info->tegra_rtc_irq);
+
+       return 0;
+}
+#endif
+
+static void tegra_rtc_shutdown(struct platform_device *pdev)
+{
+       dev_vdbg(&pdev->dev, "disabling interrupts.\n");
+       tegra_rtc_alarm_irq_enable(&pdev->dev, 0);
+}
+
+MODULE_ALIAS("platform:tegra_rtc");
+static struct platform_driver tegra_rtc_driver = {
+       .remove         = __devexit_p(tegra_rtc_remove),
+       .shutdown       = tegra_rtc_shutdown,
+       .driver         = {
+               .name   = "tegra_rtc",
+               .owner  = THIS_MODULE,
+       },
+#ifdef CONFIG_PM
+       .suspend        = tegra_rtc_suspend,
+       .resume         = tegra_rtc_resume,
+#endif
+};
+
+static int __init tegra_rtc_init(void)
+{
+       return platform_driver_probe(&tegra_rtc_driver, tegra_rtc_probe);
+}
+module_init(tegra_rtc_init);
+
+static void __exit tegra_rtc_exit(void)
+{
+       platform_driver_unregister(&tegra_rtc_driver);
+}
+module_exit(tegra_rtc_exit);
+
+MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
+MODULE_DESCRIPTION("driver for Tegra internal RTC");
+MODULE_LICENSE("GPL");
index 794bfd962266f3c55c95e24c60c768a9f5b261c0..4d2df2f76ea0daa718215c179e88fe2b45249516 100644 (file)
@@ -1917,7 +1917,7 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                return;
        }
        /* Now we try to fetch requests from the request queue */
-       while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) {
+       while ((req = blk_peek_request(queue))) {
                if (basedev->features & DASD_FEATURE_READONLY &&
                    rq_data_dir(req) == WRITE) {
                        DBF_DEV_EVENT(DBF_ERR, basedev,
index 379d8592bc6e371a24ac960eaff5b11a8a20909e..459f2cbe80fccca7c3e0d338bbe18f8bb7123de4 100644 (file)
@@ -3982,8 +3982,10 @@ out_err:
 }
 
 static struct ccw_driver dasd_eckd_driver = {
-       .name        = "dasd-eckd",
-       .owner       = THIS_MODULE,
+       .driver = {
+               .name   = "dasd-eckd",
+               .owner  = THIS_MODULE,
+       },
        .ids         = dasd_eckd_ids,
        .probe       = dasd_eckd_probe,
        .remove      = dasd_generic_remove,
index be89b3a893da4c91aa84cf509a1ab1717b3adfc0..4b71b116486838daea8132a832fcaa200f720016 100644 (file)
@@ -65,8 +65,10 @@ dasd_fba_set_online(struct ccw_device *cdev)
 }
 
 static struct ccw_driver dasd_fba_driver = {
-       .name        = "dasd-fba",
-       .owner       = THIS_MODULE,
+       .driver = {
+               .name   = "dasd-fba",
+               .owner  = THIS_MODULE,
+       },
        .ids         = dasd_fba_ids,
        .probe       = dasd_fba_probe,
        .remove      = dasd_generic_remove,
index 3fb4335d491d7aaf114769f026d13a4c8cbdcab5..694464c65fcdaaddd5c7c2b09514ca822e1606af 100644 (file)
@@ -764,8 +764,10 @@ static struct ccw_device_id raw3215_id[] = {
 };
 
 static struct ccw_driver raw3215_ccw_driver = {
-       .name           = "3215",
-       .owner          = THIS_MODULE,
+       .driver = {
+               .name   = "3215",
+               .owner  = THIS_MODULE,
+       },
        .ids            = raw3215_id,
        .probe          = &raw3215_probe,
        .remove         = &raw3215_remove,
index 96ba2fd1c8ad04added98cc56eb75aa4d3f61469..4c023761946f6bc196783a859f3a0ce60cded9f2 100644 (file)
@@ -1388,8 +1388,10 @@ static struct ccw_device_id raw3270_id[] = {
 };
 
 static struct ccw_driver raw3270_ccw_driver = {
-       .name           = "3270",
-       .owner          = THIS_MODULE,
+       .driver = {
+               .name   = "3270",
+               .owner  = THIS_MODULE,
+       },
        .ids            = raw3270_id,
        .probe          = &raw3270_probe,
        .remove         = &raw3270_remove,
index c26511171ffead57d7cce9d81612d09d84027185..9eff2df70ddb2e579c0e2ff3472278df080178d2 100644 (file)
@@ -1320,8 +1320,10 @@ tape_34xx_online(struct ccw_device *cdev)
 }
 
 static struct ccw_driver tape_34xx_driver = {
-       .name = "tape_34xx",
-       .owner = THIS_MODULE,
+       .driver = {
+               .name = "tape_34xx",
+               .owner = THIS_MODULE,
+       },
        .ids = tape_34xx_ids,
        .probe = tape_generic_probe,
        .remove = tape_generic_remove,
index de2e99e0a71b56747df232bef1110815979eec04..b98dcbd16711e7978d8c1fc58394f4797d851fe8 100644 (file)
@@ -1761,8 +1761,10 @@ tape_3590_online(struct ccw_device *cdev)
 }
 
 static struct ccw_driver tape_3590_driver = {
-       .name = "tape_3590",
-       .owner = THIS_MODULE,
+       .driver = {
+               .name = "tape_3590",
+               .owner = THIS_MODULE,
+       },
        .ids = tape_3590_ids,
        .probe = tape_generic_probe,
        .remove = tape_generic_remove,
index 55d2d0f4eabc9cbd67a4a6fe1638305f883beb00..83cea9a55e2f8c10df077710a66f23760a7431e6 100644 (file)
 static DEFINE_MUTEX(tape_block_mutex);
 static int tapeblock_open(struct block_device *, fmode_t);
 static int tapeblock_release(struct gendisk *, fmode_t);
-static int tapeblock_medium_changed(struct gendisk *);
+static unsigned int tapeblock_check_events(struct gendisk *, unsigned int);
 static int tapeblock_revalidate_disk(struct gendisk *);
 
 static const struct block_device_operations tapeblock_fops = {
        .owner           = THIS_MODULE,
        .open            = tapeblock_open,
        .release         = tapeblock_release,
-       .media_changed   = tapeblock_medium_changed,
+       .check_events    = tapeblock_check_events,
        .revalidate_disk = tapeblock_revalidate_disk,
 };
 
@@ -161,7 +161,6 @@ tapeblock_requeue(struct work_struct *work) {
 
        spin_lock_irq(&device->blk_data.request_queue_lock);
        while (
-               !blk_queue_plugged(queue) &&
                blk_peek_request(queue) &&
                nr_queued < TAPEBLOCK_MIN_REQUEUE
        ) {
@@ -237,6 +236,7 @@ tapeblock_setup_device(struct tape_device * device)
        disk->major = tapeblock_major;
        disk->first_minor = device->first_minor;
        disk->fops = &tapeblock_fops;
+       disk->events = DISK_EVENT_MEDIA_CHANGE;
        disk->private_data = tape_get_device(device);
        disk->queue = blkdat->request_queue;
        set_capacity(disk, 0);
@@ -340,8 +340,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)
        return 0;
 }
 
-static int
-tapeblock_medium_changed(struct gendisk *disk)
+static unsigned int
+tapeblock_check_events(struct gendisk *disk, unsigned int clearing)
 {
        struct tape_device *device;
 
@@ -349,7 +349,7 @@ tapeblock_medium_changed(struct gendisk *disk)
        DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n",
                device, device->blk_data.medium_changed);
 
-       return device->blk_data.medium_changed;
+       return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
 }
 
 /*
index caef1757341d4ef7a8e60e1818bbcbfe03dd3675..f6b00c3df425d192da15790e75f16f6a6af09fb2 100644 (file)
@@ -64,8 +64,10 @@ static int ur_set_offline(struct ccw_device *cdev);
 static int ur_pm_suspend(struct ccw_device *cdev);
 
 static struct ccw_driver ur_driver = {
-       .name           = "vmur",
-       .owner          = THIS_MODULE,
+       .driver = {
+               .name   = "vmur",
+               .owner  = THIS_MODULE,
+       },
        .ids            = ur_ids,
        .probe          = ur_probe,
        .remove         = ur_remove,
index 2864581d8ecb88a9d9ce362e6fbb170a57a49f46..5c567414c4bb81ee74250b01a4755d8c30da3dbc 100644 (file)
@@ -428,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
        gdev = to_ccwgroupdev(dev);
        gdrv = to_ccwgroupdrv(dev->driver);
 
-       if (!try_module_get(gdrv->owner))
+       if (!try_module_get(gdrv->driver.owner))
                return -EINVAL;
 
        ret = strict_strtoul(buf, 0, &value);
@@ -442,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
        else
                ret = -EINVAL;
 out:
-       module_put(gdrv->owner);
+       module_put(gdrv->driver.owner);
        return (ret == 0) ? count : ret;
 }
 
@@ -616,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 {
        /* register our new driver with the core */
        cdriver->driver.bus = &ccwgroup_bus_type;
-       cdriver->driver.name = cdriver->name;
-       cdriver->driver.owner = cdriver->owner;
 
        return driver_register(&cdriver->driver);
 }
index e50b12163afeafe74fabe266b51dfffd9b2c5fe8..df14c51f653224d37b6ac29c87ad4a778f2b2af9 100644 (file)
@@ -127,7 +127,7 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
-struct bus_type ccw_bus_type;
+static struct bus_type ccw_bus_type;
 
 static void io_subchannel_irq(struct subchannel *);
 static int io_subchannel_probe(struct subchannel *);
@@ -547,7 +547,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
        if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
                return -EAGAIN;
 
-       if (cdev->drv && !try_module_get(cdev->drv->owner)) {
+       if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) {
                atomic_set(&cdev->private->onoff, 0);
                return -EINVAL;
        }
@@ -573,7 +573,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
        }
 out:
        if (cdev->drv)
-               module_put(cdev->drv->owner);
+               module_put(cdev->drv->driver.owner);
        atomic_set(&cdev->private->onoff, 0);
        return (ret < 0) ? ret : count;
 }
@@ -1970,7 +1970,7 @@ static const struct dev_pm_ops ccw_pm_ops = {
        .restore = ccw_device_pm_restore,
 };
 
-struct bus_type ccw_bus_type = {
+static struct bus_type ccw_bus_type = {
        .name   = "ccw",
        .match  = ccw_bus_match,
        .uevent = ccw_uevent,
@@ -1993,8 +1993,6 @@ int ccw_driver_register(struct ccw_driver *cdriver)
        struct device_driver *drv = &cdriver->driver;
 
        drv->bus = &ccw_bus_type;
-       drv->name = cdriver->name;
-       drv->owner = cdriver->owner;
 
        return driver_register(drv);
 }
@@ -2112,5 +2110,4 @@ EXPORT_SYMBOL(ccw_device_set_offline);
 EXPORT_SYMBOL(ccw_driver_register);
 EXPORT_SYMBOL(ccw_driver_unregister);
 EXPORT_SYMBOL(get_ccwdev_by_busid);
-EXPORT_SYMBOL(ccw_bus_type);
 EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);
index 379de2d1ec496a3895f42946b8080d99f88d1a71..7e297c7bb5fffe7ed6b719279923efb098c98b71 100644 (file)
@@ -133,7 +133,6 @@ void ccw_device_set_notoper(struct ccw_device *cdev);
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
-extern struct bus_type ccw_bus_type;
 
 /* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
index 5640c89cd9de3bae5f6f283f08eda97d7b3c3960..479c665e9e7c25f91996eeb287770384009c9b7a 100644 (file)
@@ -1508,7 +1508,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
 
        if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)
                return -EBUSY;
-
+       if (!count)
+               return 0;
        if (callflags & QDIO_FLAG_SYNC_INPUT)
                return handle_inbound(irq_ptr->input_qs[q_nr],
                                      callflags, bufnr, count);
index ce3a5c13ce0bb88deec855f3fa39c4bd4360ab45..9feb62febb3d53c4434ded6b1825081855510d09 100644 (file)
@@ -264,8 +264,10 @@ static struct device *claw_root_dev;
 /* ccwgroup table  */
 
 static struct ccwgroup_driver claw_group_driver = {
-        .owner       = THIS_MODULE,
-        .name        = "claw",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "claw",
+       },
         .max_slaves  = 2,
         .driver_id   = 0xC3D3C1E6,
         .probe       = claw_probe,
@@ -282,8 +284,10 @@ static struct ccw_device_id claw_ids[] = {
 MODULE_DEVICE_TABLE(ccw, claw_ids);
 
 static struct ccw_driver claw_ccw_driver = {
-       .owner  = THIS_MODULE,
-       .name   = "claw",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "claw",
+       },
        .ids    = claw_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
index 4c28459859276dd8ebf0d3dbab55d4a3eeca4e24..c189296763a4b05b7ab71bd348b90d55287d5e5d 100644 (file)
@@ -1764,16 +1764,20 @@ static struct ccw_device_id ctcm_ids[] = {
 MODULE_DEVICE_TABLE(ccw, ctcm_ids);
 
 static struct ccw_driver ctcm_ccw_driver = {
-       .owner  = THIS_MODULE,
-       .name   = "ctcm",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ctcm",
+       },
        .ids    = ctcm_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
 };
 
 static struct ccwgroup_driver ctcm_group_driver = {
-       .owner       = THIS_MODULE,
-       .name        = CTC_DRIVER_NAME,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = CTC_DRIVER_NAME,
+       },
        .max_slaves  = 2,
        .driver_id   = 0xC3E3C3D4,      /* CTCM */
        .probe       = ctcm_probe_device,
index 30b2a820e67019ae28d2b899d1bc032d7b37b9ee..7fbc4adbb6d554678a5a03423a8167ab95069ac2 100644 (file)
@@ -2396,8 +2396,10 @@ static struct ccw_device_id lcs_ids[] = {
 MODULE_DEVICE_TABLE(ccw, lcs_ids);
 
 static struct ccw_driver lcs_ccw_driver = {
-       .owner  = THIS_MODULE,
-       .name   = "lcs",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "lcs",
+       },
        .ids    = lcs_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
@@ -2407,8 +2409,10 @@ static struct ccw_driver lcs_ccw_driver = {
  * LCS ccwgroup driver registration
  */
 static struct ccwgroup_driver lcs_group_driver = {
-       .owner       = THIS_MODULE,
-       .name        = "lcs",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "lcs",
+       },
        .max_slaves  = 2,
        .driver_id   = 0xD3C3E2,
        .probe       = lcs_probe_device,
index 25eef304bd4774b67651d6507e808fb4a0dba027..10a3a3b4dd3e9ef45aa817a0214f0406f5f9a430 100644 (file)
@@ -3902,7 +3902,9 @@ static struct ccw_device_id qeth_ids[] = {
 MODULE_DEVICE_TABLE(ccw, qeth_ids);
 
 static struct ccw_driver qeth_ccw_driver = {
-       .name = "qeth",
+       .driver = {
+               .name = "qeth",
+       },
        .ids = qeth_ids,
        .probe = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
@@ -4428,8 +4430,10 @@ static int qeth_core_restore(struct ccwgroup_device *gdev)
 }
 
 static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
-       .owner = THIS_MODULE,
-       .name = "qeth",
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "qeth",
+       },
        .driver_id = 0xD8C5E3C8,
        .probe = qeth_core_probe_device,
        .remove = qeth_core_remove_device,
index 4f7852dd30c7723c78c9409a07dfd05329f09ac0..e8b7cee62046e994187499139eda8333d766bca2 100644 (file)
@@ -251,8 +251,10 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
 }
 
 struct ccw_driver zfcp_ccw_driver = {
-       .owner       = THIS_MODULE,
-       .name        = "zfcp",
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "zfcp",
+       },
        .ids         = zfcp_ccw_device_id,
        .probe       = zfcp_ccw_probe,
        .remove      = zfcp_ccw_remove,
index f1cca4ee541006c6767b5242f124dfcefcc6d6a0..92df4d6b6147c677a76a4852bf521cd43ea88711 100644 (file)
@@ -5,4 +5,4 @@ obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
 aacraid-objs   := linit.o aachba.o commctrl.o comminit.o commsup.o \
                   dpcsup.o rx.o sa.o rkt.o nark.o
 
-EXTRA_CFLAGS   := -Idrivers/scsi
+ccflags-y      := -Idrivers/scsi
index e78ce0fa44d2dd8c9d0eb8fe87ffd3141b9c2915..c0a15c75458506373e481fc36e79a857af8abc59 100644 (file)
@@ -22,9 +22,7 @@
 # along with the aic94xx driver; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-ifeq ($(CONFIG_AIC94XX_DEBUG),y)
-       EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
-endif
+ccflags-$(CONFIG_AIC94XX_DEBUG) := -DASD_DEBUG -DASD_ENTER_EXIT
 
 obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
 aic94xx-y += aic94xx_init.o \
index 566a10024598b630f44d28544a22de8cd636ccca..2e70140f70c3d88f3aee051601e945bcd0f7abec 100644 (file)
@@ -32,4 +32,4 @@ libsas-y +=  sas_init.o     \
                sas_scsi_host.o \
                sas_task.o
 libsas-$(CONFIG_SCSI_SAS_ATA) +=       sas_ata.o
-libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=  sas_host_smp.o
\ No newline at end of file
+libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=  sas_host_smp.o
index ad05d6edb8f6906eaf28943d71738fa98a5848b7..14de249917f8c226c2159cea4cf767aa56029239 100644 (file)
 # *******************************************************************/
 ######################################################################
 
-ifneq ($(GCOV),)
-  EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage
-  EXTRA_CFLAGS += -O0
-endif
+ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage
+ccflags-$(GCOV) += -O0
 
 obj-$(CONFIG_SCSI_LPFC) := lpfc.o
 
index 52ac4264677d3a053065f2dc3c3513bbc8e7626c..ffbf759e46f1ec83db27607a210e1e0354f4398c 100644 (file)
@@ -21,9 +21,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 # USA
 
-ifeq ($(CONFIG_SCSI_MVSAS_DEBUG),y)
-       EXTRA_CFLAGS += -DMV_DEBUG
-endif
+ccflags-$(CONFIG_SCSI_MVSAS_DEBUG) := -DMV_DEBUG
 
 obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
 mvsas-y +=  mv_init.o  \
index eca379059db652691ae7988024cf6b9a818a54a5..683bf148b5b7675beecb001365fa307da11dc206 100644 (file)
@@ -1,5 +1,5 @@
 
-EXTRA_CFLAGS           += -Idrivers/scsi
+ccflags-y              := -Idrivers/scsi
 
 # 16-bit client drivers
 obj-$(CONFIG_PCMCIA_QLOGIC)    += qlogic_cs.o
index 991de3c15cfcbc4bcc61096272e747f40e30448c..633c2395a92a2c918cfd068d541f99063f9470f2 100644 (file)
@@ -3,14 +3,14 @@
  *
  *  SCSI error/timeout handling
  *      Initial versions: Eric Youngdale.  Based upon conversations with
- *                        Leonard Zubkoff and David Miller at Linux Expo, 
+ *                        Leonard Zubkoff and David Miller at Linux Expo,
  *                        ideas originating from all over the place.
  *
  *     Restructured scsi_unjam_host and associated functions.
  *     September 04, 2002 Mike Anderson (andmike@us.ibm.com)
  *
  *     Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
- *     minor  cleanups.
+ *     minor cleanups.
  *     September 30, 2002 Mike Anderson (andmike@us.ibm.com)
  */
 
@@ -129,14 +129,15 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
 {
        struct scsi_cmnd *scmd = req->special;
        enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
+       struct Scsi_Host *host = scmd->device->host;
 
        trace_scsi_dispatch_cmd_timeout(scmd);
        scsi_log_completion(scmd, TIMEOUT_ERROR);
 
-       if (scmd->device->host->transportt->eh_timed_out)
-               rtn = scmd->device->host->transportt->eh_timed_out(scmd);
-       else if (scmd->device->host->hostt->eh_timed_out)
-               rtn = scmd->device->host->hostt->eh_timed_out(scmd);
+       if (host->transportt->eh_timed_out)
+               rtn = host->transportt->eh_timed_out(scmd);
+       else if (host->hostt->eh_timed_out)
+               rtn = host->hostt->eh_timed_out(scmd);
 
        if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
                     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
@@ -195,7 +196,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
                                ++total_failures;
                                if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD)
                                        ++cmd_cancel;
-                               else 
+                               else
                                        ++cmd_failed;
                        }
                }
@@ -214,7 +215,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
 
        SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
                                          " devices require eh work\n",
-                                 total_failures, devices_failed));
+                                  total_failures, devices_failed));
 }
 #endif
 
@@ -294,7 +295,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                        return NEEDS_RETRY;
                }
                /*
-                * if the device is in the process of becoming ready, we 
+                * if the device is in the process of becoming ready, we
                 * should retry.
                 */
                if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
@@ -488,7 +489,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
  */
 static void scsi_eh_done(struct scsi_cmnd *scmd)
 {
-       struct completion     *eh_action;
+       struct completion *eh_action;
 
        SCSI_LOG_ERROR_RECOVERY(3,
                printk("%s scmd: %p result: %x\n",
@@ -507,22 +508,23 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
                                          __func__));
 
-       if (!scmd->device->host->hostt->eh_host_reset_handler)
+       if (!hostt->eh_host_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
+       rtn = hostt->eh_host_reset_handler(scmd);
 
        if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
+               if (!hostt->skip_settle_delay)
                        ssleep(HOST_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
+               scsi_report_bus_reset(host, scmd_channel(scmd));
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -536,22 +538,23 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
                                          __func__));
 
-       if (!scmd->device->host->hostt->eh_bus_reset_handler)
+       if (!hostt->eh_bus_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
+       rtn = hostt->eh_bus_reset_handler(scmd);
 
        if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
+               if (!hostt->skip_settle_delay)
                        ssleep(BUS_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
+               scsi_report_bus_reset(host, scmd_channel(scmd));
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -577,16 +580,18 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
-       if (!scmd->device->host->hostt->eh_target_reset_handler)
+       if (!hostt->eh_target_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd);
+       rtn = hostt->eh_target_reset_handler(scmd);
        if (rtn == SUCCESS) {
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
                __starget_for_each_device(scsi_target(scmd->device), NULL,
                                          __scsi_report_device_reset);
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -605,27 +610,28 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd)
 static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
 {
        int rtn;
+       struct scsi_host_template *hostt = scmd->device->host->hostt;
 
-       if (!scmd->device->host->hostt->eh_device_reset_handler)
+       if (!hostt->eh_device_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
+       rtn = hostt->eh_device_reset_handler(scmd);
        if (rtn == SUCCESS)
                __scsi_report_device_reset(scmd->device, NULL);
        return rtn;
 }
 
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd)
 {
-       if (!scmd->device->host->hostt->eh_abort_handler)
+       if (!hostt->eh_abort_handler)
                return FAILED;
 
-       return scmd->device->host->hostt->eh_abort_handler(scmd);
+       return hostt->eh_abort_handler(scmd);
 }
 
 static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
 {
-       if (scsi_try_to_abort_cmd(scmd) != SUCCESS)
+       if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS)
                if (scsi_try_bus_device_reset(scmd) != SUCCESS)
                        if (scsi_try_target_reset(scmd) != SUCCESS)
                                if (scsi_try_bus_reset(scmd) != SUCCESS)
@@ -846,7 +852,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  * Description:
  *    See if we need to request sense information.  if so, then get it
- *    now, so we have a better idea of what to do.  
+ *    now, so we have a better idea of what to do.
  *
  * Notes:
  *    This has the unfortunate side effect that if a shost adapter does
@@ -958,7 +964,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:"
                                                  "0x%p\n", current->comm,
                                                  scmd));
-               rtn = scsi_try_to_abort_cmd(scmd);
+               rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd);
                if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
                        if (!scsi_device_online(scmd->device) ||
@@ -966,7 +972,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                            !scsi_eh_tur(scmd)) {
                                scsi_eh_finish_cmd(scmd, done_q);
                        }
-                               
                } else
                        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting"
                                                          " cmd failed:"
@@ -1010,7 +1015,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
  *
  * Notes:
  *    If commands are failing due to not ready, initializing command required,
- *     try revalidating the device, which will end up sending a start unit. 
+ *     try revalidating the device, which will end up sending a start unit.
  */
 static int scsi_eh_stu(struct Scsi_Host *shost,
                              struct list_head *work_q,
@@ -1064,7 +1069,7 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
  *    Try a bus device reset.  Still, look to see whether we have multiple
  *    devices that are jammed or not - if we have multiple devices, it
  *    makes no sense to try bus_device_reset - we really would need to try
- *    a bus_reset instead. 
+ *    a bus_reset instead.
  */
 static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
                                    struct list_head *work_q,
@@ -1164,7 +1169,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
 }
 
 /**
- * scsi_eh_bus_reset - send a bus reset 
+ * scsi_eh_bus_reset - send a bus reset
  * @shost:     &scsi host being recovered.
  * @work_q:     &list_head for pending commands.
  * @done_q:    &list_head for processed commands.
@@ -1181,7 +1186,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
         * we really want to loop over the various channels, and do this on
         * a channel by channel basis.  we should also check to see if any
         * of the failed commands are on soft_reset devices, and if so, skip
-        * the reset.  
+        * the reset.
         */
 
        for (channel = 0; channel <= shost->max_channel; channel++) {
@@ -1223,7 +1228,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
 }
 
 /**
- * scsi_eh_host_reset - send a host reset 
+ * scsi_eh_host_reset - send a host reset
  * @work_q:    list_head for processed commands.
  * @done_q:    list_head for processed commands.
  */
@@ -1376,7 +1381,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                return SUCCESS;
                /*
                 * when the low level driver returns did_soft_error,
-                * it is responsible for keeping an internal retry counter 
+                * it is responsible for keeping an internal retry counter
                 * in order to avoid endless loops (db)
                 *
                 * actually this is a bug in this function here.  we should
@@ -1414,7 +1419,6 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                         */
                        break;
                /* fallthrough */
-
        case DID_BUS_BUSY:
        case DID_PARITY:
                goto maybe_retry;
@@ -1982,7 +1986,7 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
                if (sb_len > 7)
                        sshdr->additional_length = sense_buffer[7];
        } else {
-               /* 
+               /*
                 * fixed format
                 */
                if (sb_len > 2)
index 2d63c8ad1442b6d99a07d0c10c4cb02b4292d850..6d5c7ff43f5bdaf1984a62696e8acb03cdead3c5 100644 (file)
@@ -67,6 +67,13 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = {
 
 struct kmem_cache *scsi_sdb_cache;
 
+/*
+ * When to reinvoke queueing after a resource shortage. It's 3 msecs to
+ * not change behaviour from the previous unplug mechanism, experimentation
+ * may prove this needs changing.
+ */
+#define SCSI_QUEUE_DELAY       3
+
 static void scsi_run_queue(struct request_queue *q);
 
 /*
@@ -149,14 +156,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
        /*
         * Requeue this command.  It will go before all other commands
         * that are already in the queue.
-        *
-        * NOTE: there is magic here about the way the queue is plugged if
-        * we have no outstanding commands.
-        * 
-        * Although we *don't* plug the queue, we call the request
-        * function.  The SCSI request function detects the blocked condition
-        * and plugs the queue appropriately.
-         */
+        */
        spin_lock_irqsave(q->queue_lock, flags);
        blk_requeue_request(q, cmd->request);
        spin_unlock_irqrestore(q->queue_lock, flags);
@@ -1226,11 +1226,11 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
        case BLKPREP_DEFER:
                /*
                 * If we defer, the blk_peek_request() returns NULL, but the
-                * queue must be restarted, so we plug here if no returning
-                * command will automatically do that.
+                * queue must be restarted, so we schedule a callback to happen
+                * shortly.
                 */
                if (sdev->device_busy == 0)
-                       blk_plug_device(q);
+                       blk_delay_queue(q, SCSI_QUEUE_DELAY);
                break;
        default:
                req->cmd_flags |= REQ_DONTPREP;
@@ -1269,7 +1269,7 @@ static inline int scsi_dev_queue_ready(struct request_queue *q,
                                   sdev_printk(KERN_INFO, sdev,
                                   "unblocking device at zero depth\n"));
                } else {
-                       blk_plug_device(q);
+                       blk_delay_queue(q, SCSI_QUEUE_DELAY);
                        return 0;
                }
        }
@@ -1499,7 +1499,7 @@ static void scsi_request_fn(struct request_queue *q)
         * the host is no longer able to accept any more requests.
         */
        shost = sdev->host;
-       while (!blk_queue_plugged(q)) {
+       for (;;) {
                int rtn;
                /*
                 * get next queueable request.  We do this early to make sure
@@ -1578,15 +1578,8 @@ static void scsi_request_fn(struct request_queue *q)
                 */
                rtn = scsi_dispatch_cmd(cmd);
                spin_lock_irq(q->queue_lock);
-               if(rtn) {
-                       /* we're refusing the command; because of
-                        * the way locks get dropped, we need to 
-                        * check here if plugging is required */
-                       if(sdev->device_busy == 0)
-                               blk_plug_device(q);
-
-                       break;
-               }
+               if (rtn)
+                       goto out_delay;
        }
 
        goto out;
@@ -1605,9 +1598,10 @@ static void scsi_request_fn(struct request_queue *q)
        spin_lock_irq(q->queue_lock);
        blk_requeue_request(q, req);
        sdev->device_busy--;
-       if(sdev->device_busy == 0)
-               blk_plug_device(q);
- out:
+out_delay:
+       if (sdev->device_busy == 0)
+               blk_delay_queue(q, SCSI_QUEUE_DELAY);
+out:
        /* must be careful here...if we trigger the ->remove() function
         * we cannot be holding the q lock */
        spin_unlock_irq(q->queue_lock);
index 5c3ccfc6b6220d99e08f21d24458e23866876392..2941d2d92c9472349da1a29edd103e5094aa295b 100644 (file)
@@ -3913,7 +3913,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost,
        if (!get_device(dev))
                return;
 
-       while (!blk_queue_plugged(q)) {
+       while (1) {
                if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) &&
                    !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT))
                        break;
index 927e99cb72250c61154639ea8ca1eae2dd32b198..c6fcf76cade549f2fb880d976c839b915e0b9dc3 100644 (file)
@@ -173,11 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
        int ret;
        int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
 
-       while (!blk_queue_plugged(q)) {
-               req = blk_fetch_request(q);
-               if (!req)
-                       break;
-
+       while ((req = blk_fetch_request(q)) != NULL) {
                spin_unlock_irq(q->queue_lock);
 
                handler = to_sas_internal(shost->transportt)->f->smp_handler;
index 3be5db5d6343966cbbbcda26f9e12dd005f7e62b..7ff61d76b4c5de4d233353b6424ed33357b39e46 100644 (file)
@@ -597,6 +597,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
                break;
 
        default:
+               ret = BLKPREP_KILL;
                goto out;
        }
 
index 5f63c3b83828ea1db4c9e18cb2eb7a92b9611dc6..4f64183b27fa6283c80d4fa2d37aa61c61c127fe 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -630,68 +630,36 @@ long clk_round_parent(struct clk *clk, unsigned long target,
 EXPORT_SYMBOL_GPL(clk_round_parent);
 
 #ifdef CONFIG_PM
-static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+static void clks_core_resume(void)
 {
-       static pm_message_t prev_state;
        struct clk *clkp;
 
-       switch (state.event) {
-       case PM_EVENT_ON:
-               /* Resumeing from hibernation */
-               if (prev_state.event != PM_EVENT_FREEZE)
-                       break;
-
-               list_for_each_entry(clkp, &clock_list, node) {
-                       if (likely(clkp->ops)) {
-                               unsigned long rate = clkp->rate;
-
-                               if (likely(clkp->ops->set_parent))
-                                       clkp->ops->set_parent(clkp,
-                                               clkp->parent);
-                               if (likely(clkp->ops->set_rate))
-                                       clkp->ops->set_rate(clkp, rate);
-                               else if (likely(clkp->ops->recalc))
-                                       clkp->rate = clkp->ops->recalc(clkp);
-                       }
+       list_for_each_entry(clkp, &clock_list, node) {
+               if (likely(clkp->ops)) {
+                       unsigned long rate = clkp->rate;
+
+                       if (likely(clkp->ops->set_parent))
+                               clkp->ops->set_parent(clkp,
+                                       clkp->parent);
+                       if (likely(clkp->ops->set_rate))
+                               clkp->ops->set_rate(clkp, rate);
+                       else if (likely(clkp->ops->recalc))
+                               clkp->rate = clkp->ops->recalc(clkp);
                }
-               break;
-       case PM_EVENT_FREEZE:
-               break;
-       case PM_EVENT_SUSPEND:
-               break;
        }
-
-       prev_state = state;
-       return 0;
-}
-
-static int clks_sysdev_resume(struct sys_device *dev)
-{
-       return clks_sysdev_suspend(dev, PMSG_ON);
 }
 
-static struct sysdev_class clks_sysdev_class = {
-       .name = "clks",
-};
-
-static struct sysdev_driver clks_sysdev_driver = {
-       .suspend = clks_sysdev_suspend,
-       .resume = clks_sysdev_resume,
-};
-
-static struct sys_device clks_sysdev_dev = {
-       .cls = &clks_sysdev_class,
+static struct syscore_ops clks_syscore_ops = {
+       .resume = clks_core_resume,
 };
 
-static int __init clk_sysdev_init(void)
+static int __init clk_syscore_init(void)
 {
-       sysdev_class_register(&clks_sysdev_class);
-       sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
-       sysdev_register(&clks_sysdev_dev);
+       register_syscore_ops(&clks_syscore_ops);
 
        return 0;
 }
-subsys_initcall(clk_sysdev_init);
+subsys_initcall(clk_syscore_init);
 #endif
 
 /*
index 9739431092d126aefdef78ec03888c66b40b256d..5833afbf08d705899258463f3b772134557dc7a0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/sh_intc.h>
 #include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/radix-tree.h>
@@ -376,91 +377,89 @@ err0:
        return -ENOMEM;
 }
 
-static ssize_t
-show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+static int intc_suspend(void)
 {
        struct intc_desc_int *d;
 
-       d = container_of(dev, struct intc_desc_int, sysdev);
+       list_for_each_entry(d, &intc_list, list) {
+               int irq;
 
-       return sprintf(buf, "%s\n", d->chip.name);
-}
+               /* enable wakeup irqs belonging to this intc controller */
+               for_each_active_irq(irq) {
+                       struct irq_data *data;
+                       struct irq_desc *desc;
+                       struct irq_chip *chip;
 
-static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+                       data = irq_get_irq_data(irq);
+                       chip = irq_data_get_irq_chip(data);
+                       if (chip != &d->chip)
+                               continue;
+                       desc = irq_to_desc(irq);
+                       if ((desc->status & IRQ_WAKEUP))
+                               chip->irq_enable(data);
+               }
+       }
+
+       return 0;
+}
 
-static int intc_suspend(struct sys_device *dev, pm_message_t state)
+static void intc_resume(void)
 {
        struct intc_desc_int *d;
-       struct irq_data *data;
-       struct irq_desc *desc;
-       struct irq_chip *chip;
-       int irq;
-
-       /* get intc controller associated with this sysdev */
-       d = container_of(dev, struct intc_desc_int, sysdev);
 
-       switch (state.event) {
-       case PM_EVENT_ON:
-               if (d->state.event != PM_EVENT_FREEZE)
-                       break;
+       list_for_each_entry(d, &intc_list, list) {
+               int irq;
 
                for_each_active_irq(irq) {
-                       desc = irq_to_desc(irq);
+                       struct irq_data *data;
+                       struct irq_desc *desc;
+                       struct irq_chip *chip;
+
                        data = irq_get_irq_data(irq);
                        chip = irq_data_get_irq_chip(data);
-
                        /*
                         * This will catch the redirect and VIRQ cases
                         * due to the dummy_irq_chip being inserted.
                         */
                        if (chip != &d->chip)
                                continue;
+                       desc = irq_to_desc(irq);
                        if (desc->status & IRQ_DISABLED)
                                chip->irq_disable(data);
                        else
                                chip->irq_enable(data);
                }
-               break;
-       case PM_EVENT_FREEZE:
-               /* nothing has to be done */
-               break;
-       case PM_EVENT_SUSPEND:
-               /* enable wakeup irqs belonging to this intc controller */
-               for_each_active_irq(irq) {
-                       desc = irq_to_desc(irq);
-                       data = irq_get_irq_data(irq);
-                       chip = irq_data_get_irq_chip(data);
-
-                       if (chip != &d->chip)
-                               continue;
-                       if ((desc->status & IRQ_WAKEUP))
-                               chip->irq_enable(data);
-               }
-               break;
        }
-
-       d->state = state;
-
-       return 0;
 }
 
-static int intc_resume(struct sys_device *dev)
-{
-       return intc_suspend(dev, PMSG_ON);
-}
+struct syscore_ops intc_syscore_ops = {
+       .suspend        = intc_suspend,
+       .resume         = intc_resume,
+};
 
 struct sysdev_class intc_sysdev_class = {
        .name           = "intc",
-       .suspend        = intc_suspend,
-       .resume         = intc_resume,
 };
 
-/* register this intc as sysdev to allow suspend/resume */
+static ssize_t
+show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+       struct intc_desc_int *d;
+
+       d = container_of(dev, struct intc_desc_int, sysdev);
+
+       return sprintf(buf, "%s\n", d->chip.name);
+}
+
+static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+
 static int __init register_intc_sysdevs(void)
 {
        struct intc_desc_int *d;
        int error;
 
+       register_syscore_ops(&intc_syscore_ops);
+
        error = sysdev_class_register(&intc_sysdev_class);
        if (!error) {
                list_for_each_entry(d, &intc_list, list) {
index 0cf8260971d4b72ccff501708da25d7b01841e88..df36a421e6756b5e775e16d2b8995b769f18e875 100644 (file)
@@ -53,7 +53,6 @@ struct intc_desc_int {
        struct list_head list;
        struct sys_device sysdev;
        struct radix_tree_root tree;
-       pm_message_t state;
        raw_spinlock_t lock;
        unsigned int index;
        unsigned long *reg;
index 5c2b092a915e2498a4c100daa1d1e8aa3bea0fe6..5a4e0afb9ad6dc39e8a3bb041c72d0b8f21e60f7 100644 (file)
@@ -324,6 +324,7 @@ struct vendor_data {
        bool unidir;
        bool extended_cr;
        bool pl023;
+       bool loopback;
 };
 
 /**
@@ -1983,7 +1984,7 @@ static int pl022_setup(struct spi_device *spi)
 
        SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
        /* Loopback is available on all versions except PL023 */
-       if (!pl022->vendor->pl023) {
+       if (pl022->vendor->loopback) {
                if (spi->mode & SPI_LOOP)
                        tmp = LOOPBACK_ENABLED;
                else
@@ -2233,6 +2234,7 @@ static struct vendor_data vendor_arm = {
        .unidir = false,
        .extended_cr = false,
        .pl023 = false,
+       .loopback = true,
 };
 
 
@@ -2242,6 +2244,7 @@ static struct vendor_data vendor_st = {
        .unidir = false,
        .extended_cr = true,
        .pl023 = false,
+       .loopback = true,
 };
 
 static struct vendor_data vendor_st_pl023 = {
@@ -2250,6 +2253,16 @@ static struct vendor_data vendor_st_pl023 = {
        .unidir = false,
        .extended_cr = true,
        .pl023 = true,
+       .loopback = false,
+};
+
+static struct vendor_data vendor_db5500_pl023 = {
+       .fifodepth = 32,
+       .max_bpw = 32,
+       .unidir = false,
+       .extended_cr = true,
+       .pl023 = true,
+       .loopback = true,
 };
 
 static struct amba_id pl022_ids[] = {
@@ -2283,6 +2296,11 @@ static struct amba_id pl022_ids[] = {
                .mask   = 0xffffffff,
                .data   = &vendor_st_pl023,
        },
+       {
+               .id     = 0x10080023,
+               .mask   = 0xffffffff,
+               .data   = &vendor_db5500_pl023,
+       },
        { 0, 0 },
 };
 
index 3a5ed06d3d2f7b26ab68ef63aaf953c5e1e40591..6f86ba0175ac9636e564f44cf23ff41223de6b8a 100644 (file)
@@ -517,7 +517,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                dev_vdbg(&spi->dev, "read-%d %02x\n",
                                                word_len, *(rx - 1));
                        }
-               } while (c > (word_len>>3));
+               } while (c);
        } else if (word_len <= 16) {
                u16             *rx;
                const u16       *tx;
@@ -564,7 +564,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                dev_vdbg(&spi->dev, "read-%d %04x\n",
                                                word_len, *(rx - 1));
                        }
-               } while (c > (word_len>>3));
+               } while (c >= 2);
        } else if (word_len <= 32) {
                u32             *rx;
                const u32       *tx;
@@ -611,7 +611,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                dev_vdbg(&spi->dev, "read-%d %08x\n",
                                                word_len, *(rx - 1));
                        }
-               } while (c > (word_len>>3));
+               } while (c >= 4);
        }
 
        /* for TX_ONLY mode, be sure all words have shifted out */
index 4d2c75df886c88621e43a453db625e59e7876ccf..c69c6f2c2c5ceeadae69afa2efc60c636517a0e3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/spi/xilinx_spi.h>
@@ -470,7 +471,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
        struct spi_master *master;
        u8 i;
 
-       pdata = dev->dev.platform_data;
+       pdata = mfd_get_data(dev);
        if (pdata) {
                num_cs = pdata->num_chipselect;
                little_endian = pdata->little_endian;
index ccaa2009414b9404c567a812c85c3fba2aea66cd..18b43fcb4171bc267585bf90dc133c2dd57a1f4c 100644 (file)
@@ -55,11 +55,7 @@ source "drivers/staging/cx25821/Kconfig"
 
 source "drivers/staging/tm6000/Kconfig"
 
-source "drivers/staging/dabusb/Kconfig"
-
-source "drivers/staging/se401/Kconfig"
-
-source "drivers/staging/usbvideo/Kconfig"
+source "drivers/staging/cxd2099/Kconfig"
 
 source "drivers/staging/usbip/Kconfig"
 
@@ -183,5 +179,7 @@ source "drivers/staging/ste_rmi4/Kconfig"
 
 source "drivers/staging/gma500/Kconfig"
 
+source "drivers/staging/altera-stapl/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 3b223cbf86b4e5608692754e76a8d8348e24f535..cfd13cd55efbb96778c190299c8e0850a784adc1 100644 (file)
@@ -10,9 +10,7 @@ obj-$(CONFIG_SLICOSS)         += slicoss/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
 obj-$(CONFIG_VIDEO_CX25821)    += cx25821/
 obj-$(CONFIG_VIDEO_TM6000)     += tm6000/
-obj-$(CONFIG_USB_DABUSB)        += dabusb/
-obj-$(CONFIG_USB_VICAM)         += usbvideo/
-obj-$(CONFIG_USB_SE401)         += se401/
+obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_USB_IP_COMMON)    += usbip/
 obj-$(CONFIG_W35UND)           += winbond/
@@ -70,6 +68,7 @@ obj-$(CONFIG_BCM_WIMAX)               += bcm/
 obj-$(CONFIG_FT1000)           += ft1000/
 obj-$(CONFIG_SND_INTEL_SST)    += intel_sst/
 obj-$(CONFIG_SPEAKUP)          += speakup/
+obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
 obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)   += ste_rmi4/
 obj-$(CONFIG_DRM_PSB)          += gma500/
diff --git a/drivers/staging/altera-stapl/Kconfig b/drivers/staging/altera-stapl/Kconfig
new file mode 100644 (file)
index 0000000..7f01d8e
--- /dev/null
@@ -0,0 +1,8 @@
+comment "Altera FPGA firmware download module"
+
+config ALTERA_STAPL
+       tristate "Altera FPGA firmware download module"
+       depends on I2C
+       default n
+       help
+         An Altera FPGA module. Say Y when you want to support this tool.
diff --git a/drivers/staging/altera-stapl/Makefile b/drivers/staging/altera-stapl/Makefile
new file mode 100644 (file)
index 0000000..055f61e
--- /dev/null
@@ -0,0 +1,3 @@
+altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o
+
+obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o
diff --git a/drivers/staging/altera-stapl/altera-comp.c b/drivers/staging/altera-stapl/altera-comp.c
new file mode 100644 (file)
index 0000000..49b103b
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * altera-comp.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include "altera-exprt.h"
+
+#define        SHORT_BITS              16
+#define        CHAR_BITS               8
+#define        DATA_BLOB_LENGTH        3
+#define        MATCH_DATA_LENGTH       8192
+#define ALTERA_REQUEST_SIZE    1024
+#define ALTERA_BUFFER_SIZE     (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE)
+
+static u32 altera_bits_req(u32 n)
+{
+       u32 result = SHORT_BITS;
+
+       if (n == 0)
+               result = 1;
+       else {
+               /* Look for the highest non-zero bit position */
+               while ((n & (1 << (SHORT_BITS - 1))) == 0) {
+                       n <<= 1;
+                       --result;
+               }
+       }
+
+       return result;
+}
+
+static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail,
+                                                       u32 *in_index)
+{
+       u32 result = 0;
+       u32 shift = 0;
+       u32 databyte = 0;
+
+       while (bits > 0) {
+               databyte = buffer[*in_index];
+               result |= (((databyte >> (CHAR_BITS - *bits_avail))
+                       & (0xff >> (CHAR_BITS - *bits_avail))) << shift);
+
+               if (bits <= *bits_avail) {
+                       result &= (0xffff >> (SHORT_BITS - (bits + shift)));
+                       *bits_avail -= bits;
+                       bits = 0;
+               } else {
+                       ++(*in_index);
+                       shift += *bits_avail;
+                       bits -= *bits_avail;
+                       *bits_avail = CHAR_BITS;
+               }
+       }
+
+       return result;
+}
+
+u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version)
+{
+       u32 i, j, data_length = 0L;
+       u32 offset, length;
+       u32 match_data_length = MATCH_DATA_LENGTH;
+       u32 bits_avail = CHAR_BITS;
+       u32 in_index = 0L;
+
+       if (version > 0)
+               --match_data_length;
+
+       for (i = 0; i < out_length; ++i)
+               out[i] = 0;
+
+       /* Read number of bytes in data. */
+       for (i = 0; i < sizeof(in_length); ++i) {
+               data_length = data_length | (
+                       altera_read_packed(in,
+                                       CHAR_BITS,
+                                       &bits_avail,
+                                       &in_index) << (i * CHAR_BITS));
+       }
+
+       if (data_length > out_length) {
+               data_length = 0L;
+               return data_length;
+       }
+
+       i = 0;
+       while (i < data_length) {
+               /* A 0 bit indicates literal data. */
+               if (altera_read_packed(in, 1, &bits_avail,
+                                               &in_index) == 0) {
+                       for (j = 0; j < DATA_BLOB_LENGTH; ++j) {
+                               if (i < data_length) {
+                                       out[i] = (u8)altera_read_packed(in,
+                                                       CHAR_BITS,
+                                                       &bits_avail,
+                                                       &in_index);
+                                       i++;
+                               }
+                       }
+               } else {
+                       /* A 1 bit indicates offset/length to follow. */
+                       offset = altera_read_packed(in, altera_bits_req((s16)
+                                       (i > match_data_length ?
+                                               match_data_length : i)),
+                                       &bits_avail,
+                                       &in_index);
+                       length = altera_read_packed(in, CHAR_BITS,
+                                       &bits_avail,
+                                       &in_index);
+                       for (j = 0; j < length; ++j) {
+                               if (i < data_length) {
+                                       out[i] = out[i - offset];
+                                       i++;
+                               }
+                       }
+               }
+       }
+
+       return data_length;
+}
diff --git a/drivers/staging/altera-stapl/altera-exprt.h b/drivers/staging/altera-stapl/altera-exprt.h
new file mode 100644 (file)
index 0000000..39c38d8
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * altera-exprt.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef ALTERA_EXPRT_H
+#define ALTERA_EXPRT_H
+
+
+u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version);
+int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo);
+
+#endif /* ALTERA_EXPRT_H */
diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c
new file mode 100644 (file)
index 0000000..6b633b1
--- /dev/null
@@ -0,0 +1,1020 @@
+/*
+ * altera-jtag.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <staging/altera.h>
+#include "altera-exprt.h"
+#include "altera-jtag.h"
+
+#define        alt_jtag_io(a, b, c)\
+               astate->config->jtag_io(astate->config->dev, a, b, c);
+
+#define        alt_malloc(a)   kzalloc(a, GFP_KERNEL);
+
+/*
+ * This structure shows, for each JTAG state, which state is reached after
+ * a single TCK clock cycle with TMS high or TMS low, respectively.  This
+ * describes all possible state transitions in the JTAG state machine.
+ */
+struct altera_jtag_machine {
+       enum altera_jtag_state tms_high;
+       enum altera_jtag_state tms_low;
+};
+
+static const struct altera_jtag_machine altera_transitions[] = {
+       /* RESET     */ { RESET,        IDLE },
+       /* IDLE      */ { DRSELECT,     IDLE },
+       /* DRSELECT  */ { IRSELECT,     DRCAPTURE },
+       /* DRCAPTURE */ { DREXIT1,      DRSHIFT },
+       /* DRSHIFT   */ { DREXIT1,      DRSHIFT },
+       /* DREXIT1   */ { DRUPDATE,     DRPAUSE },
+       /* DRPAUSE   */ { DREXIT2,      DRPAUSE },
+       /* DREXIT2   */ { DRUPDATE,     DRSHIFT },
+       /* DRUPDATE  */ { DRSELECT,     IDLE },
+       /* IRSELECT  */ { RESET,        IRCAPTURE },
+       /* IRCAPTURE */ { IREXIT1,      IRSHIFT },
+       /* IRSHIFT   */ { IREXIT1,      IRSHIFT },
+       /* IREXIT1   */ { IRUPDATE,     IRPAUSE },
+       /* IRPAUSE   */ { IREXIT2,      IRPAUSE },
+       /* IREXIT2   */ { IRUPDATE,     IRSHIFT },
+       /* IRUPDATE  */ { DRSELECT,     IDLE }
+};
+
+/*
+ * This table contains the TMS value to be used to take the NEXT STEP on
+ * the path to the desired state.  The array index is the current state,
+ * and the bit position is the desired endstate.  To find out which state
+ * is used as the intermediate state, look up the TMS value in the
+ * altera_transitions[] table.
+ */
+static const u16 altera_jtag_path_map[16] = {
+       /* RST  RTI     SDRS    CDR     SDR     E1DR    PDR     E2DR */
+       0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF,
+       /* UDR  SIRS    CIR     SIR     E1IR    PIR     E2IR    UIR */
+       0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD
+};
+
+/* Flag bits for alt_jtag_io() function */
+#define TMS_HIGH   1
+#define TMS_LOW    0
+#define TDI_HIGH   1
+#define TDI_LOW    0
+#define READ_TDO   1
+#define IGNORE_TDO 0
+
+int altera_jinit(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+
+       /* initial JTAG state is unknown */
+       js->jtag_state = ILLEGAL_JTAG_STATE;
+
+       /* initialize to default state */
+       js->drstop_state = IDLE;
+       js->irstop_state = IDLE;
+       js->dr_pre  = 0;
+       js->dr_post = 0;
+       js->ir_pre  = 0;
+       js->ir_post = 0;
+       js->dr_length    = 0;
+       js->ir_length    = 0;
+
+       js->dr_pre_data  = NULL;
+       js->dr_post_data = NULL;
+       js->ir_pre_data  = NULL;
+       js->ir_post_data = NULL;
+       js->dr_buffer    = NULL;
+       js->ir_buffer    = NULL;
+
+       return 0;
+}
+
+int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state)
+{
+       js->drstop_state = state;
+
+       return 0;
+}
+
+int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state)
+{
+       js->irstop_state = state;
+
+       return 0;
+}
+
+int altera_set_dr_pre(struct altera_jtag *js,
+                               u32 count, u32 start_index,
+                               u8 *preamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->dr_pre) {
+               kfree(js->dr_pre_data);
+               js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->dr_pre_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->dr_pre = count;
+       } else
+               js->dr_pre = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+
+                       if (preamble_data == NULL)
+                               js->dr_pre_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (preamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->dr_pre_data[i >> 3] |=
+                                                       (1 << (i & 7));
+                               else
+                                       js->dr_pre_data[i >> 3] &=
+                                                       ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                                                       u8 *preamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->ir_pre) {
+               kfree(js->ir_pre_data);
+               js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->ir_pre_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->ir_pre = count;
+
+       } else
+               js->ir_pre = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+                       if (preamble_data == NULL)
+                               js->ir_pre_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (preamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->ir_pre_data[i >> 3] |=
+                                                       (1 << (i & 7));
+                               else
+                                       js->ir_pre_data[i >> 3] &=
+                                                       ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
+                                               u8 *postamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->dr_post) {
+               kfree(js->dr_post_data);
+               js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3);
+
+               if (js->dr_post_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->dr_post = count;
+
+       } else
+               js->dr_post = count;
+
+       if (status == 0) {
+               for (i = 0; i < count; ++i) {
+                       j = i + start_index;
+
+                       if (postamble_data == NULL)
+                               js->dr_post_data[i >> 3] |= (1 << (i & 7));
+                       else {
+                               if (postamble_data[j >> 3] & (1 << (j & 7)))
+                                       js->dr_post_data[i >> 3] |=
+                                                               (1 << (i & 7));
+                               else
+                                       js->dr_post_data[i >> 3] &=
+                                           ~(u32)(1 << (i & 7));
+
+                       }
+               }
+       }
+
+       return status;
+}
+
+int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
+                                               u8 *postamble_data)
+{
+       int status = 0;
+       u32 i;
+       u32 j;
+
+       if (count > js->ir_post) {
+               kfree(js->ir_post_data);
+               js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3);
+               if (js->ir_post_data == NULL)
+                       status = -ENOMEM;
+               else
+                       js->ir_post = count;
+
+       } else
+               js->ir_post = count;
+
+       if (status != 0)
+               return status;
+
+       for (i = 0; i < count; ++i) {
+               j = i + start_index;
+
+               if (postamble_data == NULL)
+                       js->ir_post_data[i >> 3] |= (1 << (i & 7));
+               else {
+                       if (postamble_data[j >> 3] & (1 << (j & 7)))
+                               js->ir_post_data[i >> 3] |= (1 << (i & 7));
+                       else
+                               js->ir_post_data[i >> 3] &=
+                                   ~(u32)(1 << (i & 7));
+
+               }
+       }
+
+       return status;
+}
+
+static void altera_jreset_idle(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+       int i;
+       /* Go to Test Logic Reset (no matter what the starting state may be) */
+       for (i = 0; i < 5; ++i)
+               alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+
+       /* Now step to Run Test / Idle */
+       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+       js->jtag_state = IDLE;
+}
+
+int altera_goto_jstate(struct altera_state *astate,
+                                       enum altera_jtag_state state)
+{
+       struct altera_jtag *js = &astate->js;
+       int tms;
+       int count = 0;
+       int status = 0;
+
+       if (js->jtag_state == ILLEGAL_JTAG_STATE)
+               /* initialize JTAG chain to known state */
+               altera_jreset_idle(astate);
+
+       if (js->jtag_state == state) {
+               /*
+                * We are already in the desired state.
+                * If it is a stable state, loop here.
+                * Otherwise do nothing (no clock cycles).
+                */
+               if ((state == IDLE) || (state == DRSHIFT) ||
+                       (state == DRPAUSE) || (state == IRSHIFT) ||
+                               (state == IRPAUSE)) {
+                       alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO);
+               } else if (state == RESET)
+                       alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO);
+
+       } else {
+               while ((js->jtag_state != state) && (count < 9)) {
+                       /* Get TMS value to take a step toward desired state */
+                       tms = (altera_jtag_path_map[js->jtag_state] &
+                                                       (1 << state))
+                                                       ? TMS_HIGH : TMS_LOW;
+
+                       /* Take a step */
+                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+
+                       if (tms)
+                               js->jtag_state =
+                                       altera_transitions[js->jtag_state].tms_high;
+                       else
+                               js->jtag_state =
+                                       altera_transitions[js->jtag_state].tms_low;
+
+                       ++count;
+               }
+       }
+
+       if (js->jtag_state != state)
+               status = -EREMOTEIO;
+
+       return status;
+}
+
+int altera_wait_cycles(struct altera_state *astate,
+                                       s32 cycles,
+                                       enum altera_jtag_state wait_state)
+{
+       struct altera_jtag *js = &astate->js;
+       int tms;
+       s32 count;
+       int status = 0;
+
+       if (js->jtag_state != wait_state)
+               status = altera_goto_jstate(astate, wait_state);
+
+       if (status == 0) {
+               /*
+                * Set TMS high to loop in RESET state
+                * Set TMS low to loop in any other stable state
+                */
+               tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW;
+
+               for (count = 0L; count < cycles; count++)
+                       alt_jtag_io(tms, TDI_LOW, IGNORE_TDO);
+
+       }
+
+       return status;
+}
+
+int altera_wait_msecs(struct altera_state *astate,
+                       s32 microseconds, enum altera_jtag_state wait_state)
+/*
+ * Causes JTAG hardware to sit in the specified stable
+ * state for the specified duration of real time.  If
+ * no JTAG operations have been performed yet, then only
+ * a delay is performed.  This permits the WAIT USECS
+ * statement to be used in VECTOR programs without causing
+ * any JTAG operations.
+ * Returns 0 for success, else appropriate error code.
+ */
+{
+       struct altera_jtag *js = &astate->js;
+       int status = 0;
+
+       if ((js->jtag_state != ILLEGAL_JTAG_STATE) &&
+           (js->jtag_state != wait_state))
+               status = altera_goto_jstate(astate, wait_state);
+
+       if (status == 0)
+               /* Wait for specified time interval */
+               udelay(microseconds);
+
+       return status;
+}
+
+static void altera_concatenate_data(u8 *buffer,
+                               u8 *preamble_data,
+                               u32 preamble_count,
+                               u8 *target_data,
+                               u32 start_index,
+                               u32 target_count,
+                               u8 *postamble_data,
+                               u32 postamble_count)
+/*
+ * Copies preamble data, target data, and postamble data
+ * into one buffer for IR or DR scans.
+ */
+{
+       u32 i, j, k;
+
+       for (i = 0L; i < preamble_count; ++i) {
+               if (preamble_data[i >> 3L] & (1L << (i & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+
+       j = start_index;
+       k = preamble_count + target_count;
+       for (; i < k; ++i, ++j) {
+               if (target_data[j >> 3L] & (1L << (j & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+
+       j = 0L;
+       k = preamble_count + target_count + postamble_count;
+       for (; i < k; ++i, ++j) {
+               if (postamble_data[j >> 3L] & (1L << (j & 7L)))
+                       buffer[i >> 3L] |= (1L << (i & 7L));
+               else
+                       buffer[i >> 3L] &= ~(u32)(1L << (i & 7L));
+
+       }
+}
+
+static int alt_jtag_drscan(struct altera_state *astate,
+                       int start_state,
+                       int count,
+                       u8 *tdi,
+                       u8 *tdo)
+{
+       int i = 0;
+       int tdo_bit = 0;
+       int status = 1;
+
+       /* First go to DRSHIFT state */
+       switch (start_state) {
+       case 0:                                         /* IDLE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       case 1:                                         /* DRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       case 2:                                         /* IRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(0, 0, 0);   /* DRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* DRSHIFT */
+               break;
+
+       default:
+               status = 0;
+       }
+
+       if (status) {
+               /* loop in the SHIFT-DR state */
+               for (i = 0; i < count; i++) {
+                       tdo_bit = alt_jtag_io(
+                                       (i == count - 1),
+                                       tdi[i >> 3] & (1 << (i & 7)),
+                                       (tdo != NULL));
+
+                       if (tdo != NULL) {
+                               if (tdo_bit)
+                                       tdo[i >> 3] |= (1 << (i & 7));
+                               else
+                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
+
+                       }
+               }
+
+               alt_jtag_io(0, 0, 0);   /* DRPAUSE */
+       }
+
+       return status;
+}
+
+static int alt_jtag_irscan(struct altera_state *astate,
+                   int start_state,
+                   int count,
+                   u8 *tdi,
+                   u8 *tdo)
+{
+       int i = 0;
+       int tdo_bit = 0;
+       int status = 1;
+
+       /* First go to IRSHIFT state */
+       switch (start_state) {
+       case 0:                                         /* IDLE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       case 1:                                         /* DRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* DREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* DRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       case 2:                                         /* IRPAUSE */
+               alt_jtag_io(1, 0, 0);   /* IREXIT2 */
+               alt_jtag_io(1, 0, 0);   /* IRUPDATE */
+               alt_jtag_io(1, 0, 0);   /* DRSELECT */
+               alt_jtag_io(1, 0, 0);   /* IRSELECT */
+               alt_jtag_io(0, 0, 0);   /* IRCAPTURE */
+               alt_jtag_io(0, 0, 0);   /* IRSHIFT */
+               break;
+
+       default:
+               status = 0;
+       }
+
+       if (status) {
+               /* loop in the SHIFT-IR state */
+               for (i = 0; i < count; i++) {
+                       tdo_bit = alt_jtag_io(
+                                     (i == count - 1),
+                                     tdi[i >> 3] & (1 << (i & 7)),
+                                     (tdo != NULL));
+                       if (tdo != NULL) {
+                               if (tdo_bit)
+                                       tdo[i >> 3] |= (1 << (i & 7));
+                               else
+                                       tdo[i >> 3] &= ~(u32)(1 << (i & 7));
+
+                       }
+               }
+
+               alt_jtag_io(0, 0, 0);   /* IRPAUSE */
+       }
+
+       return status;
+}
+
+static void altera_extract_target_data(u8 *buffer,
+                               u8 *target_data,
+                               u32 start_index,
+                               u32 preamble_count,
+                               u32 target_count)
+/*
+ * Copies target data from scan buffer, filtering out
+ * preamble and postamble data.
+ */
+{
+       u32 i;
+       u32 j;
+       u32 k;
+
+       j = preamble_count;
+       k = start_index + target_count;
+       for (i = start_index; i < k; ++i, ++j) {
+               if (buffer[j >> 3] & (1 << (j & 7)))
+                       target_data[i >> 3] |= (1 << (i & 7));
+               else
+                       target_data[i >> 3] &= ~(u32)(1 << (i & 7));
+
+       }
+}
+
+int altera_irscan(struct altera_state *astate,
+                               u32 count,
+                               u8 *tdi_data,
+                               u32 start_index)
+/* Shifts data into instruction register */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->ir_pre + count + js->ir_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->ir_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->ir_buffer);
+                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->ir_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->ir_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, IR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->ir_buffer,
+                                       js->ir_pre_data,
+                                       js->ir_pre,
+                                       tdi_data,
+                                       start_index,
+                                       count,
+                                       js->ir_post_data,
+                                       js->ir_post);
+               /* Do the IRSCAN */
+               alt_jtag_irscan(astate,
+                               start_code,
+                               shift_count,
+                               js->ir_buffer,
+                               NULL);
+
+               /* alt_jtag_irscan() always ends in IRPAUSE state */
+               js->jtag_state = IRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->irstop_state != IRPAUSE)
+                       status = altera_goto_jstate(astate, js->irstop_state);
+
+
+       return status;
+}
+
+int altera_swap_ir(struct altera_state *astate,
+                           u32 count,
+                           u8 *in_data,
+                           u32 in_index,
+                           u8 *out_data,
+                           u32 out_index)
+/* Shifts data into instruction register, capturing output data */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->ir_pre + count + js->ir_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->ir_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->ir_buffer);
+                       js->ir_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->ir_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->ir_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, IR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->ir_buffer,
+                                       js->ir_pre_data,
+                                       js->ir_pre,
+                                       in_data,
+                                       in_index,
+                                       count,
+                                       js->ir_post_data,
+                                       js->ir_post);
+
+               /* Do the IRSCAN */
+               alt_jtag_irscan(astate,
+                               start_code,
+                               shift_count,
+                               js->ir_buffer,
+                               js->ir_buffer);
+
+               /* alt_jtag_irscan() always ends in IRPAUSE state */
+               js->jtag_state = IRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->irstop_state != IRPAUSE)
+                       status = altera_goto_jstate(astate, js->irstop_state);
+
+
+       if (status == 0)
+               /* Now extract the returned data from the buffer */
+               altera_extract_target_data(js->ir_buffer,
+                                       out_data, out_index,
+                                       js->ir_pre, count);
+
+       return status;
+}
+
+int altera_drscan(struct altera_state *astate,
+                               u32 count,
+                               u8 *tdi_data,
+                               u32 start_index)
+/* Shifts data into data register (ignoring output data) */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->dr_pre + count + js->dr_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->dr_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->dr_buffer);
+                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
+                       if (js->dr_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->dr_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, DR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->dr_buffer,
+                                       js->dr_pre_data,
+                                       js->dr_pre,
+                                       tdi_data,
+                                       start_index,
+                                       count,
+                                       js->dr_post_data,
+                                       js->dr_post);
+               /* Do the DRSCAN */
+               alt_jtag_drscan(astate, start_code, shift_count,
+                               js->dr_buffer, NULL);
+               /* alt_jtag_drscan() always ends in DRPAUSE state */
+               js->jtag_state = DRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->drstop_state != DRPAUSE)
+                       status = altera_goto_jstate(astate, js->drstop_state);
+
+       return status;
+}
+
+int altera_swap_dr(struct altera_state *astate, u32 count,
+                               u8 *in_data, u32 in_index,
+                               u8 *out_data, u32 out_index)
+/* Shifts data into data register, capturing output data */
+{
+       struct altera_jtag *js = &astate->js;
+       int start_code = 0;
+       u32 alloc_chars = 0;
+       u32 shift_count = js->dr_pre + count + js->dr_post;
+       int status = 0;
+       enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE;
+
+       switch (js->jtag_state) {
+       case ILLEGAL_JTAG_STATE:
+       case RESET:
+       case IDLE:
+               start_code = 0;
+               start_state = IDLE;
+               break;
+
+       case DRSELECT:
+       case DRCAPTURE:
+       case DRSHIFT:
+       case DREXIT1:
+       case DRPAUSE:
+       case DREXIT2:
+       case DRUPDATE:
+               start_code = 1;
+               start_state = DRPAUSE;
+               break;
+
+       case IRSELECT:
+       case IRCAPTURE:
+       case IRSHIFT:
+       case IREXIT1:
+       case IRPAUSE:
+       case IREXIT2:
+       case IRUPDATE:
+               start_code = 2;
+               start_state = IRPAUSE;
+               break;
+
+       default:
+               status = -EREMOTEIO;
+               break;
+       }
+
+       if (status == 0)
+               if (js->jtag_state != start_state)
+                       status = altera_goto_jstate(astate, start_state);
+
+       if (status == 0) {
+               if (shift_count > js->dr_length) {
+                       alloc_chars = (shift_count + 7) >> 3;
+                       kfree(js->dr_buffer);
+                       js->dr_buffer = (u8 *)alt_malloc(alloc_chars);
+
+                       if (js->dr_buffer == NULL)
+                               status = -ENOMEM;
+                       else
+                               js->dr_length = alloc_chars * 8;
+
+               }
+       }
+
+       if (status == 0) {
+               /*
+                * Copy preamble data, DR data,
+                * and postamble data into a buffer
+                */
+               altera_concatenate_data(js->dr_buffer,
+                               js->dr_pre_data,
+                               js->dr_pre,
+                               in_data,
+                               in_index,
+                               count,
+                               js->dr_post_data,
+                               js->dr_post);
+
+               /* Do the DRSCAN */
+               alt_jtag_drscan(astate,
+                               start_code,
+                               shift_count,
+                               js->dr_buffer,
+                               js->dr_buffer);
+
+               /* alt_jtag_drscan() always ends in DRPAUSE state */
+               js->jtag_state = DRPAUSE;
+       }
+
+       if (status == 0)
+               if (js->drstop_state != DRPAUSE)
+                       status = altera_goto_jstate(astate, js->drstop_state);
+
+       if (status == 0)
+               /* Now extract the returned data from the buffer */
+               altera_extract_target_data(js->dr_buffer,
+                                       out_data,
+                                       out_index,
+                                       js->dr_pre,
+                                       count);
+
+       return status;
+}
+
+void altera_free_buffers(struct altera_state *astate)
+{
+       struct altera_jtag *js = &astate->js;
+       /* If the JTAG interface was used, reset it to TLR */
+       if (js->jtag_state != ILLEGAL_JTAG_STATE)
+               altera_jreset_idle(astate);
+
+       kfree(js->dr_pre_data);
+       js->dr_pre_data = NULL;
+
+       kfree(js->dr_post_data);
+       js->dr_post_data = NULL;
+
+       kfree(js->dr_buffer);
+       js->dr_buffer = NULL;
+
+       kfree(js->ir_pre_data);
+       js->ir_pre_data = NULL;
+
+       kfree(js->ir_post_data);
+       js->ir_post_data = NULL;
+
+       kfree(js->ir_buffer);
+       js->ir_buffer = NULL;
+}
diff --git a/drivers/staging/altera-stapl/altera-jtag.h b/drivers/staging/altera-stapl/altera-jtag.h
new file mode 100644 (file)
index 0000000..2f97e36
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * altera-jtag.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef ALTERA_JTAG_H
+#define ALTERA_JTAG_H
+
+/* Function Prototypes */
+enum altera_jtag_state {
+       ILLEGAL_JTAG_STATE = -1,
+       RESET = 0,
+       IDLE = 1,
+       DRSELECT = 2,
+       DRCAPTURE = 3,
+       DRSHIFT = 4,
+       DREXIT1 = 5,
+       DRPAUSE = 6,
+       DREXIT2 = 7,
+       DRUPDATE = 8,
+       IRSELECT = 9,
+       IRCAPTURE = 10,
+       IRSHIFT = 11,
+       IREXIT1 = 12,
+       IRPAUSE = 13,
+       IREXIT2 = 14,
+       IRUPDATE = 15
+
+};
+
+struct altera_jtag {
+       /* Global variable to store the current JTAG state */
+       enum altera_jtag_state jtag_state;
+
+       /* Store current stop-state for DR and IR scan commands */
+       enum altera_jtag_state drstop_state;
+       enum altera_jtag_state irstop_state;
+
+       /* Store current padding values */
+       u32 dr_pre;
+       u32 dr_post;
+       u32 ir_pre;
+       u32 ir_post;
+       u32 dr_length;
+       u32 ir_length;
+       u8 *dr_pre_data;
+       u8 *dr_post_data;
+       u8 *ir_pre_data;
+       u8 *ir_post_data;
+       u8 *dr_buffer;
+       u8 *ir_buffer;
+};
+
+#define ALTERA_STACK_SIZE 128
+#define ALTERA_MESSAGE_LENGTH 1024
+
+struct altera_state {
+       struct altera_config    *config;
+       struct altera_jtag      js;
+       char                    msg_buff[ALTERA_MESSAGE_LENGTH + 1];
+       long                    stack[ALTERA_STACK_SIZE];
+};
+
+int altera_jinit(struct altera_state *astate);
+int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state);
+int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state);
+int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *preamble_data);
+int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *preamble_data);
+int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *postamble_data);
+int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index,
+                               u8 *postamble_data);
+int altera_goto_jstate(struct altera_state *astate,
+                               enum altera_jtag_state state);
+int altera_wait_cycles(struct altera_state *astate, s32 cycles,
+                               enum altera_jtag_state wait_state);
+int altera_wait_msecs(struct altera_state *astate, s32 microseconds,
+                               enum altera_jtag_state wait_state);
+int altera_irscan(struct altera_state *astate, u32 count,
+                               u8 *tdi_data, u32 start_index);
+int altera_swap_ir(struct altera_state *astate,
+                               u32 count, u8 *in_data,
+                               u32 in_index, u8 *out_data,
+                               u32 out_index);
+int altera_drscan(struct altera_state *astate, u32 count,
+                               u8 *tdi_data, u32 start_index);
+int altera_swap_dr(struct altera_state *astate, u32 count,
+                               u8 *in_data, u32 in_index,
+                               u8 *out_data, u32 out_index);
+void altera_free_buffers(struct altera_state *astate);
+#endif /* ALTERA_JTAG_H */
diff --git a/drivers/staging/altera-stapl/altera-lpt.c b/drivers/staging/altera-stapl/altera-lpt.c
new file mode 100644 (file)
index 0000000..91456a0
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * altera-lpt.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Abylay Ospan <aospan@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include "altera-exprt.h"
+
+static int lpt_hardware_initialized;
+
+static void byteblaster_write(int port, int data)
+{
+       outb((u8)data, (u16)(port + 0x378));
+};
+
+static int byteblaster_read(int port)
+{
+       int data = 0;
+       data = inb((u16)(port + 0x378));
+       return data & 0xff;
+};
+
+int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo)
+{
+       int data = 0;
+       int tdo = 0;
+       int initial_lpt_ctrl = 0;
+
+       if (!lpt_hardware_initialized) {
+               initial_lpt_ctrl = byteblaster_read(2);
+               byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf);
+               lpt_hardware_initialized = 1;
+       }
+
+       data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0));
+
+       byteblaster_write(0, data);
+
+       if (read_tdo) {
+               tdo = byteblaster_read(1);
+               tdo = ((tdo & 0x80) ? 0 : 1);
+       }
+
+       byteblaster_write(0, data | 0x01);
+
+       byteblaster_write(0, data);
+
+       return tdo;
+}
diff --git a/drivers/staging/altera-stapl/altera.c b/drivers/staging/altera-stapl/altera.c
new file mode 100644 (file)
index 0000000..05aad35
--- /dev/null
@@ -0,0 +1,2527 @@
+/*
+ * altera.c
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010,2011 NetUP Inc.
+ * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <staging/altera.h>
+#include "altera-exprt.h"
+#include "altera-jtag.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debugging information");
+
+MODULE_DESCRIPTION("altera FPGA kernel module");
+MODULE_AUTHOR("Igor M. Liplianin  <liplianin@netup.ru>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(args...) \
+       if (debug) { \
+               printk(KERN_DEBUG args); \
+       }
+
+enum altera_fpga_opcode {
+       OP_NOP = 0,
+       OP_DUP,
+       OP_SWP,
+       OP_ADD,
+       OP_SUB,
+       OP_MULT,
+       OP_DIV,
+       OP_MOD,
+       OP_SHL,
+       OP_SHR,
+       OP_NOT,
+       OP_AND,
+       OP_OR,
+       OP_XOR,
+       OP_INV,
+       OP_GT,
+       OP_LT,
+       OP_RET,
+       OP_CMPS,
+       OP_PINT,
+       OP_PRNT,
+       OP_DSS,
+       OP_DSSC,
+       OP_ISS,
+       OP_ISSC,
+       OP_DPR = 0x1c,
+       OP_DPRL,
+       OP_DPO,
+       OP_DPOL,
+       OP_IPR,
+       OP_IPRL,
+       OP_IPO,
+       OP_IPOL,
+       OP_PCHR,
+       OP_EXIT,
+       OP_EQU,
+       OP_POPT,
+       OP_ABS = 0x2c,
+       OP_BCH0,
+       OP_PSH0 = 0x2f,
+       OP_PSHL = 0x40,
+       OP_PSHV,
+       OP_JMP,
+       OP_CALL,
+       OP_NEXT,
+       OP_PSTR,
+       OP_SINT = 0x47,
+       OP_ST,
+       OP_ISTP,
+       OP_DSTP,
+       OP_SWPN,
+       OP_DUPN,
+       OP_POPV,
+       OP_POPE,
+       OP_POPA,
+       OP_JMPZ,
+       OP_DS,
+       OP_IS,
+       OP_DPRA,
+       OP_DPOA,
+       OP_IPRA,
+       OP_IPOA,
+       OP_EXPT,
+       OP_PSHE,
+       OP_PSHA,
+       OP_DYNA,
+       OP_EXPV = 0x5c,
+       OP_COPY = 0x80,
+       OP_REVA,
+       OP_DSC,
+       OP_ISC,
+       OP_WAIT,
+       OP_VS,
+       OP_CMPA = 0xc0,
+       OP_VSC,
+};
+
+struct altera_procinfo {
+       char                    *name;
+       u8                      attrs;
+       struct altera_procinfo  *next;
+};
+
+/* This function checks if enough parameters are available on the stack. */
+static int altera_check_stack(int stack_ptr, int count, int *status)
+{
+       if (stack_ptr < count) {
+               *status = -EOVERFLOW;
+               return 0;
+       }
+
+       return 1;
+}
+
+static void altera_export_int(char *key, s32 value)
+{
+       dprintk("Export: key = \"%s\", value = %d\n", key, value);
+}
+
+#define HEX_LINE_CHARS 72
+#define HEX_LINE_BITS (HEX_LINE_CHARS * 4)
+
+static void altera_export_bool_array(char *key, u8 *data, s32 count)
+{
+       char string[HEX_LINE_CHARS + 1];
+       s32 i, offset;
+       u32 size, line, lines, linebits, value, j, k;
+
+       if (count > HEX_LINE_BITS) {
+               dprintk("Export: key = \"%s\", %d bits, value = HEX\n",
+                                                       key, count);
+               lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS;
+
+               for (line = 0; line < lines; ++line) {
+                       if (line < (lines - 1)) {
+                               linebits = HEX_LINE_BITS;
+                               size = HEX_LINE_CHARS;
+                               offset = count - ((line + 1) * HEX_LINE_BITS);
+                       } else {
+                               linebits =
+                                       count - ((lines - 1) * HEX_LINE_BITS);
+                               size = (linebits + 3) / 4;
+                               offset = 0L;
+                       }
+
+                       string[size] = '\0';
+                       j = size - 1;
+                       value = 0;
+
+                       for (k = 0; k < linebits; ++k) {
+                               i = k + offset;
+                               if (data[i >> 3] & (1 << (i & 7)))
+                                       value |= (1 << (i & 3));
+                               if ((i & 3) == 3) {
+                                       sprintf(&string[j], "%1x", value);
+                                       value = 0;
+                                       --j;
+                               }
+                       }
+                       if ((k & 3) > 0)
+                               sprintf(&string[j], "%1x", value);
+
+                       dprintk("%s\n", string);
+               }
+
+       } else {
+               size = (count + 3) / 4;
+               string[size] = '\0';
+               j = size - 1;
+               value = 0;
+
+               for (i = 0; i < count; ++i) {
+                       if (data[i >> 3] & (1 << (i & 7)))
+                               value |= (1 << (i & 3));
+                       if ((i & 3) == 3) {
+                               sprintf(&string[j], "%1x", value);
+                               value = 0;
+                               --j;
+                       }
+               }
+               if ((i & 3) > 0)
+                       sprintf(&string[j], "%1x", value);
+
+               dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n",
+                       key, count, string);
+       }
+}
+
+static int altera_execute(struct altera_state *astate,
+                               u8 *p,
+                               s32 program_size,
+                               s32 *error_address,
+                               int *exit_code,
+                               int *format_version)
+{
+       struct altera_config *aconf = astate->config;
+       char *msg_buff = astate->msg_buff;
+       long *stack = astate->stack;
+       int status = 0;
+       u32 first_word = 0L;
+       u32 action_table = 0L;
+       u32 proc_table = 0L;
+       u32 str_table = 0L;
+       u32 sym_table = 0L;
+       u32 data_sect = 0L;
+       u32 code_sect = 0L;
+       u32 debug_sect = 0L;
+       u32 action_count = 0L;
+       u32 proc_count = 0L;
+       u32 sym_count = 0L;
+       long *vars = NULL;
+       s32 *var_size = NULL;
+       char *attrs = NULL;
+       u8 *proc_attributes = NULL;
+       u32 pc;
+       u32 opcode_address;
+       u32 args[3];
+       u32 opcode;
+       u32 name_id;
+       u8 charbuf[4];
+       long long_tmp;
+       u32 variable_id;
+       u8 *charptr_tmp;
+       u8 *charptr_tmp2;
+       long *longptr_tmp;
+       int version = 0;
+       int delta = 0;
+       int stack_ptr = 0;
+       u32 arg_count;
+       int done = 0;
+       int bad_opcode = 0;
+       u32 count;
+       u32 index;
+       u32 index2;
+       s32 long_count;
+       s32 long_idx;
+       s32 long_idx2;
+       u32 i;
+       u32 j;
+       u32 uncomp_size;
+       u32 offset;
+       u32 value;
+       int current_proc = 0;
+       int reverse;
+
+       char *name;
+
+       dprintk("%s\n", __func__);
+
+       /* Read header information */
+       if (program_size > 52L) {
+               first_word    = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               *format_version = version + 1;
+               delta = version * 8;
+
+               action_table  = get_unaligned_be32(&p[4]);
+               proc_table    = get_unaligned_be32(&p[8]);
+               str_table  = get_unaligned_be32(&p[4 + delta]);
+               sym_table  = get_unaligned_be32(&p[16 + delta]);
+               data_sect  = get_unaligned_be32(&p[20 + delta]);
+               code_sect  = get_unaligned_be32(&p[24 + delta]);
+               debug_sect = get_unaligned_be32(&p[28 + delta]);
+               action_count  = get_unaligned_be32(&p[40 + delta]);
+               proc_count    = get_unaligned_be32(&p[44 + delta]);
+               sym_count  = get_unaligned_be32(&p[48 + (2 * delta)]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) {
+               done = 1;
+               status = -EIO;
+               goto exit_done;
+       }
+
+       if (sym_count <= 0)
+               goto exit_done;
+
+       vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL);
+
+       if (vars == NULL)
+               status = -ENOMEM;
+
+       if (status == 0) {
+               var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL);
+
+               if (var_size == NULL)
+                       status = -ENOMEM;
+       }
+
+       if (status == 0) {
+               attrs = kzalloc(sym_count, GFP_KERNEL);
+
+               if (attrs == NULL)
+                       status = -ENOMEM;
+       }
+
+       if ((status == 0) && (version > 0)) {
+               proc_attributes = kzalloc(proc_count, GFP_KERNEL);
+
+               if (proc_attributes == NULL)
+                       status = -ENOMEM;
+       }
+
+       if (status != 0)
+               goto exit_done;
+
+       delta = version * 2;
+
+       for (i = 0; i < sym_count; ++i) {
+               offset = (sym_table + ((11 + delta) * i));
+
+               value = get_unaligned_be32(&p[offset + 3 + delta]);
+
+               attrs[i] = p[offset];
+
+               /*
+                * use bit 7 of attribute byte to indicate that
+                * this buffer was dynamically allocated
+                * and should be freed later
+                */
+               attrs[i] &= 0x7f;
+
+               var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]);
+
+               /*
+                * Attribute bits:
+                * bit 0: 0 = read-only, 1 = read-write
+                * bit 1: 0 = not compressed, 1 = compressed
+                * bit 2: 0 = not initialized, 1 = initialized
+                * bit 3: 0 = scalar, 1 = array
+                * bit 4: 0 = Boolean, 1 = integer
+                * bit 5: 0 = declared variable,
+                *      1 = compiler created temporary variable
+                */
+
+               if ((attrs[i] & 0x0c) == 0x04)
+                       /* initialized scalar variable */
+                       vars[i] = value;
+               else if ((attrs[i] & 0x1e) == 0x0e) {
+                       /* initialized compressed Boolean array */
+                       uncomp_size = get_unaligned_le32(&p[data_sect + value]);
+
+                       /* allocate a buffer for the uncompressed data */
+                       vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL);
+                       if (vars[i] == 0L)
+                               status = -ENOMEM;
+                       else {
+                               /* set flag so buffer will be freed later */
+                               attrs[i] |= 0x80;
+
+                               /* uncompress the data */
+                               if (altera_shrink(&p[data_sect + value],
+                                               var_size[i],
+                                               (u8 *)vars[i],
+                                               uncomp_size,
+                                               version) != uncomp_size)
+                                       /* decompression failed */
+                                       status = -EIO;
+                               else
+                                       var_size[i] = uncomp_size * 8L;
+
+                       }
+               } else if ((attrs[i] & 0x1e) == 0x0c) {
+                       /* initialized Boolean array */
+                       vars[i] = value + data_sect + (long)p;
+               } else if ((attrs[i] & 0x1c) == 0x1c) {
+                       /* initialized integer array */
+                       vars[i] = value + data_sect;
+               } else if ((attrs[i] & 0x0c) == 0x08) {
+                       /* uninitialized array */
+
+                       /* flag attrs so that memory is freed */
+                       attrs[i] |= 0x80;
+
+                       if (var_size[i] > 0) {
+                               u32 size;
+
+                               if (attrs[i] & 0x10)
+                                       /* integer array */
+                                       size = (var_size[i] * sizeof(s32));
+                               else
+                                       /* Boolean array */
+                                       size = ((var_size[i] + 7L) / 8L);
+
+                               vars[i] = (long)kzalloc(size, GFP_KERNEL);
+
+                               if (vars[i] == 0) {
+                                       status = -ENOMEM;
+                               } else {
+                                       /* zero out memory */
+                                       for (j = 0; j < size; ++j)
+                                               ((u8 *)(vars[i]))[j] = 0;
+
+                               }
+                       } else
+                               vars[i] = 0;
+
+               } else
+                       vars[i] = 0;
+
+       }
+
+exit_done:
+       if (status != 0)
+               done = 1;
+
+       altera_jinit(astate);
+
+       pc = code_sect;
+       msg_buff[0] = '\0';
+
+       /*
+        * For JBC version 2, we will execute the procedures corresponding to
+        * the selected ACTION
+        */
+       if (version > 0) {
+               if (aconf->action == NULL) {
+                       status = -EINVAL;
+                       done = 1;
+               } else {
+                       int action_found = 0;
+                       for (i = 0; (i < action_count) && !action_found; ++i) {
+                               name_id = get_unaligned_be32(&p[action_table +
+                                                               (12 * i)]);
+
+                               name = &p[str_table + name_id];
+
+                               if (strnicmp(aconf->action, name, strlen(name)) == 0) {
+                                       action_found = 1;
+                                       current_proc =
+                                               get_unaligned_be32(&p[action_table +
+                                                               (12 * i) + 8]);
+                               }
+                       }
+
+                       if (!action_found) {
+                               status = -EINVAL;
+                               done = 1;
+                       }
+               }
+
+               if (status == 0) {
+                       int first_time = 1;
+                       i = current_proc;
+                       while ((i != 0) || first_time) {
+                               first_time = 0;
+                               /* check procedure attribute byte */
+                               proc_attributes[i] =
+                                               (p[proc_table +
+                                                               (13 * i) + 8] &
+                                                                       0x03);
+
+                               /*
+                                * BIT0 - OPTIONAL
+                                * BIT1 - RECOMMENDED
+                                * BIT6 - FORCED OFF
+                                * BIT7 - FORCED ON
+                                */
+
+                               i = get_unaligned_be32(&p[proc_table +
+                                                       (13 * i) + 4]);
+                       }
+
+                       /*
+                        * Set current_proc to the first procedure
+                        * to be executed
+                        */
+                       i = current_proc;
+                       while ((i != 0) &&
+                               ((proc_attributes[i] == 1) ||
+                               ((proc_attributes[i] & 0xc0) == 0x40))) {
+                               i = get_unaligned_be32(&p[proc_table +
+                                                       (13 * i) + 4]);
+                       }
+
+                       if ((i != 0) || ((i == 0) && (current_proc == 0) &&
+                               ((proc_attributes[0] != 1) &&
+                               ((proc_attributes[0] & 0xc0) != 0x40)))) {
+                               current_proc = i;
+                               pc = code_sect +
+                                       get_unaligned_be32(&p[proc_table +
+                                                               (13 * i) + 9]);
+                               if ((pc < code_sect) || (pc >= debug_sect))
+                                       status = -ERANGE;
+                       } else
+                               /* there are no procedures to execute! */
+                               done = 1;
+
+               }
+       }
+
+       msg_buff[0] = '\0';
+
+       while (!done) {
+               opcode = (p[pc] & 0xff);
+               opcode_address = pc;
+               ++pc;
+
+               if (debug > 1)
+                       printk("opcode: %02x\n", opcode);
+
+               arg_count = (opcode >> 6) & 3;
+               for (i = 0; i < arg_count; ++i) {
+                       args[i] = get_unaligned_be32(&p[pc]);
+                       pc += 4;
+               }
+
+               switch (opcode) {
+               case OP_NOP:
+                       break;
+               case OP_DUP:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - 1];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_SWP:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+                       break;
+               case OP_ADD:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] += stack[stack_ptr];
+                       }
+                       break;
+               case OP_SUB:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] -= stack[stack_ptr];
+                       }
+                       break;
+               case OP_MULT:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] *= stack[stack_ptr];
+                       }
+                       break;
+               case OP_DIV:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] /= stack[stack_ptr];
+                       }
+                       break;
+               case OP_MOD:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] %= stack[stack_ptr];
+                       }
+                       break;
+               case OP_SHL:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] <<= stack[stack_ptr];
+                       }
+                       break;
+               case OP_SHR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] >>= stack[stack_ptr];
+                       }
+                       break;
+               case OP_NOT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               stack[stack_ptr - 1] ^= (-1L);
+
+                       break;
+               case OP_AND:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] &= stack[stack_ptr];
+                       }
+                       break;
+               case OP_OR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] |= stack[stack_ptr];
+                       }
+                       break;
+               case OP_XOR:
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               --stack_ptr;
+                               stack[stack_ptr - 1] ^= stack[stack_ptr];
+                       }
+                       break;
+               case OP_INV:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L;
+                       break;
+               case OP_GT:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] > stack[stack_ptr]) ?
+                                                                       1L : 0L;
+
+                       break;
+               case OP_LT:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] < stack[stack_ptr]) ?
+                                                                       1L : 0L;
+
+                       break;
+               case OP_RET:
+                       if ((version > 0) && (stack_ptr == 0)) {
+                               /*
+                                * We completed one of the main procedures
+                                * of an ACTION.
+                                * Find the next procedure
+                                * to be executed and jump to it.
+                                * If there are no more procedures, then EXIT.
+                                */
+                               i = get_unaligned_be32(&p[proc_table +
+                                               (13 * current_proc) + 4]);
+                               while ((i != 0) &&
+                                       ((proc_attributes[i] == 1) ||
+                                       ((proc_attributes[i] & 0xc0) == 0x40)))
+                                       i = get_unaligned_be32(&p[proc_table +
+                                                               (13 * i) + 4]);
+
+                               if (i == 0) {
+                                       /* no procedures to execute! */
+                                       done = 1;
+                                       *exit_code = 0; /* success */
+                               } else {
+                                       current_proc = i;
+                                       pc = code_sect + get_unaligned_be32(
+                                                               &p[proc_table +
+                                                               (13 * i) + 9]);
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+
+                       } else
+                               if (altera_check_stack(stack_ptr, 1, &status)) {
+                                       pc = stack[--stack_ptr] + code_sect;
+                                       if ((pc <= code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+
+                               }
+
+                       break;
+               case OP_CMPS:
+                       /*
+                        * Array short compare
+                        * ...stack 0 is source 1 value
+                        * ...stack 1 is source 2 value
+                        * ...stack 2 is mask value
+                        * ...stack 3 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 4, &status)) {
+                               s32 a = stack[--stack_ptr];
+                               s32 b = stack[--stack_ptr];
+                               long_tmp = stack[--stack_ptr];
+                               count = stack[stack_ptr - 1];
+
+                               if ((count < 1) || (count > 32))
+                                       status = -ERANGE;
+                               else {
+                                       long_tmp &= ((-1L) >> (32 - count));
+
+                                       stack[stack_ptr - 1] =
+                                       ((a & long_tmp) == (b & long_tmp))
+                                                               ? 1L : 0L;
+                               }
+                       }
+                       break;
+               case OP_PINT:
+                       /*
+                        * PRINT add integer
+                        * ...stack 0 is integer value
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       sprintf(&msg_buff[strlen(msg_buff)],
+                                       "%ld", stack[--stack_ptr]);
+                       break;
+               case OP_PRNT:
+                       /* PRINT finish */
+                       if (debug)
+                               printk(msg_buff, "\n");
+
+                       msg_buff[0] = '\0';
+                       break;
+               case OP_DSS:
+                       /*
+                        * DRSCAN short
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_drscan(astate, count, charbuf, 0);
+                       break;
+               case OP_DSSC:
+                       /*
+                        * DRSCAN short with capture
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[stack_ptr - 1];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_swap_dr(astate, count, charbuf,
+                                                       0, charbuf, 0);
+                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
+                       break;
+               case OP_ISS:
+                       /*
+                        * IRSCAN short
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_irscan(astate, count, charbuf, 0);
+                       break;
+               case OP_ISSC:
+                       /*
+                        * IRSCAN short with capture
+                        * ...stack 0 is scan data
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+                       count = stack[stack_ptr - 1];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_swap_ir(astate, count, charbuf,
+                                                       0, charbuf, 0);
+                       stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]);
+                       break;
+               case OP_DPR:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       status = altera_set_dr_pre(&astate->js, count, 0, NULL);
+                       break;
+               case OP_DPRL:
+                       /*
+                        * DRPRE with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_dr_pre(&astate->js, count, 0,
+                                               charbuf);
+                       break;
+               case OP_DPO:
+                       /*
+                        * DRPOST
+                        * ...stack 0 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_dr_post(&astate->js, count,
+                                                               0, NULL);
+                       }
+                       break;
+               case OP_DPOL:
+                       /*
+                        * DRPOST with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_dr_post(&astate->js, count, 0,
+                                                       charbuf);
+                       break;
+               case OP_IPR:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_ir_pre(&astate->js, count,
+                                                               0, NULL);
+                       }
+                       break;
+               case OP_IPRL:
+                       /*
+                        * IRPRE with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               count = stack[--stack_ptr];
+                               long_tmp = stack[--stack_ptr];
+                               put_unaligned_le32(long_tmp, &charbuf[0]);
+                               status = altera_set_ir_pre(&astate->js, count,
+                                                       0, charbuf);
+                       }
+                       break;
+               case OP_IPO:
+                       /*
+                        * IRPOST
+                        * ...stack 0 is count
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               count = stack[--stack_ptr];
+                               status = altera_set_ir_post(&astate->js, count,
+                                                       0, NULL);
+                       }
+                       break;
+               case OP_IPOL:
+                       /*
+                        * IRPOST with literal data
+                        * ...stack 0 is count
+                        * ...stack 1 is literal data
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       count = stack[--stack_ptr];
+                       long_tmp = stack[--stack_ptr];
+                       put_unaligned_le32(long_tmp, &charbuf[0]);
+                       status = altera_set_ir_post(&astate->js, count, 0,
+                                                       charbuf);
+                       break;
+               case OP_PCHR:
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               u8 ch;
+                               count = strlen(msg_buff);
+                               ch = (char) stack[--stack_ptr];
+                               if ((ch < 1) || (ch > 127)) {
+                                       /*
+                                        * character code out of range
+                                        * instead of flagging an error,
+                                        * force the value to 127
+                                        */
+                                       ch = 127;
+                               }
+                               msg_buff[count] = ch;
+                               msg_buff[count + 1] = '\0';
+                       }
+                       break;
+               case OP_EXIT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               *exit_code = stack[--stack_ptr];
+
+                       done = 1;
+                       break;
+               case OP_EQU:
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       --stack_ptr;
+                       stack[stack_ptr - 1] =
+                               (stack[stack_ptr - 1] == stack[stack_ptr]) ?
+                                                                       1L : 0L;
+                       break;
+               case OP_POPT:
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               --stack_ptr;
+
+                       break;
+               case OP_ABS:
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       if (stack[stack_ptr - 1] < 0)
+                               stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1];
+
+                       break;
+               case OP_BCH0:
+                       /*
+                        * Batch operation 0
+                        * SWP
+                        * SWPN 7
+                        * SWP
+                        * SWPN 6
+                        * DUPN 8
+                        * SWPN 2
+                        * SWP
+                        * DUPN 6
+                        * DUPN 6
+                        */
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWPN 7 */
+                       index = 7 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* DUPN 8 */
+                       index = 8 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+
+                       /* SWPN 2 */
+                       index = 2 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* SWP  */
+                       if (altera_check_stack(stack_ptr, 2, &status)) {
+                               long_tmp = stack[stack_ptr - 2];
+                               stack[stack_ptr - 2] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+
+                       /* DUPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+
+                       /* DUPN 6 */
+                       index = 6 + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_PSH0:
+                       stack[stack_ptr++] = 0;
+                       break;
+               case OP_PSHL:
+                       stack[stack_ptr++] = (s32) args[0];
+                       break;
+               case OP_PSHV:
+                       stack[stack_ptr++] = vars[args[0]];
+                       break;
+               case OP_JMP:
+                       pc = args[0] + code_sect;
+                       if ((pc < code_sect) || (pc >= debug_sect))
+                               status = -ERANGE;
+                       break;
+               case OP_CALL:
+                       stack[stack_ptr++] = pc;
+                       pc = args[0] + code_sect;
+                       if ((pc < code_sect) || (pc >= debug_sect))
+                               status = -ERANGE;
+                       break;
+               case OP_NEXT:
+                       /*
+                        * Process FOR / NEXT loop
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is step value
+                        * ...stack 1 is end value
+                        * ...stack 2 is top address
+                        */
+                       if (altera_check_stack(stack_ptr, 3, &status)) {
+                               s32 step = stack[stack_ptr - 1];
+                               s32 end = stack[stack_ptr - 2];
+                               s32 top = stack[stack_ptr - 3];
+                               s32 iterator = vars[args[0]];
+                               int break_out = 0;
+
+                               if (step < 0) {
+                                       if (iterator <= end)
+                                               break_out = 1;
+                               } else if (iterator >= end)
+                                       break_out = 1;
+
+                               if (break_out) {
+                                       stack_ptr -= 3;
+                               } else {
+                                       vars[args[0]] = iterator + step;
+                                       pc = top + code_sect;
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+                       }
+                       break;
+               case OP_PSTR:
+                       /*
+                        * PRINT add string
+                        * ...argument 0 is string ID
+                        */
+                       count = strlen(msg_buff);
+                       strlcpy(&msg_buff[count],
+                               &p[str_table + args[0]],
+                               ALTERA_MESSAGE_LENGTH - count);
+                       break;
+               case OP_SINT:
+                       /*
+                        * STATE intermediate state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_goto_jstate(astate, args[0]);
+                       break;
+               case OP_ST:
+                       /*
+                        * STATE final state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_goto_jstate(astate, args[0]);
+                       break;
+               case OP_ISTP:
+                       /*
+                        * IRSTOP state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_set_irstop(&astate->js, args[0]);
+                       break;
+               case OP_DSTP:
+                       /*
+                        * DRSTOP state
+                        * ...argument 0 is state code
+                        */
+                       status = altera_set_drstop(&astate->js, args[0]);
+                       break;
+
+               case OP_SWPN:
+                       /*
+                        * Exchange top with Nth stack value
+                        * ...argument 0 is 0-based stack entry
+                        * to swap with top element
+                        */
+                       index = (args[0]) + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               long_tmp = stack[stack_ptr - index];
+                               stack[stack_ptr - index] = stack[stack_ptr - 1];
+                               stack[stack_ptr - 1] = long_tmp;
+                       }
+                       break;
+               case OP_DUPN:
+                       /*
+                        * Duplicate Nth stack value
+                        * ...argument 0 is 0-based stack entry to duplicate
+                        */
+                       index = (args[0]) + 1;
+                       if (altera_check_stack(stack_ptr, index, &status)) {
+                               stack[stack_ptr] = stack[stack_ptr - index];
+                               ++stack_ptr;
+                       }
+                       break;
+               case OP_POPV:
+                       /*
+                        * Pop stack into scalar variable
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is value
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status))
+                               vars[args[0]] = stack[--stack_ptr];
+
+                       break;
+               case OP_POPE:
+                       /*
+                        * Pop stack into integer array element
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is value
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /*
+                        * If variable is read-only,
+                        * convert to writable array
+                        */
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x1c)) {
+                               /* Allocate a writable buffer for this array */
+                               count = var_size[variable_id];
+                               long_tmp = vars[variable_id];
+                               longptr_tmp = kzalloc(count * sizeof(long),
+                                                               GFP_KERNEL);
+                               vars[variable_id] = (long)longptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* copy previous contents into buffer */
+                               for (i = 0; i < count; ++i) {
+                                       longptr_tmp[i] =
+                                               get_unaligned_be32(&p[long_tmp]);
+                                       long_tmp += sizeof(long);
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       /* check that variable is a writable integer array */
+                       if ((attrs[variable_id] & 0x1c) != 0x18)
+                               status = -ERANGE;
+                       else {
+                               longptr_tmp = (long *)vars[variable_id];
+
+                               /* pop the array index */
+                               index = stack[--stack_ptr];
+
+                               /* pop the value and store it into the array */
+                               longptr_tmp[index] = stack[--stack_ptr];
+                       }
+
+                       break;
+               case OP_POPA:
+                       /*
+                        * Pop stack into Boolean array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is count
+                        * ...stack 1 is array index
+                        * ...stack 2 is value
+                        */
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /*
+                        * If variable is read-only,
+                        * convert to writable array
+                        */
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L;
+                                       long_idx < long_tmp;
+                                       ++long_idx) {
+                                       charptr_tmp[long_idx] = 0;
+                               }
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                       ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7))) {
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+                                       }
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       /*
+                        * check that variable is
+                        * a writable Boolean array
+                        */
+                       if ((attrs[variable_id] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+
+                       /* pop the count (number of bits to copy) */
+                       long_count = stack[--stack_ptr];
+
+                       /* pop the array index */
+                       long_idx = stack[--stack_ptr];
+
+                       reverse = 0;
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+
+                               if (long_idx > long_count) {
+                                       reverse = 1;
+                                       long_tmp = long_count;
+                                       long_count = 1 + long_idx -
+                                                               long_count;
+                                       long_idx = long_tmp;
+
+                                       /* reverse POPA is not supported */
+                                       status = -ERANGE;
+                                       break;
+                               } else
+                                       long_count = 1 + long_count -
+                                                               long_idx;
+
+                       }
+
+                       /* pop the data */
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_count < 1) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       for (i = 0; i < long_count; ++i) {
+                               if (long_tmp & (1L << (s32) i))
+                                       charptr_tmp[long_idx >> 3L] |=
+                                               (1L << (long_idx & 7L));
+                               else
+                                       charptr_tmp[long_idx >> 3L] &=
+                                               ~(1L << (long_idx & 7L));
+
+                               ++long_idx;
+                       }
+
+                       break;
+               case OP_JMPZ:
+                       /*
+                        * Pop stack and branch if zero
+                        * ...argument 0 is address
+                        * ...stack 0 is condition value
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               if (stack[--stack_ptr] == 0) {
+                                       pc = args[0] + code_sect;
+                                       if ((pc < code_sect) ||
+                                           (pc >= debug_sect))
+                                               status = -ERANGE;
+                               }
+                       }
+                       break;
+               case OP_DS:
+               case OP_IS:
+                       /*
+                        * DRSCAN
+                        * IRSCAN
+                        * ...argument 0 is scan data variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_idx = stack[--stack_ptr];
+                       long_count = stack[--stack_ptr];
+                       reverse = 0;
+                       if (version > 0) {
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                * stack 2 = count
+                                */
+                               long_tmp = long_count;
+                               long_count = stack[--stack_ptr];
+
+                               if (long_idx > long_tmp) {
+                                       reverse = 1;
+                                       long_idx = long_tmp;
+                               }
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+
+                       if (reverse) {
+                               /*
+                                * allocate a buffer
+                                * and reverse the data order
+                                */
+                               charptr_tmp2 = charptr_tmp;
+                               charptr_tmp = kzalloc((long_count >> 3) + 1,
+                                                               GFP_KERNEL);
+                               if (charptr_tmp == NULL) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               long_tmp = long_idx + long_count - 1;
+                               long_idx2 = 0;
+                               while (long_idx2 < long_count) {
+                                       if (charptr_tmp2[long_tmp >> 3] &
+                                                       (1 << (long_tmp & 7)))
+                                               charptr_tmp[long_idx2 >> 3] |=
+                                                       (1 << (long_idx2 & 7));
+                                       else
+                                               charptr_tmp[long_idx2 >> 3] &=
+                                                       ~(1 << (long_idx2 & 7));
+
+                                       --long_tmp;
+                                       ++long_idx2;
+                               }
+                       }
+
+                       if (opcode == 0x51) /* DS */
+                               status = altera_drscan(astate, long_count,
+                                               charptr_tmp, long_idx);
+                       else /* IS */
+                               status = altera_irscan(astate, long_count,
+                                               charptr_tmp, long_idx);
+
+                       if (reverse)
+                               kfree(charptr_tmp);
+
+                       break;
+               case OP_DPRA:
+                       /*
+                        * DRPRE with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_dr_pre(&astate->js, count, index,
+                                                       charptr_tmp);
+                       break;
+               case OP_DPOA:
+                       /*
+                        * DRPOST with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_dr_post(&astate->js, count, index,
+                                                       charptr_tmp);
+                       break;
+               case OP_IPRA:
+                       /*
+                        * IRPRE with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_ir_pre(&astate->js, count, index,
+                                                       charptr_tmp);
+
+                       break;
+               case OP_IPOA:
+                       /*
+                        * IRPOST with array data
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        * ...stack 1 is count
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       index = stack[--stack_ptr];
+                       count = stack[--stack_ptr];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       status = altera_set_ir_post(&astate->js, count, index,
+                                                       charptr_tmp);
+
+                       break;
+               case OP_EXPT:
+                       /*
+                        * EXPORT
+                        * ...argument 0 is string ID
+                        * ...stack 0 is integer expression
+                        */
+                       if (altera_check_stack(stack_ptr, 1, &status)) {
+                               name = &p[str_table + args[0]];
+                               long_tmp = stack[--stack_ptr];
+                               altera_export_int(name, long_tmp);
+                       }
+                       break;
+               case OP_PSHE:
+                       /*
+                        * Push integer array element
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is array index
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       variable_id = args[0];
+                       index = stack[stack_ptr - 1];
+
+                       /* check variable type */
+                       if ((attrs[variable_id] & 0x1f) == 0x19) {
+                               /* writable integer array */
+                               longptr_tmp = (long *)vars[variable_id];
+                               stack[stack_ptr - 1] = longptr_tmp[index];
+                       } else if ((attrs[variable_id] & 0x1f) == 0x1c) {
+                               /* read-only integer array */
+                               long_tmp = vars[variable_id] +
+                                               (index * sizeof(long));
+                               stack[stack_ptr - 1] =
+                                       get_unaligned_be32(&p[long_tmp]);
+                       } else
+                               status = -ERANGE;
+
+                       break;
+               case OP_PSHA:
+                       /*
+                        * Push Boolean array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is count
+                        * ...stack 1 is array index
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       variable_id = args[0];
+
+                       /* check that variable is a Boolean array */
+                       if ((attrs[variable_id] & 0x18) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+
+                       /* pop the count (number of bits to copy) */
+                       count = stack[--stack_ptr];
+
+                       /* pop the array index */
+                       index = stack[stack_ptr - 1];
+
+                       if (version > 0)
+                               /*
+                                * stack 0 = array right index
+                                * stack 1 = array left index
+                                */
+                               count = 1 + count - index;
+
+                       if ((count < 1) || (count > 32)) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       long_tmp = 0L;
+
+                       for (i = 0; i < count; ++i)
+                               if (charptr_tmp[(i + index) >> 3] &
+                                               (1 << ((i + index) & 7)))
+                                       long_tmp |= (1L << i);
+
+                       stack[stack_ptr - 1] = long_tmp;
+
+                       break;
+               case OP_DYNA:
+                       /*
+                        * Dynamically change size of array
+                        * ...argument 0 is variable ID
+                        * ...stack 0 is new size
+                        */
+                       if (!altera_check_stack(stack_ptr, 1, &status))
+                               break;
+                       variable_id = args[0];
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_tmp > var_size[variable_id]) {
+                               var_size[variable_id] = long_tmp;
+
+                               if (attrs[variable_id] & 0x10)
+                                       /* allocate integer array */
+                                       long_tmp *= sizeof(long);
+                               else
+                                       /* allocate Boolean array */
+                                       long_tmp = (long_tmp + 7) >> 3;
+
+                               /*
+                                * If the buffer was previously allocated,
+                                * free it
+                                */
+                               if (attrs[variable_id] & 0x80) {
+                                       kfree((void *)vars[variable_id]);
+                                       vars[variable_id] = 0;
+                               }
+
+                               /*
+                                * Allocate a new buffer
+                                * of the requested size
+                                */
+                               vars[variable_id] = (long)
+                                       kzalloc(long_tmp, GFP_KERNEL);
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /*
+                                * Set the attribute bit to indicate that
+                                * this buffer was dynamically allocated and
+                                * should be freed later
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* zero out memory */
+                               count = ((var_size[variable_id] + 7L) /
+                                                                       8L);
+                               charptr_tmp = (u8 *)(vars[variable_id]);
+                               for (index = 0; index < count; ++index)
+                                       charptr_tmp[index] = 0;
+
+                       }
+
+                       break;
+               case OP_EXPV:
+                       /*
+                        * Export Boolean array
+                        * ...argument 0 is string ID
+                        * ...stack 0 is variable ID
+                        * ...stack 1 is array right index
+                        * ...stack 2 is array left index
+                        */
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+                       if (version == 0) {
+                               /* EXPV is not supported in JBC 1.0 */
+                               bad_opcode = 1;
+                               break;
+                       }
+                       name = &p[str_table + args[0]];
+                       variable_id = stack[--stack_ptr];
+                       long_idx = stack[--stack_ptr];/* right indx */
+                       long_idx2 = stack[--stack_ptr];/* left indx */
+
+                       if (long_idx > long_idx2) {
+                               /* reverse indices not supported */
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       long_count = 1 + long_idx2 - long_idx;
+
+                       charptr_tmp = (u8 *)vars[variable_id];
+                       charptr_tmp2 = NULL;
+
+                       if ((long_idx & 7L) != 0) {
+                               s32 k = long_idx;
+                               charptr_tmp2 =
+                                       kzalloc(((long_count + 7L) / 8L),
+                                                       GFP_KERNEL);
+                               if (charptr_tmp2 == NULL) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               for (i = 0; i < long_count; ++i) {
+                                       if (charptr_tmp[k >> 3] &
+                                                       (1 << (k & 7)))
+                                               charptr_tmp2[i >> 3] |=
+                                                               (1 << (i & 7));
+                                       else
+                                               charptr_tmp2[i >> 3] &=
+                                                               ~(1 << (i & 7));
+
+                                       ++k;
+                               }
+                               charptr_tmp = charptr_tmp2;
+
+                       } else if (long_idx != 0)
+                               charptr_tmp = &charptr_tmp[long_idx >> 3];
+
+                       altera_export_bool_array(name, charptr_tmp,
+                                                       long_count);
+
+                       /* free allocated buffer */
+                       if ((long_idx & 7L) != 0)
+                               kfree(charptr_tmp2);
+
+                       break;
+               case OP_COPY: {
+                       /*
+                        * Array copy
+                        * ...argument 0 is dest ID
+                        * ...argument 1 is source ID
+                        * ...stack 0 is count
+                        * ...stack 1 is dest index
+                        * ...stack 2 is source index
+                        */
+                       s32 copy_count;
+                       s32 copy_index;
+                       s32 copy_index2;
+                       s32 destleft;
+                       s32 src_count;
+                       s32 dest_count;
+                       int src_reverse = 0;
+                       int dest_reverse = 0;
+
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+
+                       copy_count = stack[--stack_ptr];
+                       copy_index = stack[--stack_ptr];
+                       copy_index2 = stack[--stack_ptr];
+                       reverse = 0;
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = source right index
+                                * stack 1 = source left index
+                                * stack 2 = destination right index
+                                * stack 3 = destination left index
+                                */
+                               destleft = stack[--stack_ptr];
+
+                               if (copy_count > copy_index) {
+                                       src_reverse = 1;
+                                       reverse = 1;
+                                       src_count = 1 + copy_count - copy_index;
+                                       /* copy_index = source start index */
+                               } else {
+                                       src_count = 1 + copy_index - copy_count;
+                                       /* source start index */
+                                       copy_index = copy_count;
+                               }
+
+                               if (copy_index2 > destleft) {
+                                       dest_reverse = 1;
+                                       reverse = !reverse;
+                                       dest_count = 1 + copy_index2 - destleft;
+                                       /* destination start index */
+                                       copy_index2 = destleft;
+                               } else
+                                       dest_count = 1 + destleft - copy_index2;
+
+                               copy_count = (src_count < dest_count) ?
+                                                       src_count : dest_count;
+
+                               if ((src_reverse || dest_reverse) &&
+                                       (src_count != dest_count))
+                                       /*
+                                        * If either the source or destination
+                                        * is reversed, we can't tolerate
+                                        * a length mismatch, because we
+                                        * "left justify" arrays when copying.
+                                        * This won't work correctly
+                                        * with reversed arrays.
+                                        */
+                                       status = -ERANGE;
+
+                       }
+
+                       count = copy_count;
+                       index = copy_index;
+                       index2 = copy_index2;
+
+                       /*
+                        * If destination is a read-only array,
+                        * allocate a buffer and convert it to a writable array
+                        */
+                       variable_id = args[1];
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L; long_idx < long_tmp;
+                                                               ++long_idx)
+                                       charptr_tmp[long_idx] = 0;
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                                               ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7)))
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+
+                               }
+
+                               /*
+                               set bit 7 - buffer was dynamically allocated */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[1]];
+                       charptr_tmp2 = (u8 *)vars[args[0]];
+
+                       /* check if destination is a writable Boolean array */
+                       if ((attrs[args[1]] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (count < 1) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (reverse)
+                               index2 += (count - 1);
+
+                       for (i = 0; i < count; ++i) {
+                               if (charptr_tmp2[index >> 3] &
+                                                       (1 << (index & 7)))
+                                       charptr_tmp[index2 >> 3] |=
+                                                       (1 << (index2 & 7));
+                               else
+                                       charptr_tmp[index2 >> 3] &=
+                                               ~(1 << (index2 & 7));
+
+                               ++index;
+                               if (reverse)
+                                       --index2;
+                               else
+                                       ++index2;
+                       }
+
+                       break;
+               }
+               case OP_DSC:
+               case OP_ISC: {
+                       /*
+                        * DRSCAN with capture
+                        * IRSCAN with capture
+                        * ...argument 0 is scan data variable ID
+                        * ...argument 1 is capture variable ID
+                        * ...stack 0 is capture index
+                        * ...stack 1 is scan data index
+                        * ...stack 2 is count
+                        */
+                       s32 scan_right, scan_left;
+                       s32 capture_count = 0;
+                       s32 scan_count = 0;
+                       s32 capture_index;
+                       s32 scan_index;
+
+                       if (!altera_check_stack(stack_ptr, 3, &status))
+                               break;
+
+                       capture_index = stack[--stack_ptr];
+                       scan_index = stack[--stack_ptr];
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = capture right index
+                                * stack 1 = capture left index
+                                * stack 2 = scan right index
+                                * stack 3 = scan left index
+                                * stack 4 = count
+                                */
+                               scan_right = stack[--stack_ptr];
+                               scan_left = stack[--stack_ptr];
+                               capture_count = 1 + scan_index - capture_index;
+                               scan_count = 1 + scan_left - scan_right;
+                               scan_index = scan_right;
+                       }
+
+                       long_count = stack[--stack_ptr];
+                       /*
+                        * If capture array is read-only, allocate a buffer
+                        * and convert it to a writable array
+                        */
+                       variable_id = args[1];
+                       if ((version > 0) &&
+                               ((attrs[variable_id] & 0x9c) == 0x0c)) {
+                               /* Allocate a writable buffer for this array */
+                               long_tmp =
+                                       (var_size[variable_id] + 7L) >> 3L;
+                               charptr_tmp2 = (u8 *)vars[variable_id];
+                               charptr_tmp =
+                                       kzalloc(long_tmp, GFP_KERNEL);
+                               vars[variable_id] = (long)charptr_tmp;
+
+                               if (vars[variable_id] == 0) {
+                                       status = -ENOMEM;
+                                       break;
+                               }
+
+                               /* zero the buffer */
+                               for (long_idx = 0L; long_idx < long_tmp;
+                                                               ++long_idx)
+                                       charptr_tmp[long_idx] = 0;
+
+                               /* copy previous contents into buffer */
+                               for (long_idx = 0L;
+                                       long_idx < var_size[variable_id];
+                                                               ++long_idx) {
+                                       long_idx2 = long_idx;
+
+                                       if (charptr_tmp2[long_idx2 >> 3] &
+                                               (1 << (long_idx2 & 7)))
+                                               charptr_tmp[long_idx >> 3] |=
+                                                       (1 << (long_idx & 7));
+
+                               }
+
+                               /*
+                                * set bit 7 - buffer was
+                                * dynamically allocated
+                                */
+                               attrs[variable_id] |= 0x80;
+
+                               /* clear bit 2 - variable is writable */
+                               attrs[variable_id] &= ~0x04;
+                               attrs[variable_id] |= 0x01;
+
+                       }
+
+                       charptr_tmp = (u8 *)vars[args[0]];
+                       charptr_tmp2 = (u8 *)vars[args[1]];
+
+                       if ((version > 0) &&
+                                       ((long_count > capture_count) ||
+                                       (long_count > scan_count))) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       /*
+                        * check that capture array
+                        * is a writable Boolean array
+                        */
+                       if ((attrs[args[1]] & 0x1c) != 0x08) {
+                               status = -ERANGE;
+                               break;
+                       }
+
+                       if (status == 0) {
+                               if (opcode == 0x82) /* DSC */
+                                       status = altera_swap_dr(astate,
+                                                       long_count,
+                                                       charptr_tmp,
+                                                       scan_index,
+                                                       charptr_tmp2,
+                                                       capture_index);
+                               else /* ISC */
+                                       status = altera_swap_ir(astate,
+                                                       long_count,
+                                                       charptr_tmp,
+                                                       scan_index,
+                                                       charptr_tmp2,
+                                                       capture_index);
+
+                       }
+
+                       break;
+               }
+               case OP_WAIT:
+                       /*
+                        * WAIT
+                        * ...argument 0 is wait state
+                        * ...argument 1 is end state
+                        * ...stack 0 is cycles
+                        * ...stack 1 is microseconds
+                        */
+                       if (!altera_check_stack(stack_ptr, 2, &status))
+                               break;
+                       long_tmp = stack[--stack_ptr];
+
+                       if (long_tmp != 0L)
+                               status = altera_wait_cycles(astate, long_tmp,
+                                                               args[0]);
+
+                       long_tmp = stack[--stack_ptr];
+
+                       if ((status == 0) && (long_tmp != 0L))
+                               status = altera_wait_msecs(astate,
+                                                               long_tmp,
+                                                               args[0]);
+
+                       if ((status == 0) && (args[1] != args[0]))
+                               status = altera_goto_jstate(astate,
+                                                               args[1]);
+
+                       if (version > 0) {
+                               --stack_ptr; /* throw away MAX cycles */
+                               --stack_ptr; /* throw away MAX microseconds */
+                       }
+                       break;
+               case OP_CMPA: {
+                       /*
+                        * Array compare
+                        * ...argument 0 is source 1 ID
+                        * ...argument 1 is source 2 ID
+                        * ...argument 2 is mask ID
+                        * ...stack 0 is source 1 index
+                        * ...stack 1 is source 2 index
+                        * ...stack 2 is mask index
+                        * ...stack 3 is count
+                        */
+                       s32 a, b;
+                       u8 *source1 = (u8 *)vars[args[0]];
+                       u8 *source2 = (u8 *)vars[args[1]];
+                       u8 *mask = (u8 *)vars[args[2]];
+                       u32 index1;
+                       u32 index2;
+                       u32 mask_index;
+
+                       if (!altera_check_stack(stack_ptr, 4, &status))
+                               break;
+
+                       index1 = stack[--stack_ptr];
+                       index2 = stack[--stack_ptr];
+                       mask_index = stack[--stack_ptr];
+                       long_count = stack[--stack_ptr];
+
+                       if (version > 0) {
+                               /*
+                                * stack 0 = source 1 right index
+                                * stack 1 = source 1 left index
+                                * stack 2 = source 2 right index
+                                * stack 3 = source 2 left index
+                                * stack 4 = mask right index
+                                * stack 5 = mask left index
+                                */
+                               s32 mask_right = stack[--stack_ptr];
+                               s32 mask_left = stack[--stack_ptr];
+                               /* source 1 count */
+                               a = 1 + index2 - index1;
+                               /* source 2 count */
+                               b = 1 + long_count - mask_index;
+                               a = (a < b) ? a : b;
+                               /* mask count */
+                               b = 1 + mask_left - mask_right;
+                               a = (a < b) ? a : b;
+                               /* source 2 start index */
+                               index2 = mask_index;
+                               /* mask start index */
+                               mask_index = mask_right;
+                               long_count = a;
+                       }
+
+                       long_tmp = 1L;
+
+                       if (long_count < 1)
+                               status = -ERANGE;
+                       else {
+                               count = long_count;
+
+                               for (i = 0; i < count; ++i) {
+                                       if (mask[mask_index >> 3] &
+                                               (1 << (mask_index & 7))) {
+                                               a = source1[index1 >> 3] &
+                                                       (1 << (index1 & 7))
+                                                               ? 1 : 0;
+                                               b = source2[index2 >> 3] &
+                                                       (1 << (index2 & 7))
+                                                               ? 1 : 0;
+
+                                               if (a != b) /* failure */
+                                                       long_tmp = 0L;
+                                       }
+                                       ++index1;
+                                       ++index2;
+                                       ++mask_index;
+                               }
+                       }
+
+                       stack[stack_ptr++] = long_tmp;
+
+                       break;
+               }
+               default:
+                       /* Unrecognized opcode -- ERROR! */
+                       bad_opcode = 1;
+                       break;
+               }
+
+               if (bad_opcode)
+                       status = -ENOSYS;
+
+               if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE))
+                       status = -EOVERFLOW;
+
+               if (status != 0) {
+                       done = 1;
+                       *error_address = (s32)(opcode_address - code_sect);
+               }
+       }
+
+       altera_free_buffers(astate);
+
+       /* Free all dynamically allocated arrays */
+       if ((attrs != NULL) && (vars != NULL))
+               for (i = 0; i < sym_count; ++i)
+                       if (attrs[i] & 0x80)
+                               kfree((void *)vars[i]);
+
+       kfree(vars);
+       kfree(var_size);
+       kfree(attrs);
+       kfree(proc_attributes);
+
+       return status;
+}
+
+static int altera_get_note(u8 *p, s32 program_size,
+                       s32 *offset, char *key, char *value, int length)
+/*
+ * Gets key and value of NOTE fields in the JBC file.
+ * Can be called in two modes:  if offset pointer is NULL,
+ * then the function searches for note fields which match
+ * the key string provided.  If offset is not NULL, then
+ * the function finds the next note field of any key,
+ * starting at the offset specified by the offset pointer.
+ * Returns 0 for success, else appropriate error code
+ */
+{
+       int status = -ENODATA;
+       u32 note_strings = 0L;
+       u32 note_table = 0L;
+       u32 note_count = 0L;
+       u32 first_word = 0L;
+       int version = 0;
+       int delta = 0;
+       char *key_ptr;
+       char *value_ptr;
+       int i;
+
+       /* Read header information */
+       if (program_size > 52L) {
+               first_word    = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               delta = version * 8;
+
+               note_strings  = get_unaligned_be32(&p[8 + delta]);
+               note_table    = get_unaligned_be32(&p[12 + delta]);
+               note_count    = get_unaligned_be32(&p[44 + (2 * delta)]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+               return -EIO;
+
+       if (note_count <= 0L)
+               return status;
+
+       if (offset == NULL) {
+               /*
+                * We will search for the first note with a specific key,
+                * and return only the value
+                */
+               for (i = 0; (i < note_count) &&
+                                               (status != 0); ++i) {
+                       key_ptr = &p[note_strings +
+                                       get_unaligned_be32(
+                                       &p[note_table + (8 * i)])];
+                       if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) &&
+                                               (key != NULL)) {
+                               status = 0;
+
+                               value_ptr = &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i) + 4])];
+
+                               if (value != NULL)
+                                       strlcpy(value, value_ptr, length);
+
+                       }
+               }
+       } else {
+               /*
+                * We will search for the next note, regardless of the key,
+                * and return both the value and the key
+                */
+
+               i = *offset;
+
+               if ((i >= 0) && (i < note_count)) {
+                       status = 0;
+
+                       if (key != NULL)
+                               strlcpy(key, &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i)])],
+                                       length);
+
+                       if (value != NULL)
+                               strlcpy(value, &p[note_strings +
+                                               get_unaligned_be32(
+                                               &p[note_table + (8 * i) + 4])],
+                                       length);
+
+                       *offset = i + 1;
+               }
+       }
+
+       return status;
+}
+
+static int altera_check_crc(u8 *p, s32 program_size)
+{
+       int status = 0;
+       u16 local_expected = 0,
+           local_actual = 0,
+           shift_reg = 0xffff;
+       int bit, feedback;
+       u8 databyte;
+       u32 i;
+       u32 crc_section = 0L;
+       u32 first_word = 0L;
+       int version = 0;
+       int delta = 0;
+
+       if (program_size > 52L) {
+               first_word  = get_unaligned_be32(&p[0]);
+               version = (first_word & 1L);
+               delta = version * 8;
+
+               crc_section = get_unaligned_be32(&p[32 + delta]);
+       }
+
+       if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L))
+               status = -EIO;
+
+       if (crc_section >= program_size)
+               status = -EIO;
+
+       if (status == 0) {
+               local_expected = (u16)get_unaligned_be16(&p[crc_section]);
+
+               for (i = 0; i < crc_section; ++i) {
+                       databyte = p[i];
+                       for (bit = 0; bit < 8; bit++) {
+                               feedback = (databyte ^ shift_reg) & 0x01;
+                               shift_reg >>= 1;
+                               if (feedback)
+                                       shift_reg ^= 0x8408;
+
+                               databyte >>= 1;
+                       }
+               }
+
+               local_actual = (u16)~shift_reg;
+
+               if (local_expected != local_actual)
+                       status = -EILSEQ;
+
+       }
+
+       if (debug || status) {
+               switch (status) {
+               case 0:
+                       printk(KERN_INFO "%s: CRC matched: %04x\n", __func__,
+                               local_actual);
+                       break;
+               case -EILSEQ:
+                       printk(KERN_ERR "%s: CRC mismatch: expected %04x, "
+                               "actual %04x\n", __func__, local_expected,
+                               local_actual);
+                       break;
+               case -ENODATA:
+                       printk(KERN_ERR "%s: expected CRC not found, "
+                               "actual CRC = %04x\n", __func__,
+                               local_actual);
+                       break;
+               case -EIO:
+                       printk(KERN_ERR "%s: error: format isn't "
+                               "recognized.\n", __func__);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: CRC function returned error "
+                               "code %d\n", __func__, status);
+                       break;
+               }
+       }
+
+       return status;
+}
+
+static int altera_get_file_info(u8 *p,
+                                       s32 program_size,
+                                       int *format_version,
+                                       int *action_count,
+                                       int *procedure_count)
+{
+       int status = -EIO;
+       u32 first_word = 0;
+       int version = 0;
+
+       if (program_size <= 52L)
+               return status;
+
+       first_word = get_unaligned_be32(&p[0]);
+
+       if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) {
+               status = 0;
+
+               version = (first_word & 1L);
+               *format_version = version + 1;
+
+               if (version > 0) {
+                       *action_count = get_unaligned_be32(&p[48]);
+                       *procedure_count = get_unaligned_be32(&p[52]);
+               }
+       }
+
+       return status;
+}
+
+static int altera_get_act_info(u8 *p,
+                                       s32 program_size,
+                                       int index,
+                                       char **name,
+                                       char **description,
+                                       struct altera_procinfo **proc_list)
+{
+       int status = -EIO;
+       struct altera_procinfo *procptr = NULL;
+       struct altera_procinfo *tmpptr = NULL;
+       u32 first_word = 0L;
+       u32 action_table = 0L;
+       u32 proc_table = 0L;
+       u32 str_table = 0L;
+       u32 note_strings = 0L;
+       u32 action_count = 0L;
+       u32 proc_count = 0L;
+       u32 act_name_id = 0L;
+       u32 act_desc_id = 0L;
+       u32 act_proc_id = 0L;
+       u32 act_proc_name = 0L;
+       u8 act_proc_attribute = 0;
+
+       if (program_size <= 52L)
+               return status;
+       /* Read header information */
+       first_word = get_unaligned_be32(&p[0]);
+
+       if (first_word != 0x4A414D01L)
+               return status;
+
+       action_table = get_unaligned_be32(&p[4]);
+       proc_table   = get_unaligned_be32(&p[8]);
+       str_table = get_unaligned_be32(&p[12]);
+       note_strings = get_unaligned_be32(&p[16]);
+       action_count = get_unaligned_be32(&p[48]);
+       proc_count   = get_unaligned_be32(&p[52]);
+
+       if (index >= action_count)
+               return status;
+
+       act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]);
+       act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]);
+       act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]);
+
+       *name = &p[str_table + act_name_id];
+
+       if (act_desc_id < (note_strings - str_table))
+               *description = &p[str_table + act_desc_id];
+
+       do {
+               act_proc_name = get_unaligned_be32(
+                                       &p[proc_table + (13 * act_proc_id)]);
+               act_proc_attribute =
+                       (p[proc_table + (13 * act_proc_id) + 8] & 0x03);
+
+               procptr = (struct altera_procinfo *)
+                               kzalloc(sizeof(struct altera_procinfo),
+                                                               GFP_KERNEL);
+
+               if (procptr == NULL)
+                       status = -ENOMEM;
+               else {
+                       procptr->name = &p[str_table + act_proc_name];
+                       procptr->attrs = act_proc_attribute;
+                       procptr->next = NULL;
+
+                       /* add record to end of linked list */
+                       if (*proc_list == NULL)
+                               *proc_list = procptr;
+                       else {
+                               tmpptr = *proc_list;
+                               while (tmpptr->next != NULL)
+                                       tmpptr = tmpptr->next;
+                               tmpptr->next = procptr;
+                       }
+               }
+
+               act_proc_id = get_unaligned_be32(
+                               &p[proc_table + (13 * act_proc_id) + 4]);
+       } while ((act_proc_id != 0) && (act_proc_id < proc_count));
+
+       return status;
+}
+
+int altera_init(struct altera_config *config, const struct firmware *fw)
+{
+       struct altera_state *astate = NULL;
+       struct altera_procinfo *proc_list = NULL;
+       struct altera_procinfo *procptr = NULL;
+       char *key = NULL;
+       char *value = NULL;
+       char *action_name = NULL;
+       char *description = NULL;
+       int exec_result = 0;
+       int exit_code = 0;
+       int format_version = 0;
+       int action_count = 0;
+       int procedure_count = 0;
+       int index = 0;
+       s32 offset = 0L;
+       s32 error_address = 0L;
+
+       key = kzalloc(33 * sizeof(char), GFP_KERNEL);
+       if (!key)
+               return -ENOMEM;
+       value = kzalloc(257 * sizeof(char), GFP_KERNEL);
+       if (!value)
+               return -ENOMEM;
+       astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL);
+       if (!astate)
+               return -ENOMEM;
+
+       astate->config = config;
+       if (!astate->config->jtag_io) {
+               dprintk(KERN_INFO "%s: using byteblaster!\n", __func__);
+               astate->config->jtag_io = netup_jtag_io_lpt;
+       }
+
+       altera_check_crc((u8 *)fw->data, fw->size);
+
+       if (debug) {
+               altera_get_file_info((u8 *)fw->data, fw->size, &format_version,
+                                       &action_count, &procedure_count);
+               printk(KERN_INFO "%s: File format is %s ByteCode format\n",
+                       __func__, (format_version == 2) ? "Jam STAPL" :
+                                               "pre-standardized Jam 1.1");
+               while (altera_get_note((u8 *)fw->data, fw->size,
+                                       &offset, key, value, 256) == 0)
+                       printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n",
+                                       __func__, key, value);
+       }
+
+       if (debug && (format_version == 2) && (action_count > 0)) {
+               printk(KERN_INFO "%s: Actions available:\n", __func__);
+               for (index = 0; index < action_count; ++index) {
+                       altera_get_act_info((u8 *)fw->data, fw->size,
+                                               index, &action_name,
+                                               &description,
+                                               &proc_list);
+
+                       if (description == NULL)
+                               printk(KERN_INFO "%s: %s\n",
+                                               __func__,
+                                               action_name);
+                       else
+                               printk(KERN_INFO "%s: %s \"%s\"\n",
+                                               __func__,
+                                               action_name,
+                                               description);
+
+                       procptr = proc_list;
+                       while (procptr != NULL) {
+                               if (procptr->attrs != 0)
+                                       printk(KERN_INFO "%s:    %s (%s)\n",
+                                               __func__,
+                                               procptr->name,
+                                               (procptr->attrs == 1) ?
+                                               "optional" : "recommended");
+
+                               proc_list = procptr->next;
+                               kfree(procptr);
+                               procptr = proc_list;
+                       }
+               }
+
+               printk(KERN_INFO "\n");
+       }
+
+       exec_result = altera_execute(astate, (u8 *)fw->data, fw->size,
+                               &error_address, &exit_code, &format_version);
+
+       if (exit_code)
+               exec_result = -EREMOTEIO;
+
+       if ((format_version == 2) && (exec_result == -EINVAL)) {
+               if (astate->config->action == NULL)
+                       printk(KERN_ERR "%s: error: no action specified for "
+                               "Jam STAPL file.\nprogram terminated.\n",
+                               __func__);
+               else
+                       printk(KERN_ERR "%s: error: action \"%s\""
+                               " is not supported "
+                               "for this Jam STAPL file.\n"
+                               "Program terminated.\n", __func__,
+                               astate->config->action);
+
+       } else if (exec_result)
+               printk(KERN_ERR "%s: error %d\n", __func__, exec_result);
+
+       kfree(key);
+       kfree(value);
+       kfree(astate);
+
+       return 0;
+}
+EXPORT_SYMBOL(altera_init);
index b2656957aa8f1fc7747486804df0b8c3fdafe1b8..5f6b5421371356043cf7768989e5417d6da8e572 100644 (file)
@@ -1,7 +1,6 @@
 config VIDEO_CX25821
        tristate "Conexant cx25821 support"
        depends on DVB_CORE && VIDEO_DEV && PCI && I2C
-       depends on BKL # please fix
        select I2C_ALGOBIT
        select VIDEO_BTCX
        select VIDEO_TVEEPROM
index 160f6693aa333b53e84dfdbd58f827451dd2bbd2..ebdba7c65bc5f467c39ad8c385ab276b23dc177d 100644 (file)
@@ -770,10 +770,12 @@ static int cx25821_alsa_init(void)
        struct cx25821_dev *dev = NULL;
        struct list_head *list;
 
+       mutex_lock(&cx25821_devlist_mutex);
        list_for_each(list, &cx25821_devlist) {
                dev = list_entry(list, struct cx25821_dev, devlist);
                cx25821_audio_initdev(dev);
        }
+       mutex_unlock(&cx25821_devlist_mutex);
 
        if (dev == NULL)
                pr_info("ERROR ALSA: no cx25821 cards found\n");
index a216b620b718eb12ded396b5391e1f43894e121f..523ac5e16c1b2d05d5a68fefc8a9fea5967d3eff 100644 (file)
@@ -33,9 +33,6 @@ MODULE_DESCRIPTION("Driver for Athena cards");
 MODULE_AUTHOR("Shu Lin - Hiep Huynh");
 MODULE_LICENSE("GPL");
 
-struct list_head cx25821_devlist;
-EXPORT_SYMBOL(cx25821_devlist);
-
 static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
@@ -46,8 +43,10 @@ MODULE_PARM_DESC(card, "card type");
 
 static unsigned int cx25821_devcount;
 
-static DEFINE_MUTEX(devlist);
+DEFINE_MUTEX(cx25821_devlist_mutex);
+EXPORT_SYMBOL(cx25821_devlist_mutex);
 LIST_HEAD(cx25821_devlist);
+EXPORT_SYMBOL(cx25821_devlist);
 
 struct sram_channel cx25821_sram_channels[] = {
        [SRAM_CH00] = {
@@ -911,9 +910,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
        dev->nr = ++cx25821_devcount;
        sprintf(dev->name, "cx25821[%d]", dev->nr);
 
-       mutex_lock(&devlist);
+       mutex_lock(&cx25821_devlist_mutex);
        list_add_tail(&dev->devlist, &cx25821_devlist);
-       mutex_unlock(&devlist);
+       mutex_unlock(&cx25821_devlist_mutex);
 
        strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown");
        strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821");
@@ -1465,9 +1464,9 @@ static void __devexit cx25821_finidev(struct pci_dev *pci_dev)
        if (pci_dev->irq)
                free_irq(pci_dev->irq, dev);
 
-       mutex_lock(&devlist);
+       mutex_lock(&cx25821_devlist_mutex);
        list_del(&dev->devlist);
-       mutex_unlock(&devlist);
+       mutex_unlock(&cx25821_devlist_mutex);
 
        cx25821_dev_unregister(dev);
        v4l2_device_unregister(v4l2_dev);
@@ -1501,7 +1500,6 @@ static struct pci_driver cx25821_pci_driver = {
 
 static int __init cx25821_init(void)
 {
-       INIT_LIST_HEAD(&cx25821_devlist);
        pr_info("driver version %d.%d.%d loaded\n",
                (CX25821_VERSION_CODE >> 16) & 0xff,
                (CX25821_VERSION_CODE >> 8) & 0xff,
index 0d8d75670516e77a8cc1b9218c87c5f8821c9778..ab05392386e86e2f19b9214c94d57532759bcca7 100644 (file)
@@ -27,7 +27,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include "cx25821-video.h"
-#include <linux/smp_lock.h>
 
 MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
 MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
@@ -815,7 +814,7 @@ static int video_open(struct file *file)
        if (NULL == fh)
               return -ENOMEM;
 
-       lock_kernel();
+       mutex_lock(&cx25821_devlist_mutex);
 
        list_for_each(list, &cx25821_devlist)
        {
@@ -832,8 +831,8 @@ static int video_open(struct file *file)
        }
 
        if (NULL == dev) {
-              unlock_kernel();
-              return -ENODEV;
+               mutex_unlock(&cx25821_devlist_mutex);
+               return -ENODEV;
        }
 
        file->private_data = fh;
@@ -862,7 +861,7 @@ static int video_open(struct file *file)
                              sizeof(struct cx25821_buffer), fh, NULL);
 
        dprintk(1, "post videobuf_queue_init()\n");
-       unlock_kernel();
+       mutex_unlock(&cx25821_devlist_mutex);
 
        return 0;
 }
index 55115235f7f66e2acb5b52d0fc8d308575b8c972..6230243e2ccbcfa3b63d11f4e1165490a9f940b0 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/kdev_t.h>
-#include <linux/smp_lock.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -445,6 +444,8 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
        v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
 
 extern struct list_head cx25821_devlist;
+extern struct mutex cx25821_devlist_mutex;
+
 extern struct cx25821_board cx25821_boards[];
 extern struct cx25821_subid cx25821_subids[];
 
diff --git a/drivers/staging/cxd2099/Kconfig b/drivers/staging/cxd2099/Kconfig
new file mode 100644 (file)
index 0000000..9d638c3
--- /dev/null
@@ -0,0 +1,11 @@
+config DVB_CXD2099
+        tristate "CXD2099AR Common Interface driver"
+        depends on DVB_CORE && PCI && I2C && DVB_NGENE
+        ---help---
+          Support for the CI module found on cineS2 DVB-S2, supported by
+         the Micronas PCIe device driver (ngene).
+
+         For now, data is passed through '/dev/dvb/adapterX/sec0':
+           - Encrypted data must be written to 'sec0'.
+           - Decrypted data can be read from 'sec0'.
+           - Setup the CAM using device 'ca0'.
diff --git a/drivers/staging/cxd2099/Makefile b/drivers/staging/cxd2099/Makefile
new file mode 100644 (file)
index 0000000..72b1455
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
diff --git a/drivers/staging/cxd2099/TODO b/drivers/staging/cxd2099/TODO
new file mode 100644 (file)
index 0000000..375bb6f
--- /dev/null
@@ -0,0 +1,12 @@
+For now, data is passed through '/dev/dvb/adapterX/sec0':
+ - Encrypted data must be written to 'sec0'.
+ - Decrypted data can be read from 'sec0'.
+ - Setup the CAM using device 'ca0'.
+
+But this is wrong. There are some discussions about the proper way for
+doing it, as seen at:
+       http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html
+
+While there's no proper fix for it, the driver should be kept in staging.
+
+Patches should be submitted to: linux-media@vger.kernel.org.
diff --git a/drivers/staging/cxd2099/cxd2099.c b/drivers/staging/cxd2099/cxd2099.c
new file mode 100644 (file)
index 0000000..b49186c
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
+ *
+ * Copyright (C) 2010 DigitalDevices UG
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include "cxd2099.h"
+
+#define MAX_BUFFER_SIZE 248
+
+struct cxd {
+       struct dvb_ca_en50221 en;
+
+       struct i2c_adapter *i2c;
+       u8     adr;
+       u8     regs[0x23];
+       u8     lastaddress;
+       u8     clk_reg_f;
+       u8     clk_reg_b;
+       int    mode;
+       u32    bitrate;
+       int    ready;
+       int    dr;
+       int    slot_stat;
+
+       u8     amem[1024];
+       int    amem_read;
+
+       int    cammode;
+       struct mutex lock;
+};
+
+static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
+                        u8 reg, u8 data)
+{
+       u8 m[2] = {reg, data};
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
+
+       if (i2c_transfer(adapter, &msg, 1) != 1) {
+               printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n",
+                      reg, adr);
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_write(struct i2c_adapter *adapter, u8 adr,
+                    u8 *data, u8 len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
+
+       if (i2c_transfer(adapter, &msg, 1) != 1) {
+               printk(KERN_ERR "Failed to write to I2C!\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
+                       u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf = &reg, .len = 1 },
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf = val, .len = 1 } };
+
+       if (i2c_transfer(adapter, msgs, 2) != 2) {
+               printk(KERN_ERR "error in i2c_read_reg\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr,
+                   u8 reg, u8 *data, u8 n)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf = &reg, .len = 1 },
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf = data, .len = n } };
+
+       if (i2c_transfer(adapter, msgs, 2) != 2) {
+               printk(KERN_ERR "error in i2c_read\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
+{
+       int status;
+
+       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       if (!status) {
+               ci->lastaddress = adr;
+               status = i2c_read(ci->i2c, ci->adr, 1, data, n);
+       }
+       return status;
+}
+
+static int read_reg(struct cxd *ci, u8 reg, u8 *val)
+{
+       return read_block(ci, reg, val, 1);
+}
+
+
+static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = { 2, address&0xff, address>>8 };
+
+       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->adr, 3, data, n);
+       return status;
+}
+
+static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = { 2, address&0xff, address>>8 };
+
+       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       if (!status) {
+               u8 buf[256] = {3};
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+       }
+       return status;
+}
+
+static int read_io(struct cxd *ci, u16 address, u8 *val)
+{
+       int status;
+       u8 addr[3] = { 2, address&0xff, address>>8 };
+
+       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->adr, 3, val, 1);
+       return status;
+}
+
+static int write_io(struct cxd *ci, u16 address, u8 val)
+{
+       int status;
+       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 buf[2] = { 3, val };
+
+       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       if (!status)
+               status = i2c_write(ci->i2c, ci->adr, buf, 2);
+
+       return status;
+}
+
+
+static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
+{
+       int status;
+
+       status = i2c_write_reg(ci->i2c, ci->adr, 0, reg);
+       if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
+               status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]);
+       ci->regs[reg] = (ci->regs[reg]&(~mask))|val;
+       if (!status) {
+               ci->lastaddress = reg;
+               status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]);
+       }
+       if (reg == 0x20)
+               ci->regs[reg] &= 0x7f;
+       return status;
+}
+
+static int write_reg(struct cxd *ci, u8 reg, u8 val)
+{
+       return write_regm(ci, reg, val, 0xff);
+}
+
+#ifdef BUFFER_MODE
+static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
+{
+       int status;
+       u8 buf[256] = {1};
+
+       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       if (!status) {
+               ci->lastaddress = adr;
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+       }
+       return status;
+}
+#endif
+
+static void set_mode(struct cxd *ci, int mode)
+{
+       if (mode == ci->mode)
+               return;
+
+       switch (mode) {
+       case 0x00: /* IO mem */
+               write_regm(ci, 0x06, 0x00, 0x07);
+               break;
+       case 0x01: /* ATT mem */
+               write_regm(ci, 0x06, 0x02, 0x07);
+               break;
+       default:
+               break;
+       }
+       ci->mode = mode;
+}
+
+static void cam_mode(struct cxd *ci, int mode)
+{
+       if (mode == ci->cammode)
+               return;
+
+       switch (mode) {
+       case 0x00:
+               write_regm(ci, 0x20, 0x80, 0x80);
+               break;
+       case 0x01:
+               printk(KERN_INFO "enable cam buffer mode\n");
+               /* write_reg(ci, 0x0d, 0x00); */
+               /* write_reg(ci, 0x0e, 0x01); */
+               write_regm(ci, 0x08, 0x40, 0x40);
+               /* read_reg(ci, 0x12, &dummy); */
+               write_regm(ci, 0x08, 0x80, 0x80);
+               break;
+       default:
+               break;
+       }
+       ci->cammode = mode;
+}
+
+
+
+#define CHK_ERROR(s) if ((status = s)) break
+
+static int init(struct cxd *ci)
+{
+       int status;
+
+       mutex_lock(&ci->lock);
+       ci->mode = -1;
+       do {
+               CHK_ERROR(write_reg(ci, 0x00, 0x00));
+               CHK_ERROR(write_reg(ci, 0x01, 0x00));
+               CHK_ERROR(write_reg(ci, 0x02, 0x10));
+               CHK_ERROR(write_reg(ci, 0x03, 0x00));
+               CHK_ERROR(write_reg(ci, 0x05, 0xFF));
+               CHK_ERROR(write_reg(ci, 0x06, 0x1F));
+               CHK_ERROR(write_reg(ci, 0x07, 0x1F));
+               CHK_ERROR(write_reg(ci, 0x08, 0x28));
+               CHK_ERROR(write_reg(ci, 0x14, 0x20));
+
+               CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+               CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
+
+               /* Sync detector */
+               CHK_ERROR(write_reg(ci, 0x0B, 0x33));
+               CHK_ERROR(write_reg(ci, 0x0C, 0x33));
+
+               CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F));
+               CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b));
+               CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F));
+               CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f));
+
+               CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */
+               CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */
+               CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */
+
+
+               CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */
+
+               CHK_ERROR(write_regm(ci, 0x03, 0x02, 02));  /* Enable IREQA Interrupt */
+               CHK_ERROR(write_reg(ci, 0x01, 0x04));  /* Enable CD Interrupt */
+               CHK_ERROR(write_reg(ci, 0x00, 0x31));  /* Enable TS1,Hot Swap,Slot A */
+               CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));  /* Put TS in bypass */
+               ci->cammode = -1;
+#ifdef BUFFER_MODE
+               cam_mode(ci, 0);
+#endif
+       } while (0);
+       mutex_unlock(&ci->lock);
+
+       return 0;
+}
+
+
+static int read_attribute_mem(struct dvb_ca_en50221 *ca,
+                             int slot, int address)
+{
+       struct cxd *ci = ca->data;
+       u8 val;
+       mutex_lock(&ci->lock);
+       set_mode(ci, 1);
+       read_pccard(ci, address, &val, 1);
+       mutex_unlock(&ci->lock);
+       return val;
+}
+
+
+static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
+                              int address, u8 value)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 1);
+       write_pccard(ci, address, &value, 1);
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+static int read_cam_control(struct dvb_ca_en50221 *ca,
+                           int slot, u8 address)
+{
+       struct cxd *ci = ca->data;
+       u8 val;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 0);
+       read_io(ci, address, &val);
+       mutex_unlock(&ci->lock);
+       return val;
+}
+
+static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
+                            u8 address, u8 value)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 0);
+       write_io(ci, address, value);
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       cam_mode(ci, 0);
+       write_reg(ci, 0x00, 0x21);
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x00, 0x31);
+       write_regm(ci, 0x20, 0x80, 0x80);
+       write_reg(ci, 0x03, 0x02);
+       ci->ready = 0;
+       ci->mode = -1;
+       {
+               int i;
+               for (i = 0; i < 100; i++) {
+                       msleep(10);
+                       if (ci->ready)
+                               break;
+               }
+       }
+       mutex_unlock(&ci->lock);
+       /* msleep(500); */
+       return 0;
+}
+
+static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       printk(KERN_INFO "slot_shutdown\n");
+       mutex_lock(&ci->lock);
+       /* write_regm(ci, 0x09, 0x08, 0x08); */
+       write_regm(ci, 0x20, 0x80, 0x80);
+       write_regm(ci, 0x06, 0x07, 0x07);
+       ci->mode = -1;
+       mutex_unlock(&ci->lock);
+       return 0; /* shutdown(ci); */
+}
+
+static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x09, 0x00, 0x08);
+       set_mode(ci, 0);
+#ifdef BUFFER_MODE
+       cam_mode(ci, 1);
+#endif
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+
+static int campoll(struct cxd *ci)
+{
+       u8 istat;
+
+       read_reg(ci, 0x04, &istat);
+       if (!istat)
+               return 0;
+       write_reg(ci, 0x05, istat);
+
+       if (istat&0x40) {
+               ci->dr = 1;
+               printk(KERN_INFO "DR\n");
+       }
+       if (istat&0x20)
+               printk(KERN_INFO "WC\n");
+
+       if (istat&2) {
+               u8 slotstat;
+
+               read_reg(ci, 0x01, &slotstat);
+               if (!(2&slotstat)) {
+                       if (!ci->slot_stat) {
+                               ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
+                               write_regm(ci, 0x03, 0x08, 0x08);
+                       }
+
+               } else {
+                       if (ci->slot_stat) {
+                               ci->slot_stat = 0;
+                               write_regm(ci, 0x03, 0x00, 0x08);
+                               printk(KERN_INFO "NO CAM\n");
+                               ci->ready = 0;
+                       }
+               }
+               if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
+                       ci->ready = 1;
+                       ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
+                       printk(KERN_INFO "READY\n");
+               }
+       }
+       return 0;
+}
+
+
+static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+       struct cxd *ci = ca->data;
+       u8 slotstat;
+
+       mutex_lock(&ci->lock);
+       campoll(ci);
+       read_reg(ci, 0x01, &slotstat);
+       mutex_unlock(&ci->lock);
+
+       return ci->slot_stat;
+}
+
+#ifdef BUFFER_MODE
+static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
+{
+       struct cxd *ci = ca->data;
+       u8 msb, lsb;
+       u16 len;
+
+       mutex_lock(&ci->lock);
+       campoll(ci);
+       mutex_unlock(&ci->lock);
+
+       printk(KERN_INFO "read_data\n");
+       if (!ci->dr)
+               return 0;
+
+       mutex_lock(&ci->lock);
+       read_reg(ci, 0x0f, &msb);
+       read_reg(ci, 0x10, &lsb);
+       len = (msb<<8)|lsb;
+       read_block(ci, 0x12, ebuf, len);
+       ci->dr = 0;
+       mutex_unlock(&ci->lock);
+
+       return len;
+}
+
+static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       printk(KERN_INFO "write_data %d\n", ecount);
+       write_reg(ci, 0x0d, ecount>>8);
+       write_reg(ci, 0x0e, ecount&0xff);
+       write_block(ci, 0x11, ebuf, ecount);
+       mutex_unlock(&ci->lock);
+       return ecount;
+}
+#endif
+
+static struct dvb_ca_en50221 en_templ = {
+       .read_attribute_mem  = read_attribute_mem,
+       .write_attribute_mem = write_attribute_mem,
+       .read_cam_control    = read_cam_control,
+       .write_cam_control   = write_cam_control,
+       .slot_reset          = slot_reset,
+       .slot_shutdown       = slot_shutdown,
+       .slot_ts_enable      = slot_ts_enable,
+       .poll_slot_status    = poll_slot_status,
+#ifdef BUFFER_MODE
+       .read_data           = read_data,
+       .write_data          = write_data,
+#endif
+
+};
+
+struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv,
+                                     struct i2c_adapter *i2c)
+{
+       struct cxd *ci = 0;
+       u32 bitrate = 62000000;
+       u8 val;
+
+       if (i2c_read_reg(i2c, adr, 0, &val) < 0) {
+               printk(KERN_ERR "No CXD2099 detected at %02x\n", adr);
+               return 0;
+       }
+
+       ci = kmalloc(sizeof(struct cxd), GFP_KERNEL);
+       if (!ci)
+               return 0;
+       memset(ci, 0, sizeof(*ci));
+
+       mutex_init(&ci->lock);
+       ci->i2c = i2c;
+       ci->adr = adr;
+       ci->lastaddress = 0xff;
+       ci->clk_reg_b = 0x4a;
+       ci->clk_reg_f = 0x1b;
+       ci->bitrate = bitrate;
+
+       memcpy(&ci->en, &en_templ, sizeof(en_templ));
+       ci->en.data = ci;
+       init(ci);
+       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr);
+       return &ci->en;
+}
+EXPORT_SYMBOL(cxd2099_attach);
+
+MODULE_DESCRIPTION("cxd2099");
+MODULE_AUTHOR("Ralph Metzler <rjkm@metzlerbros.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/cxd2099/cxd2099.h
new file mode 100644 (file)
index 0000000..bed54ff
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * cxd2099.h: Driver for the CXD2099AR Common Interface Controller
+ *
+ * Copyright (C) 2010 DigitalDevices UG
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _CXD2099_H_
+#define _CXD2099_H_
+
+#include <dvb_ca_en50221.h>
+
+#if defined(CONFIG_DVB_CXD2099) || \
+        (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
+struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/staging/dabusb/Kconfig b/drivers/staging/dabusb/Kconfig
deleted file mode 100644 (file)
index 87bdc42..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-config USB_DABUSB
-       tristate "DABUSB driver"
-       depends on USB
-       ---help---
-         A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
-         brought to you by the DAB-Team
-         <http://wwwbode.cs.tum.edu/Par/arch/dab/>.  This driver can be taken
-         as an example for URB-based bulk, control, and isochronous
-         transactions. URB's are explained in
-         <Documentation/usb/URB.txt>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dabusb.
-
diff --git a/drivers/staging/dabusb/Makefile b/drivers/staging/dabusb/Makefile
deleted file mode 100644 (file)
index 2ff2f22..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_USB_DABUSB)        += dabusb.o
-
diff --git a/drivers/staging/dabusb/TODO b/drivers/staging/dabusb/TODO
deleted file mode 100644 (file)
index f9c0314..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a driver for an experimental sample developed in 2003. The driver
-never supported any commercial product, nor had any known user.
-If nobody takes care on it, the driver will be removed for 2.6.39.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/dabusb/dabusb.c b/drivers/staging/dabusb/dabusb.c
deleted file mode 100644 (file)
index 21768a6..0000000
+++ /dev/null
@@ -1,926 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      dabusb.c  --  dab usb driver.
- *
- *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.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.
- *
- *      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.
- *
- *
- *
- *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/uaccess.h>
-#include <linux/atomic.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
-
-#include "dabusb.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.54"
-#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
-#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
-
-/* --------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define NRDABUSB 256
-#else
-#define NRDABUSB 4
-#endif
-
-/*-------------------------------------------------------------------*/
-
-static dabusb_t dabusb[NRDABUSB];
-static int buffers = 256;
-static struct usb_driver dabusb_driver;
-
-/*-------------------------------------------------------------------*/
-
-static int dabusb_add_buf_tail(pdabusb_t s, struct list_head *dst,
-                              struct list_head *src)
-{
-       unsigned long flags;
-       struct list_head *tmp;
-       int ret = 0;
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       if (list_empty(src)) {
-               /* no elements in source buffer */
-               ret = -1;
-               goto err;
-       }
-       tmp = src->next;
-       list_move_tail(tmp, dst);
-
-err:   spin_unlock_irqrestore(&s->lock, flags);
-       return ret;
-}
-/*-------------------------------------------------------------------*/
-#ifdef DEBUG
-static void dump_urb(struct urb *urb)
-{
-       dbg("urb                   :%p", urb);
-       dbg("dev                   :%p", urb->dev);
-       dbg("pipe                  :%08X", urb->pipe);
-       dbg("status                :%d", urb->status);
-       dbg("transfer_flags        :%08X", urb->transfer_flags);
-       dbg("transfer_buffer       :%p", urb->transfer_buffer);
-       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
-       dbg("actual_length         :%d", urb->actual_length);
-       dbg("setup_packet          :%p", urb->setup_packet);
-       dbg("start_frame           :%d", urb->start_frame);
-       dbg("number_of_packets     :%d", urb->number_of_packets);
-       dbg("interval              :%d", urb->interval);
-       dbg("error_count           :%d", urb->error_count);
-       dbg("context               :%p", urb->context);
-       dbg("complete              :%p", urb->complete);
-}
-#endif
-/*-------------------------------------------------------------------*/
-static int dabusb_cancel_queue(pdabusb_t s, struct list_head *q)
-{
-       unsigned long flags;
-       pbuff_t b;
-
-       dbg("dabusb_cancel_queue");
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       list_for_each_entry(b, q, buff_list) {
-#ifdef DEBUG
-               dump_urb(b->purb);
-#endif
-               usb_unlink_urb(b->purb);
-       }
-       spin_unlock_irqrestore(&s->lock, flags);
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_queue(struct list_head *q)
-{
-       struct list_head *tmp;
-       struct list_head *p;
-       pbuff_t b;
-
-       dbg("dabusb_free_queue");
-       for (p = q->next; p != q;) {
-               b = list_entry(p, buff_t, buff_list);
-
-#ifdef DEBUG
-               dump_urb(b->purb);
-#endif
-               kfree(b->purb->transfer_buffer);
-               usb_free_urb(b->purb);
-               tmp = p->next;
-               list_del(p);
-               kfree(b);
-               p = tmp;
-       }
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_buffers(pdabusb_t s)
-{
-       unsigned long flags;
-       dbg("dabusb_free_buffers");
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       dabusb_free_queue(&s->free_buff_list);
-       dabusb_free_queue(&s->rec_buff_list);
-
-       spin_unlock_irqrestore(&s->lock, flags);
-
-       s->got_mem = 0;
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static void dabusb_iso_complete(struct urb *purb)
-{
-       pbuff_t b = purb->context;
-       pdabusb_t s = b->s;
-       int i;
-       int len;
-       int dst = 0;
-       void *buf = purb->transfer_buffer;
-
-       dbg("dabusb_iso_complete");
-
-       /* process if URB was not killed */
-       if (purb->status != -ENOENT) {
-               unsigned int pipe = usb_rcvisocpipe(purb->dev, _DABUSB_ISOPIPE);
-               int pipesize = usb_maxpacket(purb->dev, pipe,
-                                            usb_pipeout(pipe));
-               for (i = 0; i < purb->number_of_packets; i++)
-                       if (!purb->iso_frame_desc[i].status) {
-                               len = purb->iso_frame_desc[i].actual_length;
-                               if (len <= pipesize) {
-                                       memcpy(buf + dst, buf + purb->iso_frame_desc[i].offset, len);
-                                       dst += len;
-                               } else
-                                       dev_err(&purb->dev->dev,
-                                               "dabusb_iso_complete: invalid len %d\n",
-                                               len);
-                       } else
-                               dev_warn(&purb->dev->dev,
-                                        "dabusb_iso_complete: corrupted packet status: %d\n",
-                                        purb->iso_frame_desc[i].status);
-               if (dst != purb->actual_length)
-                       dev_err(&purb->dev->dev,
-                               "dst!=purb->actual_length:%d!=%d\n",
-                                       dst, purb->actual_length);
-       }
-
-       if (atomic_dec_and_test(&s->pending_io) &&
-           !s->remove_pending && s->state != _stopped) {
-               s->overruns++;
-               dev_err(&purb->dev->dev, "overrun (%d)\n", s->overruns);
-       }
-       wake_up(&s->wait);
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_alloc_buffers(pdabusb_t s)
-{
-       int transfer_len = 0;
-       pbuff_t b;
-       unsigned int pipe = usb_rcvisocpipe(s->usbdev, _DABUSB_ISOPIPE);
-       int pipesize = usb_maxpacket(s->usbdev, pipe, usb_pipeout(pipe));
-       int packets = _ISOPIPESIZE / pipesize;
-       int transfer_buffer_length = packets * pipesize;
-       int i;
-
-       dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
-                pipesize, packets, transfer_buffer_length);
-
-       while (transfer_len < (s->total_buffer_size << 10)) {
-               b = kzalloc(sizeof(buff_t), GFP_KERNEL);
-               if (!b) {
-                       dev_err(&s->usbdev->dev,
-                               "kzalloc(sizeof(buff_t))==NULL\n");
-                       goto err;
-               }
-               b->s = s;
-               b->purb = usb_alloc_urb(packets, GFP_KERNEL);
-               if (!b->purb) {
-                       dev_err(&s->usbdev->dev, "usb_alloc_urb == NULL\n");
-                       kfree(b);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer = kmalloc(transfer_buffer_length,
-                                                  GFP_KERNEL);
-               if (!b->purb->transfer_buffer) {
-                       kfree(b->purb);
-                       kfree(b);
-                       dev_err(&s->usbdev->dev,
-                               "kmalloc(%d)==NULL\n", transfer_buffer_length);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer_length = transfer_buffer_length;
-               b->purb->number_of_packets = packets;
-               b->purb->complete = dabusb_iso_complete;
-               b->purb->context = b;
-               b->purb->dev = s->usbdev;
-               b->purb->pipe = pipe;
-               b->purb->transfer_flags = URB_ISO_ASAP;
-
-               for (i = 0; i < packets; i++) {
-                       b->purb->iso_frame_desc[i].offset = i * pipesize;
-                       b->purb->iso_frame_desc[i].length = pipesize;
-               }
-
-               transfer_len += transfer_buffer_length;
-               list_add_tail(&b->buff_list, &s->free_buff_list);
-       }
-       s->got_mem = transfer_len;
-
-       return 0;
-
-err:
-       dabusb_free_buffers(s);
-       return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_bulk(pdabusb_t s, pbulk_transfer_t pb)
-{
-       int ret;
-       unsigned int pipe;
-       int actual_length;
-
-       dbg("dabusb_bulk");
-
-       if (!pb->pipe)
-               pipe = usb_rcvbulkpipe(s->usbdev, 2);
-       else
-               pipe = usb_sndbulkpipe(s->usbdev, 2);
-
-       ret = usb_bulk_msg(s->usbdev, pipe, pb->data,
-                          pb->size, &actual_length, 100);
-       if (ret < 0) {
-               dev_err(&s->usbdev->dev,
-                       "usb_bulk_msg failed(%d)\n", ret);
-
-               if (usb_set_interface(s->usbdev, _DABUSB_IF, 1) < 0) {
-                       dev_err(&s->usbdev->dev, "set_interface failed\n");
-                       return -EINVAL;
-               }
-
-       }
-
-       if (ret == -EPIPE) {
-               dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");
-               if (usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
-                       dev_err(&s->usbdev->dev, "request failed\n");
-       }
-
-       pb->size = actual_length;
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_writemem(pdabusb_t s, int pos, const unsigned char *data,
-                           int len)
-{
-       int ret;
-       unsigned char *transfer_buffer =  kmalloc(len, GFP_KERNEL);
-
-       if (!transfer_buffer) {
-               dev_err(&s->usbdev->dev,
-                       "dabusb_writemem: kmalloc(%d) failed.\n", len);
-               return -ENOMEM;
-       }
-
-       memcpy(transfer_buffer, data, len);
-
-       ret = usb_control_msg(s->usbdev, usb_sndctrlpipe(s->usbdev, 0),
-                             0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
-
-       kfree(transfer_buffer);
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_8051_reset(pdabusb_t s, unsigned char reset_bit)
-{
-       dbg("dabusb_8051_reset: %d", reset_bit);
-       return dabusb_writemem(s, CPUCS_REG, &reset_bit, 1);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_loadmem(pdabusb_t s, const char *fname)
-{
-       int ret;
-       const struct ihex_binrec *rec;
-       const struct firmware *uninitialized_var(fw);
-
-       dbg("Enter dabusb_loadmem (internal)");
-
-       ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev);
-       if (ret) {
-               dev_err(&s->usbdev->dev,
-                       "Failed to load \"dabusb/firmware.fw\": %d\n", ret);
-               goto out;
-       }
-       ret = dabusb_8051_reset(s, 1);
-
-       for (rec = (const struct ihex_binrec *)fw->data; rec;
-            rec = ihex_next_binrec(rec)) {
-               dbg("dabusb_writemem: %04X %p %d)", be32_to_cpu(rec->addr),
-                   rec->data, be16_to_cpu(rec->len));
-
-               ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data,
-                                      be16_to_cpu(rec->len));
-               if (ret < 0) {
-                       dev_err(&s->usbdev->dev,
-                               "dabusb_writemem failed (%d %04X %p %d)\n",
-                               ret, be32_to_cpu(rec->addr),
-                               rec->data, be16_to_cpu(rec->len));
-                       break;
-               }
-       }
-       ret = dabusb_8051_reset(s, 0);
-       release_firmware(fw);
- out:
-       dbg("dabusb_loadmem: exit");
-
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_clear(pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2a;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_clear");
-
-       return dabusb_bulk(s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_init(pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2c;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_init");
-
-       return dabusb_bulk(s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_download(pdabusb_t s, const char *fname)
-{
-       pbulk_transfer_t b = kmalloc(sizeof(bulk_transfer_t), GFP_KERNEL);
-       const struct firmware *fw;
-       unsigned int blen, n;
-       int ret;
-
-       dbg("Enter dabusb_fpga_download (internal)");
-
-       if (!b) {
-               dev_err(&s->usbdev->dev,
-                       "kmalloc(sizeof(bulk_transfer_t))==NULL\n");
-               return -ENOMEM;
-       }
-
-       ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);
-       if (ret) {
-               dev_err(&s->usbdev->dev,
-                       "Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
-               kfree(b);
-               return ret;
-       }
-
-       b->pipe = 1;
-       ret = dabusb_fpga_clear(s, b);
-       mdelay(10);
-       blen = fw->data[73] + (fw->data[72] << 8);
-
-       dbg("Bitstream len: %i", blen);
-
-       b->data[0] = 0x2b;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 60;
-
-       for (n = 0; n <= blen + 60; n += 60) {
-               /* some cclks for startup */
-               b->size = 64;
-               memcpy(b->data + 4, fw->data + 74 + n, 60);
-               ret = dabusb_bulk(s, b);
-               if (ret < 0) {
-                       dev_err(&s->usbdev->dev, "dabusb_bulk failed.\n");
-                       break;
-               }
-               mdelay(1);
-       }
-
-       ret = dabusb_fpga_init(s, b);
-       kfree(b);
-       release_firmware(fw);
-
-       dbg("exit dabusb_fpga_download");
-
-       return ret;
-}
-
-static int dabusb_stop(pdabusb_t s)
-{
-       dbg("dabusb_stop");
-
-       s->state = _stopped;
-       dabusb_cancel_queue(s, &s->rec_buff_list);
-
-       dbg("pending_io: %d", s->pending_io.counter);
-
-       s->pending_io.counter = 0;
-       return 0;
-}
-
-static int dabusb_startrek(pdabusb_t s)
-{
-       if (!s->got_mem && s->state != _started) {
-
-               dbg("dabusb_startrek");
-
-               if (dabusb_alloc_buffers(s) < 0)
-                       return -ENOMEM;
-               dabusb_stop(s);
-               s->state = _started;
-               s->readptr = 0;
-       }
-
-       if (!list_empty(&s->free_buff_list)) {
-               pbuff_t end;
-               int ret;
-
-       while (!dabusb_add_buf_tail(s, &s->rec_buff_list, &s->free_buff_list)) {
-
-                       dbg("submitting: end:%p s->rec_buff_list:%p",
-                           s->rec_buff_list.prev, &s->rec_buff_list);
-
-                       end = list_entry(s->rec_buff_list.prev,
-                                        buff_t, buff_list);
-
-                       ret = usb_submit_urb(end->purb, GFP_KERNEL);
-                       if (ret) {
-                               dev_err(&s->usbdev->dev,
-                                       "usb_submit_urb returned:%d\n", ret);
-                               if (dabusb_add_buf_tail(s, &s->free_buff_list,
-                                                       &s->rec_buff_list))
-                                       dev_err(&s->usbdev->dev,
-                                               "startrek: dabusb_add_buf_tail failed\n");
-                               break;
-                       } else
-                               atomic_inc(&s->pending_io);
-               }
-               dbg("pending_io: %d", s->pending_io.counter);
-       }
-
-       return 0;
-}
-
-static ssize_t dabusb_read(struct file *file, char __user *buf,
-                          size_t count, loff_t *ppos)
-{
-       pdabusb_t s = (pdabusb_t)file->private_data;
-       unsigned long flags;
-       unsigned ret = 0;
-       int rem;
-       int cnt;
-       pbuff_t b;
-       struct urb *purb = NULL;
-
-       dbg("dabusb_read");
-
-       if (*ppos)
-               return -ESPIPE;
-
-       if (s->remove_pending)
-               return -EIO;
-
-
-       if (!s->usbdev)
-               return -EIO;
-
-       while (count > 0) {
-               dabusb_startrek(s);
-
-               spin_lock_irqsave(&s->lock, flags);
-
-               if (list_empty(&s->rec_buff_list)) {
-
-                       spin_unlock_irqrestore(&s->lock, flags);
-
-                       dev_err(&s->usbdev->dev,
-                               "error: rec_buf_list is empty\n");
-                       goto err;
-               }
-
-               b = list_entry(s->rec_buff_list.next, buff_t, buff_list);
-               purb = b->purb;
-
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               if (purb->status == -EINPROGRESS) {
-                       /* return nonblocking */
-                       if (file->f_flags & O_NONBLOCK) {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               goto err;
-                       }
-
-                       interruptible_sleep_on(&s->wait);
-
-                       if (signal_pending(current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               goto err;
-                       }
-
-                       spin_lock_irqsave(&s->lock, flags);
-
-                       if (list_empty(&s->rec_buff_list)) {
-                               spin_unlock_irqrestore(&s->lock, flags);
-                               dev_err(&s->usbdev->dev,
-                                       "error: still no buffer available.\n");
-                               goto err;
-                       }
-                       spin_unlock_irqrestore(&s->lock, flags);
-                       s->readptr = 0;
-               }
-               if (s->remove_pending) {
-                       ret = -EIO;
-                       goto err;
-               }
-
-               /* set remaining bytes to copy */
-               rem = purb->actual_length - s->readptr;
-
-               if (count >= rem)
-                       cnt = rem;
-               else
-                       cnt = count;
-
-               dbg("copy_to_user:%p %p %d", buf,
-                   purb->transfer_buffer + s->readptr, cnt);
-
-               if (copy_to_user(buf,
-                               purb->transfer_buffer + s->readptr,
-                               cnt)) {
-                       dev_err(&s->usbdev->dev, "read: copy_to_user failed\n");
-                       if (!ret)
-                               ret = -EFAULT;
-                       goto err;
-               }
-
-               s->readptr += cnt;
-               count -= cnt;
-               buf += cnt;
-               ret += cnt;
-
-               if (s->readptr == purb->actual_length) {
-                       /* finished, take next buffer */
-                       if (dabusb_add_buf_tail(s, &s->free_buff_list,
-                                               &s->rec_buff_list))
-                               dev_err(&s->usbdev->dev,
-                                       "read: dabusb_add_buf_tail failed\n");
-                       s->readptr = 0;
-               }
-       }
-err:                   /*mutex_unlock(&s->mutex);*/
-       return ret;
-}
-
-static int dabusb_open(struct inode *inode, struct file *file)
-{
-       int devnum = iminor(inode);
-       pdabusb_t s;
-       int r;
-
-       if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
-               return -EIO;
-
-       s = &dabusb[devnum - DABUSB_MINOR];
-
-       dbg("dabusb_open");
-       mutex_lock(&s->mutex);
-
-       while (!s->usbdev || s->opened) {
-               mutex_unlock(&s->mutex);
-
-               if (file->f_flags & O_NONBLOCK)
-                       return -EBUSY;
-               msleep_interruptible(500);
-
-               if (signal_pending(current))
-                       return -EAGAIN;
-               mutex_lock(&s->mutex);
-       }
-       if (usb_set_interface(s->usbdev, _DABUSB_IF, 1) < 0) {
-               mutex_unlock(&s->mutex);
-               dev_err(&s->usbdev->dev, "set_interface failed\n");
-               return -EINVAL;
-       }
-       s->opened = 1;
-       mutex_unlock(&s->mutex);
-
-       file->f_pos = 0;
-       file->private_data = s;
-
-       r = nonseekable_open(inode, file);
-       return r;
-}
-
-static int dabusb_release(struct inode *inode, struct file *file)
-{
-       pdabusb_t s = (pdabusb_t)file->private_data;
-
-       dbg("dabusb_release");
-
-       mutex_lock(&s->mutex);
-       dabusb_stop(s);
-       dabusb_free_buffers(s);
-       mutex_unlock(&s->mutex);
-
-       if (!s->remove_pending) {
-               if (usb_set_interface(s->usbdev, _DABUSB_IF, 0) < 0)
-                       dev_err(&s->usbdev->dev, "set_interface failed\n");
-       } else
-               wake_up(&s->remove_ok);
-
-       s->opened = 0;
-       return 0;
-}
-
-static long dabusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       pdabusb_t s = (pdabusb_t)file->private_data;
-       pbulk_transfer_t pbulk;
-       int ret = 0;
-       int version = DABUSB_VERSION;
-
-       dbg("dabusb_ioctl");
-
-       if (s->remove_pending)
-               return -EIO;
-
-       mutex_lock(&s->mutex);
-
-       if (!s->usbdev) {
-               mutex_unlock(&s->mutex);
-               return -EIO;
-       }
-
-       switch (cmd) {
-
-       case IOCTL_DAB_BULK:
-               pbulk = memdup_user((void __user *)arg,
-                                   sizeof(bulk_transfer_t));
-
-               if (IS_ERR(pbulk)) {
-                       ret = PTR_ERR(pbulk);
-                       break;
-               }
-
-               ret = dabusb_bulk(s, pbulk);
-               if (ret == 0)
-                       if (copy_to_user((void __user *)arg, pbulk,
-                                        sizeof(bulk_transfer_t)))
-                               ret = -EFAULT;
-               kfree(pbulk);
-               break;
-
-       case IOCTL_DAB_OVERRUNS:
-               ret = put_user(s->overruns, (unsigned int __user *) arg);
-               break;
-
-       case IOCTL_DAB_VERSION:
-               ret = put_user(version, (unsigned int __user *) arg);
-               break;
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       mutex_unlock(&s->mutex);
-       return ret;
-}
-
-static const struct file_operations dabusb_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .read =         dabusb_read,
-       .unlocked_ioctl =       dabusb_ioctl,
-       .open =         dabusb_open,
-       .release =      dabusb_release,
-};
-
-static char *dabusb_devnode(struct device *dev, mode_t *mode)
-{
-       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
-}
-
-static struct usb_class_driver dabusb_class = {
-       .name =         "dabusb%d",
-       .devnode =      dabusb_devnode,
-       .fops =         &dabusb_fops,
-       .minor_base =   DABUSB_MINOR,
-};
-
-
-/* --------------------------------------------------------------------- */
-static int dabusb_probe(struct usb_interface *intf,
-                        const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       int retval;
-       pdabusb_t s;
-
-       dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
-           le16_to_cpu(usbdev->descriptor.idVendor),
-           le16_to_cpu(usbdev->descriptor.idProduct),
-           intf->altsetting->desc.bInterfaceNumber);
-
-       /* We don't handle multiple configurations */
-       if (usbdev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
-           le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
-               return -ENODEV;
-
-
-
-       s = &dabusb[intf->minor];
-
-       mutex_lock(&s->mutex);
-       s->remove_pending = 0;
-       s->usbdev = usbdev;
-       s->devnum = intf->minor;
-
-       if (usb_reset_configuration(usbdev) < 0) {
-               dev_err(&intf->dev, "reset_configuration failed\n");
-               goto reject;
-       }
-       if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
-               dabusb_loadmem(s, NULL);
-               goto reject;
-       } else {
-               dabusb_fpga_download(s, NULL);
-
-               if (usb_set_interface(s->usbdev, _DABUSB_IF, 0) < 0) {
-                       dev_err(&intf->dev, "set_interface failed\n");
-                       goto reject;
-               }
-       }
-       dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
-       usb_set_intfdata(intf, s);
-       mutex_unlock(&s->mutex);
-
-       retval = usb_register_dev(intf, &dabusb_class);
-       if (retval) {
-               usb_set_intfdata(intf, NULL);
-               return -ENOMEM;
-       }
-
-       return 0;
-
-reject:
-       mutex_unlock(&s->mutex);
-       s->usbdev = NULL;
-       return -ENODEV;
-}
-
-static void dabusb_disconnect(struct usb_interface *intf)
-{
-       wait_queue_t __wait;
-       pdabusb_t s = usb_get_intfdata(intf);
-
-       dbg("dabusb_disconnect");
-
-       init_waitqueue_entry(&__wait, current);
-
-       usb_set_intfdata(intf, NULL);
-       if (s) {
-               usb_deregister_dev(intf, &dabusb_class);
-               s->remove_pending = 1;
-               wake_up(&s->wait);
-               add_wait_queue(&s->remove_ok, &__wait);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               if (s->state == _started)
-                       schedule();
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&s->remove_ok, &__wait);
-
-               s->usbdev = NULL;
-               s->overruns = 0;
-       }
-}
-
-static struct usb_device_id dabusb_ids[] = {
-       /* { USB_DEVICE(0x0547, 0x2131) },*/    /* An2131 chip, no boot ROM */
-       { USB_DEVICE(0x0547, 0x9999) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, dabusb_ids);
-
-static struct usb_driver dabusb_driver = {
-       .name =         "dabusb",
-       .probe =        dabusb_probe,
-       .disconnect =   dabusb_disconnect,
-       .id_table =     dabusb_ids,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init dabusb_init(void)
-{
-       int retval;
-       unsigned u;
-
-       /* initialize struct */
-       for (u = 0; u < NRDABUSB; u++) {
-               pdabusb_t s = &dabusb[u];
-               memset(s, 0, sizeof(dabusb_t));
-               mutex_init(&s->mutex);
-               s->usbdev = NULL;
-               s->total_buffer_size = buffers;
-               init_waitqueue_head(&s->wait);
-               init_waitqueue_head(&s->remove_ok);
-               spin_lock_init(&s->lock);
-               INIT_LIST_HEAD(&s->free_buff_list);
-               INIT_LIST_HEAD(&s->rec_buff_list);
-       }
-
-       /* register misc device */
-       retval = usb_register(&dabusb_driver);
-       if (retval)
-               goto out;
-
-       dbg("dabusb_init: driver registered");
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
-
-out:
-       return retval;
-}
-
-static void __exit dabusb_cleanup(void)
-{
-       dbg("dabusb_cleanup");
-
-       usb_deregister(&dabusb_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("dabusb/firmware.fw");
-MODULE_FIRMWARE("dabusb/bitstream.bin");
-
-module_param(buffers, int, 0);
-MODULE_PARM_DESC(buffers, "Number of buffers (default=256)");
-
-module_init(dabusb_init);
-module_exit(dabusb_cleanup);
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/staging/dabusb/dabusb.h b/drivers/staging/dabusb/dabusb.h
deleted file mode 100644 (file)
index c1772ef..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#define _BULK_DATA_LEN 64
-typedef struct {
-       unsigned char data[_BULK_DATA_LEN];
-       unsigned int size;
-       unsigned int pipe;
-} bulk_transfer_t, *pbulk_transfer_t;
-
-#define DABUSB_MINOR 240               /* some unassigned USB minor */
-#define DABUSB_VERSION 0x1000
-#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
-#define IOCTL_DAB_OVERRUNS         _IOR('d',  0x15, int)
-#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int)
-
-#ifdef __KERNEL__
-
-typedef enum { _stopped = 0, _started } driver_state_t;
-
-typedef struct {
-       struct mutex mutex;
-       struct usb_device *usbdev;
-       wait_queue_head_t wait;
-       wait_queue_head_t remove_ok;
-       spinlock_t lock;
-       atomic_t pending_io;
-       driver_state_t state;
-       int remove_pending;
-       int got_mem;
-       int total_buffer_size;
-       unsigned int overruns;
-       int readptr;
-       int opened;
-       int devnum;
-       struct list_head free_buff_list;
-       struct list_head rec_buff_list;
-} dabusb_t, *pdabusb_t;
-
-typedef struct {
-       pdabusb_t s;
-       struct urb *purb;
-       struct list_head buff_list;
-} buff_t, *pbuff_t;
-
-typedef struct {
-       wait_queue_head_t wait;
-} bulk_completion_context_t, *pbulk_completion_context_t;
-
-
-#define _DABUSB_IF 2
-#define _DABUSB_ISOPIPE 0x09
-#define _ISOPIPESIZE   16384
-
-#define _BULK_DATA_LEN 64
-/* Vendor specific request code for Anchor Upload/Download
- *This one is implemented in the core */
-#define ANCHOR_LOAD_INTERNAL  0xA0
-
-/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
-#define CPUCS_REG    0x7F92
-#define _TOTAL_BUFFERS 384
-
-#define MAX_INTEL_HEX_RECORD_LENGTH 16
-
-#ifndef _BYTE_DEFINED
-#define _BYTE_DEFINED
-typedef unsigned char BYTE;
-#endif /* !_BYTE_DEFINED */
-
-#ifndef _WORD_DEFINED
-#define _WORD_DEFINED
-typedef unsigned short WORD;
-#endif /* !_WORD_DEFINED */
-
-typedef struct _INTEL_HEX_RECORD {
-       BYTE  Length;
-       WORD  Address;
-       BYTE  Type;
-       BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
-} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
-
-#endif
index 28a28e02c9ce14df3d55ad06f5b54e48f67cbd0d..b3bd11d5879f67d1b42ba1907d31e829a361db56 100644 (file)
@@ -1391,8 +1391,7 @@ long easycap_unlocked_ioctl(struct file *file,
                break;
        }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_CTRL:
-       {
+       case VIDIOC_S_CTRL: {
                struct v4l2_control v4l2_control;
 
                JOM(8, "VIDIOC_S_CTRL\n");
index 6e02f1b0c46fc9574874d2a68a1b2dffd2e456f3..af789937be4ed8fd48a5041739290c290122d7c2 100644 (file)
@@ -124,7 +124,8 @@ static void blkvsc_shutdown(struct device *device);
 
 static int blkvsc_open(struct block_device *bdev,  fmode_t mode);
 static int blkvsc_release(struct gendisk *disk, fmode_t mode);
-static int blkvsc_media_changed(struct gendisk *gd);
+static unsigned int blkvsc_check_events(struct gendisk *gd,
+                                       unsigned int clearing);
 static int blkvsc_revalidate_disk(struct gendisk *gd);
 static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg);
 static int blkvsc_ioctl(struct block_device *bd, fmode_t mode,
@@ -155,7 +156,7 @@ static const struct block_device_operations block_ops = {
        .owner = THIS_MODULE,
        .open = blkvsc_open,
        .release = blkvsc_release,
-       .media_changed = blkvsc_media_changed,
+       .check_events = blkvsc_check_events,
        .revalidate_disk = blkvsc_revalidate_disk,
        .getgeo = blkvsc_getgeo,
        .ioctl  = blkvsc_ioctl,
@@ -357,6 +358,7 @@ static int blkvsc_probe(struct device *device)
        else
                blkdev->gd->first_minor = 0;
        blkdev->gd->fops = &block_ops;
+       blkdev->gd->events = DISK_EVENT_MEDIA_CHANGE;
        blkdev->gd->private_data = blkdev;
        blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
        sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum);
@@ -1337,10 +1339,11 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode)
        return 0;
 }
 
-static int blkvsc_media_changed(struct gendisk *gd)
+static unsigned int blkvsc_check_events(struct gendisk *gd,
+                                       unsigned int clearing)
 {
        DPRINT_DBG(BLKVSC_DRV, "- enter\n");
-       return 1;
+       return DISK_EVENT_MEDIA_CHANGE;
 }
 
 static int blkvsc_revalidate_disk(struct gendisk *gd)
index cdaff5903a8fd1bc76c73a1b96b3f4337f6c2358..526ec0fc2f042703b0237d9e29887dfd47fb23f8 100644 (file)
@@ -32,18 +32,6 @@ config LIRC_IMON
 
          Current generation iMON devices use the input layer imon driver.
 
-config LIRC_IT87
-       tristate "ITE IT87XX CIR Port Receiver"
-       depends on LIRC && PNP
-       help
-         Driver for the ITE IT87xx IR Receiver
-
-config LIRC_ITE8709
-       tristate "ITE8709 CIR Port Receiver"
-       depends on LIRC && PNP
-       help
-         Driver for the ITE8709 IR Receiver
-
 config LIRC_PARALLEL
        tristate "Homebrew Parallel Port Receiver"
        depends on LIRC && PARPORT
index 94af218d837338c34dcaaa1d8b88d68db59aa262..d76b0fa2af53413bbfe4b318fda00e0beb060a73 100644 (file)
@@ -6,8 +6,6 @@
 obj-$(CONFIG_LIRC_BT829)       += lirc_bt829.o
 obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
 obj-$(CONFIG_LIRC_IMON)                += lirc_imon.o
-obj-$(CONFIG_LIRC_IT87)                += lirc_it87.o
-obj-$(CONFIG_LIRC_ITE8709)     += lirc_ite8709.o
 obj-$(CONFIG_LIRC_PARALLEL)    += lirc_parallel.o
 obj-$(CONFIG_LIRC_SASEM)       += lirc_sasem.o
 obj-$(CONFIG_LIRC_SERIAL)      += lirc_serial.o
index 2d0263f07937be78af2c3e8717c4c19a4c36c6b3..a97800a8e12718a65225692a128c91cffb2728fe 100644 (file)
@@ -1,34 +1,33 @@
-1. Both ir-kbd-i2c and lirc_zilog provide support for RX events.
-The 'tx_only' lirc_zilog module parameter will allow ir-kbd-i2c
-and lirc_zilog to coexist in the kernel, if the user requires such a set-up.
-However the IR unit will not work well without coordination between the
-two modules.  A shared mutex, for transceiver access locking, needs to be
-supplied by bridge drivers, in struct IR_i2_init_data, to both ir-kbd-i2c
-and lirc_zilog, before they will coexist usefully.  This should be fixed
-before moving out of staging.
-
-2. References and locking need careful examination.  For cx18 and ivtv PCI
-cards, which are not easily "hot unplugged", the imperfect state of reference
-counting and locking is acceptable if not correct.  For USB connected units
-like HD PVR, PVR USB2, HVR-1900, and HVR1950, the likelyhood of an Ooops on
-unplug is probably great.  Proper reference counting and locking needs to be
-implemented before this module is moved out of staging.
-
-3. The binding between hdpvr and lirc_zilog is currently disabled,
-due to an OOPS reported a few years ago when both the hdpvr and cx18
-drivers were loaded in his system. More details can be seen at:
-       http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html
-More tests need to be done, in order to fix the reported issue.
-
-4. In addition to providing a shared mutex for transceiver access
-locking, bridge drivers, if able, should provide a chip reset() callback
+1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for
+the chips supported by lirc_zilog.  Before moving lirc_zilog out of staging:
+
+a. ir-kbd-i2c needs a module parameter added to allow the user to tell
+   ir-kbd-i2c to ignore Z8 IR units.
+
+b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c
+   does.
+
+
+2. lirc_zilog module ref-counting need examination.  It has not been
+verified that cdev and lirc_dev will take the proper module references on
+lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node
+is open.
+
+(The good news is ref-counting of lirc_zilog internal structures appears to be
+complete.  Testing has shown the cx18 module can be unloaded out from under
+irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse
+effects.  The cx18 module could then be reloaded and irw properly began
+receiving button presses again and ir_send worked without error.)
+
+
+3. Bridge drivers, if able, should provide a chip reset() callback
 to lirc_zilog via struct IR_i2c_init_data.  cx18 and ivtv already have routines
-to perform Z8 chip resets via GPIO manipulations.  This will allow lirc_zilog
+to perform Z8 chip resets via GPIO manipulations.  This would allow lirc_zilog
 to bring the chip back to normal when it hangs, in the same places the
 original lirc_pvr150 driver code does.  This is not strictly needed, so it
 is not required to move lirc_zilog out of staging.
 
-5. Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
+Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
 and installed on Hauppauge products.  When working on either module, developers
 must consider at least the following bridge drivers which mention an IR Rx unit
 at address 0x71 (indicative of a Z8):
index 235cab0eb0877483267fac5dbdf6c75364a5f59e..4039eda2a15ba9cb769b1d5588e9a6a09aa4f56a 100644 (file)
@@ -379,7 +379,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
        struct imon_context *context;
        const unsigned char vfd_packet6[] = {
                0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
-       int *data_buf;
+       int *data_buf = NULL;
 
        context = file->private_data;
        if (!context) {
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
deleted file mode 100644 (file)
index 5938616..0000000
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
- * LIRC driver for ITE IT8712/IT8705 CIR port
- *
- * Copyright (C) 2001 Hans-Gunter Lutke Uphues <hg_lu@web.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.
- *
- * 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
- *
- * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based
- * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula
- *
- * Attention: Sendmode only tested with debugging logs
- *
- * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
- *   reimplemented read function
- * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix,
- *   based on work of the following member of the Outertrack Digimatrix
- *   Forum: Art103 <r_tay@hotmail.com>
- * 2009/12/24 James Edwards <jimbo-lirc@edwardsclan.net> implemeted support
- *   for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the
- *   chip identifies as 18.
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <asm/system.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/fcntl.h>
-
-#include <linux/timer.h>
-#include <linux/pnp.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#include "lirc_it87.h"
-
-#ifdef LIRC_IT87_DIGIMATRIX
-static int digimatrix = 1;
-static int it87_freq = 36; /* kHz */
-static int irq = 9;
-#else
-static int digimatrix;
-static int it87_freq = 38; /* kHz */
-static int irq = IT87_CIR_DEFAULT_IRQ;
-#endif
-
-static unsigned long it87_bits_in_byte_out;
-static unsigned long it87_send_counter;
-static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN;
-
-#define RBUF_LEN 1024
-
-#define LIRC_DRIVER_NAME "lirc_it87"
-
-/* timeout for sequences in jiffies (=5/100s) */
-/* must be longer than TIME_CONST */
-#define IT87_TIMEOUT   (HZ*5/100)
-
-/* module parameters */
-static int debug;
-#define dprintk(fmt, args...)                                  \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
-                              fmt, ## args);                   \
-       } while (0)
-
-static int io = IT87_CIR_DEFAULT_IOBASE;
-/* receiver demodulator default: off */
-static int it87_enable_demodulator;
-
-static int timer_enabled;
-static DEFINE_SPINLOCK(timer_lock);
-static struct timer_list timerlist;
-/* time of last signal change detected */
-static struct timeval last_tv = {0, 0};
-/* time of last UART data ready interrupt */
-static struct timeval last_intr_tv = {0, 0};
-static int last_value;
-
-static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
-
-static DEFINE_SPINLOCK(hardware_lock);
-static DEFINE_SPINLOCK(dev_lock);
-static bool device_open;
-
-static int rx_buf[RBUF_LEN];
-unsigned int rx_tail, rx_head;
-
-static struct pnp_driver it87_pnp_driver;
-
-/* SECTION: Prototypes */
-
-/* Communication with user-space */
-static int lirc_open(struct inode *inode, struct file *file);
-static int lirc_close(struct inode *inode, struct file *file);
-static unsigned int lirc_poll(struct file *file, poll_table *wait);
-static ssize_t lirc_read(struct file *file, char *buf,
-                        size_t count, loff_t *ppos);
-static ssize_t lirc_write(struct file *file, const char *buf,
-                         size_t n, loff_t *pos);
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
-static void add_read_queue(int flag, unsigned long val);
-static int init_chrdev(void);
-static void drop_chrdev(void);
-/* Hardware */
-static irqreturn_t it87_interrupt(int irq, void *dev_id);
-static void send_space(unsigned long len);
-static void send_pulse(unsigned long len);
-static void init_send(void);
-static void terminate_send(unsigned long len);
-static int init_hardware(void);
-static void drop_hardware(void);
-/* Initialisation */
-static int init_port(void);
-static void drop_port(void);
-
-
-/* SECTION: Communication with user-space */
-
-static int lirc_open(struct inode *inode, struct file *file)
-{
-       spin_lock(&dev_lock);
-       if (device_open) {
-               spin_unlock(&dev_lock);
-               return -EBUSY;
-       }
-       device_open = true;
-       spin_unlock(&dev_lock);
-       return 0;
-}
-
-
-static int lirc_close(struct inode *inode, struct file *file)
-{
-       spin_lock(&dev_lock);
-       device_open = false;
-       spin_unlock(&dev_lock);
-       return 0;
-}
-
-
-static unsigned int lirc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lirc_read_queue, wait);
-       if (rx_head != rx_tail)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-
-static ssize_t lirc_read(struct file *file, char *buf,
-                        size_t count, loff_t *ppos)
-{
-       int n = 0;
-       int retval = 0;
-
-       while (n < count) {
-               if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               retval = wait_event_interruptible(lirc_read_queue,
-                                                 rx_head != rx_tail);
-               if (retval)
-                       break;
-
-               if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head),
-                                sizeof(int))) {
-                       retval = -EFAULT;
-                       break;
-               }
-               rx_head = (rx_head + 1) & (RBUF_LEN - 1);
-               n += sizeof(int);
-       }
-       if (n)
-               return n;
-       return retval;
-}
-
-
-static ssize_t lirc_write(struct file *file, const char *buf,
-                         size_t n, loff_t *pos)
-{
-       int i = 0;
-       int *tx_buf;
-
-       if (n % sizeof(int))
-               return -EINVAL;
-       tx_buf = memdup_user(buf, n);
-       if (IS_ERR(tx_buf))
-               return PTR_ERR(tx_buf);
-       n /= sizeof(int);
-       init_send();
-       while (1) {
-               if (i >= n)
-                       break;
-               if (tx_buf[i])
-                       send_pulse(tx_buf[i]);
-               i++;
-               if (i >= n)
-                       break;
-               if (tx_buf[i])
-                       send_space(tx_buf[i]);
-               i++;
-       }
-       terminate_send(tx_buf[i - 1]);
-       kfree(tx_buf);
-       return n;
-}
-
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       int retval = 0;
-       __u32 value = 0;
-       unsigned long hw_flags;
-
-       if (cmd == LIRC_GET_FEATURES)
-               value = LIRC_CAN_SEND_PULSE |
-                       LIRC_CAN_SET_SEND_CARRIER |
-                       LIRC_CAN_REC_MODE2;
-       else if (cmd == LIRC_GET_SEND_MODE)
-               value = LIRC_MODE_PULSE;
-       else if (cmd == LIRC_GET_REC_MODE)
-               value = LIRC_MODE_MODE2;
-
-       switch (cmd) {
-       case LIRC_GET_FEATURES:
-       case LIRC_GET_SEND_MODE:
-       case LIRC_GET_REC_MODE:
-               retval = put_user(value, (__u32 *) arg);
-               break;
-
-       case LIRC_SET_SEND_MODE:
-       case LIRC_SET_REC_MODE:
-               retval = get_user(value, (__u32 *) arg);
-               break;
-
-       case LIRC_SET_SEND_CARRIER:
-               retval = get_user(value, (__u32 *) arg);
-               if (retval)
-                       return retval;
-               value /= 1000;
-               if (value > IT87_CIR_FREQ_MAX ||
-                   value < IT87_CIR_FREQ_MIN)
-                       return -EINVAL;
-
-               it87_freq = value;
-
-               spin_lock_irqsave(&hardware_lock, hw_flags);
-               outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) |
-                     (it87_freq - IT87_CIR_FREQ_MIN) << 3),
-                     io + IT87_CIR_TCR2);
-               spin_unlock_irqrestore(&hardware_lock, hw_flags);
-               dprintk("demodulation frequency: %d kHz\n", it87_freq);
-
-               break;
-
-       default:
-               retval = -EINVAL;
-       }
-
-       if (retval)
-               return retval;
-
-       if (cmd == LIRC_SET_REC_MODE) {
-               if (value != LIRC_MODE_MODE2)
-                       retval = -ENOSYS;
-       } else if (cmd == LIRC_SET_SEND_MODE) {
-               if (value != LIRC_MODE_PULSE)
-                       retval = -ENOSYS;
-       }
-       return retval;
-}
-
-static void add_read_queue(int flag, unsigned long val)
-{
-       unsigned int new_rx_tail;
-       int newval;
-
-       dprintk("add flag %d with val %lu\n", flag, val);
-
-       newval = val & PULSE_MASK;
-
-       /*
-        * statistically, pulses are ~TIME_CONST/2 too long. we could
-        * maybe make this more exact, but this is good enough
-        */
-       if (flag) {
-               /* pulse */
-               if (newval > TIME_CONST / 2)
-                       newval -= TIME_CONST / 2;
-               else /* should not ever happen */
-                       newval = 1;
-               newval |= PULSE_BIT;
-       } else
-               newval += TIME_CONST / 2;
-       new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
-       if (new_rx_tail == rx_head) {
-               dprintk("Buffer overrun.\n");
-               return;
-       }
-       rx_buf[rx_tail] = newval;
-       rx_tail = new_rx_tail;
-       wake_up_interruptible(&lirc_read_queue);
-}
-
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .read           = lirc_read,
-       .write          = lirc_write,
-       .poll           = lirc_poll,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .open           = lirc_open,
-       .release        = lirc_close,
-       .llseek         = noop_llseek,
-};
-
-static int set_use_inc(void *data)
-{
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-}
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-
-static int init_chrdev(void)
-{
-       driver.minor = lirc_register_driver(&driver);
-
-       if (driver.minor < 0) {
-               printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-
-static void drop_chrdev(void)
-{
-       lirc_unregister_driver(driver.minor);
-}
-
-
-/* SECTION: Hardware */
-static long delta(struct timeval *tv1, struct timeval *tv2)
-{
-       unsigned long deltv;
-
-       deltv = tv2->tv_sec - tv1->tv_sec;
-       if (deltv > 15)
-               deltv = 0xFFFFFF;
-       else
-               deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec;
-       return deltv;
-}
-
-static void it87_timeout(unsigned long data)
-{
-       unsigned long flags;
-
-       /* avoid interference with interrupt */
-       spin_lock_irqsave(&timer_lock, flags);
-
-       if (digimatrix) {
-               /* We have timed out. Disable the RX mechanism. */
-
-               outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) |
-                    IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR);
-               if (it87_RXEN_mask)
-                       outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
-                            io + IT87_CIR_RCR);
-               dprintk(" TIMEOUT\n");
-               timer_enabled = 0;
-
-               /* fifo clear */
-               outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR,
-                    io+IT87_CIR_TCR1);
-
-       } else {
-               /*
-                * if last received signal was a pulse, but receiving stopped
-                * within the 9 bit frame, we need to finish this pulse and
-                * simulate a signal change to from pulse to space. Otherwise
-                * upper layers will receive two sequences next time.
-                */
-
-               if (last_value) {
-                       unsigned long pulse_end;
-
-                       /* determine 'virtual' pulse end: */
-                       pulse_end = delta(&last_tv, &last_intr_tv);
-                       dprintk("timeout add %d for %lu usec\n",
-                               last_value, pulse_end);
-                       add_read_queue(last_value, pulse_end);
-                       last_value = 0;
-                       last_tv = last_intr_tv;
-               }
-       }
-       spin_unlock_irqrestore(&timer_lock, flags);
-}
-
-static irqreturn_t it87_interrupt(int irq, void *dev_id)
-{
-       unsigned char data;
-       struct timeval curr_tv;
-       static unsigned long deltv;
-       unsigned long deltintrtv;
-       unsigned long flags, hw_flags;
-       int iir, lsr;
-       int fifo = 0;
-       static char lastbit;
-       char bit;
-
-       /* Bit duration in microseconds */
-       const unsigned long bit_duration = 1000000ul /
-               (115200 / IT87_CIR_BAUDRATE_DIVISOR);
-
-
-       iir = inb(io + IT87_CIR_IIR);
-
-       switch (iir & IT87_CIR_IIR_IID) {
-       case 0x4:
-       case 0x6:
-               lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO |
-                                               IT87_CIR_RSR_RXFBC);
-               fifo = lsr & IT87_CIR_RSR_RXFBC;
-               dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr);
-
-               /* avoid interference with timer */
-               spin_lock_irqsave(&timer_lock, flags);
-               spin_lock_irqsave(&hardware_lock, hw_flags);
-               if (digimatrix) {
-                       static unsigned long acc_pulse;
-                       static unsigned long acc_space;
-
-                       do {
-                               data = inb(io + IT87_CIR_DR);
-                               data = ~data;
-                               fifo--;
-                               if (data != 0x00) {
-                                       if (timer_enabled)
-                                               del_timer(&timerlist);
-                                       /*
-                                        * start timer for end of
-                                        * sequence detection
-                                        */
-                                       timerlist.expires = jiffies +
-                                                           IT87_TIMEOUT;
-                                       add_timer(&timerlist);
-                                       timer_enabled = 1;
-                               }
-                               /* Loop through */
-                               for (bit = 0; bit < 8; ++bit) {
-                                       if ((data >> bit) & 1) {
-                                               ++acc_pulse;
-                                               if (lastbit == 0) {
-                                                       add_read_queue(0,
-                                                               acc_space *
-                                                                bit_duration);
-                                                       acc_space = 0;
-                                               }
-                                       } else {
-                                               ++acc_space;
-                                               if (lastbit == 1) {
-                                                       add_read_queue(1,
-                                                               acc_pulse *
-                                                                bit_duration);
-                                                       acc_pulse = 0;
-                                               }
-                                       }
-                                       lastbit = (data >> bit) & 1;
-                               }
-
-                       } while (fifo != 0);
-               } else { /* Normal Operation */
-                       do {
-                               del_timer(&timerlist);
-                               data = inb(io + IT87_CIR_DR);
-
-                               dprintk("data=%02x\n", data);
-                               do_gettimeofday(&curr_tv);
-                               deltv = delta(&last_tv, &curr_tv);
-                               deltintrtv = delta(&last_intr_tv, &curr_tv);
-
-                               dprintk("t %lu , d %d\n",
-                                       deltintrtv, (int)data);
-
-                               /*
-                                * if nothing came in last 2 cycles,
-                                * it was gap
-                                */
-                               if (deltintrtv > TIME_CONST * 2) {
-                                       if (last_value) {
-                                               dprintk("GAP\n");
-
-                                               /* simulate signal change */
-                                               add_read_queue(last_value,
-                                                              deltv -
-                                                              deltintrtv);
-                                               last_value = 0;
-                                               last_tv.tv_sec =
-                                                       last_intr_tv.tv_sec;
-                                               last_tv.tv_usec =
-                                                       last_intr_tv.tv_usec;
-                                               deltv = deltintrtv;
-                                       }
-                               }
-                               data = 1;
-                               if (data ^ last_value) {
-                                       /*
-                                        * deltintrtv > 2*TIME_CONST,
-                                        * remember ? the other case is
-                                        * timeout
-                                        */
-                                       add_read_queue(last_value,
-                                                      deltv-TIME_CONST);
-                                       last_value = data;
-                                       last_tv = curr_tv;
-                                       if (last_tv.tv_usec >= TIME_CONST)
-                                               last_tv.tv_usec -= TIME_CONST;
-                                       else {
-                                               last_tv.tv_sec--;
-                                               last_tv.tv_usec += 1000000 -
-                                                       TIME_CONST;
-                                       }
-                               }
-                               last_intr_tv = curr_tv;
-                               if (data) {
-                                       /*
-                                        * start timer for end of
-                                        * sequence detection
-                                        */
-                                       timerlist.expires =
-                                               jiffies + IT87_TIMEOUT;
-                                       add_timer(&timerlist);
-                               }
-                               outb((inb(io + IT87_CIR_RCR) &
-                                    ~IT87_CIR_RCR_RXEN) |
-                                    IT87_CIR_RCR_RXACT,
-                                    io + IT87_CIR_RCR);
-                               if (it87_RXEN_mask)
-                                       outb(inb(io + IT87_CIR_RCR) |
-                                            IT87_CIR_RCR_RXEN,
-                                            io + IT87_CIR_RCR);
-                               fifo--;
-                       } while (fifo != 0);
-               }
-               spin_unlock_irqrestore(&hardware_lock, hw_flags);
-               spin_unlock_irqrestore(&timer_lock, flags);
-
-               return IRQ_RETVAL(IRQ_HANDLED);
-
-       default:
-               /* not our irq */
-               dprintk("unknown IRQ (shouldn't happen) !!\n");
-               return IRQ_RETVAL(IRQ_NONE);
-       }
-}
-
-
-static void send_it87(unsigned long len, unsigned long stime,
-                     unsigned char send_byte, unsigned int count_bits)
-{
-       long count = len / stime;
-       long time_left = 0;
-       static unsigned char byte_out;
-       unsigned long hw_flags;
-
-       dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte);
-
-       time_left = (long)len - (long)count * (long)stime;
-       count += ((2 * time_left) / stime);
-       while (count) {
-               long i = 0;
-               for (i = 0; i < count_bits; i++) {
-                       byte_out = (byte_out << 1) | (send_byte & 1);
-                       it87_bits_in_byte_out++;
-               }
-               if (it87_bits_in_byte_out == 8) {
-                       dprintk("out=0x%x, tsr_txfbc: 0x%x\n",
-                               byte_out,
-                               inb(io + IT87_CIR_TSR) &
-                               IT87_CIR_TSR_TXFBC);
-
-                       while ((inb(io + IT87_CIR_TSR) &
-                               IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE)
-                               ;
-
-                       spin_lock_irqsave(&hardware_lock, hw_flags);
-                       outb(byte_out, io + IT87_CIR_DR);
-                       spin_unlock_irqrestore(&hardware_lock, hw_flags);
-
-                       it87_bits_in_byte_out = 0;
-                       it87_send_counter++;
-                       byte_out = 0;
-               }
-               count--;
-       }
-}
-
-
-/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */
-
-static void send_space(unsigned long len)
-{
-       send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR);
-}
-
-static void send_pulse(unsigned long len)
-{
-       send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR);
-}
-
-
-static void init_send()
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hardware_lock, flags);
-       /* RXEN=0: receiver disable */
-       it87_RXEN_mask = 0;
-       outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN,
-            io + IT87_CIR_RCR);
-       spin_unlock_irqrestore(&hardware_lock, flags);
-       it87_bits_in_byte_out = 0;
-       it87_send_counter = 0;
-}
-
-
-static void terminate_send(unsigned long len)
-{
-       unsigned long flags;
-       unsigned long last = 0;
-
-       last = it87_send_counter;
-       /* make sure all necessary data has been sent */
-       while (last == it87_send_counter)
-               send_space(len);
-       /* wait until all data sent */
-       while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0)
-               ;
-       /* then re-enable receiver */
-       spin_lock_irqsave(&hardware_lock, flags);
-       it87_RXEN_mask = IT87_CIR_RCR_RXEN;
-       outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN,
-            io + IT87_CIR_RCR);
-       spin_unlock_irqrestore(&hardware_lock, flags);
-}
-
-
-static int init_hardware(void)
-{
-       unsigned long flags;
-       unsigned char it87_rcr = 0;
-
-       spin_lock_irqsave(&hardware_lock, flags);
-       /* init cir-port */
-       /* enable r/w-access to Baudrate-Register */
-       outb(IT87_CIR_IER_BR, io + IT87_CIR_IER);
-       outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR);
-       outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR);
-       /* Baudrate Register off, define IRQs: Input only */
-       if (digimatrix) {
-               outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER);
-               /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */
-       } else {
-               outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER);
-               /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */
-       }
-       it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1;
-       if (it87_enable_demodulator)
-               it87_rcr |= IT87_CIR_RCR_RXEND;
-       outb(it87_rcr, io + IT87_CIR_RCR);
-       if (digimatrix) {
-               /* Set FIFO depth to 1 byte, and disable TX */
-               outb(inb(io + IT87_CIR_TCR1) |  0x00,
-                    io + IT87_CIR_TCR1);
-
-               /*
-                * TX: it87_freq (36kHz), 'reserved' sensitivity
-                * setting (0x00)
-                */
-               outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00,
-                    io + IT87_CIR_TCR2);
-       } else {
-               /* TX: 38kHz, 13,3us (pulse-width) */
-               outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06,
-                    io + IT87_CIR_TCR2);
-       }
-       spin_unlock_irqrestore(&hardware_lock, flags);
-       return 0;
-}
-
-
-static void drop_hardware(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hardware_lock, flags);
-       disable_irq(irq);
-       /* receiver disable */
-       it87_RXEN_mask = 0;
-       outb(0x1, io + IT87_CIR_RCR);
-       /* turn off irqs */
-       outb(0, io + IT87_CIR_IER);
-       /* fifo clear */
-       outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1);
-       /* reset */
-       outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
-       enable_irq(irq);
-       spin_unlock_irqrestore(&hardware_lock, flags);
-}
-
-
-static unsigned char it87_read(unsigned char port)
-{
-       outb(port, IT87_ADRPORT);
-       return inb(IT87_DATAPORT);
-}
-
-
-static void it87_write(unsigned char port, unsigned char data)
-{
-       outb(port, IT87_ADRPORT);
-       outb(data, IT87_DATAPORT);
-}
-
-
-/* SECTION: Initialisation */
-
-static int init_port(void)
-{
-       unsigned long hw_flags;
-       int retval = 0;
-
-       unsigned char init_bytes[4] = IT87_INIT;
-       unsigned char it87_chipid = 0;
-       unsigned char ldn = 0;
-       unsigned int  it87_io = 0;
-       unsigned int  it87_irq = 0;
-
-       /* Enter MB PnP Mode */
-       outb(init_bytes[0], IT87_ADRPORT);
-       outb(init_bytes[1], IT87_ADRPORT);
-       outb(init_bytes[2], IT87_ADRPORT);
-       outb(init_bytes[3], IT87_ADRPORT);
-
-       /* 8712 or 8705 ? */
-       it87_chipid = it87_read(IT87_CHIP_ID1);
-       if (it87_chipid != 0x87) {
-               retval = -ENXIO;
-               return retval;
-       }
-       it87_chipid = it87_read(IT87_CHIP_ID2);
-       if ((it87_chipid != 0x05) &&
-               (it87_chipid != 0x12) &&
-               (it87_chipid != 0x18) &&
-               (it87_chipid != 0x20)) {
-               printk(KERN_INFO LIRC_DRIVER_NAME
-                      ": no IT8704/05/12/18/20 found (claimed IT87%02x), "
-                      "exiting..\n", it87_chipid);
-               retval = -ENXIO;
-               return retval;
-       }
-       printk(KERN_INFO LIRC_DRIVER_NAME
-              ": found IT87%02x.\n",
-              it87_chipid);
-
-       /* get I/O-Port and IRQ */
-       if (it87_chipid == 0x12 || it87_chipid == 0x18)
-               ldn = IT8712_CIR_LDN;
-       else
-               ldn = IT8705_CIR_LDN;
-       it87_write(IT87_LDN, ldn);
-
-       it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 +
-                 it87_read(IT87_CIR_BASE_LSB);
-       if (it87_io == 0) {
-               if (io == 0)
-                       io = IT87_CIR_DEFAULT_IOBASE;
-               printk(KERN_INFO LIRC_DRIVER_NAME
-                      ": set default io 0x%x\n",
-                      io);
-               it87_write(IT87_CIR_BASE_MSB, io / 0x100);
-               it87_write(IT87_CIR_BASE_LSB, io % 0x100);
-       } else
-               io = it87_io;
-
-       it87_irq = it87_read(IT87_CIR_IRQ);
-       if (digimatrix || it87_irq == 0) {
-               if (irq == 0)
-                       irq = IT87_CIR_DEFAULT_IRQ;
-               printk(KERN_INFO LIRC_DRIVER_NAME
-                      ": set default irq 0x%x\n",
-                      irq);
-               it87_write(IT87_CIR_IRQ, irq);
-       } else
-               irq = it87_irq;
-
-       spin_lock_irqsave(&hardware_lock, hw_flags);
-       /* reset */
-       outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER);
-       /* fifo clear */
-       outb(IT87_CIR_TCR1_FIFOCLR |
-            /*      IT87_CIR_TCR1_ILE | */
-            IT87_CIR_TCR1_TXRLE |
-            IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1);
-       spin_unlock_irqrestore(&hardware_lock, hw_flags);
-
-       /* get I/O port access and IRQ line */
-       if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                      ": i/o port 0x%.4x already in use.\n", io);
-               /* Leaving MB PnP Mode */
-               it87_write(IT87_CFGCTRL, 0x2);
-               return -EBUSY;
-       }
-
-       /* activate CIR-Device */
-       it87_write(IT87_CIR_ACT, 0x1);
-
-       /* Leaving MB PnP Mode */
-       it87_write(IT87_CFGCTRL, 0x2);
-
-       retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/,
-                            LIRC_DRIVER_NAME, NULL);
-       if (retval < 0) {
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                      ": IRQ %d already in use.\n",
-                      irq);
-               release_region(io, 8);
-               return retval;
-       }
-
-       printk(KERN_INFO LIRC_DRIVER_NAME
-              ": I/O port 0x%.4x, IRQ %d.\n", io, irq);
-
-       init_timer(&timerlist);
-       timerlist.function = it87_timeout;
-       timerlist.data = 0xabadcafe;
-
-       return 0;
-}
-
-
-static void drop_port(void)
-{
-#if 0
-       unsigned char init_bytes[4] = IT87_INIT;
-
-       /* Enter MB PnP Mode */
-       outb(init_bytes[0], IT87_ADRPORT);
-       outb(init_bytes[1], IT87_ADRPORT);
-       outb(init_bytes[2], IT87_ADRPORT);
-       outb(init_bytes[3], IT87_ADRPORT);
-
-       /* deactivate CIR-Device */
-       it87_write(IT87_CIR_ACT, 0x0);
-
-       /* Leaving MB PnP Mode */
-       it87_write(IT87_CFGCTRL, 0x2);
-#endif
-
-       del_timer_sync(&timerlist);
-       free_irq(irq, NULL);
-       release_region(io, 8);
-}
-
-
-static int init_lirc_it87(void)
-{
-       int retval;
-
-       init_waitqueue_head(&lirc_read_queue);
-       retval = init_port();
-       if (retval < 0)
-               return retval;
-       init_hardware();
-       printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n");
-       return 0;
-}
-
-static int it87_probe(struct pnp_dev *pnp_dev,
-                     const struct pnp_device_id *dev_id)
-{
-       int retval;
-
-       driver.dev = &pnp_dev->dev;
-
-       retval = init_chrdev();
-       if (retval < 0)
-               return retval;
-
-       retval = init_lirc_it87();
-       if (retval)
-               goto init_lirc_it87_failed;
-
-       return 0;
-
-init_lirc_it87_failed:
-       drop_chrdev();
-
-       return retval;
-}
-
-static int __init lirc_it87_init(void)
-{
-       return pnp_register_driver(&it87_pnp_driver);
-}
-
-
-static void __exit lirc_it87_exit(void)
-{
-       drop_hardware();
-       drop_chrdev();
-       drop_port();
-       pnp_unregister_driver(&it87_pnp_driver);
-       printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
-}
-
-/* SECTION: PNP for ITE8704/13/18 */
-
-static const struct pnp_device_id pnp_dev_table[] = {
-       {"ITE8704", 0},
-       {"ITE8713", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-static struct pnp_driver it87_pnp_driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .id_table       = pnp_dev_table,
-       .probe          = it87_probe,
-};
-
-module_init(lirc_it87_init);
-module_exit(lirc_it87_exit);
-
-MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port");
-MODULE_AUTHOR("Hans-Gunter Lutke Uphues");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, S_IRUGO);
-MODULE_PARM_DESC(io, "I/O base address (default: 0x310)");
-
-module_param(irq, int, S_IRUGO);
-#ifdef LIRC_IT87_DIGIMATRIX
-MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)");
-#else
-MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)");
-#endif
-
-module_param(it87_enable_demodulator, bool, S_IRUGO);
-MODULE_PARM_DESC(it87_enable_demodulator,
-                "Receiver demodulator enable/disable (1/0), default: 0");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
-
-module_param(digimatrix, bool, S_IRUGO | S_IWUSR);
-#ifdef LIRC_IT87_DIGIMATRIX
-MODULE_PARM_DESC(digimatrix,
-       "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1");
-#else
-MODULE_PARM_DESC(digimatrix,
-       "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0");
-#endif
-
-
-module_param(it87_freq, int, S_IRUGO);
-#ifdef LIRC_IT87_DIGIMATRIX
-MODULE_PARM_DESC(it87_freq,
-    "Carrier demodulator frequency (kHz), (default: 36)");
-#else
-MODULE_PARM_DESC(it87_freq,
-    "Carrier demodulator frequency (kHz), (default: 38)");
-#endif
diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h
deleted file mode 100644 (file)
index cf021c8..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* lirc_it87.h */
-/* SECTION: Definitions */
-
-/********************************* ITE IT87xx ************************/
-
-/* based on the following documentation from ITE:
-   a) IT8712F Preliminary CIR Programming Guide V0.1
-   b) IT8705F Simple LPC I/O Preliminary Specification V0.3
-   c) IT8712F EC-LPC I/O Preliminary Specification V0.5
-*/
-
-/* IT8712/05 Ports: */
-#define IT87_ADRPORT      0x2e
-#define IT87_DATAPORT     0x2f
-#define IT87_INIT         {0x87, 0x01, 0x55, 0x55}
-
-/* alternate Ports: */
-/*
-#define IT87_ADRPORT      0x4e
-#define IT87_DATAPORT     0x4f
-#define IT87_INIT         {0x87, 0x01, 0x55, 0xaa}
- */
-
-/* IT8712/05 Registers */
-#define IT87_CFGCTRL      0x2
-#define IT87_LDN          0x7
-#define IT87_CHIP_ID1     0x20
-#define IT87_CHIP_ID2     0x21
-#define IT87_CFG_VERSION  0x22
-#define IT87_SWSUSPEND    0x23
-
-#define IT8712_CIR_LDN    0xa
-#define IT8705_CIR_LDN    0x7
-
-/* CIR Configuration Registers: */
-#define IT87_CIR_ACT      0x30
-#define IT87_CIR_BASE_MSB 0x60
-#define IT87_CIR_BASE_LSB 0x61
-#define IT87_CIR_IRQ      0x70
-#define IT87_CIR_CONFIG   0xf0
-
-/* List of IT87_CIR registers: offset to BaseAddr */
-#define IT87_CIR_DR   0
-#define IT87_CIR_IER  1
-#define IT87_CIR_RCR  2
-#define IT87_CIR_TCR1 3
-#define IT87_CIR_TCR2 4
-#define IT87_CIR_TSR  5
-#define IT87_CIR_RSR  6
-#define IT87_CIR_BDLR 5
-#define IT87_CIR_BDHR 6
-#define IT87_CIR_IIR  7
-
-/* Bit Definition */
-/* IER: */
-#define IT87_CIR_IER_TM_EN   0x80
-#define IT87_CIR_IER_RESEVED 0x40
-#define IT87_CIR_IER_RESET   0x20
-#define IT87_CIR_IER_BR      0x10
-#define IT87_CIR_IER_IEC     0x8
-#define IT87_CIR_IER_RFOIE   0x4
-#define IT87_CIR_IER_RDAIE   0x2
-#define IT87_CIR_IER_TLDLIE  0x1
-
-/* RCR: */
-#define IT87_CIR_RCR_RDWOS  0x80
-#define IT87_CIR_RCR_HCFS   0x40
-#define IT87_CIR_RCR_RXEN   0x20
-#define IT87_CIR_RCR_RXEND  0x10
-#define IT87_CIR_RCR_RXACT  0x8
-#define IT87_CIR_RCR_RXDCR  0x7
-
-/* TCR1: */
-#define IT87_CIR_TCR1_FIFOCLR 0x80
-#define IT87_CIR_TCR1_ILE     0x40
-#define IT87_CIR_TCR1_FIFOTL  0x30
-#define IT87_CIR_TCR1_TXRLE   0x8
-#define IT87_CIR_TCR1_TXENDF  0x4
-#define IT87_CIR_TCR1_TXMPM   0x3
-
-/* TCR2: */
-#define IT87_CIR_TCR2_CFQ   0xf8
-#define IT87_CIR_TCR2_TXMPW 0x7
-
-/* TSR: */
-#define IT87_CIR_TSR_RESERVED 0xc0
-#define IT87_CIR_TSR_TXFBC    0x3f
-
-/* RSR: */
-#define IT87_CIR_RSR_RXFTO    0x80
-#define IT87_CIR_RSR_RESERVED 0x40
-#define IT87_CIR_RSR_RXFBC    0x3f
-
-/* IIR: */
-#define IT87_CIR_IIR_RESERVED 0xf8
-#define IT87_CIR_IIR_IID      0x6
-#define IT87_CIR_IIR_IIP      0x1
-
-/* TM: */
-#define IT87_CIR_TM_IL_SEL    0x80
-#define IT87_CIR_TM_RESERVED  0x40
-#define IT87_CIR_TM_TM_REG    0x3f
-
-#define IT87_CIR_FIFO_SIZE 32
-
-/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */
-#define IT87_CIR_BAUDRATE_DIVISOR 0x1
-#define IT87_CIR_DEFAULT_IOBASE 0x310
-#define IT87_CIR_DEFAULT_IRQ    0x7
-#define IT87_CIR_SPACE 0x00
-#define IT87_CIR_PULSE 0xff
-#define IT87_CIR_FREQ_MIN 27
-#define IT87_CIR_FREQ_MAX 58
-#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul)
-
-/********************************* ITE IT87xx ************************/
diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c
deleted file mode 100644 (file)
index cb20cfd..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * LIRC driver for ITE8709 CIR port
- *
- * Copyright (C) 2008 GrĆ©gory LardiĆØre <spmf2004-lirc@yahoo.fr>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/pnp.h>
-#include <linux/io.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#define LIRC_DRIVER_NAME "lirc_ite8709"
-
-#define BUF_CHUNK_SIZE sizeof(int)
-#define BUF_SIZE       (128*BUF_CHUNK_SIZE)
-
-/*
- * The ITE8709 device seems to be the combination of IT8512 superIO chip and
- * a specific firmware running on the IT8512's embedded micro-controller.
- * In addition of the embedded micro-controller, the IT8512 chip contains a
- * CIR module and several other modules. A few modules are directly accessible
- * by the host CPU, but most of them are only accessible by the
- * micro-controller. The CIR module is only accessible by the micro-controller.
- * The battery-backed SRAM module is accessible by the host CPU and the
- * micro-controller. So one of the MC's firmware role is to act as a bridge
- * between the host CPU and the CIR module. The firmware implements a kind of
- * communication protocol using the SRAM module as a shared memory. The IT8512
- * specification is publicly available on ITE's web site, but the communication
- * protocol is not, so it was reverse-engineered.
- */
-
-/* ITE8709 Registers addresses and values (reverse-engineered) */
-#define ITE8709_MODE           0x1a
-#define ITE8709_REG_ADR                0x1b
-#define ITE8709_REG_VAL                0x1c
-#define ITE8709_IIR            0x1e  /* Interrupt identification register */
-#define ITE8709_RFSR           0x1f  /* Receiver FIFO status register */
-#define ITE8709_FIFO_START     0x20
-
-#define ITE8709_MODE_READY     0X00
-#define ITE8709_MODE_WRITE     0X01
-#define ITE8709_MODE_READ      0X02
-#define ITE8709_IIR_RDAI       0x02  /* Receiver data available interrupt */
-#define ITE8709_IIR_RFOI       0x04  /* Receiver FIFO overrun interrupt */
-#define ITE8709_RFSR_MASK      0x3f  /* FIFO byte count mask */
-
-/*
- * IT8512 CIR-module registers addresses and values
- * (from IT8512 E/F specification v0.4.1)
- */
-#define IT8512_REG_MSTCR       0x01  /* Master control register */
-#define IT8512_REG_IER         0x02  /* Interrupt enable register */
-#define IT8512_REG_CFR         0x04  /* Carrier frequency register */
-#define IT8512_REG_RCR         0x05  /* Receive control register */
-#define IT8512_REG_BDLR                0x08  /* Baud rate divisor low byte register */
-#define IT8512_REG_BDHR                0x09  /* Baud rate divisor high byte register */
-
-#define IT8512_MSTCR_RESET     0x01  /* Reset registers to default value */
-#define IT8512_MSTCR_FIFOCLR   0x02  /* Clear FIFO */
-#define IT8512_MSTCR_FIFOTL_7  0x04  /* FIFO threshold level : 7 */
-#define IT8512_MSTCR_FIFOTL_25 0x0c  /* FIFO threshold level : 25 */
-#define IT8512_IER_RDAIE       0x02  /* Enable data interrupt request */
-#define IT8512_IER_RFOIE       0x04  /* Enable FIFO overrun interrupt req */
-#define IT8512_IER_IEC         0x80  /* Enable interrupt request */
-#define IT8512_CFR_CF_36KHZ    0x09  /* Carrier freq : low speed, 36kHz */
-#define IT8512_RCR_RXDCR_1     0x01  /* Demodulation carrier range : 1 */
-#define IT8512_RCR_RXACT       0x08  /* Receiver active */
-#define IT8512_RCR_RXEN                0x80  /* Receiver enable */
-#define IT8512_BDR_6           6     /* Baud rate divisor : 6 */
-
-/* Actual values used by this driver */
-#define CFG_FIFOTL     IT8512_MSTCR_FIFOTL_25
-#define CFG_CR_FREQ    IT8512_CFR_CF_36KHZ
-#define CFG_DCR                IT8512_RCR_RXDCR_1
-#define CFG_BDR                IT8512_BDR_6
-#define CFG_TIMEOUT    100000 /* Rearm interrupt when a space is > 100 ms */
-
-static int debug;
-
-struct ite8709_device {
-       int use_count;
-       int io;
-       int irq;
-       spinlock_t hardware_lock;
-       __u64 acc_pulse;
-       __u64 acc_space;
-       char lastbit;
-       struct timeval last_tv;
-       struct lirc_driver driver;
-       struct tasklet_struct tasklet;
-       char force_rearm;
-       char rearmed;
-       char device_busy;
-};
-
-#define dprintk(fmt, args...)                                  \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
-                               fmt, ## args);                  \
-       } while (0)
-
-
-static unsigned char ite8709_read(struct ite8709_device *dev,
-                                       unsigned char port)
-{
-       outb(port, dev->io);
-       return inb(dev->io+1);
-}
-
-static void ite8709_write(struct ite8709_device *dev, unsigned char port,
-                               unsigned char data)
-{
-       outb(port, dev->io);
-       outb(data, dev->io+1);
-}
-
-static void ite8709_wait_device(struct ite8709_device *dev)
-{
-       int i = 0;
-       /*
-        * loop until device tells it's ready to continue
-        * iterations count is usually ~750 but can sometimes achieve 13000
-        */
-       for (i = 0; i < 15000; i++) {
-               udelay(2);
-               if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY)
-                       break;
-       }
-}
-
-static void ite8709_write_register(struct ite8709_device *dev,
-                               unsigned char reg_adr, unsigned char reg_value)
-{
-       ite8709_wait_device(dev);
-
-       ite8709_write(dev, ITE8709_REG_VAL, reg_value);
-       ite8709_write(dev, ITE8709_REG_ADR, reg_adr);
-       ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE);
-}
-
-static void ite8709_init_hardware(struct ite8709_device *dev)
-{
-       spin_lock_irq(&dev->hardware_lock);
-       dev->device_busy = 1;
-       spin_unlock_irq(&dev->hardware_lock);
-
-       ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff);
-       ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff);
-       ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ);
-       ite8709_write_register(dev, IT8512_REG_IER,
-                       IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE);
-       ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR);
-       ite8709_write_register(dev, IT8512_REG_MSTCR,
-                                       CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
-       ite8709_write_register(dev, IT8512_REG_RCR,
-                               IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
-
-       spin_lock_irq(&dev->hardware_lock);
-       dev->device_busy = 0;
-       spin_unlock_irq(&dev->hardware_lock);
-
-       tasklet_enable(&dev->tasklet);
-}
-
-static void ite8709_drop_hardware(struct ite8709_device *dev)
-{
-       tasklet_disable(&dev->tasklet);
-
-       spin_lock_irq(&dev->hardware_lock);
-       dev->device_busy = 1;
-       spin_unlock_irq(&dev->hardware_lock);
-
-       ite8709_write_register(dev, IT8512_REG_RCR, 0);
-       ite8709_write_register(dev, IT8512_REG_MSTCR,
-                               IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR);
-
-       spin_lock_irq(&dev->hardware_lock);
-       dev->device_busy = 0;
-       spin_unlock_irq(&dev->hardware_lock);
-}
-
-static int ite8709_set_use_inc(void *data)
-{
-       struct ite8709_device *dev;
-       dev = data;
-       if (dev->use_count == 0)
-               ite8709_init_hardware(dev);
-       dev->use_count++;
-       return 0;
-}
-
-static void ite8709_set_use_dec(void *data)
-{
-       struct ite8709_device *dev;
-       dev = data;
-       dev->use_count--;
-       if (dev->use_count == 0)
-               ite8709_drop_hardware(dev);
-}
-
-static void ite8709_add_read_queue(struct ite8709_device *dev, int flag,
-                                  __u64 val)
-{
-       int value;
-
-       dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space");
-
-       value = (val > PULSE_MASK) ? PULSE_MASK : val;
-       if (flag)
-               value |= PULSE_BIT;
-
-       if (!lirc_buffer_full(dev->driver.rbuf)) {
-               lirc_buffer_write(dev->driver.rbuf, (void *) &value);
-               wake_up(&dev->driver.rbuf->wait_poll);
-       }
-}
-
-static irqreturn_t ite8709_interrupt(int irq, void *dev_id)
-{
-       unsigned char data;
-       int iir, rfsr, i;
-       int fifo = 0;
-       char bit;
-       struct timeval curr_tv;
-
-       /* Bit duration in microseconds */
-       const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR);
-
-       struct ite8709_device *dev;
-       dev = dev_id;
-
-       /*
-        * If device is busy, we simply discard data because we are in one of
-        * these two cases : shutting down or rearming the device, so this
-        * doesn't really matter and this avoids waiting too long in IRQ ctx
-        */
-       spin_lock(&dev->hardware_lock);
-       if (dev->device_busy) {
-               spin_unlock(&dev->hardware_lock);
-               return IRQ_RETVAL(IRQ_HANDLED);
-       }
-
-       iir = ite8709_read(dev, ITE8709_IIR);
-
-       switch (iir) {
-       case ITE8709_IIR_RFOI:
-               dprintk("fifo overrun, scheduling forced rearm just in case\n");
-               dev->force_rearm = 1;
-               tasklet_schedule(&dev->tasklet);
-               spin_unlock(&dev->hardware_lock);
-               return IRQ_RETVAL(IRQ_HANDLED);
-
-       case ITE8709_IIR_RDAI:
-               rfsr = ite8709_read(dev, ITE8709_RFSR);
-               fifo = rfsr & ITE8709_RFSR_MASK;
-               if (fifo > 32)
-                       fifo = 32;
-               dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo);
-
-               if (dev->rearmed) {
-                       do_gettimeofday(&curr_tv);
-                       dev->acc_space += 1000000ull
-                               * (curr_tv.tv_sec - dev->last_tv.tv_sec)
-                               + (curr_tv.tv_usec - dev->last_tv.tv_usec);
-                       dev->rearmed = 0;
-               }
-               for (i = 0; i < fifo; i++) {
-                       data = ite8709_read(dev, i+ITE8709_FIFO_START);
-                       data = ~data;
-                       /* Loop through */
-                       for (bit = 0; bit < 8; ++bit) {
-                               if ((data >> bit) & 1) {
-                                       dev->acc_pulse += bit_duration;
-                                       if (dev->lastbit == 0) {
-                                               ite8709_add_read_queue(dev, 0,
-                                                       dev->acc_space);
-                                               dev->acc_space = 0;
-                                       }
-                               } else {
-                                       dev->acc_space += bit_duration;
-                                       if (dev->lastbit == 1) {
-                                               ite8709_add_read_queue(dev, 1,
-                                                       dev->acc_pulse);
-                                               dev->acc_pulse = 0;
-                                       }
-                               }
-                               dev->lastbit = (data >> bit) & 1;
-                       }
-               }
-               ite8709_write(dev, ITE8709_RFSR, 0);
-
-               if (dev->acc_space > CFG_TIMEOUT) {
-                       dprintk("scheduling rearm IRQ\n");
-                       do_gettimeofday(&dev->last_tv);
-                       dev->force_rearm = 0;
-                       tasklet_schedule(&dev->tasklet);
-               }
-
-               spin_unlock(&dev->hardware_lock);
-               return IRQ_RETVAL(IRQ_HANDLED);
-
-       default:
-               /* not our irq */
-               dprintk("unknown IRQ (shouldn't happen) !!\n");
-               spin_unlock(&dev->hardware_lock);
-               return IRQ_RETVAL(IRQ_NONE);
-       }
-}
-
-static void ite8709_rearm_irq(unsigned long data)
-{
-       struct ite8709_device *dev;
-       unsigned long flags;
-       dev = (struct ite8709_device *) data;
-
-       spin_lock_irqsave(&dev->hardware_lock, flags);
-       dev->device_busy = 1;
-       spin_unlock_irqrestore(&dev->hardware_lock, flags);
-
-       if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) {
-               dprintk("rearming IRQ\n");
-               ite8709_write_register(dev, IT8512_REG_RCR,
-                                               IT8512_RCR_RXACT | CFG_DCR);
-               ite8709_write_register(dev, IT8512_REG_MSTCR,
-                                       CFG_FIFOTL | IT8512_MSTCR_FIFOCLR);
-               ite8709_write_register(dev, IT8512_REG_RCR,
-                               IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR);
-               if (!dev->force_rearm)
-                       dev->rearmed = 1;
-               dev->force_rearm = 0;
-       }
-
-       spin_lock_irqsave(&dev->hardware_lock, flags);
-       dev->device_busy = 0;
-       spin_unlock_irqrestore(&dev->hardware_lock, flags);
-}
-
-static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno,
-                               char *msg)
-{
-       if (msg != NULL)
-               printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg);
-
-       switch (stage) {
-       case 6:
-               if (dev->use_count > 0)
-                       ite8709_drop_hardware(dev);
-       case 5:
-               free_irq(dev->irq, dev);
-       case 4:
-               release_region(dev->io, 2);
-       case 3:
-               lirc_unregister_driver(dev->driver.minor);
-       case 2:
-               lirc_buffer_free(dev->driver.rbuf);
-               kfree(dev->driver.rbuf);
-       case 1:
-               kfree(dev);
-       case 0:
-               ;
-       }
-
-       return errno;
-}
-
-static int __devinit ite8709_pnp_probe(struct pnp_dev *dev,
-                                       const struct pnp_device_id *dev_id)
-{
-       struct lirc_driver *driver;
-       struct ite8709_device *ite8709_dev;
-       int ret;
-
-       /* Check resources validity */
-       if (!pnp_irq_valid(dev, 0))
-               return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ");
-       if (!pnp_port_valid(dev, 2))
-               return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port");
-
-       /* Allocate memory for device struct */
-       ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL);
-       if (ite8709_dev == NULL)
-               return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed");
-       pnp_set_drvdata(dev, ite8709_dev);
-
-       /* Initialize device struct */
-       ite8709_dev->use_count = 0;
-       ite8709_dev->irq = pnp_irq(dev, 0);
-       ite8709_dev->io = pnp_port_start(dev, 2);
-       ite8709_dev->hardware_lock =
-               __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock);
-       ite8709_dev->acc_pulse = 0;
-       ite8709_dev->acc_space = 0;
-       ite8709_dev->lastbit = 0;
-       do_gettimeofday(&ite8709_dev->last_tv);
-       tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq,
-                                                       (long) ite8709_dev);
-       ite8709_dev->force_rearm = 0;
-       ite8709_dev->rearmed = 0;
-       ite8709_dev->device_busy = 0;
-
-       /* Initialize driver struct */
-       driver = &ite8709_dev->driver;
-       strcpy(driver->name, LIRC_DRIVER_NAME);
-       driver->minor = -1;
-       driver->code_length = sizeof(int) * 8;
-       driver->sample_rate = 0;
-       driver->features = LIRC_CAN_REC_MODE2;
-       driver->data = ite8709_dev;
-       driver->add_to_buf = NULL;
-       driver->set_use_inc = ite8709_set_use_inc;
-       driver->set_use_dec = ite8709_set_use_dec;
-       driver->dev = &dev->dev;
-       driver->owner = THIS_MODULE;
-
-       /* Initialize LIRC buffer */
-       driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
-       if (!driver->rbuf)
-               return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
-                                      "can't allocate lirc_buffer");
-       if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE))
-               return ite8709_cleanup(ite8709_dev, 1, -ENOMEM,
-                                      "lirc_buffer_init() failed");
-
-       /* Register LIRC driver */
-       ret = lirc_register_driver(driver);
-       if (ret < 0)
-               return ite8709_cleanup(ite8709_dev, 2, ret,
-                                       "lirc_register_driver() failed");
-
-       /* Reserve I/O port access */
-       if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME))
-               return ite8709_cleanup(ite8709_dev, 3, -EBUSY,
-                                               "i/o port already in use");
-
-       /* Reserve IRQ line */
-       ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0,
-                                       LIRC_DRIVER_NAME, ite8709_dev);
-       if (ret < 0)
-               return ite8709_cleanup(ite8709_dev, 4, ret,
-                                               "IRQ already in use");
-
-       /* Initialize hardware */
-       ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */
-
-       printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n",
-                                       ite8709_dev->irq, ite8709_dev->io);
-
-       return 0;
-}
-
-static void __devexit ite8709_pnp_remove(struct pnp_dev *dev)
-{
-       struct ite8709_device *ite8709_dev;
-       ite8709_dev = pnp_get_drvdata(dev);
-
-       ite8709_cleanup(ite8709_dev, 6, 0, NULL);
-
-       printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n");
-}
-
-#ifdef CONFIG_PM
-static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state)
-{
-       struct ite8709_device *ite8709_dev;
-       ite8709_dev = pnp_get_drvdata(dev);
-
-       if (ite8709_dev->use_count > 0)
-               ite8709_drop_hardware(ite8709_dev);
-
-       return 0;
-}
-
-static int ite8709_pnp_resume(struct pnp_dev *dev)
-{
-       struct ite8709_device *ite8709_dev;
-       ite8709_dev = pnp_get_drvdata(dev);
-
-       if (ite8709_dev->use_count > 0)
-               ite8709_init_hardware(ite8709_dev);
-
-       return 0;
-}
-#else
-#define ite8709_pnp_suspend NULL
-#define ite8709_pnp_resume NULL
-#endif
-
-static const struct pnp_device_id pnp_dev_table[] = {
-       {"ITE8709", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-static struct pnp_driver ite8709_pnp_driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .probe          = ite8709_pnp_probe,
-       .remove         = __devexit_p(ite8709_pnp_remove),
-       .suspend        = ite8709_pnp_suspend,
-       .resume         = ite8709_pnp_resume,
-       .id_table       = pnp_dev_table,
-};
-
-static int __init ite8709_init_module(void)
-{
-       return pnp_register_driver(&ite8709_pnp_driver);
-}
-module_init(ite8709_init_module);
-
-static void __exit ite8709_cleanup_module(void)
-{
-       pnp_unregister_driver(&ite8709_pnp_driver);
-}
-module_exit(ite8709_cleanup_module);
-
-MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port");
-MODULE_AUTHOR("GrĆ©gory LardiĆØre");
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
index 925eabe14854d93cc0267110da2ba646758f0aaf..63a438d1c84946e88bc626308728825e10644379 100644 (file)
@@ -364,7 +364,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
        int i;
        int retval = 0;
        struct sasem_context *context;
-       int *data_buf;
+       int *data_buf = NULL;
 
        context = (struct sasem_context *) file->private_data;
        if (!context) {
index 0aad0d7a74a3789c6a416b9391e254d01843d51c..dd6a57c3c3a3149bac53eb36fd4ddeabed804050 100644 (file)
 #include <media/lirc_dev.h>
 #include <media/lirc.h>
 
+struct IR;
+
 struct IR_rx {
+       struct kref ref;
+       struct IR *ir;
+
        /* RX device */
+       struct mutex client_lock;
        struct i2c_client *c;
 
-       /* RX device buffer & lock */
-       struct lirc_buffer buf;
-       struct mutex buf_lock;
-
        /* RX polling thread data */
        struct task_struct *task;
 
@@ -80,7 +82,11 @@ struct IR_rx {
 };
 
 struct IR_tx {
+       struct kref ref;
+       struct IR *ir;
+
        /* TX device */
+       struct mutex client_lock;
        struct i2c_client *c;
 
        /* TX additional actions needed */
@@ -89,19 +95,34 @@ struct IR_tx {
 };
 
 struct IR {
+       struct kref ref;
+       struct list_head list;
+
+       /* FIXME spinlock access to l.features */
        struct lirc_driver l;
+       struct lirc_buffer rbuf;
 
        struct mutex ir_lock;
-       int open;
+       atomic_t open_count;
 
        struct i2c_adapter *adapter;
+
+       spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */
        struct IR_rx *rx;
+
+       spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */
        struct IR_tx *tx;
 };
 
-/* Minor -> data mapping */
-static struct mutex ir_devices_lock;
-static struct IR *ir_devices[MAX_IRCTL_DEVICES];
+/* IR transceiver instance object list */
+/*
+ * This lock is used for the following:
+ * a. ir_devices_list access, insertions, deletions
+ * b. struct IR kref get()s and put()s
+ * c. serialization of ir_probe() for the two i2c_clients for a Z8
+ */
+static DEFINE_MUTEX(ir_devices_lock);
+static LIST_HEAD(ir_devices_list);
 
 /* Block size for IR transmitter */
 #define TX_BLOCK_SIZE  99
@@ -147,6 +168,157 @@ static int minor = -1;    /* minor number */
                                 ## args);                              \
        } while (0)
 
+
+/* struct IR reference counting */
+static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held)
+{
+       if (ir_devices_lock_held) {
+               kref_get(&ir->ref);
+       } else {
+               mutex_lock(&ir_devices_lock);
+               kref_get(&ir->ref);
+               mutex_unlock(&ir_devices_lock);
+       }
+       return ir;
+}
+
+static void release_ir_device(struct kref *ref)
+{
+       struct IR *ir = container_of(ref, struct IR, ref);
+
+       /*
+        * Things should be in this state by now:
+        * ir->rx set to NULL and deallocated - happens before ir->rx->ir put()
+        * ir->rx->task kthread stopped - happens before ir->rx->ir put()
+        * ir->tx set to NULL and deallocated - happens before ir->tx->ir put()
+        * ir->open_count ==  0 - happens on final close()
+        * ir_lock, tx_ref_lock, rx_ref_lock, all released
+        */
+       if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
+               lirc_unregister_driver(ir->l.minor);
+               ir->l.minor = MAX_IRCTL_DEVICES;
+       }
+       if (ir->rbuf.fifo_initialized)
+               lirc_buffer_free(&ir->rbuf);
+       list_del(&ir->list);
+       kfree(ir);
+}
+
+static int put_ir_device(struct IR *ir, bool ir_devices_lock_held)
+{
+       int released;
+
+       if (ir_devices_lock_held)
+               return kref_put(&ir->ref, release_ir_device);
+
+       mutex_lock(&ir_devices_lock);
+       released = kref_put(&ir->ref, release_ir_device);
+       mutex_unlock(&ir_devices_lock);
+
+       return released;
+}
+
+/* struct IR_rx reference counting */
+static struct IR_rx *get_ir_rx(struct IR *ir)
+{
+       struct IR_rx *rx;
+
+       spin_lock(&ir->rx_ref_lock);
+       rx = ir->rx;
+       if (rx != NULL)
+               kref_get(&rx->ref);
+       spin_unlock(&ir->rx_ref_lock);
+       return rx;
+}
+
+static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held)
+{
+       /* end up polling thread */
+       if (!IS_ERR_OR_NULL(rx->task)) {
+               kthread_stop(rx->task);
+               rx->task = NULL;
+               /* Put the ir ptr that ir_probe() gave to the rx poll thread */
+               put_ir_device(rx->ir, ir_devices_lock_held);
+       }
+}
+
+static void release_ir_rx(struct kref *ref)
+{
+       struct IR_rx *rx = container_of(ref, struct IR_rx, ref);
+       struct IR *ir = rx->ir;
+
+       /*
+        * This release function can't do all the work, as we want
+        * to keep the rx_ref_lock a spinlock, and killing the poll thread
+        * and releasing the ir reference can cause a sleep.  That work is
+        * performed by put_ir_rx()
+        */
+       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+       /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */
+       ir->rx = NULL;
+       /* Don't do the kfree(rx) here; we still need to kill the poll thread */
+       return;
+}
+
+static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held)
+{
+       int released;
+       struct IR *ir = rx->ir;
+
+       spin_lock(&ir->rx_ref_lock);
+       released = kref_put(&rx->ref, release_ir_rx);
+       spin_unlock(&ir->rx_ref_lock);
+       /* Destroy the rx kthread while not holding the spinlock */
+       if (released) {
+               destroy_rx_kthread(rx, ir_devices_lock_held);
+               kfree(rx);
+               /* Make sure we're not still in a poll_table somewhere */
+               wake_up_interruptible(&ir->rbuf.wait_poll);
+       }
+       /* Do a reference put() for the rx->ir reference, if we released rx */
+       if (released)
+               put_ir_device(ir, ir_devices_lock_held);
+       return released;
+}
+
+/* struct IR_tx reference counting */
+static struct IR_tx *get_ir_tx(struct IR *ir)
+{
+       struct IR_tx *tx;
+
+       spin_lock(&ir->tx_ref_lock);
+       tx = ir->tx;
+       if (tx != NULL)
+               kref_get(&tx->ref);
+       spin_unlock(&ir->tx_ref_lock);
+       return tx;
+}
+
+static void release_ir_tx(struct kref *ref)
+{
+       struct IR_tx *tx = container_of(ref, struct IR_tx, ref);
+       struct IR *ir = tx->ir;
+
+       ir->l.features &= ~LIRC_CAN_SEND_PULSE;
+       /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */
+       ir->tx = NULL;
+       kfree(tx);
+}
+
+static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held)
+{
+       int released;
+       struct IR *ir = tx->ir;
+
+       spin_lock(&ir->tx_ref_lock);
+       released = kref_put(&tx->ref, release_ir_tx);
+       spin_unlock(&ir->tx_ref_lock);
+       /* Do a reference put() for the tx->ir reference, if we released tx */
+       if (released)
+               put_ir_device(ir, ir_devices_lock_held);
+       return released;
+}
+
 static int add_to_buf(struct IR *ir)
 {
        __u16 code;
@@ -156,23 +328,38 @@ static int add_to_buf(struct IR *ir)
        int ret;
        int failures = 0;
        unsigned char sendbuf[1] = { 0 };
-       struct IR_rx *rx = ir->rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+       struct IR_rx *rx;
+       struct IR_tx *tx;
 
+       if (lirc_buffer_full(rbuf)) {
+               dprintk("buffer overflow\n");
+               return -EOVERFLOW;
+       }
+
+       rx = get_ir_rx(ir);
        if (rx == NULL)
                return -ENXIO;
 
-       if (lirc_buffer_full(&rx->buf)) {
-               dprintk("buffer overflow\n");
-               return -EOVERFLOW;
+       /* Ensure our rx->c i2c_client remains valid for the duration */
+       mutex_lock(&rx->client_lock);
+       if (rx->c == NULL) {
+               mutex_unlock(&rx->client_lock);
+               put_ir_rx(rx, false);
+               return -ENXIO;
        }
 
+       tx = get_ir_tx(ir);
+
        /*
         * service the device as long as it is returning
         * data and we have space
         */
        do {
-               if (kthread_should_stop())
-                       return -ENODATA;
+               if (kthread_should_stop()) {
+                       ret = -ENODATA;
+                       break;
+               }
 
                /*
                 * Lock i2c bus for the duration.  RX/TX chips interfere so
@@ -182,7 +369,8 @@ static int add_to_buf(struct IR *ir)
 
                if (kthread_should_stop()) {
                        mutex_unlock(&ir->ir_lock);
-                       return -ENODATA;
+                       ret = -ENODATA;
+                       break;
                }
 
                /*
@@ -196,7 +384,7 @@ static int add_to_buf(struct IR *ir)
                                mutex_unlock(&ir->ir_lock);
                                zilog_error("unable to read from the IR chip "
                                            "after 3 resets, giving up\n");
-                               return ret;
+                               break;
                        }
 
                        /* Looks like the chip crashed, reset it */
@@ -206,19 +394,23 @@ static int add_to_buf(struct IR *ir)
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        if (kthread_should_stop()) {
                                mutex_unlock(&ir->ir_lock);
-                               return -ENODATA;
+                               ret = -ENODATA;
+                               break;
                        }
                        schedule_timeout((100 * HZ + 999) / 1000);
-                       ir->tx->need_boot = 1;
+                       if (tx != NULL)
+                               tx->need_boot = 1;
 
                        ++failures;
                        mutex_unlock(&ir->ir_lock);
+                       ret = 0;
                        continue;
                }
 
                if (kthread_should_stop()) {
                        mutex_unlock(&ir->ir_lock);
-                       return -ENODATA;
+                       ret = -ENODATA;
+                       break;
                }
                ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
                mutex_unlock(&ir->ir_lock);
@@ -234,12 +426,17 @@ static int add_to_buf(struct IR *ir)
 
                /* key pressed ? */
                if (rx->hdpvr_data_fmt) {
-                       if (got_data && (keybuf[0] == 0x80))
-                               return 0;
-                       else if (got_data && (keybuf[0] == 0x00))
-                               return -ENODATA;
-               } else if ((rx->b[0] & 0x80) == 0)
-                       return got_data ? 0 : -ENODATA;
+                       if (got_data && (keybuf[0] == 0x80)) {
+                               ret = 0;
+                               break;
+                       } else if (got_data && (keybuf[0] == 0x00)) {
+                               ret = -ENODATA;
+                               break;
+                       }
+               } else if ((rx->b[0] & 0x80) == 0) {
+                       ret = got_data ? 0 : -ENODATA;
+                       break;
+               }
 
                /* look what we have */
                code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2);
@@ -248,11 +445,16 @@ static int add_to_buf(struct IR *ir)
                codes[1] = code & 0xff;
 
                /* return it */
-               lirc_buffer_write(&rx->buf, codes);
+               lirc_buffer_write(rbuf, codes);
                ++got_data;
-       } while (!lirc_buffer_full(&rx->buf));
+               ret = 0;
+       } while (!lirc_buffer_full(rbuf));
 
-       return 0;
+       mutex_unlock(&rx->client_lock);
+       if (tx != NULL)
+               put_ir_tx(tx, false);
+       put_ir_rx(rx, false);
+       return ret;
 }
 
 /*
@@ -268,19 +470,19 @@ static int add_to_buf(struct IR *ir)
 static int lirc_thread(void *arg)
 {
        struct IR *ir = arg;
-       struct IR_rx *rx = ir->rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
 
        dprintk("poll thread started\n");
 
        while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
                /* if device not opened, we can sleep half a second */
-               if (!ir->open) {
+               if (atomic_read(&ir->open_count) == 0) {
                        schedule_timeout(HZ/2);
                        continue;
                }
 
+               set_current_state(TASK_INTERRUPTIBLE);
+
                /*
                 * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
                 * We use this interval as the chip resets every time you poll
@@ -295,7 +497,7 @@ static int lirc_thread(void *arg)
                if (kthread_should_stop())
                        break;
                if (!add_to_buf(ir))
-                       wake_up_interruptible(&rx->buf.wait_poll);
+                       wake_up_interruptible(&rbuf->wait_poll);
        }
 
        dprintk("poll thread ended\n");
@@ -304,34 +506,12 @@ static int lirc_thread(void *arg)
 
 static int set_use_inc(void *data)
 {
-       struct IR *ir = data;
-
-       if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0)
-               return -ENODEV;
-
-       /* lock bttv in memory while /dev/lirc is in use  */
-       /*
-        * this is completely broken code. lirc_unregister_driver()
-        * must be possible even when the device is open
-        */
-       if (ir->rx != NULL)
-               i2c_use_client(ir->rx->c);
-       if (ir->tx != NULL)
-               i2c_use_client(ir->tx->c);
-
        return 0;
 }
 
 static void set_use_dec(void *data)
 {
-       struct IR *ir = data;
-
-       if (ir->rx)
-               i2c_release_client(ir->rx->c);
-       if (ir->tx)
-               i2c_release_client(ir->tx->c);
-       if (ir->l.owner != NULL)
-               module_put(ir->l.owner);
+       return;
 }
 
 /* safe read of a uint32 (always network byte order) */
@@ -585,7 +765,7 @@ static int fw_load(struct IR_tx *tx)
        }
 
        /* Request codeset data file */
-       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c->dev);
+       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev);
        if (ret != 0) {
                zilog_error("firmware haup-ir-blaster.bin not available "
                            "(%d)\n", ret);
@@ -711,59 +891,32 @@ out:
        return ret;
 }
 
-/* initialise the IR TX device */
-static int tx_init(struct IR_tx *tx)
-{
-       int ret;
-
-       /* Load 'firmware' */
-       ret = fw_load(tx);
-       if (ret != 0)
-               return ret;
-
-       /* Send boot block */
-       ret = send_boot_data(tx);
-       if (ret != 0)
-               return ret;
-       tx->need_boot = 0;
-
-       /* Looks good */
-       return 0;
-}
-
-/* do nothing stub to make LIRC happy */
-static loff_t lseek(struct file *filep, loff_t offset, int orig)
-{
-       return -ESPIPE;
-}
-
 /* copied from lirc_dev */
 static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
 {
        struct IR *ir = filep->private_data;
-       struct IR_rx *rx = ir->rx;
-       int ret = 0, written = 0;
+       struct IR_rx *rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+       int ret = 0, written = 0, retries = 0;
+       unsigned int m;
        DECLARE_WAITQUEUE(wait, current);
 
        dprintk("read called\n");
-       if (rx == NULL)
-               return -ENODEV;
-
-       if (mutex_lock_interruptible(&rx->buf_lock))
-               return -ERESTARTSYS;
-
-       if (n % rx->buf.chunk_size) {
+       if (n % rbuf->chunk_size) {
                dprintk("read result = -EINVAL\n");
-               mutex_unlock(&rx->buf_lock);
                return -EINVAL;
        }
 
+       rx = get_ir_rx(ir);
+       if (rx == NULL)
+               return -ENXIO;
+
        /*
         * we add ourselves to the task queue before buffer check
         * to avoid losing scan code (in case when queue is awaken somewhere
         * between while condition checking and scheduling)
         */
-       add_wait_queue(&rx->buf.wait_poll, &wait);
+       add_wait_queue(&rbuf->wait_poll, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
 
        /*
@@ -771,7 +924,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
         * mode and 'copy_to_user' is happy, wait for data.
         */
        while (written < n && ret == 0) {
-               if (lirc_buffer_empty(&rx->buf)) {
+               if (lirc_buffer_empty(rbuf)) {
                        /*
                         * According to the read(2) man page, 'written' can be
                         * returned as less than 'n', instead of blocking
@@ -791,20 +944,27 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
                        schedule();
                        set_current_state(TASK_INTERRUPTIBLE);
                } else {
-                       unsigned char buf[rx->buf.chunk_size];
-                       lirc_buffer_read(&rx->buf, buf);
-                       ret = copy_to_user((void *)outbuf+written, buf,
-                                          rx->buf.chunk_size);
-                       written += rx->buf.chunk_size;
+                       unsigned char buf[rbuf->chunk_size];
+                       m = lirc_buffer_read(rbuf, buf);
+                       if (m == rbuf->chunk_size) {
+                               ret = copy_to_user((void *)outbuf+written, buf,
+                                                  rbuf->chunk_size);
+                               written += rbuf->chunk_size;
+                       } else {
+                               retries++;
+                       }
+                       if (retries >= 5) {
+                               zilog_error("Buffer read failed!\n");
+                               ret = -EIO;
+                       }
                }
        }
 
-       remove_wait_queue(&rx->buf.wait_poll, &wait);
+       remove_wait_queue(&rbuf->wait_poll, &wait);
+       put_ir_rx(rx, false);
        set_current_state(TASK_RUNNING);
-       mutex_unlock(&rx->buf_lock);
 
-       dprintk("read result = %s (%d)\n",
-               ret ? "-EFAULT" : "OK", ret);
+       dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK");
 
        return ret ? ret : written;
 }
@@ -931,17 +1091,27 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                          loff_t *ppos)
 {
        struct IR *ir = filep->private_data;
-       struct IR_tx *tx = ir->tx;
+       struct IR_tx *tx;
        size_t i;
        int failures = 0;
 
-       if (tx == NULL)
-               return -ENODEV;
-
        /* Validate user parameters */
        if (n % sizeof(int))
                return -EINVAL;
 
+       /* Get a struct IR_tx reference */
+       tx = get_ir_tx(ir);
+       if (tx == NULL)
+               return -ENXIO;
+
+       /* Ensure our tx->c i2c_client remains valid for the duration */
+       mutex_lock(&tx->client_lock);
+       if (tx->c == NULL) {
+               mutex_unlock(&tx->client_lock);
+               put_ir_tx(tx, false);
+               return -ENXIO;
+       }
+
        /* Lock i2c bus for the duration */
        mutex_lock(&ir->ir_lock);
 
@@ -952,11 +1122,24 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
 
                if (copy_from_user(&command, buf + i, sizeof(command))) {
                        mutex_unlock(&ir->ir_lock);
+                       mutex_unlock(&tx->client_lock);
+                       put_ir_tx(tx, false);
                        return -EFAULT;
                }
 
                /* Send boot data first if required */
                if (tx->need_boot == 1) {
+                       /* Make sure we have the 'firmware' loaded, first */
+                       ret = fw_load(tx);
+                       if (ret != 0) {
+                               mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
+                               if (ret != -ENOMEM)
+                                       ret = -EIO;
+                               return ret;
+                       }
+                       /* Prep the chip for transmitting codes */
                        ret = send_boot_data(tx);
                        if (ret == 0)
                                tx->need_boot = 0;
@@ -968,6 +1151,8 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                                            (unsigned)command & 0xFFFF);
                        if (ret == -EPROTO) {
                                mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
                                return ret;
                        }
                }
@@ -985,6 +1170,8 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
                                zilog_error("unable to send to the IR chip "
                                            "after 3 resets, giving up\n");
                                mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
                                return ret;
                        }
                        set_current_state(TASK_UNINTERRUPTIBLE);
@@ -998,6 +1185,11 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
        /* Release i2c bus */
        mutex_unlock(&ir->ir_lock);
 
+       mutex_unlock(&tx->client_lock);
+
+       /* Give back our struct IR_tx reference */
+       put_ir_tx(tx, false);
+
        /* All looks good */
        return n;
 }
@@ -1006,23 +1198,32 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
 static unsigned int poll(struct file *filep, poll_table *wait)
 {
        struct IR *ir = filep->private_data;
-       struct IR_rx *rx = ir->rx;
+       struct IR_rx *rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
        unsigned int ret;
 
        dprintk("poll called\n");
-       if (rx == NULL)
-               return -ENODEV;
-
-       mutex_lock(&rx->buf_lock);
 
-       poll_wait(filep, &rx->buf.wait_poll, wait);
+       rx = get_ir_rx(ir);
+       if (rx == NULL) {
+               /*
+                * Revisit this, if our poll function ever reports writeable
+                * status for Tx
+                */
+               dprintk("poll result = POLLERR\n");
+               return POLLERR;
+       }
 
-       dprintk("poll result = %s\n",
-               lirc_buffer_empty(&rx->buf) ? "0" : "POLLIN|POLLRDNORM");
+       /*
+        * Add our lirc_buffer's wait_queue to the poll_table. A wake up on
+        * that buffer's wait queue indicates we may have a new poll status.
+        */
+       poll_wait(filep, &rbuf->wait_poll, wait);
 
-       ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM);
+       /* Indicate what ops could happen immediately without blocking */
+       ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM);
 
-       mutex_unlock(&rx->buf_lock);
+       dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none");
        return ret;
 }
 
@@ -1030,11 +1231,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        struct IR *ir = filep->private_data;
        int result;
-       unsigned long mode, features = 0;
+       unsigned long mode, features;
 
-       features |= LIRC_CAN_SEND_PULSE;
-       if (ir->rx != NULL)
-               features |= LIRC_CAN_REC_LIRCCODE;
+       features = ir->l.features;
 
        switch (cmd) {
        case LIRC_GET_LENGTH:
@@ -1061,9 +1260,15 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                        result = -EINVAL;
                break;
        case LIRC_GET_SEND_MODE:
+               if (!(features&LIRC_CAN_SEND_MASK))
+                       return -ENOSYS;
+
                result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
                break;
        case LIRC_SET_SEND_MODE:
+               if (!(features&LIRC_CAN_SEND_MASK))
+                       return -ENOSYS;
+
                result = get_user(mode, (unsigned long *) arg);
                if (!result && mode != LIRC_MODE_PULSE)
                        return -EINVAL;
@@ -1074,13 +1279,24 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        return result;
 }
 
-/* ir_devices_lock must be held */
-static struct IR *find_ir_device_by_minor(unsigned int minor)
+static struct IR *get_ir_device_by_minor(unsigned int minor)
 {
-       if (minor >= MAX_IRCTL_DEVICES)
-               return NULL;
+       struct IR *ir;
+       struct IR *ret = NULL;
+
+       mutex_lock(&ir_devices_lock);
+
+       if (!list_empty(&ir_devices_list)) {
+               list_for_each_entry(ir, &ir_devices_list, list) {
+                       if (ir->l.minor == minor) {
+                               ret = get_ir_device(ir, true);
+                               break;
+                       }
+               }
+       }
 
-       return ir_devices[minor];
+       mutex_unlock(&ir_devices_lock);
+       return ret;
 }
 
 /*
@@ -1090,31 +1306,20 @@ static struct IR *find_ir_device_by_minor(unsigned int minor)
 static int open(struct inode *node, struct file *filep)
 {
        struct IR *ir;
-       int ret;
        unsigned int minor = MINOR(node->i_rdev);
 
        /* find our IR struct */
-       mutex_lock(&ir_devices_lock);
-       ir = find_ir_device_by_minor(minor);
-       mutex_unlock(&ir_devices_lock);
+       ir = get_ir_device_by_minor(minor);
 
        if (ir == NULL)
                return -ENODEV;
 
-       /* increment in use count */
-       mutex_lock(&ir->ir_lock);
-       ++ir->open;
-       ret = set_use_inc(ir);
-       if (ret != 0) {
-               --ir->open;
-               mutex_unlock(&ir->ir_lock);
-               return ret;
-       }
-       mutex_unlock(&ir->ir_lock);
+       atomic_inc(&ir->open_count);
 
        /* stash our IR struct */
        filep->private_data = ir;
 
+       nonseekable_open(node, filep);
        return 0;
 }
 
@@ -1128,22 +1333,12 @@ static int close(struct inode *node, struct file *filep)
                return -ENODEV;
        }
 
-       /* decrement in use count */
-       mutex_lock(&ir->ir_lock);
-       --ir->open;
-       set_use_dec(ir);
-       mutex_unlock(&ir->ir_lock);
+       atomic_dec(&ir->open_count);
 
+       put_ir_device(ir, false);
        return 0;
 }
 
-static struct lirc_driver lirc_template = {
-       .name           = "lirc_zilog",
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .owner          = THIS_MODULE
-};
-
 static int ir_remove(struct i2c_client *client);
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
 
@@ -1170,7 +1365,7 @@ static struct i2c_driver driver = {
 
 static const struct file_operations lirc_fops = {
        .owner          = THIS_MODULE,
-       .llseek         = lseek,
+       .llseek         = no_llseek,
        .read           = read,
        .write          = write,
        .poll           = poll,
@@ -1182,97 +1377,64 @@ static const struct file_operations lirc_fops = {
        .release        = close
 };
 
-static void destroy_rx_kthread(struct IR_rx *rx)
-{
-       /* end up polling thread */
-       if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) {
-               kthread_stop(rx->task);
-               rx->task = NULL;
-       }
-}
+static struct lirc_driver lirc_template = {
+       .name           = "lirc_zilog",
+       .minor          = -1,
+       .code_length    = 13,
+       .buffer_size    = BUFLEN / 2,
+       .sample_rate    = 0, /* tell lirc_dev to not start its own kthread */
+       .chunk_size     = 2,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .owner          = THIS_MODULE,
+};
 
-/* ir_devices_lock must be held */
-static int add_ir_device(struct IR *ir)
+static int ir_remove(struct i2c_client *client)
 {
-       int i;
-
-       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
-               if (ir_devices[i] == NULL) {
-                       ir_devices[i] = ir;
-                       break;
+       if (strncmp("ir_tx_z8", client->name, 8) == 0) {
+               struct IR_tx *tx = i2c_get_clientdata(client);
+               if (tx != NULL) {
+                       mutex_lock(&tx->client_lock);
+                       tx->c = NULL;
+                       mutex_unlock(&tx->client_lock);
+                       put_ir_tx(tx, false);
                }
-
-       return i == MAX_IRCTL_DEVICES ? -ENOMEM : i;
-}
-
-/* ir_devices_lock must be held */
-static void del_ir_device(struct IR *ir)
-{
-       int i;
-
-       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
-               if (ir_devices[i] == ir) {
-                       ir_devices[i] = NULL;
-                       break;
+       } else if (strncmp("ir_rx_z8", client->name, 8) == 0) {
+               struct IR_rx *rx = i2c_get_clientdata(client);
+               if (rx != NULL) {
+                       mutex_lock(&rx->client_lock);
+                       rx->c = NULL;
+                       mutex_unlock(&rx->client_lock);
+                       put_ir_rx(rx, false);
                }
-}
-
-static int ir_remove(struct i2c_client *client)
-{
-       struct IR *ir = i2c_get_clientdata(client);
-
-       mutex_lock(&ir_devices_lock);
-
-       if (ir == NULL) {
-               /* We destroyed everything when the first client came through */
-               mutex_unlock(&ir_devices_lock);
-               return 0;
        }
-
-       /* Good-bye LIRC */
-       lirc_unregister_driver(ir->l.minor);
-
-       /* Good-bye Rx */
-       destroy_rx_kthread(ir->rx);
-       if (ir->rx != NULL) {
-               if (ir->rx->buf.fifo_initialized)
-                       lirc_buffer_free(&ir->rx->buf);
-               i2c_set_clientdata(ir->rx->c, NULL);
-               kfree(ir->rx);
-       }
-
-       /* Good-bye Tx */
-       i2c_set_clientdata(ir->tx->c, NULL);
-       kfree(ir->tx);
-
-       /* Good-bye IR */
-       del_ir_device(ir);
-       kfree(ir);
-
-       mutex_unlock(&ir_devices_lock);
        return 0;
 }
 
 
 /* ir_devices_lock must be held */
-static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter)
+static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter)
 {
-       int i;
-       struct IR *ir = NULL;
+       struct IR *ir;
 
-       for (i = 0; i < MAX_IRCTL_DEVICES; i++)
-               if (ir_devices[i] != NULL &&
-                   ir_devices[i]->adapter == adapter) {
-                       ir = ir_devices[i];
-                       break;
+       if (list_empty(&ir_devices_list))
+               return NULL;
+
+       list_for_each_entry(ir, &ir_devices_list, list)
+               if (ir->adapter == adapter) {
+                       get_ir_device(ir, true);
+                       return ir;
                }
 
-       return ir;
+       return NULL;
 }
 
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct IR *ir;
+       struct IR_tx *tx;
+       struct IR_rx *rx;
        struct i2c_adapter *adap = client->adapter;
        int ret;
        bool tx_probe = false;
@@ -1296,133 +1458,170 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
        mutex_lock(&ir_devices_lock);
 
        /* Use a single struct IR instance for both the Rx and Tx functions */
-       ir = find_ir_device_by_adapter(adap);
+       ir = get_ir_device_by_adapter(adap);
        if (ir == NULL) {
                ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
                if (ir == NULL) {
                        ret = -ENOMEM;
                        goto out_no_ir;
                }
+               kref_init(&ir->ref);
+
                /* store for use in ir_probe() again, and open() later on */
-               ret = add_ir_device(ir);
-               if (ret)
-                       goto out_free_ir;
+               INIT_LIST_HEAD(&ir->list);
+               list_add_tail(&ir->list, &ir_devices_list);
 
                ir->adapter = adap;
                mutex_init(&ir->ir_lock);
+               atomic_set(&ir->open_count, 0);
+               spin_lock_init(&ir->tx_ref_lock);
+               spin_lock_init(&ir->rx_ref_lock);
 
                /* set lirc_dev stuff */
                memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
-               ir->l.minor       = minor; /* module option */
-               ir->l.code_length = 13;
-               ir->l.rbuf        = NULL;
-               ir->l.fops        = &lirc_fops;
-               ir->l.data        = ir;
-               ir->l.dev         = &adap->dev;
-               ir->l.sample_rate = 0;
+               /*
+                * FIXME this is a pointer reference to us, but no refcount.
+                *
+                * This OK for now, since lirc_dev currently won't touch this
+                * buffer as we provide our own lirc_fops.
+                *
+                * Currently our own lirc_fops rely on this ir->l.rbuf pointer
+                */
+               ir->l.rbuf = &ir->rbuf;
+               ir->l.dev  = &adap->dev;
+               ret = lirc_buffer_init(ir->l.rbuf,
+                                      ir->l.chunk_size, ir->l.buffer_size);
+               if (ret)
+                       goto out_put_ir;
        }
 
        if (tx_probe) {
+               /* Get the IR_rx instance for later, if already allocated */
+               rx = get_ir_rx(ir);
+
                /* Set up a struct IR_tx instance */
-               ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
-               if (ir->tx == NULL) {
+               tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
+               if (tx == NULL) {
                        ret = -ENOMEM;
-                       goto out_free_xx;
+                       goto out_put_xx;
                }
-
-               ir->tx->c = client;
-               ir->tx->need_boot = 1;
-               ir->tx->post_tx_ready_poll =
+               kref_init(&tx->ref);
+               ir->tx = tx;
+
+               ir->l.features |= LIRC_CAN_SEND_PULSE;
+               mutex_init(&tx->client_lock);
+               tx->c = client;
+               tx->need_boot = 1;
+               tx->post_tx_ready_poll =
                               (id->driver_data & ID_FLAG_HDPVR) ? false : true;
+
+               /* An ir ref goes to the struct IR_tx instance */
+               tx->ir = get_ir_device(ir, true);
+
+               /* A tx ref goes to the i2c_client */
+               i2c_set_clientdata(client, get_ir_tx(ir));
+
+               /*
+                * Load the 'firmware'.  We do this before registering with
+                * lirc_dev, so the first firmware load attempt does not happen
+                * after a open() or write() call on the device.
+                *
+                * Failure here is not deemed catastrophic, so the receiver will
+                * still be usable.  Firmware load will be retried in write(),
+                * if it is needed.
+                */
+               fw_load(tx);
+
+               /* Proceed only if the Rx client is also ready or not needed */
+               if (rx == NULL && !tx_only) {
+                       zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting"
+                                  " on IR Rx.\n", adap->name, adap->nr);
+                       goto out_ok;
+               }
        } else {
+               /* Get the IR_tx instance for later, if already allocated */
+               tx = get_ir_tx(ir);
+
                /* Set up a struct IR_rx instance */
-               ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
-               if (ir->rx == NULL) {
+               rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
+               if (rx == NULL) {
                        ret = -ENOMEM;
-                       goto out_free_xx;
+                       goto out_put_xx;
                }
+               kref_init(&rx->ref);
+               ir->rx = rx;
 
-               ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2);
-               if (ret)
-                       goto out_free_xx;
-
-               mutex_init(&ir->rx->buf_lock);
-               ir->rx->c = client;
-               ir->rx->hdpvr_data_fmt =
+               ir->l.features |= LIRC_CAN_REC_LIRCCODE;
+               mutex_init(&rx->client_lock);
+               rx->c = client;
+               rx->hdpvr_data_fmt =
                               (id->driver_data & ID_FLAG_HDPVR) ? true : false;
 
-               /* set lirc_dev stuff */
-               ir->l.rbuf = &ir->rx->buf;
-       }
-
-       i2c_set_clientdata(client, ir);
+               /* An ir ref goes to the struct IR_rx instance */
+               rx->ir = get_ir_device(ir, true);
 
-       /* Proceed only if we have the required Tx and Rx clients ready to go */
-       if (ir->tx == NULL ||
-           (ir->rx == NULL && !tx_only)) {
-               zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on "
-                          "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name,
-                          adap->nr, tx_probe ? "Rx" : "Tx");
-               goto out_ok;
-       }
+               /* An rx ref goes to the i2c_client */
+               i2c_set_clientdata(client, get_ir_rx(ir));
 
-       /* initialise RX device */
-       if (ir->rx != NULL) {
-               /* try to fire up polling thread */
-               ir->rx->task = kthread_run(lirc_thread, ir,
-                                          "zilog-rx-i2c-%d", adap->nr);
-               if (IS_ERR(ir->rx->task)) {
-                       ret = PTR_ERR(ir->rx->task);
+               /*
+                * Start the polling thread.
+                * It will only perform an empty loop around schedule_timeout()
+                * until we register with lirc_dev and the first user open()
+                */
+               /* An ir ref goes to the new rx polling kthread */
+               rx->task = kthread_run(lirc_thread, get_ir_device(ir, true),
+                                      "zilog-rx-i2c-%d", adap->nr);
+               if (IS_ERR(rx->task)) {
+                       ret = PTR_ERR(rx->task);
                        zilog_error("%s: could not start IR Rx polling thread"
                                    "\n", __func__);
-                       goto out_free_xx;
+                       /* Failed kthread, so put back the ir ref */
+                       put_ir_device(ir, true);
+                       /* Failure exit, so put back rx ref from i2c_client */
+                       i2c_set_clientdata(client, NULL);
+                       put_ir_rx(rx, true);
+                       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+                       goto out_put_xx;
+               }
+
+               /* Proceed only if the Tx client is also ready */
+               if (tx == NULL) {
+                       zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting"
+                                  " on IR Tx.\n", adap->name, adap->nr);
+                       goto out_ok;
                }
        }
 
        /* register with lirc */
+       ir->l.minor = minor; /* module option: user requested minor number */
        ir->l.minor = lirc_register_driver(&ir->l);
        if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
                zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n",
                            __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
                ret = -EBADRQC;
-               goto out_free_thread;
+               goto out_put_xx;
        }
+       zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
+                  adap->name, adap->nr, ir->l.minor);
 
-       /*
-        * if we have the tx device, load the 'firmware'.  We do this
-        * after registering with lirc as otherwise hotplug seems to take
-        * 10s to create the lirc device.
-        */
-       ret = tx_init(ir->tx);
-       if (ret != 0)
-               goto out_unregister;
-
-       zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n",
-                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
 out_ok:
+       if (rx != NULL)
+               put_ir_rx(rx, true);
+       if (tx != NULL)
+               put_ir_tx(tx, true);
+       put_ir_device(ir, true);
+       zilog_info("probe of IR %s on %s (i2c-%d) done\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
        mutex_unlock(&ir_devices_lock);
        return 0;
 
-out_unregister:
-       lirc_unregister_driver(ir->l.minor);
-out_free_thread:
-       destroy_rx_kthread(ir->rx);
-out_free_xx:
-       if (ir->rx != NULL) {
-               if (ir->rx->buf.fifo_initialized)
-                       lirc_buffer_free(&ir->rx->buf);
-               if (ir->rx->c != NULL)
-                       i2c_set_clientdata(ir->rx->c, NULL);
-               kfree(ir->rx);
-       }
-       if (ir->tx != NULL) {
-               if (ir->tx->c != NULL)
-                       i2c_set_clientdata(ir->tx->c, NULL);
-               kfree(ir->tx);
-       }
-out_free_ir:
-       del_ir_device(ir);
-       kfree(ir);
+out_put_xx:
+       if (rx != NULL)
+               put_ir_rx(rx, true);
+       if (tx != NULL)
+               put_ir_tx(tx, true);
+out_put_ir:
+       put_ir_device(ir, true);
 out_no_ir:
        zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n",
                    __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
@@ -1438,7 +1637,6 @@ static int __init zilog_init(void)
        zilog_notify("Zilog/Hauppauge IR driver initializing\n");
 
        mutex_init(&tx_data_lock);
-       mutex_init(&ir_devices_lock);
 
        request_module("firmware_class");
 
index b90c2cf3e2476e8b5dc625dd8b847be0a3895b82..750fe5045efaa5babdd33fa7b5babd0649d67c89 100644 (file)
@@ -574,6 +574,7 @@ static const struct backlight_ops dcon_bl_ops = {
 
 static struct backlight_properties dcon_bl_props = {
        .max_brightness = 15,
+       .type = BACKLIGHT_RAW,
        .power = FB_BLANK_UNBLANK,
 };
 
index 6607a89ccb4b309a4e34b3f7171e82cee06ba978..25294462b8b6aa55dbe031e10a173e70739eea5e 100644 (file)
@@ -781,6 +781,7 @@ static int __init samsung_init(void)
 
        /* create a backlight device to talk to this one */
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = sabi_config->max_brightness;
        backlight_device = backlight_device_register("samsung", &sdev->dev,
                                                     NULL, &backlight_ops,
diff --git a/drivers/staging/se401/Kconfig b/drivers/staging/se401/Kconfig
deleted file mode 100644 (file)
index b7f8222..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-config USB_SE401
-       tristate "USB SE401 Camera support (DEPRECATED)"
-       depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/video4linux/se401.txt>
-         for more information and for a list of supported cameras.
-
-         This driver uses the deprecated V4L1 API and will be removed in
-         2.6.39, unless someone converts it to the V4L2 API.
-
-         To compile this driver as a module, choose M here: the
-         module will be called se401.
diff --git a/drivers/staging/se401/Makefile b/drivers/staging/se401/Makefile
deleted file mode 100644 (file)
index b465d49..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SE401)         += se401.o
diff --git a/drivers/staging/se401/TODO b/drivers/staging/se401/TODO
deleted file mode 100644 (file)
index 3b2c038..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-This is an obsolete driver for some old webcams that still use V4L1 API. 
-As V4L1 support is being removed from kernel, if nobody take care on it, 
-the driver will be removed for 2.6.39.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/se401/se401.c b/drivers/staging/se401/se401.c
deleted file mode 100644 (file)
index 41360d7..0000000
+++ /dev/null
@@ -1,1492 +0,0 @@
-/*
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- *
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 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.
- *
- * 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.
- *
- *
- * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
- * their chipset available and supporting me while writing this driver.
- *     - Jeroen Vreeken
- */
-
-static const char version[] = "0.24";
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/usb.h>
-#include "se401.h"
-
-static int flickerless;
-static int video_nr = -1;
-
-static struct usb_device_id device_table[] = {
-       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
-       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
-       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
-       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
-       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
-MODULE_DESCRIPTION("SE401 USB Camera Driver");
-MODULE_LICENSE("GPL");
-module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless,
-               "Net frequency to adjust exposure time to (0/50/60)");
-module_param(video_nr, int, 0);
-
-static struct usb_driver se401_driver;
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr +=  PAGE_SIZE;
-               size -=  PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr +=  PAGE_SIZE;
-               size -=  PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-
-
-/****************************************************************************
- *
- * se401 register read/write functions
- *
- ***************************************************************************/
-
-static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
-                        unsigned short value, unsigned char *cp, int size)
-{
-       return usb_control_msg(
-               se401->dev,
-               set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
-               req,
-               (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               value,
-               0,
-               cp,
-               size,
-               1000
-       );
-}
-
-static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
-                            unsigned short param)
-{
-       /* specs say that the selector (address) should go in the value field
-          and the param in index, but in the logs of the windows driver they do
-          this the other way around...
-        */
-       return usb_control_msg(
-               se401->dev,
-               usb_sndctrlpipe(se401->dev, 0),
-               SE401_REQ_SET_EXT_FEATURE,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               param,
-               selector,
-               NULL,
-               0,
-               1000
-       );
-}
-
-static unsigned short se401_get_feature(struct usb_se401 *se401,
-                                       unsigned short selector)
-{
-       /* For 'set' the selecetor should be in index, not sure if the spec is
-          wrong here to....
-        */
-       unsigned char cp[2];
-       usb_control_msg(
-               se401->dev,
-               usb_rcvctrlpipe(se401->dev, 0),
-               SE401_REQ_GET_EXT_FEATURE,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0,
-               selector,
-               cp,
-               2,
-               1000
-       );
-       return cp[0]+cp[1]*256;
-}
-
-/****************************************************************************
- *
- * Camera control
- *
- ***************************************************************************/
-
-
-static int se401_send_pict(struct usb_se401 *se401)
-{
-       /* integration time low */
-       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
-       /* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
-       /* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
-       /* reset level value */
-       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
-       /* red color gain */
-       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
-       /* green color gain */
-       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
-       /* blue color gain */
-       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
-
-       return 0;
-}
-
-static void se401_set_exposure(struct usb_se401 *se401, int brightness)
-{
-       int integration = brightness << 5;
-
-       if (flickerless == 50)
-               integration = integration-integration % 106667;
-       if (flickerless == 60)
-               integration = integration-integration % 88889;
-       se401->brightness = integration >> 5;
-       se401->expose_h = (integration >> 16) & 0xff;
-       se401->expose_m = (integration >> 8) & 0xff;
-       se401->expose_l = integration & 0xff;
-}
-
-static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       p->brightness = se401->brightness;
-       if (se401->enhance)
-               p->whiteness = 32768;
-       else
-               p->whiteness = 0;
-
-       p->colour = 65535;
-       p->contrast = 65535;
-       p->hue = se401->rgain << 10;
-       p->palette = se401->palette;
-       p->depth = 3; /* rgb24 */
-       return 0;
-}
-
-
-static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       if (p->palette != VIDEO_PALETTE_RGB24)
-               return 1;
-       se401->palette = p->palette;
-       if (p->hue != se401->hue) {
-               se401->rgain =  p->hue >> 10;
-               se401->bgain =  0x40-(p->hue >> 10);
-               se401->hue = p->hue;
-       }
-       if (p->brightness != se401->brightness)
-               se401_set_exposure(se401, p->brightness);
-
-       if (p->whiteness >= 32768)
-               se401->enhance = 1;
-       else
-               se401->enhance = 0;
-       se401_send_pict(se401);
-       se401_send_pict(se401);
-       return 0;
-}
-
-/*
-       Hyundai have some really nice docs about this and other sensor related
-       stuff on their homepage: www.hei.co.kr
-*/
-static void se401_auto_resetlevel(struct usb_se401 *se401)
-{
-       unsigned int ahrc, alrc;
-       int oldreset = se401->resetlevel;
-
-       /* For some reason this normally read-only register doesn't get reset
-          to zero after reading them just once...
-        */
-       se401_get_feature(se401, HV7131_REG_HIREFNOH);
-       se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       se401_get_feature(se401, HV7131_REG_LOREFNOH);
-       se401_get_feature(se401, HV7131_REG_LOREFNOL);
-       ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
-           se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
-           se401_get_feature(se401, HV7131_REG_LOREFNOL);
-
-       /* Not an exact science, but it seems to work pretty well... */
-       if (alrc > 10) {
-               while (alrc >= 10 && se401->resetlevel < 63) {
-                       se401->resetlevel++;
-                       alrc /= 2;
-               }
-       } else if (ahrc > 20) {
-               while (ahrc >= 20 && se401->resetlevel > 0) {
-                       se401->resetlevel--;
-                       ahrc /= 2;
-               }
-       }
-       if (se401->resetlevel != oldreset)
-               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
-
-       return;
-}
-
-/* irq handler for snapshot button */
-static void se401_button_irq(struct urb *urb)
-{
-       struct usb_se401 *se401 = urb->context;
-       int status;
-
-       if (!se401->dev) {
-               dev_info(&urb->dev->dev, "device vapourished\n");
-               return;
-       }
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d",
-                                                       __func__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d",
-                                                       __func__, urb->status);
-               goto exit;
-       }
-
-       if (urb->actual_length  >= 2)
-               if (se401->button)
-                       se401->buttonpressed = 1;
-exit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               err("%s - usb_submit_urb failed with result %d",
-                    __func__, status);
-}
-
-static void se401_video_irq(struct urb *urb)
-{
-       struct usb_se401 *se401 = urb->context;
-       int length = urb->actual_length;
-
-       /* ohoh... */
-       if (!se401->streaming)
-               return;
-
-       if (!se401->dev) {
-               dev_info(&urb->dev->dev, "device vapourished\n");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               se401->nullpackets = 0;
-               switch (se401->scratch[se401->scratch_next].state) {
-               case BUFFER_READY:
-               case BUFFER_BUSY:
-                       se401->dropped++;
-                       break;
-               case BUFFER_UNUSED:
-                       memcpy(se401->scratch[se401->scratch_next].data,
-                               (unsigned char *)urb->transfer_buffer, length);
-                       se401->scratch[se401->scratch_next].state
-                                                       = BUFFER_READY;
-                       se401->scratch[se401->scratch_next].offset
-                                                       = se401->bayeroffset;
-                       se401->scratch[se401->scratch_next].length = length;
-                       if (waitqueue_active(&se401->wq))
-                               wake_up_interruptible(&se401->wq);
-                       se401->scratch_overflow = 0;
-                       se401->scratch_next++;
-                       if (se401->scratch_next >= SE401_NUMSCRATCH)
-                               se401->scratch_next = 0;
-                       break;
-               }
-               se401->bayeroffset += length;
-               if (se401->bayeroffset >= se401->cheight * se401->cwidth)
-                       se401->bayeroffset = 0;
-       } else {
-               se401->nullpackets++;
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS)
-                       if (waitqueue_active(&se401->wq))
-                               wake_up_interruptible(&se401->wq);
-       }
-
-       /* Resubmit urb for new data */
-       urb->status = 0;
-       urb->dev = se401->dev;
-       if (usb_submit_urb(urb, GFP_KERNEL))
-               dev_info(&urb->dev->dev, "urb burned down\n");
-       return;
-}
-
-static void se401_send_size(struct usb_se401 *se401, int width, int height)
-{
-       int i = 0;
-       int mode = 0x03; /* No compression */
-       int sendheight = height;
-       int sendwidth = width;
-
-       /* JangGu compression can only be used with the camera supported sizes,
-          but bayer seems to work with any size that fits on the sensor.
-          We check if we can use compression with the current size with either
-          4 or 16 times subcapturing, if not we use uncompressed bayer data
-          but this will result in cutouts of the maximum size....
-        */
-       while (i < se401->sizes && !(se401->width[i] == width &&
-                                               se401->height[i] == height))
-               i++;
-       while (i < se401->sizes) {
-               if (se401->width[i] == width * 2 &&
-                               se401->height[i] == height * 2) {
-                       sendheight = se401->height[i];
-                       sendwidth = se401->width[i];
-                       mode = 0x40;
-               }
-               if (se401->width[i] == width * 4 &&
-                               se401->height[i] == height * 4) {
-                       sendheight = se401->height[i];
-                       sendwidth = se401->width[i];
-                       mode = 0x42;
-               }
-               i++;
-       }
-
-       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
-       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
-
-       if (mode == 0x03)
-               se401->format = FMT_BAYER;
-       else
-               se401->format = FMT_JANGGU;
-}
-
-/*
-       In this function se401_send_pict is called several times,
-       for some reason (depending on the state of the sensor and the phase of
-       the moon :) doing this only in either place doesn't always work...
-*/
-static int se401_start_stream(struct usb_se401 *se401)
-{
-       struct urb *urb;
-       int err = 0, i;
-       se401->streaming = 1;
-
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* Set picture settings */
-       /* windowed + pix intg */
-       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
-       se401_send_pict(se401);
-
-       se401_send_size(se401, se401->cwidth, se401->cheight);
-
-       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE,
-                                                               0, NULL, 0);
-
-       /* Do some memory allocation */
-       for (i = 0; i < SE401_NUMFRAMES; i++) {
-               se401->frame[i].data = se401->fbuf + i * se401->maxframesize;
-               se401->frame[i].curpix = 0;
-       }
-       for (i = 0; i < SE401_NUMSBUF; i++) {
-               se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-               if (!se401->sbuf[i].data) {
-                       for (i = i - 1; i >= 0; i--) {
-                               kfree(se401->sbuf[i].data);
-                               se401->sbuf[i].data = NULL;
-                       }
-                       return -ENOMEM;
-               }
-       }
-
-       se401->bayeroffset = 0;
-       se401->scratch_next = 0;
-       se401->scratch_use = 0;
-       se401->scratch_overflow = 0;
-       for (i = 0; i < SE401_NUMSCRATCH; i++) {
-               se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-               if (!se401->scratch[i].data) {
-                       for (i = i - 1; i >= 0; i--) {
-                               kfree(se401->scratch[i].data);
-                               se401->scratch[i].data = NULL;
-                       }
-                       goto nomem_sbuf;
-               }
-               se401->scratch[i].state = BUFFER_UNUSED;
-       }
-
-       for (i = 0; i < SE401_NUMSBUF; i++) {
-               urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!urb) {
-                       for (i = i - 1; i >= 0; i--) {
-                               usb_kill_urb(se401->urb[i]);
-                               usb_free_urb(se401->urb[i]);
-                               se401->urb[i] = NULL;
-                       }
-                       goto nomem_scratch;
-               }
-
-               usb_fill_bulk_urb(urb, se401->dev,
-                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
-                       se401->sbuf[i].data, SE401_PACKETSIZE,
-                       se401_video_irq,
-                       se401);
-
-               se401->urb[i] = urb;
-
-               err = usb_submit_urb(se401->urb[i], GFP_KERNEL);
-               if (err)
-                       err("urb burned down");
-       }
-
-       se401->framecount = 0;
-
-       return 0;
-
- nomem_scratch:
-       for (i = 0; i < SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-               se401->scratch[i].data = NULL;
-       }
- nomem_sbuf:
-       for (i = 0; i < SE401_NUMSBUF; i++) {
-               kfree(se401->sbuf[i].data);
-               se401->sbuf[i].data = NULL;
-       }
-       return -ENOMEM;
-}
-
-static int se401_stop_stream(struct usb_se401 *se401)
-{
-       int i;
-
-       if (!se401->streaming || !se401->dev)
-               return 1;
-
-       se401->streaming = 0;
-
-       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-
-       for (i = 0; i < SE401_NUMSBUF; i++)
-               if (se401->urb[i]) {
-                       usb_kill_urb(se401->urb[i]);
-                       usb_free_urb(se401->urb[i]);
-                       se401->urb[i] = NULL;
-                       kfree(se401->sbuf[i].data);
-               }
-       for (i = 0; i < SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-               se401->scratch[i].data = NULL;
-       }
-
-       return 0;
-}
-
-static int se401_set_size(struct usb_se401 *se401, int width, int height)
-{
-       int wasstreaming = se401->streaming;
-       /* Check to see if we need to change */
-       if (se401->cwidth == width && se401->cheight == height)
-               return 0;
-
-       /* Check for a valid mode */
-       if (!width || !height)
-               return 1;
-       if ((width & 1) || (height & 1))
-               return 1;
-       if (width > se401->width[se401->sizes-1])
-               return 1;
-       if (height > se401->height[se401->sizes-1])
-               return 1;
-
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               se401_stop_stream(se401);
-       se401->cwidth = width;
-       se401->cheight = height;
-       if (wasstreaming)
-               se401_start_stream(se401);
-       return 0;
-}
-
-
-/****************************************************************************
- *
- * Video Decoding
- *
- ***************************************************************************/
-
-/*
-       This shouldn't really be done in a v4l driver....
-       But it does make the image look a lot more usable.
-       Basically it lifts the dark pixels more than the light pixels.
-*/
-static inline void enhance_picture(unsigned char *frame, int len)
-{
-       while (len--) {
-               *frame = (((*frame^255)*(*frame^255))/255)^255;
-               frame++;
-       }
-}
-
-static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
-{
-       struct se401_frame *frame = &se401->frame[se401->curframe];
-       int linelength = se401->cwidth * 3;
-
-       if (frame->curlinepix >= linelength) {
-               frame->curlinepix = 0;
-               frame->curline += linelength;
-       }
-
-       /* First three are absolute, all others relative.
-        * Format is rgb from right to left (mirrorred image),
-        * we flip it to get bgr from left to right. */
-       if (frame->curlinepix < 3)
-               *(frame->curline-frame->curlinepix) = 1 + data * 4;
-       else
-               *(frame->curline-frame->curlinepix) =
-                   *(frame->curline-frame->curlinepix + 3) + data * 4;
-       frame->curlinepix++;
-}
-
-static inline void decode_JangGu_vlc(struct usb_se401 *se401,
-                       unsigned char *data, int bit_exp, int packetlength)
-{
-       int pos = 0;
-       int vlc_cod = 0;
-       int vlc_size = 0;
-       int vlc_data = 0;
-       int bit_cur;
-       int bit;
-       data += 4;
-       while (pos < packetlength) {
-               bit_cur = 8;
-               while (bit_cur && bit_exp) {
-                       bit = ((*data) >> (bit_cur-1))&1;
-                       if (!vlc_cod) {
-                               if (bit) {
-                                       vlc_size++;
-                               } else {
-                                       if (!vlc_size)
-                                               decode_JangGu_integrate(se401, 0);
-                                       else {
-                                               vlc_cod = 2;
-                                               vlc_data = 0;
-                                       }
-                               }
-                       } else {
-                               if (vlc_cod == 2) {
-                                       if (!bit)
-                                               vlc_data =  -(1 << vlc_size) + 1;
-                                       vlc_cod--;
-                               }
-                               vlc_size--;
-                               vlc_data += bit << vlc_size;
-                               if (!vlc_size) {
-                                       decode_JangGu_integrate(se401, vlc_data);
-                                       vlc_cod = 0;
-                               }
-                       }
-                       bit_cur--;
-                       bit_exp--;
-               }
-               pos++;
-               data++;
-       }
-}
-
-static inline void decode_JangGu(struct usb_se401 *se401,
-                                               struct se401_scratch *buffer)
-{
-       unsigned char *data = buffer->data;
-       int len = buffer->length;
-       int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size;
-       int datapos = 0;
-
-       /* New image? */
-       if (!se401->frame[se401->curframe].curpix) {
-               se401->frame[se401->curframe].curlinepix = 0;
-               se401->frame[se401->curframe].curline =
-                   se401->frame[se401->curframe].data+
-                   se401->cwidth * 3 - 1;
-               if (se401->frame[se401->curframe].grabstate == FRAME_READY)
-                       se401->frame[se401->curframe].grabstate = FRAME_GRABBING;
-               se401->vlcdatapos = 0;
-       }
-       while (datapos < len) {
-               size = 1024 - se401->vlcdatapos;
-               if (size+datapos > len)
-                       size = len-datapos;
-               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
-               se401->vlcdatapos += size;
-               packetlength = 0;
-               if (se401->vlcdatapos >= 4) {
-                       bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8);
-                       pix_exp = se401->vlcdata[1] +
-                                       ((se401->vlcdata[0] & 0x3f) << 8);
-                       frameinfo = se401->vlcdata[0] & 0xc0;
-                       packetlength = ((bit_exp + 47) >> 4) << 1;
-                       if (packetlength > 1024) {
-                               se401->vlcdatapos = 0;
-                               datapos = len;
-                               packetlength = 0;
-                               se401->error++;
-                               se401->frame[se401->curframe].curpix = 0;
-                       }
-               }
-               if (packetlength && se401->vlcdatapos >= packetlength) {
-                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp,
-                                                               packetlength);
-                       se401->frame[se401->curframe].curpix += pix_exp * 3;
-                       datapos += size-(se401->vlcdatapos-packetlength);
-                       se401->vlcdatapos = 0;
-                       if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) {
-                               if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) {
-                                       if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) {
-                                               se401->frame[se401->curframe].grabstate = FRAME_DONE;
-                                               se401->framecount++;
-                                               se401->readcount++;
-                                       }
-                                       if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY)
-                                               se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1);
-                               } else
-                                       se401->error++;
-                               se401->frame[se401->curframe].curpix = 0;
-                               datapos = len;
-                       }
-               } else
-                       datapos += size;
-       }
-}
-
-static inline void decode_bayer(struct usb_se401 *se401,
-                                               struct se401_scratch *buffer)
-{
-       unsigned char *data = buffer->data;
-       int len = buffer->length;
-       int offset = buffer->offset;
-       int datasize = se401->cwidth * se401->cheight;
-       struct se401_frame *frame = &se401->frame[se401->curframe];
-       unsigned char *framedata = frame->data, *curline, *nextline;
-       int width = se401->cwidth;
-       int blineoffset = 0, bline;
-       int linelength = width * 3, i;
-
-
-       if (frame->curpix == 0) {
-               if (frame->grabstate == FRAME_READY)
-                       frame->grabstate = FRAME_GRABBING;
-
-               frame->curline = framedata + linelength;
-               frame->curlinepix = 0;
-       }
-
-       if (offset != frame->curpix) {
-               /* Regard frame as lost :( */
-               frame->curpix = 0;
-               se401->error++;
-               return;
-       }
-
-       /* Check if we have to much data */
-       if (frame->curpix + len > datasize)
-               len = datasize-frame->curpix;
-
-       if (se401->cheight % 4)
-               blineoffset = 1;
-       bline = frame->curpix / se401->cwidth+blineoffset;
-
-       curline = frame->curline;
-       nextline = curline + linelength;
-       if (nextline >= framedata+datasize * 3)
-               nextline = curline;
-       while (len) {
-               if (frame->curlinepix >= width) {
-                       frame->curlinepix -= width;
-                       bline = frame->curpix / width + blineoffset;
-                       curline += linelength*2;
-                       nextline += linelength*2;
-                       if (curline >= framedata+datasize * 3) {
-                               frame->curlinepix++;
-                               curline -= 3;
-                               nextline -= 3;
-                               len--;
-                               data++;
-                               frame->curpix++;
-                       }
-                       if (nextline >= framedata+datasize*3)
-                               nextline = curline;
-               }
-               if (bline & 1) {
-                       if (frame->curlinepix & 1) {
-                               *(curline + 2) = *data;
-                               *(curline - 1) = *data;
-                               *(nextline + 2) = *data;
-                               *(nextline - 1) = *data;
-                       } else {
-                               *(curline + 1) =
-                                       (*(curline + 1) + *data) / 2;
-                               *(curline-2) =
-                                       (*(curline - 2) + *data) / 2;
-                               *(nextline + 1) = *data;
-                               *(nextline - 2) = *data;
-                       }
-               } else {
-                       if (frame->curlinepix & 1) {
-                               *(curline + 1) =
-                                       (*(curline + 1) + *data) / 2;
-                               *(curline - 2) =
-                                       (*(curline - 2) + *data) / 2;
-                               *(nextline + 1) = *data;
-                               *(nextline - 2) = *data;
-                       } else {
-                               *curline = *data;
-                               *(curline - 3) = *data;
-                               *nextline = *data;
-                               *(nextline - 3) = *data;
-                       }
-               }
-               frame->curlinepix++;
-               curline -= 3;
-               nextline -= 3;
-               len--;
-               data++;
-               frame->curpix++;
-       }
-       frame->curline = curline;
-
-       if (frame->curpix >= datasize) {
-               /* Fix the top line */
-               framedata += linelength;
-               for (i = 0; i < linelength; i++) {
-                       framedata--;
-                       *framedata = *(framedata + linelength);
-               }
-               /* Fix the left side (green is already present) */
-               for (i = 0; i < se401->cheight; i++) {
-                       *framedata = *(framedata + 3);
-                       *(framedata + 1) = *(framedata + 4);
-                       *(framedata + 2) = *(framedata + 5);
-                       framedata += linelength;
-               }
-               frame->curpix = 0;
-               frame->grabstate = FRAME_DONE;
-               se401->framecount++;
-               se401->readcount++;
-               if (se401->frame[(se401->curframe + 1) &
-                   (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) {
-                       se401->curframe = (se401->curframe+1) &
-                                                       (SE401_NUMFRAMES-1);
-               }
-       }
-}
-
-static int se401_newframe(struct usb_se401 *se401, int framenr)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int errors = 0;
-
-       while (se401->streaming &&
-           (se401->frame[framenr].grabstate == FRAME_READY ||
-            se401->frame[framenr].grabstate == FRAME_GRABBING)) {
-               if (!se401->frame[framenr].curpix)
-                       errors++;
-
-               wait_interruptible(
-                   se401->scratch[se401->scratch_use].state != BUFFER_READY,
-                                                   &se401->wq, &wait);
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       se401->nullpackets = 0;
-                       dev_info(&se401->dev->dev,
-                        "too many null length packets, restarting capture\n");
-                       se401_stop_stream(se401);
-                       se401_start_stream(se401);
-               } else {
-                       if (se401->scratch[se401->scratch_use].state !=
-                                                               BUFFER_READY) {
-                               se401->frame[framenr].grabstate = FRAME_ERROR;
-                               return -EIO;
-                       }
-                       se401->scratch[se401->scratch_use].state = BUFFER_BUSY;
-                       if (se401->format == FMT_JANGGU)
-                               decode_JangGu(se401,
-                                       &se401->scratch[se401->scratch_use]);
-                       else
-                               decode_bayer(se401,
-                                       &se401->scratch[se401->scratch_use]);
-
-                       se401->scratch[se401->scratch_use].state =
-                                                       BUFFER_UNUSED;
-                       se401->scratch_use++;
-                       if (se401->scratch_use >= SE401_NUMSCRATCH)
-                               se401->scratch_use = 0;
-                       if (errors > SE401_MAX_ERRORS) {
-                               errors = 0;
-                               dev_info(&se401->dev->dev,
-                                     "too many errors, restarting capture\n");
-                               se401_stop_stream(se401);
-                               se401_start_stream(se401);
-                       }
-               }
-       }
-
-       if (se401->frame[framenr].grabstate == FRAME_DONE)
-               if (se401->enhance)
-                       enhance_picture(se401->frame[framenr].data,
-                                       se401->cheight * se401->cwidth * 3);
-       return 0;
-}
-
-static void usb_se401_remove_disconnected(struct usb_se401 *se401)
-{
-       int i;
-
-       se401->dev = NULL;
-
-       for (i = 0; i < SE401_NUMSBUF; i++)
-               if (se401->urb[i]) {
-                       usb_kill_urb(se401->urb[i]);
-                       usb_free_urb(se401->urb[i]);
-                       se401->urb[i] = NULL;
-                       kfree(se401->sbuf[i].data);
-               }
-
-       for (i = 0; i < SE401_NUMSCRATCH; i++)
-               kfree(se401->scratch[i].data);
-
-       if (se401->inturb) {
-               usb_kill_urb(se401->inturb);
-               usb_free_urb(se401->inturb);
-       }
-       dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name);
-
-       /* Free the memory */
-       kfree(se401->width);
-       kfree(se401->height);
-       kfree(se401);
-}
-
-
-
-/****************************************************************************
- *
- * Video4Linux
- *
- ***************************************************************************/
-
-
-static int se401_open(struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int err = 0;
-
-       mutex_lock(&se401->lock);
-       if (se401->user) {
-               mutex_unlock(&se401->lock);
-               return -EBUSY;
-       }
-       se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
-       if (se401->fbuf)
-               file->private_data = dev;
-       else
-               err = -ENOMEM;
-       se401->user = !err;
-       mutex_unlock(&se401->lock);
-
-       return err;
-}
-
-static int se401_close(struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int i;
-
-       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
-       if (se401->removed) {
-               dev_info(&se401->dev->dev, "device unregistered\n");
-               usb_se401_remove_disconnected(se401);
-       } else {
-               for (i = 0; i < SE401_NUMFRAMES; i++)
-                       se401->frame[i].grabstate = FRAME_UNUSED;
-               if (se401->streaming)
-                       se401_stop_stream(se401);
-               se401->user = 0;
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)vdev;
-
-       if (!se401->dev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-               strcpy(b->name, se401->camera_name);
-               b->type = VID_TYPE_CAPTURE;
-               b->channels = 1;
-               b->audios = 0;
-               b->maxwidth = se401->width[se401->sizes-1];
-               b->maxheight = se401->height[se401->sizes-1];
-               b->minwidth = se401->width[0];
-               b->minheight = se401->height[0];
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               v->flags = 0;
-               v->tuners = 0;
-               v->type = VIDEO_TYPE_CAMERA;
-               strcpy(v->name, "Camera");
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOCGPICT:
-       {
-               struct video_picture *p = arg;
-
-               se401_get_pict(se401, p);
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-
-               if (se401_set_pict(se401, p))
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (se401_set_size(se401, vw->width, vw->height))
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               vw->x = 0;               /* FIXME */
-               vw->y = 0;
-               vw->chromakey = 0;
-               vw->flags = 0;
-               vw->clipcount = 0;
-               vw->width = se401->cwidth;
-               vw->height = se401->cheight;
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               memset(vm, 0, sizeof(*vm));
-               vm->size = SE401_NUMFRAMES * se401->maxframesize;
-               vm->frames = SE401_NUMFRAMES;
-               for (i = 0; i < SE401_NUMFRAMES; i++)
-                       vm->offsets[i] = se401->maxframesize * i;
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-
-               if (vm->format != VIDEO_PALETTE_RGB24)
-                       return -EINVAL;
-               if (vm->frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-               if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
-                       return -EBUSY;
-
-               /* Is this according to the v4l spec??? */
-               if (se401_set_size(se401, vm->width, vm->height))
-                       return -EINVAL;
-               se401->frame[vm->frame].grabstate = FRAME_READY;
-
-               if (!se401->streaming)
-                       se401_start_stream(se401);
-
-               /* Set the picture properties */
-               if (se401->framecount == 0)
-                       se401_send_pict(se401);
-               /* Calibrate the reset level after a few frames. */
-               if (se401->framecount % 20 == 1)
-                       se401_auto_resetlevel(se401);
-
-               return 0;
-       }
-       case VIDIOCSYNC:
-       {
-               int *frame = arg;
-               int ret = 0;
-
-               if (*frame < 0 || *frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-
-               ret = se401_newframe(se401, *frame);
-               se401->frame[*frame].grabstate = FRAME_UNUSED;
-               return ret;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               memset(vb, 0, sizeof(*vb));
-               return 0;
-       }
-       case VIDIOCKEY:
-               return 0;
-       case VIDIOCCAPTURE:
-               return -EINVAL;
-       case VIDIOCSFBUF:
-               return -EINVAL;
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-               return -EINVAL;
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               return -EINVAL;
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-       default:
-               return -ENOIOCTLCMD;
-       } /* end switch */
-
-       return 0;
-}
-
-static long se401_ioctl(struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(file, cmd, arg, se401_do_ioctl);
-}
-
-static ssize_t se401_read(struct file *file, char __user *buf,
-                    size_t count, loff_t *ppos)
-{
-       int realcount = count, ret = 0;
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-
-
-       if (se401->dev ==  NULL)
-               return -EIO;
-       if (realcount > se401->cwidth*se401->cheight*3)
-               realcount = se401->cwidth*se401->cheight*3;
-
-       /* Shouldn't happen: */
-       if (se401->frame[0].grabstate == FRAME_GRABBING)
-               return -EBUSY;
-       se401->frame[0].grabstate = FRAME_READY;
-       se401->frame[1].grabstate = FRAME_UNUSED;
-       se401->curframe = 0;
-
-       if (!se401->streaming)
-               se401_start_stream(se401);
-
-       /* Set the picture properties */
-       if (se401->framecount == 0)
-               se401_send_pict(se401);
-       /* Calibrate the reset level after a few frames. */
-       if (se401->framecount%20 == 1)
-               se401_auto_resetlevel(se401);
-
-       ret = se401_newframe(se401, 0);
-
-       se401->frame[0].grabstate = FRAME_UNUSED;
-       if (ret)
-               return ret;
-       if (copy_to_user(buf, se401->frame[0].data, realcount))
-               return -EFAULT;
-
-       return realcount;
-}
-
-static int se401_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&se401->lock);
-
-       if (se401->dev ==  NULL) {
-               mutex_unlock(&se401->lock);
-               return -EIO;
-       }
-       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1)
-                                                       & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&se401->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long)se401->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&se401->lock);
-                       return -EAGAIN;
-               }
-               start +=  PAGE_SIZE;
-               pos +=  PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -=  PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&se401->lock);
-
-       return 0;
-}
-
-static const struct v4l2_file_operations se401_fops = {
-       .owner  =       THIS_MODULE,
-       .open =         se401_open,
-       .release =      se401_close,
-       .read =         se401_read,
-       .mmap =         se401_mmap,
-       .ioctl =        se401_ioctl,
-};
-static struct video_device se401_template = {
-       .name =         "se401 USB camera",
-       .fops =         &se401_fops,
-       .release = video_device_release_empty,
-};
-
-
-
-/***************************/
-static int se401_init(struct usb_se401 *se401, int button)
-{
-       int i = 0, rc;
-       unsigned char cp[0x40];
-       char temp[200];
-       int slen;
-
-       /* led on */
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* get camera descriptor */
-       rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0,
-                                                       cp, sizeof(cp));
-       if (cp[1] != 0x41) {
-               err("Wrong descriptor type");
-               return 1;
-       }
-       slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]);
-
-       se401->sizes = cp[4] + cp[5] * 256;
-       se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->width)
-               return 1;
-       se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->height) {
-               kfree(se401->width);
-               return 1;
-       }
-       for (i = 0; i < se401->sizes; i++) {
-               se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256;
-               se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256;
-       }
-       slen += snprintf(temp + slen, 200 - slen, " Sizes:");
-       for (i = 0; i < se401->sizes; i++) {
-               slen +=  snprintf(temp + slen, 200 - slen,
-                       " %dx%d", se401->width[i], se401->height[i]);
-       }
-       dev_info(&se401->dev->dev, "%s\n", temp);
-       se401->maxframesize = se401->width[se401->sizes-1] *
-                                       se401->height[se401->sizes - 1] * 3;
-
-       rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
-       se401->cwidth = cp[0]+cp[1]*256;
-       rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
-       se401->cheight = cp[0]+cp[1]*256;
-
-       if (!(cp[2] & SE401_FORMAT_BAYER)) {
-               err("Bayer format not supported!");
-               return 1;
-       }
-       /* set output mode (BAYER) */
-       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE,
-                                               SE401_FORMAT_BAYER, NULL, 0);
-
-       rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
-       se401->brightness = cp[0]+cp[1]*256;
-       /* some default values */
-       se401->resetlevel = 0x2d;
-       se401->rgain = 0x20;
-       se401->ggain = 0x20;
-       se401->bgain = 0x20;
-       se401_set_exposure(se401, 20000);
-       se401->palette = VIDEO_PALETTE_RGB24;
-       se401->enhance = 1;
-       se401->dropped = 0;
-       se401->error = 0;
-       se401->framecount = 0;
-       se401->readcount = 0;
-
-       /* Start interrupt transfers for snapshot button */
-       if (button) {
-               se401->inturb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!se401->inturb) {
-                       dev_info(&se401->dev->dev,
-                                "Allocation of inturb failed\n");
-                       return 1;
-               }
-               usb_fill_int_urb(se401->inturb, se401->dev,
-                   usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
-                   &se401->button, sizeof(se401->button),
-                   se401_button_irq,
-                   se401,
-                   8
-               );
-               if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-                       dev_info(&se401->dev->dev, "int urb burned down\n");
-                       return 1;
-               }
-       } else
-               se401->inturb = NULL;
-
-       /* Flash the led */
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-
-       return 0;
-}
-
-static int se401_probe(struct usb_interface *intf,
-       const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_interface_descriptor *interface;
-       struct usb_se401 *se401;
-       char *camera_name = NULL;
-       int button = 1;
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       interface = &intf->cur_altsetting->desc;
-
-       /* Is it an se401? */
-       if (le16_to_cpu(dev->descriptor.idVendor) ==  0x03e8 &&
-           le16_to_cpu(dev->descriptor.idProduct) ==  0x0004) {
-               camera_name = "Endpoints/Aox SE401";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x0471 &&
-           le16_to_cpu(dev->descriptor.idProduct) ==  0x030b) {
-               camera_name = "Philips PCVC665K";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) ==  0x5001) {
-               camera_name = "Kensington VideoCAM 67014";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) ==  0x5002) {
-               camera_name = "Kensington VideoCAM 6701(5/7)";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) ==  0x5003) {
-               camera_name = "Kensington VideoCAM 67016";
-               button = 0;
-       } else
-               return -ENODEV;
-
-       /* Checking vendor/product should be enough, but what the hell */
-       if (interface->bInterfaceClass != 0x00)
-               return -ENODEV;
-       if (interface->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-       /* We found one */
-       dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
-
-       se401 = kzalloc(sizeof(*se401), GFP_KERNEL);
-       if (se401 ==  NULL) {
-               err("couldn't kmalloc se401 struct");
-               return -ENOMEM;
-       }
-
-       se401->dev = dev;
-       se401->iface = interface->bInterfaceNumber;
-       se401->camera_name = camera_name;
-
-       dev_info(&intf->dev, "firmware version: %02x\n",
-                le16_to_cpu(dev->descriptor.bcdDevice) & 255);
-
-       if (se401_init(se401, button)) {
-               kfree(se401);
-               return -EIO;
-       }
-
-       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
-       memcpy(se401->vdev.name, se401->camera_name,
-                                       strlen(se401->camera_name));
-       init_waitqueue_head(&se401->wq);
-       mutex_init(&se401->lock);
-       wmb();
-
-       if (video_register_device(&se401->vdev,
-                                       VFL_TYPE_GRABBER, video_nr) < 0) {
-               kfree(se401);
-               err("video_register_device failed");
-               return -EIO;
-       }
-       dev_info(&intf->dev, "registered new video device: %s\n",
-                video_device_node_name(&se401->vdev));
-
-       usb_set_intfdata(intf, se401);
-       return 0;
-}
-
-static void se401_disconnect(struct usb_interface *intf)
-{
-       struct usb_se401 *se401 = usb_get_intfdata(intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (se401) {
-               video_unregister_device(&se401->vdev);
-               if (!se401->user)
-                       usb_se401_remove_disconnected(se401);
-               else {
-                       se401->frame[0].grabstate = FRAME_ERROR;
-                       se401->frame[0].grabstate = FRAME_ERROR;
-
-                       se401->streaming = 0;
-
-                       wake_up_interruptible(&se401->wq);
-                       se401->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver se401_driver = {
-       .name            =  "se401",
-       .id_table        =  device_table,
-       .probe           =  se401_probe,
-       .disconnect      =  se401_disconnect,
-};
-
-
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init usb_se401_init(void)
-{
-       printk(KERN_INFO "SE401 usb camera driver version %s registering\n",
-                                                               version);
-       if (flickerless)
-               if (flickerless != 50 && flickerless != 60) {
-                       printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
-                       return -1;
-       }
-       return usb_register(&se401_driver);
-}
-
-static void __exit usb_se401_exit(void)
-{
-       usb_deregister(&se401_driver);
-       printk(KERN_INFO "SE401 driver deregistered\frame");
-}
-
-module_init(usb_se401_init);
-module_exit(usb_se401_exit);
diff --git a/drivers/staging/se401/se401.h b/drivers/staging/se401/se401.h
deleted file mode 100644 (file)
index 2758f47..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-
-#ifndef __LINUX_se401_H
-#define __LINUX_se401_H
-
-#include <linux/uaccess.h>
-#include "videodev.h"
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
-#define se401_DEBUG    /* Turn on debug messages */
-
-#ifdef se401_DEBUG
-#  define PDEBUG(level, fmt, args...) \
-if (debug >= level) \
-       info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
-#else
-#  define PDEBUG(level, fmt, args...) do {} while (0)
-#endif
-
-/* An almost drop-in replacement for sleep_on_interruptible */
-#define wait_interruptible(test, queue, wait) \
-{ \
-       add_wait_queue(queue, wait); \
-       set_current_state(TASK_INTERRUPTIBLE); \
-       if (test) \
-               schedule(); \
-       remove_wait_queue(queue, wait); \
-       set_current_state(TASK_RUNNING); \
-       if (signal_pending(current)) \
-               break; \
-}
-
-#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
-#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
-#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
-#define SE401_REQ_CAPTURE_FRAME                        0x43
-#define SE401_REQ_GET_BRT                      0x44
-#define SE401_REQ_SET_BRT                      0x45
-#define SE401_REQ_GET_WIDTH                    0x4c
-#define SE401_REQ_SET_WIDTH                    0x4d
-#define SE401_REQ_GET_HEIGHT                   0x4e
-#define SE401_REQ_SET_HEIGHT                   0x4f
-#define SE401_REQ_GET_OUTPUT_MODE              0x50
-#define SE401_REQ_SET_OUTPUT_MODE              0x51
-#define SE401_REQ_GET_EXT_FEATURE              0x52
-#define SE401_REQ_SET_EXT_FEATURE              0x53
-#define SE401_REQ_CAMERA_POWER                 0x56
-#define SE401_REQ_LED_CONTROL                  0x57
-#define SE401_REQ_BIOS                         0xff
-
-#define SE401_BIOS_READ                                0x07
-
-#define SE401_FORMAT_BAYER     0x40
-
-/* Hyundai hv7131b registers
-   7121 and 7141 should be the same (haven't really checked...) */
-/* Mode registers: */
-#define HV7131_REG_MODE_A              0x00
-#define HV7131_REG_MODE_B              0x01
-#define HV7131_REG_MODE_C              0x02
-/* Frame registers: */
-#define HV7131_REG_FRSU                0x10
-#define HV7131_REG_FRSL                0x11
-#define HV7131_REG_FCSU                0x12
-#define HV7131_REG_FCSL                0x13
-#define HV7131_REG_FWHU                0x14
-#define HV7131_REG_FWHL                0x15
-#define HV7131_REG_FWWU                0x16
-#define HV7131_REG_FWWL                0x17
-/* Timing registers: */
-#define HV7131_REG_THBU                0x20
-#define HV7131_REG_THBL                0x21
-#define HV7131_REG_TVBU                0x22
-#define HV7131_REG_TVBL                0x23
-#define HV7131_REG_TITU                0x25
-#define HV7131_REG_TITM                0x26
-#define HV7131_REG_TITL                0x27
-#define HV7131_REG_TMCD                0x28
-/* Adjust Registers: */
-#define HV7131_REG_ARLV                0x30
-#define HV7131_REG_ARCG                0x31
-#define HV7131_REG_AGCG                0x32
-#define HV7131_REG_ABCG                0x33
-#define HV7131_REG_APBV                0x34
-#define HV7131_REG_ASLP                0x54
-/* Offset Registers: */
-#define HV7131_REG_OFSR                0x50
-#define HV7131_REG_OFSG                0x51
-#define HV7131_REG_OFSB                0x52
-/* REset level statistics registers: */
-#define HV7131_REG_LOREFNOH    0x57
-#define HV7131_REG_LOREFNOL    0x58
-#define HV7131_REG_HIREFNOH    0x59
-#define HV7131_REG_HIREFNOL    0x5a
-
-/* se401 registers */
-#define SE401_OPERATINGMODE    0x2000
-
-
-/* size of usb transfers */
-#define SE401_PACKETSIZE       4096
-/* number of queued bulk transfers to use, should be about 8 */
-#define SE401_NUMSBUF          1
-/* read the usb specs for this one :) */
-#define SE401_VIDEO_ENDPOINT   1
-#define SE401_BUTTON_ENDPOINT  2
-/* number of frames supported by the v4l part */
-#define SE401_NUMFRAMES                2
-/* scratch buffers for passing data to the decoders */
-#define SE401_NUMSCRATCH       32
-/* maximum amount of data in a JangGu packet */
-#define SE401_VLCDATALEN       1024
-/* number of nul sized packets to receive before kicking the camera */
-#define SE401_MAX_NULLPACKETS  4000
-/* number of decoding errors before kicking the camera */
-#define SE401_MAX_ERRORS       200
-
-struct usb_device;
-
-struct se401_sbuf {
-       unsigned char *data;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-enum {
-       FMT_BAYER,
-       FMT_JANGGU,
-};
-
-enum {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-struct se401_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-struct se401_frame {
-       unsigned char *data;            /* Frame buffer */
-
-       volatile int grabstate; /* State of grabbing */
-
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-struct usb_se401 {
-       struct video_device vdev;
-
-       /* Device structure */
-       struct usb_device *dev;
-
-       unsigned char iface;
-
-       char *camera_name;
-
-       int change;
-       int brightness;
-       int hue;
-       int rgain;
-       int ggain;
-       int bgain;
-       int expose_h;
-       int expose_m;
-       int expose_l;
-       int resetlevel;
-
-       int enhance;
-
-       int format;
-       int sizes;
-       int *width;
-       int *height;
-       int cwidth;             /* current width */
-       int cheight;            /* current height */
-       int palette;
-       int maxframesize;
-       int cframesize;         /* current framesize */
-
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-       int removed;            /* device disconnected */
-
-       int streaming;          /* Are we streaming video? */
-
-       char *fbuf;             /* Videodev buffer area */
-
-       struct urb *urb[SE401_NUMSBUF];
-       struct urb *inturb;
-
-       int button;
-       int buttonpressed;
-
-       int curframe;           /* Current receiving frame */
-       struct se401_frame frame[SE401_NUMFRAMES];
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct se401_scratch scratch[SE401_NUMSCRATCH];
-
-       /* Decoder specific data: */
-       unsigned char vlcdata[SE401_VLCDATALEN];
-       int vlcdatapos;
-       int bayeroffset;
-
-       struct se401_sbuf sbuf[SE401_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-
-#endif
-
diff --git a/drivers/staging/se401/videodev.h b/drivers/staging/se401/videodev.h
deleted file mode 100644 (file)
index f11efbe..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- *     Video for Linux version 1 - OBSOLETE
- *
- *     Header file for v4l1 drivers and applications, for
- *     Linux kernels 2.2.x or 2.4.x.
- *
- *     Provides header for legacy drivers and applications
- *
- *     See http://linuxtv.org for more info
- *
- */
-#ifndef __LINUX_VIDEODEV_H
-#define __LINUX_VIDEODEV_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/videodev2.h>
-
-#define VID_TYPE_CAPTURE       1       /* Can capture */
-#define VID_TYPE_TUNER         2       /* Can tune */
-#define VID_TYPE_TELETEXT      4       /* Does teletext */
-#define VID_TYPE_OVERLAY       8       /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY     16      /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING      32      /* Can clip */
-#define VID_TYPE_FRAMERAM      64      /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES                128     /* Scalable */
-#define VID_TYPE_MONOCHROME    256     /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE    512     /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER  1024    /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER  2048    /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER 4096    /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER 8192    /* Can encode MJPEG streams */
-
-struct video_capability
-{
-       char name[32];
-       int type;
-       int channels;   /* Num channels */
-       int audios;     /* Num audio devices */
-       int maxwidth;   /* Supported width */
-       int maxheight;  /* And height */
-       int minwidth;   /* Supported width */
-       int minheight;  /* And height */
-};
-
-
-struct video_channel
-{
-       int channel;
-       char name[32];
-       int tuners;
-       __u32  flags;
-#define VIDEO_VC_TUNER         1       /* Channel has a tuner */
-#define VIDEO_VC_AUDIO         2       /* Channel has audio */
-       __u16  type;
-#define VIDEO_TYPE_TV          1
-#define VIDEO_TYPE_CAMERA      2
-       __u16 norm;                     /* Norm set by channel */
-};
-
-struct video_tuner
-{
-       int tuner;
-       char name[32];
-       unsigned long rangelow, rangehigh;      /* Tuner range */
-       __u32 flags;
-#define VIDEO_TUNER_PAL                1
-#define VIDEO_TUNER_NTSC       2
-#define VIDEO_TUNER_SECAM      4
-#define VIDEO_TUNER_LOW                8       /* Uses KHz not MHz */
-#define VIDEO_TUNER_NORM       16      /* Tuner can set norm */
-#define VIDEO_TUNER_STEREO_ON  128     /* Tuner is seeing stereo */
-#define VIDEO_TUNER_RDS_ON      256     /* Tuner is seeing an RDS datastream */
-#define VIDEO_TUNER_MBS_ON      512     /* Tuner is seeing an MBS datastream */
-       __u16 mode;                     /* PAL/NTSC/SECAM/OTHER */
-#define VIDEO_MODE_PAL         0
-#define VIDEO_MODE_NTSC                1
-#define VIDEO_MODE_SECAM       2
-#define VIDEO_MODE_AUTO                3
-       __u16 signal;                   /* Signal strength 16bit scale */
-};
-
-struct video_picture
-{
-       __u16   brightness;
-       __u16   hue;
-       __u16   colour;
-       __u16   contrast;
-       __u16   whiteness;      /* Black and white only */
-       __u16   depth;          /* Capture depth */
-       __u16   palette;        /* Palette in use */
-#define VIDEO_PALETTE_GREY     1       /* Linear greyscale */
-#define VIDEO_PALETTE_HI240    2       /* High 240 cube (BT848) */
-#define VIDEO_PALETTE_RGB565   3       /* 565 16 bit RGB */
-#define VIDEO_PALETTE_RGB24    4       /* 24bit RGB */
-#define VIDEO_PALETTE_RGB32    5       /* 32bit RGB */
-#define VIDEO_PALETTE_RGB555   6       /* 555 15bit RGB */
-#define VIDEO_PALETTE_YUV422   7       /* YUV422 capture */
-#define VIDEO_PALETTE_YUYV     8
-#define VIDEO_PALETTE_UYVY     9       /* The great thing about standards is ... */
-#define VIDEO_PALETTE_YUV420   10
-#define VIDEO_PALETTE_YUV411   11      /* YUV411 capture */
-#define VIDEO_PALETTE_RAW      12      /* RAW capture (BT848) */
-#define VIDEO_PALETTE_YUV422P  13      /* YUV 4:2:2 Planar */
-#define VIDEO_PALETTE_YUV411P  14      /* YUV 4:1:1 Planar */
-#define VIDEO_PALETTE_YUV420P  15      /* YUV 4:2:0 Planar */
-#define VIDEO_PALETTE_YUV410P  16      /* YUV 4:1:0 Planar */
-#define VIDEO_PALETTE_PLANAR   13      /* start of planar entries */
-#define VIDEO_PALETTE_COMPONENT 7      /* start of component entries */
-};
-
-struct video_audio
-{
-       int     audio;          /* Audio channel */
-       __u16   volume;         /* If settable */
-       __u16   bass, treble;
-       __u32   flags;
-#define VIDEO_AUDIO_MUTE       1
-#define VIDEO_AUDIO_MUTABLE    2
-#define VIDEO_AUDIO_VOLUME     4
-#define VIDEO_AUDIO_BASS       8
-#define VIDEO_AUDIO_TREBLE     16
-#define VIDEO_AUDIO_BALANCE    32
-       char    name[16];
-#define VIDEO_SOUND_MONO       1
-#define VIDEO_SOUND_STEREO     2
-#define VIDEO_SOUND_LANG1      4
-#define VIDEO_SOUND_LANG2      8
-       __u16   mode;
-       __u16   balance;        /* Stereo balance */
-       __u16   step;           /* Step actual volume uses */
-};
-
-struct video_clip
-{
-       __s32   x,y;
-       __s32   width, height;
-       struct  video_clip *next;       /* For user use/driver use only */
-};
-
-struct video_window
-{
-       __u32   x,y;                    /* Position of window */
-       __u32   width,height;           /* Its size */
-       __u32   chromakey;
-       __u32   flags;
-       struct  video_clip __user *clips;       /* Set only */
-       int     clipcount;
-#define VIDEO_WINDOW_INTERLACE 1
-#define VIDEO_WINDOW_CHROMAKEY 16      /* Overlay by chromakey */
-#define VIDEO_CLIP_BITMAP      -1
-/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
-#define VIDEO_CLIPMAP_SIZE     (128 * 625)
-};
-
-struct video_capture
-{
-       __u32   x,y;                    /* Offsets into image */
-       __u32   width, height;          /* Area to capture */
-       __u16   decimation;             /* Decimation divider */
-       __u16   flags;                  /* Flags for capture */
-#define VIDEO_CAPTURE_ODD              0       /* Temporal */
-#define VIDEO_CAPTURE_EVEN             1
-};
-
-struct video_buffer
-{
-       void    *base;
-       int     height,width;
-       int     depth;
-       int     bytesperline;
-};
-
-struct video_mmap
-{
-       unsigned        int frame;              /* Frame (0 - n) for double buffer */
-       int             height,width;
-       unsigned        int format;             /* should be VIDEO_PALETTE_* */
-};
-
-struct video_key
-{
-       __u8    key[8];
-       __u32   flags;
-};
-
-struct video_mbuf
-{
-       int     size;           /* Total memory to map */
-       int     frames;         /* Frames */
-       int     offsets[VIDEO_MAX_FRAME];
-};
-
-#define        VIDEO_NO_UNIT   (-1)
-
-struct video_unit
-{
-       int     video;          /* Video minor */
-       int     vbi;            /* VBI minor */
-       int     radio;          /* Radio minor */
-       int     audio;          /* Audio minor */
-       int     teletext;       /* Teletext minor */
-};
-
-struct vbi_format {
-       __u32   sampling_rate;  /* in Hz */
-       __u32   samples_per_line;
-       __u32   sample_format;  /* VIDEO_PALETTE_RAW only (1 byte) */
-       __s32   start[2];       /* starting line for each frame */
-       __u32   count[2];       /* count of lines for each frame */
-       __u32   flags;
-#define        VBI_UNSYNC      1       /* can distingues between top/bottom field */
-#define        VBI_INTERLACED  2       /* lines are interlaced */
-};
-
-/* video_info is biased towards hardware mpeg encode/decode */
-/* but it could apply generically to any hardware compressor/decompressor */
-struct video_info
-{
-       __u32   frame_count;    /* frames output since decode/encode began */
-       __u32   h_size;         /* current unscaled horizontal size */
-       __u32   v_size;         /* current unscaled veritcal size */
-       __u32   smpte_timecode; /* current SMPTE timecode (for current GOP) */
-       __u32   picture_type;   /* current picture type */
-       __u32   temporal_reference;     /* current temporal reference */
-       __u8    user_data[256]; /* user data last found in compressed stream */
-       /* user_data[0] contains user data flags, user_data[1] has count */
-};
-
-/* generic structure for setting playback modes */
-struct video_play_mode
-{
-       int     mode;
-       int     p1;
-       int     p2;
-};
-
-/* for loading microcode / fpga programming */
-struct video_code
-{
-       char    loadwhat[16];   /* name or tag of file being passed */
-       int     datasize;
-       __u8    *data;
-};
-
-#define VIDIOCGCAP             _IOR('v',1,struct video_capability)     /* Get capabilities */
-#define VIDIOCGCHAN            _IOWR('v',2,struct video_channel)       /* Get channel info (sources) */
-#define VIDIOCSCHAN            _IOW('v',3,struct video_channel)        /* Set channel  */
-#define VIDIOCGTUNER           _IOWR('v',4,struct video_tuner)         /* Get tuner abilities */
-#define VIDIOCSTUNER           _IOW('v',5,struct video_tuner)          /* Tune the tuner for the current channel */
-#define VIDIOCGPICT            _IOR('v',6,struct video_picture)        /* Get picture properties */
-#define VIDIOCSPICT            _IOW('v',7,struct video_picture)        /* Set picture properties */
-#define VIDIOCCAPTURE          _IOW('v',8,int)                         /* Start, end capture */
-#define VIDIOCGWIN             _IOR('v',9, struct video_window)        /* Get the video overlay window */
-#define VIDIOCSWIN             _IOW('v',10, struct video_window)       /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
-#define VIDIOCGFBUF            _IOR('v',11, struct video_buffer)       /* Get frame buffer */
-#define VIDIOCSFBUF            _IOW('v',12, struct video_buffer)       /* Set frame buffer - root only */
-#define VIDIOCKEY              _IOR('v',13, struct video_key)          /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
-#define VIDIOCGFREQ            _IOR('v',14, unsigned long)             /* Set tuner */
-#define VIDIOCSFREQ            _IOW('v',15, unsigned long)             /* Set tuner */
-#define VIDIOCGAUDIO           _IOR('v',16, struct video_audio)        /* Get audio info */
-#define VIDIOCSAUDIO           _IOW('v',17, struct video_audio)        /* Audio source, mute etc */
-#define VIDIOCSYNC             _IOW('v',18, int)                       /* Sync with mmap grabbing */
-#define VIDIOCMCAPTURE         _IOW('v',19, struct video_mmap)         /* Grab frames */
-#define VIDIOCGMBUF            _IOR('v',20, struct video_mbuf)         /* Memory map buffer info */
-#define VIDIOCGUNIT            _IOR('v',21, struct video_unit)         /* Get attached units */
-#define VIDIOCGCAPTURE         _IOR('v',22, struct video_capture)      /* Get subcapture */
-#define VIDIOCSCAPTURE         _IOW('v',23, struct video_capture)      /* Set subcapture */
-#define VIDIOCSPLAYMODE                _IOW('v',24, struct video_play_mode)    /* Set output video mode/feature */
-#define VIDIOCSWRITEMODE       _IOW('v',25, int)                       /* Set write mode */
-#define VIDIOCGPLAYINFO                _IOR('v',26, struct video_info)         /* Get current playback info from hardware */
-#define VIDIOCSMICROCODE       _IOW('v',27, struct video_code)         /* Load microcode into hardware */
-#define        VIDIOCGVBIFMT           _IOR('v',28, struct vbi_format)         /* Get VBI information */
-#define        VIDIOCSVBIFMT           _IOW('v',29, struct vbi_format)         /* Set VBI information */
-
-
-#define BASE_VIDIOCPRIVATE     192             /* 192-255 are private */
-
-/* VIDIOCSWRITEMODE */
-#define VID_WRITE_MPEG_AUD             0
-#define VID_WRITE_MPEG_VID             1
-#define VID_WRITE_OSD                  2
-#define VID_WRITE_TTX                  3
-#define VID_WRITE_CC                   4
-#define VID_WRITE_MJPEG                        5
-
-/* VIDIOCSPLAYMODE */
-#define VID_PLAY_VID_OUT_MODE          0
-       /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
-#define VID_PLAY_GENLOCK               1
-       /* p1: 0 = OFF, 1 = ON */
-       /* p2: GENLOCK FINE DELAY value */
-#define VID_PLAY_NORMAL                        2
-#define VID_PLAY_PAUSE                 3
-#define VID_PLAY_SINGLE_FRAME          4
-#define VID_PLAY_FAST_FORWARD          5
-#define VID_PLAY_SLOW_MOTION           6
-#define VID_PLAY_IMMEDIATE_NORMAL      7
-#define VID_PLAY_SWITCH_CHANNELS       8
-#define VID_PLAY_FREEZE_FRAME          9
-#define VID_PLAY_STILL_MODE            10
-#define VID_PLAY_MASTER_MODE           11
-       /* p1: see below */
-#define                VID_PLAY_MASTER_NONE    1
-#define                VID_PLAY_MASTER_VIDEO   2
-#define                VID_PLAY_MASTER_AUDIO   3
-#define VID_PLAY_ACTIVE_SCANLINES      12
-       /* p1 = first active; p2 = last active */
-#define VID_PLAY_RESET                 13
-#define VID_PLAY_END_MARK              14
-
-#endif /* __LINUX_VIDEODEV_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 184cc505ed86c86370e24e0328e12fd253c10d54..acb03172a8878935b57062a399f257379e1cc930 100644 (file)
@@ -76,14 +76,11 @@ MODULE_PARM_DESC(debug, "enable debug messages");
 static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
 {
        struct tm6000_core *core = chip->core;
-       int val;
 
        dprintk(1, "Starting audio DMA\n");
 
        /* Enables audio */
-       val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
-       val |= 0x20;
-       tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40);
 
        tm6000_set_audio_bitrate(core, 48000);
 
@@ -98,13 +95,11 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
 static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
 {
        struct tm6000_core *core = chip->core;
-       int val;
+
        dprintk(1, "Stopping audio DMA\n");
 
-       /* Enables audio */
-       val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
-       val &= ~0x20;
-       tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
+       /* Disables audio */
+       tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40);
 
        tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
 
index 455038bdfc9f8d8ced98b36b4f2c3281527e57cd..146c7e86deca4d4109027fd9489be60d061809db 100644 (file)
@@ -50,6 +50,9 @@
 #define TM6010_BOARD_BEHOLD_VOYAGER            11
 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE        12
 #define TM6010_BOARD_TWINHAN_TU501             13
+#define TM6010_BOARD_BEHOLD_WANDER_LITE                14
+#define TM6010_BOARD_BEHOLD_VOYAGER_LITE       15
+#define TM5600_BOARD_TERRATEC_GRABSTER         16
 
 #define TM6000_MAXBOARDS        16
 static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
@@ -63,6 +66,8 @@ struct tm6000_board {
        char            *name;
 
        struct tm6000_capabilities caps;
+       enum            tm6000_inaudio aradio;
+       enum            tm6000_inaudio avideo;
 
        enum            tm6000_devtype type;    /* variant of the chipset */
        int             tuner_type;     /* type of the tuner */
@@ -227,12 +232,16 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_addr   = 0xc2 >> 1,
                .demod_addr   = 0x1e >> 1,
                .type         = TM6010,
+               .avideo       = TM6000_AIP_SIF1,
+               .aradio       = TM6000_AIP_LINE1,
                .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 1,
-                       .has_zl10353  = 1,
-                       .has_eeprom   = 1,
-                       .has_remote   = 1,
+                       .has_tuner      = 1,
+                       .has_dvb        = 1,
+                       .has_zl10353    = 1,
+                       .has_eeprom     = 1,
+                       .has_remote     = 1,
+                       .has_input_comp = 1,
+                       .has_input_svid = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
@@ -245,12 +254,16 @@ struct tm6000_board tm6000_boards[] = {
                .tuner_type   = TUNER_XC5000,
                .tuner_addr   = 0xc2 >> 1,
                .type         = TM6010,
+               .avideo       = TM6000_AIP_SIF1,
+               .aradio       = TM6000_AIP_LINE1,
                .caps = {
-                       .has_tuner    = 1,
-                       .has_dvb      = 0,
-                       .has_zl10353  = 0,
-                       .has_eeprom   = 1,
-                       .has_remote   = 1,
+                       .has_tuner      = 1,
+                       .has_dvb        = 0,
+                       .has_zl10353    = 0,
+                       .has_eeprom     = 1,
+                       .has_remote     = 1,
+                       .has_input_comp = 1,
+                       .has_input_svid = 1,
                },
                .gpio = {
                        .tuner_reset    = TM6010_GPIO_0,
@@ -281,6 +294,11 @@ struct tm6000_board tm6000_boards[] = {
                },
                .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
        },
+       [TM5600_BOARD_TERRATEC_GRABSTER] = {
+               .name         = "Terratec Grabster AV 150/250 MX",
+               .type         = TM5600,
+               .tuner_type   = TUNER_ABSENT,
+       },
        [TM6010_BOARD_TWINHAN_TU501] = {
                .name         = "Twinhan TU501(704D1)",
                .tuner_type   = TUNER_XC2028, /* has a XC3028 */
@@ -303,7 +321,51 @@ struct tm6000_board tm6000_boards[] = {
                        .dvb_led        = TM6010_GPIO_5,
                        .ir             = TM6010_GPIO_0,
                },
-       }
+       },
+       [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
+               .name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .demod_addr   = 0x1e >> 1,
+               .type         = TM6010,
+               .avideo       = TM6000_AIP_SIF1,
+               .aradio       = TM6000_AIP_LINE1,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 1,
+                       .has_zl10353    = 1,
+                       .has_eeprom     = 1,
+                       .has_remote     = 0,
+                       .has_input_comp = 0,
+                       .has_input_svid = 0,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .demod_reset    = TM6010_GPIO_1,
+                       .power_led      = TM6010_GPIO_6,
+               },
+       },
+       [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
+               .name         = "Beholder Voyager Lite TV/FM USB2.0",
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0xc2 >> 1,
+               .type         = TM6010,
+               .avideo       = TM6000_AIP_SIF1,
+               .aradio       = TM6000_AIP_LINE1,
+               .caps = {
+                       .has_tuner      = 1,
+                       .has_dvb        = 0,
+                       .has_zl10353    = 0,
+                       .has_eeprom     = 1,
+                       .has_remote     = 0,
+                       .has_input_comp = 0,
+                       .has_input_svid = 0,
+               },
+               .gpio = {
+                       .tuner_reset    = TM6010_GPIO_0,
+                       .power_led      = TM6010_GPIO_6,
+               },
+       },
 };
 
 /* table of devices that work with this driver */
@@ -321,10 +383,13 @@ struct usb_device_id tm6000_id_table[] = {
        { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
        { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
        { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
+       { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
        { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
        { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
        { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
        { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
+       { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
+       { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
        { },
 };
 
@@ -346,6 +411,8 @@ void tm6000_flash_led(struct tm6000_core *dev, u8 state)
                        break;
                case TM6010_BOARD_BEHOLD_WANDER:
                case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
                        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
                                dev->gpio.power_led, 0x01);
                        break;
@@ -362,6 +429,8 @@ void tm6000_flash_led(struct tm6000_core *dev, u8 state)
                        break;
                case TM6010_BOARD_BEHOLD_WANDER:
                case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
                        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
                                dev->gpio.power_led, 0x00);
                        break;
@@ -520,6 +589,7 @@ int tm6000_cards_setup(struct tm6000_core *dev)
                msleep(15);
                break;
        case TM6010_BOARD_BEHOLD_WANDER:
+       case TM6010_BOARD_BEHOLD_WANDER_LITE:
                /* Power led on (blue) */
                tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
                msleep(15);
@@ -530,6 +600,7 @@ int tm6000_cards_setup(struct tm6000_core *dev)
                msleep(15);
                break;
        case TM6010_BOARD_BEHOLD_VOYAGER:
+       case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
                /* Power led on (blue) */
                tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
                msleep(15);
@@ -588,8 +659,6 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
        tun_setup.mode_mask = 0;
        if (dev->caps.has_tuner)
                tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
-       if (dev->caps.has_dvb)
-               tun_setup.mode_mask |= T_DIGITAL_TV;
 
        switch (dev->tuner_type) {
        case TUNER_XC2028:
@@ -644,13 +713,12 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
                struct xc5000_config ctl = {
                        .i2c_address = dev->tuner_addr,
                        .if_khz      = 4570,
-                       .radio_input = XC5000_RADIO_FM1,
+                       .radio_input = XC5000_RADIO_FM1_MONO,
                        };
 
                xc5000_cfg.tuner = TUNER_XC5000;
                xc5000_cfg.priv  = &ctl;
 
-
                v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
                                     &xc5000_cfg);
                }
@@ -683,6 +751,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
 
        dev->caps = tm6000_boards[dev->model].caps;
 
+       dev->avideo = tm6000_boards[dev->model].avideo;
+       dev->aradio = tm6000_boards[dev->model].aradio;
        /* initialize hardware */
        rc = tm6000_init(dev);
        if (rc < 0)
@@ -957,6 +1027,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
                        break;
                case TM6010_BOARD_BEHOLD_WANDER:
                case TM6010_BOARD_BEHOLD_VOYAGER:
+               case TM6010_BOARD_BEHOLD_WANDER_LITE:
+               case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
                        /* Power led off */
                        tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
                                dev->gpio.power_led, 0x00);
index 96aed4ace46739e3b76aac54c299974bde44877a..778e53413afb009fbd15a0131a8e80fd76a5299b 100644 (file)
@@ -116,6 +116,29 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 }
 EXPORT_SYMBOL_GPL(tm6000_get_reg);
 
+int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
+                                               u16 index, u16 mask)
+{
+       int rc;
+       u8 buf[1];
+       u8 new_index;
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 1);
+
+       if (rc < 0)
+               return rc;
+
+       new_index = (buf[0] & ~mask) | (index & mask);
+
+       if (new_index == index)
+               return 0;
+
+       return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+                                     req, value, new_index, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
+
 int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
        int rc;
@@ -245,17 +268,12 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
        struct v4l2_frequency f;
 
        if (dev->dev_type == TM6010) {
-               int val;
-
                /* Enable video */
-               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
-               val |= 0x60;
-               tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
-               val = tm6000_get_reg(dev,
-                       TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
-               val &= ~0x40;
-               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
 
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
+                                                       0x60, 0x60);
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
+                                                       0x00, 0x40);
                tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
 
        } else {
@@ -268,11 +286,11 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
                        tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
 
                tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
                tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
                tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
 
                /* AP Software reset */
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
@@ -284,8 +302,8 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
 
                /* E3: Select input 0 - TV tuner */
-               tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60);
+               tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x60);
 
                /* This controls input */
                tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0);
@@ -344,21 +362,21 @@ int tm6000_init_digital_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
-               tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
                tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
                tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
                tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
                tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
 
-               tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
                msleep(50);
 
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
@@ -388,18 +406,19 @@ struct reg_init {
 /* The meaning of those initializations are unknown */
 struct reg_init tm6000_init_tab[] = {
        /* REG  VALUE */
-       { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f },
+       { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
        { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
        { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
        { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
-       { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 },
-       { TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 },
-       { TM6010_REQ07_RE2_OUT_SEL2, 0x00 },
-       { TM6010_REQ07_RE3_OUT_SEL1, 0x10 },
-       { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 },
-       { TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 },
-       { REQ_07_SET_GET_AVREG,  0xeb, 0x64 },          /* 48000 bits/sample, external input */
-       { REQ_07_SET_GET_AVREG,  0xee, 0xc2 },
+       { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
+       { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
+       { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
+       { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
+       { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
+       { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
+       { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 },      /* 48000 bits/sample, external input */
+       { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
+
        { TM6010_REQ07_R3F_RESET, 0x01 },               /* Start of soft reset */
        { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
        { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
@@ -470,6 +489,14 @@ struct reg_init tm6010_init_tab[] = {
        { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
        { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
        { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
+       { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00},
+       { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80},
+       { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a},
+       { TM6010_REQ08_R0D_A_AMD_THRES, 0x40},
+       { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64},
+       { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20},
+       { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe},
+       { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01},
        { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
 
        { TM6010_REQ07_R3F_RESET, 0x01 },
@@ -590,38 +617,213 @@ int tm6000_init(struct tm6000_core *dev)
 
 int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
 {
-       int val;
+       int val = 0;
+       u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+       u8 areg_0a = 0x91; /* SIF 48KHz */
 
+       switch (bitrate) {
+       case 48000:
+               areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+               areg_0a = 0x91; /* SIF 48KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       case 32000:
+               areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
+               areg_0a = 0x90; /* SIF 32KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       /* enable I2S, if we use sif or external I2S device */
        if (dev->dev_type == TM6010) {
-               val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
+               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
                if (val < 0)
                        return val;
-               val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
-               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
+
+               val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0xf0);
+               if (val < 0)
+                       return val;
+       } else {
+               val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_f0, 0xf0);
                if (val < 0)
                        return val;
        }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
 
-       val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
-       if (val < 0)
-               return val;
+int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
+{
+       if (dev->dev_type == TM6010) {
+               /* Audio crossbar setting, default SIF1 */
+               u8 areg_f0 = 0x03;
 
-       val &= 0x0f;            /* Preserve the audio input control bits */
-       switch (bitrate) {
-       case 44100:
-               val |= 0xd0;
-               dev->audio_bitrate = bitrate;
+               switch (ainp) {
+               case TM6000_AIP_SIF1:
+               case TM6000_AIP_SIF2:
+                       areg_f0 = 0x03;
+                       break;
+               case TM6000_AIP_LINE1:
+                       areg_f0 = 0x00;
+                       break;
+               case TM6000_AIP_LINE2:
+                       areg_f0 = 0x08;
+                       break;
+               default:
+                       return 0;
+                       break;
+               }
+               /* Set audio input crossbar */
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0x0f);
+       } else {
+               /* Audio setting, default LINE1 */
+               u8 areg_eb = 0x00;
+
+               switch (ainp) {
+               case TM6000_AIP_LINE1:
+                       areg_eb = 0x00;
+                       break;
+               case TM6000_AIP_LINE2:
+                       areg_eb = 0x04;
+                       break;
+               default:
+                       return 0;
+                       break;
+               }
+               /* Set audio input */
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_eb, 0x0f);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_input);
+
+void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x08;
+
+       tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
+}
+
+void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x20;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+       } else {
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
+                                                       mute_reg, 0x20);
+       }
+}
+
+int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
+{
+       enum tm6000_inaudio ainp;
+
+       if (dev->radio)
+               ainp = dev->aradio;
+       else
+               ainp = dev->avideo;
+
+       switch (ainp) {
+       case TM6000_AIP_SIF1:
+       case TM6000_AIP_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_mute_sif(dev, mute);
+               else {
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+                       return -EINVAL;
+               }
                break;
-       case 48000:
-               val |= 0x60;
-               dev->audio_bitrate = bitrate;
+       case TM6000_AIP_LINE1:
+       case TM6000_AIP_LINE2:
+               tm6010_set_mute_adc(dev, mute);
+               break;
+       default:
+               return -EINVAL;
                break;
        }
-       val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute);
+
+void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = vol & 0x0F;
+
+       if (vol < 0)
+               vol_reg |= 0x40;
+
+       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
+       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
+}
+
+void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = (vol + 0x10) & 0x1f;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
+               tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
+       } else {
+               tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
+               tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
+       }
+}
+
+void tm6000_set_volume(struct tm6000_core *dev, int vol)
+{
+       enum tm6000_inaudio ainp;
+
+       if (dev->radio) {
+               ainp = dev->aradio;
+               vol += 8; /* Offset to 0 dB */
+       } else
+               ainp = dev->avideo;
 
-       return val;
+       switch (ainp) {
+       case TM6000_AIP_SIF1:
+       case TM6000_AIP_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_volume_sif(dev, vol);
+               else
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+               break;
+       case TM6000_AIP_LINE1:
+       case TM6000_AIP_LINE2:
+               tm6010_set_volume_adc(dev, vol);
+               break;
+       default:
+               break;
+       }
 }
-EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
+EXPORT_SYMBOL_GPL(tm6000_set_volume);
 
 static LIST_HEAD(tm6000_devlist);
 static DEFINE_MUTEX(tm6000_devlist_mutex);
index 1f0ced8fa20f834c07d7ee7ab0dc9b991d015329..5375a834737401a4abd61e20f426a0ff6d9d6007 100644 (file)
@@ -97,6 +97,34 @@ enum {
        TM6000_URB_MSG_ERR,
 };
 
+/* Define specific TM6000 Video decoder registers */
+#define TM6000_REQ07_RD8_TEST_SEL                      0x07, 0xd8
+#define TM6000_REQ07_RD9_A_SIM_SEL                     0x07, 0xd9
+#define TM6000_REQ07_RDA_CLK_SEL                       0x07, 0xda
+#define TM6000_REQ07_RDB_OUT_SEL                       0x07, 0xdb
+#define TM6000_REQ07_RDC_NSEL_I2S                      0x07, 0xdc
+#define TM6000_REQ07_RDD_GPIO2_MDRV                    0x07, 0xdd
+#define TM6000_REQ07_RDE_GPIO1_MDRV                    0x07, 0xde
+#define TM6000_REQ07_RDF_PWDOWN_ACLK                   0x07, 0xdf
+#define TM6000_REQ07_RE0_VADC_REF_CTL                  0x07, 0xe0
+#define TM6000_REQ07_RE1_VADC_DACLIMP                  0x07, 0xe1
+#define TM6000_REQ07_RE2_VADC_STATUS_CTL               0x07, 0xe2
+#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1             0x07, 0xe3
+#define TM6000_REQ07_RE4_VADC_TARGET1                  0x07, 0xe4
+#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2             0x07, 0xe5
+#define TM6000_REQ07_RE6_VADC_TARGET2                  0x07, 0xe6
+#define TM6000_REQ07_RE7_VADC_AGAIN_CTL                        0x07, 0xe7
+#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL               0x07, 0xe8
+#define TM6000_REQ07_RE9_VADC_INPUT_CTL1               0x07, 0xe9
+#define TM6000_REQ07_REA_VADC_INPUT_CTL2               0x07, 0xea
+#define TM6000_REQ07_REB_VADC_AADC_MODE                        0x07, 0xeb
+#define TM6000_REQ07_REC_VADC_AADC_LVOL                        0x07, 0xec
+#define TM6000_REQ07_RED_VADC_AADC_RVOL                        0x07, 0xed
+#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL         0x07, 0xee
+#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL             0x07, 0xef
+#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW              0x07, 0xfd
+#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH             0x07, 0xfe
+
 /* Define TM6000/TM6010 Video decoder registers */
 #define TM6010_REQ07_R00_VIDEO_CONTROL0                        0x07, 0x00
 #define TM6010_REQ07_R01_VIDEO_CONTROL1                        0x07, 0x01
@@ -241,6 +269,7 @@ enum {
 #define TM6010_REQ07_RC9_VEND1                         0x07, 0xc9
 #define TM6010_REQ07_RCA_VEND0                         0x07, 0xca
 #define TM6010_REQ07_RCB_DELAY                         0x07, 0xcb
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF               0x07, 0xcc
 #define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL         0x07, 0xd0
 #define TM6010_REQ07_RD1_ADDR_FOR_REQ1                 0x07, 0xd1
@@ -250,32 +279,59 @@ enum {
 #define TM6010_REQ07_RD5_POWERSAVE                     0x07, 0xd5
 #define TM6010_REQ07_RD6_ENDP_REQ1_REQ2                        0x07, 0xd6
 #define TM6010_REQ07_RD7_ENDP_REQ3_REQ4                        0x07, 0xd7
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR                            0x07, 0xd8
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_BSIZE                      0x07, 0xd9
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_WAKEUP_SEL                 0x07, 0xda
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_WAKEUP_ADD                 0x07, 0xdb
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_LEADER1                    0x07, 0xdc
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_LEADER0                    0x07, 0xdd
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_PULSE_CNT1                 0x07, 0xde
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RD8_IR_PULSE_CNT0                 0x07, 0xdf
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE0_DVIDEO_SOURCE                 0x07, 0xe0
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF              0x07, 0xe1
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE2_OUT_SEL2                      0x07, 0xe2
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE3_OUT_SEL1                      0x07, 0xe3
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE4_OUT_SEL0                      0x07, 0xe4
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE5_REMOTE_WAKEUP                 0x07, 0xe5
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE7_PUB_GPIO                      0x07, 0xe7
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE8_TYPESEL_MOS_I2S               0x07, 0xe8
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RE9_TYPESEL_MOS_TS                        0x07, 0xe9
+/* ONLY for TM6010 */
 #define TM6010_REQ07_REA_TYPESEL_MOS_CCIR              0x07, 0xea
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF0_BIST_CRC_RESULT0              0x07, 0xf0
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF1_BIST_CRC_RESULT1              0x07, 0xf1
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF2_BIST_CRC_RESULT2              0x07, 0xf2
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF3_BIST_CRC_RESULT3              0x07, 0xf3
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF4_BIST_ERR_VST2                 0x07, 0xf4
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF5_BIST_ERR_VST1                 0x07, 0xf5
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF6_BIST_ERR_VST0                 0x07, 0xf6
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RF7_BIST                          0x07, 0xf7
+/* ONLY for TM6010 */
 #define TM6010_REQ07_RFE_POWER_DOWN                    0x07, 0xfe
 #define TM6010_REQ07_RFF_SOFT_RESET                    0x07, 0xff
 
@@ -477,7 +533,8 @@ enum {
 #define TM6010_REQ05_RC4_DATA_FIFO14           0x05, 0xf8
 #define TM6010_REQ05_RC4_DATA_FIFO15           0x05, 0xfc
 
-/* Define TM6000/TM6010 Audio decoder registers */
+/* Define TM6010 Audio decoder registers */
+/* This core available only in TM6010 */
 #define TM6010_REQ08_R00_A_VERSION             0x08, 0x00
 #define TM6010_REQ08_R01_A_INIT                        0x08, 0x01
 #define TM6010_REQ08_R02_A_FIX_GAIN_CTRL       0x08, 0x02
@@ -518,7 +575,7 @@ enum {
 #define TM6010_REQ08_R27_A_NOISE_AMP           0x08, 0x27
 #define TM6010_REQ08_R28_A_AUDIO_MODE_RES      0x08, 0x28
 
-/* Define TM6000/TM6010 Video ADC registers */
+/* Define TM6010 Video ADC registers */
 #define TM6010_REQ08_RE0_ADC_REF               0x08, 0xe0
 #define TM6010_REQ08_RE1_DAC_CLMP              0x08, 0xe1
 #define TM6010_REQ08_RE2_POWER_DOWN_CTRL1      0x08, 0xe2
@@ -534,7 +591,7 @@ enum {
 #define TM6010_REQ08_REC_REVERSE_YC_CTRL       0x08, 0xec
 #define TM6010_REQ08_RED_GAIN_SEL              0x08, 0xed
 
-/* Define TM6000/TM6010 Audio ADC registers */
+/* Define TM6010 Audio ADC registers */
 #define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG   0x08, 0xf0
 #define TM6010_REQ08_RF1_AADC_POWER_DOWN       0x08, 0xf1
 #define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL      0x08, 0xf2
index cc7b8664fc20c87b68ba66525b94e16762c825ce..da3e51bde109ba99e29e8d6071bed5a0cfb29685 100644 (file)
@@ -952,6 +952,22 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
        uint8_t mono_flag = 0;  /* No mono */
        uint8_t nicam_flag = 0; /* No NICAM */
 
+       if (dev->radio) {
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
+               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
+               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
+               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
+               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
+               tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
+               tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
+               tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
+               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
+               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
+               return 0;
+       }
+
        switch (std) {
 #if 0
        case DK_MONO:
@@ -984,20 +1000,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
        case EIAJ:
                areg_05 = 0x02;
                break;
-       case FM_RADIO:
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
-               tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
-               tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
-               tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
-               tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
-               tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
-               tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
-               return 0;
-               break;
        case I_NICAM:
                areg_05 = 0x08;
                nicam_flag = 1;
@@ -1010,6 +1012,9 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
                areg_05 = 0x0a;
                nicam_flag = 1;
                break;
+       default:
+               /* do nothink */
+               break;
        }
 
 #if 0
@@ -1156,8 +1161,6 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm)
                                rc = tm6000_load_std(dev, svideo_stds[i].common,
                                                     sizeof(svideo_stds[i].
                                                            common));
-                               tm6000_set_audio_std(dev, svideo_stds[i].audio_default_std);
-
                                goto ret;
                        }
                }
index eb9b9f1bc1387250f4382d23f721851c031c9693..c80a316d9d8f79d5d635c0c9198bec7532a5866f 100644 (file)
 /* Declare static vars that will be used as parameters */
 static unsigned int vid_limit = 16;    /* Video memory limit, in Mb */
 static int video_nr = -1;              /* /dev/videoN, -1 for autodetect */
+static int radio_nr = -1;              /* /dev/radioN, -1 for autodetect */
 
 /* Debug level */
 int tm6000_debug;
 EXPORT_SYMBOL_GPL(tm6000_debug);
 
+static const struct v4l2_queryctrl no_ctrl = {
+       .name  = "42",
+       .flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
 /* supported controls */
 static struct v4l2_queryctrl tm6000_qctrl[] = {
        {
@@ -96,9 +102,26 @@ static struct v4l2_queryctrl tm6000_qctrl[] = {
                .step          = 0x1,
                .default_value = 0,
                .flags         = 0,
+       },
+               /* --- audio --- */
+       {
+               .id            = V4L2_CID_AUDIO_MUTE,
+               .name          = "Mute",
+               .minimum       = 0,
+               .maximum       = 1,
+               .type          = V4L2_CTRL_TYPE_BOOLEAN,
+       }, {
+               .id            = V4L2_CID_AUDIO_VOLUME,
+               .name          = "Volume",
+               .minimum       = -15,
+               .maximum       = 15,
+               .step          = 1,
+               .default_value = 0,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
        }
 };
 
+static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
 static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
 
 static struct tm6000_fmt format[] = {
@@ -117,6 +140,16 @@ static struct tm6000_fmt format[] = {
        }
 };
 
+static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
+{
+       unsigned int i;
+
+       for (i = 0; i < CTRLS; i++)
+               if (tm6000_qctrl[i].id == id)
+                       return tm6000_qctrl+i;
+       return NULL;
+}
+
 /* ------------------------------------------------------------------
  *     DMA and thread functions
  * ------------------------------------------------------------------
@@ -199,13 +232,17 @@ static int copy_streams(u8 *data, unsigned long len,
        char *voutp = NULL;
        unsigned int linewidth;
 
-       /* get video buffer */
-       get_next_buf(dma_q, &vbuf);
-       if (!vbuf)
-               return rc;
-       voutp = videobuf_to_vmalloc(&vbuf->vb);
-       if (!voutp)
-               return 0;
+       if (!dev->radio) {
+               /* get video buffer */
+               get_next_buf(dma_q, &vbuf);
+
+               if (!vbuf)
+                       return rc;
+               voutp = videobuf_to_vmalloc(&vbuf->vb);
+
+               if (!voutp)
+                       return 0;
+       }
 
        for (ptr = data; ptr < endp;) {
                if (!dev->isoc_ctl.cmd) {
@@ -257,29 +294,31 @@ static int copy_streams(u8 *data, unsigned long len,
                         */
                        switch (cmd) {
                        case TM6000_URB_MSG_VIDEO:
-                               if ((dev->isoc_ctl.vfield != field) &&
-                                       (field == 1)) {
+                               if (!dev->radio) {
+                                       if ((dev->isoc_ctl.vfield != field) &&
+                                               (field == 1)) {
                                        /* Announces that a new buffer
                                         * were filled
                                         */
-                                       buffer_filled(dev, dma_q, vbuf);
-                                       dprintk(dev, V4L2_DEBUG_ISOC,
+                                               buffer_filled(dev, dma_q, vbuf);
+                                               dprintk(dev, V4L2_DEBUG_ISOC,
                                                        "new buffer filled\n");
-                                       get_next_buf(dma_q, &vbuf);
-                                       if (!vbuf)
-                                               return rc;
-                                       voutp = videobuf_to_vmalloc(&vbuf->vb);
-                                       if (!voutp)
-                                               return rc;
-                                       memset(voutp, 0, vbuf->vb.size);
-                               }
-                               linewidth = vbuf->vb.width << 1;
-                               pos = ((line << 1) - field - 1) * linewidth +
-                                       block * TM6000_URB_MSG_LEN;
-                               /* Don't allow to write out of the buffer */
-                               if (pos + size > vbuf->vb.size)
-                                       cmd = TM6000_URB_MSG_ERR;
-                               dev->isoc_ctl.vfield = field;
+                                               get_next_buf(dma_q, &vbuf);
+                                               if (!vbuf)
+                                                       return rc;
+                                               voutp = videobuf_to_vmalloc(&vbuf->vb);
+                                               if (!voutp)
+                                                       return rc;
+                                               memset(voutp, 0, vbuf->vb.size);
+                                       }
+                                       linewidth = vbuf->vb.width << 1;
+                                       pos = ((line << 1) - field - 1) *
+                                       linewidth + block * TM6000_URB_MSG_LEN;
+                                       /* Don't allow to write out of the buffer */
+                                       if (pos + size > vbuf->vb.size)
+                                               cmd = TM6000_URB_MSG_ERR;
+                                       dev->isoc_ctl.vfield = field;
+                       }
                                break;
                        case TM6000_URB_MSG_VBI:
                                break;
@@ -537,7 +576,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
 /*
  * Allocate URBs and start IRQ
  */
-static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
+static int tm6000_prepare_isoc(struct tm6000_core *dev)
 {
        struct tm6000_dmaqueue *dma_q = &dev->vidq;
        int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
@@ -566,11 +605,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
 
        dev->isoc_ctl.max_pkt_size = size;
 
-       max_packets = (framesize + size - 1) / size;
-
-       if (max_packets > TM6000_MAX_ISO_PACKETS)
-               max_packets = TM6000_MAX_ISO_PACKETS;
-
+       max_packets = TM6000_MAX_ISO_PACKETS;
        sb_size = max_packets * size;
 
        dev->isoc_ctl.num_bufs = num_bufs;
@@ -746,7 +781,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                urb_init = 1;
 
        if (urb_init) {
-               rc = tm6000_prepare_isoc(dev, buf->vb.size);
+               rc = tm6000_prepare_isoc(dev);
                if (rc < 0)
                        goto fail;
 
@@ -1045,18 +1080,27 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm)
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
 {
+       struct tm6000_fh   *fh = priv;
+       struct tm6000_core *dev = fh->dev;
+
        switch (inp->index) {
        case TM6000_INPUT_TV:
                inp->type = V4L2_INPUT_TYPE_TUNER;
                strcpy(inp->name, "Television");
                break;
        case TM6000_INPUT_COMPOSITE:
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(inp->name, "Composite");
+               if (dev->caps.has_input_comp) {
+                       inp->type = V4L2_INPUT_TYPE_CAMERA;
+                       strcpy(inp->name, "Composite");
+               } else
+                       return -EINVAL;
                break;
        case TM6000_INPUT_SVIDEO:
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               strcpy(inp->name, "S-Video");
+               if (dev->caps.has_input_svid) {
+                       inp->type = V4L2_INPUT_TYPE_CAMERA;
+                       strcpy(inp->name, "S-Video");
+               } else
+                       return -EINVAL;
                break;
        default:
                return -EINVAL;
@@ -1143,6 +1187,12 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        case V4L2_CID_HUE:
                val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
                return 0;
+       case V4L2_CID_AUDIO_MUTE:
+               val = dev->ctl_mute;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               val = dev->ctl_volume;
+               return 0;
        default:
                return -EINVAL;
        }
@@ -1174,6 +1224,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        case V4L2_CID_HUE:
                tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
                return 0;
+       case V4L2_CID_AUDIO_MUTE:
+               dev->ctl_mute = val;
+               tm6000_tvaudio_set_mute(dev, val);
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               dev->ctl_volume = val;
+               tm6000_set_volume(dev, val);
+               return 0;
        }
        return -EINVAL;
 }
@@ -1221,7 +1279,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        if (unlikely(UNSET == dev->tuner_type))
                return -EINVAL;
 
-       f->type = V4L2_TUNER_ANALOG_TV;
+       f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->freq;
 
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
@@ -1235,13 +1293,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        struct tm6000_fh   *fh  = priv;
        struct tm6000_core *dev = fh->dev;
 
-       if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
-               return -EINVAL;
-
        if (unlikely(UNSET == dev->tuner_type))
                return -EINVAL;
        if (unlikely(f->tuner != 0))
                return -EINVAL;
+       if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+               return -EINVAL;
+       if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+               return -EINVAL;
 
        dev->freq = f->frequency;
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
@@ -1249,6 +1308,122 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        return 0;
 }
 
+static int radio_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       strcpy(cap->driver, "tm6000");
+       strlcpy(cap->card, dev->name, sizeof(dev->name));
+       sprintf(cap->bus_info, "USB%04x:%04x",
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct));
+       cap->version = dev->dev_type;
+       cap->capabilities = V4L2_CAP_TUNER;
+
+       return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       memset(t, 0, sizeof(*t));
+       strcpy(t->name, "Radio");
+       t->type = V4L2_TUNER_RADIO;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+
+       if ((dev->aradio == TM6000_AIP_LINE1) ||
+                               (dev->aradio == TM6000_AIP_LINE2)) {
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+       }
+       else {
+               t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       }
+
+       return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+
+       if (0 != t->index)
+               return -EINVAL;
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+       return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+                                       struct v4l2_input *i)
+{
+       if (i->index != 0)
+               return -EINVAL;
+
+       strcpy(i->name, "Radio");
+       i->type = V4L2_INPUT_TYPE_TUNER;
+
+       return 0;
+}
+
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       memset(a, 0, sizeof(*a));
+       strcpy(a->name, "Radio");
+       return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+                                       struct v4l2_audio *a)
+{
+       return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       const struct v4l2_queryctrl *ctrl;
+
+       if (c->id <  V4L2_CID_BASE ||
+           c->id >= V4L2_CID_LASTP1)
+               return -EINVAL;
+       if (c->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl = ctrl_by_id(c->id);
+               *c = *ctrl;
+       } else
+               *c = no_ctrl;
+
+       return 0;
+}
+
 /* ------------------------------------------------------------------
        File operations for the device
    ------------------------------------------------------------------*/
@@ -1260,6 +1435,7 @@ static int tm6000_open(struct file *file)
        struct tm6000_fh *fh;
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        int i, rc;
+       int radio = 0;
 
        printk(KERN_INFO "tm6000: open called (dev=%s)\n",
                video_device_node_name(vdev));
@@ -1267,6 +1443,17 @@ static int tm6000_open(struct file *file)
        dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
                video_device_node_name(vdev));
 
+       switch (vdev->vfl_type) {
+       case VFL_TYPE_GRABBER:
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               break;
+       case VFL_TYPE_VBI:
+               type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               break;
+       case VFL_TYPE_RADIO:
+               radio = 1;
+               break;
+       }
 
        /* If more than one user, mutex should be added */
        dev->users++;
@@ -1284,8 +1471,9 @@ static int tm6000_open(struct file *file)
 
        file->private_data = fh;
        fh->dev      = dev;
-
-       fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fh->radio    = radio;
+       dev->radio   = radio;
+       fh->type     = type;
        dev->fourcc  = format[0].fourcc;
 
        fh->fmt      = format_by_fourcc(dev->fourcc);
@@ -1322,6 +1510,19 @@ static int tm6000_open(struct file *file)
                        V4L2_FIELD_INTERLACED,
                        sizeof(struct tm6000_buffer), fh, &dev->lock);
 
+       if (fh->radio) {
+               dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
+               tm6000_set_audio_input(dev, dev->aradio);
+               tm6000_set_volume(dev, dev->ctl_volume);
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+               tm6000_prepare_isoc(dev);
+               tm6000_start_thread(dev);
+       }
+       else {
+               tm6000_set_audio_input(dev, dev->avideo);
+               tm6000_set_volume(dev, dev->ctl_volume);
+       }
+
        return 0;
 }
 
@@ -1445,6 +1646,36 @@ static struct video_device tm6000_template = {
        .current_norm   = V4L2_STD_NTSC_M,
 };
 
+static const struct v4l2_file_operations radio_fops = {
+       .owner    = THIS_MODULE,
+       .open     = tm6000_open,
+       .release  = tm6000_release,
+       .ioctl    = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+       .vidioc_querycap        = radio_querycap,
+       .vidioc_g_tuner         = radio_g_tuner,
+       .vidioc_enum_input      = radio_enum_input,
+       .vidioc_g_audio         = radio_g_audio,
+       .vidioc_s_tuner         = radio_s_tuner,
+       .vidioc_s_audio         = radio_s_audio,
+       .vidioc_s_input         = radio_s_input,
+       .vidioc_s_std           = radio_s_std,
+       .vidioc_queryctrl       = radio_queryctrl,
+       .vidioc_g_input         = radio_g_input,
+       .vidioc_g_ctrl          = vidioc_g_ctrl,
+       .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_frequency     = vidioc_g_frequency,
+       .vidioc_s_frequency     = vidioc_s_frequency,
+};
+
+struct video_device tm6000_radio_template = {
+       .name                   = "tm6000",
+       .fops                   = &radio_fops,
+       .ioctl_ops              = &radio_ioctl_ops,
+};
+
 /* -----------------------------------------------------------------
  *     Initialization and module stuff
  * ------------------------------------------------------------------
@@ -1499,6 +1730,25 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
        printk(KERN_INFO "%s: registered device %s\n",
               dev->name, video_device_node_name(dev->vfd));
 
+       dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
+                                                  "radio");
+       if (!dev->radio_dev) {
+               printk(KERN_INFO "%s: can't register radio device\n",
+                      dev->name);
+               return ret; /* FIXME release resource */
+       }
+
+       ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+                                   radio_nr);
+       if (ret < 0) {
+               printk(KERN_INFO "%s: can't register radio device\n",
+                      dev->name);
+               return ret; /* FIXME release resource */
+       }
+
+       printk(KERN_INFO "%s: registered device %s\n",
+              dev->name, video_device_node_name(dev->radio_dev));
+
        printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
        return ret;
 }
@@ -1507,6 +1757,14 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev)
 {
        video_unregister_device(dev->vfd);
 
+       if (dev->radio_dev) {
+               if (video_is_registered(dev->radio_dev))
+                       video_unregister_device(dev->radio_dev);
+               else
+                       video_device_release(dev->radio_dev);
+               dev->radio_dev = NULL;
+       }
+
        return 0;
 }
 
index bf11eeec92c7fa8421afb962ce671403580a03fc..99ae50e82b28a4de24b754945a7b410f78aeedf6 100644 (file)
@@ -53,6 +53,14 @@ enum tm6000_devtype {
        TM6010,
 };
 
+enum tm6000_inaudio {
+       TM6000_AIP_UNK = 0,
+       TM6000_AIP_SIF1,
+       TM6000_AIP_SIF2,
+       TM6000_AIP_LINE1,
+       TM6000_AIP_LINE2,
+};
+
 /* ------------------------------------------------------------------
  *     Basic structures
  * ------------------------------------------------------------------
@@ -121,6 +129,8 @@ struct tm6000_capabilities {
        unsigned int    has_zl10353:1;
        unsigned int    has_eeprom:1;
        unsigned int    has_remote:1;
+       unsigned int    has_input_comp:1;
+       unsigned int    has_input_svid:1;
 };
 
 struct tm6000_dvb {
@@ -174,6 +184,8 @@ struct tm6000_core {
 
        char                            *ir_codes;
 
+       __u8                            radio;
+
        /* Demodulator configuration */
        int                             demod_addr;     /* demodulator address */
 
@@ -194,6 +206,7 @@ struct tm6000_core {
        bool                            is_res_read;
 
        struct video_device             *vfd;
+       struct video_device             *radio_dev;
        struct tm6000_dmaqueue          vidq;
        struct v4l2_device              v4l2_dev;
 
@@ -203,6 +216,9 @@ struct tm6000_core {
 
        enum tm6000_mode                mode;
 
+       int                             ctl_mute;             /* audio */
+       int                             ctl_volume;
+
        /* DVB-T support */
        struct tm6000_dvb               *dvb;
 
@@ -210,7 +226,8 @@ struct tm6000_core {
        struct snd_tm6000_card          *adev;
        struct work_struct              wq_trigger;   /* Trigger to start/stop audio for alsa module */
        atomic_t                        stream_started;  /* stream should be running if true */
-
+       enum tm6000_inaudio             avideo;
+       enum tm6000_inaudio             aradio;
 
        struct tm6000_IR                *ir;
 
@@ -248,6 +265,7 @@ struct tm6000_ops {
 
 struct tm6000_fh {
        struct tm6000_core           *dev;
+       unsigned int                 radio;
 
        /* video capture */
        struct tm6000_fmt            *fmt;
@@ -276,12 +294,17 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
 int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
+                                               u16 index, u16 mask);
 int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
 int tm6000_init(struct tm6000_core *dev);
 
 int tm6000_init_analog_mode(struct tm6000_core *dev);
 int tm6000_init_digital_mode(struct tm6000_core *dev);
 int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
+int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp);
+int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
+void tm6000_set_volume(struct tm6000_core *dev, int vol);
 
 int tm6000_v4l2_register(struct tm6000_core *dev);
 int tm6000_v4l2_unregister(struct tm6000_core *dev);
index 47e5753f732adec47eaa4ccef3b7dab42894041f..17a1be536a46beefad72d15a1737881d4df28fa0 100644 (file)
@@ -1416,7 +1416,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
                                 board, bp, port, SX_PORT(tty->index));
 
        if (sx_paranoia_check(port, tty->name, "sx_open")) {
-               func_enter();
+               func_exit();
                return -ENODEV;
        }
 
@@ -1435,13 +1435,13 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
 
        error = sx_setup_port(bp, port);
        if (error) {
-               func_enter();
+               func_exit();
                return error;
        }
 
        error = block_til_ready(tty, filp, port);
        if (error) {
-               func_enter();
+               func_exit();
                return error;
        }
 
@@ -1860,7 +1860,7 @@ static int sx_set_serial_info(struct specialix_port *port,
        func_enter();
 
        if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
-               func_enter();
+               func_exit();
                return -EFAULT;
        }
 
diff --git a/drivers/staging/usbvideo/Kconfig b/drivers/staging/usbvideo/Kconfig
deleted file mode 100644 (file)
index 566d659..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-config VIDEO_USBVIDEO
-       tristate
-
-config USB_VICAM
-       tristate "USB 3com HomeConnect (aka vicam) support (DEPRECATED)"
-       depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB
-       select VIDEO_USBVIDEO
-       ---help---
-         Say Y here if you have 3com homeconnect camera (vicam).
-
-         This driver uses the deprecated V4L1 API and will be removed in
-         2.6.39, unless someone converts it to the V4L2 API.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vicam.
diff --git a/drivers/staging/usbvideo/Makefile b/drivers/staging/usbvideo/Makefile
deleted file mode 100644 (file)
index 3c99a9a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_VIDEO_USBVIDEO)    += usbvideo.o
-obj-$(CONFIG_USB_VICAM)         += vicam.o
diff --git a/drivers/staging/usbvideo/TODO b/drivers/staging/usbvideo/TODO
deleted file mode 100644 (file)
index 3b2c038..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-This is an obsolete driver for some old webcams that still use V4L1 API. 
-As V4L1 support is being removed from kernel, if nobody take care on it, 
-the driver will be removed for 2.6.39.
-
-Please send patches to linux-media@vger.kernel.org
diff --git a/drivers/staging/usbvideo/usbvideo.c b/drivers/staging/usbvideo/usbvideo.c
deleted file mode 100644 (file)
index cd4c73a..0000000
+++ /dev/null
@@ -1,2222 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <linux/io.h>
-
-#include "usbvideo.h"
-
-#if defined(MAP_NR)
-#define        virt_to_page(v) MAP_NR(v)       /* Kernels 2.2.x */
-#endif
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-/*
- * Local prototypes.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf);
-static void usbvideo_CameraRelease(struct uvd *uvd);
-
-static long usbvideo_v4l_ioctl(struct file *file,
-                             unsigned int cmd, unsigned long arg);
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
-static int usbvideo_v4l_open(struct file *file);
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                            size_t count, loff_t *ppos);
-static int usbvideo_v4l_close(struct file *file);
-
-static int usbvideo_StartDataPump(struct uvd *uvd);
-static void usbvideo_StopDataPump(struct uvd *uvd);
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
-                                               struct usbvideo_frame *frame);
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-static void *usbvideo_rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void usbvideo_rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-static void RingQueue_Initialize(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       init_waitqueue_head(&rq->wqh);
-}
-
-static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
-{
-       /* Make sure the requested size is a power of 2 and
-          round up if necessary. This allows index wrapping
-          using masks rather than modulo */
-
-       int i = 1;
-       assert(rq != NULL);
-       assert(rqLen > 0);
-
-       while (rqLen >> i)
-               i++;
-       if (rqLen != 1 << (i-1))
-               rqLen = 1 << i;
-
-       rq->length = rqLen;
-       rq->ri = rq->wi = 0;
-       rq->queue = usbvideo_rvmalloc(rq->length);
-       assert(rq->queue != NULL);
-}
-
-static int RingQueue_IsAllocated(const struct RingQueue *rq)
-{
-       if (rq == NULL)
-               return 0;
-       return (rq->queue != NULL) && (rq->length > 0);
-}
-
-static void RingQueue_Free(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (RingQueue_IsAllocated(rq)) {
-               usbvideo_rvfree(rq->queue, rq->length);
-               rq->queue = NULL;
-               rq->length = 0;
-       }
-}
-
-int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
-{
-       int rql, toread;
-
-       assert(rq != NULL);
-       assert(dst != NULL);
-
-       rql = RingQueue_GetLength(rq);
-       if (!rql)
-               return 0;
-
-       /* Clip requested length to available data */
-       if (len > rql)
-               len = rql;
-
-       toread = len;
-       if (rq->ri > rq->wi) {
-               /* Read data from tail */
-               int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
-               memcpy(dst, rq->queue + rq->ri, read);
-               toread -= read;
-               dst += read;
-               rq->ri = (rq->ri + read) & (rq->length-1);
-       }
-       if (toread) {
-               /* Read data from head */
-               memcpy(dst, rq->queue + rq->ri, toread);
-               rq->ri = (rq->ri + toread) & (rq->length-1);
-       }
-       return len;
-}
-
-EXPORT_SYMBOL(RingQueue_Dequeue);
-
-int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
-{
-       int enqueued = 0;
-
-       assert(rq != NULL);
-       assert(cdata != NULL);
-       assert(rq->length > 0);
-       while (n > 0) {
-               int m, q_avail;
-
-               /* Calculate the largest chunk that fits the tail of the ring */
-               q_avail = rq->length - rq->wi;
-               if (q_avail <= 0) {
-                       rq->wi = 0;
-                       q_avail = rq->length;
-               }
-               m = n;
-               assert(q_avail > 0);
-               if (m > q_avail)
-                       m = q_avail;
-
-               memcpy(rq->queue + rq->wi, cdata, m);
-               RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
-               cdata += m;
-               enqueued += m;
-               n -= m;
-       }
-       return enqueued;
-}
-
-EXPORT_SYMBOL(RingQueue_Enqueue);
-
-static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       interruptible_sleep_on(&rq->wqh);
-}
-
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (waitqueue_active(&rq->wqh))
-               wake_up_interruptible(&rq->wqh);
-}
-
-EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
-
-void RingQueue_Flush(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       rq->ri = 0;
-       rq->wi = 0;
-}
-
-EXPORT_SYMBOL(RingQueue_Flush);
-
-
-/*
- * usbvideo_VideosizeToString()
- *
- * This procedure converts given videosize value to readable string.
- *
- * History:
- * 07-Aug-2000 Created.
- * 19-Oct-2000 Reworked for usbvideo module.
- */
-static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
-{
-       char tmp[40];
-       int n;
-
-       n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
-       assert(n < sizeof(tmp));
-       if ((buf == NULL) || (bufLen < n))
-               err("usbvideo_VideosizeToString: buffer is too small.");
-       else
-               memmove(buf, tmp, n);
-}
-
-/*
- * usbvideo_OverlayChar()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
-                                int x, int y, int ch)
-{
-       static const unsigned short digits[16] = {
-               0xF6DE, /* 0 */
-               0x2492, /* 1 */
-               0xE7CE, /* 2 */
-               0xE79E, /* 3 */
-               0xB792, /* 4 */
-               0xF39E, /* 5 */
-               0xF3DE, /* 6 */
-               0xF492, /* 7 */
-               0xF7DE, /* 8 */
-               0xF79E, /* 9 */
-               0x77DA, /* a */
-               0xD75C, /* b */
-               0xF24E, /* c */
-               0xD6DC, /* d */
-               0xF34E, /* e */
-               0xF348  /* f */
-       };
-       unsigned short digit;
-       int ix, iy;
-       int value;
-
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       value = hex_to_bin(ch);
-       if (value < 0)
-               return;
-       digit = digits[value];
-
-       for (iy = 0; iy < 5; iy++) {
-               for (ix = 0; ix < 3; ix++) {
-                       if (digit & 0x8000) {
-                               if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))
-/* TODO */                             RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
-                       }
-                       digit = digit << 1;
-               }
-       }
-}
-
-/*
- * usbvideo_OverlayString()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
-                                  int x, int y, const char *str)
-{
-       while (*str) {
-               usbvideo_OverlayChar(uvd, frame, x, y, *str);
-               str++;
-               x += 4; /* 3 pixels character + 1 space */
-       }
-}
-
-/*
- * usbvideo_OverlayStats()
- *
- * Overlays important debugging information.
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       const int y_diff = 8;
-       char tmp[16];
-       int x = 10, y = 10;
-       long i, j, barLength;
-       const int qi_x1 = 60, qi_y1 = 10;
-       const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
-
-       /* Call the user callback, see if we may proceed after that */
-       if (VALID_CALLBACK(uvd, overlayHook)) {
-               if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
-                       return;
-       }
-
-       /*
-        * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
-        * Left edge symbolizes the queue index 0; right edge symbolizes
-        * the full capacity of the queue.
-        */
-       barLength = qi_x2 - qi_x1 - 2;
-       if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
-/* TODO */     long u_lo, u_hi, q_used;
-               long m_ri, m_wi, m_lo, m_hi;
-
-               /*
-                * Determine fill zones (used areas of the queue):
-                * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
-                *
-                * if u_lo < 0 then there is no first filler.
-                */
-
-               q_used = RingQueue_GetLength(&uvd->dp);
-               if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
-                       u_hi = uvd->dp.length;
-                       u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
-               } else {
-                       u_hi = (q_used + uvd->dp.ri);
-                       u_lo = -1;
-               }
-
-               /* Convert byte indices into screen units */
-               m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
-               m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
-               m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
-               m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
-
-               for (j = qi_y1; j < (qi_y1 + qi_h); j++) {
-                       for (i = qi_x1; i < qi_x2; i++) {
-                               /* Draw border lines */
-                               if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
-                                   (i == qi_x1) || (i == (qi_x2 - 1))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
-                                       continue;
-                               }
-                               /* For all other points the Y coordinate does not matter */
-                               if ((i >= m_ri) && (i <= (m_ri + 3)))
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
-                               else if ((i >= m_wi) && (i <= (m_wi + 3)))
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
-                               else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
-                       }
-               }
-       }
-
-       sprintf(tmp, "%8lx", uvd->stats.frame_num);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_length);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.data_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.header_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.colour);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.hue);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-}
-
-/*
- * usbvideo_ReportStatistics()
- *
- * This procedure prints packet and transfer statistics.
- *
- * History:
- * 14-Jan-2000 Corrected default multiplier.
- */
-static void usbvideo_ReportStatistics(const struct uvd *uvd)
-{
-       if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
-               unsigned long allPackets, badPackets, goodPackets, percent;
-               allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
-               badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
-               goodPackets = allPackets - badPackets;
-               /* Calculate percentage wisely, remember integer limits */
-               assert(allPackets != 0);
-               if (goodPackets < (((unsigned long)-1)/100))
-                       percent = (100 * goodPackets) / allPackets;
-               else
-                       percent = goodPackets / (allPackets / 100);
-               dev_info(&uvd->dev->dev,
-                        "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n",
-                        allPackets, badPackets, percent);
-               if (uvd->iso_packet_len > 0) {
-                       unsigned long allBytes, xferBytes;
-                       char multiplier = ' ';
-                       allBytes = allPackets * uvd->iso_packet_len;
-                       xferBytes = uvd->stats.data_count;
-                       assert(allBytes != 0);
-                       if (xferBytes < (((unsigned long)-1)/100))
-                               percent = (100 * xferBytes) / allBytes;
-                       else
-                               percent = xferBytes / (allBytes / 100);
-                       /* Scale xferBytes for easy reading */
-                       if (xferBytes > 10*1024) {
-                               xferBytes /= 1024;
-                               multiplier = 'K';
-                               if (xferBytes > 10*1024) {
-                                       xferBytes /= 1024;
-                                       multiplier = 'M';
-                                       if (xferBytes > 10*1024) {
-                                               xferBytes /= 1024;
-                                               multiplier = 'G';
-                                               if (xferBytes > 10*1024) {
-                                                       xferBytes /= 1024;
-                                                       multiplier = 'T';
-                                               }
-                                       }
-                               }
-                       }
-                       dev_info(&uvd->dev->dev,
-                                "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n",
-                                xferBytes, multiplier, percent);
-               }
-       }
-}
-
-/*
- * usbvideo_TestPattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- *           continues from the current scanline.
- * pmode      0: fill the frame with solid blue color (like on VCR or TV)
- *           1: Draw a colored grid
- *
- * History:
- * 01-Feb-2000 Created.
- */
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
-{
-       struct usbvideo_frame *frame;
-       int num_cell = 0;
-       int scan_length = 0;
-       static int num_pass;
-
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __func__);
-               return;
-       }
-       if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-               err("%s: uvd->curframe=%d.", __func__, uvd->curframe);
-               return;
-       }
-
-       /* Grab the current frame */
-       frame = &uvd->frame[uvd->curframe];
-
-       /* Optionally start at the beginning */
-       if (fullframe) {
-               frame->curline = 0;
-               frame->seqRead_Length = 0;
-       }
-#if 0
-       {       /* For debugging purposes only */
-               char tmp[20];
-               usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
-               dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp);
-       }
-#endif
-       /* Form every scan line */
-       for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
-               int i;
-               unsigned char *f = frame->data +
-                       (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
-               for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-                       unsigned char cb = 0x80;
-                       unsigned char cg = 0;
-                       unsigned char cr = 0;
-
-                       if (pmode == 1) {
-                               if (frame->curline % 32 == 0)
-                                       cb = 0, cg = cr = 0xFF;
-                               else if (i % 32 == 0) {
-                                       if (frame->curline % 32 == 1)
-                                               num_cell++;
-                                       cb = 0, cg = cr = 0xFF;
-                               } else {
-                                       cb = ((num_cell*7) + num_pass) & 0xFF;
-                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
-                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
-                               }
-                       } else {
-                               /* Just the blue screen */
-                       }
-
-                       *f++ = cb;
-                       *f++ = cg;
-                       *f++ = cr;
-                       scan_length += 3;
-               }
-       }
-
-       frame->frameState = FrameState_Done;
-       frame->seqRead_Length += scan_length;
-       ++num_pass;
-
-       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
-       usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_TestPattern);
-
-
-#ifdef DEBUG
-/*
- * usbvideo_HexDump()
- *
- * A debugging tool. Prints hex dumps.
- *
- * History:
- * 29-Jul-2000 Added printing of offsets.
- */
-void usbvideo_HexDump(const unsigned char *data, int len)
-{
-       const int bytes_per_line = 32;
-       char tmp[128]; /* 32*3 + 5 */
-       int i, k;
-
-       for (i = k = 0; len > 0; i++, len--) {
-               if (i > 0 && ((i % bytes_per_line) == 0)) {
-                       printk("%s\n", tmp);
-                       k = 0;
-               }
-               if ((i % bytes_per_line) == 0)
-                       k += sprintf(&tmp[k], "%04x: ", i);
-               k += sprintf(&tmp[k], "%02x ", data[i]);
-       }
-       if (k > 0)
-               printk("%s\n", tmp);
-}
-
-EXPORT_SYMBOL(usbvideo_HexDump);
-
-#endif
-
-/* ******************************************************************** */
-
-/* XXX: this piece of crap really wants some error handling.. */
-static int usbvideo_ClientIncModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __func__);
-               return -EINVAL;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __func__);
-               return -EINVAL;
-       }
-       if (!try_module_get(uvd->handle->md_module)) {
-               err("%s: try_module_get() == 0", __func__);
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static void usbvideo_ClientDecModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __func__);
-               return;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __func__);
-               return;
-       }
-       if (uvd->handle->md_module == NULL) {
-               err("%s: uvd->handle->md_module == NULL", __func__);
-               return;
-       }
-       module_put(uvd->handle->md_module);
-}
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTbl,
-       struct module *md,
-       const struct usb_device_id *id_table)
-{
-       struct usbvideo *cams;
-       int i, base_size, result;
-
-       /* Check parameters for sanity */
-       if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-               err("%s: Illegal call", __func__);
-               return -EINVAL;
-       }
-
-       /* Check registration callback - must be set! */
-       if (cbTbl->probe == NULL) {
-               err("%s: probe() is required!", __func__);
-               return -EINVAL;
-       }
-
-       base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-       cams = kzalloc(base_size, GFP_KERNEL);
-       if (cams == NULL) {
-               err("Failed to allocate %d. bytes for usbvideo struct", base_size);
-               return -ENOMEM;
-       }
-       dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-           __func__, cams, base_size, num_cams);
-
-       /* Copy callbacks, apply defaults for those that are not set */
-       memmove(&cams->cb, cbTbl, sizeof(cams->cb));
-       if (cams->cb.getFrame == NULL)
-               cams->cb.getFrame = usbvideo_GetFrame;
-       if (cams->cb.disconnect == NULL)
-               cams->cb.disconnect = usbvideo_Disconnect;
-       if (cams->cb.startDataPump == NULL)
-               cams->cb.startDataPump = usbvideo_StartDataPump;
-       if (cams->cb.stopDataPump == NULL)
-               cams->cb.stopDataPump = usbvideo_StopDataPump;
-
-       cams->num_cameras = num_cams;
-       cams->cam = (struct uvd *) &cams[1];
-       cams->md_module = md;
-       mutex_init(&cams->lock);        /* to 1 == available */
-
-       for (i = 0; i < num_cams; i++) {
-               struct uvd *up = &cams->cam[i];
-
-               up->handle = cams;
-
-               /* Allocate user_data separately because of kmalloc's limits */
-               if (num_extra > 0) {
-                       up->user_size = num_cams * num_extra;
-                       up->user_data = kmalloc(up->user_size, GFP_KERNEL);
-                       if (up->user_data == NULL) {
-                               err("%s: Failed to allocate user_data (%d. bytes)",
-                                   __func__, up->user_size);
-                               while (i) {
-                                       up = &cams->cam[--i];
-                                       kfree(up->user_data);
-                               }
-                               kfree(cams);
-                               return -ENOMEM;
-                       }
-                       dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-                            __func__, i, up->user_data, up->user_size);
-               }
-       }
-
-       /*
-        * Register ourselves with USB stack.
-        */
-       strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
-       cams->usbdrv.name = cams->drvName;
-       cams->usbdrv.probe = cams->cb.probe;
-       cams->usbdrv.disconnect = cams->cb.disconnect;
-       cams->usbdrv.id_table = id_table;
-
-       /*
-        * Update global handle to usbvideo. This is very important
-        * because probe() can be called before usb_register() returns.
-        * If the handle is not yet updated then the probe() will fail.
-        */
-       *pCams = cams;
-       result = usb_register(&cams->usbdrv);
-       if (result) {
-               for (i = 0; i < num_cams; i++) {
-                       struct uvd *up = &cams->cam[i];
-                       kfree(up->user_data);
-               }
-               kfree(cams);
-       }
-
-       return result;
-}
-
-EXPORT_SYMBOL(usbvideo_register);
-
-/*
- * usbvideo_Deregister()
- *
- * Procedure frees all usbvideo and user data structures. Be warned that
- * if you had some dynamically allocated components in ->user field then
- * you should free them before calling here.
- */
-void usbvideo_Deregister(struct usbvideo **pCams)
-{
-       struct usbvideo *cams;
-       int i;
-
-       if (pCams == NULL) {
-               err("%s: pCams == NULL", __func__);
-               return;
-       }
-       cams = *pCams;
-       if (cams == NULL) {
-               err("%s: cams == NULL", __func__);
-               return;
-       }
-
-       dbg("%s: Deregistering %s driver.", __func__, cams->drvName);
-       usb_deregister(&cams->usbdrv);
-
-       dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras);
-       for (i = 0; i < cams->num_cameras; i++) {
-               struct uvd *up = &cams->cam[i];
-               int warning = 0;
-
-               if (up->user_data != NULL) {
-                       if (up->user_size <= 0)
-                               ++warning;
-               } else {
-                       if (up->user_size > 0)
-                               ++warning;
-               }
-               if (warning) {
-                       err("%s: Warning: user_data=$%p user_size=%d.",
-                           __func__, up->user_data, up->user_size);
-               } else {
-                       dbg("%s: Freeing %d. $%p->user_data=$%p",
-                           __func__, i, up, up->user_data);
-                       kfree(up->user_data);
-               }
-       }
-       /* Whole array was allocated in one chunk */
-       dbg("%s: Freed %d uvd structures",
-           __func__, cams->num_cameras);
-       kfree(cams);
-       *pCams = NULL;
-}
-
-EXPORT_SYMBOL(usbvideo_Deregister);
-
-/*
- * usbvideo_Disconnect()
- *
- * This procedure stops all driver activity. Deallocation of
- * the interface-private structure (pointed by 'ptr') is done now
- * (if we don't have any open files) or later, when those files
- * are closed. After that driver should be removable.
- *
- * This code handles surprise removal. The uvd->user is a counter which
- * increments on open() and decrements on close(). If we see here that
- * this counter is not 0 then we have a client who still has us opened.
- * We set uvd->remove_pending flag as early as possible, and after that
- * all access to the camera will gracefully fail. These failures should
- * prompt client to (eventually) close the video device, and then - in
- * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
- *
- * History:
- * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
- * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 19-Oct-2000 Moved to usbvideo module.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf)
-{
-       struct uvd *uvd = usb_get_intfdata(intf);
-       int i;
-
-       if (uvd == NULL) {
-               err("%s($%p): Illegal call.", __func__, intf);
-               return;
-       }
-
-       usb_set_intfdata(intf, NULL);
-
-       usbvideo_ClientIncModCount(uvd);
-       if (uvd->debug > 0)
-               dev_info(&intf->dev, "%s(%p.)\n", __func__, intf);
-
-       mutex_lock(&uvd->lock);
-       uvd->remove_pending = 1; /* Now all ISO data will be ignored */
-
-       /* At this time we ask to cancel outstanding URBs */
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++)
-               usb_free_urb(uvd->sbuf[i].urb);
-
-       usb_put_dev(uvd->dev);
-       uvd->dev = NULL;            /* USB device is no more */
-
-       video_unregister_device(&uvd->vdev);
-       if (uvd->debug > 0)
-               dev_info(&intf->dev, "%s: Video unregistered.\n", __func__);
-
-       if (uvd->user)
-               dev_info(&intf->dev, "%s: In use, disconnect pending.\n",
-                        __func__);
-       else
-               usbvideo_CameraRelease(uvd);
-       mutex_unlock(&uvd->lock);
-       dev_info(&intf->dev, "USB camera disconnected.\n");
-
-       usbvideo_ClientDecModCount(uvd);
-}
-
-/*
- * usbvideo_CameraRelease()
- *
- * This code does final release of uvd. This happens
- * after the device is disconnected -and- all clients
- * closed their files.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static void usbvideo_CameraRelease(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: Illegal call", __func__);
-               return;
-       }
-
-       RingQueue_Free(&uvd->dp);
-       if (VALID_CALLBACK(uvd, userFree))
-               GET_CALLBACK(uvd, userFree)(uvd);
-       uvd->uvd_used = 0;      /* This is atomic, no need to take mutex */
-}
-
-/*
- * usbvideo_find_struct()
- *
- * This code searches the array of preallocated (static) structures
- * and returns index of the first one that isn't in use. Returns -1
- * if there are no free structures.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static int usbvideo_find_struct(struct usbvideo *cams)
-{
-       int u, rv = -1;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return -1;
-       }
-       mutex_lock(&cams->lock);
-       for (u = 0; u < cams->num_cameras; u++) {
-               struct uvd *uvd = &cams->cam[u];
-               if (!uvd->uvd_used) { /* This one is free */
-                       uvd->uvd_used = 1;      /* In use now */
-                       mutex_init(&uvd->lock); /* to 1 == available */
-                       uvd->dev = NULL;
-                       rv = u;
-                       break;
-               }
-       }
-       mutex_unlock(&cams->lock);
-       return rv;
-}
-
-static const struct v4l2_file_operations usbvideo_fops = {
-       .owner =  THIS_MODULE,
-       .open =   usbvideo_v4l_open,
-       .release = usbvideo_v4l_close,
-       .read =    usbvideo_v4l_read,
-       .mmap =    usbvideo_v4l_mmap,
-       .ioctl =   usbvideo_v4l_ioctl,
-};
-static const struct video_device usbvideo_template = {
-       .fops =       &usbvideo_fops,
-};
-
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
-{
-       int i, devnum;
-       struct uvd *uvd = NULL;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return NULL;
-       }
-
-       devnum = usbvideo_find_struct(cams);
-       if (devnum == -1) {
-               err("IBM USB camera driver: Too many devices!");
-               return NULL;
-       }
-       uvd = &cams->cam[devnum];
-       dbg("Device entry #%d. at $%p", devnum, uvd);
-
-       /* Not relying upon caller we increase module counter ourselves */
-       usbvideo_ClientIncModCount(uvd);
-
-       mutex_lock(&uvd->lock);
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (uvd->sbuf[i].urb == NULL) {
-                       err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
-                       uvd->uvd_used = 0;
-                       uvd = NULL;
-                       goto allocate_done;
-               }
-       }
-       uvd->user = 0;
-       uvd->remove_pending = 0;
-       uvd->last_error = 0;
-       RingQueue_Initialize(&uvd->dp);
-
-       /* Initialize video device structure */
-       uvd->vdev = usbvideo_template;
-       sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
-       /*
-        * The client is free to overwrite those because we
-        * return control to the client's probe function right now.
-        */
-allocate_done:
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-       return uvd;
-}
-
-EXPORT_SYMBOL(usbvideo_AllocateDevice);
-
-int usbvideo_RegisterVideoDevice(struct uvd *uvd)
-{
-       char tmp1[20], tmp2[20];        /* Buffers for printing */
-
-       if (uvd == NULL) {
-               err("%s: Illegal call.", __func__);
-               return -EINVAL;
-       }
-       if (uvd->video_endp == 0) {
-               dev_info(&uvd->dev->dev,
-                        "%s: No video endpoint specified; data pump disabled.\n",
-                        __func__);
-       }
-       if (uvd->paletteBits == 0) {
-               err("%s: No palettes specified!", __func__);
-               return -EINVAL;
-       }
-       if (uvd->defaultPalette == 0) {
-               dev_info(&uvd->dev->dev, "%s: No default palette!\n",
-                        __func__);
-       }
-
-       uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
-               VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
-       usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
-       usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
-
-       if (uvd->debug > 0) {
-               dev_info(&uvd->dev->dev,
-                        "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n",
-                        __func__, uvd->iface, uvd->video_endp,
-                        uvd->paletteBits);
-       }
-       if (uvd->dev == NULL) {
-               err("%s: uvd->dev == NULL", __func__);
-               return -EINVAL;
-       }
-       uvd->vdev.parent = &uvd->dev->dev;
-       uvd->vdev.release = video_device_release_empty;
-       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
-               err("%s: video_register_device failed", __func__);
-               return -EPIPE;
-       }
-       if (uvd->debug > 1) {
-               dev_info(&uvd->dev->dev,
-                        "%s: video_register_device() successful\n", __func__);
-       }
-
-       dev_info(&uvd->dev->dev, "%s on %s: canvas=%s videosize=%s\n",
-                (uvd->handle != NULL) ? uvd->handle->drvName : "???",
-                video_device_node_name(&uvd->vdev), tmp2, tmp1);
-
-       usb_get_dev(uvd->dev);
-       return 0;
-}
-
-EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
-
-/* ******************************************************************** */
-
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct uvd *uvd = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EFAULT;
-
-       if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-               return -EINVAL;
-
-       pos = (unsigned long) uvd->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-/*
- * usbvideo_v4l_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'uvdser'). The procedure
- * then allocates buffers needed for video processing.
- *
- * History:
- * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
- *             camera is also initialized here (once per connect), at
- *             expense of V4L client (it waits on open() call).
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- */
-static int usbvideo_v4l_open(struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct uvd *uvd = (struct uvd *) dev;
-       const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
-       int i, errCode = 0;
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
-
-       if (usbvideo_ClientIncModCount(uvd) < 0)
-               return -ENODEV;
-       mutex_lock(&uvd->lock);
-
-       if (uvd->user) {
-               err("%s: Someone tried to open an already opened device!", __func__);
-               errCode = -EBUSY;
-       } else {
-               /* Clear statistics */
-               memset(&uvd->stats, 0, sizeof(uvd->stats));
-
-               /* Clean pointers so we know if we allocated something */
-               for (i = 0; i < USBVIDEO_NUMSBUF; i++)
-                       uvd->sbuf[i].data = NULL;
-
-               /* Allocate memory for the frame buffers */
-               uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
-               uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
-               RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
-               if ((uvd->fbuf == NULL) ||
-                   (!RingQueue_IsAllocated(&uvd->dp))) {
-                       err("%s: Failed to allocate fbuf or dp", __func__);
-                       errCode = -ENOMEM;
-               } else {
-                       /* Allocate all buffers */
-                       for (i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-                               uvd->frame[i].frameState = FrameState_Unused;
-                               uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
-                               /*
-                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
-                                * is not used (using read() instead).
-                                */
-                               uvd->frame[i].canvas = uvd->canvas;
-                               uvd->frame[i].seqRead_Index = 0;
-                       }
-                       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-                               uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
-                               if (uvd->sbuf[i].data == NULL) {
-                                       errCode = -ENOMEM;
-                                       break;
-                               }
-                       }
-               }
-               if (errCode != 0) {
-                       /* Have to free all that memory */
-                       if (uvd->fbuf != NULL) {
-                               usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-                               uvd->fbuf = NULL;
-                       }
-                       RingQueue_Free(&uvd->dp);
-                       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-                               kfree(uvd->sbuf[i].data);
-                               uvd->sbuf[i].data = NULL;
-                       }
-               }
-       }
-
-       /* If so far no errors then we shall start the camera */
-       if (errCode == 0) {
-               /* Start data pump if we have valid endpoint */
-               if (uvd->video_endp != 0)
-                       errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
-               if (errCode == 0) {
-                       if (VALID_CALLBACK(uvd, setupOnOpen)) {
-                               if (uvd->debug > 1)
-                                       dev_info(&uvd->dev->dev,
-                                                "%s: setupOnOpen callback\n",
-                                                __func__);
-                               errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
-                               if (errCode < 0) {
-                                       err("%s: setupOnOpen callback failed (%d.).",
-                                           __func__, errCode);
-                               } else if (uvd->debug > 1) {
-                                       dev_info(&uvd->dev->dev,
-                                                "%s: setupOnOpen callback successful\n",
-                                                __func__);
-                               }
-                       }
-                       if (errCode == 0) {
-                               uvd->settingsAdjusted = 0;
-                               if (uvd->debug > 1)
-                                       dev_info(&uvd->dev->dev,
-                                                "%s: Open succeeded.\n",
-                                                __func__);
-                               uvd->user++;
-                               file->private_data = uvd;
-                       }
-               }
-       }
-       mutex_unlock(&uvd->lock);
-       if (errCode != 0)
-               usbvideo_ClientDecModCount(uvd);
-       if (uvd->debug > 0)
-               dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__,
-                        errCode);
-       return errCode;
-}
-
-/*
- * usbvideo_v4l_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in usbvideo_v4l_open().
- *
- * History:
- * 22-Jan-2000 Moved scratch buffer deallocation here.
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
- */
-static int usbvideo_v4l_close(struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct uvd *uvd = (struct uvd *) dev;
-       int i;
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
-
-       mutex_lock(&uvd->lock);
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-       usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-       uvd->fbuf = NULL;
-       RingQueue_Free(&uvd->dp);
-
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               kfree(uvd->sbuf[i].data);
-               uvd->sbuf[i].data = NULL;
-       }
-
-#if USBVIDEO_REPORT_STATS
-       usbvideo_ReportStatistics(uvd);
-#endif
-
-       uvd->user--;
-       if (uvd->remove_pending) {
-               if (uvd->debug > 0)
-                       dev_info(&uvd->dev->dev, "%s: Final disconnect.\n",
-                                __func__);
-               usbvideo_CameraRelease(uvd);
-       }
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__);
-       file->private_data = NULL;
-       return 0;
-}
-
-/*
- * usbvideo_v4l_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
- * History:
- * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
- */
-static long usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
-       struct uvd *uvd = file->private_data;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-               {
-                       struct video_capability *b = arg;
-                       *b = uvd->vcap;
-                       return 0;
-               }
-       case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-                       *v = uvd->vchan;
-                       return 0;
-               }
-       case VIDIOCSCHAN:
-               {
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCGPICT:
-               {
-                       struct video_picture *pic = arg;
-                       *pic = uvd->vpic;
-                       return 0;
-               }
-       case VIDIOCSPICT:
-               {
-                       struct video_picture *pic = arg;
-                       /*
-                        * Use temporary 'video_picture' structure to preserve our
-                        * own settings (such as color depth, palette) that we
-                        * aren't allowing everyone (V4L client) to change.
-                        */
-                       uvd->vpic.brightness = pic->brightness;
-                       uvd->vpic.hue = pic->hue;
-                       uvd->vpic.colour = pic->colour;
-                       uvd->vpic.contrast = pic->contrast;
-                       uvd->settingsAdjusted = 0;      /* Will force new settings */
-                       return 0;
-               }
-       case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       if (VALID_CALLBACK(uvd, setVideoMode))
-                               return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != VIDEOSIZE_X(uvd->canvas))
-                               return -EINVAL;
-                       if (vw->height != VIDEOSIZE_Y(uvd->canvas))
-                               return -EINVAL;
-
-                       return 0;
-               }
-       case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = VIDEOSIZE_X(uvd->videosize);
-                       vw->height = VIDEOSIZE_Y(uvd->videosize);
-                       vw->chromakey = 0;
-                       if (VALID_CALLBACK(uvd, getFPS))
-                               vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
-                       else
-                               vw->flags = 10; /* FIXME: do better! */
-                       return 0;
-               }
-       case VIDIOCGMBUF:
-               {
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
-                       vm->frames = USBVIDEO_NUMFRAMES;
-                       for (i = 0; i < USBVIDEO_NUMFRAMES; i++)
-                               vm->offsets[i] = i * uvd->max_frame_size;
-
-                       return 0;
-               }
-       case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap *vm = arg;
-
-                       if (uvd->debug >= 1) {
-                               dev_info(&uvd->dev->dev,
-                                        "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n",
-                                        vm->frame, vm->width, vm->height, vm->format);
-                       }
-                       /*
-                        * Check if the requested size is supported. If the requestor
-                        * requests too big a frame then we may be tricked into accessing
-                        * outside of own preallocated frame buffer (in uvd->frame).
-                        * This will cause oops or a security hole. Theoretically, we
-                        * could only clamp the size down to acceptable bounds, but then
-                        * we'd need to figure out how to insert our smaller buffer into
-                        * larger caller's buffer... this is not an easy question. So we
-                        * here just flatly reject too large requests, assuming that the
-                        * caller will resubmit with smaller size. Callers should know
-                        * what size we support (returned by VIDIOCGCAP). However vidcat,
-                        * for one, does not care and allows to ask for any size.
-                        */
-                       if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
-                           (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
-                               if (uvd->debug > 0) {
-                                       dev_info(&uvd->dev->dev,
-                                                "VIDIOCMCAPTURE: Size=%dx%d "
-                                                "too large; allowed only up "
-                                                "to %ldx%ld\n", vm->width,
-                                                vm->height,
-                                                VIDEOSIZE_X(uvd->canvas),
-                                                VIDEOSIZE_Y(uvd->canvas));
-                               }
-                               return -EINVAL;
-                       }
-                       /* Check if the palette is supported */
-                       if (((1L << vm->format) & uvd->paletteBits) == 0) {
-                               if (uvd->debug > 0) {
-                                       dev_info(&uvd->dev->dev,
-                                                "VIDIOCMCAPTURE: format=%d. "
-                                                "not supported "
-                                                "(paletteBits=$%08lx)\n",
-                                                vm->format, uvd->paletteBits);
-                               }
-                               return -EINVAL;
-                       }
-                       if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
-                               err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
-                               return -EINVAL;
-                       }
-                       if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
-                               /* Not an error - can happen */
-                       }
-                       uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
-                       uvd->frame[vm->frame].palette = vm->format;
-
-                       /* Mark it as ready */
-                       uvd->frame[vm->frame].frameState = FrameState_Ready;
-
-                       return usbvideo_NewFrame(uvd, vm->frame);
-               }
-       case VIDIOCSYNC:
-               {
-                       int *frameNum = arg;
-                       int ret;
-
-                       if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
-                               return -EINVAL;
-
-                       if (uvd->debug >= 1)
-                               dev_info(&uvd->dev->dev,
-                                        "VIDIOCSYNC: syncing to frame %d.\n",
-                                        *frameNum);
-                       if (uvd->flags & FLAGS_NO_DECODING)
-                               ret = usbvideo_GetFrame(uvd, *frameNum);
-                       else if (VALID_CALLBACK(uvd, getFrame)) {
-                               ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
-                               if ((ret < 0) && (uvd->debug >= 1))
-                                       err("VIDIOCSYNC: getFrame() returned %d.", ret);
-                       } else {
-                               err("VIDIOCSYNC: getFrame is not set");
-                               ret = -EFAULT;
-                       }
-
-                       /*
-                        * The frame is in FrameState_Done_Hold state. Release it
-                        * right now because its data is already mapped into
-                        * the user space and it's up to the application to
-                        * make use of it until it asks for another frame.
-                        */
-                       uvd->frame[*frameNum].frameState = FrameState_Unused;
-                       return ret;
-               }
-       case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb, 0, sizeof(*vb));
-                       return 0;
-               }
-       case VIDIOCKEY:
-               return 0;
-
-       case VIDIOCCAPTURE:
-               return -EINVAL;
-
-       case VIDIOCSFBUF:
-
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static long usbvideo_v4l_ioctl(struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl);
-}
-
-/*
- * usbvideo_v4l_read()
- *
- * This is mostly boring stuff. We simply ask for a frame and when it
- * arrives copy all the video data from it into user space. There is
- * no obvious need to override this method.
- *
- * History:
- * 20-Oct-2000 Created.
- * 01-Nov-2000 Added mutex (uvd->lock).
- */
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                     size_t count, loff_t *ppos)
-{
-       struct uvd *uvd = file->private_data;
-       int noblock = file->f_flags & O_NONBLOCK;
-       int frmx = -1, i;
-       struct usbvideo_frame *frame;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
-               return -EFAULT;
-
-       if (uvd->debug >= 1)
-               dev_info(&uvd->dev->dev,
-                        "%s: %Zd. bytes, noblock=%d.\n",
-                        __func__, count, noblock);
-
-       mutex_lock(&uvd->lock);
-
-       /* See if a frame is completed, then use it. */
-       for (i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-               if ((uvd->frame[i].frameState == FrameState_Done) ||
-                   (uvd->frame[i].frameState == FrameState_Done_Hold) ||
-                   (uvd->frame[i].frameState == FrameState_Error)) {
-                       frmx = i;
-                       break;
-               }
-       }
-
-       /* FIXME: If we don't start a frame here then who ever does? */
-       if (noblock && (frmx == -1)) {
-               count = -EAGAIN;
-               goto read_done;
-       }
-
-       /*
-        * If no FrameState_Done, look for a FrameState_Grabbing state.
-        * See if a frame is in process (grabbing), then use it.
-        * We will need to wait until it becomes cooked, of course.
-        */
-       if (frmx == -1) {
-               for (i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-                       if (uvd->frame[i].frameState == FrameState_Grabbing) {
-                               frmx = i;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * If no frame is active, start one. We don't care which one
-        * it will be, so #0 is as good as any.
-        * In read access mode we don't have convenience of VIDIOCMCAPTURE
-        * to specify the requested palette (video format) on per-frame
-        * basis. This means that we have to return data in -some- format
-        * and just hope that the client knows what to do with it.
-        * The default format is configured in uvd->defaultPalette field
-        * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
-        * frame and initiate the frame filling process.
-        */
-       if (frmx == -1) {
-               if (uvd->defaultPalette == 0) {
-                       err("%s: No default palette; don't know what to do!", __func__);
-                       count = -EFAULT;
-                       goto read_done;
-               }
-               frmx = 0;
-               /*
-                * We have no per-frame control over video size.
-                * Therefore we only can use whatever size was
-                * specified as default.
-                */
-               uvd->frame[frmx].request = uvd->videosize;
-               uvd->frame[frmx].palette = uvd->defaultPalette;
-               uvd->frame[frmx].frameState = FrameState_Ready;
-               usbvideo_NewFrame(uvd, frmx);
-               /* Now frame 0 is supposed to start filling... */
-       }
-
-       /*
-        * Get a pointer to the active frame. It is either previously
-        * completed frame or frame in progress but not completed yet.
-        */
-       frame = &uvd->frame[frmx];
-
-       /*
-        * Sit back & wait until the frame gets filled and postprocessed.
-        * If we fail to get the picture [in time] then return the error.
-        * In this call we specify that we want the frame to be waited for,
-        * postprocessed and switched into FrameState_Done_Hold state. This
-        * state is used to hold the frame as "fully completed" between
-        * subsequent partial reads of the same frame.
-        */
-       if (frame->frameState != FrameState_Done_Hold) {
-               long rv = -EFAULT;
-               if (uvd->flags & FLAGS_NO_DECODING)
-                       rv = usbvideo_GetFrame(uvd, frmx);
-               else if (VALID_CALLBACK(uvd, getFrame))
-                       rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
-               else
-                       err("getFrame is not set");
-               if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
-                       count = rv;
-                       goto read_done;
-               }
-       }
-
-       /*
-        * Copy bytes to user space. We allow for partial reads, which
-        * means that the user application can request read less than
-        * the full frame size. It is up to the application to issue
-        * subsequent calls until entire frame is read.
-        *
-        * First things first, make sure we don't copy more than we
-        * have - even if the application wants more. That would be
-        * a big security embarassment!
-        */
-       if ((count + frame->seqRead_Index) > frame->seqRead_Length)
-               count = frame->seqRead_Length - frame->seqRead_Index;
-
-       /*
-        * Copy requested amount of data to user space. We start
-        * copying from the position where we last left it, which
-        * will be zero for a new frame (not read before).
-        */
-       if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
-               count = -EFAULT;
-               goto read_done;
-       }
-
-       /* Update last read position */
-       frame->seqRead_Index += count;
-       if (uvd->debug >= 1) {
-               err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
-                       __func__, count, frame->seqRead_Index);
-       }
-
-       /* Finally check if the frame is done with and "release" it */
-       if (frame->seqRead_Index >= frame->seqRead_Length) {
-               /* All data has been read */
-               frame->seqRead_Index = 0;
-
-               /* Mark it as available to be used again. */
-               uvd->frame[frmx].frameState = FrameState_Unused;
-               if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES))
-                       err("%s: usbvideo_NewFrame failed.", __func__);
-       }
-read_done:
-       mutex_unlock(&uvd->lock);
-       return count;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
-{
-       char *cdata;
-       int i, totlen = 0;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               int n = urb->iso_frame_desc[i].actual_length;
-               int st = urb->iso_frame_desc[i].status;
-
-               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       if (uvd->debug >= 1)
-                               err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       uvd->stats.iso_skip_count++;
-                       continue;
-               }
-               totlen += n;    /* Little local accounting */
-               RingQueue_Enqueue(&uvd->dp, cdata, n);
-       }
-       return totlen;
-}
-
-static void usbvideo_IsocIrq(struct urb *urb)
-{
-       int i, ret, len;
-       struct uvd *uvd = urb->context;
-
-       /* We don't want to do anything if we are about to be removed! */
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-#if 0
-       if (urb->actual_length > 0) {
-               dev_info(&uvd->dev->dev,
-                        "urb=$%p status=%d. errcount=%d. length=%d.\n",
-                        urb, urb->status, urb->error_count,
-                        urb->actual_length);
-       } else {
-               static int c = 0;
-               if (c++ % 100 == 0)
-                       dev_info(&uvd->dev->dev, "No Isoc data\n");
-       }
-#endif
-
-       if (!uvd->streaming) {
-               if (uvd->debug >= 1)
-                       dev_info(&uvd->dev->dev,
-                                "Not streaming, but interrupt!\n");
-               return;
-       }
-
-       uvd->stats.urb_count++;
-       if (urb->actual_length <= 0)
-               goto urb_done_with;
-
-       /* Copy the data received into ring queue */
-       len = usbvideo_CompressIsochronous(uvd, urb);
-       uvd->stats.urb_length = len;
-       if (len <= 0)
-               goto urb_done_with;
-
-       /* Here we got some data */
-       uvd->stats.data_count += len;
-       RingQueue_WakeUpInterruptible(&uvd->dp);
-
-urb_done_with:
-       for (i = 0; i < FRAMES_PER_DESC; i++) {
-               urb->iso_frame_desc[i].status = 0;
-               urb->iso_frame_desc[i].actual_length = 0;
-       }
-       urb->status = 0;
-       urb->dev = uvd->dev;
-       ret = usb_submit_urb(urb, GFP_KERNEL);
-       if (ret)
-               err("usb_submit_urb error (%d)", ret);
-       return;
-}
-
-/*
- * usbvideo_StartDataPump()
- *
- * History:
- * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
- *             of hardcoded values. Simplified by using for loop,
- *             allowed any number of URBs.
- */
-static int usbvideo_StartDataPump(struct uvd *uvd)
-{
-       struct usb_device *dev = uvd->dev;
-       int i, errFlag;
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
-
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("%s: Camera is not operational", __func__);
-               return -EFAULT;
-       }
-       uvd->curframe = -1;
-
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
-       if (i < 0) {
-               err("%s: usb_set_interface error", __func__);
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-       if (VALID_CALLBACK(uvd, videoStart))
-               GET_CALLBACK(uvd, videoStart)(uvd);
-       else
-               err("%s: videoStart not set", __func__);
-
-       /* We double buffer the Iso lists */
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = usbvideo_IsocIrq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
-               for (j = k = 0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = uvd->iso_packet_len;
-               }
-       }
-
-       /* Submit all URBs */
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errFlag)
-                       err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag);
-       }
-
-       uvd->streaming = 1;
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev,
-                        "%s: streaming=1 video_endp=$%02x\n", __func__,
-                        uvd->video_endp);
-       return 0;
-}
-
-/*
- * usbvideo_StopDataPump()
- *
- * This procedure stops streaming and deallocates URBs. Then it
- * activates zero-bandwidth alt. setting of the video interface.
- *
- * History:
- * 22-Jan-2000 Corrected order of actions to work after surprise removal.
- * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
- */
-static void usbvideo_StopDataPump(struct uvd *uvd)
-{
-       int i, j;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
-
-       /* Unschedule all of the iso td's */
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++)
-               usb_kill_urb(uvd->sbuf[i].urb);
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__);
-       uvd->streaming = 0;
-
-       if (!uvd->remove_pending) {
-               /* Invoke minidriver's magic to stop the camera */
-               if (VALID_CALLBACK(uvd, videoStop))
-                       GET_CALLBACK(uvd, videoStop)(uvd);
-               else
-                       err("%s: videoStop not set", __func__);
-
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("%s: usb_set_interface() error %d.", __func__, j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-/*
- * usbvideo_NewFrame()
- *
- * History:
- * 29-Mar-00 Added copying of previous frame into the current one.
- * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
- */
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
-{
-       struct usbvideo_frame *frame;
-       int n;
-
-       if (uvd->debug > 1)
-               dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd,
-                        framenum);
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /*  ready to be grabbed into, then use it instead */
-       if (uvd->curframe != -1)
-               return 0;
-
-       /* If necessary we adjust picture settings between frames */
-       if (!uvd->settingsAdjusted) {
-               if (VALID_CALLBACK(uvd, adjustPicture))
-                       GET_CALLBACK(uvd, adjustPicture)(uvd);
-               uvd->settingsAdjusted = 1;
-       }
-
-       n = (framenum + 1) % USBVIDEO_NUMFRAMES;
-       if (uvd->frame[n].frameState == FrameState_Ready)
-               framenum = n;
-
-       frame = &uvd->frame[framenum];
-
-       frame->frameState = FrameState_Grabbing;
-       frame->scanstate = ScanState_Scanning;
-       frame->seqRead_Length = 0;      /* Accumulated in xxx_parse_data() */
-       frame->deinterlace = Deinterlace_None;
-       frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
-       uvd->curframe = framenum;
-
-       /*
-        * Normally we would want to copy previous frame into the current one
-        * before we even start filling it with data; this allows us to stop
-        * filling at any moment; top portion of the frame will be new and
-        * bottom portion will stay as it was in previous frame. If we don't
-        * do that then missing chunks of video stream will result in flickering
-        * portions of old data whatever it was before.
-        *
-        * If we choose not to copy previous frame (to, for example, save few
-        * bus cycles - the frame can be pretty large!) then we have an option
-        * to clear the frame before using. If we experience losses in this
-        * mode then missing picture will be black (no flickering).
-        *
-        * Finally, if user chooses not to clean the current frame before
-        * filling it with data then the old data will be visible if we fail
-        * to refill entire frame with new data.
-        */
-       if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
-               /* This copies previous frame into this one to mask losses */
-               int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
-               memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
-       } else {
-               if (uvd->flags & FLAGS_CLEAN_FRAMES) {
-                       /* This provides a "clean" frame but slows things down */
-                       memset(frame->data, 0, uvd->max_frame_size);
-               }
-       }
-       return 0;
-}
-
-/*
- * usbvideo_CollectRawData()
- *
- * This procedure can be used instead of 'processData' callback if you
- * only want to dump the raw data from the camera into the output
- * device (frame buffer). You can look at it with V4L client, but the
- * image will be unwatchable. The main purpose of this code and of the
- * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
- * new, unknown cameras. This procedure will be automatically invoked
- * instead of the specified callback handler when uvd->flags has bit
- * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
- * based on usbvideo can use this feature at any time.
- */
-static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       int n;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-
-       /* Try to move data from queue into frame buffer */
-       n = RingQueue_GetLength(&uvd->dp);
-       if (n > 0) {
-               int m;
-               /* See how much space we have left */
-               m = uvd->max_frame_size - frame->seqRead_Length;
-               if (n > m)
-                       n = m;
-               /* Now move that much data into frame buffer */
-               RingQueue_Dequeue(
-                       &uvd->dp,
-                       frame->data + frame->seqRead_Length,
-                       m);
-               frame->seqRead_Length += m;
-       }
-       /* See if we filled the frame */
-       if (frame->seqRead_Length >= uvd->max_frame_size) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
-{
-       struct usbvideo_frame *frame = &uvd->frame[frameNum];
-
-       if (uvd->debug >= 2)
-               dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd,
-                        frameNum);
-
-       switch (frame->frameState) {
-       case FrameState_Unused:
-               if (uvd->debug >= 2)
-                       dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n",
-                                __func__);
-               return -EINVAL;
-       case FrameState_Ready:
-       case FrameState_Grabbing:
-       case FrameState_Error:
-       {
-               int ntries, signalPending;
-redo:
-               if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                       if (uvd->debug >= 2)
-                               dev_info(&uvd->dev->dev,
-                                        "%s: Camera is not operational (1)\n",
-                                        __func__);
-                       return -EIO;
-               }
-               ntries = 0;
-               do {
-                       RingQueue_InterruptibleSleepOn(&uvd->dp);
-                       signalPending = signal_pending(current);
-                       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                               if (uvd->debug >= 2)
-                                       dev_info(&uvd->dev->dev,
-                                                "%s: Camera is not "
-                                                "operational (2)\n", __func__);
-                               return -EIO;
-                       }
-                       assert(uvd->fbuf != NULL);
-                       if (signalPending) {
-                               if (uvd->debug >= 2)
-                                       dev_info(&uvd->dev->dev,
-                                       "%s: Signal=$%08x\n", __func__,
-                                       signalPending);
-                               if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
-                                       usbvideo_TestPattern(uvd, 1, 0);
-                                       uvd->curframe = -1;
-                                       uvd->stats.frame_num++;
-                                       if (uvd->debug >= 2)
-                                               dev_info(&uvd->dev->dev,
-                                                        "%s: Forced test "
-                                                        "pattern screen\n",
-                                                        __func__);
-                                       return 0;
-                               } else {
-                                       /* Standard answer: Interrupted! */
-                                       if (uvd->debug >= 2)
-                                               dev_info(&uvd->dev->dev,
-                                                        "%s: Interrupted!\n",
-                                                        __func__);
-                                       return -EINTR;
-                               }
-                       } else {
-                               /* No signals - we just got new data in dp queue */
-                               if (uvd->flags & FLAGS_NO_DECODING)
-                                       usbvideo_CollectRawData(uvd, frame);
-                               else if (VALID_CALLBACK(uvd, processData))
-                                       GET_CALLBACK(uvd, processData)(uvd, frame);
-                               else
-                                       err("%s: processData not set", __func__);
-                       }
-               } while (frame->frameState == FrameState_Grabbing);
-               if (uvd->debug >= 2) {
-                       dev_info(&uvd->dev->dev,
-                                "%s: Grabbing done; state=%d. (%lu. bytes)\n",
-                                __func__, frame->frameState,
-                                frame->seqRead_Length);
-               }
-               if (frame->frameState == FrameState_Error) {
-                       int ret = usbvideo_NewFrame(uvd, frameNum);
-                       if (ret < 0) {
-                               err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret);
-                               return ret;
-                       }
-                       goto redo;
-               }
-               /* Note that we fall through to meet our destiny below */
-       }
-       case FrameState_Done:
-               /*
-                * Do all necessary postprocessing of data prepared in
-                * "interrupt" code and the collecting code above. The
-                * frame gets marked as FrameState_Done by queue parsing code.
-                * This status means that we collected enough data and
-                * most likely processed it as we went through. However
-                * the data may need postprocessing, such as deinterlacing
-                * or picture adjustments implemented in software (horror!)
-                *
-                * As soon as the frame becomes "final" it gets promoted to
-                * FrameState_Done_Hold status where it will remain until the
-                * caller consumed all the video data from the frame. Then
-                * the empty shell of ex-frame is thrown out for dogs to eat.
-                * But we, worried about pets, will recycle the frame!
-                */
-               uvd->stats.frame_num++;
-               if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
-                       if (VALID_CALLBACK(uvd, postProcess))
-                               GET_CALLBACK(uvd, postProcess)(uvd, frame);
-                       if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
-                               usbvideo_SoftwareContrastAdjustment(uvd, frame);
-               }
-               frame->frameState = FrameState_Done_Hold;
-               if (uvd->debug >= 2)
-                       dev_info(&uvd->dev->dev,
-                                "%s: Entered FrameState_Done_Hold state.\n",
-                                __func__);
-               return 0;
-
-       case FrameState_Done_Hold:
-               /*
-                * We stay in this state indefinitely until someone external,
-                * like ioctl() or read() call finishes digesting the frame
-                * data. Then it will mark the frame as FrameState_Unused and
-                * it will be released back into the wild to roam freely.
-                */
-               if (uvd->debug >= 2)
-                       dev_info(&uvd->dev->dev,
-                                "%s: FrameState_Done_Hold state.\n",
-                                __func__);
-               return 0;
-       }
-
-       /* Catch-all for other cases. We shall not be here. */
-       err("%s: Invalid state %d.", __func__, frame->frameState);
-       frame->frameState = FrameState_Unused;
-       return 0;
-}
-
-/*
- * usbvideo_DeinterlaceFrame()
- *
- * This procedure deinterlaces the given frame. Some cameras produce
- * only half of scanlines - sometimes only even lines, sometimes only
- * odd lines. The deinterlacing method is stored in frame->deinterlace
- * variable.
- *
- * Here we scan the frame vertically and replace missing scanlines with
- * average between surrounding ones - before and after. If we have no
- * line above then we just copy next line. Similarly, if we need to
- * create a last line then preceding line is used.
- */
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
-           (frame->deinterlace == Deinterlace_FillOddLines)) {
-               const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-               int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
-
-               for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
-                       const unsigned char *fs1, *fs2;
-                       unsigned char *fd;
-                       int ip, in, j;  /* Previous and next lines */
-
-                       /*
-                        * Need to average lines before and after 'i'.
-                        * If we go out of bounds seeking those lines then
-                        * we point back to existing line.
-                        */
-                       ip = i - 1;     /* First, get rough numbers */
-                       in = i + 1;
-
-                       /* Now validate */
-                       if (ip < 0)
-                               ip = in;
-                       if (in >= VIDEOSIZE_Y(frame->request))
-                               in = ip;
-
-                       /* Sanity check */
-                       if ((ip < 0) || (in < 0) ||
-                           (ip >= VIDEOSIZE_Y(frame->request)) ||
-                           (in >= VIDEOSIZE_Y(frame->request))) {
-                               err("Error: ip=%d. in=%d. req.height=%ld.",
-                                   ip, in, VIDEOSIZE_Y(frame->request));
-                               break;
-                       }
-
-                       /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
-                       fs1 = frame->data + (v4l_linesize * ip);
-                       fs2 = frame->data + (v4l_linesize * in);
-                       fd = frame->data + (v4l_linesize * i);
-
-                       /* Average lines around destination */
-                       for (j = 0; j < v4l_linesize; j++) {
-                               fd[j] = (unsigned char)((((unsigned) fs1[j]) +
-                                                        ((unsigned)fs2[j])) >> 1);
-                       }
-               }
-       }
-
-       /* Optionally display statistics on the screen */
-       if (uvd->flags & FLAGS_OVERLAY_STATS)
-               usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
-
-/*
- * usbvideo_SoftwareContrastAdjustment()
- *
- * This code adjusts the contrast of the frame, assuming RGB24 format.
- * As most software image processing, this job is CPU-intensive.
- * Get a camera that supports hardware adjustment!
- *
- * History:
- * 09-Feb-2001  Created.
- */
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
-                                               struct usbvideo_frame *frame)
-{
-       int i, j, v4l_linesize;
-       signed long adj;
-       const int ccm = 128; /* Color correction median - see below */
-
-       if ((uvd == NULL) || (frame == NULL)) {
-               err("%s: Illegal call.", __func__);
-               return;
-       }
-       adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
-       if (adj == 0) {
-               /* In rare case of no adjustment */
-               return;
-       }
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-       for (i = 0; i < VIDEOSIZE_Y(frame->request); i++) {
-               unsigned char *fd = frame->data + (v4l_linesize * i);
-               for (j = 0; j < v4l_linesize; j++) {
-                       signed long v = (signed long) fd[j];
-                       /* Magnify up to 2 times, reduce down to zero */
-                       v = 128 + ((ccm + adj) * (v - 128)) / ccm;
-                       RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
-                       fd[j] = (unsigned char) v;
-               }
-       }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/usbvideo/usbvideo.h b/drivers/staging/usbvideo/usbvideo.h
deleted file mode 100644 (file)
index 95638a0..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef usbvideo_h
-#define        usbvideo_h
-
-#include "videodev.h"
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-#define USBVIDEO_REPORT_STATS  1       /* Set to 0 to block statistics on close */
-
-/* Bit flags (options) */
-#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
-#define        FLAGS_MONOCHROME                (1 << 1)
-#define FLAGS_DISPLAY_HINTS            (1 << 2)
-#define FLAGS_OVERLAY_STATS            (1 << 3)
-#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
-#define FLAGS_SEPARATE_FRAMES          (1 << 5)
-#define FLAGS_CLEAN_FRAMES             (1 << 6)
-#define        FLAGS_NO_DECODING               (1 << 7)
-
-/* Bit flags for frames (apply to the frame where they are specified) */
-#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST  (1 << 0)
-
-/* Camera capabilities (maximum) */
-#define CAMERA_URB_FRAMES       32
-#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
-#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
-#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
-
-#define V4L_BYTES_PER_PIXEL     3      /* Because we produce RGB24 */
-
-/*
- * Use this macro to construct constants for different video sizes.
- * We have to deal with different video sizes that have to be
- * configured in the device or compared against when we receive
- * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
- * #defines and that's the end of story. However this solution
- * does not allow to convert between real pixel sizes and the
- * constant (integer) value that may be used to tag a frame or
- * whatever. The set of macros below constructs videosize constants
- * from the pixel size and allows to reconstruct the pixel size
- * from the combined value later.
- */
-#define        VIDEOSIZE(x,y)  (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
-#define        VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
-#define        VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
-typedef unsigned long videosize_t;
-
-/*
- * This macro checks if the camera is still operational. The 'uvd'
- * pointer must be valid, uvd->dev must be valid, we are not
- * removing the device and the device has not erred on us.
- */
-#define CAMERA_IS_OPERATIONAL(uvd) (\
-       (uvd != NULL) && \
-       ((uvd)->dev != NULL) && \
-       ((uvd)->last_error == 0) && \
-       (!(uvd)->remove_pending))
-
-/*
- * We use macros to do YUV -> RGB conversion because this is
- * very important for speed and totally unimportant for size.
- *
- * YUV -> RGB Conversion
- * ---------------------
- *
- * B = 1.164*(Y-16)                + 2.018*(V-128)
- * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
- * R = 1.164*(Y-16) + 1.596*(U-128)
- *
- * If you fancy integer arithmetics (as you should), hear this:
- *
- * 65536*B = 76284*(Y-16)                + 132252*(V-128)
- * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
- * 65536*R = 76284*(Y-16) + 104595*(U-128)
- *
- * Make sure the output values are within [0..255] range.
- */
-#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
-    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
-    mm_y = (my) - 16;  \
-    mm_u = (mu) - 128; \
-    mm_v = (mv) - 128; \
-    mm_yc= mm_y * 76284; \
-    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
-    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
-    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
-    mb = LIMIT_RGB(mm_b); \
-    mg = LIMIT_RGB(mm_g); \
-    mr = LIMIT_RGB(mm_r); \
-}
-
-#define        RING_QUEUE_SIZE         (128*1024)      /* Must be a power of 2 */
-#define        RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
-#define        RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define        RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
-
-struct RingQueue {
-       unsigned char *queue;   /* Data from the Isoc data pump */
-       int length;             /* How many bytes allocated for the queue */
-       int wi;                 /* That's where we write */
-       int ri;                 /* Read from here until you hit write index */
-       wait_queue_head_t wqh;  /* Processes waiting */
-};
-
-enum ScanState {
-       ScanState_Scanning,     /* Scanning for header */
-       ScanState_Lines         /* Parsing lines */
-};
-
-/* Completion states of the data parser */
-enum ParseState {
-       scan_Continue,          /* Just parse next item */
-       scan_NextFrame,         /* Frame done, send it to V4L */
-       scan_Out,               /* Not enough data for frame */
-       scan_EndParse           /* End parsing */
-};
-
-enum FrameState {
-       FrameState_Unused,      /* Unused (no MCAPTURE) */
-       FrameState_Ready,       /* Ready to start grabbing */
-       FrameState_Grabbing,    /* In the process of being grabbed into */
-       FrameState_Done,        /* Finished grabbing, but not been synced yet */
-       FrameState_Done_Hold,   /* Are syncing or reading */
-       FrameState_Error,       /* Something bad happened while processing */
-};
-
-/*
- * Some frames may contain only even or odd lines. This type
- * specifies what type of deinterlacing is required.
- */
-enum Deinterlace {
-       Deinterlace_None=0,
-       Deinterlace_FillOddLines,
-       Deinterlace_FillEvenLines
-};
-
-#define USBVIDEO_NUMFRAMES     2       /* How many frames we work with */
-#define USBVIDEO_NUMSBUF       2       /* How many URBs linked in a ring */
-
-/* This structure represents one Isoc request - URB and buffer */
-struct usbvideo_sbuf {
-       char *data;
-       struct urb *urb;
-};
-
-struct usbvideo_frame {
-       char *data;             /* Frame buffer */
-       unsigned long header;   /* Significant bits from the header */
-
-       videosize_t canvas;     /* The canvas (max. image) allocated */
-       videosize_t request;    /* That's what the application asked for */
-       unsigned short palette; /* The desired format */
-
-       enum FrameState frameState;/* State of grabbing */
-       enum ScanState scanstate;       /* State of scanning */
-       enum Deinterlace deinterlace;
-       int flags;              /* USBVIDEO_FRAME_FLAG_xxx bit flags */
-
-       int curline;            /* Line of frame we're working on */
-
-       long seqRead_Length;    /* Raw data length of frame */
-       long seqRead_Index;     /* Amount of data that has been already read */
-
-       void *user;             /* Additional data that user may need */
-};
-
-/* Statistics that can be overlaid on screen */
-struct usbvideo_statistics {
-       unsigned long frame_num;        /* Sequential number of the frame */
-       unsigned long urb_count;        /* How many URBs we received so far */
-       unsigned long urb_length;       /* Length of last URB */
-       unsigned long data_count;       /* How many bytes we received */
-       unsigned long header_count;     /* How many frame headers we found */
-       unsigned long iso_skip_count;   /* How many empty ISO packets received */
-       unsigned long iso_err_count;    /* How many bad ISO packets received */
-};
-
-struct usbvideo;
-
-struct uvd {
-       struct video_device vdev;       /* Must be the first field! */
-       struct usb_device *dev;
-       struct usbvideo *handle;        /* Points back to the struct usbvideo */
-       void *user_data;                /* Camera-dependent data */
-       int user_size;                  /* Size of that camera-dependent data */
-       int debug;                      /* Debug level for usbvideo */
-       unsigned char iface;            /* Video interface number */
-       unsigned char video_endp;
-       unsigned char ifaceAltActive;
-       unsigned char ifaceAltInactive; /* Alt settings */
-       unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
-       unsigned long paletteBits;      /* Which palettes we accept? */
-       unsigned short defaultPalette;  /* What palette to use for read() */
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-
-       videosize_t videosize;  /* Current setting */
-       videosize_t canvas;     /* This is the width,height of the V4L canvas */
-       int max_frame_size;     /* Bytes in one video frame */
-
-       int uvd_used;           /* Is this structure in use? */
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-       int settingsAdjusted;   /* Have we adjusted contrast etc.? */
-       int last_error;         /* What calamity struck us? */
-
-       char *fbuf;             /* Videodev buffer area */
-       int fbuf_size;          /* Videodev buffer size */
-
-       int curframe;
-       int iso_packet_len;     /* Videomode-dependent, saves bus bandwidth */
-
-       struct RingQueue dp;    /* Isoc data pump */
-       struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
-       struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
-
-       volatile int remove_pending;    /* If set then about to exit */
-
-       struct video_picture vpic, vpic_old;    /* Picture settings */
-       struct video_capability vcap;           /* Video capabilities */
-       struct video_channel vchan;     /* May be used for tuner support */
-       struct usbvideo_statistics stats;
-       char videoName[32];             /* Holds name like "video7" */
-};
-
-/*
- * usbvideo callbacks (virtual methods). They are set when usbvideo
- * services are registered. All of these default to NULL, except those
- * that default to usbvideo-provided methods.
- */
-struct usbvideo_cb {
-       int (*probe)(struct usb_interface *, const struct usb_device_id *);
-       void (*userFree)(struct uvd *);
-       void (*disconnect)(struct usb_interface *);
-       int (*setupOnOpen)(struct uvd *);
-       void (*videoStart)(struct uvd *);
-       void (*videoStop)(struct uvd *);
-       void (*processData)(struct uvd *, struct usbvideo_frame *);
-       void (*postProcess)(struct uvd *, struct usbvideo_frame *);
-       void (*adjustPicture)(struct uvd *);
-       int (*getFPS)(struct uvd *);
-       int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
-       int (*getFrame)(struct uvd *, int);
-       int (*startDataPump)(struct uvd *uvd);
-       void (*stopDataPump)(struct uvd *uvd);
-       int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
-};
-
-struct usbvideo {
-       int num_cameras;                /* As allocated */
-       struct usb_driver usbdrv;       /* Interface to the USB stack */
-       char drvName[80];               /* Driver name */
-       struct mutex lock;              /* Mutex protecting camera structures */
-       struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
-       struct video_device vdt;        /* Video device template */
-       struct uvd *cam;                        /* Array of camera structures */
-       struct module *md_module;       /* Minidriver module */
-};
-
-
-/*
- * This macro retrieves callback address from the struct uvd object.
- * No validity checks are done here, so be sure to check the
- * callback beforehand with VALID_CALLBACK.
- */
-#define        GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
-
-/*
- * This macro returns either callback pointer or NULL. This is safe
- * macro, meaning that most of components of data structures involved
- * may be NULL - this only results in NULL being returned. You may
- * wish to use this macro to make sure that the callback is callable.
- * However keep in mind that those checks take time.
- */
-#define        VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
-               ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
-
-int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
-int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
-void RingQueue_Flush(struct RingQueue *rq);
-
-static inline int RingQueue_GetLength(const struct RingQueue *rq)
-{
-       return (rq->wi - rq->ri + rq->length) & (rq->length-1);
-}
-
-static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
-{
-       return rq->length - RingQueue_GetLength(rq);
-}
-
-void usbvideo_DrawLine(
-       struct usbvideo_frame *frame,
-       int x1, int y1,
-       int x2, int y2,
-       unsigned char cr, unsigned char cg, unsigned char cb);
-void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
-
-/* Memory allocation routines */
-unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTable,
-       struct module *md,
-       const struct usb_device_id *id_table);
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
-int usbvideo_RegisterVideoDevice(struct uvd *uvd);
-void usbvideo_Deregister(struct usbvideo **uvt);
-
-int usbvideo_v4l_initialize(struct video_device *dev);
-
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
-
-/*
- * This code performs bounds checking - use it when working with
- * new formats, or else you may get oopses all over the place.
- * If pixel falls out of bounds then it gets shoved back (as close
- * to place of offence as possible) and is painted bright red.
- *
- * There are two important concepts: frame width, height and
- * V4L canvas width, height. The former is the area requested by
- * the application -for this very frame-. The latter is the largest
- * possible frame that we can serve (we advertise that via V4L ioctl).
- * The frame data is expected to be formatted as lines of length
- * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
- */
-static inline void RGB24_PUTPIXEL(
-       struct usbvideo_frame *fr,
-       int ix, int iy,
-       unsigned char vr,
-       unsigned char vg,
-       unsigned char vb)
-{
-       register unsigned char *pf;
-       int limiter = 0, mx, my;
-       mx = ix;
-       my = iy;
-       if (mx < 0) {
-               mx=0;
-               limiter++;
-       } else if (mx >= VIDEOSIZE_X((fr)->request)) {
-               mx= VIDEOSIZE_X((fr)->request) - 1;
-               limiter++;
-       }
-       if (my < 0) {
-               my = 0;
-               limiter++;
-       } else if (my >= VIDEOSIZE_Y((fr)->request)) {
-               my = VIDEOSIZE_Y((fr)->request) - 1;
-               limiter++;
-       }
-       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
-       if (limiter) {
-               *pf++ = 0;
-               *pf++ = 0;
-               *pf++ = 0xFF;
-       } else {
-               *pf++ = (vb);
-               *pf++ = (vg);
-               *pf++ = (vr);
-       }
-}
-
-#endif /* usbvideo_h */
diff --git a/drivers/staging/usbvideo/vicam.c b/drivers/staging/usbvideo/vicam.c
deleted file mode 100644 (file)
index 38a373a..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * USB ViCam WebCam driver
- * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
- *                    Christopher L Cheney (ccheney@cheney.cx),
- *                    Pavel Machek (pavel@ucw.cz),
- *                    John Tyner (jtyner@cs.ucr.edu),
- *                    Monroe Williams (monroe@pobox.com)
- *
- * Supports 3COM HomeConnect PC Digital WebCam
- * Supports Compro PS39U WebCam
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This source code is based heavily on the CPiA webcam driver which was
- * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
- *
- * Portions of this code were also copied from usbvideo.c
- *
- * Special thanks to the whole team at Sourceforge for help making
- * this driver become a reality.  Notably:
- * Andy Armstrong who reverse engineered the color encoding and
- * Pavel Machek and Chris Cheney who worked on reverse engineering the
- *    camera controls and wrote the first generation driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include "videodev.h"
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
-#include "usbvideo.h"
-
-/* #define VICAM_DEBUG */
-
-#ifdef VICAM_DEBUG
-#define ADBG(lineno, fmt, args...) printk(fmt, jiffies, __func__, lineno, ##args)
-#define DBG(fmt, args...) ADBG((__LINE__), KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt, ##args)
-#else
-#define DBG(fmn, args...) do {} while (0)
-#endif
-
-#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
-#define DRIVER_DESC             "ViCam WebCam Driver"
-
-/* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID    0x04c1
-#define USB_VICAM_PRODUCT_ID   0x009d
-#define USB_COMPRO_VENDOR_ID   0x0602
-#define USB_COMPRO_PRODUCT_ID  0x1001
-
-#define VICAM_BYTES_PER_PIXEL   3
-#define VICAM_MAX_READ_SIZE     (512*242+128)
-#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
-#define VICAM_FRAMES            2
-
-#define VICAM_HEADER_SIZE       64
-
-/* rvmalloc / rvfree copied from usbvideo.c
- *
- * Not sure why these are not yet non-statics which I can reference through
- * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
- * in the future.
- *
-*/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-struct vicam_camera {
-       u16 shutter_speed;      /* capture shutter speed */
-       u16 gain;               /* capture gain */
-
-       u8 *raw_image;          /* raw data captured from the camera */
-       u8 *framebuf;           /* processed data in RGB24 format */
-       u8 *cntrlbuf;           /* area used to send control msgs */
-
-       struct video_device vdev;       /* v4l video device */
-       struct usb_device *udev;        /* usb device */
-
-       /* guard against simultaneous accesses to the camera */
-       struct mutex cam_lock;
-
-       int is_initialized;
-       u8 open_count;
-       u8 bulkEndpoint;
-       int needsDummyRead;
-};
-
-static int vicam_probe(struct usb_interface *intf, const struct usb_device_id *id);
-static void vicam_disconnect(struct usb_interface *intf);
-static void read_frame(struct vicam_camera *cam, int framenum);
-static void vicam_decode_color(const u8 *, u8 *);
-
-static int __send_control_msg(struct vicam_camera *cam,
-                             u8 request,
-                             u16 value,
-                             u16 index,
-                             unsigned char *cp,
-                             u16 size)
-{
-       int status;
-
-       /* cp must be memory that has been allocated by kmalloc */
-
-       status = usb_control_msg(cam->udev,
-                                usb_sndctrlpipe(cam->udev, 0),
-                                request,
-                                USB_DIR_OUT | USB_TYPE_VENDOR |
-                                USB_RECIP_DEVICE, value, index,
-                                cp, size, 1000);
-
-       status = min(status, 0);
-
-       if (status < 0) {
-               printk(KERN_INFO "Failed sending control message, error %d.\n",
-                      status);
-       }
-
-       return status;
-}
-
-static int send_control_msg(struct vicam_camera *cam,
-                           u8 request,
-                           u16 value,
-                           u16 index,
-                           unsigned char *cp,
-                           u16 size)
-{
-       int status = -ENODEV;
-       mutex_lock(&cam->cam_lock);
-       if (cam->udev) {
-               status = __send_control_msg(cam, request, value,
-                                           index, cp, size);
-       }
-       mutex_unlock(&cam->cam_lock);
-       return status;
-}
-static int
-initialize_camera(struct vicam_camera *cam)
-{
-       int err;
-       const struct ihex_binrec *rec;
-       const struct firmware *uninitialized_var(fw);
-
-       err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
-       if (err) {
-               printk(KERN_ERR "Failed to load \"vicam/firmware.fw\": %d\n",
-                      err);
-               return err;
-       }
-
-       for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
-               memcpy(cam->cntrlbuf, rec->data, be16_to_cpu(rec->len));
-
-               err = send_control_msg(cam, 0xff, 0, 0,
-                                      cam->cntrlbuf, be16_to_cpu(rec->len));
-               if (err)
-                       break;
-       }
-
-       release_firmware(fw);
-
-       return err;
-}
-
-static int
-set_camera_power(struct vicam_camera *cam, int state)
-{
-       int status;
-
-       status = send_control_msg(cam, 0x50, state, 0, NULL, 0);
-       if (status < 0)
-               return status;
-
-       if (state)
-               send_control_msg(cam, 0x55, 1, 0, NULL, 0);
-
-       return 0;
-}
-
-static long
-vicam_ioctl(struct file *file, unsigned int ioctlnr, unsigned long arg)
-{
-       void __user *user_arg = (void __user *)arg;
-       struct vicam_camera *cam = file->private_data;
-       long retval = 0;
-
-       if (!cam)
-               return -ENODEV;
-
-       switch (ioctlnr) {
-               /* query capabilities */
-       case VIDIOCGCAP:
-               {
-                       struct video_capability b;
-
-                       DBG("VIDIOCGCAP\n");
-                       memset(&b, 0, sizeof(b));
-                       strcpy(b.name, "ViCam-based Camera");
-                       b.type = VID_TYPE_CAPTURE;
-                       b.channels = 1;
-                       b.audios = 0;
-                       b.maxwidth = 320;       /* VIDEOSIZE_CIF */
-                       b.maxheight = 240;
-                       b.minwidth = 320;       /* VIDEOSIZE_48_48 */
-                       b.minheight = 240;
-
-                       if (copy_to_user(user_arg, &b, sizeof(b)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-               /* get/set video source - we are a camera and nothing else */
-       case VIDIOCGCHAN:
-               {
-                       struct video_channel v;
-
-                       DBG("VIDIOCGCHAN\n");
-                       if (copy_from_user(&v, user_arg, sizeof(v))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       if (v.channel != 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       v.channel = 0;
-                       strcpy(v.name, "Camera");
-                       v.tuners = 0;
-                       v.flags = 0;
-                       v.type = VIDEO_TYPE_CAMERA;
-                       v.norm = 0;
-
-                       if (copy_to_user(user_arg, &v, sizeof(v)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSCHAN:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, user_arg, sizeof(v)))
-                               retval = -EFAULT;
-                       DBG("VIDIOCSCHAN %d\n", v);
-
-                       if (retval == 0 && v != 0)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* image properties */
-       case VIDIOCGPICT:
-               {
-                       struct video_picture vp;
-                       DBG("VIDIOCGPICT\n");
-                       memset(&vp, 0, sizeof(struct video_picture));
-                       vp.brightness = cam->gain << 8;
-                       vp.depth = 24;
-                       vp.palette = VIDEO_PALETTE_RGB24;
-                       if (copy_to_user(user_arg, &vp, sizeof(struct video_picture)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSPICT:
-               {
-                       struct video_picture vp;
-
-                       if (copy_from_user(&vp, user_arg, sizeof(vp))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
-                           vp.palette);
-
-                       cam->gain = vp.brightness >> 8;
-
-                       if (vp.depth != 24
-                           || vp.palette != VIDEO_PALETTE_RGB24)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* get/set capture window */
-       case VIDIOCGWIN:
-               {
-                       struct video_window vw;
-                       vw.x = 0;
-                       vw.y = 0;
-                       vw.width = 320;
-                       vw.height = 240;
-                       vw.chromakey = 0;
-                       vw.flags = 0;
-                       vw.clips = NULL;
-                       vw.clipcount = 0;
-
-                       DBG("VIDIOCGWIN\n");
-
-                       if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
-                               retval = -EFAULT;
-
-                       /* I'm not sure what the deal with a capture window is, it is very poorly described
-                        * in the doc.  So I won't support it now. */
-                       break;
-               }
-
-       case VIDIOCSWIN:
-               {
-
-                       struct video_window vw;
-
-                       if (copy_from_user(&vw, user_arg, sizeof(vw))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
-
-                       if (vw.width != 320 || vw.height != 240)
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-               /* mmap interface */
-       case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-                       int i;
-
-                       DBG("VIDIOCGMBUF\n");
-                       memset(&vm, 0, sizeof(vm));
-                       vm.size =
-                           VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
-                       vm.frames = VICAM_FRAMES;
-                       for (i = 0; i < VICAM_FRAMES; i++)
-                               vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
-
-                       if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-       case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-                       /* int video_size; */
-
-                       if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",
-                           vm.frame, vm.width, vm.height, vm.format);
-
-                       if (vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24)
-                               retval = -EINVAL;
-
-                       /* in theory right here we'd start the image capturing
-                        * (fill in a bulk urb and submit it asynchronously)
-                        *
-                        * Instead we're going to do a total hack job for now and
-                        * retrieve the frame in VIDIOCSYNC */
-
-                       break;
-               }
-
-       case VIDIOCSYNC:
-               {
-                       int frame;
-
-                       if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       DBG("VIDIOCSYNC: %d\n", frame);
-
-                       read_frame(cam, frame);
-                       vicam_decode_color(cam->raw_image,
-                                          cam->framebuf +
-                                          frame * VICAM_MAX_FRAME_SIZE);
-
-                       break;
-               }
-
-               /* pointless to implement overlay with this camera */
-       case VIDIOCCAPTURE:
-       case VIDIOCGFBUF:
-       case VIDIOCSFBUF:
-       case VIDIOCKEY:
-               retval = -EINVAL;
-               break;
-
-               /* tuner interface - we have none */
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               retval = -EINVAL;
-               break;
-
-               /* audio interface - we have none */
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               retval = -EINVAL;
-               break;
-       default:
-               retval = -ENOIOCTLCMD;
-               break;
-       }
-
-       return retval;
-}
-
-static int
-vicam_open(struct file *file)
-{
-       struct vicam_camera *cam = video_drvdata(file);
-
-       DBG("open\n");
-
-       if (!cam) {
-               printk(KERN_ERR
-                      "vicam video_device improperly initialized");
-               return -EINVAL;
-       }
-
-       /* cam_lock/open_count protects us from simultaneous opens
-        * ... for now. we probably shouldn't rely on this fact forever.
-        */
-
-       mutex_lock(&cam->cam_lock);
-       if (cam->open_count > 0) {
-               printk(KERN_INFO
-                      "vicam_open called on already opened camera");
-               mutex_unlock(&cam->cam_lock);
-               return -EBUSY;
-       }
-
-       cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
-       if (!cam->raw_image) {
-               mutex_unlock(&cam->cam_lock);
-               return -ENOMEM;
-       }
-
-       cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       if (!cam->framebuf) {
-               kfree(cam->raw_image);
-               mutex_unlock(&cam->cam_lock);
-               return -ENOMEM;
-       }
-
-       cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!cam->cntrlbuf) {
-               kfree(cam->raw_image);
-               rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-               mutex_unlock(&cam->cam_lock);
-               return -ENOMEM;
-       }
-
-       cam->needsDummyRead = 1;
-       cam->open_count++;
-
-       file->private_data = cam;
-       mutex_unlock(&cam->cam_lock);
-
-
-       /* First upload firmware, then turn the camera on */
-
-       if (!cam->is_initialized) {
-               initialize_camera(cam);
-
-               cam->is_initialized = 1;
-       }
-
-       set_camera_power(cam, 1);
-
-       return 0;
-}
-
-static int
-vicam_close(struct file *file)
-{
-       struct vicam_camera *cam = file->private_data;
-       int open_count;
-       struct usb_device *udev;
-
-       DBG("close\n");
-
-       /* it's not the end of the world if
-        * we fail to turn the camera off.
-        */
-
-       set_camera_power(cam, 0);
-
-       kfree(cam->raw_image);
-       rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       kfree(cam->cntrlbuf);
-
-       mutex_lock(&cam->cam_lock);
-
-       cam->open_count--;
-       open_count = cam->open_count;
-       udev = cam->udev;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count && !udev)
-               kfree(cam);
-
-       return 0;
-}
-
-static void vicam_decode_color(const u8 *data, u8 *rgb)
-{
-       /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
-        * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
-        */
-
-       int i, prevY, nextY;
-
-       prevY = 512;
-       nextY = 512;
-
-       data += VICAM_HEADER_SIZE;
-
-       for (i = 0; i < 240; i++, data += 512) {
-               const int y = (i * 242) / 240;
-
-               int j, prevX, nextX;
-               int Y, Cr, Cb;
-
-               if (y == 242 - 1)
-                       nextY = -512;
-
-               prevX = 1;
-               nextX = 1;
-
-               for (j = 0; j < 320; j++, rgb += 3) {
-                       const int x = (j * 512) / 320;
-                       const u8 * const src = &data[x];
-
-                       if (x == 512 - 1)
-                               nextX = -1;
-
-                       Cr = (src[prevX] - src[0]) +
-                               (src[nextX] - src[0]);
-                       Cr /= 2;
-
-                       Cb = (src[prevY] - src[prevX + prevY]) +
-                               (src[prevY] - src[nextX + prevY]) +
-                               (src[nextY] - src[prevX + nextY]) +
-                               (src[nextY] - src[nextX + nextY]);
-                       Cb /= 4;
-
-                       Y = 1160 * (src[0] + (Cr / 2) - 16);
-
-                       if (i & 1) {
-                               int Ct = Cr;
-                               Cr = Cb;
-                               Cb = Ct;
-                       }
-
-                       if ((x ^ i) & 1) {
-                               Cr = -Cr;
-                               Cb = -Cb;
-                       }
-
-                       rgb[0] = clamp(((Y + (2017 * Cb)) +
-                                       500) / 900, 0, 255);
-                       rgb[1] = clamp(((Y - (392 * Cb) -
-                                         (813 * Cr)) +
-                                         500) / 1000, 0, 255);
-                       rgb[2] = clamp(((Y + (1594 * Cr)) +
-                                       500) / 1300, 0, 255);
-
-                       prevX = -1;
-               }
-
-               prevY = -512;
-       }
-}
-
-static void
-read_frame(struct vicam_camera *cam, int framenum)
-{
-       unsigned char *request = cam->cntrlbuf;
-       int realShutter;
-       int n;
-       int actual_length;
-
-       if (cam->needsDummyRead) {
-               cam->needsDummyRead = 0;
-               read_frame(cam, framenum);
-       }
-
-       memset(request, 0, 16);
-       request[0] = cam->gain; /* 0 = 0% gain, FF = 100% gain */
-
-       request[1] = 0; /* 512x242 capture */
-
-       request[2] = 0x90;      /* the function of these two bytes */
-       request[3] = 0x07;      /* is not yet understood */
-
-       if (cam->shutter_speed > 60) {
-               /* Short exposure */
-               realShutter =
-                   ((-15631900 / cam->shutter_speed) + 260533) / 1000;
-               request[4] = realShutter & 0xFF;
-               request[5] = (realShutter >> 8) & 0xFF;
-               request[6] = 0x03;
-               request[7] = 0x01;
-       } else {
-               /* Long exposure */
-               realShutter = 15600 / cam->shutter_speed - 1;
-               request[4] = 0;
-               request[5] = 0;
-               request[6] = realShutter & 0xFF;
-               request[7] = realShutter >> 8;
-       }
-
-       /* Per John Markus BjĆørndalen, byte at index 8 causes problems if it isn't 0*/
-       request[8] = 0;
-       /* bytes 9-15 do not seem to affect exposure or image quality */
-
-       mutex_lock(&cam->cam_lock);
-
-       if (!cam->udev)
-               goto done;
-
-       n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
-
-       if (n < 0) {
-               printk(KERN_ERR
-                      " Problem sending frame capture control message");
-               goto done;
-       }
-
-       n = usb_bulk_msg(cam->udev,
-                        usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
-                        cam->raw_image,
-                        512 * 242 + 128, &actual_length, 10000);
-
-       if (n < 0) {
-               printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
-                      n);
-       }
-
- done:
-       mutex_unlock(&cam->cam_lock);
-}
-
-static ssize_t
-vicam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-       struct vicam_camera *cam = file->private_data;
-
-       DBG("read %d bytes.\n", (int) count);
-
-       if (*ppos >= VICAM_MAX_FRAME_SIZE) {
-               *ppos = 0;
-               return 0;
-       }
-
-       if (*ppos == 0) {
-               read_frame(cam, 0);
-               vicam_decode_color(cam->raw_image,
-                                  cam->framebuf +
-                                  0 * VICAM_MAX_FRAME_SIZE);
-       }
-
-       count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
-
-       if (copy_to_user(buf, &cam->framebuf[*ppos], count))
-               count = -EFAULT;
-       else
-               *ppos += count;
-
-       if (count == VICAM_MAX_FRAME_SIZE)
-               *ppos = 0;
-
-       return count;
-}
-
-
-static int
-vicam_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       /* TODO: allocate the raw frame buffer if necessary */
-       unsigned long page, pos;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       struct vicam_camera *cam = file->private_data;
-
-       if (!cam)
-               return -ENODEV;
-
-       DBG("vicam_mmap: %ld\n", size);
-
-       /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
-        * to the size the application requested for mmap and it was screwing apps up.
-        if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
-        return -EINVAL;
-        */
-
-       pos = (unsigned long)cam->framebuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-static const struct v4l2_file_operations vicam_fops = {
-       .owner          = THIS_MODULE,
-       .open           = vicam_open,
-       .release        = vicam_close,
-       .read           = vicam_read,
-       .mmap           = vicam_mmap,
-       .ioctl          = vicam_ioctl,
-};
-
-static struct video_device vicam_template = {
-       .name           = "ViCam-based USB Camera",
-       .fops           = &vicam_fops,
-       .release        = video_device_release_empty,
-};
-
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table[] = {
-       {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
-       {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
-       {}                      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, vicam_table);
-
-static struct usb_driver vicam_driver = {
-       .name           = "vicam",
-       .probe          = vicam_probe,
-       .disconnect     = vicam_disconnect,
-       .id_table       = vicam_table
-};
-
-/**
- *     vicam_probe
- *     @intf: the interface
- *     @id: the device id
- *
- *     Called by the usb core when a new device is connected that it thinks
- *     this driver might be interested in.
- */
-static int
-vicam_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       int bulkEndpoint = 0;
-       const struct usb_host_interface *interface;
-       const struct usb_endpoint_descriptor *endpoint;
-       struct vicam_camera *cam;
-
-       printk(KERN_INFO "ViCam based webcam connected\n");
-
-       interface = intf->cur_altsetting;
-
-       DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
-              interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
-       endpoint = &interface->endpoint[0].desc;
-
-       if (usb_endpoint_is_bulk_in(endpoint)) {
-               /* we found a bulk in endpoint */
-               bulkEndpoint = endpoint->bEndpointAddress;
-       } else {
-               printk(KERN_ERR
-                      "No bulk in endpoint was found ?! (this is bad)\n");
-       }
-
-       cam = kzalloc(sizeof(struct vicam_camera), GFP_KERNEL);
-       if (cam == NULL) {
-               printk(KERN_WARNING
-                      "could not allocate kernel memory for vicam_camera struct\n");
-               return -ENOMEM;
-       }
-
-
-       cam->shutter_speed = 15;
-
-       mutex_init(&cam->cam_lock);
-
-       memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
-       video_set_drvdata(&cam->vdev, cam);
-
-       cam->udev = dev;
-       cam->bulkEndpoint = bulkEndpoint;
-
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               kfree(cam);
-               printk(KERN_WARNING "video_register_device failed\n");
-               return -EIO;
-       }
-
-       printk(KERN_INFO "ViCam webcam driver now controlling device %s\n",
-               video_device_node_name(&cam->vdev));
-
-       usb_set_intfdata(intf, cam);
-
-       return 0;
-}
-
-static void
-vicam_disconnect(struct usb_interface *intf)
-{
-       int open_count;
-       struct vicam_camera *cam = usb_get_intfdata(intf);
-       usb_set_intfdata(intf, NULL);
-
-       /* we must unregister the device before taking its
-        * cam_lock. This is because the video open call
-        * holds the same lock as video unregister. if we
-        * unregister inside of the cam_lock and open also
-        * uses the cam_lock, we get deadlock.
-        */
-
-       video_unregister_device(&cam->vdev);
-
-       /* stop the camera from being used */
-
-       mutex_lock(&cam->cam_lock);
-
-       /* mark the camera as gone */
-
-       cam->udev = NULL;
-
-       /* the only thing left to do is synchronize with
-        * our close/release function on who should release
-        * the camera memory. if there are any users using the
-        * camera, it's their job. if there are no users,
-        * it's ours.
-        */
-
-       open_count = cam->open_count;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count)
-               kfree(cam);
-
-       printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
-}
-
-/*
- */
-static int __init
-usb_vicam_init(void)
-{
-       int retval;
-       DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-       retval = usb_register(&vicam_driver);
-       if (retval)
-               printk(KERN_WARNING "usb_register failed!\n");
-       return retval;
-}
-
-static void __exit
-usb_vicam_exit(void)
-{
-       DBG(KERN_INFO
-              "ViCam-based WebCam driver shutdown\n");
-
-       usb_deregister(&vicam_driver);
-}
-
-module_init(usb_vicam_init);
-module_exit(usb_vicam_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("vicam/firmware.fw");
diff --git a/drivers/staging/usbvideo/videodev.h b/drivers/staging/usbvideo/videodev.h
deleted file mode 100644 (file)
index f11efbe..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- *     Video for Linux version 1 - OBSOLETE
- *
- *     Header file for v4l1 drivers and applications, for
- *     Linux kernels 2.2.x or 2.4.x.
- *
- *     Provides header for legacy drivers and applications
- *
- *     See http://linuxtv.org for more info
- *
- */
-#ifndef __LINUX_VIDEODEV_H
-#define __LINUX_VIDEODEV_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/videodev2.h>
-
-#define VID_TYPE_CAPTURE       1       /* Can capture */
-#define VID_TYPE_TUNER         2       /* Can tune */
-#define VID_TYPE_TELETEXT      4       /* Does teletext */
-#define VID_TYPE_OVERLAY       8       /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY     16      /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING      32      /* Can clip */
-#define VID_TYPE_FRAMERAM      64      /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES                128     /* Scalable */
-#define VID_TYPE_MONOCHROME    256     /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE    512     /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER  1024    /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER  2048    /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER 4096    /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER 8192    /* Can encode MJPEG streams */
-
-struct video_capability
-{
-       char name[32];
-       int type;
-       int channels;   /* Num channels */
-       int audios;     /* Num audio devices */
-       int maxwidth;   /* Supported width */
-       int maxheight;  /* And height */
-       int minwidth;   /* Supported width */
-       int minheight;  /* And height */
-};
-
-
-struct video_channel
-{
-       int channel;
-       char name[32];
-       int tuners;
-       __u32  flags;
-#define VIDEO_VC_TUNER         1       /* Channel has a tuner */
-#define VIDEO_VC_AUDIO         2       /* Channel has audio */
-       __u16  type;
-#define VIDEO_TYPE_TV          1
-#define VIDEO_TYPE_CAMERA      2
-       __u16 norm;                     /* Norm set by channel */
-};
-
-struct video_tuner
-{
-       int tuner;
-       char name[32];
-       unsigned long rangelow, rangehigh;      /* Tuner range */
-       __u32 flags;
-#define VIDEO_TUNER_PAL                1
-#define VIDEO_TUNER_NTSC       2
-#define VIDEO_TUNER_SECAM      4
-#define VIDEO_TUNER_LOW                8       /* Uses KHz not MHz */
-#define VIDEO_TUNER_NORM       16      /* Tuner can set norm */
-#define VIDEO_TUNER_STEREO_ON  128     /* Tuner is seeing stereo */
-#define VIDEO_TUNER_RDS_ON      256     /* Tuner is seeing an RDS datastream */
-#define VIDEO_TUNER_MBS_ON      512     /* Tuner is seeing an MBS datastream */
-       __u16 mode;                     /* PAL/NTSC/SECAM/OTHER */
-#define VIDEO_MODE_PAL         0
-#define VIDEO_MODE_NTSC                1
-#define VIDEO_MODE_SECAM       2
-#define VIDEO_MODE_AUTO                3
-       __u16 signal;                   /* Signal strength 16bit scale */
-};
-
-struct video_picture
-{
-       __u16   brightness;
-       __u16   hue;
-       __u16   colour;
-       __u16   contrast;
-       __u16   whiteness;      /* Black and white only */
-       __u16   depth;          /* Capture depth */
-       __u16   palette;        /* Palette in use */
-#define VIDEO_PALETTE_GREY     1       /* Linear greyscale */
-#define VIDEO_PALETTE_HI240    2       /* High 240 cube (BT848) */
-#define VIDEO_PALETTE_RGB565   3       /* 565 16 bit RGB */
-#define VIDEO_PALETTE_RGB24    4       /* 24bit RGB */
-#define VIDEO_PALETTE_RGB32    5       /* 32bit RGB */
-#define VIDEO_PALETTE_RGB555   6       /* 555 15bit RGB */
-#define VIDEO_PALETTE_YUV422   7       /* YUV422 capture */
-#define VIDEO_PALETTE_YUYV     8
-#define VIDEO_PALETTE_UYVY     9       /* The great thing about standards is ... */
-#define VIDEO_PALETTE_YUV420   10
-#define VIDEO_PALETTE_YUV411   11      /* YUV411 capture */
-#define VIDEO_PALETTE_RAW      12      /* RAW capture (BT848) */
-#define VIDEO_PALETTE_YUV422P  13      /* YUV 4:2:2 Planar */
-#define VIDEO_PALETTE_YUV411P  14      /* YUV 4:1:1 Planar */
-#define VIDEO_PALETTE_YUV420P  15      /* YUV 4:2:0 Planar */
-#define VIDEO_PALETTE_YUV410P  16      /* YUV 4:1:0 Planar */
-#define VIDEO_PALETTE_PLANAR   13      /* start of planar entries */
-#define VIDEO_PALETTE_COMPONENT 7      /* start of component entries */
-};
-
-struct video_audio
-{
-       int     audio;          /* Audio channel */
-       __u16   volume;         /* If settable */
-       __u16   bass, treble;
-       __u32   flags;
-#define VIDEO_AUDIO_MUTE       1
-#define VIDEO_AUDIO_MUTABLE    2
-#define VIDEO_AUDIO_VOLUME     4
-#define VIDEO_AUDIO_BASS       8
-#define VIDEO_AUDIO_TREBLE     16
-#define VIDEO_AUDIO_BALANCE    32
-       char    name[16];
-#define VIDEO_SOUND_MONO       1
-#define VIDEO_SOUND_STEREO     2
-#define VIDEO_SOUND_LANG1      4
-#define VIDEO_SOUND_LANG2      8
-       __u16   mode;
-       __u16   balance;        /* Stereo balance */
-       __u16   step;           /* Step actual volume uses */
-};
-
-struct video_clip
-{
-       __s32   x,y;
-       __s32   width, height;
-       struct  video_clip *next;       /* For user use/driver use only */
-};
-
-struct video_window
-{
-       __u32   x,y;                    /* Position of window */
-       __u32   width,height;           /* Its size */
-       __u32   chromakey;
-       __u32   flags;
-       struct  video_clip __user *clips;       /* Set only */
-       int     clipcount;
-#define VIDEO_WINDOW_INTERLACE 1
-#define VIDEO_WINDOW_CHROMAKEY 16      /* Overlay by chromakey */
-#define VIDEO_CLIP_BITMAP      -1
-/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
-#define VIDEO_CLIPMAP_SIZE     (128 * 625)
-};
-
-struct video_capture
-{
-       __u32   x,y;                    /* Offsets into image */
-       __u32   width, height;          /* Area to capture */
-       __u16   decimation;             /* Decimation divider */
-       __u16   flags;                  /* Flags for capture */
-#define VIDEO_CAPTURE_ODD              0       /* Temporal */
-#define VIDEO_CAPTURE_EVEN             1
-};
-
-struct video_buffer
-{
-       void    *base;
-       int     height,width;
-       int     depth;
-       int     bytesperline;
-};
-
-struct video_mmap
-{
-       unsigned        int frame;              /* Frame (0 - n) for double buffer */
-       int             height,width;
-       unsigned        int format;             /* should be VIDEO_PALETTE_* */
-};
-
-struct video_key
-{
-       __u8    key[8];
-       __u32   flags;
-};
-
-struct video_mbuf
-{
-       int     size;           /* Total memory to map */
-       int     frames;         /* Frames */
-       int     offsets[VIDEO_MAX_FRAME];
-};
-
-#define        VIDEO_NO_UNIT   (-1)
-
-struct video_unit
-{
-       int     video;          /* Video minor */
-       int     vbi;            /* VBI minor */
-       int     radio;          /* Radio minor */
-       int     audio;          /* Audio minor */
-       int     teletext;       /* Teletext minor */
-};
-
-struct vbi_format {
-       __u32   sampling_rate;  /* in Hz */
-       __u32   samples_per_line;
-       __u32   sample_format;  /* VIDEO_PALETTE_RAW only (1 byte) */
-       __s32   start[2];       /* starting line for each frame */
-       __u32   count[2];       /* count of lines for each frame */
-       __u32   flags;
-#define        VBI_UNSYNC      1       /* can distingues between top/bottom field */
-#define        VBI_INTERLACED  2       /* lines are interlaced */
-};
-
-/* video_info is biased towards hardware mpeg encode/decode */
-/* but it could apply generically to any hardware compressor/decompressor */
-struct video_info
-{
-       __u32   frame_count;    /* frames output since decode/encode began */
-       __u32   h_size;         /* current unscaled horizontal size */
-       __u32   v_size;         /* current unscaled veritcal size */
-       __u32   smpte_timecode; /* current SMPTE timecode (for current GOP) */
-       __u32   picture_type;   /* current picture type */
-       __u32   temporal_reference;     /* current temporal reference */
-       __u8    user_data[256]; /* user data last found in compressed stream */
-       /* user_data[0] contains user data flags, user_data[1] has count */
-};
-
-/* generic structure for setting playback modes */
-struct video_play_mode
-{
-       int     mode;
-       int     p1;
-       int     p2;
-};
-
-/* for loading microcode / fpga programming */
-struct video_code
-{
-       char    loadwhat[16];   /* name or tag of file being passed */
-       int     datasize;
-       __u8    *data;
-};
-
-#define VIDIOCGCAP             _IOR('v',1,struct video_capability)     /* Get capabilities */
-#define VIDIOCGCHAN            _IOWR('v',2,struct video_channel)       /* Get channel info (sources) */
-#define VIDIOCSCHAN            _IOW('v',3,struct video_channel)        /* Set channel  */
-#define VIDIOCGTUNER           _IOWR('v',4,struct video_tuner)         /* Get tuner abilities */
-#define VIDIOCSTUNER           _IOW('v',5,struct video_tuner)          /* Tune the tuner for the current channel */
-#define VIDIOCGPICT            _IOR('v',6,struct video_picture)        /* Get picture properties */
-#define VIDIOCSPICT            _IOW('v',7,struct video_picture)        /* Set picture properties */
-#define VIDIOCCAPTURE          _IOW('v',8,int)                         /* Start, end capture */
-#define VIDIOCGWIN             _IOR('v',9, struct video_window)        /* Get the video overlay window */
-#define VIDIOCSWIN             _IOW('v',10, struct video_window)       /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
-#define VIDIOCGFBUF            _IOR('v',11, struct video_buffer)       /* Get frame buffer */
-#define VIDIOCSFBUF            _IOW('v',12, struct video_buffer)       /* Set frame buffer - root only */
-#define VIDIOCKEY              _IOR('v',13, struct video_key)          /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
-#define VIDIOCGFREQ            _IOR('v',14, unsigned long)             /* Set tuner */
-#define VIDIOCSFREQ            _IOW('v',15, unsigned long)             /* Set tuner */
-#define VIDIOCGAUDIO           _IOR('v',16, struct video_audio)        /* Get audio info */
-#define VIDIOCSAUDIO           _IOW('v',17, struct video_audio)        /* Audio source, mute etc */
-#define VIDIOCSYNC             _IOW('v',18, int)                       /* Sync with mmap grabbing */
-#define VIDIOCMCAPTURE         _IOW('v',19, struct video_mmap)         /* Grab frames */
-#define VIDIOCGMBUF            _IOR('v',20, struct video_mbuf)         /* Memory map buffer info */
-#define VIDIOCGUNIT            _IOR('v',21, struct video_unit)         /* Get attached units */
-#define VIDIOCGCAPTURE         _IOR('v',22, struct video_capture)      /* Get subcapture */
-#define VIDIOCSCAPTURE         _IOW('v',23, struct video_capture)      /* Set subcapture */
-#define VIDIOCSPLAYMODE                _IOW('v',24, struct video_play_mode)    /* Set output video mode/feature */
-#define VIDIOCSWRITEMODE       _IOW('v',25, int)                       /* Set write mode */
-#define VIDIOCGPLAYINFO                _IOR('v',26, struct video_info)         /* Get current playback info from hardware */
-#define VIDIOCSMICROCODE       _IOW('v',27, struct video_code)         /* Load microcode into hardware */
-#define        VIDIOCGVBIFMT           _IOR('v',28, struct vbi_format)         /* Get VBI information */
-#define        VIDIOCSVBIFMT           _IOW('v',29, struct vbi_format)         /* Set VBI information */
-
-
-#define BASE_VIDIOCPRIVATE     192             /* 192-255 are private */
-
-/* VIDIOCSWRITEMODE */
-#define VID_WRITE_MPEG_AUD             0
-#define VID_WRITE_MPEG_VID             1
-#define VID_WRITE_OSD                  2
-#define VID_WRITE_TTX                  3
-#define VID_WRITE_CC                   4
-#define VID_WRITE_MJPEG                        5
-
-/* VIDIOCSPLAYMODE */
-#define VID_PLAY_VID_OUT_MODE          0
-       /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
-#define VID_PLAY_GENLOCK               1
-       /* p1: 0 = OFF, 1 = ON */
-       /* p2: GENLOCK FINE DELAY value */
-#define VID_PLAY_NORMAL                        2
-#define VID_PLAY_PAUSE                 3
-#define VID_PLAY_SINGLE_FRAME          4
-#define VID_PLAY_FAST_FORWARD          5
-#define VID_PLAY_SLOW_MOTION           6
-#define VID_PLAY_IMMEDIATE_NORMAL      7
-#define VID_PLAY_SWITCH_CHANNELS       8
-#define VID_PLAY_FREEZE_FRAME          9
-#define VID_PLAY_STILL_MODE            10
-#define VID_PLAY_MASTER_MODE           11
-       /* p1: see below */
-#define                VID_PLAY_MASTER_NONE    1
-#define                VID_PLAY_MASTER_VIDEO   2
-#define                VID_PLAY_MASTER_AUDIO   3
-#define VID_PLAY_ACTIVE_SCANLINES      12
-       /* p1 = first active; p2 = last active */
-#define VID_PLAY_RESET                 13
-#define VID_PLAY_END_MARK              14
-
-#endif /* __LINUX_VIDEODEV_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index e1851f00be568f07e17fbd6c45070bdc9d01de93..842cd9214a5ec120989e8a339ab158433dff5b91 100644 (file)
@@ -381,10 +381,10 @@ static int cyasblkdev_blk_ioctl(
        return -ENOTTY;
 }
 
-/* Media_changed block_device opp
+/* check_events block_device opp
  * this one is called by kernel to confirm if the media really changed
  * as we indicated by issuing check_disk_change() call */
-int cyasblkdev_media_changed(struct gendisk *gd)
+unsigned int cyasblkdev_check_events(struct gendisk *gd, unsigned int clearing)
 {
        struct cyasblkdev_blk_data *bd;
 
@@ -402,7 +402,7 @@ int cyasblkdev_media_changed(struct gendisk *gd)
                #endif
        }
 
-       /* return media change state "1" yes, 0 no */
+       /* return media change state - DISK_EVENT_MEDIA_CHANGE yes, 0 no */
        return 0;
 }
 
@@ -432,7 +432,7 @@ static struct block_device_operations cyasblkdev_bdops = {
        .ioctl                  = cyasblkdev_blk_ioctl,
        /* .getgeo              = cyasblkdev_blk_getgeo, */
        /* added to support media removal( real and simulated) media */
-       .media_changed  = cyasblkdev_media_changed,
+       .check_events           = cyasblkdev_check_events,
        /* added to support media removal( real and simulated) media */
        .revalidate_disk = cyasblkdev_revalidate_disk,
        .owner                  = THIS_MODULE,
@@ -1090,6 +1090,7 @@ static int cyasblkdev_add_disks(int bus_num,
                bd->user_disk_0->first_minor = devidx << CYASBLKDEV_SHIFT;
                bd->user_disk_0->minors = 8;
                bd->user_disk_0->fops = &cyasblkdev_bdops;
+               bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE;
                bd->user_disk_0->private_data = bd;
                bd->user_disk_0->queue = bd->queue.queue;
                bd->dbgprn_flags = DBGPRN_RD_RQ;
@@ -1190,6 +1191,7 @@ static int cyasblkdev_add_disks(int bus_num,
                bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT;
                bd->user_disk_1->minors = 8;
                bd->user_disk_1->fops = &cyasblkdev_bdops;
+               bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE;
                bd->user_disk_1->private_data = bd;
                bd->user_disk_1->queue = bd->queue.queue;
                bd->dbgprn_flags = DBGPRN_RD_RQ;
@@ -1278,6 +1280,7 @@ static int cyasblkdev_add_disks(int bus_num,
                                (devidx + 2) << CYASBLKDEV_SHIFT;
                        bd->system_disk->minors = 8;
                        bd->system_disk->fops = &cyasblkdev_bdops;
+                       bd->system_disk->events = DISK_EVENT_MEDIA_CHANGE;
                        bd->system_disk->private_data = bd;
                        bd->system_disk->queue = bd->queue.queue;
                        /* don't search for vfat
index 3df570db0e4ff21cd57f4f0c229bf555f9b4fbdd..eb0afec046e115d99d729788875e2bcc9c6a6ebd 100644 (file)
@@ -391,9 +391,8 @@ static int iblock_do_task(struct se_task *task)
 {
        struct se_device *dev = task->task_se_cmd->se_dev;
        struct iblock_req *req = IBLOCK_REQ(task);
-       struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev;
-       struct request_queue *q = bdev_get_queue(ibd->ibd_bd);
        struct bio *bio = req->ib_bio, *nbio = NULL;
+       struct blk_plug plug;
        int rw;
 
        if (task->task_data_direction == DMA_TO_DEVICE) {
@@ -411,6 +410,7 @@ static int iblock_do_task(struct se_task *task)
                rw = READ;
        }
 
+       blk_start_plug(&plug);
        while (bio) {
                nbio = bio->bi_next;
                bio->bi_next = NULL;
@@ -420,9 +420,8 @@ static int iblock_do_task(struct se_task *task)
                submit_bio(rw, bio);
                bio = nbio;
        }
+       blk_finish_plug(&plug);
 
-       if (q->unplug_fn)
-               q->unplug_fn(q);
        return PYX_TRANSPORT_SENT_TO_TRANSPORT;
 }
 
index 713b7ea4a60709e89e164fd4765e75e5397ed57f..fc6f2a5bde01324675424b01da941e8718ccd259 100644 (file)
@@ -560,7 +560,8 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 
        tz->hwmon = NULL;
        device_remove_file(hwmon->device, &tz->temp_input.attr);
-       device_remove_file(hwmon->device, &tz->temp_crit.attr);
+       if (tz->ops->get_crit_temp)
+               device_remove_file(hwmon->device, &tz->temp_crit.attr);
 
        mutex_lock(&thermal_list_lock);
        list_del(&tz->hwmon_node);
index 16402445f2b237303589ede6d768753bb08c6166..03c285bb2f182681c9038a3d535ad3962b733d30 100644 (file)
@@ -251,11 +251,11 @@ static int __init bfin_jc_init(void)
        bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
        bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
        if (!bfin_jc_write_buf.buf)
-               goto err;
+               goto err_buf;
 
        bfin_jc_driver = alloc_tty_driver(1);
        if (!bfin_jc_driver)
-               goto err;
+               goto err_driver;
 
        bfin_jc_driver->owner        = THIS_MODULE;
        bfin_jc_driver->driver_name  = DRV_NAME;
@@ -275,7 +275,9 @@ static int __init bfin_jc_init(void)
 
  err:
        put_tty_driver(bfin_jc_driver);
+ err_driver:
        kfree(bfin_jc_write_buf.buf);
+ err_buf:
        kthread_stop(bfin_jc_kthread);
        return ret;
 }
index 81f13958e751095d869a2935460163d8111f4098..43db715f15026d491d87cc1d3c7e443ddcf2f341 100644 (file)
@@ -306,7 +306,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = {
 
 static void sysrq_handle_showmem(int key)
 {
-       show_mem();
+       show_mem(0);
 }
 static struct sysrq_key_op sysrq_showmem_op = {
        .handler        = sysrq_handle_showmem,
index d8210ca007206628163efea3b2eb6dff473fadf7..b9451219528b76bf01a900b0873dea751b27e9d5 100644 (file)
@@ -322,7 +322,7 @@ void tty_schedule_flip(struct tty_struct *tty)
        if (tty->buf.tail != NULL)
                tty->buf.tail->commit = tty->buf.tail->used;
        spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
+       schedule_work(&tty->buf.work);
 }
 EXPORT_SYMBOL(tty_schedule_flip);
 
@@ -402,7 +402,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
 static void flush_to_ldisc(struct work_struct *work)
 {
        struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
+               container_of(work, struct tty_struct, buf.work);
        unsigned long   flags;
        struct tty_ldisc *disc;
 
@@ -443,7 +443,7 @@ static void flush_to_ldisc(struct work_struct *work)
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
                        if (!tty->receive_room || seen_tail) {
-                               schedule_delayed_work(&tty->buf.work, 1);
+                               schedule_work(&tty->buf.work);
                                break;
                        }
                        if (count > tty->receive_room)
@@ -481,7 +481,7 @@ static void flush_to_ldisc(struct work_struct *work)
  */
 void tty_flush_to_ldisc(struct tty_struct *tty)
 {
-       flush_delayed_work(&tty->buf.work);
+       flush_work(&tty->buf.work);
 }
 
 /**
@@ -506,9 +506,9 @@ void tty_flip_buffer_push(struct tty_struct *tty)
        spin_unlock_irqrestore(&tty->buf.lock, flags);
 
        if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
+               flush_to_ldisc(&tty->buf.work);
        else
-               schedule_delayed_work(&tty->buf.work, 1);
+               schedule_work(&tty->buf.work);
 }
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
@@ -529,6 +529,6 @@ void tty_buffer_init(struct tty_struct *tty)
        tty->buf.tail = NULL;
        tty->buf.free = NULL;
        tty->buf.memory_used = 0;
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+       INIT_WORK(&tty->buf.work, flush_to_ldisc);
 }
 
index 0fc564a977065a24cf0bb377d54be5e9049cb039..e19e136471165dd163509750bddd6382ce70bcd2 100644 (file)
@@ -529,7 +529,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
 static int tty_ldisc_halt(struct tty_struct *tty)
 {
        clear_bit(TTY_LDISC, &tty->flags);
-       return cancel_delayed_work_sync(&tty->buf.work);
+       return cancel_work_sync(&tty->buf.work);
 }
 
 /**
@@ -542,7 +542,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
 {
        flush_work_sync(&tty->hangup_work);
        flush_work_sync(&tty->SAK_work);
-       flush_delayed_work_sync(&tty->buf.work);
+       flush_work_sync(&tty->buf.work);
 }
 
 /**
@@ -722,9 +722,9 @@ enable:
        /* Restart the work queue in case no characters kick it off. Safe if
           already running */
        if (work)
-               schedule_delayed_work(&tty->buf.work, 1);
+               schedule_work(&tty->buf.work);
        if (o_work)
-               schedule_delayed_work(&o_tty->buf.work, 1);
+               schedule_work(&o_tty->buf.work);
        mutex_unlock(&tty->ldisc_mutex);
        tty_unlock();
        return retval;
@@ -830,12 +830,12 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 
        /*
         * this is like tty_ldisc_halt, but we need to give up
-        * the BTM before calling cancel_delayed_work_sync,
-        * which may need to wait for another function taking the BTM
+        * the BTM before calling cancel_work_sync, which may
+        * need to wait for another function taking the BTM
         */
        clear_bit(TTY_LDISC, &tty->flags);
        tty_unlock();
-       cancel_delayed_work_sync(&tty->buf.work);
+       cancel_work_sync(&tty->buf.work);
        mutex_unlock(&tty->ldisc_mutex);
 
        tty_lock();
index 6dd3c68c13add15f4a0452f06694fbd7a2c06cf4..d6b342b5b423ce69fc989cdf3593fa892d7f9167 100644 (file)
@@ -600,7 +600,7 @@ static void fn_scroll_back(struct vc_data *vc)
 
 static void fn_show_mem(struct vc_data *vc)
 {
-       show_mem();
+       show_mem(0);
 }
 
 static void fn_show_state(struct vc_data *vc)
index f492a7f2b6ee2e74cd56aa44b03fbd55ba74e613..e057e5381465b1a12c03e550f3ff6b2f9d4d24e0 100644 (file)
@@ -297,6 +297,8 @@ static void acm_ctrl_irq(struct urb *urb)
        if (!ACM_READY(acm))
                goto exit;
 
+       usb_mark_last_busy(acm->dev);
+
        data = (unsigned char *)(dr + 1);
        switch (dr->bNotificationType) {
        case USB_CDC_NOTIFY_NETWORK_CONNECTION:
@@ -336,7 +338,6 @@ static void acm_ctrl_irq(struct urb *urb)
                break;
        }
 exit:
-       usb_mark_last_busy(acm->dev);
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
                dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
@@ -533,6 +534,8 @@ static void acm_softint(struct work_struct *work)
        if (!ACM_READY(acm))
                return;
        tty = tty_port_tty_get(&acm->port);
+       if (!tty)
+               return;
        tty_wakeup(tty);
        tty_kref_put(tty);
 }
@@ -646,8 +649,10 @@ static void acm_port_down(struct acm *acm)
                usb_kill_urb(acm->ctrlurb);
                for (i = 0; i < ACM_NW; i++)
                        usb_kill_urb(acm->wb[i].urb);
+               tasklet_disable(&acm->urb_task);
                for (i = 0; i < nr; i++)
                        usb_kill_urb(acm->ru[i].urb);
+               tasklet_enable(&acm->urb_task);
                acm->control->needs_remote_wakeup = 0;
                usb_autopm_put_interface(acm->control);
        }
index 47085e5879abb57758601722bb62c7734380a254..a97c018dd41980ebc6a9087d235f7ee1fdc965b4 100644 (file)
@@ -281,7 +281,7 @@ static void cleanup(struct wdm_device *desc)
                          desc->sbuf,
                          desc->validity->transfer_dma);
        usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->wMaxCommand,
+                         desc->bMaxPacketSize0,
                          desc->inbuf,
                          desc->response->transfer_dma);
        kfree(desc->orq);
index a7131ad630f9ad54535205017352ee10175df384..37518dfdeb987188089eb43c3147417ce14615a9 100644 (file)
@@ -802,7 +802,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                                    tbuf, ctrl.wLength, tmo);
                usb_lock_device(dev);
                snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
-                       tbuf, i);
+                         tbuf, max(i, 0));
                if ((i > 0) && ctrl.wLength) {
                        if (copy_to_user(ctrl.data, tbuf, i)) {
                                free_page((unsigned long)tbuf);
index 38072e4e74bd66776e64ae6fdd9c1ad97dac3aae..e35a17687c05f77b9ecc55b4002d0b13386081b6 100644 (file)
@@ -1646,7 +1646,7 @@ static int autosuspend_check(struct usb_device *udev)
        return 0;
 }
 
-static int usb_runtime_suspend(struct device *dev)
+int usb_runtime_suspend(struct device *dev)
 {
        struct usb_device       *udev = to_usb_device(dev);
        int                     status;
@@ -1667,7 +1667,7 @@ static int usb_runtime_suspend(struct device *dev)
        return status;
 }
 
-static int usb_runtime_resume(struct device *dev)
+int usb_runtime_resume(struct device *dev)
 {
        struct usb_device       *udev = to_usb_device(dev);
        int                     status;
@@ -1679,7 +1679,7 @@ static int usb_runtime_resume(struct device *dev)
        return status;
 }
 
-static int usb_runtime_idle(struct device *dev)
+int usb_runtime_idle(struct device *dev)
 {
        struct usb_device       *udev = to_usb_device(dev);
 
@@ -1691,19 +1691,10 @@ static int usb_runtime_idle(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops usb_bus_pm_ops = {
-       .runtime_suspend =      usb_runtime_suspend,
-       .runtime_resume =       usb_runtime_resume,
-       .runtime_idle =         usb_runtime_idle,
-};
-
 #endif /* CONFIG_USB_SUSPEND */
 
 struct bus_type usb_bus_type = {
        .name =         "usb",
        .match =        usb_device_match,
        .uevent =       usb_uevent,
-#ifdef CONFIG_USB_SUSPEND
-       .pm =           &usb_bus_pm_ops,
-#endif
 };
index 079cb57bab4f214f5d6aecf5a538044a404477da..d9d4b169404f9d46fbda9f5fa7cc09d00468d0a2 100644 (file)
@@ -315,6 +315,11 @@ static const struct dev_pm_ops usb_device_pm_ops = {
        .thaw =         usb_dev_thaw,
        .poweroff =     usb_dev_poweroff,
        .restore =      usb_dev_restore,
+#ifdef CONFIG_USB_SUSPEND
+       .runtime_suspend =      usb_runtime_suspend,
+       .runtime_resume =       usb_runtime_resume,
+       .runtime_idle =         usb_runtime_idle,
+#endif
 };
 
 #endif /* CONFIG_PM */
index a9cf484ecae4c9efd39d298f607127d1f4e32fc3..d450b742137e45f4c9c728044ce394f578cac302 100644 (file)
@@ -77,6 +77,9 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 extern void usb_autosuspend_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
 extern int usb_remote_wakeup(struct usb_device *dev);
+extern int usb_runtime_suspend(struct device *dev);
+extern int usb_runtime_resume(struct device *dev);
+extern int usb_runtime_idle(struct device *dev);
 
 #else
 
index fe99895fb098753bf5e88c3ab9cd0984c10fffc1..98ded66e8d3fc5ccfbe4bfd9170c51e99cf3b752 100644 (file)
@@ -315,7 +315,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        int                     stopped;
        unsigned                count = 0;
        u8                      state;
-       const __le32            halt = HALT_BIT(ehci);
        struct ehci_qh_hw       *hw = qh->hw;
 
        if (unlikely (list_empty (&qh->qtd_list)))
@@ -422,7 +421,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                                        && !(qtd->hw_alt_next
                                                & EHCI_LIST_END(ehci))) {
                                stopped = 1;
-                               goto halt;
                        }
 
                /* stop scanning when we reach qtds the hc is using */
@@ -456,16 +454,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                                 */
                                ehci_clear_tt_buffer(ehci, qh, urb, token);
                        }
-
-                       /* force halt for unlinked or blocked qh, so we'll
-                        * patch the qh later and so that completions can't
-                        * activate it while we "know" it's stopped.
-                        */
-                       if ((halt & hw->hw_token) == 0) {
-halt:
-                               hw->hw_token |= halt;
-                               wmb ();
-                       }
                }
 
                /* unless we already know the urb's status, collect qtd status
index 8dabe8e31d8c2293e1e65e86b0069914bac70483..3558491dd87d5eaae84df78fc15e0348382eaaf4 100644 (file)
@@ -185,7 +185,7 @@ static struct platform_driver ohci_hcd_tmio_driver;
 
 static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
        struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1);
        struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2);
@@ -274,7 +274,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
        struct tmio_hcd *tmio = hcd_to_tmio(hcd);
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
 
        usb_remove_hcd(hcd);
        tmio_stop_hc(dev);
@@ -293,7 +293,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct usb_hcd *hcd = platform_get_drvdata(dev);
        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
        struct tmio_hcd *tmio = hcd_to_tmio(hcd);
@@ -326,7 +326,7 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
 
 static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct usb_hcd *hcd = platform_get_drvdata(dev);
        struct ohci_hcd *ohci = hcd_to_ohci(hcd);
        struct tmio_hcd *tmio = hcd_to_tmio(hcd);
index 1fa6ce3e4a23367a47503136f02892ad760ace1c..68ab460a735c15e94c9cd04600a9e499582b3200 100644 (file)
@@ -282,6 +282,7 @@ static int appledisplay_probe(struct usb_interface *iface,
        snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
                atomic_inc_return(&count_displays) - 1);
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 0xff;
        pdata->bd = backlight_device_register(bl_name, NULL, pdata,
                                              &appledisplay_bl_data, &props);
index f7a2057380321fa7c102b140ce0bf2f4374e9db1..8b1d94a769140ca0ab6f9f6a082384b8725c9873 100644 (file)
@@ -177,12 +177,11 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
        spin_lock_irqsave(&priv->asynclock, flags);
        list_add_tail(&rq->asynclist, &priv->asynclist);
        spin_unlock_irqrestore(&priv->asynclock, flags);
+       kref_get(&rq->ref_count);
        ret = usb_submit_urb(rq->urb, mem_flags);
-       if (!ret) {
-               kref_get(&rq->ref_count);
+       if (!ret)
                return rq;
-       }
-       kref_put(&rq->ref_count, destroy_async);
+       destroy_async(&rq->ref_count);
        err("submit_async_request submit_urb failed with %d", ret);
        return NULL;
 }
index 9d49d1cd7ce2308024fb7d2b7cc73538e00dd9cc..52312e8af213a4d0d6cdd515aa50757fd06bfa56 100644 (file)
@@ -322,7 +322,7 @@ static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
                mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
 }
 
-static int bfin_musb_get_vbus_status(struct musb *musb)
+static int bfin_musb_vbus_status(struct musb *musb)
 {
        return 0;
 }
@@ -540,7 +540,7 @@ static struct dev_pm_ops bfin_pm_ops = {
        .resume         = bfin_resume,
 };
 
-#define DEV_PM_OPS     &bfin_pm_op,
+#define DEV_PM_OPS     &bfin_pm_ops
 #else
 #define DEV_PM_OPS     NULL
 #endif
@@ -548,7 +548,7 @@ static struct dev_pm_ops bfin_pm_ops = {
 static struct platform_driver bfin_driver = {
        .remove         = __exit_p(bfin_remove),
        .driver         = {
-               .name   = "musb-bfin",
+               .name   = "musb-blackfin",
                .pm     = DEV_PM_OPS,
        },
 };
index 5c7b321d3959751f94281ab6cc2205e228bc142f..98519c5d8b5cc23e5407dac87a521004d8885f59 100644 (file)
@@ -1880,12 +1880,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                if (retval < 0) {
                        DBG(1, "add_hcd failed, %d\n", retval);
                        goto err2;
-
-                       if ((musb->xceiv->last_event == USB_EVENT_ID)
-                                               && musb->xceiv->set_vbus)
-                               otg_set_vbus(musb->xceiv, 1);
                }
 
+               if ((musb->xceiv->last_event == USB_EVENT_ID)
+                                       && musb->xceiv->set_vbus)
+                       otg_set_vbus(musb->xceiv, 1);
+
                hcd->self.uses_pio_for_control = 1;
 
                if (musb->xceiv->last_event == USB_EVENT_NONE)
index a65ddd5438693e7d235a190eb44f2f9ac163e534..e4fad5e643d74d6ab01995b0e84b9b53ea47fff7 100644 (file)
@@ -698,8 +698,7 @@ static void play_delayed(struct usb_serial_port *port)
                        /* we have to throw away the rest */
                        do {
                                unbusy_queued_urb(urb, portdata);
-                               //extremely dirty
-                               atomic_dec(&port->serial->interface->dev.power.usage_count);
+                               usb_autopm_put_interface_no_suspend(port->serial->interface);
                        } while ((urb = usb_get_from_anchor(&portdata->delayed)));
                        break;
                }
index 013c8ce5720599c7f394c7ad7e1db8b22944cec6..5fc983c5b92cb6677026fb8e5ddb18349150bee0 100644 (file)
@@ -120,8 +120,23 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
 static int
 clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
 {
+       u32 caps;
        int ret = 0;
 
+       if (fb->panel->caps && fb->board->caps)
+               caps = fb->panel->caps & fb->board->caps;
+       else {
+               /* Old way of specifying what can be used */
+               caps = fb->panel->cntl & CNTL_BGR ?
+                       CLCD_CAP_BGR : CLCD_CAP_RGB;
+               /* But mask out 444 modes as they weren't supported */
+               caps &= ~CLCD_CAP_444;
+       }
+
+       /* Only TFT panels can do RGB888/BGR888 */
+       if (!(fb->panel->cntl & CNTL_LCDTFT))
+               caps &= ~CLCD_CAP_888;
+
        memset(&var->transp, 0, sizeof(var->transp));
 
        var->red.msb_right = 0;
@@ -133,6 +148,13 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
        case 2:
        case 4:
        case 8:
+               /* If we can't do 5551, reject */
+               caps &= CLCD_CAP_5551;
+               if (!caps) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                var->red.length         = var->bits_per_pixel;
                var->red.offset         = 0;
                var->green.length       = var->bits_per_pixel;
@@ -140,23 +162,61 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
                var->blue.length        = var->bits_per_pixel;
                var->blue.offset        = 0;
                break;
+
        case 16:
-               var->red.length = 5;
-               var->blue.length = 5;
+               /* If we can't do 444, 5551 or 565, reject */
+               if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                /*
-                * Green length can be 5 or 6 depending whether
-                * we're operating in RGB555 or RGB565 mode.
+                * Green length can be 4, 5 or 6 depending whether
+                * we're operating in 444, 5551 or 565 mode.
                 */
-               if (var->green.length != 5 && var->green.length != 6)
-                       var->green.length = 6;
+               if (var->green.length == 4 && caps & CLCD_CAP_444)
+                       caps &= CLCD_CAP_444;
+               if (var->green.length == 5 && caps & CLCD_CAP_5551)
+                       caps &= CLCD_CAP_5551;
+               else if (var->green.length == 6 && caps & CLCD_CAP_565)
+                       caps &= CLCD_CAP_565;
+               else {
+                       /*
+                        * PL110 officially only supports RGB555,
+                        * but may be wired up to allow RGB565.
+                        */
+                       if (caps & CLCD_CAP_565) {
+                               var->green.length = 6;
+                               caps &= CLCD_CAP_565;
+                       } else if (caps & CLCD_CAP_5551) {
+                               var->green.length = 5;
+                               caps &= CLCD_CAP_5551;
+                       } else {
+                               var->green.length = 4;
+                               caps &= CLCD_CAP_444;
+                       }
+               }
+
+               if (var->green.length >= 5) {
+                       var->red.length = 5;
+                       var->blue.length = 5;
+               } else {
+                       var->red.length = 4;
+                       var->blue.length = 4;
+               }
                break;
        case 32:
-               if (fb->panel->cntl & CNTL_LCDTFT) {
-                       var->red.length         = 8;
-                       var->green.length       = 8;
-                       var->blue.length        = 8;
+               /* If we can't do 888, reject */
+               caps &= CLCD_CAP_888;
+               if (!caps) {
+                       ret = -EINVAL;
                        break;
                }
+
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -168,7 +228,20 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
         * the bitfield length defined above.
         */
        if (ret == 0 && var->bits_per_pixel >= 16) {
-               if (fb->panel->cntl & CNTL_BGR) {
+               bool bgr, rgb;
+
+               bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
+               rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
+
+               if (!bgr && !rgb)
+                       /*
+                        * The requested format was not possible, try just
+                        * our capabilities.  One of BGR or RGB must be
+                        * supported.
+                        */
+                       bgr = caps & CLCD_CAP_BGR;
+
+               if (bgr) {
                        var->blue.offset = 0;
                        var->green.offset = var->blue.offset + var->blue.length;
                        var->red.offset = var->green.offset + var->green.length;
@@ -443,8 +516,8 @@ static int clcdfb_register(struct clcd_fb *fb)
 
        fb_set_var(&fb->fb, &fb->fb.var);
 
-        printk(KERN_INFO "CLCD: %s hardware, %s display\n",
-               fb->board->name, fb->panel->mode.name);
+       dev_info(&fb->dev->dev, "%s hardware, %s display\n",
+                fb->board->name, fb->panel->mode.name);
 
        ret = register_framebuffer(&fb->fb);
        if (ret == 0)
@@ -486,6 +559,10 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
        fb->dev = dev;
        fb->board = board;
 
+       dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n",
+               amba_part(dev), amba_rev(dev),
+               (unsigned long long)dev->res.start);
+
        ret = fb->board->setup(fb);
        if (ret)
                goto free_fb;
index 391ac939f011cd9102184154c1cbcd42e09878b7..8686429cbdf07b57af8564849ad64b7a8624ff16 100644 (file)
@@ -158,12 +158,19 @@ static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
        }
 }
 
+static void arkfb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
+{
+       struct arkfb_info *par = info->par;
+
+       svga_tilecursor(par->state.vgabase, info, cursor);
+}
+
 static struct fb_tile_ops arkfb_tile_ops = {
        .fb_settile     = arkfb_settile,
        .fb_tilecopy    = svga_tilecopy,
        .fb_tilefill    = svga_tilefill,
        .fb_tileblit    = svga_tileblit,
-       .fb_tilecursor  = svga_tilecursor,
+       .fb_tilecursor  = arkfb_tilecursor,
        .fb_get_tilemax = svga_get_tilemax,
 };
 
@@ -466,32 +473,40 @@ static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
 
 static void ark_dac_read_regs(void *data, u8 *code, int count)
 {
-       u8 regval = vga_rseq(NULL, 0x1C);
+       struct fb_info *info = data;
+       struct arkfb_info *par;
+       u8 regval;
 
+       par = info->par;
+       regval = vga_rseq(par->state.vgabase, 0x1C);
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
-               code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+               vga_wseq(par->state.vgabase, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
+               code[1] = vga_r(par->state.vgabase, dac_regs[code[0] & 3]);
                count--;
                code += 2;
        }
 
-       vga_wseq(NULL, 0x1C, regval);
+       vga_wseq(par->state.vgabase, 0x1C, regval);
 }
 
 static void ark_dac_write_regs(void *data, u8 *code, int count)
 {
-       u8 regval = vga_rseq(NULL, 0x1C);
+       struct fb_info *info = data;
+       struct arkfb_info *par;
+       u8 regval;
 
+       par = info->par;
+       regval = vga_rseq(par->state.vgabase, 0x1C);
        while (count != 0)
        {
-               vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
-               vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+               vga_wseq(par->state.vgabase, 0x1C, regval | (code[0] & 4 ? 0x80 : 0));
+               vga_w(par->state.vgabase, dac_regs[code[0] & 3], code[1]);
                count--;
                code += 2;
        }
 
-       vga_wseq(NULL, 0x1C, regval);
+       vga_wseq(par->state.vgabase, 0x1C, regval);
 }
 
 
@@ -507,8 +522,8 @@ static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
        }
 
        /* Set VGA misc register  */
-       regval = vga_r(NULL, VGA_MIS_R);
-       vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+       regval = vga_r(par->state.vgabase, VGA_MIS_R);
+       vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
 }
 
 
@@ -520,7 +535,10 @@ static int arkfb_open(struct fb_info *info, int user)
 
        mutex_lock(&(par->open_lock));
        if (par->ref_count == 0) {
+               void __iomem *vgabase = par->state.vgabase;
+
                memset(&(par->state), 0, sizeof(struct vgastate));
+               par->state.vgabase = vgabase;
                par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
                par->state.num_crtc = 0x60;
                par->state.num_seq = 0x30;
@@ -646,50 +664,50 @@ static int arkfb_set_par(struct fb_info *info)
        info->var.activate = FB_ACTIVATE_NOW;
 
        /* Unlock registers */
-       svga_wcrt_mask(0x11, 0x00, 0x80);
+       svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
 
        /* Blank screen and turn off sync */
-       svga_wseq_mask(0x01, 0x20, 0x20);
-       svga_wcrt_mask(0x17, 0x00, 0x80);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
 
        /* Set default values */
-       svga_set_default_gfx_regs();
-       svga_set_default_atc_regs();
-       svga_set_default_seq_regs();
-       svga_set_default_crt_regs();
-       svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
-       svga_wcrt_multi(ark_start_address_regs, 0);
+       svga_set_default_gfx_regs(par->state.vgabase);
+       svga_set_default_atc_regs(par->state.vgabase);
+       svga_set_default_seq_regs(par->state.vgabase);
+       svga_set_default_crt_regs(par->state.vgabase);
+       svga_wcrt_multi(par->state.vgabase, ark_line_compare_regs, 0xFFFFFFFF);
+       svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, 0);
 
        /* ARK specific initialization */
-       svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
-       svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+       svga_wseq_mask(par->state.vgabase, 0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+       svga_wseq_mask(par->state.vgabase, 0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
 
-       vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
-       vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
-       vga_wseq(NULL, 0x15, 0);
-       vga_wseq(NULL, 0x16, 0);
+       vga_wseq(par->state.vgabase, 0x13, info->fix.smem_start >> 16);
+       vga_wseq(par->state.vgabase, 0x14, info->fix.smem_start >> 24);
+       vga_wseq(par->state.vgabase, 0x15, 0);
+       vga_wseq(par->state.vgabase, 0x16, 0);
 
        /* Set the FIFO threshold register */
        /* It is fascinating way to store 5-bit value in 8-bit register */
        regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
-       vga_wseq(NULL, 0x18, regval);
+       vga_wseq(par->state.vgabase, 0x18, regval);
 
        /* Set the offset register */
        pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
-       svga_wcrt_multi(ark_offset_regs, offset_value);
+       svga_wcrt_multi(par->state.vgabase, ark_offset_regs, offset_value);
 
        /* fix for hi-res textmode */
-       svga_wcrt_mask(0x40, 0x08, 0x08);
+       svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08);
 
        if (info->var.vmode & FB_VMODE_DOUBLE)
-               svga_wcrt_mask(0x09, 0x80, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80);
        else
-               svga_wcrt_mask(0x09, 0x00, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80);
 
        if (info->var.vmode & FB_VMODE_INTERLACED)
-               svga_wcrt_mask(0x44, 0x04, 0x04);
+               svga_wcrt_mask(par->state.vgabase, 0x44, 0x04, 0x04);
        else
-               svga_wcrt_mask(0x44, 0x00, 0x04);
+               svga_wcrt_mask(par->state.vgabase, 0x44, 0x00, 0x04);
 
        hmul = 1;
        hdiv = 1;
@@ -699,40 +717,40 @@ static int arkfb_set_par(struct fb_info *info)
        switch (mode) {
        case 0:
                pr_debug("fb%d: text mode\n", info->node);
-               svga_set_textmode_vga_regs();
+               svga_set_textmode_vga_regs(par->state.vgabase);
 
-               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
-               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */
                dac_set_mode(par->dac, DAC_PSEUDO8_8);
 
                break;
        case 1:
                pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
-               vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+               vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
 
-               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
-               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */
                dac_set_mode(par->dac, DAC_PSEUDO8_8);
                break;
        case 2:
                pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
-               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */
                dac_set_mode(par->dac, DAC_PSEUDO8_8);
                break;
        case 3:
                pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+               vga_wseq(par->state.vgabase, 0x11, 0x16); /* 8bpp accel mode */
 
                if (info->var.pixclock > 20000) {
                        pr_debug("fb%d: not using multiplex\n", info->node);
-                       svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+                       svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */
                        dac_set_mode(par->dac, DAC_PSEUDO8_8);
                } else {
                        pr_debug("fb%d: using multiplex\n", info->node);
-                       svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+                       svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */
                        dac_set_mode(par->dac, DAC_PSEUDO8_16);
                        hdiv = 2;
                }
@@ -740,22 +758,22 @@ static int arkfb_set_par(struct fb_info *info)
        case 4:
                pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
-               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x1A); /* 16bpp accel mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */
                dac_set_mode(par->dac, DAC_RGB1555_16);
                break;
        case 5:
                pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
-               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x1A); /* 16bpp accel mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */
                dac_set_mode(par->dac, DAC_RGB0565_16);
                break;
        case 6:
                pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
-               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x16); /* 8bpp accel mode ??? */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */
                dac_set_mode(par->dac, DAC_RGB0888_16);
                hmul = 3;
                hdiv = 2;
@@ -763,8 +781,8 @@ static int arkfb_set_par(struct fb_info *info)
        case 7:
                pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
 
-               vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
-               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               vga_wseq(par->state.vgabase, 0x11, 0x1E); /* 32bpp accel mode */
+               svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */
                dac_set_mode(par->dac, DAC_RGB8888_16);
                hmul = 2;
                break;
@@ -774,7 +792,7 @@ static int arkfb_set_par(struct fb_info *info)
        }
 
        ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
-       svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+       svga_set_timings(par->state.vgabase, &ark_timing_regs, &(info->var), hmul, hdiv,
                         (info->var.vmode & FB_VMODE_DOUBLE)     ? 2 : 1,
                         (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
                          hmul, info->node);
@@ -782,12 +800,12 @@ static int arkfb_set_par(struct fb_info *info)
        /* Set interlaced mode start/end register */
        value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
        value = ((value * hmul / hdiv) / 8) - 5;
-       vga_wcrt(NULL, 0x42, (value + 1) / 2);
+       vga_wcrt(par->state.vgabase, 0x42, (value + 1) / 2);
 
        memset_io(info->screen_base, 0x00, screen_size);
        /* Device and screen back on */
-       svga_wcrt_mask(0x17, 0x80, 0x80);
-       svga_wseq_mask(0x01, 0x00, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
 
        return 0;
 }
@@ -857,23 +875,25 @@ static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
 static int arkfb_blank(int blank_mode, struct fb_info *info)
 {
+       struct arkfb_info *par = info->par;
+
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
                pr_debug("fb%d: unblank\n", info->node);
-               svga_wseq_mask(0x01, 0x00, 0x20);
-               svga_wcrt_mask(0x17, 0x80, 0x80);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
                break;
        case FB_BLANK_NORMAL:
                pr_debug("fb%d: blank\n", info->node);
-               svga_wseq_mask(0x01, 0x20, 0x20);
-               svga_wcrt_mask(0x17, 0x80, 0x80);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
                break;
        case FB_BLANK_POWERDOWN:
        case FB_BLANK_HSYNC_SUSPEND:
        case FB_BLANK_VSYNC_SUSPEND:
                pr_debug("fb%d: sync down\n", info->node);
-               svga_wseq_mask(0x01, 0x20, 0x20);
-               svga_wcrt_mask(0x17, 0x00, 0x80);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
                break;
        }
        return 0;
@@ -884,6 +904,7 @@ static int arkfb_blank(int blank_mode, struct fb_info *info)
 
 static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+       struct arkfb_info *par = info->par;
        unsigned int offset;
 
        /* Calculate the offset */
@@ -897,7 +918,7 @@ static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info
        }
 
        /* Set the offset */
-       svga_wcrt_multi(ark_start_address_regs, offset);
+       svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, offset);
 
        return 0;
 }
@@ -930,6 +951,8 @@ static struct fb_ops arkfb_ops = {
 /* PCI probe */
 static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
+       struct pci_bus_region bus_reg;
+       struct resource vga_res;
        struct fb_info *info;
        struct arkfb_info *par;
        int rc;
@@ -985,8 +1008,17 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_
                goto err_iomap;
        }
 
+       bus_reg.start = 0;
+       bus_reg.end = 64 * 1024;
+
+       vga_res.flags = IORESOURCE_IO;
+
+       pcibios_bus_to_resource(dev, &vga_res, &bus_reg);
+
+       par->state.vgabase = (void __iomem *) vga_res.start;
+
        /* FIXME get memsize */
-       regval = vga_rseq(NULL, 0x10);
+       regval = vga_rseq(par->state.vgabase, 0x10);
        info->screen_size = (1 << (regval >> 6)) << 20;
        info->fix.smem_len = info->screen_size;
 
index bac1634502167bbac687fe49eec161e903fead35..ccecf99745873327b1c373d677e8f0b2e49921c1 100644 (file)
@@ -68,7 +68,7 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
 }
 #endif
 
-static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
                | ATMEL_LCDC_POL_POSITIVE
                | ATMEL_LCDC_ENA_PWMENABLE;
 
@@ -127,6 +127,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
                return;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 0xff;
        bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
                                       &atmel_lcdc_bl_ops, &props);
@@ -163,6 +164,10 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
 
 static void init_contrast(struct atmel_lcdfb_info *sinfo)
 {
+       /* contrast pwm can be 'inverted' */
+       if (sinfo->lcdcon_pol_negative)
+                       contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+
        /* have some default contrast/backlight settings */
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
@@ -710,11 +715,35 @@ static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
        return 0;
 }
 
+static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+       case FB_BLANK_NORMAL:
+               atmel_lcdfb_start(sinfo);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+               break;
+       case FB_BLANK_POWERDOWN:
+               atmel_lcdfb_stop(sinfo);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* let fbcon do a soft blank for us */
+       return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
+}
+
 static struct fb_ops atmel_lcdfb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = atmel_lcdfb_check_var,
        .fb_set_par     = atmel_lcdfb_set_par,
        .fb_setcolreg   = atmel_lcdfb_setcolreg,
+       .fb_blank       = atmel_lcdfb_blank,
        .fb_pan_display = atmel_lcdfb_pan_display,
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
@@ -816,6 +845,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
                sinfo->guard_time = pdata_sinfo->guard_time;
                sinfo->smem_len = pdata_sinfo->smem_len;
                sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+               sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
                sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
        } else {
                dev_err(dev, "cannot get default configuration\n");
index 4cb6a576c5672ea1576ed12c80fc46fbacbff8c8..b0b2ac335347c7c1c9c311c6569a38139117d823 100644 (file)
@@ -1818,6 +1818,7 @@ static void aty128_bl_init(struct aty128fb_par *par)
        snprintf(name, sizeof(name), "aty128bl%d", info->node);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, info->dev, par, &aty128_bl_data,
                                       &props);
index 94e293fce1d2c8f6eb66f6fc03e44064eb270e0d..d437b3daf1f5f08b39172048f44e6c2c7510ffca 100644 (file)
@@ -2241,6 +2241,7 @@ static void aty_bl_init(struct atyfb_par *par)
        snprintf(name, sizeof(name), "atybl%d", info->node);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, info->dev, par, &aty_bl_data,
                                       &props);
index 9b811ddbce83853207d24903854d81bf5bc630e5..db572df7e1ef0fddd4d267523bf29daef6584f03 100644 (file)
@@ -158,6 +158,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
        snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, rinfo->info->dev, pdata,
                                       &radeon_bl_data, &props);
index 3c1e13ed1cba2041ae76e30bf6fe3cf7894056cb..32f8cf6200a7533ce7bce35a4896fcdb4ff7946b 100644 (file)
@@ -1248,7 +1248,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
 
        /* Workaround from XFree */
        if (rinfo->is_mobility) {
-               /* A temporal workaround for the occational blanking on certain laptop
+               /* A temporal workaround for the occasional blanking on certain laptop
                 * panels. This appears to related to the PLL divider registers
                 * (fail to lock?). It occurs even when all dividers are the same
                 * with their old settings. In this case we really don't need to
index 78d1f4cd1fe098b1e970a9f0f52e41899880ba0b..ab1d0fd7631630ef2cfdd0fc5c5022a08284aec6 100644 (file)
@@ -100,6 +100,9 @@ void radeon_create_i2c_busses(struct radeonfb_info *rinfo)
 {
        rinfo->i2c[0].rinfo     = rinfo;
        rinfo->i2c[0].ddc_reg   = GPIO_MONID;
+#ifndef CONFIG_PPC
+       rinfo->i2c[0].adapter.class = I2C_CLASS_HWMON;
+#endif
        radeon_setup_i2c_bus(&rinfo->i2c[0], "monid");
 
        rinfo->i2c[1].rinfo     = rinfo;
index b224396b86d56ce0f63ecd765b14e6e59d010fd0..c8b520e9a11ae3ec3005311eaae9550d1660cac9 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/backlight.h>
+#include <linux/mfd/core.h>
 #include <linux/mfd/88pm860x.h>
-#include <linux/slab.h>
 
 #define MAX_BRIGHTNESS         (0xFF)
 #define MIN_BRIGHTNESS         (0)
@@ -161,32 +162,13 @@ static const struct backlight_ops pm860x_backlight_ops = {
        .get_brightness = pm860x_backlight_get_brightness,
 };
 
-static int __check_device(struct pm860x_backlight_pdata *pdata, char *name)
-{
-       struct pm860x_backlight_pdata *p = pdata;
-       int ret = -EINVAL;
-
-       while (p && p->id) {
-               if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0))
-                       break;
-
-               if (!strncmp(name, pm860x_backlight_name[p->flags],
-                       MFD_NAME_SIZE)) {
-                       ret = (int)p->flags;
-                       break;
-               }
-               p++;
-       }
-       return ret;
-}
-
 static int pm860x_backlight_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct pm860x_platform_data *pm860x_pdata;
        struct pm860x_backlight_pdata *pdata = NULL;
        struct pm860x_backlight_data *data;
        struct backlight_device *bl;
+       struct mfd_cell *cell;
        struct resource *res;
        struct backlight_properties props;
        unsigned char value;
@@ -199,10 +181,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (pdev->dev.parent->platform_data) {
-               pm860x_pdata = pdev->dev.parent->platform_data;
-               pdata = pm860x_pdata->backlight;
-       }
+       cell = pdev->dev.platform_data;
+       if (cell == NULL)
+               return -ENODEV;
+       pdata = cell->mfd_data;
        if (pdata == NULL) {
                dev_err(&pdev->dev, "platform data isn't assigned to "
                        "backlight\n");
@@ -219,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        data->current_brightness = MAX_BRIGHTNESS;
        data->pwm = pdata->pwm;
        data->iset = pdata->iset;
-       data->port = __check_device(pdata, name);
+       data->port = pdata->flags;
        if (data->port < 0) {
                dev_err(&pdev->dev, "wrong platform data is assigned");
                kfree(data);
@@ -227,6 +209,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = MAX_BRIGHTNESS;
        bl = backlight_device_register(name, &pdev->dev, data,
                                        &pm860x_backlight_ops, &props);
index e54a337227ea964c5c6fea4c9bd32fdb5ced97a0..0c9373bedd1f39d61d8b391bcc54a630d6d981c8 100644 (file)
@@ -109,6 +109,14 @@ config LCD_S6E63M0
          If you have an S6E63M0 LCD Panel, say Y to enable its
          LCD control driver.
 
+config LCD_LD9040
+       tristate "LD9040 AMOLED LCD Driver"
+       depends on SPI && BACKLIGHT_CLASS_DEVICE
+       default n
+       help
+         If you have an LD9040 Panel, say Y to enable its
+         control driver.
+
 endif # LCD_CLASS_DEVICE
 
 #
@@ -236,12 +244,12 @@ config BACKLIGHT_MAX8925
          If you have a LCD backlight connected to the WLED output of MAX8925
          WLED output, say Y here to enable this driver.
 
-config BACKLIGHT_MBP_NVIDIA
-       tristate "MacBook Pro Nvidia Backlight Driver"
-       depends on X86
+config BACKLIGHT_APPLE
+       tristate "Apple Backlight Driver"
+       depends on X86 && ACPI
        help
-         If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
-        to enable a driver for its backlight
+         If you have an Intel-based Apple say Y to enable a driver for its
+        backlight.
 
 config BACKLIGHT_TOSA
        tristate "Sharp SL-6000 Backlight Driver"
index 44c0f81ad85d96c731e1bfe3f1a2068c37f3484c..b9ca8490df87850dc746e5a4661b67f5294589a4 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_LCD_VGG2432A4)      += vgg2432a4.o
 obj-$(CONFIG_LCD_TDO24M)          += tdo24m.o
 obj-$(CONFIG_LCD_TOSA)            += tosa_lcd.o
 obj-$(CONFIG_LCD_S6E63M0)      += s6e63m0.o
+obj-$(CONFIG_LCD_LD9040)       += ld9040.o
 
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
@@ -26,7 +27,7 @@ obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
 obj-$(CONFIG_BACKLIGHT_PWM)    += pwm_bl.o
 obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)        += max8925_bl.o
-obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
+obj-$(CONFIG_BACKLIGHT_APPLE)  += apple_bl.o
 obj-$(CONFIG_BACKLIGHT_TOSA)   += tosa_bl.o
 obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
index 9f436e014f85b3e809198f37e42d8b57cc387fe1..af3119707dbfe2a65b4f9a9da2e9eadee6e5360d 100644 (file)
@@ -303,6 +303,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
        mutex_init(&data->lock);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = ADP5020_MAX_BRIGHTNESS;
        bl = backlight_device_register(pdev->name, data->master, data,
                                       &adp5520_bl_ops, &props);
index 734c650a47c433be7524e27b35b5e3c5b5eea0ad..d2a96a421ffda737048ea7e30169ecfbb9a71d65 100644 (file)
@@ -709,6 +709,7 @@ static int __devinit adp8860_probe(struct i2c_client *client,
        i2c_set_clientdata(client, data);
 
        memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = ADP8860_MAX_BRIGHTNESS;
 
        mutex_init(&data->lock);
index fe9af129c5dd1cb969ea0e0cf418a7b66d5db3b2..c861c41af4423382e42692ce4108e31a44cecf8a 100644 (file)
@@ -104,6 +104,7 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 0xff;
        bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
                                          bl, &adx_backlight_ops, &props);
diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
new file mode 100644 (file)
index 0000000..be98d15
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  Backlight Driver for Intel-based Apples
+ *
+ *  Copyright (c) Red Hat <mjg@redhat.com>
+ *  Based on code from Pommed:
+ *  Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch>
+ *  Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
+ *  Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
+ *
+ *  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 driver triggers SMIs which cause the firmware to change the
+ *  backlight brightness. This is icky in many ways, but it's impractical to
+ *  get at the firmware code in order to figure out what it's actually doing.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+
+static struct backlight_device *apple_backlight_device;
+
+struct hw_data {
+       /* I/O resource to allocate. */
+       unsigned long iostart;
+       unsigned long iolen;
+       /* Backlight operations structure. */
+       const struct backlight_ops backlight_ops;
+       void (*set_brightness)(int);
+};
+
+static const struct hw_data *hw_data;
+
+#define DRIVER "apple_backlight: "
+
+/* Module parameters. */
+static int debug;
+module_param_named(debug, debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
+
+/*
+ * Implementation for machines with Intel chipset.
+ */
+static void intel_chipset_set_brightness(int intensity)
+{
+       outb(0x04 | (intensity << 4), 0xb3);
+       outb(0xbf, 0xb2);
+}
+
+static int intel_chipset_send_intensity(struct backlight_device *bd)
+{
+       int intensity = bd->props.brightness;
+
+       if (debug)
+               printk(KERN_DEBUG DRIVER "setting brightness to %d\n",
+                      intensity);
+
+       intel_chipset_set_brightness(intensity);
+       return 0;
+}
+
+static int intel_chipset_get_intensity(struct backlight_device *bd)
+{
+       int intensity;
+
+       outb(0x03, 0xb3);
+       outb(0xbf, 0xb2);
+       intensity = inb(0xb3) >> 4;
+
+       if (debug)
+               printk(KERN_DEBUG DRIVER "read brightness of %d\n",
+                      intensity);
+
+       return intensity;
+}
+
+static const struct hw_data intel_chipset_data = {
+       .iostart = 0xb2,
+       .iolen = 2,
+       .backlight_ops  = {
+               .options        = BL_CORE_SUSPENDRESUME,
+               .get_brightness = intel_chipset_get_intensity,
+               .update_status  = intel_chipset_send_intensity,
+       },
+       .set_brightness = intel_chipset_set_brightness,
+};
+
+/*
+ * Implementation for machines with Nvidia chipset.
+ */
+static void nvidia_chipset_set_brightness(int intensity)
+{
+       outb(0x04 | (intensity << 4), 0x52f);
+       outb(0xbf, 0x52e);
+}
+
+static int nvidia_chipset_send_intensity(struct backlight_device *bd)
+{
+       int intensity = bd->props.brightness;
+
+       if (debug)
+               printk(KERN_DEBUG DRIVER "setting brightness to %d\n",
+                      intensity);
+
+       nvidia_chipset_set_brightness(intensity);
+       return 0;
+}
+
+static int nvidia_chipset_get_intensity(struct backlight_device *bd)
+{
+       int intensity;
+
+       outb(0x03, 0x52f);
+       outb(0xbf, 0x52e);
+       intensity = inb(0x52f) >> 4;
+
+       if (debug)
+               printk(KERN_DEBUG DRIVER "read brightness of %d\n",
+                      intensity);
+
+       return intensity;
+}
+
+static const struct hw_data nvidia_chipset_data = {
+       .iostart = 0x52e,
+       .iolen = 2,
+       .backlight_ops          = {
+               .options        = BL_CORE_SUSPENDRESUME,
+               .get_brightness = nvidia_chipset_get_intensity,
+               .update_status  = nvidia_chipset_send_intensity
+       },
+       .set_brightness = nvidia_chipset_set_brightness,
+};
+
+static int __devinit apple_bl_add(struct acpi_device *dev)
+{
+       struct backlight_properties props;
+       struct pci_dev *host;
+       int intensity;
+
+       host = pci_get_bus_and_slot(0, 0);
+
+       if (!host) {
+               printk(KERN_ERR DRIVER "unable to find PCI host\n");
+               return -ENODEV;
+       }
+
+       if (host->vendor == PCI_VENDOR_ID_INTEL)
+               hw_data = &intel_chipset_data;
+       else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
+               hw_data = &nvidia_chipset_data;
+
+       pci_dev_put(host);
+
+       if (!hw_data) {
+               printk(KERN_ERR DRIVER "unknown hardware\n");
+               return -ENODEV;
+       }
+
+       /* Check that the hardware responds - this may not work under EFI */
+
+       intensity = hw_data->backlight_ops.get_brightness(NULL);
+
+       if (!intensity) {
+               hw_data->set_brightness(1);
+               if (!hw_data->backlight_ops.get_brightness(NULL))
+                       return -ENODEV;
+
+               hw_data->set_brightness(0);
+       }
+
+       if (!request_region(hw_data->iostart, hw_data->iolen,
+                           "Apple backlight"))
+               return -ENXIO;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
+       props.max_brightness = 15;
+       apple_backlight_device = backlight_device_register("apple_backlight",
+                                 NULL, NULL, &hw_data->backlight_ops, &props);
+
+       if (IS_ERR(apple_backlight_device)) {
+               release_region(hw_data->iostart, hw_data->iolen);
+               return PTR_ERR(apple_backlight_device);
+       }
+
+       apple_backlight_device->props.brightness =
+               hw_data->backlight_ops.get_brightness(apple_backlight_device);
+       backlight_update_status(apple_backlight_device);
+
+       return 0;
+}
+
+static int __devexit apple_bl_remove(struct acpi_device *dev, int type)
+{
+       backlight_device_unregister(apple_backlight_device);
+
+       release_region(hw_data->iostart, hw_data->iolen);
+       hw_data = NULL;
+       return 0;
+}
+
+static const struct acpi_device_id apple_bl_ids[] = {
+       {"APP0002", 0},
+       {"", 0},
+};
+
+static struct acpi_driver apple_bl_driver = {
+       .name = "Apple backlight",
+       .ids = apple_bl_ids,
+       .ops = {
+               .add = apple_bl_add,
+               .remove = apple_bl_remove,
+       },
+};
+
+static int __init apple_bl_init(void)
+{
+       return acpi_bus_register_driver(&apple_bl_driver);
+}
+
+static void __exit apple_bl_exit(void)
+{
+       acpi_bus_unregister_driver(&apple_bl_driver);
+}
+
+module_init(apple_bl_init);
+module_exit(apple_bl_exit);
+
+MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
+MODULE_DESCRIPTION("Apple Backlight Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(acpi, apple_bl_ids);
+MODULE_ALIAS("mbp_nvidia_bl");
index e6a66dab088c10a697f438625651d6d17f2aed4c..0443a4f718580c4381acf7d5cb538e941b7e2aa5 100644 (file)
@@ -168,6 +168,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
        bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl,
                                          &atmel_pwm_bl_ops, &props);
index 08703299ef61184bf3e0cd212601f2817e9e8e63..80d292fb92d8a3c10825130867dbdc55b586f939 100644 (file)
 #include <asm/backlight.h>
 #endif
 
+static const char const *backlight_types[] = {
+       [BACKLIGHT_RAW] = "raw",
+       [BACKLIGHT_PLATFORM] = "platform",
+       [BACKLIGHT_FIRMWARE] = "firmware",
+};
+
 #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
                           defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
 /* This callback gets called when something important happens inside a
@@ -169,6 +175,14 @@ static ssize_t backlight_store_brightness(struct device *dev,
        return rc;
 }
 
+static ssize_t backlight_show_type(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct backlight_device *bd = to_backlight_device(dev);
+
+       return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
+}
+
 static ssize_t backlight_show_max_brightness(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -234,6 +248,7 @@ static struct device_attribute bl_device_attributes[] = {
        __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
                     NULL),
        __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+       __ATTR(type, 0444, backlight_show_type, NULL),
        __ATTR_NULL,
 };
 
@@ -292,9 +307,16 @@ struct backlight_device *backlight_device_register(const char *name,
        dev_set_drvdata(&new_bd->dev, devdata);
 
        /* Set default properties */
-       if (props)
+       if (props) {
                memcpy(&new_bd->props, props,
                       sizeof(struct backlight_properties));
+               if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {
+                       WARN(1, "%s: invalid backlight type", name);
+                       new_bd->props.type = BACKLIGHT_RAW;
+               }
+       } else {
+               new_bd->props.type = BACKLIGHT_RAW;
+       }
 
        rc = device_register(&new_bd->dev);
        if (rc) {
index 1e71c35083bb4ca8505031efeee5db036a2a2c51..af6098396fe6d067d17a40e439c56ba254a72ab5 100644 (file)
@@ -562,6 +562,7 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi)
        lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = pdata->max_intensity;
        lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd,
                                                &corgi_bl_ops, &props);
index 397d15eb1ea8aee3d4fe870ae87f8b14f161654f..6c8c54041fae84f7bb33faf084e3ec9ff932f081 100644 (file)
@@ -193,6 +193,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        }
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL,
                                        &cr_backlight_ops, &props);
        if (IS_ERR(bdp)) {
index 87659ed79bd7aa3eae7cc1fafd6e12e8cad79e25..62043f12a5a4845d35ee4d338693ed23193c7d36 100644 (file)
@@ -136,6 +136,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
                da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
                                DA9034_WLED_ISET(pdata->output_current));
 
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = max_brightness;
        bl = backlight_device_register(pdev->name, data->da903x_dev, data,
                                       &da903x_backlight_ops, &props);
index b0cc49184803344c11f8802a9ce147ec61c072fe..9f1e389d51d2f8fac9337bf6be305705b2fd6b07 100644 (file)
@@ -87,6 +87,7 @@ static int __init ep93xxbl_probe(struct platform_device *dev)
        ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = EP93XX_MAX_BRIGHT;
        bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
                                       &ep93xxbl_ops, &props);
index 312ca619735d4dcafa4a0bb70294be13fe5081db..8c6befd65a33240ceed7da9f2a784a463b5f0381 100644 (file)
@@ -91,6 +91,7 @@ static int genericbl_probe(struct platform_device *pdev)
                name = machinfo->name;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = machinfo->max_intensity;
        bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops,
                                       &props);
index 267d23f8d645fc889d7f5faace0d951e93ae41c0..38aa002721416d2b195f6673f610216b5f77527e 100644 (file)
@@ -109,6 +109,7 @@ static int __devinit hp680bl_probe(struct platform_device *pdev)
        struct backlight_device *bd;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = HP680_MAX_INTENSITY;
        bd = backlight_device_register("hp680-bl", &pdev->dev, NULL,
                                       &hp680bl_ops, &props);
index 2f177b3a4885c1658685712703d266184b5b35ed..de65d80159beed3b90b21313070538b42c3ee4aa 100644 (file)
@@ -106,6 +106,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
        struct backlight_device *bd;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = BL_MAX_BRIGHT;
        bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
                                       &jornada_bl_ops, &props);
@@ -146,12 +147,12 @@ static struct platform_driver jornada_bl_driver = {
        },
 };
 
-int __init jornada_bl_init(void)
+static int __init jornada_bl_init(void)
 {
        return platform_driver_register(&jornada_bl_driver);
 }
 
-void __exit jornada_bl_exit(void)
+static void __exit jornada_bl_exit(void)
 {
        platform_driver_unregister(&jornada_bl_driver);
 }
index cbbb167fd268fd4bc4751b181037f2c5de62144c..d2ff658b4144f91cf6d10a6e04f5178822db26f8 100644 (file)
@@ -135,12 +135,12 @@ static struct platform_driver jornada_lcd_driver = {
        },
 };
 
-int __init jornada_lcd_init(void)
+static int __init jornada_lcd_init(void)
 {
        return platform_driver_register(&jornada_lcd_driver);
 }
 
-void __exit jornada_lcd_exit(void)
+static void __exit jornada_lcd_exit(void)
 {
        platform_driver_unregister(&jornada_lcd_driver);
 }
index f439a863228755d22621f57b4ecb384327ab3966..72dd5556a35bdbe825f4fb86033f82828f206bc3 100644 (file)
@@ -149,6 +149,7 @@ static int kb3886bl_probe(struct platform_device *pdev)
                machinfo->limit_mask = -1;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = machinfo->max_intensity;
        kb3886_backlight_device = backlight_device_register("kb3886-bl",
                                                            &pdev->dev, NULL,
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c
new file mode 100644 (file)
index 0000000..7281b25
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * ld9040 AMOLED LCD panel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * Author: Donghwa Lee  <dh09.lee@samsung.com>
+ * Derived from drivers/video/backlight/s6e63m0.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+
+#include "ld9040_gamma.h"
+
+#define SLEEPMSEC              0x1000
+#define ENDDEF                 0x2000
+#define        DEFMASK                 0xFF00
+#define COMMAND_ONLY           0xFE
+#define DATA_ONLY              0xFF
+
+#define MIN_BRIGHTNESS         0
+#define MAX_BRIGHTNESS         24
+#define power_is_on(pwr)       ((pwr) <= FB_BLANK_NORMAL)
+
+struct ld9040 {
+       struct device                   *dev;
+       struct spi_device               *spi;
+       unsigned int                    power;
+       unsigned int                    current_brightness;
+
+       struct lcd_device               *ld;
+       struct backlight_device         *bd;
+       struct lcd_platform_data        *lcd_pd;
+};
+
+static const unsigned short seq_swreset[] = {
+       0x01, COMMAND_ONLY,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_user_setting[] = {
+       0xF0, 0x5A,
+
+       DATA_ONLY, 0x5A,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_elvss_on[] = {
+       0xB1, 0x0D,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x16,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gtcon[] = {
+       0xF7, 0x09,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_panel_condition[] = {
+       0xF8, 0x05,
+
+       DATA_ONLY, 0x65,
+       DATA_ONLY, 0x96,
+       DATA_ONLY, 0x71,
+       DATA_ONLY, 0x7D,
+       DATA_ONLY, 0x19,
+       DATA_ONLY, 0x3B,
+       DATA_ONLY, 0x0D,
+       DATA_ONLY, 0x19,
+       DATA_ONLY, 0x7E,
+       DATA_ONLY, 0x0D,
+       DATA_ONLY, 0xE2,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x7E,
+       DATA_ONLY, 0x7D,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x02,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_set1[] = {
+       0xF9, 0x00,
+
+       DATA_ONLY, 0xA7,
+       DATA_ONLY, 0xB4,
+       DATA_ONLY, 0xAE,
+       DATA_ONLY, 0xBF,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x91,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB2,
+       DATA_ONLY, 0xB4,
+       DATA_ONLY, 0xAA,
+       DATA_ONLY, 0xBB,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xAC,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB3,
+       DATA_ONLY, 0xB1,
+       DATA_ONLY, 0xAA,
+       DATA_ONLY, 0xBC,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB3,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_ctrl[] = {
+       0xFB, 0x02,
+
+       DATA_ONLY, 0x5A,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_start[] = {
+       0xF9, COMMAND_ONLY,
+
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_apon[] = {
+       0xF3, 0x00,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x0A,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_ctrl[] = {
+       0xF2, 0x02,
+
+       DATA_ONLY, 0x08,
+       DATA_ONLY, 0x08,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x10,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_manual_pwr[] = {
+       0xB0, 0x04,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_pwr_ctrl[] = {
+       0xF4, 0x0A,
+
+       DATA_ONLY, 0x87,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x6A,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x02,
+       DATA_ONLY, 0x88,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_sleep_out[] = {
+       0x11, COMMAND_ONLY,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_sleep_in[] = {
+       0x10, COMMAND_ONLY,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_on[] = {
+       0x29, COMMAND_ONLY,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_off[] = {
+       0x28, COMMAND_ONLY,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vci1_1st_en[] = {
+       0xF3, 0x10,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl1_en[] = {
+       0xF3, 0x11,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl2_en[] = {
+       0xF3, 0x13,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vci1_2nd_en[] = {
+       0xF3, 0x33,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl3_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vreg1_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x01,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vgh_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x11,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vgl_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x31,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vmos_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xB1,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vint_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xF1,
+       /* DATA_ONLY, 0x71,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vbh_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xF9,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_vbl_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFD,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gam_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_sd_amp_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x80,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_gls_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x81,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_els_en[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x83,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static const unsigned short seq_el_on[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x87,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+       ENDDEF, 0x00
+};
+
+static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data)
+{
+       u16 buf[1];
+       struct spi_message msg;
+
+       struct spi_transfer xfer = {
+               .len            = 2,
+               .tx_buf         = buf,
+       };
+
+       buf[0] = (addr << 8) | data;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       return spi_sync(lcd->spi, &msg);
+}
+
+static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address,
+       unsigned char command)
+{
+       int ret = 0;
+
+       if (address != DATA_ONLY)
+               ret = ld9040_spi_write_byte(lcd, 0x0, address);
+       if (command != COMMAND_ONLY)
+               ret = ld9040_spi_write_byte(lcd, 0x1, command);
+
+       return ret;
+}
+
+static int ld9040_panel_send_sequence(struct ld9040 *lcd,
+       const unsigned short *wbuf)
+{
+       int ret = 0, i = 0;
+
+       while ((wbuf[i] & DEFMASK) != ENDDEF) {
+               if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
+                       ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
+                       if (ret)
+                               break;
+               } else
+                       udelay(wbuf[i+1]*1000);
+               i += 2;
+       }
+
+       return ret;
+}
+
+static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma)
+{
+       unsigned int i = 0;
+       int ret = 0;
+
+       /* start gamma table updating. */
+       ret = ld9040_panel_send_sequence(lcd, seq_gamma_start);
+       if (ret) {
+               dev_err(lcd->dev, "failed to disable gamma table updating.\n");
+               goto gamma_err;
+       }
+
+       for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
+               ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]);
+               if (ret) {
+                       dev_err(lcd->dev, "failed to set gamma table.\n");
+                       goto gamma_err;
+               }
+       }
+
+       /* update gamma table. */
+       ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl);
+       if (ret)
+               dev_err(lcd->dev, "failed to update gamma table.\n");
+
+gamma_err:
+       return ret;
+}
+
+static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
+{
+       int ret = 0;
+
+       ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
+
+       return ret;
+}
+
+
+static int ld9040_ldi_init(struct ld9040 *lcd)
+{
+       int ret, i;
+       static const unsigned short *init_seq[] = {
+               seq_user_setting,
+               seq_panel_condition,
+               seq_display_ctrl,
+               seq_manual_pwr,
+               seq_elvss_on,
+               seq_gtcon,
+               seq_gamma_set1,
+               seq_gamma_ctrl,
+               seq_sleep_out,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+               ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
+               /* workaround: minimum delay time for transferring CMD */
+               udelay(300);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int ld9040_ldi_enable(struct ld9040 *lcd)
+{
+       int ret = 0;
+
+       ret = ld9040_panel_send_sequence(lcd, seq_display_on);
+
+       return ret;
+}
+
+static int ld9040_ldi_disable(struct ld9040 *lcd)
+{
+       int ret;
+
+       ret = ld9040_panel_send_sequence(lcd, seq_display_off);
+       ret = ld9040_panel_send_sequence(lcd, seq_sleep_in);
+
+       return ret;
+}
+
+static int ld9040_power_on(struct ld9040 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd = NULL;
+       pd = lcd->lcd_pd;
+       if (!pd) {
+               dev_err(lcd->dev, "platform data is NULL.\n");
+               return -EFAULT;
+       }
+
+       if (!pd->power_on) {
+               dev_err(lcd->dev, "power_on is NULL.\n");
+               return -EFAULT;
+       } else {
+               pd->power_on(lcd->ld, 1);
+               mdelay(pd->power_on_delay);
+       }
+
+       if (!pd->reset) {
+               dev_err(lcd->dev, "reset is NULL.\n");
+               return -EFAULT;
+       } else {
+               pd->reset(lcd->ld);
+               mdelay(pd->reset_delay);
+       }
+
+       ret = ld9040_ldi_init(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to initialize ldi.\n");
+               return ret;
+       }
+
+       ret = ld9040_ldi_enable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to enable ldi.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ld9040_power_off(struct ld9040 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd = NULL;
+
+       pd = lcd->lcd_pd;
+       if (!pd) {
+               dev_err(lcd->dev, "platform data is NULL.\n");
+               return -EFAULT;
+       }
+
+       ret = ld9040_ldi_disable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "lcd setting failed.\n");
+               return -EIO;
+       }
+
+       mdelay(pd->power_off_delay);
+
+       if (!pd->power_on) {
+               dev_err(lcd->dev, "power_on is NULL.\n");
+               return -EFAULT;
+       } else
+               pd->power_on(lcd->ld, 0);
+
+       return 0;
+}
+
+static int ld9040_power(struct ld9040 *lcd, int power)
+{
+       int ret = 0;
+
+       if (power_is_on(power) && !power_is_on(lcd->power))
+               ret = ld9040_power_on(lcd);
+       else if (!power_is_on(power) && power_is_on(lcd->power))
+               ret = ld9040_power_off(lcd);
+
+       if (!ret)
+               lcd->power = power;
+
+       return ret;
+}
+
+static int ld9040_set_power(struct lcd_device *ld, int power)
+{
+       struct ld9040 *lcd = lcd_get_data(ld);
+
+       if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+               power != FB_BLANK_NORMAL) {
+               dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+               return -EINVAL;
+       }
+
+       return ld9040_power(lcd, power);
+}
+
+static int ld9040_get_power(struct lcd_device *ld)
+{
+       struct ld9040 *lcd = lcd_get_data(ld);
+
+       return lcd->power;
+}
+
+static int ld9040_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int ld9040_set_brightness(struct backlight_device *bd)
+{
+       int ret = 0, brightness = bd->props.brightness;
+       struct ld9040 *lcd = bl_get_data(bd);
+
+       if (brightness < MIN_BRIGHTNESS ||
+               brightness > bd->props.max_brightness) {
+               dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
+                       MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+               return -EINVAL;
+       }
+
+       ret = ld9040_gamma_ctl(lcd, bd->props.brightness);
+       if (ret) {
+               dev_err(&bd->dev, "lcd brightness setting failed.\n");
+               return -EIO;
+       }
+
+       return ret;
+}
+
+static struct lcd_ops ld9040_lcd_ops = {
+       .set_power = ld9040_set_power,
+       .get_power = ld9040_get_power,
+};
+
+static const struct backlight_ops ld9040_backlight_ops  = {
+       .get_brightness = ld9040_get_brightness,
+       .update_status = ld9040_set_brightness,
+};
+
+
+static int ld9040_probe(struct spi_device *spi)
+{
+       int ret = 0;
+       struct ld9040 *lcd = NULL;
+       struct lcd_device *ld = NULL;
+       struct backlight_device *bd = NULL;
+
+       lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL);
+       if (!lcd)
+               return -ENOMEM;
+
+       /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
+       spi->bits_per_word = 9;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "spi setup failed.\n");
+               goto out_free_lcd;
+       }
+
+       lcd->spi = spi;
+       lcd->dev = &spi->dev;
+
+       lcd->lcd_pd = spi->dev.platform_data;
+       if (!lcd->lcd_pd) {
+               dev_err(&spi->dev, "platform data is NULL.\n");
+               goto out_free_lcd;
+       }
+
+       ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
+       if (IS_ERR(ld)) {
+               ret = PTR_ERR(ld);
+               goto out_free_lcd;
+       }
+
+       lcd->ld = ld;
+
+       bd = backlight_device_register("ld9040-bl", &spi->dev,
+               lcd, &ld9040_backlight_ops, NULL);
+       if (IS_ERR(ld)) {
+               ret = PTR_ERR(ld);
+               goto out_free_lcd;
+       }
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = MAX_BRIGHTNESS;
+       lcd->bd = bd;
+
+       /*
+        * if lcd panel was on from bootloader like u-boot then
+        * do not lcd on.
+        */
+       if (!lcd->lcd_pd->lcd_enabled) {
+               /*
+                * if lcd panel was off from bootloader then
+                * current lcd status is powerdown and then
+                * it enables lcd panel.
+                */
+               lcd->power = FB_BLANK_POWERDOWN;
+
+               ld9040_power(lcd, FB_BLANK_UNBLANK);
+       } else
+               lcd->power = FB_BLANK_UNBLANK;
+
+       dev_set_drvdata(&spi->dev, lcd);
+
+       dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
+       return 0;
+
+out_free_lcd:
+       kfree(lcd);
+       return ret;
+}
+
+static int __devexit ld9040_remove(struct spi_device *spi)
+{
+       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+       ld9040_power(lcd, FB_BLANK_POWERDOWN);
+       lcd_device_unregister(lcd->ld);
+       kfree(lcd);
+
+       return 0;
+}
+
+#if defined(CONFIG_PM)
+static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       int ret = 0;
+       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+       /*
+        * when lcd panel is suspend, lcd panel becomes off
+        * regardless of status.
+        */
+       ret = ld9040_power(lcd, FB_BLANK_POWERDOWN);
+
+       return ret;
+}
+
+static int ld9040_resume(struct spi_device *spi)
+{
+       int ret = 0;
+       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+       lcd->power = FB_BLANK_POWERDOWN;
+
+       ret = ld9040_power(lcd, FB_BLANK_UNBLANK);
+
+       return ret;
+}
+#else
+#define ld9040_suspend         NULL
+#define ld9040_resume          NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt. */
+static void ld9040_shutdown(struct spi_device *spi)
+{
+       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+       ld9040_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ld9040_driver = {
+       .driver = {
+               .name   = "ld9040",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ld9040_probe,
+       .remove         = __devexit_p(ld9040_remove),
+       .shutdown       = ld9040_shutdown,
+       .suspend        = ld9040_suspend,
+       .resume         = ld9040_resume,
+};
+
+static int __init ld9040_init(void)
+{
+       return spi_register_driver(&ld9040_driver);
+}
+
+static void __exit ld9040_exit(void)
+{
+       spi_unregister_driver(&ld9040_driver);
+}
+
+module_init(ld9040_init);
+module_exit(ld9040_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_DESCRIPTION("ld9040 LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h
new file mode 100644 (file)
index 0000000..038d9c8
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Gamma level definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _LD9040_BRIGHTNESS_H
+#define _LD9040_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL                25
+#define GAMMA_TABLE_COUNT      21
+
+/* gamma value: 2.2 */
+static const unsigned int ld9040_22_300[] = {
+       0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91,
+       0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac,
+       0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3
+};
+
+static const unsigned int ld9040_22_290[] = {
+       0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89,
+       0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4,
+       0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa
+};
+
+static const unsigned int ld9040_22_280[] = {
+       0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86,
+       0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0,
+       0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7
+};
+
+static const unsigned int ld9040_22_270[] = {
+       0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84,
+       0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d,
+       0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4
+
+};
+static const unsigned int ld9040_22_260[] = {
+       0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80,
+       0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a,
+       0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0
+};
+
+static const unsigned int ld9040_22_250[] = {
+       0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d,
+       0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97,
+       0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d
+};
+
+static const unsigned int ld9040_22_240[] = {
+       0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a,
+       0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94,
+       0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a
+};
+
+static const unsigned int ld9040_22_230[] = {
+       0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77,
+       0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90,
+       0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97
+};
+
+static const unsigned int ld9040_22_220[] = {
+       0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75,
+       0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e,
+       0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94
+};
+
+static const unsigned int ld9040_22_210[] = {
+       0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72,
+       0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a,
+       0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91
+};
+
+static const unsigned int ld9040_22_200[] = {
+       0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f,
+       0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86,
+       0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d
+};
+
+static const unsigned int ld9040_22_190[] = {
+       0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c,
+       0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82,
+       0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89
+};
+
+static const unsigned int ld9040_22_180[] = {
+       0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69,
+       0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f,
+       0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85
+};
+
+static const unsigned int ld9040_22_170[] = {
+       0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65,
+       0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a,
+       0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81
+};
+
+static const unsigned int ld9040_22_160[] = {
+       0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62,
+       0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76,
+       0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e
+};
+
+static const unsigned int ld9040_22_150[] = {
+       0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f,
+       0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72,
+       0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a
+};
+
+static const unsigned int ld9040_22_140[] = {
+       0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b,
+       0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e,
+       0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75
+};
+
+static const unsigned int ld9040_22_130[] = {
+       0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57,
+       0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a,
+       0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70
+};
+
+static const unsigned int ld9040_22_120[] = {
+       0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53,
+       0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65,
+       0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c
+};
+
+static const unsigned int ld9040_22_110[] = {
+       0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f,
+       0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60,
+       0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67
+};
+
+static const unsigned int ld9040_22_100[] = {
+       0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b,
+       0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c,
+       0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62
+};
+
+static const unsigned int ld9040_22_90[] = {
+       0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46,
+       0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56,
+       0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d
+};
+
+static const unsigned int ld9040_22_80[] = {
+       0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41,
+       0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51,
+       0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57
+};
+
+static const unsigned int ld9040_22_70[] = {
+       0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c,
+       0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b,
+       0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52
+};
+
+static const unsigned int ld9040_22_50[] = {
+       0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30,
+       0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d,
+       0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44
+};
+
+struct ld9040_gamma {
+       unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
+} gamma_table = {
+       .gamma_22_table[0] = (unsigned int *)&ld9040_22_50,
+       .gamma_22_table[1] = (unsigned int *)&ld9040_22_70,
+       .gamma_22_table[2] = (unsigned int *)&ld9040_22_80,
+       .gamma_22_table[3] = (unsigned int *)&ld9040_22_90,
+       .gamma_22_table[4] = (unsigned int *)&ld9040_22_100,
+       .gamma_22_table[5] = (unsigned int *)&ld9040_22_110,
+       .gamma_22_table[6] = (unsigned int *)&ld9040_22_120,
+       .gamma_22_table[7] = (unsigned int *)&ld9040_22_130,
+       .gamma_22_table[8] = (unsigned int *)&ld9040_22_140,
+       .gamma_22_table[9] = (unsigned int *)&ld9040_22_150,
+       .gamma_22_table[10] = (unsigned int *)&ld9040_22_160,
+       .gamma_22_table[11] = (unsigned int *)&ld9040_22_170,
+       .gamma_22_table[12] = (unsigned int *)&ld9040_22_180,
+       .gamma_22_table[13] = (unsigned int *)&ld9040_22_190,
+       .gamma_22_table[14] = (unsigned int *)&ld9040_22_200,
+       .gamma_22_table[15] = (unsigned int *)&ld9040_22_210,
+       .gamma_22_table[16] = (unsigned int *)&ld9040_22_220,
+       .gamma_22_table[17] = (unsigned int *)&ld9040_22_230,
+       .gamma_22_table[18] = (unsigned int *)&ld9040_22_240,
+       .gamma_22_table[19] = (unsigned int *)&ld9040_22_250,
+       .gamma_22_table[20] = (unsigned int *)&ld9040_22_260,
+       .gamma_22_table[21] = (unsigned int *)&ld9040_22_270,
+       .gamma_22_table[22] = (unsigned int *)&ld9040_22_280,
+       .gamma_22_table[23] = (unsigned int *)&ld9040_22_290,
+       .gamma_22_table[24] = (unsigned int *)&ld9040_22_300,
+};
+
+#endif
index d2f59015d517093b01a1901466b871a82c17a4b2..bbca3127071e3a380acce9a843c8b963361fc322 100644 (file)
@@ -184,6 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev)
        local_irq_restore(flags);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 4;
        locomolcd_bl_device = backlight_device_register("locomo-bl",
                                                        &ldev->dev, NULL,
index 209acc105cbcb440c4ed289c81a26f7b65ce0dfe..07e8e273ced0b98898e0509dcc1de30424142eda 100644 (file)
@@ -136,6 +136,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
        data->current_brightness = 0;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = MAX_BRIGHTNESS;
        bl = backlight_device_register(name, &pdev->dev, data,
                                        &max8925_backlight_ops, &props);
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
deleted file mode 100644 (file)
index 1485f73..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- *  Backlight Driver for Nvidia 8600 in Macbook Pro
- *
- *  Copyright (c) Red Hat <mjg@redhat.com>
- *  Based on code from Pommed:
- *  Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch>
- *  Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
- *  Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
- *
- *  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 driver triggers SMIs which cause the firmware to change the
- *  backlight brightness. This is icky in many ways, but it's impractical to
- *  get at the firmware code in order to figure out what it's actually doing.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/backlight.h>
-#include <linux/err.h>
-#include <linux/dmi.h>
-#include <linux/io.h>
-
-static struct backlight_device *mbp_backlight_device;
-
-/* Structure to be passed to the DMI_MATCH function. */
-struct dmi_match_data {
-       /* I/O resource to allocate. */
-       unsigned long iostart;
-       unsigned long iolen;
-       /* Backlight operations structure. */
-       const struct backlight_ops backlight_ops;
-};
-
-/* Module parameters. */
-static int debug;
-module_param_named(debug, debug, int, 0644);
-MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
-
-/*
- * Implementation for MacBooks with Intel chipset.
- */
-static int intel_chipset_send_intensity(struct backlight_device *bd)
-{
-       int intensity = bd->props.brightness;
-
-       if (debug)
-               printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
-                      intensity);
-
-       outb(0x04 | (intensity << 4), 0xb3);
-       outb(0xbf, 0xb2);
-       return 0;
-}
-
-static int intel_chipset_get_intensity(struct backlight_device *bd)
-{
-       int intensity;
-
-       outb(0x03, 0xb3);
-       outb(0xbf, 0xb2);
-       intensity = inb(0xb3) >> 4;
-
-       if (debug)
-               printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
-                      intensity);
-
-       return intensity;
-}
-
-static const struct dmi_match_data intel_chipset_data = {
-       .iostart = 0xb2,
-       .iolen = 2,
-       .backlight_ops  = {
-               .options        = BL_CORE_SUSPENDRESUME,
-               .get_brightness = intel_chipset_get_intensity,
-               .update_status  = intel_chipset_send_intensity,
-       }
-};
-
-/*
- * Implementation for MacBooks with Nvidia chipset.
- */
-static int nvidia_chipset_send_intensity(struct backlight_device *bd)
-{
-       int intensity = bd->props.brightness;
-
-       if (debug)
-               printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
-                      intensity);
-
-       outb(0x04 | (intensity << 4), 0x52f);
-       outb(0xbf, 0x52e);
-       return 0;
-}
-
-static int nvidia_chipset_get_intensity(struct backlight_device *bd)
-{
-       int intensity;
-
-       outb(0x03, 0x52f);
-       outb(0xbf, 0x52e);
-       intensity = inb(0x52f) >> 4;
-
-       if (debug)
-               printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
-                      intensity);
-
-       return intensity;
-}
-
-static const struct dmi_match_data nvidia_chipset_data = {
-       .iostart = 0x52e,
-       .iolen = 2,
-       .backlight_ops          = {
-               .options        = BL_CORE_SUSPENDRESUME,
-               .get_brightness = nvidia_chipset_get_intensity,
-               .update_status  = nvidia_chipset_send_intensity
-       }
-};
-
-/*
- * DMI matching.
- */
-static /* const */ struct dmi_match_data *driver_data;
-
-static int mbp_dmi_match(const struct dmi_system_id *id)
-{
-       driver_data = id->driver_data;
-
-       printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident);
-       return 1;
-}
-
-static const struct dmi_system_id __initdata mbp_device_table[] = {
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 1,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 2,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 3,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 4,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 4,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 1,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 1,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 2,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 2,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 3,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 3,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 4,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookAir 1,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"),
-               },
-               .driver_data    = (void *)&intel_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 5,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 5,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBook 6,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookAir 2,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 5,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 5,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 5,3",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 5,4",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookPro 5,5",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookAir 3,1",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       {
-               .callback       = mbp_dmi_match,
-               .ident          = "MacBookAir 3,2",
-               .matches        = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
-               },
-               .driver_data    = (void *)&nvidia_chipset_data,
-       },
-       { }
-};
-
-static int __init mbp_init(void)
-{
-       struct backlight_properties props;
-       if (!dmi_check_system(mbp_device_table))
-               return -ENODEV;
-
-       if (!request_region(driver_data->iostart, driver_data->iolen, 
-                                               "Macbook Pro backlight"))
-               return -ENXIO;
-
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.max_brightness = 15;
-       mbp_backlight_device = backlight_device_register("mbp_backlight", NULL,
-                                                        NULL,
-                                                        &driver_data->backlight_ops,
-                                                        &props);
-       if (IS_ERR(mbp_backlight_device)) {
-               release_region(driver_data->iostart, driver_data->iolen);
-               return PTR_ERR(mbp_backlight_device);
-       }
-
-       mbp_backlight_device->props.brightness =
-               driver_data->backlight_ops.get_brightness(mbp_backlight_device);
-       backlight_update_status(mbp_backlight_device);
-
-       return 0;
-}
-
-static void __exit mbp_exit(void)
-{
-       backlight_device_unregister(mbp_backlight_device);
-
-       release_region(driver_data->iostart, driver_data->iolen);
-}
-
-module_init(mbp_init);
-module_exit(mbp_exit);
-
-MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
-MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(dmi, mbp_device_table);
index d3bc56296c8d98007321a1cce4945c7bdd7e0259..08d26a72394c8e9920cc23e115802c642902305d 100644 (file)
@@ -146,6 +146,7 @@ static int omapbl_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = OMAPBL_MAX_INTENSITY;
        dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
                                        &props);
index 3c424f7efdccc895f1b9b0be2ed768a9b0ca471e..ef5628d60563841aceab7bca62191c0faf57f763 100644 (file)
@@ -112,6 +112,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
        if (!pcf_bl)
                return -ENOMEM;
 
+       bl_props.type = BACKLIGHT_RAW;
        bl_props.max_brightness = 0x3f;
        bl_props.power = FB_BLANK_UNBLANK;
 
index 809278c90738945b8546bad7faeb7676f842114f..6af183d6465ee80b4892c671fce687b85a6a272a 100644 (file)
@@ -84,6 +84,7 @@ static int progearbl_probe(struct platform_device *pdev)
        pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
        progear_backlight_device = backlight_device_register("progear-bl",
                                                             &pdev->dev, NULL,
index 21866ec69656d6be90e69af18a56316895f9d69f..b8f38ec6eb1898ab0b60d606ec1f3998e11fe339 100644 (file)
@@ -28,6 +28,7 @@ struct pwm_bl_data {
        unsigned int            lth_brightness;
        int                     (*notify)(struct device *,
                                          int brightness);
+       int                     (*check_fb)(struct device *, struct fb_info *);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -62,9 +63,18 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
        return bl->props.brightness;
 }
 
+static int pwm_backlight_check_fb(struct backlight_device *bl,
+                                 struct fb_info *info)
+{
+       struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+
+       return !pb->check_fb || pb->check_fb(pb->dev, info);
+}
+
 static const struct backlight_ops pwm_backlight_ops = {
        .update_status  = pwm_backlight_update_status,
        .get_brightness = pwm_backlight_get_brightness,
+       .check_fb       = pwm_backlight_check_fb,
 };
 
 static int pwm_backlight_probe(struct platform_device *pdev)
@@ -95,6 +105,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb->period = data->pwm_period_ns;
        pb->notify = data->notify;
+       pb->check_fb = data->check_fb;
        pb->lth_brightness = data->lth_brightness *
                (data->pwm_period_ns / data->max_brightness);
        pb->dev = &pdev->dev;
@@ -108,6 +119,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
                dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = data->max_brightness;
        bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
                                       &pwm_backlight_ops, &props);
index 5927db0da9998f87f273d9430d782c26723fb16e..322040f686c2c7bd9be40932fda03392cbfb3577 100644 (file)
@@ -778,6 +778,7 @@ static int __devinit s6e63m0_probe(struct spi_device *spi)
 
        bd->props.max_brightness = MAX_BRIGHTNESS;
        bd->props.brightness = MAX_BRIGHTNESS;
+       bd->props.type = BACKLIGHT_RAW;
        lcd->bd = bd;
 
        /*
index 2a04b382ec4834a03270db15701136f5f01694cf..425a7365470b14861f47da75e72fbb46fb915e3f 100644 (file)
@@ -102,6 +102,7 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
        data->i2c = client;
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 512 - 1;
        data->bl = backlight_device_register("tosa-bl", &client->dev, data,
                                             &bl_ops, &props);
index 08fd87f3aecce368219ed7cb08dfdaa0aebafef6..d4c6eb248ff997893499a13dd2d824fe4abebabc 100644 (file)
@@ -193,6 +193,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
        data->current_brightness = 0;
        data->isink_reg = isink_reg;
 
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = max_isel;
        bl = backlight_device_register("wm831x", &pdev->dev, data,
                                       &wm831x_backlight_ops, &props);
index e7d0f525041e7aa8ec0da2c6f34880ad4493def2..2464b910b5905cd3fb4db743eb5904f8c13e1ea4 100644 (file)
@@ -649,6 +649,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
        }
 #ifndef NO_BL_SUPPORT
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 255;
        bl_dev = backlight_device_register("bf54x-bl", NULL, NULL,
                                           &bfin_lq043fb_bl_ops, &props);
index 3cf77676947cbd19a59e3ec0a0604337e49df072..d8de29f0dd8d9111f772cc43a02627c20ac36e6f 100644 (file)
@@ -545,6 +545,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
        }
 #ifndef NO_BL_SUPPORT
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = 255;
        bl_dev = backlight_device_register("bf52x-bl", NULL, NULL,
                                           &bfin_lq043fb_bl_ops, &props);
index e2c85b0db632adb71871d3f353ee88894cf442fb..f1889500662757d337d066648964e685d53e7f78 100644 (file)
@@ -565,6 +565,7 @@ out_dealloc_cmap:
 
 out_unmap_regs:
        cg14_unmap_regs(op, info, par);
+       framebuffer_release(info);
 
 out_err:
        return err;
index 4ffad90bde4205e52d1c56a10f498677d0e21fc1..179e96cdb323fa9e91f22f42be016f55a32993ea 100644 (file)
@@ -821,6 +821,7 @@ out_dealloc_cmap:
 
 out_unmap_regs:
        cg6_unmap_regs(op, info, par);
+       framebuffer_release(info);
 
 out_err:
        return err;
index 9c092b8d64e6a5d0a205a71002afa5f917adf20b..c58393402da2ef466bd8de0edce08dae0ea53aac 100644 (file)
@@ -823,10 +823,10 @@ static int set_con2fb_map(int unit, int newidx, int user)
        if (oldidx == newidx)
                return 0;
 
-       if (!info || fbcon_has_exited)
+       if (!info)
                return -EINVAL;
 
-       if (!err && !search_for_mapped_con()) {
+       if (!search_for_mapped_con() || !con_is_bound(&fb_con)) {
                info_idx = newidx;
                return fbcon_takeover(0);
        }
index 0056a41e5c35c2a3d323c69845a2db895a080108..15e8e1a89c45def0d7f9ebc0ab8fbdaa1563ff8b 100644 (file)
@@ -83,7 +83,7 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
                        int softback_lines, int fg, int bg)
 {
        struct fb_tilecursor cursor;
-       int use_sw = (vc->vc_cursor_type & 0x01);
+       int use_sw = (vc->vc_cursor_type & 0x10);
 
        cursor.sx = vc->vc_x;
        cursor.sy = vc->vc_y;
index bd89fb3be8c23d5d3ca413ae941235ee02f35383..d03a232d90b2ca7b86bb25a93f53fa7e68796f49 100644 (file)
 #define V_SYNC_WIDTH       COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
 #define V_SYNC_OFFSET      COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
 
-#define H_SYNC_WIDTH       COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
-#define H_SYNC_OFFSET      COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
+#define H_SYNC_WIDTH       COMBINE_HI_8LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
+#define H_SYNC_OFFSET      COMBINE_HI_8LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
 
 #define H_SIZE_LO          (unsigned)block[ 12 ]
 #define V_SIZE_LO          (unsigned)block[ 13 ]
index 910c5e6f67021e3281bcd10be1a5b4ef8d490e42..14102a3f70f5cc69bd19963919bad3522a2cda06 100644 (file)
@@ -1010,7 +1010,7 @@ out_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 
 out_unmap_dac:
-       of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+       of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
 
 out_unmap_fbc:
        of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
index c77bcc6ab463c2ce1cfd17abdb813d490c4376bd..1b94643ecbcfff4dd63eca7b52953ba2f702f21e 100644 (file)
@@ -299,7 +299,7 @@ static int __devexit hecubafb_remove(struct platform_device *dev)
 
 static struct platform_driver hecubafb_driver = {
        .probe  = hecubafb_probe,
-       .remove = hecubafb_remove,
+       .remove = __devexit_p(hecubafb_remove),
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "hecubafb",
index c8e280f1bb0bf78181570a8d9b36956d55683ae6..ebf8495ff198b601220ee25b43545b4efe65b3b9 100644 (file)
@@ -321,11 +321,11 @@ static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_
        unsigned long paddr, vaddr;
 
        paddr = d->resource.start;
-       if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
+       if (!request_mem_region(d->resource.start, resource_size(&d->resource), d->name))
                 return -EBUSY;
 
        if (d->scode >= DIOII_SCBASE) {
-               vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
+               vaddr = (unsigned long)ioremap(paddr, resource_size(&d->resource));
        } else {
                vaddr = paddr + DIO_VIRADDRBASE;
        }
@@ -344,7 +344,7 @@ static void __devexit hpfb_remove_one(struct dio_dev *d)
        unregister_framebuffer(&fb_info);
        if (d->scode >= DIOII_SCBASE)
                iounmap((void *)fb_regs);
-        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
+       release_mem_region(d->resource.start, resource_size(&d->resource));
 }
 
 static struct dio_device_id hpfb_dio_tbl[] = {
index 69bd4a581d4aaec71b211f2f3328fd2f3db07a1c..ef72cb4838349f2b0e674362e13eb831584432fe 100644 (file)
@@ -499,6 +499,7 @@ static void imxfb_init_backlight(struct imxfb_info *fbi)
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.max_brightness = 0xff;
+       props.type = BACKLIGHT_RAW;
        writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
 
        bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi,
index 6c782d3ae1bede62c0bc8a7c93526c144d102600..f7d631ebee8e34981360a83e5c56c97555238a43 100644 (file)
@@ -4,7 +4,4 @@ intelfb-y := intelfbdrv.o intelfbhw.o
 intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
 intelfb-objs := $(intelfb-y)
 
-ifdef CONFIG_FB_INTEL_DEBUG
-#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
-EXTRA_CFLAGS += -DDEBUG -DREGDUMP
-endif
+ccflags-$(CONFIG_FB_INTEL_DEBUG) := -DDEBUG -DREGDUMP
index a082debe824b9969bf3cb76018d638471b6700ae..5ce6fa6e59f0b98c362a99419eb65d253b8f7cf9 100644 (file)
 
 #include <linux/version.h>
 
-#define __OLD_VIDIOC_
-
 #include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
@@ -1152,7 +1150,6 @@ static int matroxfb_ioctl(struct fb_info *info,
                                        return -EFAULT;
                                return err;
                        }
-               case VIDIOC_S_CTRL_OLD:
                case VIDIOC_S_CTRL:
                        {
                                struct v4l2_control ctrl;
@@ -1461,13 +1458,6 @@ 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,
@@ -2119,8 +2109,6 @@ 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,
index 63ed3b72b01c47ab34ba61e97831cb566e0ab7b2..ed64edfd2c43b7a97e693ff30b6e26972caaf7f7 100644 (file)
@@ -765,7 +765,7 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
 
 static struct platform_driver metronomefb_driver = {
        .probe  = metronomefb_probe,
-       .remove = metronomefb_remove,
+       .remove = __devexit_p(metronomefb_remove),
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "metronomefb",
index 6aac6d1b937bed75a5c0e160c0ff60f0cbdaf2fe..8471008aa6ff6b97c60425d09238174f3a4644e8 100644 (file)
@@ -111,6 +111,7 @@ void nvidia_bl_init(struct nvidia_par *par)
        snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops,
                                       &props);
index 083c8fe53e24147962a1f821657cf1bfcff8608c..15e7f1912af9bd0bc40578aa3164d96bb2acabad 100644 (file)
@@ -5,13 +5,18 @@ config FB_OMAP
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select TWL4030_CORE if MACH_OMAP_2430SDP
        help
           Frame buffer driver for OMAP based boards.
 
 config FB_OMAP_LCD_VGA
         bool "Use LCD in VGA mode"
                depends on MACH_OMAP_3430SDP || MACH_OMAP_LDP
-
+               help
+                 Set LCD resolution as VGA (640 X 480).
+                 Default resolution without this option is QVGA(320 X 240).
+                 Please take a look at drivers/video/omap/lcd_ldp.c file
+                 for lcd driver code.
 choice
        depends on FB_OMAP && MACH_OVERO
        prompt "Screen resolution"
index 87785c215a52c6e94ca9a0d799f1f25ed89c654d..c0504a8a5079cab34f364cbf29208dae3f91fb26 100644 (file)
@@ -397,8 +397,7 @@ static inline void free_req(struct blizzard_request *req)
 
        spin_lock_irqsave(&blizzard.req_lock, flags);
 
-       list_del(&req->entry);
-       list_add(&req->entry, &blizzard.free_req_list);
+       list_move(&req->entry, &blizzard.free_req_list);
        if (!(req->flags & REQ_FROM_IRQ_POOL))
                up(&blizzard.req_sema);
 
index 0016f77cd13fb076c09682586454598e97e0d386..084aa0ac562b022d66343d245be79e69d763dd78 100644 (file)
@@ -269,8 +269,7 @@ static inline void free_req(struct hwa742_request *req)
 
        spin_lock_irqsave(&hwa742.req_lock, flags);
 
-       list_del(&req->entry);
-       list_add(&req->entry, &hwa742.free_req_list);
+       list_move(&req->entry, &hwa742.free_req_list);
        if (!(req->flags & REQ_FROM_IRQ_POOL))
                up(&hwa742.req_sema);
 
index 940cab394c2e6b173c2cae0abae51db5ddd583bb..d18ad6b2372af818671780c532700422c911f3e8 100644 (file)
@@ -9,6 +9,12 @@ config PANEL_GENERIC_DPI
          Supports LCD Panel used in TI SDP3430 and EVM boards,
          OMAP3517 EVM boards and CM-T35.
 
+config PANEL_LGPHILIPS_LB035Q02
+       tristate "LG.Philips LB035Q02 LCD Panel"
+       depends on OMAP2_DSS && SPI
+       help
+         LCD Panel used on the Gumstix Overo Palo35
+
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
         depends on OMAP2_DSS
index 861f0255ec6ba5d12739b40dcc194886a1986b51..0f601ab3abf490fc03473de41859e078d9a6f4ee 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
+obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
 obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
 obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
 
index e77310653207c1c8202c0bbabddc692c6df4f2b6..7e04c921aa2a8585d4cb180776d9469c0b4d44ce 100644 (file)
@@ -534,6 +534,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
 
        props.fb_blank = FB_BLANK_UNBLANK;
        props.power = FB_BLANK_UNBLANK;
+       props.type = BACKLIGHT_RAW;
 
        bldev = backlight_device_register("acx565akm", &md->spi->dev,
                        md, &acx565akm_bl_ops, &props);
index 07eb30ee59c873f416219ffba6a3d42b722726a5..4a9b9ff59467fa10c3c274432bb6c901334bd560 100644 (file)
@@ -156,6 +156,31 @@ static struct panel_config generic_dpi_panels[] = {
                .power_off_delay        = 0,
                .name                   = "toppoly_tdo35s",
        },
+
+       /* Samsung LTE430WQ-F0C */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 9200,
+
+                       .hfp            = 8,
+                       .hsw            = 41,
+                       .hbp            = 45 - 41,
+
+                       .vfp            = 4,
+                       .vsw            = 10,
+                       .vbp            = 12 - 10,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "samsung_lte430wq_f0c",
+       },
 };
 
 struct panel_drv_data {
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
new file mode 100644 (file)
index 0000000..271324d
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * LCD panel driver for LG.Philips LB035Q02
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+
+#include <plat/display.h>
+
+struct lb035q02_data {
+       struct mutex lock;
+};
+
+static struct omap_video_timings lb035q02_timings = {
+       .x_res = 320,
+       .y_res = 240,
+
+       .pixel_clock    = 6500,
+
+       .hsw            = 2,
+       .hfp            = 20,
+       .hbp            = 68,
+
+       .vsw            = 2,
+       .vfp            = 4,
+       .vbp            = 18,
+};
+
+static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
+{
+       int r;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               return 0;
+
+       r = omapdss_dpi_display_enable(dssdev);
+       if (r)
+               goto err0;
+
+       if (dssdev->platform_enable) {
+               r = dssdev->platform_enable(dssdev);
+               if (r)
+                       goto err1;
+       }
+
+       return 0;
+err1:
+       omapdss_dpi_display_disable(dssdev);
+err0:
+       return r;
+}
+
+static void lb035q02_panel_power_off(struct omap_dss_device *dssdev)
+{
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+               return;
+
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+
+       omapdss_dpi_display_disable(dssdev);
+}
+
+static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld;
+       int r;
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+               OMAP_DSS_LCD_IHS;
+       dssdev->panel.timings = lb035q02_timings;
+
+       ld = kzalloc(sizeof(*ld), GFP_KERNEL);
+       if (!ld) {
+               r = -ENOMEM;
+               goto err;
+       }
+       mutex_init(&ld->lock);
+       dev_set_drvdata(&dssdev->dev, ld);
+       return 0;
+err:
+       return r;
+}
+
+static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+       kfree(ld);
+}
+
+static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&ld->lock);
+
+       r = lb035q02_panel_power_on(dssdev);
+       if (r)
+               goto err;
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ld->lock);
+       return 0;
+err:
+       mutex_unlock(&ld->lock);
+       return r;
+}
+
+static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ld->lock);
+
+       lb035q02_panel_power_off(dssdev);
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       mutex_unlock(&ld->lock);
+}
+
+static int lb035q02_panel_suspend(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+
+       mutex_lock(&ld->lock);
+
+       lb035q02_panel_power_off(dssdev);
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       mutex_unlock(&ld->lock);
+       return 0;
+}
+
+static int lb035q02_panel_resume(struct omap_dss_device *dssdev)
+{
+       struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
+       int r;
+
+       mutex_lock(&ld->lock);
+
+       r = lb035q02_panel_power_on(dssdev);
+       if (r)
+               goto err;
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+       mutex_unlock(&ld->lock);
+       return 0;
+err:
+       mutex_unlock(&ld->lock);
+       return r;
+}
+
+static struct omap_dss_driver lb035q02_driver = {
+       .probe          = lb035q02_panel_probe,
+       .remove         = lb035q02_panel_remove,
+
+       .enable         = lb035q02_panel_enable,
+       .disable        = lb035q02_panel_disable,
+       .suspend        = lb035q02_panel_suspend,
+       .resume         = lb035q02_panel_resume,
+
+       .driver         = {
+               .name   = "lgphilips_lb035q02_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val)
+{
+       struct spi_message msg;
+       struct spi_transfer index_xfer = {
+               .len            = 3,
+               .cs_change      = 1,
+       };
+       struct spi_transfer value_xfer = {
+               .len            = 3,
+       };
+       u8      buffer[16];
+
+       spi_message_init(&msg);
+
+       /* register index */
+       buffer[0] = 0x70;
+       buffer[1] = 0x00;
+       buffer[2] = reg & 0x7f;
+       index_xfer.tx_buf = buffer;
+       spi_message_add_tail(&index_xfer, &msg);
+
+       /* register value */
+       buffer[4] = 0x72;
+       buffer[5] = val >> 8;
+       buffer[6] = val;
+       value_xfer.tx_buf = buffer + 4;
+       spi_message_add_tail(&value_xfer, &msg);
+
+       return spi_sync(spi, &msg);
+}
+
+static void init_lb035q02_panel(struct spi_device *spi)
+{
+       /* Init sequence from page 28 of the lb035q02 spec */
+       lb035q02_write_reg(spi, 0x01, 0x6300);
+       lb035q02_write_reg(spi, 0x02, 0x0200);
+       lb035q02_write_reg(spi, 0x03, 0x0177);
+       lb035q02_write_reg(spi, 0x04, 0x04c7);
+       lb035q02_write_reg(spi, 0x05, 0xffc0);
+       lb035q02_write_reg(spi, 0x06, 0xe806);
+       lb035q02_write_reg(spi, 0x0a, 0x4008);
+       lb035q02_write_reg(spi, 0x0b, 0x0000);
+       lb035q02_write_reg(spi, 0x0d, 0x0030);
+       lb035q02_write_reg(spi, 0x0e, 0x2800);
+       lb035q02_write_reg(spi, 0x0f, 0x0000);
+       lb035q02_write_reg(spi, 0x16, 0x9f80);
+       lb035q02_write_reg(spi, 0x17, 0x0a0f);
+       lb035q02_write_reg(spi, 0x1e, 0x00c1);
+       lb035q02_write_reg(spi, 0x30, 0x0300);
+       lb035q02_write_reg(spi, 0x31, 0x0007);
+       lb035q02_write_reg(spi, 0x32, 0x0000);
+       lb035q02_write_reg(spi, 0x33, 0x0000);
+       lb035q02_write_reg(spi, 0x34, 0x0707);
+       lb035q02_write_reg(spi, 0x35, 0x0004);
+       lb035q02_write_reg(spi, 0x36, 0x0302);
+       lb035q02_write_reg(spi, 0x37, 0x0202);
+       lb035q02_write_reg(spi, 0x3a, 0x0a0d);
+       lb035q02_write_reg(spi, 0x3b, 0x0806);
+}
+
+static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi)
+{
+       init_lb035q02_panel(spi);
+       return omap_dss_register_driver(&lb035q02_driver);
+}
+
+static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi)
+{
+       omap_dss_unregister_driver(&lb035q02_driver);
+       return 0;
+}
+
+static struct spi_driver lb035q02_spi_driver = {
+       .driver         = {
+               .name   = "lgphilips_lb035q02_panel-spi",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = lb035q02_panel_spi_probe,
+       .remove         = __devexit_p(lb035q02_panel_spi_remove),
+};
+
+static int __init lb035q02_panel_drv_init(void)
+{
+       return spi_register_driver(&lb035q02_spi_driver);
+}
+
+static void __exit lb035q02_panel_drv_exit(void)
+{
+       spi_unregister_driver(&lb035q02_spi_driver);
+}
+
+module_init(lb035q02_panel_drv_init);
+module_exit(lb035q02_panel_drv_exit);
+MODULE_LICENSE("GPL");
index 9a138f650e0567e9e9f60118648fcd39543e06f6..d2b35d2df2a60ad03c29b3cf18b0ebae9cce65b7 100644 (file)
@@ -99,6 +99,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.max_brightness = dssdev->max_backlight_level;
+       props.type = BACKLIGHT_RAW;
 
        bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev,
                        &sharp_ls_bl_ops, &props);
index 61026f96ad20a012bcba26ad1e76a981e8a4f7d8..adc9900458e1cd7b0e627bb9fb4e9bc16f0b7175 100644 (file)
@@ -218,6 +218,8 @@ struct taal_data {
                u16 w;
                u16 h;
        } update_region;
+       int channel;
+
        struct delayed_work te_timeout_work;
 
        bool use_dsi_bl;
@@ -257,12 +259,12 @@ static void hw_guard_wait(struct taal_data *td)
        }
 }
 
-static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
+static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
 {
        int r;
        u8 buf[1];
 
-       r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
+       r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf, 1);
 
        if (r < 0)
                return r;
@@ -272,17 +274,17 @@ static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
        return 0;
 }
 
-static int taal_dcs_write_0(u8 dcs_cmd)
+static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd)
 {
-       return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
+       return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1);
 }
 
-static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
+static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
 {
        u8 buf[2];
        buf[0] = dcs_cmd;
        buf[1] = param;
-       return dsi_vc_dcs_write(TCH, buf, 2);
+       return dsi_vc_dcs_write(td->channel, buf, 2);
 }
 
 static int taal_sleep_in(struct taal_data *td)
@@ -294,7 +296,7 @@ static int taal_sleep_in(struct taal_data *td)
        hw_guard_wait(td);
 
        cmd = DCS_SLEEP_IN;
-       r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
+       r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1);
        if (r)
                return r;
 
@@ -312,7 +314,7 @@ static int taal_sleep_out(struct taal_data *td)
 
        hw_guard_wait(td);
 
-       r = taal_dcs_write_0(DCS_SLEEP_OUT);
+       r = taal_dcs_write_0(td, DCS_SLEEP_OUT);
        if (r)
                return r;
 
@@ -324,30 +326,30 @@ static int taal_sleep_out(struct taal_data *td)
        return 0;
 }
 
-static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
+static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3)
 {
        int r;
 
-       r = taal_dcs_read_1(DCS_GET_ID1, id1);
+       r = taal_dcs_read_1(td, DCS_GET_ID1, id1);
        if (r)
                return r;
-       r = taal_dcs_read_1(DCS_GET_ID2, id2);
+       r = taal_dcs_read_1(td, DCS_GET_ID2, id2);
        if (r)
                return r;
-       r = taal_dcs_read_1(DCS_GET_ID3, id3);
+       r = taal_dcs_read_1(td, DCS_GET_ID3, id3);
        if (r)
                return r;
 
        return 0;
 }
 
-static int taal_set_addr_mode(u8 rotate, bool mirror)
+static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
 {
        int r;
        u8 mode;
        int b5, b6, b7;
 
-       r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
+       r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode);
        if (r)
                return r;
 
@@ -381,10 +383,11 @@ static int taal_set_addr_mode(u8 rotate, bool mirror)
        mode &= ~((1<<7) | (1<<6) | (1<<5));
        mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
 
-       return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
+       return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode);
 }
 
-static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
+static int taal_set_update_window(struct taal_data *td,
+               u16 x, u16 y, u16 w, u16 h)
 {
        int r;
        u16 x1 = x;
@@ -399,7 +402,7 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
        buf[3] = (x2 >> 8) & 0xff;
        buf[4] = (x2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
@@ -409,11 +412,11 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
        buf[3] = (y2 >> 8) & 0xff;
        buf[4] = (y2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
-       dsi_vc_send_bta_sync(TCH);
+       dsi_vc_send_bta_sync(td->channel);
 
        return r;
 }
@@ -439,7 +442,7 @@ static int taal_bl_update_status(struct backlight_device *dev)
        if (td->use_dsi_bl) {
                if (td->enabled) {
                        dsi_bus_lock();
-                       r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
+                       r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
                        dsi_bus_unlock();
                } else {
                        r = 0;
@@ -502,7 +505,7 @@ static ssize_t taal_num_errors_show(struct device *dev,
 
        if (td->enabled) {
                dsi_bus_lock();
-               r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
+               r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
                dsi_bus_unlock();
        } else {
                r = -ENODEV;
@@ -528,7 +531,7 @@ static ssize_t taal_hw_revision_show(struct device *dev,
 
        if (td->enabled) {
                dsi_bus_lock();
-               r = taal_get_id(&id1, &id2, &id3);
+               r = taal_get_id(td, &id1, &id2, &id3);
                dsi_bus_unlock();
        } else {
                r = -ENODEV;
@@ -590,7 +593,7 @@ static ssize_t store_cabc_mode(struct device *dev,
        if (td->enabled) {
                dsi_bus_lock();
                if (!td->cabc_broken)
-                       taal_dcs_write_1(DCS_WRITE_CABC, i);
+                       taal_dcs_write_1(td, DCS_WRITE_CABC, i);
                dsi_bus_unlock();
        }
 
@@ -729,6 +732,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
                props.max_brightness = 255;
        else
                props.max_brightness = 127;
+
+       props.type = BACKLIGHT_RAW;
        bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
                                          &taal_bl_ops, &props);
        if (IS_ERR(bldev)) {
@@ -774,14 +779,29 @@ static int taal_probe(struct omap_dss_device *dssdev)
                dev_dbg(&dssdev->dev, "Using GPIO TE\n");
        }
 
+       r = omap_dsi_request_vc(dssdev, &td->channel);
+       if (r) {
+               dev_err(&dssdev->dev, "failed to get virtual channel\n");
+               goto err_req_vc;
+       }
+
+       r = omap_dsi_set_vc_id(dssdev, td->channel, TCH);
+       if (r) {
+               dev_err(&dssdev->dev, "failed to set VC_ID\n");
+               goto err_vc_id;
+       }
+
        r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
        if (r) {
                dev_err(&dssdev->dev, "failed to create sysfs files\n");
-               goto err_sysfs;
+               goto err_vc_id;
        }
 
        return 0;
-err_sysfs:
+
+err_vc_id:
+       omap_dsi_release_vc(dssdev, td->channel);
+err_req_vc:
        if (panel_data->use_ext_te)
                free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
 err_irq:
@@ -808,6 +828,7 @@ static void taal_remove(struct omap_dss_device *dssdev)
        dev_dbg(&dssdev->dev, "remove\n");
 
        sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
+       omap_dsi_release_vc(dssdev, td->channel);
 
        if (panel_data->use_ext_te) {
                int gpio = panel_data->ext_te_gpio;
@@ -846,13 +867,13 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 
        taal_hw_reset(dssdev);
 
-       omapdss_dsi_vc_enable_hs(TCH, false);
+       omapdss_dsi_vc_enable_hs(td->channel, false);
 
        r = taal_sleep_out(td);
        if (r)
                goto err;
 
-       r = taal_get_id(&id1, &id2, &id3);
+       r = taal_get_id(td, &id1, &id2, &id3);
        if (r)
                goto err;
 
@@ -861,30 +882,30 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                (id2 == 0x00 || id2 == 0xff || id2 == 0x81))
                td->cabc_broken = true;
 
-       r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
+       r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff);
        if (r)
                goto err;
 
-       r = taal_dcs_write_1(DCS_CTRL_DISPLAY,
+       r = taal_dcs_write_1(td, DCS_CTRL_DISPLAY,
                        (1<<2) | (1<<5));       /* BL | BCTRL */
        if (r)
                goto err;
 
-       r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
+       r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
        if (r)
                goto err;
 
-       r = taal_set_addr_mode(td->rotate, td->mirror);
+       r = taal_set_addr_mode(td, td->rotate, td->mirror);
        if (r)
                goto err;
 
        if (!td->cabc_broken) {
-               r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
+               r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode);
                if (r)
                        goto err;
        }
 
-       r = taal_dcs_write_0(DCS_DISPLAY_ON);
+       r = taal_dcs_write_0(td, DCS_DISPLAY_ON);
        if (r)
                goto err;
 
@@ -903,7 +924,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                td->intro_printed = true;
        }
 
-       omapdss_dsi_vc_enable_hs(TCH, true);
+       omapdss_dsi_vc_enable_hs(td->channel, true);
 
        return 0;
 err:
@@ -921,7 +942,7 @@ static void taal_power_off(struct omap_dss_device *dssdev)
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        int r;
 
-       r = taal_dcs_write_0(DCS_DISPLAY_OFF);
+       r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
        if (!r) {
                r = taal_sleep_in(td);
                /* HACK: wait a bit so that the message goes through */
@@ -1089,7 +1110,7 @@ static irqreturn_t taal_te_isr(int irq, void *data)
        if (old) {
                cancel_delayed_work(&td->te_timeout_work);
 
-               r = omap_dsi_update(dssdev, TCH,
+               r = omap_dsi_update(dssdev, td->channel,
                                td->update_region.x,
                                td->update_region.y,
                                td->update_region.w,
@@ -1139,7 +1160,7 @@ static int taal_update(struct omap_dss_device *dssdev,
        if (r)
                goto err;
 
-       r = taal_set_update_window(x, y, w, h);
+       r = taal_set_update_window(td, x, y, w, h);
        if (r)
                goto err;
 
@@ -1153,7 +1174,7 @@ static int taal_update(struct omap_dss_device *dssdev,
                                msecs_to_jiffies(250));
                atomic_set(&td->do_update, 1);
        } else {
-               r = omap_dsi_update(dssdev, TCH, x, y, w, h,
+               r = omap_dsi_update(dssdev, td->channel, x, y, w, h,
                                taal_framedone_cb, dssdev);
                if (r)
                        goto err;
@@ -1191,9 +1212,9 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        int r;
 
        if (enable)
-               r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+               r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
        else
-               r = taal_dcs_write_0(DCS_TEAR_OFF);
+               r = taal_dcs_write_0(td, DCS_TEAR_OFF);
 
        if (!panel_data->use_ext_te)
                omapdss_dsi_enable_te(dssdev, enable);
@@ -1263,7 +1284,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
        dsi_bus_lock();
 
        if (td->enabled) {
-               r = taal_set_addr_mode(rotate, td->mirror);
+               r = taal_set_addr_mode(td, rotate, td->mirror);
                if (r)
                        goto err;
        }
@@ -1306,7 +1327,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
        dsi_bus_lock();
        if (td->enabled) {
-               r = taal_set_addr_mode(td->rotate, enable);
+               r = taal_set_addr_mode(td, td->rotate, enable);
                if (r)
                        goto err;
        }
@@ -1350,13 +1371,13 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
 
        dsi_bus_lock();
 
-       r = taal_dcs_read_1(DCS_GET_ID1, &id1);
+       r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
        if (r)
                goto err2;
-       r = taal_dcs_read_1(DCS_GET_ID2, &id2);
+       r = taal_dcs_read_1(td, DCS_GET_ID2, &id2);
        if (r)
                goto err2;
-       r = taal_dcs_read_1(DCS_GET_ID3, &id3);
+       r = taal_dcs_read_1(td, DCS_GET_ID3, &id3);
        if (r)
                goto err2;
 
@@ -1404,9 +1425,9 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
        else
                plen = 2;
 
-       taal_set_update_window(x, y, w, h);
+       taal_set_update_window(td, x, y, w, h);
 
-       r = dsi_vc_set_max_rx_packet_size(TCH, plen);
+       r = dsi_vc_set_max_rx_packet_size(td->channel, plen);
        if (r)
                goto err2;
 
@@ -1414,7 +1435,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
                u8 dcs_cmd = first ? 0x2e : 0x3e;
                first = 0;
 
-               r = dsi_vc_dcs_read(TCH, dcs_cmd,
+               r = dsi_vc_dcs_read(td->channel, dcs_cmd,
                                buf + buf_used, size - buf_used);
 
                if (r < 0) {
@@ -1440,7 +1461,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
        r = buf_used;
 
 err3:
-       dsi_vc_set_max_rx_packet_size(TCH, 1);
+       dsi_vc_set_max_rx_packet_size(td->channel, 1);
 err2:
        dsi_bus_unlock();
 err1:
@@ -1466,7 +1487,7 @@ static void taal_esd_work(struct work_struct *work)
 
        dsi_bus_lock();
 
-       r = taal_dcs_read_1(DCS_RDDSDR, &state1);
+       r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
        if (r) {
                dev_err(&dssdev->dev, "failed to read Taal status\n");
                goto err;
@@ -1479,7 +1500,7 @@ static void taal_esd_work(struct work_struct *work)
                goto err;
        }
 
-       r = taal_dcs_read_1(DCS_RDDSDR, &state2);
+       r = taal_dcs_read_1(td, DCS_RDDSDR, &state2);
        if (r) {
                dev_err(&dssdev->dev, "failed to read Taal status\n");
                goto err;
@@ -1495,7 +1516,7 @@ static void taal_esd_work(struct work_struct *work)
        /* Self-diagnostics result is also shown on TE GPIO line. We need
         * to re-enable TE after self diagnostics */
        if (td->te_enabled && panel_data->use_ext_te) {
-               r = taal_dcs_write_1(DCS_TEAR_ON, 0);
+               r = taal_dcs_write_1(td, DCS_TEAR_ON, 0);
                if (r)
                        goto err;
        }
index 43b64403eaa453b48f30302b64c3bbbeb9ce67fc..bfc5da0e9700b7dea404085f50ae56cfb774ba42 100644 (file)
@@ -1,8 +1,8 @@
 menuconfig OMAP2_DSS
-        tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
-        depends on ARCH_OMAP2 || ARCH_OMAP3
+        tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)"
+        depends on ARCH_OMAP2PLUS
         help
-          OMAP2/3 Display Subsystem support.
+         OMAP2+ Display Subsystem support.
 
 if OMAP2_DSS
 
@@ -60,6 +60,14 @@ config OMAP2_DSS_VENC
        help
          OMAP Video Encoder support for S-Video and composite TV-out.
 
+config OMAP4_DSS_HDMI
+       bool "HDMI support"
+       depends on ARCH_OMAP4
+        default y
+       help
+         HDMI Interface. This adds the High Definition Multimedia Interface.
+         See http://www.hdmi.org/ for HDMI specification.
+
 config OMAP2_DSS_SDI
        bool "SDI support"
        depends on ARCH_OMAP3
index 7db17b5e570c43c17afde3b01681c167c20b012c..10d9d3bb3e24c5b4f6eb9a9944a8ad6e9634ac32 100644 (file)
@@ -5,3 +5,5 @@ omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
 omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
 omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
 omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
+omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
+                                   hdmi_omap4_panel.o
index 8e89f604928098306485494ca829a7b11c42d0c3..1aa2ed1e786e11cb2ae5f9d827d0b3b78791a504 100644 (file)
 #include <linux/regulator/consumer.h>
 
 #include <plat/display.h>
-#include <plat/clock.h>
 
 #include "dss.h"
 #include "dss_features.h"
 
 static struct {
        struct platform_device *pdev;
-       int             ctx_id;
-
-       struct clk      *dss_ick;
-       struct clk      *dss1_fck;
-       struct clk      *dss2_fck;
-       struct clk      *dss_54m_fck;
-       struct clk      *dss_96m_fck;
-       unsigned        num_clks_enabled;
 
        struct regulator *vdds_dsi_reg;
        struct regulator *vdds_sdi_reg;
-       struct regulator *vdda_dac_reg;
 } core;
 
-static void dss_clk_enable_all_no_ctx(void);
-static void dss_clk_disable_all_no_ctx(void);
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
-
 static char *def_disp_name;
 module_param_named(def_disp, def_disp_name, charp, 0);
-MODULE_PARM_DESC(def_disp_name, "default display name");
+MODULE_PARM_DESC(def_disp, "default display name");
 
 #ifdef DEBUG
 unsigned int dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
-/* CONTEXT */
-static int dss_get_ctx_id(void)
-{
-       struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
-       int r;
-
-       if (!pdata->get_last_off_on_transaction_id)
-               return 0;
-       r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
-       if (r < 0) {
-               dev_err(&core.pdev->dev, "getting transaction ID failed, "
-                               "will force context restore\n");
-               r = -1;
-       }
-       return r;
-}
-
-int dss_need_ctx_restore(void)
-{
-       int id = dss_get_ctx_id();
-
-       if (id < 0 || id != core.ctx_id) {
-               DSSDBG("ctx id %d -> id %d\n",
-                               core.ctx_id, id);
-               core.ctx_id = id;
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static void save_all_ctx(void)
-{
-       DSSDBG("save context\n");
-
-       dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-
-       dss_save_context();
-       dispc_save_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_save_context();
-#endif
-
-       dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
-}
-
-static void restore_all_ctx(void)
-{
-       DSSDBG("restore context\n");
-
-       dss_clk_enable_all_no_ctx();
-
-       dss_restore_context();
-       dispc_restore_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_restore_context();
-#endif
-
-       dss_clk_disable_all_no_ctx();
-}
-
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-/* CLOCKS */
-static void core_dump_clocks(struct seq_file *s)
-{
-       int i;
-       struct clk *clocks[5] = {
-               core.dss_ick,
-               core.dss1_fck,
-               core.dss2_fck,
-               core.dss_54m_fck,
-               core.dss_96m_fck
-       };
-
-       seq_printf(s, "- CORE -\n");
-
-       seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
-
-       for (i = 0; i < 5; i++) {
-               if (!clocks[i])
-                       continue;
-               seq_printf(s, "%-15s\t%lu\t%d\n",
-                               clocks[i]->name,
-                               clk_get_rate(clocks[i]),
-                               clocks[i]->usecount);
-       }
-}
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
-
-static int dss_get_clock(struct clk **clock, const char *clk_name)
-{
-       struct clk *clk;
-
-       clk = clk_get(&core.pdev->dev, clk_name);
-
-       if (IS_ERR(clk)) {
-               DSSERR("can't get clock %s", clk_name);
-               return PTR_ERR(clk);
-       }
-
-       *clock = clk;
-
-       DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
-
-       return 0;
-}
-
-static int dss_get_clocks(void)
-{
-       int r;
-
-       core.dss_ick = NULL;
-       core.dss1_fck = NULL;
-       core.dss2_fck = NULL;
-       core.dss_54m_fck = NULL;
-       core.dss_96m_fck = NULL;
-
-       r = dss_get_clock(&core.dss_ick, "ick");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&core.dss1_fck, "dss1_fck");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&core.dss2_fck, "dss2_fck");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&core.dss_96m_fck, "video_fck");
-       if (r)
-               goto err;
-
-       return 0;
-
-err:
-       if (core.dss_ick)
-               clk_put(core.dss_ick);
-       if (core.dss1_fck)
-               clk_put(core.dss1_fck);
-       if (core.dss2_fck)
-               clk_put(core.dss2_fck);
-       if (core.dss_54m_fck)
-               clk_put(core.dss_54m_fck);
-       if (core.dss_96m_fck)
-               clk_put(core.dss_96m_fck);
-
-       return r;
-}
-
-static void dss_put_clocks(void)
-{
-       if (core.dss_96m_fck)
-               clk_put(core.dss_96m_fck);
-       clk_put(core.dss_54m_fck);
-       clk_put(core.dss1_fck);
-       clk_put(core.dss2_fck);
-       clk_put(core.dss_ick);
-}
-
-unsigned long dss_clk_get_rate(enum dss_clock clk)
-{
-       switch (clk) {
-       case DSS_CLK_ICK:
-               return clk_get_rate(core.dss_ick);
-       case DSS_CLK_FCK1:
-               return clk_get_rate(core.dss1_fck);
-       case DSS_CLK_FCK2:
-               return clk_get_rate(core.dss2_fck);
-       case DSS_CLK_54M:
-               return clk_get_rate(core.dss_54m_fck);
-       case DSS_CLK_96M:
-               return clk_get_rate(core.dss_96m_fck);
-       }
-
-       BUG();
-       return 0;
-}
-
-static unsigned count_clk_bits(enum dss_clock clks)
-{
-       unsigned num_clks = 0;
-
-       if (clks & DSS_CLK_ICK)
-               ++num_clks;
-       if (clks & DSS_CLK_FCK1)
-               ++num_clks;
-       if (clks & DSS_CLK_FCK2)
-               ++num_clks;
-       if (clks & DSS_CLK_54M)
-               ++num_clks;
-       if (clks & DSS_CLK_96M)
-               ++num_clks;
-
-       return num_clks;
-}
-
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
-{
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_enable(core.dss_ick);
-       if (clks & DSS_CLK_FCK1)
-               clk_enable(core.dss1_fck);
-       if (clks & DSS_CLK_FCK2)
-               clk_enable(core.dss2_fck);
-       if (clks & DSS_CLK_54M)
-               clk_enable(core.dss_54m_fck);
-       if (clks & DSS_CLK_96M)
-               clk_enable(core.dss_96m_fck);
-
-       core.num_clks_enabled += num_clks;
-}
-
-void dss_clk_enable(enum dss_clock clks)
-{
-       bool check_ctx = core.num_clks_enabled == 0;
-
-       dss_clk_enable_no_ctx(clks);
-
-       if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
-               restore_all_ctx();
-}
-
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
-{
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_disable(core.dss_ick);
-       if (clks & DSS_CLK_FCK1)
-               clk_disable(core.dss1_fck);
-       if (clks & DSS_CLK_FCK2)
-               clk_disable(core.dss2_fck);
-       if (clks & DSS_CLK_54M)
-               clk_disable(core.dss_54m_fck);
-       if (clks & DSS_CLK_96M)
-               clk_disable(core.dss_96m_fck);
-
-       core.num_clks_enabled -= num_clks;
-}
-
-void dss_clk_disable(enum dss_clock clks)
-{
-       if (cpu_is_omap34xx()) {
-               unsigned num_clks = count_clk_bits(clks);
-
-               BUG_ON(core.num_clks_enabled < num_clks);
-
-               if (core.num_clks_enabled == num_clks)
-                       save_all_ctx();
-       }
-
-       dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_enable_all_no_ctx(void)
-{
-       enum dss_clock clks;
-
-       clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_96M;
-       dss_clk_enable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all_no_ctx(void)
-{
-       enum dss_clock clks;
-
-       clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_96M;
-       dss_clk_disable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all(void)
-{
-       enum dss_clock clks;
-
-       clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_96M;
-       dss_clk_disable(clks);
-}
-
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -390,32 +84,7 @@ struct regulator *dss_get_vdds_sdi(void)
        return reg;
 }
 
-struct regulator *dss_get_vdda_dac(void)
-{
-       struct regulator *reg;
-
-       if (core.vdda_dac_reg != NULL)
-               return core.vdda_dac_reg;
-
-       reg = regulator_get(&core.pdev->dev, "vdda_dac");
-       if (!IS_ERR(reg))
-               core.vdda_dac_reg = reg;
-
-       return reg;
-}
-
-/* DEBUGFS */
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-static void dss_debug_dump_clocks(struct seq_file *s)
-{
-       core_dump_clocks(s);
-       dss_dump_clocks(s);
-       dispc_dump_clocks(s);
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_dump_clocks(s);
-#endif
-}
-
 static int dss_debug_show(struct seq_file *s, void *unused)
 {
        void (*func)(struct seq_file *) = s->private;
@@ -497,7 +166,6 @@ static inline void dss_uninitialize_debugfs(void)
 static int omap_dss_probe(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
-       int skip_init = 0;
        int r;
        int i;
 
@@ -508,63 +176,43 @@ static int omap_dss_probe(struct platform_device *pdev)
        dss_init_overlay_managers(pdev);
        dss_init_overlays(pdev);
 
-       r = dss_get_clocks();
-       if (r)
-               goto err_clocks;
-
-       dss_clk_enable_all_no_ctx();
-
-       core.ctx_id = dss_get_ctx_id();
-       DSSDBG("initial ctx id %u\n", core.ctx_id);
-
-#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
-       /* DISPC_CONTROL */
-       if (omap_readl(0x48050440) & 1) /* LCD enabled? */
-               skip_init = 1;
-#endif
-
-       r = dss_init(skip_init);
+       r = dss_init_platform_driver();
        if (r) {
-               DSSERR("Failed to initialize DSS\n");
+               DSSERR("Failed to initialize DSS platform driver\n");
                goto err_dss;
        }
 
-       r = rfbi_init();
-       if (r) {
-               DSSERR("Failed to initialize rfbi\n");
-               goto err_rfbi;
-       }
+       /* keep clocks enabled to prevent context saves/restores during init */
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
-       r = dpi_init(pdev);
+       r = rfbi_init_platform_driver();
        if (r) {
-               DSSERR("Failed to initialize dpi\n");
-               goto err_dpi;
+               DSSERR("Failed to initialize rfbi platform driver\n");
+               goto err_rfbi;
        }
 
-       r = dispc_init();
+       r = dispc_init_platform_driver();
        if (r) {
-               DSSERR("Failed to initialize dispc\n");
+               DSSERR("Failed to initialize dispc platform driver\n");
                goto err_dispc;
        }
 
-       r = venc_init(pdev);
+       r = venc_init_platform_driver();
        if (r) {
-               DSSERR("Failed to initialize venc\n");
+               DSSERR("Failed to initialize venc platform driver\n");
                goto err_venc;
        }
 
-       if (cpu_is_omap34xx()) {
-               r = sdi_init(skip_init);
-               if (r) {
-                       DSSERR("Failed to initialize SDI\n");
-                       goto err_sdi;
-               }
+       r = dsi_init_platform_driver();
+       if (r) {
+               DSSERR("Failed to initialize DSI platform driver\n");
+               goto err_dsi;
+       }
 
-               r = dsi_init(pdev);
-               if (r) {
-                       DSSERR("Failed to initialize DSI\n");
-                       goto err_dsi;
-               }
+       r = hdmi_init_platform_driver();
+       if (r) {
+               DSSERR("Failed to initialize hdmi\n");
+               goto err_hdmi;
        }
 
        r = dss_initialize_debugfs();
@@ -589,32 +237,25 @@ static int omap_dss_probe(struct platform_device *pdev)
                        pdata->default_device = dssdev;
        }
 
-       dss_clk_disable_all();
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        return 0;
 
 err_register:
        dss_uninitialize_debugfs();
 err_debugfs:
-       if (cpu_is_omap34xx())
-               dsi_exit();
+       hdmi_uninit_platform_driver();
+err_hdmi:
+       dsi_uninit_platform_driver();
 err_dsi:
-       if (cpu_is_omap34xx())
-               sdi_exit();
-err_sdi:
-       venc_exit();
+       venc_uninit_platform_driver();
 err_venc:
-       dispc_exit();
+       dispc_uninit_platform_driver();
 err_dispc:
-       dpi_exit();
-err_dpi:
-       rfbi_exit();
+       rfbi_uninit_platform_driver();
 err_rfbi:
-       dss_exit();
+       dss_uninit_platform_driver();
 err_dss:
-       dss_clk_disable_all_no_ctx();
-       dss_put_clocks();
-err_clocks:
 
        return r;
 }
@@ -623,61 +264,15 @@ static int omap_dss_remove(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
        int i;
-       int c;
 
        dss_uninitialize_debugfs();
 
-       venc_exit();
-       dispc_exit();
-       dpi_exit();
-       rfbi_exit();
-       if (cpu_is_omap34xx()) {
-               dsi_exit();
-               sdi_exit();
-       }
-
-       dss_exit();
-
-       /* these should be removed at some point */
-       c = core.dss_ick->usecount;
-       if (c > 0) {
-               DSSERR("warning: dss_ick usecount %d, disabling\n", c);
-               while (c-- > 0)
-                       clk_disable(core.dss_ick);
-       }
-
-       c = core.dss1_fck->usecount;
-       if (c > 0) {
-               DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
-               while (c-- > 0)
-                       clk_disable(core.dss1_fck);
-       }
-
-       c = core.dss2_fck->usecount;
-       if (c > 0) {
-               DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
-               while (c-- > 0)
-                       clk_disable(core.dss2_fck);
-       }
-
-       c = core.dss_54m_fck->usecount;
-       if (c > 0) {
-               DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
-               while (c-- > 0)
-                       clk_disable(core.dss_54m_fck);
-       }
-
-       if (core.dss_96m_fck) {
-               c = core.dss_96m_fck->usecount;
-               if (c > 0) {
-                       DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
-                                       c);
-                       while (c-- > 0)
-                               clk_disable(core.dss_96m_fck);
-               }
-       }
-
-       dss_put_clocks();
+       venc_uninit_platform_driver();
+       dispc_uninit_platform_driver();
+       rfbi_uninit_platform_driver();
+       dsi_uninit_platform_driver();
+       hdmi_uninit_platform_driver();
+       dss_uninit_platform_driver();
 
        dss_uninit_overlays(pdev);
        dss_uninit_overlay_managers(pdev);
@@ -965,11 +560,6 @@ static void __exit omap_dss_exit(void)
                core.vdds_sdi_reg = NULL;
        }
 
-       if (core.vdda_dac_reg != NULL) {
-               regulator_put(core.vdda_dac_reg);
-               core.vdda_dac_reg = NULL;
-       }
-
        platform_driver_unregister(&omap_dss_driver);
 
        omap_dss_bus_unregister();
index 9f8c69f16e619dd1eec954f5ae5eba13c659ec06..7804779c9da150bb2ddf431cc9ac1134ef901e89 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/hardirq.h>
+#include <linux/interrupt.h>
 
 #include <plat/sram.h>
 #include <plat/clock.h>
@@ -42,8 +43,6 @@
 #include "dss_features.h"
 
 /* DISPC */
-#define DISPC_BASE                     0x48050400
-
 #define DISPC_SZ_REGS                  SZ_4K
 
 struct dispc_reg { u16 idx; };
@@ -74,7 +73,7 @@ struct dispc_reg { u16 idx; };
 #define DISPC_TIMING_H(ch)             DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
 #define DISPC_TIMING_V(ch)             DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
 #define DISPC_POL_FREQ(ch)             DISPC_REG(ch != 2 ? 0x006C : 0x0408)
-#define DISPC_DIVISOR(ch)              DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
+#define DISPC_DIVISORo(ch)             DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
 #define DISPC_GLOBAL_ALPHA             DISPC_REG(0x0074)
 #define DISPC_SIZE_DIG                 DISPC_REG(0x0078)
 #define DISPC_SIZE_LCD(ch)             DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
@@ -129,6 +128,7 @@ struct dispc_reg { u16 idx; };
 
 #define DISPC_VID_PRELOAD(n)           DISPC_REG(0x230 + (n)*0x04)
 
+#define DISPC_DIVISOR                  DISPC_REG(0x0804)
 
 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
                                         DISPC_IRQ_OCP_ERR | \
@@ -178,7 +178,9 @@ struct dispc_irq_stats {
 };
 
 static struct {
+       struct platform_device *pdev;
        void __iomem    *base;
+       int irq;
 
        u32     fifo_size[3];
 
@@ -230,7 +232,7 @@ void dispc_save_context(void)
        SR(TIMING_H(0));
        SR(TIMING_V(0));
        SR(POL_FREQ(0));
-       SR(DIVISOR(0));
+       SR(DIVISORo(0));
        SR(GLOBAL_ALPHA);
        SR(SIZE_DIG);
        SR(SIZE_LCD(0));
@@ -242,7 +244,7 @@ void dispc_save_context(void)
                SR(TIMING_H(2));
                SR(TIMING_V(2));
                SR(POL_FREQ(2));
-               SR(DIVISOR(2));
+               SR(DIVISORo(2));
                SR(CONFIG2);
        }
 
@@ -373,6 +375,9 @@ void dispc_save_context(void)
        SR(VID_FIR_COEF_V(1, 7));
 
        SR(VID_PRELOAD(1));
+
+       if (dss_has_feature(FEAT_CORE_CLK_DIV))
+               SR(DIVISOR);
 }
 
 void dispc_restore_context(void)
@@ -389,7 +394,7 @@ void dispc_restore_context(void)
        RR(TIMING_H(0));
        RR(TIMING_V(0));
        RR(POL_FREQ(0));
-       RR(DIVISOR(0));
+       RR(DIVISORo(0));
        RR(GLOBAL_ALPHA);
        RR(SIZE_DIG);
        RR(SIZE_LCD(0));
@@ -400,7 +405,7 @@ void dispc_restore_context(void)
                RR(TIMING_H(2));
                RR(TIMING_V(2));
                RR(POL_FREQ(2));
-               RR(DIVISOR(2));
+               RR(DIVISORo(2));
                RR(CONFIG2);
        }
 
@@ -532,6 +537,9 @@ void dispc_restore_context(void)
 
        RR(VID_PRELOAD(1));
 
+       if (dss_has_feature(FEAT_CORE_CLK_DIV))
+               RR(DIVISOR);
+
        /* enable last, because LCD & DIGIT enable are here */
        RR(CONTROL);
        if (dss_has_feature(FEAT_MGR_LCD2))
@@ -552,9 +560,9 @@ void dispc_restore_context(void)
 static inline void enable_clocks(bool enable)
 {
        if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 bool dispc_go_busy(enum omap_channel channel)
@@ -1000,6 +1008,20 @@ void dispc_set_burst_size(enum omap_plane plane,
        enable_clocks(0);
 }
 
+void dispc_enable_gamma_table(bool enable)
+{
+       /*
+        * This is partially implemented to support only disabling of
+        * the gamma table.
+        */
+       if (enable) {
+               DSSWARN("Gamma table enabling for TV not yet supported");
+               return;
+       }
+
+       REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
+}
+
 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 {
        u32 val;
@@ -1129,10 +1151,16 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
        u32 val;
        const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
                                      DISPC_VID_ACCU0(1) };
+       u8 hor_start, hor_end, vert_start, vert_end;
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+       dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+       dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+       val = FLD_VAL(vaccu, vert_start, vert_end) |
+                       FLD_VAL(haccu, hor_start, hor_end);
+
        dispc_write_reg(ac0_reg[plane-1], val);
 }
 
@@ -1141,10 +1169,16 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
        u32 val;
        const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
                                      DISPC_VID_ACCU1(1) };
+       u8 hor_start, hor_end, vert_start, vert_end;
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
+       dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
+       dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
+
+       val = FLD_VAL(vaccu, vert_start, vert_end) |
+                       FLD_VAL(haccu, hor_start, hor_end);
+
        dispc_write_reg(ac1_reg[plane-1], val);
 }
 
@@ -1182,16 +1216,25 @@ static void _dispc_set_scaling(enum omap_plane plane,
        _dispc_set_fir(plane, fir_hinc, fir_vinc);
 
        l = dispc_read_reg(dispc_reg_att[plane]);
-       l &= ~((0x0f << 5) | (0x3 << 21));
 
+       /* RESIZEENABLE and VERTICALTAPS */
+       l &= ~((0x3 << 5) | (0x1 << 21));
        l |= fir_hinc ? (1 << 5) : 0;
        l |= fir_vinc ? (1 << 6) : 0;
+       l |= five_taps ? (1 << 21) : 0;
 
-       l |= hscaleup ? 0 : (1 << 7);
-       l |= vscaleup ? 0 : (1 << 8);
+       /* VRESIZECONF and HRESIZECONF */
+       if (dss_has_feature(FEAT_RESIZECONF)) {
+               l &= ~(0x3 << 7);
+               l |= hscaleup ? 0 : (1 << 7);
+               l |= vscaleup ? 0 : (1 << 8);
+       }
 
-       l |= five_taps ? (1 << 21) : 0;
-       l |= five_taps ? (1 << 22) : 0;
+       /* LINEBUFFERSPLIT */
+       if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
+               l &= ~(0x1 << 22);
+               l |= five_taps ? (1 << 22) : 0;
+       }
 
        dispc_write_reg(dispc_reg_att[plane], l);
 
@@ -1215,9 +1258,11 @@ static void _dispc_set_scaling(enum omap_plane plane,
 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                bool mirroring, enum omap_color_mode color_mode)
 {
+       bool row_repeat = false;
+       int vidrot = 0;
+
        if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY) {
-               int vidrot = 0;
 
                if (mirroring) {
                        switch (rotation) {
@@ -1251,16 +1296,15 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                        }
                }
 
-               REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
-
                if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
-                       REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
+                       row_repeat = true;
                else
-                       REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
-       } else {
-               REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
-               REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
+                       row_repeat = false;
        }
+
+       REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+       if (dss_has_feature(FEAT_ROWREPEATENABLE))
+               REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
 }
 
 static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -2293,7 +2337,7 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
        BUG_ON(pck_div < 2);
 
        enable_clocks(1);
-       dispc_write_reg(DISPC_DIVISOR(channel),
+       dispc_write_reg(DISPC_DIVISORo(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
        enable_clocks(0);
 }
@@ -2302,7 +2346,7 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
                int *pck_div)
 {
        u32 l;
-       l = dispc_read_reg(DISPC_DIVISOR(channel));
+       l = dispc_read_reg(DISPC_DIVISORo(channel));
        *lck_div = FLD_GET(l, 23, 16);
        *pck_div = FLD_GET(l, 7, 0);
 }
@@ -2311,14 +2355,17 @@ unsigned long dispc_fclk_rate(void)
 {
        unsigned long r = 0;
 
-       if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
-               r = dss_clk_get_rate(DSS_CLK_FCK1);
-       else
-#ifdef CONFIG_OMAP2_DSS_DSI
-               r = dsi_get_dsi1_pll_rate();
-#else
-       BUG();
-#endif
+       switch (dss_get_dispc_clk_source()) {
+       case DSS_CLK_SRC_FCK:
+               r = dss_clk_get_rate(DSS_CLK_FCK);
+               break;
+       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               r = dsi_get_pll_hsdiv_dispc_rate();
+               break;
+       default:
+               BUG();
+       }
+
        return r;
 }
 
@@ -2328,47 +2375,72 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
        unsigned long r;
        u32 l;
 
-       l = dispc_read_reg(DISPC_DIVISOR(channel));
+       l = dispc_read_reg(DISPC_DIVISORo(channel));
 
        lcd = FLD_GET(l, 23, 16);
 
-       r = dispc_fclk_rate();
+       switch (dss_get_lcd_clk_source(channel)) {
+       case DSS_CLK_SRC_FCK:
+               r = dss_clk_get_rate(DSS_CLK_FCK);
+               break;
+       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               r = dsi_get_pll_hsdiv_dispc_rate();
+               break;
+       default:
+               BUG();
+       }
 
        return r / lcd;
 }
 
 unsigned long dispc_pclk_rate(enum omap_channel channel)
 {
-       int lcd, pcd;
+       int pcd;
        unsigned long r;
        u32 l;
 
-       l = dispc_read_reg(DISPC_DIVISOR(channel));
+       l = dispc_read_reg(DISPC_DIVISORo(channel));
 
-       lcd = FLD_GET(l, 23, 16);
        pcd = FLD_GET(l, 7, 0);
 
-       r = dispc_fclk_rate();
+       r = dispc_lclk_rate(channel);
 
-       return r / lcd / pcd;
+       return r / pcd;
 }
 
 void dispc_dump_clocks(struct seq_file *s)
 {
        int lcd, pcd;
+       u32 l;
+       enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+       enum dss_clk_source lcd_clk_src;
 
        enable_clocks(1);
 
        seq_printf(s, "- DISPC -\n");
 
-       seq_printf(s, "dispc fclk source = %s\n",
-                       dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
-                       "dss1_alwon_fclk" : "dsi1_pll_fclk");
+       seq_printf(s, "dispc fclk source = %s (%s)\n",
+                       dss_get_generic_clk_source_name(dispc_clk_src),
+                       dss_feat_get_clk_source_name(dispc_clk_src));
 
        seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
 
+       if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+               seq_printf(s, "- DISPC-CORE-CLK -\n");
+               l = dispc_read_reg(DISPC_DIVISOR);
+               lcd = FLD_GET(l, 23, 16);
+
+               seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
+                               (dispc_fclk_rate()/lcd), lcd);
+       }
        seq_printf(s, "- LCD1 -\n");
 
+       lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD);
+
+       seq_printf(s, "lcd1_clk source = %s (%s)\n",
+               dss_get_generic_clk_source_name(lcd_clk_src),
+               dss_feat_get_clk_source_name(lcd_clk_src));
+
        dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
 
        seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2378,6 +2450,12 @@ void dispc_dump_clocks(struct seq_file *s)
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                seq_printf(s, "- LCD2 -\n");
 
+               lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2);
+
+               seq_printf(s, "lcd2_clk source = %s (%s)\n",
+                       dss_get_generic_clk_source_name(lcd_clk_src),
+                       dss_feat_get_clk_source_name(lcd_clk_src));
+
                dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
 
                seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
@@ -2440,7 +2518,7 @@ void dispc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        DUMPREG(DISPC_REVISION);
        DUMPREG(DISPC_SYSCONFIG);
@@ -2459,7 +2537,7 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_TIMING_H(0));
        DUMPREG(DISPC_TIMING_V(0));
        DUMPREG(DISPC_POL_FREQ(0));
-       DUMPREG(DISPC_DIVISOR(0));
+       DUMPREG(DISPC_DIVISORo(0));
        DUMPREG(DISPC_GLOBAL_ALPHA);
        DUMPREG(DISPC_SIZE_DIG);
        DUMPREG(DISPC_SIZE_LCD(0));
@@ -2471,7 +2549,7 @@ void dispc_dump_regs(struct seq_file *s)
                DUMPREG(DISPC_TIMING_H(2));
                DUMPREG(DISPC_TIMING_V(2));
                DUMPREG(DISPC_POL_FREQ(2));
-               DUMPREG(DISPC_DIVISOR(2));
+               DUMPREG(DISPC_DIVISORo(2));
                DUMPREG(DISPC_SIZE_LCD(2));
        }
 
@@ -2597,7 +2675,7 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_VID_PRELOAD(0));
        DUMPREG(DISPC_VID_PRELOAD(1));
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
@@ -2713,8 +2791,8 @@ int dispc_get_clock_div(enum omap_channel channel,
 
        fck = dispc_fclk_rate();
 
-       cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
-       cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
+       cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
+       cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
 
        cinfo->lck = fck / cinfo->lck_div;
        cinfo->pck = cinfo->lck / cinfo->pck_div;
@@ -2791,6 +2869,9 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
                break;
        }
 
+       if (ret)
+               goto err;
+
        _omap_dispc_set_irqs();
 
        spin_unlock_irqrestore(&dispc.irq_lock, flags);
@@ -2866,10 +2947,10 @@ static void print_irq_status(u32 status)
  * but we presume they are on because we got an IRQ. However,
  * an irq handler may turn the clocks off, so we may not have
  * clock later in the function. */
-void dispc_irq_handler(void)
+static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
 {
        int i;
-       u32 irqstatus;
+       u32 irqstatus, irqenable;
        u32 handledirqs = 0;
        u32 unhandled_errors;
        struct omap_dispc_isr_data *isr_data;
@@ -2878,6 +2959,13 @@ void dispc_irq_handler(void)
        spin_lock(&dispc.irq_lock);
 
        irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
+       irqenable = dispc_read_reg(DISPC_IRQENABLE);
+
+       /* IRQ is not for us */
+       if (!(irqstatus & irqenable)) {
+               spin_unlock(&dispc.irq_lock);
+               return IRQ_NONE;
+       }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
        spin_lock(&dispc.irq_stats_lock);
@@ -2929,6 +3017,8 @@ void dispc_irq_handler(void)
        }
 
        spin_unlock(&dispc.irq_lock);
+
+       return IRQ_HANDLED;
 }
 
 static void dispc_error_worker(struct work_struct *work)
@@ -3253,6 +3343,15 @@ static void _omap_dispc_initial_config(void)
        l = FLD_MOD(l, 1, 0, 0);        /* AUTOIDLE */
        dispc_write_reg(DISPC_SYSCONFIG, l);
 
+       /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
+       if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
+               l = dispc_read_reg(DISPC_DIVISOR);
+               /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
+               l = FLD_MOD(l, 1, 0, 0);
+               l = FLD_MOD(l, 1, 23, 16);
+               dispc_write_reg(DISPC_DIVISOR, l);
+       }
+
        /* FUNCGATED */
        if (dss_has_feature(FEAT_FUNCGATED))
                REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
@@ -3269,47 +3368,6 @@ static void _omap_dispc_initial_config(void)
        dispc_read_plane_fifo_sizes();
 }
 
-int dispc_init(void)
-{
-       u32 rev;
-
-       spin_lock_init(&dispc.irq_lock);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-       spin_lock_init(&dispc.irq_stats_lock);
-       dispc.irq_stats.last_reset = jiffies;
-#endif
-
-       INIT_WORK(&dispc.error_work, dispc_error_worker);
-
-       dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
-       if (!dispc.base) {
-               DSSERR("can't ioremap DISPC\n");
-               return -ENOMEM;
-       }
-
-       enable_clocks(1);
-
-       _omap_dispc_initial_config();
-
-       _omap_dispc_initialize_irq();
-
-       dispc_save_context();
-
-       rev = dispc_read_reg(DISPC_REVISION);
-       printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
-              FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
-       enable_clocks(0);
-
-       return 0;
-}
-
-void dispc_exit(void)
-{
-       iounmap(dispc.base);
-}
-
 int dispc_enable_plane(enum omap_plane plane, bool enable)
 {
        DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
@@ -3359,3 +3417,94 @@ int dispc_setup_plane(enum omap_plane plane,
 
        return r;
 }
+
+/* DISPC HW IP initialisation */
+static int omap_dispchw_probe(struct platform_device *pdev)
+{
+       u32 rev;
+       int r = 0;
+       struct resource *dispc_mem;
+
+       dispc.pdev = pdev;
+
+       spin_lock_init(&dispc.irq_lock);
+
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+       spin_lock_init(&dispc.irq_stats_lock);
+       dispc.irq_stats.last_reset = jiffies;
+#endif
+
+       INIT_WORK(&dispc.error_work, dispc_error_worker);
+
+       dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
+       if (!dispc_mem) {
+               DSSERR("can't get IORESOURCE_MEM DISPC\n");
+               r = -EINVAL;
+               goto fail0;
+       }
+       dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
+       if (!dispc.base) {
+               DSSERR("can't ioremap DISPC\n");
+               r = -ENOMEM;
+               goto fail0;
+       }
+       dispc.irq = platform_get_irq(dispc.pdev, 0);
+       if (dispc.irq < 0) {
+               DSSERR("platform_get_irq failed\n");
+               r = -ENODEV;
+               goto fail1;
+       }
+
+       r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
+               "OMAP DISPC", dispc.pdev);
+       if (r < 0) {
+               DSSERR("request_irq failed\n");
+               goto fail1;
+       }
+
+       enable_clocks(1);
+
+       _omap_dispc_initial_config();
+
+       _omap_dispc_initialize_irq();
+
+       dispc_save_context();
+
+       rev = dispc_read_reg(DISPC_REVISION);
+       dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
+              FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+       enable_clocks(0);
+
+       return 0;
+fail1:
+       iounmap(dispc.base);
+fail0:
+       return r;
+}
+
+static int omap_dispchw_remove(struct platform_device *pdev)
+{
+       free_irq(dispc.irq, dispc.pdev);
+       iounmap(dispc.base);
+       return 0;
+}
+
+static struct platform_driver omap_dispchw_driver = {
+       .probe          = omap_dispchw_probe,
+       .remove         = omap_dispchw_remove,
+       .driver         = {
+               .name   = "omapdss_dispc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int dispc_init_platform_driver(void)
+{
+       return platform_driver_register(&omap_dispchw_driver);
+}
+
+void dispc_uninit_platform_driver(void)
+{
+       return platform_driver_unregister(&omap_dispchw_driver);
+}
index 22dd7a474f79bd8fae54987dd66f01ac554fb8e6..a85a6f38b40c126661e3cf9e61febef169d53fcc 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
-#include <linux/list.h>
 #include <linux/platform_device.h>
 
 #include <plat/display.h>
 #include "dss.h"
 
-static LIST_HEAD(display_list);
-
 static ssize_t display_enabled_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -345,6 +342,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
                        return 16;
        case OMAP_DISPLAY_TYPE_VENC:
        case OMAP_DISPLAY_TYPE_SDI:
+       case OMAP_DISPLAY_TYPE_HDMI:
                return 24;
        default:
                BUG();
@@ -371,6 +369,7 @@ bool dss_use_replication(struct omap_dss_device *dssdev,
        case OMAP_DISPLAY_TYPE_DPI:
                bpp = dssdev->phy.dpi.data_lines;
                break;
+       case OMAP_DISPLAY_TYPE_HDMI:
        case OMAP_DISPLAY_TYPE_VENC:
        case OMAP_DISPLAY_TYPE_SDI:
                bpp = 24;
@@ -393,29 +392,6 @@ void dss_init_device(struct platform_device *pdev,
        int i;
        int r;
 
-       switch (dssdev->type) {
-#ifdef CONFIG_OMAP2_DSS_DPI
-       case OMAP_DISPLAY_TYPE_DPI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_RFBI
-       case OMAP_DISPLAY_TYPE_DBI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_SDI
-       case OMAP_DISPLAY_TYPE_SDI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
-       case OMAP_DISPLAY_TYPE_DSI:
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
-       case OMAP_DISPLAY_TYPE_VENC:
-#endif
-               break;
-       default:
-               DSSERR("Support for display '%s' not compiled in.\n",
-                               dssdev->name);
-               return;
-       }
-
        switch (dssdev->type) {
 #ifdef CONFIG_OMAP2_DSS_DPI
        case OMAP_DISPLAY_TYPE_DPI:
@@ -442,8 +418,13 @@ void dss_init_device(struct platform_device *pdev,
                r = dsi_init_display(dssdev);
                break;
 #endif
+       case OMAP_DISPLAY_TYPE_HDMI:
+               r = hdmi_init_display(dssdev);
+               break;
        default:
-               BUG();
+               DSSERR("Support for display '%s' not compiled in.\n",
+                               dssdev->name);
+               return;
        }
 
        if (r) {
index 75fb0a5154304a92bbe5b0164a1257064436d2ec..2d3ca4ca4a05b14583b89f5cf9e622edef4a72cd 100644 (file)
@@ -57,13 +57,13 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
        if (r)
                return r;
 
-       dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
+       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
 
        r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
                return r;
 
-       *fck = dsi_cinfo.dsi1_pll_fclk;
+       *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
        *lck_div = dispc_cinfo.lck_div;
        *pck_div = dispc_cinfo.pck_div;
 
@@ -107,7 +107,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        bool is_tft;
        int r = 0;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
@@ -137,7 +137,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        dispc_set_lcd_timings(dssdev->manager->id, t);
 
 err0:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
        return r;
 }
 
@@ -173,14 +173,14 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
                        goto err1;
        }
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        r = dpi_basic_init(dssdev);
        if (r)
                goto err2;
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_clk_enable(DSS_CLK_FCK2);
+       dss_clk_enable(DSS_CLK_SYSCK);
        r = dsi_pll_init(dssdev, 0, 1);
        if (r)
                goto err3;
@@ -199,10 +199,10 @@ err4:
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
        dsi_pll_uninit();
 err3:
-       dss_clk_disable(DSS_CLK_FCK2);
+       dss_clk_disable(DSS_CLK_SYSCK);
 #endif
 err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
 err1:
@@ -217,12 +217,12 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
        dssdev->manager->disable(dssdev->manager);
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
        dsi_pll_uninit();
-       dss_clk_disable(DSS_CLK_FCK2);
+       dss_clk_disable(DSS_CLK_SYSCK);
 #endif
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
@@ -271,7 +271,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                if (r)
                        return r;
 
-               fck = dsi_cinfo.dsi1_pll_fclk;
+               fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
                lck_div = dispc_cinfo.lck_div;
                pck_div = dispc_cinfo.pck_div;
        }
@@ -303,22 +303,27 @@ int dpi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
 
-       return 0;
-}
+       if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
+               struct regulator *vdds_dsi;
 
-int dpi_init(struct platform_device *pdev)
-{
-       if (cpu_is_omap34xx()) {
-               dpi.vdds_dsi_reg = dss_get_vdds_dsi();
-               if (IS_ERR(dpi.vdds_dsi_reg)) {
+               vdds_dsi = dss_get_vdds_dsi();
+
+               if (IS_ERR(vdds_dsi)) {
                        DSSERR("can't get VDDS_DSI regulator\n");
-                       return PTR_ERR(dpi.vdds_dsi_reg);
+                       return PTR_ERR(vdds_dsi);
                }
+
+               dpi.vdds_dsi_reg = vdds_dsi;
        }
 
        return 0;
 }
 
+int dpi_init(void)
+{
+       return 0;
+}
+
 void dpi_exit(void)
 {
 }
index ddf3a05608228ac58c83f0c3246a43631a202e08..0a7f1a47f8e3b5fb0b30c369f971dd77146490b4 100644 (file)
 #include <plat/clock.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 /*#define VERBOSE_IRQ*/
 #define DSI_CATCH_MISSING_TE
 
-#define DSI_BASE               0x4804FC00
-
 struct dsi_reg { u16 idx; };
 
 #define DSI_REG(idx)           ((const struct dsi_reg) { idx })
@@ -186,13 +185,15 @@ struct dsi_reg { u16 idx; };
 #define DSI_DT_RX_SHORT_READ_1         0x21
 #define DSI_DT_RX_SHORT_READ_2         0x22
 
-#define FINT_MAX 2100000
-#define FINT_MIN 750000
-#define REGN_MAX (1 << 7)
-#define REGM_MAX ((1 << 11) - 1)
-#define REGM3_MAX (1 << 4)
-#define REGM4_MAX (1 << 4)
-#define LP_DIV_MAX ((1 << 13) - 1)
+typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+
+#define DSI_MAX_NR_ISRS                2
+
+struct dsi_isr_data {
+       omap_dsi_isr_t  isr;
+       void            *arg;
+       u32             mask;
+};
 
 enum fifo_size {
        DSI_FIFO_SIZE_0         = 0,
@@ -220,9 +221,17 @@ struct dsi_irq_stats {
        unsigned cio_irqs[32];
 };
 
+struct dsi_isr_tables {
+       struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
+       struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
+       struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
+};
+
 static struct
 {
+       struct platform_device *pdev;
        void __iomem    *base;
+       int irq;
 
        struct dsi_clock_info current_cinfo;
 
@@ -232,6 +241,7 @@ static struct
                enum dsi_vc_mode mode;
                struct omap_dss_device *dssdev;
                enum fifo_size fifo_size;
+               int vc_id;
        } vc[4];
 
        struct mutex lock;
@@ -239,8 +249,10 @@ static struct
 
        unsigned pll_locked;
 
-       struct completion bta_completion;
-       void (*bta_callback)(void);
+       spinlock_t irq_lock;
+       struct dsi_isr_tables isr_tables;
+       /* space for a copy used by the interrupt handler */
+       struct dsi_isr_tables isr_tables_copy;
 
        int update_channel;
        struct dsi_update_region update_region;
@@ -275,6 +287,11 @@ static struct
        spinlock_t irq_stats_lock;
        struct dsi_irq_stats irq_stats;
 #endif
+       /* DSI PLL Parameter Ranges */
+       unsigned long regm_max, regn_max;
+       unsigned long  regm_dispc_max, regm_dsi_max;
+       unsigned long  fint_min, fint_max;
+       unsigned long lpdiv_max;
 } dsi;
 
 #ifdef DEBUG
@@ -318,6 +335,11 @@ static bool dsi_bus_is_locked(void)
        return dsi.bus_lock.count == 0;
 }
 
+static void dsi_completion_handler(void *data, u32 mask)
+{
+       complete((struct completion *)data);
+}
+
 static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
                int value)
 {
@@ -387,6 +409,9 @@ static void dsi_perf_show(const char *name)
 
 static void print_irq_status(u32 status)
 {
+       if (status == 0)
+               return;
+
 #ifndef VERBOSE_IRQ
        if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
                return;
@@ -422,6 +447,9 @@ static void print_irq_status(u32 status)
 
 static void print_irq_status_vc(int channel, u32 status)
 {
+       if (status == 0)
+               return;
+
 #ifndef VERBOSE_IRQ
        if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
                return;
@@ -448,6 +476,9 @@ static void print_irq_status_vc(int channel, u32 status)
 
 static void print_irq_status_cio(u32 status)
 {
+       if (status == 0)
+               return;
+
        printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
 
 #define PIS(x) \
@@ -478,22 +509,33 @@ static void print_irq_status_cio(u32 status)
        printk("\n");
 }
 
-static int debug_irq;
-
-/* called from dss */
-void dsi_irq_handler(void)
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
 {
-       u32 irqstatus, vcstatus, ciostatus;
        int i;
 
-       irqstatus = dsi_read_reg(DSI_IRQSTATUS);
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
        spin_lock(&dsi.irq_stats_lock);
+
        dsi.irq_stats.irq_count++;
        dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+
+       for (i = 0; i < 4; ++i)
+               dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+
+       dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+
+       spin_unlock(&dsi.irq_stats_lock);
+}
+#else
+#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
 #endif
 
+static int debug_irq;
+
+static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+       int i;
+
        if (irqstatus & DSI_IRQ_ERROR_MASK) {
                DSSERR("DSI error, irqstatus %x\n", irqstatus);
                print_irq_status(irqstatus);
@@ -504,37 +546,88 @@ void dsi_irq_handler(void)
                print_irq_status(irqstatus);
        }
 
-#ifdef DSI_CATCH_MISSING_TE
-       if (irqstatus & DSI_IRQ_TE_TRIGGER)
-               del_timer(&dsi.te_timer);
-#endif
+       for (i = 0; i < 4; ++i) {
+               if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
+                       DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+                                      i, vcstatus[i]);
+                       print_irq_status_vc(i, vcstatus[i]);
+               } else if (debug_irq) {
+                       print_irq_status_vc(i, vcstatus[i]);
+               }
+       }
+
+       if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+               DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+               print_irq_status_cio(ciostatus);
+       } else if (debug_irq) {
+               print_irq_status_cio(ciostatus);
+       }
+}
+
+static void dsi_call_isrs(struct dsi_isr_data *isr_array,
+               unsigned isr_array_size, u32 irqstatus)
+{
+       struct dsi_isr_data *isr_data;
+       int i;
+
+       for (i = 0; i < isr_array_size; i++) {
+               isr_data = &isr_array[i];
+               if (isr_data->isr && isr_data->mask & irqstatus)
+                       isr_data->isr(isr_data->arg, irqstatus);
+       }
+}
+
+static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
+               u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+       int i;
+
+       dsi_call_isrs(isr_tables->isr_table,
+                       ARRAY_SIZE(isr_tables->isr_table),
+                       irqstatus);
 
        for (i = 0; i < 4; ++i) {
-               if ((irqstatus & (1<<i)) == 0)
+               if (vcstatus[i] == 0)
                        continue;
+               dsi_call_isrs(isr_tables->isr_table_vc[i],
+                               ARRAY_SIZE(isr_tables->isr_table_vc[i]),
+                               vcstatus[i]);
+       }
 
-               vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+       if (ciostatus != 0)
+               dsi_call_isrs(isr_tables->isr_table_cio,
+                               ARRAY_SIZE(isr_tables->isr_table_cio),
+                               ciostatus);
+}
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-               dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
-#endif
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+{
+       u32 irqstatus, vcstatus[4], ciostatus;
+       int i;
 
-               if (vcstatus & DSI_VC_IRQ_BTA) {
-                       complete(&dsi.bta_completion);
+       spin_lock(&dsi.irq_lock);
 
-                       if (dsi.bta_callback)
-                               dsi.bta_callback();
-               }
+       irqstatus = dsi_read_reg(DSI_IRQSTATUS);
 
-               if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
-                       DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
-                                      i, vcstatus);
-                       print_irq_status_vc(i, vcstatus);
-               } else if (debug_irq) {
-                       print_irq_status_vc(i, vcstatus);
+       /* IRQ is not for us */
+       if (!irqstatus) {
+               spin_unlock(&dsi.irq_lock);
+               return IRQ_NONE;
+       }
+
+       dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+       /* flush posted write */
+       dsi_read_reg(DSI_IRQSTATUS);
+
+       for (i = 0; i < 4; ++i) {
+               if ((irqstatus & (1 << i)) == 0) {
+                       vcstatus[i] = 0;
+                       continue;
                }
 
-               dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
+               vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+
+               dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
                /* flush posted write */
                dsi_read_reg(DSI_VC_IRQSTATUS(i));
        }
@@ -542,117 +635,307 @@ void dsi_irq_handler(void)
        if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
                ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-               dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
-#endif
-
                dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
                /* flush posted write */
                dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+       } else {
+               ciostatus = 0;
+       }
 
-               if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
-                       DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
-                       print_irq_status_cio(ciostatus);
-               } else if (debug_irq) {
-                       print_irq_status_cio(ciostatus);
-               }
+#ifdef DSI_CATCH_MISSING_TE
+       if (irqstatus & DSI_IRQ_TE_TRIGGER)
+               del_timer(&dsi.te_timer);
+#endif
+
+       /* make a copy and unlock, so that isrs can unregister
+        * themselves */
+       memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+
+       spin_unlock(&dsi.irq_lock);
+
+       dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+
+       dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+
+       dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
+
+       return IRQ_HANDLED;
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+               unsigned isr_array_size, u32 default_mask,
+               const struct dsi_reg enable_reg,
+               const struct dsi_reg status_reg)
+{
+       struct dsi_isr_data *isr_data;
+       u32 mask;
+       u32 old_mask;
+       int i;
+
+       mask = default_mask;
+
+       for (i = 0; i < isr_array_size; i++) {
+               isr_data = &isr_array[i];
+
+               if (isr_data->isr == NULL)
+                       continue;
+
+               mask |= isr_data->mask;
        }
 
-       dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
-       /* flush posted write */
-       dsi_read_reg(DSI_IRQSTATUS);
+       old_mask = dsi_read_reg(enable_reg);
+       /* clear the irqstatus for newly enabled irqs */
+       dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
+       dsi_write_reg(enable_reg, mask);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-       spin_unlock(&dsi.irq_stats_lock);
+       /* flush posted writes */
+       dsi_read_reg(enable_reg);
+       dsi_read_reg(status_reg);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(void)
+{
+       u32 mask = DSI_IRQ_ERROR_MASK;
+#ifdef DSI_CATCH_MISSING_TE
+       mask |= DSI_IRQ_TE_TRIGGER;
 #endif
+       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+                       DSI_IRQENABLE, DSI_IRQSTATUS);
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(int vc)
+{
+       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+                       DSI_VC_IRQ_ERROR_MASK,
+                       DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
 }
 
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(void)
+{
+       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+                       DSI_CIO_IRQ_ERROR_MASK,
+                       DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+}
 
 static void _dsi_initialize_irq(void)
 {
-       u32 l;
+       unsigned long flags;
+       int vc;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+
+       _omap_dsi_set_irqs();
+       for (vc = 0; vc < 4; ++vc)
+               _omap_dsi_set_irqs_vc(vc);
+       _omap_dsi_set_irqs_cio();
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+}
+
+static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+               struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+       struct dsi_isr_data *isr_data;
+       int free_idx;
        int i;
 
-       /* disable all interrupts */
-       dsi_write_reg(DSI_IRQENABLE, 0);
-       for (i = 0; i < 4; ++i)
-               dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
-       dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
+       BUG_ON(isr == NULL);
 
-       /* clear interrupt status */
-       l = dsi_read_reg(DSI_IRQSTATUS);
-       dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
+       /* check for duplicate entry and find a free slot */
+       free_idx = -1;
+       for (i = 0; i < isr_array_size; i++) {
+               isr_data = &isr_array[i];
 
-       for (i = 0; i < 4; ++i) {
-               l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
-               dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
+               if (isr_data->isr == isr && isr_data->arg == arg &&
+                               isr_data->mask == mask) {
+                       return -EINVAL;
+               }
+
+               if (isr_data->isr == NULL && free_idx == -1)
+                       free_idx = i;
        }
 
-       l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
-       dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
+       if (free_idx == -1)
+               return -EBUSY;
 
-       /* enable error irqs */
-       l = DSI_IRQ_ERROR_MASK;
-#ifdef DSI_CATCH_MISSING_TE
-       l |= DSI_IRQ_TE_TRIGGER;
-#endif
-       dsi_write_reg(DSI_IRQENABLE, l);
+       isr_data = &isr_array[free_idx];
+       isr_data->isr = isr;
+       isr_data->arg = arg;
+       isr_data->mask = mask;
 
-       l = DSI_VC_IRQ_ERROR_MASK;
-       for (i = 0; i < 4; ++i)
-               dsi_write_reg(DSI_VC_IRQENABLE(i), l);
+       return 0;
+}
+
+static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+               struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+       struct dsi_isr_data *isr_data;
+       int i;
+
+       for (i = 0; i < isr_array_size; i++) {
+               isr_data = &isr_array[i];
+               if (isr_data->isr != isr || isr_data->arg != arg ||
+                               isr_data->mask != mask)
+                       continue;
+
+               isr_data->isr = NULL;
+               isr_data->arg = NULL;
+               isr_data->mask = 0;
+
+               return 0;
+       }
 
-       l = DSI_CIO_IRQ_ERROR_MASK;
-       dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
+       return -EINVAL;
 }
 
-static u32 dsi_get_errors(void)
+static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
 {
        unsigned long flags;
-       u32 e;
-       spin_lock_irqsave(&dsi.errors_lock, flags);
-       e = dsi.errors;
-       dsi.errors = 0;
-       spin_unlock_irqrestore(&dsi.errors_lock, flags);
-       return e;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+       if (r == 0)
+               _omap_dsi_set_irqs();
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+       return r;
 }
 
-static void dsi_vc_enable_bta_irq(int channel)
+static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
 {
-       u32 l;
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+       if (r == 0)
+               _omap_dsi_set_irqs();
 
-       dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
 
-       l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-       l |= DSI_VC_IRQ_BTA;
-       dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+       return r;
 }
 
-static void dsi_vc_disable_bta_irq(int channel)
+static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+               u32 mask)
 {
-       u32 l;
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_register_isr(isr, arg, mask,
+                       dsi.isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+       if (r == 0)
+               _omap_dsi_set_irqs_vc(channel);
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+       return r;
+}
+
+static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+               u32 mask)
+{
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_unregister_isr(isr, arg, mask,
+                       dsi.isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+       if (r == 0)
+               _omap_dsi_set_irqs_vc(channel);
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+       return r;
+}
+
+static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+       if (r == 0)
+               _omap_dsi_set_irqs_cio();
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+       return r;
+}
+
+static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&dsi.irq_lock, flags);
+
+       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+       if (r == 0)
+               _omap_dsi_set_irqs_cio();
+
+       spin_unlock_irqrestore(&dsi.irq_lock, flags);
 
-       l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-       l &= ~DSI_VC_IRQ_BTA;
-       dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
+       return r;
 }
 
-/* DSI func clock. this could also be DSI2_PLL_FCLK */
+static u32 dsi_get_errors(void)
+{
+       unsigned long flags;
+       u32 e;
+       spin_lock_irqsave(&dsi.errors_lock, flags);
+       e = dsi.errors;
+       dsi.errors = 0;
+       spin_unlock_irqrestore(&dsi.errors_lock, flags);
+       return e;
+}
+
+/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
 static inline void enable_clocks(bool enable)
 {
        if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
 static inline void dsi_enable_pll_clock(bool enable)
 {
        if (enable)
-               dss_clk_enable(DSS_CLK_FCK2);
+               dss_clk_enable(DSS_CLK_SYSCK);
        else
-               dss_clk_disable(DSS_CLK_FCK2);
+               dss_clk_disable(DSS_CLK_SYSCK);
 
        if (enable && dsi.pll_locked) {
                if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
@@ -707,14 +990,14 @@ static inline int dsi_if_enable(bool enable)
        return 0;
 }
 
-unsigned long dsi_get_dsi1_pll_rate(void)
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
 {
-       return dsi.current_cinfo.dsi1_pll_fclk;
+       return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk;
 }
 
-static unsigned long dsi_get_dsi2_pll_rate(void)
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(void)
 {
-       return dsi.current_cinfo.dsi2_pll_fclk;
+       return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk;
 }
 
 static unsigned long dsi_get_txbyteclkhs(void)
@@ -726,12 +1009,12 @@ static unsigned long dsi_fclk_rate(void)
 {
        unsigned long r;
 
-       if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
-               /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
-               r = dss_clk_get_rate(DSS_CLK_FCK1);
+       if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) {
+               /* DSI FCLK source is DSS_CLK_FCK */
+               r = dss_clk_get_rate(DSS_CLK_FCK);
        } else {
-               /* DSI FCLK source is DSI2_PLL_FCLK */
-               r = dsi_get_dsi2_pll_rate();
+               /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
+               r = dsi_get_pll_hsdiv_dsi_rate();
        }
 
        return r;
@@ -745,7 +1028,7 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
 
        lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
 
-       if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
+       if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
                return -EINVAL;
 
        dsi_fclk = dsi_fclk_rate();
@@ -795,22 +1078,22 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
 static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                struct dsi_clock_info *cinfo)
 {
-       if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
+       if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
                return -EINVAL;
 
-       if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
+       if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
                return -EINVAL;
 
-       if (cinfo->regm3 > REGM3_MAX)
+       if (cinfo->regm_dispc > dsi.regm_dispc_max)
                return -EINVAL;
 
-       if (cinfo->regm4 > REGM4_MAX)
+       if (cinfo->regm_dsi > dsi.regm_dsi_max)
                return -EINVAL;
 
-       if (cinfo->use_dss2_fck) {
-               cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
+       if (cinfo->use_sys_clk) {
+               cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
                /* XXX it is unclear if highfreq should be used
-                * with DSS2_FCK source also */
+                * with DSS_SYS_CLK source also */
                cinfo->highfreq = 0;
        } else {
                cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
@@ -823,7 +1106,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
 
        cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
 
-       if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
+       if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
                return -EINVAL;
 
        cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -831,15 +1114,17 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
        if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
                return -EINVAL;
 
-       if (cinfo->regm3 > 0)
-               cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
+       if (cinfo->regm_dispc > 0)
+               cinfo->dsi_pll_hsdiv_dispc_clk =
+                       cinfo->clkin4ddr / cinfo->regm_dispc;
        else
-               cinfo->dsi1_pll_fclk = 0;
+               cinfo->dsi_pll_hsdiv_dispc_clk = 0;
 
-       if (cinfo->regm4 > 0)
-               cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
+       if (cinfo->regm_dsi > 0)
+               cinfo->dsi_pll_hsdiv_dsi_clk =
+                       cinfo->clkin4ddr / cinfo->regm_dsi;
        else
-               cinfo->dsi2_pll_fclk = 0;
+               cinfo->dsi_pll_hsdiv_dsi_clk = 0;
 
        return 0;
 }
@@ -852,23 +1137,25 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
        struct dispc_clock_info best_dispc;
        int min_fck_per_pck;
        int match = 0;
-       unsigned long dss_clk_fck2;
+       unsigned long dss_sys_clk, max_dss_fck;
+
+       dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
 
-       dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
+       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
        if (req_pck == dsi.cache_req_pck &&
-                       dsi.cache_cinfo.clkin == dss_clk_fck2) {
+                       dsi.cache_cinfo.clkin == dss_sys_clk) {
                DSSDBG("DSI clock info found from cache\n");
                *dsi_cinfo = dsi.cache_cinfo;
-               dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
-                               dispc_cinfo);
+               dispc_find_clk_divs(is_tft, req_pck,
+                       dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
                return 0;
        }
 
        min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
 
        if (min_fck_per_pck &&
-               req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+               req_pck * min_fck_per_pck > max_dss_fck) {
                DSSERR("Requested pixel clock not possible with the current "
                                "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
                                "the constraint off.\n");
@@ -882,24 +1169,24 @@ retry:
        memset(&best_dispc, 0, sizeof(best_dispc));
 
        memset(&cur, 0, sizeof(cur));
-       cur.clkin = dss_clk_fck2;
-       cur.use_dss2_fck = 1;
+       cur.clkin = dss_sys_clk;
+       cur.use_sys_clk = 1;
        cur.highfreq = 0;
 
        /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
        /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
        /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
-       for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
+       for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
                if (cur.highfreq == 0)
                        cur.fint = cur.clkin / cur.regn;
                else
                        cur.fint = cur.clkin / (2 * cur.regn);
 
-               if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
+               if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
                        continue;
 
                /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
-               for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
+               for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
                        unsigned long a, b;
 
                        a = 2 * cur.regm * (cur.clkin/1000);
@@ -909,30 +1196,32 @@ retry:
                        if (cur.clkin4ddr > 1800 * 1000 * 1000)
                                break;
 
-                       /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3  < 173MHz */
-                       for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
-                                       ++cur.regm3) {
+                       /* dsi_pll_hsdiv_dispc_clk(MHz) =
+                        * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
+                       for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
+                                       ++cur.regm_dispc) {
                                struct dispc_clock_info cur_dispc;
-                               cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
+                               cur.dsi_pll_hsdiv_dispc_clk =
+                                       cur.clkin4ddr / cur.regm_dispc;
 
                                /* this will narrow down the search a bit,
                                 * but still give pixclocks below what was
                                 * requested */
-                               if (cur.dsi1_pll_fclk  < req_pck)
+                               if (cur.dsi_pll_hsdiv_dispc_clk  < req_pck)
                                        break;
 
-                               if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
+                               if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
                                        continue;
 
                                if (min_fck_per_pck &&
-                                       cur.dsi1_pll_fclk <
+                                       cur.dsi_pll_hsdiv_dispc_clk <
                                                req_pck * min_fck_per_pck)
                                        continue;
 
                                match = 1;
 
                                dispc_find_clk_divs(is_tft, req_pck,
-                                               cur.dsi1_pll_fclk,
+                                               cur.dsi_pll_hsdiv_dispc_clk,
                                                &cur_dispc);
 
                                if (abs(cur_dispc.pck - req_pck) <
@@ -961,9 +1250,9 @@ found:
                return -EINVAL;
        }
 
-       /* DSI2_PLL_FCLK (regm4) is not used */
-       best.regm4 = 0;
-       best.dsi2_pll_fclk = 0;
+       /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
+       best.regm_dsi = 0;
+       best.dsi_pll_hsdiv_dsi_clk = 0;
 
        if (dsi_cinfo)
                *dsi_cinfo = best;
@@ -982,23 +1271,27 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        int r = 0;
        u32 l;
        int f;
+       u8 regn_start, regn_end, regm_start, regm_end;
+       u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
 
        DSSDBGF();
 
        dsi.current_cinfo.fint = cinfo->fint;
        dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
-       dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
-       dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
+       dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+                       cinfo->dsi_pll_hsdiv_dispc_clk;
+       dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk =
+                       cinfo->dsi_pll_hsdiv_dsi_clk;
 
        dsi.current_cinfo.regn = cinfo->regn;
        dsi.current_cinfo.regm = cinfo->regm;
-       dsi.current_cinfo.regm3 = cinfo->regm3;
-       dsi.current_cinfo.regm4 = cinfo->regm4;
+       dsi.current_cinfo.regm_dispc = cinfo->regm_dispc;
+       dsi.current_cinfo.regm_dsi = cinfo->regm_dsi;
 
        DSSDBG("DSI Fint %ld\n", cinfo->fint);
 
        DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
-                       cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
+                       cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree",
                        cinfo->clkin,
                        cinfo->highfreq);
 
@@ -1015,24 +1308,39 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
 
        DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
 
-       DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
-                       cinfo->regm3, cinfo->dsi1_pll_fclk);
-       DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
-                       cinfo->regm4, cinfo->dsi2_pll_fclk);
+       DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
+               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               cinfo->dsi_pll_hsdiv_dispc_clk);
+       DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
+               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               cinfo->dsi_pll_hsdiv_dsi_clk);
+
+       dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
+       dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
+       dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
+                       &regm_dispc_end);
+       dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
+                       &regm_dsi_end);
 
        REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
 
        l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
        l = FLD_MOD(l, 1, 0, 0);                /* DSI_PLL_STOPMODE */
-       l = FLD_MOD(l, cinfo->regn - 1, 7, 1);  /* DSI_PLL_REGN */
-       l = FLD_MOD(l, cinfo->regm, 18, 8);     /* DSI_PLL_REGM */
-       l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
-                       22, 19);                /* DSI_CLOCK_DIV */
-       l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
-                       26, 23);                /* DSIPROTO_CLOCK_DIV */
+       /* DSI_PLL_REGN */
+       l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
+       /* DSI_PLL_REGM */
+       l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
+       /* DSI_CLOCK_DIV */
+       l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
+                       regm_dispc_start, regm_dispc_end);
+       /* DSIPROTO_CLOCK_DIV */
+       l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
+                       regm_dsi_start, regm_dsi_end);
        dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
 
-       BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
+       BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
        if (cinfo->fint < 1000000)
                f = 0x3;
        else if (cinfo->fint < 1250000)
@@ -1046,7 +1354,7 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
 
        l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
        l = FLD_MOD(l, f, 4, 1);                /* DSI_PLL_FREQSEL */
-       l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
+       l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
                        11, 11);                /* DSI_PLL_CLKSEL */
        l = FLD_MOD(l, cinfo->highfreq,
                        12, 12);                /* DSI_PLL_HIGHFREQ */
@@ -1101,6 +1409,26 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
 
        DSSDBG("PLL init\n");
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+       /*
+        * HACK: this is just a quick hack to get the USE_DSI_PLL
+        * option working. USE_DSI_PLL is itself a big hack, and
+        * should be removed.
+        */
+       if (dsi.vdds_dsi_reg == NULL) {
+               struct regulator *vdds_dsi;
+
+               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+               if (IS_ERR(vdds_dsi)) {
+                       DSSERR("can't get VDDS_DSI regulator\n");
+                       return PTR_ERR(vdds_dsi);
+               }
+
+               dsi.vdds_dsi_reg = vdds_dsi;
+       }
+#endif
+
        enable_clocks(1);
        dsi_enable_pll_clock(1);
 
@@ -1162,6 +1490,10 @@ void dsi_dump_clocks(struct seq_file *s)
 {
        int clksel;
        struct dsi_clock_info *cinfo = &dsi.current_cinfo;
+       enum dss_clk_source dispc_clk_src, dsi_clk_src;
+
+       dispc_clk_src = dss_get_dispc_clk_source();
+       dsi_clk_src = dss_get_dsi_clk_source();
 
        enable_clocks(1);
 
@@ -1171,30 +1503,34 @@ void dsi_dump_clocks(struct seq_file *s)
 
        seq_printf(s,   "dsi pll source = %s\n",
                        clksel == 0 ?
-                       "dss2_alwon_fclk" : "pclkfree");
+                       "dss_sys_clk" : "pclkfree");
 
        seq_printf(s,   "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
 
        seq_printf(s,   "CLKIN4DDR\t%-16luregm %u\n",
                        cinfo->clkin4ddr, cinfo->regm);
 
-       seq_printf(s,   "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
-                       cinfo->dsi1_pll_fclk,
-                       cinfo->regm3,
-                       dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+       seq_printf(s,   "%s (%s)\t%-16luregm_dispc %u\t(%s)\n",
+                       dss_get_generic_clk_source_name(dispc_clk_src),
+                       dss_feat_get_clk_source_name(dispc_clk_src),
+                       cinfo->dsi_pll_hsdiv_dispc_clk,
+                       cinfo->regm_dispc,
+                       dispc_clk_src == DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
-       seq_printf(s,   "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
-                       cinfo->dsi2_pll_fclk,
-                       cinfo->regm4,
-                       dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
+       seq_printf(s,   "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
+                       dss_get_generic_clk_source_name(dsi_clk_src),
+                       dss_feat_get_clk_source_name(dsi_clk_src),
+                       cinfo->dsi_pll_hsdiv_dsi_clk,
+                       cinfo->regm_dsi,
+                       dsi_clk_src == DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
        seq_printf(s,   "- DSI -\n");
 
-       seq_printf(s,   "dsi fclk source = %s\n",
-                       dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
-                       "dss1_alwon_fclk" : "dsi2_pll_fclk");
+       seq_printf(s,   "dsi fclk source = %s (%s)\n",
+                       dss_get_generic_clk_source_name(dsi_clk_src),
+                       dss_feat_get_clk_source_name(dsi_clk_src));
 
        seq_printf(s,   "DSI_FCLK\t%lu\n", dsi_fclk_rate());
 
@@ -1306,7 +1642,7 @@ void dsi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        DUMPREG(DSI_REVISION);
        DUMPREG(DSI_SYSCONFIG);
@@ -1378,7 +1714,7 @@ void dsi_dump_regs(struct seq_file *s)
        DUMPREG(DSI_PLL_CONFIGURATION1);
        DUMPREG(DSI_PLL_CONFIGURATION2);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
@@ -1622,20 +1958,6 @@ static int _dsi_reset(void)
        return _dsi_wait_reset();
 }
 
-static void dsi_reset_tx_fifo(int channel)
-{
-       u32 mask;
-       u32 l;
-
-       /* set fifosize of the channel to 0, then return the old size */
-       l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
-
-       mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
-       dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
-
-       dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
-}
-
 static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
 {
@@ -1753,8 +2075,6 @@ static void dsi_vc_initial_config(int channel)
        r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
 
        dsi_write_reg(DSI_VC_CTRL(channel), r);
-
-       dsi.vc[channel].mode = DSI_VC_MODE_L4;
 }
 
 static int dsi_vc_config_l4(int channel)
@@ -1922,33 +2242,44 @@ static int dsi_vc_send_bta(int channel)
 
 int dsi_vc_send_bta_sync(int channel)
 {
+       DECLARE_COMPLETION_ONSTACK(completion);
        int r = 0;
        u32 err;
 
-       INIT_COMPLETION(dsi.bta_completion);
+       r = dsi_register_isr_vc(channel, dsi_completion_handler,
+                       &completion, DSI_VC_IRQ_BTA);
+       if (r)
+               goto err0;
 
-       dsi_vc_enable_bta_irq(channel);
+       r = dsi_register_isr(dsi_completion_handler, &completion,
+                       DSI_IRQ_ERROR_MASK);
+       if (r)
+               goto err1;
 
        r = dsi_vc_send_bta(channel);
        if (r)
-               goto err;
+               goto err2;
 
-       if (wait_for_completion_timeout(&dsi.bta_completion,
+       if (wait_for_completion_timeout(&completion,
                                msecs_to_jiffies(500)) == 0) {
                DSSERR("Failed to receive BTA\n");
                r = -EIO;
-               goto err;
+               goto err2;
        }
 
        err = dsi_get_errors();
        if (err) {
                DSSERR("Error while sending BTA: %x\n", err);
                r = -EIO;
-               goto err;
+               goto err2;
        }
-err:
-       dsi_vc_disable_bta_irq(channel);
-
+err2:
+       dsi_unregister_isr(dsi_completion_handler, &completion,
+                       DSI_IRQ_ERROR_MASK);
+err1:
+       dsi_unregister_isr_vc(channel, dsi_completion_handler,
+                       &completion, DSI_VC_IRQ_BTA);
+err0:
        return r;
 }
 EXPORT_SYMBOL(dsi_vc_send_bta_sync);
@@ -1961,7 +2292,7 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type,
 
        WARN_ON(!dsi_bus_is_locked());
 
-       data_id = data_type | channel << 6;
+       data_id = data_type | dsi.vc[channel].vc_id << 6;
 
        val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
                FLD_VAL(ecc, 31, 24);
@@ -2064,7 +2395,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
                return -EINVAL;
        }
 
-       data_id = data_type | channel << 6;
+       data_id = data_type | dsi.vc[channel].vc_id << 6;
 
        r = (data_id << 0) | (data << 8) | (ecc << 24);
 
@@ -2762,19 +3093,20 @@ static void dsi_te_timeout(unsigned long arg)
 }
 #endif
 
+static void dsi_framedone_bta_callback(void *data, u32 mask);
+
 static void dsi_handle_framedone(int error)
 {
        const int channel = dsi.update_channel;
 
-       cancel_delayed_work(&dsi.framedone_timeout_work);
+       dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+                       NULL, DSI_VC_IRQ_BTA);
 
-       dsi_vc_disable_bta_irq(channel);
+       cancel_delayed_work(&dsi.framedone_timeout_work);
 
        /* SIDLEMODE back to smart-idle */
        dispc_enable_sidle();
 
-       dsi.bta_callback = NULL;
-
        if (dsi.te_enabled) {
                /* enable LP_RX_TO again after the TE */
                REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
@@ -2808,7 +3140,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
        dsi_handle_framedone(-ETIMEDOUT);
 }
 
-static void dsi_framedone_bta_callback(void)
+static void dsi_framedone_bta_callback(void *data, u32 mask)
 {
        dsi_handle_framedone(0);
 
@@ -2848,15 +3180,19 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
         * asynchronously.
         * */
 
-       dsi.bta_callback = dsi_framedone_bta_callback;
-
-       barrier();
-
-       dsi_vc_enable_bta_irq(channel);
+       r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
+                       NULL, DSI_VC_IRQ_BTA);
+       if (r) {
+               DSSERR("Failed to register BTA ISR\n");
+               dsi_handle_framedone(-EIO);
+               return;
+       }
 
        r = dsi_vc_send_bta(channel);
        if (r) {
                DSSERR("BTA after framedone failed\n");
+               dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+                               NULL, DSI_VC_IRQ_BTA);
                dsi_handle_framedone(-EIO);
        }
 }
@@ -2984,12 +3320,12 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
        struct dsi_clock_info cinfo;
        int r;
 
-       /* we always use DSS2_FCK as input clock */
-       cinfo.use_dss2_fck = true;
+       /* we always use DSS_CLK_SYSCK as input clock */
+       cinfo.use_sys_clk = true;
        cinfo.regn  = dssdev->phy.dsi.div.regn;
        cinfo.regm  = dssdev->phy.dsi.div.regm;
-       cinfo.regm3 = dssdev->phy.dsi.div.regm3;
-       cinfo.regm4 = dssdev->phy.dsi.div.regm4;
+       cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc;
+       cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi;
        r = dsi_calc_clock_rates(dssdev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
@@ -3011,7 +3347,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
        int r;
        unsigned long long fck;
 
-       fck = dsi_get_dsi1_pll_rate();
+       fck = dsi_get_pll_hsdiv_dispc_rate();
 
        dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
        dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
@@ -3045,8 +3381,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        if (r)
                goto err1;
 
-       dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
-       dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
+       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+       dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
 
        DSSDBG("PLL OK\n");
 
@@ -3082,8 +3418,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 err3:
        dsi_complexio_uninit();
 err2:
-       dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
-       dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
 err1:
        dsi_pll_uninit();
 err0:
@@ -3099,8 +3435,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
        dsi_vc_enable(2, 0);
        dsi_vc_enable(3, 0);
 
-       dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
-       dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
+       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
        dsi_complexio_uninit();
        dsi_pll_uninit();
 }
@@ -3220,29 +3556,107 @@ int dsi_init_display(struct omap_dss_device *dssdev)
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
                OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
 
-       dsi.vc[0].dssdev = dssdev;
-       dsi.vc[1].dssdev = dssdev;
+       if (dsi.vdds_dsi_reg == NULL) {
+               struct regulator *vdds_dsi;
+
+               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+
+               if (IS_ERR(vdds_dsi)) {
+                       DSSERR("can't get VDDS_DSI regulator\n");
+                       return PTR_ERR(vdds_dsi);
+               }
+
+               dsi.vdds_dsi_reg = vdds_dsi;
+       }
 
        return 0;
 }
 
-void dsi_wait_dsi1_pll_active(void)
+int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+               if (!dsi.vc[i].dssdev) {
+                       dsi.vc[i].dssdev = dssdev;
+                       *channel = i;
+                       return 0;
+               }
+       }
+
+       DSSERR("cannot get VC for display %s", dssdev->name);
+       return -ENOSPC;
+}
+EXPORT_SYMBOL(omap_dsi_request_vc);
+
+int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
+{
+       if (vc_id < 0 || vc_id > 3) {
+               DSSERR("VC ID out of range\n");
+               return -EINVAL;
+       }
+
+       if (channel < 0 || channel > 3) {
+               DSSERR("Virtual Channel out of range\n");
+               return -EINVAL;
+       }
+
+       if (dsi.vc[channel].dssdev != dssdev) {
+               DSSERR("Virtual Channel not allocated to display %s\n",
+                       dssdev->name);
+               return -EINVAL;
+       }
+
+       dsi.vc[channel].vc_id = vc_id;
+
+       return 0;
+}
+EXPORT_SYMBOL(omap_dsi_set_vc_id);
+
+void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
+{
+       if ((channel >= 0 && channel <= 3) &&
+               dsi.vc[channel].dssdev == dssdev) {
+               dsi.vc[channel].dssdev = NULL;
+               dsi.vc[channel].vc_id = 0;
+       }
+}
+EXPORT_SYMBOL(omap_dsi_release_vc);
+
+void dsi_wait_pll_hsdiv_dispc_active(void)
 {
        if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
-               DSSERR("DSI1 PLL clock not active\n");
+               DSSERR("%s (%s) not active\n",
+                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
 }
 
-void dsi_wait_dsi2_pll_active(void)
+void dsi_wait_pll_hsdiv_dsi_active(void)
 {
        if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
-               DSSERR("DSI2 PLL clock not active\n");
+               DSSERR("%s (%s) not active\n",
+                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
+}
+
+static void dsi_calc_clock_param_ranges(void)
+{
+       dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
+       dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
+       dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
+       dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
+       dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
+       dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
+       dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
 }
 
-int dsi_init(struct platform_device *pdev)
+static int dsi_init(struct platform_device *pdev)
 {
        u32 rev;
-       int r;
+       int r, i;
+       struct resource *dsi_mem;
 
+       spin_lock_init(&dsi.irq_lock);
        spin_lock_init(&dsi.errors_lock);
        dsi.errors = 0;
 
@@ -3251,8 +3665,6 @@ int dsi_init(struct platform_device *pdev)
        dsi.irq_stats.last_reset = jiffies;
 #endif
 
-       init_completion(&dsi.bta_completion);
-
        mutex_init(&dsi.lock);
        sema_init(&dsi.bus_lock, 1);
 
@@ -3268,24 +3680,45 @@ int dsi_init(struct platform_device *pdev)
        dsi.te_timer.function = dsi_te_timeout;
        dsi.te_timer.data = 0;
 #endif
-       dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
+       dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0);
+       if (!dsi_mem) {
+               DSSERR("can't get IORESOURCE_MEM DSI\n");
+               r = -EINVAL;
+               goto err1;
+       }
+       dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem));
        if (!dsi.base) {
                DSSERR("can't ioremap DSI\n");
                r = -ENOMEM;
                goto err1;
        }
+       dsi.irq = platform_get_irq(dsi.pdev, 0);
+       if (dsi.irq < 0) {
+               DSSERR("platform_get_irq failed\n");
+               r = -ENODEV;
+               goto err2;
+       }
 
-       dsi.vdds_dsi_reg = dss_get_vdds_dsi();
-       if (IS_ERR(dsi.vdds_dsi_reg)) {
-               DSSERR("can't get VDDS_DSI regulator\n");
-               r = PTR_ERR(dsi.vdds_dsi_reg);
+       r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED,
+               "OMAP DSI1", dsi.pdev);
+       if (r < 0) {
+               DSSERR("request_irq failed\n");
                goto err2;
        }
 
+       /* DSI VCs initialization */
+       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
+               dsi.vc[i].mode = DSI_VC_MODE_L4;
+               dsi.vc[i].dssdev = NULL;
+               dsi.vc[i].vc_id = 0;
+       }
+
+       dsi_calc_clock_param_ranges();
+
        enable_clocks(1);
 
        rev = dsi_read_reg(DSI_REVISION);
-       printk(KERN_INFO "OMAP DSI rev %d.%d\n",
+       dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
        enable_clocks(0);
@@ -3298,8 +3731,14 @@ err1:
        return r;
 }
 
-void dsi_exit(void)
+static void dsi_exit(void)
 {
+       if (dsi.vdds_dsi_reg != NULL) {
+               regulator_put(dsi.vdds_dsi_reg);
+               dsi.vdds_dsi_reg = NULL;
+       }
+
+       free_irq(dsi.irq, dsi.pdev);
        iounmap(dsi.base);
 
        destroy_workqueue(dsi.workqueue);
@@ -3307,3 +3746,41 @@ void dsi_exit(void)
        DSSDBG("omap_dsi_exit\n");
 }
 
+/* DSI1 HW IP initialisation */
+static int omap_dsi1hw_probe(struct platform_device *pdev)
+{
+       int r;
+       dsi.pdev = pdev;
+       r = dsi_init(pdev);
+       if (r) {
+               DSSERR("Failed to initialize DSI\n");
+               goto err_dsi;
+       }
+err_dsi:
+       return r;
+}
+
+static int omap_dsi1hw_remove(struct platform_device *pdev)
+{
+       dsi_exit();
+       return 0;
+}
+
+static struct platform_driver omap_dsi1hw_driver = {
+       .probe          = omap_dsi1hw_probe,
+       .remove         = omap_dsi1hw_remove,
+       .driver         = {
+               .name   = "omapdss_dsi1",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int dsi_init_platform_driver(void)
+{
+       return platform_driver_register(&omap_dsi1hw_driver);
+}
+
+void dsi_uninit_platform_driver(void)
+{
+       return platform_driver_unregister(&omap_dsi1hw_driver);
+}
index 77c3621c9171867a340ae146039e08aed1cc7ffd..3f1fee63c67830d2e9778238d2040b865df6cbef 100644 (file)
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/clk.h>
 
 #include <plat/display.h>
+#include <plat/clock.h>
 #include "dss.h"
-
-#define DSS_BASE                       0x48050000
+#include "dss_features.h"
 
 #define DSS_SZ_REGS                    SZ_512
 
@@ -59,9 +58,17 @@ struct dss_reg {
        dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
 
 static struct {
+       struct platform_device *pdev;
        void __iomem    *base;
+       int             ctx_id;
 
        struct clk      *dpll4_m4_ck;
+       struct clk      *dss_ick;
+       struct clk      *dss_fck;
+       struct clk      *dss_sys_clk;
+       struct clk      *dss_tv_fck;
+       struct clk      *dss_video_fck;
+       unsigned        num_clks_enabled;
 
        unsigned long   cache_req_pck;
        unsigned long   cache_prate;
@@ -70,10 +77,22 @@ static struct {
 
        enum dss_clk_source dsi_clk_source;
        enum dss_clk_source dispc_clk_source;
+       enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
+static const char * const dss_generic_clk_source_names[] = {
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI_PLL_HSDIV_DISPC",
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI_PLL_HSDIV_DSI",
+       [DSS_CLK_SRC_FCK]                       = "DSS_FCK",
+};
+
+static void dss_clk_enable_all_no_ctx(void);
+static void dss_clk_disable_all_no_ctx(void);
+static void dss_clk_enable_no_ctx(enum dss_clock clks);
+static void dss_clk_disable_no_ctx(enum dss_clock clks);
+
 static int _omap_dss_wait_reset(void);
 
 static inline void dss_write_reg(const struct dss_reg idx, u32 val)
@@ -99,10 +118,11 @@ void dss_save_context(void)
        SR(SYSCONFIG);
        SR(CONTROL);
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-       SR(SDI_CONTROL);
-       SR(PLL_CONTROL);
-#endif
+       if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+                       OMAP_DISPLAY_TYPE_SDI) {
+               SR(SDI_CONTROL);
+               SR(PLL_CONTROL);
+       }
 }
 
 void dss_restore_context(void)
@@ -113,10 +133,11 @@ void dss_restore_context(void)
        RR(SYSCONFIG);
        RR(CONTROL);
 
-#ifdef CONFIG_OMAP2_DSS_SDI
-       RR(SDI_CONTROL);
-       RR(PLL_CONTROL);
-#endif
+       if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+                       OMAP_DISPLAY_TYPE_SDI) {
+               RR(SDI_CONTROL);
+               RR(PLL_CONTROL);
+       }
 }
 
 #undef SR
@@ -209,66 +230,96 @@ void dss_sdi_disable(void)
        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 }
 
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
+{
+       return dss_generic_clk_source_names[clk_src];
+}
+
 void dss_dump_clocks(struct seq_file *s)
 {
        unsigned long dpll4_ck_rate;
        unsigned long dpll4_m4_ck_rate;
+       const char *fclk_name, *fclk_real_name;
+       unsigned long fclk_rate;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
-
-       dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-       dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        seq_printf(s, "- DSS -\n");
 
-       seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
+       fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
+       fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
+       fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
 
-       if (cpu_is_omap3630())
-               seq_printf(s, "dss1_alwon_fclk = %lu / %lu  = %lu\n",
-                       dpll4_ck_rate,
-                       dpll4_ck_rate / dpll4_m4_ck_rate,
-                       dss_clk_get_rate(DSS_CLK_FCK1));
-       else
-               seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
-                       dpll4_ck_rate,
-                       dpll4_ck_rate / dpll4_m4_ck_rate,
-                       dss_clk_get_rate(DSS_CLK_FCK1));
+       if (dss.dpll4_m4_ck) {
+               dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+               dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+
+               seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               if (cpu_is_omap3630() || cpu_is_omap44xx())
+                       seq_printf(s, "%s (%s) = %lu / %lu  = %lu\n",
+                                       fclk_name, fclk_real_name,
+                                       dpll4_ck_rate,
+                                       dpll4_ck_rate / dpll4_m4_ck_rate,
+                                       fclk_rate);
+               else
+                       seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
+                                       fclk_name, fclk_real_name,
+                                       dpll4_ck_rate,
+                                       dpll4_ck_rate / dpll4_m4_ck_rate,
+                                       fclk_rate);
+       } else {
+               seq_printf(s, "%s (%s) = %lu\n",
+                               fclk_name, fclk_real_name,
+                               fclk_rate);
+       }
+
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 void dss_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        DUMPREG(DSS_REVISION);
        DUMPREG(DSS_SYSCONFIG);
        DUMPREG(DSS_SYSSTATUS);
        DUMPREG(DSS_IRQSTATUS);
        DUMPREG(DSS_CONTROL);
-       DUMPREG(DSS_SDI_CONTROL);
-       DUMPREG(DSS_PLL_CONTROL);
-       DUMPREG(DSS_SDI_STATUS);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
+                       OMAP_DISPLAY_TYPE_SDI) {
+               DUMPREG(DSS_SDI_CONTROL);
+               DUMPREG(DSS_PLL_CONTROL);
+               DUMPREG(DSS_SDI_STATUS);
+       }
+
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
 void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
 {
        int b;
+       u8 start, end;
+
+       switch (clk_src) {
+       case DSS_CLK_SRC_FCK:
+               b = 0;
+               break;
+       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               b = 1;
+               dsi_wait_pll_hsdiv_dispc_active();
+               break;
+       default:
+               BUG();
+       }
 
-       BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
-                       clk_src != DSS_SRC_DSS1_ALWON_FCLK);
-
-       b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
-
-       if (clk_src == DSS_SRC_DSI1_PLL_FCLK)
-               dsi_wait_dsi1_pll_active();
+       dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
 
-       REG_FLD_MOD(DSS_CONTROL, b, 0, 0);      /* DISPC_CLK_SWITCH */
+       REG_FLD_MOD(DSS_CONTROL, b, start, end);        /* DISPC_CLK_SWITCH */
 
        dss.dispc_clk_source = clk_src;
 }
@@ -277,19 +328,51 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
 {
        int b;
 
-       BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
-                       clk_src != DSS_SRC_DSS1_ALWON_FCLK);
-
-       b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
-
-       if (clk_src == DSS_SRC_DSI2_PLL_FCLK)
-               dsi_wait_dsi2_pll_active();
+       switch (clk_src) {
+       case DSS_CLK_SRC_FCK:
+               b = 0;
+               break;
+       case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+               b = 1;
+               dsi_wait_pll_hsdiv_dsi_active();
+               break;
+       default:
+               BUG();
+       }
 
        REG_FLD_MOD(DSS_CONTROL, b, 1, 1);      /* DSI_CLK_SWITCH */
 
        dss.dsi_clk_source = clk_src;
 }
 
+void dss_select_lcd_clk_source(enum omap_channel channel,
+               enum dss_clk_source clk_src)
+{
+       int b, ix, pos;
+
+       if (!dss_has_feature(FEAT_LCD_CLK_SRC))
+               return;
+
+       switch (clk_src) {
+       case DSS_CLK_SRC_FCK:
+               b = 0;
+               break;
+       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
+               b = 1;
+               dsi_wait_pll_hsdiv_dispc_active();
+               break;
+       default:
+               BUG();
+       }
+
+       pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12;
+       REG_FLD_MOD(DSS_CONTROL, b, pos, pos);  /* LCDx_CLK_SWITCH */
+
+       ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+       dss.lcd_clk_source[ix] = clk_src;
+}
+
 enum dss_clk_source dss_get_dispc_clk_source(void)
 {
        return dss.dispc_clk_source;
@@ -300,34 +383,52 @@ enum dss_clk_source dss_get_dsi_clk_source(void)
        return dss.dsi_clk_source;
 }
 
+enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+{
+       int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+       return dss.lcd_clk_source[ix];
+}
+
 /* calculate clock rates using dividers in cinfo */
 int dss_calc_clock_rates(struct dss_clock_info *cinfo)
 {
-       unsigned long prate;
+       if (dss.dpll4_m4_ck) {
+               unsigned long prate;
+               u16 fck_div_max = 16;
 
-       if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) ||
-                                               cinfo->fck_div == 0)
-               return -EINVAL;
+               if (cpu_is_omap3630() || cpu_is_omap44xx())
+                       fck_div_max = 32;
+
+               if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
+                       return -EINVAL;
 
-       prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+               prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
 
-       cinfo->fck = prate / cinfo->fck_div;
+               cinfo->fck = prate / cinfo->fck_div;
+       } else {
+               if (cinfo->fck_div != 0)
+                       return -EINVAL;
+               cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+       }
 
        return 0;
 }
 
 int dss_set_clock_div(struct dss_clock_info *cinfo)
 {
-       unsigned long prate;
-       int r;
+       if (dss.dpll4_m4_ck) {
+               unsigned long prate;
+               int r;
 
-       if (cpu_is_omap34xx()) {
                prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
                DSSDBG("dpll4_m4 = %ld\n", prate);
 
                r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
                if (r)
                        return r;
+       } else {
+               if (cinfo->fck_div != 0)
+                       return -EINVAL;
        }
 
        DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
@@ -337,12 +438,14 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
 
 int dss_get_clock_div(struct dss_clock_info *cinfo)
 {
-       cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
+       cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
 
-       if (cpu_is_omap34xx()) {
+       if (dss.dpll4_m4_ck) {
                unsigned long prate;
+
                prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-               if (cpu_is_omap3630())
+
+               if (cpu_is_omap3630() || cpu_is_omap44xx())
                        cinfo->fck_div = prate / (cinfo->fck);
                else
                        cinfo->fck_div = prate / (cinfo->fck / 2);
@@ -355,7 +458,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
 
 unsigned long dss_get_dpll4_rate(void)
 {
-       if (cpu_is_omap34xx())
+       if (dss.dpll4_m4_ck)
                return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
        else
                return 0;
@@ -369,16 +472,18 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
        struct dss_clock_info best_dss;
        struct dispc_clock_info best_dispc;
 
-       unsigned long fck;
+       unsigned long fck, max_dss_fck;
 
-       u16 fck_div;
+       u16 fck_div, fck_div_max = 16;
 
        int match = 0;
        int min_fck_per_pck;
 
        prate = dss_get_dpll4_rate();
 
-       fck = dss_clk_get_rate(DSS_CLK_FCK1);
+       max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+       fck = dss_clk_get_rate(DSS_CLK_FCK);
        if (req_pck == dss.cache_req_pck &&
                        ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
                         dss.cache_dss_cinfo.fck == fck)) {
@@ -391,7 +496,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
        min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
 
        if (min_fck_per_pck &&
-               req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
+               req_pck * min_fck_per_pck > max_dss_fck) {
                DSSERR("Requested pixel clock not possible with the current "
                                "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
                                "the constraint off.\n");
@@ -402,10 +507,10 @@ retry:
        memset(&best_dss, 0, sizeof(best_dss));
        memset(&best_dispc, 0, sizeof(best_dispc));
 
-       if (cpu_is_omap24xx()) {
+       if (dss.dpll4_m4_ck == NULL) {
                struct dispc_clock_info cur_dispc;
                /* XXX can we change the clock on omap2? */
-               fck = dss_clk_get_rate(DSS_CLK_FCK1);
+               fck = dss_clk_get_rate(DSS_CLK_FCK);
                fck_div = 1;
 
                dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
@@ -417,17 +522,19 @@ retry:
                best_dispc = cur_dispc;
 
                goto found;
-       } else if (cpu_is_omap34xx()) {
-               for (fck_div = (cpu_is_omap3630() ? 32 : 16);
-                                       fck_div > 0; --fck_div) {
+       } else {
+               if (cpu_is_omap3630() || cpu_is_omap44xx())
+                       fck_div_max = 32;
+
+               for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
                        struct dispc_clock_info cur_dispc;
 
-                       if (cpu_is_omap3630())
+                       if (fck_div_max == 32)
                                fck = prate / fck_div;
                        else
                                fck = prate / fck_div * 2;
 
-                       if (fck > DISPC_MAX_FCK)
+                       if (fck > max_dss_fck)
                                continue;
 
                        if (min_fck_per_pck &&
@@ -450,8 +557,6 @@ retry:
                                        goto found;
                        }
                }
-       } else {
-               BUG();
        }
 
 found:
@@ -482,31 +587,6 @@ found:
        return 0;
 }
 
-
-
-static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
-{
-       dispc_irq_handler();
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
-{
-       u32 irqstatus;
-
-       irqstatus = dss_read_reg(DSS_IRQSTATUS);
-
-       if (irqstatus & (1<<0)) /* DISPC_IRQ */
-               dispc_irq_handler();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       if (irqstatus & (1<<1)) /* DSI_IRQ */
-               dsi_irq_handler();
-#endif
-
-       return IRQ_HANDLED;
-}
-
 static int _omap_dss_wait_reset(void)
 {
        int t = 0;
@@ -549,34 +629,45 @@ void dss_set_dac_pwrdn_bgz(bool enable)
        REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
 }
 
-int dss_init(bool skip_init)
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
+{
+       REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
+}
+
+static int dss_init(void)
 {
        int r;
        u32 rev;
+       struct resource *dss_mem;
+       struct clk *dpll4_m4_ck;
 
-       dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
+       dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+       if (!dss_mem) {
+               DSSERR("can't get IORESOURCE_MEM DSS\n");
+               r = -EINVAL;
+               goto fail0;
+       }
+       dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
        if (!dss.base) {
                DSSERR("can't ioremap DSS\n");
                r = -ENOMEM;
                goto fail0;
        }
 
-       if (!skip_init) {
-               /* disable LCD and DIGIT output. This seems to fix the synclost
-                * problem that we get, if the bootloader starts the DSS and
-                * the kernel resets it */
-               omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
+       /* disable LCD and DIGIT output. This seems to fix the synclost
+        * problem that we get, if the bootloader starts the DSS and
+        * the kernel resets it */
+       omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
 
-               /* We need to wait here a bit, otherwise we sometimes start to
-                * get synclost errors, and after that only power cycle will
-                * restore DSS functionality. I have no idea why this happens.
-                * And we have to wait _before_ resetting the DSS, but after
-                * enabling clocks.
-                */
-               msleep(50);
+       /* We need to wait here a bit, otherwise we sometimes start to
+        * get synclost errors, and after that only power cycle will
+        * restore DSS functionality. I have no idea why this happens.
+        * And we have to wait _before_ resetting the DSS, but after
+        * enabling clocks.
+        */
+       msleep(50);
 
-               _omap_dss_reset();
-       }
+       _omap_dss_reset();
 
        /* autoidle */
        REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
@@ -589,29 +680,30 @@ int dss_init(bool skip_init)
        REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
        REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
 #endif
-
-       r = request_irq(INT_24XX_DSS_IRQ,
-                       cpu_is_omap24xx()
-                       ? dss_irq_handler_omap2
-                       : dss_irq_handler_omap3,
-                       0, "OMAP DSS", NULL);
-
-       if (r < 0) {
-               DSSERR("omap2 dss: request_irq failed\n");
-               goto fail1;
-       }
-
        if (cpu_is_omap34xx()) {
-               dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
-               if (IS_ERR(dss.dpll4_m4_ck)) {
+               dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
+               if (IS_ERR(dpll4_m4_ck)) {
                        DSSERR("Failed to get dpll4_m4_ck\n");
-                       r = PTR_ERR(dss.dpll4_m4_ck);
-                       goto fail2;
+                       r = PTR_ERR(dpll4_m4_ck);
+                       goto fail1;
                }
+       } else if (cpu_is_omap44xx()) {
+               dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
+               if (IS_ERR(dpll4_m4_ck)) {
+                       DSSERR("Failed to get dpll4_m4_ck\n");
+                       r = PTR_ERR(dpll4_m4_ck);
+                       goto fail1;
+               }
+       } else { /* omap24xx */
+               dpll4_m4_ck = NULL;
        }
 
-       dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
-       dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
+       dss.dpll4_m4_ck = dpll4_m4_ck;
+
+       dss.dsi_clk_source = DSS_CLK_SRC_FCK;
+       dss.dispc_clk_source = DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
 
        dss_save_context();
 
@@ -621,21 +713,416 @@ int dss_init(bool skip_init)
 
        return 0;
 
-fail2:
-       free_irq(INT_24XX_DSS_IRQ, NULL);
 fail1:
        iounmap(dss.base);
 fail0:
        return r;
 }
 
-void dss_exit(void)
+static void dss_exit(void)
 {
-       if (cpu_is_omap34xx())
+       if (dss.dpll4_m4_ck)
                clk_put(dss.dpll4_m4_ck);
 
-       free_irq(INT_24XX_DSS_IRQ, NULL);
-
        iounmap(dss.base);
 }
 
+/* CONTEXT */
+static int dss_get_ctx_id(void)
+{
+       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+       int r;
+
+       if (!pdata->board_data->get_last_off_on_transaction_id)
+               return 0;
+       r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
+       if (r < 0) {
+               dev_err(&dss.pdev->dev, "getting transaction ID failed, "
+                               "will force context restore\n");
+               r = -1;
+       }
+       return r;
+}
+
+int dss_need_ctx_restore(void)
+{
+       int id = dss_get_ctx_id();
+
+       if (id < 0 || id != dss.ctx_id) {
+               DSSDBG("ctx id %d -> id %d\n",
+                               dss.ctx_id, id);
+               dss.ctx_id = id;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+static void save_all_ctx(void)
+{
+       DSSDBG("save context\n");
+
+       dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+
+       dss_save_context();
+       dispc_save_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+       dsi_save_context();
+#endif
+
+       dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
+}
+
+static void restore_all_ctx(void)
+{
+       DSSDBG("restore context\n");
+
+       dss_clk_enable_all_no_ctx();
+
+       dss_restore_context();
+       dispc_restore_context();
+#ifdef CONFIG_OMAP2_DSS_DSI
+       dsi_restore_context();
+#endif
+
+       dss_clk_disable_all_no_ctx();
+}
+
+static int dss_get_clock(struct clk **clock, const char *clk_name)
+{
+       struct clk *clk;
+
+       clk = clk_get(&dss.pdev->dev, clk_name);
+
+       if (IS_ERR(clk)) {
+               DSSERR("can't get clock %s", clk_name);
+               return PTR_ERR(clk);
+       }
+
+       *clock = clk;
+
+       DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
+
+       return 0;
+}
+
+static int dss_get_clocks(void)
+{
+       int r;
+       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
+
+       dss.dss_ick = NULL;
+       dss.dss_fck = NULL;
+       dss.dss_sys_clk = NULL;
+       dss.dss_tv_fck = NULL;
+       dss.dss_video_fck = NULL;
+
+       r = dss_get_clock(&dss.dss_ick, "ick");
+       if (r)
+               goto err;
+
+       r = dss_get_clock(&dss.dss_fck, "fck");
+       if (r)
+               goto err;
+
+       if (!pdata->opt_clock_available) {
+               r = -ENODEV;
+               goto err;
+       }
+
+       if (pdata->opt_clock_available("sys_clk")) {
+               r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
+               if (r)
+                       goto err;
+       }
+
+       if (pdata->opt_clock_available("tv_clk")) {
+               r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
+               if (r)
+                       goto err;
+       }
+
+       if (pdata->opt_clock_available("video_clk")) {
+               r = dss_get_clock(&dss.dss_video_fck, "video_clk");
+               if (r)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       if (dss.dss_ick)
+               clk_put(dss.dss_ick);
+       if (dss.dss_fck)
+               clk_put(dss.dss_fck);
+       if (dss.dss_sys_clk)
+               clk_put(dss.dss_sys_clk);
+       if (dss.dss_tv_fck)
+               clk_put(dss.dss_tv_fck);
+       if (dss.dss_video_fck)
+               clk_put(dss.dss_video_fck);
+
+       return r;
+}
+
+static void dss_put_clocks(void)
+{
+       if (dss.dss_video_fck)
+               clk_put(dss.dss_video_fck);
+       if (dss.dss_tv_fck)
+               clk_put(dss.dss_tv_fck);
+       if (dss.dss_sys_clk)
+               clk_put(dss.dss_sys_clk);
+       clk_put(dss.dss_fck);
+       clk_put(dss.dss_ick);
+}
+
+unsigned long dss_clk_get_rate(enum dss_clock clk)
+{
+       switch (clk) {
+       case DSS_CLK_ICK:
+               return clk_get_rate(dss.dss_ick);
+       case DSS_CLK_FCK:
+               return clk_get_rate(dss.dss_fck);
+       case DSS_CLK_SYSCK:
+               return clk_get_rate(dss.dss_sys_clk);
+       case DSS_CLK_TVFCK:
+               return clk_get_rate(dss.dss_tv_fck);
+       case DSS_CLK_VIDFCK:
+               return clk_get_rate(dss.dss_video_fck);
+       }
+
+       BUG();
+       return 0;
+}
+
+static unsigned count_clk_bits(enum dss_clock clks)
+{
+       unsigned num_clks = 0;
+
+       if (clks & DSS_CLK_ICK)
+               ++num_clks;
+       if (clks & DSS_CLK_FCK)
+               ++num_clks;
+       if (clks & DSS_CLK_SYSCK)
+               ++num_clks;
+       if (clks & DSS_CLK_TVFCK)
+               ++num_clks;
+       if (clks & DSS_CLK_VIDFCK)
+               ++num_clks;
+
+       return num_clks;
+}
+
+static void dss_clk_enable_no_ctx(enum dss_clock clks)
+{
+       unsigned num_clks = count_clk_bits(clks);
+
+       if (clks & DSS_CLK_ICK)
+               clk_enable(dss.dss_ick);
+       if (clks & DSS_CLK_FCK)
+               clk_enable(dss.dss_fck);
+       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+               clk_enable(dss.dss_sys_clk);
+       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+               clk_enable(dss.dss_tv_fck);
+       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+               clk_enable(dss.dss_video_fck);
+
+       dss.num_clks_enabled += num_clks;
+}
+
+void dss_clk_enable(enum dss_clock clks)
+{
+       bool check_ctx = dss.num_clks_enabled == 0;
+
+       dss_clk_enable_no_ctx(clks);
+
+       /*
+        * HACK: On omap4 the registers may not be accessible right after
+        * enabling the clocks. At some point this will be handled by
+        * pm_runtime, but for the time begin this should make things work.
+        */
+       if (cpu_is_omap44xx() && check_ctx)
+               udelay(10);
+
+       if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
+               restore_all_ctx();
+}
+
+static void dss_clk_disable_no_ctx(enum dss_clock clks)
+{
+       unsigned num_clks = count_clk_bits(clks);
+
+       if (clks & DSS_CLK_ICK)
+               clk_disable(dss.dss_ick);
+       if (clks & DSS_CLK_FCK)
+               clk_disable(dss.dss_fck);
+       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
+               clk_disable(dss.dss_sys_clk);
+       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
+               clk_disable(dss.dss_tv_fck);
+       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
+               clk_disable(dss.dss_video_fck);
+
+       dss.num_clks_enabled -= num_clks;
+}
+
+void dss_clk_disable(enum dss_clock clks)
+{
+       if (cpu_is_omap34xx()) {
+               unsigned num_clks = count_clk_bits(clks);
+
+               BUG_ON(dss.num_clks_enabled < num_clks);
+
+               if (dss.num_clks_enabled == num_clks)
+                       save_all_ctx();
+       }
+
+       dss_clk_disable_no_ctx(clks);
+}
+
+static void dss_clk_enable_all_no_ctx(void)
+{
+       enum dss_clock clks;
+
+       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+       if (cpu_is_omap34xx())
+               clks |= DSS_CLK_VIDFCK;
+       dss_clk_enable_no_ctx(clks);
+}
+
+static void dss_clk_disable_all_no_ctx(void)
+{
+       enum dss_clock clks;
+
+       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
+       if (cpu_is_omap34xx())
+               clks |= DSS_CLK_VIDFCK;
+       dss_clk_disable_no_ctx(clks);
+}
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+/* CLOCKS */
+static void core_dump_clocks(struct seq_file *s)
+{
+       int i;
+       struct clk *clocks[5] = {
+               dss.dss_ick,
+               dss.dss_fck,
+               dss.dss_sys_clk,
+               dss.dss_tv_fck,
+               dss.dss_video_fck
+       };
+
+       seq_printf(s, "- CORE -\n");
+
+       seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
+
+       for (i = 0; i < 5; i++) {
+               if (!clocks[i])
+                       continue;
+               seq_printf(s, "%-15s\t%lu\t%d\n",
+                               clocks[i]->name,
+                               clk_get_rate(clocks[i]),
+                               clocks[i]->usecount);
+       }
+}
+#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
+
+/* DEBUGFS */
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s)
+{
+       core_dump_clocks(s);
+       dss_dump_clocks(s);
+       dispc_dump_clocks(s);
+#ifdef CONFIG_OMAP2_DSS_DSI
+       dsi_dump_clocks(s);
+#endif
+}
+#endif
+
+
+/* DSS HW IP initialisation */
+static int omap_dsshw_probe(struct platform_device *pdev)
+{
+       int r;
+
+       dss.pdev = pdev;
+
+       r = dss_get_clocks();
+       if (r)
+               goto err_clocks;
+
+       dss_clk_enable_all_no_ctx();
+
+       dss.ctx_id = dss_get_ctx_id();
+       DSSDBG("initial ctx id %u\n", dss.ctx_id);
+
+       r = dss_init();
+       if (r) {
+               DSSERR("Failed to initialize DSS\n");
+               goto err_dss;
+       }
+
+       r = dpi_init();
+       if (r) {
+               DSSERR("Failed to initialize DPI\n");
+               goto err_dpi;
+       }
+
+       r = sdi_init();
+       if (r) {
+               DSSERR("Failed to initialize SDI\n");
+               goto err_sdi;
+       }
+
+       dss_clk_disable_all_no_ctx();
+       return 0;
+err_sdi:
+       dpi_exit();
+err_dpi:
+       dss_exit();
+err_dss:
+       dss_clk_disable_all_no_ctx();
+       dss_put_clocks();
+err_clocks:
+       return r;
+}
+
+static int omap_dsshw_remove(struct platform_device *pdev)
+{
+
+       dss_exit();
+
+       /*
+        * As part of hwmod changes, DSS is not the only controller of dss
+        * clocks; hwmod framework itself will also enable clocks during hwmod
+        * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
+        * need to disable clocks if their usecounts > 1.
+        */
+       WARN_ON(dss.num_clks_enabled > 0);
+
+       dss_put_clocks();
+       return 0;
+}
+
+static struct platform_driver omap_dsshw_driver = {
+       .probe          = omap_dsshw_probe,
+       .remove         = omap_dsshw_remove,
+       .driver         = {
+               .name   = "omapdss_dss",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int dss_init_platform_driver(void)
+{
+       return platform_driver_register(&omap_dsshw_driver);
+}
+
+void dss_uninit_platform_driver(void)
+{
+       return platform_driver_unregister(&omap_dsshw_driver);
+}
index b394951120ac349a5bf78f702f89af8a9fc2bb9f..c2f582bb19c05f49f22c34e6bea1a1bd015a9cb1 100644 (file)
@@ -97,8 +97,6 @@ extern unsigned int dss_debug;
 #define FLD_MOD(orig, val, start, end) \
        (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
 
-#define DISPC_MAX_FCK 173000000
-
 enum omap_burst_size {
        OMAP_DSS_BURST_4x32 = 0,
        OMAP_DSS_BURST_8x32 = 1,
@@ -112,17 +110,25 @@ enum omap_parallel_interface_mode {
 };
 
 enum dss_clock {
-       DSS_CLK_ICK     = 1 << 0,
-       DSS_CLK_FCK1    = 1 << 1,
-       DSS_CLK_FCK2    = 1 << 2,
-       DSS_CLK_54M     = 1 << 3,
-       DSS_CLK_96M     = 1 << 4,
+       DSS_CLK_ICK     = 1 << 0,       /* DSS_L3_ICLK and DSS_L4_ICLK */
+       DSS_CLK_FCK     = 1 << 1,       /* DSS1_ALWON_FCLK */
+       DSS_CLK_SYSCK   = 1 << 2,       /* DSS2_ALWON_FCLK */
+       DSS_CLK_TVFCK   = 1 << 3,       /* DSS_TV_FCLK */
+       DSS_CLK_VIDFCK  = 1 << 4,       /* DSS_96M_FCLK*/
 };
 
 enum dss_clk_source {
-       DSS_SRC_DSI1_PLL_FCLK,
-       DSS_SRC_DSI2_PLL_FCLK,
-       DSS_SRC_DSS1_ALWON_FCLK,
+       DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,        /* OMAP3: DSI1_PLL_FCLK
+                                                * OMAP4: PLL1_CLK1 */
+       DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,          /* OMAP3: DSI2_PLL_FCLK
+                                                * OMAP4: PLL1_CLK2 */
+       DSS_CLK_SRC_FCK,                        /* OMAP2/3: DSS1_ALWON_FCLK
+                                                * OMAP4: DSS_FCLK */
+};
+
+enum dss_hdmi_venc_clk_source_select {
+       DSS_VENC_TV_CLK = 0,
+       DSS_HDMI_M_PCLK = 1,
 };
 
 struct dss_clock_info {
@@ -148,36 +154,42 @@ struct dsi_clock_info {
        unsigned long fint;
        unsigned long clkin4ddr;
        unsigned long clkin;
-       unsigned long dsi1_pll_fclk;
-       unsigned long dsi2_pll_fclk;
-
+       unsigned long dsi_pll_hsdiv_dispc_clk;  /* OMAP3: DSI1_PLL_CLK
+                                                * OMAP4: PLLx_CLK1 */
+       unsigned long dsi_pll_hsdiv_dsi_clk;    /* OMAP3: DSI2_PLL_CLK
+                                                * OMAP4: PLLx_CLK2 */
        unsigned long lp_clk;
 
        /* dividers */
        u16 regn;
        u16 regm;
-       u16 regm3;
-       u16 regm4;
-
+       u16 regm_dispc; /* OMAP3: REGM3
+                        * OMAP4: REGM4 */
+       u16 regm_dsi;   /* OMAP3: REGM4
+                        * OMAP4: REGM5 */
        u16 lp_clk_div;
 
        u8 highfreq;
-       bool use_dss2_fck;
+       bool use_sys_clk;
+};
+
+/* HDMI PLL structure */
+struct hdmi_pll_info {
+       u16 regn;
+       u16 regm;
+       u32 regmf;
+       u16 regm2;
+       u16 regsd;
+       u16 dcofreq;
 };
 
 struct seq_file;
 struct platform_device;
 
 /* core */
-void dss_clk_enable(enum dss_clock clks);
-void dss_clk_disable(enum dss_clock clks);
-unsigned long dss_clk_get_rate(enum dss_clock clk);
-int dss_need_ctx_restore(void);
-void dss_dump_clocks(struct seq_file *s);
 struct bus_type *dss_get_bus(void);
 struct regulator *dss_get_vdds_dsi(void);
 struct regulator *dss_get_vdds_sdi(void);
-struct regulator *dss_get_vdda_dac(void);
 
 /* display */
 int dss_suspend_all_devices(void);
@@ -214,13 +226,23 @@ void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
 void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 
 /* DSS */
-int dss_init(bool skip_init);
-void dss_exit(void);
+int dss_init_platform_driver(void);
+void dss_uninit_platform_driver(void);
 
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
 void dss_save_context(void);
 void dss_restore_context(void);
+void dss_clk_enable(enum dss_clock clks);
+void dss_clk_disable(enum dss_clock clks);
+unsigned long dss_clk_get_rate(enum dss_clock clk);
+int dss_need_ctx_restore(void);
+const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src);
+void dss_dump_clocks(struct seq_file *s);
 
 void dss_dump_regs(struct seq_file *s);
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
+void dss_debug_dump_clocks(struct seq_file *s);
+#endif
 
 void dss_sdi_init(u8 datapairs);
 int dss_sdi_enable(void);
@@ -228,8 +250,11 @@ void dss_sdi_disable(void);
 
 void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
 void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_lcd_clk_source(enum omap_channel channel,
+               enum dss_clk_source clk_src);
 enum dss_clk_source dss_get_dispc_clk_source(void);
 enum dss_clk_source dss_get_dsi_clk_source(void);
+enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
 
 void dss_set_venc_output(enum omap_dss_venc_type type);
 void dss_set_dac_pwrdn_bgz(bool enable);
@@ -244,11 +269,11 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
 
 /* SDI */
 #ifdef CONFIG_OMAP2_DSS_SDI
-int sdi_init(bool skip_init);
+int sdi_init(void);
 void sdi_exit(void);
 int sdi_init_display(struct omap_dss_device *display);
 #else
-static inline int sdi_init(bool skip_init)
+static inline int sdi_init(void)
 {
        return 0;
 }
@@ -259,8 +284,8 @@ static inline void sdi_exit(void)
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
-int dsi_init(struct platform_device *pdev);
-void dsi_exit(void);
+int dsi_init_platform_driver(void);
+void dsi_uninit_platform_driver(void);
 
 void dsi_dump_clocks(struct seq_file *s);
 void dsi_dump_irqs(struct seq_file *s);
@@ -271,7 +296,7 @@ void dsi_restore_context(void);
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
-unsigned long dsi_get_dsi1_pll_rate(void);
+unsigned long dsi_get_pll_hsdiv_dispc_rate(void);
 int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
 int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
                struct dsi_clock_info *cinfo,
@@ -282,31 +307,36 @@ void dsi_pll_uninit(void);
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
                u32 fifo_size, enum omap_burst_size *burst_size,
                u32 *fifo_low, u32 *fifo_high);
-void dsi_wait_dsi1_pll_active(void);
-void dsi_wait_dsi2_pll_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(void);
+void dsi_wait_pll_hsdiv_dsi_active(void);
 #else
-static inline int dsi_init(struct platform_device *pdev)
+static inline int dsi_init_platform_driver(void)
 {
        return 0;
 }
-static inline void dsi_exit(void)
+static inline void dsi_uninit_platform_driver(void)
 {
 }
-static inline void dsi_wait_dsi1_pll_active(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
 {
+       WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
+       return 0;
 }
-static inline void dsi_wait_dsi2_pll_active(void)
+static inline void dsi_wait_pll_hsdiv_dispc_active(void)
+{
+}
+static inline void dsi_wait_pll_hsdiv_dsi_active(void)
 {
 }
 #endif
 
 /* DPI */
 #ifdef CONFIG_OMAP2_DSS_DPI
-int dpi_init(struct platform_device *pdev);
+int dpi_init(void);
 void dpi_exit(void);
 int dpi_init_display(struct omap_dss_device *dssdev);
 #else
-static inline int dpi_init(struct platform_device *pdev)
+static inline int dpi_init(void)
 {
        return 0;
 }
@@ -316,8 +346,8 @@ static inline void dpi_exit(void)
 #endif
 
 /* DISPC */
-int dispc_init(void);
-void dispc_exit(void);
+int dispc_init_platform_driver(void);
+void dispc_uninit_platform_driver(void);
 void dispc_dump_clocks(struct seq_file *s);
 void dispc_dump_irqs(struct seq_file *s);
 void dispc_dump_regs(struct seq_file *s);
@@ -350,6 +380,7 @@ void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
 void dispc_set_channel_out(enum omap_plane plane,
                enum omap_channel channel_out);
 
+void dispc_enable_gamma_table(bool enable);
 int dispc_setup_plane(enum omap_plane plane,
                      u32 paddr, u16 screen_width,
                      u16 pos_x, u16 pos_y,
@@ -409,24 +440,50 @@ int dispc_get_clock_div(enum omap_channel channel,
 
 /* VENC */
 #ifdef CONFIG_OMAP2_DSS_VENC
-int venc_init(struct platform_device *pdev);
-void venc_exit(void);
+int venc_init_platform_driver(void);
+void venc_uninit_platform_driver(void);
 void venc_dump_regs(struct seq_file *s);
 int venc_init_display(struct omap_dss_device *display);
 #else
-static inline int venc_init(struct platform_device *pdev)
+static inline int venc_init_platform_driver(void)
+{
+       return 0;
+}
+static inline void venc_uninit_platform_driver(void)
+{
+}
+#endif
+
+/* HDMI */
+#ifdef CONFIG_OMAP4_DSS_HDMI
+int hdmi_init_platform_driver(void);
+void hdmi_uninit_platform_driver(void);
+int hdmi_init_display(struct omap_dss_device *dssdev);
+#else
+static inline int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+       return 0;
+}
+static inline int hdmi_init_platform_driver(void)
 {
        return 0;
 }
-static inline void venc_exit(void)
+static inline void hdmi_uninit_platform_driver(void)
 {
 }
 #endif
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+                                       struct omap_video_timings *timings);
+int hdmi_panel_init(void);
+void hdmi_panel_exit(void);
 
 /* RFBI */
 #ifdef CONFIG_OMAP2_DSS_RFBI
-int rfbi_init(void);
-void rfbi_exit(void);
+int rfbi_init_platform_driver(void);
+void rfbi_uninit_platform_driver(void);
 void rfbi_dump_regs(struct seq_file *s);
 
 int rfbi_configure(int rfbi_module, int bpp, int lines);
@@ -437,11 +494,11 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
 unsigned long rfbi_get_max_tx_rate(void);
 int rfbi_init_display(struct omap_dss_device *display);
 #else
-static inline int rfbi_init(void)
+static inline int rfbi_init_platform_driver(void)
 {
        return 0;
 }
-static inline void rfbi_exit(void)
+static inline void rfbi_uninit_platform_driver(void)
 {
 }
 #endif
index cf3ef696e141ee7be4f8a2e3feb99afa86d7f417..aa1622241d0d728612c57bda460951d251cf590d 100644 (file)
 #include <plat/display.h>
 #include <plat/cpu.h>
 
+#include "dss.h"
 #include "dss_features.h"
 
 /* Defines a generic omap register field */
 struct dss_reg_field {
-       enum dss_feat_reg_field id;
        u8 start, end;
 };
 
+struct dss_param_range {
+       int min, max;
+};
+
 struct omap_dss_features {
        const struct dss_reg_field *reg_fields;
        const int num_reg_fields;
@@ -43,28 +47,67 @@ struct omap_dss_features {
        const int num_ovls;
        const enum omap_display_type *supported_displays;
        const enum omap_color_mode *supported_color_modes;
+       const char * const *clksrc_names;
+       const struct dss_param_range *dss_params;
 };
 
 /* This struct is assigned to one of the below during initialization */
 static struct omap_dss_features *omap_current_dss_features;
 
 static const struct dss_reg_field omap2_dss_reg_fields[] = {
-       { FEAT_REG_FIRHINC, 11, 0 },
-       { FEAT_REG_FIRVINC, 27, 16 },
-       { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 },
-       { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 },
-       { FEAT_REG_FIFOSIZE, 8, 0 },
+       [FEAT_REG_FIRHINC]                      = { 11, 0 },
+       [FEAT_REG_FIRVINC]                      = { 27, 16 },
+       [FEAT_REG_FIFOLOWTHRESHOLD]             = { 8, 0 },
+       [FEAT_REG_FIFOHIGHTHRESHOLD]            = { 24, 16 },
+       [FEAT_REG_FIFOSIZE]                     = { 8, 0 },
+       [FEAT_REG_HORIZONTALACCU]               = { 9, 0 },
+       [FEAT_REG_VERTICALACCU]                 = { 25, 16 },
+       [FEAT_REG_DISPC_CLK_SWITCH]             = { 0, 0 },
+       [FEAT_REG_DSIPLL_REGN]                  = { 0, 0 },
+       [FEAT_REG_DSIPLL_REGM]                  = { 0, 0 },
+       [FEAT_REG_DSIPLL_REGM_DISPC]            = { 0, 0 },
+       [FEAT_REG_DSIPLL_REGM_DSI]              = { 0, 0 },
 };
 
 static const struct dss_reg_field omap3_dss_reg_fields[] = {
-       { FEAT_REG_FIRHINC, 12, 0 },
-       { FEAT_REG_FIRVINC, 28, 16 },
-       { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 },
-       { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 },
-       { FEAT_REG_FIFOSIZE, 10, 0 },
+       [FEAT_REG_FIRHINC]                      = { 12, 0 },
+       [FEAT_REG_FIRVINC]                      = { 28, 16 },
+       [FEAT_REG_FIFOLOWTHRESHOLD]             = { 11, 0 },
+       [FEAT_REG_FIFOHIGHTHRESHOLD]            = { 27, 16 },
+       [FEAT_REG_FIFOSIZE]                     = { 10, 0 },
+       [FEAT_REG_HORIZONTALACCU]               = { 9, 0 },
+       [FEAT_REG_VERTICALACCU]                 = { 25, 16 },
+       [FEAT_REG_DISPC_CLK_SWITCH]             = { 0, 0 },
+       [FEAT_REG_DSIPLL_REGN]                  = { 7, 1 },
+       [FEAT_REG_DSIPLL_REGM]                  = { 18, 8 },
+       [FEAT_REG_DSIPLL_REGM_DISPC]            = { 22, 19 },
+       [FEAT_REG_DSIPLL_REGM_DSI]              = { 26, 23 },
+};
+
+static const struct dss_reg_field omap4_dss_reg_fields[] = {
+       [FEAT_REG_FIRHINC]                      = { 12, 0 },
+       [FEAT_REG_FIRVINC]                      = { 28, 16 },
+       [FEAT_REG_FIFOLOWTHRESHOLD]             = { 15, 0 },
+       [FEAT_REG_FIFOHIGHTHRESHOLD]            = { 31, 16 },
+       [FEAT_REG_FIFOSIZE]                     = { 15, 0 },
+       [FEAT_REG_HORIZONTALACCU]               = { 10, 0 },
+       [FEAT_REG_VERTICALACCU]                 = { 26, 16 },
+       [FEAT_REG_DISPC_CLK_SWITCH]             = { 9, 8 },
+       [FEAT_REG_DSIPLL_REGN]                  = { 8, 1 },
+       [FEAT_REG_DSIPLL_REGM]                  = { 20, 9 },
+       [FEAT_REG_DSIPLL_REGM_DISPC]            = { 25, 21 },
+       [FEAT_REG_DSIPLL_REGM_DSI]              = { 30, 26 },
 };
 
 static const enum omap_display_type omap2_dss_supported_displays[] = {
+       /* OMAP_DSS_CHANNEL_LCD */
+       OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
+
+       /* OMAP_DSS_CHANNEL_DIGIT */
+       OMAP_DISPLAY_TYPE_VENC,
+};
+
+static const enum omap_display_type omap3430_dss_supported_displays[] = {
        /* OMAP_DSS_CHANNEL_LCD */
        OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
        OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
@@ -73,10 +116,10 @@ static const enum omap_display_type omap2_dss_supported_displays[] = {
        OMAP_DISPLAY_TYPE_VENC,
 };
 
-static const enum omap_display_type omap3_dss_supported_displays[] = {
+static const enum omap_display_type omap3630_dss_supported_displays[] = {
        /* OMAP_DSS_CHANNEL_LCD */
        OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
-       OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
+       OMAP_DISPLAY_TYPE_DSI,
 
        /* OMAP_DSS_CHANNEL_DIGIT */
        OMAP_DISPLAY_TYPE_VENC,
@@ -87,7 +130,7 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
        OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
 
        /* OMAP_DSS_CHANNEL_DIGIT */
-       OMAP_DISPLAY_TYPE_VENC,
+       OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
 
        /* OMAP_DSS_CHANNEL_LCD2 */
        OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
@@ -134,6 +177,54 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
        OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
+static const char * const omap2_dss_clk_source_names[] = {
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "N/A",
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "N/A",
+       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK1",
+};
+
+static const char * const omap3_dss_clk_source_names[] = {
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI1_PLL_FCLK",
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI2_PLL_FCLK",
+       [DSS_CLK_SRC_FCK]                       = "DSS1_ALWON_FCLK",
+};
+
+static const char * const omap4_dss_clk_source_names[] = {
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "PLL1_CLK1",
+       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "PLL1_CLK2",
+       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK",
+};
+
+static const struct dss_param_range omap2_dss_param_range[] = {
+       [FEAT_PARAM_DSS_FCK]                    = { 0, 173000000 },
+       [FEAT_PARAM_DSIPLL_REGN]                = { 0, 0 },
+       [FEAT_PARAM_DSIPLL_REGM]                = { 0, 0 },
+       [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, 0 },
+       [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, 0 },
+       [FEAT_PARAM_DSIPLL_FINT]                = { 0, 0 },
+       [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, 0 },
+};
+
+static const struct dss_param_range omap3_dss_param_range[] = {
+       [FEAT_PARAM_DSS_FCK]                    = { 0, 173000000 },
+       [FEAT_PARAM_DSIPLL_REGN]                = { 0, (1 << 7) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM]                = { 0, (1 << 11) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, (1 << 4) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, (1 << 4) - 1 },
+       [FEAT_PARAM_DSIPLL_FINT]                = { 750000, 2100000 },
+       [FEAT_PARAM_DSIPLL_LPDIV]               = { 1, (1 << 13) - 1},
+};
+
+static const struct dss_param_range omap4_dss_param_range[] = {
+       [FEAT_PARAM_DSS_FCK]                    = { 0, 186000000 },
+       [FEAT_PARAM_DSIPLL_REGN]                = { 0, (1 << 8) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM]                = { 0, (1 << 12) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM_DISPC]          = { 0, (1 << 5) - 1 },
+       [FEAT_PARAM_DSIPLL_REGM_DSI]            = { 0, (1 << 5) - 1 },
+       [FEAT_PARAM_DSIPLL_FINT]                = { 500000, 2500000 },
+       [FEAT_PARAM_DSIPLL_LPDIV]               = { 0, (1 << 13) - 1 },
+};
+
 /* OMAP2 DSS Features */
 static struct omap_dss_features omap2_dss_features = {
        .reg_fields = omap2_dss_reg_fields,
@@ -141,12 +232,15 @@ static struct omap_dss_features omap2_dss_features = {
 
        .has_feature    =
                FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
-               FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
+               FEAT_PCKFREEENABLE | FEAT_FUNCGATED |
+               FEAT_ROWREPEATENABLE | FEAT_RESIZECONF,
 
        .num_mgrs = 2,
        .num_ovls = 3,
        .supported_displays = omap2_dss_supported_displays,
        .supported_color_modes = omap2_dss_supported_color_modes,
+       .clksrc_names = omap2_dss_clk_source_names,
+       .dss_params = omap2_dss_param_range,
 };
 
 /* OMAP3 DSS Features */
@@ -157,12 +251,15 @@ static struct omap_dss_features omap3430_dss_features = {
        .has_feature    =
                FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-               FEAT_FUNCGATED,
+               FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
+               FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
 
        .num_mgrs = 2,
        .num_ovls = 3,
-       .supported_displays = omap3_dss_supported_displays,
+       .supported_displays = omap3430_dss_supported_displays,
        .supported_color_modes = omap3_dss_supported_color_modes,
+       .clksrc_names = omap3_dss_clk_source_names,
+       .dss_params = omap3_dss_param_range,
 };
 
 static struct omap_dss_features omap3630_dss_features = {
@@ -172,27 +269,34 @@ static struct omap_dss_features omap3630_dss_features = {
        .has_feature    =
                FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
-               FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
+               FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
+               FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
+               FEAT_RESIZECONF,
 
        .num_mgrs = 2,
        .num_ovls = 3,
-       .supported_displays = omap3_dss_supported_displays,
+       .supported_displays = omap3630_dss_supported_displays,
        .supported_color_modes = omap3_dss_supported_color_modes,
+       .clksrc_names = omap3_dss_clk_source_names,
+       .dss_params = omap3_dss_param_range,
 };
 
 /* OMAP4 DSS Features */
 static struct omap_dss_features omap4_dss_features = {
-       .reg_fields = omap3_dss_reg_fields,
-       .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+       .reg_fields = omap4_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
        .has_feature    =
                FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
-               FEAT_MGR_LCD2,
+               FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
 
        .num_mgrs = 3,
        .num_ovls = 3,
        .supported_displays = omap4_dss_supported_displays,
        .supported_color_modes = omap3_dss_supported_color_modes,
+       .clksrc_names = omap4_dss_clk_source_names,
+       .dss_params = omap4_dss_param_range,
 };
 
 /* Functions returning values related to a DSS feature */
@@ -206,6 +310,16 @@ int dss_feat_get_num_ovls(void)
        return omap_current_dss_features->num_ovls;
 }
 
+unsigned long dss_feat_get_param_min(enum dss_range_param param)
+{
+       return omap_current_dss_features->dss_params[param].min;
+}
+
+unsigned long dss_feat_get_param_max(enum dss_range_param param)
+{
+       return omap_current_dss_features->dss_params[param].max;
+}
+
 enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
 {
        return omap_current_dss_features->supported_displays[channel];
@@ -223,6 +337,11 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
                        color_mode;
 }
 
+const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+{
+       return omap_current_dss_features->clksrc_names[id];
+}
+
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
index b9c70be9258874dbdca30c6f53eeaefba6307267..12e9c4ef0dec4426fb0197c62559152f623ef703 100644 (file)
@@ -22,6 +22,7 @@
 
 #define MAX_DSS_MANAGERS       3
 #define MAX_DSS_OVERLAYS       3
+#define MAX_DSS_LCD_MANAGERS   2
 
 /* DSS has feature id */
 enum dss_feat_id {
@@ -33,6 +34,12 @@ enum dss_feat_id {
        FEAT_PCKFREEENABLE      = 1 << 5,
        FEAT_FUNCGATED          = 1 << 6,
        FEAT_MGR_LCD2           = 1 << 7,
+       FEAT_LINEBUFFERSPLIT    = 1 << 8,
+       FEAT_ROWREPEATENABLE    = 1 << 9,
+       FEAT_RESIZECONF         = 1 << 10,
+       /* Independent core clk divider */
+       FEAT_CORE_CLK_DIV       = 1 << 11,
+       FEAT_LCD_CLK_SRC        = 1 << 12,
 };
 
 /* DSS register field id */
@@ -42,15 +49,35 @@ enum dss_feat_reg_field {
        FEAT_REG_FIFOHIGHTHRESHOLD,
        FEAT_REG_FIFOLOWTHRESHOLD,
        FEAT_REG_FIFOSIZE,
+       FEAT_REG_HORIZONTALACCU,
+       FEAT_REG_VERTICALACCU,
+       FEAT_REG_DISPC_CLK_SWITCH,
+       FEAT_REG_DSIPLL_REGN,
+       FEAT_REG_DSIPLL_REGM,
+       FEAT_REG_DSIPLL_REGM_DISPC,
+       FEAT_REG_DSIPLL_REGM_DSI,
+};
+
+enum dss_range_param {
+       FEAT_PARAM_DSS_FCK,
+       FEAT_PARAM_DSIPLL_REGN,
+       FEAT_PARAM_DSIPLL_REGM,
+       FEAT_PARAM_DSIPLL_REGM_DISPC,
+       FEAT_PARAM_DSIPLL_REGM_DSI,
+       FEAT_PARAM_DSIPLL_FINT,
+       FEAT_PARAM_DSIPLL_LPDIV,
 };
 
 /* DSS Feature Functions */
 int dss_feat_get_num_mgrs(void);
 int dss_feat_get_num_ovls(void);
+unsigned long dss_feat_get_param_min(enum dss_range_param param);
+unsigned long dss_feat_get_param_max(enum dss_range_param param);
 enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
 enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
 bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
+const char *dss_feat_get_clk_source_name(enum dss_clk_source id);
 
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
new file mode 100644 (file)
index 0000000..0d44f07
--- /dev/null
@@ -0,0 +1,1332 @@
+/*
+ * hdmi.c
+ *
+ * HDMI interface DSS driver setting for TI's OMAP4 family of processor.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Yong Zhi
+ *     Mythri pk <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <plat/display.h>
+
+#include "dss.h"
+#include "hdmi.h"
+
+static struct {
+       struct mutex lock;
+       struct omap_display_platform_data *pdata;
+       struct platform_device *pdev;
+       void __iomem *base_wp;  /* HDMI wrapper */
+       int code;
+       int mode;
+       u8 edid[HDMI_EDID_MAX_LENGTH];
+       u8 edid_set;
+       bool custom_set;
+       struct hdmi_config cfg;
+} hdmi;
+
+/*
+ * Logic for the below structure :
+ * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
+ * There is a correspondence between CEA/VESA timing and code, please
+ * refer to section 6.3 in HDMI 1.3 specification for timing code.
+ *
+ * In the below structure, cea_vesa_timings corresponds to all OMAP4
+ * supported CEA and VESA timing values.code_cea corresponds to the CEA
+ * code, It is used to get the timing from cea_vesa_timing array.Similarly
+ * with code_vesa. Code_index is used for back mapping, that is once EDID
+ * is read from the TV, EDID is parsed to find the timing values and then
+ * map it to corresponding CEA or VESA index.
+ */
+
+static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = {
+       { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0},
+       { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1},
+       { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1},
+       { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0},
+       { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0},
+       { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0},
+       { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0},
+       { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1},
+       { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1},
+       { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1},
+       { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0},
+       { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0},
+       { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1},
+       { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0},
+       { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1},
+       /* VESA From Here */
+       { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0},
+       { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1},
+       { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1},
+       { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0},
+       { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0},
+       { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1},
+       { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1},
+       { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1},
+       { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0},
+       { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0},
+       { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0},
+       { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0},
+       { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1},
+       { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1},
+       { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1},
+       { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1},
+       { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1},
+       { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1},
+       { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}
+};
+
+/*
+ * This is a static mapping array which maps the timing values
+ * with corresponding CEA / VESA code
+ */
+static const int code_index[OMAP_HDMI_TIMINGS_NB] = {
+       1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32,
+       /* <--15 CEA 17--> vesa*/
+       4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A,
+       0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B
+};
+
+/*
+ * This is reverse static mapping which maps the CEA / VESA code
+ * to the corresponding timing values
+ */
+static const int code_cea[39] = {
+       -1,  0,  3,  3,  2,  8,  5,  5, -1, -1,
+       -1, -1, -1, -1, -1, -1,  9, 10, 10,  1,
+       7,   6,  6, -1, -1, -1, -1, -1, -1, 11,
+       11, 12, 14, -1, -1, 13, 13,  4,  4
+};
+
+static const int code_vesa[85] = {
+       -1, -1, -1, -1, 15, -1, -1, -1, -1, 16,
+       -1, -1, -1, -1, 17, -1, 23, -1, -1, -1,
+       -1, -1, 29, 18, -1, -1, -1, 32, 19, -1,
+       -1, -1, 21, -1, -1, 22, -1, -1, -1, 20,
+       -1, 30, 24, -1, -1, -1, -1, 25, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, 31, 26, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, 27, 28, -1, 33};
+
+static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0};
+
+static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val)
+{
+       __raw_writel(val, hdmi.base_wp + idx.idx);
+}
+
+static inline u32 hdmi_read_reg(const struct hdmi_reg idx)
+{
+       return __raw_readl(hdmi.base_wp + idx.idx);
+}
+
+static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
+                               int b2, int b1, u32 val)
+{
+       u32 t = 0;
+       while (val != REG_GET(idx, b2, b1)) {
+               udelay(1);
+               if (t++ > 10000)
+                       return !val;
+       }
+       return val;
+}
+
+int hdmi_init_display(struct omap_dss_device *dssdev)
+{
+       DSSDBG("init_display\n");
+
+       return 0;
+}
+
+static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq,
+               struct hdmi_pll_info *fmt, u16 sd)
+{
+       u32 r;
+
+       /* PLL start always use manual mode */
+       REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
+
+       r = hdmi_read_reg(PLLCTRL_CFG1);
+       r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
+       r = FLD_MOD(r, fmt->regn, 8, 1);  /* CFG1_PLL_REGN */
+
+       hdmi_write_reg(PLLCTRL_CFG1, r);
+
+       r = hdmi_read_reg(PLLCTRL_CFG2);
+
+       r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+       r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
+       r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
+
+       if (dcofreq) {
+               /* divider programming for frequency beyond 1000Mhz */
+               REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10);
+               r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
+       } else {
+               r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
+       }
+
+       hdmi_write_reg(PLLCTRL_CFG2, r);
+
+       r = hdmi_read_reg(PLLCTRL_CFG4);
+       r = FLD_MOD(r, fmt->regm2, 24, 18);
+       r = FLD_MOD(r, fmt->regmf, 17, 0);
+
+       hdmi_write_reg(PLLCTRL_CFG4, r);
+
+       /* go now */
+       REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0);
+
+       /* wait for bit change */
+       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) {
+               DSSERR("PLL GO bit not set\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Wait till the lock bit is set in PLL status */
+       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
+               DSSWARN("cannot lock PLL\n");
+               DSSWARN("CFG1 0x%x\n",
+                       hdmi_read_reg(PLLCTRL_CFG1));
+               DSSWARN("CFG2 0x%x\n",
+                       hdmi_read_reg(PLLCTRL_CFG2));
+               DSSWARN("CFG4 0x%x\n",
+                       hdmi_read_reg(PLLCTRL_CFG4));
+               return -ETIMEDOUT;
+       }
+
+       DSSDBG("PLL locked!\n");
+
+       return 0;
+}
+
+/* PHY_PWR_CMD */
+static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val)
+{
+       /* Command for power control of HDMI PHY */
+       REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6);
+
+       /* Status of the power control of HDMI PHY */
+       if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) {
+               DSSERR("Failed to set PHY power mode to %d\n", val);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/* PLL_PWR_CMD */
+static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val)
+{
+       /* Command for power control of HDMI PLL */
+       REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2);
+
+       /* wait till PHY_PWR_STATUS is set */
+       if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) {
+               DSSERR("Failed to set PHY_PWR_STATUS\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int hdmi_pll_reset(void)
+{
+       /* SYSRESET  controlled by power FSM */
+       REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+
+       /* READ 0x0 reset is in progress */
+       if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) {
+               DSSERR("Failed to sysreset PLL\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int hdmi_phy_init(void)
+{
+       u16 r = 0;
+
+       r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON);
+       if (r)
+               return r;
+
+       r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON);
+       if (r)
+               return r;
+
+       /*
+        * Read address 0 in order to get the SCP reset done completed
+        * Dummy access performed to make sure reset is done
+        */
+       hdmi_read_reg(HDMI_TXPHY_TX_CTRL);
+
+       /*
+        * Write to phy address 0 to configure the clock
+        * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
+        */
+       REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+
+       /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
+       hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
+
+       /* Setup max LDO voltage */
+       REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+
+       /* Write to phy address 3 to change the polarity control */
+       REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+
+       return 0;
+}
+
+static int hdmi_wait_softreset(void)
+{
+       /* reset W1 */
+       REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
+
+       /* wait till SOFTRESET == 0 */
+       if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
+               DSSERR("sysconfig reset failed\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int hdmi_pll_program(struct hdmi_pll_info *fmt)
+{
+       u16 r = 0;
+       enum hdmi_clk_refsel refsel;
+
+       /* wait for wrapper reset */
+       r = hdmi_wait_softreset();
+       if (r)
+               return r;
+
+       r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+       if (r)
+               return r;
+
+       r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
+       if (r)
+               return r;
+
+       r = hdmi_pll_reset();
+       if (r)
+               return r;
+
+       refsel = HDMI_REFSEL_SYSCLK;
+
+       r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static void hdmi_phy_off(void)
+{
+       hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF);
+}
+
+static int hdmi_core_ddc_edid(u8 *pedid, int ext)
+{
+       u32 i, j;
+       char checksum = 0;
+       u32 offset = 0;
+
+       /* Turn on CLK for DDC */
+       REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0);
+
+       /*
+        * SW HACK : Without the Delay DDC(i2c bus) reads 0 values /
+        * right shifted values( The behavior is not consistent and seen only
+        * with some TV's)
+        */
+       usleep_range(800, 1000);
+
+       if (!ext) {
+               /* Clk SCL Devices */
+               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0);
+
+               /* HDMI_CORE_DDC_STATUS_IN_PROG */
+               if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+                                               4, 4, 0) != 0) {
+                       DSSERR("Failed to program DDC\n");
+                       return -ETIMEDOUT;
+               }
+
+               /* Clear FIFO */
+               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0);
+
+               /* HDMI_CORE_DDC_STATUS_IN_PROG */
+               if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS,
+                                               4, 4, 0) != 0) {
+                       DSSERR("Failed to program DDC\n");
+                       return -ETIMEDOUT;
+               }
+
+       } else {
+               if (ext % 2 != 0)
+                       offset = 0x80;
+       }
+
+       /* Load Segment Address Register */
+       REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0);
+
+       /* Load Slave Address Register */
+       REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
+
+       /* Load Offset Address Register */
+       REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+
+       /* Load Byte Count */
+       REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+       REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
+
+       /* Set DDC_CMD */
+       if (ext)
+               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0);
+       else
+               REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0);
+
+       /* HDMI_CORE_DDC_STATUS_BUS_LOW */
+       if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
+               DSSWARN("I2C Bus Low?\n");
+               return -EIO;
+       }
+       /* HDMI_CORE_DDC_STATUS_NO_ACK */
+       if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
+               DSSWARN("I2C No Ack\n");
+               return -EIO;
+       }
+
+       i = ext * 128;
+       j = 0;
+       while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) ||
+                       (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) &&
+                       j < 128) {
+
+               if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) {
+                       /* FIFO not empty */
+                       pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0);
+                       j++;
+               }
+       }
+
+       for (j = 0; j < 128; j++)
+               checksum += pedid[j];
+
+       if (checksum != 0) {
+               DSSERR("E-EDID checksum failed!!\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int read_edid(u8 *pedid, u16 max_length)
+{
+       int r = 0, n = 0, i = 0;
+       int max_ext_blocks = (max_length / 128) - 1;
+
+       r = hdmi_core_ddc_edid(pedid, 0);
+       if (r) {
+               return r;
+       } else {
+               n = pedid[0x7e];
+
+               /*
+                * README: need to comply with max_length set by the caller.
+                * Better implementation should be to allocate necessary
+                * memory to store EDID according to nb_block field found
+                * in first block
+                */
+               if (n > max_ext_blocks)
+                       n = max_ext_blocks;
+
+               for (i = 1; i <= n; i++) {
+                       r = hdmi_core_ddc_edid(pedid, i);
+                       if (r)
+                               return r;
+               }
+       }
+       return 0;
+}
+
+static int get_timings_index(void)
+{
+       int code;
+
+       if (hdmi.mode == 0)
+               code = code_vesa[hdmi.code];
+       else
+               code = code_cea[hdmi.code];
+
+       if (code == -1) {
+               /* HDMI code 4 corresponds to 640 * 480 VGA */
+               hdmi.code = 4;
+               /* DVI mode 1 corresponds to HDMI 0 to DVI */
+               hdmi.mode = HDMI_DVI;
+
+               code = code_vesa[hdmi.code];
+       }
+       return code;
+}
+
+static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
+{
+       int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0;
+       int timing_vsync = 0, timing_hsync = 0;
+       struct omap_video_timings temp;
+       struct hdmi_cm cm = {-1};
+       DSSDBG("hdmi_get_code\n");
+
+       for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) {
+               temp = cea_vesa_timings[i].timings;
+               if ((temp.pixel_clock == timing->pixel_clock) &&
+                       (temp.x_res == timing->x_res) &&
+                       (temp.y_res == timing->y_res)) {
+
+                       temp_hsync = temp.hfp + temp.hsw + temp.hbp;
+                       timing_hsync = timing->hfp + timing->hsw + timing->hbp;
+                       temp_vsync = temp.vfp + temp.vsw + temp.vbp;
+                       timing_vsync = timing->vfp + timing->vsw + timing->vbp;
+
+                       DSSDBG("temp_hsync = %d , temp_vsync = %d"
+                               "timing_hsync = %d, timing_vsync = %d\n",
+                               temp_hsync, temp_hsync,
+                               timing_hsync, timing_vsync);
+
+                       if ((temp_hsync == timing_hsync) &&
+                                       (temp_vsync == timing_vsync)) {
+                               code = i;
+                               cm.code = code_index[i];
+                               if (code < 14)
+                                       cm.mode = HDMI_HDMI;
+                               else
+                                       cm.mode = HDMI_DVI;
+                               DSSDBG("Hdmi_code = %d mode = %d\n",
+                                        cm.code, cm.mode);
+                               break;
+                        }
+               }
+       }
+
+       return cm;
+}
+
+static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid ,
+               struct omap_video_timings *timings)
+{
+       /* X and Y resolution */
+       timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) |
+                        edid[current_descriptor_addrs + 2]);
+       timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) |
+                        edid[current_descriptor_addrs + 5]);
+
+       timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) |
+                               edid[current_descriptor_addrs]);
+
+       timings->pixel_clock = 10 * timings->pixel_clock;
+
+       /* HORIZONTAL FRONT PORCH */
+       timings->hfp = edid[current_descriptor_addrs + 8] |
+                       ((edid[current_descriptor_addrs + 11] & 0xc0) << 2);
+       /* HORIZONTAL SYNC WIDTH */
+       timings->hsw = edid[current_descriptor_addrs + 9] |
+                       ((edid[current_descriptor_addrs + 11] & 0x30) << 4);
+       /* HORIZONTAL BACK PORCH */
+       timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) |
+                       edid[current_descriptor_addrs + 3]) -
+                       (timings->hfp + timings->hsw);
+       /* VERTICAL FRONT PORCH */
+       timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) |
+                       ((edid[current_descriptor_addrs + 11] & 0x0f) << 2);
+       /* VERTICAL SYNC WIDTH */
+       timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) |
+                       ((edid[current_descriptor_addrs + 11] & 0x03) << 4);
+       /* VERTICAL BACK PORCH */
+       timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) |
+                       edid[current_descriptor_addrs + 6]) -
+                       (timings->vfp + timings->vsw);
+
+}
+
+/* Description : This function gets the resolution information from EDID */
+static void get_edid_timing_data(u8 *edid)
+{
+       u8 count;
+       u16 current_descriptor_addrs;
+       struct hdmi_cm cm;
+       struct omap_video_timings edid_timings;
+
+       /* seach block 0, there are 4 DTDs arranged in priority order */
+       for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+               current_descriptor_addrs =
+                       EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+                       count * EDID_TIMING_DESCRIPTOR_SIZE;
+               get_horz_vert_timing_info(current_descriptor_addrs,
+                               edid, &edid_timings);
+               cm = hdmi_get_code(&edid_timings);
+               DSSDBG("Block0[%d] value matches code = %d , mode = %d\n",
+                       count, cm.code, cm.mode);
+               if (cm.code == -1) {
+                       continue;
+               } else {
+                       hdmi.code = cm.code;
+                       hdmi.mode = cm.mode;
+                       DSSDBG("code = %d , mode = %d\n",
+                               hdmi.code, hdmi.mode);
+                       return;
+               }
+       }
+       if (edid[0x7e] != 0x00) {
+               for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+                       count++) {
+                       current_descriptor_addrs =
+                       EDID_DESCRIPTOR_BLOCK1_ADDRESS +
+                       count * EDID_TIMING_DESCRIPTOR_SIZE;
+                       get_horz_vert_timing_info(current_descriptor_addrs,
+                                               edid, &edid_timings);
+                       cm = hdmi_get_code(&edid_timings);
+                       DSSDBG("Block1[%d] value matches code = %d, mode = %d",
+                               count, cm.code, cm.mode);
+                       if (cm.code == -1) {
+                               continue;
+                       } else {
+                               hdmi.code = cm.code;
+                               hdmi.mode = cm.mode;
+                               DSSDBG("code = %d , mode = %d\n",
+                                       hdmi.code, hdmi.mode);
+                               return;
+                       }
+               }
+       }
+
+       DSSINFO("no valid timing found , falling back to VGA\n");
+       hdmi.code = 4; /* setting default value of 640 480 VGA */
+       hdmi.mode = HDMI_DVI;
+}
+
+static void hdmi_read_edid(struct omap_video_timings *dp)
+{
+       int ret = 0, code;
+
+       memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH);
+
+       if (!hdmi.edid_set)
+               ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH);
+
+       if (!ret) {
+               if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) {
+                       /* search for timings of default resolution */
+                       get_edid_timing_data(hdmi.edid);
+                       hdmi.edid_set = true;
+               }
+       } else {
+               DSSWARN("failed to read E-EDID\n");
+       }
+
+       if (!hdmi.edid_set) {
+               DSSINFO("fallback to VGA\n");
+               hdmi.code = 4; /* setting default value of 640 480 VGA */
+               hdmi.mode = HDMI_DVI;
+       }
+
+       code = get_timings_index();
+
+       *dp = cea_vesa_timings[code].timings;
+}
+
+static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
+                       struct hdmi_core_infoframe_avi *avi_cfg,
+                       struct hdmi_core_packet_enable_repeat *repeat_cfg)
+{
+       DSSDBG("Enter hdmi_core_init\n");
+
+       /* video core */
+       video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
+       video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
+       video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
+       video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
+       video_cfg->hdmi_dvi = HDMI_DVI;
+       video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
+
+       /* info frame */
+       avi_cfg->db1_format = 0;
+       avi_cfg->db1_active_info = 0;
+       avi_cfg->db1_bar_info_dv = 0;
+       avi_cfg->db1_scan_info = 0;
+       avi_cfg->db2_colorimetry = 0;
+       avi_cfg->db2_aspect_ratio = 0;
+       avi_cfg->db2_active_fmt_ar = 0;
+       avi_cfg->db3_itc = 0;
+       avi_cfg->db3_ec = 0;
+       avi_cfg->db3_q_range = 0;
+       avi_cfg->db3_nup_scaling = 0;
+       avi_cfg->db4_videocode = 0;
+       avi_cfg->db5_pixel_repeat = 0;
+       avi_cfg->db6_7_line_eoftop = 0 ;
+       avi_cfg->db8_9_line_sofbottom = 0;
+       avi_cfg->db10_11_pixel_eofleft = 0;
+       avi_cfg->db12_13_pixel_sofright = 0;
+
+       /* packet enable and repeat */
+       repeat_cfg->audio_pkt = 0;
+       repeat_cfg->audio_pkt_repeat = 0;
+       repeat_cfg->avi_infoframe = 0;
+       repeat_cfg->avi_infoframe_repeat = 0;
+       repeat_cfg->gen_cntrl_pkt = 0;
+       repeat_cfg->gen_cntrl_pkt_repeat = 0;
+       repeat_cfg->generic_pkt = 0;
+       repeat_cfg->generic_pkt_repeat = 0;
+}
+
+static void hdmi_core_powerdown_disable(void)
+{
+       DSSDBG("Enter hdmi_core_powerdown_disable\n");
+       REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_release(void)
+{
+       DSSDBG("Enter hdmi_core_swreset_release\n");
+       REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0);
+}
+
+static void hdmi_core_swreset_assert(void)
+{
+       DSSDBG("Enter hdmi_core_swreset_assert\n");
+       REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0);
+}
+
+/* DSS_HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_video_config *cfg)
+{
+       u32 r = 0;
+
+       /* sys_ctrl1 default configuration not tunable */
+       r = hdmi_read_reg(HDMI_CORE_CTRL1);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2);
+       r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1);
+       hdmi_write_reg(HDMI_CORE_CTRL1, r);
+
+       REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
+
+       /* Vid_Mode */
+       r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE);
+
+       /* dither truncation configuration */
+       if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
+               r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
+               r = FLD_MOD(r, 1, 5, 5);
+       } else {
+               r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
+               r = FLD_MOD(r, 0, 5, 5);
+       }
+       hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r);
+
+       /* HDMI_Ctrl */
+       r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL);
+       r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
+       r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
+       r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r);
+
+       /* TMDS_CTRL */
+       REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL,
+               cfg->tclk_sel_clkmult, 6, 5);
+}
+
+static void hdmi_core_aux_infoframe_avi_config(
+               struct hdmi_core_infoframe_avi info_avi)
+{
+       u32 val;
+       char sum = 0, checksum = 0;
+
+       sum += 0x82 + 0x002 + 0x00D;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D);
+
+       val = (info_avi.db1_format << 5) |
+               (info_avi.db1_active_info << 4) |
+               (info_avi.db1_bar_info_dv << 2) |
+               (info_avi.db1_scan_info);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val);
+       sum += val;
+
+       val = (info_avi.db2_colorimetry << 6) |
+               (info_avi.db2_aspect_ratio << 4) |
+               (info_avi.db2_active_fmt_ar);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val);
+       sum += val;
+
+       val = (info_avi.db3_itc << 7) |
+               (info_avi.db3_ec << 4) |
+               (info_avi.db3_q_range << 2) |
+               (info_avi.db3_nup_scaling);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val);
+       sum += val;
+
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode);
+       sum += info_avi.db4_videocode;
+
+       val = info_avi.db5_pixel_repeat;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val);
+       sum += val;
+
+       val = info_avi.db6_7_line_eoftop & 0x00FF;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val);
+       sum += val;
+
+       val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val);
+       sum += val;
+
+       val = info_avi.db8_9_line_sofbottom & 0x00FF;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val);
+       sum += val;
+
+       val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val);
+       sum += val;
+
+       val = info_avi.db10_11_pixel_eofleft & 0x00FF;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val);
+       sum += val;
+
+       val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val);
+       sum += val;
+
+       val = info_avi.db12_13_pixel_sofright & 0x00FF;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val);
+       sum += val;
+
+       val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
+       hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val);
+       sum += val;
+
+       checksum = 0x100 - sum;
+       hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum);
+}
+
+static void hdmi_core_av_packet_config(
+               struct hdmi_core_packet_enable_repeat repeat_cfg)
+{
+       /* enable/repeat the infoframe */
+       hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1,
+               (repeat_cfg.audio_pkt << 5) |
+               (repeat_cfg.audio_pkt_repeat << 4) |
+               (repeat_cfg.avi_infoframe << 1) |
+               (repeat_cfg.avi_infoframe_repeat));
+
+       /* enable/repeat the packet */
+       hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2,
+               (repeat_cfg.gen_cntrl_pkt << 3) |
+               (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
+               (repeat_cfg.generic_pkt << 1) |
+               (repeat_cfg.generic_pkt_repeat));
+}
+
+static void hdmi_wp_init(struct omap_video_timings *timings,
+                       struct hdmi_video_format *video_fmt,
+                       struct hdmi_video_interface *video_int)
+{
+       DSSDBG("Enter hdmi_wp_init\n");
+
+       timings->hbp = 0;
+       timings->hfp = 0;
+       timings->hsw = 0;
+       timings->vbp = 0;
+       timings->vfp = 0;
+       timings->vsw = 0;
+
+       video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
+       video_fmt->y_res = 0;
+       video_fmt->x_res = 0;
+
+       video_int->vsp = 0;
+       video_int->hsp = 0;
+
+       video_int->interlacing = 0;
+       video_int->tm = 0; /* HDMI_TIMING_SLAVE */
+
+}
+
+static void hdmi_wp_video_start(bool start)
+{
+       REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31);
+}
+
+static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt,
+       struct omap_video_timings *timings, struct hdmi_config *param)
+{
+       DSSDBG("Enter hdmi_wp_video_init_format\n");
+
+       video_fmt->y_res = param->timings.timings.y_res;
+       video_fmt->x_res = param->timings.timings.x_res;
+
+       timings->hbp = param->timings.timings.hbp;
+       timings->hfp = param->timings.timings.hfp;
+       timings->hsw = param->timings.timings.hsw;
+       timings->vbp = param->timings.timings.vbp;
+       timings->vfp = param->timings.timings.vfp;
+       timings->vsw = param->timings.timings.vsw;
+}
+
+static void hdmi_wp_video_config_format(
+               struct hdmi_video_format *video_fmt)
+{
+       u32 l = 0;
+
+       REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8);
+
+       l |= FLD_VAL(video_fmt->y_res, 31, 16);
+       l |= FLD_VAL(video_fmt->x_res, 15, 0);
+       hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l);
+}
+
+static void hdmi_wp_video_config_interface(
+               struct hdmi_video_interface *video_int)
+{
+       u32 r;
+       DSSDBG("Enter hdmi_wp_video_config_interface\n");
+
+       r = hdmi_read_reg(HDMI_WP_VIDEO_CFG);
+       r = FLD_MOD(r, video_int->vsp, 7, 7);
+       r = FLD_MOD(r, video_int->hsp, 6, 6);
+       r = FLD_MOD(r, video_int->interlacing, 3, 3);
+       r = FLD_MOD(r, video_int->tm, 1, 0);
+       hdmi_write_reg(HDMI_WP_VIDEO_CFG, r);
+}
+
+static void hdmi_wp_video_config_timing(
+               struct omap_video_timings *timings)
+{
+       u32 timing_h = 0;
+       u32 timing_v = 0;
+
+       DSSDBG("Enter hdmi_wp_video_config_timing\n");
+
+       timing_h |= FLD_VAL(timings->hbp, 31, 20);
+       timing_h |= FLD_VAL(timings->hfp, 19, 8);
+       timing_h |= FLD_VAL(timings->hsw, 7, 0);
+       hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h);
+
+       timing_v |= FLD_VAL(timings->vbp, 31, 20);
+       timing_v |= FLD_VAL(timings->vfp, 19, 8);
+       timing_v |= FLD_VAL(timings->vsw, 7, 0);
+       hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v);
+}
+
+static void hdmi_basic_configure(struct hdmi_config *cfg)
+{
+       /* HDMI */
+       struct omap_video_timings video_timing;
+       struct hdmi_video_format video_format;
+       struct hdmi_video_interface video_interface;
+       /* HDMI core */
+       struct hdmi_core_infoframe_avi avi_cfg;
+       struct hdmi_core_video_config v_core_cfg;
+       struct hdmi_core_packet_enable_repeat repeat_cfg;
+
+       hdmi_wp_init(&video_timing, &video_format,
+               &video_interface);
+
+       hdmi_core_init(&v_core_cfg,
+               &avi_cfg,
+               &repeat_cfg);
+
+       hdmi_wp_video_init_format(&video_format,
+                       &video_timing, cfg);
+
+       hdmi_wp_video_config_timing(&video_timing);
+
+       /* video config */
+       video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+       hdmi_wp_video_config_format(&video_format);
+
+       video_interface.vsp = cfg->timings.vsync_pol;
+       video_interface.hsp = cfg->timings.hsync_pol;
+       video_interface.interlacing = cfg->interlace;
+       video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */
+
+       hdmi_wp_video_config_interface(&video_interface);
+
+       /*
+        * configure core video part
+        * set software reset in the core
+        */
+       hdmi_core_swreset_assert();
+
+       /* power down off */
+       hdmi_core_powerdown_disable();
+
+       v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
+       v_core_cfg.hdmi_dvi = cfg->cm.mode;
+
+       hdmi_core_video_config(&v_core_cfg);
+
+       /* release software reset in the core */
+       hdmi_core_swreset_release();
+
+       /*
+        * configure packet
+        * info frame video see doc CEA861-D page 65
+        */
+       avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
+       avi_cfg.db1_active_info =
+               HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
+       avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
+       avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
+       avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
+       avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
+       avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
+       avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
+       avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
+       avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
+       avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
+       avi_cfg.db4_videocode = cfg->cm.code;
+       avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
+       avi_cfg.db6_7_line_eoftop = 0;
+       avi_cfg.db8_9_line_sofbottom = 0;
+       avi_cfg.db10_11_pixel_eofleft = 0;
+       avi_cfg.db12_13_pixel_sofright = 0;
+
+       hdmi_core_aux_infoframe_avi_config(avi_cfg);
+
+       /* enable/repeat the infoframe */
+       repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
+       repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
+       /* wakeup */
+       repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
+       repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
+       hdmi_core_av_packet_config(repeat_cfg);
+}
+
+static void update_hdmi_timings(struct hdmi_config *cfg,
+               struct omap_video_timings *timings, int code)
+{
+       cfg->timings.timings.x_res = timings->x_res;
+       cfg->timings.timings.y_res = timings->y_res;
+       cfg->timings.timings.hbp = timings->hbp;
+       cfg->timings.timings.hfp = timings->hfp;
+       cfg->timings.timings.hsw = timings->hsw;
+       cfg->timings.timings.vbp = timings->vbp;
+       cfg->timings.timings.vfp = timings->vfp;
+       cfg->timings.timings.vsw = timings->vsw;
+       cfg->timings.timings.pixel_clock = timings->pixel_clock;
+       cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol;
+       cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
+}
+
+static void hdmi_compute_pll(unsigned long clkin, int phy,
+       int n, struct hdmi_pll_info *pi)
+{
+       unsigned long refclk;
+       u32 mf;
+
+       /*
+        * Input clock is predivided by N + 1
+        * out put of which is reference clk
+        */
+       refclk = clkin / (n + 1);
+       pi->regn = n;
+
+       /*
+        * multiplier is pixel_clk/ref_clk
+        * Multiplying by 100 to avoid fractional part removal
+        */
+       pi->regm = (phy * 100/(refclk))/100;
+       pi->regm2 = 1;
+
+       /*
+        * fractional multiplier is remainder of the difference between
+        * multiplier and actual phy(required pixel clock thus should be
+        * multiplied by 2^18(262144) divided by the reference clock
+        */
+       mf = (phy - pi->regm * refclk) * 262144;
+       pi->regmf = mf/(refclk);
+
+       /*
+        * Dcofreq should be set to 1 if required pixel clock
+        * is greater than 1000MHz
+        */
+       pi->dcofreq = phy > 1000 * 100;
+       pi->regsd = ((pi->regm * clkin / 10) / ((n + 1) * 250) + 5) / 10;
+
+       DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
+       DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
+}
+
+static void hdmi_enable_clocks(int enable)
+{
+       if (enable)
+               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
+                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+       else
+               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
+                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
+}
+
+static int hdmi_power_on(struct omap_dss_device *dssdev)
+{
+       int r, code = 0;
+       struct hdmi_pll_info pll_data;
+       struct omap_video_timings *p;
+       int clkin, n, phy;
+
+       hdmi_enable_clocks(1);
+
+       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+       p = &dssdev->panel.timings;
+
+       DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
+               dssdev->panel.timings.x_res,
+               dssdev->panel.timings.y_res);
+
+       if (!hdmi.custom_set) {
+               DSSDBG("Read EDID as no EDID is not set on poweron\n");
+               hdmi_read_edid(p);
+       }
+       code = get_timings_index();
+       dssdev->panel.timings = cea_vesa_timings[code].timings;
+       update_hdmi_timings(&hdmi.cfg, p, code);
+
+       clkin = 3840; /* 38.4 MHz */
+       n = 15; /* this is a constant for our math */
+       phy = p->pixel_clock;
+
+       hdmi_compute_pll(clkin, phy, n, &pll_data);
+
+       hdmi_wp_video_start(0);
+
+       /* config the PLL and PHY first */
+       r = hdmi_pll_program(&pll_data);
+       if (r) {
+               DSSDBG("Failed to lock PLL\n");
+               goto err;
+       }
+
+       r = hdmi_phy_init();
+       if (r) {
+               DSSDBG("Failed to start PHY\n");
+               goto err;
+       }
+
+       hdmi.cfg.cm.mode = hdmi.mode;
+       hdmi.cfg.cm.code = hdmi.code;
+       hdmi_basic_configure(&hdmi.cfg);
+
+       /* Make selection of HDMI in DSS */
+       dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+       /* Select the dispc clock source as PRCM clock, to ensure that it is not
+        * DSI PLL source as the clock selected by DSI PLL might not be
+        * sufficient for the resolution selected / that can be changed
+        * dynamically by user. This can be moved to single location , say
+        * Boardfile.
+        */
+       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+
+       /* bypass TV gamma table */
+       dispc_enable_gamma_table(0);
+
+       /* tv size */
+       dispc_set_digit_size(dssdev->panel.timings.x_res,
+                       dssdev->panel.timings.y_res);
+
+       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1);
+
+       hdmi_wp_video_start(1);
+
+       return 0;
+err:
+       hdmi_enable_clocks(0);
+       return -EIO;
+}
+
+static void hdmi_power_off(struct omap_dss_device *dssdev)
+{
+       dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
+
+       hdmi_wp_video_start(0);
+       hdmi_phy_off();
+       hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
+       hdmi_enable_clocks(0);
+
+       hdmi.edid_set = 0;
+}
+
+int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
+                                       struct omap_video_timings *timings)
+{
+       struct hdmi_cm cm;
+
+       cm = hdmi_get_code(timings);
+       if (cm.code == -1) {
+               DSSERR("Invalid timing entered\n");
+               return -EINVAL;
+       }
+
+       return 0;
+
+}
+
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+{
+       struct hdmi_cm cm;
+
+       hdmi.custom_set = 1;
+       cm = hdmi_get_code(&dssdev->panel.timings);
+       hdmi.code = cm.code;
+       hdmi.mode = cm.mode;
+       omapdss_hdmi_display_enable(dssdev);
+       hdmi.custom_set = 0;
+}
+
+int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       DSSDBG("ENTER hdmi_display_enable\n");
+
+       mutex_lock(&hdmi.lock);
+
+       r = omap_dss_start_device(dssdev);
+       if (r) {
+               DSSERR("failed to start device\n");
+               goto err0;
+       }
+
+       if (dssdev->platform_enable) {
+               r = dssdev->platform_enable(dssdev);
+               if (r) {
+                       DSSERR("failed to enable GPIO's\n");
+                       goto err1;
+               }
+       }
+
+       r = hdmi_power_on(dssdev);
+       if (r) {
+               DSSERR("failed to power on device\n");
+               goto err2;
+       }
+
+       mutex_unlock(&hdmi.lock);
+       return 0;
+
+err2:
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+err1:
+       omap_dss_stop_device(dssdev);
+err0:
+       mutex_unlock(&hdmi.lock);
+       return r;
+}
+
+void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+       DSSDBG("Enter hdmi_display_disable\n");
+
+       mutex_lock(&hdmi.lock);
+
+       hdmi_power_off(dssdev);
+
+       if (dssdev->platform_disable)
+               dssdev->platform_disable(dssdev);
+
+       omap_dss_stop_device(dssdev);
+
+       mutex_unlock(&hdmi.lock);
+}
+
+/* HDMI HW IP initialisation */
+static int omapdss_hdmihw_probe(struct platform_device *pdev)
+{
+       struct resource *hdmi_mem;
+
+       hdmi.pdata = pdev->dev.platform_data;
+       hdmi.pdev = pdev;
+
+       mutex_init(&hdmi.lock);
+
+       hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
+       if (!hdmi_mem) {
+               DSSERR("can't get IORESOURCE_MEM HDMI\n");
+               return -EINVAL;
+       }
+
+       /* Base address taken from platform */
+       hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem));
+       if (!hdmi.base_wp) {
+               DSSERR("can't ioremap WP\n");
+               return -ENOMEM;
+       }
+
+       hdmi_panel_init();
+
+       return 0;
+}
+
+static int omapdss_hdmihw_remove(struct platform_device *pdev)
+{
+       hdmi_panel_exit();
+
+       iounmap(hdmi.base_wp);
+
+       return 0;
+}
+
+static struct platform_driver omapdss_hdmihw_driver = {
+       .probe          = omapdss_hdmihw_probe,
+       .remove         = omapdss_hdmihw_remove,
+       .driver         = {
+               .name   = "omapdss_hdmi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int hdmi_init_platform_driver(void)
+{
+       return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void hdmi_uninit_platform_driver(void)
+{
+       return platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
new file mode 100644 (file)
index 0000000..9887ab9
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * hdmi.h
+ *
+ * HDMI driver definition for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _OMAP4_DSS_HDMI_H_
+#define _OMAP4_DSS_HDMI_H_
+
+#include <linux/string.h>
+#include <plat/display.h>
+
+#define HDMI_WP                0x0
+#define HDMI_CORE_SYS          0x400
+#define HDMI_CORE_AV           0x900
+#define HDMI_PLLCTRL           0x200
+#define HDMI_PHY               0x300
+
+struct hdmi_reg { u16 idx; };
+
+#define HDMI_REG(idx)                  ((const struct hdmi_reg) { idx })
+
+/* HDMI Wrapper */
+#define HDMI_WP_REG(idx)                       HDMI_REG(HDMI_WP + idx)
+
+#define HDMI_WP_REVISION                       HDMI_WP_REG(0x0)
+#define HDMI_WP_SYSCONFIG                      HDMI_WP_REG(0x10)
+#define HDMI_WP_IRQSTATUS_RAW                  HDMI_WP_REG(0x24)
+#define HDMI_WP_IRQSTATUS                      HDMI_WP_REG(0x28)
+#define HDMI_WP_PWR_CTRL                       HDMI_WP_REG(0x40)
+#define HDMI_WP_IRQENABLE_SET                  HDMI_WP_REG(0x2C)
+#define HDMI_WP_VIDEO_CFG                      HDMI_WP_REG(0x50)
+#define HDMI_WP_VIDEO_SIZE                     HDMI_WP_REG(0x60)
+#define HDMI_WP_VIDEO_TIMING_H                 HDMI_WP_REG(0x68)
+#define HDMI_WP_VIDEO_TIMING_V                 HDMI_WP_REG(0x6C)
+#define HDMI_WP_WP_CLK                         HDMI_WP_REG(0x70)
+
+/* HDMI IP Core System */
+#define HDMI_CORE_SYS_REG(idx)                 HDMI_REG(HDMI_CORE_SYS + idx)
+
+#define HDMI_CORE_SYS_VND_IDL                  HDMI_CORE_SYS_REG(0x0)
+#define HDMI_CORE_SYS_DEV_IDL                  HDMI_CORE_SYS_REG(0x8)
+#define HDMI_CORE_SYS_DEV_IDH                  HDMI_CORE_SYS_REG(0xC)
+#define HDMI_CORE_SYS_DEV_REV                  HDMI_CORE_SYS_REG(0x10)
+#define HDMI_CORE_SYS_SRST                     HDMI_CORE_SYS_REG(0x14)
+#define HDMI_CORE_CTRL1                        HDMI_CORE_SYS_REG(0x20)
+#define HDMI_CORE_SYS_SYS_STAT                 HDMI_CORE_SYS_REG(0x24)
+#define HDMI_CORE_SYS_VID_ACEN                 HDMI_CORE_SYS_REG(0x124)
+#define HDMI_CORE_SYS_VID_MODE                 HDMI_CORE_SYS_REG(0x128)
+#define HDMI_CORE_SYS_INTR_STATE               HDMI_CORE_SYS_REG(0x1C0)
+#define HDMI_CORE_SYS_INTR1                    HDMI_CORE_SYS_REG(0x1C4)
+#define HDMI_CORE_SYS_INTR2                    HDMI_CORE_SYS_REG(0x1C8)
+#define HDMI_CORE_SYS_INTR3                    HDMI_CORE_SYS_REG(0x1CC)
+#define HDMI_CORE_SYS_INTR4                    HDMI_CORE_SYS_REG(0x1D0)
+#define HDMI_CORE_SYS_UMASK1                   HDMI_CORE_SYS_REG(0x1D4)
+#define HDMI_CORE_SYS_TMDS_CTRL                HDMI_CORE_SYS_REG(0x208)
+#define HDMI_CORE_SYS_DE_DLY                   HDMI_CORE_SYS_REG(0xC8)
+#define HDMI_CORE_SYS_DE_CTRL                  HDMI_CORE_SYS_REG(0xCC)
+#define HDMI_CORE_SYS_DE_TOP                   HDMI_CORE_SYS_REG(0xD0)
+#define HDMI_CORE_SYS_DE_CNTL                  HDMI_CORE_SYS_REG(0xD8)
+#define HDMI_CORE_SYS_DE_CNTH                  HDMI_CORE_SYS_REG(0xDC)
+#define HDMI_CORE_SYS_DE_LINL                  HDMI_CORE_SYS_REG(0xE0)
+#define HDMI_CORE_SYS_DE_LINH_1                HDMI_CORE_SYS_REG(0xE4)
+#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC        0x1
+#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC        0x1
+#define HDMI_CORE_CTRL1_BSEL_24BITBUS          0x1
+#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE        0x1
+
+/* HDMI DDC E-DID */
+#define HDMI_CORE_DDC_CMD                      HDMI_CORE_SYS_REG(0x3CC)
+#define HDMI_CORE_DDC_STATUS                   HDMI_CORE_SYS_REG(0x3C8)
+#define HDMI_CORE_DDC_ADDR                     HDMI_CORE_SYS_REG(0x3B4)
+#define HDMI_CORE_DDC_OFFSET                   HDMI_CORE_SYS_REG(0x3BC)
+#define HDMI_CORE_DDC_COUNT1                   HDMI_CORE_SYS_REG(0x3C0)
+#define HDMI_CORE_DDC_COUNT2                   HDMI_CORE_SYS_REG(0x3C4)
+#define HDMI_CORE_DDC_DATA                     HDMI_CORE_SYS_REG(0x3D0)
+#define HDMI_CORE_DDC_SEGM                     HDMI_CORE_SYS_REG(0x3B8)
+
+/* HDMI IP Core Audio Video */
+#define HDMI_CORE_AV_REG(idx)                  HDMI_REG(HDMI_CORE_AV + idx)
+
+#define HDMI_CORE_AV_HDMI_CTRL                 HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_DPD                       HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1                  HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2                  HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE                  HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS                  HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN                   HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM                 HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_AVI_DBYTE(n)              HDMI_CORE_AV_REG(n * 4 + 0x110)
+#define HDMI_CORE_AV_AVI_DBYTE_NELEMS          HDMI_CORE_AV_REG(15)
+#define HDMI_CORE_AV_SPD_DBYTE                 HDMI_CORE_AV_REG(0x190)
+#define HDMI_CORE_AV_SPD_DBYTE_NELEMS          HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_MPEG_DBYTE                HDMI_CORE_AV_REG(0x290)
+#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_GEN_DBYTE                 HDMI_CORE_AV_REG(0x300)
+#define HDMI_CORE_AV_GEN_DBYTE_NELEMS          HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_GEN2_DBYTE                HDMI_CORE_AV_REG(0x380)
+#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS         HDMI_CORE_AV_REG(31)
+#define HDMI_CORE_AV_ACR_CTRL                  HDMI_CORE_AV_REG(0x4)
+#define HDMI_CORE_AV_FREQ_SVAL                 HDMI_CORE_AV_REG(0x8)
+#define HDMI_CORE_AV_N_SVAL1                   HDMI_CORE_AV_REG(0xC)
+#define HDMI_CORE_AV_N_SVAL2                   HDMI_CORE_AV_REG(0x10)
+#define HDMI_CORE_AV_N_SVAL3                   HDMI_CORE_AV_REG(0x14)
+#define HDMI_CORE_AV_CTS_SVAL1                 HDMI_CORE_AV_REG(0x18)
+#define HDMI_CORE_AV_CTS_SVAL2                 HDMI_CORE_AV_REG(0x1C)
+#define HDMI_CORE_AV_CTS_SVAL3                 HDMI_CORE_AV_REG(0x20)
+#define HDMI_CORE_AV_CTS_HVAL1                 HDMI_CORE_AV_REG(0x24)
+#define HDMI_CORE_AV_CTS_HVAL2                 HDMI_CORE_AV_REG(0x28)
+#define HDMI_CORE_AV_CTS_HVAL3                 HDMI_CORE_AV_REG(0x2C)
+#define HDMI_CORE_AV_AUD_MODE                  HDMI_CORE_AV_REG(0x50)
+#define HDMI_CORE_AV_SPDIF_CTRL                HDMI_CORE_AV_REG(0x54)
+#define HDMI_CORE_AV_HW_SPDIF_FS               HDMI_CORE_AV_REG(0x60)
+#define HDMI_CORE_AV_SWAP_I2S                  HDMI_CORE_AV_REG(0x64)
+#define HDMI_CORE_AV_SPDIF_ERTH                HDMI_CORE_AV_REG(0x6C)
+#define HDMI_CORE_AV_I2S_IN_MAP                HDMI_CORE_AV_REG(0x70)
+#define HDMI_CORE_AV_I2S_IN_CTRL               HDMI_CORE_AV_REG(0x74)
+#define HDMI_CORE_AV_I2S_CHST0                 HDMI_CORE_AV_REG(0x78)
+#define HDMI_CORE_AV_I2S_CHST1                 HDMI_CORE_AV_REG(0x7C)
+#define HDMI_CORE_AV_I2S_CHST2                 HDMI_CORE_AV_REG(0x80)
+#define HDMI_CORE_AV_I2S_CHST4                 HDMI_CORE_AV_REG(0x84)
+#define HDMI_CORE_AV_I2S_CHST5                 HDMI_CORE_AV_REG(0x88)
+#define HDMI_CORE_AV_ASRC                      HDMI_CORE_AV_REG(0x8C)
+#define HDMI_CORE_AV_I2S_IN_LEN                HDMI_CORE_AV_REG(0x90)
+#define HDMI_CORE_AV_HDMI_CTRL                 HDMI_CORE_AV_REG(0xBC)
+#define HDMI_CORE_AV_AUDO_TXSTAT               HDMI_CORE_AV_REG(0xC0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1          HDMI_CORE_AV_REG(0xCC)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2          HDMI_CORE_AV_REG(0xD0)
+#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3          HDMI_CORE_AV_REG(0xD4)
+#define HDMI_CORE_AV_TEST_TXCTRL               HDMI_CORE_AV_REG(0xF0)
+#define HDMI_CORE_AV_DPD                       HDMI_CORE_AV_REG(0xF4)
+#define HDMI_CORE_AV_PB_CTRL1                  HDMI_CORE_AV_REG(0xF8)
+#define HDMI_CORE_AV_PB_CTRL2                  HDMI_CORE_AV_REG(0xFC)
+#define HDMI_CORE_AV_AVI_TYPE                  HDMI_CORE_AV_REG(0x100)
+#define HDMI_CORE_AV_AVI_VERS                  HDMI_CORE_AV_REG(0x104)
+#define HDMI_CORE_AV_AVI_LEN                   HDMI_CORE_AV_REG(0x108)
+#define HDMI_CORE_AV_AVI_CHSUM                 HDMI_CORE_AV_REG(0x10C)
+#define HDMI_CORE_AV_SPD_TYPE                  HDMI_CORE_AV_REG(0x180)
+#define HDMI_CORE_AV_SPD_VERS                  HDMI_CORE_AV_REG(0x184)
+#define HDMI_CORE_AV_SPD_LEN                   HDMI_CORE_AV_REG(0x188)
+#define HDMI_CORE_AV_SPD_CHSUM                 HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_MPEG_TYPE                 HDMI_CORE_AV_REG(0x280)
+#define HDMI_CORE_AV_MPEG_VERS                 HDMI_CORE_AV_REG(0x284)
+#define HDMI_CORE_AV_MPEG_LEN                  HDMI_CORE_AV_REG(0x288)
+#define HDMI_CORE_AV_MPEG_CHSUM                HDMI_CORE_AV_REG(0x28C)
+#define HDMI_CORE_AV_CP_BYTE1                  HDMI_CORE_AV_REG(0x37C)
+#define HDMI_CORE_AV_CEC_ADDR_ID               HDMI_CORE_AV_REG(0x3FC)
+#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE          0x4
+#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE         0x4
+#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE         0x4
+#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE          0x4
+
+/* PLL */
+#define HDMI_PLL_REG(idx)                      HDMI_REG(HDMI_PLLCTRL + idx)
+
+#define PLLCTRL_PLL_CONTROL                    HDMI_PLL_REG(0x0)
+#define PLLCTRL_PLL_STATUS                     HDMI_PLL_REG(0x4)
+#define PLLCTRL_PLL_GO                         HDMI_PLL_REG(0x8)
+#define PLLCTRL_CFG1                           HDMI_PLL_REG(0xC)
+#define PLLCTRL_CFG2                           HDMI_PLL_REG(0x10)
+#define PLLCTRL_CFG3                           HDMI_PLL_REG(0x14)
+#define PLLCTRL_CFG4                           HDMI_PLL_REG(0x20)
+
+/* HDMI PHY */
+#define HDMI_PHY_REG(idx)                      HDMI_REG(HDMI_PHY + idx)
+
+#define HDMI_TXPHY_TX_CTRL                     HDMI_PHY_REG(0x0)
+#define HDMI_TXPHY_DIGITAL_CTRL                HDMI_PHY_REG(0x4)
+#define HDMI_TXPHY_POWER_CTRL                  HDMI_PHY_REG(0x8)
+#define HDMI_TXPHY_PAD_CFG_CTRL                HDMI_PHY_REG(0xC)
+
+/* HDMI EDID Length  */
+#define HDMI_EDID_MAX_LENGTH                   256
+#define EDID_TIMING_DESCRIPTOR_SIZE            0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS         0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS         0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR     4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR     4
+
+#define OMAP_HDMI_TIMINGS_NB                   34
+
+#define REG_FLD_MOD(idx, val, start, end) \
+       hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end))
+#define REG_GET(idx, start, end) \
+       FLD_GET(hdmi_read_reg(idx), start, end)
+
+/* HDMI timing structure */
+struct hdmi_timings {
+       struct omap_video_timings timings;
+       int vsync_pol;
+       int hsync_pol;
+};
+
+enum hdmi_phy_pwr {
+       HDMI_PHYPWRCMD_OFF = 0,
+       HDMI_PHYPWRCMD_LDOON = 1,
+       HDMI_PHYPWRCMD_TXON = 2
+};
+
+enum hdmi_pll_pwr {
+       HDMI_PLLPWRCMD_ALLOFF = 0,
+       HDMI_PLLPWRCMD_PLLONLY = 1,
+       HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
+       HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
+};
+
+enum hdmi_clk_refsel {
+       HDMI_REFSEL_PCLK = 0,
+       HDMI_REFSEL_REF1 = 1,
+       HDMI_REFSEL_REF2 = 2,
+       HDMI_REFSEL_SYSCLK = 3
+};
+
+enum hdmi_core_inputbus_width {
+       HDMI_INPUT_8BIT = 0,
+       HDMI_INPUT_10BIT = 1,
+       HDMI_INPUT_12BIT = 2
+};
+
+enum hdmi_core_dither_trunc {
+       HDMI_OUTPUTTRUNCATION_8BIT = 0,
+       HDMI_OUTPUTTRUNCATION_10BIT = 1,
+       HDMI_OUTPUTTRUNCATION_12BIT = 2,
+       HDMI_OUTPUTDITHER_8BIT = 3,
+       HDMI_OUTPUTDITHER_10BIT = 4,
+       HDMI_OUTPUTDITHER_12BIT = 5
+};
+
+enum hdmi_core_deepcolor_ed {
+       HDMI_DEEPCOLORPACKECTDISABLE = 0,
+       HDMI_DEEPCOLORPACKECTENABLE = 1
+};
+
+enum hdmi_core_packet_mode {
+       HDMI_PACKETMODERESERVEDVALUE = 0,
+       HDMI_PACKETMODE24BITPERPIXEL = 4,
+       HDMI_PACKETMODE30BITPERPIXEL = 5,
+       HDMI_PACKETMODE36BITPERPIXEL = 6,
+       HDMI_PACKETMODE48BITPERPIXEL = 7
+};
+
+enum hdmi_core_hdmi_dvi {
+       HDMI_DVI = 0,
+       HDMI_HDMI = 1
+};
+
+enum hdmi_core_tclkselclkmult {
+       HDMI_FPLL05IDCK = 0,
+       HDMI_FPLL10IDCK = 1,
+       HDMI_FPLL20IDCK = 2,
+       HDMI_FPLL40IDCK = 3
+};
+
+enum hdmi_core_packet_ctrl {
+       HDMI_PACKETENABLE = 1,
+       HDMI_PACKETDISABLE = 0,
+       HDMI_PACKETREPEATON = 1,
+       HDMI_PACKETREPEATOFF = 0
+};
+
+/* INFOFRAME_AVI_ definitions */
+enum hdmi_core_infoframe {
+       HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
+       HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
+       HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
+       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
+       HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON =  1,
+       HDMI_INFOFRAME_AVI_DB1B_NO = 0,
+       HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
+       HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
+       HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
+       HDMI_INFOFRAME_AVI_DB1S_0 = 0,
+       HDMI_INFOFRAME_AVI_DB1S_1 = 1,
+       HDMI_INFOFRAME_AVI_DB1S_2 = 2,
+       HDMI_INFOFRAME_AVI_DB2C_NO = 0,
+       HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
+       HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
+       HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
+       HDMI_INFOFRAME_AVI_DB2M_NO = 0,
+       HDMI_INFOFRAME_AVI_DB2M_43 = 1,
+       HDMI_INFOFRAME_AVI_DB2M_169 = 2,
+       HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
+       HDMI_INFOFRAME_AVI_DB2R_43 = 9,
+       HDMI_INFOFRAME_AVI_DB2R_169 = 10,
+       HDMI_INFOFRAME_AVI_DB2R_149 = 11,
+       HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
+       HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
+       HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
+       HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
+       HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
+       HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
+       HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
+       HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
+       HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
+       HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
+       HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
+       HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
+       HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
+       HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
+       HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
+       HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
+       HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
+       HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
+       HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
+       HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
+       HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+};
+
+enum hdmi_packing_mode {
+       HDMI_PACK_10b_RGB_YUV444 = 0,
+       HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
+       HDMI_PACK_20b_YUV422 = 2,
+       HDMI_PACK_ALREADYPACKED = 7
+};
+
+struct hdmi_core_video_config {
+       enum hdmi_core_inputbus_width   ip_bus_width;
+       enum hdmi_core_dither_trunc     op_dither_truc;
+       enum hdmi_core_deepcolor_ed     deep_color_pkt;
+       enum hdmi_core_packet_mode      pkt_mode;
+       enum hdmi_core_hdmi_dvi         hdmi_dvi;
+       enum hdmi_core_tclkselclkmult   tclk_sel_clkmult;
+};
+
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_avi {
+       u8      db1_format;
+               /* Y0, Y1 rgb,yCbCr */
+       u8      db1_active_info;
+               /* A0  Active information Present */
+       u8      db1_bar_info_dv;
+               /* B0, B1 Bar info data valid */
+       u8      db1_scan_info;
+               /* S0, S1 scan information */
+       u8      db2_colorimetry;
+               /* C0, C1 colorimetry */
+       u8      db2_aspect_ratio;
+               /* M0, M1 Aspect ratio (4:3, 16:9) */
+       u8      db2_active_fmt_ar;
+               /* R0...R3 Active format aspect ratio */
+       u8      db3_itc;
+               /* ITC IT content. */
+       u8      db3_ec;
+               /* EC0, EC1, EC2 Extended colorimetry */
+       u8      db3_q_range;
+               /* Q1, Q0 Quantization range */
+       u8      db3_nup_scaling;
+               /* SC1, SC0 Non-uniform picture scaling */
+       u8      db4_videocode;
+               /* VIC0..6 Video format identification */
+       u8      db5_pixel_repeat;
+               /* PR0..PR3 Pixel repetition factor */
+       u16     db6_7_line_eoftop;
+               /* Line number end of top bar */
+       u16     db8_9_line_sofbottom;
+               /* Line number start of bottom bar */
+       u16     db10_11_pixel_eofleft;
+               /* Pixel number end of left bar */
+       u16     db12_13_pixel_sofright;
+               /* Pixel number start of right bar */
+};
+
+struct hdmi_core_packet_enable_repeat {
+       u32     audio_pkt;
+       u32     audio_pkt_repeat;
+       u32     avi_infoframe;
+       u32     avi_infoframe_repeat;
+       u32     gen_cntrl_pkt;
+       u32     gen_cntrl_pkt_repeat;
+       u32     generic_pkt;
+       u32     generic_pkt_repeat;
+};
+
+struct hdmi_video_format {
+       enum hdmi_packing_mode  packing_mode;
+       u32                     y_res;  /* Line per panel */
+       u32                     x_res;  /* pixel per line */
+};
+
+struct hdmi_video_interface {
+       int     vsp;    /* Vsync polarity */
+       int     hsp;    /* Hsync polarity */
+       int     interlacing;
+       int     tm;     /* Timing mode */
+};
+
+struct hdmi_cm {
+       int     code;
+       int     mode;
+};
+
+struct hdmi_config {
+       struct hdmi_timings timings;
+       u16     interlace;
+       struct hdmi_cm cm;
+};
+
+#endif
diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_omap4_panel.c
new file mode 100644 (file)
index 0000000..ffb5de9
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * hdmi_omap4_panel.c
+ *
+ * HDMI library support functions for TI OMAP4 processors.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors:    Mythri P k <mythripk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <plat/display.h>
+
+#include "dss.h"
+
+static struct {
+       struct mutex hdmi_lock;
+} hdmi;
+
+
+static int hdmi_panel_probe(struct omap_dss_device *dssdev)
+{
+       DSSDBG("ENTER hdmi_panel_probe\n");
+
+       dssdev->panel.config = OMAP_DSS_LCD_TFT |
+                       OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
+
+       /*
+        * Initialize the timings to 640 * 480
+        * This is only for framebuffer update not for TV timing setting
+        * Setting TV timing will be done only on enable
+        */
+       dssdev->panel.timings.x_res = 640;
+       dssdev->panel.timings.y_res = 480;
+
+       DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
+               dssdev->panel.timings.x_res,
+               dssdev->panel.timings.y_res);
+       return 0;
+}
+
+static void hdmi_panel_remove(struct omap_dss_device *dssdev)
+{
+
+}
+
+static int hdmi_panel_enable(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+       DSSDBG("ENTER hdmi_panel_enable\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       r = omapdss_hdmi_display_enable(dssdev);
+       if (r) {
+               DSSERR("failed to power on\n");
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static void hdmi_panel_disable(struct omap_dss_device *dssdev)
+{
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+               omapdss_hdmi_display_disable(dssdev);
+
+       dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+       omapdss_hdmi_display_disable(dssdev);
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static int hdmi_panel_resume(struct omap_dss_device *dssdev)
+{
+       int r = 0;
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       r = omapdss_hdmi_display_enable(dssdev);
+       if (r) {
+               DSSERR("failed to power on\n");
+               goto err;
+       }
+
+       dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+
+       return r;
+}
+
+static void hdmi_get_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       mutex_lock(&hdmi.hdmi_lock);
+
+       *timings = dssdev->panel.timings;
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       DSSDBG("hdmi_set_timings\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       dssdev->panel.timings = *timings;
+
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               /* turn the hdmi off and on to get new timings to use */
+               omapdss_hdmi_display_disable(dssdev);
+               omapdss_hdmi_display_set_timing(dssdev);
+       }
+
+       mutex_unlock(&hdmi.hdmi_lock);
+}
+
+static int hdmi_check_timings(struct omap_dss_device *dssdev,
+                       struct omap_video_timings *timings)
+{
+       int r = 0;
+
+       DSSDBG("hdmi_check_timings\n");
+
+       mutex_lock(&hdmi.hdmi_lock);
+
+       r = omapdss_hdmi_display_check_timing(dssdev, timings);
+       if (r) {
+               DSSERR("Timing cannot be applied\n");
+               goto err;
+       }
+err:
+       mutex_unlock(&hdmi.hdmi_lock);
+       return r;
+}
+
+static struct omap_dss_driver hdmi_driver = {
+       .probe          = hdmi_panel_probe,
+       .remove         = hdmi_panel_remove,
+       .enable         = hdmi_panel_enable,
+       .disable        = hdmi_panel_disable,
+       .suspend        = hdmi_panel_suspend,
+       .resume         = hdmi_panel_resume,
+       .get_timings    = hdmi_get_timings,
+       .set_timings    = hdmi_set_timings,
+       .check_timings  = hdmi_check_timings,
+       .driver                 = {
+               .name   = "hdmi_panel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int hdmi_panel_init(void)
+{
+       mutex_init(&hdmi.hdmi_lock);
+
+       omap_dss_register_driver(&hdmi_driver);
+
+       return 0;
+}
+
+void hdmi_panel_exit(void)
+{
+       omap_dss_unregister_driver(&hdmi_driver);
+
+}
index 172d4e69730917e3a2a4630c8bdcaf4d24c60e92..bcd37ec86952fae81d0327366833503717de520e 100644 (file)
@@ -515,6 +515,8 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
 
        if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
                irq = DISPC_IRQ_EVSYNC_ODD;
+       } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) {
+               irq = DISPC_IRQ_EVSYNC_EVEN;
        } else {
                if (mgr->id == OMAP_DSS_CHANNEL_LCD)
                        irq = DISPC_IRQ_VSYNC;
@@ -536,7 +538,8 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+                       || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -613,7 +616,8 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+                       || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
                if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
@@ -1377,6 +1381,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                case OMAP_DISPLAY_TYPE_DBI:
                case OMAP_DISPLAY_TYPE_SDI:
                case OMAP_DISPLAY_TYPE_VENC:
+               case OMAP_DISPLAY_TYPE_HDMI:
                        default_get_overlay_fifo_thresholds(ovl->id, size,
                                        &oc->burst_size, &oc->fifo_low,
                                        &oc->fifo_high);
@@ -1394,7 +1399,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        }
 
        r = 0;
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (!dss_cache.irq_enabled) {
                u32 mask;
 
@@ -1407,7 +1412,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                dss_cache.irq_enabled = true;
        }
        configure_dispc();
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        spin_unlock_irqrestore(&dss_cache.lock, flags);
 
index 456efef03c20c6de3a30bcd6aa1355862c4e6c05..f1aca6d0401117c9858a4300b5dfe0748a7863e4 100644 (file)
@@ -490,7 +490,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
 
        ovl->manager = mgr;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        /* XXX: on manual update display, in auto update mode, a bug happens
         * here. When an overlay is first enabled on LCD, then it's disabled,
         * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
@@ -499,7 +499,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
         * but I don't understand how or why. */
        msleep(40);
        dispc_set_channel_out(ovl->id, mgr->id);
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        return 0;
 }
@@ -679,7 +679,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
                        lcd2_mgr->set_device(lcd2_mgr, dssdev);
                        mgr = lcd2_mgr;
                }
-       } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
+       } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
+                       && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
                if (!lcd_mgr->device || force) {
                        if (lcd_mgr->device)
                                lcd_mgr->unset_device(lcd_mgr);
@@ -688,7 +689,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
                }
        }
 
-       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
+       if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
+                       || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                if (!tv_mgr->device || force) {
                        if (tv_mgr->device)
                                tv_mgr->unset_device(tv_mgr);
index 10a2ffe02882e929f6c64250ba2ba9d87242ccaf..5ea17f49c6110c3d3703c89b34e5f52e366f67ce 100644 (file)
@@ -36,8 +36,6 @@
 #include <plat/display.h>
 #include "dss.h"
 
-#define RFBI_BASE               0x48050800
-
 struct rfbi_reg { u16 idx; };
 
 #define RFBI_REG(idx)          ((const struct rfbi_reg) { idx })
@@ -100,6 +98,7 @@ static int rfbi_convert_timings(struct rfbi_timings *t);
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
 
 static struct {
+       struct platform_device *pdev;
        void __iomem    *base;
 
        unsigned long   l4_khz;
@@ -142,9 +141,9 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
 static void rfbi_enable_clocks(bool enable)
 {
        if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
 void omap_rfbi_write_command(const void *buf, u32 len)
@@ -497,7 +496,7 @@ unsigned long rfbi_get_max_tx_rate(void)
        };
 
        l4_rate = rfbi.l4_khz / 1000;
-       dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
+       dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000;
 
        for (i = 0; i < ARRAY_SIZE(ftab); i++) {
                /* Use a window instead of an exact match, to account
@@ -922,7 +921,7 @@ void rfbi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        DUMPREG(RFBI_REVISION);
        DUMPREG(RFBI_SYSCONFIG);
@@ -953,54 +952,10 @@ void rfbi_dump_regs(struct seq_file *s)
        DUMPREG(RFBI_VSYNC_WIDTH);
        DUMPREG(RFBI_HSYNC_WIDTH);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
-int rfbi_init(void)
-{
-       u32 rev;
-       u32 l;
-
-       spin_lock_init(&rfbi.cmd_lock);
-
-       init_completion(&rfbi.cmd_done);
-       atomic_set(&rfbi.cmd_fifo_full, 0);
-       atomic_set(&rfbi.cmd_pending, 0);
-
-       rfbi.base = ioremap(RFBI_BASE, SZ_256);
-       if (!rfbi.base) {
-               DSSERR("can't ioremap RFBI\n");
-               return -ENOMEM;
-       }
-
-       rfbi_enable_clocks(1);
-
-       msleep(10);
-
-       rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
-
-       /* Enable autoidle and smart-idle */
-       l = rfbi_read_reg(RFBI_SYSCONFIG);
-       l |= (1 << 0) | (2 << 3);
-       rfbi_write_reg(RFBI_SYSCONFIG, l);
-
-       rev = rfbi_read_reg(RFBI_REVISION);
-       printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
-              FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
-
-       rfbi_enable_clocks(0);
-
-       return 0;
-}
-
-void rfbi_exit(void)
-{
-       DSSDBG("rfbi_exit\n");
-
-       iounmap(rfbi.base);
-}
-
 int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
@@ -1056,3 +1011,74 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
        return 0;
 }
+
+/* RFBI HW IP initialisation */
+static int omap_rfbihw_probe(struct platform_device *pdev)
+{
+       u32 rev;
+       u32 l;
+       struct resource *rfbi_mem;
+
+       rfbi.pdev = pdev;
+
+       spin_lock_init(&rfbi.cmd_lock);
+
+       init_completion(&rfbi.cmd_done);
+       atomic_set(&rfbi.cmd_fifo_full, 0);
+       atomic_set(&rfbi.cmd_pending, 0);
+
+       rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
+       if (!rfbi_mem) {
+               DSSERR("can't get IORESOURCE_MEM RFBI\n");
+               return -EINVAL;
+       }
+       rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
+       if (!rfbi.base) {
+               DSSERR("can't ioremap RFBI\n");
+               return -ENOMEM;
+       }
+
+       rfbi_enable_clocks(1);
+
+       msleep(10);
+
+       rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+
+       /* Enable autoidle and smart-idle */
+       l = rfbi_read_reg(RFBI_SYSCONFIG);
+       l |= (1 << 0) | (2 << 3);
+       rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+       rev = rfbi_read_reg(RFBI_REVISION);
+       dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
+              FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+       rfbi_enable_clocks(0);
+
+       return 0;
+}
+
+static int omap_rfbihw_remove(struct platform_device *pdev)
+{
+       iounmap(rfbi.base);
+       return 0;
+}
+
+static struct platform_driver omap_rfbihw_driver = {
+       .probe          = omap_rfbihw_probe,
+       .remove         = omap_rfbihw_remove,
+       .driver         = {
+               .name   = "omapdss_rfbi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int rfbi_init_platform_driver(void)
+{
+       return platform_driver_register(&omap_rfbihw_driver);
+}
+
+void rfbi_uninit_platform_driver(void)
+{
+       return platform_driver_unregister(&omap_rfbihw_driver);
+}
index b64adf7dfc88b20963829245e0061c6ad1df4960..54a53e648180e1e31fe830777d2302056f33b2fc 100644 (file)
@@ -30,7 +30,6 @@
 #include "dss.h"
 
 static struct {
-       bool skip_init;
        bool update_enabled;
        struct regulator *vdds_sdi_reg;
 } sdi;
@@ -68,9 +67,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err1;
 
-       /* In case of skip_init sdi_init has already enabled the clocks */
-       if (!sdi.skip_init)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        sdi_basic_init(dssdev);
 
@@ -80,14 +77,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
 
-       if (!sdi.skip_init) {
-               r = dss_calc_clock_div(1, t->pixel_clock * 1000,
-                               &dss_cinfo, &dispc_cinfo);
-       } else {
-               r = dss_get_clock_div(&dss_cinfo);
-               r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
-       }
-
+       r = dss_calc_clock_div(1, t->pixel_clock * 1000,
+                       &dss_cinfo, &dispc_cinfo);
        if (r)
                goto err2;
 
@@ -116,21 +107,17 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-       if (!sdi.skip_init) {
-               dss_sdi_init(dssdev->phy.sdi.datapairs);
-               r = dss_sdi_enable();
-               if (r)
-                       goto err1;
-               mdelay(2);
-       }
+       dss_sdi_init(dssdev->phy.sdi.datapairs);
+       r = dss_sdi_enable();
+       if (r)
+               goto err1;
+       mdelay(2);
 
        dssdev->manager->enable(dssdev->manager);
 
-       sdi.skip_init = 0;
-
        return 0;
 err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
        regulator_disable(sdi.vdds_sdi_reg);
 err1:
        omap_dss_stop_device(dssdev);
@@ -145,7 +132,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 
        dss_sdi_disable();
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        regulator_disable(sdi.vdds_sdi_reg);
 
@@ -157,25 +144,24 @@ int sdi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("SDI init\n");
 
+       if (sdi.vdds_sdi_reg == NULL) {
+               struct regulator *vdds_sdi;
+
+               vdds_sdi = dss_get_vdds_sdi();
+
+               if (IS_ERR(vdds_sdi)) {
+                       DSSERR("can't get VDDS_SDI regulator\n");
+                       return PTR_ERR(vdds_sdi);
+               }
+
+               sdi.vdds_sdi_reg = vdds_sdi;
+       }
+
        return 0;
 }
 
-int sdi_init(bool skip_init)
+int sdi_init(void)
 {
-       /* we store this for first display enable, then clear it */
-       sdi.skip_init = skip_init;
-
-       sdi.vdds_sdi_reg = dss_get_vdds_sdi();
-       if (IS_ERR(sdi.vdds_sdi_reg)) {
-               DSSERR("can't get VDDS_SDI regulator\n");
-               return PTR_ERR(sdi.vdds_sdi_reg);
-       }
-       /*
-        * Enable clocks already here, otherwise there would be a toggle
-        * of them until sdi_display_enable is called.
-        */
-       if (skip_init)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
        return 0;
 }
 
index eff35050e28a6149f188ee3ef87f1ace6e704774..8e35a5bae429c8a858e0c6acf5ac3bca92c2ca79 100644 (file)
@@ -39,8 +39,6 @@
 
 #include "dss.h"
 
-#define VENC_BASE      0x48050C00
-
 /* Venc registers */
 #define VENC_REV_ID                            0x00
 #define VENC_STATUS                            0x04
@@ -289,6 +287,7 @@ const struct omap_video_timings omap_dss_ntsc_timings = {
 EXPORT_SYMBOL(omap_dss_ntsc_timings);
 
 static struct {
+       struct platform_device *pdev;
        void __iomem *base;
        struct mutex venc_lock;
        u32 wss_data;
@@ -381,11 +380,11 @@ static void venc_reset(void)
 static void venc_enable_clocks(int enable)
 {
        if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
-                               DSS_CLK_96M);
+               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+                               DSS_CLK_VIDFCK);
        else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
-                               DSS_CLK_96M);
+               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
+                               DSS_CLK_VIDFCK);
 }
 
 static const struct venc_config *venc_timings_to_config(
@@ -641,50 +640,23 @@ static struct omap_dss_driver venc_driver = {
 };
 /* driver end */
 
-
-
-int venc_init(struct platform_device *pdev)
+int venc_init_display(struct omap_dss_device *dssdev)
 {
-       u8 rev_id;
+       DSSDBG("init_display\n");
 
-       mutex_init(&venc.venc_lock);
+       if (venc.vdda_dac_reg == NULL) {
+               struct regulator *vdda_dac;
 
-       venc.wss_data = 0;
+               vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac");
 
-       venc.base = ioremap(VENC_BASE, SZ_1K);
-       if (!venc.base) {
-               DSSERR("can't ioremap VENC\n");
-               return -ENOMEM;
-       }
+               if (IS_ERR(vdda_dac)) {
+                       DSSERR("can't get VDDA_DAC regulator\n");
+                       return PTR_ERR(vdda_dac);
+               }
 
-       venc.vdda_dac_reg = dss_get_vdda_dac();
-       if (IS_ERR(venc.vdda_dac_reg)) {
-               iounmap(venc.base);
-               DSSERR("can't get VDDA_DAC regulator\n");
-               return PTR_ERR(venc.vdda_dac_reg);
+               venc.vdda_dac_reg = vdda_dac;
        }
 
-       venc_enable_clocks(1);
-
-       rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
-       printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
-
-       venc_enable_clocks(0);
-
-       return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_exit(void)
-{
-       omap_dss_unregister_driver(&venc_driver);
-
-       iounmap(venc.base);
-}
-
-int venc_init_display(struct omap_dss_device *dssdev)
-{
-       DSSDBG("init_display\n");
-
        return 0;
 }
 
@@ -740,3 +712,73 @@ void venc_dump_regs(struct seq_file *s)
 
 #undef DUMPREG
 }
+
+/* VENC HW IP initialisation */
+static int omap_venchw_probe(struct platform_device *pdev)
+{
+       u8 rev_id;
+       struct resource *venc_mem;
+
+       venc.pdev = pdev;
+
+       mutex_init(&venc.venc_lock);
+
+       venc.wss_data = 0;
+
+       venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
+       if (!venc_mem) {
+               DSSERR("can't get IORESOURCE_MEM VENC\n");
+               return -EINVAL;
+       }
+       venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
+       if (!venc.base) {
+               DSSERR("can't ioremap VENC\n");
+               return -ENOMEM;
+       }
+
+       venc_enable_clocks(1);
+
+       rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
+       dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
+
+       venc_enable_clocks(0);
+
+       return omap_dss_register_driver(&venc_driver);
+}
+
+static int omap_venchw_remove(struct platform_device *pdev)
+{
+       if (venc.vdda_dac_reg != NULL) {
+               regulator_put(venc.vdda_dac_reg);
+               venc.vdda_dac_reg = NULL;
+       }
+       omap_dss_unregister_driver(&venc_driver);
+
+       iounmap(venc.base);
+       return 0;
+}
+
+static struct platform_driver omap_venchw_driver = {
+       .probe          = omap_venchw_probe,
+       .remove         = omap_venchw_remove,
+       .driver         = {
+               .name   = "omapdss_venc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+int venc_init_platform_driver(void)
+{
+       if (cpu_is_omap44xx())
+               return 0;
+
+       return platform_driver_register(&omap_venchw_driver);
+}
+
+void venc_uninit_platform_driver(void)
+{
+       if (cpu_is_omap44xx())
+               return;
+
+       return platform_driver_unregister(&omap_venchw_driver);
+}
index 65149b22cf373d7582e86af6da00107d60b8e9e1..aa33386c81ff25ed3502f0998ffbe59d0463886c 100644 (file)
@@ -1,5 +1,5 @@
 menuconfig FB_OMAP2
-        tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
+        tristate "OMAP2+ frame buffer support (EXPERIMENTAL)"
         depends on FB && OMAP2_DSS
 
        select OMAP2_VRAM
@@ -8,10 +8,10 @@ menuconfig FB_OMAP2
         select FB_CFB_COPYAREA
         select FB_CFB_IMAGEBLIT
         help
-          Frame buffer driver for OMAP2/3 based boards.
+         Frame buffer driver for OMAP2+ based boards.
 
 config FB_OMAP2_DEBUG_SUPPORT
-       bool "Debug support for OMAP2/3 FB"
+        bool "Debug support for OMAP2+ FB"
        default y
        depends on FB_OMAP2
        help
index 4fdab8e9c4963249ab9d47b19eb33c56a9422fbe..505ec667204906130eb4457e6d96d75b885f670b 100644 (file)
@@ -2090,7 +2090,7 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
 {
        int r;
        u8 bpp;
-       struct omap_video_timings timings;
+       struct omap_video_timings timings, temp_timings;
 
        r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
        if (r)
@@ -2100,14 +2100,23 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
        fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
        ++fbdev->num_bpp_overrides;
 
-       if (!display->driver->check_timings || !display->driver->set_timings)
-               return -EINVAL;
+       if (display->driver->check_timings) {
+               r = display->driver->check_timings(display, &timings);
+               if (r)
+                       return r;
+       } else {
+               /* If check_timings is not present compare xres and yres */
+               if (display->driver->get_timings) {
+                       display->driver->get_timings(display, &temp_timings);
 
-       r = display->driver->check_timings(display, &timings);
-       if (r)
-               return r;
+                       if (temp_timings.x_res != timings.x_res ||
+                               temp_timings.y_res != timings.y_res)
+                               return -EINVAL;
+               }
+       }
 
-       display->driver->set_timings(display, &timings);
+       if (display->driver->set_timings)
+                       display->driver->set_timings(display, &timings);
 
        return 0;
 }
index da388186d617154174c8ad9dbdaf3bde5c6f345e..d8ab7be4fd6b5953ba1f2d57928b541038554c60 100644 (file)
@@ -355,6 +355,7 @@ static void riva_bl_init(struct riva_par *par)
        snprintf(name, sizeof(name), "rivabl%d", info->node);
 
        memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
        bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,
                                       &props);
index 83ce9a04d872427013348665a58b89789bfdfc8f..6817d187d46eac726b7cd44349b51ae480188155 100644 (file)
@@ -1340,6 +1340,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
        sfb->bus_clk = clk_get(dev, "lcd");
        if (IS_ERR(sfb->bus_clk)) {
                dev_err(dev, "failed to get bus clock\n");
+               ret = PTR_ERR(sfb->bus_clk);
                goto err_sfb;
        }
 
index 75738a92861000a75b87c7694d9980a241b9ca10..ddedad9cd06971aa94a598f4a8930185e43982c7 100644 (file)
@@ -64,6 +64,8 @@ static const struct svga_fb_format s3fb_formats[] = {
 
 static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3,
        35000, 240000, 14318};
+static const struct svga_pll s3_trio3d_pll = {3, 129, 3, 31, 0, 4,
+       230000, 460000, 14318};
 
 static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512};
 
@@ -72,7 +74,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
                        "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge",
                        "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
                        "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P",
-                       "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"};
+                       "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X",
+                       "S3 Trio3D"};
 
 #define CHIP_UNKNOWN           0x00
 #define CHIP_732_TRIO32                0x01
@@ -93,6 +96,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_360_TRIO3D_1X     0x10
 #define CHIP_362_TRIO3D_2X     0x11
 #define CHIP_368_TRIO3D_2X     0x12
+#define CHIP_365_TRIO3D                0x13
 
 #define CHIP_XXX_TRIO          0x80
 #define CHIP_XXX_TRIO64V2_DXGX 0x81
@@ -119,9 +123,11 @@ static const struct vga_regset s3_v_sync_start_regs[]   = {{0x10, 0, 7}, {0x07,
 static const struct vga_regset s3_v_sync_end_regs[]     = {{0x11, 0, 3}, VGA_REGSET_END};
 
 static const struct vga_regset s3_line_compare_regs[]   = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x5E, 6, 6}, VGA_REGSET_END};
-static const struct vga_regset s3_start_address_regs[]  = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x31, 4, 5}, {0x51, 0, 1}, VGA_REGSET_END};
+static const struct vga_regset s3_start_address_regs[]  = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x69, 0, 4}, VGA_REGSET_END};
 static const struct vga_regset s3_offset_regs[]         = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */
 
+static const struct vga_regset s3_dtpc_regs[]          = {{0x3B, 0, 7}, {0x5D, 6, 6}, VGA_REGSET_END};
+
 static const struct svga_timing_regs s3_timing_regs     = {
        s3_h_total_regs, s3_h_display_regs, s3_h_blank_start_regs,
        s3_h_blank_end_regs, s3_h_sync_start_regs, s3_h_sync_end_regs,
@@ -188,12 +194,19 @@ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
        }
 }
 
+static void s3fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
+{
+       struct s3fb_info *par = info->par;
+
+       svga_tilecursor(par->state.vgabase, info, cursor);
+}
+
 static struct fb_tile_ops s3fb_tile_ops = {
        .fb_settile     = svga_settile,
        .fb_tilecopy    = svga_tilecopy,
        .fb_tilefill    = svga_tilefill,
        .fb_tileblit    = svga_tileblit,
-       .fb_tilecursor  = svga_tilecursor,
+       .fb_tilecursor  = s3fb_tilecursor,
        .fb_get_tilemax = svga_get_tilemax,
 };
 
@@ -202,7 +215,7 @@ static struct fb_tile_ops s3fb_fast_tile_ops = {
        .fb_tilecopy    = svga_tilecopy,
        .fb_tilefill    = svga_tilefill,
        .fb_tileblit    = svga_tileblit,
-       .fb_tilecursor  = svga_tilecursor,
+       .fb_tilecursor  = s3fb_tilecursor,
        .fb_get_tilemax = svga_get_tilemax,
 };
 
@@ -334,33 +347,34 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
        u8 regval;
        int rv;
 
-       rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+       rv = svga_compute_pll((par->chip == CHIP_365_TRIO3D) ? &s3_trio3d_pll : &s3_pll,
+                             1000000000 / pixclock, &m, &n, &r, info->node);
        if (rv < 0) {
                printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
                return;
        }
 
        /* Set VGA misc register  */
-       regval = vga_r(NULL, VGA_MIS_R);
-       vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+       regval = vga_r(par->state.vgabase, VGA_MIS_R);
+       vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
 
        /* Set S3 clock registers */
        if (par->chip == CHIP_360_TRIO3D_1X ||
            par->chip == CHIP_362_TRIO3D_2X ||
            par->chip == CHIP_368_TRIO3D_2X) {
-               vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
-               vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */
+               vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6));   /* n and two bits of r */
+               vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */
        } else
-               vga_wseq(NULL, 0x12, (n - 2) | (r << 5));
-       vga_wseq(NULL, 0x13, m - 2);
+               vga_wseq(par->state.vgabase, 0x12, (n - 2) | (r << 5));
+       vga_wseq(par->state.vgabase, 0x13, m - 2);
 
        udelay(1000);
 
        /* Activate clock - write 0, 1, 0 to seq/15 bit 5 */
-       regval = vga_rseq (NULL, 0x15); /* | 0x80; */
-       vga_wseq(NULL, 0x15, regval & ~(1<<5));
-       vga_wseq(NULL, 0x15, regval |  (1<<5));
-       vga_wseq(NULL, 0x15, regval & ~(1<<5));
+       regval = vga_rseq (par->state.vgabase, 0x15); /* | 0x80; */
+       vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5));
+       vga_wseq(par->state.vgabase, 0x15, regval |  (1<<5));
+       vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5));
 }
 
 
@@ -372,7 +386,10 @@ static int s3fb_open(struct fb_info *info, int user)
 
        mutex_lock(&(par->open_lock));
        if (par->ref_count == 0) {
+               void __iomem *vgabase = par->state.vgabase;
+
                memset(&(par->state), 0, sizeof(struct vgastate));
+               par->state.vgabase = vgabase;
                par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
                par->state.num_crtc = 0x70;
                par->state.num_seq = 0x20;
@@ -470,6 +487,7 @@ static int s3fb_set_par(struct fb_info *info)
        struct s3fb_info *par = info->par;
        u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
        u32 bpp = info->var.bits_per_pixel;
+       u32 htotal, hsstart;
 
        if (bpp != 0) {
                info->fix.ypanstep = 1;
@@ -504,99 +522,112 @@ static int s3fb_set_par(struct fb_info *info)
        info->var.activate = FB_ACTIVATE_NOW;
 
        /* Unlock registers */
-       vga_wcrt(NULL, 0x38, 0x48);
-       vga_wcrt(NULL, 0x39, 0xA5);
-       vga_wseq(NULL, 0x08, 0x06);
-       svga_wcrt_mask(0x11, 0x00, 0x80);
+       vga_wcrt(par->state.vgabase, 0x38, 0x48);
+       vga_wcrt(par->state.vgabase, 0x39, 0xA5);
+       vga_wseq(par->state.vgabase, 0x08, 0x06);
+       svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
 
        /* Blank screen and turn off sync */
-       svga_wseq_mask(0x01, 0x20, 0x20);
-       svga_wcrt_mask(0x17, 0x00, 0x80);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
 
        /* Set default values */
-       svga_set_default_gfx_regs();
-       svga_set_default_atc_regs();
-       svga_set_default_seq_regs();
-       svga_set_default_crt_regs();
-       svga_wcrt_multi(s3_line_compare_regs, 0xFFFFFFFF);
-       svga_wcrt_multi(s3_start_address_regs, 0);
+       svga_set_default_gfx_regs(par->state.vgabase);
+       svga_set_default_atc_regs(par->state.vgabase);
+       svga_set_default_seq_regs(par->state.vgabase);
+       svga_set_default_crt_regs(par->state.vgabase);
+       svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF);
+       svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0);
 
        /* S3 specific initialization */
-       svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */
-       svga_wcrt_mask(0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */
+       svga_wcrt_mask(par->state.vgabase, 0x58, 0x10, 0x10); /* enable linear framebuffer */
+       svga_wcrt_mask(par->state.vgabase, 0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */
 
-/*     svga_wcrt_mask(0x33, 0x08, 0x08); */ /* DDR ?   */
-/*     svga_wcrt_mask(0x43, 0x01, 0x01); */ /* DDR ?   */
-       svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ?   */
-       svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ?   */
+/*     svga_wcrt_mask(par->state.vgabase, 0x33, 0x08, 0x08); */ /* DDR ?       */
+/*     svga_wcrt_mask(par->state.vgabase, 0x43, 0x01, 0x01); */ /* DDR ?       */
+       svga_wcrt_mask(par->state.vgabase, 0x33, 0x00, 0x08); /* no DDR ?       */
+       svga_wcrt_mask(par->state.vgabase, 0x43, 0x00, 0x01); /* no DDR ?       */
 
-       svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
+       svga_wcrt_mask(par->state.vgabase, 0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
 
-/*     svga_wcrt_mask(0x58, 0x03, 0x03); */
+/*     svga_wcrt_mask(par->state.vgabase, 0x58, 0x03, 0x03); */
 
-/*     svga_wcrt_mask(0x53, 0x12, 0x13); */ /* enable MMIO */
-/*     svga_wcrt_mask(0x40, 0x08, 0x08); */ /* enable write buffer */
+/*     svga_wcrt_mask(par->state.vgabase, 0x53, 0x12, 0x13); */ /* enable MMIO */
+/*     svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08); */ /* enable write buffer */
 
 
        /* Set the offset register */
        pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
-       svga_wcrt_multi(s3_offset_regs, offset_value);
+       svga_wcrt_multi(par->state.vgabase, s3_offset_regs, offset_value);
 
        if (par->chip != CHIP_360_TRIO3D_1X &&
            par->chip != CHIP_362_TRIO3D_2X &&
            par->chip != CHIP_368_TRIO3D_2X) {
-               vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
-               vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
-               vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
-               vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+               vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */
+               vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */
+               vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */
+               vga_wcrt(par->state.vgabase, 0x62, 0xff); /* L parameter */
        }
 
-       vga_wcrt(NULL, 0x3A, 0x35);
-       svga_wattr(0x33, 0x00);
+       vga_wcrt(par->state.vgabase, 0x3A, 0x35);
+       svga_wattr(par->state.vgabase, 0x33, 0x00);
 
        if (info->var.vmode & FB_VMODE_DOUBLE)
-               svga_wcrt_mask(0x09, 0x80, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80);
        else
-               svga_wcrt_mask(0x09, 0x00, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80);
 
        if (info->var.vmode & FB_VMODE_INTERLACED)
-               svga_wcrt_mask(0x42, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x42, 0x20, 0x20);
        else
-               svga_wcrt_mask(0x42, 0x00, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x42, 0x00, 0x20);
 
        /* Disable hardware graphics cursor */
-       svga_wcrt_mask(0x45, 0x00, 0x01);
+       svga_wcrt_mask(par->state.vgabase, 0x45, 0x00, 0x01);
        /* Disable Streams engine */
-       svga_wcrt_mask(0x67, 0x00, 0x0C);
+       svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0x0C);
 
        mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix));
 
        /* S3 virge DX hack */
        if (par->chip == CHIP_375_VIRGE_DX) {
-               vga_wcrt(NULL, 0x86, 0x80);
-               vga_wcrt(NULL, 0x90, 0x00);
+               vga_wcrt(par->state.vgabase, 0x86, 0x80);
+               vga_wcrt(par->state.vgabase, 0x90, 0x00);
        }
 
        /* S3 virge VX hack */
        if (par->chip == CHIP_988_VIRGE_VX) {
-               vga_wcrt(NULL, 0x50, 0x00);
-               vga_wcrt(NULL, 0x67, 0x50);
+               vga_wcrt(par->state.vgabase, 0x50, 0x00);
+               vga_wcrt(par->state.vgabase, 0x67, 0x50);
 
-               vga_wcrt(NULL, 0x63, (mode <= 2) ? 0x90 : 0x09);
-               vga_wcrt(NULL, 0x66, 0x90);
+               vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
+               vga_wcrt(par->state.vgabase, 0x66, 0x90);
        }
 
        if (par->chip == CHIP_360_TRIO3D_1X ||
            par->chip == CHIP_362_TRIO3D_2X ||
-           par->chip == CHIP_368_TRIO3D_2X) {
+           par->chip == CHIP_368_TRIO3D_2X ||
+           par->chip == CHIP_365_TRIO3D    ||
+           par->chip == CHIP_375_VIRGE_DX  ||
+           par->chip == CHIP_385_VIRGE_GX) {
                dbytes = info->var.xres * ((bpp+7)/8);
-               vga_wcrt(NULL, 0x91, (dbytes + 7) / 8);
-               vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
+               vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8);
+               vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
 
-               vga_wcrt(NULL, 0x66, 0x81);
+               vga_wcrt(par->state.vgabase, 0x66, 0x81);
        }
 
-       svga_wcrt_mask(0x31, 0x00, 0x40);
+       if (par->chip == CHIP_356_VIRGE_GX2  ||
+           par->chip == CHIP_357_VIRGE_GX2P ||
+           par->chip == CHIP_359_VIRGE_GX2P ||
+           par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X)
+               vga_wcrt(par->state.vgabase, 0x34, 0x00);
+       else    /* enable Data Transfer Position Control (DTPC) */
+               vga_wcrt(par->state.vgabase, 0x34, 0x10);
+
+       svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40);
        multiplex = 0;
        hmul = 1;
 
@@ -604,51 +635,51 @@ static int s3fb_set_par(struct fb_info *info)
        switch (mode) {
        case 0:
                pr_debug("fb%d: text mode\n", info->node);
-               svga_set_textmode_vga_regs();
+               svga_set_textmode_vga_regs(par->state.vgabase);
 
                /* Set additional registers like in 8-bit mode */
-               svga_wcrt_mask(0x50, 0x00, 0x30);
-               svga_wcrt_mask(0x67, 0x00, 0xF0);
+               svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
 
                /* Disable enhanced mode */
-               svga_wcrt_mask(0x3A, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
 
                if (fasttext) {
                        pr_debug("fb%d: high speed text mode set\n", info->node);
-                       svga_wcrt_mask(0x31, 0x40, 0x40);
+                       svga_wcrt_mask(par->state.vgabase, 0x31, 0x40, 0x40);
                }
                break;
        case 1:
                pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
-               vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+               vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
 
                /* Set additional registers like in 8-bit mode */
-               svga_wcrt_mask(0x50, 0x00, 0x30);
-               svga_wcrt_mask(0x67, 0x00, 0xF0);
+               svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
 
                /* disable enhanced mode */
-               svga_wcrt_mask(0x3A, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
                break;
        case 2:
                pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
 
                /* Set additional registers like in 8-bit mode */
-               svga_wcrt_mask(0x50, 0x00, 0x30);
-               svga_wcrt_mask(0x67, 0x00, 0xF0);
+               svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
 
                /* disable enhanced mode */
-               svga_wcrt_mask(0x3A, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
                break;
        case 3:
                pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
-               svga_wcrt_mask(0x50, 0x00, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
                if (info->var.pixclock > 20000 ||
                    par->chip == CHIP_360_TRIO3D_1X ||
                    par->chip == CHIP_362_TRIO3D_2X ||
                    par->chip == CHIP_368_TRIO3D_2X)
-                       svga_wcrt_mask(0x67, 0x00, 0xF0);
+                       svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
                else {
-                       svga_wcrt_mask(0x67, 0x10, 0xF0);
+                       svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0);
                        multiplex = 1;
                }
                break;
@@ -656,12 +687,21 @@ static int s3fb_set_par(struct fb_info *info)
                pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
                if (par->chip == CHIP_988_VIRGE_VX) {
                        if (info->var.pixclock > 20000)
-                               svga_wcrt_mask(0x67, 0x20, 0xF0);
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0);
                        else
-                               svga_wcrt_mask(0x67, 0x30, 0xF0);
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
+               } else if (par->chip == CHIP_365_TRIO3D) {
+                       svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
+                       if (info->var.pixclock > 8695) {
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
+                               hmul = 2;
+                       } else {
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0);
+                               multiplex = 1;
+                       }
                } else {
-                       svga_wcrt_mask(0x50, 0x10, 0x30);
-                       svga_wcrt_mask(0x67, 0x30, 0xF0);
+                       svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
+                       svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
                        if (par->chip != CHIP_360_TRIO3D_1X &&
                            par->chip != CHIP_362_TRIO3D_2X &&
                            par->chip != CHIP_368_TRIO3D_2X)
@@ -672,12 +712,21 @@ static int s3fb_set_par(struct fb_info *info)
                pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
                if (par->chip == CHIP_988_VIRGE_VX) {
                        if (info->var.pixclock > 20000)
-                               svga_wcrt_mask(0x67, 0x40, 0xF0);
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0);
                        else
-                               svga_wcrt_mask(0x67, 0x50, 0xF0);
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
+               } else if (par->chip == CHIP_365_TRIO3D) {
+                       svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
+                       if (info->var.pixclock > 8695) {
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
+                               hmul = 2;
+                       } else {
+                               svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0);
+                               multiplex = 1;
+                       }
                } else {
-                       svga_wcrt_mask(0x50, 0x10, 0x30);
-                       svga_wcrt_mask(0x67, 0x50, 0xF0);
+                       svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
+                       svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
                        if (par->chip != CHIP_360_TRIO3D_1X &&
                            par->chip != CHIP_362_TRIO3D_2X &&
                            par->chip != CHIP_368_TRIO3D_2X)
@@ -687,12 +736,12 @@ static int s3fb_set_par(struct fb_info *info)
        case 6:
                /* VIRGE VX case */
                pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
-               svga_wcrt_mask(0x67, 0xD0, 0xF0);
+               svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
                break;
        case 7:
                pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
-               svga_wcrt_mask(0x50, 0x30, 0x30);
-               svga_wcrt_mask(0x67, 0xD0, 0xF0);
+               svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30);
+               svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
                break;
        default:
                printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
@@ -700,25 +749,30 @@ static int s3fb_set_par(struct fb_info *info)
        }
 
        if (par->chip != CHIP_988_VIRGE_VX) {
-               svga_wseq_mask(0x15, multiplex ? 0x10 : 0x00, 0x10);
-               svga_wseq_mask(0x18, multiplex ? 0x80 : 0x00, 0x80);
+               svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10);
+               svga_wseq_mask(par->state.vgabase, 0x18, multiplex ? 0x80 : 0x00, 0x80);
        }
 
        s3_set_pixclock(info, info->var.pixclock);
-       svga_set_timings(&s3_timing_regs, &(info->var), hmul, 1,
+       svga_set_timings(par->state.vgabase, &s3_timing_regs, &(info->var), hmul, 1,
                         (info->var.vmode & FB_VMODE_DOUBLE)     ? 2 : 1,
                         (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
                         hmul, info->node);
 
        /* Set interlaced mode start/end register */
-       value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
-       value = ((value * hmul) / 8) - 5;
-       vga_wcrt(NULL, 0x3C, (value + 1) / 2);
+       htotal = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+       htotal = ((htotal * hmul) / 8) - 5;
+       vga_wcrt(par->state.vgabase, 0x3C, (htotal + 1) / 2);
+
+       /* Set Data Transfer Position */
+       hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8;
+       value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1);
+       svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value);
 
        memset_io(info->screen_base, 0x00, screen_size);
        /* Device and screen back on */
-       svga_wcrt_mask(0x17, 0x80, 0x80);
-       svga_wseq_mask(0x01, 0x00, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
 
        return 0;
 }
@@ -788,31 +842,33 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
 static int s3fb_blank(int blank_mode, struct fb_info *info)
 {
+       struct s3fb_info *par = info->par;
+
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
                pr_debug("fb%d: unblank\n", info->node);
-               svga_wcrt_mask(0x56, 0x00, 0x06);
-               svga_wseq_mask(0x01, 0x00, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
                break;
        case FB_BLANK_NORMAL:
                pr_debug("fb%d: blank\n", info->node);
-               svga_wcrt_mask(0x56, 0x00, 0x06);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_HSYNC_SUSPEND:
                pr_debug("fb%d: hsync\n", info->node);
-               svga_wcrt_mask(0x56, 0x02, 0x06);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_VSYNC_SUSPEND:
                pr_debug("fb%d: vsync\n", info->node);
-               svga_wcrt_mask(0x56, 0x04, 0x06);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_POWERDOWN:
                pr_debug("fb%d: sync down\n", info->node);
-               svga_wcrt_mask(0x56, 0x06, 0x06);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        }
 
@@ -822,8 +878,9 @@ static int s3fb_blank(int blank_mode, struct fb_info *info)
 
 /* Pan the display */
 
-static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) {
-
+static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct s3fb_info *par = info->par;
        unsigned int offset;
 
        /* Calculate the offset */
@@ -837,7 +894,7 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        }
 
        /* Set the offset */
-       svga_wcrt_multi(s3_start_address_regs, offset);
+       svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, offset);
 
        return 0;
 }
@@ -863,12 +920,14 @@ static struct fb_ops s3fb_ops = {
 
 /* ------------------------------------------------------------------------- */
 
-static int __devinit s3_identification(int chip)
+static int __devinit s3_identification(struct s3fb_info *par)
 {
+       int chip = par->chip;
+
        if (chip == CHIP_XXX_TRIO) {
-               u8 cr30 = vga_rcrt(NULL, 0x30);
-               u8 cr2e = vga_rcrt(NULL, 0x2e);
-               u8 cr2f = vga_rcrt(NULL, 0x2f);
+               u8 cr30 = vga_rcrt(par->state.vgabase, 0x30);
+               u8 cr2e = vga_rcrt(par->state.vgabase, 0x2e);
+               u8 cr2f = vga_rcrt(par->state.vgabase, 0x2f);
 
                if ((cr30 == 0xE0) || (cr30 == 0xE1)) {
                        if (cr2e == 0x10)
@@ -883,7 +942,7 @@ static int __devinit s3_identification(int chip)
        }
 
        if (chip == CHIP_XXX_TRIO64V2_DXGX) {
-               u8 cr6f = vga_rcrt(NULL, 0x6f);
+               u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f);
 
                if (! (cr6f & 0x01))
                        return CHIP_775_TRIO64V2_DX;
@@ -892,7 +951,7 @@ static int __devinit s3_identification(int chip)
        }
 
        if (chip == CHIP_XXX_VIRGE_DXGX) {
-               u8 cr6f = vga_rcrt(NULL, 0x6f);
+               u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f);
 
                if (! (cr6f & 0x01))
                        return CHIP_375_VIRGE_DX;
@@ -901,7 +960,7 @@ static int __devinit s3_identification(int chip)
        }
 
        if (chip == CHIP_36X_TRIO3D_1X_2X) {
-               switch (vga_rcrt(NULL, 0x2f)) {
+               switch (vga_rcrt(par->state.vgabase, 0x2f)) {
                case 0x00:
                        return CHIP_360_TRIO3D_1X;
                case 0x01:
@@ -919,6 +978,8 @@ static int __devinit s3_identification(int chip)
 
 static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
+       struct pci_bus_region bus_reg;
+       struct resource vga_res;
        struct fb_info *info;
        struct s3fb_info *par;
        int rc;
@@ -968,31 +1029,42 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
                goto err_iomap;
        }
 
+       bus_reg.start = 0;
+       bus_reg.end = 64 * 1024;
+
+       vga_res.flags = IORESOURCE_IO;
+
+       pcibios_bus_to_resource(dev, &vga_res, &bus_reg);
+
+       par->state.vgabase = (void __iomem *) vga_res.start;
+
        /* Unlock regs */
-       cr38 = vga_rcrt(NULL, 0x38);
-       cr39 = vga_rcrt(NULL, 0x39);
-       vga_wseq(NULL, 0x08, 0x06);
-       vga_wcrt(NULL, 0x38, 0x48);
-       vga_wcrt(NULL, 0x39, 0xA5);
+       cr38 = vga_rcrt(par->state.vgabase, 0x38);
+       cr39 = vga_rcrt(par->state.vgabase, 0x39);
+       vga_wseq(par->state.vgabase, 0x08, 0x06);
+       vga_wcrt(par->state.vgabase, 0x38, 0x48);
+       vga_wcrt(par->state.vgabase, 0x39, 0xA5);
 
        /* Identify chip type */
        par->chip = id->driver_data & CHIP_MASK;
-       par->rev = vga_rcrt(NULL, 0x2f);
+       par->rev = vga_rcrt(par->state.vgabase, 0x2f);
        if (par->chip & CHIP_UNDECIDED_FLAG)
-               par->chip = s3_identification(par->chip);
+               par->chip = s3_identification(par);
 
        /* Find how many physical memory there is on card */
        /* 0x36 register is accessible even if other registers are locked */
-       regval = vga_rcrt(NULL, 0x36);
+       regval = vga_rcrt(par->state.vgabase, 0x36);
        if (par->chip == CHIP_360_TRIO3D_1X ||
            par->chip == CHIP_362_TRIO3D_2X ||
-           par->chip == CHIP_368_TRIO3D_2X) {
+           par->chip == CHIP_368_TRIO3D_2X ||
+           par->chip == CHIP_365_TRIO3D) {
                switch ((regval & 0xE0) >> 5) {
                case 0: /* 8MB -- only 4MB usable for display */
                case 1: /* 4MB with 32-bit bus */
                case 2: /* 4MB */
                        info->screen_size = 4 << 20;
                        break;
+               case 4: /* 2MB on 365 Trio3D */
                case 6: /* 2MB */
                        info->screen_size = 2 << 20;
                        break;
@@ -1002,13 +1074,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        info->fix.smem_len = info->screen_size;
 
        /* Find MCLK frequency */
-       regval = vga_rseq(NULL, 0x10);
-       par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F)  + 2);
+       regval = vga_rseq(par->state.vgabase, 0x10);
+       par->mclk_freq = ((vga_rseq(par->state.vgabase, 0x11) + 2) * 14318) / ((regval & 0x1F)  + 2);
        par->mclk_freq = par->mclk_freq >> (regval >> 5);
 
        /* Restore locks */
-       vga_wcrt(NULL, 0x38, cr38);
-       vga_wcrt(NULL, 0x39, cr39);
+       vga_wcrt(par->state.vgabase, 0x38, cr38);
+       vga_wcrt(par->state.vgabase, 0x39, cr39);
 
        strcpy(info->fix.id, s3_names [par->chip]);
        info->fix.mmio_start = 0;
@@ -1027,6 +1099,14 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
                goto err_find_mode;
        }
 
+       /* maximize virtual vertical size for fast scrolling */
+       info->var.yres_virtual = info->fix.smem_len * 8 /
+                       (info->var.bits_per_pixel * info->var.xres_virtual);
+       if (info->var.yres_virtual < info->var.yres) {
+               dev_err(info->device, "virtual vertical size smaller than real\n");
+               goto err_find_mode;
+       }
+
        rc = fb_alloc_cmap(&info->cmap, 256, 0);
        if (rc < 0) {
                dev_err(info->device, "cannot allocate colormap\n");
@@ -1044,8 +1124,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
 
        if (par->chip == CHIP_UNKNOWN)
                printk(KERN_INFO "fb%d: unknown chip, CR2D=%x, CR2E=%x, CRT2F=%x, CRT30=%x\n",
-                       info->node, vga_rcrt(NULL, 0x2d), vga_rcrt(NULL, 0x2e),
-                       vga_rcrt(NULL, 0x2f), vga_rcrt(NULL, 0x30));
+                       info->node, vga_rcrt(par->state.vgabase, 0x2d), vga_rcrt(par->state.vgabase, 0x2e),
+                       vga_rcrt(par->state.vgabase, 0x2f), vga_rcrt(par->state.vgabase, 0x30));
 
        /* Record a reference to the driver data */
        pci_set_drvdata(dev, info);
@@ -1192,6 +1272,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
+       {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D},
 
        {0, 0, 0, 0, 0, 0, 0}
 };
index bea38fce2470298f4bf27345ab72b0007abb260b..8fe19582c4602f65badeb17fbccb930574e243dc 100644 (file)
@@ -459,14 +459,14 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev)
        }
 
        par->ioarea = request_mem_region(res->start,
-                                        (res->end - res->start), pdev->name);
+                                        resource_size(res), pdev->name);
        if (!par->ioarea) {
                dev_err(&pdev->dev, "mmio area busy\n");
                ret = -EBUSY;
                goto out_fb;
        }
 
-       par->base = ioremap_nocache(res->start, res->end - res->start + 1);
+       par->base = ioremap_nocache(res->start, resource_size(res));
        if (!par->base) {
                dev_err(&pdev->dev, "cannot remap\n");
                ret = -ENODEV;
index bf2629f83f409418a96bd46da1df53d6c4032efe..757665bc500f1c009540673ed497f556f1a26024 100644 (file)
@@ -1088,8 +1088,9 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent,
 
        bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch,
                                       &sh_mobile_lcdc_bl_ops, NULL);
-       if (!bl) {
-               dev_err(parent, "unable to register backlight device\n");
+       if (IS_ERR(bl)) {
+               dev_err(parent, "unable to register backlight device: %ld\n",
+                       PTR_ERR(bl));
                return NULL;
        }
 
index eac7a01925f3d26e03ab33cc2650a76278993391..1987f1b7212f40732c2c28315d3791b3d08d2652 100644 (file)
@@ -495,6 +495,7 @@ struct sis_video_info {
        unsigned int    refresh_rate;
 
        unsigned int    chip;
+       unsigned int    chip_real_id;
        u8              revision_id;
        int             sisvga_enabled;         /* PCI device was enabled */
 
index 2fb8c5a660fb88ebd42c10f90739ee233648b974..75259845933deb53ab030a2067bb52e69259f673 100644 (file)
@@ -4563,6 +4563,11 @@ sisfb_post_sis315330(struct pci_dev *pdev)
 }
 #endif
 
+static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
+{
+       return ivideo->chip_real_id == XGI_21;
+}
+
 static void __devinit
 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
 {
@@ -4627,11 +4632,11 @@ sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
        return 1;
 }
 
-static void __devinit
+static int __devinit
 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
 {
        unsigned int buswidth, ranksize, channelab, mapsize;
-       int i, j, k, l;
+       int i, j, k, l, status;
        u8 reg, sr14;
        static const u8 dramsr13[12 * 5] = {
                0x02, 0x0e, 0x0b, 0x80, 0x5d,
@@ -4673,7 +4678,7 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
                SiS_SetReg(SISSR, 0x13, 0x35);
                SiS_SetReg(SISSR, 0x14, 0x41);
                /* TODO */
-               return;
+               return -ENOMEM;
        }
 
        /* Non-interleaving */
@@ -4835,6 +4840,7 @@ bail_out:
 
        j = (ivideo->chip == XGI_20) ? 5 : 9;
        k = (ivideo->chip == XGI_20) ? 12 : 4;
+       status = -EIO;
 
        for(i = 0; i < k; i++) {
 
@@ -4868,11 +4874,15 @@ bail_out:
                SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
                sisfb_post_xgi_delay(ivideo, 1);
 
-               if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
+               if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
+                       status = 0;
                        break;
+               }
        }
 
        iounmap(ivideo->video_vbase);
+
+       return status;
 }
 
 static void __devinit
@@ -4931,6 +4941,175 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
        sisfb_post_xgi_delay(ivideo, 0x43);
 }
 
+static void __devinit
+sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb)
+{
+       unsigned char *bios = ivideo->bios_abase;
+       u8 v1;
+
+       SiS_SetReg(SISSR, 0x28, 0x64);
+       SiS_SetReg(SISSR, 0x29, 0x63);
+       sisfb_post_xgi_delay(ivideo, 15);
+       SiS_SetReg(SISSR, 0x18, 0x00);
+       SiS_SetReg(SISSR, 0x19, 0x20);
+       SiS_SetReg(SISSR, 0x16, 0x00);
+       SiS_SetReg(SISSR, 0x16, 0x80);
+       SiS_SetReg(SISSR, 0x18, 0xc5);
+       SiS_SetReg(SISSR, 0x19, 0x23);
+       SiS_SetReg(SISSR, 0x16, 0x00);
+       SiS_SetReg(SISSR, 0x16, 0x80);
+       sisfb_post_xgi_delay(ivideo, 1);
+       SiS_SetReg(SISCR, 0x97, 0x11);
+       sisfb_post_xgi_setclocks(ivideo, regb);
+       sisfb_post_xgi_delay(ivideo, 0x46);
+       SiS_SetReg(SISSR, 0x18, 0xc5);
+       SiS_SetReg(SISSR, 0x19, 0x23);
+       SiS_SetReg(SISSR, 0x16, 0x00);
+       SiS_SetReg(SISSR, 0x16, 0x80);
+       sisfb_post_xgi_delay(ivideo, 1);
+       SiS_SetReg(SISSR, 0x1b, 0x04);
+       sisfb_post_xgi_delay(ivideo, 1);
+       SiS_SetReg(SISSR, 0x1b, 0x00);
+       sisfb_post_xgi_delay(ivideo, 1);
+       v1 = 0x31;
+       if (ivideo->haveXGIROM) {
+               v1 = bios[0xf0];
+       }
+       SiS_SetReg(SISSR, 0x18, v1);
+       SiS_SetReg(SISSR, 0x19, 0x06);
+       SiS_SetReg(SISSR, 0x16, 0x04);
+       SiS_SetReg(SISSR, 0x16, 0x84);
+       sisfb_post_xgi_delay(ivideo, 1);
+}
+
+static void __devinit
+sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
+{
+       sisfb_post_xgi_setclocks(ivideo, 1);
+
+       SiS_SetReg(SISCR, 0x97, 0x11);
+       sisfb_post_xgi_delay(ivideo, 0x46);
+
+       SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS2 */
+       SiS_SetReg(SISSR, 0x19, 0x80);
+       SiS_SetReg(SISSR, 0x16, 0x05);
+       SiS_SetReg(SISSR, 0x16, 0x85);
+
+       SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS3 */
+       SiS_SetReg(SISSR, 0x19, 0xc0);
+       SiS_SetReg(SISSR, 0x16, 0x05);
+       SiS_SetReg(SISSR, 0x16, 0x85);
+
+       SiS_SetReg(SISSR, 0x18, 0x00);  /* EMRS1 */
+       SiS_SetReg(SISSR, 0x19, 0x40);
+       SiS_SetReg(SISSR, 0x16, 0x05);
+       SiS_SetReg(SISSR, 0x16, 0x85);
+
+       SiS_SetReg(SISSR, 0x18, 0x42);  /* MRS1 */
+       SiS_SetReg(SISSR, 0x19, 0x02);
+       SiS_SetReg(SISSR, 0x16, 0x05);
+       SiS_SetReg(SISSR, 0x16, 0x85);
+       sisfb_post_xgi_delay(ivideo, 1);
+
+       SiS_SetReg(SISSR, 0x1b, 0x04);
+       sisfb_post_xgi_delay(ivideo, 1);
+
+       SiS_SetReg(SISSR, 0x1b, 0x00);
+       sisfb_post_xgi_delay(ivideo, 1);
+
+       SiS_SetReg(SISSR, 0x18, 0x42);  /* MRS1 */
+       SiS_SetReg(SISSR, 0x19, 0x00);
+       SiS_SetReg(SISSR, 0x16, 0x05);
+       SiS_SetReg(SISSR, 0x16, 0x85);
+       sisfb_post_xgi_delay(ivideo, 1);
+}
+
+static void __devinit
+sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
+{
+       unsigned char *bios = ivideo->bios_abase;
+       static const u8 cs158[8] = {
+               0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs160[8] = {
+               0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       static const u8 cs168[8] = {
+               0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       u8 reg;
+       u8 v1;
+       u8 v2;
+       u8 v3;
+
+       SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
+       SiS_SetReg(SISCR, 0x82, 0x77);
+       SiS_SetReg(SISCR, 0x86, 0x00);
+       reg = SiS_GetReg(SISCR, 0x86);
+       SiS_SetReg(SISCR, 0x86, 0x88);
+       reg = SiS_GetReg(SISCR, 0x86);
+       v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
+       if (ivideo->haveXGIROM) {
+               v1 = bios[regb + 0x168];
+               v2 = bios[regb + 0x160];
+               v3 = bios[regb + 0x158];
+       }
+       SiS_SetReg(SISCR, 0x86, v1);
+       SiS_SetReg(SISCR, 0x82, 0x77);
+       SiS_SetReg(SISCR, 0x85, 0x00);
+       reg = SiS_GetReg(SISCR, 0x85);
+       SiS_SetReg(SISCR, 0x85, 0x88);
+       reg = SiS_GetReg(SISCR, 0x85);
+       SiS_SetReg(SISCR, 0x85, v2);
+       SiS_SetReg(SISCR, 0x82, v3);
+       SiS_SetReg(SISCR, 0x98, 0x01);
+       SiS_SetReg(SISCR, 0x9a, 0x02);
+       if (sisfb_xgi_is21(ivideo))
+               sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
+       else
+               sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
+}
+
+static u8 __devinit
+sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
+{
+       unsigned char *bios = ivideo->bios_abase;
+       u8 ramtype;
+       u8 reg;
+       u8 v1;
+
+       ramtype = 0x00; v1 = 0x10;
+       if (ivideo->haveXGIROM) {
+               ramtype = bios[0x62];
+               v1 = bios[0x1d2];
+       }
+       if (!(ramtype & 0x80)) {
+               if (sisfb_xgi_is21(ivideo)) {
+                       SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
+                       SiS_SetRegOR(SISCR, 0x4a, 0x80);  /* GPIOH EN */
+                       reg = SiS_GetReg(SISCR, 0x48);
+                       SiS_SetRegOR(SISCR, 0xb4, 0x02);
+                       ramtype = reg & 0x01;             /* GPIOH */
+               } else if (ivideo->chip == XGI_20) {
+                       SiS_SetReg(SISCR, 0x97, v1);
+                       reg = SiS_GetReg(SISCR, 0x97);
+                       if (reg & 0x10) {
+                               ramtype = (reg & 0x01) << 1;
+                       }
+               } else {
+                       reg = SiS_GetReg(SISSR, 0x39);
+                       ramtype = reg & 0x02;
+                       if (!(ramtype)) {
+                               reg = SiS_GetReg(SISSR, 0x3a);
+                               ramtype = (reg >> 1) & 0x01;
+                       }
+               }
+       }
+       ramtype &= 0x07;
+
+       return ramtype;
+}
+
 static int __devinit
 sisfb_post_xgi(struct pci_dev *pdev)
 {
@@ -5213,9 +5392,23 @@ sisfb_post_xgi(struct pci_dev *pdev)
                SiS_SetReg(SISCR, 0x77, v1);
        }
 
-       /* RAM type */
-
-       regb = 0;       /* ! */
+       /* RAM type:
+        *
+        * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
+        *
+        * The code seems to written so that regb should equal ramtype,
+        * however, so far it has been hardcoded to 0. Enable other values only
+        * on XGI Z9, as it passes the POST, and add a warning for others.
+        */
+       ramtype = sisfb_post_xgi_ramtype(ivideo);
+       if (!sisfb_xgi_is21(ivideo) && ramtype) {
+               dev_warn(&pdev->dev,
+                        "RAM type something else than expected: %d\n",
+                        ramtype);
+               regb = 0;
+       } else {
+               regb = ramtype;
+       }
 
        v1 = 0xff;
        if(ivideo->haveXGIROM) {
@@ -5367,7 +5560,10 @@ sisfb_post_xgi(struct pci_dev *pdev)
                }
        }
 
-       SiS_SetReg(SISSR, 0x17, 0x00);
+       if (regb == 1)
+               SiS_SetReg(SISSR, 0x17, 0x80);          /* DDR2 */
+       else
+               SiS_SetReg(SISSR, 0x17, 0x00);          /* DDR1 */
        SiS_SetReg(SISSR, 0x1a, 0x87);
 
        if(ivideo->chip == XGI_20) {
@@ -5375,31 +5571,6 @@ sisfb_post_xgi(struct pci_dev *pdev)
                SiS_SetReg(SISSR, 0x1c, 0x00);
        }
 
-       ramtype = 0x00; v1 = 0x10;
-       if(ivideo->haveXGIROM) {
-               ramtype = bios[0x62];
-               v1 = bios[0x1d2];
-       }
-       if(!(ramtype & 0x80)) {
-               if(ivideo->chip == XGI_20) {
-                       SiS_SetReg(SISCR, 0x97, v1);
-                       reg = SiS_GetReg(SISCR, 0x97);
-                       if(reg & 0x10) {
-                               ramtype = (reg & 0x01) << 1;
-                       }
-               } else {
-                       reg = SiS_GetReg(SISSR, 0x39);
-                       ramtype = reg & 0x02;
-                       if(!(ramtype)) {
-                               reg = SiS_GetReg(SISSR, 0x3a);
-                               ramtype = (reg >> 1) & 0x01;
-                       }
-               }
-       }
-       ramtype &= 0x07;
-
-       regb = 0;       /* ! */
-
        switch(ramtype) {
        case 0:
                sisfb_post_xgi_setclocks(ivideo, regb);
@@ -5485,61 +5656,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
                SiS_SetReg(SISSR, 0x1b, 0x00);
                break;
        case 1:
-               SiS_SetReg(SISCR, 0x82, 0x77);
-               SiS_SetReg(SISCR, 0x86, 0x00);
-               reg = SiS_GetReg(SISCR, 0x86);
-               SiS_SetReg(SISCR, 0x86, 0x88);
-               reg = SiS_GetReg(SISCR, 0x86);
-               v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
-               if(ivideo->haveXGIROM) {
-                       v1 = bios[regb + 0x168];
-                       v2 = bios[regb + 0x160];
-                       v3 = bios[regb + 0x158];
-               }
-               SiS_SetReg(SISCR, 0x86, v1);
-               SiS_SetReg(SISCR, 0x82, 0x77);
-               SiS_SetReg(SISCR, 0x85, 0x00);
-               reg = SiS_GetReg(SISCR, 0x85);
-               SiS_SetReg(SISCR, 0x85, 0x88);
-               reg = SiS_GetReg(SISCR, 0x85);
-               SiS_SetReg(SISCR, 0x85, v2);
-               SiS_SetReg(SISCR, 0x82, v3);
-               SiS_SetReg(SISCR, 0x98, 0x01);
-               SiS_SetReg(SISCR, 0x9a, 0x02);
-
-               SiS_SetReg(SISSR, 0x28, 0x64);
-               SiS_SetReg(SISSR, 0x29, 0x63);
-               sisfb_post_xgi_delay(ivideo, 15);
-               SiS_SetReg(SISSR, 0x18, 0x00);
-               SiS_SetReg(SISSR, 0x19, 0x20);
-               SiS_SetReg(SISSR, 0x16, 0x00);
-               SiS_SetReg(SISSR, 0x16, 0x80);
-               SiS_SetReg(SISSR, 0x18, 0xc5);
-               SiS_SetReg(SISSR, 0x19, 0x23);
-               SiS_SetReg(SISSR, 0x16, 0x00);
-               SiS_SetReg(SISSR, 0x16, 0x80);
-               sisfb_post_xgi_delay(ivideo, 1);
-               SiS_SetReg(SISCR, 0x97, 0x11);
-               sisfb_post_xgi_setclocks(ivideo, regb);
-               sisfb_post_xgi_delay(ivideo, 0x46);
-               SiS_SetReg(SISSR, 0x18, 0xc5);
-               SiS_SetReg(SISSR, 0x19, 0x23);
-               SiS_SetReg(SISSR, 0x16, 0x00);
-               SiS_SetReg(SISSR, 0x16, 0x80);
-               sisfb_post_xgi_delay(ivideo, 1);
-               SiS_SetReg(SISSR, 0x1b, 0x04);
-               sisfb_post_xgi_delay(ivideo, 1);
-               SiS_SetReg(SISSR, 0x1b, 0x00);
-               sisfb_post_xgi_delay(ivideo, 1);
-               v1 = 0x31;
-               if(ivideo->haveXGIROM) {
-                       v1 = bios[0xf0];
-               }
-               SiS_SetReg(SISSR, 0x18, v1);
-               SiS_SetReg(SISSR, 0x19, 0x06);
-               SiS_SetReg(SISSR, 0x16, 0x04);
-               SiS_SetReg(SISSR, 0x16, 0x84);
-               sisfb_post_xgi_delay(ivideo, 1);
+               sisfb_post_xgi_ddr2(ivideo, regb);
                break;
        default:
                sisfb_post_xgi_setclocks(ivideo, regb);
@@ -5648,6 +5765,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
                SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
 
        } else {
+               int err;
 
                /* Set default mode, don't clear screen */
                ivideo->SiS_Pr.SiS_UseOEM = false;
@@ -5661,10 +5779,16 @@ sisfb_post_xgi(struct pci_dev *pdev)
 
                /* Disable read-cache */
                SiS_SetRegAND(SISSR, 0x21, 0xdf);
-               sisfb_post_xgi_ramsize(ivideo);
+               err = sisfb_post_xgi_ramsize(ivideo);
                /* Enable read-cache */
                SiS_SetRegOR(SISSR, 0x21, 0x20);
 
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "%s: RAM size detection failed: %d\n",
+                               __func__, err);
+                       return 0;
+               }
        }
 
 #if 0
@@ -5777,6 +5901,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 #endif
 
        ivideo->chip = chipinfo->chip;
+       ivideo->chip_real_id = chipinfo->chip;
        ivideo->sisvga_engine = chipinfo->vgaengine;
        ivideo->hwcursor_size = chipinfo->hwcursor_size;
        ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
@@ -6010,6 +6135,18 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                sisfb_detect_custom_timing(ivideo);
        }
 
+#ifdef CONFIG_FB_SIS_315
+       if (ivideo->chip == XGI_20) {
+               /* Check if our Z7 chip is actually Z9 */
+               SiS_SetRegOR(SISCR, 0x4a, 0x40);        /* GPIOG EN */
+               reg = SiS_GetReg(SISCR, 0x48);
+               if (reg & 0x02) {                       /* GPIOG */
+                       ivideo->chip_real_id = XGI_21;
+                       dev_info(&pdev->dev, "Z9 detected\n");
+               }
+       }
+#endif
+
        /* POST card in case this has not been done by the BIOS */
        if( (!ivideo->sisvga_enabled)
 #if !defined(__i386__) && !defined(__x86_64__)
index 12c0dfaf251876baf61b54ce5fe848e73151d371..e3f9976cfef084ee5fcde6236d96424adc4c6f10 100644 (file)
@@ -87,6 +87,7 @@ typedef enum _SIS_CHIP_TYPE {
     SIS_341,
     SIS_342,
     XGI_20  = 75,
+    XGI_21,
     XGI_40,
     MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
index bcb44a594ebcb944821cfe2f09d621f470cfa056..46d1a64fe80d0eb569912ead930aaa76d6734f05 100644 (file)
 #include <linux/sm501.h>
 #include <linux/sm501-regs.h>
 
+#include "edid.h"
+
+static char *fb_mode = "640x480-16@60";
+static unsigned long default_bpp = 16;
+
+static struct fb_videomode __devinitdata sm501_default_mode = {
+       .refresh        = 60,
+       .xres           = 640,
+       .yres           = 480,
+       .pixclock       = 20833,
+       .left_margin    = 142,
+       .right_margin   = 13,
+       .upper_margin   = 21,
+       .lower_margin   = 1,
+       .hsync_len      = 69,
+       .vsync_len      = 3,
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode          = FB_VMODE_NONINTERLACED
+};
+
 #define NR_PALETTE     256
 
 enum sm501_controller {
@@ -77,6 +97,7 @@ struct sm501fb_info {
        void __iomem            *regs2d;        /* 2d remapped registers */
        void __iomem            *fbmem;         /* remapped framebuffer */
        size_t                   fbmem_len;     /* length of remapped region */
+       u8 *edid_data;
 };
 
 /* per-framebuffer private data */
@@ -117,7 +138,7 @@ static inline int v_total(struct fb_var_screeninfo *var)
 
 static inline void sm501fb_sync_regs(struct sm501fb_info *info)
 {
-       readl(info->regs);
+       smc501_readl(info->regs);
 }
 
 /* sm501_alloc_mem
@@ -262,7 +283,7 @@ static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
 
        /* set gamma values */
        for (offset = 0; offset < 256 * 4; offset += 4) {
-               writel(value, fbi->regs + palette + offset);
+               smc501_writel(value, fbi->regs + palette + offset);
                value += 0x010101;      /* Advance RGB by 1,1,1.*/
        }
 }
@@ -476,7 +497,8 @@ static int sm501fb_set_par_common(struct fb_info *info,
 
        /* set start of framebuffer to the screen */
 
-       writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
+       smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP,
+                       fbi->regs + head_addr);
 
        /* program CRT clock  */
 
@@ -519,7 +541,7 @@ static void sm501fb_set_par_geometry(struct fb_info *info,
        reg = info->fix.line_length;
        reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
 
-       writel(reg, fbi->regs + (par->head == HEAD_CRT ?
+       smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ?
                    SM501_DC_CRT_FB_OFFSET :  SM501_DC_PANEL_FB_OFFSET));
 
        /* program horizontal total */
@@ -527,27 +549,27 @@ static void sm501fb_set_par_geometry(struct fb_info *info,
        reg  = (h_total(var) - 1) << 16;
        reg |= (var->xres - 1);
 
-       writel(reg, base + SM501_OFF_DC_H_TOT);
+       smc501_writel(reg, base + SM501_OFF_DC_H_TOT);
 
        /* program horizontal sync */
 
        reg  = var->hsync_len << 16;
        reg |= var->xres + var->right_margin - 1;
 
-       writel(reg, base + SM501_OFF_DC_H_SYNC);
+       smc501_writel(reg, base + SM501_OFF_DC_H_SYNC);
 
        /* program vertical total */
 
        reg  = (v_total(var) - 1) << 16;
        reg |= (var->yres - 1);
 
-       writel(reg, base + SM501_OFF_DC_V_TOT);
+       smc501_writel(reg, base + SM501_OFF_DC_V_TOT);
 
        /* program vertical sync */
        reg  = var->vsync_len << 16;
        reg |= var->yres + var->lower_margin - 1;
 
-       writel(reg, base + SM501_OFF_DC_V_SYNC);
+       smc501_writel(reg, base + SM501_OFF_DC_V_SYNC);
 }
 
 /* sm501fb_pan_crt
@@ -566,15 +588,15 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
 
        xoffs = var->xoffset * bytes_pixel;
 
-       reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+       reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
 
        reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
        reg |= ((xoffs & 15) / bytes_pixel) << 4;
-       writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
+       smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
 
        reg = (par->screen.sm_addr + xoffs +
               var->yoffset * info->fix.line_length);
-       writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
+       smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
 
        sm501fb_sync_regs(fbi);
        return 0;
@@ -593,10 +615,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
        unsigned long reg;
 
        reg = var->xoffset | (var->xres_virtual << 16);
-       writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
+       smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
 
        reg = var->yoffset | (var->yres_virtual << 16);
-       writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
+       smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
 
        sm501fb_sync_regs(fbi);
        return 0;
@@ -622,7 +644,7 @@ static int sm501fb_set_par_crt(struct fb_info *info)
        /* enable CRT DAC - note 0 is on!*/
        sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
 
-       control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+       control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
 
        control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
                    SM501_DC_CRT_CONTROL_GAMMA |
@@ -684,7 +706,7 @@ static int sm501fb_set_par_crt(struct fb_info *info)
  out_update:
        dev_dbg(fbi->dev, "new control is %08lx\n", control);
 
-       writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
+       smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
        sm501fb_sync_regs(fbi);
 
        return 0;
@@ -696,18 +718,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
        void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
        struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
 
-       control = readl(ctrl_reg);
+       control = smc501_readl(ctrl_reg);
 
        if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
                /* enable panel power */
 
                control |= SM501_DC_PANEL_CONTROL_VDD;  /* FPVDDEN */
-               writel(control, ctrl_reg);
+               smc501_writel(control, ctrl_reg);
                sm501fb_sync_regs(fbi);
                mdelay(10);
 
                control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
-               writel(control, ctrl_reg);
+               smc501_writel(control, ctrl_reg);
                sm501fb_sync_regs(fbi);
                mdelay(10);
 
@@ -719,7 +741,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                        else
                                control |= SM501_DC_PANEL_CONTROL_BIAS;
 
-                       writel(control, ctrl_reg);
+                       smc501_writel(control, ctrl_reg);
                        sm501fb_sync_regs(fbi);
                        mdelay(10);
                }
@@ -730,7 +752,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                        else
                                control |= SM501_DC_PANEL_CONTROL_FPEN;
 
-                       writel(control, ctrl_reg);
+                       smc501_writel(control, ctrl_reg);
                        sm501fb_sync_regs(fbi);
                        mdelay(10);
                }
@@ -742,7 +764,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                        else
                                control &= ~SM501_DC_PANEL_CONTROL_FPEN;
 
-                       writel(control, ctrl_reg);
+                       smc501_writel(control, ctrl_reg);
                        sm501fb_sync_regs(fbi);
                        mdelay(10);
                }
@@ -753,18 +775,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
                        else
                                control &= ~SM501_DC_PANEL_CONTROL_BIAS;
 
-                       writel(control, ctrl_reg);
+                       smc501_writel(control, ctrl_reg);
                        sm501fb_sync_regs(fbi);
                        mdelay(10);
                }
 
                control &= ~SM501_DC_PANEL_CONTROL_DATA;
-               writel(control, ctrl_reg);
+               smc501_writel(control, ctrl_reg);
                sm501fb_sync_regs(fbi);
                mdelay(10);
 
                control &= ~SM501_DC_PANEL_CONTROL_VDD;
-               writel(control, ctrl_reg);
+               smc501_writel(control, ctrl_reg);
                sm501fb_sync_regs(fbi);
                mdelay(10);
        }
@@ -799,7 +821,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
 
        /* update control register */
 
-       control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
+       control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL);
        control &= (SM501_DC_PANEL_CONTROL_GAMMA |
                    SM501_DC_PANEL_CONTROL_VDD  |
                    SM501_DC_PANEL_CONTROL_DATA |
@@ -833,16 +855,16 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
                BUG();
        }
 
-       writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
+       smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
 
        /* panel plane top left and bottom right location */
 
-       writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
+       smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
 
        reg  = var->xres - 1;
        reg |= (var->yres - 1) << 16;
 
-       writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
+       smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
 
        /* program panel control register */
 
@@ -855,7 +877,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
        if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
                control |= SM501_DC_PANEL_CONTROL_VSP;
 
-       writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
+       smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
        sm501fb_sync_regs(fbi);
 
        /* ensure the panel interface is not tristated at this point */
@@ -924,7 +946,7 @@ static int sm501fb_setcolreg(unsigned regno,
                        val |= (green >> 8) << 8;
                        val |= blue >> 8;
 
-                       writel(val, base + (regno * 4));
+                       smc501_writel(val, base + (regno * 4));
                }
 
                break;
@@ -980,7 +1002,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
 
        dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
 
-       ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+       ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
 
        switch (blank_mode) {
        case FB_BLANK_POWERDOWN:
@@ -1004,7 +1026,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
 
        }
 
-       writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
+       smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
        sm501fb_sync_regs(fbi);
 
        return 0;
@@ -1041,12 +1063,14 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        if (cursor->image.depth > 1)
                return -EINVAL;
 
-       hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
+       hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR);
 
        if (cursor->enable)
-               writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+               smc501_writel(hwc_addr | SM501_HWC_EN,
+                               base + SM501_OFF_HWC_ADDR);
        else
-               writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+               smc501_writel(hwc_addr & ~SM501_HWC_EN,
+                               base + SM501_OFF_HWC_ADDR);
 
        /* set data */
        if (cursor->set & FB_CUR_SETPOS) {
@@ -1060,7 +1084,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 
                //y += cursor->image.height;
 
-               writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
+               smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
        }
 
        if (cursor->set & FB_CUR_SETCMAP) {
@@ -1080,8 +1104,8 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 
                dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
 
-               writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
-               writel(fg, base + SM501_OFF_HWC_COLOR_3);
+               smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
+               smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3);
        }
 
        if (cursor->set & FB_CUR_SETSIZE ||
@@ -1102,7 +1126,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                        __func__, cursor->image.width, cursor->image.height);
 
                for (op = 0; op < (64*64*2)/8; op+=4)
-                       writel(0x0, dst + op);
+                       smc501_writel(0x0, dst + op);
 
                for (y = 0; y < cursor->image.height; y++) {
                        for (x = 0; x < cursor->image.width; x++) {
@@ -1141,7 +1165,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev,
        struct sm501fb_info *info = dev_get_drvdata(dev);
        unsigned long ctrl;
 
-       ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+       ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
        ctrl &= SM501_DC_CRT_CONTROL_SEL;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
@@ -1172,7 +1196,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
 
        dev_info(dev, "setting crt source to head %d\n", head);
 
-       ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+       ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
 
        if (head == HEAD_CRT) {
                ctrl |= SM501_DC_CRT_CONTROL_SEL;
@@ -1184,7 +1208,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
                ctrl &= ~SM501_DC_CRT_CONTROL_TE;
        }
 
-       writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+       smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
        sm501fb_sync_regs(info);
 
        return len;
@@ -1205,7 +1229,8 @@ static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
        unsigned int reg;
 
        for (reg = start; reg < (len + start); reg += 4)
-               ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
+               ptr += sprintf(ptr, "%08x = %08x\n", reg,
+                               smc501_readl(mem + reg));
 
        return ptr - buf;
 }
@@ -1257,7 +1282,7 @@ static int sm501fb_sync(struct fb_info *info)
 
        /* wait for the 2d engine to be ready */
        while ((count > 0) &&
-              (readl(fbi->regs + SM501_SYSTEM_CONTROL) &
+              (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) &
                SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
                count--;
 
@@ -1312,45 +1337,46 @@ static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *are
                return;
 
        /* set the base addresses */
-       writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
-       writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
+       smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
+       smc501_writel(par->screen.sm_addr,
+                       fbi->regs2d + SM501_2D_DESTINATION_BASE);
 
        /* set the window width */
-       writel((info->var.xres << 16) | info->var.xres,
+       smc501_writel((info->var.xres << 16) | info->var.xres,
               fbi->regs2d + SM501_2D_WINDOW_WIDTH);
 
        /* set window stride */
-       writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
+       smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
               fbi->regs2d + SM501_2D_PITCH);
 
        /* set data format */
        switch (info->var.bits_per_pixel) {
        case 8:
-               writel(0, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
                break;
        case 16:
-               writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
                break;
        case 32:
-               writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
                break;
        }
 
        /* 2d compare mask */
-       writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
+       smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
 
        /* 2d mask */
-       writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
+       smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
 
        /* source and destination x y */
-       writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
-       writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
+       smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
+       smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
 
        /* w/h */
-       writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
+       smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
 
        /* do area move */
-       writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
+       smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
 }
 
 static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
@@ -1372,47 +1398,49 @@ static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rec
                return;
 
        /* set the base addresses */
-       writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
-       writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
+       smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
+       smc501_writel(par->screen.sm_addr,
+                       fbi->regs2d + SM501_2D_DESTINATION_BASE);
 
        /* set the window width */
-       writel((info->var.xres << 16) | info->var.xres,
+       smc501_writel((info->var.xres << 16) | info->var.xres,
               fbi->regs2d + SM501_2D_WINDOW_WIDTH);
 
        /* set window stride */
-       writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
+       smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
               fbi->regs2d + SM501_2D_PITCH);
 
        /* set data format */
        switch (info->var.bits_per_pixel) {
        case 8:
-               writel(0, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
                break;
        case 16:
-               writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
                break;
        case 32:
-               writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
+               smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
                break;
        }
 
        /* 2d compare mask */
-       writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
+       smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
 
        /* 2d mask */
-       writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
+       smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
 
        /* colour */
-       writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
+       smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
 
        /* x y */
-       writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION);
+       smc501_writel((rect->dx << 16) | rect->dy,
+                       fbi->regs2d + SM501_2D_DESTINATION);
 
        /* w/h */
-       writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
+       smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
 
        /* do rectangle fill */
-       writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
+       smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
 }
 
 
@@ -1470,11 +1498,12 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
 
        /* initialise the colour registers */
 
-       writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
+       smc501_writel(par->cursor.sm_addr,
+                       par->cursor_regs + SM501_OFF_HWC_ADDR);
 
-       writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
-       writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
-       writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
+       smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
+       smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
+       smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
        sm501fb_sync_regs(info);
 
        return 0;
@@ -1581,7 +1610,7 @@ static int sm501fb_start(struct sm501fb_info *info,
 
        /* clear palette ram - undefined at power on */
        for (k = 0; k < (256 * 3); k++)
-               writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
+               smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
 
        /* enable display controller */
        sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
@@ -1649,20 +1678,20 @@ static int sm501fb_init_fb(struct fb_info *fb,
        switch (head) {
        case HEAD_CRT:
                pd = info->pdata->fb_crt;
-               ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+               ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
                enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
 
                /* ensure we set the correct source register */
                if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
                        ctrl |= SM501_DC_CRT_CONTROL_SEL;
-                       writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+                       smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
                }
 
                break;
 
        case HEAD_PANEL:
                pd = info->pdata->fb_pnl;
-               ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
+               ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL);
                enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
                break;
 
@@ -1680,7 +1709,7 @@ static int sm501fb_init_fb(struct fb_info *fb,
 
        if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
                ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
-               writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+               smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
                enable = 0;
        }
 
@@ -1700,6 +1729,15 @@ static int sm501fb_init_fb(struct fb_info *fb,
                FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
                FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
 
+#if defined(CONFIG_OF)
+#ifdef __BIG_ENDIAN
+       if (of_get_property(info->dev->parent->of_node, "little-endian", NULL))
+               fb->flags |= FBINFO_FOREIGN_ENDIAN;
+#else
+       if (of_get_property(info->dev->parent->of_node, "big-endian", NULL))
+               fb->flags |= FBINFO_FOREIGN_ENDIAN;
+#endif
+#endif
        /* fixed data */
 
        fb->fix.type            = FB_TYPE_PACKED_PIXELS;
@@ -1717,9 +1755,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
        fb->var.vmode           = FB_VMODE_NONINTERLACED;
        fb->var.bits_per_pixel  = 16;
 
+       if (info->edid_data) {
+                       /* Now build modedb from EDID */
+                       fb_edid_to_monspecs(info->edid_data, &fb->monspecs);
+                       fb_videomode_to_modelist(fb->monspecs.modedb,
+                                                fb->monspecs.modedb_len,
+                                                &fb->modelist);
+       }
+
        if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
                /* TODO read the mode from the current display */
-
        } else {
                if (pd->def_mode) {
                        dev_info(info->dev, "using supplied mode\n");
@@ -1729,12 +1774,37 @@ static int sm501fb_init_fb(struct fb_info *fb,
                        fb->var.xres_virtual = fb->var.xres;
                        fb->var.yres_virtual = fb->var.yres;
                } else {
-                       ret = fb_find_mode(&fb->var, fb,
+                       if (info->edid_data) {
+                               ret = fb_find_mode(&fb->var, fb, fb_mode,
+                                       fb->monspecs.modedb,
+                                       fb->monspecs.modedb_len,
+                                       &sm501_default_mode, default_bpp);
+                               /* edid_data is no longer needed, free it */
+                               kfree(info->edid_data);
+                       } else {
+                               ret = fb_find_mode(&fb->var, fb,
                                           NULL, NULL, 0, NULL, 8);
+                       }
 
-                       if (ret == 0 || ret == 4) {
-                               dev_err(info->dev,
-                                       "failed to get initial mode\n");
+                       switch (ret) {
+                       case 1:
+                               dev_info(info->dev, "using mode specified in "
+                                               "@mode\n");
+                               break;
+                       case 2:
+                               dev_info(info->dev, "using mode specified in "
+                                       "@mode with ignored refresh rate\n");
+                               break;
+                       case 3:
+                               dev_info(info->dev, "using mode default "
+                                       "mode\n");
+                               break;
+                       case 4:
+                               dev_info(info->dev, "using mode from list\n");
+                               break;
+                       default:
+                               dev_info(info->dev, "ret = %d\n", ret);
+                               dev_info(info->dev, "failed to find mode\n");
                                return -EINVAL;
                        }
                }
@@ -1875,8 +1945,32 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
        }
 
        if (info->pdata == NULL) {
-               dev_info(dev, "using default configuration data\n");
+               int found = 0;
+#if defined(CONFIG_OF)
+               struct device_node *np = pdev->dev.parent->of_node;
+               const u8 *prop;
+               const char *cp;
+               int len;
+
                info->pdata = &sm501fb_def_pdata;
+               if (np) {
+                       /* Get EDID */
+                       cp = of_get_property(np, "mode", &len);
+                       if (cp)
+                               strcpy(fb_mode, cp);
+                       prop = of_get_property(np, "edid", &len);
+                       if (prop && len == EDID_LENGTH) {
+                               info->edid_data = kmemdup(prop, EDID_LENGTH,
+                                                         GFP_KERNEL);
+                               if (info->edid_data)
+                                       found = 1;
+                       }
+               }
+#endif
+               if (!found) {
+                       dev_info(dev, "using default configuration data\n");
+                       info->pdata = &sm501fb_def_pdata;
+               }
        }
 
        /* probe for the presence of each panel */
@@ -2085,7 +2179,7 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
        struct sm501fb_info *info = platform_get_drvdata(pdev);
 
        /* store crt control to resume with */
-       info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+       info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
 
        sm501fb_suspend_fb(info, HEAD_CRT);
        sm501fb_suspend_fb(info, HEAD_PANEL);
@@ -2109,10 +2203,10 @@ static int sm501fb_resume(struct platform_device *pdev)
 
        /* restore the items we want to be saved for crt control */
 
-       crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+       crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
        crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
        crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
-       writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
+       smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
 
        sm501fb_resume_fb(info, HEAD_CRT);
        sm501fb_resume_fb(info, HEAD_PANEL);
@@ -2149,6 +2243,11 @@ static void __exit sm501fb_cleanup(void)
 module_init(sm501fb_init);
 module_exit(sm501fb_cleanup);
 
+module_param_named(mode, fb_mode, charp, 0);
+MODULE_PARM_DESC(mode,
+       "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+module_param_named(bpp, default_bpp, ulong, 0);
+MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
 MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
 MODULE_DESCRIPTION("SM501 Framebuffer driver");
 MODULE_LICENSE("GPL v2");
index fdb45674e2f628b906e3997cf22eebe7c38f6711..33df9ec917951d1e48871af8f3a1edb8f8ccf319 100644 (file)
 
 
 /* Write a CRT register value spread across multiple registers */
-void svga_wcrt_multi(const struct vga_regset *regset, u32 value) {
-
+void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
+{
        u8 regval, bitval, bitnum;
 
        while (regset->regnum != VGA_REGSET_END_VAL) {
-               regval = vga_rcrt(NULL, regset->regnum);
+               regval = vga_rcrt(regbase, regset->regnum);
                bitnum = regset->lowbit;
                while (bitnum <= regset->highbit) {
                        bitval = 1 << bitnum;
@@ -34,18 +34,18 @@ void svga_wcrt_multi(const struct vga_regset *regset, u32 value) {
                        bitnum ++;
                        value = value >> 1;
                }
-               vga_wcrt(NULL, regset->regnum, regval);
+               vga_wcrt(regbase, regset->regnum, regval);
                regset ++;
        }
 }
 
 /* Write a sequencer register value spread across multiple registers */
-void svga_wseq_multi(const struct vga_regset *regset, u32 value) {
-
+void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
+{
        u8 regval, bitval, bitnum;
 
        while (regset->regnum != VGA_REGSET_END_VAL) {
-               regval = vga_rseq(NULL, regset->regnum);
+               regval = vga_rseq(regbase, regset->regnum);
                bitnum = regset->lowbit;
                while (bitnum <= regset->highbit) {
                        bitval = 1 << bitnum;
@@ -54,7 +54,7 @@ void svga_wseq_multi(const struct vga_regset *regset, u32 value) {
                        bitnum ++;
                        value = value >> 1;
                }
-               vga_wseq(NULL, regset->regnum, regval);
+               vga_wseq(regbase, regset->regnum, regval);
                regset ++;
        }
 }
@@ -75,95 +75,95 @@ static unsigned int svga_regset_size(const struct vga_regset *regset)
 
 
 /* Set graphics controller registers to sane values */
-void svga_set_default_gfx_regs(void)
+void svga_set_default_gfx_regs(void __iomem *regbase)
 {
        /* All standard GFX registers (GR00 - GR08) */
-       vga_wgfx(NULL, VGA_GFX_SR_VALUE, 0x00);
-       vga_wgfx(NULL, VGA_GFX_SR_ENABLE, 0x00);
-       vga_wgfx(NULL, VGA_GFX_COMPARE_VALUE, 0x00);
-       vga_wgfx(NULL, VGA_GFX_DATA_ROTATE, 0x00);
-       vga_wgfx(NULL, VGA_GFX_PLANE_READ, 0x00);
-       vga_wgfx(NULL, VGA_GFX_MODE, 0x00);
-/*     vga_wgfx(NULL, VGA_GFX_MODE, 0x20); */
-/*     vga_wgfx(NULL, VGA_GFX_MODE, 0x40); */
-       vga_wgfx(NULL, VGA_GFX_MISC, 0x05);
-/*     vga_wgfx(NULL, VGA_GFX_MISC, 0x01); */
-       vga_wgfx(NULL, VGA_GFX_COMPARE_MASK, 0x0F);
-       vga_wgfx(NULL, VGA_GFX_BIT_MASK, 0xFF);
+       vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00);
+       vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00);
+       vga_wgfx(regbase, VGA_GFX_MODE, 0x00);
+/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */
+/*     vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */
+       vga_wgfx(regbase, VGA_GFX_MISC, 0x05);
+/*     vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */
+       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F);
+       vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF);
 }
 
 /* Set attribute controller registers to sane values */
-void svga_set_default_atc_regs(void)
+void svga_set_default_atc_regs(void __iomem *regbase)
 {
        u8 count;
 
-       vga_r(NULL, 0x3DA);
-       vga_w(NULL, VGA_ATT_W, 0x00);
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x00);
 
        /* All standard ATC registers (AR00 - AR14) */
        for (count = 0; count <= 0xF; count ++)
-               svga_wattr(count, count);
+               svga_wattr(regbase, count, count);
 
-       svga_wattr(VGA_ATC_MODE, 0x01);
-/*     svga_wattr(VGA_ATC_MODE, 0x41); */
-       svga_wattr(VGA_ATC_OVERSCAN, 0x00);
-       svga_wattr(VGA_ATC_PLANE_ENABLE, 0x0F);
-       svga_wattr(VGA_ATC_PEL, 0x00);
-       svga_wattr(VGA_ATC_COLOR_PAGE, 0x00);
+       svga_wattr(regbase, VGA_ATC_MODE, 0x01);
+/*     svga_wattr(regbase, VGA_ATC_MODE, 0x41); */
+       svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00);
+       svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F);
+       svga_wattr(regbase, VGA_ATC_PEL, 0x00);
+       svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00);
 
-       vga_r(NULL, 0x3DA);
-       vga_w(NULL, VGA_ATT_W, 0x20);
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x20);
 }
 
 /* Set sequencer registers to sane values */
-void svga_set_default_seq_regs(void)
+void svga_set_default_seq_regs(void __iomem *regbase)
 {
        /* Standard sequencer registers (SR01 - SR04), SR00 is not set */
-       vga_wseq(NULL, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
-       vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
-       vga_wseq(NULL, VGA_SEQ_CHARACTER_MAP, 0x00);
-/*     vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
-       vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
+       vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
+       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
+       vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
+/*     vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
+       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
 }
 
 /* Set CRTC registers to sane values */
-void svga_set_default_crt_regs(void)
+void svga_set_default_crt_regs(void __iomem *regbase)
 {
        /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
-       svga_wcrt_mask(0x03, 0x80, 0x80);       /* Enable vertical retrace EVRA */
-       vga_wcrt(NULL, VGA_CRTC_PRESET_ROW, 0);
-       svga_wcrt_mask(VGA_CRTC_MAX_SCAN, 0, 0x1F);
-       vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0);
-       vga_wcrt(NULL, VGA_CRTC_MODE, 0xE3);
+       svga_wcrt_mask(regbase, 0x03, 0x80, 0x80);      /* Enable vertical retrace EVRA */
+       vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
+       svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F);
+       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
+       vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3);
 }
 
-void svga_set_textmode_vga_regs(void)
+void svga_set_textmode_vga_regs(void __iomem *regbase)
 {
-       /* svga_wseq_mask(0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */
-       vga_wseq(NULL, VGA_SEQ_MEMORY_MODE,     VGA_SR04_EXT_MEM);
-       vga_wseq(NULL, VGA_SEQ_PLANE_WRITE,     0x03);
+       /* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */
+       vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);
+       vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03);
 
-       vga_wcrt(NULL, VGA_CRTC_MAX_SCAN,       0x0f); /* 0x4f */
-       vga_wcrt(NULL, VGA_CRTC_UNDERLINE,      0x1f);
-       svga_wcrt_mask(VGA_CRTC_MODE,           0x23, 0x7f);
+       vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */
+       vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f);
+       svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f);
 
-       vga_wcrt(NULL, VGA_CRTC_CURSOR_START,   0x0d);
-       vga_wcrt(NULL, VGA_CRTC_CURSOR_END,     0x0e);
-       vga_wcrt(NULL, VGA_CRTC_CURSOR_HI,      0x00);
-       vga_wcrt(NULL, VGA_CRTC_CURSOR_LO,      0x00);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00);
+       vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00);
 
-       vga_wgfx(NULL, VGA_GFX_MODE,            0x10); /* Odd/even memory mode */
-       vga_wgfx(NULL, VGA_GFX_MISC,            0x0E); /* Misc graphics register - text mode enable */
-       vga_wgfx(NULL, VGA_GFX_COMPARE_MASK,    0x00);
+       vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */
+       vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */
+       vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00);
 
-       vga_r(NULL, 0x3DA);
-       vga_w(NULL, VGA_ATT_W, 0x00);
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x00);
 
-       svga_wattr(0x10, 0x0C);                 /* Attribute Mode Control Register - text mode, blinking and line graphics */
-       svga_wattr(0x13, 0x08);                 /* Horizontal Pixel Panning Register  */
+       svga_wattr(regbase, 0x10, 0x0C);                        /* Attribute Mode Control Register - text mode, blinking and line graphics */
+       svga_wattr(regbase, 0x13, 0x08);                        /* Horizontal Pixel Panning Register  */
 
-       vga_r(NULL, 0x3DA);
-       vga_w(NULL, VGA_ATT_W, 0x20);
+       vga_r(regbase, 0x3DA);
+       vga_w(regbase, VGA_ATT_W, 0x20);
 }
 
 #if 0
@@ -299,7 +299,7 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
 }
 
 /* Set cursor in text (tileblit) mode */
-void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
+void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor)
 {
        u8 cs = 0x0d;
        u8 ce = 0x0e;
@@ -310,7 +310,7 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
        if (! cursor -> mode)
                return;
 
-       svga_wcrt_mask(0x0A, 0x20, 0x20); /* disable cursor */
+       svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */
 
        if (cursor -> shape == FB_TILE_CURSOR_NONE)
                return;
@@ -334,11 +334,11 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
        }
 
        /* set cursor position */
-       vga_wcrt(NULL, 0x0E, pos >> 8);
-       vga_wcrt(NULL, 0x0F, pos & 0xFF);
+       vga_wcrt(regbase, 0x0E, pos >> 8);
+       vga_wcrt(regbase, 0x0F, pos & 0xFF);
 
-       vga_wcrt(NULL, 0x0B, ce); /* set cursor end */
-       vga_wcrt(NULL, 0x0A, cs); /* set cursor start and enable it */
+       vga_wcrt(regbase, 0x0B, ce); /* set cursor end */
+       vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */
 }
 
 int svga_get_tilemax(struct fb_info *info)
@@ -507,8 +507,9 @@ int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screenin
 }
 
 /* Set CRT timing registers */
-void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var,
-                       u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
+void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
+                     struct fb_var_screeninfo *var,
+                     u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
 {
        u8 regval;
        u32 value;
@@ -516,66 +517,66 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf
        value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal total      : %d\n", node, value);
-       svga_wcrt_multi(tm->h_total_regs, (value / 8) - 5);
+       svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5);
 
        value = var->xres;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal display    : %d\n", node, value);
-       svga_wcrt_multi(tm->h_display_regs, (value / 8) - 1);
+       svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1);
 
        value = var->xres;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal blank start: %d\n", node, value);
-       svga_wcrt_multi(tm->h_blank_start_regs, (value / 8) - 1 + hborder);
+       svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder);
 
        value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal blank end  : %d\n", node, value);
-       svga_wcrt_multi(tm->h_blank_end_regs, (value / 8) - 1 - hborder);
+       svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder);
 
        value = var->xres + var->right_margin;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal sync start : %d\n", node, value);
-       svga_wcrt_multi(tm->h_sync_start_regs, (value / 8));
+       svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8));
 
        value = var->xres + var->right_margin + var->hsync_len;
        value = (value * hmul) / hdiv;
        pr_debug("fb%d: horizontal sync end   : %d\n", node, value);
-       svga_wcrt_multi(tm->h_sync_end_regs, (value / 8));
+       svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8));
 
        value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical total        : %d\n", node, value);
-       svga_wcrt_multi(tm->v_total_regs, value - 2);
+       svga_wcrt_multi(regbase, tm->v_total_regs, value - 2);
 
        value = var->yres;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical display      : %d\n", node, value);
-       svga_wcrt_multi(tm->v_display_regs, value - 1);
+       svga_wcrt_multi(regbase, tm->v_display_regs, value - 1);
 
        value = var->yres;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical blank start  : %d\n", node, value);
-       svga_wcrt_multi(tm->v_blank_start_regs, value);
+       svga_wcrt_multi(regbase, tm->v_blank_start_regs, value);
 
        value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical blank end    : %d\n", node, value);
-       svga_wcrt_multi(tm->v_blank_end_regs, value - 2);
+       svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2);
 
        value = var->yres + var->lower_margin;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical sync start   : %d\n", node, value);
-       svga_wcrt_multi(tm->v_sync_start_regs, value);
+       svga_wcrt_multi(regbase, tm->v_sync_start_regs, value);
 
        value = var->yres + var->lower_margin + var->vsync_len;
        value = (value * vmul) / vdiv;
        pr_debug("fb%d: vertical sync end     : %d\n", node, value);
-       svga_wcrt_multi(tm->v_sync_end_regs, value);
+       svga_wcrt_multi(regbase, tm->v_sync_end_regs, value);
 
        /* Set horizontal and vertical sync pulse polarity in misc register */
 
-       regval = vga_r(NULL, VGA_MIS_R);
+       regval = vga_r(regbase, VGA_MIS_R);
        if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
                pr_debug("fb%d: positive horizontal sync\n", node);
                regval = regval & ~0x80;
@@ -590,7 +591,7 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf
                pr_debug("fb%d: negative vertical sync\n\n", node);
                regval = regval | 0x40;
        }
-       vga_w(NULL, VGA_MIS_W, regval);
+       vga_w(regbase, VGA_MIS_W, regval);
 }
 
 
index 855b71993f61f9cb0f10822c9dd810375178bcc5..07c66e9466343bec9b9f7cd0741698903d44e1e5 100644 (file)
@@ -480,6 +480,7 @@ out_dealloc_cmap:
 
 out_unmap_regs:
        tcx_unmap_regs(op, info, par);
+       framebuffer_release(info);
 
 out_err:
        return err;
index dfef88c803d45ec48129cb31236ad156231cfd4c..9710bf8caeaeb13db419928dffd3a0aa5c925fcb 100644 (file)
@@ -250,8 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
  */
 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 tmio_fb_data *data = mfd_get_data(dev);
        struct fb_info *info = platform_get_drvdata(dev);
        struct tmiofb_par *par = info->par;
 
@@ -268,7 +267,7 @@ static int tmiofb_hw_stop(struct platform_device *dev)
  */
 static int tmiofb_hw_init(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct fb_info *info = platform_get_drvdata(dev);
        struct tmiofb_par *par = info->par;
        const struct resource *nlcr = &cell->resources[0];
@@ -312,8 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev)
  */
 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 tmio_fb_data *data = mfd_get_data(dev);
        struct fb_info *info = platform_get_drvdata(dev);
        struct fb_videomode *mode = info->mode;
        struct tmiofb_par *par = info->par;
@@ -559,9 +557,8 @@ static int tmiofb_ioctl(struct fb_info *fbi,
 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 tmio_fb_data *data =
+                       mfd_get_data(to_platform_device(info->device));
        struct fb_videomode *best = NULL;
        int i;
 
@@ -581,9 +578,8 @@ 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;
+       struct tmio_fb_data *data =
+                       mfd_get_data(to_platform_device(info->device));
 
        mode = tmiofb_find_mode(info, var);
        if (!mode || var->bits_per_pixel > 16)
@@ -683,8 +679,8 @@ static struct fb_ops tmiofb_ops = {
 
 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;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
+       struct tmio_fb_data *data = mfd_get_data(dev);
        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);
@@ -811,7 +807,7 @@ err_ioremap_ccr:
 
 static int __devexit tmiofb_remove(struct platform_device *dev)
 {
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        struct fb_info *info = platform_get_drvdata(dev);
        int irq = platform_get_irq(dev, 0);
        struct tmiofb_par *par;
@@ -941,7 +937,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
 #ifdef CONFIG_FB_TMIO_ACCELL
        struct tmiofb_par *par = info->par;
 #endif
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        int retval = 0;
 
        console_lock();
@@ -973,7 +969,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
 static int tmiofb_resume(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
-       struct mfd_cell *cell = dev->dev.platform_data;
+       const struct mfd_cell *cell = mfd_get_cell(dev);
        int retval = 0;
 
        console_lock();
index 5180a215d781337912c4e71d6a8e0cdbdd35ba55..7f8472cc993b2908e2ebc695cac102242dccc921 100644 (file)
@@ -1552,8 +1552,7 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
                        int rc;
 
                        /* Find the largest power-of-two */
-                       while (temp_size & (temp_size - 1))
-                               temp_size &= (temp_size - 1);
+                       temp_size = roundup_pow_of_two(temp_size);
 
                        /* Try and find a power of two to add */
                        do {
@@ -1566,6 +1565,28 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
 #endif /* CONFIG_MTRR */
 }
 
+static void __devinit uvesafb_ioremap(struct fb_info *info)
+{
+#ifdef CONFIG_X86
+       switch (mtrr) {
+       case 1: /* uncachable */
+               info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 2: /* write-back */
+               info->screen_base = ioremap_cache(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 3: /* write-combining */
+               info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len);
+               break;
+       case 4: /* write-through */
+       default:
+               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+               break;
+       }
+#else
+       info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+#endif /* CONFIG_X86 */
+}
 
 static ssize_t uvesafb_show_vbe_ver(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -1736,15 +1757,22 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
 
        uvesafb_init_info(info, mode);
 
+       if (!request_region(0x3c0, 32, "uvesafb")) {
+               printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
+               err = -EIO;
+               goto out_mode;
+       }
+
        if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
                                "uvesafb")) {
                printk(KERN_ERR "uvesafb: cannot reserve video memory at "
                                "0x%lx\n", info->fix.smem_start);
                err = -EIO;
-               goto out_mode;
+               goto out_reg;
        }
 
-       info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+       uvesafb_init_mtrr(info);
+       uvesafb_ioremap(info);
 
        if (!info->screen_base) {
                printk(KERN_ERR
@@ -1755,20 +1783,13 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
                goto out_mem;
        }
 
-       if (!request_region(0x3c0, 32, "uvesafb")) {
-               printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
-               err = -EIO;
-               goto out_unmap;
-       }
-
-       uvesafb_init_mtrr(info);
        platform_set_drvdata(dev, info);
 
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR
                        "uvesafb: failed to register framebuffer device\n");
                err = -EINVAL;
-               goto out_reg;
+               goto out_unmap;
        }
 
        printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
@@ -1785,12 +1806,12 @@ static int __devinit uvesafb_probe(struct platform_device *dev)
 
        return 0;
 
-out_reg:
-       release_region(0x3c0, 32);
 out_unmap:
        iounmap(info->screen_base);
 out_mem:
        release_mem_region(info->fix.smem_start, info->fix.smem_len);
+out_reg:
+       release_region(0x3c0, 32);
 out_mode:
        if (!list_empty(&info->modelist))
                fb_destroy_modelist(&info->modelist);
index 931a567f9aff4219cf015f7855189725313b810b..970e43d13f52bdce1a4a5cfc4e782745ddf53657 100644 (file)
@@ -891,8 +891,7 @@ static int vmlfb_set_par(struct fb_info *info)
        int ret;
 
        mutex_lock(&vml_mutex);
-       list_del(&vinfo->head);
-       list_add(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
+       list_move(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
        ret = vmlfb_set_par_locked(vinfo);
 
        mutex_unlock(&vml_mutex);
index 6a069d04791415088f8b14d40f658279815cf721..a99bbe86db13d77183ac258333435c6be56ce187 100644 (file)
@@ -303,19 +303,6 @@ static int __init vesafb_probe(struct platform_device *dev)
        info->apertures->ranges[0].base = screen_info.lfb_base;
        info->apertures->ranges[0].size = size_total;
 
-       info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
-       if (!info->screen_base) {
-               printk(KERN_ERR
-                      "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
-                       vesafb_fix.smem_len, vesafb_fix.smem_start);
-               err = -EIO;
-               goto err;
-       }
-
-       printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
-              "using %dk, total %dk\n",
-              vesafb_fix.smem_start, info->screen_base,
-              size_remap/1024, size_total/1024);
        printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
               vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
 
@@ -438,8 +425,7 @@ static int __init vesafb_probe(struct platform_device *dev)
                        int rc;
 
                        /* Find the largest power-of-two */
-                       while (temp_size & (temp_size - 1))
-                               temp_size &= (temp_size - 1);
+                       temp_size = roundup_pow_of_two(temp_size);
 
                        /* Try and find a power of two to add */
                        do {
@@ -451,6 +437,34 @@ static int __init vesafb_probe(struct platform_device *dev)
        }
 #endif
        
+       switch (mtrr) {
+       case 1: /* uncachable */
+               info->screen_base = ioremap_nocache(vesafb_fix.smem_start, vesafb_fix.smem_len);
+               break;
+       case 2: /* write-back */
+               info->screen_base = ioremap_cache(vesafb_fix.smem_start, vesafb_fix.smem_len);
+               break;
+       case 3: /* write-combining */
+               info->screen_base = ioremap_wc(vesafb_fix.smem_start, vesafb_fix.smem_len);
+               break;
+       case 4: /* write-through */
+       default:
+               info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
+               break;
+       }
+       if (!info->screen_base) {
+               printk(KERN_ERR
+                      "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+                       vesafb_fix.smem_len, vesafb_fix.smem_start);
+               err = -EIO;
+               goto err;
+       }
+
+       printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
+              "using %dk, total %dk\n",
+              vesafb_fix.smem_start, info->screen_base,
+              size_remap/1024, size_total/1024);
+
        info->fbops = &vesafb_ops;
        info->var = vesafb_defined;
        info->fix = vesafb_fix;
index d66f963e930e3d2791e004b120b6a98b8b5dec92..137996dc547e98ffd7c12470a2bdfa2c296b02d7 100644 (file)
@@ -94,9 +94,6 @@ extern int viafb_LCD_ON;
 extern int viafb_DVI_ON;
 extern int viafb_hotplug;
 
-extern int strict_strtoul(const char *cp, unsigned int base,
-       unsigned long *res);
-
 u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
        *plvds_setting_info, struct lvds_chip_information
        *plvds_chip_info, u8 index);
index a2965ab92cfb815a289b21d8a30884e32db8c999..f9b3e3dc24219fcdabcf9235a95720292c107c12 100644 (file)
@@ -121,13 +121,19 @@ MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, d
 
 /* ------------------------------------------------------------------------- */
 
+static void vt8623fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
+{
+       struct vt8623fb_info *par = info->par;
+
+       svga_tilecursor(par->state.vgabase, info, cursor);
+}
 
 static struct fb_tile_ops vt8623fb_tile_ops = {
        .fb_settile     = svga_settile,
        .fb_tilecopy    = svga_tilecopy,
        .fb_tilefill    = svga_tilefill,
        .fb_tileblit    = svga_tileblit,
-       .fb_tilecursor  = svga_tilecursor,
+       .fb_tilecursor  = vt8623fb_tilecursor,
        .fb_get_tilemax = svga_get_tilemax,
 };
 
@@ -253,6 +259,7 @@ static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *re
 
 static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
 {
+       struct vt8623fb_info *par = info->par;
        u16 m, n, r;
        u8 regval;
        int rv;
@@ -264,18 +271,18 @@ static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
        }
 
        /* Set VGA misc register  */
-       regval = vga_r(NULL, VGA_MIS_R);
-       vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+       regval = vga_r(par->state.vgabase, VGA_MIS_R);
+       vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
 
        /* Set clock registers */
-       vga_wseq(NULL, 0x46, (n  | (r << 6)));
-       vga_wseq(NULL, 0x47, m);
+       vga_wseq(par->state.vgabase, 0x46, (n  | (r << 6)));
+       vga_wseq(par->state.vgabase, 0x47, m);
 
        udelay(1000);
 
        /* PLL reset */
-       svga_wseq_mask(0x40, 0x02, 0x02);
-       svga_wseq_mask(0x40, 0x00, 0x02);
+       svga_wseq_mask(par->state.vgabase, 0x40, 0x02, 0x02);
+       svga_wseq_mask(par->state.vgabase, 0x40, 0x00, 0x02);
 }
 
 
@@ -285,7 +292,10 @@ static int vt8623fb_open(struct fb_info *info, int user)
 
        mutex_lock(&(par->open_lock));
        if (par->ref_count == 0) {
+               void __iomem *vgabase = par->state.vgabase;
+
                memset(&(par->state), 0, sizeof(struct vgastate));
+               par->state.vgabase = vgabase;
                par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
                par->state.num_crtc = 0xA2;
                par->state.num_seq = 0x50;
@@ -373,6 +383,7 @@ static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *inf
 static int vt8623fb_set_par(struct fb_info *info)
 {
        u32 mode, offset_value, fetch_value, screen_size;
+       struct vt8623fb_info *par = info->par;
        u32 bpp = info->var.bits_per_pixel;
 
        if (bpp != 0) {
@@ -414,82 +425,82 @@ static int vt8623fb_set_par(struct fb_info *info)
        info->var.activate = FB_ACTIVATE_NOW;
 
        /* Unlock registers */
-       svga_wseq_mask(0x10, 0x01, 0x01);
-       svga_wcrt_mask(0x11, 0x00, 0x80);
-       svga_wcrt_mask(0x47, 0x00, 0x01);
+       svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01);
+       svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
+       svga_wcrt_mask(par->state.vgabase, 0x47, 0x00, 0x01);
 
        /* Device, screen and sync off */
-       svga_wseq_mask(0x01, 0x20, 0x20);
-       svga_wcrt_mask(0x36, 0x30, 0x30);
-       svga_wcrt_mask(0x17, 0x00, 0x80);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
 
        /* Set default values */
-       svga_set_default_gfx_regs();
-       svga_set_default_atc_regs();
-       svga_set_default_seq_regs();
-       svga_set_default_crt_regs();
-       svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
-       svga_wcrt_multi(vt8623_start_address_regs, 0);
+       svga_set_default_gfx_regs(par->state.vgabase);
+       svga_set_default_atc_regs(par->state.vgabase);
+       svga_set_default_seq_regs(par->state.vgabase);
+       svga_set_default_crt_regs(par->state.vgabase);
+       svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF);
+       svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0);
 
-       svga_wcrt_multi(vt8623_offset_regs, offset_value);
-       svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+       svga_wcrt_multi(par->state.vgabase, vt8623_offset_regs, offset_value);
+       svga_wseq_multi(par->state.vgabase, vt8623_fetch_count_regs, fetch_value);
 
        /* Clear H/V Skew */
-       svga_wcrt_mask(0x03, 0x00, 0x60);
-       svga_wcrt_mask(0x05, 0x00, 0x60);
+       svga_wcrt_mask(par->state.vgabase, 0x03, 0x00, 0x60);
+       svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60);
 
        if (info->var.vmode & FB_VMODE_DOUBLE)
-               svga_wcrt_mask(0x09, 0x80, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80);
        else
-               svga_wcrt_mask(0x09, 0x00, 0x80);
+               svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80);
 
-       svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
-       svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
-       svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read threshold
-       vga_wseq(NULL, 0x17, 0x1F);       // FIFO depth
-       vga_wseq(NULL, 0x18, 0x4E);
-       svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+       svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0); // DI/DVP bus
+       svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F); // DI/DVP bus
+       svga_wseq_mask(par->state.vgabase, 0x16, 0x08, 0xBF); // FIFO read threshold
+       vga_wseq(par->state.vgabase, 0x17, 0x1F);       // FIFO depth
+       vga_wseq(par->state.vgabase, 0x18, 0x4E);
+       svga_wseq_mask(par->state.vgabase, 0x1A, 0x08, 0x08); // enable MMIO ?
 
-       vga_wcrt(NULL, 0x32, 0x00);
-       vga_wcrt(NULL, 0x34, 0x00);
-       vga_wcrt(NULL, 0x6A, 0x80);
-       vga_wcrt(NULL, 0x6A, 0xC0);
+       vga_wcrt(par->state.vgabase, 0x32, 0x00);
+       vga_wcrt(par->state.vgabase, 0x34, 0x00);
+       vga_wcrt(par->state.vgabase, 0x6A, 0x80);
+       vga_wcrt(par->state.vgabase, 0x6A, 0xC0);
 
-       vga_wgfx(NULL, 0x20, 0x00);
-       vga_wgfx(NULL, 0x21, 0x00);
-       vga_wgfx(NULL, 0x22, 0x00);
+       vga_wgfx(par->state.vgabase, 0x20, 0x00);
+       vga_wgfx(par->state.vgabase, 0x21, 0x00);
+       vga_wgfx(par->state.vgabase, 0x22, 0x00);
 
        /* Set SR15 according to number of bits per pixel */
        mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
        switch (mode) {
        case 0:
                pr_debug("fb%d: text mode\n", info->node);
-               svga_set_textmode_vga_regs();
-               svga_wseq_mask(0x15, 0x00, 0xFE);
-               svga_wcrt_mask(0x11, 0x60, 0x70);
+               svga_set_textmode_vga_regs(par->state.vgabase);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE);
+               svga_wcrt_mask(par->state.vgabase, 0x11, 0x60, 0x70);
                break;
        case 1:
                pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
-               vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
-               svga_wseq_mask(0x15, 0x20, 0xFE);
-               svga_wcrt_mask(0x11, 0x00, 0x70);
+               vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE);
+               svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70);
                break;
        case 2:
                pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
-               svga_wseq_mask(0x15, 0x00, 0xFE);
-               svga_wcrt_mask(0x11, 0x00, 0x70);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE);
+               svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70);
                break;
        case 3:
                pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
-               svga_wseq_mask(0x15, 0x22, 0xFE);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0x22, 0xFE);
                break;
        case 4:
                pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
-               svga_wseq_mask(0x15, 0xB6, 0xFE);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0xB6, 0xFE);
                break;
        case 5:
                pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
-               svga_wseq_mask(0x15, 0xAE, 0xFE);
+               svga_wseq_mask(par->state.vgabase, 0x15, 0xAE, 0xFE);
                break;
        default:
                printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
@@ -497,16 +508,16 @@ static int vt8623fb_set_par(struct fb_info *info)
        }
 
        vt8623_set_pixclock(info, info->var.pixclock);
-       svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+       svga_set_timings(par->state.vgabase, &vt8623_timing_regs, &(info->var), 1, 1,
                         (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
                         1, info->node);
 
        memset_io(info->screen_base, 0x00, screen_size);
 
        /* Device and screen back on */
-       svga_wcrt_mask(0x17, 0x80, 0x80);
-       svga_wcrt_mask(0x36, 0x00, 0x30);
-       svga_wseq_mask(0x01, 0x00, 0x20);
+       svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
+       svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
+       svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
 
        return 0;
 }
@@ -569,31 +580,33 @@ static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
 static int vt8623fb_blank(int blank_mode, struct fb_info *info)
 {
+       struct vt8623fb_info *par = info->par;
+
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
                pr_debug("fb%d: unblank\n", info->node);
-               svga_wcrt_mask(0x36, 0x00, 0x30);
-               svga_wseq_mask(0x01, 0x00, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
                break;
        case FB_BLANK_NORMAL:
                pr_debug("fb%d: blank\n", info->node);
-               svga_wcrt_mask(0x36, 0x00, 0x30);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_HSYNC_SUSPEND:
                pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
-               svga_wcrt_mask(0x36, 0x10, 0x30);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x36, 0x10, 0x30);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_VSYNC_SUSPEND:
                pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
-               svga_wcrt_mask(0x36, 0x20, 0x30);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x36, 0x20, 0x30);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        case FB_BLANK_POWERDOWN:
                pr_debug("fb%d: DPMS off (no sync)\n", info->node);
-               svga_wcrt_mask(0x36, 0x30, 0x30);
-               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30);
+               svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
                break;
        }
 
@@ -603,6 +616,7 @@ static int vt8623fb_blank(int blank_mode, struct fb_info *info)
 
 static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+       struct vt8623fb_info *par = info->par;
        unsigned int offset;
 
        /* Calculate the offset */
@@ -616,7 +630,7 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i
        }
 
        /* Set the offset */
-       svga_wcrt_multi(vt8623_start_address_regs, offset);
+       svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, offset);
 
        return 0;
 }
@@ -647,6 +661,8 @@ static struct fb_ops vt8623fb_ops = {
 
 static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
+       struct pci_bus_region bus_reg;
+       struct resource vga_res;
        struct fb_info *info;
        struct vt8623fb_info *par;
        unsigned int memsize1, memsize2;
@@ -705,9 +721,18 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
                goto err_iomap_2;
        }
 
+       bus_reg.start = 0;
+       bus_reg.end = 64 * 1024;
+
+       vga_res.flags = IORESOURCE_IO;
+
+       pcibios_bus_to_resource(dev, &vga_res, &bus_reg);
+
+       par->state.vgabase = (void __iomem *) vga_res.start;
+
        /* Find how many physical memory there is on card */
-       memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
-       memsize2 = vga_rseq(NULL, 0x39) << 2;
+       memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;
+       memsize2 = vga_rseq(par->state.vgabase, 0x39) << 2;
 
        if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
                info->screen_size = memsize1 << 20;
index 6b85e7fefa43c52a5636b8a9ec41fb8c30503418..95921b77cf8650068f2641816f267eb97da9acfc 100644 (file)
@@ -90,7 +90,7 @@ struct ds1wm_data {
        void            __iomem *map;
        int             bus_shift; /* # of shifts to calc register offsets */
        struct platform_device *pdev;
-       struct mfd_cell *cell;
+       const struct mfd_cell *cell;
        int             irq;
        int             active_high;
        int             slave_present;
@@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk)
 static void ds1wm_up(struct ds1wm_data *ds1wm_data)
 {
        int divisor;
-       struct ds1wm_driver_data *plat = ds1wm_data->cell->driver_data;
+       struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev);
 
        if (ds1wm_data->cell->enable)
                ds1wm_data->cell->enable(ds1wm_data->pdev);
@@ -330,16 +330,11 @@ static int ds1wm_probe(struct platform_device *pdev)
        struct ds1wm_data *ds1wm_data;
        struct ds1wm_driver_data *plat;
        struct resource *res;
-       struct mfd_cell *cell;
        int ret;
 
        if (!pdev)
                return -ENODEV;
 
-       cell = pdev->dev.platform_data;
-       if (!cell)
-               return -ENODEV;
-
        ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL);
        if (!ds1wm_data)
                return -ENOMEM;
@@ -356,13 +351,13 @@ static int ds1wm_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err0;
        }
-       plat = cell->driver_data;
+       plat = mfd_get_data(pdev);
 
        /* calculate bus shift from mem resource */
        ds1wm_data->bus_shift = resource_size(res) >> 3;
 
        ds1wm_data->pdev = pdev;
-       ds1wm_data->cell = cell;
+       ds1wm_data->cell = mfd_get_cell(pdev);
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
index 3939e53f5f981d327ff344d522ab59f4df43238b..d8e725082fdc1c103d66f91eab6694e65af18c06 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/mfd/rdc321x.h>
+#include <linux/mfd/core.h>
 
 #define RDC_WDT_MASK   0x80000000 /* Mask */
 #define RDC_WDT_EN     0x00800000 /* Enable bit */
@@ -231,7 +232,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
        struct resource *r;
        struct rdc321x_wdt_pdata *pdata;
 
-       pdata = platform_get_drvdata(pdev);
+       pdata = mfd_get_data(pdev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                return -ENODEV;
index 515455296378324b6d0aadbe0314dd2bd0716337..535ab6eccb1a8de6090ff94448a3bf044d1b6514 100644 (file)
@@ -262,7 +262,7 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
        if (strcmp(name, "") != 0)
                return -EINVAL;
 
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        /*
         * We allow set/get/list of acl when access=client is not specified
         */
@@ -312,7 +312,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
        if (strcmp(name, "") != 0)
                return -EINVAL;
 
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        /*
         * set the attribute on the remote. Without even looking at the
         * xattr value. We leave it to the server to validate
@@ -323,7 +323,7 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
        if (value) {
                /* update the cached acl value */
index cd63e002d826b18fbacff41577753fea62f5f37b..0ee594569dcceb60f4ff795f48fe83c87003fd47 100644 (file)
@@ -134,7 +134,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
        struct v9fs_session_info *v9ses;
        struct p9_fid *fid, *old_fid = NULL;
 
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        access = v9ses->flags & V9FS_ACCESS_MASK;
        fid = v9fs_fid_find(dentry, uid, any);
        if (fid)
@@ -237,7 +237,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
        int  any, access;
        struct v9fs_session_info *v9ses;
 
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        access = v9ses->flags & V9FS_ACCESS_MASK;
        switch (access) {
        case V9FS_ACCESS_SINGLE:
@@ -286,9 +286,11 @@ static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid)
 
 struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
 {
-       int err;
+       int err, flags;
        struct p9_fid *fid;
+       struct v9fs_session_info *v9ses;
 
+       v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_clone_with_uid(dentry, 0);
        if (IS_ERR(fid))
                goto error_out;
@@ -297,8 +299,17 @@ struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
         * dirty pages. We always request for the open fid in read-write
         * mode so that a partial page write which result in page
         * read can work.
+        *
+        * we don't have a tsyncfs operation for older version
+        * of protocol. So make sure the write back fid is
+        * opened in O_SYNC mode.
         */
-       err = p9_client_open(fid, O_RDWR);
+       if (!v9fs_proto_dotl(v9ses))
+               flags = O_RDWR | O_SYNC;
+       else
+               flags = O_RDWR;
+
+       err = p9_client_open(fid, flags);
        if (err < 0) {
                p9_client_clunk(fid);
                fid = ERR_PTR(err);
index bd8496db135b4846068915396dd6c8d6fb2ade90..9665c2b840e6442a11b550f59da6ddf0ed73f256 100644 (file)
@@ -130,6 +130,7 @@ struct v9fs_inode {
 #endif
        unsigned int cache_validity;
        struct p9_fid *writeback_fid;
+       struct mutex v_mutex;
        struct inode vfs_inode;
 };
 
@@ -173,6 +174,11 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
        return (inode->i_sb->s_fs_info);
 }
 
+static inline struct v9fs_session_info *v9fs_dentry2v9ses(struct dentry *dentry)
+{
+       return dentry->d_sb->s_fs_info;
+}
+
 static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses)
 {
        return v9ses->flags & V9FS_PROTO_2000U;
index 78bcb97c3425c5225ab03d8c8802c9d0e6b0d426..ffed55817f0cd8f5cd1f6560e66805935419835a 100644 (file)
@@ -90,7 +90,9 @@ int v9fs_file_open(struct inode *inode, struct file *file)
        }
 
        file->private_data = fid;
-       if (v9ses->cache && !v9inode->writeback_fid) {
+       mutex_lock(&v9inode->v_mutex);
+       if (v9ses->cache && !v9inode->writeback_fid &&
+           ((file->f_flags & O_ACCMODE) != O_RDONLY)) {
                /*
                 * clone a fid and add it to writeback_fid
                 * we do it during open time instead of
@@ -101,10 +103,12 @@ int v9fs_file_open(struct inode *inode, struct file *file)
                fid = v9fs_writeback_fid(file->f_path.dentry);
                if (IS_ERR(fid)) {
                        err = PTR_ERR(fid);
+                       mutex_unlock(&v9inode->v_mutex);
                        goto out_error;
                }
                v9inode->writeback_fid = (void *) fid;
        }
+       mutex_unlock(&v9inode->v_mutex);
 #ifdef CONFIG_9P_FSCACHE
        if (v9ses->cache)
                v9fs_cache_inode_set_cookie(inode, file);
@@ -504,9 +508,12 @@ v9fs_file_write(struct file *filp, const char __user * data,
        if (!count)
                goto out;
 
-       return v9fs_file_write_internal(filp->f_path.dentry->d_inode,
+       retval = v9fs_file_write_internal(filp->f_path.dentry->d_inode,
                                        filp->private_data,
-                                       data, count, offset, 1);
+                                       data, count, &origin, 1);
+       /* update offset on successful write */
+       if (retval > 0)
+               *offset = origin;
 out:
        return retval;
 }
index 8a2c232f708a022d44d72522544697d84233aa08..7f6c6770319538c3094f7b26eb40fc18a398475d 100644 (file)
@@ -221,6 +221,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
 #endif
        v9inode->writeback_fid = NULL;
        v9inode->cache_validity = 0;
+       mutex_init(&v9inode->v_mutex);
        return &v9inode->vfs_inode;
 }
 
@@ -650,7 +651,9 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
        /* if we are opening a file, assign the open fid to the file */
        if (nd && nd->flags & LOOKUP_OPEN) {
                v9inode = V9FS_I(dentry->d_inode);
-               if (v9ses->cache && !v9inode->writeback_fid) {
+               mutex_lock(&v9inode->v_mutex);
+               if (v9ses->cache && !v9inode->writeback_fid &&
+                   ((flags & O_ACCMODE) != O_RDONLY)) {
                        /*
                         * clone a fid and add it to writeback_fid
                         * we do it during open time instead of
@@ -661,10 +664,12 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
                        inode_fid = v9fs_writeback_fid(dentry);
                        if (IS_ERR(inode_fid)) {
                                err = PTR_ERR(inode_fid);
+                               mutex_unlock(&v9inode->v_mutex);
                                goto error;
                        }
                        v9inode->writeback_fid = (void *) inode_fid;
                }
+               mutex_unlock(&v9inode->v_mutex);
                filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
                if (IS_ERR(filp)) {
                        err = PTR_ERR(filp);
@@ -931,7 +936,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 
        P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
        err = -EPERM;
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
                generic_fillattr(dentry->d_inode, stat);
                return 0;
@@ -967,8 +972,12 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
        struct p9_wstat wstat;
 
        P9_DPRINTK(P9_DEBUG_VFS, "\n");
+       retval = inode_change_ok(dentry->d_inode, iattr);
+       if (retval)
+               return retval;
+
        retval = -EPERM;
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_lookup(dentry);
        if(IS_ERR(fid))
                return PTR_ERR(fid);
@@ -993,12 +1002,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
                if (iattr->ia_valid & ATTR_GID)
                        wstat.n_gid = iattr->ia_gid;
        }
-       if ((iattr->ia_valid & ATTR_SIZE) &&
-           iattr->ia_size != i_size_read(dentry->d_inode)) {
-               retval = vmtruncate(dentry->d_inode, iattr->ia_size);
-               if (retval)
-                       return retval;
-       }
+
        /* Write all dirty data */
        if (S_ISREG(dentry->d_inode->i_mode))
                filemap_write_and_wait(dentry->d_inode->i_mapping);
@@ -1006,6 +1010,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
        retval = p9_client_wstat(fid, &wstat);
        if (retval < 0)
                return retval;
+
+       if ((iattr->ia_valid & ATTR_SIZE) &&
+           iattr->ia_size != i_size_read(dentry->d_inode))
+               truncate_setsize(dentry->d_inode, iattr->ia_size);
+
        v9fs_invalidate_inode_attr(dentry->d_inode);
 
        setattr_copy(dentry->d_inode, iattr);
@@ -1130,7 +1139,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
 
        P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
        retval = -EPERM;
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
                return PTR_ERR(fid);
index 67c138e94feb6f8d64ea78cba9d32c9aa0afd7fa..ffbb113d5f33537892fd001dd0d75af9e6d1fd69 100644 (file)
@@ -245,7 +245,9 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        v9fs_set_create_acl(dentry, dacl, pacl);
 
        v9inode = V9FS_I(inode);
-       if (v9ses->cache && !v9inode->writeback_fid) {
+       mutex_lock(&v9inode->v_mutex);
+       if (v9ses->cache && !v9inode->writeback_fid &&
+           ((flags & O_ACCMODE) != O_RDONLY)) {
                /*
                 * clone a fid and add it to writeback_fid
                 * we do it during open time instead of
@@ -256,10 +258,12 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                inode_fid = v9fs_writeback_fid(dentry);
                if (IS_ERR(inode_fid)) {
                        err = PTR_ERR(inode_fid);
+                       mutex_unlock(&v9inode->v_mutex);
                        goto error;
                }
                v9inode->writeback_fid = (void *) inode_fid;
        }
+       mutex_unlock(&v9inode->v_mutex);
        /* Since we are opening a file, assign the open fid to the file */
        filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
        if (IS_ERR(filp)) {
@@ -391,7 +395,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
 
        P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
        err = -EPERM;
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
                generic_fillattr(dentry->d_inode, stat);
                return 0;
@@ -448,17 +452,11 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
        p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
 
        retval = -EPERM;
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
                return PTR_ERR(fid);
 
-       if ((iattr->ia_valid & ATTR_SIZE) &&
-           iattr->ia_size != i_size_read(dentry->d_inode)) {
-               retval = vmtruncate(dentry->d_inode, iattr->ia_size);
-               if (retval)
-                       return retval;
-       }
        /* Write all dirty data */
        if (S_ISREG(dentry->d_inode->i_mode))
                filemap_write_and_wait(dentry->d_inode->i_mapping);
@@ -466,8 +464,12 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
        retval = p9_client_setattr(fid, &p9attr);
        if (retval < 0)
                return retval;
-       v9fs_invalidate_inode_attr(dentry->d_inode);
 
+       if ((iattr->ia_valid & ATTR_SIZE) &&
+           iattr->ia_size != i_size_read(dentry->d_inode))
+               truncate_setsize(dentry->d_inode, iattr->ia_size);
+
+       v9fs_invalidate_inode_attr(dentry->d_inode);
        setattr_copy(dentry->d_inode, iattr);
        mark_inode_dirty(dentry->d_inode);
        if (iattr->ia_valid & ATTR_MODE) {
index 09fd08d1606fb5bf97b05de78722e74eb7f4b710..f3eed3383e4fdeb87dddc890ad732925f0245319 100644 (file)
@@ -262,7 +262,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
                goto done;
        }
 
-       v9ses = v9fs_inode2v9ses(dentry->d_inode);
+       v9ses = v9fs_dentry2v9ses(dentry);
        if (v9fs_proto_dotl(v9ses)) {
                res = p9_client_statfs(fid, &rs);
                if (res == 0) {
index 2ff622f6f547f5f01d661150e7e41939aa029cc3..718ac1f440c6729c334b800375d853a5bd107366 100644 (file)
@@ -50,6 +50,7 @@ struct adfs_sb_info {
        gid_t           s_gid;          /* owner gid                             */
        umode_t         s_owner_mask;   /* ADFS owner perm -> unix perm          */
        umode_t         s_other_mask;   /* ADFS other perm -> unix perm          */
+       int             s_ftsuffix;     /* ,xyz hex filetype suffix option */
 
        __u32           s_ids_per_zone; /* max. no ids in one zone               */
        __u32           s_idlen;        /* length of ID in map                   */
@@ -79,6 +80,10 @@ struct adfs_dir {
 
        int                     nr_buffers;
        struct buffer_head      *bh[4];
+
+       /* big directories need allocated buffers */
+       struct buffer_head      **bh_fplus;
+
        unsigned int            pos;
        unsigned int            parent_id;
 
@@ -89,7 +94,7 @@ struct adfs_dir {
 /*
  * This is the overall maximum name length
  */
-#define ADFS_MAX_NAME_LEN      256
+#define ADFS_MAX_NAME_LEN      (256 + 4) /* +4 for ,xyz hex filetype suffix */
 struct object_info {
        __u32           parent_id;              /* parent object id     */
        __u32           file_id;                /* object id            */
@@ -97,10 +102,26 @@ struct object_info {
        __u32           execaddr;               /* execution address    */
        __u32           size;                   /* size                 */
        __u8            attr;                   /* RISC OS attributes   */
-       unsigned char   name_len;               /* name length          */
+       unsigned int    name_len;               /* name length          */
        char            name[ADFS_MAX_NAME_LEN];/* file name            */
+
+       /* RISC OS file type (12-bit: derived from loadaddr) */
+       __u16           filetype;
 };
 
+/* RISC OS 12-bit filetype converts to ,xyz hex filename suffix */
+static inline int append_filetype_suffix(char *buf, __u16 filetype)
+{
+       if (filetype == 0xffff) /* no explicit 12-bit file type was set */
+               return 0;
+
+       *buf++ = ',';
+       *buf++ = hex_asc_lo(filetype >> 8);
+       *buf++ = hex_asc_lo(filetype >> 4);
+       *buf++ = hex_asc_lo(filetype >> 0);
+       return 4;
+}
+
 struct adfs_dir_ops {
        int     (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir);
        int     (*setpos)(struct adfs_dir *dir, unsigned int fpos);
index bafc71222e25666370a201b9f45ca5e35b3ba391..4bbe853ee50a1ee8931470802a6581139f16257f 100644 (file)
@@ -52,7 +52,6 @@ static inline int adfs_readname(char *buf, char *ptr, int maxlen)
                        *buf++ = *ptr;
                ptr++;
        }
-       *buf = '\0';
 
        return buf - old_buf;
 }
@@ -208,7 +207,8 @@ release_buffers:
  * convert a disk-based directory entry to a Linux ADFS directory entry
  */
 static inline void
-adfs_dir2obj(struct object_info *obj, struct adfs_direntry *de)
+adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj,
+       struct adfs_direntry *de)
 {
        obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN);
        obj->file_id  = adfs_readval(de->dirinddiscadd, 3);
@@ -216,6 +216,23 @@ adfs_dir2obj(struct object_info *obj, struct adfs_direntry *de)
        obj->execaddr = adfs_readval(de->direxec, 4);
        obj->size     = adfs_readval(de->dirlen,  4);
        obj->attr     = de->newdiratts;
+       obj->filetype = -1;
+
+       /*
+        * object is a file and is filetyped and timestamped?
+        * RISC OS 12-bit filetype is stored in load_address[19:8]
+        */
+       if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
+               (0xfff00000 == (0xfff00000 & obj->loadaddr))) {
+               obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
+
+               /* optionally append the ,xyz hex filetype suffix */
+               if (ADFS_SB(dir->sb)->s_ftsuffix)
+                       obj->name_len +=
+                               append_filetype_suffix(
+                                       &obj->name[obj->name_len],
+                                       obj->filetype);
+       }
 }
 
 /*
@@ -260,7 +277,7 @@ __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
        if (!de.dirobname[0])
                return -ENOENT;
 
-       adfs_dir2obj(obj, &de);
+       adfs_dir2obj(dir, obj, &de);
 
        return 0;
 }
index 1796bb352d0541843043ba1e96bbee44dc36f381..d9e3bee4e653ff2c6df48006ddcdb3119082233a 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/buffer_head.h>
+#include <linux/slab.h>
 #include "adfs.h"
 #include "dir_fplus.h"
 
@@ -22,30 +23,53 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
 
        dir->nr_buffers = 0;
 
+       /* start off using fixed bh set - only alloc for big dirs */
+       dir->bh_fplus = &dir->bh[0];
+
        block = __adfs_block_map(sb, id, 0);
        if (!block) {
                adfs_error(sb, "dir object %X has a hole at offset 0", id);
                goto out;
        }
 
-       dir->bh[0] = sb_bread(sb, block);
-       if (!dir->bh[0])
+       dir->bh_fplus[0] = sb_bread(sb, block);
+       if (!dir->bh_fplus[0])
                goto out;
        dir->nr_buffers += 1;
 
-       h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+       h = (struct adfs_bigdirheader *)dir->bh_fplus[0]->b_data;
        size = le32_to_cpu(h->bigdirsize);
        if (size != sz) {
-               printk(KERN_WARNING "adfs: adfs_fplus_read: directory header size\n"
-                               " does not match directory size\n");
+               printk(KERN_WARNING "adfs: adfs_fplus_read:"
+                                       " directory header size %X\n"
+                                       " does not match directory size %X\n",
+                                       size, sz);
        }
 
        if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
            h->bigdirversion[2] != 0 || size & 2047 ||
-           h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME))
+           h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME)) {
+               printk(KERN_WARNING "adfs: dir object %X has"
+                                       " malformed dir header\n", id);
                goto out;
+       }
 
        size >>= sb->s_blocksize_bits;
+       if (size > sizeof(dir->bh)/sizeof(dir->bh[0])) {
+               /* this directory is too big for fixed bh set, must allocate */
+               struct buffer_head **bh_fplus =
+                       kzalloc(size * sizeof(struct buffer_head *),
+                               GFP_KERNEL);
+               if (!bh_fplus) {
+                       adfs_error(sb, "not enough memory for"
+                                       " dir object %X (%d blocks)", id, size);
+                       goto out;
+               }
+               dir->bh_fplus = bh_fplus;
+               /* copy over the pointer to the block that we've already read */
+               dir->bh_fplus[0] = dir->bh[0];
+       }
+
        for (blk = 1; blk < size; blk++) {
                block = __adfs_block_map(sb, id, blk);
                if (!block) {
@@ -53,25 +77,44 @@ adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct
                        goto out;
                }
 
-               dir->bh[blk] = sb_bread(sb, block);
-               if (!dir->bh[blk])
+               dir->bh_fplus[blk] = sb_bread(sb, block);
+               if (!dir->bh_fplus[blk]) {
+                       adfs_error(sb,  "dir object %X failed read for"
+                                       " offset %d, mapped block %X",
+                                       id, blk, block);
                        goto out;
-               dir->nr_buffers = blk;
+               }
+
+               dir->nr_buffers += 1;
        }
 
-       t = (struct adfs_bigdirtail *)(dir->bh[size - 1]->b_data + (sb->s_blocksize - 8));
+       t = (struct adfs_bigdirtail *)
+               (dir->bh_fplus[size - 1]->b_data + (sb->s_blocksize - 8));
 
        if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
            t->bigdirendmasseq != h->startmasseq ||
-           t->reserved[0] != 0 || t->reserved[1] != 0)
+           t->reserved[0] != 0 || t->reserved[1] != 0) {
+               printk(KERN_WARNING "adfs: dir object %X has "
+                                       "malformed dir end\n", id);
                goto out;
+       }
 
        dir->parent_id = le32_to_cpu(h->bigdirparent);
        dir->sb = sb;
        return 0;
+
 out:
-       for (i = 0; i < dir->nr_buffers; i++)
-               brelse(dir->bh[i]);
+       if (dir->bh_fplus) {
+               for (i = 0; i < dir->nr_buffers; i++)
+                       brelse(dir->bh_fplus[i]);
+
+               if (&dir->bh[0] != dir->bh_fplus)
+                       kfree(dir->bh_fplus);
+
+               dir->bh_fplus = NULL;
+       }
+
+       dir->nr_buffers = 0;
        dir->sb = NULL;
        return ret;
 }
@@ -79,7 +122,8 @@ out:
 static int
 adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
 {
-       struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+       struct adfs_bigdirheader *h =
+               (struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
        int ret = -ENOENT;
 
        if (fpos <= le32_to_cpu(h->bigdirentries)) {
@@ -102,21 +146,27 @@ dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
        partial = sb->s_blocksize - offset;
 
        if (partial >= len)
-               memcpy(to, dir->bh[buffer]->b_data + offset, len);
+               memcpy(to, dir->bh_fplus[buffer]->b_data + offset, len);
        else {
                char *c = (char *)to;
 
                remainder = len - partial;
 
-               memcpy(c, dir->bh[buffer]->b_data + offset, partial);
-               memcpy(c + partial, dir->bh[buffer + 1]->b_data, remainder);
+               memcpy(c,
+                       dir->bh_fplus[buffer]->b_data + offset,
+                       partial);
+
+               memcpy(c + partial,
+                       dir->bh_fplus[buffer + 1]->b_data,
+                       remainder);
        }
 }
 
 static int
 adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
 {
-       struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+       struct adfs_bigdirheader *h =
+               (struct adfs_bigdirheader *) dir->bh_fplus[0]->b_data;
        struct adfs_bigdirentry bde;
        unsigned int offset;
        int i, ret = -ENOENT;
@@ -147,6 +197,24 @@ adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
                if (obj->name[i] == '/')
                        obj->name[i] = '.';
 
+       obj->filetype = -1;
+
+       /*
+        * object is a file and is filetyped and timestamped?
+        * RISC OS 12-bit filetype is stored in load_address[19:8]
+        */
+       if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&
+               (0xfff00000 == (0xfff00000 & obj->loadaddr))) {
+               obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);
+
+               /* optionally append the ,xyz hex filetype suffix */
+               if (ADFS_SB(dir->sb)->s_ftsuffix)
+                       obj->name_len +=
+                               append_filetype_suffix(
+                                       &obj->name[obj->name_len],
+                                       obj->filetype);
+       }
+
        dir->pos += 1;
        ret = 0;
 out:
@@ -160,7 +228,7 @@ adfs_fplus_sync(struct adfs_dir *dir)
        int i;
 
        for (i = dir->nr_buffers - 1; i >= 0; i--) {
-               struct buffer_head *bh = dir->bh[i];
+               struct buffer_head *bh = dir->bh_fplus[i];
                sync_dirty_buffer(bh);
                if (buffer_req(bh) && !buffer_uptodate(bh))
                        err = -EIO;
@@ -174,8 +242,17 @@ adfs_fplus_free(struct adfs_dir *dir)
 {
        int i;
 
-       for (i = 0; i < dir->nr_buffers; i++)
-               brelse(dir->bh[i]);
+       if (dir->bh_fplus) {
+               for (i = 0; i < dir->nr_buffers; i++)
+                       brelse(dir->bh_fplus[i]);
+
+               if (&dir->bh[0] != dir->bh_fplus)
+                       kfree(dir->bh_fplus);
+
+               dir->bh_fplus = NULL;
+       }
+
+       dir->nr_buffers = 0;
        dir->sb = NULL;
 }
 
index 09fe40198d1c3c51c38df861a422d63e31638000..d5250c5aae21e10c560180e1042234d3a4d91f25 100644 (file)
@@ -72,32 +72,18 @@ static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
 static const struct address_space_operations adfs_aops = {
        .readpage       = adfs_readpage,
        .writepage      = adfs_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = adfs_write_begin,
        .write_end      = generic_write_end,
        .bmap           = _adfs_bmap
 };
 
-static inline unsigned int
-adfs_filetype(struct inode *inode)
-{
-       unsigned int type;
-
-       if (ADFS_I(inode)->stamped)
-               type = (ADFS_I(inode)->loadaddr >> 8) & 0xfff;
-       else
-               type = (unsigned int) -1;
-
-       return type;
-}
-
 /*
  * Convert ADFS attributes and filetype to Linux permission.
  */
 static umode_t
 adfs_atts2mode(struct super_block *sb, struct inode *inode)
 {
-       unsigned int filetype, attr = ADFS_I(inode)->attr;
+       unsigned int attr = ADFS_I(inode)->attr;
        umode_t mode, rmask;
        struct adfs_sb_info *asb = ADFS_SB(sb);
 
@@ -106,9 +92,7 @@ adfs_atts2mode(struct super_block *sb, struct inode *inode)
                return S_IFDIR | S_IXUGO | mode;
        }
 
-       filetype = adfs_filetype(inode);
-
-       switch (filetype) {
+       switch (ADFS_I(inode)->filetype) {
        case 0xfc0:     /* LinkFS */
                return S_IFLNK|S_IRWXUGO;
 
@@ -174,50 +158,48 @@ adfs_mode2atts(struct super_block *sb, struct inode *inode)
 
 /*
  * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
- * referenced to 1 Jan 1900 (til 2248)
+ * referenced to 1 Jan 1900 (til 2248) so we need to discard 2208988800 seconds
+ * of time to convert from RISC OS epoch to Unix epoch.
  */
 static void
 adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
 {
        unsigned int high, low;
+       /* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
+        * 01 Jan 1900 00:00:00 (RISC OS epoch)
+        */
+       static const s64 nsec_unix_epoch_diff_risc_os_epoch =
+                                                       2208988800000000000LL;
+       s64 nsec;
 
        if (ADFS_I(inode)->stamped == 0)
                goto cur_time;
 
-       high = ADFS_I(inode)->loadaddr << 24;
-       low  = ADFS_I(inode)->execaddr;
+       high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
+       low  = ADFS_I(inode)->execaddr;    /* bottom 32 bits of timestamp */
 
-       high |= low >> 8;
-       low  &= 255;
+       /* convert 40-bit centi-seconds to 32-bit seconds
+        * going via nanoseconds to retain precision
+        */
+       nsec = (((s64) high << 32) | (s64) low) * 10000000; /* cs to ns */
 
        /* Files dated pre  01 Jan 1970 00:00:00. */
-       if (high < 0x336e996a)
+       if (nsec < nsec_unix_epoch_diff_risc_os_epoch)
                goto too_early;
 
-       /* Files dated post 18 Jan 2038 03:14:05. */
-       if (high >= 0x656e9969)
-               goto too_late;
+       /* convert from RISC OS to Unix epoch */
+       nsec -= nsec_unix_epoch_diff_risc_os_epoch;
 
-       /* discard 2208988800 (0x336e996a00) seconds of time */
-       high -= 0x336e996a;
-
-       /* convert 40-bit centi-seconds to 32-bit seconds */
-       tv->tv_sec = (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
-       tv->tv_nsec = 0;
+       *tv = ns_to_timespec(nsec);
        return;
 
  cur_time:
-       *tv = CURRENT_TIME_SEC;
+       *tv = CURRENT_TIME;
        return;
 
  too_early:
        tv->tv_sec = tv->tv_nsec = 0;
        return;
-
- too_late:
-       tv->tv_sec = 0x7ffffffd;
-       tv->tv_nsec = 0;
-       return;
 }
 
 /*
@@ -279,7 +261,8 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
        ADFS_I(inode)->loadaddr  = obj->loadaddr;
        ADFS_I(inode)->execaddr  = obj->execaddr;
        ADFS_I(inode)->attr      = obj->attr;
-       ADFS_I(inode)->stamped    = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
+       ADFS_I(inode)->filetype  = obj->filetype;
+       ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
        inode->i_mode    = adfs_atts2mode(sb, inode);
        adfs_adfs2unix_time(&inode->i_mtime, inode);
index 06d7388b477b472a391eb6a2150b7a9c03399ae7..c8bf36a1996a3f8559ab947d001feb07fd23350b 100644 (file)
@@ -138,17 +138,20 @@ static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",ownmask=%o", asb->s_owner_mask);
        if (asb->s_other_mask != ADFS_DEFAULT_OTHER_MASK)
                seq_printf(seq, ",othmask=%o", asb->s_other_mask);
+       if (asb->s_ftsuffix != 0)
+               seq_printf(seq, ",ftsuffix=%u", asb->s_ftsuffix);
 
        return 0;
 }
 
-enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
+enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_ftsuffix, Opt_err};
 
 static const match_table_t tokens = {
        {Opt_uid, "uid=%u"},
        {Opt_gid, "gid=%u"},
        {Opt_ownmask, "ownmask=%o"},
        {Opt_othmask, "othmask=%o"},
+       {Opt_ftsuffix, "ftsuffix=%u"},
        {Opt_err, NULL}
 };
 
@@ -189,6 +192,11 @@ static int parse_options(struct super_block *sb, char *options)
                                return -EINVAL;
                        asb->s_other_mask = option;
                        break;
+               case Opt_ftsuffix:
+                       if (match_int(args, &option))
+                               return -EINVAL;
+                       asb->s_ftsuffix = option;
+                       break;
                default:
                        printk("ADFS-fs: unrecognised mount option \"%s\" "
                                        "or missing value\n", p);
@@ -366,6 +374,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
        asb->s_gid = 0;
        asb->s_owner_mask = ADFS_DEFAULT_OWNER_MASK;
        asb->s_other_mask = ADFS_DEFAULT_OTHER_MASK;
+       asb->s_ftsuffix = 0;
 
        if (parse_options(sb, data))
                goto error;
@@ -445,11 +454,13 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
 
        root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
        root_obj.name_len  = 0;
-       root_obj.loadaddr  = 0;
-       root_obj.execaddr  = 0;
+       /* Set root object date as 01 Jan 1987 00:00:00 */
+       root_obj.loadaddr  = 0xfff0003f;
+       root_obj.execaddr  = 0xec22c000;
        root_obj.size      = ADFS_NEWDIR_SIZE;
        root_obj.attr      = ADFS_NDA_DIRECTORY   | ADFS_NDA_OWNER_READ |
                             ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ;
+       root_obj.filetype  = -1;
 
        /*
         * If this is a F+ disk with variable length directories,
@@ -463,6 +474,12 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
                asb->s_dir     = &adfs_f_dir_ops;
                asb->s_namelen = ADFS_F_NAME_LEN;
        }
+       /*
+        * ,xyz hex filetype suffix may be added by driver
+        * to files that have valid RISC OS filetype
+        */
+       if (asb->s_ftsuffix)
+               asb->s_namelen += 4;
 
        sb->s_d_op = &adfs_dentry_operations;
        root = adfs_iget(sb, &root_obj);
index b2c4f54446f3c720e22dd51ce6717c5d1e9a6b3e..3988b4a78339aab8ff6dd1fd3656560ccd9aee3f 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Linux affs filesystem routines.
 #
 
-#EXTRA_CFLAGS=-DDEBUG=1
+#ccflags-y := -DDEBUG=1
 
 obj-$(CONFIG_AFFS_FS) += affs.o
 
index 0a90dcd46de28d33f2768fde829ac7800abdc9e4..acf321b70fcd1a8522da3658449ebcaed3a9e733 100644 (file)
@@ -429,7 +429,6 @@ static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations affs_aops = {
        .readpage = affs_readpage,
        .writepage = affs_writepage,
-       .sync_page = block_sync_page,
        .write_begin = affs_write_begin,
        .write_end = generic_write_end,
        .bmap = _affs_bmap
@@ -786,7 +785,6 @@ out:
 const struct address_space_operations affs_aops_ofs = {
        .readpage = affs_readpage_ofs,
        //.writepage = affs_writepage_ofs,
-       //.sync_page = affs_sync_page_ofs,
        .write_begin = affs_write_begin_ofs,
        .write_end = affs_write_end_ofs
 };
index 7f54f43b8f7c9557d652e741ecdc544b207b73d3..e29ec485af255822b8414be128fc8ef66da9a204 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -34,8 +34,6 @@
 #include <linux/security.h>
 #include <linux/eventfd.h>
 #include <linux/blkdev.h>
-#include <linux/mempool.h>
-#include <linux/hash.h>
 #include <linux/compat.h>
 
 #include <asm/kmap_types.h>
@@ -65,14 +63,6 @@ static DECLARE_WORK(fput_work, aio_fput_routine);
 static DEFINE_SPINLOCK(fput_lock);
 static LIST_HEAD(fput_head);
 
-#define AIO_BATCH_HASH_BITS    3 /* allocated on-stack, so don't go crazy */
-#define AIO_BATCH_HASH_SIZE    (1 << AIO_BATCH_HASH_BITS)
-struct aio_batch_entry {
-       struct hlist_node list;
-       struct address_space *mapping;
-};
-mempool_t *abe_pool;
-
 static void aio_kick_handler(struct work_struct *);
 static void aio_queue_work(struct kioctx *);
 
@@ -86,8 +76,7 @@ static int __init aio_setup(void)
        kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
        aio_wq = alloc_workqueue("aio", 0, 1);  /* used to limit concurrency */
-       abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry));
-       BUG_ON(!aio_wq || !abe_pool);
+       BUG_ON(!aio_wq);
 
        pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
 
@@ -520,7 +509,7 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
        ctx->reqs_active--;
 
        if (unlikely(!ctx->reqs_active && ctx->dead))
-               wake_up(&ctx->wait);
+               wake_up_all(&ctx->wait);
 }
 
 static void aio_fput_routine(struct work_struct *data)
@@ -1229,7 +1218,7 @@ static void io_destroy(struct kioctx *ioctx)
         * by other CPUs at this point.  Right now, we rely on the
         * locking done by the above calls to ensure this consistency.
         */
-       wake_up(&ioctx->wait);
+       wake_up_all(&ioctx->wait);
        put_ioctx(ioctx);       /* once for the lookup */
 }
 
@@ -1525,57 +1514,8 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
        return 0;
 }
 
-static void aio_batch_add(struct address_space *mapping,
-                         struct hlist_head *batch_hash)
-{
-       struct aio_batch_entry *abe;
-       struct hlist_node *pos;
-       unsigned bucket;
-
-       bucket = hash_ptr(mapping, AIO_BATCH_HASH_BITS);
-       hlist_for_each_entry(abe, pos, &batch_hash[bucket], list) {
-               if (abe->mapping == mapping)
-                       return;
-       }
-
-       abe = mempool_alloc(abe_pool, GFP_KERNEL);
-
-       /*
-        * we should be using igrab here, but
-        * we don't want to hammer on the global
-        * inode spinlock just to take an extra
-        * reference on a file that we must already
-        * have a reference to.
-        *
-        * When we're called, we always have a reference
-        * on the file, so we must always have a reference
-        * on the inode, so ihold() is safe here.
-        */
-       ihold(mapping->host);
-       abe->mapping = mapping;
-       hlist_add_head(&abe->list, &batch_hash[bucket]);
-       return;
-}
-
-static void aio_batch_free(struct hlist_head *batch_hash)
-{
-       struct aio_batch_entry *abe;
-       struct hlist_node *pos, *n;
-       int i;
-
-       for (i = 0; i < AIO_BATCH_HASH_SIZE; i++) {
-               hlist_for_each_entry_safe(abe, pos, n, &batch_hash[i], list) {
-                       blk_run_address_space(abe->mapping);
-                       iput(abe->mapping->host);
-                       hlist_del(&abe->list);
-                       mempool_free(abe, abe_pool);
-               }
-       }
-}
-
 static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
-                        struct iocb *iocb, struct hlist_head *batch_hash,
-                        bool compat)
+                        struct iocb *iocb, bool compat)
 {
        struct kiocb *req;
        struct file *file;
@@ -1666,11 +1606,6 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                        ;
        }
        spin_unlock_irq(&ctx->ctx_lock);
-       if (req->ki_opcode == IOCB_CMD_PREAD ||
-           req->ki_opcode == IOCB_CMD_PREADV ||
-           req->ki_opcode == IOCB_CMD_PWRITE ||
-           req->ki_opcode == IOCB_CMD_PWRITEV)
-               aio_batch_add(file->f_mapping, batch_hash);
 
        aio_put_req(req);       /* drop extra ref to req */
        return 0;
@@ -1687,7 +1622,7 @@ long do_io_submit(aio_context_t ctx_id, long nr,
        struct kioctx *ctx;
        long ret = 0;
        int i;
-       struct hlist_head batch_hash[AIO_BATCH_HASH_SIZE] = { { 0, }, };
+       struct blk_plug plug;
 
        if (unlikely(nr < 0))
                return -EINVAL;
@@ -1704,6 +1639,8 @@ long do_io_submit(aio_context_t ctx_id, long nr,
                return -EINVAL;
        }
 
+       blk_start_plug(&plug);
+
        /*
         * AKPM: should this return a partial result if some of the IOs were
         * successfully submitted?
@@ -1722,11 +1659,11 @@ long do_io_submit(aio_context_t ctx_id, long nr,
                        break;
                }
 
-               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash, compat);
+               ret = io_submit_one(ctx, user_iocb, &tmp, compat);
                if (ret)
                        break;
        }
-       aio_batch_free(batch_hash);
+       blk_finish_plug(&plug);
 
        put_ioctx(ctx);
        return i ? i : ret;
index 7ca41811afa1147ad764acbd1fe5b5957c883f5d..1007ed6163146e5de5c5e0695ab6f40a6ad8c390 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -59,7 +59,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
                /* Also check the setgid bit! */
                if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
@@ -69,7 +69,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
 
        /* Check for setting the inode time. */
        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
        }
 
index 54f9237927288bd43d629156ddbd7a77532a9d48..475f9c597cb7c0dd86bce6a0c42602377d33fc14 100644 (file)
@@ -61,8 +61,6 @@ do {                                                  \
                current->pid, __func__, ##args);        \
 } while (0)
 
-extern spinlock_t autofs4_lock;
-
 /* 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
index 1442da4860e5ef6ad303fd5868fa70c68a5601a6..509fe1eb66ae31babcceda94ab8fd0a04268ebcb 100644 (file)
@@ -372,6 +372,10 @@ static int autofs_dev_ioctl_setpipefd(struct file *fp,
                return -EBUSY;
        } else {
                struct file *pipe = fget(pipefd);
+               if (!pipe) {
+                       err = -EBADF;
+                       goto out;
+               }
                if (!pipe->f_op || !pipe->f_op->write) {
                        err = -EPIPE;
                        fput(pipe);
index f43100b9662bd020f2fd609a68e7d4e1f2243ad0..450f529a4eaeb6e6d48bd147548a2ad3fb72f961 100644 (file)
@@ -86,19 +86,71 @@ done:
        return status;
 }
 
+/*
+ * Calculate and dget next entry in the subdirs list under root.
+ */
+static struct dentry *get_next_positive_subdir(struct dentry *prev,
+                                               struct dentry *root)
+{
+       struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
+       struct list_head *next;
+       struct dentry *p, *q;
+
+       spin_lock(&sbi->lookup_lock);
+
+       if (prev == NULL) {
+               spin_lock(&root->d_lock);
+               prev = dget_dlock(root);
+               next = prev->d_subdirs.next;
+               p = prev;
+               goto start;
+       }
+
+       p = prev;
+       spin_lock(&p->d_lock);
+again:
+       next = p->d_u.d_child.next;
+start:
+       if (next == &root->d_subdirs) {
+               spin_unlock(&p->d_lock);
+               spin_unlock(&sbi->lookup_lock);
+               dput(prev);
+               return NULL;
+       }
+
+       q = list_entry(next, struct dentry, d_u.d_child);
+
+       spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
+       /* Negative dentry - try next */
+       if (!simple_positive(q)) {
+               spin_unlock(&p->d_lock);
+               p = q;
+               goto again;
+       }
+       dget_dlock(q);
+       spin_unlock(&q->d_lock);
+       spin_unlock(&p->d_lock);
+       spin_unlock(&sbi->lookup_lock);
+
+       dput(prev);
+
+       return q;
+}
+
 /*
  * Calculate and dget next entry in top down tree traversal.
  */
 static struct dentry *get_next_positive_dentry(struct dentry *prev,
                                                struct dentry *root)
 {
+       struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
        struct list_head *next;
        struct dentry *p, *ret;
 
        if (prev == NULL)
                return dget(root);
 
-       spin_lock(&autofs4_lock);
+       spin_lock(&sbi->lookup_lock);
 relock:
        p = prev;
        spin_lock(&p->d_lock);
@@ -110,7 +162,7 @@ again:
 
                        if (p == root) {
                                spin_unlock(&p->d_lock);
-                               spin_unlock(&autofs4_lock);
+                               spin_unlock(&sbi->lookup_lock);
                                dput(prev);
                                return NULL;
                        }
@@ -140,7 +192,7 @@ again:
        dget_dlock(ret);
        spin_unlock(&ret->d_lock);
        spin_unlock(&p->d_lock);
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->lookup_lock);
 
        dput(prev);
 
@@ -290,11 +342,8 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
        spin_lock(&sbi->fs_lock);
        ino = autofs4_dentry_ino(root);
        /* No point expiring a pending mount */
-       if (ino->flags & AUTOFS_INF_PENDING) {
-               spin_unlock(&sbi->fs_lock);
-               return NULL;
-       }
-       managed_dentry_set_transit(root);
+       if (ino->flags & AUTOFS_INF_PENDING)
+               goto out;
        if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
                struct autofs_info *ino = autofs4_dentry_ino(root);
                ino->flags |= AUTOFS_INF_EXPIRING;
@@ -302,7 +351,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
                spin_unlock(&sbi->fs_lock);
                return root;
        }
-       managed_dentry_clear_transit(root);
+out:
        spin_unlock(&sbi->fs_lock);
        dput(root);
 
@@ -336,13 +385,12 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
        timeout = sbi->exp_timeout;
 
        dentry = NULL;
-       while ((dentry = get_next_positive_dentry(dentry, root))) {
+       while ((dentry = get_next_positive_subdir(dentry, root))) {
                spin_lock(&sbi->fs_lock);
                ino = autofs4_dentry_ino(dentry);
                /* No point expiring a pending mount */
                if (ino->flags & AUTOFS_INF_PENDING)
-                       goto cont;
-               managed_dentry_set_transit(dentry);
+                       goto next;
 
                /*
                 * Case 1: (i) indirect mount or top level pseudo direct mount
@@ -402,8 +450,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
                        }
                }
 next:
-               managed_dentry_clear_transit(dentry);
-cont:
                spin_unlock(&sbi->fs_lock);
        }
        return NULL;
@@ -415,13 +461,13 @@ found:
        ino->flags |= AUTOFS_INF_EXPIRING;
        init_completion(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
-       spin_lock(&autofs4_lock);
+       spin_lock(&sbi->lookup_lock);
        spin_lock(&expired->d_parent->d_lock);
        spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
        list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
        spin_unlock(&expired->d_lock);
        spin_unlock(&expired->d_parent->d_lock);
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->lookup_lock);
        return expired;
 }
 
@@ -484,8 +530,6 @@ int autofs4_expire_run(struct super_block *sb,
        spin_lock(&sbi->fs_lock);
        ino = autofs4_dentry_ino(dentry);
        ino->flags &= ~AUTOFS_INF_EXPIRING;
-       if (!d_unhashed(dentry))
-               managed_dentry_clear_transit(dentry);
        complete_all(&ino->expire_complete);
        spin_unlock(&sbi->fs_lock);
 
@@ -513,9 +557,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
                spin_lock(&sbi->fs_lock);
                ino->flags &= ~AUTOFS_INF_EXPIRING;
                spin_lock(&dentry->d_lock);
-               if (ret)
-                       __managed_dentry_clear_transit(dentry);
-               else {
+               if (!ret) {
                        if ((IS_ROOT(dentry) ||
                            (autofs_type_indirect(sbi->type) &&
                             IS_ROOT(dentry->d_parent))) &&
index e6f84d26f4cf53f4c99f0eacb48b49d16b712163..96804a17bbd0b299279fd7848c48cd5bef119609 100644 (file)
@@ -23,8 +23,6 @@
 
 #include "autofs_i.h"
 
-DEFINE_SPINLOCK(autofs4_lock);
-
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
 static int autofs4_dir_unlink(struct inode *,struct dentry *);
 static int autofs4_dir_rmdir(struct inode *,struct dentry *);
@@ -125,15 +123,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
         * autofs file system so just let the libfs routines handle
         * it.
         */
-       spin_lock(&autofs4_lock);
+       spin_lock(&sbi->lookup_lock);
        spin_lock(&dentry->d_lock);
        if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
                spin_unlock(&dentry->d_lock);
-               spin_unlock(&autofs4_lock);
+               spin_unlock(&sbi->lookup_lock);
                return -ENOENT;
        }
        spin_unlock(&dentry->d_lock);
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->lookup_lock);
 
 out:
        return dcache_dir_open(inode, file);
@@ -171,7 +169,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
        const unsigned char *str = name->name;
        struct list_head *p, *head;
 
-       spin_lock(&autofs4_lock);
        spin_lock(&sbi->lookup_lock);
        head = &sbi->active_list;
        list_for_each(p, head) {
@@ -204,14 +201,12 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
                        dget_dlock(active);
                        spin_unlock(&active->d_lock);
                        spin_unlock(&sbi->lookup_lock);
-                       spin_unlock(&autofs4_lock);
                        return active;
                }
 next:
                spin_unlock(&active->d_lock);
        }
        spin_unlock(&sbi->lookup_lock);
-       spin_unlock(&autofs4_lock);
 
        return NULL;
 }
@@ -226,7 +221,6 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
        const unsigned char *str = name->name;
        struct list_head *p, *head;
 
-       spin_lock(&autofs4_lock);
        spin_lock(&sbi->lookup_lock);
        head = &sbi->expiring_list;
        list_for_each(p, head) {
@@ -259,14 +253,12 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
                        dget_dlock(expiring);
                        spin_unlock(&expiring->d_lock);
                        spin_unlock(&sbi->lookup_lock);
-                       spin_unlock(&autofs4_lock);
                        return expiring;
                }
 next:
                spin_unlock(&expiring->d_lock);
        }
        spin_unlock(&sbi->lookup_lock);
-       spin_unlock(&autofs4_lock);
 
        return NULL;
 }
@@ -275,17 +267,16 @@ static int autofs4_mount_wait(struct dentry *dentry)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
-       int status;
+       int status = 0;
 
        if (ino->flags & AUTOFS_INF_PENDING) {
                DPRINTK("waiting for mount name=%.*s",
                        dentry->d_name.len, dentry->d_name.name);
                status = autofs4_wait(sbi, dentry, NFY_MOUNT);
                DPRINTK("mount wait done status=%d", status);
-               ino->last_used = jiffies;
-               return status;
        }
-       return 0;
+       ino->last_used = jiffies;
+       return status;
 }
 
 static int do_expire_wait(struct dentry *dentry)
@@ -319,9 +310,12 @@ static struct dentry *autofs4_mountpoint_changed(struct path *path)
         */
        if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) {
                struct dentry *parent = dentry->d_parent;
+               struct autofs_info *ino;
                struct dentry *new = d_lookup(parent, &dentry->d_name);
                if (!new)
                        return NULL;
+               ino = autofs4_dentry_ino(new);
+               ino->last_used = jiffies;
                dput(path->dentry);
                path->dentry = new;
        }
@@ -338,18 +332,6 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
        DPRINTK("dentry=%p %.*s",
                dentry, dentry->d_name.len, dentry->d_name.name);
 
-       /*
-        * Someone may have manually umounted this or it was a submount
-        * that has gone away.
-        */
-       spin_lock(&dentry->d_lock);
-       if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
-               if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
-                    (dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
-                       __managed_dentry_set_transit(path->dentry);
-       }
-       spin_unlock(&dentry->d_lock);
-
        /* The daemon never triggers a mount. */
        if (autofs4_oz_mode(sbi))
                return NULL;
@@ -418,18 +400,17 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
 done:
        if (!(ino->flags & AUTOFS_INF_EXPIRING)) {
                /*
-                * Any needed mounting has been completed and the path updated
-                * so turn this into a normal dentry so we don't continually
-                * call ->d_automount() and ->d_manage().
-                */
-               spin_lock(&dentry->d_lock);
-               __managed_dentry_clear_transit(dentry);
-               /*
+                * Any needed mounting has been completed and the path
+                * updated so clear DCACHE_NEED_AUTOMOUNT so we don't
+                * call ->d_automount() on rootless multi-mounts since
+                * it can lead to an incorrect ELOOP error return.
+                *
                 * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and
                 * symlinks as in all other cases the dentry will be covered by
                 * an actual mount so ->d_automount() won't be called during
                 * the follow.
                 */
+               spin_lock(&dentry->d_lock);
                if ((!d_mountpoint(dentry) &&
                    !list_empty(&dentry->d_subdirs)) ||
                    (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)))
@@ -455,6 +436,8 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 
        /* The daemon never waits. */
        if (autofs4_oz_mode(sbi)) {
+               if (rcu_walk)
+                       return 0;
                if (!d_mountpoint(dentry))
                        return -EISDIR;
                return 0;
@@ -612,12 +595,12 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
 
        dir->i_mtime = CURRENT_TIME;
 
-       spin_lock(&autofs4_lock);
-       autofs4_add_expiring(dentry);
+       spin_lock(&sbi->lookup_lock);
+       __autofs4_add_expiring(dentry);
        spin_lock(&dentry->d_lock);
        __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->lookup_lock);
 
        return 0;
 }
@@ -686,20 +669,17 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
        if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
-       spin_lock(&autofs4_lock);
        spin_lock(&sbi->lookup_lock);
        spin_lock(&dentry->d_lock);
        if (!list_empty(&dentry->d_subdirs)) {
                spin_unlock(&dentry->d_lock);
                spin_unlock(&sbi->lookup_lock);
-               spin_unlock(&autofs4_lock);
                return -ENOTEMPTY;
        }
        __autofs4_add_expiring(dentry);
-       spin_unlock(&sbi->lookup_lock);
        __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->lookup_lock);
 
        if (sbi->version < 5)
                autofs_clear_leaf_automount_flags(dentry);
index 56010056b2e6d9001280597b73146ccb839d1b87..25435987d6ae1cdcbbcfea4e9bf4d744c55bab44 100644 (file)
@@ -197,12 +197,12 @@ rename_retry:
 
        seq = read_seqbegin(&rename_lock);
        rcu_read_lock();
-       spin_lock(&autofs4_lock);
+       spin_lock(&sbi->fs_lock);
        for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
                len += tmp->d_name.len + 1;
 
        if (!len || --len > NAME_MAX) {
-               spin_unlock(&autofs4_lock);
+               spin_unlock(&sbi->fs_lock);
                rcu_read_unlock();
                if (read_seqretry(&rename_lock, seq))
                        goto rename_retry;
@@ -218,7 +218,7 @@ rename_retry:
                p -= tmp->d_name.len;
                strncpy(p, tmp->d_name.name, tmp->d_name.len);
        }
-       spin_unlock(&autofs4_lock);
+       spin_unlock(&sbi->fs_lock);
        rcu_read_unlock();
        if (read_seqretry(&rename_lock, seq))
                goto rename_retry;
index b1d0c794747b7537dbade4895eccae70aa78cc5e..06457ed8f3e7c5fc258fc8cdc7f0f3bf88eeddf4 100644 (file)
@@ -75,7 +75,6 @@ static const struct inode_operations befs_dir_inode_operations = {
 
 static const struct address_space_operations befs_aops = {
        .readpage       = befs_readpage,
-       .sync_page      = block_sync_page,
        .bmap           = befs_bmap,
 };
 
index 685ecff3ab31728d2362a9be39f98dfbc76947c4..b14cebfd90477ead4b15f0c1583da6393c247de5 100644 (file)
@@ -97,7 +97,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode,
        if (!inode)
                return -ENOSPC;
        mutex_lock(&info->bfs_lock);
-       ino = find_first_zero_bit(info->si_imap, info->si_lasti);
+       ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1);
        if (ino > info->si_lasti) {
                mutex_unlock(&info->bfs_lock);
                iput(inode);
index eb67edd0f8ea3f39c112faebfed1a877b37f686d..f20e8a71062f4d2bc15e1daacf44398b8cab4906 100644 (file)
@@ -186,7 +186,6 @@ static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations bfs_aops = {
        .readpage       = bfs_readpage,
        .writepage      = bfs_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = bfs_write_begin,
        .write_end      = generic_write_end,
        .bmap           = bfs_bmap,
index d5b640ba6cb1a30ab06adc214e76ae37f2b1ec75..f34078d702d3bdbe1ee69bc1122b63d3facf5009 100644 (file)
@@ -570,7 +570,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        unsigned long elf_entry;
        unsigned long interp_load_addr = 0;
        unsigned long start_code, end_code, start_data, end_data;
-       unsigned long reloc_func_desc = 0;
+       unsigned long reloc_func_desc __maybe_unused = 0;
        int executable_stack = EXSTACK_DEFAULT;
        unsigned long def_flags = 0;
        struct {
@@ -1906,7 +1906,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        segs = current->mm->map_count;
        segs += elf_core_extra_phdrs();
 
-       gate_vma = get_gate_vma(current);
+       gate_vma = get_gate_vma(current->mm);
        if (gate_vma != NULL)
                segs++;
 
index e49cce234c653162560796710ee125134053183d..9c5e6b2cd11a84fa3f04611b35cebb6e2232b186 100644 (file)
@@ -761,6 +761,9 @@ int bioset_integrity_create(struct bio_set *bs, int pool_size)
 {
        unsigned int max_slab = vecs_to_idx(BIO_MAX_PAGES);
 
+       if (bs->bio_integrity_pool)
+               return 0;
+
        bs->bio_integrity_pool =
                mempool_create_slab_pool(pool_size, bip_slab[max_slab].slab);
 
index 4bd454fa844e3efc8c44755c7ea9847477f813ff..4d6d4b6c2bf1d2d8122e6383e2a469be8dae8fbf 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -43,7 +43,7 @@ static mempool_t *bio_split_pool __read_mostly;
  * unsigned short
  */
 #define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
+static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
        BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
 };
 #undef BV
@@ -111,7 +111,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
        if (!slab)
                goto out_unlock;
 
-       printk("bio: create slab <%s> at %d\n", bslab->name, entry);
+       printk(KERN_INFO "bio: create slab <%s> at %d\n", bslab->name, entry);
        bslab->slab = slab;
        bslab->slab_ref = 1;
        bslab->slab_size = sz;
@@ -1636,9 +1636,6 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
        if (!bs->bio_pool)
                goto bad;
 
-       if (bioset_integrity_create(bs, pool_size))
-               goto bad;
-
        if (!biovec_create_pools(bs, pool_size))
                return bs;
 
@@ -1656,12 +1653,10 @@ static void __init biovec_init_slabs(void)
                int size;
                struct biovec_slab *bvs = bvec_slabs + i;
 
-#ifndef CONFIG_BLK_DEV_INTEGRITY
                if (bvs->nr_vecs <= BIO_INLINE_VECS) {
                        bvs->slab = NULL;
                        continue;
                }
-#endif
 
                size = bvs->nr_vecs * sizeof(struct bio_vec);
                bvs->slab = kmem_cache_create(bvs->name, size, 0,
@@ -1684,6 +1679,9 @@ static int __init init_bio(void)
        if (!fs_bio_set)
                panic("bio: can't allocate bios\n");
 
+       if (bioset_integrity_create(fs_bio_set, BIO_POOL_SIZE))
+               panic("bio: can't create integrity pool\n");
+
        bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES,
                                                     sizeof(struct bio_pair));
        if (!bio_split_pool)
index 889287019599a861d90a51d6808cfb2d032fc255..c1511c674f53f19b81ac334419a6976e477ca373 100644 (file)
@@ -55,11 +55,13 @@ EXPORT_SYMBOL(I_BDEV);
 static void bdev_inode_switch_bdi(struct inode *inode,
                        struct backing_dev_info *dst)
 {
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
+       spin_lock(&inode->i_lock);
        inode->i_data.backing_dev_info = dst;
        if (inode->i_state & I_DIRTY)
                list_move(&inode->i_wb_list, &dst->wb.b_dirty);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_wb_list_lock);
 }
 
 static sector_t max_block(struct block_device *bdev)
@@ -1087,6 +1089,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        if (!disk)
                goto out;
 
+       disk_block_events(disk);
        mutex_lock_nested(&bdev->bd_mutex, for_part);
        if (!bdev->bd_openers) {
                bdev->bd_disk = disk;
@@ -1108,10 +1111,11 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                         */
                                        disk_put_part(bdev->bd_part);
                                        bdev->bd_part = NULL;
-                                       module_put(disk->fops->owner);
-                                       put_disk(disk);
                                        bdev->bd_disk = NULL;
                                        mutex_unlock(&bdev->bd_mutex);
+                                       disk_unblock_events(disk);
+                                       module_put(disk->fops->owner);
+                                       put_disk(disk);
                                        goto restart;
                                }
                                if (ret)
@@ -1148,9 +1152,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
                }
        } else {
-               module_put(disk->fops->owner);
-               put_disk(disk);
-               disk = NULL;
                if (bdev->bd_contains == bdev) {
                        if (bdev->bd_disk->fops->open) {
                                ret = bdev->bd_disk->fops->open(bdev, mode);
@@ -1160,11 +1161,15 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        if (bdev->bd_invalidated)
                                rescan_partitions(bdev->bd_disk, bdev);
                }
+               /* only one opener holds refs to the module and disk */
+               module_put(disk->fops->owner);
+               put_disk(disk);
        }
        bdev->bd_openers++;
        if (for_part)
                bdev->bd_part_count++;
        mutex_unlock(&bdev->bd_mutex);
+       disk_unblock_events(disk);
        return 0;
 
  out_clear:
@@ -1177,10 +1182,10 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        bdev->bd_contains = NULL;
  out_unlock_bdev:
        mutex_unlock(&bdev->bd_mutex);
- out:
-       if (disk)
-               module_put(disk->fops->owner);
+       disk_unblock_events(disk);
+       module_put(disk->fops->owner);
        put_disk(disk);
+ out:
        bdput(bdev);
 
        return ret;
@@ -1446,14 +1451,13 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
                if (bdev_free) {
                        if (bdev->bd_write_holder) {
                                disk_unblock_events(bdev->bd_disk);
-                               bdev->bd_write_holder = false;
-                       } else
                                disk_check_events(bdev->bd_disk);
+                               bdev->bd_write_holder = false;
+                       }
                }
 
                mutex_unlock(&bdev->bd_mutex);
-       } else
-               disk_check_events(bdev->bd_disk);
+       }
 
        return __blkdev_put(bdev, mode, 0);
 }
@@ -1527,7 +1531,6 @@ static int blkdev_releasepage(struct page *page, gfp_t wait)
 static const struct address_space_operations def_blk_aops = {
        .readpage       = blkdev_readpage,
        .writepage      = blkdev_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = blkdev_write_begin,
        .write_end      = blkdev_write_end,
        .writepages     = generic_writepages,
index 9c949348510b476f776321bbe8f42f3c858c980e..de34bfad9ec3cab33f35ead4f31d9605f48af66c 100644 (file)
@@ -170,7 +170,7 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
        int ret;
        struct posix_acl *acl = NULL;
 
-       if (!is_owner_or_cap(dentry->d_inode))
+       if (!inode_owner_or_capable(dentry->d_inode))
                return -EPERM;
 
        if (!IS_POSIXACL(dentry->d_inode))
index 100b07f021b406a97d9f24ae04e3665418eca833..830d261d0e6b9a7faba479160edb72df3d8a6d2a 100644 (file)
@@ -847,7 +847,6 @@ static const struct address_space_operations btree_aops = {
        .writepages     = btree_writepages,
        .releasepage    = btree_releasepage,
        .invalidatepage = btree_invalidatepage,
-       .sync_page      = block_sync_page,
 #ifdef CONFIG_MIGRATION
        .migratepage    = btree_migratepage,
 #endif
@@ -1330,82 +1329,6 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
        return ret;
 }
 
-/*
- * this unplugs every device on the box, and it is only used when page
- * is null
- */
-static void __unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
-{
-       struct btrfs_device *device;
-       struct btrfs_fs_info *info;
-
-       info = (struct btrfs_fs_info *)bdi->unplug_io_data;
-       list_for_each_entry(device, &info->fs_devices->devices, dev_list) {
-               if (!device->bdev)
-                       continue;
-
-               bdi = blk_get_backing_dev_info(device->bdev);
-               if (bdi->unplug_io_fn)
-                       bdi->unplug_io_fn(bdi, page);
-       }
-}
-
-static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
-{
-       struct inode *inode;
-       struct extent_map_tree *em_tree;
-       struct extent_map *em;
-       struct address_space *mapping;
-       u64 offset;
-
-       /* the generic O_DIRECT read code does this */
-       if (1 || !page) {
-               __unplug_io_fn(bdi, page);
-               return;
-       }
-
-       /*
-        * page->mapping may change at any time.  Get a consistent copy
-        * and use that for everything below
-        */
-       smp_mb();
-       mapping = page->mapping;
-       if (!mapping)
-               return;
-
-       inode = mapping->host;
-
-       /*
-        * don't do the expensive searching for a small number of
-        * devices
-        */
-       if (BTRFS_I(inode)->root->fs_info->fs_devices->open_devices <= 2) {
-               __unplug_io_fn(bdi, page);
-               return;
-       }
-
-       offset = page_offset(page);
-
-       em_tree = &BTRFS_I(inode)->extent_tree;
-       read_lock(&em_tree->lock);
-       em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE);
-       read_unlock(&em_tree->lock);
-       if (!em) {
-               __unplug_io_fn(bdi, page);
-               return;
-       }
-
-       if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
-               free_extent_map(em);
-               __unplug_io_fn(bdi, page);
-               return;
-       }
-       offset = offset - em->start;
-       btrfs_unplug_page(&BTRFS_I(inode)->root->fs_info->mapping_tree,
-                         em->block_start + offset, page);
-       free_extent_map(em);
-}
-
 /*
  * If this fails, caller must call bdi_destroy() to get rid of the
  * bdi again.
@@ -1420,8 +1343,6 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
                return err;
 
        bdi->ra_pages   = default_backing_dev_info.ra_pages;
-       bdi->unplug_io_fn       = btrfs_unplug_io_fn;
-       bdi->unplug_io_data     = info;
        bdi->congested_fn       = btrfs_congested_fn;
        bdi->congested_data     = info;
        return 0;
index 714adc4ac4c24eaae26900bb9e862bc8b874432b..b5b92824a27137980287ad2418c565b425dd1bfa 100644 (file)
@@ -2188,7 +2188,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        unsigned long nr_written = 0;
 
        if (wbc->sync_mode == WB_SYNC_ALL)
-               write_flags = WRITE_SYNC_PLUG;
+               write_flags = WRITE_SYNC;
        else
                write_flags = WRITE;
 
index 512c3d1da083add52ddac41d85e1b694dbfd18f3..119520bdb9a540d8dc0f9bcf94d66b01df0af068 100644 (file)
@@ -7340,7 +7340,6 @@ static const struct address_space_operations btrfs_aops = {
        .writepage      = btrfs_writepage,
        .writepages     = btrfs_writepages,
        .readpages      = btrfs_readpages,
-       .sync_page      = block_sync_page,
        .direct_IO      = btrfs_direct_IO,
        .invalidatepage = btrfs_invalidatepage,
        .releasepage    = btrfs_releasepage,
index 5fdb2abc4fa789d49db9b76cd4e459d8c0d3bc85..d1bace3df9b61fab21ca50a9e84ff427fedc75ea 100644 (file)
@@ -158,7 +158,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                      FS_SYNC_FL | FS_DIRSYNC_FL))
                return -EOPNOTSUPP;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EACCES;
 
        mutex_lock(&inode->i_mutex);
@@ -1077,7 +1077,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        if (flags & ~BTRFS_SUBVOL_RDONLY)
                return -EOPNOTSUPP;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EACCES;
 
        down_write(&root->fs_info->subvol_sem);
index dd13eb81ee4011df4d52103665d30465fe696306..9d554e8e6583e62a277eaa906ebd8dbe03d0f39f 100644 (file)
@@ -162,7 +162,6 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        struct bio *cur;
        int again = 0;
        unsigned long num_run;
-       unsigned long num_sync_run;
        unsigned long batch_run = 0;
        unsigned long limit;
        unsigned long last_waited = 0;
@@ -173,11 +172,6 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
 
-       /* we want to make sure that every time we switch from the sync
-        * list to the normal list, we unplug
-        */
-       num_sync_run = 0;
-
 loop:
        spin_lock(&device->io_lock);
 
@@ -223,15 +217,6 @@ loop_lock:
 
        spin_unlock(&device->io_lock);
 
-       /*
-        * if we're doing the regular priority list, make sure we unplug
-        * for any high prio bios we've sent down
-        */
-       if (pending_bios == &device->pending_bios && num_sync_run > 0) {
-               num_sync_run = 0;
-               blk_run_backing_dev(bdi, NULL);
-       }
-
        while (pending) {
 
                rmb();
@@ -259,19 +244,11 @@ loop_lock:
 
                BUG_ON(atomic_read(&cur->bi_cnt) == 0);
 
-               if (cur->bi_rw & REQ_SYNC)
-                       num_sync_run++;
-
                submit_bio(cur->bi_rw, cur);
                num_run++;
                batch_run++;
-               if (need_resched()) {
-                       if (num_sync_run) {
-                               blk_run_backing_dev(bdi, NULL);
-                               num_sync_run = 0;
-                       }
+               if (need_resched())
                        cond_resched();
-               }
 
                /*
                 * we made progress, there is more work to do and the bdi
@@ -304,13 +281,8 @@ loop_lock:
                                 * against it before looping
                                 */
                                last_waited = ioc->last_waited;
-                               if (need_resched()) {
-                                       if (num_sync_run) {
-                                               blk_run_backing_dev(bdi, NULL);
-                                               num_sync_run = 0;
-                                       }
+                               if (need_resched())
                                        cond_resched();
-                               }
                                continue;
                        }
                        spin_lock(&device->io_lock);
@@ -323,22 +295,6 @@ loop_lock:
                }
        }
 
-       if (num_sync_run) {
-               num_sync_run = 0;
-               blk_run_backing_dev(bdi, NULL);
-       }
-       /*
-        * IO has already been through a long path to get here.  Checksumming,
-        * async helper threads, perhaps compression.  We've done a pretty
-        * good job of collecting a batch of IO and should just unplug
-        * the device right away.
-        *
-        * This will help anyone who is waiting on the IO, they might have
-        * already unplugged, but managed to do so before the bio they
-        * cared about found its way down here.
-        */
-       blk_run_backing_dev(bdi, NULL);
-
        cond_resched();
        if (again)
                goto loop;
@@ -2955,7 +2911,7 @@ static int find_live_mirror(struct map_lookup *map, int first, int num,
 static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                             u64 logical, u64 *length,
                             struct btrfs_multi_bio **multi_ret,
-                            int mirror_num, struct page *unplug_page)
+                            int mirror_num)
 {
        struct extent_map *em;
        struct map_lookup *map;
@@ -2987,11 +2943,6 @@ again:
        em = lookup_extent_mapping(em_tree, logical, *length);
        read_unlock(&em_tree->lock);
 
-       if (!em && unplug_page) {
-               kfree(multi);
-               return 0;
-       }
-
        if (!em) {
                printk(KERN_CRIT "unable to find logical %llu len %llu\n",
                       (unsigned long long)logical,
@@ -3047,13 +2998,13 @@ again:
                *length = em->len - offset;
        }
 
-       if (!multi_ret && !unplug_page)
+       if (!multi_ret)
                goto out;
 
        num_stripes = 1;
        stripe_index = 0;
        if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
-               if (unplug_page || (rw & REQ_WRITE))
+               if (rw & REQ_WRITE)
                        num_stripes = map->num_stripes;
                else if (mirror_num)
                        stripe_index = mirror_num - 1;
@@ -3075,7 +3026,7 @@ again:
                stripe_index = do_div(stripe_nr, factor);
                stripe_index *= map->sub_stripes;
 
-               if (unplug_page || (rw & REQ_WRITE))
+               if (rw & REQ_WRITE)
                        num_stripes = map->sub_stripes;
                else if (mirror_num)
                        stripe_index += mirror_num - 1;
@@ -3095,22 +3046,10 @@ again:
        BUG_ON(stripe_index >= map->num_stripes);
 
        for (i = 0; i < num_stripes; i++) {
-               if (unplug_page) {
-                       struct btrfs_device *device;
-                       struct backing_dev_info *bdi;
-
-                       device = map->stripes[stripe_index].dev;
-                       if (device->bdev) {
-                               bdi = blk_get_backing_dev_info(device->bdev);
-                               if (bdi->unplug_io_fn)
-                                       bdi->unplug_io_fn(bdi, unplug_page);
-                       }
-               } else {
-                       multi->stripes[i].physical =
-                               map->stripes[stripe_index].physical +
-                               stripe_offset + stripe_nr * map->stripe_len;
-                       multi->stripes[i].dev = map->stripes[stripe_index].dev;
-               }
+               multi->stripes[i].physical =
+                       map->stripes[stripe_index].physical +
+                       stripe_offset + stripe_nr * map->stripe_len;
+               multi->stripes[i].dev = map->stripes[stripe_index].dev;
                stripe_index++;
        }
        if (multi_ret) {
@@ -3128,7 +3067,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                      struct btrfs_multi_bio **multi_ret, int mirror_num)
 {
        return __btrfs_map_block(map_tree, rw, logical, length, multi_ret,
-                                mirror_num, NULL);
+                                mirror_num);
 }
 
 int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
@@ -3196,14 +3135,6 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        return 0;
 }
 
-int btrfs_unplug_page(struct btrfs_mapping_tree *map_tree,
-                     u64 logical, struct page *page)
-{
-       u64 length = PAGE_CACHE_SIZE;
-       return __btrfs_map_block(map_tree, READ, logical, &length,
-                                NULL, 0, page);
-}
-
 static void end_bio_multi_stripe(struct bio *bio, int err)
 {
        struct btrfs_multi_bio *multi = bio->bi_private;
index f5ec2d44150df2a484d6f6b88f856ba9ba8b6464..faccd47c6c468fb7534f43ecf8a4f7dd691def77 100644 (file)
@@ -57,7 +57,8 @@ static struct list_head *zlib_alloc_workspace(void)
        if (!workspace)
                return ERR_PTR(-ENOMEM);
 
-       workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
+       workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize(
+                                               MAX_WBITS, MAX_MEM_LEVEL));
        workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
        workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
        if (!workspace->def_strm.workspace ||
index 2219a76e2caf08415b2e207bc23466d4154d35e0..a08bb8e61c6fc275376c9a0748226deb34a6b0f0 100644 (file)
@@ -54,23 +54,15 @@ init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
 }
 EXPORT_SYMBOL(init_buffer);
 
-static int sync_buffer(void *word)
+static int sleep_on_buffer(void *word)
 {
-       struct block_device *bd;
-       struct buffer_head *bh
-               = container_of(word, struct buffer_head, b_state);
-
-       smp_mb();
-       bd = bh->b_bdev;
-       if (bd)
-               blk_run_address_space(bd->bd_inode->i_mapping);
        io_schedule();
        return 0;
 }
 
 void __lock_buffer(struct buffer_head *bh)
 {
-       wait_on_bit_lock(&bh->b_state, BH_Lock, sync_buffer,
+       wait_on_bit_lock(&bh->b_state, BH_Lock, sleep_on_buffer,
                                                        TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(__lock_buffer);
@@ -90,7 +82,7 @@ EXPORT_SYMBOL(unlock_buffer);
  */
 void __wait_on_buffer(struct buffer_head * bh)
 {
-       wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE);
+       wait_on_bit(&bh->b_state, BH_Lock, sleep_on_buffer, TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(__wait_on_buffer);
 
@@ -749,10 +741,12 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
 {
        struct buffer_head *bh;
        struct list_head tmp;
-       struct address_space *mapping, *prev_mapping = NULL;
+       struct address_space *mapping;
        int err = 0, err2;
+       struct blk_plug plug;
 
        INIT_LIST_HEAD(&tmp);
+       blk_start_plug(&plug);
 
        spin_lock(lock);
        while (!list_empty(list)) {
@@ -775,7 +769,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
                                 * still in flight on potentially older
                                 * contents.
                                 */
-                               write_dirty_buffer(bh, WRITE_SYNC_PLUG);
+                               write_dirty_buffer(bh, WRITE_SYNC);
 
                                /*
                                 * Kick off IO for the previous mapping. Note
@@ -783,16 +777,16 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
                                 * wait_on_buffer() will do that for us
                                 * through sync_buffer().
                                 */
-                               if (prev_mapping && prev_mapping != mapping)
-                                       blk_run_address_space(prev_mapping);
-                               prev_mapping = mapping;
-
                                brelse(bh);
                                spin_lock(lock);
                        }
                }
        }
 
+       spin_unlock(lock);
+       blk_finish_plug(&plug);
+       spin_lock(lock);
+
        while (!list_empty(&tmp)) {
                bh = BH_ENTRY(tmp.prev);
                get_bh(bh);
@@ -1144,7 +1138,7 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
  * inode list.
  *
  * mark_buffer_dirty() is atomic.  It takes bh->b_page->mapping->private_lock,
- * mapping->tree_lock and the global inode_lock.
+ * mapping->tree_lock and mapping->host->i_lock.
  */
 void mark_buffer_dirty(struct buffer_head *bh)
 {
@@ -1614,14 +1608,8 @@ EXPORT_SYMBOL(unmap_underlying_metadata);
  * prevents this contention from occurring.
  *
  * If block_write_full_page() is called with wbc->sync_mode ==
- * WB_SYNC_ALL, the writes are posted using WRITE_SYNC_PLUG; this
- * causes the writes to be flagged as synchronous writes, but the
- * block device queue will NOT be unplugged, since usually many pages
- * will be pushed to the out before the higher-level caller actually
- * waits for the writes to be completed.  The various wait functions,
- * such as wait_on_writeback_range() will ultimately call sync_page()
- * which will ultimately call blk_run_backing_dev(), which will end up
- * unplugging the device queue.
+ * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this
+ * causes the writes to be flagged as synchronous writes.
  */
 static int __block_write_full_page(struct inode *inode, struct page *page,
                        get_block_t *get_block, struct writeback_control *wbc,
@@ -1634,7 +1622,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
        const unsigned blocksize = 1 << inode->i_blkbits;
        int nr_underway = 0;
        int write_op = (wbc->sync_mode == WB_SYNC_ALL ?
-                       WRITE_SYNC_PLUG : WRITE);
+                       WRITE_SYNC : WRITE);
 
        BUG_ON(!PageLocked(page));
 
@@ -3138,17 +3126,6 @@ out:
 }
 EXPORT_SYMBOL(try_to_free_buffers);
 
-void block_sync_page(struct page *page)
-{
-       struct address_space *mapping;
-
-       smp_mb();
-       mapping = page_mapping(page);
-       if (mapping)
-               blk_run_backing_dev(mapping->backing_dev_info, page);
-}
-EXPORT_SYMBOL(block_sync_page);
-
 /*
  * There are no bdflush tunables left.  But distributions are
  * still running obsolete flush daemons, so we terminate them here.
index 08f65faac1126aa7a5096ec2a7233e5fb332242b..0dba6915712becaef62b6802bb88d1a7b36ea854 100644 (file)
@@ -210,8 +210,6 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        if (!fsc->debugfs_congestion_kb)
                goto out;
 
-       dout("a\n");
-
        snprintf(name, sizeof(name), "../../bdi/%s",
                 dev_name(fsc->backing_dev_info.dev));
        fsc->debugfs_bdi =
@@ -221,7 +219,6 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        if (!fsc->debugfs_bdi)
                goto out;
 
-       dout("b\n");
        fsc->debugfs_mdsmap = debugfs_create_file("mdsmap",
                                        0600,
                                        fsc->client->debugfs_dir,
@@ -230,7 +227,6 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        if (!fsc->debugfs_mdsmap)
                goto out;
 
-       dout("ca\n");
        fsc->debugfs_mdsc = debugfs_create_file("mdsc",
                                                0600,
                                                fsc->client->debugfs_dir,
@@ -239,7 +235,6 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        if (!fsc->debugfs_mdsc)
                goto out;
 
-       dout("da\n");
        fsc->debugfs_caps = debugfs_create_file("caps",
                                                   0400,
                                                   fsc->client->debugfs_dir,
@@ -248,7 +243,6 @@ int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
        if (!fsc->debugfs_caps)
                goto out;
 
-       dout("ea\n");
        fsc->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
                                        0600,
                                        fsc->client->debugfs_dir,
index ebafa65a29b6580619c75256195547a5107cb86d..1a867a3601aea88ee25c9fadf399d4a2a3472498 100644 (file)
@@ -161,7 +161,7 @@ more:
        filp->f_pos = di->offset;
        err = filldir(dirent, dentry->d_name.name,
                      dentry->d_name.len, di->offset,
-                     dentry->d_inode->i_ino,
+                     ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
                      dentry->d_inode->i_mode >> 12);
 
        if (last) {
@@ -245,15 +245,17 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
                dout("readdir off 0 -> '.'\n");
                if (filldir(dirent, ".", 1, ceph_make_fpos(0, 0),
-                           inode->i_ino, inode->i_mode >> 12) < 0)
+                           ceph_translate_ino(inode->i_sb, inode->i_ino),
+                           inode->i_mode >> 12) < 0)
                        return 0;
                filp->f_pos = 1;
                off = 1;
        }
        if (filp->f_pos == 1) {
+               ino_t ino = filp->f_dentry->d_parent->d_inode->i_ino;
                dout("readdir off 1 -> '..'\n");
                if (filldir(dirent, "..", 2, ceph_make_fpos(0, 1),
-                           filp->f_dentry->d_parent->d_inode->i_ino,
+                           ceph_translate_ino(inode->i_sb, ino),
                            inode->i_mode >> 12) < 0)
                        return 0;
                filp->f_pos = 2;
@@ -377,7 +379,8 @@ more:
                if (filldir(dirent,
                            rinfo->dir_dname[off - fi->offset],
                            rinfo->dir_dname_len[off - fi->offset],
-                           pos, ino, ftype) < 0) {
+                           pos,
+                           ceph_translate_ino(inode->i_sb, ino), ftype) < 0) {
                        dout("filldir stopping us...\n");
                        return 0;
                }
@@ -1024,14 +1027,13 @@ out_touch:
 }
 
 /*
- * When a dentry is released, clear the dir I_COMPLETE if it was part
- * of the current dir gen or if this is in the snapshot namespace.
+ * Release our ceph_dentry_info.
  */
-static void ceph_dentry_release(struct dentry *dentry)
+static void ceph_d_release(struct dentry *dentry)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
 
-       dout("dentry_release %p\n", dentry);
+       dout("d_release %p\n", dentry);
        if (di) {
                ceph_dentry_lru_del(dentry);
                if (di->lease_session)
@@ -1256,14 +1258,14 @@ const struct inode_operations ceph_dir_iops = {
 
 const struct dentry_operations ceph_dentry_ops = {
        .d_revalidate = ceph_d_revalidate,
-       .d_release = ceph_dentry_release,
+       .d_release = ceph_d_release,
 };
 
 const struct dentry_operations ceph_snapdir_dentry_ops = {
        .d_revalidate = ceph_snapdir_d_revalidate,
-       .d_release = ceph_dentry_release,
+       .d_release = ceph_d_release,
 };
 
 const struct dentry_operations ceph_snap_dentry_ops = {
-       .d_release = ceph_dentry_release,
+       .d_release = ceph_d_release,
 };
index 7d0e4a82d898a83f2695eead6ffc767689ffe140..159b512d5a271379abf0bde217fd46feeb38c79b 100644 (file)
@@ -564,11 +564,19 @@ more:
                         * start_request so that a tid has been assigned.
                         */
                        spin_lock(&ci->i_unsafe_lock);
-                       list_add(&req->r_unsafe_item, &ci->i_unsafe_writes);
+                       list_add_tail(&req->r_unsafe_item,
+                                     &ci->i_unsafe_writes);
                        spin_unlock(&ci->i_unsafe_lock);
                        ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
                }
+               
                ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+               if (ret < 0 && req->r_safe_callback) {
+                       spin_lock(&ci->i_unsafe_lock);
+                       list_del_init(&req->r_unsafe_item);
+                       spin_unlock(&ci->i_unsafe_lock);
+                       ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
+               }
        }
 
        if (file->f_flags & O_DIRECT)
index 193bfa5e9cbd7943bcb2a8124b5fa9ed6717cac4..b54c97da1c43fd8a4d52238d469c0aa6cb904772 100644 (file)
@@ -36,6 +36,13 @@ static void ceph_vmtruncate_work(struct work_struct *work);
 /*
  * find or create an inode, given the ceph ino number
  */
+static int ceph_set_ino_cb(struct inode *inode, void *data)
+{
+       ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
+       inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
+       return 0;
+}
+
 struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
 {
        struct inode *inode;
@@ -1030,9 +1037,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                        dout("fill_trace doing d_move %p -> %p\n",
                             req->r_old_dentry, dn);
 
-                       /* d_move screws up d_subdirs order */
-                       ceph_i_clear(dir, CEPH_I_COMPLETE);
-
                        d_move(req->r_old_dentry, dn);
                        dout(" src %p '%.*s' dst %p '%.*s'\n",
                             req->r_old_dentry,
@@ -1044,12 +1048,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                           rehashing bug in vfs_rename_dir */
                        ceph_invalidate_dentry_lease(dn);
 
-                       /* take overwritten dentry's readdir offset */
-                       dout("dn %p gets %p offset %lld (old offset %lld)\n",
-                            req->r_old_dentry, dn, ceph_dentry(dn)->offset,
+                       /*
+                        * d_move() puts the renamed dentry at the end of
+                        * d_subdirs.  We need to assign it an appropriate
+                        * directory offset so we can behave when holding
+                        * I_COMPLETE.
+                        */
+                       ceph_set_dentry_offset(req->r_old_dentry);
+                       dout("dn %p gets new offset %lld\n", req->r_old_dentry, 
                             ceph_dentry(req->r_old_dentry)->offset);
-                       ceph_dentry(req->r_old_dentry)->offset =
-                               ceph_dentry(dn)->offset;
 
                        dn = req->r_old_dentry;  /* use old_dentry */
                        in = dn->d_inode;
@@ -1809,7 +1816,7 @@ int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
        err = ceph_do_getattr(inode, CEPH_STAT_CAP_INODE_ALL);
        if (!err) {
                generic_fillattr(inode, stat);
-               stat->ino = inode->i_ino;
+               stat->ino = ceph_translate_ino(inode->i_sb, inode->i_ino);
                if (ceph_snap(inode) != CEPH_NOSNAP)
                        stat->dev = ceph_snap(inode);
                else
index 9c5085465a63056ac493a5febe8b184163c933a6..a9e78b4a258c9adf55b7d48b8f77208619993472 100644 (file)
@@ -131,6 +131,7 @@ enum {
        Opt_rbytes,
        Opt_norbytes,
        Opt_noasyncreaddir,
+       Opt_ino32,
 };
 
 static match_table_t fsopt_tokens = {
@@ -150,6 +151,7 @@ static match_table_t fsopt_tokens = {
        {Opt_rbytes, "rbytes"},
        {Opt_norbytes, "norbytes"},
        {Opt_noasyncreaddir, "noasyncreaddir"},
+       {Opt_ino32, "ino32"},
        {-1, NULL}
 };
 
@@ -225,6 +227,9 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_noasyncreaddir:
                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
                break;
+       case Opt_ino32:
+               fsopt->flags |= CEPH_MOUNT_OPT_INO32;
+               break;
        default:
                BUG_ON(token);
        }
@@ -288,7 +293,7 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
         fsopt->sb_flags = flags;
         fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
 
-        fsopt->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
+        fsopt->rsize = CEPH_RSIZE_DEFAULT;
         fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
        fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
        fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
@@ -370,7 +375,7 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
 
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
-       if (fsopt->rsize != CEPH_MOUNT_RSIZE_DEFAULT)
+       if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
                seq_printf(m, ",rsize=%d", fsopt->rsize);
        if (fsopt->congestion_kb != default_congestion_kb())
                seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb);
index 20b907d76ae2f1be3b9e5ef4859bb1866b833c8a..619fe719968ff124771de1811b80ba165a54c2b3 100644 (file)
@@ -27,6 +27,7 @@
 #define CEPH_MOUNT_OPT_DIRSTAT         (1<<4) /* `cat dirname` for stats */
 #define CEPH_MOUNT_OPT_RBYTES          (1<<5) /* dir st_bytes = rbytes */
 #define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
+#define CEPH_MOUNT_OPT_INO32           (1<<8) /* 32 bit inos */
 
 #define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES)
 
@@ -35,6 +36,7 @@
 #define ceph_test_mount_opt(fsc, opt) \
        (!!((fsc)->mount_options->flags & CEPH_MOUNT_OPT_##opt))
 
+#define CEPH_RSIZE_DEFAULT             (512*1024) /* readahead */
 #define CEPH_MAX_READDIR_DEFAULT        1024
 #define CEPH_MAX_READDIR_BYTES_DEFAULT  (512*1024)
 #define CEPH_SNAPDIRNAME_DEFAULT        ".snap"
@@ -319,6 +321,16 @@ static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
        return container_of(inode, struct ceph_inode_info, vfs_inode);
 }
 
+static inline struct ceph_fs_client *ceph_inode_to_client(struct inode *inode)
+{
+       return (struct ceph_fs_client *)inode->i_sb->s_fs_info;
+}
+
+static inline struct ceph_fs_client *ceph_sb_to_client(struct super_block *sb)
+{
+       return (struct ceph_fs_client *)sb->s_fs_info;
+}
+
 static inline struct ceph_vino ceph_vino(struct inode *inode)
 {
        return ceph_inode(inode)->i_vino;
@@ -327,19 +339,49 @@ static inline struct ceph_vino ceph_vino(struct inode *inode)
 /*
  * ino_t is <64 bits on many architectures, blech.
  *
- * don't include snap in ino hash, at least for now.
+ *               i_ino (kernel inode)   st_ino (userspace)
+ * i386          32                     32
+ * x86_64+ino32  64                     32
+ * x86_64        64                     64
+ */
+static inline u32 ceph_ino_to_ino32(ino_t ino)
+{
+       ino ^= ino >> (sizeof(ino) * 8 - 32);
+       if (!ino)
+               ino = 1;
+       return ino;
+}
+
+/*
+ * kernel i_ino value
  */
 static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
 {
        ino_t ino = (ino_t)vino.ino;  /* ^ (vino.snap << 20); */
 #if BITS_PER_LONG == 32
-       ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
-       if (!ino)
-               ino = 1;
+       ino = ceph_ino_to_ino32(ino);
 #endif
        return ino;
 }
 
+/*
+ * user-visible ino (stat, filldir)
+ */
+#if BITS_PER_LONG == 32
+static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino)
+{
+       return ino;
+}
+#else
+static inline ino_t ceph_translate_ino(struct super_block *sb, ino_t ino)
+{
+       if (ceph_test_mount_opt(ceph_sb_to_client(sb), INO32))
+               ino = ceph_ino_to_ino32(ino);
+       return ino;
+}
+#endif
+
+
 /* for printf-style formatting */
 #define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
 
@@ -428,13 +470,6 @@ static inline loff_t ceph_make_fpos(unsigned frag, unsigned off)
        return ((loff_t)frag << 32) | (loff_t)off;
 }
 
-static inline int ceph_set_ino_cb(struct inode *inode, void *data)
-{
-       ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
-       inode->i_ino = ceph_vino_to_ino(*(struct ceph_vino *)data);
-       return 0;
-}
-
 /*
  * caps helpers
  */
@@ -503,15 +538,6 @@ extern void ceph_reservation_status(struct ceph_fs_client *client,
                                    int *total, int *avail, int *used,
                                    int *reserved, int *min);
 
-static inline struct ceph_fs_client *ceph_inode_to_client(struct inode *inode)
-{
-       return (struct ceph_fs_client *)inode->i_sb->s_fs_info;
-}
-
-static inline struct ceph_fs_client *ceph_sb_to_client(struct super_block *sb)
-{
-       return (struct ceph_fs_client *)sb->s_fs_info;
-}
 
 
 /*
index e964b1cd5dd092bda83d274da53248a50dfd0ba3..c27d236738fc08ff80d32eceabc8f412140afbb2 100644 (file)
@@ -1569,34 +1569,6 @@ int cifs_fsync(struct file *file, int datasync)
        return rc;
 }
 
-/* static void cifs_sync_page(struct page *page)
-{
-       struct address_space *mapping;
-       struct inode *inode;
-       unsigned long index = page->index;
-       unsigned int rpages = 0;
-       int rc = 0;
-
-       cFYI(1, "sync page %p", page);
-       mapping = page->mapping;
-       if (!mapping)
-               return 0;
-       inode = mapping->host;
-       if (!inode)
-               return; */
-
-/*     fill in rpages then
-       result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
-
-/*     cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index);
-
-#if 0
-       if (rc < 0)
-               return rc;
-       return 0;
-#endif
-} */
-
 /*
  * As file closes, flush all cached write data for this inode checking
  * for write behind errors.
@@ -2510,7 +2482,6 @@ const struct address_space_operations cifs_addr_ops = {
        .set_page_dirty = __set_page_dirty_nobuffers,
        .releasepage = cifs_release_page,
        .invalidatepage = cifs_invalidate_page,
-       /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
 
@@ -2528,6 +2499,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
        .set_page_dirty = __set_page_dirty_nobuffers,
        .releasepage = cifs_release_page,
        .invalidatepage = cifs_invalidate_page,
-       /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
index 6c22e61da39779be11ef3e9765de1b1df17743d4..1bab69a0d347696d28f854f6b1928f09937ac5f5 100644 (file)
@@ -9,4 +9,4 @@ coda-objs := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o \
 
 # If you want debugging output, please uncomment the following line.
 
-# EXTRA_CFLAGS += -DDEBUG -DDEBUG_SMB_MALLOC=1
+# ccflags-y := -DDEBUG -DDEBUG_SMB_MALLOC=1
index c6405ce3c50ecb92f3b800b3f750dd96835d41f9..af56ad56a89ae68982036755438e3a2e22e9798f 100644 (file)
@@ -13,7 +13,6 @@
 
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *fs_table_header;
-#endif
 
 static ctl_table coda_table[] = {
        {
@@ -40,7 +39,6 @@ static ctl_table coda_table[] = {
        {}
 };
 
-#ifdef CONFIG_SYSCTL
 static ctl_table fs_table[] = {
        {
                .procname       = "coda",
@@ -49,22 +47,27 @@ static ctl_table fs_table[] = {
        },
        {}
 };
-#endif
 
 void coda_sysctl_init(void)
 {
-#ifdef CONFIG_SYSCTL
        if ( !fs_table_header )
                fs_table_header = register_sysctl_table(fs_table);
-#endif
 }
 
 void coda_sysctl_clean(void)
 {
-#ifdef CONFIG_SYSCTL
        if ( fs_table_header ) {
                unregister_sysctl_table(fs_table_header);
                fs_table_header = NULL;
        }
-#endif
 }
+
+#else
+void coda_sysctl_init(void)
+{
+}
+
+void coda_sysctl_clean(void)
+{
+}
+#endif
index c6d31a3bab8863af2c5403e487f1cfc23bf63310..72fe6cda9108a162177e91093514a68854323f5a 100644 (file)
@@ -1671,9 +1671,6 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-#define MAX_SELECT_SECONDS \
-       ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
 int compat_core_sys_select(int n, compat_ulong_t __user *inp,
        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
        struct timespec *end_time)
index 1bb547c9cad6d98d5c2816a3bf01d46481a72224..2f27e578d4660e89c1215d7a9edc2dffa6439c89 100644 (file)
@@ -479,6 +479,7 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
        struct dentry *root = sb->s_root;
        struct pts_fs_info *fsi = DEVPTS_SB(sb);
        struct pts_mount_opts *opts = &fsi->mount_opts;
+       int ret = 0;
        char s[12];
 
        /* We're supposed to be given the slave end of a pty */
@@ -501,14 +502,17 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
        mutex_lock(&root->d_inode->i_mutex);
 
        dentry = d_alloc_name(root, s);
-       if (!IS_ERR(dentry)) {
+       if (dentry) {
                d_add(dentry, inode);
                fsnotify_create(root->d_inode, dentry);
+       } else {
+               iput(inode);
+               ret = -ENOMEM;
        }
 
        mutex_unlock(&root->d_inode->i_mutex);
 
-       return 0;
+       return ret;
 }
 
 struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
@@ -544,17 +548,12 @@ void devpts_pty_kill(struct tty_struct *tty)
        mutex_lock(&root->d_inode->i_mutex);
 
        dentry = d_find_alias(inode);
-       if (IS_ERR(dentry))
-               goto out;
-
-       if (dentry) {
-               inode->i_nlink--;
-               d_delete(dentry);
-               dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
-       }
 
+       inode->i_nlink--;
+       d_delete(dentry);
+       dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
        dput(dentry);           /* d_find_alias above */
-out:
+
        mutex_unlock(&root->d_inode->i_mutex);
 }
 
index dcb5577cde1de8ebdf57106a91248c17db81b823..ac5f164170e386fe242eb758345173c6e8e8697c 100644 (file)
@@ -1110,11 +1110,8 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
            ((rw & READ) || (dio->result == dio->size)))
                ret = -EIOCBQUEUED;
 
-       if (ret != -EIOCBQUEUED) {
-               /* All IO is now issued, send it on its way */
-               blk_run_address_space(inode->i_mapping);
+       if (ret != -EIOCBQUEUED)
                dio_await_completion(dio);
-       }
 
        /*
         * Sync will always be dropping the final ref and completing the
@@ -1176,7 +1173,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        struct dio *dio;
 
        if (rw & WRITE)
-               rw = WRITE_ODIRECT_PLUG;
+               rw = WRITE_ODIRECT;
 
        if (bdev)
                bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev));
index 2195c213ab2f556b1aecf106ffa693c2249f850a..98b77c89494caf7c364272194316d431e10cfcef 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/writeback.h>
 #include <linux/sysctl.h>
 #include <linux/gfp.h>
+#include "internal.h"
 
 /* A global variable is a bit ugly, but it keeps the code simple */
 int sysctl_drop_caches;
@@ -16,20 +17,23 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
 {
        struct inode *inode, *toput_inode = NULL;
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
-                       continue;
-               if (inode->i_mapping->nrpages == 0)
+               spin_lock(&inode->i_lock);
+               if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
+                   (inode->i_mapping->nrpages == 0)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
                __iget(inode);
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_sb_list_lock);
                invalidate_mapping_pages(inode->i_mapping, 0, -1);
                iput(toput_inode);
                toput_inode = inode;
-               spin_lock(&inode_lock);
+               spin_lock(&inode_sb_list_lock);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
        iput(toput_inode);
 }
 
@@ -45,7 +49,11 @@ static void drop_slab(void)
 int drop_caches_sysctl_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
-       proc_dointvec_minmax(table, write, buffer, length, ppos);
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+       if (ret)
+               return ret;
        if (write) {
                if (sysctl_drop_caches & 1)
                        iterate_supers(drop_pagecache_sb, NULL);
index a8e7797b947795f2ef70a05c82a204fd493ba472..9c13412e6c99c78d11c3a89a42e007c82fb1b58b 100644 (file)
@@ -23,7 +23,6 @@ static sector_t _efs_bmap(struct address_space *mapping, sector_t block)
 }
 static const struct address_space_operations efs_aops = {
        .readpage = efs_readpage,
-       .sync_page = block_sync_page,
        .bmap = _efs_bmap
 };
 
index ff12f7ac73ef703a4bbd9ab3ca995f87785677bf..ed38801b57a711075ae12dda582ca25c54d2257b 100644 (file)
@@ -315,6 +315,19 @@ static void ep_nested_calls_init(struct nested_calls *ncalls)
        spin_lock_init(&ncalls->lock);
 }
 
+/**
+ * ep_events_available - Checks if ready events might be available.
+ *
+ * @ep: Pointer to the eventpoll context.
+ *
+ * Returns: Returns a value different than zero if ready events are available,
+ *          or zero otherwise.
+ */
+static inline int ep_events_available(struct eventpoll *ep)
+{
+       return !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR;
+}
+
 /**
  * ep_call_nested - Perform a bound (possibly) nested call, by checking
  *                  that the recursion limit is not exceeded, and that
@@ -1135,12 +1148,29 @@ static inline struct timespec ep_set_mstimeout(long ms)
        return timespec_add_safe(now, ts);
 }
 
+/**
+ * ep_poll - Retrieves ready events, and delivers them to the caller supplied
+ *           event buffer.
+ *
+ * @ep: Pointer to the eventpoll context.
+ * @events: Pointer to the userspace buffer where the ready events should be
+ *          stored.
+ * @maxevents: Size (in terms of number of events) of the caller event buffer.
+ * @timeout: Maximum timeout for the ready events fetch operation, in
+ *           milliseconds. If the @timeout is zero, the function will not block,
+ *           while if the @timeout is less than zero, the function will block
+ *           until at least one event has been retrieved (or an error
+ *           occurred).
+ *
+ * Returns: Returns the number of ready events which have been fetched, or an
+ *          error code, in case of error.
+ */
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout)
 {
-       int res, eavail, timed_out = 0;
+       int res = 0, eavail, timed_out = 0;
        unsigned long flags;
-       long slack;
+       long slack = 0;
        wait_queue_t wait;
        ktime_t expires, *to = NULL;
 
@@ -1151,14 +1181,19 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                to = &expires;
                *to = timespec_to_ktime(end_time);
        } else if (timeout == 0) {
+               /*
+                * Avoid the unnecessary trip to the wait queue loop, if the
+                * caller specified a non blocking operation.
+                */
                timed_out = 1;
+               spin_lock_irqsave(&ep->lock, flags);
+               goto check_events;
        }
 
-retry:
+fetch_events:
        spin_lock_irqsave(&ep->lock, flags);
 
-       res = 0;
-       if (list_empty(&ep->rdllist)) {
+       if (!ep_events_available(ep)) {
                /*
                 * We don't have any available event to return to the caller.
                 * We need to sleep here, and we will be wake up by
@@ -1174,7 +1209,7 @@ retry:
                         * to TASK_INTERRUPTIBLE before doing the checks.
                         */
                        set_current_state(TASK_INTERRUPTIBLE);
-                       if (!list_empty(&ep->rdllist) || timed_out)
+                       if (ep_events_available(ep) || timed_out)
                                break;
                        if (signal_pending(current)) {
                                res = -EINTR;
@@ -1191,8 +1226,9 @@ retry:
 
                set_current_state(TASK_RUNNING);
        }
+check_events:
        /* Is it worth to try to dig for events ? */
-       eavail = !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR;
+       eavail = ep_events_available(ep);
 
        spin_unlock_irqrestore(&ep->lock, flags);
 
@@ -1203,7 +1239,7 @@ retry:
         */
        if (!res && eavail &&
            !(res = ep_send_events(ep, events, maxevents)) && !timed_out)
-               goto retry;
+               goto fetch_events;
 
        return res;
 }
index ba99e1abb1aa3427aca0e95f116e4deaa85ff793..5e62d26a4fecec227d81700b0b9fd6542b715ad6 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1875,7 +1875,7 @@ static void wait_for_dump_helpers(struct file *file)
 
 
 /*
- * uhm_pipe_setup
+ * umh_pipe_setup
  * helper function to customize the process used
  * to collect the core in userspace.  Specifically
  * it sets up a pipe and installs it as fd 0 (stdin)
index f0d520312d8b6ed1c3b35dc00675f1a84c0ed263..5e74ad3d40090e66a5951cad3435a7570b6f8777 100644 (file)
 #define EXOFS_ROOT_ID  0x10002 /* object ID for root directory */
 
 /* exofs Application specific page/attribute */
+/* Inode attrs */
 # define EXOFS_APAGE_FS_DATA   (OSD_APAGE_APP_DEFINED_FIRST + 3)
 # define EXOFS_ATTR_INODE_DATA 1
 # define EXOFS_ATTR_INODE_FILE_LAYOUT  2
 # define EXOFS_ATTR_INODE_DIR_LAYOUT   3
+/* Partition attrs */
+# define EXOFS_APAGE_SB_DATA   (0xF0000000U + 3)
+# define EXOFS_ATTR_SB_STATS   1
 
 /*
  * The maximum number of files we can have is limited by the size of the
@@ -86,8 +90,8 @@ enum {
  */
 enum {EXOFS_FSCB_VER = 1, EXOFS_DT_VER = 1};
 struct exofs_fscb {
-       __le64  s_nextid;       /* Highest object ID used */
-       __le64  s_numfiles;     /* Number of files on fs */
+       __le64  s_nextid;       /* Only used after mkfs */
+       __le64  s_numfiles;     /* Only used after mkfs */
        __le32  s_version;      /* == EXOFS_FSCB_VER */
        __le16  s_magic;        /* Magic signature */
        __le16  s_newfs;        /* Non-zero if this is a new fs */
@@ -97,6 +101,16 @@ struct exofs_fscb {
        __le64  s_dev_table_count; /* == 0 means no dev_table */
 } __packed;
 
+/*
+ * This struct is set on the FS partition's attributes.
+ * [EXOFS_APAGE_SB_DATA, EXOFS_ATTR_SB_STATS] and is written together
+ * with the create command, to atomically persist the sb writeable information.
+ */
+struct exofs_sb_stats {
+       __le64  s_nextid;       /* Highest object ID used */
+       __le64  s_numfiles;     /* Number of files on fs */
+} __packed;
+
 /*
  * Describes the raid used in the FS. It is part of the device table.
  * This here is taken from the pNFS-objects definition. In exofs we
index dcc941d82d67dc60448c8d97521850034df15b00..d0941c6a1f72ede1fa9c57c32d7bdaae639eb8e1 100644 (file)
@@ -124,7 +124,7 @@ out:
 
 Ebadsize:
        EXOFS_ERR("ERROR [exofs_check_page]: "
-               "size of directory #%lu is not a multiple of chunk size",
+               "size of directory(0x%lx) is not a multiple of chunk size\n",
                dir->i_ino
        );
        goto fail;
@@ -142,8 +142,8 @@ Espan:
        goto bad_entry;
 bad_entry:
        EXOFS_ERR(
-               "ERROR [exofs_check_page]: bad entry in directory #%lu: %s - "
-               "offset=%lu, inode=%llu, rec_len=%d, name_len=%d",
+               "ERROR [exofs_check_page]: bad entry in directory(0x%lx): %s - "
+               "offset=%lu, inode=0x%llu, rec_len=%d, name_len=%d\n",
                dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
                _LLU(le64_to_cpu(p->inode_no)),
                rec_len, p->name_len);
@@ -151,8 +151,8 @@ bad_entry:
 Eend:
        p = (struct exofs_dir_entry *)(kaddr + offs);
        EXOFS_ERR("ERROR [exofs_check_page]: "
-               "entry in directory #%lu spans the page boundary"
-               "offset=%lu, inode=%llu",
+               "entry in directory(0x%lx) spans the page boundary"
+               "offset=%lu, inode=0x%llx\n",
                dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
                _LLU(le64_to_cpu(p->inode_no)));
 fail:
@@ -261,9 +261,8 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                struct page *page = exofs_get_page(inode, n);
 
                if (IS_ERR(page)) {
-                       EXOFS_ERR("ERROR: "
-                                  "bad page in #%lu",
-                                  inode->i_ino);
+                       EXOFS_ERR("ERROR: bad page in directory(0x%lx)\n",
+                                 inode->i_ino);
                        filp->f_pos += PAGE_CACHE_SIZE - offset;
                        return PTR_ERR(page);
                }
@@ -283,7 +282,8 @@ exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                for (; (char *)de <= limit; de = exofs_next_entry(de)) {
                        if (de->rec_len == 0) {
                                EXOFS_ERR("ERROR: "
-                                       "zero-length directory entry");
+                                    "zero-length entry in directory(0x%lx)\n",
+                                    inode->i_ino);
                                exofs_put_page(page);
                                return -EIO;
                        }
@@ -342,9 +342,9 @@ struct exofs_dir_entry *exofs_find_entry(struct inode *dir,
                        kaddr += exofs_last_byte(dir, n) - reclen;
                        while ((char *) de <= kaddr) {
                                if (de->rec_len == 0) {
-                                       EXOFS_ERR(
-                                               "ERROR: exofs_find_entry: "
-                                               "zero-length directory entry");
+                                       EXOFS_ERR("ERROR: zero-length entry in "
+                                                 "directory(0x%lx)\n",
+                                                 dir->i_ino);
                                        exofs_put_page(page);
                                        goto out;
                                }
@@ -472,7 +472,8 @@ int exofs_add_link(struct dentry *dentry, struct inode *inode)
                        }
                        if (de->rec_len == 0) {
                                EXOFS_ERR("ERROR: exofs_add_link: "
-                                       "zero-length directory entry");
+                                     "zero-length entry in directory(0x%lx)\n",
+                                     inode->i_ino);
                                err = -EIO;
                                goto out_unlock;
                        }
@@ -491,7 +492,8 @@ int exofs_add_link(struct dentry *dentry, struct inode *inode)
                exofs_put_page(page);
        }
 
-       EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=%p", dentry, inode);
+       EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=0x%lx\n",
+                 dentry, inode->i_ino);
        return -EINVAL;
 
 got_it:
@@ -542,7 +544,8 @@ int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
        while (de < dir) {
                if (de->rec_len == 0) {
                        EXOFS_ERR("ERROR: exofs_delete_entry:"
-                               "zero-length directory entry");
+                                 "zero-length entry in directory(0x%lx)\n",
+                                 inode->i_ino);
                        err = -EIO;
                        goto out;
                }
index 2dc925fa10106ca3a5e17f42ddea94ff316c0b5f..c965806c2821c0900b05f17bb450210c655525e5 100644 (file)
@@ -77,7 +77,7 @@ struct exofs_layout {
  * our extension to the in-memory superblock
  */
 struct exofs_sb_info {
-       struct exofs_fscb s_fscb;               /* Written often, pre-allocate*/
+       struct exofs_sb_stats s_ess;            /* Written often, pre-allocate*/
        int             s_timeout;              /* timeout for OSD operations */
        uint64_t        s_nextid;               /* highest object ID used     */
        uint32_t        s_numfiles;             /* number of files on fs      */
@@ -256,6 +256,8 @@ static inline int exofs_oi_read(struct exofs_i_info *oi,
 }
 
 /* inode.c               */
+unsigned exofs_max_io_pages(struct exofs_layout *layout,
+                           unsigned expected_pages);
 int exofs_setattr(struct dentry *, struct iattr *);
 int exofs_write_begin(struct file *file, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
@@ -279,7 +281,7 @@ int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
                    struct inode *);
 
 /* super.c               */
-int exofs_sync_fs(struct super_block *sb, int wait);
+int exofs_sbi_write_stats(struct exofs_sb_info *sbi);
 
 /*********************
  * operation vectors *
index b905c79b4f0afc88b7a1997009960f09f50f595f..45ca323d8363440b1c0641c6b29302911677eb9d 100644 (file)
@@ -45,22 +45,8 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
 static int exofs_file_fsync(struct file *filp, int datasync)
 {
        int ret;
-       struct inode *inode = filp->f_mapping->host;
-       struct super_block *sb;
-
-       if (!(inode->i_state & I_DIRTY))
-               return 0;
-       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
-               return 0;
-
-       ret = sync_inode_metadata(inode, 1);
-
-       /* This is a good place to write the sb */
-       /* TODO: Sechedule an sb-sync on create */
-       sb = inode->i_sb;
-       if (sb->s_dirt)
-               exofs_sync_fs(sb, 1);
 
+       ret = sync_inode_metadata(filp->f_mapping->host, 1);
        return ret;
 }
 
index a7555238c41aaf942237b2aafb780c8605244812..8472c098445ddbe332c0ee33aa10988cb03a9b15 100644 (file)
@@ -43,6 +43,17 @@ enum { BIO_MAX_PAGES_KMALLOC =
                PAGE_SIZE / sizeof(struct page *),
 };
 
+unsigned exofs_max_io_pages(struct exofs_layout *layout,
+                           unsigned expected_pages)
+{
+       unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC);
+
+       /* TODO: easily support bio chaining */
+       pages =  min_t(unsigned, pages,
+                      layout->group_width * BIO_MAX_PAGES_KMALLOC);
+       return pages;
+}
+
 struct page_collect {
        struct exofs_sb_info *sbi;
        struct inode *inode;
@@ -97,8 +108,7 @@ static void _pcol_reset(struct page_collect *pcol)
 
 static int pcol_try_alloc(struct page_collect *pcol)
 {
-       unsigned pages = min_t(unsigned, pcol->expected_pages,
-                         MAX_PAGES_KMALLOC);
+       unsigned pages;
 
        if (!pcol->ios) { /* First time allocate io_state */
                int ret = exofs_get_io_state(&pcol->sbi->layout, &pcol->ios);
@@ -108,8 +118,7 @@ static int pcol_try_alloc(struct page_collect *pcol)
        }
 
        /* TODO: easily support bio chaining */
-       pages =  min_t(unsigned, pages,
-                      pcol->sbi->layout.group_width * BIO_MAX_PAGES_KMALLOC);
+       pages =  exofs_max_io_pages(&pcol->sbi->layout, pcol->expected_pages);
 
        for (; pages; pages >>= 1) {
                pcol->pages = kmalloc(pages * sizeof(struct page *),
@@ -350,8 +359,10 @@ static int readpage_strip(void *data, struct page *page)
 
                if (!pcol->read_4_write)
                        unlock_page(page);
-               EXOFS_DBGMSG("readpage_strip(0x%lx, 0x%lx) empty page,"
-                            " splitting\n", inode->i_ino, page->index);
+               EXOFS_DBGMSG("readpage_strip(0x%lx) empty page len=%zx "
+                            "read_4_write=%d index=0x%lx end_index=0x%lx "
+                            "splitting\n", inode->i_ino, len,
+                            pcol->read_4_write, page->index, end_index);
 
                return read_exec(pcol);
        }
@@ -722,11 +733,28 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
 
         /* read modify write */
        if (!PageUptodate(page) && (len != PAGE_CACHE_SIZE)) {
+               loff_t i_size = i_size_read(mapping->host);
+               pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+               size_t rlen;
+
+               if (page->index < end_index)
+                       rlen = PAGE_CACHE_SIZE;
+               else if (page->index == end_index)
+                       rlen = i_size & ~PAGE_CACHE_MASK;
+               else
+                       rlen = 0;
+
+               if (!rlen) {
+                       clear_highpage(page);
+                       SetPageUptodate(page);
+                       goto out;
+               }
+
                ret = _readpage(page, true);
                if (ret) {
                        /*SetPageError was done by _readpage. Is it ok?*/
                        unlock_page(page);
-                       EXOFS_DBGMSG("__readpage_filler failed\n");
+                       EXOFS_DBGMSG("__readpage failed\n");
                }
        }
 out:
@@ -795,7 +823,6 @@ const struct address_space_operations exofs_aops = {
        .direct_IO      = NULL, /* TODO: Should be trivial to do */
 
        /* With these NULL has special meaning or default is not exported */
-       .sync_page      = NULL,
        .get_xip_mem    = NULL,
        .migratepage    = NULL,
        .launder_page   = NULL,
@@ -1030,6 +1057,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
        }
 
+       inode->i_mapping->backing_dev_info = sb->s_bdi;
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &exofs_file_inode_operations;
                inode->i_fop = &exofs_file_operations;
@@ -1073,6 +1101,7 @@ int __exofs_wait_obj_created(struct exofs_i_info *oi)
        }
        return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
 }
+
 /*
  * Callback function from exofs_new_inode().  The important thing is that we
  * set the obj_created flag so that other methods know that the object exists on
@@ -1130,7 +1159,7 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
 
        sbi = sb->s_fs_info;
 
-       sb->s_dirt = 1;
+       inode->i_mapping->backing_dev_info = sb->s_bdi;
        inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
        inode->i_blkbits = EXOFS_BLKSHIFT;
@@ -1141,6 +1170,8 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
        spin_unlock(&sbi->s_next_gen_lock);
        insert_inode_hash(inode);
 
+       exofs_sbi_write_stats(sbi); /* Make sure new sbi->s_nextid is on disk */
+
        mark_inode_dirty(inode);
 
        ret = exofs_get_io_state(&sbi->layout, &ios);
@@ -1271,7 +1302,8 @@ out:
 
 int exofs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       return exofs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
+       /* FIXME: fix fsync and use wbc->sync_mode == WB_SYNC_ALL */
+       return exofs_update_inode(inode, 1);
 }
 
 /*
index 8c6c4669b381699d78b52e541c7ad59fd82a9c1b..06065bd37fc339070948a141cd8063c9d39af8ad 100644 (file)
@@ -48,6 +48,7 @@
  * struct to hold what we get from mount options
  */
 struct exofs_mountopt {
+       bool is_osdname;
        const char *dev_name;
        uint64_t pid;
        int timeout;
@@ -56,7 +57,7 @@ struct exofs_mountopt {
 /*
  * exofs-specific mount-time options.
  */
-enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
+enum { Opt_name, Opt_pid, Opt_to, Opt_err };
 
 /*
  * Our mount-time options.  These should ideally be 64-bit unsigned, but the
@@ -64,6 +65,7 @@ enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err };
  * sufficient for most applications now.
  */
 static match_table_t tokens = {
+       {Opt_name, "osdname=%s"},
        {Opt_pid, "pid=%u"},
        {Opt_to, "to=%u"},
        {Opt_err, NULL}
@@ -94,6 +96,14 @@ static int parse_options(char *options, struct exofs_mountopt *opts)
 
                token = match_token(p, tokens, args);
                switch (token) {
+               case Opt_name:
+                       opts->dev_name = match_strdup(&args[0]);
+                       if (unlikely(!opts->dev_name)) {
+                               EXOFS_ERR("Error allocating dev_name");
+                               return -ENOMEM;
+                       }
+                       opts->is_osdname = true;
+                       break;
                case Opt_pid:
                        if (0 == match_strlcpy(str, &args[0], sizeof(str)))
                                return -EINVAL;
@@ -203,6 +213,101 @@ static void destroy_inodecache(void)
 static const struct super_operations exofs_sops;
 static const struct export_operations exofs_export_ops;
 
+static const struct osd_attr g_attr_sb_stats = ATTR_DEF(
+       EXOFS_APAGE_SB_DATA,
+       EXOFS_ATTR_SB_STATS,
+       sizeof(struct exofs_sb_stats));
+
+static int __sbi_read_stats(struct exofs_sb_info *sbi)
+{
+       struct osd_attr attrs[] = {
+               [0] = g_attr_sb_stats,
+       };
+       struct exofs_io_state *ios;
+       int ret;
+
+       ret = exofs_get_io_state(&sbi->layout, &ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               return ret;
+       }
+
+       ios->cred = sbi->s_cred;
+
+       ios->in_attr = attrs;
+       ios->in_attr_len = ARRAY_SIZE(attrs);
+
+       ret = exofs_sbi_read(ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("Error reading super_block stats => %d\n", ret);
+               goto out;
+       }
+
+       ret = extract_attr_from_ios(ios, &attrs[0]);
+       if (ret) {
+               EXOFS_ERR("%s: extract_attr of sb_stats failed\n", __func__);
+               goto out;
+       }
+       if (attrs[0].len) {
+               struct exofs_sb_stats *ess;
+
+               if (unlikely(attrs[0].len != sizeof(*ess))) {
+                       EXOFS_ERR("%s: Wrong version of exofs_sb_stats "
+                                 "size(%d) != expected(%zd)\n",
+                                 __func__, attrs[0].len, sizeof(*ess));
+                       goto out;
+               }
+
+               ess = attrs[0].val_ptr;
+               sbi->s_nextid = le64_to_cpu(ess->s_nextid);
+               sbi->s_numfiles = le32_to_cpu(ess->s_numfiles);
+       }
+
+out:
+       exofs_put_io_state(ios);
+       return ret;
+}
+
+static void stats_done(struct exofs_io_state *ios, void *p)
+{
+       exofs_put_io_state(ios);
+       /* Good thanks nothing to do anymore */
+}
+
+/* Asynchronously write the stats attribute */
+int exofs_sbi_write_stats(struct exofs_sb_info *sbi)
+{
+       struct osd_attr attrs[] = {
+               [0] = g_attr_sb_stats,
+       };
+       struct exofs_io_state *ios;
+       int ret;
+
+       ret = exofs_get_io_state(&sbi->layout, &ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__);
+               return ret;
+       }
+
+       sbi->s_ess.s_nextid   = cpu_to_le64(sbi->s_nextid);
+       sbi->s_ess.s_numfiles = cpu_to_le64(sbi->s_numfiles);
+       attrs[0].val_ptr = &sbi->s_ess;
+
+       ios->cred = sbi->s_cred;
+       ios->done = stats_done;
+       ios->private = sbi;
+       ios->out_attr = attrs;
+       ios->out_attr_len = ARRAY_SIZE(attrs);
+
+       ret = exofs_sbi_write(ios);
+       if (unlikely(ret)) {
+               EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
+               exofs_put_io_state(ios);
+       }
+
+       return ret;
+}
+
 /*
  * Write the superblock to the OSD
  */
@@ -213,18 +318,25 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        struct exofs_io_state *ios;
        int ret = -ENOMEM;
 
-       lock_super(sb);
+       fscb = kmalloc(sizeof(*fscb), GFP_KERNEL);
+       if (unlikely(!fscb))
+               return -ENOMEM;
+
        sbi = sb->s_fs_info;
-       fscb = &sbi->s_fscb;
 
+       /* NOTE: We no longer dirty the super_block anywhere in exofs. The
+        * reason we write the fscb here on unmount is so we can stay backwards
+        * compatible with fscb->s_version == 1. (What we are not compatible
+        * with is if a new version FS crashed and then we try to mount an old
+        * version). Otherwise the exofs_fscb is read-only from mkfs time. All
+        * the writeable info is set in exofs_sbi_write_stats() above.
+        */
        ret = exofs_get_io_state(&sbi->layout, &ios);
-       if (ret)
+       if (unlikely(ret))
                goto out;
 
-       /* Note: We only write the changing part of the fscb. .i.e upto the
-        *       the fscb->s_dev_table_oid member. There is no read-modify-write
-        *       here.
-        */
+       lock_super(sb);
+
        ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);
        memset(fscb, 0, ios->length);
        fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
@@ -239,16 +351,17 @@ int exofs_sync_fs(struct super_block *sb, int wait)
        ios->cred = sbi->s_cred;
 
        ret = exofs_sbi_write(ios);
-       if (unlikely(ret)) {
+       if (unlikely(ret))
                EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__);
-               goto out;
-       }
-       sb->s_dirt = 0;
+       else
+               sb->s_dirt = 0;
+
 
+       unlock_super(sb);
 out:
        EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret);
        exofs_put_io_state(ios);
-       unlock_super(sb);
+       kfree(fscb);
        return ret;
 }
 
@@ -292,13 +405,14 @@ static void exofs_put_super(struct super_block *sb)
        int num_pend;
        struct exofs_sb_info *sbi = sb->s_fs_info;
 
-       if (sb->s_dirt)
-               exofs_write_super(sb);
-
        /* make sure there are no pending commands */
        for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0;
             num_pend = atomic_read(&sbi->s_curr_pending)) {
                wait_queue_head_t wq;
+
+               printk(KERN_NOTICE "%s: !!Pending operations in flight. "
+                      "This is a BUG. please report to osd-dev@open-osd.org\n",
+                      __func__);
                init_waitqueue_head(&wq);
                wait_event_timeout(wq,
                                  (atomic_read(&sbi->s_curr_pending) == 0),
@@ -390,6 +504,23 @@ static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs,
        return 0;
 }
 
+static unsigned __ra_pages(struct exofs_layout *layout)
+{
+       const unsigned _MIN_RA = 32; /* min 128K read-ahead */
+       unsigned ra_pages = layout->group_width * layout->stripe_unit /
+                               PAGE_SIZE;
+       unsigned max_io_pages = exofs_max_io_pages(layout, ~0);
+
+       ra_pages *= 2; /* two stripes */
+       if (ra_pages < _MIN_RA)
+               ra_pages = roundup(_MIN_RA, ra_pages / 2);
+
+       if (ra_pages > max_io_pages)
+               ra_pages = max_io_pages;
+
+       return ra_pages;
+}
+
 /* @odi is valid only as long as @fscb_dev is valid */
 static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
                             struct osd_dev_info *odi)
@@ -495,7 +626,7 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi,
                }
 
                od = osduld_info_lookup(&odi);
-               if (unlikely(IS_ERR(od))) {
+               if (IS_ERR(od)) {
                        ret = PTR_ERR(od);
                        EXOFS_ERR("ERROR: device requested is not found "
                                  "osd_name-%s =>%d\n", odi.osdname, ret);
@@ -558,9 +689,17 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_bdi;
 
        /* use mount options to fill superblock */
-       od = osduld_path_lookup(opts->dev_name);
+       if (opts->is_osdname) {
+               struct osd_dev_info odi = {.systemid_len = 0};
+
+               odi.osdname_len = strlen(opts->dev_name);
+               odi.osdname = (u8 *)opts->dev_name;
+               od = osduld_info_lookup(&odi);
+       } else {
+               od = osduld_path_lookup(opts->dev_name);
+       }
        if (IS_ERR(od)) {
-               ret = PTR_ERR(od);
+               ret = -EINVAL;
                goto free_sbi;
        }
 
@@ -594,6 +733,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_sbi;
 
        sb->s_magic = le16_to_cpu(fscb.s_magic);
+       /* NOTE: we read below to be backward compatible with old versions */
        sbi->s_nextid = le64_to_cpu(fscb.s_nextid);
        sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles);
 
@@ -604,7 +744,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                ret = -EINVAL;
                goto free_sbi;
        }
-       if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) {
+       if (le32_to_cpu(fscb.s_version) > EXOFS_FSCB_VER) {
                EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n",
                          EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version));
                ret = -EINVAL;
@@ -622,7 +762,10 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
                        goto free_sbi;
        }
 
+       __sbi_read_stats(sbi);
+
        /* set up operation vectors */
+       sbi->bdi.ra_pages = __ra_pages(&sbi->layout);
        sb->s_bdi = &sbi->bdi;
        sb->s_fs_info = sbi;
        sb->s_op = &exofs_sops;
@@ -652,6 +795,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)
 
        _exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0],
                            sbi->layout.s_pid);
+       if (opts->is_osdname)
+               kfree(opts->dev_name);
        return 0;
 
 free_sbi:
@@ -660,6 +805,8 @@ free_bdi:
        EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n",
                  opts->dev_name, sbi->layout.s_pid, ret);
        exofs_free_sbi(sbi);
+       if (opts->is_osdname)
+               kfree(opts->dev_name);
        return ret;
 }
 
@@ -677,7 +824,8 @@ static struct dentry *exofs_mount(struct file_system_type *type,
        if (ret)
                return ERR_PTR(ret);
 
-       opts.dev_name = dev_name;
+       if (!opts.dev_name)
+               opts.dev_name = dev_name;
        return mount_nodev(type, flags, &opts, exofs_fill_super);
 }
 
index 7b4180554a62a3c9ce2807487477d93485602bf3..abea5a17c76444edced01a069ccd2ddfc57acc6f 100644 (file)
@@ -406,7 +406,7 @@ ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
                return -EINVAL;
        if (!test_opt(dentry->d_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(dentry->d_inode))
+       if (!inode_owner_or_capable(dentry->d_inode))
                return -EPERM;
 
        if (value) {
index 1b48c337087293bfb95733d52def539f68ff219d..645be9e7ee4713b9bfc6fc7c11095ce57addcd09 100644 (file)
@@ -174,3 +174,9 @@ ext2_group_first_block_no(struct super_block *sb, unsigned long group_no)
        return group_no * (ext2_fsblk_t)EXT2_BLOCKS_PER_GROUP(sb) +
                le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block);
 }
+
+#define ext2_set_bit   __test_and_set_bit_le
+#define ext2_clear_bit __test_and_clear_bit_le
+#define ext2_test_bit  test_bit_le
+#define ext2_find_first_zero_bit       find_first_zero_bit_le
+#define ext2_find_next_zero_bit                find_next_zero_bit_le
index 40ad210a5049a6eed9b184b3c30750ce6951fa46..c47f706878b5f1c8befcd65e5dc9c68b46382200 100644 (file)
@@ -860,7 +860,6 @@ const struct address_space_operations ext2_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext2_write_begin,
        .write_end              = ext2_write_end,
        .bmap                   = ext2_bmap,
@@ -880,7 +879,6 @@ const struct address_space_operations ext2_nobh_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
        .writepage              = ext2_nobh_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext2_nobh_write_begin,
        .write_end              = nobh_write_end,
        .bmap                   = ext2_bmap,
index e7431309bdca9b7c873a34718263f14097b81ff5..f81e250ac5c4d62d7616a8f724d30ae8ae9265e7 100644 (file)
@@ -39,7 +39,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (ret)
                        return ret;
 
-               if (!is_owner_or_cap(inode)) {
+               if (!inode_owner_or_capable(inode)) {
                        ret = -EACCES;
                        goto setflags_out;
                }
@@ -89,7 +89,7 @@ setflags_out:
        case EXT2_IOC_GETVERSION:
                return put_user(inode->i_generation, (int __user *) arg);
        case EXT2_IOC_SETVERSION:
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
                ret = mnt_want_write(filp->f_path.mnt);
                if (ret)
@@ -115,7 +115,7 @@ setflags_out:
                if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
                        return -ENOTTY;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                if (get_user(rsv_window_size, (int __user *)arg))
index e4fa49e6c539310c2a4c67de8ae8fb7f647c7ec2..9d021c0d472a3666bc8bf77122a5ed09f877060d 100644 (file)
@@ -435,7 +435,7 @@ ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
                return -EINVAL;
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        if (value) {
index ae94f6d949f526d04fc0e2dcb8983622eeab8fa0..fe2541d250e44d0f9fe8a79f7ecbe39f5fbca34c 100644 (file)
@@ -1894,7 +1894,6 @@ static const struct address_space_operations ext3_ordered_aops = {
        .readpage               = ext3_readpage,
        .readpages              = ext3_readpages,
        .writepage              = ext3_ordered_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext3_write_begin,
        .write_end              = ext3_ordered_write_end,
        .bmap                   = ext3_bmap,
@@ -1910,7 +1909,6 @@ static const struct address_space_operations ext3_writeback_aops = {
        .readpage               = ext3_readpage,
        .readpages              = ext3_readpages,
        .writepage              = ext3_writeback_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext3_write_begin,
        .write_end              = ext3_writeback_write_end,
        .bmap                   = ext3_bmap,
@@ -1926,7 +1924,6 @@ static const struct address_space_operations ext3_journalled_aops = {
        .readpage               = ext3_readpage,
        .readpages              = ext3_readpages,
        .writepage              = ext3_journalled_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext3_write_begin,
        .write_end              = ext3_journalled_write_end,
        .set_page_dirty         = ext3_journalled_set_page_dirty,
index fc080dd561f74ecf8b00a48038e8c9f18f4a789e..f4090bd2f345218df867b618806569415c1de688 100644 (file)
@@ -38,7 +38,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                unsigned int oldflags;
                unsigned int jflag;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -123,7 +123,7 @@ flags_out:
                __u32 generation;
                int err;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
 
                err = mnt_want_write(filp->f_path.mnt);
@@ -192,7 +192,7 @@ setversion_out:
                if (err)
                        return err;
 
-               if (!is_owner_or_cap(inode)) {
+               if (!inode_owner_or_capable(inode)) {
                        err = -EACCES;
                        goto setrsvsz_out;
                }
index e0270d1f8d82b68e8823cccc4db7539fb9a34f5b..21eacd7b7d79f558695b37216f6e9ea4745fb05e 100644 (file)
@@ -433,7 +433,7 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
                return -EINVAL;
        if (!test_opt(inode->i_sb, POSIX_ACL))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        if (value) {
index adf96b822781b25234ea4a3301bd6330aed01c92..97b970e7dd130abdcb86d4ece7c6526718e05cf0 100644 (file)
@@ -21,6 +21,8 @@
 #include "ext4_jbd2.h"
 #include "mballoc.h"
 
+#include <trace/events/ext4.h>
+
 /*
  * balloc.c contains the blocks allocation and deallocation routines
  */
@@ -342,6 +344,7 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
         * We do it here so the bitmap uptodate bit
         * get set with buffer lock held.
         */
+       trace_ext4_read_block_bitmap_load(sb, block_group);
        set_bitmap_uptodate(bh);
        if (bh_submit_read(bh) < 0) {
                put_bh(bh);
index 3aa0b72b3b94b42bea4a499e836068ed991814ce..4daaf2b753f4fa037fd783ac34e47e15d1438b55 100644 (file)
@@ -923,14 +923,14 @@ struct ext4_inode_info {
 #define test_opt2(sb, opt)             (EXT4_SB(sb)->s_mount_opt2 & \
                                         EXT4_MOUNT2_##opt)
 
-#define ext4_set_bit                   ext2_set_bit
+#define ext4_set_bit                   __test_and_set_bit_le
 #define ext4_set_bit_atomic            ext2_set_bit_atomic
-#define ext4_clear_bit                 ext2_clear_bit
+#define ext4_clear_bit                 __test_and_clear_bit_le
 #define ext4_clear_bit_atomic          ext2_clear_bit_atomic
-#define ext4_test_bit                  ext2_test_bit
-#define ext4_find_first_zero_bit       ext2_find_first_zero_bit
-#define ext4_find_next_zero_bit                ext2_find_next_zero_bit
-#define ext4_find_next_bit             ext2_find_next_bit
+#define ext4_test_bit                  test_bit_le
+#define ext4_find_first_zero_bit       find_first_zero_bit_le
+#define ext4_find_next_zero_bit                find_next_zero_bit_le
+#define ext4_find_next_bit             find_next_bit_le
 
 /*
  * Maximal mount counts between two filesystem checks
index d8b992e658c154796efadb80bb8a605ee365409e..e25e99bf7ee13321afc8702bf91506a08557f148 100644 (file)
@@ -202,13 +202,6 @@ static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed)
        return 1;
 }
 
-static inline void ext4_journal_release_buffer(handle_t *handle,
-                                               struct buffer_head *bh)
-{
-       if (ext4_handle_valid(handle))
-               jbd2_journal_release_buffer(handle, bh);
-}
-
 static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
 {
        return ext4_journal_start_sb(inode->i_sb, nblocks);
index 7516fb9c0bd5ade918540dc4ad8c2d0b53aee249..dd2cb5076ff9d0831486fbc79757763da0c9bbc8 100644 (file)
@@ -44,6 +44,8 @@
 #include "ext4_jbd2.h"
 #include "ext4_extents.h"
 
+#include <trace/events/ext4.h>
+
 static int ext4_ext_truncate_extend_restart(handle_t *handle,
                                            struct inode *inode,
                                            int needed)
@@ -664,6 +666,8 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
                if (unlikely(!bh))
                        goto err;
                if (!bh_uptodate_or_lock(bh)) {
+                       trace_ext4_ext_load_extent(inode, block,
+                                               path[ppos].p_block);
                        if (bh_submit_read(bh) < 0) {
                                put_bh(bh);
                                goto err;
@@ -1034,7 +1038,7 @@ cleanup:
                for (i = 0; i < depth; i++) {
                        if (!ablocks[i])
                                continue;
-                       ext4_free_blocks(handle, inode, 0, ablocks[i], 1,
+                       ext4_free_blocks(handle, inode, NULL, ablocks[i], 1,
                                         EXT4_FREE_BLOCKS_METADATA);
                }
        }
@@ -2059,7 +2063,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
        if (err)
                return err;
        ext_debug("index is empty, remove it, free block %llu\n", leaf);
-       ext4_free_blocks(handle, inode, 0, leaf, 1,
+       ext4_free_blocks(handle, inode, NULL, leaf, 1,
                         EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
        return err;
 }
@@ -2156,7 +2160,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
                num = le32_to_cpu(ex->ee_block) + ee_len - from;
                start = ext4_ext_pblock(ex) + ee_len - num;
                ext_debug("free last %u blocks starting %llu\n", num, start);
-               ext4_free_blocks(handle, inode, 0, start, num, flags);
+               ext4_free_blocks(handle, inode, NULL, start, num, flags);
        } else if (from == le32_to_cpu(ex->ee_block)
                   && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
                printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n",
@@ -3108,14 +3112,13 @@ static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
 {
        int i, depth;
        struct ext4_extent_header *eh;
-       struct ext4_extent *ex, *last_ex;
+       struct ext4_extent *last_ex;
 
        if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
                return 0;
 
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
-       ex = path[depth].p_ext;
 
        if (unlikely(!eh->eh_entries)) {
                EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and "
@@ -3295,9 +3298,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                        struct ext4_map_blocks *map, int flags)
 {
        struct ext4_ext_path *path = NULL;
-       struct ext4_extent_header *eh;
        struct ext4_extent newex, *ex;
-       ext4_fsblk_t newblock;
+       ext4_fsblk_t newblock = 0;
        int err = 0, depth, ret;
        unsigned int allocated = 0;
        struct ext4_allocation_request ar;
@@ -3305,6 +3307,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 
        ext_debug("blocks %u/%u requested for inode %lu\n",
                  map->m_lblk, map->m_len, inode->i_ino);
+       trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
        /* check in cache */
        if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
@@ -3352,7 +3355,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                err = -EIO;
                goto out2;
        }
-       eh = path[depth].p_hdr;
 
        ex = path[depth].p_ext;
        if (ex) {
@@ -3485,7 +3487,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                /* not a good idea to call discard here directly,
                 * but otherwise we'd need to call it every free() */
                ext4_discard_preallocations(inode);
-               ext4_free_blocks(handle, inode, 0, ext4_ext_pblock(&newex),
+               ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex),
                                 ext4_ext_get_actual_len(&newex), 0);
                goto out2;
        }
@@ -3525,6 +3527,8 @@ out2:
                ext4_ext_drop_refs(path);
                kfree(path);
        }
+       trace_ext4_ext_map_blocks_exit(inode, map->m_lblk,
+               newblock, map->m_len, err ? err : allocated);
        return err ? err : allocated;
 }
 
@@ -3658,6 +3662,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                return -EOPNOTSUPP;
 
+       trace_ext4_fallocate_enter(inode, offset, len, mode);
        map.m_lblk = offset >> blkbits;
        /*
         * We can't just convert len to max_blocks because
@@ -3673,6 +3678,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        ret = inode_newsize_ok(inode, (len + offset));
        if (ret) {
                mutex_unlock(&inode->i_mutex);
+               trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
                return ret;
        }
 retry:
@@ -3717,6 +3723,8 @@ retry:
                goto retry;
        }
        mutex_unlock(&inode->i_mutex);
+       trace_ext4_fallocate_exit(inode, offset, max_blocks,
+                               ret > 0 ? ret2 : ret);
        return ret > 0 ? ret2 : ret;
 }
 
@@ -3775,6 +3783,7 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
        }
        return ret > 0 ? ret2 : ret;
 }
+
 /*
  * Callback function called for each extent to gather FIEMAP information.
  */
@@ -3782,38 +3791,162 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
                       struct ext4_ext_cache *newex, struct ext4_extent *ex,
                       void *data)
 {
-       struct fiemap_extent_info *fieinfo = data;
-       unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
        __u64   logical;
        __u64   physical;
        __u64   length;
+       loff_t  size;
        __u32   flags = 0;
-       int     error;
+       int             ret = 0;
+       struct fiemap_extent_info *fieinfo = data;
+       unsigned char blksize_bits;
 
-       logical =  (__u64)newex->ec_block << blksize_bits;
+       blksize_bits = inode->i_sb->s_blocksize_bits;
+       logical = (__u64)newex->ec_block << blksize_bits;
 
        if (newex->ec_start == 0) {
-               pgoff_t offset;
-               struct page *page;
+               /*
+                * No extent in extent-tree contains block @newex->ec_start,
+                * then the block may stay in 1)a hole or 2)delayed-extent.
+                *
+                * Holes or delayed-extents are processed as follows.
+                * 1. lookup dirty pages with specified range in pagecache.
+                *    If no page is got, then there is no delayed-extent and
+                *    return with EXT_CONTINUE.
+                * 2. find the 1st mapped buffer,
+                * 3. check if the mapped buffer is both in the request range
+                *    and a delayed buffer. If not, there is no delayed-extent,
+                *    then return.
+                * 4. a delayed-extent is found, the extent will be collected.
+                */
+               ext4_lblk_t     end = 0;
+               pgoff_t         last_offset;
+               pgoff_t         offset;
+               pgoff_t         index;
+               struct page     **pages = NULL;
                struct buffer_head *bh = NULL;
+               struct buffer_head *head = NULL;
+               unsigned int nr_pages = PAGE_SIZE / sizeof(struct page *);
+
+               pages = kmalloc(PAGE_SIZE, GFP_KERNEL);
+               if (pages == NULL)
+                       return -ENOMEM;
 
                offset = logical >> PAGE_SHIFT;
-               page = find_get_page(inode->i_mapping, offset);
-               if (!page || !page_has_buffers(page))
-                       return EXT_CONTINUE;
+repeat:
+               last_offset = offset;
+               head = NULL;
+               ret = find_get_pages_tag(inode->i_mapping, &offset,
+                                       PAGECACHE_TAG_DIRTY, nr_pages, pages);
+
+               if (!(flags & FIEMAP_EXTENT_DELALLOC)) {
+                       /* First time, try to find a mapped buffer. */
+                       if (ret == 0) {
+out:
+                               for (index = 0; index < ret; index++)
+                                       page_cache_release(pages[index]);
+                               /* just a hole. */
+                               kfree(pages);
+                               return EXT_CONTINUE;
+                       }
 
-               bh = page_buffers(page);
+                       /* Try to find the 1st mapped buffer. */
+                       end = ((__u64)pages[0]->index << PAGE_SHIFT) >>
+                                 blksize_bits;
+                       if (!page_has_buffers(pages[0]))
+                               goto out;
+                       head = page_buffers(pages[0]);
+                       if (!head)
+                               goto out;
 
-               if (!bh)
-                       return EXT_CONTINUE;
+                       bh = head;
+                       do {
+                               if (buffer_mapped(bh)) {
+                                       /* get the 1st mapped buffer. */
+                                       if (end > newex->ec_block +
+                                               newex->ec_len)
+                                               /* The buffer is out of
+                                                * the request range.
+                                                */
+                                               goto out;
+                                       goto found_mapped_buffer;
+                               }
+                               bh = bh->b_this_page;
+                               end++;
+                       } while (bh != head);
 
-               if (buffer_delay(bh)) {
-                       flags |= FIEMAP_EXTENT_DELALLOC;
-                       page_cache_release(page);
+                       /* No mapped buffer found. */
+                       goto out;
                } else {
-                       page_cache_release(page);
-                       return EXT_CONTINUE;
+                       /*Find contiguous delayed buffers. */
+                       if (ret > 0 && pages[0]->index == last_offset)
+                               head = page_buffers(pages[0]);
+                       bh = head;
                }
+
+found_mapped_buffer:
+               if (bh != NULL && buffer_delay(bh)) {
+                       /* 1st or contiguous delayed buffer found. */
+                       if (!(flags & FIEMAP_EXTENT_DELALLOC)) {
+                               /*
+                                * 1st delayed buffer found, record
+                                * the start of extent.
+                                */
+                               flags |= FIEMAP_EXTENT_DELALLOC;
+                               newex->ec_block = end;
+                               logical = (__u64)end << blksize_bits;
+                       }
+                       /* Find contiguous delayed buffers. */
+                       do {
+                               if (!buffer_delay(bh))
+                                       goto found_delayed_extent;
+                               bh = bh->b_this_page;
+                               end++;
+                       } while (bh != head);
+
+                       for (index = 1; index < ret; index++) {
+                               if (!page_has_buffers(pages[index])) {
+                                       bh = NULL;
+                                       break;
+                               }
+                               head = page_buffers(pages[index]);
+                               if (!head) {
+                                       bh = NULL;
+                                       break;
+                               }
+                               if (pages[index]->index !=
+                                       pages[0]->index + index) {
+                                       /* Blocks are not contiguous. */
+                                       bh = NULL;
+                                       break;
+                               }
+                               bh = head;
+                               do {
+                                       if (!buffer_delay(bh))
+                                               /* Delayed-extent ends. */
+                                               goto found_delayed_extent;
+                                       bh = bh->b_this_page;
+                                       end++;
+                               } while (bh != head);
+                       }
+               } else if (!(flags & FIEMAP_EXTENT_DELALLOC))
+                       /* a hole found. */
+                       goto out;
+
+found_delayed_extent:
+               newex->ec_len = min(end - newex->ec_block,
+                                               (ext4_lblk_t)EXT_INIT_MAX_LEN);
+               if (ret == nr_pages && bh != NULL &&
+                       newex->ec_len < EXT_INIT_MAX_LEN &&
+                       buffer_delay(bh)) {
+                       /* Have not collected an extent and continue. */
+                       for (index = 0; index < ret; index++)
+                               page_cache_release(pages[index]);
+                       goto repeat;
+               }
+
+               for (index = 0; index < ret; index++)
+                       page_cache_release(pages[index]);
+               kfree(pages);
        }
 
        physical = (__u64)newex->ec_start << blksize_bits;
@@ -3822,32 +3955,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
        if (ex && ext4_ext_is_uninitialized(ex))
                flags |= FIEMAP_EXTENT_UNWRITTEN;
 
-       /*
-        * If this extent reaches EXT_MAX_BLOCK, it must be last.
-        *
-        * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK,
-        * this also indicates no more allocated blocks.
-        *
-        * XXX this might miss a single-block extent at EXT_MAX_BLOCK
-        */
-       if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
-           newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) {
-               loff_t size = i_size_read(inode);
-               loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb);
-
+       size = i_size_read(inode);
+       if (logical + length >= size)
                flags |= FIEMAP_EXTENT_LAST;
-               if ((flags & FIEMAP_EXTENT_DELALLOC) &&
-                   logical+length > size)
-                       length = (size - logical + bs - 1) & ~(bs-1);
-       }
 
-       error = fiemap_fill_next_extent(fieinfo, logical, physical,
+       ret = fiemap_fill_next_extent(fieinfo, logical, physical,
                                        length, flags);
-       if (error < 0)
-               return error;
-       if (error == 1)
+       if (ret < 0)
+               return ret;
+       if (ret == 1)
                return EXT_BREAK;
-
        return EXT_CONTINUE;
 }
 
index 7829b287822a4207080c4089921e22418a855d93..7f74019d6d7766e0657d7d8620c128c7006af5b7 100644 (file)
@@ -164,20 +164,20 @@ int ext4_sync_file(struct file *file, int datasync)
 
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
-       trace_ext4_sync_file(file, datasync);
+       trace_ext4_sync_file_enter(file, datasync);
 
        if (inode->i_sb->s_flags & MS_RDONLY)
                return 0;
 
        ret = ext4_flush_completed_IO(inode);
        if (ret < 0)
-               return ret;
+               goto out;
 
        if (!journal) {
                ret = generic_file_fsync(file, datasync);
                if (!ret && !list_empty(&inode->i_dentry))
                        ext4_sync_parent(inode);
-               return ret;
+               goto out;
        }
 
        /*
@@ -194,8 +194,10 @@ int ext4_sync_file(struct file *file, int datasync)
         *  (they were dirtied by commit).  But that's OK - the blocks are
         *  safe in-journal, which is all fsync() needs to ensure.
         */
-       if (ext4_should_journal_data(inode))
-               return ext4_force_commit(inode->i_sb);
+       if (ext4_should_journal_data(inode)) {
+               ret = ext4_force_commit(inode->i_sb);
+               goto out;
+       }
 
        commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
        if (jbd2_log_start_commit(journal, commit_tid)) {
@@ -215,5 +217,7 @@ int ext4_sync_file(struct file *file, int datasync)
                ret = jbd2_log_wait_commit(journal, commit_tid);
        } else if (journal->j_flags & JBD2_BARRIER)
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+ out:
+       trace_ext4_sync_file_exit(inode, ret);
        return ret;
 }
index 78b79e1bd7ed2214af4399bd628fd4158d36410e..21bb2f61e50223c2da0946c4b48db0e4c947e1a7 100644 (file)
@@ -152,6 +152,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
         * We do it here so the bitmap uptodate bit
         * get set with buffer lock held.
         */
+       trace_ext4_load_inode_bitmap(sb, block_group);
        set_bitmap_uptodate(bh);
        if (bh_submit_read(bh) < 0) {
                put_bh(bh);
@@ -649,7 +650,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
                *group = parent_group + flex_size;
                if (*group > ngroups)
                        *group = 0;
-               return find_group_orlov(sb, parent, group, mode, 0);
+               return find_group_orlov(sb, parent, group, mode, NULL);
        }
 
        /*
@@ -1054,6 +1055,11 @@ got:
                }
        }
 
+       if (ext4_handle_valid(handle)) {
+               ei->i_sync_tid = handle->h_transaction->t_tid;
+               ei->i_datasync_tid = handle->h_transaction->t_tid;
+       }
+
        err = ext4_mark_inode_dirty(handle, inode);
        if (err) {
                ext4_std_error(sb, err);
index 9f7f9e49914fa775709d5c99e805440fd4ff0f9f..1a86282b90244c43fe75ae106d32c05b027b21d4 100644 (file)
@@ -173,7 +173,7 @@ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        jbd_debug(2, "restarting handle %p\n", handle);
        up_write(&EXT4_I(inode)->i_data_sem);
-       ret = ext4_journal_restart(handle, blocks_for_truncate(inode));
+       ret = ext4_journal_restart(handle, nblocks);
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode);
 
@@ -720,7 +720,7 @@ allocated:
        return ret;
 failed_out:
        for (i = 0; i < index; i++)
-               ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0);
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
        return ret;
 }
 
@@ -823,20 +823,20 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
        return err;
 failed:
        /* Allocation failed, free what we already allocated */
-       ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0);
+       ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0);
        for (i = 1; i <= n ; i++) {
                /*
                 * branch[i].bh is newly allocated, so there is no
                 * need to revoke the block, which is why we don't
                 * need to set EXT4_FREE_BLOCKS_METADATA.
                 */
-               ext4_free_blocks(handle, inode, 0, new_blocks[i], 1,
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1,
                                 EXT4_FREE_BLOCKS_FORGET);
        }
        for (i = n+1; i < indirect_blks; i++)
-               ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0);
+               ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
 
-       ext4_free_blocks(handle, inode, 0, new_blocks[i], num, 0);
+       ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0);
 
        return err;
 }
@@ -924,7 +924,7 @@ err_out:
                ext4_free_blocks(handle, inode, where[i].bh, 0, 1,
                                 EXT4_FREE_BLOCKS_FORGET);
        }
-       ext4_free_blocks(handle, inode, 0, le32_to_cpu(where[num].key),
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key),
                         blks, 0);
 
        return err;
@@ -973,6 +973,7 @@ static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
        int count = 0;
        ext4_fsblk_t first_block = 0;
 
+       trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
        J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
        J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
        depth = ext4_block_to_path(inode, map->m_lblk, offsets,
@@ -1058,6 +1059,8 @@ cleanup:
                partial--;
        }
 out:
+       trace_ext4_ind_map_blocks_exit(inode, map->m_lblk,
+                               map->m_pblk, map->m_len, err);
        return err;
 }
 
@@ -2060,7 +2063,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                if (nr_pages == 0)
                        break;
                for (i = 0; i < nr_pages; i++) {
-                       int commit_write = 0, redirty_page = 0;
+                       int commit_write = 0, skip_page = 0;
                        struct page *page = pvec.pages[i];
 
                        index = page->index;
@@ -2086,14 +2089,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                         * If the page does not have buffers (for
                         * whatever reason), try to create them using
                         * __block_write_begin.  If this fails,
-                        * redirty the page and move on.
+                        * skip the page and move on.
                         */
                        if (!page_has_buffers(page)) {
                                if (__block_write_begin(page, 0, len,
                                                noalloc_get_block_write)) {
-                               redirty_page:
-                                       redirty_page_for_writepage(mpd->wbc,
-                                                                  page);
+                               skip_page:
                                        unlock_page(page);
                                        continue;
                                }
@@ -2104,7 +2105,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                        block_start = 0;
                        do {
                                if (!bh)
-                                       goto redirty_page;
+                                       goto skip_page;
                                if (map && (cur_logical >= map->m_lblk) &&
                                    (cur_logical <= (map->m_lblk +
                                                     (map->m_len - 1)))) {
@@ -2120,22 +2121,23 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
                                        clear_buffer_unwritten(bh);
                                }
 
-                               /* redirty page if block allocation undone */
+                               /* skip page if block allocation undone */
                                if (buffer_delay(bh) || buffer_unwritten(bh))
-                                       redirty_page = 1;
+                                       skip_page = 1;
                                bh = bh->b_this_page;
                                block_start += bh->b_size;
                                cur_logical++;
                                pblock++;
                        } while (bh != page_bufs);
 
-                       if (redirty_page)
-                               goto redirty_page;
+                       if (skip_page)
+                               goto skip_page;
 
                        if (commit_write)
                                /* mark the buffer_heads as dirty & uptodate */
                                block_commit_write(page, 0, len);
 
+                       clear_page_dirty_for_io(page);
                        /*
                         * Delalloc doesn't support data journalling,
                         * but eventually maybe we'll lift this
@@ -2165,8 +2167,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
        return ret;
 }
 
-static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
-                                       sector_t logical, long blk_cnt)
+static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd)
 {
        int nr_pages, i;
        pgoff_t index, end;
@@ -2174,9 +2175,8 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd,
        struct inode *inode = mpd->inode;
        struct address_space *mapping = inode->i_mapping;
 
-       index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
-       end   = (logical + blk_cnt - 1) >>
-                               (PAGE_CACHE_SHIFT - inode->i_blkbits);
+       index = mpd->first_page;
+       end   = mpd->next_page - 1;
        while (index <= end) {
                nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE);
                if (nr_pages == 0)
@@ -2279,9 +2279,8 @@ static void mpage_da_map_and_submit(struct mpage_da_data *mpd)
                err = blks;
                /*
                 * If get block returns EAGAIN or ENOSPC and there
-                * appears to be free blocks we will call
-                * ext4_writepage() for all of the pages which will
-                * just redirty the pages.
+                * appears to be free blocks we will just let
+                * mpage_da_submit_io() unlock all of the pages.
                 */
                if (err == -EAGAIN)
                        goto submit_io;
@@ -2312,8 +2311,10 @@ static void mpage_da_map_and_submit(struct mpage_da_data *mpd)
                                ext4_print_free_blocks(mpd->inode);
                }
                /* invalidate all the pages */
-               ext4_da_block_invalidatepages(mpd, next,
-                               mpd->b_size >> mpd->inode->i_blkbits);
+               ext4_da_block_invalidatepages(mpd);
+
+               /* Mark this page range as having been completed */
+               mpd->io_done = 1;
                return;
        }
        BUG_ON(blks == 0);
@@ -2437,102 +2438,6 @@ static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh)
        return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh);
 }
 
-/*
- * __mpage_da_writepage - finds extent of pages and blocks
- *
- * @page: page to consider
- * @wbc: not used, we just follow rules
- * @data: context
- *
- * The function finds extents of pages and scan them for all blocks.
- */
-static int __mpage_da_writepage(struct page *page,
-                               struct writeback_control *wbc,
-                               struct mpage_da_data *mpd)
-{
-       struct inode *inode = mpd->inode;
-       struct buffer_head *bh, *head;
-       sector_t logical;
-
-       /*
-        * Can we merge this page to current extent?
-        */
-       if (mpd->next_page != page->index) {
-               /*
-                * Nope, we can't. So, we map non-allocated blocks
-                * and start IO on them
-                */
-               if (mpd->next_page != mpd->first_page) {
-                       mpage_da_map_and_submit(mpd);
-                       /*
-                        * skip rest of the page in the page_vec
-                        */
-                       redirty_page_for_writepage(wbc, page);
-                       unlock_page(page);
-                       return MPAGE_DA_EXTENT_TAIL;
-               }
-
-               /*
-                * Start next extent of pages ...
-                */
-               mpd->first_page = page->index;
-
-               /*
-                * ... and blocks
-                */
-               mpd->b_size = 0;
-               mpd->b_state = 0;
-               mpd->b_blocknr = 0;
-       }
-
-       mpd->next_page = page->index + 1;
-       logical = (sector_t) page->index <<
-                 (PAGE_CACHE_SHIFT - inode->i_blkbits);
-
-       if (!page_has_buffers(page)) {
-               mpage_add_bh_to_extent(mpd, logical, PAGE_CACHE_SIZE,
-                                      (1 << BH_Dirty) | (1 << BH_Uptodate));
-               if (mpd->io_done)
-                       return MPAGE_DA_EXTENT_TAIL;
-       } else {
-               /*
-                * Page with regular buffer heads, just add all dirty ones
-                */
-               head = page_buffers(page);
-               bh = head;
-               do {
-                       BUG_ON(buffer_locked(bh));
-                       /*
-                        * We need to try to allocate
-                        * unmapped blocks in the same page.
-                        * Otherwise we won't make progress
-                        * with the page in ext4_writepage
-                        */
-                       if (ext4_bh_delay_or_unwritten(NULL, bh)) {
-                               mpage_add_bh_to_extent(mpd, logical,
-                                                      bh->b_size,
-                                                      bh->b_state);
-                               if (mpd->io_done)
-                                       return MPAGE_DA_EXTENT_TAIL;
-                       } else if (buffer_dirty(bh) && (buffer_mapped(bh))) {
-                               /*
-                                * mapped dirty buffer. We need to update
-                                * the b_state because we look at
-                                * b_state in mpage_da_map_blocks. We don't
-                                * update b_size because if we find an
-                                * unmapped buffer_head later we need to
-                                * use the b_state flag of that buffer_head.
-                                */
-                               if (mpd->b_size == 0)
-                                       mpd->b_state = bh->b_state & BH_FLAGS;
-                       }
-                       logical++;
-               } while ((bh = bh->b_this_page) != head);
-       }
-
-       return 0;
-}
-
 /*
  * This is a special get_blocks_t callback which is used by
  * ext4_da_write_begin().  It will either return mapped block or
@@ -2597,7 +2502,6 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                 * for partial write.
                 */
                set_buffer_new(bh);
-               set_buffer_mapped(bh);
        }
        return 0;
 }
@@ -2811,27 +2715,27 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
 
 /*
  * write_cache_pages_da - walk the list of dirty pages of the given
- * address space and call the callback function (which usually writes
- * the pages).
- *
- * This is a forked version of write_cache_pages().  Differences:
- *     Range cyclic is ignored.
- *     no_nrwrite_index_update is always presumed true
+ * address space and accumulate pages that need writing, and call
+ * mpage_da_map_and_submit to map a single contiguous memory region
+ * and then write them.
  */
 static int write_cache_pages_da(struct address_space *mapping,
                                struct writeback_control *wbc,
                                struct mpage_da_data *mpd,
                                pgoff_t *done_index)
 {
-       int ret = 0;
-       int done = 0;
-       struct pagevec pvec;
-       unsigned nr_pages;
-       pgoff_t index;
-       pgoff_t end;            /* Inclusive */
-       long nr_to_write = wbc->nr_to_write;
-       int tag;
-
+       struct buffer_head      *bh, *head;
+       struct inode            *inode = mapping->host;
+       struct pagevec          pvec;
+       unsigned int            nr_pages;
+       sector_t                logical;
+       pgoff_t                 index, end;
+       long                    nr_to_write = wbc->nr_to_write;
+       int                     i, tag, ret = 0;
+
+       memset(mpd, 0, sizeof(struct mpage_da_data));
+       mpd->wbc = wbc;
+       mpd->inode = inode;
        pagevec_init(&pvec, 0);
        index = wbc->range_start >> PAGE_CACHE_SHIFT;
        end = wbc->range_end >> PAGE_CACHE_SHIFT;
@@ -2842,13 +2746,11 @@ static int write_cache_pages_da(struct address_space *mapping,
                tag = PAGECACHE_TAG_DIRTY;
 
        *done_index = index;
-       while (!done && (index <= end)) {
-               int i;
-
+       while (index <= end) {
                nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
                              min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
                if (nr_pages == 0)
-                       break;
+                       return 0;
 
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
@@ -2860,60 +2762,100 @@ static int write_cache_pages_da(struct address_space *mapping,
                         * mapping. However, page->index will not change
                         * because we have a reference on the page.
                         */
-                       if (page->index > end) {
-                               done = 1;
-                               break;
-                       }
+                       if (page->index > end)
+                               goto out;
 
                        *done_index = page->index + 1;
 
+                       /*
+                        * If we can't merge this page, and we have
+                        * accumulated an contiguous region, write it
+                        */
+                       if ((mpd->next_page != page->index) &&
+                           (mpd->next_page != mpd->first_page)) {
+                               mpage_da_map_and_submit(mpd);
+                               goto ret_extent_tail;
+                       }
+
                        lock_page(page);
 
                        /*
-                        * Page truncated or invalidated. We can freely skip it
-                        * then, even for data integrity operations: the page
-                        * has disappeared concurrently, so there could be no
-                        * real expectation of this data interity operation
-                        * even if there is now a new, dirty page at the same
-                        * pagecache address.
+                        * If the page is no longer dirty, or its
+                        * mapping no longer corresponds to inode we
+                        * are writing (which means it has been
+                        * truncated or invalidated), or the page is
+                        * already under writeback and we are not
+                        * doing a data integrity writeback, skip the page
                         */
-                       if (unlikely(page->mapping != mapping)) {
-continue_unlock:
+                       if (!PageDirty(page) ||
+                           (PageWriteback(page) &&
+                            (wbc->sync_mode == WB_SYNC_NONE)) ||
+                           unlikely(page->mapping != mapping)) {
                                unlock_page(page);
                                continue;
                        }
 
-                       if (!PageDirty(page)) {
-                               /* someone wrote it for us */
-                               goto continue_unlock;
-                       }
-
-                       if (PageWriteback(page)) {
-                               if (wbc->sync_mode != WB_SYNC_NONE)
-                                       wait_on_page_writeback(page);
-                               else
-                                       goto continue_unlock;
-                       }
+                       if (PageWriteback(page))
+                               wait_on_page_writeback(page);
 
                        BUG_ON(PageWriteback(page));
-                       if (!clear_page_dirty_for_io(page))
-                               goto continue_unlock;
 
-                       ret = __mpage_da_writepage(page, wbc, mpd);
-                       if (unlikely(ret)) {
-                               if (ret == AOP_WRITEPAGE_ACTIVATE) {
-                                       unlock_page(page);
-                                       ret = 0;
-                               } else {
-                                       done = 1;
-                                       break;
-                               }
+                       if (mpd->next_page != page->index)
+                               mpd->first_page = page->index;
+                       mpd->next_page = page->index + 1;
+                       logical = (sector_t) page->index <<
+                               (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+                       if (!page_has_buffers(page)) {
+                               mpage_add_bh_to_extent(mpd, logical,
+                                                      PAGE_CACHE_SIZE,
+                                                      (1 << BH_Dirty) | (1 << BH_Uptodate));
+                               if (mpd->io_done)
+                                       goto ret_extent_tail;
+                       } else {
+                               /*
+                                * Page with regular buffer heads,
+                                * just add all dirty ones
+                                */
+                               head = page_buffers(page);
+                               bh = head;
+                               do {
+                                       BUG_ON(buffer_locked(bh));
+                                       /*
+                                        * We need to try to allocate
+                                        * unmapped blocks in the same page.
+                                        * Otherwise we won't make progress
+                                        * with the page in ext4_writepage
+                                        */
+                                       if (ext4_bh_delay_or_unwritten(NULL, bh)) {
+                                               mpage_add_bh_to_extent(mpd, logical,
+                                                                      bh->b_size,
+                                                                      bh->b_state);
+                                               if (mpd->io_done)
+                                                       goto ret_extent_tail;
+                                       } else if (buffer_dirty(bh) && (buffer_mapped(bh))) {
+                                               /*
+                                                * mapped dirty buffer. We need
+                                                * to update the b_state
+                                                * because we look at b_state
+                                                * in mpage_da_map_blocks.  We
+                                                * don't update b_size because
+                                                * if we find an unmapped
+                                                * buffer_head later we need to
+                                                * use the b_state flag of that
+                                                * buffer_head.
+                                                */
+                                               if (mpd->b_size == 0)
+                                                       mpd->b_state = bh->b_state & BH_FLAGS;
+                                       }
+                                       logical++;
+                               } while ((bh = bh->b_this_page) != head);
                        }
 
                        if (nr_to_write > 0) {
                                nr_to_write--;
                                if (nr_to_write == 0 &&
-                                   wbc->sync_mode == WB_SYNC_NONE) {
+                                   wbc->sync_mode == WB_SYNC_NONE)
                                        /*
                                         * We stop writing back only if we are
                                         * not doing integrity sync. In case of
@@ -2924,14 +2866,18 @@ continue_unlock:
                                         * pages, but have not synced all of the
                                         * old dirty pages.
                                         */
-                                       done = 1;
-                                       break;
-                               }
+                                       goto out;
                        }
                }
                pagevec_release(&pvec);
                cond_resched();
        }
+       return 0;
+ret_extent_tail:
+       ret = MPAGE_DA_EXTENT_TAIL;
+out:
+       pagevec_release(&pvec);
+       cond_resched();
        return ret;
 }
 
@@ -2945,7 +2891,6 @@ static int ext4_da_writepages(struct address_space *mapping,
        struct mpage_da_data mpd;
        struct inode *inode = mapping->host;
        int pages_written = 0;
-       long pages_skipped;
        unsigned int max_pages;
        int range_cyclic, cycled = 1, io_done = 0;
        int needed_blocks, ret = 0;
@@ -3028,11 +2973,6 @@ static int ext4_da_writepages(struct address_space *mapping,
                wbc->nr_to_write = desired_nr_to_write;
        }
 
-       mpd.wbc = wbc;
-       mpd.inode = mapping->host;
-
-       pages_skipped = wbc->pages_skipped;
-
 retry:
        if (wbc->sync_mode == WB_SYNC_ALL)
                tag_pages_for_writeback(mapping, index, end);
@@ -3059,22 +2999,10 @@ retry:
                }
 
                /*
-                * Now call __mpage_da_writepage to find the next
+                * Now call write_cache_pages_da() to find the next
                 * contiguous region of logical blocks that need
-                * blocks to be allocated by ext4.  We don't actually
-                * submit the blocks for I/O here, even though
-                * write_cache_pages thinks it will, and will set the
-                * pages as clean for write before calling
-                * __mpage_da_writepage().
+                * blocks to be allocated by ext4 and submit them.
                 */
-               mpd.b_size = 0;
-               mpd.b_state = 0;
-               mpd.b_blocknr = 0;
-               mpd.first_page = 0;
-               mpd.next_page = 0;
-               mpd.io_done = 0;
-               mpd.pages_written = 0;
-               mpd.retval = 0;
                ret = write_cache_pages_da(mapping, wbc, &mpd, &done_index);
                /*
                 * If we have a contiguous extent of pages and we
@@ -3096,7 +3024,6 @@ retry:
                         * and try again
                         */
                        jbd2_journal_force_commit_nested(sbi->s_journal);
-                       wbc->pages_skipped = pages_skipped;
                        ret = 0;
                } else if (ret == MPAGE_DA_EXTENT_TAIL) {
                        /*
@@ -3104,7 +3031,6 @@ retry:
                         * rest of the pages
                         */
                        pages_written += mpd.pages_written;
-                       wbc->pages_skipped = pages_skipped;
                        ret = 0;
                        io_done = 1;
                } else if (wbc->nr_to_write)
@@ -3122,11 +3048,6 @@ retry:
                wbc->range_end  = mapping->writeback_index - 1;
                goto retry;
        }
-       if (pages_skipped != wbc->pages_skipped)
-               ext4_msg(inode->i_sb, KERN_CRIT,
-                        "This should not happen leaving %s "
-                        "with nr_to_write = %ld ret = %d",
-                        __func__, wbc->nr_to_write, ret);
 
        /* Update index */
        wbc->range_cyclic = range_cyclic;
@@ -3460,6 +3381,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
 
 static int ext4_readpage(struct file *file, struct page *page)
 {
+       trace_ext4_readpage(page);
        return mpage_readpage(page, ext4_get_block);
 }
 
@@ -3494,6 +3416,8 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset)
 {
        journal_t *journal = EXT4_JOURNAL(page->mapping->host);
 
+       trace_ext4_invalidatepage(page, offset);
+
        /*
         * free any io_end structure allocated for buffers to be discarded
         */
@@ -3515,6 +3439,8 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
 {
        journal_t *journal = EXT4_JOURNAL(page->mapping->host);
 
+       trace_ext4_releasepage(page);
+
        WARN_ON(PageChecked(page));
        if (!page_has_buffers(page))
                return 0;
@@ -3873,11 +3799,16 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       ssize_t ret;
 
+       trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw);
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
-               return ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
-
-       return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
+               ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs);
+       else
+               ret = ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs);
+       trace_ext4_direct_IO_exit(inode, offset,
+                               iov_length(iov, nr_segs), rw, ret);
+       return ret;
 }
 
 /*
@@ -3903,7 +3834,6 @@ static const struct address_space_operations ext4_ordered_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
        .writepage              = ext4_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_ordered_write_end,
        .bmap                   = ext4_bmap,
@@ -3919,7 +3849,6 @@ static const struct address_space_operations ext4_writeback_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
        .writepage              = ext4_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_writeback_write_end,
        .bmap                   = ext4_bmap,
@@ -3935,7 +3864,6 @@ static const struct address_space_operations ext4_journalled_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
        .writepage              = ext4_writepage,
-       .sync_page              = block_sync_page,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_journalled_write_end,
        .set_page_dirty         = ext4_journalled_set_page_dirty,
@@ -3951,7 +3879,6 @@ static const struct address_space_operations ext4_da_aops = {
        .readpages              = ext4_readpages,
        .writepage              = ext4_writepage,
        .writepages             = ext4_da_writepages,
-       .sync_page              = block_sync_page,
        .write_begin            = ext4_da_write_begin,
        .write_end              = ext4_da_write_end,
        .bmap                   = ext4_bmap,
@@ -4177,6 +4104,9 @@ no_top:
  *
  * We release `count' blocks on disk, but (last - first) may be greater
  * than `count' because there can be holes in there.
+ *
+ * Return 0 on success, 1 on invalid block range
+ * and < 0 on fatal error.
  */
 static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
                             struct buffer_head *bh,
@@ -4203,33 +4133,32 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
                if (bh) {
                        BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
                        err = ext4_handle_dirty_metadata(handle, inode, bh);
-                       if (unlikely(err)) {
-                               ext4_std_error(inode->i_sb, err);
-                               return 1;
-                       }
+                       if (unlikely(err))
+                               goto out_err;
                }
                err = ext4_mark_inode_dirty(handle, inode);
-               if (unlikely(err)) {
-                       ext4_std_error(inode->i_sb, err);
-                       return 1;
-               }
+               if (unlikely(err))
+                       goto out_err;
                err = ext4_truncate_restart_trans(handle, inode,
                                                  blocks_for_truncate(inode));
-               if (unlikely(err)) {
-                       ext4_std_error(inode->i_sb, err);
-                       return 1;
-               }
+               if (unlikely(err))
+                       goto out_err;
                if (bh) {
                        BUFFER_TRACE(bh, "retaking write access");
-                       ext4_journal_get_write_access(handle, bh);
+                       err = ext4_journal_get_write_access(handle, bh);
+                       if (unlikely(err))
+                               goto out_err;
                }
        }
 
        for (p = first; p < last; p++)
                *p = 0;
 
-       ext4_free_blocks(handle, inode, 0, block_to_free, count, flags);
+       ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags);
        return 0;
+out_err:
+       ext4_std_error(inode->i_sb, err);
+       return err;
 }
 
 /**
@@ -4263,7 +4192,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
        ext4_fsblk_t nr;                    /* Current block # */
        __le32 *p;                          /* Pointer into inode/ind
                                               for current block */
-       int err;
+       int err = 0;
 
        if (this_bh) {                          /* For indirect block */
                BUFFER_TRACE(this_bh, "get_write_access");
@@ -4285,9 +4214,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
                        } else if (nr == block_to_free + count) {
                                count++;
                        } else {
-                               if (ext4_clear_blocks(handle, inode, this_bh,
-                                                     block_to_free, count,
-                                                     block_to_free_p, p))
+                               err = ext4_clear_blocks(handle, inode, this_bh,
+                                                       block_to_free, count,
+                                                       block_to_free_p, p);
+                               if (err)
                                        break;
                                block_to_free = nr;
                                block_to_free_p = p;
@@ -4296,9 +4226,12 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
                }
        }
 
-       if (count > 0)
-               ext4_clear_blocks(handle, inode, this_bh, block_to_free,
-                                 count, block_to_free_p, p);
+       if (!err && count > 0)
+               err = ext4_clear_blocks(handle, inode, this_bh, block_to_free,
+                                       count, block_to_free_p, p);
+       if (err < 0)
+               /* fatal error */
+               return;
 
        if (this_bh) {
                BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata");
@@ -4416,7 +4349,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
                         * transaction where the data blocks are
                         * actually freed.
                         */
-                       ext4_free_blocks(handle, inode, 0, nr, 1,
+                       ext4_free_blocks(handle, inode, NULL, nr, 1,
                                         EXT4_FREE_BLOCKS_METADATA|
                                         EXT4_FREE_BLOCKS_FORGET);
 
@@ -4500,6 +4433,8 @@ void ext4_truncate(struct inode *inode)
        ext4_lblk_t last_block;
        unsigned blocksize = inode->i_sb->s_blocksize;
 
+       trace_ext4_truncate_enter(inode);
+
        if (!ext4_can_truncate(inode))
                return;
 
@@ -4510,6 +4445,7 @@ void ext4_truncate(struct inode *inode)
 
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
                ext4_ext_truncate(inode);
+               trace_ext4_truncate_exit(inode);
                return;
        }
 
@@ -4639,6 +4575,7 @@ out_stop:
                ext4_orphan_del(handle, inode);
 
        ext4_journal_stop(handle);
+       trace_ext4_truncate_exit(inode);
 }
 
 /*
@@ -4770,6 +4707,7 @@ make_io:
                 * has in-inode xattrs, or we don't have this inode in memory.
                 * Read the block from disk.
                 */
+               trace_ext4_load_inode(inode);
                get_bh(bh);
                bh->b_end_io = end_buffer_read_sync;
                submit_bh(READ_META, bh);
@@ -4875,7 +4813,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                return inode;
 
        ei = EXT4_I(inode);
-       iloc.bh = 0;
+       iloc.bh = NULL;
 
        ret = __ext4_get_inode_loc(inode, &iloc, 0);
        if (ret < 0)
index eb3bc2fe647e710de889f04da3afaf5821e00556..808c554e773fdc2658c4708f1697edabab665acc 100644 (file)
@@ -38,7 +38,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                unsigned int oldflags;
                unsigned int jflag;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
@@ -146,7 +146,7 @@ flags_out:
                __u32 generation;
                int err;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
 
                err = mnt_want_write(filp->f_path.mnt);
@@ -298,7 +298,7 @@ mext_out:
        case EXT4_IOC_MIGRATE:
        {
                int err;
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                err = mnt_want_write(filp->f_path.mnt);
@@ -320,7 +320,7 @@ mext_out:
        case EXT4_IOC_ALLOC_DA_BLKS:
        {
                int err;
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                err = mnt_want_write(filp->f_path.mnt);
@@ -334,16 +334,22 @@ mext_out:
        case FITRIM:
        {
                struct super_block *sb = inode->i_sb;
+               struct request_queue *q = bdev_get_queue(sb->s_bdev);
                struct fstrim_range range;
                int ret = 0;
 
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
+               if (!blk_queue_discard(q))
+                       return -EOPNOTSUPP;
+
                if (copy_from_user(&range, (struct fstrim_range *)arg,
                    sizeof(range)))
                        return -EFAULT;
 
+               range.minlen = max((unsigned int)range.minlen,
+                                  q->limits.discard_granularity);
                ret = ext4_trim_fs(sb, &range);
                if (ret < 0)
                        return ret;
@@ -421,6 +427,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                return err;
        }
        case EXT4_IOC_MOVE_EXT:
+       case FITRIM:
                break;
        default:
                return -ENOIOCTLCMD;
index d1fe09aea73dc92419b0bf574694b6add33d7d8e..a5837a837a8bfea8e835563054c99b6fde0897e4 100644 (file)
@@ -432,9 +432,10 @@ static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max)
        }
 
        /* at order 0 we see each particular block */
-       *max = 1 << (e4b->bd_blkbits + 3);
-       if (order == 0)
+       if (order == 0) {
+               *max = 1 << (e4b->bd_blkbits + 3);
                return EXT4_MB_BITMAP(e4b);
+       }
 
        bb = EXT4_MB_BUDDY(e4b) + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order];
        *max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order];
@@ -616,7 +617,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
        MB_CHECK_ASSERT(e4b->bd_info->bb_fragments == fragments);
 
        grp = ext4_get_group_info(sb, e4b->bd_group);
-       buddy = mb_find_buddy(e4b, 0, &max);
        list_for_each(cur, &grp->bb_prealloc_list) {
                ext4_group_t groupnr;
                struct ext4_prealloc_space *pa;
@@ -635,7 +635,12 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
 #define mb_check_buddy(e4b)
 #endif
 
-/* FIXME!! need more doc */
+/*
+ * Divide blocks started from @first with length @len into
+ * smaller chunks with power of 2 blocks.
+ * Clear the bits in bitmap which the blocks of the chunk(s) covered,
+ * then increase bb_counters[] for corresponded chunk size.
+ */
 static void ext4_mb_mark_free_simple(struct super_block *sb,
                                void *buddy, ext4_grpblk_t first, ext4_grpblk_t len,
                                        struct ext4_group_info *grp)
@@ -2381,7 +2386,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
        /* An 8TB filesystem with 64-bit pointers requires a 4096 byte
         * kmalloc. A 128kb malloc should suffice for a 256TB filesystem.
         * So a two level scheme suffices for now. */
-       sbi->s_group_info = kmalloc(array_size, GFP_KERNEL);
+       sbi->s_group_info = kzalloc(array_size, GFP_KERNEL);
        if (sbi->s_group_info == NULL) {
                printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n");
                return -ENOMEM;
@@ -3208,7 +3213,7 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
        cur_distance = abs(goal_block - cpa->pa_pstart);
        new_distance = abs(goal_block - pa->pa_pstart);
 
-       if (cur_distance < new_distance)
+       if (cur_distance <= new_distance)
                return cpa;
 
        /* drop the previous reference */
@@ -3907,7 +3912,8 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
        struct super_block *sb = ac->ac_sb;
        ext4_group_t ngroups, i;
 
-       if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
+       if (!mb_enable_debug ||
+           (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED))
                return;
 
        printk(KERN_ERR "EXT4-fs: Can't allocate:"
@@ -4753,7 +4759,8 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count,
  * bitmap. Then issue a TRIM command on this extent and free the extent in
  * the group buddy bitmap. This is done until whole group is scanned.
  */
-ext4_grpblk_t ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
+static ext4_grpblk_t
+ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b,
                ext4_grpblk_t start, ext4_grpblk_t max, ext4_grpblk_t minblocks)
 {
        void *bitmap;
@@ -4863,10 +4870,15 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                        break;
                }
 
-               if (len >= EXT4_BLOCKS_PER_GROUP(sb))
-                       len -= (EXT4_BLOCKS_PER_GROUP(sb) - first_block);
-               else
+               /*
+                * For all the groups except the last one, last block will
+                * always be EXT4_BLOCKS_PER_GROUP(sb), so we only need to
+                * change it for the last group in which case start +
+                * len < EXT4_BLOCKS_PER_GROUP(sb).
+                */
+               if (first_block + len < EXT4_BLOCKS_PER_GROUP(sb))
                        last_block = first_block + len;
+               len -= last_block - first_block;
 
                if (e4b.bd_info->bb_free >= minlen) {
                        cnt = ext4_trim_all_free(sb, &e4b, first_block,
index b619322c76f0c5ea56d831b787d77e2911657a25..22bd4d7f289b834b277fb55ce92cefa019c9d354 100644 (file)
@@ -169,7 +169,7 @@ struct ext4_allocation_context {
        /* original request */
        struct ext4_free_extent ac_o_ex;
 
-       /* goal request (after normalization) */
+       /* goal request (normalized ac_o_ex) */
        struct ext4_free_extent ac_g_ex;
 
        /* the best found extent */
index b0a126f23c20cd70f662834411fdf870910a575f..d1bafa57f48367d7403ba4ef74734ece57349778 100644 (file)
@@ -263,7 +263,7 @@ static int free_dind_blocks(handle_t *handle,
        for (i = 0; i < max_entries; i++) {
                if (tmp_idata[i]) {
                        extend_credit_for_blkdel(handle, inode);
-                       ext4_free_blocks(handle, inode, 0,
+                       ext4_free_blocks(handle, inode, NULL,
                                         le32_to_cpu(tmp_idata[i]), 1,
                                         EXT4_FREE_BLOCKS_METADATA |
                                         EXT4_FREE_BLOCKS_FORGET);
@@ -271,7 +271,7 @@ static int free_dind_blocks(handle_t *handle,
        }
        put_bh(bh);
        extend_credit_for_blkdel(handle, inode);
-       ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1,
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
                         EXT4_FREE_BLOCKS_METADATA |
                         EXT4_FREE_BLOCKS_FORGET);
        return 0;
@@ -302,7 +302,7 @@ static int free_tind_blocks(handle_t *handle,
        }
        put_bh(bh);
        extend_credit_for_blkdel(handle, inode);
-       ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1,
+       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
                         EXT4_FREE_BLOCKS_METADATA |
                         EXT4_FREE_BLOCKS_FORGET);
        return 0;
@@ -315,7 +315,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
        /* ei->i_data[EXT4_IND_BLOCK] */
        if (i_data[0]) {
                extend_credit_for_blkdel(handle, inode);
-               ext4_free_blocks(handle, inode, 0,
+               ext4_free_blocks(handle, inode, NULL,
                                le32_to_cpu(i_data[0]), 1,
                                 EXT4_FREE_BLOCKS_METADATA |
                                 EXT4_FREE_BLOCKS_FORGET);
@@ -428,7 +428,7 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
        }
        put_bh(bh);
        extend_credit_for_blkdel(handle, inode);
-       ext4_free_blocks(handle, inode, 0, block, 1,
+       ext4_free_blocks(handle, inode, NULL, block, 1,
                         EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
        return retval;
 }
index e781b7ea56305dfde5c7458c78294a5dcc6d9361..67fd0b0258589ae64428d26530807b898e79854b 100644 (file)
@@ -40,6 +40,7 @@
 #include "xattr.h"
 #include "acl.h"
 
+#include <trace/events/ext4.h>
 /*
  * define how far ahead to read directories while searching them.
  */
@@ -2183,6 +2184,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        struct ext4_dir_entry_2 *de;
        handle_t *handle;
 
+       trace_ext4_unlink_enter(dir, dentry);
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
        dquot_initialize(dir);
@@ -2228,6 +2230,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 end_unlink:
        ext4_journal_stop(handle);
        brelse(bh);
+       trace_ext4_unlink_exit(dentry, retval);
        return retval;
 }
 
@@ -2402,6 +2405,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!new_inode && new_dir != old_dir &&
                    EXT4_DIR_LINK_MAX(new_dir))
                        goto end_rename;
+               BUFFER_TRACE(dir_bh, "get_write_access");
+               retval = ext4_journal_get_write_access(handle, dir_bh);
+               if (retval)
+                       goto end_rename;
        }
        if (!new_bh) {
                retval = ext4_add_entry(handle, new_dentry, old_inode);
@@ -2409,7 +2416,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto end_rename;
        } else {
                BUFFER_TRACE(new_bh, "get write access");
-               ext4_journal_get_write_access(handle, new_bh);
+               retval = ext4_journal_get_write_access(handle, new_bh);
+               if (retval)
+                       goto end_rename;
                new_de->inode = cpu_to_le32(old_inode->i_ino);
                if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
                                              EXT4_FEATURE_INCOMPAT_FILETYPE))
@@ -2470,8 +2479,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
        ext4_update_dx_flag(old_dir);
        if (dir_bh) {
-               BUFFER_TRACE(dir_bh, "get_write_access");
-               ext4_journal_get_write_access(handle, dir_bh);
                PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
                                                cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
index 955cc309142fe983dc41d95467b1f5a66d7a6b69..b6dbd056fcb1d7f532f428e34cae4ef5248680ce 100644 (file)
@@ -259,6 +259,11 @@ static void ext4_end_bio(struct bio *bio, int error)
                             bi_sector >> (inode->i_blkbits - 9));
        }
 
+       if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+               ext4_free_io_end(io_end);
+               return;
+       }
+
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
        list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list);
@@ -279,9 +284,9 @@ void ext4_io_submit(struct ext4_io_submit *io)
                BUG_ON(bio_flagged(io->io_bio, BIO_EOPNOTSUPP));
                bio_put(io->io_bio);
        }
-       io->io_bio = 0;
+       io->io_bio = NULL;
        io->io_op = 0;
-       io->io_end = 0;
+       io->io_end = NULL;
 }
 
 static int io_submit_init(struct ext4_io_submit *io,
@@ -310,8 +315,7 @@ static int io_submit_init(struct ext4_io_submit *io,
        io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 
        io->io_bio = bio;
-       io->io_op = (wbc->sync_mode == WB_SYNC_ALL ?
-                       WRITE_SYNC_PLUG : WRITE);
+       io->io_op = (wbc->sync_mode == WB_SYNC_ALL ?  WRITE_SYNC : WRITE);
        io->io_next_block = bh->b_blocknr;
        return 0;
 }
@@ -381,8 +385,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
 
        BUG_ON(!PageLocked(page));
        BUG_ON(PageWriteback(page));
-       set_page_writeback(page);
-       ClearPageError(page);
 
        io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS);
        if (!io_page) {
@@ -393,6 +395,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
        io_page->p_page = page;
        atomic_set(&io_page->p_count, 1);
        get_page(page);
+       set_page_writeback(page);
+       ClearPageError(page);
 
        for (bh = head = page_buffers(page), block_start = 0;
             bh != head || !block_start;
index 3ecc6e45d2f93568c5ccc298058a0d859a1768e5..80bbc9c60c247659047b805c9a74155bf2baeb14 100644 (file)
@@ -230,7 +230,7 @@ static int setup_new_group_blocks(struct super_block *sb,
        }
 
        /* Zero out all of the reserved backup group descriptor table blocks */
-       ext4_debug("clear inode table blocks %#04llx -> %#04llx\n",
+       ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
                        block, sbi->s_itb_per_group);
        err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb,
                               GFP_NOFS);
@@ -248,7 +248,7 @@ static int setup_new_group_blocks(struct super_block *sb,
 
        /* Zero out all of the inode table blocks */
        block = input->inode_table;
-       ext4_debug("clear inode table blocks %#04llx -> %#04llx\n",
+       ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
                        block, sbi->s_itb_per_group);
        err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS);
        if (err)
@@ -499,12 +499,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        return err;
 
 exit_inode:
-       /* ext4_journal_release_buffer(handle, iloc.bh); */
+       /* ext4_handle_release_buffer(handle, iloc.bh); */
        brelse(iloc.bh);
 exit_dindj:
-       /* ext4_journal_release_buffer(handle, dind); */
+       /* ext4_handle_release_buffer(handle, dind); */
 exit_sbh:
-       /* ext4_journal_release_buffer(handle, EXT4_SB(sb)->s_sbh); */
+       /* ext4_handle_release_buffer(handle, EXT4_SB(sb)->s_sbh); */
 exit_dind:
        brelse(dind);
 exit_bh:
@@ -586,7 +586,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
                        /*
                        int j;
                        for (j = 0; j < i; j++)
-                               ext4_journal_release_buffer(handle, primary[j]);
+                               ext4_handle_release_buffer(handle, primary[j]);
                         */
                        goto exit_bh;
                }
index 203f9e4a70be3afe974d492d9ca3c7f5c089738f..22546ad7f0aea7d2e5b6215c89eb9f24f1537c14 100644 (file)
@@ -54,9 +54,9 @@
 
 static struct proc_dir_entry *ext4_proc_root;
 static struct kset *ext4_kset;
-struct ext4_lazy_init *ext4_li_info;
-struct mutex ext4_li_mtx;
-struct ext4_features *ext4_feat;
+static struct ext4_lazy_init *ext4_li_info;
+static struct mutex ext4_li_mtx;
+static struct ext4_features *ext4_feat;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
@@ -75,6 +75,7 @@ static void ext4_write_super(struct super_block *sb);
 static int ext4_freeze(struct super_block *sb);
 static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
                       const char *dev_name, void *data);
+static int ext4_feature_set_ok(struct super_block *sb, int readonly);
 static void ext4_destroy_lazyinit_thread(void);
 static void ext4_unregister_li_request(struct super_block *sb);
 static void ext4_clear_request_list(void);
@@ -594,7 +595,7 @@ __acquires(bitlock)
 
        vaf.fmt = fmt;
        vaf.va = &args;
-       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
+       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
               sb->s_id, function, line, grp);
        if (ino)
                printk(KERN_CONT "inode %lu: ", ino);
@@ -997,13 +998,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (test_opt(sb, OLDALLOC))
                seq_puts(seq, ",oldalloc");
 #ifdef CONFIG_EXT4_FS_XATTR
-       if (test_opt(sb, XATTR_USER) &&
-               !(def_mount_opts & EXT4_DEFM_XATTR_USER))
+       if (test_opt(sb, XATTR_USER))
                seq_puts(seq, ",user_xattr");
-       if (!test_opt(sb, XATTR_USER) &&
-           (def_mount_opts & EXT4_DEFM_XATTR_USER)) {
+       if (!test_opt(sb, XATTR_USER))
                seq_puts(seq, ",nouser_xattr");
-       }
 #endif
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
        if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
@@ -1041,8 +1039,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
            !(def_mount_opts & EXT4_DEFM_NODELALLOC))
                seq_puts(seq, ",nodelalloc");
 
-       if (test_opt(sb, MBLK_IO_SUBMIT))
-               seq_puts(seq, ",mblk_io_submit");
+       if (!test_opt(sb, MBLK_IO_SUBMIT))
+               seq_puts(seq, ",nomblk_io_submit");
        if (sbi->s_stripe)
                seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
        /*
@@ -1451,7 +1449,7 @@ static int parse_options(char *options, struct super_block *sb,
                 * Initialize args struct so we know whether arg was
                 * found; some options take optional arguments.
                 */
-               args[0].to = args[0].from = 0;
+               args[0].to = args[0].from = NULL;
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_bsd_df:
@@ -1771,7 +1769,7 @@ set_qf_format:
                                return 0;
                        if (option < 0 || option > (1 << 30))
                                return 0;
-                       if (!is_power_of_2(option)) {
+                       if (option && !is_power_of_2(option)) {
                                ext4_msg(sb, KERN_ERR,
                                         "EXT4-fs: inode_readahead_blks"
                                         " must be a power of 2");
@@ -2120,6 +2118,13 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                return;
        }
 
+       /* Check if feature set would not allow a r/w mount */
+       if (!ext4_feature_set_ok(sb, 0)) {
+               ext4_msg(sb, KERN_INFO, "Skipping orphan cleanup due to "
+                        "unknown ROCOMPAT features");
+               return;
+       }
+
        if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
                if (es->s_last_orphan)
                        jbd_debug(1, "Errors on filesystem, "
@@ -2412,7 +2417,7 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
        if (parse_strtoul(buf, 0x40000000, &t))
                return -EINVAL;
 
-       if (!is_power_of_2(t))
+       if (t && !is_power_of_2(t))
                return -EINVAL;
 
        sbi->s_inode_readahead_blks = t;
@@ -3095,14 +3100,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        if (def_mount_opts & EXT4_DEFM_UID16)
                set_opt(sb, NO_UID32);
+       /* xattr user namespace & acls are now defaulted on */
 #ifdef CONFIG_EXT4_FS_XATTR
-       if (def_mount_opts & EXT4_DEFM_XATTR_USER)
-               set_opt(sb, XATTR_USER);
+       set_opt(sb, XATTR_USER);
 #endif
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
-       if (def_mount_opts & EXT4_DEFM_ACL)
-               set_opt(sb, POSIX_ACL);
+       set_opt(sb, POSIX_ACL);
 #endif
+       set_opt(sb, MBLK_IO_SUBMIT);
        if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
                set_opt(sb, JOURNAL_DATA);
        else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
@@ -3516,7 +3521,7 @@ no_journal:
         * concurrency isn't really necessary.  Limit it to 1.
         */
        EXT4_SB(sb)->dio_unwritten_wq =
-               alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM, 1);
+               alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
                goto failed_mount_wq;
@@ -3531,17 +3536,16 @@ no_journal:
        if (IS_ERR(root)) {
                ext4_msg(sb, KERN_ERR, "get root inode failed");
                ret = PTR_ERR(root);
+               root = NULL;
                goto failed_mount4;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
-               iput(root);
                ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
                goto failed_mount4;
        }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
                ext4_msg(sb, KERN_ERR, "get root dentry failed");
-               iput(root);
                ret = -ENOMEM;
                goto failed_mount4;
        }
@@ -3657,6 +3661,8 @@ cantfind_ext4:
        goto failed_mount;
 
 failed_mount4:
+       iput(root);
+       sb->s_root = NULL;
        ext4_msg(sb, KERN_ERR, "mount failed");
        destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq);
 failed_mount_wq:
index fc32176eee39ede67320bebeb44a80812d7d0f21..b545ca1c459c42e2cc6aef35ce49dea3fcd2694d 100644 (file)
@@ -735,7 +735,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                        int offset = (char *)s->here - bs->bh->b_data;
 
                        unlock_buffer(bs->bh);
-                       jbd2_journal_release_buffer(handle, bs->bh);
+                       ext4_handle_release_buffer(handle, bs->bh);
                        if (ce) {
                                mb_cache_entry_release(ce);
                                ce = NULL;
@@ -833,7 +833,7 @@ inserted:
                        new_bh = sb_getblk(sb, block);
                        if (!new_bh) {
 getblk_failed:
-                               ext4_free_blocks(handle, inode, 0, block, 1,
+                               ext4_free_blocks(handle, inode, NULL, block, 1,
                                                 EXT4_FREE_BLOCKS_METADATA);
                                error = -EIO;
                                goto cleanup;
index 0e277ec4b6120663795086b3a0cc80c4d1fcc813..8d68690bdcf1b2f26bb318972218930daa9676a6 100644 (file)
@@ -236,7 +236,6 @@ static const struct address_space_operations fat_aops = {
        .readpages      = fat_readpages,
        .writepage      = fat_writepage,
        .writepages     = fat_writepages,
-       .sync_page      = block_sync_page,
        .write_begin    = fat_write_begin,
        .write_end      = fat_write_end,
        .direct_IO      = fat_direct_IO,
index 6c82e5bac03932bf11e154b9c7c9e86b774e93cd..22764c7c8382ce607ca5f9ec9b1a2f48e3d15c4e 100644 (file)
@@ -159,7 +159,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 
        /* O_NOATIME can only be set by the owner or superuser */
        if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EPERM;
 
        /* required for strict SunOS emulation */
index 4e303c22d5ee53613682530bd1705a0a3cec8382..b1a524d798e720cf18ad7ad4decdab430a2b9c5e 100644 (file)
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -66,8 +66,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
                                /* suppress POLLHUP until we have
                                 * seen a writer */
                                filp->f_version = pipe->w_counter;
-                       } else 
-                       {
+                       } else {
                                wait_for_partner(inode, &pipe->w_counter);
                                if(signal_pending(current))
                                        goto err_rd;
index 1429f3ae1e868f2cb6f066542c3675d1d09134cd..5d318c44f8554bdbf5304a707557e413089b2913 100644 (file)
@@ -44,7 +44,6 @@ static sector_t               vxfs_bmap(struct address_space *, sector_t);
 const struct address_space_operations vxfs_aops = {
        .readpage =             vxfs_readpage,
        .bmap =                 vxfs_bmap,
-       .sync_page =            block_sync_page,
 };
 
 inline void
index 59c6e4956786e36b323bbbdea49822e7539ef355..b5ed541fb13773e0df9f2b09f87e71faaf4f82d9 100644 (file)
@@ -175,6 +175,17 @@ void bdi_start_background_writeback(struct backing_dev_info *bdi)
        spin_unlock_bh(&bdi->wb_lock);
 }
 
+/*
+ * Remove the inode from the writeback list it is on.
+ */
+void inode_wb_list_del(struct inode *inode)
+{
+       spin_lock(&inode_wb_list_lock);
+       list_del_init(&inode->i_wb_list);
+       spin_unlock(&inode_wb_list_lock);
+}
+
+
 /*
  * Redirty an inode: set its when-it-was dirtied timestamp and move it to the
  * furthest end of its superblock's dirty-inode list.
@@ -188,6 +199,7 @@ static void redirty_tail(struct inode *inode)
 {
        struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 
+       assert_spin_locked(&inode_wb_list_lock);
        if (!list_empty(&wb->b_dirty)) {
                struct inode *tail;
 
@@ -205,14 +217,17 @@ static void requeue_io(struct inode *inode)
 {
        struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 
+       assert_spin_locked(&inode_wb_list_lock);
        list_move(&inode->i_wb_list, &wb->b_more_io);
 }
 
 static void inode_sync_complete(struct inode *inode)
 {
        /*
-        * Prevent speculative execution through spin_unlock(&inode_lock);
+        * Prevent speculative execution through
+        * spin_unlock(&inode_wb_list_lock);
         */
+
        smp_mb();
        wake_up_bit(&inode->i_state, __I_SYNC);
 }
@@ -286,6 +301,7 @@ static void move_expired_inodes(struct list_head *delaying_queue,
  */
 static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this)
 {
+       assert_spin_locked(&inode_wb_list_lock);
        list_splice_init(&wb->b_more_io, &wb->b_io);
        move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
 }
@@ -306,25 +322,25 @@ static void inode_wait_for_writeback(struct inode *inode)
        wait_queue_head_t *wqh;
 
        wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
-        while (inode->i_state & I_SYNC) {
-               spin_unlock(&inode_lock);
+       while (inode->i_state & I_SYNC) {
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_wb_list_lock);
                __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE);
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
+               spin_lock(&inode->i_lock);
        }
 }
 
 /*
- * Write out an inode's dirty pages.  Called under inode_lock.  Either the
- * caller has ref on the inode (either via __iget or via syscall against an fd)
- * or the inode has I_WILL_FREE set (via generic_forget_inode)
+ * Write out an inode's dirty pages.  Called under inode_wb_list_lock and
+ * inode->i_lock.  Either the caller has an active reference on the inode or
+ * the inode has I_WILL_FREE set.
  *
  * If `wait' is set, wait on the writeout.
  *
  * The whole writeout design is quite complex and fragile.  We want to avoid
  * starvation of particular inodes when others are being redirtied, prevent
  * livelocks, etc.
- *
- * Called under inode_lock.
  */
 static int
 writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
@@ -333,6 +349,9 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        unsigned dirty;
        int ret;
 
+       assert_spin_locked(&inode_wb_list_lock);
+       assert_spin_locked(&inode->i_lock);
+
        if (!atomic_read(&inode->i_count))
                WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING)));
        else
@@ -363,7 +382,8 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        /* Set I_SYNC, reset I_DIRTY_PAGES */
        inode->i_state |= I_SYNC;
        inode->i_state &= ~I_DIRTY_PAGES;
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_wb_list_lock);
 
        ret = do_writepages(mapping, wbc);
 
@@ -383,10 +403,10 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
         * due to delalloc, clear dirty metadata flags right before
         * write_inode()
         */
-       spin_lock(&inode_lock);
+       spin_lock(&inode->i_lock);
        dirty = inode->i_state & I_DIRTY;
        inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
        /* Don't write the inode if only I_DIRTY_PAGES was set */
        if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
                int err = write_inode(inode, wbc);
@@ -394,7 +414,8 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
                        ret = err;
        }
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
+       spin_lock(&inode->i_lock);
        inode->i_state &= ~I_SYNC;
        if (!(inode->i_state & I_FREEING)) {
                if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
@@ -506,7 +527,9 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
                 * kind does not need peridic writeout yet, and for the latter
                 * kind writeout is handled by the freer.
                 */
+               spin_lock(&inode->i_lock);
                if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+                       spin_unlock(&inode->i_lock);
                        requeue_io(inode);
                        continue;
                }
@@ -515,10 +538,13 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
                 * Was this inode dirtied after sync_sb_inodes was called?
                 * This keeps sync from extra jobs and livelock.
                 */
-               if (inode_dirtied_after(inode, wbc->wb_start))
+               if (inode_dirtied_after(inode, wbc->wb_start)) {
+                       spin_unlock(&inode->i_lock);
                        return 1;
+               }
 
                __iget(inode);
+
                pages_skipped = wbc->pages_skipped;
                writeback_single_inode(inode, wbc);
                if (wbc->pages_skipped != pages_skipped) {
@@ -528,10 +554,11 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
                         */
                        redirty_tail(inode);
                }
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_wb_list_lock);
                iput(inode);
                cond_resched();
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                if (wbc->nr_to_write <= 0) {
                        wbc->more_io = 1;
                        return 1;
@@ -550,7 +577,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb,
 
        if (!wbc->wb_start)
                wbc->wb_start = jiffies; /* livelock avoidance */
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
 
@@ -568,7 +595,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb,
                if (ret)
                        break;
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
        /* Leave any unwritten inodes on b_io */
 }
 
@@ -577,11 +604,11 @@ static void __writeback_inodes_sb(struct super_block *sb,
 {
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
        writeback_sb_inodes(sb, wb, wbc, true);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
 }
 
 /*
@@ -720,13 +747,15 @@ static long wb_writeback(struct bdi_writeback *wb,
                 * become available for writeback. Otherwise
                 * we'll just busyloop.
                 */
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                if (!list_empty(&wb->b_more_io))  {
                        inode = wb_inode(wb->b_more_io.prev);
                        trace_wbc_writeback_wait(&wbc, wb->bdi);
+                       spin_lock(&inode->i_lock);
                        inode_wait_for_writeback(inode);
+                       spin_unlock(&inode->i_lock);
                }
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_wb_list_lock);
        }
 
        return wrote;
@@ -992,7 +1021,6 @@ void __mark_inode_dirty(struct inode *inode, int flags)
 {
        struct super_block *sb = inode->i_sb;
        struct backing_dev_info *bdi = NULL;
-       bool wakeup_bdi = false;
 
        /*
         * Don't do this for I_DIRTY_PAGES - that doesn't actually
@@ -1016,7 +1044,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
        if (unlikely(block_dump))
                block_dump___mark_inode_dirty(inode);
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode->i_lock);
        if ((inode->i_state & flags) != flags) {
                const int was_dirty = inode->i_state & I_DIRTY;
 
@@ -1028,7 +1056,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                 * superblock list, based upon its state.
                 */
                if (inode->i_state & I_SYNC)
-                       goto out;
+                       goto out_unlock_inode;
 
                /*
                 * Only add valid (hashed) inodes to the superblock's
@@ -1036,16 +1064,17 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                 */
                if (!S_ISBLK(inode->i_mode)) {
                        if (inode_unhashed(inode))
-                               goto out;
+                               goto out_unlock_inode;
                }
                if (inode->i_state & I_FREEING)
-                       goto out;
+                       goto out_unlock_inode;
 
                /*
                 * If the inode was already on b_dirty/b_io/b_more_io, don't
                 * reposition it (that would break b_dirty time-ordering).
                 */
                if (!was_dirty) {
+                       bool wakeup_bdi = false;
                        bdi = inode_to_bdi(inode);
 
                        if (bdi_cap_writeback_dirty(bdi)) {
@@ -1062,15 +1091,20 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                                        wakeup_bdi = true;
                        }
 
+                       spin_unlock(&inode->i_lock);
+                       spin_lock(&inode_wb_list_lock);
                        inode->dirtied_when = jiffies;
                        list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
+                       spin_unlock(&inode_wb_list_lock);
+
+                       if (wakeup_bdi)
+                               bdi_wakeup_thread_delayed(bdi);
+                       return;
                }
        }
-out:
-       spin_unlock(&inode_lock);
+out_unlock_inode:
+       spin_unlock(&inode->i_lock);
 
-       if (wakeup_bdi)
-               bdi_wakeup_thread_delayed(bdi);
 }
 EXPORT_SYMBOL(__mark_inode_dirty);
 
@@ -1101,7 +1135,7 @@ static void wait_sb_inodes(struct super_block *sb)
         */
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
 
        /*
         * Data integrity sync. Must wait for all pages under writeback,
@@ -1111,22 +1145,25 @@ static void wait_sb_inodes(struct super_block *sb)
         * we still have to wait for that writeout.
         */
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               struct address_space *mapping;
+               struct address_space *mapping = inode->i_mapping;
 
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
-                       continue;
-               mapping = inode->i_mapping;
-               if (mapping->nrpages == 0)
+               spin_lock(&inode->i_lock);
+               if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
+                   (mapping->nrpages == 0)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
                __iget(inode);
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_sb_list_lock);
+
                /*
-                * We hold a reference to 'inode' so it couldn't have
-                * been removed from s_inodes list while we dropped the
-                * inode_lock.  We cannot iput the inode now as we can
-                * be holding the last reference and we cannot iput it
-                * under inode_lock. So we keep the reference and iput
-                * it later.
+                * We hold a reference to 'inode' so it couldn't have been
+                * removed from s_inodes list while we dropped the
+                * inode_sb_list_lock.  We cannot iput the inode now as we can
+                * be holding the last reference and we cannot iput it under
+                * inode_sb_list_lock. So we keep the reference and iput it
+                * later.
                 */
                iput(old_inode);
                old_inode = inode;
@@ -1135,9 +1172,9 @@ static void wait_sb_inodes(struct super_block *sb)
 
                cond_resched();
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_sb_list_lock);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
        iput(old_inode);
 }
 
@@ -1271,9 +1308,11 @@ int write_inode_now(struct inode *inode, int sync)
                wbc.nr_to_write = 0;
 
        might_sleep();
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
+       spin_lock(&inode->i_lock);
        ret = writeback_single_inode(inode, &wbc);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_wb_list_lock);
        if (sync)
                inode_sync_wait(inode);
        return ret;
@@ -1295,9 +1334,11 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc)
 {
        int ret;
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
+       spin_lock(&inode->i_lock);
        ret = writeback_single_inode(inode, wbc);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_wb_list_lock);
        return ret;
 }
 EXPORT_SYMBOL(sync_inode);
index 7c39b885f969550d290d5202596a4e6d171d3181..b6cca47f7b07781c8c71a4ab2ea2facac67d37e5 100644 (file)
@@ -305,7 +305,7 @@ static void cuse_gendev_release(struct device *dev)
 static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 {
        struct cuse_conn *cc = fc_to_cc(fc);
-       struct cuse_init_out *arg = &req->misc.cuse_init_out;
+       struct cuse_init_out *arg = req->out.args[0].value;
        struct page *page = req->pages[0];
        struct cuse_devinfo devinfo = { };
        struct device *dev;
@@ -384,6 +384,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
        dev_set_uevent_suppress(dev, 0);
        kobject_uevent(&dev->kobj, KOBJ_ADD);
 out:
+       kfree(arg);
        __free_page(page);
        return;
 
@@ -405,6 +406,7 @@ static int cuse_send_init(struct cuse_conn *cc)
        struct page *page;
        struct fuse_conn *fc = &cc->fc;
        struct cuse_init_in *arg;
+       void *outarg;
 
        BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);
 
@@ -419,6 +421,10 @@ static int cuse_send_init(struct cuse_conn *cc)
        if (!page)
                goto err_put_req;
 
+       outarg = kzalloc(sizeof(struct cuse_init_out), GFP_KERNEL);
+       if (!outarg)
+               goto err_free_page;
+
        arg = &req->misc.cuse_init_in;
        arg->major = FUSE_KERNEL_VERSION;
        arg->minor = FUSE_KERNEL_MINOR_VERSION;
@@ -429,7 +435,7 @@ static int cuse_send_init(struct cuse_conn *cc)
        req->in.args[0].value = arg;
        req->out.numargs = 2;
        req->out.args[0].size = sizeof(struct cuse_init_out);
-       req->out.args[0].value = &req->misc.cuse_init_out;
+       req->out.args[0].value = outarg;
        req->out.args[1].size = CUSE_INIT_INFO_MAX;
        req->out.argvar = 1;
        req->out.argpages = 1;
@@ -440,6 +446,8 @@ static int cuse_send_init(struct cuse_conn *cc)
 
        return 0;
 
+err_free_page:
+       __free_page(page);
 err_put_req:
        fuse_put_request(fc, req);
 err:
index cf8d28d1fbadb90dd50725c950fa9f6f30bb426b..640fc229df10323b6c9fc94b0bda452157bf1ef0 100644 (file)
@@ -737,14 +737,12 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
        if (WARN_ON(PageMlocked(oldpage)))
                goto out_fallback_unlock;
 
-       remove_from_page_cache(oldpage);
-       page_cache_release(oldpage);
-
-       err = add_to_page_cache_locked(newpage, mapping, index, GFP_KERNEL);
+       err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL);
        if (err) {
-               printk(KERN_WARNING "fuse_try_move_page: failed to add page");
-               goto out_fallback_unlock;
+               unlock_page(newpage);
+               return err;
        }
+
        page_cache_get(newpage);
 
        if (!(buf->flags & PIPE_BUF_FLAG_LRU))
@@ -1910,6 +1908,21 @@ __acquires(fc->lock)
                kfree(dequeue_forget(fc, 1, NULL));
 }
 
+static void end_polls(struct fuse_conn *fc)
+{
+       struct rb_node *p;
+
+       p = rb_first(&fc->polled_files);
+
+       while (p) {
+               struct fuse_file *ff;
+               ff = rb_entry(p, struct fuse_file, polled_node);
+               wake_up_interruptible_all(&ff->poll_wait);
+
+               p = rb_next(p);
+       }
+}
+
 /*
  * Abort all requests.
  *
@@ -1937,6 +1950,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
                fc->blocked = 0;
                end_io_requests(fc);
                end_queued_requests(fc);
+               end_polls(fc);
                wake_up_all(&fc->waitq);
                wake_up_all(&fc->blocked_waitq);
                kill_fasync(&fc->fasync, SIGIO, POLL_IN);
@@ -1953,6 +1967,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
                fc->connected = 0;
                fc->blocked = 0;
                end_queued_requests(fc);
+               end_polls(fc);
                wake_up_all(&fc->blocked_waitq);
                spin_unlock(&fc->lock);
                fuse_conn_put(fc);
index 8bd0ef9286c376cf980e83b2513764d8bb683eef..c6ba49bd95b34136d04bae30b83342933c35ce7a 100644 (file)
@@ -158,10 +158,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 {
        struct inode *inode;
 
-       if (nd && nd->flags & LOOKUP_RCU)
-               return -ECHILD;
-
-       inode = entry->d_inode;
+       inode = ACCESS_ONCE(entry->d_inode);
        if (inode && is_bad_inode(inode))
                return 0;
        else if (fuse_dentry_time(entry) < get_jiffies_64()) {
@@ -177,6 +174,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                if (!inode)
                        return 0;
 
+               if (nd->flags & LOOKUP_RCU)
+                       return -ECHILD;
+
                fc = get_fuse_conn(inode);
                req = fuse_get_req(fc);
                if (IS_ERR(req))
@@ -970,6 +970,14 @@ static int fuse_access(struct inode *inode, int mask)
        return err;
 }
 
+static int fuse_perm_getattr(struct inode *inode, int flags)
+{
+       if (flags & IPERM_FLAG_RCU)
+               return -ECHILD;
+
+       return fuse_do_getattr(inode, NULL, NULL);
+}
+
 /*
  * Check permission.  The two basic access models of FUSE are:
  *
@@ -989,9 +997,6 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
        bool refreshed = false;
        int err = 0;
 
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
        if (!fuse_allow_task(fc, current))
                return -EACCES;
 
@@ -1000,9 +1005,15 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
         */
        if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
            ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
-               err = fuse_update_attributes(inode, NULL, NULL, &refreshed);
-               if (err)
-                       return err;
+               struct fuse_inode *fi = get_fuse_inode(inode);
+
+               if (fi->i_time < get_jiffies_64()) {
+                       refreshed = true;
+
+                       err = fuse_perm_getattr(inode, flags);
+                       if (err)
+                               return err;
+               }
        }
 
        if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
@@ -1012,7 +1023,7 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
                   attributes.  This is also needed, because the root
                   node will at first have no permissions */
                if (err == -EACCES && !refreshed) {
-                       err = fuse_do_getattr(inode, NULL, NULL);
+                       err = fuse_perm_getattr(inode, flags);
                        if (!err)
                                err = generic_permission(inode, mask,
                                                        flags, NULL);
@@ -1023,13 +1034,16 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
                   noticed immediately, only after the attribute
                   timeout has expired */
        } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
+               if (flags & IPERM_FLAG_RCU)
+                       return -ECHILD;
+
                err = fuse_access(inode, mask);
        } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                if (!(inode->i_mode & S_IXUGO)) {
                        if (refreshed)
                                return -EACCES;
 
-                       err = fuse_do_getattr(inode, NULL, NULL);
+                       err = fuse_perm_getattr(inode, flags);
                        if (!err && !(inode->i_mode & S_IXUGO))
                                return -EACCES;
                }
index 9e0832dbb1e3dfb8e0872273fc53800f60a9251d..6ea00734984e1e32fd28bce98b75eb794446361e 100644 (file)
@@ -222,7 +222,7 @@ static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode)
                rb_erase(&ff->polled_node, &fc->polled_files);
        spin_unlock(&fc->lock);
 
-       wake_up_interruptible_sync(&ff->poll_wait);
+       wake_up_interruptible_all(&ff->poll_wait);
 
        inarg->fh = ff->fh;
        inarg->flags = flags;
index d4286947bc2cf57a6aba78109d3592ceb988205e..b788becada76bf8616512fb766525fc89950eeec 100644 (file)
@@ -272,7 +272,6 @@ struct fuse_req {
                struct fuse_init_in init_in;
                struct fuse_init_out init_out;
                struct cuse_init_in cuse_init_in;
-               struct cuse_init_out cuse_init_out;
                struct {
                        struct fuse_read_in in;
                        u64 attr_ver;
index 051b1a084528b382201ae2a5dd3f7c536a60122c..cc6ec4b2f0ffed9c05959b149614a8a1e19e467d 100644 (file)
@@ -870,7 +870,6 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
 
        fc->bdi.name = "fuse";
        fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-       fc->bdi.unplug_io_fn = default_unplug_io_fn;
        /* fuse does it's own writeback accounting */
        fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
 
index 06c48a89183293b86e25d87329cb2d6aa6e3b775..8f26d1a5891226acc324798ed84bdeb27950145c 100644 (file)
@@ -74,7 +74,7 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value,
                return -EINVAL;
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
        if (value) {
                acl = posix_acl_from_xattr(value, size);
index 21f7e46da4c015925b5ff4ae1b6856f25653ea64..f3d23ef4e876a913aa48608bfe71aa2d192ecb05 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS := -I$(src)
+ccflags-y := -I$(src)
 obj-$(CONFIG_GFS2_FS) += gfs2.o
 gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \
        glops.o inode.o log.o lops.o main.o meta_io.o \
index aad77e4f61b574a3b29bb253a01e29046c70da55..c71995b111bf6f4347ffb313692c4ee66ff6f74e 100644 (file)
@@ -1117,7 +1117,6 @@ static const struct address_space_operations gfs2_writeback_aops = {
        .writepages = gfs2_writeback_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
-       .sync_page = block_sync_page,
        .write_begin = gfs2_write_begin,
        .write_end = gfs2_write_end,
        .bmap = gfs2_bmap,
@@ -1133,7 +1132,6 @@ static const struct address_space_operations gfs2_ordered_aops = {
        .writepage = gfs2_ordered_writepage,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
-       .sync_page = block_sync_page,
        .write_begin = gfs2_write_begin,
        .write_end = gfs2_write_end,
        .set_page_dirty = gfs2_set_page_dirty,
@@ -1151,7 +1149,6 @@ static const struct address_space_operations gfs2_jdata_aops = {
        .writepages = gfs2_jdata_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
-       .sync_page = block_sync_page,
        .write_begin = gfs2_write_begin,
        .write_end = gfs2_write_end,
        .set_page_dirty = gfs2_set_page_dirty,
index 4074b952b059fde1e44efe84d27e5ba17a87a25c..b2682e073eee0a593b1ab43c74291aa08e6af674 100644 (file)
@@ -221,7 +221,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
                goto out_drop_write;
 
        error = -EACCES;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                goto out;
 
        error = 0;
index e7ed31f858dda0b9219391adb94ab639885b3673..5b102c1887fd92ffd9b1c14dc01458f112736973 100644 (file)
@@ -121,7 +121,7 @@ __acquires(&sdp->sd_ail_lock)
                        lock_buffer(bh);
                        if (test_clear_buffer_dirty(bh)) {
                                bh->b_end_io = end_buffer_write_sync;
-                               submit_bh(WRITE_SYNC_PLUG, bh);
+                               submit_bh(WRITE_SYNC, bh);
                        } else {
                                unlock_buffer(bh);
                                brelse(bh);
@@ -647,7 +647,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
                lock_buffer(bh);
                if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) {
                        bh->b_end_io = end_buffer_write_sync;
-                       submit_bh(WRITE_SYNC_PLUG, bh);
+                       submit_bh(WRITE_SYNC, bh);
                } else {
                        unlock_buffer(bh);
                        brelse(bh);
index e919abf25ecde693dcb361412ea7438d5a5f7510..51d27f00ebb47ad1b7c5be178c2ad630e6fbefd0 100644 (file)
@@ -204,7 +204,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
                }
 
                gfs2_log_unlock(sdp);
-               submit_bh(WRITE_SYNC_PLUG, bh);
+               submit_bh(WRITE_SYNC, bh);
                gfs2_log_lock(sdp);
 
                n = 0;
@@ -214,7 +214,7 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
                        gfs2_log_unlock(sdp);
                        lock_buffer(bd2->bd_bh);
                        bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-                       submit_bh(WRITE_SYNC_PLUG, bh);
+                       submit_bh(WRITE_SYNC, bh);
                        gfs2_log_lock(sdp);
                        if (++n >= num)
                                break;
@@ -356,7 +356,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
                sdp->sd_log_num_revoke--;
 
                if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
-                       submit_bh(WRITE_SYNC_PLUG, bh);
+                       submit_bh(WRITE_SYNC, bh);
 
                        bh = gfs2_log_get_buf(sdp);
                        mh = (struct gfs2_meta_header *)bh->b_data;
@@ -373,7 +373,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
        }
        gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 
-       submit_bh(WRITE_SYNC_PLUG, bh);
+       submit_bh(WRITE_SYNC, bh);
 }
 
 static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
@@ -575,7 +575,7 @@ static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
        ptr = bh_log_ptr(bh);
        
        get_bh(bh);
-       submit_bh(WRITE_SYNC_PLUG, bh);
+       submit_bh(WRITE_SYNC, bh);
        gfs2_log_lock(sdp);
        while(!list_empty(list)) {
                bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list);
@@ -601,7 +601,7 @@ static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
                } else {
                        bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh);
                }
-               submit_bh(WRITE_SYNC_PLUG, bh1);
+               submit_bh(WRITE_SYNC, bh1);
                gfs2_log_lock(sdp);
                ptr += 2;
        }
index 01d97f4865535cb11accdd4689dddfa2c5ece66a..675349b5a1335de5e7c8f4ef22730fbed46b7463 100644 (file)
@@ -37,7 +37,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
        struct buffer_head *bh, *head;
        int nr_underway = 0;
        int write_op = REQ_META |
-               (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC_PLUG : WRITE);
+               (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
 
        BUG_ON(!PageLocked(page));
        BUG_ON(!page_has_buffers(page));
@@ -94,7 +94,6 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
 const struct address_space_operations gfs2_meta_aops = {
        .writepage = gfs2_aspace_writepage,
        .releasepage = gfs2_releasepage,
-       .sync_page = block_sync_page,
 };
 
 /**
index dffb4e996643557f04ae1c83292bd729ef5adada..fff16c968e67705a4d82e0bfcda6fca54aa005b0 100644 (file)
@@ -150,7 +150,6 @@ static int hfs_writepages(struct address_space *mapping,
 const struct address_space_operations hfs_btree_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = hfs_write_begin,
        .write_end      = generic_write_end,
        .bmap           = hfs_bmap,
@@ -160,7 +159,6 @@ const struct address_space_operations hfs_btree_aops = {
 const struct address_space_operations hfs_aops = {
        .readpage       = hfs_readpage,
        .writepage      = hfs_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = hfs_write_begin,
        .write_end      = generic_write_end,
        .bmap           = hfs_bmap,
index a8df651747f0eadaa8af44dffda657f2d64aea3d..b248a6cfcad93bb76631f7756b07b4ee6aff3d7e 100644 (file)
@@ -146,7 +146,6 @@ static int hfsplus_writepages(struct address_space *mapping,
 const struct address_space_operations hfsplus_btree_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = hfsplus_write_begin,
        .write_end      = generic_write_end,
        .bmap           = hfsplus_bmap,
@@ -156,7 +155,6 @@ const struct address_space_operations hfsplus_btree_aops = {
 const struct address_space_operations hfsplus_aops = {
        .readpage       = hfsplus_readpage,
        .writepage      = hfsplus_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = hfsplus_write_begin,
        .write_end      = generic_write_end,
        .bmap           = hfsplus_bmap,
index 508ce662ce122b0b5bea34f6f6260ae22ef0a512..fbaa6690c8e0ecd0ecbd49c47b6c182262301fea 100644 (file)
@@ -47,7 +47,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
        if (err)
                goto out;
 
-       if (!is_owner_or_cap(inode)) {
+       if (!inode_owner_or_capable(inode)) {
                err = -EACCES;
                goto out_drop_write;
        }
index 2dbae20450f8f7953109d781b0faff8a933354c5..9b9eb6933e43d8620a38ec744f77d4d8712e3b9a 100644 (file)
@@ -119,7 +119,6 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations hpfs_aops = {
        .readpage = hpfs_readpage,
        .writepage = hpfs_writepage,
-       .sync_page = block_sync_page,
        .write_begin = hpfs_write_begin,
        .write_end = generic_write_end,
        .bmap = _hpfs_bmap
index 9885082b470f72eef35b2fa286affb9a58ecbdc2..b9eeb1cd03ff540dc87aa31f43dc9eb03fbafb61 100644 (file)
@@ -332,8 +332,7 @@ static void truncate_huge_page(struct page *page)
 {
        cancel_dirty_page(page, /* No IO accounting for huge pages? */0);
        ClearPageUptodate(page);
-       remove_from_page_cache(page);
-       put_page(page);
+       delete_from_page_cache(page);
 }
 
 static void truncate_hugepages(struct inode *inode, loff_t lstart)
index 9910c039f026254a9caea134a5a7ac8d40c9c76f..05a1f75ae79181cbb190b93a29c5fa4e03dff0d4 100644 (file)
 #include <linux/async.h>
 #include <linux/posix_acl.h>
 #include <linux/ima.h>
+#include <linux/cred.h>
+#include "internal.h"
+
+/*
+ * inode locking rules.
+ *
+ * inode->i_lock protects:
+ *   inode->i_state, inode->i_hash, __iget()
+ * inode_lru_lock protects:
+ *   inode_lru, inode->i_lru
+ * inode_sb_list_lock protects:
+ *   sb->s_inodes, inode->i_sb_list
+ * inode_wb_list_lock protects:
+ *   bdi->wb.b_{dirty,io,more_io}, inode->i_wb_list
+ * inode_hash_lock protects:
+ *   inode_hashtable, inode->i_hash
+ *
+ * Lock ordering:
+ *
+ * inode_sb_list_lock
+ *   inode->i_lock
+ *     inode_lru_lock
+ *
+ * inode_wb_list_lock
+ *   inode->i_lock
+ *
+ * inode_hash_lock
+ *   inode_sb_list_lock
+ *   inode->i_lock
+ *
+ * iunique_lock
+ *   inode_hash_lock
+ */
 
 /*
  * This is needed for the following functions:
@@ -59,6 +92,8 @@
 
 static unsigned int i_hash_mask __read_mostly;
 static unsigned int i_hash_shift __read_mostly;
+static struct hlist_head *inode_hashtable __read_mostly;
+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);
 
 /*
  * Each inode can be on two separate lists. One is
@@ -73,15 +108,10 @@ static unsigned int i_hash_shift __read_mostly;
  */
 
 static LIST_HEAD(inode_lru);
-static struct hlist_head *inode_hashtable __read_mostly;
+static DEFINE_SPINLOCK(inode_lru_lock);
 
-/*
- * A simple spinlock to protect the list manipulations.
- *
- * NOTE! You also have to own the lock if you change
- * the i_state of an inode while it is in use..
- */
-DEFINE_SPINLOCK(inode_lock);
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock);
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock);
 
 /*
  * iprune_sem provides exclusion between the icache shrinking and the
@@ -136,15 +166,6 @@ int proc_nr_inodes(ctl_table *table, int write,
 }
 #endif
 
-static void wake_up_inode(struct inode *inode)
-{
-       /*
-        * Prevent speculative execution through spin_unlock(&inode_lock);
-        */
-       smp_mb();
-       wake_up_bit(&inode->i_state, __I_NEW);
-}
-
 /**
  * inode_init_always - perform inode structure intialisation
  * @sb: superblock inode belongs to
@@ -335,7 +356,7 @@ static void init_once(void *foo)
 }
 
 /*
- * inode_lock must be held
+ * inode->i_lock must be held
  */
 void __iget(struct inode *inode)
 {
@@ -353,23 +374,22 @@ EXPORT_SYMBOL(ihold);
 
 static void inode_lru_list_add(struct inode *inode)
 {
+       spin_lock(&inode_lru_lock);
        if (list_empty(&inode->i_lru)) {
                list_add(&inode->i_lru, &inode_lru);
                inodes_stat.nr_unused++;
        }
+       spin_unlock(&inode_lru_lock);
 }
 
 static void inode_lru_list_del(struct inode *inode)
 {
+       spin_lock(&inode_lru_lock);
        if (!list_empty(&inode->i_lru)) {
                list_del_init(&inode->i_lru);
                inodes_stat.nr_unused--;
        }
-}
-
-static inline void __inode_sb_list_add(struct inode *inode)
-{
-       list_add(&inode->i_sb_list, &inode->i_sb->s_inodes);
+       spin_unlock(&inode_lru_lock);
 }
 
 /**
@@ -378,15 +398,17 @@ static inline void __inode_sb_list_add(struct inode *inode)
  */
 void inode_sb_list_add(struct inode *inode)
 {
-       spin_lock(&inode_lock);
-       __inode_sb_list_add(inode);
-       spin_unlock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
+       list_add(&inode->i_sb_list, &inode->i_sb->s_inodes);
+       spin_unlock(&inode_sb_list_lock);
 }
 EXPORT_SYMBOL_GPL(inode_sb_list_add);
 
-static inline void __inode_sb_list_del(struct inode *inode)
+static inline void inode_sb_list_del(struct inode *inode)
 {
+       spin_lock(&inode_sb_list_lock);
        list_del_init(&inode->i_sb_list);
+       spin_unlock(&inode_sb_list_lock);
 }
 
 static unsigned long hash(struct super_block *sb, unsigned long hashval)
@@ -411,23 +433,14 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval)
 {
        struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval);
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_hash_lock);
+       spin_lock(&inode->i_lock);
        hlist_add_head(&inode->i_hash, b);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_hash_lock);
 }
 EXPORT_SYMBOL(__insert_inode_hash);
 
-/**
- *     __remove_inode_hash - remove an inode from the hash
- *     @inode: inode to unhash
- *
- *     Remove an inode from the superblock.
- */
-static void __remove_inode_hash(struct inode *inode)
-{
-       hlist_del_init(&inode->i_hash);
-}
-
 /**
  *     remove_inode_hash - remove an inode from the hash
  *     @inode: inode to unhash
@@ -436,9 +449,11 @@ static void __remove_inode_hash(struct inode *inode)
  */
 void remove_inode_hash(struct inode *inode)
 {
-       spin_lock(&inode_lock);
+       spin_lock(&inode_hash_lock);
+       spin_lock(&inode->i_lock);
        hlist_del_init(&inode->i_hash);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_hash_lock);
 }
 EXPORT_SYMBOL(remove_inode_hash);
 
@@ -455,10 +470,29 @@ void end_writeback(struct inode *inode)
 }
 EXPORT_SYMBOL(end_writeback);
 
+/*
+ * Free the inode passed in, removing it from the lists it is still connected
+ * to. We remove any pages still attached to the inode and wait for any IO that
+ * is still in progress before finally destroying the inode.
+ *
+ * An inode must already be marked I_FREEING so that we avoid the inode being
+ * moved back onto lists if we race with other code that manipulates the lists
+ * (e.g. writeback_single_inode). The caller is responsible for setting this.
+ *
+ * An inode must already be removed from the LRU list before being evicted from
+ * the cache. This should occur atomically with setting the I_FREEING state
+ * flag, so no inodes here should ever be on the LRU when being evicted.
+ */
 static void evict(struct inode *inode)
 {
        const struct super_operations *op = inode->i_sb->s_op;
 
+       BUG_ON(!(inode->i_state & I_FREEING));
+       BUG_ON(!list_empty(&inode->i_lru));
+
+       inode_wb_list_del(inode);
+       inode_sb_list_del(inode);
+
        if (op->evict_inode) {
                op->evict_inode(inode);
        } else {
@@ -470,6 +504,15 @@ static void evict(struct inode *inode)
                bd_forget(inode);
        if (S_ISCHR(inode->i_mode) && inode->i_cdev)
                cd_forget(inode);
+
+       remove_inode_hash(inode);
+
+       spin_lock(&inode->i_lock);
+       wake_up_bit(&inode->i_state, __I_NEW);
+       BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
+       spin_unlock(&inode->i_lock);
+
+       destroy_inode(inode);
 }
 
 /*
@@ -488,14 +531,6 @@ static void dispose_list(struct list_head *head)
                list_del_init(&inode->i_lru);
 
                evict(inode);
-
-               spin_lock(&inode_lock);
-               __remove_inode_hash(inode);
-               __inode_sb_list_del(inode);
-               spin_unlock(&inode_lock);
-
-               wake_up_inode(inode);
-               destroy_inode(inode);
        }
 }
 
@@ -513,25 +548,23 @@ void evict_inodes(struct super_block *sb)
        struct inode *inode, *next;
        LIST_HEAD(dispose);
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                if (atomic_read(&inode->i_count))
                        continue;
-               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
+
+               spin_lock(&inode->i_lock);
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
 
                inode->i_state |= I_FREEING;
-
-               /*
-                * Move the inode off the IO lists and LRU once I_FREEING is
-                * set so that it won't get moved back on there if it is dirty.
-                */
-               list_move(&inode->i_lru, &dispose);
-               list_del_init(&inode->i_wb_list);
-               if (!(inode->i_state & (I_DIRTY | I_SYNC)))
-                       inodes_stat.nr_unused--;
+               inode_lru_list_del(inode);
+               spin_unlock(&inode->i_lock);
+               list_add(&inode->i_lru, &dispose);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
 
        dispose_list(&dispose);
 
@@ -560,31 +593,30 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
        struct inode *inode, *next;
        LIST_HEAD(dispose);
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
+               spin_lock(&inode->i_lock);
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
                if (inode->i_state & I_DIRTY && !kill_dirty) {
+                       spin_unlock(&inode->i_lock);
                        busy = 1;
                        continue;
                }
                if (atomic_read(&inode->i_count)) {
+                       spin_unlock(&inode->i_lock);
                        busy = 1;
                        continue;
                }
 
                inode->i_state |= I_FREEING;
-
-               /*
-                * Move the inode off the IO lists and LRU once I_FREEING is
-                * set so that it won't get moved back on there if it is dirty.
-                */
-               list_move(&inode->i_lru, &dispose);
-               list_del_init(&inode->i_wb_list);
-               if (!(inode->i_state & (I_DIRTY | I_SYNC)))
-                       inodes_stat.nr_unused--;
+               inode_lru_list_del(inode);
+               spin_unlock(&inode->i_lock);
+               list_add(&inode->i_lru, &dispose);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
 
        dispose_list(&dispose);
 
@@ -606,7 +638,7 @@ static int can_unuse(struct inode *inode)
 
 /*
  * Scan `goal' inodes on the unused list for freeable ones. They are moved to a
- * temporary list and then are freed outside inode_lock by dispose_list().
+ * temporary list and then are freed outside inode_lru_lock by dispose_list().
  *
  * Any inodes which are pinned purely because of attached pagecache have their
  * pagecache removed.  If the inode has metadata buffers attached to
@@ -627,7 +659,7 @@ static void prune_icache(int nr_to_scan)
        unsigned long reap = 0;
 
        down_read(&iprune_sem);
-       spin_lock(&inode_lock);
+       spin_lock(&inode_lru_lock);
        for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
                struct inode *inode;
 
@@ -636,6 +668,16 @@ static void prune_icache(int nr_to_scan)
 
                inode = list_entry(inode_lru.prev, struct inode, i_lru);
 
+               /*
+                * we are inverting the inode_lru_lock/inode->i_lock here,
+                * so use a trylock. If we fail to get the lock, just move the
+                * inode to the back of the list so we don't spin on it.
+                */
+               if (!spin_trylock(&inode->i_lock)) {
+                       list_move(&inode->i_lru, &inode_lru);
+                       continue;
+               }
+
                /*
                 * Referenced or dirty inodes are still in use. Give them
                 * another pass through the LRU as we canot reclaim them now.
@@ -643,47 +685,51 @@ static void prune_icache(int nr_to_scan)
                if (atomic_read(&inode->i_count) ||
                    (inode->i_state & ~I_REFERENCED)) {
                        list_del_init(&inode->i_lru);
+                       spin_unlock(&inode->i_lock);
                        inodes_stat.nr_unused--;
                        continue;
                }
 
                /* recently referenced inodes get one more pass */
                if (inode->i_state & I_REFERENCED) {
-                       list_move(&inode->i_lru, &inode_lru);
                        inode->i_state &= ~I_REFERENCED;
+                       list_move(&inode->i_lru, &inode_lru);
+                       spin_unlock(&inode->i_lock);
                        continue;
                }
                if (inode_has_buffers(inode) || inode->i_data.nrpages) {
                        __iget(inode);
-                       spin_unlock(&inode_lock);
+                       spin_unlock(&inode->i_lock);
+                       spin_unlock(&inode_lru_lock);
                        if (remove_inode_buffers(inode))
                                reap += invalidate_mapping_pages(&inode->i_data,
                                                                0, -1);
                        iput(inode);
-                       spin_lock(&inode_lock);
+                       spin_lock(&inode_lru_lock);
 
                        if (inode != list_entry(inode_lru.next,
                                                struct inode, i_lru))
                                continue;       /* wrong inode or list_empty */
-                       if (!can_unuse(inode))
+                       /* avoid lock inversions with trylock */
+                       if (!spin_trylock(&inode->i_lock))
                                continue;
+                       if (!can_unuse(inode)) {
+                               spin_unlock(&inode->i_lock);
+                               continue;
+                       }
                }
                WARN_ON(inode->i_state & I_NEW);
                inode->i_state |= I_FREEING;
+               spin_unlock(&inode->i_lock);
 
-               /*
-                * Move the inode off the IO lists and LRU once I_FREEING is
-                * set so that it won't get moved back on there if it is dirty.
-                */
                list_move(&inode->i_lru, &freeable);
-               list_del_init(&inode->i_wb_list);
                inodes_stat.nr_unused--;
        }
        if (current_is_kswapd())
                __count_vm_events(KSWAPD_INODESTEAL, reap);
        else
                __count_vm_events(PGINODESTEAL, reap);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_lru_lock);
 
        dispose_list(&freeable);
        up_read(&iprune_sem);
@@ -732,15 +778,21 @@ static struct inode *find_inode(struct super_block *sb,
 
 repeat:
        hlist_for_each_entry(inode, node, head, i_hash) {
-               if (inode->i_sb != sb)
+               spin_lock(&inode->i_lock);
+               if (inode->i_sb != sb) {
+                       spin_unlock(&inode->i_lock);
                        continue;
-               if (!test(inode, data))
+               }
+               if (!test(inode, data)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
                        __wait_on_freeing_inode(inode);
                        goto repeat;
                }
                __iget(inode);
+               spin_unlock(&inode->i_lock);
                return inode;
        }
        return NULL;
@@ -758,15 +810,21 @@ static struct inode *find_inode_fast(struct super_block *sb,
 
 repeat:
        hlist_for_each_entry(inode, node, head, i_hash) {
-               if (inode->i_ino != ino)
+               spin_lock(&inode->i_lock);
+               if (inode->i_ino != ino) {
+                       spin_unlock(&inode->i_lock);
                        continue;
-               if (inode->i_sb != sb)
+               }
+               if (inode->i_sb != sb) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
                        __wait_on_freeing_inode(inode);
                        goto repeat;
                }
                __iget(inode);
+               spin_unlock(&inode->i_lock);
                return inode;
        }
        return NULL;
@@ -826,19 +884,26 @@ struct inode *new_inode(struct super_block *sb)
 {
        struct inode *inode;
 
-       spin_lock_prefetch(&inode_lock);
+       spin_lock_prefetch(&inode_sb_list_lock);
 
        inode = alloc_inode(sb);
        if (inode) {
-               spin_lock(&inode_lock);
-               __inode_sb_list_add(inode);
+               spin_lock(&inode->i_lock);
                inode->i_state = 0;
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
+               inode_sb_list_add(inode);
        }
        return inode;
 }
 EXPORT_SYMBOL(new_inode);
 
+/**
+ * unlock_new_inode - clear the I_NEW state and wake up any waiters
+ * @inode:     new inode to unlock
+ *
+ * Called when the inode is fully initialised to clear the new state of the
+ * inode and wake up anyone waiting for the inode to finish initialisation.
+ */
 void unlock_new_inode(struct inode *inode)
 {
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -858,51 +923,67 @@ void unlock_new_inode(struct inode *inode)
                }
        }
 #endif
-       /*
-        * This is special!  We do not need the spinlock when clearing I_NEW,
-        * because we're guaranteed that nobody else tries to do anything about
-        * the state of the inode when it is locked, as we just created it (so
-        * there can be no old holders that haven't tested I_NEW).
-        * However we must emit the memory barrier so that other CPUs reliably
-        * see the clearing of I_NEW after the other inode initialisation has
-        * completed.
-        */
-       smp_mb();
+       spin_lock(&inode->i_lock);
        WARN_ON(!(inode->i_state & I_NEW));
        inode->i_state &= ~I_NEW;
-       wake_up_inode(inode);
+       wake_up_bit(&inode->i_state, __I_NEW);
+       spin_unlock(&inode->i_lock);
 }
 EXPORT_SYMBOL(unlock_new_inode);
 
-/*
- * This is called without the inode lock held.. Be careful.
+/**
+ * iget5_locked - obtain an inode from a mounted file system
+ * @sb:                super block of file system
+ * @hashval:   hash value (usually inode number) to get
+ * @test:      callback used for comparisons between inodes
+ * @set:       callback used to initialize a new struct inode
+ * @data:      opaque data pointer to pass to @test and @set
+ *
+ * Search for the inode specified by @hashval and @data in the inode cache,
+ * and if present it is return it with an increased reference count. This is
+ * a generalized version of iget_locked() for file systems where the inode
+ * number is not sufficient for unique identification of an inode.
+ *
+ * If the inode is not in cache, allocate a new inode and return it locked,
+ * hashed, and with the I_NEW flag set. The file system gets to fill it in
+ * before unlocking it via unlock_new_inode().
  *
- * We no longer cache the sb_flags in i_flags - see fs.h
- *     -- rmk@arm.uk.linux.org
+ * Note both @test and @set are called with the inode_hash_lock held, so can't
+ * sleep.
  */
-static struct inode *get_new_inode(struct super_block *sb,
-                               struct hlist_head *head,
-                               int (*test)(struct inode *, void *),
-                               int (*set)(struct inode *, void *),
-                               void *data)
+struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
+               int (*test)(struct inode *, void *),
+               int (*set)(struct inode *, void *), void *data)
 {
+       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
        struct inode *inode;
 
+       spin_lock(&inode_hash_lock);
+       inode = find_inode(sb, head, test, data);
+       spin_unlock(&inode_hash_lock);
+
+       if (inode) {
+               wait_on_inode(inode);
+               return inode;
+       }
+
        inode = alloc_inode(sb);
        if (inode) {
                struct inode *old;
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_hash_lock);
                /* We released the lock, so.. */
                old = find_inode(sb, head, test, data);
                if (!old) {
                        if (set(inode, data))
                                goto set_failed;
 
-                       hlist_add_head(&inode->i_hash, head);
-                       __inode_sb_list_add(inode);
+                       spin_lock(&inode->i_lock);
                        inode->i_state = I_NEW;
-                       spin_unlock(&inode_lock);
+                       hlist_add_head(&inode->i_hash, head);
+                       spin_unlock(&inode->i_lock);
+                       inode_sb_list_add(inode);
+                       spin_unlock(&inode_hash_lock);
 
                        /* Return the locked inode with I_NEW set, the
                         * caller is responsible for filling in the contents
@@ -915,7 +996,7 @@ static struct inode *get_new_inode(struct super_block *sb,
                 * us. Use the old inode instead of the one we just
                 * allocated.
                 */
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_hash_lock);
                destroy_inode(inode);
                inode = old;
                wait_on_inode(inode);
@@ -923,33 +1004,53 @@ static struct inode *get_new_inode(struct super_block *sb,
        return inode;
 
 set_failed:
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_hash_lock);
        destroy_inode(inode);
        return NULL;
 }
+EXPORT_SYMBOL(iget5_locked);
 
-/*
- * get_new_inode_fast is the fast path version of get_new_inode, see the
- * comment at iget_locked for details.
+/**
+ * iget_locked - obtain an inode from a mounted file system
+ * @sb:                super block of file system
+ * @ino:       inode number to get
+ *
+ * Search for the inode specified by @ino in the inode cache and if present
+ * return it with an increased reference count. This is for file systems
+ * where the inode number is sufficient for unique identification of an inode.
+ *
+ * If the inode is not in cache, allocate a new inode and return it locked,
+ * hashed, and with the I_NEW flag set.  The file system gets to fill it in
+ * before unlocking it via unlock_new_inode().
  */
-static struct inode *get_new_inode_fast(struct super_block *sb,
-                               struct hlist_head *head, unsigned long ino)
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
 {
+       struct hlist_head *head = inode_hashtable + hash(sb, ino);
        struct inode *inode;
 
+       spin_lock(&inode_hash_lock);
+       inode = find_inode_fast(sb, head, ino);
+       spin_unlock(&inode_hash_lock);
+       if (inode) {
+               wait_on_inode(inode);
+               return inode;
+       }
+
        inode = alloc_inode(sb);
        if (inode) {
                struct inode *old;
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_hash_lock);
                /* We released the lock, so.. */
                old = find_inode_fast(sb, head, ino);
                if (!old) {
                        inode->i_ino = ino;
-                       hlist_add_head(&inode->i_hash, head);
-                       __inode_sb_list_add(inode);
+                       spin_lock(&inode->i_lock);
                        inode->i_state = I_NEW;
-                       spin_unlock(&inode_lock);
+                       hlist_add_head(&inode->i_hash, head);
+                       spin_unlock(&inode->i_lock);
+                       inode_sb_list_add(inode);
+                       spin_unlock(&inode_hash_lock);
 
                        /* Return the locked inode with I_NEW set, the
                         * caller is responsible for filling in the contents
@@ -962,13 +1063,14 @@ static struct inode *get_new_inode_fast(struct super_block *sb,
                 * us. Use the old inode instead of the one we just
                 * allocated.
                 */
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_hash_lock);
                destroy_inode(inode);
                inode = old;
                wait_on_inode(inode);
        }
        return inode;
 }
+EXPORT_SYMBOL(iget_locked);
 
 /*
  * search the inode cache for a matching inode number.
@@ -983,10 +1085,14 @@ static int test_inode_iunique(struct super_block *sb, unsigned long ino)
        struct hlist_node *node;
        struct inode *inode;
 
+       spin_lock(&inode_hash_lock);
        hlist_for_each_entry(inode, node, b, i_hash) {
-               if (inode->i_ino == ino && inode->i_sb == sb)
+               if (inode->i_ino == ino && inode->i_sb == sb) {
+                       spin_unlock(&inode_hash_lock);
                        return 0;
+               }
        }
+       spin_unlock(&inode_hash_lock);
 
        return 1;
 }
@@ -1016,7 +1122,6 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
        static unsigned int counter;
        ino_t res;
 
-       spin_lock(&inode_lock);
        spin_lock(&iunique_lock);
        do {
                if (counter <= max_reserved)
@@ -1024,7 +1129,6 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
                res = counter++;
        } while (!test_inode_iunique(sb, res));
        spin_unlock(&iunique_lock);
-       spin_unlock(&inode_lock);
 
        return res;
 }
@@ -1032,89 +1136,23 @@ EXPORT_SYMBOL(iunique);
 
 struct inode *igrab(struct inode *inode)
 {
-       spin_lock(&inode_lock);
-       if (!(inode->i_state & (I_FREEING|I_WILL_FREE)))
+       spin_lock(&inode->i_lock);
+       if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) {
                __iget(inode);
-       else
+               spin_unlock(&inode->i_lock);
+       } else {
+               spin_unlock(&inode->i_lock);
                /*
                 * Handle the case where s_op->clear_inode is not been
                 * called yet, and somebody is calling igrab
                 * while the inode is getting freed.
                 */
                inode = NULL;
-       spin_unlock(&inode_lock);
+       }
        return inode;
 }
 EXPORT_SYMBOL(igrab);
 
-/**
- * ifind - internal function, you want ilookup5() or iget5().
- * @sb:                super block of file system to search
- * @head:       the head of the list to search
- * @test:      callback used for comparisons between inodes
- * @data:      opaque data pointer to pass to @test
- * @wait:      if true wait for the inode to be unlocked, if false do not
- *
- * ifind() searches for the inode specified by @data in the inode
- * cache. This is a generalized version of ifind_fast() for file systems where
- * the inode number is not sufficient for unique identification of an inode.
- *
- * If the inode is in the cache, the inode is returned with an incremented
- * reference count.
- *
- * Otherwise NULL is returned.
- *
- * Note, @test is called with the inode_lock held, so can't sleep.
- */
-static struct inode *ifind(struct super_block *sb,
-               struct hlist_head *head, int (*test)(struct inode *, void *),
-               void *data, const int wait)
-{
-       struct inode *inode;
-
-       spin_lock(&inode_lock);
-       inode = find_inode(sb, head, test, data);
-       if (inode) {
-               spin_unlock(&inode_lock);
-               if (likely(wait))
-                       wait_on_inode(inode);
-               return inode;
-       }
-       spin_unlock(&inode_lock);
-       return NULL;
-}
-
-/**
- * ifind_fast - internal function, you want ilookup() or iget().
- * @sb:                super block of file system to search
- * @head:       head of the list to search
- * @ino:       inode number to search for
- *
- * ifind_fast() searches for the inode @ino in the inode cache. This is for
- * file systems where the inode number is sufficient for unique identification
- * of an inode.
- *
- * If the inode is in the cache, the inode is returned with an incremented
- * reference count.
- *
- * Otherwise NULL is returned.
- */
-static struct inode *ifind_fast(struct super_block *sb,
-               struct hlist_head *head, unsigned long ino)
-{
-       struct inode *inode;
-
-       spin_lock(&inode_lock);
-       inode = find_inode_fast(sb, head, ino);
-       if (inode) {
-               spin_unlock(&inode_lock);
-               wait_on_inode(inode);
-               return inode;
-       }
-       spin_unlock(&inode_lock);
-       return NULL;
-}
-
 /**
  * ilookup5_nowait - search for an inode in the inode cache
  * @sb:                super block of file system to search
@@ -1122,26 +1160,26 @@ static struct inode *ifind_fast(struct super_block *sb,
  * @test:      callback used for comparisons between inodes
  * @data:      opaque data pointer to pass to @test
  *
- * ilookup5() uses ifind() to search for the inode specified by @hashval and
- * @data in the inode cache. This is a generalized version of ilookup() for
- * file systems where the inode number is not sufficient for unique
- * identification of an inode.
- *
+ * Search for the inode specified by @hashval and @data in the inode cache.
  * If the inode is in the cache, the inode is returned with an incremented
- * reference count.  Note, the inode lock is not waited upon so you have to be
- * very careful what you do with the returned inode.  You probably should be
- * using ilookup5() instead.
+ * reference count.
  *
- * Otherwise NULL is returned.
+ * Note: I_NEW is not waited upon so you have to be very careful what you do
+ * with the returned inode.  You probably should be using ilookup5() instead.
  *
- * Note, @test is called with the inode_lock held, so can't sleep.
+ * Note: @test is called with the inode_hash_lock held, so can't sleep.
  */
 struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval,
                int (*test)(struct inode *, void *), void *data)
 {
        struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *inode;
+
+       spin_lock(&inode_hash_lock);
+       inode = find_inode(sb, head, test, data);
+       spin_unlock(&inode_hash_lock);
 
-       return ifind(sb, head, test, data, 0);
+       return inode;
 }
 EXPORT_SYMBOL(ilookup5_nowait);
 
@@ -1152,24 +1190,24 @@ EXPORT_SYMBOL(ilookup5_nowait);
  * @test:      callback used for comparisons between inodes
  * @data:      opaque data pointer to pass to @test
  *
- * ilookup5() uses ifind() to search for the inode specified by @hashval and
- * @data in the inode cache. This is a generalized version of ilookup() for
- * file systems where the inode number is not sufficient for unique
- * identification of an inode.
- *
- * If the inode is in the cache, the inode lock is waited upon and the inode is
+ * Search for the inode specified by @hashval and @data in the inode cache,
+ * and if the inode is in the cache, return the inode with an incremented
+ * reference count.  Waits on I_NEW before returning the inode.
  * returned with an incremented reference count.
  *
- * Otherwise NULL is returned.
+ * This is a generalized version of ilookup() for file systems where the
+ * inode number is not sufficient for unique identification of an inode.
  *
- * Note, @test is called with the inode_lock held, so can't sleep.
+ * Note: @test is called with the inode_hash_lock held, so can't sleep.
  */
 struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
                int (*test)(struct inode *, void *), void *data)
 {
-       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *inode = ilookup5_nowait(sb, hashval, test, data);
 
-       return ifind(sb, head, test, data, 1);
+       if (inode)
+               wait_on_inode(inode);
+       return inode;
 }
 EXPORT_SYMBOL(ilookup5);
 
@@ -1178,91 +1216,23 @@ EXPORT_SYMBOL(ilookup5);
  * @sb:                super block of file system to search
  * @ino:       inode number to search for
  *
- * ilookup() uses ifind_fast() to search for the inode @ino in the inode cache.
- * This is for file systems where the inode number is sufficient for unique
- * identification of an inode.
- *
- * If the inode is in the cache, the inode is returned with an incremented
- * reference count.
- *
- * Otherwise NULL is returned.
+ * Search for the inode @ino in the inode cache, and if the inode is in the
+ * cache, the inode is returned with an incremented reference count.
  */
 struct inode *ilookup(struct super_block *sb, unsigned long ino)
 {
        struct hlist_head *head = inode_hashtable + hash(sb, ino);
-
-       return ifind_fast(sb, head, ino);
-}
-EXPORT_SYMBOL(ilookup);
-
-/**
- * iget5_locked - obtain an inode from a mounted file system
- * @sb:                super block of file system
- * @hashval:   hash value (usually inode number) to get
- * @test:      callback used for comparisons between inodes
- * @set:       callback used to initialize a new struct inode
- * @data:      opaque data pointer to pass to @test and @set
- *
- * iget5_locked() uses ifind() to search for the inode specified by @hashval
- * and @data in the inode cache and if present it is returned with an increased
- * reference count. This is a generalized version of iget_locked() for file
- * systems where the inode number is not sufficient for unique identification
- * of an inode.
- *
- * If the inode is not in cache, get_new_inode() is called to allocate a new
- * inode and this is returned locked, hashed, and with the I_NEW flag set. The
- * file system gets to fill it in before unlocking it via unlock_new_inode().
- *
- * Note both @test and @set are called with the inode_lock held, so can't sleep.
- */
-struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
-               int (*test)(struct inode *, void *),
-               int (*set)(struct inode *, void *), void *data)
-{
-       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
        struct inode *inode;
 
-       inode = ifind(sb, head, test, data, 1);
-       if (inode)
-               return inode;
-       /*
-        * get_new_inode() will do the right thing, re-trying the search
-        * in case it had to block at any point.
-        */
-       return get_new_inode(sb, head, test, set, data);
-}
-EXPORT_SYMBOL(iget5_locked);
-
-/**
- * iget_locked - obtain an inode from a mounted file system
- * @sb:                super block of file system
- * @ino:       inode number to get
- *
- * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
- * the inode cache and if present it is returned with an increased reference
- * count. This is for file systems where the inode number is sufficient for
- * unique identification of an inode.
- *
- * If the inode is not in cache, get_new_inode_fast() is called to allocate a
- * new inode and this is returned locked, hashed, and with the I_NEW flag set.
- * The file system gets to fill it in before unlocking it via
- * unlock_new_inode().
- */
-struct inode *iget_locked(struct super_block *sb, unsigned long ino)
-{
-       struct hlist_head *head = inode_hashtable + hash(sb, ino);
-       struct inode *inode;
+       spin_lock(&inode_hash_lock);
+       inode = find_inode_fast(sb, head, ino);
+       spin_unlock(&inode_hash_lock);
 
-       inode = ifind_fast(sb, head, ino);
        if (inode)
-               return inode;
-       /*
-        * get_new_inode_fast() will do the right thing, re-trying the search
-        * in case it had to block at any point.
-        */
-       return get_new_inode_fast(sb, head, ino);
+               wait_on_inode(inode);
+       return inode;
 }
-EXPORT_SYMBOL(iget_locked);
+EXPORT_SYMBOL(ilookup);
 
 int insert_inode_locked(struct inode *inode)
 {
@@ -1270,27 +1240,33 @@ int insert_inode_locked(struct inode *inode)
        ino_t ino = inode->i_ino;
        struct hlist_head *head = inode_hashtable + hash(sb, ino);
 
-       inode->i_state |= I_NEW;
        while (1) {
                struct hlist_node *node;
                struct inode *old = NULL;
-               spin_lock(&inode_lock);
+               spin_lock(&inode_hash_lock);
                hlist_for_each_entry(old, node, head, i_hash) {
                        if (old->i_ino != ino)
                                continue;
                        if (old->i_sb != sb)
                                continue;
-                       if (old->i_state & (I_FREEING|I_WILL_FREE))
+                       spin_lock(&old->i_lock);
+                       if (old->i_state & (I_FREEING|I_WILL_FREE)) {
+                               spin_unlock(&old->i_lock);
                                continue;
+                       }
                        break;
                }
                if (likely(!node)) {
+                       spin_lock(&inode->i_lock);
+                       inode->i_state |= I_NEW;
                        hlist_add_head(&inode->i_hash, head);
-                       spin_unlock(&inode_lock);
+                       spin_unlock(&inode->i_lock);
+                       spin_unlock(&inode_hash_lock);
                        return 0;
                }
                __iget(old);
-               spin_unlock(&inode_lock);
+               spin_unlock(&old->i_lock);
+               spin_unlock(&inode_hash_lock);
                wait_on_inode(old);
                if (unlikely(!inode_unhashed(old))) {
                        iput(old);
@@ -1307,29 +1283,34 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval,
        struct super_block *sb = inode->i_sb;
        struct hlist_head *head = inode_hashtable + hash(sb, hashval);
 
-       inode->i_state |= I_NEW;
-
        while (1) {
                struct hlist_node *node;
                struct inode *old = NULL;
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_hash_lock);
                hlist_for_each_entry(old, node, head, i_hash) {
                        if (old->i_sb != sb)
                                continue;
                        if (!test(old, data))
                                continue;
-                       if (old->i_state & (I_FREEING|I_WILL_FREE))
+                       spin_lock(&old->i_lock);
+                       if (old->i_state & (I_FREEING|I_WILL_FREE)) {
+                               spin_unlock(&old->i_lock);
                                continue;
+                       }
                        break;
                }
                if (likely(!node)) {
+                       spin_lock(&inode->i_lock);
+                       inode->i_state |= I_NEW;
                        hlist_add_head(&inode->i_hash, head);
-                       spin_unlock(&inode_lock);
+                       spin_unlock(&inode->i_lock);
+                       spin_unlock(&inode_hash_lock);
                        return 0;
                }
                __iget(old);
-               spin_unlock(&inode_lock);
+               spin_unlock(&old->i_lock);
+               spin_unlock(&inode_hash_lock);
                wait_on_inode(old);
                if (unlikely(!inode_unhashed(old))) {
                        iput(old);
@@ -1374,47 +1355,35 @@ static void iput_final(struct inode *inode)
        const struct super_operations *op = inode->i_sb->s_op;
        int drop;
 
+       WARN_ON(inode->i_state & I_NEW);
+
        if (op && op->drop_inode)
                drop = op->drop_inode(inode);
        else
                drop = generic_drop_inode(inode);
 
+       if (!drop && (sb->s_flags & MS_ACTIVE)) {
+               inode->i_state |= I_REFERENCED;
+               if (!(inode->i_state & (I_DIRTY|I_SYNC)))
+                       inode_lru_list_add(inode);
+               spin_unlock(&inode->i_lock);
+               return;
+       }
+
        if (!drop) {
-               if (sb->s_flags & MS_ACTIVE) {
-                       inode->i_state |= I_REFERENCED;
-                       if (!(inode->i_state & (I_DIRTY|I_SYNC))) {
-                               inode_lru_list_add(inode);
-                       }
-                       spin_unlock(&inode_lock);
-                       return;
-               }
-               WARN_ON(inode->i_state & I_NEW);
                inode->i_state |= I_WILL_FREE;
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
                write_inode_now(inode, 1);
-               spin_lock(&inode_lock);
+               spin_lock(&inode->i_lock);
                WARN_ON(inode->i_state & I_NEW);
                inode->i_state &= ~I_WILL_FREE;
-               __remove_inode_hash(inode);
        }
 
-       WARN_ON(inode->i_state & I_NEW);
        inode->i_state |= I_FREEING;
-
-       /*
-        * Move the inode off the IO lists and LRU once I_FREEING is
-        * set so that it won't get moved back on there if it is dirty.
-        */
        inode_lru_list_del(inode);
-       list_del_init(&inode->i_wb_list);
+       spin_unlock(&inode->i_lock);
 
-       __inode_sb_list_del(inode);
-       spin_unlock(&inode_lock);
        evict(inode);
-       remove_inode_hash(inode);
-       wake_up_inode(inode);
-       BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
-       destroy_inode(inode);
 }
 
 /**
@@ -1431,7 +1400,7 @@ void iput(struct inode *inode)
        if (inode) {
                BUG_ON(inode->i_state & I_CLEAR);
 
-               if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
+               if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock))
                        iput_final(inode);
        }
 }
@@ -1610,9 +1579,8 @@ EXPORT_SYMBOL(inode_wait);
  * to recheck inode state.
  *
  * It doesn't matter if I_NEW is not set initially, a call to
- * wake_up_inode() after removing from the hash list will DTRT.
- *
- * This is called with inode_lock held.
+ * wake_up_bit(&inode->i_state, __I_NEW) after removing from the hash list
+ * will DTRT.
  */
 static void __wait_on_freeing_inode(struct inode *inode)
 {
@@ -1620,10 +1588,11 @@ static void __wait_on_freeing_inode(struct inode *inode)
        DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW);
        wq = bit_waitqueue(&inode->i_state, __I_NEW);
        prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode->i_lock);
+       spin_unlock(&inode_hash_lock);
        schedule();
        finish_wait(wq, &wait.wait);
-       spin_lock(&inode_lock);
+       spin_lock(&inode_hash_lock);
 }
 
 static __initdata unsigned long ihash_entries;
@@ -1715,7 +1684,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
 EXPORT_SYMBOL(init_special_inode);
 
 /**
- * Init uid,gid,mode for new inode according to posix standards
+ * inode_init_owner - Init uid,gid,mode for new inode according to posix standards
  * @inode: New inode
  * @dir: Directory inode
  * @mode: mode of the new inode
@@ -1733,3 +1702,22 @@ void inode_init_owner(struct inode *inode, const struct inode *dir,
        inode->i_mode = mode;
 }
 EXPORT_SYMBOL(inode_init_owner);
+
+/**
+ * inode_owner_or_capable - check current task permissions to inode
+ * @inode: inode being checked
+ *
+ * Return true if current either has CAP_FOWNER to the inode, or
+ * owns the file.
+ */
+bool inode_owner_or_capable(const struct inode *inode)
+{
+       struct user_namespace *ns = inode_userns(inode);
+
+       if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
+               return true;
+       if (ns_capable(ns, CAP_FOWNER))
+               return true;
+       return false;
+}
+EXPORT_SYMBOL(inode_owner_or_capable);
index 17191546d52768691e405da4cc53735d9589e275..b29c46e4e32f6d72cc80c60073e85dcac9397750 100644 (file)
@@ -64,6 +64,7 @@ extern int copy_mount_string(const void __user *, char **);
 
 extern unsigned int mnt_get_count(struct vfsmount *mnt);
 extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
+extern struct vfsmount *lookup_mnt(struct path *);
 extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
                                struct vfsmount *);
 extern void release_mounts(struct list_head *);
@@ -124,6 +125,13 @@ extern long do_handle_open(int mountdirfd,
 /*
  * inode.c
  */
+extern spinlock_t inode_sb_list_lock;
+
+/*
+ * fs-writeback.c
+ */
+extern void inode_wb_list_del(struct inode *inode);
+
 extern int get_nr_dirty_inodes(void);
 extern void evict_inodes(struct super_block *);
 extern int invalidate_inodes(struct super_block *, bool);
index 1eebeb72b20276191fcad6199d8bf0b79a4d9921..1d9b9fcb2db48ec682b4e696bbab9dbb79fd26b9 100644 (file)
@@ -548,6 +548,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 {
        int error = 0;
        int __user *argp = (int __user *)arg;
+       struct inode *inode = filp->f_path.dentry->d_inode;
 
        switch (cmd) {
        case FIOCLEX:
@@ -567,13 +568,11 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                break;
 
        case FIOQSIZE:
-               if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
-                   S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
-                   S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
-                       loff_t res =
-                               inode_get_bytes(filp->f_path.dentry->d_inode);
-                       error = copy_to_user((loff_t __user *)arg, &res,
-                                            sizeof(res)) ? -EFAULT : 0;
+               if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
+                   S_ISLNK(inode->i_mode)) {
+                       loff_t res = inode_get_bytes(inode);
+                       error = copy_to_user(argp, &res, sizeof(res)) ?
+                                       -EFAULT : 0;
                } else
                        error = -ENOTTY;
                break;
@@ -590,14 +589,10 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                return ioctl_fiemap(filp, arg);
 
        case FIGETBSZ:
-       {
-               struct inode *inode = filp->f_path.dentry->d_inode;
-               int __user *p = (int __user *)arg;
-               return put_user(inode->i_sb->s_blocksize, p);
-       }
+               return put_user(inode->i_sb->s_blocksize, argp);
 
        default:
-               if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
+               if (S_ISREG(inode->i_mode))
                        error = file_ioctl(filp, cmd, arg);
                else
                        error = vfs_ioctl(filp, cmd, arg);
index a0f3833c0dbf578ae0f6477007ae443eae9b728b..3db5ba4568fc8efd30025a9e9906eb01a47f9c45 100644 (file)
@@ -1158,7 +1158,6 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
 
 static const struct address_space_operations isofs_aops = {
        .readpage = isofs_readpage,
-       .sync_page = block_sync_page,
        .bmap = _isofs_bmap
 };
 
index 34a4861c14b85d493a8b653c4ce700a4c580842e..da871ee084d365780f8a3f78078550e48d3f12ea 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/bio.h>
+#include <linux/blkdev.h>
 
 /*
  * Default IO end handler for temporary BJ_IO buffer_heads.
@@ -294,7 +295,7 @@ void journal_commit_transaction(journal_t *journal)
        int first_tag = 0;
        int tag_flag;
        int i;
-       int write_op = WRITE_SYNC;
+       struct blk_plug plug;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -327,13 +328,6 @@ void journal_commit_transaction(journal_t *journal)
        spin_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
-       /*
-        * Use plugged writes here, since we want to submit several before
-        * we unplug the device. We don't do explicit unplugging in here,
-        * instead we rely on sync_buffer() doing the unplug for us.
-        */
-       if (commit_transaction->t_synchronous_commit)
-               write_op = WRITE_SYNC_PLUG;
        spin_lock(&commit_transaction->t_handle_lock);
        while (commit_transaction->t_updates) {
                DEFINE_WAIT(wait);
@@ -418,8 +412,10 @@ void journal_commit_transaction(journal_t *journal)
         * Now start flushing things to disk, in the order they appear
         * on the transaction lists.  Data blocks go first.
         */
+       blk_start_plug(&plug);
        err = journal_submit_data_buffers(journal, commit_transaction,
-                                         write_op);
+                                         WRITE_SYNC);
+       blk_finish_plug(&plug);
 
        /*
         * Wait for all previously submitted IO to complete.
@@ -480,7 +476,9 @@ void journal_commit_transaction(journal_t *journal)
                err = 0;
        }
 
-       journal_write_revoke_records(journal, commit_transaction, write_op);
+       blk_start_plug(&plug);
+
+       journal_write_revoke_records(journal, commit_transaction, WRITE_SYNC);
 
        /*
         * If we found any dirty or locked buffers, then we should have
@@ -650,7 +648,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(write_op, bh);
+                               submit_bh(WRITE_SYNC, bh);
                        }
                        cond_resched();
 
@@ -661,6 +659,8 @@ start_journal_io:
                }
        }
 
+       blk_finish_plug(&plug);
+
        /* Lo and behold: we have just managed to send a transaction to
            the log.  Before we can commit it, wait for the IO so far to
            complete.  Control buffers being written are on the
index f3ad1598b20128bc3acaaa1bd81e7ece1e27e270..fa36d7662b217455a99a83f93e35899dbf950e4a 100644 (file)
@@ -137,9 +137,9 @@ static int journal_submit_commit_record(journal_t *journal,
        if (journal->j_flags & JBD2_BARRIER &&
            !JBD2_HAS_INCOMPAT_FEATURE(journal,
                                       JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT))
-               ret = submit_bh(WRITE_SYNC_PLUG | WRITE_FLUSH_FUA, bh);
+               ret = submit_bh(WRITE_SYNC | WRITE_FLUSH_FUA, bh);
        else
-               ret = submit_bh(WRITE_SYNC_PLUG, bh);
+               ret = submit_bh(WRITE_SYNC, bh);
 
        *cbh = bh;
        return ret;
@@ -329,7 +329,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        int tag_bytes = journal_tag_bytes(journal);
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
-       int write_op = WRITE_SYNC;
+       struct blk_plug plug;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -363,13 +363,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        write_lock(&journal->j_state_lock);
        commit_transaction->t_state = T_LOCKED;
 
-       /*
-        * Use plugged writes here, since we want to submit several before
-        * we unplug the device. We don't do explicit unplugging in here,
-        * instead we rely on sync_buffer() doing the unplug for us.
-        */
-       if (commit_transaction->t_synchronous_commit)
-               write_op = WRITE_SYNC_PLUG;
        trace_jbd2_commit_locking(journal, commit_transaction);
        stats.run.rs_wait = commit_transaction->t_max_wait;
        stats.run.rs_locked = jiffies;
@@ -469,8 +462,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        if (err)
                jbd2_journal_abort(journal, err);
 
+       blk_start_plug(&plug);
        jbd2_journal_write_revoke_records(journal, commit_transaction,
-                                         write_op);
+                                         WRITE_SYNC);
+       blk_finish_plug(&plug);
 
        jbd_debug(3, "JBD: commit phase 2\n");
 
@@ -497,6 +492,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        err = 0;
        descriptor = NULL;
        bufs = 0;
+       blk_start_plug(&plug);
        while (commit_transaction->t_buffers) {
 
                /* Find the next buffer to be journaled... */
@@ -658,7 +654,7 @@ start_journal_io:
                                clear_buffer_dirty(bh);
                                set_buffer_uptodate(bh);
                                bh->b_end_io = journal_end_buffer_io_sync;
-                               submit_bh(write_op, bh);
+                               submit_bh(WRITE_SYNC, bh);
                        }
                        cond_resched();
                        stats.run.rs_blocks_logged += bufs;
@@ -699,6 +695,8 @@ start_journal_io:
                        __jbd2_journal_abort_hard(journal);
        }
 
+       blk_finish_plug(&plug);
+
        /* Lo and behold: we have just managed to send a transaction to
            the log.  Before we can commit it, wait for the IO so far to
            complete.  Control buffers being written are on the
index 95b79672150ab7b6159b00e3ca4083b41eaca9c7..828a0e1ea4387c19c91218b1e8d219a3d3b643b1 100644 (file)
@@ -402,7 +402,7 @@ static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
 
        if (name[0] != '\0')
                return -EINVAL;
-       if (!is_owner_or_cap(dentry->d_inode))
+       if (!inode_owner_or_capable(dentry->d_inode))
                return -EPERM;
 
        if (value) {
index fd05a0b9431df3e2bb37ed3b4bed29a131c37ffd..5a001020c542a652726e18521429d2d44b6c31d5 100644 (file)
@@ -40,12 +40,13 @@ static z_stream inf_strm, def_strm;
 
 static int __init alloc_workspaces(void)
 {
-       def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
+       def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS,
+                                                       MAX_MEM_LEVEL));
        if (!def_strm.workspace) {
-               printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
+               printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
                return -ENOMEM;
        }
-       D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
+       D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)));
        inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
        if (!inf_strm.workspace) {
                printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
index 3adb6395e42de858ada7adec76b964dfef250e41..a58fa72d7e59e511cc849eb01cee92fa5afb1320 100644 (file)
@@ -13,4 +13,4 @@ jfs-y    := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
 
 jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
 
-EXTRA_CFLAGS += -D_JFS_4K
+ccflags-y := -D_JFS_4K
index 9978803ceedc519ea90a84bbe04f7a77b8bc5b4e..eddbb373209e9c2dc013657bc041d44badb0aa29 100644 (file)
@@ -352,7 +352,6 @@ const struct address_space_operations jfs_aops = {
        .readpages      = jfs_readpages,
        .writepage      = jfs_writepage,
        .writepages     = jfs_writepages,
-       .sync_page      = block_sync_page,
        .write_begin    = jfs_write_begin,
        .write_end      = nobh_write_end,
        .bmap           = jfs_bmap,
index afe222bf300fc90f0931492b45969c1d09fcc9bc..6f98a1866776842c6ff4ab3d217129eec975b192 100644 (file)
@@ -72,7 +72,7 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (err)
                        return err;
 
-               if (!is_owner_or_cap(inode)) {
+               if (!inode_owner_or_capable(inode)) {
                        err = -EACCES;
                        goto setflags_out;
                }
index 48b44bd8267b960e7e5bd330521f9da93d6d1a6f..6740d34cd82b802e948b8760fcf13954a8a12ad2 100644 (file)
@@ -583,7 +583,6 @@ static void metapage_invalidatepage(struct page *page, unsigned long offset)
 const struct address_space_operations jfs_metapage_aops = {
        .readpage       = metapage_readpage,
        .writepage      = metapage_writepage,
-       .sync_page      = block_sync_page,
        .releasepage    = metapage_releasepage,
        .invalidatepage = metapage_invalidatepage,
        .set_page_dirty = __set_page_dirty_nobuffers,
index 3fa4c32272dfa16453f4fbe6995354d219cf4d91..24838f1eeee5c0f5093d96fef01c80d1835991ea 100644 (file)
@@ -678,7 +678,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
        struct posix_acl *acl;
        int rc;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        /*
index 822c3d1843af732934c9a393ffe8a51a0f7ff73f..0a4f50dfadfbf672ff3bc0bcba0581a3e94b83bb 100644 (file)
@@ -414,17 +414,7 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
        fl->fl_ops = NULL;
        fl->fl_lmops = NULL;
 
-       switch (l->l_type) {
-       case F_RDLCK:
-       case F_WRLCK:
-       case F_UNLCK:
-               fl->fl_type = l->l_type;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return (0);
+       return assign_type(fl, l->l_type);
 }
 #endif
 
index 44bbfd249abc129ac7544be77b9cbd7a62b04e3e..961f02b86d97e22f595e235e96c8876bff08214e 100644 (file)
@@ -81,7 +81,7 @@ error:
 
 int __init logfs_compr_init(void)
 {
-       size_t size = max(zlib_deflate_workspacesize(),
+       size_t size = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
                        zlib_inflate_workspacesize());
        stream.workspace = vmalloc(size);
        if (!stream.workspace)
index 723bc5bca09ae3837448c3a286e50ff38e427576..1adc8d455f0ea2d66237436184766c5ed120688f 100644 (file)
@@ -39,7 +39,6 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw)
        bio.bi_end_io = request_complete;
 
        submit_bio(rw, &bio);
-       generic_unplug_device(bdev_get_queue(bdev));
        wait_for_completion(&complete);
        return test_bit(BIO_UPTODATE, &bio.bi_flags) ? 0 : -EIO;
 }
@@ -168,7 +167,6 @@ static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len)
        }
        len = PAGE_ALIGN(len);
        __bdev_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT);
-       generic_unplug_device(bdev_get_queue(logfs_super(sb)->s_bdev));
 }
 
 
index e86376b87af11d26034188df8d3c2da2bc469587..c2ad7028def4ebf78295a418ab8d49b1bb7ff765 100644 (file)
@@ -196,7 +196,7 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                err = get_user(flags, (int __user *)arg);
index 03b8c240aeda37ea287b36f8ebaeeae1ee23a479..edfea7a3a747fa2c984a5817d82909fdccc7d0ea 100644 (file)
@@ -293,7 +293,7 @@ static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        return ret;
 }
 
-/* called with inode_lock held */
+/* called with inode->i_lock held */
 static int logfs_drop_inode(struct inode *inode)
 {
        struct logfs_super *super = logfs_super(inode->i_sb);
index 0fd7ca99426469f924fa54473bd8ef606d4c73ab..6624684dd5decbd55845113000ad1b783f029ebb 100644 (file)
@@ -15,3 +15,11 @@ config MINIX_FS
          module will be called minix.  Note that the file system of your root
          partition (the one containing the directory /) cannot be compiled as
          a module.
+
+config MINIX_FS_NATIVE_ENDIAN
+       def_bool MINIX_FS
+       depends on H8300 || M32R || MICROBLAZE || MIPS || S390 || SUPERH || SPARC || XTENSA || (M68K && !MMU)
+
+config MINIX_FS_BIG_ENDIAN_16BIT_INDEXED
+       def_bool MINIX_FS
+       depends on M68K && MMU
index ae0b83f476a63be6a51bdef77e10504b29bd9f99..adcdc0a4e182673ef953e5bafd8e040987df6948 100644 (file)
@@ -399,7 +399,6 @@ static sector_t minix_bmap(struct address_space *mapping, sector_t block)
 static const struct address_space_operations minix_aops = {
        .readpage = minix_readpage,
        .writepage = minix_writepage,
-       .sync_page = block_sync_page,
        .write_begin = minix_write_begin,
        .write_end = generic_write_end,
        .bmap = minix_bmap
index 407b1c84911e9402df59b886cf25b036f346f441..341e2122879a7604611426d4f702f211ee3ed59a 100644 (file)
@@ -88,4 +88,78 @@ static inline struct minix_inode_info *minix_i(struct inode *inode)
        return list_entry(inode, struct minix_inode_info, vfs_inode);
 }
 
+#if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \
+       defined(CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED)
+
+#error Minix file system byte order broken
+
+#elif defined(CONFIG_MINIX_FS_NATIVE_ENDIAN)
+
+/*
+ * big-endian 32 or 64 bit indexed bitmaps on big-endian system or
+ * little-endian bitmaps on little-endian system
+ */
+
+#define minix_test_and_set_bit(nr, addr)       \
+       __test_and_set_bit((nr), (unsigned long *)(addr))
+#define minix_set_bit(nr, addr)                \
+       __set_bit((nr), (unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr, addr) \
+       __test_and_clear_bit((nr), (unsigned long *)(addr))
+#define minix_test_bit(nr, addr)               \
+       test_bit((nr), (unsigned long *)(addr))
+#define minix_find_first_zero_bit(addr, size) \
+       find_first_zero_bit((unsigned long *)(addr), (size))
+
+#elif defined(CONFIG_MINIX_FS_BIG_ENDIAN_16BIT_INDEXED)
+
+/*
+ * big-endian 16bit indexed bitmaps
+ */
+
+static inline int minix_find_first_zero_bit(const void *vaddr, unsigned size)
+{
+       const unsigned short *p = vaddr, *addr = vaddr;
+       unsigned short num;
+
+       if (!size)
+               return 0;
+
+       size = (size >> 4) + ((size & 15) > 0);
+       while (*p++ == 0xffff) {
+               if (--size == 0)
+                       return (p - addr) << 4;
+       }
+
+       num = *--p;
+       return ((p - addr) << 4) + ffz(num);
+}
+
+#define minix_test_and_set_bit(nr, addr)       \
+       __test_and_set_bit((nr) ^ 16, (unsigned long *)(addr))
+#define minix_set_bit(nr, addr)        \
+       __set_bit((nr) ^ 16, (unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr, addr)     \
+       __test_and_clear_bit((nr) ^ 16, (unsigned long *)(addr))
+
+static inline int minix_test_bit(int nr, const void *vaddr)
+{
+       const unsigned short *p = vaddr;
+       return (p[nr >> 4] & (1U << (nr & 15))) != 0;
+}
+
+#else
+
+/*
+ * little-endian bitmaps
+ */
+
+#define minix_test_and_set_bit __test_and_set_bit_le
+#define minix_set_bit          __set_bit_le
+#define minix_test_and_clear_bit       __test_and_clear_bit_le
+#define minix_test_bit test_bit_le
+#define minix_find_first_zero_bit      find_first_zero_bit_le
+
+#endif
+
 #endif /* FS_MINIX_H */
index d78455a81ec979a734f28d7874b6654e5a087e7e..0afc809e46e09b53cb767e56795fba3139c4b181 100644 (file)
@@ -364,6 +364,9 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
        sector_t last_block_in_bio = 0;
        struct buffer_head map_bh;
        unsigned long first_logical_block = 0;
+       struct blk_plug plug;
+
+       blk_start_plug(&plug);
 
        map_bh.b_state = 0;
        map_bh.b_size = 0;
@@ -385,6 +388,7 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages,
        BUG_ON(!list_empty(pages));
        if (bio)
                mpage_bio_submit(READ, bio);
+       blk_finish_plug(&plug);
        return 0;
 }
 EXPORT_SYMBOL(mpage_readpages);
@@ -666,8 +670,11 @@ int
 mpage_writepages(struct address_space *mapping,
                struct writeback_control *wbc, get_block_t get_block)
 {
+       struct blk_plug plug;
        int ret;
 
+       blk_start_plug(&plug);
+
        if (!get_block)
                ret = generic_writepages(mapping, wbc);
        else {
@@ -682,6 +689,7 @@ mpage_writepages(struct address_space *mapping,
                if (mpd.bio)
                        mpage_bio_submit(WRITE, mpd.bio);
        }
+       blk_finish_plug(&plug);
        return ret;
 }
 EXPORT_SYMBOL(mpage_writepages);
index 5a9a6c3094daf1fe7cd6fbc4e95110dd2bd028e0..3cb616d38d9cf616f3b381c34b988f5d37f6fac2 100644 (file)
@@ -183,6 +183,9 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag
 
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
 
+       if (current_user_ns() != inode_userns(inode))
+               goto other_perms;
+
        if (current_fsuid() == inode->i_uid)
                mode >>= 6;
        else {
@@ -196,6 +199,7 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag
                        mode >>= 3;
        }
 
+other_perms:
        /*
         * If the DACs are ok we don't need any capability check.
         */
@@ -237,7 +241,7 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags,
         * Executable DACs are overridable if at least one exec bit is set.
         */
        if (!(mask & MAY_EXEC) || execute_ok(inode))
-               if (capable(CAP_DAC_OVERRIDE))
+               if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
                        return 0;
 
        /*
@@ -245,7 +249,7 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags,
         */
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
        if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
-               if (capable(CAP_DAC_READ_SEARCH))
+               if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
                        return 0;
 
        return -EACCES;
@@ -654,6 +658,7 @@ static inline int handle_reval_path(struct nameidata *nd)
 static inline int exec_permission(struct inode *inode, unsigned int flags)
 {
        int ret;
+       struct user_namespace *ns = inode_userns(inode);
 
        if (inode->i_op->permission) {
                ret = inode->i_op->permission(inode, MAY_EXEC, flags);
@@ -666,7 +671,8 @@ static inline int exec_permission(struct inode *inode, unsigned int flags)
        if (ret == -ECHILD)
                return ret;
 
-       if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
+       if (ns_capable(ns, CAP_DAC_OVERRIDE) ||
+                       ns_capable(ns, CAP_DAC_READ_SEARCH))
                goto ok;
 
        return ret;
@@ -986,6 +992,12 @@ int follow_down_one(struct path *path)
        return 0;
 }
 
+static inline bool managed_dentry_might_block(struct dentry *dentry)
+{
+       return (dentry->d_flags & DCACHE_MANAGE_TRANSIT &&
+               dentry->d_op->d_manage(dentry, true) < 0);
+}
+
 /*
  * Skip to top of mountpoint pile in rcuwalk mode.  We abort the rcu-walk if we
  * meet a managed dentry and we're not walking to "..".  True is returned to
@@ -994,19 +1006,26 @@ int follow_down_one(struct path *path)
 static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                               struct inode **inode, bool reverse_transit)
 {
-       while (d_mountpoint(path->dentry)) {
+       for (;;) {
                struct vfsmount *mounted;
-               if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
-                   !reverse_transit &&
-                   path->dentry->d_op->d_manage(path->dentry, true) < 0)
+               /*
+                * Don't forget we might have a non-mountpoint managed dentry
+                * that wants to block transit.
+                */
+               *inode = path->dentry->d_inode;
+               if (!reverse_transit &&
+                    unlikely(managed_dentry_might_block(path->dentry)))
                        return false;
+
+               if (!d_mountpoint(path->dentry))
+                       break;
+
                mounted = __lookup_mnt(path->mnt, path->dentry, 1);
                if (!mounted)
                        break;
                path->mnt = mounted;
                path->dentry = mounted->mnt_root;
                nd->seq = read_seqcount_begin(&path->dentry->d_seq);
-               *inode = path->dentry->d_inode;
        }
 
        if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
@@ -1644,13 +1663,16 @@ static int path_lookupat(int dfd, const char *name,
                        err = -ECHILD;
        }
 
-       if (!err)
+       if (!err) {
                err = handle_reval_path(nd);
+               if (err)
+                       path_put(&nd->path);
+       }
 
        if (!err && nd->flags & LOOKUP_DIRECTORY) {
                if (!nd->inode->i_op->lookup) {
                        path_put(&nd->path);
-                       return -ENOTDIR;
+                       err = -ENOTDIR;
                }
        }
 
@@ -1842,11 +1864,15 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
 
        if (!(dir->i_mode & S_ISVTX))
                return 0;
+       if (current_user_ns() != inode_userns(inode))
+               goto other_userns;
        if (inode->i_uid == fsuid)
                return 0;
        if (dir->i_uid == fsuid)
                return 0;
-       return !capable(CAP_FOWNER);
+
+other_userns:
+       return !ns_capable(inode_userns(inode), CAP_FOWNER);
 }
 
 /*
@@ -2026,7 +2052,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
        }
 
        /* O_NOATIME can only be set by the owner or superuser */
-       if (flag & O_NOATIME && !is_owner_or_cap(inode))
+       if (flag & O_NOATIME && !inode_owner_or_capable(inode))
                return -EPERM;
 
        /*
@@ -2440,7 +2466,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
        if (error)
                return error;
 
-       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
+       if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
+           !ns_capable(inode_userns(dir), CAP_MKNOD))
                return -EPERM;
 
        if (!dir->i_op->mknod)
index 9263995bf6a1f53577139619ed8072c89db193f0..7dba2ed03429460f27aba058955208ed5dd929ec 100644 (file)
@@ -2701,7 +2701,7 @@ void __init mnt_init(void)
        if (!mount_hashtable)
                panic("Failed to allocate mount hash table\n");
 
-       printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);
+       printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE);
 
        for (u = 0; u < HASH_SIZE; u++)
                INIT_LIST_HEAD(&mount_hashtable[u]);
index 68ea095100a817262d1858bba4754c22c5206016..c66af563f2ceef35fbf68b01527866f8128711d0 100644 (file)
@@ -11,6 +11,6 @@ ncpfs-$(CONFIG_NCPFS_EXTRAS)   += symlink.o
 ncpfs-$(CONFIG_NCPFS_NFS_NS)   += symlink.o
 
 # If you want debugging output, please uncomment the following line
-# EXTRA_CFLAGS += -DDEBUG_NCP=1
+# ccflags-y := -DDEBUG_NCP=1
 
 CFLAGS_ncplib_kernel.o := -finline-functions
index abdf38d5971d663902c6b137d53089efdf54c699..7237672216c804769b945c9b09b1e57e1b3de202 100644 (file)
@@ -44,6 +44,7 @@
 /* #define NFS_DEBUG_VERBOSE 1 */
 
 static int nfs_opendir(struct inode *, struct file *);
+static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
 static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *);
 static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *);
@@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = nfs_readdir,
        .open           = nfs_opendir,
-       .release        = nfs_release,
+       .release        = nfs_closedir,
        .fsync          = nfs_fsync_dir,
 };
 
@@ -133,13 +134,35 @@ const struct inode_operations nfs4_dir_inode_operations = {
 
 #endif /* CONFIG_NFS_V4 */
 
+static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred)
+{
+       struct nfs_open_dir_context *ctx;
+       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       if (ctx != NULL) {
+               ctx->duped = 0;
+               ctx->dir_cookie = 0;
+               ctx->dup_cookie = 0;
+               ctx->cred = get_rpccred(cred);
+       } else
+               ctx = ERR_PTR(-ENOMEM);
+       return ctx;
+}
+
+static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
+{
+       put_rpccred(ctx->cred);
+       kfree(ctx);
+}
+
 /*
  * Open file
  */
 static int
 nfs_opendir(struct inode *inode, struct file *filp)
 {
-       int res;
+       int res = 0;
+       struct nfs_open_dir_context *ctx;
+       struct rpc_cred *cred;
 
        dfprintk(FILE, "NFS: open dir(%s/%s)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
@@ -147,8 +170,15 @@ nfs_opendir(struct inode *inode, struct file *filp)
 
        nfs_inc_stats(inode, NFSIOS_VFSOPEN);
 
-       /* Call generic open code in order to cache credentials */
-       res = nfs_open(inode, filp);
+       cred = rpc_lookup_cred();
+       if (IS_ERR(cred))
+               return PTR_ERR(cred);
+       ctx = alloc_nfs_open_dir_context(cred);
+       if (IS_ERR(ctx)) {
+               res = PTR_ERR(ctx);
+               goto out;
+       }
+       filp->private_data = ctx;
        if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) {
                /* This is a mountpoint, so d_revalidate will never
                 * have been called, so we need to refresh the
@@ -156,9 +186,18 @@ nfs_opendir(struct inode *inode, struct file *filp)
                 */
                __nfs_revalidate_inode(NFS_SERVER(inode), inode);
        }
+out:
+       put_rpccred(cred);
        return res;
 }
 
+static int
+nfs_closedir(struct inode *inode, struct file *filp)
+{
+       put_nfs_open_dir_context(filp->private_data);
+       return 0;
+}
+
 struct nfs_cache_array_entry {
        u64 cookie;
        u64 ino;
@@ -284,19 +323,20 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
 {
        loff_t diff = desc->file->f_pos - desc->current_index;
        unsigned int index;
+       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        if (diff < 0)
                goto out_eof;
        if (diff >= array->size) {
                if (array->eof_index >= 0)
                        goto out_eof;
-               desc->current_index += array->size;
                return -EAGAIN;
        }
 
        index = (unsigned int)diff;
        *desc->dir_cookie = array->array[index].cookie;
        desc->cache_entry_index = index;
+       ctx->duped = 0;
        return 0;
 out_eof:
        desc->eof = 1;
@@ -307,10 +347,18 @@ static
 int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
 {
        int i;
+       loff_t new_pos;
        int status = -EAGAIN;
+       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        for (i = 0; i < array->size; i++) {
                if (array->array[i].cookie == *desc->dir_cookie) {
+                       new_pos = desc->current_index + i;
+                       if (new_pos < desc->file->f_pos) {
+                               ctx->dup_cookie = *desc->dir_cookie;
+                               ctx->duped = 1;
+                       }
+                       desc->file->f_pos = new_pos;
                        desc->cache_entry_index = i;
                        return 0;
                }
@@ -342,6 +390,7 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
 
        if (status == -EAGAIN) {
                desc->last_cookie = array->last_cookie;
+               desc->current_index += array->size;
                desc->page_index++;
        }
        nfs_readdir_release_array(desc->page);
@@ -354,7 +403,8 @@ static
 int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
                        struct nfs_entry *entry, struct file *file, struct inode *inode)
 {
-       struct rpc_cred *cred = nfs_file_cred(file);
+       struct nfs_open_dir_context *ctx = file->private_data;
+       struct rpc_cred *cred = ctx->cred;
        unsigned long   timestamp, gencount;
        int             error;
 
@@ -693,6 +743,20 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        int i = 0;
        int res = 0;
        struct nfs_cache_array *array = NULL;
+       struct nfs_open_dir_context *ctx = file->private_data;
+
+       if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) {
+               if (printk_ratelimit()) {
+                       pr_notice("NFS: directory %s/%s contains a readdir loop.  "
+                               "Please contact your server vendor.  "
+                               "Offending cookie: %llu\n",
+                               file->f_dentry->d_parent->d_name.name,
+                               file->f_dentry->d_name.name,
+                               *desc->dir_cookie);
+               }
+               res = -ELOOP;
+               goto out;
+       }
 
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
@@ -785,6 +849,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode    *inode = dentry->d_inode;
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
+       struct nfs_open_dir_context *dir_ctx = filp->private_data;
        int res;
 
        dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
@@ -801,7 +866,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        memset(desc, 0, sizeof(*desc));
 
        desc->file = filp;
-       desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
+       desc->dir_cookie = &dir_ctx->dir_cookie;
        desc->decode = NFS_PROTO(inode)->decode_dirent;
        desc->plus = NFS_USE_READDIRPLUS(inode);
 
@@ -853,6 +918,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
 {
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
+       struct nfs_open_dir_context *dir_ctx = filp->private_data;
 
        dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n",
                        dentry->d_parent->d_name.name,
@@ -872,7 +938,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
        }
        if (offset != filp->f_pos) {
                filp->f_pos = offset;
-               nfs_file_open_context(filp)->dir_cookie = 0;
+               dir_ctx->dir_cookie = 0;
+               dir_ctx->duped = 0;
        }
 out:
        mutex_unlock(&inode->i_mutex);
@@ -1068,7 +1135,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        if (fhandle == NULL || fattr == NULL)
                goto out_error;
 
-       error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+       error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
        if (error)
                goto out_bad;
        if (nfs_compare_fh(NFS_FH(inode), fhandle))
@@ -1224,7 +1291,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
        parent = dentry->d_parent;
        /* Protect against concurrent sillydeletes */
        nfs_block_sillyrename(parent);
-       error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+       error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
        if (error == -ENOENT)
                goto no_entry;
        if (error < 0) {
@@ -1562,7 +1629,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
        if (dentry->d_inode)
                goto out;
        if (fhandle->size == 0) {
-               error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+               error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr);
                if (error)
                        goto out_error;
        }
index d85a534b15cd1805175345a2e94538f2fcefe10e..3ac5bd695e5e9554ceb2c5ceda9411dbe13d7c7b 100644 (file)
@@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync)
                ret = xchg(&ctx->error, 0);
        if (!ret && status < 0)
                ret = status;
+       if (!ret && !datasync)
+               /* application has asked for meta-data sync */
+               ret = pnfs_layoutcommit_inode(inode, true);
        return ret;
 }
 
index 1084792bc0fec1fd2ecefd4a3cc04e7450c1bf7c..dcb61548887fdba13fc484c844aeb3a6b14a0fe9 100644 (file)
@@ -222,6 +222,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh,
                goto out;
        }
 
+       if (fattr->valid & NFS_ATTR_FATTR_FSID &&
+           !nfs_fsid_equal(&server->fsid, &fattr->fsid))
+               memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
+
        inode = nfs_fhget(sb, mntfh, fattr);
        if (IS_ERR(inode)) {
                dprintk("nfs_get_root: get root inode failed\n");
index 01768e5e2c9b8b688f6521220922597719b4505d..57bb31ad7a5ec1c46a5533db711ee6d7d423f68e 100644 (file)
@@ -254,7 +254,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
        struct inode *inode = ERR_PTR(-ENOENT);
        unsigned long hash;
 
-       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
+       nfs_attr_check_mountpoint(sb, fattr);
+
+       if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0 && (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0)
                goto out_no_inode;
        if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
                goto out_no_inode;
@@ -298,8 +300,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                        if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
                                set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
-                       if ((fattr->valid & NFS_ATTR_FATTR_FSID)
-                                       && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
+                       if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT ||
+                                       fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
                                if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
                                        inode->i_op = &nfs_referral_inode_operations;
                                else
@@ -639,7 +641,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr
                ctx->mode = f_mode;
                ctx->flags = 0;
                ctx->error = 0;
-               ctx->dir_cookie = 0;
                nfs_init_lock_context(&ctx->lock_context);
                ctx->lock_context.open_context = ctx;
                INIT_LIST_HEAD(&ctx->list);
@@ -1471,6 +1472,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi)
        nfsi->delegation_state = 0;
        init_rwsem(&nfsi->rwsem);
        nfsi->layout = NULL;
+       atomic_set(&nfsi->commits_outstanding, 0);
 #endif
 }
 
index 72e0bddf7a2fe86d481270d1d9d6c9c47a89399e..ce118ce885dd5e20276356011e288d8502c6ef11 100644 (file)
@@ -39,6 +39,12 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
        return 0;
 }
 
+static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr)
+{
+       if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid))
+               fattr->valid |= NFS_ATTR_FATTR_MOUNTPOINT;
+}
+
 struct nfs_clone_mount {
        const struct super_block *sb;
        const struct dentry *dentry;
@@ -214,6 +220,7 @@ extern const u32 nfs41_maxwrite_overhead;
 /* nfs4proc.c */
 #ifdef CONFIG_NFS_V4
 extern struct rpc_procinfo nfs4_procedures[];
+void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *);
 #endif
 
 extern int nfs4_init_ds_session(struct nfs_client *clp);
@@ -276,11 +283,25 @@ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
 extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
 
 /* write.c */
+extern void nfs_commit_free(struct nfs_write_data *p);
 extern int nfs_initiate_write(struct nfs_write_data *data,
                              struct rpc_clnt *clnt,
                              const struct rpc_call_ops *call_ops,
                              int how);
 extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
+extern int nfs_initiate_commit(struct nfs_write_data *data,
+                              struct rpc_clnt *clnt,
+                              const struct rpc_call_ops *call_ops,
+                              int how);
+extern void nfs_init_commit(struct nfs_write_data *data,
+                           struct list_head *head,
+                           struct pnfs_layout_segment *lseg);
+void nfs_retry_commit(struct list_head *page_list,
+                     struct pnfs_layout_segment *lseg);
+void nfs_commit_clear_lock(struct nfs_inode *nfsi);
+void nfs_commitdata_release(void *data);
+void nfs_commit_release_pages(struct nfs_write_data *data);
+
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
                struct page *, struct page *);
@@ -296,12 +317,14 @@ extern int nfs4_init_client(struct nfs_client *clp,
                            rpc_authflavor_t authflavour,
                            int noresvport);
 extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data);
-extern int _nfs4_call_sync(struct nfs_server *server,
+extern int _nfs4_call_sync(struct rpc_clnt *clnt,
+                          struct nfs_server *server,
                           struct rpc_message *msg,
                           struct nfs4_sequence_args *args,
                           struct nfs4_sequence_res *res,
                           int cache_reply);
-extern int _nfs4_call_sync_session(struct nfs_server *server,
+extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
+                                  struct nfs_server *server,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
                                   struct nfs4_sequence_res *res,
index c0b8344db0c65129d08d6a299a051fed0ce430fd..ad92bf731ff570a560919ef4eb22b3eb50f0027e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/vfs.h>
+#include <linux/sunrpc/gss_api.h>
 #include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
@@ -27,7 +28,8 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ;
 
 static struct vfsmount *nfs_do_submount(struct dentry *dentry,
                                        struct nfs_fh *fh,
-                                       struct nfs_fattr *fattr);
+                                       struct nfs_fattr *fattr,
+                                       rpc_authflavor_t authflavor);
 
 /*
  * nfs_path - reconstruct the path given an arbitrary dentry
@@ -98,7 +100,7 @@ rename_retry:
                namelen--;
        buflen -= namelen;
        if (buflen < 0) {
-               spin_lock(&dentry->d_lock);
+               spin_unlock(&dentry->d_lock);
                rcu_read_unlock();
                goto Elong;
        }
@@ -108,7 +110,7 @@ rename_retry:
        rcu_read_unlock();
        return end;
 Elong_unlock:
-       spin_lock(&dentry->d_lock);
+       spin_unlock(&dentry->d_lock);
        rcu_read_unlock();
        if (read_seqretry(&rename_lock, seq))
                goto rename_retry;
@@ -116,6 +118,100 @@ Elong:
        return ERR_PTR(-ENAMETOOLONG);
 }
 
+#ifdef CONFIG_NFS_V4
+static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode)
+{
+       struct gss_api_mech *mech;
+       struct xdr_netobj oid;
+       int i;
+       rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
+
+       for (i = 0; i < flavors->num_flavors; i++) {
+               struct nfs4_secinfo_flavor *flavor;
+               flavor = &flavors->flavors[i];
+
+               if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
+                       pseudoflavor = flavor->flavor;
+                       break;
+               } else if (flavor->flavor == RPC_AUTH_GSS) {
+                       oid.len  = flavor->gss.sec_oid4.len;
+                       oid.data = flavor->gss.sec_oid4.data;
+                       mech = gss_mech_get_by_OID(&oid);
+                       if (!mech)
+                               continue;
+                       pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
+                       gss_mech_put(mech);
+                       break;
+               }
+       }
+
+       return pseudoflavor;
+}
+
+static rpc_authflavor_t nfs_negotiate_security(const struct dentry *parent, const struct dentry *dentry)
+{
+       int status = 0;
+       struct page *page;
+       struct nfs4_secinfo_flavors *flavors;
+       int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
+       rpc_authflavor_t flavor = RPC_AUTH_UNIX;
+
+       secinfo = NFS_PROTO(parent->d_inode)->secinfo;
+       if (secinfo != NULL) {
+               page = alloc_page(GFP_KERNEL);
+               if (!page) {
+                       status = -ENOMEM;
+                       goto out;
+               }
+               flavors = page_address(page);
+               status = secinfo(parent->d_inode, &dentry->d_name, flavors);
+               flavor = nfs_find_best_sec(flavors, dentry->d_inode);
+               put_page(page);
+       }
+
+       return flavor;
+
+out:
+       status = -ENOMEM;
+       return status;
+}
+
+static rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent,
+                                    struct dentry *dentry, struct path *path,
+                                    struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+       rpc_authflavor_t flavor;
+       struct rpc_clnt *clone;
+       struct rpc_auth *auth;
+       int err;
+
+       flavor = nfs_negotiate_security(parent, path->dentry);
+       if (flavor < 0)
+               goto out;
+       clone  = rpc_clone_client(server->client);
+       auth   = rpcauth_create(flavor, clone);
+       if (!auth) {
+               flavor = -EIO;
+               goto out;
+       }
+       err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode,
+                                                 &path->dentry->d_name,
+                                                 fh, fattr);
+       if (err < 0)
+               flavor = err;
+out:
+       return flavor;
+}
+#else /* CONFIG_NFS_V4 */
+static inline rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server,
+                                    struct dentry *parent, struct dentry *dentry,
+                                    struct path *path, struct nfs_fh *fh,
+                                    struct nfs_fattr *fattr)
+{
+       return -EPERM;
+}
+#endif /* CONFIG_NFS_V4 */
+
 /*
  * nfs_d_automount - Handle crossing a mountpoint on the server
  * @path - The mountpoint
@@ -136,6 +232,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
        struct nfs_fh *fh = NULL;
        struct nfs_fattr *fattr = NULL;
        int err;
+       rpc_authflavor_t flavor = 1;
 
        dprintk("--> nfs_d_automount()\n");
 
@@ -153,9 +250,16 @@ struct vfsmount *nfs_d_automount(struct path *path)
 
        /* Look it up again to get its attributes */
        parent = dget_parent(path->dentry);
-       err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
+       err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode,
                                                  &path->dentry->d_name,
                                                  fh, fattr);
+       if (err == -EPERM) {
+               flavor = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr);
+               if (flavor < 0)
+                       err = flavor;
+               else
+                       err = 0;
+       }
        dput(parent);
        if (err != 0) {
                mnt = ERR_PTR(err);
@@ -165,7 +269,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
        if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
                mnt = nfs_do_refmount(path->dentry);
        else
-               mnt = nfs_do_submount(path->dentry, fh, fattr);
+               mnt = nfs_do_submount(path->dentry, fh, fattr, flavor);
        if (IS_ERR(mnt))
                goto out;
 
@@ -232,17 +336,20 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
  * @dentry - parent directory
  * @fh - filehandle for new root dentry
  * @fattr - attributes for new root inode
+ * @authflavor - security flavor to use when performing the mount
  *
  */
 static struct vfsmount *nfs_do_submount(struct dentry *dentry,
                                        struct nfs_fh *fh,
-                                       struct nfs_fattr *fattr)
+                                       struct nfs_fattr *fattr,
+                                       rpc_authflavor_t authflavor)
 {
        struct nfs_clone_mount mountdata = {
                .sb = dentry->d_sb,
                .dentry = dentry,
                .fh = fh,
                .fattr = fattr,
+               .authflavor = authflavor,
        };
        struct vfsmount *mnt = ERR_PTR(-ENOMEM);
        char *page = (char *) __get_free_page(GFP_USER);
index d0c80d8b3f96e96d9d5cdf0c60afd5fbf8d90665..38053d823eb061060cdccdd904ebe9f830ee0c7f 100644 (file)
@@ -141,7 +141,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 }
 
 static int
-nfs3_proc_lookup(struct inode *dir, struct qstr *name,
+nfs3_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
                 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        struct nfs3_diropargs   arg = {
index c64be1cff08072929037c710209a56a73e5c8bad..e1c261ddd65dc591408633469e5e90ec176f476c 100644 (file)
@@ -57,7 +57,8 @@ enum nfs4_session_state {
 struct nfs4_minor_version_ops {
        u32     minor_version;
 
-       int     (*call_sync)(struct nfs_server *server,
+       int     (*call_sync)(struct rpc_clnt *clnt,
+                       struct nfs_server *server,
                        struct rpc_message *msg,
                        struct nfs4_sequence_args *args,
                        struct nfs4_sequence_res *res,
@@ -262,6 +263,8 @@ extern int nfs4_proc_destroy_session(struct nfs4_session *);
 extern int nfs4_init_session(struct nfs_server *server);
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
                struct nfs_fsinfo *fsinfo);
+extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data,
+                                 bool sync);
 
 static inline bool
 is_ds_only_client(struct nfs_client *clp)
index 42855846481781cd7d2bc04b631ab8f2334317bb..6f8192f4cfc759b653c186c5122565bacdd96631 100644 (file)
@@ -153,6 +153,23 @@ static int filelayout_read_done_cb(struct rpc_task *task,
        return 0;
 }
 
+/*
+ * We reference the rpc_cred of the first WRITE that triggers the need for
+ * a LAYOUTCOMMIT, and use it to send the layoutcommit compound.
+ * rfc5661 is not clear about which credential should be used.
+ */
+static void
+filelayout_set_layoutcommit(struct nfs_write_data *wdata)
+{
+       if (FILELAYOUT_LSEG(wdata->lseg)->commit_through_mds ||
+           wdata->res.verf->committed == NFS_FILE_SYNC)
+               return;
+
+       pnfs_set_layoutcommit(wdata);
+       dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino,
+               (unsigned long) wdata->lseg->pls_end_pos);
+}
+
 /*
  * Call ops for the async read/write cases
  * In the case of dense layouts, the offset needs to be reset to its
@@ -210,6 +227,38 @@ static int filelayout_write_done_cb(struct rpc_task *task,
                return -EAGAIN;
        }
 
+       filelayout_set_layoutcommit(data);
+       return 0;
+}
+
+/* Fake up some data that will cause nfs_commit_release to retry the writes. */
+static void prepare_to_resend_writes(struct nfs_write_data *data)
+{
+       struct nfs_page *first = nfs_list_entry(data->pages.next);
+
+       data->task.tk_status = 0;
+       memcpy(data->verf.verifier, first->wb_verf.verifier,
+              sizeof(first->wb_verf.verifier));
+       data->verf.verifier[0]++; /* ensure verifier mismatch */
+}
+
+static int filelayout_commit_done_cb(struct rpc_task *task,
+                                    struct nfs_write_data *data)
+{
+       int reset = 0;
+
+       if (filelayout_async_handle_error(task, data->args.context->state,
+                                         data->ds_clp, &reset) == -EAGAIN) {
+               dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
+                       __func__, data->ds_clp, data->ds_clp->cl_session);
+               if (reset) {
+                       prepare_to_resend_writes(data);
+                       filelayout_set_lo_fail(data->lseg);
+               } else
+                       nfs_restart_rpc(task, data->ds_clp);
+               return -EAGAIN;
+       }
+
        return 0;
 }
 
@@ -240,6 +289,16 @@ static void filelayout_write_release(void *data)
        wdata->mds_ops->rpc_release(data);
 }
 
+static void filelayout_commit_release(void *data)
+{
+       struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+       nfs_commit_release_pages(wdata);
+       if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
+               nfs_commit_clear_lock(NFS_I(wdata->inode));
+       nfs_commitdata_release(wdata);
+}
+
 struct rpc_call_ops filelayout_read_call_ops = {
        .rpc_call_prepare = filelayout_read_prepare,
        .rpc_call_done = filelayout_read_call_done,
@@ -252,6 +311,12 @@ struct rpc_call_ops filelayout_write_call_ops = {
        .rpc_release = filelayout_write_release,
 };
 
+struct rpc_call_ops filelayout_commit_call_ops = {
+       .rpc_call_prepare = filelayout_write_prepare,
+       .rpc_call_done = filelayout_write_call_done,
+       .rpc_release = filelayout_commit_release,
+};
+
 static enum pnfs_try_status
 filelayout_read_pagelist(struct nfs_read_data *data)
 {
@@ -320,10 +385,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
                data->inode->i_ino, sync, (size_t) data->args.count, offset,
                ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
 
-       /* We can't handle commit to ds yet */
-       if (!FILELAYOUT_LSEG(lseg)->commit_through_mds)
-               data->args.stable = NFS_FILE_SYNC;
-
        data->write_done_cb = filelayout_write_done_cb;
        data->ds_clp = ds->ds_clp;
        fh = nfs4_fl_select_ds_fh(lseg, j);
@@ -441,12 +502,33 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                         struct nfs4_layoutget_res *lgr,
                         struct nfs4_deviceid *id)
 {
-       uint32_t *p = (uint32_t *)lgr->layout.buf;
+       struct xdr_stream stream;
+       struct xdr_buf buf = {
+               .pages =  lgr->layoutp->pages,
+               .page_len =  lgr->layoutp->len,
+               .buflen =  lgr->layoutp->len,
+               .len = lgr->layoutp->len,
+       };
+       struct page *scratch;
+       __be32 *p;
        uint32_t nfl_util;
        int i;
 
        dprintk("%s: set_layout_map Begin\n", __func__);
 
+       scratch = alloc_page(GFP_KERNEL);
+       if (!scratch)
+               return -ENOMEM;
+
+       xdr_init_decode(&stream, &buf, NULL);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
+
+       /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
+        * num_fh (4) */
+       p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20);
+       if (unlikely(!p))
+               goto out_err;
+
        memcpy(id, p, sizeof(*id));
        p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
        print_deviceid(id);
@@ -468,32 +550,57 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
                fl->pattern_offset);
 
+       if (!fl->num_fh)
+               goto out_err;
+
        fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
                               GFP_KERNEL);
        if (!fl->fh_array)
-               return -ENOMEM;
+               goto out_err;
 
        for (i = 0; i < fl->num_fh; i++) {
                /* Do we want to use a mempool here? */
                fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
-               if (!fl->fh_array[i]) {
-                       filelayout_free_fh_array(fl);
-                       return -ENOMEM;
-               }
+               if (!fl->fh_array[i])
+                       goto out_err_free;
+
+               p = xdr_inline_decode(&stream, 4);
+               if (unlikely(!p))
+                       goto out_err_free;
                fl->fh_array[i]->size = be32_to_cpup(p++);
                if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
                        printk(KERN_ERR "Too big fh %d received %d\n",
                               i, fl->fh_array[i]->size);
-                       filelayout_free_fh_array(fl);
-                       return -EIO;
+                       goto out_err_free;
                }
+
+               p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
+               if (unlikely(!p))
+                       goto out_err_free;
                memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
-               p += XDR_QUADLEN(fl->fh_array[i]->size);
                dprintk("DEBUG: %s: fh len %d\n", __func__,
                        fl->fh_array[i]->size);
        }
 
+       __free_page(scratch);
        return 0;
+
+out_err_free:
+       filelayout_free_fh_array(fl);
+out_err:
+       __free_page(scratch);
+       return -EIO;
+}
+
+static void
+filelayout_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
+
+       dprintk("--> %s\n", __func__);
+       nfs4_fl_put_deviceid(fl->dsaddr);
+       kfree(fl->commit_buckets);
+       _filelayout_free_lseg(fl);
 }
 
 static struct pnfs_layout_segment *
@@ -514,17 +621,28 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
                _filelayout_free_lseg(fl);
                return NULL;
        }
-       return &fl->generic_hdr;
-}
 
-static void
-filelayout_free_lseg(struct pnfs_layout_segment *lseg)
-{
-       struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
-
-       dprintk("--> %s\n", __func__);
-       nfs4_fl_put_deviceid(fl->dsaddr);
-       _filelayout_free_lseg(fl);
+       /* This assumes there is only one IOMODE_RW lseg.  What
+        * we really want to do is have a layout_hdr level
+        * dictionary of <multipath_list4, fh> keys, each
+        * associated with a struct list_head, populated by calls
+        * to filelayout_write_pagelist().
+        * */
+       if ((!fl->commit_through_mds) && (lgr->range.iomode == IOMODE_RW)) {
+               int i;
+               int size = (fl->stripe_type == STRIPE_SPARSE) ?
+                       fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
+
+               fl->commit_buckets = kcalloc(size, sizeof(struct list_head), GFP_KERNEL);
+               if (!fl->commit_buckets) {
+                       filelayout_free_lseg(&fl->generic_hdr);
+                       return NULL;
+               }
+               fl->number_of_buckets = size;
+               for (i = 0; i < size; i++)
+                       INIT_LIST_HEAD(&fl->commit_buckets[i]);
+       }
+       return &fl->generic_hdr;
 }
 
 /*
@@ -552,6 +670,191 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
        return (p_stripe == r_stripe);
 }
 
+static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
+{
+       return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
+}
+
+static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
+{
+       if (fl->stripe_type == STRIPE_SPARSE)
+               return nfs4_fl_calc_ds_index(&fl->generic_hdr, j);
+       else
+               return j;
+}
+
+struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
+{
+       struct pnfs_layout_segment *lseg = req->wb_commit_lseg;
+       struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
+       u32 i, j;
+       struct list_head *list;
+
+       /* Note that we are calling nfs4_fl_calc_j_index on each page
+        * that ends up being committed to a data server.  An attractive
+        * alternative is to add a field to nfs_write_data and nfs_page
+        * to store the value calculated in filelayout_write_pagelist
+        * and just use that here.
+        */
+       j = nfs4_fl_calc_j_index(lseg,
+                                (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
+       i = select_bucket_index(fl, j);
+       list = &fl->commit_buckets[i];
+       if (list_empty(list)) {
+               /* Non-empty buckets hold a reference on the lseg */
+               get_lseg(lseg);
+       }
+       return list;
+}
+
+static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
+{
+       struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
+
+       if (flseg->stripe_type == STRIPE_SPARSE)
+               return i;
+       else
+               return nfs4_fl_calc_ds_index(lseg, i);
+}
+
+static struct nfs_fh *
+select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
+{
+       struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
+
+       if (flseg->stripe_type == STRIPE_SPARSE) {
+               if (flseg->num_fh == 1)
+                       i = 0;
+               else if (flseg->num_fh == 0)
+                       /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
+                       return NULL;
+       }
+       return flseg->fh_array[i];
+}
+
+static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
+{
+       struct pnfs_layout_segment *lseg = data->lseg;
+       struct nfs4_pnfs_ds *ds;
+       u32 idx;
+       struct nfs_fh *fh;
+
+       idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
+       ds = nfs4_fl_prepare_ds(lseg, idx);
+       if (!ds) {
+               printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+               set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+               prepare_to_resend_writes(data);
+               data->mds_ops->rpc_release(data);
+               return -EAGAIN;
+       }
+       dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
+       data->write_done_cb = filelayout_commit_done_cb;
+       data->ds_clp = ds->ds_clp;
+       fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
+       if (fh)
+               data->args.fh = fh;
+       return nfs_initiate_commit(data, ds->ds_clp->cl_rpcclient,
+                                  &filelayout_commit_call_ops, how);
+}
+
+/*
+ * This is only useful while we are using whole file layouts.
+ */
+static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
+{
+       struct pnfs_layout_segment *lseg, *rv = NULL;
+
+       spin_lock(&inode->i_lock);
+       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
+               if (lseg->pls_range.iomode == IOMODE_RW)
+                       rv = get_lseg(lseg);
+       spin_unlock(&inode->i_lock);
+       return rv;
+}
+
+static int alloc_ds_commits(struct inode *inode, struct list_head *list)
+{
+       struct pnfs_layout_segment *lseg;
+       struct nfs4_filelayout_segment *fl;
+       struct nfs_write_data *data;
+       int i, j;
+
+       /* Won't need this when non-whole file layout segments are supported
+        * instead we will use a pnfs_layout_hdr structure */
+       lseg = find_only_write_lseg(inode);
+       if (!lseg)
+               return 0;
+       fl = FILELAYOUT_LSEG(lseg);
+       for (i = 0; i < fl->number_of_buckets; i++) {
+               if (list_empty(&fl->commit_buckets[i]))
+                       continue;
+               data = nfs_commitdata_alloc();
+               if (!data)
+                       goto out_bad;
+               data->ds_commit_index = i;
+               data->lseg = lseg;
+               list_add(&data->pages, list);
+       }
+       put_lseg(lseg);
+       return 0;
+
+out_bad:
+       for (j = i; j < fl->number_of_buckets; j++) {
+               if (list_empty(&fl->commit_buckets[i]))
+                       continue;
+               nfs_retry_commit(&fl->commit_buckets[i], lseg);
+               put_lseg(lseg);  /* associated with emptying bucket */
+       }
+       put_lseg(lseg);
+       /* Caller will clean up entries put on list */
+       return -ENOMEM;
+}
+
+/* This follows nfs_commit_list pretty closely */
+static int
+filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
+                          int how)
+{
+       struct nfs_write_data   *data, *tmp;
+       LIST_HEAD(list);
+
+       if (!list_empty(mds_pages)) {
+               data = nfs_commitdata_alloc();
+               if (!data)
+                       goto out_bad;
+               data->lseg = NULL;
+               list_add(&data->pages, &list);
+       }
+
+       if (alloc_ds_commits(inode, &list))
+               goto out_bad;
+
+       list_for_each_entry_safe(data, tmp, &list, pages) {
+               list_del_init(&data->pages);
+               atomic_inc(&NFS_I(inode)->commits_outstanding);
+               if (!data->lseg) {
+                       nfs_init_commit(data, mds_pages, NULL);
+                       nfs_initiate_commit(data, NFS_CLIENT(inode),
+                                           data->mds_ops, how);
+               } else {
+                       nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg);
+                       filelayout_initiate_commit(data, how);
+               }
+       }
+       return 0;
+ out_bad:
+       list_for_each_entry_safe(data, tmp, &list, pages) {
+               nfs_retry_commit(&data->pages, data->lseg);
+               list_del_init(&data->pages);
+               nfs_commit_free(data);
+       }
+       nfs_retry_commit(mds_pages, NULL);
+       nfs_commit_clear_lock(NFS_I(inode));
+       return -ENOMEM;
+}
+
 static struct pnfs_layoutdriver_type filelayout_type = {
        .id                     = LAYOUT_NFSV4_1_FILES,
        .name                   = "LAYOUT_NFSV4_1_FILES",
@@ -559,6 +862,9 @@ static struct pnfs_layoutdriver_type filelayout_type = {
        .alloc_lseg             = filelayout_alloc_lseg,
        .free_lseg              = filelayout_free_lseg,
        .pg_test                = filelayout_pg_test,
+       .mark_pnfs_commit       = filelayout_mark_pnfs_commit,
+       .choose_commit_list     = filelayout_choose_commit_list,
+       .commit_pagelist        = filelayout_commit_pagelist,
        .read_pagelist          = filelayout_read_pagelist,
        .write_pagelist         = filelayout_write_pagelist,
 };
index ee0c907742b529f5bf1ea54cc8b70f9db87f5e2c..085a354e0f0895d721082c9236b21fcbcf5cda98 100644 (file)
@@ -79,6 +79,8 @@ struct nfs4_filelayout_segment {
        struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
        unsigned int num_fh;
        struct nfs_fh **fh_array;
+       struct list_head *commit_buckets; /* Sort commits to ds */
+       int number_of_buckets;
 };
 
 static inline struct nfs4_filelayout_segment *
index 68143c162e3be30ef824027a1db99de69975acfc..de5350f2b2492139bf9b9d913a5bdf9e99a50ec3 100644 (file)
@@ -261,7 +261,7 @@ out:
  * Currently only support ipv4, and one multi-path address.
  */
 static struct nfs4_pnfs_ds *
-decode_and_add_ds(__be32 **pp, struct inode *inode)
+decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode)
 {
        struct nfs4_pnfs_ds *ds = NULL;
        char *buf;
@@ -269,25 +269,34 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
        u32 ip_addr, port;
        int nlen, rlen, i;
        int tmp[2];
-       __be32 *r_netid, *r_addr, *p = *pp;
+       __be32 *p;
 
        /* r_netid */
+       p = xdr_inline_decode(streamp, 4);
+       if (unlikely(!p))
+               goto out_err;
        nlen = be32_to_cpup(p++);
-       r_netid = p;
-       p += XDR_QUADLEN(nlen);
 
-       /* r_addr */
-       rlen = be32_to_cpup(p++);
-       r_addr = p;
-       p += XDR_QUADLEN(rlen);
-       *pp = p;
+       p = xdr_inline_decode(streamp, nlen);
+       if (unlikely(!p))
+               goto out_err;
 
        /* Check that netid is "tcp" */
-       if (nlen != 3 ||  memcmp((char *)r_netid, "tcp", 3)) {
+       if (nlen != 3 ||  memcmp((char *)p, "tcp", 3)) {
                dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__);
                goto out_err;
        }
 
+       /* r_addr */
+       p = xdr_inline_decode(streamp, 4);
+       if (unlikely(!p))
+               goto out_err;
+       rlen = be32_to_cpup(p);
+
+       p = xdr_inline_decode(streamp, rlen);
+       if (unlikely(!p))
+               goto out_err;
+
        /* ipv6 length plus port is legal */
        if (rlen > INET6_ADDRSTRLEN + 8) {
                dprintk("%s: Invalid address, length %d\n", __func__,
@@ -300,7 +309,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
                goto out_err;
        }
        buf[rlen] = '\0';
-       memcpy(buf, r_addr, rlen);
+       memcpy(buf, p, rlen);
 
        /* replace the port dots with dashes for the in4_pton() delimiter*/
        for (i = 0; i < 2; i++) {
@@ -336,90 +345,154 @@ out_err:
 static struct nfs4_file_layout_dsaddr*
 decode_device(struct inode *ino, struct pnfs_device *pdev)
 {
-       int i, dummy;
+       int i;
        u32 cnt, num;
        u8 *indexp;
-       __be32 *p = (__be32 *)pdev->area, *indicesp;
-       struct nfs4_file_layout_dsaddr *dsaddr;
+       __be32 *p;
+       u8 *stripe_indices;
+       u8 max_stripe_index;
+       struct nfs4_file_layout_dsaddr *dsaddr = NULL;
+       struct xdr_stream stream;
+       struct xdr_buf buf = {
+               .pages = pdev->pages,
+               .page_len = pdev->pglen,
+               .buflen = pdev->pglen,
+               .len = pdev->pglen,
+       };
+       struct page *scratch;
+
+       /* set up xdr stream */
+       scratch = alloc_page(GFP_KERNEL);
+       if (!scratch)
+               goto out_err;
+
+       xdr_init_decode(&stream, &buf, NULL);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 
        /* Get the stripe count (number of stripe index) */
-       cnt = be32_to_cpup(p++);
+       p = xdr_inline_decode(&stream, 4);
+       if (unlikely(!p))
+               goto out_err_free_scratch;
+
+       cnt = be32_to_cpup(p);
        dprintk("%s stripe count  %d\n", __func__, cnt);
        if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
                printk(KERN_WARNING "%s: stripe count %d greater than "
                       "supported maximum %d\n", __func__,
                        cnt, NFS4_PNFS_MAX_STRIPE_CNT);
-               goto out_err;
+               goto out_err_free_scratch;
+       }
+
+       /* read stripe indices */
+       stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL);
+       if (!stripe_indices)
+               goto out_err_free_scratch;
+
+       p = xdr_inline_decode(&stream, cnt << 2);
+       if (unlikely(!p))
+               goto out_err_free_stripe_indices;
+
+       indexp = &stripe_indices[0];
+       max_stripe_index = 0;
+       for (i = 0; i < cnt; i++) {
+               *indexp = be32_to_cpup(p++);
+               max_stripe_index = max(max_stripe_index, *indexp);
+               indexp++;
        }
 
        /* Check the multipath list count */
-       indicesp = p;
-       p += XDR_QUADLEN(cnt << 2);
-       num = be32_to_cpup(p++);
+       p = xdr_inline_decode(&stream, 4);
+       if (unlikely(!p))
+               goto out_err_free_stripe_indices;
+
+       num = be32_to_cpup(p);
        dprintk("%s ds_num %u\n", __func__, num);
        if (num > NFS4_PNFS_MAX_MULTI_CNT) {
                printk(KERN_WARNING "%s: multipath count %d greater than "
                        "supported maximum %d\n", __func__,
                        num, NFS4_PNFS_MAX_MULTI_CNT);
-               goto out_err;
+               goto out_err_free_stripe_indices;
        }
+
+       /* validate stripe indices are all < num */
+       if (max_stripe_index >= num) {
+               printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n",
+                       __func__, max_stripe_index, num);
+               goto out_err_free_stripe_indices;
+       }
+
        dsaddr = kzalloc(sizeof(*dsaddr) +
                        (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
                        GFP_KERNEL);
        if (!dsaddr)
-               goto out_err;
-
-       dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL);
-       if (!dsaddr->stripe_indices)
-               goto out_err_free;
+               goto out_err_free_stripe_indices;
 
        dsaddr->stripe_count = cnt;
+       dsaddr->stripe_indices = stripe_indices;
+       stripe_indices = NULL;
        dsaddr->ds_num = num;
 
        memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id));
 
-       /* Go back an read stripe indices */
-       p = indicesp;
-       indexp = &dsaddr->stripe_indices[0];
-       for (i = 0; i < dsaddr->stripe_count; i++) {
-               *indexp = be32_to_cpup(p++);
-               if (*indexp >= num)
-                       goto out_err_free;
-               indexp++;
-       }
-       /* Skip already read multipath list count */
-       p++;
-
        for (i = 0; i < dsaddr->ds_num; i++) {
                int j;
+               u32 mp_count;
+
+               p = xdr_inline_decode(&stream, 4);
+               if (unlikely(!p))
+                       goto out_err_free_deviceid;
 
-               dummy = be32_to_cpup(p++); /* multipath count */
-               if (dummy > 1) {
+               mp_count = be32_to_cpup(p); /* multipath count */
+               if (mp_count > 1) {
                        printk(KERN_WARNING
                               "%s: Multipath count %d not supported, "
                               "skipping all greater than 1\n", __func__,
-                               dummy);
+                               mp_count);
                }
-               for (j = 0; j < dummy; j++) {
+               for (j = 0; j < mp_count; j++) {
                        if (j == 0) {
-                               dsaddr->ds_list[i] = decode_and_add_ds(&p, ino);
+                               dsaddr->ds_list[i] = decode_and_add_ds(&stream,
+                                       ino);
                                if (dsaddr->ds_list[i] == NULL)
-                                       goto out_err_free;
+                                       goto out_err_free_deviceid;
                        } else {
                                u32 len;
                                /* skip extra multipath */
-                               len = be32_to_cpup(p++);
-                               p += XDR_QUADLEN(len);
-                               len = be32_to_cpup(p++);
-                               p += XDR_QUADLEN(len);
-                               continue;
+
+                               /* read len, skip */
+                               p = xdr_inline_decode(&stream, 4);
+                               if (unlikely(!p))
+                                       goto out_err_free_deviceid;
+                               len = be32_to_cpup(p);
+
+                               p = xdr_inline_decode(&stream, len);
+                               if (unlikely(!p))
+                                       goto out_err_free_deviceid;
+
+                               /* read len, skip */
+                               p = xdr_inline_decode(&stream, 4);
+                               if (unlikely(!p))
+                                       goto out_err_free_deviceid;
+                               len = be32_to_cpup(p);
+
+                               p = xdr_inline_decode(&stream, len);
+                               if (unlikely(!p))
+                                       goto out_err_free_deviceid;
                        }
                }
        }
+
+       __free_page(scratch);
        return dsaddr;
 
-out_err_free:
+out_err_free_deviceid:
        nfs4_fl_free_deviceid(dsaddr);
+       /* stripe_indicies was part of dsaddr */
+       goto out_err_free_scratch;
+out_err_free_stripe_indices:
+       kfree(stripe_indices);
+out_err_free_scratch:
+       __free_page(scratch);
 out_err:
        dprintk("%s ERROR: returning NULL\n", __func__);
        return NULL;
@@ -498,11 +571,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
                        goto out_free;
        }
 
-       /* set pdev->area */
-       pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL);
-       if (!pdev->area)
-               goto out_free;
-
        memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
        pdev->layout_type = LAYOUT_NFSV4_1_FILES;
        pdev->pages = pages;
@@ -521,8 +589,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id)
         */
        dsaddr = decode_and_add_device(inode, pdev);
 out_free:
-       if (pdev->area != NULL)
-               vunmap(pdev->area);
        for (i = 0; i < max_pages; i++)
                __free_page(pages[i]);
        kfree(pages);
index 1d84e7088af9dbe3306a6ed6b0204edf64faac71..dfd1e6d7e6c3c645886424f2858d27874233566f 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/gss_api.h>
 #include <linux/nfs.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
@@ -71,7 +72,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
-static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+static int _nfs4_proc_lookup(struct rpc_clnt *client, struct inode *dir,
+                            const struct qstr *name, struct nfs_fh *fhandle,
+                            struct nfs_fattr *fattr);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                            struct nfs_fattr *fattr, struct iattr *sattr,
@@ -85,6 +88,8 @@ static int nfs4_map_errors(int err)
        switch (err) {
        case -NFS4ERR_RESOURCE:
                return -EREMOTEIO;
+       case -NFS4ERR_WRONGSEC:
+               return -EPERM;
        case -NFS4ERR_BADOWNER:
        case -NFS4ERR_BADNAME:
                return -EINVAL;
@@ -657,7 +662,8 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = {
        .rpc_call_done = nfs41_call_sync_done,
 };
 
-static int nfs4_call_sync_sequence(struct nfs_server *server,
+static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
+                                  struct nfs_server *server,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
                                   struct nfs4_sequence_res *res,
@@ -673,7 +679,7 @@ static int nfs4_call_sync_sequence(struct nfs_server *server,
                .cache_reply = cache_reply,
        };
        struct rpc_task_setup task_setup = {
-               .rpc_client = server->client,
+               .rpc_client = clnt,
                .rpc_message = msg,
                .callback_ops = &nfs41_call_sync_ops,
                .callback_data = &data
@@ -692,13 +698,14 @@ static int nfs4_call_sync_sequence(struct nfs_server *server,
        return ret;
 }
 
-int _nfs4_call_sync_session(struct nfs_server *server,
+int _nfs4_call_sync_session(struct rpc_clnt *clnt,
+                           struct nfs_server *server,
                            struct rpc_message *msg,
                            struct nfs4_sequence_args *args,
                            struct nfs4_sequence_res *res,
                            int cache_reply)
 {
-       return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0);
 }
 
 #else
@@ -709,19 +716,28 @@ static int nfs4_sequence_done(struct rpc_task *task,
 }
 #endif /* CONFIG_NFS_V4_1 */
 
-int _nfs4_call_sync(struct nfs_server *server,
+int _nfs4_call_sync(struct rpc_clnt *clnt,
+                   struct nfs_server *server,
                    struct rpc_message *msg,
                    struct nfs4_sequence_args *args,
                    struct nfs4_sequence_res *res,
                    int cache_reply)
 {
        args->sa_session = res->sr_session = NULL;
-       return rpc_call_sync(server->client, msg, 0);
+       return rpc_call_sync(clnt, msg, 0);
 }
 
-#define nfs4_call_sync(server, msg, args, res, cache_reply) \
-       (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \
-                       &(res)->seq_res, (cache_reply))
+static inline
+int nfs4_call_sync(struct rpc_clnt *clnt,
+                  struct nfs_server *server,
+                  struct rpc_message *msg,
+                  struct nfs4_sequence_args *args,
+                  struct nfs4_sequence_res *res,
+                  int cache_reply)
+{
+       return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
+                                               args, res, cache_reply);
+}
 
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
 {
@@ -1831,7 +1847,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        } else
                memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
 
-       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (status == 0 && state != NULL)
                renew_lease(server, timestamp);
        return status;
@@ -2090,7 +2106,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
        };
        int status;
 
-       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (status == 0) {
                memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
                server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
@@ -2160,7 +2176,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
        };
 
        nfs_fattr_init(info->fattr);
-       return nfs4_call_sync(server, &msg, &args, &res, 0);
+       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -2176,15 +2192,43 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
        return err;
 }
 
+static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
+                               struct nfs_fsinfo *info, rpc_authflavor_t flavor)
+{
+       struct rpc_auth *auth;
+       int ret;
+
+       auth = rpcauth_create(flavor, server->client);
+       if (!auth) {
+               ret = -EIO;
+               goto out;
+       }
+       ret = nfs4_lookup_root(server, fhandle, info);
+       if (ret < 0)
+               ret = -EAGAIN;
+out:
+       return ret;
+}
+
 /*
  * get the file handle for the "/" directory on the server
  */
 static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                              struct nfs_fsinfo *info)
 {
-       int status;
+       int i, len, status = 0;
+       rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2];
+
+       flav_array[0] = RPC_AUTH_UNIX;
+       len = gss_mech_list_pseudoflavors(&flav_array[1]);
+       flav_array[1+len] = RPC_AUTH_NULL;
+       len += 2;
 
-       status = nfs4_lookup_root(server, fhandle, info);
+       for (i = 0; i < len; i++) {
+               status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
+               if (status == 0)
+                       break;
+       }
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
        if (status == 0)
@@ -2249,7 +2293,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
        };
        
        nfs_fattr_init(fattr);
-       return nfs4_call_sync(server, &msg, &args, &res, 0);
+       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
@@ -2309,9 +2353,9 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        return status;
 }
 
-static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh,
-               const struct qstr *name, struct nfs_fh *fhandle,
-               struct nfs_fattr *fattr)
+static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server,
+               const struct nfs_fh *dirfh, const struct qstr *name,
+               struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        int                    status;
        struct nfs4_lookup_arg args = {
@@ -2333,7 +2377,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d
        nfs_fattr_init(fattr);
 
        dprintk("NFS call  lookupfh %s\n", name->name);
-       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
        dprintk("NFS reply lookupfh: %d\n", status);
        return status;
 }
@@ -2345,7 +2389,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr);
+               err = _nfs4_proc_lookupfh(server->client, server, dirfh, name, fhandle, fattr);
                /* FIXME: !!!! */
                if (err == -NFS4ERR_MOVED) {
                        err = -EREMOTE;
@@ -2356,27 +2400,41 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
        return err;
 }
 
-static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
-               struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
+               const struct qstr *name, struct nfs_fh *fhandle,
+               struct nfs_fattr *fattr)
 {
        int status;
        
        dprintk("NFS call  lookup %s\n", name->name);
-       status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr);
+       status = _nfs4_proc_lookupfh(clnt, NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr);
        if (status == -NFS4ERR_MOVED)
                status = nfs4_get_referral(dir, name, fattr, fhandle);
        dprintk("NFS reply lookup: %d\n", status);
        return status;
 }
 
-static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh)
+{
+       memset(fh, 0, sizeof(struct nfs_fh));
+       fattr->fsid.major = 1;
+       fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
+               NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT;
+       fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+       fattr->nlink = 2;
+}
+
+static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
+                           struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        struct nfs4_exception exception = { };
        int err;
        do {
                err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_lookup(dir, name, fhandle, fattr),
+                               _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr),
                                &exception);
+               if (err == -EPERM)
+                       nfs_fixup_secinfo_attributes(fattr, fhandle);
        } while (exception.retry);
        return err;
 }
@@ -2421,7 +2479,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        if (res.fattr == NULL)
                return -ENOMEM;
 
-       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (!status) {
                entry->mask = 0;
                if (res.access & NFS4_ACCESS_READ)
@@ -2488,7 +2546,7 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
                .rpc_resp = &res,
        };
 
-       return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0);
+       return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_proc_readlink(struct inode *inode, struct page *page,
@@ -2577,7 +2635,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
        if (res.dir_attr == NULL)
                goto out;
 
-       status = nfs4_call_sync(server, &msg, &args, &res, 1);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
        if (status == 0) {
                update_changeattr(dir, &res.cinfo);
                nfs_post_op_update_inode(dir, res.dir_attr);
@@ -2678,7 +2736,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
        if (res.old_fattr == NULL || res.new_fattr == NULL)
                goto out;
 
-       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (!status) {
                update_changeattr(old_dir, &res.old_cinfo);
                nfs_post_op_update_inode(old_dir, res.old_fattr);
@@ -2729,7 +2787,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
        if (res.fattr == NULL || res.dir_attr == NULL)
                goto out;
 
-       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (!status) {
                update_changeattr(dir, &res.cinfo);
                nfs_post_op_update_inode(dir, res.dir_attr);
@@ -2792,8 +2850,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 
 static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
 {
-       int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg,
-                                   &data->arg, &data->res, 1);
+       int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
+                                   &data->arg.seq_args, &data->res.seq_res, 1);
        if (status == 0) {
                update_changeattr(dir, &data->res.dir_cinfo);
                nfs_post_op_update_inode(dir, data->res.dir_fattr);
@@ -2905,7 +2963,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                        (unsigned long long)cookie);
        nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
        res.pgbase = args.pgbase;
-       status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0);
+       status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
        if (status >= 0) {
                memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
                status += args.pgbase;
@@ -2997,7 +3055,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
        };
 
        nfs_fattr_init(fsstat->fattr);
-       return  nfs4_call_sync(server, &msg, &args, &res, 0);
+       return  nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
@@ -3028,7 +3086,7 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp = &res,
        };
 
-       return nfs4_call_sync(server, &msg, &args, &res, 0);
+       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
@@ -3073,7 +3131,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
        }
 
        nfs_fattr_init(pathconf->fattr);
-       return nfs4_call_sync(server, &msg, &args, &res, 0);
+       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
 
 static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -3195,12 +3253,9 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
 }
 
-static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
+static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->inode;
-       
-       if (!nfs4_sequence_done(task, &data->res.seq_res))
-               return -EAGAIN;
 
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
                nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
@@ -3210,11 +3265,24 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
        return 0;
 }
 
+static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
+{
+       if (!nfs4_sequence_done(task, &data->res.seq_res))
+               return -EAGAIN;
+       return data->write_done_cb(task, data);
+}
+
 static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
 {
        struct nfs_server *server = NFS_SERVER(data->inode);
-       
-       data->args.bitmask = server->cache_consistency_bitmask;
+
+       if (data->lseg) {
+               data->args.bitmask = NULL;
+               data->res.fattr = NULL;
+       } else
+               data->args.bitmask = server->cache_consistency_bitmask;
+       if (!data->write_done_cb)
+               data->write_done_cb = nfs4_commit_done_cb;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
 }
@@ -3452,7 +3520,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                resp_buf = buf;
                buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);
        }
-       ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0);
+       ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
        if (ret)
                goto out_free;
        if (res.acl_len > args.acl_len)
@@ -3527,7 +3595,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        if (i < 0)
                return i;
        nfs_inode_return_delegation(inode);
-       ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 
        /*
         * Free each page after tx, so the only ref left is
@@ -3890,7 +3958,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
        lsp = request->fl_u.nfs4_fl.owner;
        arg.lock_owner.id = lsp->ls_id.id;
        arg.lock_owner.s_dev = server->s_dev;
-       status = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        switch (status) {
                case 0:
                        request->fl_type = F_UNLCK;
@@ -4618,12 +4686,46 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
        nfs_fattr_init(&fs_locations->fattr);
        fs_locations->server = server;
        fs_locations->nlocations = 0;
-       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        nfs_fixup_referral_attributes(&fs_locations->fattr);
        dprintk("%s: returned status = %d\n", __func__, status);
        return status;
 }
 
+static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+{
+       int status;
+       struct nfs4_secinfo_arg args = {
+               .dir_fh = NFS_FH(dir),
+               .name   = name,
+       };
+       struct nfs4_secinfo_res res = {
+               .flavors     = flavors,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+
+       dprintk("NFS call  secinfo %s\n", name->name);
+       status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
+       dprintk("NFS reply  secinfo: %d\n", status);
+       return status;
+}
+
+int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+{
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = nfs4_handle_exception(NFS_SERVER(dir),
+                               _nfs4_proc_secinfo(dir, name, flavors),
+                               &exception);
+       } while (exception.retry);
+       return err;
+}
+
 #ifdef CONFIG_NFS_V4_1
 /*
  * Check the exchange flags returned by the server for invalid flags, having
@@ -5516,8 +5618,6 @@ static void nfs4_layoutget_release(void *calldata)
        struct nfs4_layoutget *lgp = calldata;
 
        dprintk("--> %s\n", __func__);
-       if (lgp->res.layout.buf != NULL)
-               free_page((unsigned long) lgp->res.layout.buf);
        put_nfs_open_context(lgp->args.ctx);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
@@ -5549,12 +5649,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
 
        dprintk("--> %s\n", __func__);
 
-       lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS);
-       if (lgp->res.layout.buf == NULL) {
-               nfs4_layoutget_release(lgp);
-               return -ENOMEM;
-       }
-
+       lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -5586,7 +5681,7 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
        int status;
 
        dprintk("--> %s\n", __func__);
-       status = nfs4_call_sync(server, &msg, &args, &res, 0);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        dprintk("<-- %s status=%d\n", __func__, status);
 
        return status;
@@ -5606,6 +5701,100 @@ int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
 }
 EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
 
+static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutcommit_data *data = calldata;
+       struct nfs_server *server = NFS_SERVER(data->args.inode);
+
+       if (nfs4_setup_sequence(server, &data->args.seq_args,
+                               &data->res.seq_res, 1, task))
+               return;
+       rpc_call_start(task);
+}
+
+static void
+nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_layoutcommit_data *data = calldata;
+       struct nfs_server *server = NFS_SERVER(data->args.inode);
+
+       if (!nfs4_sequence_done(task, &data->res.seq_res))
+               return;
+
+       switch (task->tk_status) { /* Just ignore these failures */
+       case NFS4ERR_DELEG_REVOKED: /* layout was recalled */
+       case NFS4ERR_BADIOMODE:     /* no IOMODE_RW layout for range */
+       case NFS4ERR_BADLAYOUT:     /* no layout */
+       case NFS4ERR_GRACE:         /* loca_recalim always false */
+               task->tk_status = 0;
+       }
+
+       if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
+               nfs_restart_rpc(task, server->nfs_client);
+               return;
+       }
+
+       if (task->tk_status == 0)
+               nfs_post_op_update_inode_force_wcc(data->args.inode,
+                                                  data->res.fattr);
+}
+
+static void nfs4_layoutcommit_release(void *calldata)
+{
+       struct nfs4_layoutcommit_data *data = calldata;
+
+       /* Matched by references in pnfs_set_layoutcommit */
+       put_lseg(data->lseg);
+       put_rpccred(data->cred);
+       kfree(data);
+}
+
+static const struct rpc_call_ops nfs4_layoutcommit_ops = {
+       .rpc_call_prepare = nfs4_layoutcommit_prepare,
+       .rpc_call_done = nfs4_layoutcommit_done,
+       .rpc_release = nfs4_layoutcommit_release,
+};
+
+int
+nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
+{
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT],
+               .rpc_argp = &data->args,
+               .rpc_resp = &data->res,
+               .rpc_cred = data->cred,
+       };
+       struct rpc_task_setup task_setup_data = {
+               .task = &data->task,
+               .rpc_client = NFS_CLIENT(data->args.inode),
+               .rpc_message = &msg,
+               .callback_ops = &nfs4_layoutcommit_ops,
+               .callback_data = data,
+               .flags = RPC_TASK_ASYNC,
+       };
+       struct rpc_task *task;
+       int status = 0;
+
+       dprintk("NFS: %4d initiating layoutcommit call. sync %d "
+               "lbw: %llu inode %lu\n",
+               data->task.tk_pid, sync,
+               data->args.lastbytewritten,
+               data->args.inode->i_ino);
+
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       if (sync == false)
+               goto out;
+       status = nfs4_wait_for_completion_rpc_task(task);
+       if (status != 0)
+               goto out;
+       status = task->tk_status;
+out:
+       dprintk("%s: status %d\n", __func__, status);
+       rpc_put_task(task);
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -5741,6 +5930,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .close_context  = nfs4_close_context,
        .open_context   = nfs4_atomic_open,
        .init_client    = nfs4_init_client,
+       .secinfo        = nfs4_proc_secinfo,
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
index 0cf560f77884c0925eefc32920233b8b0217c603..dddfb5795d7b8c67999ebfc819b5cd8021e36cd8 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/kdev_t.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/msg_prot.h>
+#include <linux/sunrpc/gss_api.h>
 #include <linux/nfs.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
@@ -112,7 +113,7 @@ static int nfs4_stat_to_errno(int);
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
 #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
 #define encode_fsinfo_maxsz    (encode_getattr_maxsz)
-#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 11)
+#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 15)
 #define encode_renew_maxsz     (op_encode_hdr_maxsz + 3)
 #define decode_renew_maxsz     (op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
@@ -253,6 +254,8 @@ static int nfs4_stat_to_errno(int);
                                (encode_getattr_maxsz)
 #define decode_fs_locations_maxsz \
                                (0)
+#define encode_secinfo_maxsz   (op_encode_hdr_maxsz + nfs4_name_maxsz)
+#define decode_secinfo_maxsz   (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)))
 
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_MAX_MACHINE_NAME_LEN (64)
@@ -324,6 +327,18 @@ static int nfs4_stat_to_errno(int);
 #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \
                                decode_stateid_maxsz + \
                                XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE))
+#define encode_layoutcommit_maxsz (op_encode_hdr_maxsz +          \
+                               2 /* offset */ + \
+                               2 /* length */ + \
+                               1 /* reclaim */ + \
+                               encode_stateid_maxsz + \
+                               1 /* new offset (true) */ + \
+                               2 /* last byte written */ + \
+                               1 /* nt_timechanged (false) */ + \
+                               1 /* layoutupdate4 layout type */ + \
+                               1 /* NULL filelayout layoutupdate4 payload */)
+#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
+
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -676,6 +691,14 @@ static int nfs4_stat_to_errno(int);
                                 decode_putfh_maxsz + \
                                 decode_lookup_maxsz + \
                                 decode_fs_locations_maxsz)
+#define NFS4_enc_secinfo_sz    (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_secinfo_maxsz)
+#define NFS4_dec_secinfo_sz    (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_secinfo_maxsz)
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_enc_exchange_id_sz \
                                (compound_encode_hdr_maxsz + \
@@ -727,6 +750,17 @@ static int nfs4_stat_to_errno(int);
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz +        \
                                decode_layoutget_maxsz)
+#define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz +\
+                               encode_putfh_maxsz + \
+                               encode_layoutcommit_maxsz + \
+                               encode_getattr_maxsz)
+#define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_layoutcommit_maxsz + \
+                               decode_getattr_maxsz)
+
 
 const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                      compound_encode_hdr_maxsz +
@@ -1620,6 +1654,18 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state
        hdr->replen += decode_delegreturn_maxsz;
 }
 
+static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
+{
+       int len = name->len;
+       __be32 *p;
+
+       p = reserve_space(xdr, 8 + len);
+       *p++ = cpu_to_be32(OP_SECINFO);
+       xdr_encode_opaque(p, name->name, len);
+       hdr->nops++;
+       hdr->replen += decode_secinfo_maxsz;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 /* NFSv4.1 operations */
 static void encode_exchange_id(struct xdr_stream *xdr,
@@ -1816,6 +1862,34 @@ encode_layoutget(struct xdr_stream *xdr,
        hdr->nops++;
        hdr->replen += decode_layoutget_maxsz;
 }
+
+static int
+encode_layoutcommit(struct xdr_stream *xdr,
+                   const struct nfs4_layoutcommit_args *args,
+                   struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
+               NFS_SERVER(args->inode)->pnfs_curr_ld->id);
+
+       p = reserve_space(xdr, 48 + NFS4_STATEID_SIZE);
+       *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
+       /* Only whole file layouts */
+       p = xdr_encode_hyper(p, 0); /* offset */
+       p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
+       *p++ = cpu_to_be32(0); /* reclaim */
+       p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
+       *p++ = cpu_to_be32(1); /* newoffset = TRUE */
+       p = xdr_encode_hyper(p, args->lastbytewritten);
+       *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
+       *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */
+       *p++ = cpu_to_be32(0); /* no file layout payload */
+
+       hdr->nops++;
+       hdr->replen += decode_layoutcommit_maxsz;
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -2294,7 +2368,8 @@ static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
        encode_commit(xdr, args, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       if (args->bitmask)
+               encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2465,6 +2540,24 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+/*
+ * Encode SECINFO request
+ */
+static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
+                               struct xdr_stream *xdr,
+                               struct nfs4_secinfo_arg *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->dir_fh, &hdr);
+       encode_secinfo(xdr, args->name, &hdr);
+       encode_nops(&hdr);
+}
+
 #if defined(CONFIG_NFS_V4_1)
 /*
  * EXCHANGE_ID request
@@ -2604,8 +2697,32 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, NFS_FH(args->inode), &hdr);
        encode_layoutget(xdr, args, &hdr);
+
+       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
+           args->layout.pages, 0, args->layout.pglen);
+
        encode_nops(&hdr);
 }
+
+/*
+ *  Encode LAYOUTCOMMIT request
+ */
+static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
+                                    struct xdr_stream *xdr,
+                                    struct nfs4_layoutcommit_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, NFS_FH(args->inode), &hdr);
+       encode_layoutcommit(xdr, args, &hdr);
+       encode_getfattr(xdr, args->bitmask, &hdr);
+       encode_nops(&hdr);
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
@@ -2925,6 +3042,7 @@ static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap)
                if (unlikely(!p))
                        goto out_overflow;
                bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
+               return -be32_to_cpup(p);
        }
        return 0;
 out_overflow:
@@ -3912,6 +4030,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
        fattr->valid |= status;
 
        status = decode_attr_error(xdr, bitmap);
+       if (status == -NFS4ERR_WRONGSEC) {
+               nfs_fixup_secinfo_attributes(fattr, fh);
+               status = 0;
+       }
        if (status < 0)
                goto xdr_error;
 
@@ -4680,6 +4802,73 @@ static int decode_delegreturn(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_DELEGRETURN);
 }
 
+static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
+{
+       __be32 *p;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       flavor->gss.sec_oid4.len = be32_to_cpup(p);
+       if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
+               goto out_err;
+
+       p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
+       if (unlikely(!p))
+               goto out_overflow;
+       memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);
+
+       p = xdr_inline_decode(xdr, 8);
+       if (unlikely(!p))
+               goto out_overflow;
+       flavor->gss.qop4 = be32_to_cpup(p++);
+       flavor->gss.service = be32_to_cpup(p);
+
+       return 0;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+out_err:
+       return -EINVAL;
+}
+
+static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
+{
+       struct nfs4_secinfo_flavor *sec_flavor;
+       int status;
+       __be32 *p;
+       int i;
+
+       status = decode_op_hdr(xdr, OP_SECINFO);
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->flavors->num_flavors = be32_to_cpup(p);
+
+       for (i = 0; i < res->flavors->num_flavors; i++) {
+               sec_flavor = &res->flavors->flavors[i];
+               if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE)
+                       break;
+
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               sec_flavor->flavor = be32_to_cpup(p);
+
+               if (sec_flavor->flavor == RPC_AUTH_GSS) {
+                       if (decode_secinfo_gss(xdr, sec_flavor))
+                               break;
+               }
+       }
+
+       return 0;
+
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 static int decode_exchange_id(struct xdr_stream *xdr,
                              struct nfs41_exchange_id_res *res)
@@ -4950,6 +5139,9 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
        __be32 *p;
        int status;
        u32 layout_count;
+       struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+       struct kvec *iov = rcvbuf->head;
+       u32 hdrlen, recvd;
 
        status = decode_op_hdr(xdr, OP_LAYOUTGET);
        if (status)
@@ -4966,17 +5158,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                return -EINVAL;
        }
 
-       p = xdr_inline_decode(xdr, 24);
+       p = xdr_inline_decode(xdr, 28);
        if (unlikely(!p))
                goto out_overflow;
        p = xdr_decode_hyper(p, &res->range.offset);
        p = xdr_decode_hyper(p, &res->range.length);
        res->range.iomode = be32_to_cpup(p++);
        res->type = be32_to_cpup(p++);
-
-       status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p);
-       if (unlikely(status))
-               return status;
+       res->layoutp->len = be32_to_cpup(p);
 
        dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
                __func__,
@@ -4984,12 +5173,18 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
                (unsigned long)res->range.length,
                res->range.iomode,
                res->type,
-               res->layout.len);
+               res->layoutp->len);
 
-       /* nfs4_proc_layoutget allocated a single page */
-       if (res->layout.len > PAGE_SIZE)
-               return -ENOMEM;
-       memcpy(res->layout.buf, p, res->layout.len);
+       hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
+       recvd = req->rq_rcv_buf.len - hdrlen;
+       if (res->layoutp->len > recvd) {
+               dprintk("NFS: server cheating in layoutget reply: "
+                               "layout len %u > recvd %u\n",
+                               res->layoutp->len, recvd);
+               return -EINVAL;
+       }
+
+       xdr_read_pages(xdr, res->layoutp->len);
 
        if (layout_count > 1) {
                /* We only handle a length one array at the moment.  Any
@@ -5006,6 +5201,35 @@ out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
 }
+
+static int decode_layoutcommit(struct xdr_stream *xdr,
+                              struct rpc_rqst *req,
+                              struct nfs4_layoutcommit_res *res)
+{
+       __be32 *p;
+       __u32 sizechanged;
+       int status;
+
+       status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       sizechanged = be32_to_cpup(p);
+
+       if (sizechanged) {
+               /* throw away new size */
+               p = xdr_inline_decode(xdr, 8);
+               if (unlikely(!p))
+                       goto out_overflow;
+       }
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -5723,8 +5947,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_commit(xdr, res);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       if (res->fattr)
+               decode_getfattr(xdr, res->fattr, res->server,
+                               !RPC_IS_ASYNC(rqstp->rq_task));
 out:
        return status;
 }
@@ -5919,6 +6144,32 @@ out:
        return status;
 }
 
+/*
+ * Decode SECINFO response
+ */
+static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
+                               struct xdr_stream *xdr,
+                               struct nfs4_secinfo_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_secinfo(xdr, res);
+       if (status)
+               goto out;
+out:
+       return status;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 /*
  * Decode EXCHANGE_ID response
@@ -6066,6 +6317,34 @@ static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
 out:
        return status;
 }
+
+/*
+ * Decode LAYOUTCOMMIT response
+ */
+static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
+                                    struct xdr_stream *xdr,
+                                    struct nfs4_layoutcommit_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status)
+               goto out;
+       status = decode_layoutcommit(xdr, rqstp, res);
+       if (status)
+               goto out;
+       decode_getfattr(xdr, res->fattr, res->server,
+                       !RPC_IS_ASYNC(rqstp->rq_task));
+out:
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /**
@@ -6180,10 +6459,6 @@ static struct {
        { NFS4ERR_SYMLINK,      -ELOOP          },
        { NFS4ERR_OP_ILLEGAL,   -EOPNOTSUPP     },
        { NFS4ERR_DEADLOCK,     -EDEADLK        },
-       { NFS4ERR_WRONGSEC,     -EPERM          }, /* FIXME: this needs
-                                                   * to be handled by a
-                                                   * middle-layer.
-                                                   */
        { -1,                   -EIO            }
 };
 
@@ -6258,6 +6533,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(SETACL,            enc_setacl,             dec_setacl),
        PROC(FS_LOCATIONS,      enc_fs_locations,       dec_fs_locations),
        PROC(RELEASE_LOCKOWNER, enc_release_lockowner,  dec_release_lockowner),
+       PROC(SECINFO,           enc_secinfo,            dec_secinfo),
 #if defined(CONFIG_NFS_V4_1)
        PROC(EXCHANGE_ID,       enc_exchange_id,        dec_exchange_id),
        PROC(CREATE_SESSION,    enc_create_session,     dec_create_session),
@@ -6267,6 +6543,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
        PROC(RECLAIM_COMPLETE,  enc_reclaim_complete,   dec_reclaim_complete),
        PROC(GETDEVICEINFO,     enc_getdeviceinfo,      dec_getdeviceinfo),
        PROC(LAYOUTGET,         enc_layoutget,          dec_layoutget),
+       PROC(LAYOUTCOMMIT,      enc_layoutcommit,       dec_layoutcommit),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index 23e7944106692a99a15118667a7d21820de3c1be..87a593c2b055503e727c2cda93a396ecb2681fb5 100644 (file)
@@ -223,6 +223,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_count = 0;
        desc->pg_bsize = bsize;
        desc->pg_base = 0;
+       desc->pg_moreio = 0;
        desc->pg_inode = inode;
        desc->pg_doio = doio;
        desc->pg_ioflags = io_flags;
@@ -335,9 +336,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                           struct nfs_page *req)
 {
        while (!nfs_pageio_do_add_request(desc, req)) {
+               desc->pg_moreio = 1;
                nfs_pageio_doio(desc);
                if (desc->pg_error < 0)
                        return 0;
+               desc->pg_moreio = 0;
        }
        return 1;
 }
@@ -395,6 +398,7 @@ int nfs_scan_list(struct nfs_inode *nfsi,
        pgoff_t idx_end;
        int found, i;
        int res;
+       struct list_head *list;
 
        res = 0;
        if (npages == 0)
@@ -415,10 +419,10 @@ int nfs_scan_list(struct nfs_inode *nfsi,
                        idx_start = req->wb_index + 1;
                        if (nfs_set_page_tag_locked(req)) {
                                kref_get(&req->wb_kref);
-                               nfs_list_remove_request(req);
                                radix_tree_tag_clear(&nfsi->nfs_page_tree,
                                                req->wb_index, tag);
-                               nfs_list_add_request(req, dst);
+                               list = pnfs_choose_commit_list(req, dst);
+                               nfs_list_add_request(req, list);
                                res++;
                                if (res == INT_MAX)
                                        goto out;
index f38813a0a295929e3fb8abb0ebe6b109f11571ed..d9ab97269ce6e83c2fbd652fddebb789f761a271 100644 (file)
@@ -259,6 +259,7 @@ put_lseg(struct pnfs_layout_segment *lseg)
                pnfs_free_lseg_list(&free_me);
        }
 }
+EXPORT_SYMBOL_GPL(put_lseg);
 
 static bool
 should_free_lseg(u32 lseg_iomode, u32 recall_iomode)
@@ -471,6 +472,9 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs4_layoutget *lgp;
        struct pnfs_layout_segment *lseg = NULL;
+       struct page **pages = NULL;
+       int i;
+       u32 max_resp_sz, max_pages;
 
        dprintk("--> %s\n", __func__);
 
@@ -478,6 +482,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp = kzalloc(sizeof(*lgp), GFP_KERNEL);
        if (lgp == NULL)
                return NULL;
+
+       /* allocate pages for xdr post processing */
+       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       max_pages = max_resp_sz >> PAGE_SHIFT;
+
+       pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL);
+       if (!pages)
+               goto out_err_free;
+
+       for (i = 0; i < max_pages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL);
+               if (!pages[i])
+                       goto out_err_free;
+       }
+
        lgp->args.minlength = NFS4_MAX_UINT64;
        lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
        lgp->args.range.iomode = iomode;
@@ -486,6 +505,8 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
+       lgp->args.layout.pages = pages;
+       lgp->args.layout.pglen = max_pages * PAGE_SIZE;
        lgp->lsegpp = &lseg;
 
        /* Synchronously retrieve layout information from server and
@@ -496,7 +517,26 @@ send_layoutget(struct pnfs_layout_hdr *lo,
                /* remember that LAYOUTGET failed and suspend trying */
                set_bit(lo_fail_bit(iomode), &lo->plh_flags);
        }
+
+       /* free xdr pages */
+       for (i = 0; i < max_pages; i++)
+               __free_page(pages[i]);
+       kfree(pages);
+
        return lseg;
+
+out_err_free:
+       /* free any allocated xdr pages, lgp as it's not used */
+       if (pages) {
+               for (i = 0; i < max_pages; i++) {
+                       if (!pages[i])
+                               break;
+                       __free_page(pages[i]);
+               }
+               kfree(pages);
+       }
+       kfree(lgp);
+       return NULL;
 }
 
 bool pnfs_roc(struct inode *ino)
@@ -945,3 +985,105 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
        dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
        return trypnfs;
 }
+
+/*
+ * Currently there is only one (whole file) write lseg.
+ */
+static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode)
+{
+       struct pnfs_layout_segment *lseg, *rv = NULL;
+
+       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
+               if (lseg->pls_range.iomode == IOMODE_RW)
+                       rv = lseg;
+       return rv;
+}
+
+void
+pnfs_set_layoutcommit(struct nfs_write_data *wdata)
+{
+       struct nfs_inode *nfsi = NFS_I(wdata->inode);
+       loff_t end_pos = wdata->args.offset + wdata->res.count;
+
+       spin_lock(&nfsi->vfs_inode.i_lock);
+       if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
+               /* references matched in nfs4_layoutcommit_release */
+               get_lseg(wdata->lseg);
+               wdata->lseg->pls_lc_cred =
+                       get_rpccred(wdata->args.context->state->owner->so_cred);
+               mark_inode_dirty_sync(wdata->inode);
+               dprintk("%s: Set layoutcommit for inode %lu ",
+                       __func__, wdata->inode->i_ino);
+       }
+       if (end_pos > wdata->lseg->pls_end_pos)
+               wdata->lseg->pls_end_pos = end_pos;
+       spin_unlock(&nfsi->vfs_inode.i_lock);
+}
+EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
+
+/*
+ * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
+ * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
+ * data to disk to allow the server to recover the data if it crashes.
+ * LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag
+ * is off, and a COMMIT is sent to a data server, or
+ * if WRITEs to a data server return NFS_DATA_SYNC.
+ */
+int
+pnfs_layoutcommit_inode(struct inode *inode, bool sync)
+{
+       struct nfs4_layoutcommit_data *data;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct pnfs_layout_segment *lseg;
+       struct rpc_cred *cred;
+       loff_t end_pos;
+       int status = 0;
+
+       dprintk("--> %s inode %lu\n", __func__, inode->i_ino);
+
+       if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+               return 0;
+
+       /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
+       data = kzalloc(sizeof(*data), GFP_NOFS);
+       if (!data) {
+               mark_inode_dirty_sync(inode);
+               status = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock(&inode->i_lock);
+       if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
+               spin_unlock(&inode->i_lock);
+               kfree(data);
+               goto out;
+       }
+       /*
+        * Currently only one (whole file) write lseg which is referenced
+        * in pnfs_set_layoutcommit and will be found.
+        */
+       lseg = pnfs_list_write_lseg(inode);
+
+       end_pos = lseg->pls_end_pos;
+       cred = lseg->pls_lc_cred;
+       lseg->pls_end_pos = 0;
+       lseg->pls_lc_cred = NULL;
+
+       memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
+               sizeof(nfsi->layout->plh_stateid.data));
+       spin_unlock(&inode->i_lock);
+
+       data->args.inode = inode;
+       data->lseg = lseg;
+       data->cred = cred;
+       nfs_fattr_init(&data->fattr);
+       data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
+       data->res.fattr = &data->fattr;
+       data->args.lastbytewritten = end_pos - 1;
+       data->res.server = NFS_SERVER(inode);
+
+       status = nfs4_proc_layoutcommit(data, sync);
+out:
+       dprintk("<-- %s status %d\n", __func__, status);
+       return status;
+}
index 6380b9405bcde5ac02137cf455b2e88d6bed8d6e..bc4827202e7a2c862ae628c1e27b0bae48a9a93d 100644 (file)
@@ -43,6 +43,8 @@ struct pnfs_layout_segment {
        atomic_t pls_refcount;
        unsigned long pls_flags;
        struct pnfs_layout_hdr *pls_layout;
+       struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
+       loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
 };
 
 enum pnfs_try_status {
@@ -74,6 +76,13 @@ struct pnfs_layoutdriver_type {
        /* test for nfs page cache coalescing */
        int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
 
+       /* Returns true if layoutdriver wants to divert this request to
+        * driver's commit routine.
+        */
+       bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
+       struct list_head * (*choose_commit_list) (struct nfs_page *req);
+       int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
+
        /*
         * Return PNFS_ATTEMPTED to indicate the layout code has attempted
         * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
@@ -100,7 +109,6 @@ struct pnfs_device {
        unsigned int  layout_type;
        unsigned int  mincount;
        struct page **pages;
-       void          *area;
        unsigned int  pgbase;
        unsigned int  pglen;
 };
@@ -145,7 +153,8 @@ bool pnfs_roc(struct inode *ino);
 void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
 bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
-
+void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
+int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
 
 static inline int lo_fail_bit(u32 iomode)
 {
@@ -169,6 +178,51 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
        return nfss->pnfs_curr_ld != NULL;
 }
 
+static inline void
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+{
+       if (lseg) {
+               struct pnfs_layoutdriver_type *ld;
+
+               ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
+               if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
+                       set_bit(PG_PNFS_COMMIT, &req->wb_flags);
+                       req->wb_commit_lseg = get_lseg(lseg);
+               }
+       }
+}
+
+static inline int
+pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
+{
+       if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags))
+               return PNFS_NOT_ATTEMPTED;
+       return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
+}
+
+static inline struct list_head *
+pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+{
+       struct list_head *rv;
+
+       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
+               struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
+
+               set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
+               rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
+               /* matched by ref taken when PG_PNFS_COMMIT is set */
+               put_lseg(req->wb_commit_lseg);
+       } else
+               rv = mds;
+       return rv;
+}
+
+static inline void pnfs_clear_request_commit(struct nfs_page *req)
+{
+       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
+               put_lseg(req->wb_commit_lseg);
+}
+
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -252,6 +306,31 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
        pgio->pg_test = NULL;
 }
 
+static inline void
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+{
+}
+
+static inline int
+pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
+{
+       return PNFS_NOT_ATTEMPTED;
+}
+
+static inline struct list_head *
+pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+{
+       return mds;
+}
+
+static inline void pnfs_clear_request_commit(struct nfs_page *req)
+{
+}
+
+static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
+{
+       return 0;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */
index b8ec170f2a0f97f480b501ffe17dc68978167aaf..ac40b8535d7e0e7493f13063afdbe57169837c9e 100644 (file)
@@ -177,7 +177,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 }
 
 static int
-nfs_proc_lookup(struct inode *dir, struct qstr *name,
+nfs_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
                struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        struct nfs_diropargs    arg = {
index 47a3ad63e0d573b1211560bc20f5e7fe612d74fb..85d75254328ebd1c822187e51a3f5b5e9fc320b7 100644 (file)
@@ -59,6 +59,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void)
        }
        return p;
 }
+EXPORT_SYMBOL_GPL(nfs_commitdata_alloc);
 
 void nfs_commit_free(struct nfs_write_data *p)
 {
@@ -66,6 +67,7 @@ void nfs_commit_free(struct nfs_write_data *p)
                kfree(p->pagevec);
        mempool_free(p, nfs_commit_mempool);
 }
+EXPORT_SYMBOL_GPL(nfs_commit_free);
 
 struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
 {
@@ -179,8 +181,8 @@ static int wb_priority(struct writeback_control *wbc)
        if (wbc->for_reclaim)
                return FLUSH_HIGHPRI | FLUSH_STABLE;
        if (wbc->for_kupdate || wbc->for_background)
-               return FLUSH_LOWPRI;
-       return 0;
+               return FLUSH_LOWPRI | FLUSH_COND_STABLE;
+       return FLUSH_COND_STABLE;
 }
 
 /*
@@ -441,7 +443,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
  * Add a request to the inode's commit list.
  */
 static void
-nfs_mark_request_commit(struct nfs_page *req)
+nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
        struct inode *inode = req->wb_context->path.dentry->d_inode;
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -453,6 +455,7 @@ nfs_mark_request_commit(struct nfs_page *req)
                        NFS_PAGE_TAG_COMMIT);
        nfsi->ncommit++;
        spin_unlock(&inode->i_lock);
+       pnfs_mark_request_commit(req, lseg);
        inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
        inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
        __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
@@ -474,14 +477,18 @@ nfs_clear_request_commit(struct nfs_page *req)
 static inline
 int nfs_write_need_commit(struct nfs_write_data *data)
 {
-       return data->verf.committed != NFS_FILE_SYNC;
+       if (data->verf.committed == NFS_DATA_SYNC)
+               return data->lseg == NULL;
+       else
+               return data->verf.committed != NFS_FILE_SYNC;
 }
 
 static inline
-int nfs_reschedule_unstable_write(struct nfs_page *req)
+int nfs_reschedule_unstable_write(struct nfs_page *req,
+                                 struct nfs_write_data *data)
 {
        if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
-               nfs_mark_request_commit(req);
+               nfs_mark_request_commit(req, data->lseg);
                return 1;
        }
        if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) {
@@ -492,7 +499,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
 }
 #else
 static inline void
-nfs_mark_request_commit(struct nfs_page *req)
+nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
 }
 
@@ -509,7 +516,8 @@ int nfs_write_need_commit(struct nfs_write_data *data)
 }
 
 static inline
-int nfs_reschedule_unstable_write(struct nfs_page *req)
+int nfs_reschedule_unstable_write(struct nfs_page *req,
+                                 struct nfs_write_data *data)
 {
        return 0;
 }
@@ -612,9 +620,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
        }
 
        if (nfs_clear_request_commit(req) &&
-                       radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
-                               req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL)
+           radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
+                                req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
                NFS_I(inode)->ncommit--;
+               pnfs_clear_request_commit(req);
+       }
 
        /* Okay, the request matches. Update the region */
        if (offset < req->wb_offset) {
@@ -762,11 +772,12 @@ int nfs_updatepage(struct file *file, struct page *page,
        return status;
 }
 
-static void nfs_writepage_release(struct nfs_page *req)
+static void nfs_writepage_release(struct nfs_page *req,
+                                 struct nfs_write_data *data)
 {
        struct page *page = req->wb_page;
 
-       if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req))
+       if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
                nfs_inode_remove_request(req);
        nfs_clear_page_tag_locked(req);
        nfs_end_page_writeback(page);
@@ -863,7 +874,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
        data->args.context = get_nfs_open_context(req->wb_context);
        data->args.lock_context = req->wb_lock_context;
        data->args.stable  = NFS_UNSTABLE;
-       if (how & FLUSH_STABLE) {
+       if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
                data->args.stable = NFS_DATA_SYNC;
                if (!nfs_need_commit(NFS_I(inode)))
                        data->args.stable = NFS_FILE_SYNC;
@@ -912,6 +923,12 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
 
        nfs_list_remove_request(req);
 
+       if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
+           (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit ||
+            desc->pg_count > wsize))
+               desc->pg_ioflags &= ~FLUSH_COND_STABLE;
+
+
        nbytes = desc->pg_count;
        do {
                size_t len = min(nbytes, wsize);
@@ -1002,6 +1019,10 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
        if ((!lseg) && list_is_singular(&data->pages))
                lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW);
 
+       if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
+           (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
+               desc->pg_ioflags &= ~FLUSH_COND_STABLE;
+
        /* Set up the argument struct */
        ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags);
 out:
@@ -1074,7 +1095,7 @@ static void nfs_writeback_release_partial(void *calldata)
 
 out:
        if (atomic_dec_and_test(&req->wb_complete))
-               nfs_writepage_release(req);
+               nfs_writepage_release(req, data);
        nfs_writedata_release(calldata);
 }
 
@@ -1141,7 +1162,7 @@ static void nfs_writeback_release_full(void *calldata)
 
                if (nfs_write_need_commit(data)) {
                        memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
-                       nfs_mark_request_commit(req);
+                       nfs_mark_request_commit(req, data->lseg);
                        dprintk(" marked for commit\n");
                        goto next;
                }
@@ -1251,57 +1272,82 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait)
 {
+       int ret;
+
        if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags))
                return 1;
-       if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags,
-                               NFS_INO_COMMIT, nfs_wait_bit_killable,
-                               TASK_KILLABLE))
-               return 1;
-       return 0;
+       if (!may_wait)
+               return 0;
+       ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
+                               NFS_INO_COMMIT,
+                               nfs_wait_bit_killable,
+                               TASK_KILLABLE);
+       return (ret < 0) ? ret : 1;
 }
 
-static void nfs_commit_clear_lock(struct nfs_inode *nfsi)
+void nfs_commit_clear_lock(struct nfs_inode *nfsi)
 {
        clear_bit(NFS_INO_COMMIT, &nfsi->flags);
        smp_mb__after_clear_bit();
        wake_up_bit(&nfsi->flags, NFS_INO_COMMIT);
 }
+EXPORT_SYMBOL_GPL(nfs_commit_clear_lock);
 
-
-static void nfs_commitdata_release(void *data)
+void nfs_commitdata_release(void *data)
 {
        struct nfs_write_data *wdata = data;
 
+       put_lseg(wdata->lseg);
        put_nfs_open_context(wdata->args.context);
        nfs_commit_free(wdata);
 }
+EXPORT_SYMBOL_GPL(nfs_commitdata_release);
 
-/*
- * Set up the argument/result storage required for the RPC call.
- */
-static int nfs_commit_rpcsetup(struct list_head *head,
-               struct nfs_write_data *data,
-               int how)
+int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt,
+                       const struct rpc_call_ops *call_ops,
+                       int how)
 {
-       struct nfs_page *first = nfs_list_entry(head->next);
-       struct inode *inode = first->wb_context->path.dentry->d_inode;
-       int priority = flush_task_priority(how);
        struct rpc_task *task;
+       int priority = flush_task_priority(how);
        struct rpc_message msg = {
                .rpc_argp = &data->args,
                .rpc_resp = &data->res,
-               .rpc_cred = first->wb_context->cred,
+               .rpc_cred = data->cred,
        };
        struct rpc_task_setup task_setup_data = {
                .task = &data->task,
-               .rpc_client = NFS_CLIENT(inode),
+               .rpc_client = clnt,
                .rpc_message = &msg,
-               .callback_ops = &nfs_commit_ops,
+               .callback_ops = call_ops,
                .callback_data = data,
                .workqueue = nfsiod_workqueue,
                .flags = RPC_TASK_ASYNC,
                .priority = priority,
        };
+       /* Set up the initial task struct.  */
+       NFS_PROTO(data->inode)->commit_setup(data, &msg);
+
+       dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
+
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       if (how & FLUSH_SYNC)
+               rpc_wait_for_completion_task(task);
+       rpc_put_task(task);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nfs_initiate_commit);
+
+/*
+ * Set up the argument/result storage required for the RPC call.
+ */
+void nfs_init_commit(struct nfs_write_data *data,
+                           struct list_head *head,
+                           struct pnfs_layout_segment *lseg)
+{
+       struct nfs_page *first = nfs_list_entry(head->next);
+       struct inode *inode = first->wb_context->path.dentry->d_inode;
 
        /* Set up the RPC argument and reply structs
         * NB: take care not to mess about with data->commit et al. */
@@ -1309,7 +1355,9 @@ static int nfs_commit_rpcsetup(struct list_head *head,
        list_splice_init(head, &data->pages);
 
        data->inode       = inode;
-       data->cred        = msg.rpc_cred;
+       data->cred        = first->wb_context->cred;
+       data->lseg        = lseg; /* reference transferred */
+       data->mds_ops     = &nfs_commit_ops;
 
        data->args.fh     = NFS_FH(data->inode);
        /* Note: we always request a commit of the entire inode */
@@ -1320,20 +1368,25 @@ static int nfs_commit_rpcsetup(struct list_head *head,
        data->res.fattr   = &data->fattr;
        data->res.verf    = &data->verf;
        nfs_fattr_init(&data->fattr);
+}
+EXPORT_SYMBOL_GPL(nfs_init_commit);
 
-       /* Set up the initial task struct.  */
-       NFS_PROTO(inode)->commit_setup(data, &msg);
-
-       dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
+void nfs_retry_commit(struct list_head *page_list,
+                     struct pnfs_layout_segment *lseg)
+{
+       struct nfs_page *req;
 
-       task = rpc_run_task(&task_setup_data);
-       if (IS_ERR(task))
-               return PTR_ERR(task);
-       if (how & FLUSH_SYNC)
-               rpc_wait_for_completion_task(task);
-       rpc_put_task(task);
-       return 0;
+       while (!list_empty(page_list)) {
+               req = nfs_list_entry(page_list->next);
+               nfs_list_remove_request(req);
+               nfs_mark_request_commit(req, lseg);
+               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+               dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
+                            BDI_RECLAIMABLE);
+               nfs_clear_page_tag_locked(req);
+       }
 }
+EXPORT_SYMBOL_GPL(nfs_retry_commit);
 
 /*
  * Commit dirty pages
@@ -1342,7 +1395,6 @@ static int
 nfs_commit_list(struct inode *inode, struct list_head *head, int how)
 {
        struct nfs_write_data   *data;
-       struct nfs_page         *req;
 
        data = nfs_commitdata_alloc();
 
@@ -1350,17 +1402,10 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
                goto out_bad;
 
        /* Set up the argument struct */
-       return nfs_commit_rpcsetup(head, data, how);
+       nfs_init_commit(data, head, NULL);
+       return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how);
  out_bad:
-       while (!list_empty(head)) {
-               req = nfs_list_entry(head->next);
-               nfs_list_remove_request(req);
-               nfs_mark_request_commit(req);
-               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
-               dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
-                               BDI_RECLAIMABLE);
-               nfs_clear_page_tag_locked(req);
-       }
+       nfs_retry_commit(head, NULL);
        nfs_commit_clear_lock(NFS_I(inode));
        return -ENOMEM;
 }
@@ -1380,10 +1425,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
                return;
 }
 
-static void nfs_commit_release(void *calldata)
+void nfs_commit_release_pages(struct nfs_write_data *data)
 {
-       struct nfs_write_data   *data = calldata;
-       struct nfs_page         *req;
+       struct nfs_page *req;
        int status = data->task.tk_status;
 
        while (!list_empty(&data->pages)) {
@@ -1417,6 +1461,14 @@ static void nfs_commit_release(void *calldata)
        next:
                nfs_clear_page_tag_locked(req);
        }
+}
+EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
+
+static void nfs_commit_release(void *calldata)
+{
+       struct nfs_write_data *data = calldata;
+
+       nfs_commit_release_pages(data);
        nfs_commit_clear_lock(NFS_I(data->inode));
        nfs_commitdata_release(calldata);
 }
@@ -1433,23 +1485,30 @@ int nfs_commit_inode(struct inode *inode, int how)
 {
        LIST_HEAD(head);
        int may_wait = how & FLUSH_SYNC;
-       int res = 0;
+       int res;
 
-       if (!nfs_commit_set_lock(NFS_I(inode), may_wait))
+       res = nfs_commit_set_lock(NFS_I(inode), may_wait);
+       if (res <= 0)
                goto out_mark_dirty;
        spin_lock(&inode->i_lock);
        res = nfs_scan_commit(inode, &head, 0, 0);
        spin_unlock(&inode->i_lock);
        if (res) {
-               int error = nfs_commit_list(inode, &head, how);
+               int error;
+
+               error = pnfs_commit_list(inode, &head, how);
+               if (error == PNFS_NOT_ATTEMPTED)
+                       error = nfs_commit_list(inode, &head, how);
                if (error < 0)
                        return error;
-               if (may_wait)
-                       wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT,
-                                       nfs_wait_bit_killable,
-                                       TASK_KILLABLE);
-               else
+               if (!may_wait)
                        goto out_mark_dirty;
+               error = wait_on_bit(&NFS_I(inode)->flags,
+                               NFS_INO_COMMIT,
+                               nfs_wait_bit_killable,
+                               TASK_KILLABLE);
+               if (error < 0)
+                       return error;
        } else
                nfs_commit_clear_lock(NFS_I(inode));
        return res;
@@ -1503,7 +1562,22 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
 
 int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       return nfs_commit_unstable_pages(inode, wbc);
+       int ret;
+
+       ret = nfs_commit_unstable_pages(inode, wbc);
+       if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) {
+               int status;
+               bool sync = true;
+
+               if (wbc->sync_mode == WB_SYNC_NONE || wbc->nonblocking ||
+                   wbc->for_background)
+                       sync = false;
+
+               status = pnfs_layoutcommit_inode(inode, sync);
+               if (status < 0)
+                       return status;
+       }
+       return ret;
 }
 
 /*
index 84c27d69d421e494c2c41359f06dd02eb2c32960..ec0f277be7f5d4162bc4f12f6e84de17025b0935 100644 (file)
@@ -117,7 +117,6 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
                 * invoked in contexts where a memory allocation failure is
                 * fatal.  Fortunately this fake ACL is small enough to
                 * construct on the stack. */
-               memset(acl2, 0, sizeof(acl2));
                posix_acl_init(acl2, 4);
 
                /* Insert entries in canonical order: other orders seem
index 8b31e5f8795de8fb520e5f1a0676b60c93530c01..ad000aeb21a2aa85d351b32038f57032cfb8a78e 100644 (file)
@@ -299,7 +299,6 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
 
 #define        EXPORT_HASHBITS         8
 #define        EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
-#define        EXPORT_HASHMASK         (EXPORT_HASHMAX -1)
 
 static struct cache_head *export_table[EXPORT_HASHMAX];
 
index 6d2c397d458b6c9481998711ad1bb406fd6fd79c..55780a22fdbdcc02b0dcfb05bfadb3dc2417347e 100644 (file)
@@ -63,7 +63,6 @@ struct ent {
 
 #define ENT_HASHBITS          8
 #define ENT_HASHMAX           (1 << ENT_HASHBITS)
-#define ENT_HASHMASK          (ENT_HASHMAX - 1)
 
 static void
 ent_init(struct cache_head *cnew, struct cache_head *citm)
index db52546143d1290ba8f1510a94b8db0054b45200..5fcb1396a7e324ada8f3cf639f2e6c025ca9a689 100644 (file)
@@ -984,8 +984,8 @@ typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
                              void *);
 enum nfsd4_op_flags {
        ALLOWED_WITHOUT_FH = 1 << 0,    /* No current filehandle required */
-       ALLOWED_ON_ABSENT_FS = 2 << 0,  /* ops processed on absent fs */
-       ALLOWED_AS_FIRST_OP = 3 << 0,   /* ops reqired first in compound */
+       ALLOWED_ON_ABSENT_FS = 1 << 1,  /* ops processed on absent fs */
+       ALLOWED_AS_FIRST_OP = 1 << 2,   /* ops reqired first in compound */
 };
 
 struct nfsd4_operation {
index 7b566ec14e1833cac3f7c61d5ab6b5bb169e3abb..fbde6f79922ed0ce13ee9b97074ffcfce9555508 100644 (file)
@@ -148,7 +148,7 @@ static struct list_head     ownerstr_hashtbl[OWNER_HASH_SIZE];
 /* hash table for nfs4_file */
 #define FILE_HASH_BITS                   8
 #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
-#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)
+
 /* hash table for (open)nfs4_stateid */
 #define STATEID_HASH_BITS              10
 #define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)
@@ -316,64 +316,6 @@ static struct list_head    unconf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head client_lru;
 static struct list_head close_lru;
 
-static void unhash_generic_stateid(struct nfs4_stateid *stp)
-{
-       list_del(&stp->st_hash);
-       list_del(&stp->st_perfile);
-       list_del(&stp->st_perstateowner);
-}
-
-static void free_generic_stateid(struct nfs4_stateid *stp)
-{
-       put_nfs4_file(stp->st_file);
-       kmem_cache_free(stateid_slab, stp);
-}
-
-static void release_lock_stateid(struct nfs4_stateid *stp)
-{
-       struct file *file;
-
-       unhash_generic_stateid(stp);
-       file = find_any_file(stp->st_file);
-       if (file)
-               locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
-       free_generic_stateid(stp);
-}
-
-static void unhash_lockowner(struct nfs4_stateowner *sop)
-{
-       struct nfs4_stateid *stp;
-
-       list_del(&sop->so_idhash);
-       list_del(&sop->so_strhash);
-       list_del(&sop->so_perstateid);
-       while (!list_empty(&sop->so_stateids)) {
-               stp = list_first_entry(&sop->so_stateids,
-                               struct nfs4_stateid, st_perstateowner);
-               release_lock_stateid(stp);
-       }
-}
-
-static void release_lockowner(struct nfs4_stateowner *sop)
-{
-       unhash_lockowner(sop);
-       nfs4_put_stateowner(sop);
-}
-
-static void
-release_stateid_lockowners(struct nfs4_stateid *open_stp)
-{
-       struct nfs4_stateowner *lock_sop;
-
-       while (!list_empty(&open_stp->st_lockowners)) {
-               lock_sop = list_entry(open_stp->st_lockowners.next,
-                               struct nfs4_stateowner, so_perstateid);
-               /* list_del(&open_stp->st_lockowners);  */
-               BUG_ON(lock_sop->so_is_open_owner);
-               release_lockowner(lock_sop);
-       }
-}
-
 /*
  * We store the NONE, READ, WRITE, and BOTH bits separately in the
  * st_{access,deny}_bmap field of the stateid, in order to track not
@@ -446,13 +388,71 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
        return nfs4_access_to_omode(access);
 }
 
-static void release_open_stateid(struct nfs4_stateid *stp)
+static void unhash_generic_stateid(struct nfs4_stateid *stp)
+{
+       list_del(&stp->st_hash);
+       list_del(&stp->st_perfile);
+       list_del(&stp->st_perstateowner);
+}
+
+static void free_generic_stateid(struct nfs4_stateid *stp)
 {
        int oflag = nfs4_access_bmap_to_omode(stp);
 
+       nfs4_file_put_access(stp->st_file, oflag);
+       put_nfs4_file(stp->st_file);
+       kmem_cache_free(stateid_slab, stp);
+}
+
+static void release_lock_stateid(struct nfs4_stateid *stp)
+{
+       struct file *file;
+
+       unhash_generic_stateid(stp);
+       file = find_any_file(stp->st_file);
+       if (file)
+               locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
+       free_generic_stateid(stp);
+}
+
+static void unhash_lockowner(struct nfs4_stateowner *sop)
+{
+       struct nfs4_stateid *stp;
+
+       list_del(&sop->so_idhash);
+       list_del(&sop->so_strhash);
+       list_del(&sop->so_perstateid);
+       while (!list_empty(&sop->so_stateids)) {
+               stp = list_first_entry(&sop->so_stateids,
+                               struct nfs4_stateid, st_perstateowner);
+               release_lock_stateid(stp);
+       }
+}
+
+static void release_lockowner(struct nfs4_stateowner *sop)
+{
+       unhash_lockowner(sop);
+       nfs4_put_stateowner(sop);
+}
+
+static void
+release_stateid_lockowners(struct nfs4_stateid *open_stp)
+{
+       struct nfs4_stateowner *lock_sop;
+
+       while (!list_empty(&open_stp->st_lockowners)) {
+               lock_sop = list_entry(open_stp->st_lockowners.next,
+                               struct nfs4_stateowner, so_perstateid);
+               /* list_del(&open_stp->st_lockowners);  */
+               BUG_ON(lock_sop->so_is_open_owner);
+               release_lockowner(lock_sop);
+       }
+}
+
+static void release_open_stateid(struct nfs4_stateid *stp)
+{
        unhash_generic_stateid(stp);
        release_stateid_lockowners(stp);
-       nfs4_file_put_access(stp->st_file, oflag);
        free_generic_stateid(stp);
 }
 
@@ -608,7 +608,8 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4
        u32 maxrpc = nfsd_serv->sv_max_mesg;
 
        new->maxreqs = numslots;
-       new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
+       new->maxresp_cached = min_t(u32, req->maxresp_cached,
+                                       slotsize + NFSD_MIN_HDR_SEQ_SZ);
        new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
        new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
        new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
@@ -3735,6 +3736,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
+       stp->st_access_bmap = 0;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
        stp->st_openstp = open_stp;
 
@@ -3749,6 +3751,17 @@ check_lock_length(u64 offset, u64 length)
             LOFF_OVERFLOW(offset, length)));
 }
 
+static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access)
+{
+       struct nfs4_file *fp = lock_stp->st_file;
+       int oflag = nfs4_access_to_omode(access);
+
+       if (test_bit(access, &lock_stp->st_access_bmap))
+               return;
+       nfs4_file_get_access(fp, oflag);
+       __set_bit(access, &lock_stp->st_access_bmap);
+}
+
 /*
  *  LOCK operation 
  */
@@ -3765,7 +3778,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock conflock;
        __be32 status = 0;
        unsigned int strhashval;
-       unsigned int cmd;
        int err;
 
        dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -3847,22 +3859,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (lock->lk_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
-                       if (find_readable_file(lock_stp->st_file)) {
-                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ);
-                               filp = find_readable_file(lock_stp->st_file);
-                       }
+                       filp = find_readable_file(lock_stp->st_file);
+                       if (filp)
+                               get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
                        file_lock.fl_type = F_RDLCK;
-                       cmd = F_SETLK;
-               break;
+                       break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
-                       if (find_writeable_file(lock_stp->st_file)) {
-                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE);
-                               filp = find_writeable_file(lock_stp->st_file);
-                       }
+                       filp = find_writeable_file(lock_stp->st_file);
+                       if (filp)
+                               get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
                        file_lock.fl_type = F_WRLCK;
-                       cmd = F_SETLK;
-               break;
+                       break;
                default:
                        status = nfserr_inval;
                goto out;
@@ -3886,7 +3894,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        * Note: locks.c uses the BKL to protect the inode's lock list.
        */
 
-       err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
+       err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
        switch (-err) {
        case 0: /* success! */
                update_stateid(&lock_stp->st_stateid);
index 615f0a9f06008e54ceda4ff4804b295fdf3a8b13..c6766af00d983ec2573266b6592f62fc2f8ba1c9 100644 (file)
@@ -1142,7 +1142,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
 
        u32 dummy;
        char *machine_name;
-       int i, j;
+       int i;
        int nr_secflavs;
 
        READ_BUF(16);
@@ -1215,8 +1215,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
                        READ_BUF(4);
                        READ32(dummy);
                        READ_BUF(dummy * 4);
-                       for (j = 0; j < dummy; ++j)
-                               READ32(dummy);
                        break;
                case RPC_AUTH_GSS:
                        dprintk("RPC_AUTH_GSS callback secflavor "
@@ -1232,7 +1230,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
                        READ_BUF(4);
                        READ32(dummy);
                        READ_BUF(dummy);
-                       p += XDR_QUADLEN(dummy);
                        break;
                default:
                        dprintk("Illegal callback secflavor\n");
index 33b3e2b06779da530630fbb43800b3587c2728d9..1f5eae40f34ef4aa57174be24445a39854906e71 100644 (file)
 #include <linux/nfsd/syscall.h>
 #include <linux/lockd/lockd.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/gss_api.h>
 
 #include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
 
 /*
- *     We have a single directory with 9 nodes in it.
+ *     We have a single directory with several nodes in it.
  */
 enum {
        NFSD_Root = 1,
@@ -42,6 +43,7 @@ enum {
        NFSD_Versions,
        NFSD_Ports,
        NFSD_MaxBlkSize,
+       NFSD_SupportedEnctypes,
        /*
         * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
         * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -187,6 +189,34 @@ static struct file_operations export_features_operations = {
        .release        = single_release,
 };
 
+#ifdef CONFIG_SUNRPC_GSS
+static int supported_enctypes_show(struct seq_file *m, void *v)
+{
+       struct gss_api_mech *k5mech;
+
+       k5mech = gss_mech_get_by_name("krb5");
+       if (k5mech == NULL)
+               goto out;
+       if (k5mech->gm_upcall_enctypes != NULL)
+               seq_printf(m, k5mech->gm_upcall_enctypes);
+       gss_mech_put(k5mech);
+out:
+       return 0;
+}
+
+static int supported_enctypes_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, supported_enctypes_show, NULL);
+}
+
+static struct file_operations supported_enctypes_ops = {
+       .open           = supported_enctypes_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif /* CONFIG_SUNRPC_GSS */
+
 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
 extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
 
@@ -1397,6 +1427,9 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
                [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
+#ifdef CONFIG_SUNRPC_GSS
+               [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
+#endif /* CONFIG_SUNRPC_GSS */
 #ifdef CONFIG_NFSD_V4
                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
index 2d31224b07bfa1fb43ea9eff05c31938bc6ebe7d..6bd2f3c21f2b7195b355be089084bc8222176a45 100644 (file)
@@ -367,16 +367,12 @@ struct nfs4_file {
        struct list_head        fi_delegations;
        /* One each for O_RDONLY, O_WRONLY, O_RDWR: */
        struct file *           fi_fds[3];
-       /* One each for O_RDONLY, O_WRONLY: */
-       atomic_t                fi_access[2];
        /*
-        * Each open stateid contributes 1 to either fi_readers or
-        * fi_writers, or both, depending on the open mode.  A
-        * delegation also takes an fi_readers reference.  Lock
-        * stateid's take none.
+        * Each open or lock stateid contributes 1 to either
+        * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending
+        * on open or lock mode:
         */
-       atomic_t                fi_readers;
-       atomic_t                fi_writers;
+       atomic_t                fi_access[2];
        struct file             *fi_deleg_file;
        struct file_lock        *fi_lease;
        atomic_t                fi_delegees;
index ff93025ae2f7ccdfe2740933c96e293a10b8ab31..2e1cebde90df4c69baa21635e959f9d81c9809f1 100644 (file)
@@ -1749,8 +1749,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
                if (host_err)
                        goto out_drop_write;
        }
-       if (host_err)
-               goto out_drop_write;
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
index d7fd696e595ccdcb67f42e7a1d9b9e21f6dec3dc..0a0a66d98cce85f327b32080c8a97045e8babdf7 100644 (file)
@@ -521,8 +521,8 @@ void nilfs_palloc_commit_free_entry(struct inode *inode,
                                    group_offset, bitmap))
                printk(KERN_WARNING "%s: entry number %llu already freed\n",
                       __func__, (unsigned long long)req->pr_entry_nr);
-
-       nilfs_palloc_group_desc_add_entries(inode, group, desc, 1);
+       else
+               nilfs_palloc_group_desc_add_entries(inode, group, desc, 1);
 
        kunmap(req->pr_bitmap_bh->b_page);
        kunmap(req->pr_desc_bh->b_page);
@@ -558,8 +558,8 @@ void nilfs_palloc_abort_alloc_entry(struct inode *inode,
                                    group_offset, bitmap))
                printk(KERN_WARNING "%s: entry number %llu already freed\n",
                       __func__, (unsigned long long)req->pr_entry_nr);
-
-       nilfs_palloc_group_desc_add_entries(inode, group, desc, 1);
+       else
+               nilfs_palloc_group_desc_add_entries(inode, group, desc, 1);
 
        kunmap(req->pr_bitmap_bh->b_page);
        kunmap(req->pr_desc_bh->b_page);
@@ -665,7 +665,7 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
                for (j = i, n = 0;
                     (j < nitems) && nilfs_palloc_group_is_in(inode, group,
                                                              entry_nrs[j]);
-                    j++, n++) {
+                    j++) {
                        nilfs_palloc_group(inode, entry_nrs[j], &group_offset);
                        if (!nilfs_clear_bit_atomic(
                                    nilfs_mdt_bgl_lock(inode, group),
@@ -674,6 +674,8 @@ int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
                                       "%s: entry number %llu already freed\n",
                                       __func__,
                                       (unsigned long long)entry_nrs[j]);
+                       } else {
+                               n++;
                        }
                }
                nilfs_palloc_group_desc_add_entries(inode, group, desc, n);
index 9af34a7e6e13e1ba17e660a3b1f0fb767b484b89..f5fde36b9e28d09f07596d23b127005fcb26384e 100644 (file)
@@ -74,7 +74,7 @@ int nilfs_palloc_freev(struct inode *, __u64 *, size_t);
 
 #define nilfs_set_bit_atomic           ext2_set_bit_atomic
 #define nilfs_clear_bit_atomic         ext2_clear_bit_atomic
-#define nilfs_find_next_zero_bit       ext2_find_next_zero_bit
+#define nilfs_find_next_zero_bit       find_next_zero_bit_le
 
 /*
  * persistent object allocator cache
index 3ee67c67cc52ee5d6d0711023bb2c2ad43c1e32c..4723f04e9b12a0e904f945997b5e1aa73cfc757b 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include "nilfs.h"
 #include "bmap.h"
-#include "sb.h"
 #include "btree.h"
 #include "direct.h"
 #include "btnode.h"
@@ -425,17 +424,6 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *bmap)
 /*
  * Internal use only
  */
-
-void nilfs_bmap_add_blocks(const struct nilfs_bmap *bmap, int n)
-{
-       inode_add_bytes(bmap->b_inode, (1 << bmap->b_inode->i_blkbits) * n);
-}
-
-void nilfs_bmap_sub_blocks(const struct nilfs_bmap *bmap, int n)
-{
-       inode_sub_bytes(bmap->b_inode, (1 << bmap->b_inode->i_blkbits) * n);
-}
-
 __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap,
                              const struct buffer_head *bh)
 {
index bde1c0aa2e15a3a0c3eb9f4071d78dce586f0d17..40d9f453d31c121d29dc09279bfa57ece7d79d7d 100644 (file)
@@ -240,9 +240,6 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *,
 __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64);
 __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *);
 
-void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int);
-void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int);
-
 
 /* Assume that bmap semaphore is locked. */
 static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap)
index 85f7baa15f5dd8fa1eac905b8c8840c73b0294fa..609cd223eea85abf39232688e2ccbd9dad94ee68 100644 (file)
 #include "page.h"
 #include "btnode.h"
 
-
-static const struct address_space_operations def_btnode_aops = {
-       .sync_page              = block_sync_page,
-};
-
 void nilfs_btnode_cache_init(struct address_space *btnc,
                             struct backing_dev_info *bdi)
 {
-       nilfs_mapping_init(btnc, bdi, &def_btnode_aops);
+       nilfs_mapping_init(btnc, bdi);
 }
 
 void nilfs_btnode_cache_clear(struct address_space *btnc)
index 300c2bc00c3f4c29034459d885fa4adf34850c99..d451ae0e0bf373917b88e4591b60f4ad912bc3db 100644 (file)
@@ -1174,7 +1174,7 @@ static int nilfs_btree_insert(struct nilfs_bmap *btree, __u64 key, __u64 ptr)
        if (ret < 0)
                goto out;
        nilfs_btree_commit_insert(btree, path, level, key, ptr);
-       nilfs_bmap_add_blocks(btree, stats.bs_nblocks);
+       nilfs_inode_add_blocks(btree->b_inode, stats.bs_nblocks);
 
  out:
        nilfs_btree_free_path(path);
@@ -1511,7 +1511,7 @@ static int nilfs_btree_delete(struct nilfs_bmap *btree, __u64 key)
        if (ret < 0)
                goto out;
        nilfs_btree_commit_delete(btree, path, level, dat);
-       nilfs_bmap_sub_blocks(btree, stats.bs_nblocks);
+       nilfs_inode_sub_blocks(btree->b_inode, stats.bs_nblocks);
 
 out:
        nilfs_btree_free_path(path);
@@ -1776,7 +1776,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *btree,
                return ret;
        nilfs_btree_commit_convert_and_insert(btree, key, ptr, keys, ptrs, n,
                                              di, ni, bh);
-       nilfs_bmap_add_blocks(btree, stats.bs_nblocks);
+       nilfs_inode_add_blocks(btree->b_inode, stats.bs_nblocks);
        return 0;
 }
 
index 9d45773b79e63f9d7be433ca604caef7fc518cea..3a1923943b14c9300bd8af952451efa86177c09c 100644 (file)
@@ -440,7 +440,6 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
        nilfs_commit_chunk(page, mapping, from, to);
        nilfs_put_page(page);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-/*     NILFS_I(dir)->i_flags &= ~NILFS_BTREE_FL; */
 }
 
 /*
@@ -531,7 +530,6 @@ got_it:
        nilfs_set_de_type(de, inode);
        nilfs_commit_chunk(page, page->mapping, from, to);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-/*     NILFS_I(dir)->i_flags &= ~NILFS_BTREE_FL; */
        nilfs_mark_inode_dirty(dir);
        /* OFFSET_CACHE */
 out_put:
@@ -579,7 +577,6 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
        dir->inode = 0;
        nilfs_commit_chunk(page, mapping, from, to);
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-/*     NILFS_I(inode)->i_flags &= ~NILFS_BTREE_FL; */
 out:
        nilfs_put_page(page);
        return err;
@@ -684,7 +681,7 @@ const struct file_operations nilfs_dir_operations = {
        .readdir        = nilfs_readdir,
        .unlocked_ioctl = nilfs_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl   = nilfs_ioctl,
+       .compat_ioctl   = nilfs_compat_ioctl,
 #endif /* CONFIG_COMPAT */
        .fsync          = nilfs_sync_file,
 
index 324d80c57518ad09a83cab70ee1ca6abfae4d644..82f4865e86dd5de3b33570be200a205c87d95ccf 100644 (file)
@@ -146,7 +146,7 @@ static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
                if (NILFS_BMAP_USE_VBN(bmap))
                        nilfs_bmap_set_target_v(bmap, key, req.bpr_ptr);
 
-               nilfs_bmap_add_blocks(bmap, 1);
+               nilfs_inode_add_blocks(bmap->b_inode, 1);
        }
        return ret;
 }
@@ -168,7 +168,7 @@ static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
        if (!ret) {
                nilfs_bmap_commit_end_ptr(bmap, &req, dat);
                nilfs_direct_set_ptr(bmap, key, NILFS_BMAP_INVALID_PTR);
-               nilfs_bmap_sub_blocks(bmap, 1);
+               nilfs_inode_sub_blocks(bmap->b_inode, 1);
        }
        return ret;
 }
index 2f560c9fb808192cdddad3277c345e04440b1fb6..93589fccdd9744c59d6783931eca235b727d5432 100644 (file)
@@ -59,7 +59,7 @@ static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct nilfs_transaction_info ti;
        int ret;
 
-       if (unlikely(nilfs_near_disk_full(NILFS_SB(inode->i_sb)->s_nilfs)))
+       if (unlikely(nilfs_near_disk_full(inode->i_sb->s_fs_info)))
                return VM_FAULT_SIGBUS; /* -ENOSPC */
 
        lock_page(page);
@@ -142,7 +142,7 @@ const struct file_operations nilfs_file_operations = {
        .aio_write      = generic_file_aio_write,
        .unlocked_ioctl = nilfs_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl   = nilfs_ioctl,
+       .compat_ioctl   = nilfs_compat_ioctl,
 #endif /* CONFIG_COMPAT */
        .mmap           = nilfs_file_mmap,
        .open           = generic_file_open,
index caf9a6a3fb54f0e0dd4cd63ccf103fd6aef20a70..1c2a3e23f8b2dec6b1f895098239864d7f5e9946 100644 (file)
@@ -49,7 +49,6 @@
 #include "ifile.h"
 
 static const struct address_space_operations def_gcinode_aops = {
-       .sync_page              = block_sync_page,
 };
 
 /*
index 2fd440d8d6b8d9b2b469c2aaec757bca05a9ac58..c0aa27490c027f40c40a12951caf38720f0ff417 100644 (file)
@@ -41,6 +41,24 @@ struct nilfs_iget_args {
        int for_gc;
 };
 
+void nilfs_inode_add_blocks(struct inode *inode, int n)
+{
+       struct nilfs_root *root = NILFS_I(inode)->i_root;
+
+       inode_add_bytes(inode, (1 << inode->i_blkbits) * n);
+       if (root)
+               atomic_add(n, &root->blocks_count);
+}
+
+void nilfs_inode_sub_blocks(struct inode *inode, int n)
+{
+       struct nilfs_root *root = NILFS_I(inode)->i_root;
+
+       inode_sub_bytes(inode, (1 << inode->i_blkbits) * n);
+       if (root)
+               atomic_sub(n, &root->blocks_count);
+}
+
 /**
  * nilfs_get_block() - get a file block on the filesystem (callback function)
  * @inode - inode struct of the target file
@@ -262,7 +280,6 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
 const struct address_space_operations nilfs_aops = {
        .writepage              = nilfs_writepage,
        .readpage               = nilfs_readpage,
-       .sync_page              = block_sync_page,
        .writepages             = nilfs_writepages,
        .set_page_dirty         = nilfs_set_page_dirty,
        .readpages              = nilfs_readpages,
@@ -277,7 +294,7 @@ const struct address_space_operations nilfs_aops = {
 struct inode *nilfs_new_inode(struct inode *dir, int mode)
 {
        struct super_block *sb = dir->i_sb;
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct inode *inode;
        struct nilfs_inode_info *ii;
        struct nilfs_root *root;
@@ -315,19 +332,16 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)
                /* No lock is needed; iget() ensures it. */
        }
 
-       ii->i_flags = NILFS_I(dir)->i_flags;
-       if (S_ISLNK(mode))
-               ii->i_flags &= ~(NILFS_IMMUTABLE_FL | NILFS_APPEND_FL);
-       if (!S_ISDIR(mode))
-               ii->i_flags &= ~NILFS_DIRSYNC_FL;
+       ii->i_flags = nilfs_mask_flags(
+               mode, NILFS_I(dir)->i_flags & NILFS_FL_INHERITED);
 
        /* ii->i_file_acl = 0; */
        /* ii->i_dir_acl = 0; */
        ii->i_dir_start_lookup = 0;
        nilfs_set_inode_flags(inode);
-       spin_lock(&sbi->s_next_gen_lock);
-       inode->i_generation = sbi->s_next_generation++;
-       spin_unlock(&sbi->s_next_gen_lock);
+       spin_lock(&nilfs->ns_next_gen_lock);
+       inode->i_generation = nilfs->ns_next_generation++;
+       spin_unlock(&nilfs->ns_next_gen_lock);
        insert_inode_hash(inode);
 
        err = nilfs_init_acl(inode, dir);
@@ -359,17 +373,15 @@ void nilfs_set_inode_flags(struct inode *inode)
 
        inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME |
                            S_DIRSYNC);
-       if (flags & NILFS_SYNC_FL)
+       if (flags & FS_SYNC_FL)
                inode->i_flags |= S_SYNC;
-       if (flags & NILFS_APPEND_FL)
+       if (flags & FS_APPEND_FL)
                inode->i_flags |= S_APPEND;
-       if (flags & NILFS_IMMUTABLE_FL)
+       if (flags & FS_IMMUTABLE_FL)
                inode->i_flags |= S_IMMUTABLE;
-#ifndef NILFS_ATIME_DISABLE
-       if (flags & NILFS_NOATIME_FL)
-#endif
+       if (flags & FS_NOATIME_FL)
                inode->i_flags |= S_NOATIME;
-       if (flags & NILFS_DIRSYNC_FL)
+       if (flags & FS_DIRSYNC_FL)
                inode->i_flags |= S_DIRSYNC;
        mapping_set_gfp_mask(inode->i_mapping,
                             mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
@@ -420,7 +432,7 @@ static int __nilfs_read_inode(struct super_block *sb,
                              struct nilfs_root *root, unsigned long ino,
                              struct inode *inode)
 {
-       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct buffer_head *bh;
        struct nilfs_inode *raw_inode;
        int err;
@@ -707,6 +719,7 @@ void nilfs_evict_inode(struct inode *inode)
        struct nilfs_transaction_info ti;
        struct super_block *sb = inode->i_sb;
        struct nilfs_inode_info *ii = NILFS_I(inode);
+       int ret;
 
        if (inode->i_nlink || !ii->i_root || unlikely(is_bad_inode(inode))) {
                if (inode->i_data.nrpages)
@@ -725,8 +738,9 @@ void nilfs_evict_inode(struct inode *inode)
        nilfs_mark_inode_dirty(inode);
        end_writeback(inode);
 
-       nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino);
-       atomic_dec(&ii->i_root->inodes_count);
+       ret = nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino);
+       if (!ret)
+               atomic_dec(&ii->i_root->inodes_count);
 
        nilfs_clear_inode(inode);
 
@@ -792,18 +806,18 @@ int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
 
 int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_inode_info *ii = NILFS_I(inode);
        int err;
 
-       spin_lock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
        if (ii->i_bh == NULL) {
-               spin_unlock(&sbi->s_inode_lock);
+               spin_unlock(&nilfs->ns_inode_lock);
                err = nilfs_ifile_get_inode_block(ii->i_root->ifile,
                                                  inode->i_ino, pbh);
                if (unlikely(err))
                        return err;
-               spin_lock(&sbi->s_inode_lock);
+               spin_lock(&nilfs->ns_inode_lock);
                if (ii->i_bh == NULL)
                        ii->i_bh = *pbh;
                else {
@@ -814,36 +828,36 @@ int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh)
                *pbh = ii->i_bh;
 
        get_bh(*pbh);
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
        return 0;
 }
 
 int nilfs_inode_dirty(struct inode *inode)
 {
        struct nilfs_inode_info *ii = NILFS_I(inode);
-       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        int ret = 0;
 
        if (!list_empty(&ii->i_dirty)) {
-               spin_lock(&sbi->s_inode_lock);
+               spin_lock(&nilfs->ns_inode_lock);
                ret = test_bit(NILFS_I_DIRTY, &ii->i_state) ||
                        test_bit(NILFS_I_BUSY, &ii->i_state);
-               spin_unlock(&sbi->s_inode_lock);
+               spin_unlock(&nilfs->ns_inode_lock);
        }
        return ret;
 }
 
 int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);
        struct nilfs_inode_info *ii = NILFS_I(inode);
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
 
-       atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks);
+       atomic_add(nr_dirty, &nilfs->ns_ndirtyblks);
 
        if (test_and_set_bit(NILFS_I_DIRTY, &ii->i_state))
                return 0;
 
-       spin_lock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
        if (!test_bit(NILFS_I_QUEUED, &ii->i_state) &&
            !test_bit(NILFS_I_BUSY, &ii->i_state)) {
                /* Because this routine may race with nilfs_dispose_list(),
@@ -851,18 +865,18 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
                if (list_empty(&ii->i_dirty) && igrab(inode) == NULL) {
                        /* This will happen when somebody is freeing
                           this inode. */
-                       nilfs_warning(sbi->s_super, __func__,
+                       nilfs_warning(inode->i_sb, __func__,
                                      "cannot get inode (ino=%lu)\n",
                                      inode->i_ino);
-                       spin_unlock(&sbi->s_inode_lock);
+                       spin_unlock(&nilfs->ns_inode_lock);
                        return -EINVAL; /* NILFS_I_DIRTY may remain for
                                           freeing inode */
                }
                list_del(&ii->i_dirty);
-               list_add_tail(&ii->i_dirty, &sbi->s_dirty_files);
+               list_add_tail(&ii->i_dirty, &nilfs->ns_dirty_files);
                set_bit(NILFS_I_QUEUED, &ii->i_state);
        }
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
        return 0;
 }
 
index 496738963fdbd029aa2a39723442020c5c4d9e93..f2469ba6246bd76458da3ce2b40121dd5f5d7d2b 100644 (file)
@@ -26,7 +26,9 @@
 #include <linux/capability.h>  /* capable() */
 #include <linux/uaccess.h>     /* copy_from_user(), copy_to_user() */
 #include <linux/vmalloc.h>
+#include <linux/compat.h>      /* compat_ptr() */
 #include <linux/mount.h>       /* mnt_want_write(), mnt_drop_write() */
+#include <linux/buffer_head.h>
 #include <linux/nilfs2_fs.h>
 #include "nilfs.h"
 #include "segment.h"
@@ -97,11 +99,74 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
        return ret;
 }
 
+static int nilfs_ioctl_getflags(struct inode *inode, void __user *argp)
+{
+       unsigned int flags = NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE;
+
+       return put_user(flags, (int __user *)argp);
+}
+
+static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
+                               void __user *argp)
+{
+       struct nilfs_transaction_info ti;
+       unsigned int flags, oldflags;
+       int ret;
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (get_user(flags, (int __user *)argp))
+               return -EFAULT;
+
+       ret = mnt_want_write(filp->f_path.mnt);
+       if (ret)
+               return ret;
+
+       flags = nilfs_mask_flags(inode->i_mode, flags);
+
+       mutex_lock(&inode->i_mutex);
+
+       oldflags = NILFS_I(inode)->i_flags;
+
+       /*
+        * The IMMUTABLE and APPEND_ONLY flags can only be changed by the
+        * relevant capability.
+        */
+       ret = -EPERM;
+       if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
+           !capable(CAP_LINUX_IMMUTABLE))
+               goto out;
+
+       ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
+       if (ret)
+               goto out;
+
+       NILFS_I(inode)->i_flags = (oldflags & ~FS_FL_USER_MODIFIABLE) |
+               (flags & FS_FL_USER_MODIFIABLE);
+
+       nilfs_set_inode_flags(inode);
+       inode->i_ctime = CURRENT_TIME;
+       if (IS_SYNC(inode))
+               nilfs_set_transaction_flag(NILFS_TI_SYNC);
+
+       nilfs_mark_inode_dirty(inode);
+       ret = nilfs_transaction_commit(inode->i_sb);
+out:
+       mutex_unlock(&inode->i_mutex);
+       mnt_drop_write(filp->f_path.mnt);
+       return ret;
+}
+
+static int nilfs_ioctl_getversion(struct inode *inode, void __user *argp)
+{
+       return put_user(inode->i_generation, (int __user *)argp);
+}
+
 static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
                                     unsigned int cmd, void __user *argp)
 {
-       struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
-       struct inode *cpfile = nilfs->ns_cpfile;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_transaction_info ti;
        struct nilfs_cpmode cpmode;
        int ret;
@@ -121,7 +186,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
 
        nilfs_transaction_begin(inode->i_sb, &ti, 0);
        ret = nilfs_cpfile_change_cpmode(
-               cpfile, cpmode.cm_cno, cpmode.cm_mode);
+               nilfs->ns_cpfile, cpmode.cm_cno, cpmode.cm_mode);
        if (unlikely(ret < 0))
                nilfs_transaction_abort(inode->i_sb);
        else
@@ -137,7 +202,7 @@ static int
 nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
                              unsigned int cmd, void __user *argp)
 {
-       struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_transaction_info ti;
        __u64 cno;
        int ret;
@@ -154,7 +219,7 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
                goto out;
 
        nilfs_transaction_begin(inode->i_sb, &ti, 0);
-       ret = nilfs_cpfile_delete_checkpoint(cpfile, cno);
+       ret = nilfs_cpfile_delete_checkpoint(nilfs->ns_cpfile, cno);
        if (unlikely(ret < 0))
                nilfs_transaction_abort(inode->i_sb);
        else
@@ -180,7 +245,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
                                  unsigned int cmd, void __user *argp)
 {
-       struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_cpstat cpstat;
        int ret;
 
@@ -211,7 +276,7 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
 static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
                                  unsigned int cmd, void __user *argp)
 {
-       struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_sustat sustat;
        int ret;
 
@@ -267,7 +332,7 @@ nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
 static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
                                  unsigned int cmd, void __user *argp)
 {
-       struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_argv argv;
        int ret;
 
@@ -336,7 +401,7 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb,
                                   struct nilfs_argv *argv, void *buf)
 {
        size_t nmembs = argv->v_nmembs;
-       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct inode *inode;
        struct nilfs_vdesc *vdesc;
        struct buffer_head *bh, *n;
@@ -550,7 +615,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
                ret = PTR_ERR(kbufs[4]);
                goto out;
        }
-       nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+       nilfs = inode->i_sb->s_fs_info;
 
        for (n = 0; n < 4; n++) {
                ret = -EINVAL;
@@ -623,7 +688,7 @@ static int nilfs_ioctl_sync(struct inode *inode, struct file *filp,
                return ret;
 
        if (argp != NULL) {
-               nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+               nilfs = inode->i_sb->s_fs_info;
                down_read(&nilfs->ns_segctor_sem);
                cno = nilfs->ns_cno - 1;
                up_read(&nilfs->ns_segctor_sem);
@@ -641,7 +706,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp,
                                                  void *, size_t, size_t))
 
 {
-       struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct nilfs_argv argv;
        int ret;
 
@@ -666,6 +731,12 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
 
        switch (cmd) {
+       case FS_IOC_GETFLAGS:
+               return nilfs_ioctl_getflags(inode, argp);
+       case FS_IOC_SETFLAGS:
+               return nilfs_ioctl_setflags(inode, filp, argp);
+       case FS_IOC_GETVERSION:
+               return nilfs_ioctl_getversion(inode, argp);
        case NILFS_IOCTL_CHANGE_CPMODE:
                return nilfs_ioctl_change_cpmode(inode, filp, cmd, argp);
        case NILFS_IOCTL_DELETE_CHECKPOINT:
@@ -696,3 +767,23 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return -ENOTTY;
        }
 }
+
+#ifdef CONFIG_COMPAT
+long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case FS_IOC32_GETFLAGS:
+               cmd = FS_IOC_GETFLAGS;
+               break;
+       case FS_IOC32_SETFLAGS:
+               cmd = FS_IOC_SETFLAGS;
+               break;
+       case FS_IOC32_GETVERSION:
+               cmd = FS_IOC_GETVERSION;
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return nilfs_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
index a0babd2bff6a2e03a924e45110ff1a8698f59fd6..a649b05f7069db7b0beb31b7ebf10e5639a245bd 100644 (file)
@@ -399,7 +399,6 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc)
 
 static const struct address_space_operations def_mdt_aops = {
        .writepage              = nilfs_mdt_write_page,
-       .sync_page              = block_sync_page,
 };
 
 static const struct inode_operations def_mdt_iops;
@@ -438,10 +437,6 @@ void nilfs_mdt_set_entry_size(struct inode *inode, unsigned entry_size,
        mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size);
 }
 
-static const struct address_space_operations shadow_map_aops = {
-       .sync_page              = block_sync_page,
-};
-
 /**
  * nilfs_mdt_setup_shadow_map - setup shadow map and bind it to metadata file
  * @inode: inode of the metadata file
@@ -455,9 +450,9 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode,
 
        INIT_LIST_HEAD(&shadow->frozen_buffers);
        address_space_init_once(&shadow->frozen_data);
-       nilfs_mapping_init(&shadow->frozen_data, bdi, &shadow_map_aops);
+       nilfs_mapping_init(&shadow->frozen_data, bdi);
        address_space_init_once(&shadow->frozen_btnodes);
-       nilfs_mapping_init(&shadow->frozen_btnodes, bdi, &shadow_map_aops);
+       nilfs_mapping_init(&shadow->frozen_btnodes, bdi);
        mi->mi_shadow = shadow;
        return 0;
 }
index b13734bf3521d7370c03f623b46d023dd80241c0..ed68563ec708bd135c7abe0145a960de771424fb 100644 (file)
@@ -66,7 +66,7 @@ static inline struct nilfs_mdt_info *NILFS_MDT(const struct inode *inode)
 
 static inline struct the_nilfs *NILFS_I_NILFS(struct inode *inode)
 {
-       return NILFS_SB(inode->i_sb)->s_nilfs;
+       return inode->i_sb->s_fs_info;
 }
 
 /* Default GFP flags using highmem */
index 161791d26458b3c6669dbb11cdd6741a8ae9facb..546849b3e88f1935585067628e158f4233631d17 100644 (file)
@@ -482,7 +482,7 @@ static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno,
        if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO)
                return ERR_PTR(-ESTALE);
 
-       root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno);
+       root = nilfs_lookup_root(sb->s_fs_info, cno);
        if (!root)
                return ERR_PTR(-ESTALE);
 
index 777e8fd043049dcfb53def4e5cc78ec50a9ec991..856e8e4e0b74df250ef4c619eb6096f01f4866d7 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/blkdev.h>
 #include <linux/nilfs2_fs.h>
 #include "the_nilfs.h"
-#include "sb.h"
 #include "bmap.h"
 
 /*
@@ -122,7 +121,7 @@ enum {
 #define NILFS_SYS_INO_BITS   \
   ((unsigned int)(1 << NILFS_ROOT_INO) | NILFS_MDT_INO_BITS)
 
-#define NILFS_FIRST_INO(sb)  (NILFS_SB(sb)->s_nilfs->ns_first_ino)
+#define NILFS_FIRST_INO(sb) (((struct the_nilfs *)sb->s_fs_info)->ns_first_ino)
 
 #define NILFS_MDT_INODE(sb, ino) \
   ((ino) < NILFS_FIRST_INO(sb) && (NILFS_MDT_INO_BITS & (1 << (ino))))
@@ -212,6 +211,23 @@ static inline int nilfs_init_acl(struct inode *inode, struct inode *dir)
 
 #define NILFS_ATIME_DISABLE
 
+/* Flags that should be inherited by new inodes from their parent. */
+#define NILFS_FL_INHERITED                                             \
+       (FS_SECRM_FL | FS_UNRM_FL | FS_COMPR_FL | FS_SYNC_FL |          \
+        FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL |\
+        FS_COMPRBLK_FL | FS_NOCOMP_FL | FS_NOTAIL_FL | FS_DIRSYNC_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 nilfs_mask_flags(umode_t mode, __u32 flags)
+{
+       if (S_ISDIR(mode))
+               return flags;
+       else if (S_ISREG(mode))
+               return flags & ~(FS_DIRSYNC_FL | FS_TOPDIR_FL);
+       else
+               return flags & (FS_NODUMP_FL | FS_NOATIME_FL);
+}
+
 /* dir.c */
 extern int nilfs_add_link(struct dentry *, struct inode *);
 extern ino_t nilfs_inode_by_name(struct inode *, const struct qstr *);
@@ -229,10 +245,13 @@ extern int nilfs_sync_file(struct file *, int);
 
 /* ioctl.c */
 long nilfs_ioctl(struct file *, unsigned int, unsigned long);
+long nilfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *,
                                       void **);
 
 /* inode.c */
+void nilfs_inode_add_blocks(struct inode *inode, int n);
+void nilfs_inode_sub_blocks(struct inode *inode, int n);
 extern struct inode *nilfs_new_inode(struct inode *, int);
 extern void nilfs_free_inode(struct inode *);
 extern int nilfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
@@ -275,11 +294,11 @@ extern int nilfs_check_feature_compatibility(struct super_block *,
                                             struct nilfs_super_block *);
 extern void nilfs_set_log_cursor(struct nilfs_super_block *,
                                 struct the_nilfs *);
-extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
-                                                     int flip);
-extern int nilfs_commit_super(struct nilfs_sb_info *, int);
-extern int nilfs_cleanup_super(struct nilfs_sb_info *);
-int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
+struct nilfs_super_block **nilfs_prepare_super(struct super_block *sb,
+                                              int flip);
+int nilfs_commit_super(struct super_block *sb, int flag);
+int nilfs_cleanup_super(struct super_block *sb);
+int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
                            struct nilfs_root **root);
 int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno);
 
index a585b35fd6bc201c9d3063005792101da769ab01..4d2a1ee0eb47f492663a4211012ec5710bcd22c4 100644 (file)
@@ -493,15 +493,14 @@ unsigned nilfs_page_count_clean_buffers(struct page *page,
 }
 
 void nilfs_mapping_init(struct address_space *mapping,
-                       struct backing_dev_info *bdi,
-                       const struct address_space_operations *aops)
+                       struct backing_dev_info *bdi)
 {
        mapping->host = NULL;
        mapping->flags = 0;
        mapping_set_gfp_mask(mapping, GFP_NOFS);
        mapping->assoc_mapping = NULL;
        mapping->backing_dev_info = bdi;
-       mapping->a_ops = aops;
+       mapping->a_ops = NULL;
 }
 
 /*
index 2a00953ebd5f1b58b92494dbd684eb6128d76598..f06b79ad7493160877b1b82e45bc2f2acfd9b02f 100644 (file)
@@ -62,8 +62,7 @@ int nilfs_copy_dirty_pages(struct address_space *, struct address_space *);
 void nilfs_copy_back_pages(struct address_space *, struct address_space *);
 void nilfs_clear_dirty_pages(struct address_space *);
 void nilfs_mapping_init(struct address_space *mapping,
-                       struct backing_dev_info *bdi,
-                       const struct address_space_operations *aops);
+                       struct backing_dev_info *bdi);
 unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned);
 unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
                                            sector_t start_blk,
index 3dfcd3b7d3891a030ea8dd7a01c0a51a73aea0bf..ba4a64518f389d6dcad64830050d4fdf635746a8 100644 (file)
@@ -425,7 +425,7 @@ void nilfs_dispose_segment_list(struct list_head *head)
 }
 
 static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
-                                             struct nilfs_sb_info *sbi,
+                                             struct super_block *sb,
                                              struct nilfs_recovery_info *ri)
 {
        struct list_head *head = &ri->ri_used_segments;
@@ -501,7 +501,7 @@ static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
 }
 
 static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
-                                     struct nilfs_sb_info *sbi,
+                                     struct super_block *sb,
                                      struct nilfs_root *root,
                                      struct list_head *head,
                                      unsigned long *nr_salvaged_blocks)
@@ -514,7 +514,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
        int err = 0, err2 = 0;
 
        list_for_each_entry_safe(rb, n, head, list) {
-               inode = nilfs_iget(sbi->s_super, root, rb->ino);
+               inode = nilfs_iget(sb, root, rb->ino);
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
                        inode = NULL;
@@ -572,11 +572,11 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
  * nilfs_do_roll_forward - salvage logical segments newer than the latest
  * checkpoint
  * @nilfs: nilfs object
- * @sbi: nilfs_sb_info
+ * @sb: super block instance
  * @ri: pointer to a nilfs_recovery_info
  */
 static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
-                                struct nilfs_sb_info *sbi,
+                                struct super_block *sb,
                                 struct nilfs_root *root,
                                 struct nilfs_recovery_info *ri)
 {
@@ -648,7 +648,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
                                goto failed;
                        if (flags & NILFS_SS_LOGEND) {
                                err = nilfs_recover_dsync_blocks(
-                                       nilfs, sbi, root, &dsync_blocks,
+                                       nilfs, sb, root, &dsync_blocks,
                                        &nsalvaged_blocks);
                                if (unlikely(err))
                                        goto failed;
@@ -681,7 +681,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
 
        if (nsalvaged_blocks) {
                printk(KERN_INFO "NILFS (device %s): salvaged %lu blocks\n",
-                      sbi->s_super->s_id, nsalvaged_blocks);
+                      sb->s_id, nsalvaged_blocks);
                ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
        }
  out:
@@ -695,7 +695,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
        printk(KERN_ERR
               "NILFS (device %s): Error roll-forwarding "
               "(err=%d, pseg block=%llu). ",
-              sbi->s_super->s_id, err, (unsigned long long)pseg_start);
+              sb->s_id, err, (unsigned long long)pseg_start);
        goto out;
 }
 
@@ -724,7 +724,7 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
 /**
  * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
  * @nilfs: nilfs object
- * @sbi: nilfs_sb_info
+ * @sb: super block instance
  * @ri: pointer to a nilfs_recovery_info struct to store search results.
  *
  * Return Value: On success, 0 is returned.  On error, one of the following
@@ -741,7 +741,7 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
  * %-ENOMEM - Insufficient memory available.
  */
 int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
-                             struct nilfs_sb_info *sbi,
+                             struct super_block *sb,
                              struct nilfs_recovery_info *ri)
 {
        struct nilfs_root *root;
@@ -750,32 +750,32 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
        if (ri->ri_lsegs_start == 0 || ri->ri_lsegs_end == 0)
                return 0;
 
-       err = nilfs_attach_checkpoint(sbi, ri->ri_cno, true, &root);
+       err = nilfs_attach_checkpoint(sb, ri->ri_cno, true, &root);
        if (unlikely(err)) {
                printk(KERN_ERR
                       "NILFS: error loading the latest checkpoint.\n");
                return err;
        }
 
-       err = nilfs_do_roll_forward(nilfs, sbi, root, ri);
+       err = nilfs_do_roll_forward(nilfs, sb, root, ri);
        if (unlikely(err))
                goto failed;
 
        if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {
-               err = nilfs_prepare_segment_for_recovery(nilfs, sbi, ri);
+               err = nilfs_prepare_segment_for_recovery(nilfs, sb, ri);
                if (unlikely(err)) {
                        printk(KERN_ERR "NILFS: Error preparing segments for "
                               "recovery.\n");
                        goto failed;
                }
 
-               err = nilfs_attach_segment_constructor(sbi, root);
+               err = nilfs_attach_log_writer(sb, root);
                if (unlikely(err))
                        goto failed;
 
                set_nilfs_discontinued(nilfs);
-               err = nilfs_construct_segment(sbi->s_super);
-               nilfs_detach_segment_constructor(sbi);
+               err = nilfs_construct_segment(sb);
+               nilfs_detach_log_writer(sb);
 
                if (unlikely(err)) {
                        printk(KERN_ERR "NILFS: Oops! recovery failed. "
diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h
deleted file mode 100644 (file)
index 7a17715..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * sb.h - NILFS on-memory super block structure.
- *
- * Copyright (C) 2005-2008 Nippon Telegraph and Telephone 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * Written by Ryusuke Konishi <ryusuke@osrg.net>
- *
- */
-
-#ifndef _NILFS_SB
-#define _NILFS_SB
-
-#include <linux/types.h>
-#include <linux/fs.h>
-
-struct the_nilfs;
-struct nilfs_sc_info;
-
-/*
- * NILFS super-block data in memory
- */
-struct nilfs_sb_info {
-       /* Mount options */
-       unsigned long s_mount_opt;
-       uid_t s_resuid;
-       gid_t s_resgid;
-
-       unsigned long s_interval;       /* construction interval */
-       unsigned long s_watermark;      /* threshold of data amount
-                                          for the segment construction */
-
-       /* Fundamental members */
-       struct super_block *s_super;    /* reverse pointer to super_block */
-       struct the_nilfs *s_nilfs;
-
-       /* Segment constructor */
-       struct list_head s_dirty_files; /* dirty files list */
-       struct nilfs_sc_info *s_sc_info; /* segment constructor info */
-       spinlock_t s_inode_lock;        /* Lock for the nilfs inode.
-                                          It covers s_dirty_files list */
-
-       /* Inode allocator */
-       spinlock_t s_next_gen_lock;
-       u32 s_next_generation;
-};
-
-static inline struct nilfs_sb_info *NILFS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-static inline struct nilfs_sc_info *NILFS_SC(struct nilfs_sb_info *sbi)
-{
-       return sbi->s_sc_info;
-}
-
-/*
- * Bit operations for the mount option
- */
-#define nilfs_clear_opt(sbi, opt)  \
-       do { (sbi)->s_mount_opt &= ~NILFS_MOUNT_##opt; } while (0)
-#define nilfs_set_opt(sbi, opt)  \
-       do { (sbi)->s_mount_opt |= NILFS_MOUNT_##opt; } while (0)
-#define nilfs_test_opt(sbi, opt)   ((sbi)->s_mount_opt & NILFS_MOUNT_##opt)
-#define nilfs_write_opt(sbi, mask, opt)                                        \
-       do { (sbi)->s_mount_opt =                                       \
-               (((sbi)->s_mount_opt & ~NILFS_MOUNT_##mask) |           \
-                NILFS_MOUNT_##opt);                                    \
-       } while (0)
-
-#endif /* _NILFS_SB */
index 0f83e93935b2fb02347c7c0a7c0f3e131d94af14..2853ff20f85a2b30f8f6ac9a9c36e880bebf845c 100644 (file)
@@ -509,7 +509,7 @@ static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
                 * Last BIO is always sent through the following
                 * submission.
                 */
-               rw |= REQ_SYNC | REQ_UNPLUG;
+               rw |= REQ_SYNC;
                res = nilfs_segbuf_submit_bio(segbuf, &wi, rw);
        }
 
index 2de9f636792a7545290bbd95ce90b80f28345063..afe4f2183454d49a4be19b902c200b1922ebcc4e 100644 (file)
@@ -104,8 +104,7 @@ struct nilfs_sc_operations {
 static void nilfs_segctor_start_timer(struct nilfs_sc_info *);
 static void nilfs_segctor_do_flush(struct nilfs_sc_info *, int);
 static void nilfs_segctor_do_immediate_flush(struct nilfs_sc_info *);
-static void nilfs_dispose_list(struct nilfs_sb_info *, struct list_head *,
-                              int);
+static void nilfs_dispose_list(struct the_nilfs *, struct list_head *, int);
 
 #define nilfs_cnt32_gt(a, b)   \
        (typecheck(__u32, a) && typecheck(__u32, b) && \
@@ -182,7 +181,6 @@ int nilfs_transaction_begin(struct super_block *sb,
                            struct nilfs_transaction_info *ti,
                            int vacancy_check)
 {
-       struct nilfs_sb_info *sbi;
        struct the_nilfs *nilfs;
        int ret = nilfs_prepare_segment_lock(ti);
 
@@ -193,8 +191,7 @@ int nilfs_transaction_begin(struct super_block *sb,
 
        vfs_check_frozen(sb, SB_FREEZE_WRITE);
 
-       sbi = NILFS_SB(sb);
-       nilfs = sbi->s_nilfs;
+       nilfs = sb->s_fs_info;
        down_read(&nilfs->ns_segctor_sem);
        if (vacancy_check && nilfs_near_disk_full(nilfs)) {
                up_read(&nilfs->ns_segctor_sem);
@@ -225,8 +222,7 @@ int nilfs_transaction_begin(struct super_block *sb,
 int nilfs_transaction_commit(struct super_block *sb)
 {
        struct nilfs_transaction_info *ti = current->journal_info;
-       struct nilfs_sb_info *sbi;
-       struct nilfs_sc_info *sci;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        int err = 0;
 
        BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC);
@@ -235,16 +231,15 @@ int nilfs_transaction_commit(struct super_block *sb)
                ti->ti_count--;
                return 0;
        }
-       sbi = NILFS_SB(sb);
-       sci = NILFS_SC(sbi);
-       if (sci != NULL) {
+       if (nilfs->ns_writer) {
+               struct nilfs_sc_info *sci = nilfs->ns_writer;
+
                if (ti->ti_flags & NILFS_TI_COMMIT)
                        nilfs_segctor_start_timer(sci);
-               if (atomic_read(&sbi->s_nilfs->ns_ndirtyblks) >
-                   sci->sc_watermark)
+               if (atomic_read(&nilfs->ns_ndirtyblks) > sci->sc_watermark)
                        nilfs_segctor_do_flush(sci, 0);
        }
-       up_read(&sbi->s_nilfs->ns_segctor_sem);
+       up_read(&nilfs->ns_segctor_sem);
        current->journal_info = ti->ti_save;
 
        if (ti->ti_flags & NILFS_TI_SYNC)
@@ -257,13 +252,14 @@ int nilfs_transaction_commit(struct super_block *sb)
 void nilfs_transaction_abort(struct super_block *sb)
 {
        struct nilfs_transaction_info *ti = current->journal_info;
+       struct the_nilfs *nilfs = sb->s_fs_info;
 
        BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC);
        if (ti->ti_count > 0) {
                ti->ti_count--;
                return;
        }
-       up_read(&NILFS_SB(sb)->s_nilfs->ns_segctor_sem);
+       up_read(&nilfs->ns_segctor_sem);
 
        current->journal_info = ti->ti_save;
        if (ti->ti_flags & NILFS_TI_DYNAMIC_ALLOC)
@@ -272,9 +268,8 @@ void nilfs_transaction_abort(struct super_block *sb)
 
 void nilfs_relax_pressure_in_lock(struct super_block *sb)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct nilfs_sc_info *sci = NILFS_SC(sbi);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
 
        if (!sci || !sci->sc_flush_request)
                return;
@@ -294,11 +289,13 @@ void nilfs_relax_pressure_in_lock(struct super_block *sb)
        downgrade_write(&nilfs->ns_segctor_sem);
 }
 
-static void nilfs_transaction_lock(struct nilfs_sb_info *sbi,
+static void nilfs_transaction_lock(struct super_block *sb,
                                   struct nilfs_transaction_info *ti,
                                   int gcflag)
 {
        struct nilfs_transaction_info *cur_ti = current->journal_info;
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
 
        WARN_ON(cur_ti);
        ti->ti_flags = NILFS_TI_WRITER;
@@ -309,30 +306,31 @@ static void nilfs_transaction_lock(struct nilfs_sb_info *sbi,
        current->journal_info = ti;
 
        for (;;) {
-               down_write(&sbi->s_nilfs->ns_segctor_sem);
-               if (!test_bit(NILFS_SC_PRIOR_FLUSH, &NILFS_SC(sbi)->sc_flags))
+               down_write(&nilfs->ns_segctor_sem);
+               if (!test_bit(NILFS_SC_PRIOR_FLUSH, &sci->sc_flags))
                        break;
 
-               nilfs_segctor_do_immediate_flush(NILFS_SC(sbi));
+               nilfs_segctor_do_immediate_flush(sci);
 
-               up_write(&sbi->s_nilfs->ns_segctor_sem);
+               up_write(&nilfs->ns_segctor_sem);
                yield();
        }
        if (gcflag)
                ti->ti_flags |= NILFS_TI_GC;
 }
 
-static void nilfs_transaction_unlock(struct nilfs_sb_info *sbi)
+static void nilfs_transaction_unlock(struct super_block *sb)
 {
        struct nilfs_transaction_info *ti = current->journal_info;
+       struct the_nilfs *nilfs = sb->s_fs_info;
 
        BUG_ON(ti == NULL || ti->ti_magic != NILFS_TI_MAGIC);
        BUG_ON(ti->ti_count > 0);
 
-       up_write(&sbi->s_nilfs->ns_segctor_sem);
+       up_write(&nilfs->ns_segctor_sem);
        current->journal_info = ti->ti_save;
        if (!list_empty(&ti->ti_garbage))
-               nilfs_dispose_list(sbi, &ti->ti_garbage, 0);
+               nilfs_dispose_list(nilfs, &ti->ti_garbage, 0);
 }
 
 static void *nilfs_segctor_map_segsum_entry(struct nilfs_sc_info *sci,
@@ -714,7 +712,7 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
        }
 }
 
-static void nilfs_dispose_list(struct nilfs_sb_info *sbi,
+static void nilfs_dispose_list(struct the_nilfs *nilfs,
                               struct list_head *head, int force)
 {
        struct nilfs_inode_info *ii, *n;
@@ -722,7 +720,7 @@ static void nilfs_dispose_list(struct nilfs_sb_info *sbi,
        unsigned nv = 0;
 
        while (!list_empty(head)) {
-               spin_lock(&sbi->s_inode_lock);
+               spin_lock(&nilfs->ns_inode_lock);
                list_for_each_entry_safe(ii, n, head, i_dirty) {
                        list_del_init(&ii->i_dirty);
                        if (force) {
@@ -733,14 +731,14 @@ static void nilfs_dispose_list(struct nilfs_sb_info *sbi,
                        } else if (test_bit(NILFS_I_DIRTY, &ii->i_state)) {
                                set_bit(NILFS_I_QUEUED, &ii->i_state);
                                list_add_tail(&ii->i_dirty,
-                                             &sbi->s_dirty_files);
+                                             &nilfs->ns_dirty_files);
                                continue;
                        }
                        ivec[nv++] = ii;
                        if (nv == SC_N_INODEVEC)
                                break;
                }
-               spin_unlock(&sbi->s_inode_lock);
+               spin_unlock(&nilfs->ns_inode_lock);
 
                for (pii = ivec; nv > 0; pii++, nv--)
                        iput(&(*pii)->vfs_inode);
@@ -773,24 +771,23 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci)
 
 static int nilfs_segctor_confirm(struct nilfs_sc_info *sci)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        int ret = 0;
 
-       if (nilfs_test_metadata_dirty(sbi->s_nilfs, sci->sc_root))
+       if (nilfs_test_metadata_dirty(nilfs, sci->sc_root))
                set_bit(NILFS_SC_DIRTY, &sci->sc_flags);
 
-       spin_lock(&sbi->s_inode_lock);
-       if (list_empty(&sbi->s_dirty_files) && nilfs_segctor_clean(sci))
+       spin_lock(&nilfs->ns_inode_lock);
+       if (list_empty(&nilfs->ns_dirty_files) && nilfs_segctor_clean(sci))
                ret++;
 
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
        return ret;
 }
 
 static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
 
        nilfs_mdt_clear_dirty(sci->sc_root->ifile);
        nilfs_mdt_clear_dirty(nilfs->ns_cpfile);
@@ -800,7 +797,7 @@ static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci)
 
 static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci)
 {
-       struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        struct buffer_head *bh_cp;
        struct nilfs_checkpoint *raw_cp;
        int err;
@@ -824,8 +821,7 @@ static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci)
 
 static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        struct buffer_head *bh_cp;
        struct nilfs_checkpoint *raw_cp;
        int err;
@@ -1049,8 +1045,7 @@ static int nilfs_segctor_scan_file_dsync(struct nilfs_sc_info *sci,
 
 static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        struct list_head *head;
        struct nilfs_inode_info *ii;
        size_t ndone;
@@ -1859,7 +1854,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
 {
        struct nilfs_segment_buffer *segbuf;
        struct page *bd_page = NULL, *fs_page = NULL;
-       struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        int update_sr = false;
 
        list_for_each_entry(segbuf, &sci->sc_write_logs, sb_list) {
@@ -1963,30 +1958,30 @@ static int nilfs_segctor_wait(struct nilfs_sc_info *sci)
        return ret;
 }
 
-static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci,
-                                       struct nilfs_sb_info *sbi)
+static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci,
+                                            struct the_nilfs *nilfs)
 {
        struct nilfs_inode_info *ii, *n;
        struct inode *ifile = sci->sc_root->ifile;
 
-       spin_lock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
  retry:
-       list_for_each_entry_safe(ii, n, &sbi->s_dirty_files, i_dirty) {
+       list_for_each_entry_safe(ii, n, &nilfs->ns_dirty_files, i_dirty) {
                if (!ii->i_bh) {
                        struct buffer_head *ibh;
                        int err;
 
-                       spin_unlock(&sbi->s_inode_lock);
+                       spin_unlock(&nilfs->ns_inode_lock);
                        err = nilfs_ifile_get_inode_block(
                                ifile, ii->vfs_inode.i_ino, &ibh);
                        if (unlikely(err)) {
-                               nilfs_warning(sbi->s_super, __func__,
+                               nilfs_warning(sci->sc_super, __func__,
                                              "failed to get inode block.\n");
                                return err;
                        }
                        nilfs_mdt_mark_buffer_dirty(ibh);
                        nilfs_mdt_mark_dirty(ifile);
-                       spin_lock(&sbi->s_inode_lock);
+                       spin_lock(&nilfs->ns_inode_lock);
                        if (likely(!ii->i_bh))
                                ii->i_bh = ibh;
                        else
@@ -1999,18 +1994,18 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci,
                list_del(&ii->i_dirty);
                list_add_tail(&ii->i_dirty, &sci->sc_dirty_files);
        }
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
 
        return 0;
 }
 
-static void nilfs_segctor_check_out_files(struct nilfs_sc_info *sci,
-                                         struct nilfs_sb_info *sbi)
+static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci,
+                                            struct the_nilfs *nilfs)
 {
        struct nilfs_transaction_info *ti = current->journal_info;
        struct nilfs_inode_info *ii, *n;
 
-       spin_lock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
        list_for_each_entry_safe(ii, n, &sci->sc_dirty_files, i_dirty) {
                if (!test_and_clear_bit(NILFS_I_UPDATED, &ii->i_state) ||
                    test_bit(NILFS_I_DIRTY, &ii->i_state))
@@ -2022,7 +2017,7 @@ static void nilfs_segctor_check_out_files(struct nilfs_sc_info *sci,
                list_del(&ii->i_dirty);
                list_add_tail(&ii->i_dirty, &ti->ti_garbage);
        }
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
 }
 
 /*
@@ -2030,15 +2025,14 @@ static void nilfs_segctor_check_out_files(struct nilfs_sc_info *sci,
  */
 static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        struct page *failed_page;
        int err;
 
        sci->sc_stage.scnt = NILFS_ST_INIT;
        sci->sc_cno = nilfs->ns_cno;
 
-       err = nilfs_segctor_check_in_files(sci, sbi);
+       err = nilfs_segctor_collect_dirty_files(sci, nilfs);
        if (unlikely(err))
                goto out;
 
@@ -2116,7 +2110,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
        } while (sci->sc_stage.scnt != NILFS_ST_DONE);
 
  out:
-       nilfs_segctor_check_out_files(sci, sbi);
+       nilfs_segctor_drop_written_files(sci, nilfs);
        return err;
 
  failed_to_write:
@@ -2169,8 +2163,8 @@ static void nilfs_segctor_do_flush(struct nilfs_sc_info *sci, int bn)
  */
 void nilfs_flush_segment(struct super_block *sb, ino_t ino)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct nilfs_sc_info *sci = NILFS_SC(sbi);
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
 
        if (!sci || nilfs_doing_construction())
                return;
@@ -2259,8 +2253,8 @@ static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err)
  */
 int nilfs_construct_segment(struct super_block *sb)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct nilfs_sc_info *sci = NILFS_SC(sbi);
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
        struct nilfs_transaction_info *ti;
        int err;
 
@@ -2297,8 +2291,8 @@ int nilfs_construct_segment(struct super_block *sb)
 int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
                                  loff_t start, loff_t end)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct nilfs_sc_info *sci = NILFS_SC(sbi);
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
        struct nilfs_inode_info *ii;
        struct nilfs_transaction_info ti;
        int err = 0;
@@ -2306,33 +2300,33 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
        if (!sci)
                return -EROFS;
 
-       nilfs_transaction_lock(sbi, &ti, 0);
+       nilfs_transaction_lock(sb, &ti, 0);
 
        ii = NILFS_I(inode);
        if (test_bit(NILFS_I_INODE_DIRTY, &ii->i_state) ||
-           nilfs_test_opt(sbi, STRICT_ORDER) ||
+           nilfs_test_opt(nilfs, STRICT_ORDER) ||
            test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) ||
-           nilfs_discontinued(sbi->s_nilfs)) {
-               nilfs_transaction_unlock(sbi);
+           nilfs_discontinued(nilfs)) {
+               nilfs_transaction_unlock(sb);
                err = nilfs_segctor_sync(sci);
                return err;
        }
 
-       spin_lock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
        if (!test_bit(NILFS_I_QUEUED, &ii->i_state) &&
            !test_bit(NILFS_I_BUSY, &ii->i_state)) {
-               spin_unlock(&sbi->s_inode_lock);
-               nilfs_transaction_unlock(sbi);
+               spin_unlock(&nilfs->ns_inode_lock);
+               nilfs_transaction_unlock(sb);
                return 0;
        }
-       spin_unlock(&sbi->s_inode_lock);
+       spin_unlock(&nilfs->ns_inode_lock);
        sci->sc_dsync_inode = ii;
        sci->sc_dsync_start = start;
        sci->sc_dsync_end = end;
 
        err = nilfs_segctor_do_construct(sci, SC_LSEG_DSYNC);
 
-       nilfs_transaction_unlock(sbi);
+       nilfs_transaction_unlock(sb);
        return err;
 }
 
@@ -2388,8 +2382,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
  */
 static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        struct nilfs_super_block **sbp;
        int err = 0;
 
@@ -2407,11 +2400,12 @@ static int nilfs_segctor_construct(struct nilfs_sc_info *sci, int mode)
                    nilfs_discontinued(nilfs)) {
                        down_write(&nilfs->ns_sem);
                        err = -EIO;
-                       sbp = nilfs_prepare_super(sbi,
+                       sbp = nilfs_prepare_super(sci->sc_super,
                                                  nilfs_sb_will_flip(nilfs));
                        if (likely(sbp)) {
                                nilfs_set_log_cursor(sbp[0], nilfs);
-                               err = nilfs_commit_super(sbi, NILFS_SB_COMMIT);
+                               err = nilfs_commit_super(sci->sc_super,
+                                                        NILFS_SB_COMMIT);
                        }
                        up_write(&nilfs->ns_sem);
                }
@@ -2443,16 +2437,15 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head)
 int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
                         void **kbufs)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct nilfs_sc_info *sci = NILFS_SC(sbi);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
+       struct nilfs_sc_info *sci = nilfs->ns_writer;
        struct nilfs_transaction_info ti;
        int err;
 
        if (unlikely(!sci))
                return -EROFS;
 
-       nilfs_transaction_lock(sbi, &ti, 1);
+       nilfs_transaction_lock(sb, &ti, 1);
 
        err = nilfs_mdt_save_to_shadow_map(nilfs->ns_dat);
        if (unlikely(err))
@@ -2480,14 +2473,14 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(sci->sc_interval);
        }
-       if (nilfs_test_opt(sbi, DISCARD)) {
+       if (nilfs_test_opt(nilfs, DISCARD)) {
                int ret = nilfs_discard_segments(nilfs, sci->sc_freesegs,
                                                 sci->sc_nfreesegs);
                if (ret) {
                        printk(KERN_WARNING
                               "NILFS warning: error %d on discard request, "
                               "turning discards off for the device\n", ret);
-                       nilfs_clear_opt(sbi, DISCARD);
+                       nilfs_clear_opt(nilfs, DISCARD);
                }
        }
 
@@ -2495,16 +2488,15 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,
        sci->sc_freesegs = NULL;
        sci->sc_nfreesegs = 0;
        nilfs_mdt_clear_shadow_map(nilfs->ns_dat);
-       nilfs_transaction_unlock(sbi);
+       nilfs_transaction_unlock(sb);
        return err;
 }
 
 static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
        struct nilfs_transaction_info ti;
 
-       nilfs_transaction_lock(sbi, &ti, 0);
+       nilfs_transaction_lock(sci->sc_super, &ti, 0);
        nilfs_segctor_construct(sci, mode);
 
        /*
@@ -2515,7 +2507,7 @@ static void nilfs_segctor_thread_construct(struct nilfs_sc_info *sci, int mode)
        if (test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags))
                nilfs_segctor_start_timer(sci);
 
-       nilfs_transaction_unlock(sbi);
+       nilfs_transaction_unlock(sci->sc_super);
 }
 
 static void nilfs_segctor_do_immediate_flush(struct nilfs_sc_info *sci)
@@ -2561,7 +2553,7 @@ static int nilfs_segctor_flush_mode(struct nilfs_sc_info *sci)
 static int nilfs_segctor_thread(void *arg)
 {
        struct nilfs_sc_info *sci = (struct nilfs_sc_info *)arg;
-       struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        int timeout = 0;
 
        sci->sc_timer.data = (unsigned long)current;
@@ -2672,17 +2664,17 @@ static void nilfs_segctor_kill_thread(struct nilfs_sc_info *sci)
 /*
  * Setup & clean-up functions
  */
-static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi,
+static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb,
                                               struct nilfs_root *root)
 {
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_sc_info *sci;
 
        sci = kzalloc(sizeof(*sci), GFP_KERNEL);
        if (!sci)
                return NULL;
 
-       sci->sc_sbi = sbi;
-       sci->sc_super = sbi->s_super;
+       sci->sc_super = sb;
 
        nilfs_get_root(root);
        sci->sc_root = root;
@@ -2702,10 +2694,10 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi,
        sci->sc_mjcp_freq = HZ * NILFS_SC_DEFAULT_SR_FREQ;
        sci->sc_watermark = NILFS_SC_DEFAULT_WATERMARK;
 
-       if (sbi->s_interval)
-               sci->sc_interval = sbi->s_interval;
-       if (sbi->s_watermark)
-               sci->sc_watermark = sbi->s_watermark;
+       if (nilfs->ns_interval)
+               sci->sc_interval = nilfs->ns_interval;
+       if (nilfs->ns_watermark)
+               sci->sc_watermark = nilfs->ns_watermark;
        return sci;
 }
 
@@ -2716,12 +2708,11 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
        /* The segctord thread was stopped and its timer was removed.
           But some tasks remain. */
        do {
-               struct nilfs_sb_info *sbi = sci->sc_sbi;
                struct nilfs_transaction_info ti;
 
-               nilfs_transaction_lock(sbi, &ti, 0);
+               nilfs_transaction_lock(sci->sc_super, &ti, 0);
                ret = nilfs_segctor_construct(sci, SC_LSEG_SR);
-               nilfs_transaction_unlock(sbi);
+               nilfs_transaction_unlock(sci->sc_super);
 
        } while (ret && retrycount-- > 0);
 }
@@ -2736,10 +2727,10 @@ static void nilfs_segctor_write_out(struct nilfs_sc_info *sci)
  */
 static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
 {
-       struct nilfs_sb_info *sbi = sci->sc_sbi;
+       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
        int flag;
 
-       up_write(&sbi->s_nilfs->ns_segctor_sem);
+       up_write(&nilfs->ns_segctor_sem);
 
        spin_lock(&sci->sc_state_lock);
        nilfs_segctor_kill_thread(sci);
@@ -2753,9 +2744,9 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
        WARN_ON(!list_empty(&sci->sc_copied_buffers));
 
        if (!list_empty(&sci->sc_dirty_files)) {
-               nilfs_warning(sbi->s_super, __func__,
+               nilfs_warning(sci->sc_super, __func__,
                              "dirty file(s) after the final construction\n");
-               nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1);
+               nilfs_dispose_list(nilfs, &sci->sc_dirty_files, 1);
        }
 
        WARN_ON(!list_empty(&sci->sc_segbufs));
@@ -2763,79 +2754,78 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
 
        nilfs_put_root(sci->sc_root);
 
-       down_write(&sbi->s_nilfs->ns_segctor_sem);
+       down_write(&nilfs->ns_segctor_sem);
 
        del_timer_sync(&sci->sc_timer);
        kfree(sci);
 }
 
 /**
- * nilfs_attach_segment_constructor - attach a segment constructor
- * @sbi: nilfs_sb_info
+ * nilfs_attach_log_writer - attach log writer
+ * @sb: super block instance
  * @root: root object of the current filesystem tree
  *
- * nilfs_attach_segment_constructor() allocates a struct nilfs_sc_info,
- * initializes it, and starts the segment constructor.
+ * This allocates a log writer object, initializes it, and starts the
+ * log writer.
  *
  * Return Value: On success, 0 is returned. On error, one of the following
  * negative error code is returned.
  *
  * %-ENOMEM - Insufficient memory available.
  */
-int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi,
-                                    struct nilfs_root *root)
+int nilfs_attach_log_writer(struct super_block *sb, struct nilfs_root *root)
 {
+       struct the_nilfs *nilfs = sb->s_fs_info;
        int err;
 
-       if (NILFS_SC(sbi)) {
+       if (nilfs->ns_writer) {
                /*
                 * This happens if the filesystem was remounted
                 * read/write after nilfs_error degenerated it into a
                 * read-only mount.
                 */
-               nilfs_detach_segment_constructor(sbi);
+               nilfs_detach_log_writer(sb);
        }
 
-       sbi->s_sc_info = nilfs_segctor_new(sbi, root);
-       if (!sbi->s_sc_info)
+       nilfs->ns_writer = nilfs_segctor_new(sb, root);
+       if (!nilfs->ns_writer)
                return -ENOMEM;
 
-       err = nilfs_segctor_start_thread(NILFS_SC(sbi));
+       err = nilfs_segctor_start_thread(nilfs->ns_writer);
        if (err) {
-               kfree(sbi->s_sc_info);
-               sbi->s_sc_info = NULL;
+               kfree(nilfs->ns_writer);
+               nilfs->ns_writer = NULL;
        }
        return err;
 }
 
 /**
- * nilfs_detach_segment_constructor - destroy the segment constructor
- * @sbi: nilfs_sb_info
+ * nilfs_detach_log_writer - destroy log writer
+ * @sb: super block instance
  *
- * nilfs_detach_segment_constructor() kills the segment constructor daemon,
- * frees the struct nilfs_sc_info, and destroy the dirty file list.
+ * This kills log writer daemon, frees the log writer object, and
+ * destroys list of dirty files.
  */
-void nilfs_detach_segment_constructor(struct nilfs_sb_info *sbi)
+void nilfs_detach_log_writer(struct super_block *sb)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        LIST_HEAD(garbage_list);
 
        down_write(&nilfs->ns_segctor_sem);
-       if (NILFS_SC(sbi)) {
-               nilfs_segctor_destroy(NILFS_SC(sbi));
-               sbi->s_sc_info = NULL;
+       if (nilfs->ns_writer) {
+               nilfs_segctor_destroy(nilfs->ns_writer);
+               nilfs->ns_writer = NULL;
        }
 
        /* Force to free the list of dirty files */
-       spin_lock(&sbi->s_inode_lock);
-       if (!list_empty(&sbi->s_dirty_files)) {
-               list_splice_init(&sbi->s_dirty_files, &garbage_list);
-               nilfs_warning(sbi->s_super, __func__,
-                             "Non empty dirty list after the last "
-                             "segment construction\n");
-       }
-       spin_unlock(&sbi->s_inode_lock);
+       spin_lock(&nilfs->ns_inode_lock);
+       if (!list_empty(&nilfs->ns_dirty_files)) {
+               list_splice_init(&nilfs->ns_dirty_files, &garbage_list);
+               nilfs_warning(sb, __func__,
+                             "Hit dirty file after stopped log writer\n");
+       }
+       spin_unlock(&nilfs->ns_inode_lock);
        up_write(&nilfs->ns_segctor_sem);
 
-       nilfs_dispose_list(sbi, &garbage_list, 1);
+       nilfs_dispose_list(nilfs, &garbage_list, 1);
 }
index cd8056e7cbed076ecdfb63284b7a97149a4c5003..6c02a86745fb19417d093da0af0ed205ac00a1a7 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/nilfs2_fs.h>
-#include "sb.h"
+#include "nilfs.h"
 
 struct nilfs_root;
 
@@ -88,7 +88,6 @@ struct nilfs_segsum_pointer {
 /**
  * struct nilfs_sc_info - Segment constructor information
  * @sc_super: Back pointer to super_block struct
- * @sc_sbi: Back pointer to nilfs_sb_info struct
  * @sc_root: root object of the current filesystem tree
  * @sc_nblk_inc: Block count of current generation
  * @sc_dirty_files: List of files to be written
@@ -131,7 +130,6 @@ struct nilfs_segsum_pointer {
  */
 struct nilfs_sc_info {
        struct super_block     *sc_super;
-       struct nilfs_sb_info   *sc_sbi;
        struct nilfs_root      *sc_root;
 
        unsigned long           sc_nblk_inc;
@@ -235,18 +233,16 @@ extern void nilfs_flush_segment(struct super_block *, ino_t);
 extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *,
                                void **);
 
-int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi,
-                                    struct nilfs_root *root);
-extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *);
+int nilfs_attach_log_writer(struct super_block *sb, struct nilfs_root *root);
+void nilfs_detach_log_writer(struct super_block *sb);
 
 /* recovery.c */
 extern int nilfs_read_super_root_block(struct the_nilfs *, sector_t,
                                       struct buffer_head **, int);
 extern int nilfs_search_super_root(struct the_nilfs *,
                                   struct nilfs_recovery_info *);
-extern int nilfs_salvage_orphan_logs(struct the_nilfs *,
-                                    struct nilfs_sb_info *,
-                                    struct nilfs_recovery_info *);
+int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, struct super_block *sb,
+                             struct nilfs_recovery_info *ri);
 extern void nilfs_dispose_segment_list(struct list_head *);
 
 #endif /* _NILFS_SEGMENT_H */
index 1673b3d99842018206640c77ea9922840c5a2bc4..062cca065195ea7f430f45cf9259896be44be788 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/parser.h>
-#include <linux/random.h>
 #include <linux/crc32.h>
 #include <linux/vfs.h>
 #include <linux/writeback.h>
@@ -72,23 +71,23 @@ struct kmem_cache *nilfs_transaction_cachep;
 struct kmem_cache *nilfs_segbuf_cachep;
 struct kmem_cache *nilfs_btree_path_cache;
 
-static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount);
+static int nilfs_setup_super(struct super_block *sb, int is_mount);
 static int nilfs_remount(struct super_block *sb, int *flags, char *data);
 
-static void nilfs_set_error(struct nilfs_sb_info *sbi)
+static void nilfs_set_error(struct super_block *sb)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp;
 
        down_write(&nilfs->ns_sem);
        if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
                nilfs->ns_mount_state |= NILFS_ERROR_FS;
-               sbp = nilfs_prepare_super(sbi, 0);
+               sbp = nilfs_prepare_super(sb, 0);
                if (likely(sbp)) {
                        sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
                        if (sbp[1])
                                sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
-                       nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
+                       nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL);
                }
        }
        up_write(&nilfs->ns_sem);
@@ -109,7 +108,7 @@ static void nilfs_set_error(struct nilfs_sb_info *sbi)
 void nilfs_error(struct super_block *sb, const char *function,
                 const char *fmt, ...)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct va_format vaf;
        va_list args;
 
@@ -124,15 +123,15 @@ void nilfs_error(struct super_block *sb, const char *function,
        va_end(args);
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               nilfs_set_error(sbi);
+               nilfs_set_error(sb);
 
-               if (nilfs_test_opt(sbi, ERRORS_RO)) {
+               if (nilfs_test_opt(nilfs, ERRORS_RO)) {
                        printk(KERN_CRIT "Remounting filesystem read-only\n");
                        sb->s_flags |= MS_RDONLY;
                }
        }
 
-       if (nilfs_test_opt(sbi, ERRORS_PANIC))
+       if (nilfs_test_opt(nilfs, ERRORS_PANIC))
                panic("NILFS (device %s): panic forced after error\n",
                      sb->s_id);
 }
@@ -189,14 +188,14 @@ void nilfs_destroy_inode(struct inode *inode)
        call_rcu(&inode->i_rcu, nilfs_i_callback);
 }
 
-static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
+static int nilfs_sync_super(struct super_block *sb, int flag)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        int err;
 
  retry:
        set_buffer_dirty(nilfs->ns_sbh[0]);
-       if (nilfs_test_opt(sbi, BARRIER)) {
+       if (nilfs_test_opt(nilfs, BARRIER)) {
                err = __sync_dirty_buffer(nilfs->ns_sbh[0],
                                          WRITE_SYNC | WRITE_FLUSH_FUA);
        } else {
@@ -263,10 +262,10 @@ void nilfs_set_log_cursor(struct nilfs_super_block *sbp,
        spin_unlock(&nilfs->ns_last_segment_lock);
 }
 
-struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
+struct nilfs_super_block **nilfs_prepare_super(struct super_block *sb,
                                               int flip)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp = nilfs->ns_sbp;
 
        /* nilfs->ns_sem must be locked by the caller. */
@@ -276,7 +275,7 @@ struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
                        memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
                } else {
                        printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
-                              sbi->s_super->s_id);
+                              sb->s_id);
                        return NULL;
                }
        } else if (sbp[1] &&
@@ -290,9 +289,9 @@ struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
        return sbp;
 }
 
-int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
+int nilfs_commit_super(struct super_block *sb, int flag)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp = nilfs->ns_sbp;
        time_t t;
 
@@ -312,27 +311,28 @@ int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
                                            nilfs->ns_sbsize));
        }
        clear_nilfs_sb_dirty(nilfs);
-       return nilfs_sync_super(sbi, flag);
+       return nilfs_sync_super(sb, flag);
 }
 
 /**
  * nilfs_cleanup_super() - write filesystem state for cleanup
- * @sbi: nilfs_sb_info to be unmounted or degraded to read-only
+ * @sb: super block instance to be unmounted or degraded to read-only
  *
  * This function restores state flags in the on-disk super block.
  * This will set "clean" flag (i.e. NILFS_VALID_FS) unless the
  * filesystem was not clean previously.
  */
-int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
+int nilfs_cleanup_super(struct super_block *sb)
 {
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp;
        int flag = NILFS_SB_COMMIT;
        int ret = -EIO;
 
-       sbp = nilfs_prepare_super(sbi, 0);
+       sbp = nilfs_prepare_super(sb, 0);
        if (sbp) {
-               sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state);
-               nilfs_set_log_cursor(sbp[0], sbi->s_nilfs);
+               sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state);
+               nilfs_set_log_cursor(sbp[0], nilfs);
                if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) {
                        /*
                         * make the "clean" flag also to the opposite
@@ -342,21 +342,20 @@ int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
                        sbp[1]->s_state = sbp[0]->s_state;
                        flag = NILFS_SB_COMMIT_ALL;
                }
-               ret = nilfs_commit_super(sbi, flag);
+               ret = nilfs_commit_super(sb, flag);
        }
        return ret;
 }
 
 static void nilfs_put_super(struct super_block *sb)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
 
-       nilfs_detach_segment_constructor(sbi);
+       nilfs_detach_log_writer(sb);
 
        if (!(sb->s_flags & MS_RDONLY)) {
                down_write(&nilfs->ns_sem);
-               nilfs_cleanup_super(sbi);
+               nilfs_cleanup_super(sb);
                up_write(&nilfs->ns_sem);
        }
 
@@ -365,15 +364,12 @@ static void nilfs_put_super(struct super_block *sb)
        iput(nilfs->ns_dat);
 
        destroy_nilfs(nilfs);
-       sbi->s_super = NULL;
        sb->s_fs_info = NULL;
-       kfree(sbi);
 }
 
 static int nilfs_sync_fs(struct super_block *sb, int wait)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp;
        int err = 0;
 
@@ -383,10 +379,10 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
 
        down_write(&nilfs->ns_sem);
        if (nilfs_sb_dirty(nilfs)) {
-               sbp = nilfs_prepare_super(sbi, nilfs_sb_will_flip(nilfs));
+               sbp = nilfs_prepare_super(sb, nilfs_sb_will_flip(nilfs));
                if (likely(sbp)) {
                        nilfs_set_log_cursor(sbp[0], nilfs);
-                       nilfs_commit_super(sbi, NILFS_SB_COMMIT);
+                       nilfs_commit_super(sb, NILFS_SB_COMMIT);
                }
        }
        up_write(&nilfs->ns_sem);
@@ -394,10 +390,10 @@ static int nilfs_sync_fs(struct super_block *sb, int wait)
        return err;
 }
 
-int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
+int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
                            struct nilfs_root **rootp)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_root *root;
        struct nilfs_checkpoint *raw_cp;
        struct buffer_head *bh_cp;
@@ -426,7 +422,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
                goto failed;
        }
 
-       err = nilfs_ifile_read(sbi->s_super, root, nilfs->ns_inode_size,
+       err = nilfs_ifile_read(sb, root, nilfs->ns_inode_size,
                               &raw_cp->cp_ifile_inode, &root->ifile);
        if (err)
                goto failed_bh;
@@ -450,8 +446,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
 
 static int nilfs_freeze(struct super_block *sb)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        int err;
 
        if (sb->s_flags & MS_RDONLY)
@@ -459,21 +454,20 @@ static int nilfs_freeze(struct super_block *sb)
 
        /* Mark super block clean */
        down_write(&nilfs->ns_sem);
-       err = nilfs_cleanup_super(sbi);
+       err = nilfs_cleanup_super(sb);
        up_write(&nilfs->ns_sem);
        return err;
 }
 
 static int nilfs_unfreeze(struct super_block *sb)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
 
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
        down_write(&nilfs->ns_sem);
-       nilfs_setup_super(sbi, false);
+       nilfs_setup_super(sb, false);
        up_write(&nilfs->ns_sem);
        return 0;
 }
@@ -530,22 +524,22 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
 {
        struct super_block *sb = vfs->mnt_sb;
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root;
 
-       if (!nilfs_test_opt(sbi, BARRIER))
+       if (!nilfs_test_opt(nilfs, BARRIER))
                seq_puts(seq, ",nobarrier");
        if (root->cno != NILFS_CPTREE_CURRENT_CNO)
                seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno);
-       if (nilfs_test_opt(sbi, ERRORS_PANIC))
+       if (nilfs_test_opt(nilfs, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
-       if (nilfs_test_opt(sbi, ERRORS_CONT))
+       if (nilfs_test_opt(nilfs, ERRORS_CONT))
                seq_puts(seq, ",errors=continue");
-       if (nilfs_test_opt(sbi, STRICT_ORDER))
+       if (nilfs_test_opt(nilfs, STRICT_ORDER))
                seq_puts(seq, ",order=strict");
-       if (nilfs_test_opt(sbi, NORECOVERY))
+       if (nilfs_test_opt(nilfs, NORECOVERY))
                seq_puts(seq, ",norecovery");
-       if (nilfs_test_opt(sbi, DISCARD))
+       if (nilfs_test_opt(nilfs, DISCARD))
                seq_puts(seq, ",discard");
 
        return 0;
@@ -594,7 +588,7 @@ static match_table_t tokens = {
 
 static int parse_options(char *options, struct super_block *sb, int is_remount)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct the_nilfs *nilfs = sb->s_fs_info;
        char *p;
        substring_t args[MAX_OPT_ARGS];
 
@@ -609,29 +603,29 @@ static int parse_options(char *options, struct super_block *sb, int is_remount)
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_barrier:
-                       nilfs_set_opt(sbi, BARRIER);
+                       nilfs_set_opt(nilfs, BARRIER);
                        break;
                case Opt_nobarrier:
-                       nilfs_clear_opt(sbi, BARRIER);
+                       nilfs_clear_opt(nilfs, BARRIER);
                        break;
                case Opt_order:
                        if (strcmp(args[0].from, "relaxed") == 0)
                                /* Ordered data semantics */
-                               nilfs_clear_opt(sbi, STRICT_ORDER);
+                               nilfs_clear_opt(nilfs, STRICT_ORDER);
                        else if (strcmp(args[0].from, "strict") == 0)
                                /* Strict in-order semantics */
-                               nilfs_set_opt(sbi, STRICT_ORDER);
+                               nilfs_set_opt(nilfs, STRICT_ORDER);
                        else
                                return 0;
                        break;
                case Opt_err_panic:
-                       nilfs_write_opt(sbi, ERROR_MODE, ERRORS_PANIC);
+                       nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_PANIC);
                        break;
                case Opt_err_ro:
-                       nilfs_write_opt(sbi, ERROR_MODE, ERRORS_RO);
+                       nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_RO);
                        break;
                case Opt_err_cont:
-                       nilfs_write_opt(sbi, ERROR_MODE, ERRORS_CONT);
+                       nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_CONT);
                        break;
                case Opt_snapshot:
                        if (is_remount) {
@@ -642,13 +636,13 @@ static int parse_options(char *options, struct super_block *sb, int is_remount)
                        }
                        break;
                case Opt_norecovery:
-                       nilfs_set_opt(sbi, NORECOVERY);
+                       nilfs_set_opt(nilfs, NORECOVERY);
                        break;
                case Opt_discard:
-                       nilfs_set_opt(sbi, DISCARD);
+                       nilfs_set_opt(nilfs, DISCARD);
                        break;
                case Opt_nodiscard:
-                       nilfs_clear_opt(sbi, DISCARD);
+                       nilfs_clear_opt(nilfs, DISCARD);
                        break;
                default:
                        printk(KERN_ERR
@@ -660,22 +654,24 @@ static int parse_options(char *options, struct super_block *sb, int is_remount)
 }
 
 static inline void
-nilfs_set_default_options(struct nilfs_sb_info *sbi,
+nilfs_set_default_options(struct super_block *sb,
                          struct nilfs_super_block *sbp)
 {
-       sbi->s_mount_opt =
+       struct the_nilfs *nilfs = sb->s_fs_info;
+
+       nilfs->ns_mount_opt =
                NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER;
 }
 
-static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount)
+static int nilfs_setup_super(struct super_block *sb, int is_mount)
 {
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_super_block **sbp;
        int max_mnt_count;
        int mnt_count;
 
        /* nilfs->ns_sem must be locked by the caller. */
-       sbp = nilfs_prepare_super(sbi, 0);
+       sbp = nilfs_prepare_super(sb, 0);
        if (!sbp)
                return -EIO;
 
@@ -706,7 +702,7 @@ skip_mount_setup:
        /* synchronize sbp[1] with sbp[0] */
        if (sbp[1])
                memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
-       return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
+       return nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL);
 }
 
 struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb,
@@ -727,7 +723,7 @@ int nilfs_store_magic_and_option(struct super_block *sb,
                                 struct nilfs_super_block *sbp,
                                 char *data)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
+       struct the_nilfs *nilfs = sb->s_fs_info;
 
        sb->s_magic = le16_to_cpu(sbp->s_magic);
 
@@ -736,12 +732,12 @@ int nilfs_store_magic_and_option(struct super_block *sb,
        sb->s_flags |= MS_NOATIME;
 #endif
 
-       nilfs_set_default_options(sbi, sbp);
+       nilfs_set_default_options(sb, sbp);
 
-       sbi->s_resuid = le16_to_cpu(sbp->s_def_resuid);
-       sbi->s_resgid = le16_to_cpu(sbp->s_def_resgid);
-       sbi->s_interval = le32_to_cpu(sbp->s_c_interval);
-       sbi->s_watermark = le32_to_cpu(sbp->s_c_block_max);
+       nilfs->ns_resuid = le16_to_cpu(sbp->s_def_resuid);
+       nilfs->ns_resgid = le16_to_cpu(sbp->s_def_resgid);
+       nilfs->ns_interval = le32_to_cpu(sbp->s_c_interval);
+       nilfs->ns_watermark = le32_to_cpu(sbp->s_c_block_max);
 
        return !parse_options(data, sb, 0) ? -EINVAL : 0 ;
 }
@@ -822,7 +818,7 @@ static int nilfs_get_root_dentry(struct super_block *sb,
 static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
                                 struct dentry **root_dentry)
 {
-       struct the_nilfs *nilfs = NILFS_SB(s)->s_nilfs;
+       struct the_nilfs *nilfs = s->s_fs_info;
        struct nilfs_root *root;
        int ret;
 
@@ -840,7 +836,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
                goto out;
        }
 
-       ret = nilfs_attach_checkpoint(NILFS_SB(s), cno, false, &root);
+       ret = nilfs_attach_checkpoint(s, cno, false, &root);
        if (ret) {
                printk(KERN_ERR "NILFS: error loading snapshot "
                       "(checkpoint number=%llu).\n",
@@ -874,7 +870,7 @@ static int nilfs_try_to_shrink_tree(struct dentry *root_dentry)
 
 int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno)
 {
-       struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        struct nilfs_root *root;
        struct inode *inode;
        struct dentry *dentry;
@@ -887,7 +883,7 @@ int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno)
                return true;    /* protect recent checkpoints */
 
        ret = false;
-       root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno);
+       root = nilfs_lookup_root(nilfs, cno);
        if (root) {
                inode = nilfs_ilookup(sb, root, NILFS_ROOT_INO);
                if (inode) {
@@ -917,43 +913,21 @@ static int
 nilfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct the_nilfs *nilfs;
-       struct nilfs_sb_info *sbi;
        struct nilfs_root *fsroot;
        struct backing_dev_info *bdi;
        __u64 cno;
        int err;
 
-       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
+       nilfs = alloc_nilfs(sb->s_bdev);
+       if (!nilfs)
                return -ENOMEM;
 
-       sb->s_fs_info = sbi;
-       sbi->s_super = sb;
-
-       nilfs = alloc_nilfs(sb->s_bdev);
-       if (!nilfs) {
-               err = -ENOMEM;
-               goto failed_sbi;
-       }
-       sbi->s_nilfs = nilfs;
+       sb->s_fs_info = nilfs;
 
-       err = init_nilfs(nilfs, sbi, (char *)data);
+       err = init_nilfs(nilfs, sb, (char *)data);
        if (err)
                goto failed_nilfs;
 
-       spin_lock_init(&sbi->s_inode_lock);
-       INIT_LIST_HEAD(&sbi->s_dirty_files);
-
-       /*
-        * Following initialization is overlapped because
-        * nilfs_sb_info structure has been cleared at the beginning.
-        * But we reserve them to keep our interest and make ready
-        * for the future change.
-        */
-       get_random_bytes(&sbi->s_next_generation,
-                        sizeof(sbi->s_next_generation));
-       spin_lock_init(&sbi->s_next_gen_lock);
-
        sb->s_op = &nilfs_sops;
        sb->s_export_op = &nilfs_export_ops;
        sb->s_root = NULL;
@@ -962,12 +936,12 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
        sb->s_bdi = bdi ? : &default_backing_dev_info;
 
-       err = load_nilfs(nilfs, sbi);
+       err = load_nilfs(nilfs, sb);
        if (err)
                goto failed_nilfs;
 
        cno = nilfs_last_cno(nilfs);
-       err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot);
+       err = nilfs_attach_checkpoint(sb, cno, true, &fsroot);
        if (err) {
                printk(KERN_ERR "NILFS: error loading last checkpoint "
                       "(checkpoint number=%llu).\n", (unsigned long long)cno);
@@ -975,7 +949,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               err = nilfs_attach_segment_constructor(sbi, fsroot);
+               err = nilfs_attach_log_writer(sb, fsroot);
                if (err)
                        goto failed_checkpoint;
        }
@@ -988,14 +962,14 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
 
        if (!(sb->s_flags & MS_RDONLY)) {
                down_write(&nilfs->ns_sem);
-               nilfs_setup_super(sbi, true);
+               nilfs_setup_super(sb, true);
                up_write(&nilfs->ns_sem);
        }
 
        return 0;
 
  failed_segctor:
-       nilfs_detach_segment_constructor(sbi);
+       nilfs_detach_log_writer(sb);
 
  failed_checkpoint:
        nilfs_put_root(fsroot);
@@ -1007,23 +981,18 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
 
  failed_nilfs:
        destroy_nilfs(nilfs);
-
- failed_sbi:
-       sb->s_fs_info = NULL;
-       kfree(sbi);
        return err;
 }
 
 static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 {
-       struct nilfs_sb_info *sbi = NILFS_SB(sb);
-       struct the_nilfs *nilfs = sbi->s_nilfs;
+       struct the_nilfs *nilfs = sb->s_fs_info;
        unsigned long old_sb_flags;
        unsigned long old_mount_opt;
        int err;
 
        old_sb_flags = sb->s_flags;
-       old_mount_opt = sbi->s_mount_opt;
+       old_mount_opt = nilfs->ns_mount_opt;
 
        if (!parse_options(data, sb, 1)) {
                err = -EINVAL;
@@ -1043,8 +1012,8 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                goto out;
        if (*flags & MS_RDONLY) {
-               /* Shutting down the segment constructor */
-               nilfs_detach_segment_constructor(sbi);
+               /* Shutting down log writer */
+               nilfs_detach_log_writer(sb);
                sb->s_flags |= MS_RDONLY;
 
                /*
@@ -1052,7 +1021,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
                 * the RDONLY flag and then mark the partition as valid again.
                 */
                down_write(&nilfs->ns_sem);
-               nilfs_cleanup_super(sbi);
+               nilfs_cleanup_super(sb);
                up_write(&nilfs->ns_sem);
        } else {
                __u64 features;
@@ -1079,12 +1048,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
                sb->s_flags &= ~MS_RDONLY;
 
                root = NILFS_I(sb->s_root->d_inode)->i_root;
-               err = nilfs_attach_segment_constructor(sbi, root);
+               err = nilfs_attach_log_writer(sb, root);
                if (err)
                        goto restore_opts;
 
                down_write(&nilfs->ns_sem);
-               nilfs_setup_super(sbi, true);
+               nilfs_setup_super(sb, true);
                up_write(&nilfs->ns_sem);
        }
  out:
@@ -1092,13 +1061,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
 
  restore_opts:
        sb->s_flags = old_sb_flags;
-       sbi->s_mount_opt = old_mount_opt;
+       nilfs->ns_mount_opt = old_mount_opt;
        return err;
 }
 
 struct nilfs_super_data {
        struct block_device *bdev;
-       struct nilfs_sb_info *sbi;
        __u64 cno;
        int flags;
 };
index ad4ac607cf5734fda535667e898ad9b4cccaab63..d2acd1a651f31caf260d964c719fed086b43cb85 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
+#include <linux/random.h>
 #include <linux/crc32.h>
 #include "nilfs.h"
 #include "segment.h"
@@ -75,7 +76,10 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
        nilfs->ns_bdev = bdev;
        atomic_set(&nilfs->ns_ndirtyblks, 0);
        init_rwsem(&nilfs->ns_sem);
+       INIT_LIST_HEAD(&nilfs->ns_dirty_files);
        INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
+       spin_lock_init(&nilfs->ns_inode_lock);
+       spin_lock_init(&nilfs->ns_next_gen_lock);
        spin_lock_init(&nilfs->ns_last_segment_lock);
        nilfs->ns_cptree = RB_ROOT;
        spin_lock_init(&nilfs->ns_cptree_lock);
@@ -197,16 +201,16 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
 /**
  * load_nilfs - load and recover the nilfs
  * @nilfs: the_nilfs structure to be released
- * @sbi: nilfs_sb_info used to recover past segment
+ * @sb: super block isntance used to recover past segment
  *
  * load_nilfs() searches and load the latest super root,
  * attaches the last segment, and does recovery if needed.
  * The caller must call this exclusively for simultaneous mounts.
  */
-int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
+int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
 {
        struct nilfs_recovery_info ri;
-       unsigned int s_flags = sbi->s_super->s_flags;
+       unsigned int s_flags = sb->s_flags;
        int really_read_only = bdev_read_only(nilfs->ns_bdev);
        int valid_fs = nilfs_valid_fs(nilfs);
        int err;
@@ -271,7 +275,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
                        goto scan_error;
        }
 
-       err = nilfs_load_super_root(nilfs, sbi->s_super, ri.ri_super_root);
+       err = nilfs_load_super_root(nilfs, sb, ri.ri_super_root);
        if (unlikely(err)) {
                printk(KERN_ERR "NILFS: error loading super root.\n");
                goto failed;
@@ -283,7 +287,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
        if (s_flags & MS_RDONLY) {
                __u64 features;
 
-               if (nilfs_test_opt(sbi, NORECOVERY)) {
+               if (nilfs_test_opt(nilfs, NORECOVERY)) {
                        printk(KERN_INFO "NILFS: norecovery option specified. "
                               "skipping roll-forward recovery\n");
                        goto skip_recovery;
@@ -304,21 +308,21 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
                        err = -EROFS;
                        goto failed_unload;
                }
-               sbi->s_super->s_flags &= ~MS_RDONLY;
-       } else if (nilfs_test_opt(sbi, NORECOVERY)) {
+               sb->s_flags &= ~MS_RDONLY;
+       } else if (nilfs_test_opt(nilfs, NORECOVERY)) {
                printk(KERN_ERR "NILFS: recovery cancelled because norecovery "
                       "option was specified for a read/write mount\n");
                err = -EINVAL;
                goto failed_unload;
        }
 
-       err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
+       err = nilfs_salvage_orphan_logs(nilfs, sb, &ri);
        if (err)
                goto failed_unload;
 
        down_write(&nilfs->ns_sem);
        nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
-       err = nilfs_cleanup_super(sbi);
+       err = nilfs_cleanup_super(sb);
        up_write(&nilfs->ns_sem);
 
        if (err) {
@@ -330,7 +334,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
 
  skip_recovery:
        nilfs_clear_recovery_info(&ri);
-       sbi->s_super->s_flags = s_flags;
+       sb->s_flags = s_flags;
        return 0;
 
  scan_error:
@@ -344,7 +348,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
 
  failed:
        nilfs_clear_recovery_info(&ri);
-       sbi->s_super->s_flags = s_flags;
+       sb->s_flags = s_flags;
        return err;
 }
 
@@ -475,10 +479,13 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
                        return -EIO;
                }
                printk(KERN_WARNING
-                      "NILFS warning: unable to read primary superblock\n");
-       } else if (!sbp[1])
+                      "NILFS warning: unable to read primary superblock "
+                      "(blocksize = %d)\n", blocksize);
+       } else if (!sbp[1]) {
                printk(KERN_WARNING
-                      "NILFS warning: unable to read secondary superblock\n");
+                      "NILFS warning: unable to read secondary superblock "
+                      "(blocksize = %d)\n", blocksize);
+       }
 
        /*
         * Compare two super blocks and set 1 in swp if the secondary
@@ -505,7 +512,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
 
        if (!valid[!swp])
                printk(KERN_WARNING "NILFS warning: broken superblock. "
-                      "using spare superblock.\n");
+                      "using spare superblock (blocksize = %d).\n", blocksize);
        if (swp)
                nilfs_swap_super_block(nilfs);
 
@@ -519,7 +526,6 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
 /**
  * init_nilfs - initialize a NILFS instance.
  * @nilfs: the_nilfs structure
- * @sbi: nilfs_sb_info
  * @sb: super block
  * @data: mount options
  *
@@ -530,9 +536,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs,
  * Return Value: On success, 0 is returned. On error, a negative error
  * code is returned.
  */
-int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
+int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data)
 {
-       struct super_block *sb = sbi->s_super;
        struct nilfs_super_block *sbp;
        int blocksize;
        int err;
@@ -588,6 +593,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
        nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
        nilfs->ns_blocksize = blocksize;
 
+       get_random_bytes(&nilfs->ns_next_generation,
+                        sizeof(nilfs->ns_next_generation));
+
        err = nilfs_store_disk_layout(nilfs, sbp);
        if (err)
                goto failed_sbh;
index fd85e4c05c6b2b850da079b2282280754f72eaf6..f4968145c2a3ee22bdbff5fb7d4e2dd40f6fd392 100644 (file)
@@ -31,7 +31,8 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/slab.h>
-#include "sb.h"
+
+struct nilfs_sc_info;
 
 /* the_nilfs struct */
 enum {
@@ -65,13 +66,23 @@ enum {
  * @ns_last_cno: checkpoint number of the latest segment
  * @ns_prot_seq: least sequence number of segments which must not be reclaimed
  * @ns_prev_seq: base sequence number used to decide if advance log cursor
- * @ns_segctor_sem: segment constructor semaphore
+ * @ns_writer: log writer
+ * @ns_segctor_sem: semaphore protecting log write
  * @ns_dat: DAT file inode
  * @ns_cpfile: checkpoint file inode
  * @ns_sufile: segusage file inode
  * @ns_cptree: rb-tree of all mounted checkpoints (nilfs_root)
  * @ns_cptree_lock: lock protecting @ns_cptree
+ * @ns_dirty_files: list of dirty files
+ * @ns_inode_lock: lock protecting @ns_dirty_files
  * @ns_gc_inodes: dummy inodes to keep live blocks
+ * @ns_next_generation: next generation number for inodes
+ * @ns_next_gen_lock: lock protecting @ns_next_generation
+ * @ns_mount_opt: mount options
+ * @ns_resuid: uid for reserved blocks
+ * @ns_resgid: gid for reserved blocks
+ * @ns_interval: checkpoint creation interval
+ * @ns_watermark: watermark for the number of dirty buffers
  * @ns_blocksize_bits: bit length of block size
  * @ns_blocksize: block size
  * @ns_nsegments: number of segments in filesystem
@@ -131,6 +142,7 @@ struct the_nilfs {
        u64                     ns_prot_seq;
        u64                     ns_prev_seq;
 
+       struct nilfs_sc_info   *ns_writer;
        struct rw_semaphore     ns_segctor_sem;
 
        /*
@@ -145,9 +157,25 @@ struct the_nilfs {
        struct rb_root          ns_cptree;
        spinlock_t              ns_cptree_lock;
 
+       /* Dirty inode list */
+       struct list_head        ns_dirty_files;
+       spinlock_t              ns_inode_lock;
+
        /* GC inode list */
        struct list_head        ns_gc_inodes;
 
+       /* Inode allocator */
+       u32                     ns_next_generation;
+       spinlock_t              ns_next_gen_lock;
+
+       /* Mount options */
+       unsigned long           ns_mount_opt;
+
+       uid_t                   ns_resuid;
+       gid_t                   ns_resgid;
+       unsigned long           ns_interval;
+       unsigned long           ns_watermark;
+
        /* Disk layout information (static) */
        unsigned int            ns_blocksize_bits;
        unsigned int            ns_blocksize;
@@ -180,6 +208,20 @@ THE_NILFS_FNS(DISCONTINUED, discontinued)
 THE_NILFS_FNS(GC_RUNNING, gc_running)
 THE_NILFS_FNS(SB_DIRTY, sb_dirty)
 
+/*
+ * Mount option operations
+ */
+#define nilfs_clear_opt(nilfs, opt)  \
+       do { (nilfs)->ns_mount_opt &= ~NILFS_MOUNT_##opt; } while (0)
+#define nilfs_set_opt(nilfs, opt)  \
+       do { (nilfs)->ns_mount_opt |= NILFS_MOUNT_##opt; } while (0)
+#define nilfs_test_opt(nilfs, opt) ((nilfs)->ns_mount_opt & NILFS_MOUNT_##opt)
+#define nilfs_write_opt(nilfs, mask, opt)                              \
+       do { (nilfs)->ns_mount_opt =                                    \
+               (((nilfs)->ns_mount_opt & ~NILFS_MOUNT_##mask) |        \
+                NILFS_MOUNT_##opt);                                    \
+       } while (0)
+
 /**
  * struct nilfs_root - nilfs root object
  * @cno: checkpoint number
@@ -224,15 +266,14 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
 void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
 struct the_nilfs *alloc_nilfs(struct block_device *bdev);
 void destroy_nilfs(struct the_nilfs *nilfs);
-int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
-int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
+int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data);
+int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb);
 int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t);
 int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
 struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno);
 struct nilfs_root *nilfs_find_or_create_root(struct the_nilfs *nilfs,
                                             __u64 cno);
 void nilfs_put_root(struct nilfs_root *root);
-struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
 int nilfs_near_disk_full(struct the_nilfs *);
 void nilfs_fall_back_super_block(struct the_nilfs *);
 void nilfs_swap_super_block(struct the_nilfs *);
index 4c29fcf557d13d21100030c31ab98aa44b555a62..07ea8d3e6ea2d2fc6f9c984d2077ac439c3453ac 100644 (file)
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/writeback.h> /* for inode_lock */
 
 #include <asm/atomic.h>
 
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
 
+#include "../internal.h"
+
 /*
  * Recalculate the mask of events relevant to a given inode locked.
  */
@@ -237,15 +238,14 @@ out:
  * fsnotify_unmount_inodes - an sb is unmounting.  handle any watched inodes.
  * @list: list of inodes being unmounted (sb->s_inodes)
  *
- * Called with inode_lock held, protecting the unmounting super block's list
- * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay.
- * We temporarily drop inode_lock, however, and CAN block.
+ * Called during unmount with no locks held, so needs to be safe against
+ * concurrent modifiers. We temporarily drop inode_sb_list_lock and CAN block.
  */
 void fsnotify_unmount_inodes(struct list_head *list)
 {
        struct inode *inode, *next_i, *need_iput = NULL;
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
                struct inode *need_iput_tmp;
 
@@ -254,8 +254,11 @@ void fsnotify_unmount_inodes(struct list_head *list)
                 * I_WILL_FREE, or I_NEW which is fine because by that point
                 * the inode cannot have any associated watches.
                 */
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               spin_lock(&inode->i_lock);
+               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
 
                /*
                 * If i_count is zero, the inode cannot have any watches and
@@ -263,8 +266,10 @@ void fsnotify_unmount_inodes(struct list_head *list)
                 * evict all inodes with zero i_count from icache which is
                 * unnecessarily violent and may in fact be illegal to do.
                 */
-               if (!atomic_read(&inode->i_count))
+               if (!atomic_read(&inode->i_count)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
 
                need_iput_tmp = need_iput;
                need_iput = NULL;
@@ -274,22 +279,25 @@ void fsnotify_unmount_inodes(struct list_head *list)
                        __iget(inode);
                else
                        need_iput_tmp = NULL;
+               spin_unlock(&inode->i_lock);
 
                /* In case the dropping of a reference would nuke next_i. */
                if ((&next_i->i_sb_list != list) &&
-                   atomic_read(&next_i->i_count) &&
-                   !(next_i->i_state & (I_FREEING | I_WILL_FREE))) {
-                       __iget(next_i);
-                       need_iput = next_i;
+                   atomic_read(&next_i->i_count)) {
+                       spin_lock(&next_i->i_lock);
+                       if (!(next_i->i_state & (I_FREEING | I_WILL_FREE))) {
+                               __iget(next_i);
+                               need_iput = next_i;
+                       }
+                       spin_unlock(&next_i->i_lock);
                }
 
                /*
-                * We can safely drop inode_lock here because we hold
+                * We can safely drop inode_sb_list_lock here because we hold
                 * references on both inode and next_i.  Also no new inodes
-                * will be added since the umount has begun.  Finally,
-                * iprune_mutex keeps shrink_icache_memory() away.
+                * will be added since the umount has begun.
                 */
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_sb_list_lock);
 
                if (need_iput_tmp)
                        iput(need_iput_tmp);
@@ -301,7 +309,7 @@ void fsnotify_unmount_inodes(struct list_head *list)
 
                iput(inode);
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_sb_list_lock);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
 }
index 325185e514bbda65cab96525d8e2e26577be5e4e..50c00856f7308daf2237baba41c659f1d495e119 100644 (file)
@@ -91,7 +91,6 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/srcu.h>
-#include <linux/writeback.h> /* for inode_lock */
 
 #include <asm/atomic.h>
 
index 85eebff6d0d7de00928c5281e7418688c2265907..e86577d6c5c3d99e8377798dc64a950d51543540 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/mount.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/writeback.h> /* for inode_lock */
 
 #include <asm/atomic.h>
 
index 4ff028fcfd6e36a6cd576a8ce084d5486df696c4..30206b238433bac48582af6c252dc9413575de1d 100644 (file)
@@ -2,18 +2,13 @@
 
 obj-$(CONFIG_NTFS_FS) += ntfs.o
 
-ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
-            index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
-            unistr.o upcase.o
+ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
+         index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
+         unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.30\"
+ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
 
-ifeq ($(CONFIG_NTFS_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-y := -DNTFS_VERSION=\"2.1.30\"
+ccflags-$(CONFIG_NTFS_DEBUG)   += -DDEBUG
+ccflags-$(CONFIG_NTFS_RW)      += -DNTFS_RW
 
-ifeq ($(CONFIG_NTFS_RW),y)
-EXTRA_CFLAGS += -DNTFS_RW
-
-ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
-endif
index c3c2c7ac9020402d28dd0d2357ae2828c6e639a5..0b1e885b8cf8f8f72325c5a1c09d17fef64acd6f 100644 (file)
@@ -1543,8 +1543,6 @@ err_out:
  */
 const struct address_space_operations ntfs_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
-       .sync_page      = block_sync_page,      /* Currently, just unplugs the
-                                                  disk request queue. */
 #ifdef NTFS_RW
        .writepage      = ntfs_writepage,       /* Write dirty page to disk. */
 #endif /* NTFS_RW */
@@ -1560,8 +1558,6 @@ const struct address_space_operations ntfs_aops = {
  */
 const struct address_space_operations ntfs_mst_aops = {
        .readpage       = ntfs_readpage,        /* Fill page with data. */
-       .sync_page      = block_sync_page,      /* Currently, just unplugs the
-                                                  disk request queue. */
 #ifdef NTFS_RW
        .writepage      = ntfs_writepage,       /* Write dirty page to disk. */
        .set_page_dirty = __set_page_dirty_nobuffers,   /* Set the page dirty
index 6551c7cbad92954202258d8715a3d44e06bc7d4b..ef9ed854255c8d2c8b15bdaf0e99545004f05aed 100644 (file)
@@ -698,8 +698,7 @@ lock_retry_remap:
                                        "uptodate! Unplugging the disk queue "
                                        "and rescheduling.");
                        get_bh(tbh);
-                       blk_run_address_space(mapping);
-                       schedule();
+                       io_schedule();
                        put_bh(tbh);
                        if (unlikely(!buffer_uptodate(tbh)))
                                goto read_err;
index a627ed82c0a3f4c4303b8de8239e693826bc7862..0b56c6b7ec01feeb06359516f863598a3330621e 100644 (file)
@@ -54,7 +54,7 @@
  *
  * Return 1 if the attributes match and 0 if not.
  *
- * NOTE: This function runs with the inode_lock spin lock held so it is not
+ * NOTE: This function runs with the inode->i_lock spin lock held so it is not
  * allowed to sleep.
  */
 int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
@@ -98,7 +98,7 @@ int ntfs_test_inode(struct inode *vi, ntfs_attr *na)
  *
  * Return 0 on success and -errno on error.
  *
- * NOTE: This function runs with the inode_lock spin lock held so it is not
+ * NOTE: This function runs with the inode->i_lock spin lock held so it is not
  * allowed to sleep. (Hence the GFP_ATOMIC allocation.)
  */
 static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na)
index 07d9fd85435028f2ca2e0ad1b298a490741b6c70..d8a0313e99e6af42b8412e91bb44cb2d7bb410b8 100644 (file)
@@ -1,6 +1,6 @@
-EXTRA_CFLAGS += -Ifs/ocfs2
+ccflags-y := -Ifs/ocfs2
 
-EXTRA_CFLAGS += -DCATCH_BH_JBD_RACES
+ccflags-y += -DCATCH_BH_JBD_RACES
 
 obj-$(CONFIG_OCFS2_FS) +=      \
        ocfs2.o                 \
index 704f6b1742f3204ddf9eae9bb0ebbdfd0e1fcace..90f2729b7a5bc031e778fad1cf4b665409394247 100644 (file)
@@ -497,7 +497,7 @@ static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
        if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
                return -EOPNOTSUPP;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        if (value) {
index 1fbb0e20131bf39e82f1822e0de172b7889497de..daea0359e9740263a525cec5c7f645e456d9a909 100644 (file)
@@ -2043,7 +2043,6 @@ const struct address_space_operations ocfs2_aops = {
        .write_begin            = ocfs2_write_begin,
        .write_end              = ocfs2_write_end,
        .bmap                   = ocfs2_bmap,
-       .sync_page              = block_sync_page,
        .direct_IO              = ocfs2_direct_IO,
        .invalidatepage         = ocfs2_invalidatepage,
        .releasepage            = ocfs2_releasepage,
index b108e863d8f65ab23ec5921fd425a9273f78365e..1adab287bd24c814ceb042be381744b3c3fc3e7c 100644 (file)
@@ -367,11 +367,7 @@ static inline void o2hb_bio_wait_dec(struct o2hb_bio_wait_ctxt *wc,
 static void o2hb_wait_on_io(struct o2hb_region *reg,
                            struct o2hb_bio_wait_ctxt *wc)
 {
-       struct address_space *mapping = reg->hr_bdev->bd_inode->i_mapping;
-
-       blk_run_address_space(mapping);
        o2hb_bio_wait_dec(wc, 1);
-
        wait_for_completion(&wc->wc_io_complete);
 }
 
index dcebf0d920fa17cbd0bae8db9bcb2090f4a3e3a6..c8a044efbb150653c32d94460fa929944d25181f 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -Ifs/ocfs2
+ccflags-y := -Ifs/ocfs2
 
 obj-$(CONFIG_OCFS2_FS_O2CB) += ocfs2_dlm.o
 
index df69b4856d0d82fd908d64acf48472dd8c8e578f..f14be89a67016101afb74705399a7724ec6d55bf 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -Ifs/ocfs2
+ccflags-y := -Ifs/ocfs2
 
 obj-$(CONFIG_OCFS2_FS) += ocfs2_dlmfs.o
 
index 7a48681961521a957e1947ba9abdbb8d290f9cde..09de77ce002ab0f68e9e0783521f5eba3f6ae056 100644 (file)
@@ -82,7 +82,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
        }
 
        status = -EACCES;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                goto bail_unlock;
 
        if (!S_ISDIR(inode->i_mode))
index 51cd6898e7f1c1ecc16814d9b19e0f27658e0f50..1a97ba1ec3fc286550d6e325d144996d64a3d1ca 100644 (file)
@@ -831,18 +831,18 @@ static inline unsigned int ocfs2_clusters_to_megabytes(struct super_block *sb,
 
 static inline void _ocfs2_set_bit(unsigned int bit, unsigned long *bitmap)
 {
-       ext2_set_bit(bit, bitmap);
+       __test_and_set_bit_le(bit, bitmap);
 }
 #define ocfs2_set_bit(bit, addr) _ocfs2_set_bit((bit), (unsigned long *)(addr))
 
 static inline void _ocfs2_clear_bit(unsigned int bit, unsigned long *bitmap)
 {
-       ext2_clear_bit(bit, bitmap);
+       __test_and_clear_bit_le(bit, bitmap);
 }
 #define ocfs2_clear_bit(bit, addr) _ocfs2_clear_bit((bit), (unsigned long *)(addr))
 
-#define ocfs2_test_bit ext2_test_bit
-#define ocfs2_find_next_zero_bit ext2_find_next_zero_bit
-#define ocfs2_find_next_bit ext2_find_next_bit
+#define ocfs2_test_bit test_bit_le
+#define ocfs2_find_next_zero_bit find_next_zero_bit_le
+#define ocfs2_find_next_bit find_next_bit_le
 #endif  /* OCFS2_H */
 
index 8a6d34fa668a0715e349000f0706b7d6526bfe61..d738a7e493ddc07ed1b4b1fb7a30198b3d477c5f 100644 (file)
@@ -372,7 +372,6 @@ const struct address_space_operations omfs_aops = {
        .readpages = omfs_readpages,
        .writepage = omfs_writepage,
        .writepages = omfs_writepages,
-       .sync_page = block_sync_page,
        .write_begin = omfs_write_begin,
        .write_end = generic_write_end,
        .bmap = omfs_bmap,
index f83ca80cc59a1d72c8b933d7562efc853cfe3f8c..b52cf013ffa145de32e5c641aba7a3625de8cc29 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -835,17 +835,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
 
        validate_creds(cred);
 
-       /*
-        * We must always pass in a valid mount pointer.   Historically
-        * callers got away with not passing it, but we must enforce this at
-        * the earliest possible point now to avoid strange problems deep in the
-        * filesystem stack.
-        */
-       if (!mnt) {
-               printk(KERN_WARNING "%s called with NULL vfsmount\n", __func__);
-               dump_stack();
-               return ERR_PTR(-EINVAL);
-       }
+       /* We must always pass in a valid mount pointer. */
+       BUG_ON(!mnt);
 
        error = -ENFILE;
        f = get_empty_filp();
index 9c21119512b9ace640f1d6107f73b7681c4f1417..ac546975031f7dd9a0f110f9a4479c6e34cef15c 100644 (file)
@@ -290,7 +290,8 @@ ssize_t part_inflight_show(struct device *dev,
 {
        struct hd_struct *p = dev_to_part(dev);
 
-       return sprintf(buf, "%8u %8u\n", p->in_flight[0], p->in_flight[1]);
+       return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]),
+               atomic_read(&p->in_flight[1]));
 }
 
 #ifdef CONFIG_FAIL_MAKE_REQUEST
index 7c99c1cf7e5c47b70fffa60f455f30a6f18ee91e..5e4f776b0917a48bf0602d9ce8f0000f2b54d77d 100644 (file)
@@ -489,8 +489,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                vsize,
                mm ? get_mm_rss(mm) : 0,
                rsslim,
-               mm ? mm->start_code : 0,
-               mm ? mm->end_code : 0,
+               mm ? (permitted ? mm->start_code : 1) : 0,
+               mm ? (permitted ? mm->end_code : 1) : 0,
                (permitted && mm) ? mm->start_stack : 0,
                esp,
                eip,
index d49c4b5d2c3e92c1ed8a4be1ef979df91762c323..5a670c11aeacc85fd767a8383f45d39d6ac6ea7e 100644 (file)
@@ -191,17 +191,20 @@ static int proc_root_link(struct inode *inode, struct path *path)
        return result;
 }
 
-/*
- * Return zero if current may access user memory in @task, -error if not.
- */
-static int check_mem_permission(struct task_struct *task)
+static struct mm_struct *__check_mem_permission(struct task_struct *task)
 {
+       struct mm_struct *mm;
+
+       mm = get_task_mm(task);
+       if (!mm)
+               return ERR_PTR(-EINVAL);
+
        /*
         * A task can always look at itself, in case it chooses
         * to use system calls instead of load instructions.
         */
        if (task == current)
-               return 0;
+               return mm;
 
        /*
         * If current is actively ptrace'ing, and would also be
@@ -213,27 +216,53 @@ static int check_mem_permission(struct task_struct *task)
                match = (tracehook_tracer_task(task) == current);
                rcu_read_unlock();
                if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
-                       return 0;
+                       return mm;
        }
 
        /*
         * Noone else is allowed.
         */
-       return -EPERM;
+       mmput(mm);
+       return ERR_PTR(-EPERM);
+}
+
+/*
+ * If current may access user memory in @task return a reference to the
+ * corresponding mm, otherwise ERR_PTR.
+ */
+static struct mm_struct *check_mem_permission(struct task_struct *task)
+{
+       struct mm_struct *mm;
+       int err;
+
+       /*
+        * Avoid racing if task exec's as we might get a new mm but validate
+        * against old credentials.
+        */
+       err = mutex_lock_killable(&task->signal->cred_guard_mutex);
+       if (err)
+               return ERR_PTR(err);
+
+       mm = __check_mem_permission(task);
+       mutex_unlock(&task->signal->cred_guard_mutex);
+
+       return mm;
 }
 
 struct mm_struct *mm_for_maps(struct task_struct *task)
 {
        struct mm_struct *mm;
+       int err;
 
-       if (mutex_lock_killable(&task->signal->cred_guard_mutex))
-               return NULL;
+       err =  mutex_lock_killable(&task->signal->cred_guard_mutex);
+       if (err)
+               return ERR_PTR(err);
 
        mm = get_task_mm(task);
        if (mm && mm != current->mm &&
                        !ptrace_may_access(task, PTRACE_MODE_READ)) {
                mmput(mm);
-               mm = NULL;
+               mm = ERR_PTR(-EACCES);
        }
        mutex_unlock(&task->signal->cred_guard_mutex);
 
@@ -279,9 +308,9 @@ out:
 
 static int proc_pid_auxv(struct task_struct *task, char *buffer)
 {
-       int res = 0;
-       struct mm_struct *mm = get_task_mm(task);
-       if (mm) {
+       struct mm_struct *mm = mm_for_maps(task);
+       int res = PTR_ERR(mm);
+       if (mm && !IS_ERR(mm)) {
                unsigned int nwords = 0;
                do {
                        nwords += 2;
@@ -318,6 +347,23 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
 }
 #endif /* CONFIG_KALLSYMS */
 
+static int lock_trace(struct task_struct *task)
+{
+       int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
+       if (err)
+               return err;
+       if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) {
+               mutex_unlock(&task->signal->cred_guard_mutex);
+               return -EPERM;
+       }
+       return 0;
+}
+
+static void unlock_trace(struct task_struct *task)
+{
+       mutex_unlock(&task->signal->cred_guard_mutex);
+}
+
 #ifdef CONFIG_STACKTRACE
 
 #define MAX_STACK_TRACE_DEPTH  64
@@ -327,6 +373,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
 {
        struct stack_trace trace;
        unsigned long *entries;
+       int err;
        int i;
 
        entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL);
@@ -337,15 +384,20 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
        trace.max_entries       = MAX_STACK_TRACE_DEPTH;
        trace.entries           = entries;
        trace.skip              = 0;
-       save_stack_trace_tsk(task, &trace);
 
-       for (i = 0; i < trace.nr_entries; i++) {
-               seq_printf(m, "[<%p>] %pS\n",
-                          (void *)entries[i], (void *)entries[i]);
+       err = lock_trace(task);
+       if (!err) {
+               save_stack_trace_tsk(task, &trace);
+
+               for (i = 0; i < trace.nr_entries; i++) {
+                       seq_printf(m, "[<%pK>] %pS\n",
+                                  (void *)entries[i], (void *)entries[i]);
+               }
+               unlock_trace(task);
        }
        kfree(entries);
 
-       return 0;
+       return err;
 }
 #endif
 
@@ -508,18 +560,22 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer)
 {
        long nr;
        unsigned long args[6], sp, pc;
+       int res = lock_trace(task);
+       if (res)
+               return res;
 
        if (task_current_syscall(task, &nr, args, 6, &sp, &pc))
-               return sprintf(buffer, "running\n");
-
-       if (nr < 0)
-               return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc);
-
-       return sprintf(buffer,
+               res = sprintf(buffer, "running\n");
+       else if (nr < 0)
+               res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc);
+       else
+               res = sprintf(buffer,
                       "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
                       nr,
                       args[0], args[1], args[2], args[3], args[4], args[5],
                       sp, pc);
+       unlock_trace(task);
+       return res;
 }
 #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
 
@@ -775,18 +831,14 @@ static ssize_t mem_read(struct file * file, char __user * buf,
        if (!task)
                goto out_no_task;
 
-       if (check_mem_permission(task))
-               goto out;
-
        ret = -ENOMEM;
        page = (char *)__get_free_page(GFP_TEMPORARY);
        if (!page)
                goto out;
 
-       ret = 0;
-       mm = get_task_mm(task);
-       if (!mm)
+       mm = check_mem_permission(task);
+       ret = PTR_ERR(mm);
+       if (IS_ERR(mm))
                goto out_free;
 
        ret = -EIO;
@@ -800,8 +852,8 @@ static ssize_t mem_read(struct file * file, char __user * buf,
                int this_len, retval;
 
                this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
-               retval = access_process_vm(task, src, page, this_len, 0);
-               if (!retval || check_mem_permission(task)) {
+               retval = access_remote_vm(mm, src, page, this_len, 0);
+               if (!retval) {
                        if (!ret)
                                ret = -EIO;
                        break;
@@ -829,10 +881,6 @@ out_no_task:
        return ret;
 }
 
-#define mem_write NULL
-
-#ifndef mem_write
-/* This is a security hazard */
 static ssize_t mem_write(struct file * file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
@@ -840,18 +888,25 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
        char *page;
        struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        unsigned long dst = *ppos;
+       struct mm_struct *mm;
 
        copied = -ESRCH;
        if (!task)
                goto out_no_task;
 
-       if (check_mem_permission(task))
-               goto out;
+       mm = check_mem_permission(task);
+       copied = PTR_ERR(mm);
+       if (IS_ERR(mm))
+               goto out_task;
+
+       copied = -EIO;
+       if (file->private_data != (void *)((long)current->self_exec_id))
+               goto out_mm;
 
        copied = -ENOMEM;
        page = (char *)__get_free_page(GFP_TEMPORARY);
        if (!page)
-               goto out;
+               goto out_mm;
 
        copied = 0;
        while (count > 0) {
@@ -862,7 +917,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
                        copied = -EFAULT;
                        break;
                }
-               retval = access_process_vm(task, dst, page, this_len, 1);
+               retval = access_remote_vm(mm, dst, page, this_len, 1);
                if (!retval) {
                        if (!copied)
                                copied = -EIO;
@@ -875,12 +930,13 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
        }
        *ppos = dst;
        free_page((unsigned long) page);
-out:
+out_mm:
+       mmput(mm);
+out_task:
        put_task_struct(task);
 out_no_task:
        return copied;
 }
-#endif
 
 loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 {
@@ -917,20 +973,18 @@ static ssize_t environ_read(struct file *file, char __user *buf,
        if (!task)
                goto out_no_task;
 
-       if (!ptrace_may_access(task, PTRACE_MODE_READ))
-               goto out;
-
        ret = -ENOMEM;
        page = (char *)__get_free_page(GFP_TEMPORARY);
        if (!page)
                goto out;
 
-       ret = 0;
 
-       mm = get_task_mm(task);
-       if (!mm)
+       mm = mm_for_maps(task);
+       ret = PTR_ERR(mm);
+       if (!mm || IS_ERR(mm))
                goto out_free;
 
+       ret = 0;
        while (count > 0) {
                int this_len, retval, max_len;
 
@@ -2748,8 +2802,12 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
 static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task)
 {
-       seq_printf(m, "%08x\n", task->personality);
-       return 0;
+       int err = lock_trace(task);
+       if (!err) {
+               seq_printf(m, "%08x\n", task->personality);
+               unlock_trace(task);
+       }
+       return err;
 }
 
 /*
@@ -2768,7 +2826,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("environ",    S_IRUSR, proc_environ_operations),
        INF("auxv",       S_IRUSR, proc_pid_auxv),
        ONE("status",     S_IRUGO, proc_pid_status),
-       ONE("personality", S_IRUSR, proc_pid_personality),
+       ONE("personality", S_IRUGO, proc_pid_personality),
        INF("limits",     S_IRUGO, proc_pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, proc_pid_sched_operations),
@@ -2778,7 +2836,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #endif
        REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
-       INF("syscall",    S_IRUSR, proc_pid_syscall),
+       INF("syscall",    S_IRUGO, proc_pid_syscall),
 #endif
        INF("cmdline",    S_IRUGO, proc_pid_cmdline),
        ONE("stat",       S_IRUGO, proc_tgid_stat),
@@ -2797,7 +2855,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
        REG("smaps",      S_IRUGO, proc_smaps_operations),
-       REG("pagemap",    S_IRUSR, proc_pagemap_operations),
+       REG("pagemap",    S_IRUGO, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",       S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
@@ -2806,7 +2864,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        INF("wchan",      S_IRUGO, proc_pid_wchan),
 #endif
 #ifdef CONFIG_STACKTRACE
-       ONE("stack",      S_IRUSR, proc_pid_stack),
+       ONE("stack",      S_IRUGO, proc_pid_stack),
 #endif
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat",  S_IRUGO, proc_pid_schedstat),
@@ -3108,14 +3166,14 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("environ",   S_IRUSR, proc_environ_operations),
        INF("auxv",      S_IRUSR, proc_pid_auxv),
        ONE("status",    S_IRUGO, proc_pid_status),
-       ONE("personality", S_IRUSR, proc_pid_personality),
+       ONE("personality", S_IRUGO, proc_pid_personality),
        INF("limits",    S_IRUGO, proc_pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, proc_pid_sched_operations),
 #endif
        REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
-       INF("syscall",   S_IRUSR, proc_pid_syscall),
+       INF("syscall",   S_IRUGO, proc_pid_syscall),
 #endif
        INF("cmdline",   S_IRUGO, proc_pid_cmdline),
        ONE("stat",      S_IRUGO, proc_tid_stat),
@@ -3133,7 +3191,7 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
        REG("smaps",     S_IRUGO, proc_smaps_operations),
-       REG("pagemap",    S_IRUSR, proc_pagemap_operations),
+       REG("pagemap",    S_IRUGO, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",      S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
@@ -3142,7 +3200,7 @@ static const struct pid_entry tid_base_stuff[] = {
        INF("wchan",     S_IRUGO, proc_pid_wchan),
 #endif
 #ifdef CONFIG_STACKTRACE
-       ONE("stack",      S_IRUSR, proc_pid_stack),
+       ONE("stack",      S_IRUGO, proc_pid_stack),
 #endif
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat", S_IRUGO, proc_pid_schedstat),
@@ -3161,7 +3219,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
 #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),
-       REG("sessionid",  S_IRUSR, proc_sessionid_operations),
+       REG("sessionid",  S_IRUGO, proc_sessionid_operations),
 #endif
 #ifdef CONFIG_FAULT_INJECTION
        REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
index 01e07f2a188fb0d58686d14b36e63e02b7dea08b..f1281339b6fadc27ab1237e2d0191f666b0ed5ce 100644 (file)
@@ -28,7 +28,7 @@
 
 DEFINE_SPINLOCK(proc_subdir_lock);
 
-static int proc_match(int len, const char *name, struct proc_dir_entry *de)
+static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de)
 {
        if (de->namelen != len)
                return 0;
@@ -303,7 +303,7 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
 {
        const char              *cp = name, *next;
        struct proc_dir_entry   *de;
-       int                     len;
+       unsigned int            len;
 
        de = *ret;
        if (!de)
@@ -602,7 +602,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
 {
        struct proc_dir_entry *ent = NULL;
        const char *fn = name;
-       int len;
+       unsigned int len;
 
        /* make sure name is valid */
        if (!name || !strlen(name)) goto out;
@@ -786,7 +786,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
        struct proc_dir_entry **p;
        struct proc_dir_entry *de = NULL;
        const char *fn = name;
-       int len;
+       unsigned int len;
 
        spin_lock(&proc_subdir_lock);
        if (__xlate_proc_name(name, &parent, &fn) != 0) {
index d6a7ca1fdac53dfdf47fb7109207c0ec7597a3e7..d15aa1b1cc8fea9f9a7e702849035095e38f4613 100644 (file)
@@ -46,8 +46,6 @@ static void proc_evict_inode(struct inode *inode)
        }
 }
 
-struct vfsmount *proc_mnt;
-
 static struct kmem_cache * proc_inode_cachep;
 
 static struct inode *proc_alloc_inode(struct super_block *sb)
index 9ad561ded4092a83301db4cd5d6c7f0be37740ce..c03e8d3a3a5b550ef8b88bc60776b48b42795065 100644 (file)
@@ -107,7 +107,6 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde)
 }
 void pde_put(struct proc_dir_entry *pde);
 
-extern struct vfsmount *proc_mnt;
 int proc_fill_super(struct super_block *);
 struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
 
index ef9fa8e24ad65f9b13a2a4cb989a14466ac3db8b..a9000e9cfee54ac804eb71e75d0b72bf989041ed 100644 (file)
@@ -43,17 +43,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
        struct pid_namespace *ns;
        struct proc_inode *ei;
 
-       if (proc_mnt) {
-               /* Seed the root directory with a pid so it doesn't need
-                * to be special in base.c.  I would do this earlier but
-                * the only task alive when /proc is mounted the first time
-                * is the init_task and it doesn't have any pids.
-                */
-               ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode);
-               if (!ei->pid)
-                       ei->pid = find_get_pid(1);
-       }
-
        if (flags & MS_KERNMOUNT)
                ns = (struct pid_namespace *)data;
        else
@@ -71,16 +60,16 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
                        return ERR_PTR(err);
                }
 
-               ei = PROC_I(sb->s_root->d_inode);
-               if (!ei->pid) {
-                       rcu_read_lock();
-                       ei->pid = get_pid(find_pid_ns(1, ns));
-                       rcu_read_unlock();
-               }
-
                sb->s_flags |= MS_ACTIVE;
        }
 
+       ei = PROC_I(sb->s_root->d_inode);
+       if (!ei->pid) {
+               rcu_read_lock();
+               ei->pid = get_pid(find_pid_ns(1, ns));
+               rcu_read_unlock();
+       }
+
        return dget(sb->s_root);
 }
 
@@ -101,19 +90,20 @@ static struct file_system_type proc_fs_type = {
 
 void __init proc_root_init(void)
 {
+       struct vfsmount *mnt;
        int err;
 
        proc_init_inodecache();
        err = register_filesystem(&proc_fs_type);
        if (err)
                return;
-       proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);
-       if (IS_ERR(proc_mnt)) {
+       mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);
+       if (IS_ERR(mnt)) {
                unregister_filesystem(&proc_fs_type);
                return;
        }
 
-       init_pid_ns.proc_mnt = proc_mnt;
+       init_pid_ns.proc_mnt = mnt;
        proc_symlink("mounts", NULL, "self/mounts");
 
        proc_net_init();
index 60b914860f815e146d8ae5fea8eefae2dcaf95ea..7c708a418acc38412f4a4d77626be3dc4b39e03f 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
+#include <linux/huge_mm.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/highmem.h>
@@ -7,6 +8,7 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
+#include <linux/rmap.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
 
@@ -119,14 +121,14 @@ static void *m_start(struct seq_file *m, loff_t *pos)
 
        priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
        if (!priv->task)
-               return NULL;
+               return ERR_PTR(-ESRCH);
 
        mm = mm_for_maps(priv->task);
-       if (!mm)
-               return NULL;
+       if (!mm || IS_ERR(mm))
+               return mm;
        down_read(&mm->mmap_sem);
 
-       tail_vma = get_gate_vma(priv->task);
+       tail_vma = get_gate_vma(priv->task->mm);
        priv->tail_vma = tail_vma;
 
        /* Start with last addr hint */
@@ -249,8 +251,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
                const char *name = arch_vma_name(vma);
                if (!name) {
                        if (mm) {
-                               if (vma->vm_start <= mm->start_brk &&
-                                               vma->vm_end >= mm->brk) {
+                               if (vma->vm_start <= mm->brk &&
+                                               vma->vm_end >= mm->start_brk) {
                                        name = "[heap]";
                                } else if (vma->vm_start <= mm->start_stack &&
                                           vma->vm_end >= mm->start_stack) {
@@ -277,7 +279,8 @@ static int show_map(struct seq_file *m, void *v)
        show_map_vma(m, vma);
 
        if (m->count < m->size)  /* vma is copied successfully */
-               m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
+               m->version = (vma != get_gate_vma(task->mm))
+                       ? vma->vm_start : 0;
        return 0;
 }
 
@@ -329,58 +332,86 @@ struct mem_size_stats {
        unsigned long private_dirty;
        unsigned long referenced;
        unsigned long anonymous;
+       unsigned long anonymous_thp;
        unsigned long swap;
        u64 pss;
 };
 
-static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
-                          struct mm_walk *walk)
+
+static void smaps_pte_entry(pte_t ptent, unsigned long addr,
+               unsigned long ptent_size, struct mm_walk *walk)
 {
        struct mem_size_stats *mss = walk->private;
        struct vm_area_struct *vma = mss->vma;
-       pte_t *pte, ptent;
-       spinlock_t *ptl;
        struct page *page;
        int mapcount;
 
-       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-       for (; addr != end; pte++, addr += PAGE_SIZE) {
-               ptent = *pte;
-
-               if (is_swap_pte(ptent)) {
-                       mss->swap += PAGE_SIZE;
-                       continue;
-               }
+       if (is_swap_pte(ptent)) {
+               mss->swap += ptent_size;
+               return;
+       }
 
-               if (!pte_present(ptent))
-                       continue;
+       if (!pte_present(ptent))
+               return;
+
+       page = vm_normal_page(vma, addr, ptent);
+       if (!page)
+               return;
+
+       if (PageAnon(page))
+               mss->anonymous += ptent_size;
+
+       mss->resident += ptent_size;
+       /* Accumulate the size in pages that have been accessed. */
+       if (pte_young(ptent) || PageReferenced(page))
+               mss->referenced += ptent_size;
+       mapcount = page_mapcount(page);
+       if (mapcount >= 2) {
+               if (pte_dirty(ptent) || PageDirty(page))
+                       mss->shared_dirty += ptent_size;
+               else
+                       mss->shared_clean += ptent_size;
+               mss->pss += (ptent_size << PSS_SHIFT) / mapcount;
+       } else {
+               if (pte_dirty(ptent) || PageDirty(page))
+                       mss->private_dirty += ptent_size;
+               else
+                       mss->private_clean += ptent_size;
+               mss->pss += (ptent_size << PSS_SHIFT);
+       }
+}
 
-               page = vm_normal_page(vma, addr, ptent);
-               if (!page)
-                       continue;
+static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+                          struct mm_walk *walk)
+{
+       struct mem_size_stats *mss = walk->private;
+       struct vm_area_struct *vma = mss->vma;
+       pte_t *pte;
+       spinlock_t *ptl;
 
-               if (PageAnon(page))
-                       mss->anonymous += PAGE_SIZE;
-
-               mss->resident += PAGE_SIZE;
-               /* Accumulate the size in pages that have been accessed. */
-               if (pte_young(ptent) || PageReferenced(page))
-                       mss->referenced += PAGE_SIZE;
-               mapcount = page_mapcount(page);
-               if (mapcount >= 2) {
-                       if (pte_dirty(ptent) || PageDirty(page))
-                               mss->shared_dirty += PAGE_SIZE;
-                       else
-                               mss->shared_clean += PAGE_SIZE;
-                       mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
+       spin_lock(&walk->mm->page_table_lock);
+       if (pmd_trans_huge(*pmd)) {
+               if (pmd_trans_splitting(*pmd)) {
+                       spin_unlock(&walk->mm->page_table_lock);
+                       wait_split_huge_page(vma->anon_vma, pmd);
                } else {
-                       if (pte_dirty(ptent) || PageDirty(page))
-                               mss->private_dirty += PAGE_SIZE;
-                       else
-                               mss->private_clean += PAGE_SIZE;
-                       mss->pss += (PAGE_SIZE << PSS_SHIFT);
+                       smaps_pte_entry(*(pte_t *)pmd, addr,
+                                       HPAGE_PMD_SIZE, walk);
+                       spin_unlock(&walk->mm->page_table_lock);
+                       mss->anonymous_thp += HPAGE_PMD_SIZE;
+                       return 0;
                }
+       } else {
+               spin_unlock(&walk->mm->page_table_lock);
        }
+       /*
+        * The mmap_sem held all the way back in m_start() is what
+        * keeps khugepaged out of here and from collapsing things
+        * in here.
+        */
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       for (; addr != end; pte++, addr += PAGE_SIZE)
+               smaps_pte_entry(*pte, addr, PAGE_SIZE, walk);
        pte_unmap_unlock(pte - 1, ptl);
        cond_resched();
        return 0;
@@ -416,6 +447,7 @@ static int show_smap(struct seq_file *m, void *v)
                   "Private_Dirty:  %8lu kB\n"
                   "Referenced:     %8lu kB\n"
                   "Anonymous:      %8lu kB\n"
+                  "AnonHugePages:  %8lu kB\n"
                   "Swap:           %8lu kB\n"
                   "KernelPageSize: %8lu kB\n"
                   "MMUPageSize:    %8lu kB\n"
@@ -429,6 +461,7 @@ static int show_smap(struct seq_file *m, void *v)
                   mss.private_dirty >> 10,
                   mss.referenced >> 10,
                   mss.anonymous >> 10,
+                  mss.anonymous_thp >> 10,
                   mss.swap >> 10,
                   vma_kernel_pagesize(vma) >> 10,
                   vma_mmu_pagesize(vma) >> 10,
@@ -436,7 +469,8 @@ static int show_smap(struct seq_file *m, void *v)
                        (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
 
        if (m->count < m->size)  /* vma is copied successfully */
-               m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
+               m->version = (vma != get_gate_vma(task->mm))
+                       ? vma->vm_start : 0;
        return 0;
 }
 
@@ -467,6 +501,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
        spinlock_t *ptl;
        struct page *page;
 
+       split_huge_page_pmd(walk->mm, pmd);
+
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        for (; addr != end; pte++, addr += PAGE_SIZE) {
                ptent = *pte;
@@ -623,6 +659,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        pte_t *pte;
        int err = 0;
 
+       split_huge_page_pmd(walk->mm, pmd);
+
        /* find the first VMA at or above 'addr' */
        vma = find_vma(walk->mm, addr);
        for (; addr != end; addr += PAGE_SIZE) {
@@ -728,8 +766,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (!task)
                goto out;
 
-       ret = -EACCES;
-       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+       mm = mm_for_maps(task);
+       ret = PTR_ERR(mm);
+       if (!mm || IS_ERR(mm))
                goto out_task;
 
        ret = -EINVAL;
@@ -742,10 +781,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (!count)
                goto out_task;
 
-       mm = get_task_mm(task);
-       if (!mm)
-               goto out_task;
-
        pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
        pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
        ret = -ENOMEM;
index b535d3e5d5f19ede72090e9d06b8f1dcf0e09cd3..980de547c0709b758307dce07a6e81ea9a9c59bd 100644 (file)
@@ -199,13 +199,13 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        /* pin the task and mm whilst we play with them */
        priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
        if (!priv->task)
-               return NULL;
+               return ERR_PTR(-ESRCH);
 
        mm = mm_for_maps(priv->task);
-       if (!mm) {
+       if (!mm || IS_ERR(mm)) {
                put_task_struct(priv->task);
                priv->task = NULL;
-               return NULL;
+               return mm;
        }
        down_read(&mm->mmap_sem);
 
index 08342232cb1c4f82ddb07db1fc4c8fcb9908d72b..977ed272384574e0220bdfe06439ea3cdd045ad5 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/string.h>
 #include <linux/mount.h>
 #include <linux/ramfs.h>
+#include <linux/parser.h>
 #include <linux/sched.h>
 #include <linux/magic.h>
 #include <linux/pstore.h>
@@ -73,11 +74,16 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
        struct pstore_private *p = dentry->d_inode->i_private;
 
        p->erase(p->id);
-       kfree(p);
 
        return simple_unlink(dir, dentry);
 }
 
+static void pstore_evict_inode(struct inode *inode)
+{
+       end_writeback(inode);
+       kfree(inode->i_private);
+}
+
 static const struct inode_operations pstore_dir_inode_operations = {
        .lookup         = simple_lookup,
        .unlink         = pstore_unlink,
@@ -107,9 +113,52 @@ static struct inode *pstore_get_inode(struct super_block *sb,
        return inode;
 }
 
+enum {
+       Opt_kmsg_bytes, Opt_err
+};
+
+static const match_table_t tokens = {
+       {Opt_kmsg_bytes, "kmsg_bytes=%u"},
+       {Opt_err, NULL}
+};
+
+static void parse_options(char *options)
+{
+       char            *p;
+       substring_t     args[MAX_OPT_ARGS];
+       int             option;
+
+       if (!options)
+               return;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_kmsg_bytes:
+                       if (!match_int(&args[0], &option))
+                               pstore_set_kmsg_bytes(option);
+                       break;
+               }
+       }
+}
+
+static int pstore_remount(struct super_block *sb, int *flags, char *data)
+{
+       parse_options(data);
+
+       return 0;
+}
+
 static const struct super_operations pstore_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
+       .evict_inode    = pstore_evict_inode,
+       .remount_fs     = pstore_remount,
        .show_options   = generic_show_options,
 };
 
@@ -209,6 +258,8 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_op                = &pstore_ops;
        sb->s_time_gran         = 1;
 
+       parse_options(data);
+
        inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0);
        if (!inode) {
                err = -ENOMEM;
@@ -252,28 +303,7 @@ static struct file_system_type pstore_fs_type = {
 
 static int __init init_pstore_fs(void)
 {
-       int rc = 0;
-       struct kobject *pstorefs_kobj;
-
-       pstorefs_kobj = kobject_create_and_add("pstore", fs_kobj);
-       if (!pstorefs_kobj) {
-               rc = -ENOMEM;
-               goto done;
-       }
-
-       rc = sysfs_create_file(pstorefs_kobj, &pstore_kmsg_bytes_attr.attr);
-       if (rc)
-               goto done1;
-
-       rc = register_filesystem(&pstore_fs_type);
-       if (rc == 0)
-               goto done;
-
-       sysfs_remove_file(pstorefs_kobj, &pstore_kmsg_bytes_attr.attr);
-done1:
-       kobject_put(pstorefs_kobj);
-done:
-       return rc;
+       return register_filesystem(&pstore_fs_type);
 }
 module_init(init_pstore_fs)
 
index 76c26d2fab2925e2f4835e7707fb55a88b5e74c0..8c9f23eb16451a294cfb1b379c8cb8b55c40565d 100644 (file)
@@ -1,7 +1,6 @@
+extern void    pstore_set_kmsg_bytes(int);
 extern void    pstore_get_records(void);
 extern int     pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
                              char *data, size_t size,
                              struct timespec time, int (*erase)(u64));
 extern int     pstore_is_mounted(void);
-
-extern struct kobj_attribute pstore_kmsg_bytes_attr;
index 705fdf8abf6e5b838481029576b86879b8f79152..f835a25625ff5c7e74e5834cc9e6057697d02941 100644 (file)
 static DEFINE_SPINLOCK(pstore_lock);
 static struct pstore_info *psinfo;
 
-/* How much of the console log to snapshot. /sys/fs/pstore/kmsg_bytes */
+/* How much of the console log to snapshot */
 static unsigned long kmsg_bytes = 10240;
 
-static ssize_t b_show(struct kobject *kobj,
-                     struct kobj_attribute *attr, char *buf)
+void pstore_set_kmsg_bytes(int bytes)
 {
-       return snprintf(buf, PAGE_SIZE, "%lu\n", kmsg_bytes);
+       kmsg_bytes = bytes;
 }
 
-static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
-                      const char *buf, size_t count)
-{
-       return (sscanf(buf, "%lu", &kmsg_bytes) > 0) ? count : 0;
-}
-
-struct kobj_attribute pstore_kmsg_bytes_attr =
-       __ATTR(kmsg_bytes, S_IRUGO | S_IWUSR, b_show, b_store);
-
 /* Tag each group of saved records with a sequence number */
 static int     oopscount;
 
+static char *reason_str[] = {
+       "Oops", "Panic", "Kexec", "Restart", "Halt", "Poweroff", "Emergency"
+};
+
 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
  * written bytes, older bytes are in (s1,l1). Save as much
@@ -71,15 +65,20 @@ static void pstore_dump(struct kmsg_dumper *dumper,
        unsigned long   s1_start, s2_start;
        unsigned long   l1_cpy, l2_cpy;
        unsigned long   size, total = 0;
-       char            *dst;
+       char            *dst, *why;
        u64             id;
        int             hsize, part = 1;
 
+       if (reason < ARRAY_SIZE(reason_str))
+               why = reason_str[reason];
+       else
+               why = "Unknown";
+
        mutex_lock(&psinfo->buf_mutex);
        oopscount++;
        while (total < kmsg_bytes) {
                dst = psinfo->buf;
-               hsize = sprintf(dst, "Oops#%d Part%d\n", oopscount, part++);
+               hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++);
                size = psinfo->bufsize - hsize;
                dst += hsize;
 
@@ -96,7 +95,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
                memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
 
                id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy);
-               if (pstore_is_mounted())
+               if (reason == KMSG_DUMP_OOPS && pstore_is_mounted())
                        pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id,
                                      psinfo->buf, hsize + l1_cpy + l2_cpy,
                                      CURRENT_TIME, psinfo->erase);
index e63b4171d583bca9f5f32bc106eacac52ba89fde..2b0646613f5a1f86da0637e7c131dc36c28e9005 100644 (file)
@@ -335,7 +335,6 @@ static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 static const struct address_space_operations qnx4_aops = {
        .readpage       = qnx4_readpage,
        .writepage      = qnx4_writepage,
-       .sync_page      = block_sync_page,
        .write_begin    = qnx4_write_begin,
        .write_end      = generic_write_end,
        .bmap           = qnx4_bmap
index a2a622e079f08f55c5dfe2a8b40c8b8c59a04db5..fcc8ae75d8743383c8a3436a867bb8c12b1b08b9 100644 (file)
@@ -76,7 +76,7 @@
 #include <linux/buffer_head.h>
 #include <linux/capability.h>
 #include <linux/quotaops.h>
-#include <linux/writeback.h> /* for inode_lock, oddly enough.. */
+#include "../internal.h" /* ugh */
 
 #include <asm/uaccess.h>
 
@@ -900,33 +900,38 @@ static void add_dquot_ref(struct super_block *sb, int type)
        int reserved = 0;
 #endif
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
+               spin_lock(&inode->i_lock);
+               if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
+                   !atomic_read(&inode->i_writecount) ||
+                   !dqinit_needed(inode, type)) {
+                       spin_unlock(&inode->i_lock);
                        continue;
+               }
 #ifdef CONFIG_QUOTA_DEBUG
                if (unlikely(inode_get_rsv_space(inode) > 0))
                        reserved = 1;
 #endif
-               if (!atomic_read(&inode->i_writecount))
-                       continue;
-               if (!dqinit_needed(inode, type))
-                       continue;
-
                __iget(inode);
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_sb_list_lock);
 
                iput(old_inode);
                __dquot_initialize(inode, type);
-               /* We hold a reference to 'inode' so it couldn't have been
-                * removed from s_inodes list while we dropped the inode_lock.
-                * We cannot iput the inode now as we can be holding the last
-                * reference and we cannot iput it under inode_lock. So we
-                * keep the reference and iput it later. */
+
+               /*
+                * We hold a reference to 'inode' so it couldn't have been
+                * removed from s_inodes list while we dropped the
+                * inode_sb_list_lock We cannot iput the inode now as we can be
+                * holding the last reference and we cannot iput it under
+                * inode_sb_list_lock. So we keep the reference and iput it
+                * later.
+                */
                old_inode = inode;
-               spin_lock(&inode_lock);
+               spin_lock(&inode_sb_list_lock);
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
        iput(old_inode);
 
 #ifdef CONFIG_QUOTA_DEBUG
@@ -1007,7 +1012,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,
        struct inode *inode;
        int reserved = 0;
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_sb_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                /*
                 *  We have to scan also I_NEW inodes because they can already
@@ -1021,7 +1026,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,
                        remove_inode_dquot_ref(inode, type, tofree_head);
                }
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_sb_list_lock);
 #ifdef CONFIG_QUOTA_DEBUG
        if (reserved) {
                printk(KERN_WARNING "VFS (%s): Writes happened after quota"
index 792b3cb2cd18a745772e8d6e138656c1c5314eaf..3c3b00165114c8023d4e8e98c1cafb9474095039 100644 (file)
@@ -31,9 +31,7 @@ endif
 # and causing a panic. Since this behavior only affects ppc32, this ifeq
 # will work around it. If any other architecture displays this behavior,
 # add it here.
-ifeq ($(CONFIG_PPC32),y)
-EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0400, -O1)
-endif
+ccflags-$(CONFIG_PPC32) := $(call cc-ifversion, -lt, 0400, -O1)
 
 TAGS:
        etags *.c
index 1bba24bad82080382e3007a10da67b85305d88db..4fd5bb33dbb5e40f4969e38d7c4b52756d8bfab7 100644 (file)
@@ -3217,7 +3217,6 @@ const struct address_space_operations reiserfs_address_space_operations = {
        .readpages = reiserfs_readpages,
        .releasepage = reiserfs_releasepage,
        .invalidatepage = reiserfs_invalidatepage,
-       .sync_page = block_sync_page,
        .write_begin = reiserfs_write_begin,
        .write_end = reiserfs_write_end,
        .bmap = reiserfs_aop_bmap,
index 79265fdc317a09889c6ce3c2343bb17594bce40e..4e153051bc75bf691f2352c8bf3c177613195f40 100644 (file)
@@ -59,7 +59,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                        if (err)
                                break;
 
-                       if (!is_owner_or_cap(inode)) {
+                       if (!inode_owner_or_capable(inode)) {
                                err = -EPERM;
                                goto setflags_out;
                        }
@@ -103,7 +103,7 @@ setflags_out:
                err = put_user(inode->i_generation, (int __user *)arg);
                break;
        case REISERFS_IOC_SETVERSION:
-               if (!is_owner_or_cap(inode)) {
+               if (!inode_owner_or_capable(inode)) {
                        err = -EPERM;
                        break;
                }
index 90d2fcb67a314633a4f3855dc08e057a43390a40..3dc38f1206fc06a6757521a399263edca7d1f844 100644 (file)
@@ -26,7 +26,7 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value,
        size_t jcreate_blocks;
        if (!reiserfs_posixacl(inode->i_sb))
                return -EOPNOTSUPP;
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        if (value) {
index e56560d2b08a8db433f890f7a8baa344f50a3df1..d33418fdc858fbbe7f929d692dae1533c2e9a271 100644 (file)
@@ -517,9 +517,6 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-#define MAX_SELECT_SECONDS \
-       ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
 int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
                           fd_set __user *exp, struct timespec *end_time)
 {
index aa68a8a315180250e03395f91628f9fb5857e514..efc309fa3035998189f827147f4ccd0e84aa9733 100644 (file)
@@ -5,12 +5,12 @@ config SQUASHFS
        help
          Saying Y here includes support for SquashFS 4.0 (a Compressed
          Read-Only File System).  Squashfs is a highly compressed read-only
-         filesystem for Linux.  It uses zlib/lzo compression to compress both
-         files, inodes and directories.  Inodes in the system are very small
-         and all blocks are packed to minimise data overhead. Block sizes
-         greater than 4K are supported up to a maximum of 1 Mbytes (default
-         block size 128K).  SquashFS 4.0 supports 64 bit filesystems and files
-         (larger than 4GB), full uid/gid information, hard links and
+         filesystem for Linux.  It uses zlib, lzo or xz compression to
+         compress both files, inodes and directories.  Inodes in the system
+         are very small and all blocks are packed to minimise data overhead.
+         Block sizes greater than 4K are supported up to a maximum of 1 Mbytes
+         (default block size 128K).  SquashFS 4.0 supports 64 bit filesystems
+         and files (larger than 4GB), full uid/gid information, hard links and
          timestamps.
 
          Squashfs is intended for general read-only filesystem use, for
index a5940e54c4ddedba7a9f8ae7b2a9a8401669b19b..e921bd213738fdfe1d15b50150c1060986d3e0ec 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/types.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 #include <linux/buffer_head.h>
 
 #include "squashfs_fs.h"
@@ -74,3 +75,36 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
 
        return decompressor[i];
 }
+
+
+void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags)
+{
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       void *strm, *buffer = NULL;
+       int length = 0;
+
+       /*
+        * Read decompressor specific options from file system if present
+        */
+       if (SQUASHFS_COMP_OPTS(flags)) {
+               buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+               if (buffer == NULL)
+                       return ERR_PTR(-ENOMEM);
+
+               length = squashfs_read_data(sb, &buffer,
+                       sizeof(struct squashfs_super_block), 0, NULL,
+                       PAGE_CACHE_SIZE, 1);
+
+               if (length < 0) {
+                       strm = ERR_PTR(length);
+                       goto finished;
+               }
+       }
+
+       strm = msblk->decompressor->init(msblk, buffer, length);
+
+finished:
+       kfree(buffer);
+
+       return strm;
+}
index 3b305a70f7aa22a17e687495aab097c27cd18722..099745ad5691ed1e129afba411eb56e821a4be27 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 struct squashfs_decompressor {
-       void    *(*init)(struct squashfs_sb_info *);
+       void    *(*init)(struct squashfs_sb_info *, void *, int);
        void    (*free)(void *);
        int     (*decompress)(struct squashfs_sb_info *, void **,
                struct buffer_head **, int, int, int, int, int);
@@ -33,11 +33,6 @@ struct squashfs_decompressor {
        int     supported;
 };
 
-static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk)
-{
-       return msblk->decompressor->init(msblk);
-}
-
 static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
        void *s)
 {
index 0dc340aa2be97d5373e719f74c84d866e00ef465..3f79cd1d0c197b4428356c120fbff7cead1042fe 100644 (file)
@@ -172,6 +172,11 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
                length += sizeof(dirh);
 
                dir_count = le32_to_cpu(dirh.count) + 1;
+
+               /* dir_count should never be larger than 256 */
+               if (dir_count > 256)
+                       goto failed_read;
+
                while (dir_count--) {
                        /*
                         * Read directory entry.
@@ -183,6 +188,10 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
 
                        size = le16_to_cpu(dire->size) + 1;
 
+                       /* size should never be larger than SQUASHFS_NAME_LEN */
+                       if (size > SQUASHFS_NAME_LEN)
+                               goto failed_read;
+
                        err = squashfs_read_metadata(inode->i_sb, dire->name,
                                        &block, &offset, size);
                        if (err < 0)
index 7da759e34c525e8bb12efd2ae496b0776349c3b0..00f4dfc5f0884cb6d77920130883521b04635784 100644 (file)
@@ -37,7 +37,7 @@ struct squashfs_lzo {
        void    *output;
 };
 
-static void *lzo_init(struct squashfs_sb_info *msblk)
+static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len)
 {
        int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
 
@@ -58,7 +58,7 @@ failed2:
 failed:
        ERROR("Failed to allocate lzo workspace\n");
        kfree(stream);
-       return NULL;
+       return ERR_PTR(-ENOMEM);
 }
 
 
index 7a9464d08cf632bef2395baea734c9eae9d8d6a7..5d922a6701ab730bf27d70451dd5c37c17337c9e 100644 (file)
@@ -176,6 +176,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
                length += sizeof(dirh);
 
                dir_count = le32_to_cpu(dirh.count) + 1;
+
+               /* dir_count should never be larger than 256 */
+               if (dir_count > 256)
+                       goto data_error;
+
                while (dir_count--) {
                        /*
                         * Read directory entry.
@@ -187,6 +192,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
 
                        size = le16_to_cpu(dire->size) + 1;
 
+                       /* size should never be larger than SQUASHFS_NAME_LEN */
+                       if (size > SQUASHFS_NAME_LEN)
+                               goto data_error;
+
                        err = squashfs_read_metadata(dir->i_sb, dire->name,
                                        &block, &offset, size);
                        if (err < 0)
@@ -228,6 +237,9 @@ exit_lookup:
        d_add(dentry, inode);
        return ERR_PTR(0);
 
+data_error:
+       err = -EIO;
+
 read_failure:
        ERROR("Unable to read directory block [%llx:%x]\n",
                squashfs_i(dir)->start + msblk->directory_table,
index ba729d808876de53b7168bdcd69bf738d3fb6b41..1f2e608b87858ffdd39911bd09155e4bbc845cac 100644 (file)
@@ -48,6 +48,7 @@ extern int squashfs_read_table(struct super_block *, void *, u64, int);
 
 /* decompressor.c */
 extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
+extern void *squashfs_decompressor_init(struct super_block *, unsigned short);
 
 /* export.c */
 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
index 39533feffd6d3a3e02d8a5ceeb5f37c93587c656..4582c568ef4d115df3491af9f7c46216e5acb7bf 100644 (file)
@@ -57,6 +57,7 @@
 #define SQUASHFS_ALWAYS_FRAG           5
 #define SQUASHFS_DUPLICATE             6
 #define SQUASHFS_EXPORT                        7
+#define SQUASHFS_COMP_OPT              10
 
 #define SQUASHFS_BIT(flag, bit)                ((flag >> bit) & 1)
 
@@ -81,6 +82,9 @@
 #define SQUASHFS_EXPORTABLE(flags)             SQUASHFS_BIT(flags, \
                                                SQUASHFS_EXPORT)
 
+#define SQUASHFS_COMP_OPTS(flags)              SQUASHFS_BIT(flags, \
+                                               SQUASHFS_COMP_OPT)
+
 /* Max number of types and file types */
 #define SQUASHFS_DIR_TYPE              1
 #define SQUASHFS_REG_TYPE              2
index 20700b9f2b4cdf6a7e4d921e741839c1bb8427d7..5c8184c061a49e15920909b07d151b0a6b985ea6 100644 (file)
@@ -199,10 +199,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
 
        err = -ENOMEM;
 
-       msblk->stream = squashfs_decompressor_init(msblk);
-       if (msblk->stream == NULL)
-               goto failed_mount;
-
        msblk->block_cache = squashfs_cache_init("metadata",
                        SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
        if (msblk->block_cache == NULL)
@@ -215,6 +211,13 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+       msblk->stream = squashfs_decompressor_init(sb, flags);
+       if (IS_ERR(msblk->stream)) {
+               err = PTR_ERR(msblk->stream);
+               msblk->stream = NULL;
+               goto failed_mount;
+       }
+
        /* Allocate and read id index table */
        msblk->id_table = squashfs_read_id_index_table(sb,
                le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids));
@@ -370,8 +373,8 @@ static void squashfs_put_super(struct super_block *sb)
 }
 
 
-static struct dentry *squashfs_mount(struct file_system_type *fs_type, int flags,
-                               const char *dev_name, void *data)
+static struct dentry *squashfs_mount(struct file_system_type *fs_type,
+                               int flags, const char *dev_name, void *data)
 {
        return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super);
 }
index c4eb400182564c13728fc88f95edf6db294eb2ac..aa47a286d1f8e813b47e2d7fd30ee22957e9ced1 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
 #include <linux/xz.h>
+#include <linux/bitops.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
 #include "squashfs.h"
 #include "decompressor.h"
 
@@ -38,24 +38,57 @@ struct squashfs_xz {
        struct xz_buf buf;
 };
 
-static void *squashfs_xz_init(struct squashfs_sb_info *msblk)
+struct comp_opts {
+       __le32 dictionary_size;
+       __le32 flags;
+};
+
+static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff,
+       int len)
 {
-       int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
+       struct comp_opts *comp_opts = buff;
+       struct squashfs_xz *stream;
+       int dict_size = msblk->block_size;
+       int err, n;
+
+       if (comp_opts) {
+               /* check compressor options are the expected length */
+               if (len < sizeof(*comp_opts)) {
+                       err = -EIO;
+                       goto failed;
+               }
 
-       struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
-       if (stream == NULL)
+               dict_size = le32_to_cpu(comp_opts->dictionary_size);
+
+               /* the dictionary size should be 2^n or 2^n+2^(n+1) */
+               n = ffs(dict_size) - 1;
+               if (dict_size != (1 << n) && dict_size != (1 << n) +
+                                               (1 << (n + 1))) {
+                       err = -EIO;
+                       goto failed;
+               }
+       }
+
+       dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE);
+
+       stream = kmalloc(sizeof(*stream), GFP_KERNEL);
+       if (stream == NULL) {
+               err = -ENOMEM;
                goto failed;
+       }
 
-       stream->state = xz_dec_init(XZ_PREALLOC, block_size);
-       if (stream->state == NULL)
+       stream->state = xz_dec_init(XZ_PREALLOC, dict_size);
+       if (stream->state == NULL) {
+               kfree(stream);
+               err = -ENOMEM;
                goto failed;
+       }
 
        return stream;
 
 failed:
-       ERROR("Failed to allocate xz workspace\n");
-       kfree(stream);
-       return NULL;
+       ERROR("Failed to initialise xz decompressor\n");
+       return ERR_PTR(err);
 }
 
 
index 4661ae2b1cec8040adcadc4018deb63735309f92..517688b32ffaec065505ef967742d43c1295421f 100644 (file)
 #include <linux/buffer_head.h>
 #include <linux/slab.h>
 #include <linux/zlib.h>
+#include <linux/vmalloc.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs.h"
 #include "decompressor.h"
 
-static void *zlib_init(struct squashfs_sb_info *dummy)
+static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len)
 {
        z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
        if (stream == NULL)
                goto failed;
-       stream->workspace = kmalloc(zlib_inflate_workspacesize(),
-               GFP_KERNEL);
+       stream->workspace = vmalloc(zlib_inflate_workspacesize());
        if (stream->workspace == NULL)
                goto failed;
 
@@ -47,7 +47,7 @@ static void *zlib_init(struct squashfs_sb_info *dummy)
 failed:
        ERROR("Failed to allocate zlib workspace\n");
        kfree(stream);
-       return NULL;
+       return ERR_PTR(-ENOMEM);
 }
 
 
@@ -56,7 +56,7 @@ static void zlib_free(void *strm)
        z_stream *stream = strm;
 
        if (stream)
-               kfree(stream->workspace);
+               vfree(stream->workspace);
        kfree(stream);
 }
 
index e84864908264067fcde8f26736a80b31b6a2ec1b..8a06881b1920b9e164ab276ffe73180ebfbbe97a 100644 (file)
@@ -71,6 +71,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
 #else
                INIT_LIST_HEAD(&s->s_files);
 #endif
+               s->s_bdi = &default_backing_dev_info;
                INIT_LIST_HEAD(&s->s_instances);
                INIT_HLIST_BL_HEAD(&s->s_anon);
                INIT_LIST_HEAD(&s->s_inodes);
@@ -936,6 +937,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
        sb = root->d_sb;
        BUG_ON(!sb);
        WARN_ON(!sb->s_bdi);
+       WARN_ON(sb->s_bdi == &default_backing_dev_info);
        sb->s_flags |= MS_BORN;
 
        error = security_sb_kern_mount(sb, flags, secdata);
index ba76b9623e7e809f6b3c5e6223020836069dc4ab..c38ec163da6ccba00a0146c75606c1b548b31343 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
 #include <linux/syscalls.h>
@@ -33,7 +34,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
         * This should be safe, as we require bdi backing to actually
         * write out data in the first place
         */
-       if (!sb->s_bdi || sb->s_bdi == &noop_backing_dev_info)
+       if (sb->s_bdi == &noop_backing_dev_info)
                return 0;
 
        if (sb->s_qcop && sb->s_qcop->quota_sync)
@@ -79,7 +80,7 @@ EXPORT_SYMBOL_GPL(sync_filesystem);
 
 static void sync_one_sb(struct super_block *sb, void *arg)
 {
-       if (!(sb->s_flags & MS_RDONLY) && sb->s_bdi)
+       if (!(sb->s_flags & MS_RDONLY))
                __sync_filesystem(sb, *(int *)arg);
 }
 /*
@@ -128,6 +129,29 @@ void emergency_sync(void)
        }
 }
 
+/*
+ * sync a single super
+ */
+SYSCALL_DEFINE1(syncfs, int, fd)
+{
+       struct file *file;
+       struct super_block *sb;
+       int ret;
+       int fput_needed;
+
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       sb = file->f_dentry->d_sb;
+
+       down_read(&sb->s_umount);
+       ret = sync_filesystem(sb);
+       up_read(&sb->s_umount);
+
+       fput_light(file, fput_needed);
+       return ret;
+}
+
 /**
  * vfs_fsync_range - helper to sync a range of data & metadata to disk
  * @file:              file to sync
index 9ca66276315e08828b4b4708b82060013f416320..fa8d43c92bb81a7a03d3eda50f35dccec42bd44b 100644 (file)
@@ -488,7 +488,6 @@ static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations sysv_aops = {
        .readpage = sysv_readpage,
        .writepage = sysv_writepage,
-       .sync_page = block_sync_page,
        .write_begin = sysv_write_begin,
        .write_end = generic_write_end,
        .bmap = sysv_bmap
index 1d1859dc3de5a88f323aa00b7ebcb12a557b7baa..d7440904be170871c473cb09229de0e11b48fa16 100644 (file)
@@ -58,12 +58,3 @@ config UBIFS_FS_DEBUG
          down UBIFS. You can then further enable / disable individual  debugging
          features using UBIFS module parameters and the corresponding sysfs
          interfaces.
-
-config UBIFS_FS_DEBUG_CHKS
-       bool "Enable extra checks"
-       depends on UBIFS_FS_DEBUG
-       help
-         If extra checks are enabled UBIFS will check the consistency of its
-         internal data structures during operation. However, UBIFS performance
-         is dramatically slower when this option is selected especially if the
-         file system is large.
index 01c2b028e52570e13afa64c2440145070ea1f2d7..f25a7339f80028427f5ca8208f0839facbe6a25b 100644 (file)
@@ -818,7 +818,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
        printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
               current->pid, lnum);
 
-       buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
                return;
index d77db7e36484e3f79bece27ee4a11f3a6b80df6f..28be1e6a65e8c1af71fc754cb3ecf7dd6eaf2ca2 100644 (file)
@@ -448,10 +448,12 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
                if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) {
                        /*
                         * We change whole page so no need to load it. But we
-                        * have to set the @PG_checked flag to make the further
-                        * code know that the page is new. This might be not
-                        * true, but it is better to budget more than to read
-                        * the page from the media.
+                        * do not know whether this page exists on the media or
+                        * not, so we assume the latter because it requires
+                        * larger budget. The assumption is that it is better
+                        * to budget a bit more than to read the page from the
+                        * media. Thus, we are setting the @PG_checked flag
+                        * here.
                         */
                        SetPageChecked(page);
                        skipped_read = 1;
@@ -559,6 +561,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
                dbg_gen("copied %d instead of %d, read page and repeat",
                        copied, len);
                cancel_budget(c, page, ui, appending);
+               ClearPageChecked(page);
 
                /*
                 * Return 0 to force VFS to repeat the whole operation, or the
index 8aacd64957a223c0a01e2d9c54dd73c9d7fbd409..548acf494afd1720a4181e4dbd6861970b24ab34 100644 (file)
@@ -160,7 +160,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                if (IS_RDONLY(inode))
                        return -EROFS;
 
-               if (!is_owner_or_cap(inode))
+               if (!inode_owner_or_capable(inode))
                        return -EACCES;
 
                if (get_user(flags, (int __user *) arg))
index c7b25e2f7764dd83fcf7db60cebe5c191aa6a3c2..0ee0847f24218b0e44cfefeb888dc501b8d159f1 100644 (file)
@@ -1094,7 +1094,7 @@ static int scan_check_cb(struct ubifs_info *c,
                }
        }
 
-       buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubifs_err("cannot allocate memory to scan LEB %d", lnum);
                goto out;
index 0a3c2c3f5c4a305675d94f2a191d4b362879c869..0c9c69bd983a94c0854d90508a15832b99b6fe0f 100644 (file)
@@ -1633,7 +1633,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
        if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
                return 0;
 
-       buf = p = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubifs_err("cannot allocate memory for ltab checking");
                return 0;
@@ -1885,7 +1885,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
 
        printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
               current->pid, lnum);
-       buf = p = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubifs_err("cannot allocate memory to dump LPT");
                return;
index 2cdbd31641d7eff40681cae07547935f443d7b0f..09df318e368f492f3d249f97680c1f9b479393c7 100644 (file)
@@ -898,7 +898,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
        if (c->no_orphs)
                return 0;
 
-       buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+       buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
        if (!buf) {
                ubifs_err("cannot allocate memory to check orphans");
                return 0;
index e5dc1e120e8dfd9d4018ffc9ae961593f284a867..6ddd9973e68175da389451831852fc7bb6874029 100644 (file)
@@ -2011,7 +2011,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
         */
        c->bdi.name = "ubifs",
        c->bdi.capabilities = BDI_CAP_MAP_COPY;
-       c->bdi.unplug_io_fn = default_unplug_io_fn;
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
index 8994dd041660613873d7aa39f033883b61f24173..95518a9f589e395fac2adb4d6bb46d335b977e11 100644 (file)
 #include "udf_i.h"
 #include "udf_sb.h"
 
-#define udf_clear_bit(nr, addr) ext2_clear_bit(nr, addr)
-#define udf_set_bit(nr, addr) ext2_set_bit(nr, addr)
-#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
-#define udf_find_next_one_bit(addr, size, offset) \
-               ext2_find_next_bit((unsigned long *)(addr), size, offset)
+#define udf_clear_bit  __test_and_clear_bit_le
+#define udf_set_bit    __test_and_set_bit_le
+#define udf_test_bit   test_bit_le
+#define udf_find_next_one_bit  find_next_bit_le
 
 static int read_block_bitmap(struct super_block *sb,
                             struct udf_bitmap *bitmap, unsigned int block,
index f391a2adc69970c7a44a54883d1d01b35572498b..2a346bb1d9f5f082338555fb50e754e19eb4aa67 100644 (file)
@@ -98,7 +98,6 @@ static int udf_adinicb_write_end(struct file *file,
 const struct address_space_operations udf_adinicb_aops = {
        .readpage       = udf_adinicb_readpage,
        .writepage      = udf_adinicb_writepage,
-       .sync_page      = block_sync_page,
        .write_begin = simple_write_begin,
        .write_end = udf_adinicb_write_end,
 };
index ccc81432141411aadb24aa10b076d82e376ae5c4..1d1358ed80c13e5da17849c7773bc8a6d1861e7c 100644 (file)
@@ -140,7 +140,6 @@ static sector_t udf_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations udf_aops = {
        .readpage       = udf_readpage,
        .writepage      = udf_writepage,
-       .sync_page      = block_sync_page,
        .write_begin            = udf_write_begin,
        .write_end              = generic_write_end,
        .bmap           = udf_bmap,
index 03c255f12df5110acdee54cbf8433ac13ac79e75..27a4babe7df0bcaf406e260631d86e44abb5ba51 100644 (file)
@@ -552,7 +552,6 @@ static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
 const struct address_space_operations ufs_aops = {
        .readpage = ufs_readpage,
        .writepage = ufs_writepage,
-       .sync_page = block_sync_page,
        .write_begin = ufs_write_begin,
        .write_end = generic_write_end,
        .bmap = ufs_bmap
index e56a4f567212a211c61a2f9f0f132ab3fd4f42be..11014302c9ca63959ea29310a8173c74f48bd3ea 100644 (file)
@@ -479,7 +479,7 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size)
                        break;
                if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
                        ufs_sync_inode (inode);
-               blk_run_address_space(inode->i_mapping);
+               blk_flush_plug(current);
                yield();
        }
 
index 9f8775ce381c403647e84d1df9d45ae78c80a573..95417592824094c0655a0bf5839c3da442d5db46 100644 (file)
@@ -408,7 +408,7 @@ static inline unsigned _ubh_find_next_zero_bit_(
        for (;;) {
                count = min_t(unsigned int, size + offset, uspi->s_bpf);
                size -= count - offset;
-               pos = ext2_find_next_zero_bit (ubh->bh[base]->b_data, count, offset);
+               pos = find_next_zero_bit_le(ubh->bh[base]->b_data, count, offset);
                if (pos < count || !size)
                        break;
                base++;
index 179b586906573a444561a892e906d2f5b02963e8..ba653f3dc1bc9c66010290e53e0bb2a5b8fd94b1 100644 (file)
@@ -95,7 +95,7 @@ static int utimes_common(struct path *path, struct timespec *times)
                 if (IS_IMMUTABLE(inode))
                        goto mnt_drop_write_and_out;
 
-               if (!is_owner_or_cap(inode)) {
+               if (!inode_owner_or_capable(inode)) {
                        error = inode_permission(inode, MAY_WRITE);
                        if (error)
                                goto mnt_drop_write_and_out;
index 01bb8135e14aafcc4b8782b749374e6b79049afc..a19acdb81cd1270c174711c851b17013edb9ca80 100644 (file)
@@ -59,7 +59,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
                if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
                        return -EPERM;
                if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
-                   (mask & MAY_WRITE) && !is_owner_or_cap(inode))
+                   (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
                        return -EPERM;
        }
 
index faca449970995ab41a8fc9117efeceac63cf1991..284a7c89697efd7d083b5a60dfc9671796fe80b1 100644 (file)
 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
 
-EXTRA_CFLAGS +=         -I$(src) -I$(src)/linux-2.6
+ccflags-y := -I$(src) -I$(src)/linux-2.6
+ccflags-$(CONFIG_XFS_DEBUG) += -g
 
 XFS_LINUX := linux-2.6
 
-ifeq ($(CONFIG_XFS_DEBUG),y)
-       EXTRA_CFLAGS += -g
-endif
-
 obj-$(CONFIG_XFS_FS)           += xfs.o
 
 xfs-y                          += linux-2.6/xfs_trace.o
@@ -105,11 +102,10 @@ xfs-y                             += $(addprefix $(XFS_LINUX)/, \
                                   xfs_globals.o \
                                   xfs_ioctl.o \
                                   xfs_iops.o \
+                                  xfs_message.o \
                                   xfs_super.o \
                                   xfs_sync.o \
                                   xfs_xattr.o)
 
 # Objects in support/
-xfs-y                          += $(addprefix support/, \
-                                  debug.o \
-                                  uuid.o)
+xfs-y                          += support/uuid.o
index 666c9db48eb63893cc3da777c44478ccd4d6942b..a907de565db3bf287f7d1a7894fff23f85ca18d5 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/backing-dev.h>
 #include "time.h"
 #include "kmem.h"
+#include "xfs_message.h"
 
 /*
  * Greedy allocation.  May fail and may return vmalloced memory.
@@ -56,8 +57,8 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
                        return ptr;
                if (!(++retries % 100))
-                       printk(KERN_ERR "XFS: possible memory allocation "
-                                       "deadlock in %s (mode:0x%x)\n",
+                       xfs_err(NULL,
+               "possible memory allocation deadlock in %s (mode:0x%x)",
                                        __func__, lflags);
                congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
@@ -112,8 +113,8 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
                if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP)))
                        return ptr;
                if (!(++retries % 100))
-                       printk(KERN_ERR "XFS: possible memory allocation "
-                                       "deadlock in %s (mode:0x%x)\n",
+                       xfs_err(NULL,
+               "possible memory allocation deadlock in %s (mode:0x%x)",
                                        __func__, lflags);
                congestion_wait(BLK_RW_ASYNC, HZ/50);
        } while (1);
index ec7bbb5645b63d85811e2ee731637139881b370c..52dbd14260ba691fdbf9cc46b1e46d13fc461e9e 100644 (file)
@@ -413,8 +413,7 @@ xfs_submit_ioend_bio(
        if (xfs_ioend_new_eof(ioend))
                xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
 
-       submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
-                  WRITE_SYNC_PLUG : WRITE, bio);
+       submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
 }
 
 STATIC struct bio *
@@ -854,7 +853,7 @@ xfs_aops_discard_page(
        if (XFS_FORCED_SHUTDOWN(ip->i_mount))
                goto out_invalidate;
 
-       xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+       xfs_alert(ip->i_mount,
                "page discard on page %p, inode 0x%llx, offset %llu.",
                        page, ip->i_ino, offset);
 
@@ -872,7 +871,7 @@ xfs_aops_discard_page(
                if (error) {
                        /* something screwed, just bail */
                        if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                               xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+                               xfs_alert(ip->i_mount,
                        "page discard unable to remove delalloc mapping.");
                        }
                        break;
@@ -1411,7 +1410,7 @@ xfs_vm_write_failed(
                if (error) {
                        /* something screwed, just bail */
                        if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                               xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+                               xfs_alert(ip->i_mount,
                        "xfs_vm_write_failed: unable to clean up ino %lld",
                                                ip->i_ino);
                        }
@@ -1495,7 +1494,6 @@ const struct address_space_operations xfs_address_space_operations = {
        .readpages              = xfs_vm_readpages,
        .writepage              = xfs_vm_writepage,
        .writepages             = xfs_vm_writepages,
-       .sync_page              = block_sync_page,
        .releasepage            = xfs_vm_releasepage,
        .invalidatepage         = xfs_vm_invalidatepage,
        .write_begin            = xfs_vm_write_begin,
index f83a4c830a65e865f8d680849278f5dfa4eb41a2..c05324d3282c0bae23ac943b8b1b47d7e9dfe416 100644 (file)
@@ -401,9 +401,8 @@ _xfs_buf_lookup_pages(
                         * handle buffer allocation failures we can't do much.
                         */
                        if (!(++retries % 100))
-                               printk(KERN_ERR
-                                       "XFS: possible memory allocation "
-                                       "deadlock in %s (mode:0x%x)\n",
+                               xfs_err(NULL,
+               "possible memory allocation deadlock in %s (mode:0x%x)",
                                        __func__, gfp_mask);
 
                        XFS_STATS_INC(xb_page_retries);
@@ -615,8 +614,8 @@ xfs_buf_get(
        if (!(bp->b_flags & XBF_MAPPED)) {
                error = _xfs_buf_map_pages(bp, flags);
                if (unlikely(error)) {
-                       printk(KERN_WARNING "%s: failed to map pages\n",
-                                       __func__);
+                       xfs_warn(target->bt_mount,
+                               "%s: failed to map pages\n", __func__);
                        goto no_buffer;
                }
        }
@@ -850,8 +849,8 @@ xfs_buf_get_uncached(
 
        error = _xfs_buf_map_pages(bp, XBF_MAPPED);
        if (unlikely(error)) {
-               printk(KERN_WARNING "%s: failed to map pages\n",
-                               __func__);
+               xfs_warn(target->bt_mount,
+                       "%s: failed to map pages\n", __func__);
                goto fail_free_mem;
        }
 
@@ -991,7 +990,7 @@ xfs_buf_lock(
        if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE))
                xfs_log_force(bp->b_target->bt_mount, 0);
        if (atomic_read(&bp->b_io_remaining))
-               blk_run_address_space(bp->b_target->bt_mapping);
+               blk_flush_plug(current);
        down(&bp->b_sema);
        XB_SET_OWNER(bp);
 
@@ -1035,9 +1034,7 @@ xfs_buf_wait_unpin(
                set_current_state(TASK_UNINTERRUPTIBLE);
                if (atomic_read(&bp->b_pin_count) == 0)
                        break;
-               if (atomic_read(&bp->b_io_remaining))
-                       blk_run_address_space(bp->b_target->bt_mapping);
-               schedule();
+               io_schedule();
        }
        remove_wait_queue(&bp->b_waiters, &wait);
        set_current_state(TASK_RUNNING);
@@ -1443,7 +1440,7 @@ xfs_buf_iowait(
        trace_xfs_buf_iowait(bp, _RET_IP_);
 
        if (atomic_read(&bp->b_io_remaining))
-               blk_run_address_space(bp->b_target->bt_mapping);
+               blk_flush_plug(current);
        wait_for_completion(&bp->b_iowait);
 
        trace_xfs_buf_iowait_done(bp, _RET_IP_);
@@ -1617,8 +1614,8 @@ xfs_setsize_buftarg_flags(
        btp->bt_smask = sectorsize - 1;
 
        if (set_blocksize(btp->bt_bdev, sectorsize)) {
-               printk(KERN_WARNING
-                       "XFS: Cannot set_blocksize to %u on device %s\n",
+               xfs_warn(btp->bt_mount,
+                       "Cannot set_blocksize to %u on device %s\n",
                        sectorsize, XFS_BUFTARG_NAME(btp));
                return EINVAL;
        }
@@ -1667,7 +1664,6 @@ xfs_mapping_buftarg(
        struct inode            *inode;
        struct address_space    *mapping;
        static const struct address_space_operations mapping_aops = {
-               .sync_page = block_sync_page,
                .migratepage = fail_migrate_page,
        };
 
@@ -1948,7 +1944,7 @@ xfsbufd(
                        count++;
                }
                if (count)
-                       blk_run_address_space(target->bt_mapping);
+                       blk_flush_plug(current);
 
        } while (!kthread_should_stop());
 
@@ -1996,7 +1992,7 @@ xfs_flush_buftarg(
 
        if (wait) {
                /* Expedite and wait for IO to complete. */
-               blk_run_address_space(target->bt_mapping);
+               blk_flush_plug(current);
                while (!list_empty(&wait_list)) {
                        bp = list_first_entry(&wait_list, struct xfs_buf, b_list);
 
index 096494997747da5904ed71a9af24d70c1555106e..244be9cbfe78d195ca1ee0a3ff20473f244af0a0 100644 (file)
@@ -39,7 +39,6 @@
 #include <mrlock.h>
 #include <time.h>
 
-#include <support/debug.h>
 #include <support/uuid.h>
 
 #include <linux/semaphore.h>
@@ -86,6 +85,7 @@
 #include <xfs_aops.h>
 #include <xfs_super.h>
 #include <xfs_buf.h>
+#include <xfs_message.h>
 
 /*
  * Feature macros (disable/enable)
@@ -280,4 +280,25 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
 #define __arch_pack
 #endif
 
+#define ASSERT_ALWAYS(expr)    \
+       (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+
+#ifndef DEBUG
+#define ASSERT(expr)   ((void)0)
+
+#ifndef STATIC
+# define STATIC static noinline
+#endif
+
+#else /* DEBUG */
+
+#define ASSERT(expr)   \
+       (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+
+#ifndef STATIC
+# define STATIC noinline
+#endif
+
+#endif /* DEBUG */
+
 #endif /* __XFS_LINUX__ */
diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/linux-2.6/xfs_message.c
new file mode 100644 (file)
index 0000000..508e06f
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011 Red Hat, 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.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_types.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+
+/*
+ * XFS logging functions
+ */
+static int
+__xfs_printk(
+       const char              *level,
+       const struct xfs_mount  *mp,
+       struct va_format        *vaf)
+{
+       if (mp && mp->m_fsname)
+               return printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf);
+       return printk("%sXFS: %pV\n", level, vaf);
+}
+
+int xfs_printk(
+       const char              *level,
+       const struct xfs_mount  *mp,
+       const char              *fmt, ...)
+{
+       struct va_format        vaf;
+       va_list                 args;
+       int                      r;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       r = __xfs_printk(level, mp, &vaf);
+       va_end(args);
+
+       return r;
+}
+
+#define define_xfs_printk_level(func, kern_level)              \
+int func(const struct xfs_mount *mp, const char *fmt, ...)     \
+{                                                              \
+       struct va_format        vaf;                            \
+       va_list                 args;                           \
+       int                     r;                              \
+                                                               \
+       va_start(args, fmt);                                    \
+                                                               \
+       vaf.fmt = fmt;                                          \
+       vaf.va = &args;                                         \
+                                                               \
+       r = __xfs_printk(kern_level, mp, &vaf);                 \
+       va_end(args);                                           \
+                                                               \
+       return r;                                               \
+}                                                              \
+
+define_xfs_printk_level(xfs_emerg, KERN_EMERG);
+define_xfs_printk_level(xfs_alert, KERN_ALERT);
+define_xfs_printk_level(xfs_crit, KERN_CRIT);
+define_xfs_printk_level(xfs_err, KERN_ERR);
+define_xfs_printk_level(xfs_warn, KERN_WARNING);
+define_xfs_printk_level(xfs_notice, KERN_NOTICE);
+define_xfs_printk_level(xfs_info, KERN_INFO);
+#ifdef DEBUG
+define_xfs_printk_level(xfs_debug, KERN_DEBUG);
+#endif
+
+int
+xfs_alert_tag(
+       const struct xfs_mount  *mp,
+       int                     panic_tag,
+       const char              *fmt, ...)
+{
+       struct va_format        vaf;
+       va_list                 args;
+       int                     do_panic = 0;
+       int                     r;
+
+       if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) {
+               xfs_printk(KERN_ALERT, mp,
+                       "XFS: Transforming an alert into a BUG.");
+               do_panic = 1;
+       }
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       r = __xfs_printk(KERN_ALERT, mp, &vaf);
+       va_end(args);
+
+       BUG_ON(do_panic);
+
+       return r;
+}
+
+void
+assfail(char *expr, char *file, int line)
+{
+       xfs_emerg(NULL, "Assertion failed: %s, file: %s, line: %d",
+               expr, file, line);
+       BUG();
+}
+
+void
+xfs_hex_dump(void *p, int length)
+{
+       print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1);
+}
diff --git a/fs/xfs/linux-2.6/xfs_message.h b/fs/xfs/linux-2.6/xfs_message.h
new file mode 100644 (file)
index 0000000..e77ffa1
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __XFS_MESSAGE_H
+#define __XFS_MESSAGE_H 1
+
+struct xfs_mount;
+
+extern int xfs_printk(const char *level, const struct xfs_mount *mp,
+                      const char *fmt, ...)
+        __attribute__ ((format (printf, 3, 4)));
+extern int xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_alert(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_alert_tag(const struct xfs_mount *mp, int tag,
+                        const char *fmt, ...)
+        __attribute__ ((format (printf, 3, 4)));
+extern int xfs_crit(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_err(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_warn(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_notice(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+extern int xfs_info(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+
+#ifdef DEBUG
+extern int xfs_debug(const struct xfs_mount *mp, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+#else
+#define xfs_debug(mp, fmt, ...)        (0)
+#endif
+
+extern void assfail(char *expr, char *f, int l);
+
+extern void xfs_hex_dump(void *p, int length);
+
+#endif /* __XFS_MESSAGE_H */
index 9731898083ae86ee79f546f372684ab5d03dbcc8..818c4cf2de863e5450ac75ad300a1c78bfdbca60 100644 (file)
@@ -172,6 +172,15 @@ xfs_parseargs(
        int                     iosize = 0;
        __uint8_t               iosizelog = 0;
 
+       /*
+        * set up the mount name first so all the errors will refer to the
+        * correct device.
+        */
+       mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL);
+       if (!mp->m_fsname)
+               return ENOMEM;
+       mp->m_fsname_len = strlen(mp->m_fsname) + 1;
+
        /*
         * Copy binary VFS mount flags we are interested in.
         */
@@ -189,6 +198,7 @@ xfs_parseargs(
        mp->m_flags |= XFS_MOUNT_BARRIER;
        mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE;
        mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
+       mp->m_flags |= XFS_MOUNT_DELAYLOG;
 
        /*
         * These can be overridden by the mount option parsing.
@@ -207,24 +217,21 @@ xfs_parseargs(
 
                if (!strcmp(this_char, MNTOPT_LOGBUFS)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        mp->m_logbufs = simple_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        mp->m_logbsize = suffix_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -232,14 +239,12 @@ xfs_parseargs(
                        if (!mp->m_logname)
                                return ENOMEM;
                } else if (!strcmp(this_char, MNTOPT_MTPT)) {
-                       cmn_err(CE_WARN,
-                               "XFS: %s option not allowed on this system",
+                       xfs_warn(mp, "%s option not allowed on this system",
                                this_char);
                        return EINVAL;
                } else if (!strcmp(this_char, MNTOPT_RTDEV)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -248,8 +253,7 @@ xfs_parseargs(
                                return ENOMEM;
                } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -257,8 +261,7 @@ xfs_parseargs(
                        iosizelog = ffs(iosize) - 1;
                } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -280,16 +283,14 @@ xfs_parseargs(
                        mp->m_flags |= XFS_MOUNT_SWALLOC;
                } else if (!strcmp(this_char, MNTOPT_SUNIT)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
                        dsunit = simple_strtoul(value, &eov, 10);
                } else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
                        if (!value || !*value) {
-                               cmn_err(CE_WARN,
-                                       "XFS: %s option requires an argument",
+                               xfs_warn(mp, "%s option requires an argument",
                                        this_char);
                                return EINVAL;
                        }
@@ -297,8 +298,7 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
                        mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
 #if !XFS_BIG_INUMS
-                       cmn_err(CE_WARN,
-                               "XFS: %s option not allowed on this system",
+                       xfs_warn(mp, "%s option not allowed on this system",
                                this_char);
                        return EINVAL;
 #endif
@@ -356,20 +356,19 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
                        mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
                } else if (!strcmp(this_char, "ihashsize")) {
-                       cmn_err(CE_WARN,
-       "XFS: ihashsize no longer used, option is deprecated.");
+                       xfs_warn(mp,
+       "ihashsize no longer used, option is deprecated.");
                } else if (!strcmp(this_char, "osyncisdsync")) {
-                       cmn_err(CE_WARN,
-       "XFS: osyncisdsync has no effect, option is deprecated.");
+                       xfs_warn(mp,
+       "osyncisdsync has no effect, option is deprecated.");
                } else if (!strcmp(this_char, "osyncisosync")) {
-                       cmn_err(CE_WARN,
-       "XFS: osyncisosync has no effect, option is deprecated.");
+                       xfs_warn(mp,
+       "osyncisosync has no effect, option is deprecated.");
                } else if (!strcmp(this_char, "irixsgid")) {
-                       cmn_err(CE_WARN,
-       "XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
+                       xfs_warn(mp,
+       "irixsgid is now a sysctl(2) variable, option is deprecated.");
                } else {
-                       cmn_err(CE_WARN,
-                               "XFS: unknown mount option [%s].", this_char);
+                       xfs_warn(mp, "unknown mount option [%s].", this_char);
                        return EINVAL;
                }
        }
@@ -379,40 +378,37 @@ xfs_parseargs(
         */
        if ((mp->m_flags & XFS_MOUNT_NORECOVERY) &&
            !(mp->m_flags & XFS_MOUNT_RDONLY)) {
-               cmn_err(CE_WARN, "XFS: no-recovery mounts must be read-only.");
+               xfs_warn(mp, "no-recovery mounts must be read-only.");
                return EINVAL;
        }
 
        if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) {
-               cmn_err(CE_WARN,
-       "XFS: sunit and swidth options incompatible with the noalign option");
+               xfs_warn(mp,
+       "sunit and swidth options incompatible with the noalign option");
                return EINVAL;
        }
 
 #ifndef CONFIG_XFS_QUOTA
        if (XFS_IS_QUOTA_RUNNING(mp)) {
-               cmn_err(CE_WARN,
-                       "XFS: quota support not available in this kernel.");
+               xfs_warn(mp, "quota support not available in this kernel.");
                return EINVAL;
        }
 #endif
 
        if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
            (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
-               cmn_err(CE_WARN,
-                       "XFS: cannot mount with both project and group quota");
+               xfs_warn(mp, "cannot mount with both project and group quota");
                return EINVAL;
        }
 
        if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
-               cmn_err(CE_WARN,
-                       "XFS: sunit and swidth must be specified together");
+               xfs_warn(mp, "sunit and swidth must be specified together");
                return EINVAL;
        }
 
        if (dsunit && (dswidth % dsunit != 0)) {
-               cmn_err(CE_WARN,
-       "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)",
+               xfs_warn(mp,
+       "stripe width (%d) must be a multiple of the stripe unit (%d)",
                        dswidth, dsunit);
                return EINVAL;
        }
@@ -438,8 +434,7 @@ done:
            mp->m_logbufs != 0 &&
            (mp->m_logbufs < XLOG_MIN_ICLOGS ||
             mp->m_logbufs > XLOG_MAX_ICLOGS)) {
-               cmn_err(CE_WARN,
-                       "XFS: invalid logbufs value: %d [not %d-%d]",
+               xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]",
                        mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
                return XFS_ERROR(EINVAL);
        }
@@ -448,22 +443,16 @@ done:
            (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE ||
             mp->m_logbsize > XLOG_MAX_RECORD_BSIZE ||
             !is_power_of_2(mp->m_logbsize))) {
-               cmn_err(CE_WARN,
-       "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
+               xfs_warn(mp,
+                       "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
                        mp->m_logbsize);
                return XFS_ERROR(EINVAL);
        }
 
-       mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL);
-       if (!mp->m_fsname)
-               return ENOMEM;
-       mp->m_fsname_len = strlen(mp->m_fsname) + 1;
-
        if (iosizelog) {
                if (iosizelog > XFS_MAX_IO_LOG ||
                    iosizelog < XFS_MIN_IO_LOG) {
-                       cmn_err(CE_WARN,
-               "XFS: invalid log iosize: %d [not %d-%d]",
+                       xfs_warn(mp, "invalid log iosize: %d [not %d-%d]",
                                iosizelog, XFS_MIN_IO_LOG,
                                XFS_MAX_IO_LOG);
                        return XFS_ERROR(EINVAL);
@@ -610,7 +599,7 @@ xfs_blkdev_get(
                                    mp);
        if (IS_ERR(*bdevp)) {
                error = PTR_ERR(*bdevp);
-               printk("XFS: Invalid device [%s], error=%d\n", name, error);
+               xfs_warn(mp, "Invalid device [%s], error=%d\n", name, error);
        }
 
        return -error;
@@ -664,23 +653,23 @@ xfs_mountfs_check_barriers(xfs_mount_t *mp)
        int error;
 
        if (mp->m_logdev_targp != mp->m_ddev_targp) {
-               xfs_fs_cmn_err(CE_NOTE, mp,
+               xfs_notice(mp,
                  "Disabling barriers, not supported with external log device");
                mp->m_flags &= ~XFS_MOUNT_BARRIER;
                return;
        }
 
        if (xfs_readonly_buftarg(mp->m_ddev_targp)) {
-               xfs_fs_cmn_err(CE_NOTE, mp,
-                 "Disabling barriers, underlying device is readonly");
+               xfs_notice(mp,
+                       "Disabling barriers, underlying device is readonly");
                mp->m_flags &= ~XFS_MOUNT_BARRIER;
                return;
        }
 
        error = xfs_barrier_test(mp);
        if (error) {
-               xfs_fs_cmn_err(CE_NOTE, mp,
-                 "Disabling barriers, trial barrier write failed");
+               xfs_notice(mp,
+                       "Disabling barriers, trial barrier write failed");
                mp->m_flags &= ~XFS_MOUNT_BARRIER;
                return;
        }
@@ -743,8 +732,8 @@ xfs_open_devices(
                        goto out_close_logdev;
 
                if (rtdev == ddev || rtdev == logdev) {
-                       cmn_err(CE_WARN,
-       "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
+                       xfs_warn(mp,
+       "Cannot mount filesystem with identical rtdev and ddev/logdev.");
                        error = EINVAL;
                        goto out_close_rtdev;
                }
@@ -1345,8 +1334,8 @@ xfs_fs_remount(
                         * options that we can't actually change.
                         */
 #if 0
-                       printk(KERN_INFO
-       "XFS: mount option \"%s\" not supported for remount\n", p);
+                       xfs_info(mp,
+               "mount option \"%s\" not supported for remount\n", p);
                        return -EINVAL;
 #else
                        break;
@@ -1367,8 +1356,7 @@ xfs_fs_remount(
                if (mp->m_update_flags) {
                        error = xfs_mount_log_sb(mp, mp->m_update_flags);
                        if (error) {
-                               cmn_err(CE_WARN,
-                                       "XFS: failed to write sb changes");
+                               xfs_warn(mp, "failed to write sb changes");
                                return error;
                        }
                        mp->m_update_flags = 0;
@@ -1452,15 +1440,15 @@ xfs_finish_flags(
                        mp->m_logbsize = mp->m_sb.sb_logsunit;
                } else if (mp->m_logbsize > 0 &&
                           mp->m_logbsize < mp->m_sb.sb_logsunit) {
-                       cmn_err(CE_WARN,
-       "XFS: logbuf size must be greater than or equal to log stripe size");
+                       xfs_warn(mp,
+               "logbuf size must be greater than or equal to log stripe size");
                        return XFS_ERROR(EINVAL);
                }
        } else {
                /* Fail a mount if the logbuf is larger than 32K */
                if (mp->m_logbsize > XLOG_BIG_RECORD_BSIZE) {
-                       cmn_err(CE_WARN,
-       "XFS: logbuf size for version 1 logs must be 16K or 32K");
+                       xfs_warn(mp,
+               "logbuf size for version 1 logs must be 16K or 32K");
                        return XFS_ERROR(EINVAL);
                }
        }
@@ -1477,8 +1465,8 @@ xfs_finish_flags(
         * prohibit r/w mounts of read-only filesystems
         */
        if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) {
-               cmn_err(CE_WARN,
-       "XFS: cannot mount a read-only filesystem as read-write");
+               xfs_warn(mp,
+                       "cannot mount a read-only filesystem as read-write");
                return XFS_ERROR(EROFS);
        }
 
index e22f0057d21fa8d2d3e04c11a2e62438ac17a3e9..6c10f1d2e3d3a8e4e094c5153d90b5c8ac60973f 100644 (file)
@@ -425,8 +425,7 @@ xfs_quiesce_attr(
        /* Push the superblock and write an unmount record */
        error = xfs_log_sbcount(mp, 1);
        if (error)
-               xfs_fs_cmn_err(CE_WARN, mp,
-                               "xfs_attr_quiesce: failed to log sb changes. "
+               xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. "
                                "Frozen image may not be consistent.");
        xfs_log_unmount_write(mp);
        xfs_unmountfs_writesb(mp);
@@ -806,7 +805,7 @@ xfs_reclaim_inode(
         * pass on the error.
         */
        if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-               xfs_fs_cmn_err(CE_WARN, ip->i_mount,
+               xfs_warn(ip->i_mount,
                        "inode 0x%llx background reclaim flush failed with %d",
                        (long long)ip->i_ino, error);
        }
index ee3cee097e7eba33b7139987b6c201ef44c82f64..ee2d2adaa438121a1c875a5a7dda6b96f16c20c0 100644 (file)
@@ -37,7 +37,7 @@ xfs_stats_clear_proc_handler(
        ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
 
        if (!ret && write && *valp) {
-               printk("XFS Clearing xfsstats\n");
+               xfs_notice(NULL, "Clearing xfsstats");
                for_each_possible_cpu(c) {
                        preempt_disable();
                        /* save vn_active, it's a universal truth! */
index d22aa3103106c47d7d0ca6b9f1532bd17b4289ea..7e241647850335967262b8763ff14bdb5dd86a5b 100644 (file)
@@ -544,9 +544,10 @@ xfs_qm_dqtobp(
        /*
         * A simple sanity check in case we got a corrupted dquot...
         */
-       if (xfs_qm_dqcheck(ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,
+       error = xfs_qm_dqcheck(mp, ddq, id, dqp->dq_flags & XFS_DQ_ALLTYPES,
                           flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN),
-                          "dqtobp")) {
+                          "dqtobp");
+       if (error) {
                if (!(flags & XFS_QMOPT_DQREPAIR)) {
                        xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(EIO);
@@ -827,7 +828,7 @@ xfs_qm_dqget(
        if (xfs_do_dqerror) {
                if ((xfs_dqerror_target == mp->m_ddev_targp) &&
                    (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) {
-                       cmn_err(CE_DEBUG, "Returning error in dqget");
+                       xfs_debug(mp, "Returning error in dqget");
                        return (EIO);
                }
        }
@@ -1207,8 +1208,9 @@ xfs_qm_dqflush(
        /*
         * A simple sanity check in case we got a corrupted dquot..
         */
-       if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), 0,
-                          XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
+       error = xfs_qm_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0,
+                          XFS_QMOPT_DOWARN, "dqflush (incore copy)");
+       if (error) {
                xfs_buf_relse(bp);
                xfs_dqfunlock(dqp);
                xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
@@ -1391,8 +1393,8 @@ xfs_qm_dqpurge(
                 */
                error = xfs_qm_dqflush(dqp, SYNC_WAIT);
                if (error)
-                       xfs_fs_cmn_err(CE_WARN, mp,
-                               "xfs_qm_dqpurge: dquot %p flush failed", dqp);
+                       xfs_warn(mp, "%s: dquot %p flush failed",
+                               __func__, dqp);
                xfs_dqflock(dqp);
        }
        ASSERT(atomic_read(&dqp->q_pincount) == 0);
@@ -1425,36 +1427,38 @@ xfs_qm_dqpurge(
 void
 xfs_qm_dqprint(xfs_dquot_t *dqp)
 {
-       cmn_err(CE_DEBUG, "-----------KERNEL DQUOT----------------");
-       cmn_err(CE_DEBUG, "---- dquotID =  %d",
+       struct xfs_mount        *mp = dqp->q_mount;
+
+       xfs_debug(mp, "-----------KERNEL DQUOT----------------");
+       xfs_debug(mp, "---- dquotID =  %d",
                (int)be32_to_cpu(dqp->q_core.d_id));
-       cmn_err(CE_DEBUG, "---- type    =  %s", DQFLAGTO_TYPESTR(dqp));
-       cmn_err(CE_DEBUG, "---- fs      =  0x%p", dqp->q_mount);
-       cmn_err(CE_DEBUG, "---- blkno   =  0x%x", (int) dqp->q_blkno);
-       cmn_err(CE_DEBUG, "---- boffset =  0x%x", (int) dqp->q_bufoffset);
-       cmn_err(CE_DEBUG, "---- blkhlimit =  %Lu (0x%x)",
+       xfs_debug(mp, "---- type    =  %s", DQFLAGTO_TYPESTR(dqp));
+       xfs_debug(mp, "---- fs      =  0x%p", dqp->q_mount);
+       xfs_debug(mp, "---- blkno   =  0x%x", (int) dqp->q_blkno);
+       xfs_debug(mp, "---- boffset =  0x%x", (int) dqp->q_bufoffset);
+       xfs_debug(mp, "---- blkhlimit =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_blk_hardlimit),
                (int)be64_to_cpu(dqp->q_core.d_blk_hardlimit));
-       cmn_err(CE_DEBUG, "---- blkslimit =  %Lu (0x%x)",
+       xfs_debug(mp, "---- blkslimit =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_blk_softlimit),
                (int)be64_to_cpu(dqp->q_core.d_blk_softlimit));
-       cmn_err(CE_DEBUG, "---- inohlimit =  %Lu (0x%x)",
+       xfs_debug(mp, "---- inohlimit =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_ino_hardlimit),
                (int)be64_to_cpu(dqp->q_core.d_ino_hardlimit));
-       cmn_err(CE_DEBUG, "---- inoslimit =  %Lu (0x%x)",
+       xfs_debug(mp, "---- inoslimit =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_ino_softlimit),
                (int)be64_to_cpu(dqp->q_core.d_ino_softlimit));
-       cmn_err(CE_DEBUG, "---- bcount  =  %Lu (0x%x)",
+       xfs_debug(mp, "---- bcount  =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_bcount),
                (int)be64_to_cpu(dqp->q_core.d_bcount));
-       cmn_err(CE_DEBUG, "---- icount  =  %Lu (0x%x)",
+       xfs_debug(mp, "---- icount  =  %Lu (0x%x)",
                be64_to_cpu(dqp->q_core.d_icount),
                (int)be64_to_cpu(dqp->q_core.d_icount));
-       cmn_err(CE_DEBUG, "---- btimer  =  %d",
+       xfs_debug(mp, "---- btimer  =  %d",
                (int)be32_to_cpu(dqp->q_core.d_btimer));
-       cmn_err(CE_DEBUG, "---- itimer  =  %d",
+       xfs_debug(mp, "---- itimer  =  %d",
                (int)be32_to_cpu(dqp->q_core.d_itimer));
-       cmn_err(CE_DEBUG, "---------------------------");
+       xfs_debug(mp, "---------------------------");
 }
 #endif
 
index 2a1f3dc10a02dba4f401a326fd72f07bd40212af..9e0e2fa3f2c8c532157609229734329cd8a3bbee 100644 (file)
@@ -136,9 +136,8 @@ xfs_qm_dquot_logitem_push(
         */
        error = xfs_qm_dqflush(dqp, 0);
        if (error)
-               xfs_fs_cmn_err(CE_WARN, dqp->q_mount,
-                       "xfs_qm_dquot_logitem_push: push error %d on dqp %p",
-                       error, dqp);
+               xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
+                       __func__, error, dqp);
        xfs_dqunlock(dqp);
 }
 
index 206a2815ced67399c9cfa248a45d185605e12aee..254ee062bd7dde135e0c238ca3696fe180ec78fe 100644 (file)
@@ -80,7 +80,7 @@ xfs_qm_dquot_list_print(
        int             i = 0;
 
        list_for_each_entry(dqp, &mp->m_quotainfo->qi_dqlist_lock, qi_mplist) {
-               cmn_err(CE_DEBUG, "   %d. \"%d (%s)\"   "
+               xfs_debug(mp, "   %d. \"%d (%s)\"   "
                                  "bcnt = %lld, icnt = %lld, refs = %d",
                        i++, be32_to_cpu(dqp->q_core.d_id),
                        DQFLAGTO_TYPESTR(dqp),
@@ -205,7 +205,7 @@ xfs_qm_destroy(
        list_for_each_entry_safe(dqp, n, &xqm->qm_dqfrlist, q_freelist) {
                xfs_dqlock(dqp);
 #ifdef QUOTADEBUG
-               cmn_err(CE_DEBUG, "FREELIST destroy 0x%p", dqp);
+               xfs_debug(dqp->q_mount, "FREELIST destroy 0x%p", dqp);
 #endif
                list_del_init(&dqp->q_freelist);
                xfs_Gqm->qm_dqfrlist_cnt--;
@@ -341,9 +341,7 @@ xfs_qm_mount_quotas(
         * quotas immediately.
         */
        if (mp->m_sb.sb_rextents) {
-               cmn_err(CE_NOTE,
-                       "Cannot turn on quotas for realtime filesystem %s",
-                       mp->m_fsname);
+               xfs_notice(mp, "Cannot turn on quotas for realtime filesystem");
                mp->m_qflags = 0;
                goto write_changes;
        }
@@ -402,14 +400,13 @@ xfs_qm_mount_quotas(
                         * off, but the on disk superblock doesn't know that !
                         */
                        ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "XFS mount_quotas: Superblock update failed!");
+                       xfs_alert(mp, "%s: Superblock update failed!",
+                               __func__);
                }
        }
 
        if (error) {
-               xfs_fs_cmn_err(CE_WARN, mp,
-                       "Failed to initialize disk quotas.");
+               xfs_warn(mp, "Failed to initialize disk quotas.");
                return;
        }
 
@@ -1229,13 +1226,6 @@ xfs_qm_qino_alloc(
                return error;
        }
 
-       /*
-        * Keep an extra reference to this quota inode. This inode is
-        * locked exclusively and joined to the transaction already.
-        */
-       ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL));
-       IHOLD(*ip);
-
        /*
         * Make the changes in the superblock, and log those too.
         * sbfields arg may contain fields other than *QUOTINO;
@@ -1264,7 +1254,7 @@ xfs_qm_qino_alloc(
        xfs_mod_sb(tp, sbfields);
 
        if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) {
-               xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
+               xfs_alert(mp, "%s failed (error %d)!", __func__, error);
                return error;
        }
        return 0;
@@ -1299,7 +1289,7 @@ xfs_qm_reset_dqcounts(
                 * output any warnings because it's perfectly possible to
                 * find uninitialised dquot blks. See comment in xfs_qm_dqcheck.
                 */
-               (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR,
+               (void) xfs_qm_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
                                      "xfs_quotacheck");
                ddq->d_bcount = 0;
                ddq->d_icount = 0;
@@ -1676,7 +1666,7 @@ xfs_qm_quotacheck(
         */
        ASSERT(list_empty(&mp->m_quotainfo->qi_dqlist));
 
-       cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname);
+       xfs_notice(mp, "Quotacheck needed: Please wait.");
 
        /*
         * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset
@@ -1754,9 +1744,9 @@ xfs_qm_quotacheck(
 
  error_return:
        if (error) {
-               cmn_err(CE_WARN, "XFS quotacheck %s: Unsuccessful (Error %d): "
-                       "Disabling quotas.",
-                       mp->m_fsname, error);
+               xfs_warn(mp,
+       "Quotacheck: Unsuccessful (Error %d): Disabling quotas.",
+                       error);
                /*
                 * We must turn off quotas.
                 */
@@ -1764,12 +1754,11 @@ xfs_qm_quotacheck(
                ASSERT(xfs_Gqm != NULL);
                xfs_qm_destroy_quotainfo(mp);
                if (xfs_mount_reset_sbqflags(mp)) {
-                       cmn_err(CE_WARN, "XFS quotacheck %s: "
-                               "Failed to reset quota flags.", mp->m_fsname);
+                       xfs_warn(mp,
+                               "Quotacheck: Failed to reset quota flags.");
                }
-       } else {
-               cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname);
-       }
+       } else
+               xfs_notice(mp, "Quotacheck: Done.");
        return (error);
 }
 
@@ -1937,8 +1926,8 @@ again:
                         */
                        error = xfs_qm_dqflush(dqp, 0);
                        if (error) {
-                               xfs_fs_cmn_err(CE_WARN, mp,
-                       "xfs_qm_dqreclaim: dquot %p flush failed", dqp);
+                               xfs_warn(mp, "%s: dquot %p flush failed",
+                                       __func__, dqp);
                        }
                        goto dqunlock;
                }
@@ -2115,7 +2104,7 @@ xfs_qm_write_sb_changes(
        int             error;
 
 #ifdef QUOTADEBUG
-       cmn_err(CE_NOTE, "Writing superblock quota changes :%s", mp->m_fsname);
+       xfs_notice(mp, "Writing superblock quota changes");
 #endif
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
        if ((error = xfs_trans_reserve(tp, 0,
index 45b5cb1788abb953d43f845cf462332cfe5863ac..774d7ec6df8e800e43c484916fbcec7d920de1e1 100644 (file)
@@ -119,8 +119,7 @@ xfs_qm_newmount(
             (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
            (!gquotaondisk &&  XFS_IS_OQUOTA_ON(mp)))  &&
            xfs_dev_is_read_only(mp, "changing quota state")) {
-               cmn_err(CE_WARN,
-                       "XFS: please mount with%s%s%s%s.",
+               xfs_warn(mp, "please mount with%s%s%s%s.",
                        (!quotaondisk ? "out quota" : ""),
                        (uquotaondisk ? " usrquota" : ""),
                        (pquotaondisk ? " prjquota" : ""),
index bdebc183223e53c47ab6734976f1ba2bc1aa8901..c82f06778a27d4388f9bdf61ac6c1193c1b373eb 100644 (file)
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 
-#ifdef DEBUG
-# define qdprintk(s, args...)  cmn_err(CE_DEBUG, s, ## args)
-#else
-# define qdprintk(s, args...)  do { } while (0)
-#endif
-
 STATIC int     xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
 STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
                                        uint);
@@ -294,7 +288,8 @@ xfs_qm_scall_trunc_qfiles(
        int             error = 0, error2 = 0;
 
        if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
-               qdprintk("qtrunc flags=%x m_qflags=%x\n", flags, mp->m_qflags);
+               xfs_debug(mp, "%s: flags=%x m_qflags=%x\n",
+                       __func__, flags, mp->m_qflags);
                return XFS_ERROR(EINVAL);
        }
 
@@ -331,7 +326,8 @@ xfs_qm_scall_quotaon(
        sbflags = 0;
 
        if (flags == 0) {
-               qdprintk("quotaon: zero flags, m_qflags=%x\n", mp->m_qflags);
+               xfs_debug(mp, "%s: zero flags, m_qflags=%x\n",
+                       __func__, mp->m_qflags);
                return XFS_ERROR(EINVAL);
        }
 
@@ -352,8 +348,9 @@ xfs_qm_scall_quotaon(
            (flags & XFS_GQUOTA_ACCT) == 0 &&
            (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
            (flags & XFS_OQUOTA_ENFD))) {
-               qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
-                       flags, mp->m_sb.sb_qflags);
+               xfs_debug(mp,
+                       "%s: Can't enforce without acct, flags=%x sbflags=%x\n",
+                       __func__, flags, mp->m_sb.sb_qflags);
                return XFS_ERROR(EINVAL);
        }
        /*
@@ -541,7 +538,7 @@ xfs_qm_scall_setqlim(
                        q->qi_bsoftlimit = soft;
                }
        } else {
-               qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft);
+               xfs_debug(mp, "blkhard %Ld < blksoft %Ld\n", hard, soft);
        }
        hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
                (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
@@ -557,7 +554,7 @@ xfs_qm_scall_setqlim(
                        q->qi_rtbsoftlimit = soft;
                }
        } else {
-               qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
+               xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld\n", hard, soft);
        }
 
        hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
@@ -574,7 +571,7 @@ xfs_qm_scall_setqlim(
                        q->qi_isoftlimit = soft;
                }
        } else {
-               qdprintk("ihard %Ld < isoft %Ld\n", hard, soft);
+               xfs_debug(mp, "ihard %Ld < isoft %Ld\n", hard, soft);
        }
 
        /*
@@ -939,10 +936,11 @@ struct mutex  qcheck_lock;
 #define DQTEST_LIST_PRINT(l, NXT, title) \
 { \
          xfs_dqtest_t  *dqp; int i = 0;\
-         cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \
+         xfs_debug(NULL, "%s (#%d)", title, (int) (l)->qh_nelems); \
          for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \
               dqp = (xfs_dqtest_t *)dqp->NXT) { \
-               cmn_err(CE_DEBUG, "  %d. \"%d (%s)\"  bcnt = %d, icnt = %d", \
+               xfs_debug(dqp->q_mount,         \
+                       "  %d. \"%d (%s)\"  bcnt = %d, icnt = %d", \
                         ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp),      \
                         dqp->d_bcount, dqp->d_icount); } \
 }
@@ -966,16 +964,17 @@ xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp)
 }
 STATIC void
 xfs_qm_dqtest_print(
-       xfs_dqtest_t    *d)
+       struct xfs_mount        *mp,
+       struct dqtest           *d)
 {
-       cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------");
-       cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id);
-       cmn_err(CE_DEBUG, "---- fs       = 0x%p", d->q_mount);
-       cmn_err(CE_DEBUG, "---- bcount   = %Lu (0x%x)",
+       xfs_debug(mp, "-----------DQTEST DQUOT----------------");
+       xfs_debug(mp, "---- dquot ID = %d", d->d_id);
+       xfs_debug(mp, "---- fs       = 0x%p", d->q_mount);
+       xfs_debug(mp, "---- bcount   = %Lu (0x%x)",
                d->d_bcount, (int)d->d_bcount);
-       cmn_err(CE_DEBUG, "---- icount   = %Lu (0x%x)",
+       xfs_debug(mp, "---- icount   = %Lu (0x%x)",
                d->d_icount, (int)d->d_icount);
-       cmn_err(CE_DEBUG, "---------------------------");
+       xfs_debug(mp, "---------------------------");
 }
 
 STATIC void
@@ -989,12 +988,14 @@ xfs_qm_dqtest_failed(
 {
        qmtest_nfails++;
        if (error)
-               cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s",
-                      d->d_id, error, reason);
+               xfs_debug(dqp->q_mount,
+                       "quotacheck failed id=%d, err=%d\nreason: %s",
+                       d->d_id, error, reason);
        else
-               cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]",
-                      d->d_id, reason, (int)a, (int)b);
-       xfs_qm_dqtest_print(d);
+               xfs_debug(dqp->q_mount,
+                       "quotacheck failed id=%d (%s) [%d != %d]",
+                       d->d_id, reason, (int)a, (int)b);
+       xfs_qm_dqtest_print(dqp->q_mount, d);
        if (dqp)
                xfs_qm_dqprint(dqp);
 }
@@ -1021,9 +1022,9 @@ xfs_dqtest_cmp2(
            be64_to_cpu(dqp->q_core.d_bcount) >=
            be64_to_cpu(dqp->q_core.d_blk_softlimit)) {
                if (!dqp->q_core.d_btimer && dqp->q_core.d_id) {
-                       cmn_err(CE_DEBUG,
-                               "%d [%s] [0x%p] BLK TIMER NOT STARTED",
-                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+                       xfs_debug(dqp->q_mount,
+                               "%d [%s] BLK TIMER NOT STARTED",
+                               d->d_id, DQFLAGTO_TYPESTR(d));
                        err++;
                }
        }
@@ -1031,16 +1032,16 @@ xfs_dqtest_cmp2(
            be64_to_cpu(dqp->q_core.d_icount) >=
            be64_to_cpu(dqp->q_core.d_ino_softlimit)) {
                if (!dqp->q_core.d_itimer && dqp->q_core.d_id) {
-                       cmn_err(CE_DEBUG,
-                               "%d [%s] [0x%p] INO TIMER NOT STARTED",
-                               d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+                       xfs_debug(dqp->q_mount,
+                               "%d [%s] INO TIMER NOT STARTED",
+                               d->d_id, DQFLAGTO_TYPESTR(d));
                        err++;
                }
        }
 #ifdef QUOTADEBUG
        if (!err) {
-               cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked",
-                       d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount);
+               xfs_debug(dqp->q_mount, "%d [%s] qchecked",
+                       d->d_id, DQFLAGTO_TYPESTR(d));
        }
 #endif
        return (err);
@@ -1137,8 +1138,8 @@ xfs_qm_internalqcheck_adjust(
 
        if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
                *res = BULKSTAT_RV_NOTHING;
-               qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n",
-                       (unsigned long long) ino,
+               xfs_debug(mp, "%s: ino=%llu, uqino=%llu, gqino=%llu\n",
+                       __func__, (unsigned long long) ino,
                        (unsigned long long) mp->m_sb.sb_uquotino,
                        (unsigned long long) mp->m_sb.sb_gquotino);
                return XFS_ERROR(EINVAL);
@@ -1223,12 +1224,12 @@ xfs_qm_internalqcheck(
                                 xfs_qm_internalqcheck_adjust,
                                 0, NULL, &done);
                if (error) {
-                       cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);
+                       xfs_debug(mp, "Bulkstat returned error 0x%x", error);
                        break;
                }
        } while (!done);
 
-       cmn_err(CE_DEBUG, "Checking results against system dquots");
+       xfs_debug(mp, "Checking results against system dquots");
        for (i = 0; i < qmtest_hashmask; i++) {
                xfs_dqtest_t    *d, *n;
                xfs_dqhash_t    *h;
@@ -1246,10 +1247,10 @@ xfs_qm_internalqcheck(
        }
 
        if (qmtest_nfails) {
-               cmn_err(CE_DEBUG, "******** quotacheck failed  ********");
-               cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails);
+               xfs_debug(mp, "******** quotacheck failed  ********");
+               xfs_debug(mp, "failures = %d", qmtest_nfails);
        } else {
-               cmn_err(CE_DEBUG, "******** quotacheck successful! ********");
+               xfs_debug(mp, "******** quotacheck successful! ********");
        }
        kmem_free(qmtest_udqtab);
        kmem_free(qmtest_gdqtab);
index 7de91d1b75c06c91daea768da891ab49a4152818..2a36487313319f45b45b5dbc39bc4fc1c69c8d64 100644 (file)
@@ -643,8 +643,9 @@ xfs_trans_dqresv(
             (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
              (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
 #ifdef QUOTADEBUG
-               cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
-                         " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
+               xfs_debug(mp,
+                       "BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?",
+                       nblks, *resbcountp, hardlimit);
 #endif
                if (nblks > 0) {
                        /*
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
deleted file mode 100644 (file)
index 0df8889..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 Silicon 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include <xfs.h>
-#include "debug.h"
-
-/* xfs_mount.h drags a lot of crap in, sorry.. */
-#include "xfs_sb.h"
-#include "xfs_inum.h"
-#include "xfs_ag.h"
-#include "xfs_mount.h"
-#include "xfs_error.h"
-
-void
-cmn_err(
-       const char      *lvl,
-       const char      *fmt,
-       ...)
-{
-       struct va_format vaf;
-       va_list         args;
-
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-
-       printk("%s%pV", lvl, &vaf);
-       va_end(args);
-
-       BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
-}
-
-void
-xfs_fs_cmn_err(
-       const char              *lvl,
-       struct xfs_mount        *mp,
-       const char              *fmt,
-       ...)
-{
-       struct va_format        vaf;
-       va_list                 args;
-
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-
-       printk("%sFilesystem %s: %pV", lvl, mp->m_fsname, &vaf);
-       va_end(args);
-
-       BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
-}
-
-/* All callers to xfs_cmn_err use CE_ALERT, so don't bother testing lvl */
-void
-xfs_cmn_err(
-       int                     panic_tag,
-       const char              *lvl,
-       struct xfs_mount        *mp,
-       const char              *fmt,
-       ...)
-{
-       struct va_format        vaf;
-       va_list                 args;
-       int                     do_panic = 0;
-
-       if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) {
-               printk(KERN_ALERT "XFS: Transforming an alert into a BUG.");
-               do_panic = 1;
-       }
-
-       va_start(args, fmt);
-       vaf.fmt = fmt;
-       vaf.va = &args;
-
-       printk(KERN_ALERT "Filesystem %s: %pV", mp->m_fsname, &vaf);
-       va_end(args);
-
-       BUG_ON(do_panic);
-}
-
-void
-assfail(char *expr, char *file, int line)
-{
-       printk(KERN_CRIT "Assertion failed: %s, file: %s, line: %d\n", expr,
-              file, line);
-       BUG();
-}
-
-void
-xfs_hex_dump(void *p, int length)
-{
-       print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1);
-}
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h
deleted file mode 100644 (file)
index 05699f6..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2000-2005 Silicon 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.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef        __XFS_SUPPORT_DEBUG_H__
-#define        __XFS_SUPPORT_DEBUG_H__
-
-#include <stdarg.h>
-
-struct xfs_mount;
-
-#define CE_DEBUG        KERN_DEBUG
-#define CE_CONT         KERN_INFO
-#define CE_NOTE         KERN_NOTICE
-#define CE_WARN         KERN_WARNING
-#define CE_ALERT        KERN_ALERT
-#define CE_PANIC        KERN_EMERG
-
-void cmn_err(const char *lvl, const char *fmt, ...)
-               __attribute__ ((format (printf, 2, 3)));
-void xfs_fs_cmn_err( const char *lvl, struct xfs_mount *mp,
-               const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-void xfs_cmn_err( int panic_tag, const char *lvl, struct xfs_mount *mp,
-               const char *fmt, ...) __attribute__ ((format (printf, 4, 5)));
-
-extern void assfail(char *expr, char *f, int l);
-
-#define ASSERT_ALWAYS(expr)    \
-       (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
-
-#ifndef DEBUG
-#define ASSERT(expr)   ((void)0)
-
-#ifndef STATIC
-# define STATIC static noinline
-#endif
-
-#else /* DEBUG */
-
-#define ASSERT(expr)   \
-       (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
-
-#ifndef STATIC
-# define STATIC noinline
-#endif
-
-#endif /* DEBUG */
-#endif  /* __XFS_SUPPORT_DEBUG_H__ */
index f3227984a9bf815d554034ec4661bdcc37d6db36..4bc3c649aee4bb35a6c7ebaa790ef8b73d264073 100644 (file)
@@ -147,10 +147,9 @@ xfs_alloc_get_rec(
  */
 STATIC void
 xfs_alloc_compute_aligned(
+       xfs_alloc_arg_t *args,          /* allocation argument structure */
        xfs_agblock_t   foundbno,       /* starting block in found extent */
        xfs_extlen_t    foundlen,       /* length in found extent */
-       xfs_extlen_t    alignment,      /* alignment for allocation */
-       xfs_extlen_t    minlen,         /* minimum length for allocation */
        xfs_agblock_t   *resbno,        /* result block number */
        xfs_extlen_t    *reslen)        /* result length */
 {
@@ -158,8 +157,8 @@ xfs_alloc_compute_aligned(
        xfs_extlen_t    diff;
        xfs_extlen_t    len;
 
-       if (alignment > 1 && foundlen >= minlen) {
-               bno = roundup(foundbno, alignment);
+       if (args->alignment > 1 && foundlen >= args->minlen) {
+               bno = roundup(foundbno, args->alignment);
                diff = bno - foundbno;
                len = diff >= foundlen ? 0 : foundlen - diff;
        } else {
@@ -464,6 +463,27 @@ xfs_alloc_read_agfl(
        return 0;
 }
 
+STATIC int
+xfs_alloc_update_counters(
+       struct xfs_trans        *tp,
+       struct xfs_perag        *pag,
+       struct xfs_buf          *agbp,
+       long                    len)
+{
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(agbp);
+
+       pag->pagf_freeblks += len;
+       be32_add_cpu(&agf->agf_freeblks, len);
+
+       xfs_trans_agblocks_delta(tp, len);
+       if (unlikely(be32_to_cpu(agf->agf_freeblks) >
+                    be32_to_cpu(agf->agf_length)))
+               return EFSCORRUPTED;
+
+       xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
+       return 0;
+}
+
 /*
  * Allocation group level functions.
  */
@@ -505,49 +525,44 @@ xfs_alloc_ag_vextent(
                ASSERT(0);
                /* NOTREACHED */
        }
-       if (error)
+
+       if (error || args->agbno == NULLAGBLOCK)
                return error;
-       /*
-        * If the allocation worked, need to change the agf structure
-        * (and log it), and the superblock.
-        */
-       if (args->agbno != NULLAGBLOCK) {
-               xfs_agf_t       *agf;   /* allocation group freelist header */
-               long            slen = (long)args->len;
 
-               ASSERT(args->len >= args->minlen && args->len <= args->maxlen);
-               ASSERT(!(args->wasfromfl) || !args->isfl);
-               ASSERT(args->agbno % args->alignment == 0);
-               if (!(args->wasfromfl)) {
-
-                       agf = XFS_BUF_TO_AGF(args->agbp);
-                       be32_add_cpu(&agf->agf_freeblks, -(args->len));
-                       xfs_trans_agblocks_delta(args->tp,
-                                                -((long)(args->len)));
-                       args->pag->pagf_freeblks -= args->len;
-                       ASSERT(be32_to_cpu(agf->agf_freeblks) <=
-                               be32_to_cpu(agf->agf_length));
-                       xfs_alloc_log_agf(args->tp, args->agbp,
-                                               XFS_AGF_FREEBLKS);
-                       /*
-                        * Search the busylist for these blocks and mark the
-                        * transaction as synchronous if blocks are found. This
-                        * avoids the need to block due to a synchronous log
-                        * force to ensure correct ordering as the synchronous
-                        * transaction will guarantee that for us.
-                        */
-                       if (xfs_alloc_busy_search(args->mp, args->agno,
-                                               args->agbno, args->len))
-                               xfs_trans_set_sync(args->tp);
-               }
-               if (!args->isfl)
-                       xfs_trans_mod_sb(args->tp,
-                               args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS :
-                                       XFS_TRANS_SB_FDBLOCKS, -slen);
-               XFS_STATS_INC(xs_allocx);
-               XFS_STATS_ADD(xs_allocb, args->len);
+       ASSERT(args->len >= args->minlen);
+       ASSERT(args->len <= args->maxlen);
+       ASSERT(!args->wasfromfl || !args->isfl);
+       ASSERT(args->agbno % args->alignment == 0);
+
+       if (!args->wasfromfl) {
+               error = xfs_alloc_update_counters(args->tp, args->pag,
+                                                 args->agbp,
+                                                 -((long)(args->len)));
+               if (error)
+                       return error;
+
+               /*
+                * Search the busylist for these blocks and mark the
+                * transaction as synchronous if blocks are found. This
+                * avoids the need to block due to a synchronous log
+                * force to ensure correct ordering as the synchronous
+                * transaction will guarantee that for us.
+                */
+               if (xfs_alloc_busy_search(args->mp, args->agno,
+                                       args->agbno, args->len))
+                       xfs_trans_set_sync(args->tp);
        }
-       return 0;
+
+       if (!args->isfl) {
+               xfs_trans_mod_sb(args->tp, args->wasdel ?
+                                XFS_TRANS_SB_RES_FDBLOCKS :
+                                XFS_TRANS_SB_FDBLOCKS,
+                                -((long)(args->len)));
+       }
+
+       XFS_STATS_INC(xs_allocx);
+       XFS_STATS_ADD(xs_allocb, args->len);
+       return error;
 }
 
 /*
@@ -693,8 +708,7 @@ xfs_alloc_find_best_extent(
                if (error)
                        goto error0;
                XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-               xfs_alloc_compute_aligned(*sbno, *slen, args->alignment,
-                                         args->minlen, &bno, slena);
+               xfs_alloc_compute_aligned(args, *sbno, *slen, &bno, slena);
 
                /*
                 * The good extent is closer than this one.
@@ -866,8 +880,8 @@ xfs_alloc_ag_vextent_near(
                        if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
                                goto error0;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-                       xfs_alloc_compute_aligned(ltbno, ltlen, args->alignment,
-                                       args->minlen, &ltbnoa, &ltlena);
+                       xfs_alloc_compute_aligned(args, ltbno, ltlen,
+                                                 &ltbnoa, &ltlena);
                        if (ltlena < args->minlen)
                                continue;
                        args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
@@ -987,8 +1001,8 @@ xfs_alloc_ag_vextent_near(
                        if ((error = xfs_alloc_get_rec(bno_cur_lt, &ltbno, &ltlen, &i)))
                                goto error0;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-                       xfs_alloc_compute_aligned(ltbno, ltlen, args->alignment,
-                                       args->minlen, &ltbnoa, &ltlena);
+                       xfs_alloc_compute_aligned(args, ltbno, ltlen,
+                                                 &ltbnoa, &ltlena);
                        if (ltlena >= args->minlen)
                                break;
                        if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i)))
@@ -1003,8 +1017,8 @@ xfs_alloc_ag_vextent_near(
                        if ((error = xfs_alloc_get_rec(bno_cur_gt, &gtbno, &gtlen, &i)))
                                goto error0;
                        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-                       xfs_alloc_compute_aligned(gtbno, gtlen, args->alignment,
-                                       args->minlen, &gtbnoa, &gtlena);
+                       xfs_alloc_compute_aligned(args, gtbno, gtlen,
+                                                 &gtbnoa, &gtlena);
                        if (gtlena >= args->minlen)
                                break;
                        if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
@@ -1183,8 +1197,7 @@ xfs_alloc_ag_vextent_size(
         * once aligned; if not, we search left for something better.
         * This can't happen in the second case above.
         */
-       xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen,
-               &rbno, &rlen);
+       xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen);
        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
        XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||
                        (rlen <= flen && rbno + rlen <= fbno + flen), error0);
@@ -1209,8 +1222,8 @@ xfs_alloc_ag_vextent_size(
                        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
                        if (flen < bestrlen)
                                break;
-                       xfs_alloc_compute_aligned(fbno, flen, args->alignment,
-                               args->minlen, &rbno, &rlen);
+                       xfs_alloc_compute_aligned(args, fbno, flen,
+                                                 &rbno, &rlen);
                        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
                        XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||
                                (rlen <= flen && rbno + rlen <= fbno + flen),
@@ -1388,6 +1401,7 @@ xfs_free_ag_extent(
        xfs_mount_t     *mp;            /* mount point struct for filesystem */
        xfs_agblock_t   nbno;           /* new starting block of freespace */
        xfs_extlen_t    nlen;           /* new length of freespace */
+       xfs_perag_t     *pag;           /* per allocation group data */
 
        mp = tp->t_mountp;
        /*
@@ -1586,30 +1600,20 @@ xfs_free_ag_extent(
        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
        xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
        cnt_cur = NULL;
+
        /*
         * Update the freespace totals in the ag and superblock.
         */
-       {
-               xfs_agf_t       *agf;
-               xfs_perag_t     *pag;           /* per allocation group data */
-
-               pag = xfs_perag_get(mp, agno);
-               pag->pagf_freeblks += len;
-               xfs_perag_put(pag);
-
-               agf = XFS_BUF_TO_AGF(agbp);
-               be32_add_cpu(&agf->agf_freeblks, len);
-               xfs_trans_agblocks_delta(tp, len);
-               XFS_WANT_CORRUPTED_GOTO(
-                       be32_to_cpu(agf->agf_freeblks) <=
-                       be32_to_cpu(agf->agf_length),
-                       error0);
-               xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
-               if (!isfl)
-                       xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len);
-               XFS_STATS_INC(xs_freex);
-               XFS_STATS_ADD(xs_freeb, len);
-       }
+       pag = xfs_perag_get(mp, agno);
+       error = xfs_alloc_update_counters(tp, pag, agbp, len);
+       xfs_perag_put(pag);
+       if (error)
+               goto error0;
+
+       if (!isfl)
+               xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len);
+       XFS_STATS_INC(xs_freex);
+       XFS_STATS_ADD(xs_freeb, len);
 
        trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright);
 
index dc3afd7739ff40754d1e04eda13178acc78ef3c2..fa00788de2f549acf0d51bdb913e64350f703b16 100644 (file)
@@ -2365,6 +2365,13 @@ xfs_bmap_rtalloc(
         */
        if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN)
                ralen = MAXEXTLEN / mp->m_sb.sb_rextsize;
+
+       /*
+        * Lock out other modifications to the RT bitmap inode.
+        */
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+
        /*
         * If it's an allocation to an empty file at offset 0,
         * pick an extent that will space things out in the rt area.
@@ -3519,7 +3526,7 @@ xfs_bmap_search_extents(
 
        if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
                     !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
-               xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
+               xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
                                "Access to block zero in inode %llu "
                                "start_block: %llx start_off: %llx "
                                "blkcnt: %llx extent-state: %x lastx: %x\n",
@@ -4193,12 +4200,11 @@ xfs_bmap_read_extents(
                num_recs = xfs_btree_get_numrecs(block);
                if (unlikely(i + num_recs > room)) {
                        ASSERT(i + num_recs <= room);
-                       xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
+                       xfs_warn(ip->i_mount,
                                "corrupt dinode %Lu, (btree extents).",
                                (unsigned long long) ip->i_ino);
-                       XFS_ERROR_REPORT("xfs_bmap_read_extents(1)",
-                                        XFS_ERRLEVEL_LOW,
-                                       ip->i_mount);
+                       XFS_CORRUPTION_ERROR("xfs_bmap_read_extents(1)",
+                               XFS_ERRLEVEL_LOW, ip->i_mount, block);
                        goto error0;
                }
                XFS_WANT_CORRUPTED_GOTO(
@@ -5772,7 +5778,7 @@ xfs_check_block(
                        else
                                thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr);
                        if (*thispa == *pp) {
-                               cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
+                               xfs_warn(mp, "%s: thispa(%d) == pp(%d) %Ld",
                                        __func__, j, i,
                                        (unsigned long long)be64_to_cpu(*thispa));
                                panic("%s: ptrs are equal in node\n",
@@ -5937,11 +5943,11 @@ xfs_bmap_check_leaf_extents(
        return;
 
 error0:
-       cmn_err(CE_WARN, "%s: at error0", __func__);
+       xfs_warn(mp, "%s: at error0", __func__);
        if (bp_release)
                xfs_trans_brelse(NULL, bp);
 error_norelse:
-       cmn_err(CE_WARN, "%s: BAD after btree leaves for %d extents",
+       xfs_warn(mp, "%s: BAD after btree leaves for %d extents",
                __func__, i);
        panic("%s: CORRUPTED BTREE OR SOMETHING", __func__);
        return;
@@ -6144,7 +6150,7 @@ xfs_bmap_punch_delalloc_range(
                if (error) {
                        /* something screwed, just bail */
                        if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                               xfs_fs_cmn_err(CE_ALERT, ip->i_mount,
+                               xfs_alert(ip->i_mount,
                        "Failed delalloc mapping lookup ino %lld fsb %lld.",
                                                ip->i_ino, start_fsb);
                        }
index 6f8c21ce0d6d95fd8c45a5d3eea4ef0240fad1fd..e5413d96f1af90a67831dc2498e8d5fbdd8e42ed 100644 (file)
@@ -130,10 +130,12 @@ xfs_buf_item_log_check(
        orig = bip->bli_orig;
        buffer = XFS_BUF_PTR(bp);
        for (x = 0; x < XFS_BUF_COUNT(bp); x++) {
-               if (orig[x] != buffer[x] && !btst(bip->bli_logged, x))
-                       cmn_err(CE_PANIC,
-       "xfs_buf_item_log_check bip %x buffer %x orig %x index %d",
-                               bip, bp, orig, x);
+               if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) {
+                       xfs_emerg(bp->b_mount,
+                               "%s: bip %x buffer %x orig %x index %d",
+                               __func__, bip, bp, orig, x);
+                       ASSERT(0);
+               }
        }
 }
 #else
@@ -983,10 +985,9 @@ xfs_buf_iodone_callbacks(
        if (XFS_BUF_TARGET(bp) != lasttarg ||
            time_after(jiffies, (lasttime + 5*HZ))) {
                lasttime = jiffies;
-               cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
-                               " block 0x%llx in %s",
+               xfs_alert(mp, "Device %s: metadata write error block 0x%llx",
                        XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
-                     (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
+                     (__uint64_t)XFS_BUF_ADDR(bp));
        }
        lasttarg = XFS_BUF_TARGET(bp);
 
index 1c00bedb3175c1f5e58d006b0cdf0c8089bc0df5..6102ac6d1dffb99adf41f7ad9171b618e0ab3ae7 100644 (file)
@@ -1995,13 +1995,12 @@ xfs_da_do_buf(
                error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED);
                if (unlikely(error == EFSCORRUPTED)) {
                        if (xfs_error_level >= XFS_ERRLEVEL_LOW) {
-                               cmn_err(CE_ALERT, "xfs_da_do_buf: bno %lld\n",
-                                       (long long)bno);
-                               cmn_err(CE_ALERT, "dir: inode %lld\n",
+                               xfs_alert(mp, "%s: bno %lld dir: inode %lld",
+                                       __func__, (long long)bno,
                                        (long long)dp->i_ino);
                                for (i = 0; i < nmap; i++) {
-                                       cmn_err(CE_ALERT,
-                                               "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d\n",
+                                       xfs_alert(mp,
+"[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d",
                                                i,
                                                (long long)mapp[i].br_startoff,
                                                (long long)mapp[i].br_startblock,
index e60490bc00a61b6c8bc1bfbe04df4e56e536596c..be628677c2884723c58cce77f6f98af4ff3d1926 100644 (file)
@@ -270,9 +270,9 @@ xfs_swap_extents(
        /* check inode formats now that data is flushed */
        error = xfs_swap_extents_check_format(ip, tip);
        if (error) {
-               xfs_fs_cmn_err(CE_NOTE, mp,
+               xfs_notice(mp,
                    "%s: inode 0x%llx format is incompatible for exchanging.",
-                               __FILE__, ip->i_ino);
+                               __func__, ip->i_ino);
                goto out_unlock;
        }
 
index a1321bc7f19210a3b4bd1d87ec7c9d5eae410b28..dba7a71cedf3e6f903368416554730d9885142ad 100644 (file)
@@ -159,7 +159,7 @@ xfs_dir_ino_validate(
                XFS_AGINO_TO_INO(mp, agno, agino) == ino;
        if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
                        XFS_RANDOM_DIR_INO_VALIDATE))) {
-               xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
+               xfs_warn(mp, "Invalid inode number 0x%Lx",
                                (unsigned long long) ino);
                XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
                return XFS_ERROR(EFSCORRUPTED);
index f9a0864b696afea29fec8567a906ac793c882455..a0aab7d3294fd4874df67f70014f4f5a7df7dcb0 100644 (file)
@@ -899,10 +899,9 @@ xfs_dir2_leafn_rebalance(
        if(blk2->index < 0) {
                state->inleaf = 1;
                blk2->index = 0;
-               cmn_err(CE_ALERT,
-                       "xfs_dir2_leafn_rebalance: picked the wrong leaf? reverting original leaf: "
-                       "blk1->index %d\n",
-                       blk1->index);
+               xfs_alert(args->dp->i_mount,
+       "%s: picked the wrong leaf? reverting original leaf: blk1->index %d\n",
+                       __func__, blk1->index);
        }
 }
 
@@ -1641,26 +1640,22 @@ xfs_dir2_node_addname_int(
                        }
 
                        if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) {
-                               cmn_err(CE_ALERT,
-                                       "xfs_dir2_node_addname_int: dir ino "
-                                       "%llu needed freesp block %lld for\n"
-                                       "  data block %lld, got %lld\n"
-                                       "  ifbno %llu lastfbno %d\n",
-                                       (unsigned long long)dp->i_ino,
+                               xfs_alert(mp,
+                       "%s: dir ino " "%llu needed freesp block %lld for\n"
+                       "  data block %lld, got %lld ifbno %llu lastfbno %d",
+                                       __func__, (unsigned long long)dp->i_ino,
                                        (long long)xfs_dir2_db_to_fdb(mp, dbno),
                                        (long long)dbno, (long long)fbno,
                                        (unsigned long long)ifbno, lastfbno);
                                if (fblk) {
-                                       cmn_err(CE_ALERT,
-                                               " fblk 0x%p blkno %llu "
-                                               "index %d magic 0x%x\n",
+                                       xfs_alert(mp,
+                               " fblk 0x%p blkno %llu index %d magic 0x%x",
                                                fblk,
                                                (unsigned long long)fblk->blkno,
                                                fblk->index,
                                                fblk->magic);
                                } else {
-                                       cmn_err(CE_ALERT,
-                                               " ... fblk is NULL\n");
+                                       xfs_alert(mp, " ... fblk is NULL");
                                }
                                XFS_ERROR_REPORT("xfs_dir2_node_addname_int",
                                                 XFS_ERRLEVEL_LOW, mp);
index 4c7db74a05f70ba5359c81ad6480c1d34c86ca01..39f06336b99dd7ae13d86bf216fa146437a9af36 100644 (file)
@@ -48,7 +48,7 @@ xfs_error_trap(int e)
                        break;
                if (e != xfs_etrap[i])
                        continue;
-               cmn_err(CE_NOTE, "xfs_error_trap: error %d", e);
+               xfs_notice(NULL, "%s: error %d", __func__, e);
                BUG();
                break;
        }
@@ -74,7 +74,7 @@ xfs_error_test(int error_tag, int *fsidp, char *expression,
 
        for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
                if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
-                       cmn_err(CE_WARN,
+                       xfs_warn(NULL,
        "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
                                expression, file, line, xfs_etest_fsname[i]);
                        return 1;
@@ -95,14 +95,14 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp)
 
        for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
                if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
-                       cmn_err(CE_WARN, "XFS error tag #%d on", error_tag);
+                       xfs_warn(mp, "error tag #%d on", error_tag);
                        return 0;
                }
        }
 
        for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
                if (xfs_etest[i] == 0) {
-                       cmn_err(CE_WARN, "Turned on XFS error tag #%d",
+                       xfs_warn(mp, "Turned on XFS error tag #%d",
                                error_tag);
                        xfs_etest[i] = error_tag;
                        xfs_etest_fsid[i] = fsid;
@@ -114,7 +114,7 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp)
                }
        }
 
-       cmn_err(CE_WARN, "error tag overflow, too many turned on");
+       xfs_warn(mp, "error tag overflow, too many turned on");
 
        return 1;
 }
@@ -133,7 +133,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
                if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
                     xfs_etest[i] != 0) {
                        cleared = 1;
-                       cmn_err(CE_WARN, "Clearing XFS error tag #%d",
+                       xfs_warn(mp, "Clearing XFS error tag #%d",
                                xfs_etest[i]);
                        xfs_etest[i] = 0;
                        xfs_etest_fsid[i] = 0LL;
@@ -144,9 +144,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
        }
 
        if (loud || cleared)
-               cmn_err(CE_WARN,
-                       "Cleared all XFS error tags for filesystem \"%s\"",
-                       mp->m_fsname);
+               xfs_warn(mp, "Cleared all XFS error tags for filesystem");
 
        return 0;
 }
@@ -162,9 +160,8 @@ xfs_error_report(
        inst_t                  *ra)
 {
        if (level <= xfs_error_level) {
-               xfs_cmn_err(XFS_PTAG_ERROR_REPORT,
-                           CE_ALERT, mp,
-               "XFS internal error %s at line %d of file %s.  Caller 0x%p\n",
+               xfs_alert_tag(mp, XFS_PTAG_ERROR_REPORT,
+               "Internal error %s at line %d of file %s.  Caller 0x%p\n",
                            tag, linenum, filename, ra);
 
                xfs_stack_trace();
@@ -184,4 +181,5 @@ xfs_corruption_error(
        if (level <= xfs_error_level)
                xfs_hex_dump(p, 16);
        xfs_error_report(tag, level, mp, filename, linenum, ra);
+       xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair");
 }
index 10dce5475f022061ac95e863b98a07b6c715c21d..079a367f44eeb6f67c16666c695a5fd3a246637d 100644 (file)
@@ -145,10 +145,8 @@ extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud);
 #endif /* DEBUG */
 
 /*
- * XFS panic tags -- allow a call to xfs_cmn_err() be turned into
- *                     a panic by setting xfs_panic_mask in a
- *                     sysctl.  update xfs_max[XFS_PARAM] if
- *                     more are added.
+ * XFS panic tags -- allow a call to xfs_alert_tag() be turned into
+ *                     a panic by setting xfs_panic_mask in a sysctl.
  */
 #define                XFS_NO_PTAG                     0
 #define                XFS_PTAG_IFLUSH                 0x00000001
@@ -160,17 +158,4 @@ extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud);
 #define                XFS_PTAG_SHUTDOWN_LOGERROR      0x00000040
 #define                XFS_PTAG_FSBLOCK_ZERO           0x00000080
 
-struct xfs_mount;
-
-extern void xfs_hex_dump(void *p, int length);
-
-#define xfs_fs_repair_cmn_err(level, mp, fmt, args...) \
-       xfs_fs_cmn_err(level, mp, fmt "  Unmount and run xfs_repair.", ## args)
-
-#define xfs_fs_mount_cmn_err(f, fmt, args...) \
-       do { \
-               if (!(f & XFS_MFSI_QUIET))      \
-                       cmn_err(CE_WARN, "XFS: " fmt, ## args); \
-       } while (0)
-
 #endif /* __XFS_ERROR_H__ */
index 85668efb3e3e03221b5e6dd3f517ad2e38b16f94..9153d2c77caf2856ea636bb76d317f2ef1a8676e 100644 (file)
@@ -385,8 +385,8 @@ xfs_growfs_data_private(
                                  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
                                  XFS_FSS_TO_BB(mp, 1), 0, &bp);
                if (error) {
-                       xfs_fs_cmn_err(CE_WARN, mp,
-                       "error %d reading secondary superblock for ag %d",
+                       xfs_warn(mp,
+               "error %d reading secondary superblock for ag %d",
                                error, agno);
                        break;
                }
@@ -399,7 +399,7 @@ xfs_growfs_data_private(
                if (!(error = xfs_bwrite(mp, bp))) {
                        continue;
                } else {
-                       xfs_fs_cmn_err(CE_WARN, mp,
+                       xfs_warn(mp,
                "write error %d updating secondary superblock for ag %d",
                                error, agno);
                        break; /* no point in continuing */
index 0626a32c3447a4e8ab4a3676ba5aad9e35cd1f0a..84ebeec16642155d3bf5faf48b3443585504389a 100644 (file)
@@ -1055,28 +1055,23 @@ xfs_difree(
         */
        agno = XFS_INO_TO_AGNO(mp, inode);
        if (agno >= mp->m_sb.sb_agcount)  {
-               cmn_err(CE_WARN,
-                       "xfs_difree: agno >= mp->m_sb.sb_agcount (%d >= %d) on %s.  Returning EINVAL.",
-                       agno, mp->m_sb.sb_agcount, mp->m_fsname);
+               xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
+                       __func__, agno, mp->m_sb.sb_agcount);
                ASSERT(0);
                return XFS_ERROR(EINVAL);
        }
        agino = XFS_INO_TO_AGINO(mp, inode);
        if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
-               cmn_err(CE_WARN,
-                       "xfs_difree: inode != XFS_AGINO_TO_INO() "
-                       "(%llu != %llu) on %s.  Returning EINVAL.",
-                       (unsigned long long)inode,
-                       (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino),
-                       mp->m_fsname);
+               xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
+                       __func__, (unsigned long long)inode,
+                       (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
                ASSERT(0);
                return XFS_ERROR(EINVAL);
        }
        agbno = XFS_AGINO_TO_AGBNO(mp, agino);
        if (agbno >= mp->m_sb.sb_agblocks)  {
-               cmn_err(CE_WARN,
-                       "xfs_difree: agbno >= mp->m_sb.sb_agblocks (%d >= %d) on %s.  Returning EINVAL.",
-                       agbno, mp->m_sb.sb_agblocks, mp->m_fsname);
+               xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
+                       __func__, agbno, mp->m_sb.sb_agblocks);
                ASSERT(0);
                return XFS_ERROR(EINVAL);
        }
@@ -1085,9 +1080,8 @@ xfs_difree(
         */
        error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
        if (error) {
-               cmn_err(CE_WARN,
-                       "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s.  Returning error.",
-                       error, mp->m_fsname);
+               xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
+                       __func__, error);
                return error;
        }
        agi = XFS_BUF_TO_AGI(agbp);
@@ -1106,17 +1100,15 @@ xfs_difree(
         * Look for the entry describing this inode.
         */
        if ((error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i))) {
-               cmn_err(CE_WARN,
-                       "xfs_difree: xfs_inobt_lookup returned()  an error %d on %s.  Returning error.",
-                       error, mp->m_fsname);
+               xfs_warn(mp, "%s: xfs_inobt_lookup() returned error %d.",
+                       __func__, error);
                goto error0;
        }
        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
        error = xfs_inobt_get_rec(cur, &rec, &i);
        if (error) {
-               cmn_err(CE_WARN,
-                       "xfs_difree: xfs_inobt_get_rec()  returned an error %d on %s.  Returning error.",
-                       error, mp->m_fsname);
+               xfs_warn(mp, "%s: xfs_inobt_get_rec() returned error %d.",
+                       __func__, error);
                goto error0;
        }
        XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
@@ -1157,8 +1149,8 @@ xfs_difree(
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
 
                if ((error = xfs_btree_delete(cur, &i))) {
-                       cmn_err(CE_WARN, "xfs_difree: xfs_btree_delete returned an error %d on %s.\n",
-                               error, mp->m_fsname);
+                       xfs_warn(mp, "%s: xfs_btree_delete returned error %d.",
+                               __func__, error);
                        goto error0;
                }
 
@@ -1170,9 +1162,8 @@ xfs_difree(
 
                error = xfs_inobt_update(cur, &rec);
                if (error) {
-                       cmn_err(CE_WARN,
-       "xfs_difree: xfs_inobt_update returned an error %d on %s.",
-                               error, mp->m_fsname);
+                       xfs_warn(mp, "%s: xfs_inobt_update returned error %d.",
+                               __func__, error);
                        goto error0;
                }
 
@@ -1218,10 +1209,9 @@ xfs_imap_lookup(
 
        error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
        if (error) {
-               xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
-                               "xfs_ialloc_read_agi() returned "
-                               "error %d, agno %d",
-                               error, agno);
+               xfs_alert(mp,
+                       "%s: xfs_ialloc_read_agi() returned error %d, agno %d",
+                       __func__, error, agno);
                return error;
        }
 
@@ -1299,24 +1289,21 @@ xfs_imap(
                if (flags & XFS_IGET_UNTRUSTED)
                        return XFS_ERROR(EINVAL);
                if (agno >= mp->m_sb.sb_agcount) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                                       "xfs_imap: agno (%d) >= "
-                                       "mp->m_sb.sb_agcount (%d)",
-                                       agno,  mp->m_sb.sb_agcount);
+                       xfs_alert(mp,
+                               "%s: agno (%d) >= mp->m_sb.sb_agcount (%d)",
+                               __func__, agno, mp->m_sb.sb_agcount);
                }
                if (agbno >= mp->m_sb.sb_agblocks) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                                       "xfs_imap: agbno (0x%llx) >= "
-                                       "mp->m_sb.sb_agblocks (0x%lx)",
-                                       (unsigned long long) agbno,
-                                       (unsigned long) mp->m_sb.sb_agblocks);
+                       xfs_alert(mp,
+               "%s: agbno (0x%llx) >= mp->m_sb.sb_agblocks (0x%lx)",
+                               __func__, (unsigned long long)agbno,
+                               (unsigned long)mp->m_sb.sb_agblocks);
                }
                if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                                       "xfs_imap: ino (0x%llx) != "
-                                       "XFS_AGINO_TO_INO(mp, agno, agino) "
-                                       "(0x%llx)",
-                                       ino, XFS_AGINO_TO_INO(mp, agno, agino));
+                       xfs_alert(mp,
+               "%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)",
+                               __func__, ino,
+                               XFS_AGINO_TO_INO(mp, agno, agino));
                }
                xfs_stack_trace();
 #endif /* DEBUG */
@@ -1388,10 +1375,9 @@ out_map:
         */
        if ((imap->im_blkno + imap->im_len) >
            XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
-               xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
-                       "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
-                       " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
-                       (unsigned long long) imap->im_blkno,
+               xfs_alert(mp,
+       "%s: (im_blkno (0x%llx) + im_len (0x%llx)) > sb_dblocks (0x%llx)",
+                       __func__, (unsigned long long) imap->im_blkno,
                        (unsigned long long) imap->im_len,
                        XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
                return XFS_ERROR(EINVAL);
index be7cf625421f15a50a739af9dfc1166981a3fd06..da871f5322368dffac20f1514a5966a45f26061e 100644 (file)
@@ -110,8 +110,8 @@ xfs_inobp_check(
                dip = (xfs_dinode_t *)xfs_buf_offset(bp,
                                        i * mp->m_sb.sb_inodesize);
                if (!dip->di_next_unlinked)  {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p.  About to pop an ASSERT.",
+                       xfs_alert(mp,
+       "Detected bogus zero next_unlinked field in incore inode buffer 0x%p.",
                                bp);
                        ASSERT(dip->di_next_unlinked);
                }
@@ -142,10 +142,9 @@ xfs_imap_to_bp(
                                   (int)imap->im_len, buf_flags, &bp);
        if (error) {
                if (error != EAGAIN) {
-                       cmn_err(CE_WARN,
-                               "xfs_imap_to_bp: xfs_trans_read_buf()returned "
-                               "an error %d on %s.  Returning error.",
-                               error, mp->m_fsname);
+                       xfs_warn(mp,
+                               "%s: xfs_trans_read_buf() returned error %d.",
+                               __func__, error);
                } else {
                        ASSERT(buf_flags & XBF_TRYLOCK);
                }
@@ -180,12 +179,11 @@ xfs_imap_to_bp(
                        XFS_CORRUPTION_ERROR("xfs_imap_to_bp",
                                                XFS_ERRLEVEL_HIGH, mp, dip);
 #ifdef DEBUG
-                       cmn_err(CE_PANIC,
-                                       "Device %s - bad inode magic/vsn "
-                                       "daddr %lld #%d (magic=%x)",
-                               XFS_BUFTARG_NAME(mp->m_ddev_targp),
+                       xfs_emerg(mp,
+                               "bad inode magic/vsn daddr %lld #%d (magic=%x)",
                                (unsigned long long)imap->im_blkno, i,
                                be16_to_cpu(dip->di_magic));
+                       ASSERT(0);
 #endif
                        xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(EFSCORRUPTED);
@@ -317,7 +315,7 @@ xfs_iformat(
        if (unlikely(be32_to_cpu(dip->di_nextents) +
                     be16_to_cpu(dip->di_anextents) >
                     be64_to_cpu(dip->di_nblocks))) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
+               xfs_warn(ip->i_mount,
                        "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
                        (unsigned long long)ip->i_ino,
                        (int)(be32_to_cpu(dip->di_nextents) +
@@ -330,8 +328,7 @@ xfs_iformat(
        }
 
        if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                       "corrupt dinode %Lu, forkoff = 0x%x.",
+               xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
                        (unsigned long long)ip->i_ino,
                        dip->di_forkoff);
                XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
@@ -341,7 +338,7 @@ xfs_iformat(
 
        if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
                     !ip->i_mount->m_rtdev_targp)) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
+               xfs_warn(ip->i_mount,
                        "corrupt dinode %Lu, has realtime flag set.",
                        ip->i_ino);
                XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
@@ -373,9 +370,8 @@ xfs_iformat(
                         * no local regular files yet
                         */
                        if (unlikely((be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG)) {
-                               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                                       "corrupt inode %Lu "
-                                       "(local format for regular file).",
+                               xfs_warn(ip->i_mount,
+                       "corrupt inode %Lu (local format for regular file).",
                                        (unsigned long long) ip->i_ino);
                                XFS_CORRUPTION_ERROR("xfs_iformat(4)",
                                                     XFS_ERRLEVEL_LOW,
@@ -385,9 +381,8 @@ xfs_iformat(
 
                        di_size = be64_to_cpu(dip->di_size);
                        if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
-                               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                                       "corrupt inode %Lu "
-                                       "(bad size %Ld for local inode).",
+                               xfs_warn(ip->i_mount,
+                       "corrupt inode %Lu (bad size %Ld for local inode).",
                                        (unsigned long long) ip->i_ino,
                                        (long long) di_size);
                                XFS_CORRUPTION_ERROR("xfs_iformat(5)",
@@ -431,9 +426,8 @@ xfs_iformat(
                size = be16_to_cpu(atp->hdr.totsize);
 
                if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
-                       xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                               "corrupt inode %Lu "
-                               "(bad attr fork size %Ld).",
+                       xfs_warn(ip->i_mount,
+                               "corrupt inode %Lu (bad attr fork size %Ld).",
                                (unsigned long long) ip->i_ino,
                                (long long) size);
                        XFS_CORRUPTION_ERROR("xfs_iformat(8)",
@@ -488,9 +482,8 @@ xfs_iformat_local(
         * kmem_alloc() or memcpy() below.
         */
        if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                       "corrupt inode %Lu "
-                       "(bad size %d for local fork, size = %d).",
+               xfs_warn(ip->i_mount,
+       "corrupt inode %Lu (bad size %d for local fork, size = %d).",
                        (unsigned long long) ip->i_ino, size,
                        XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
                XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
@@ -547,8 +540,7 @@ xfs_iformat_extents(
         * kmem_alloc() or memcpy() below.
         */
        if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                       "corrupt inode %Lu ((a)extents = %d).",
+               xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
                        (unsigned long long) ip->i_ino, nex);
                XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
                                     ip->i_mount, dip);
@@ -623,11 +615,10 @@ xfs_iformat_btree(
            || XFS_BMDR_SPACE_CALC(nrecs) >
                        XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)
            || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
-               xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount,
-                       "corrupt inode %Lu (btree).",
+               xfs_warn(ip->i_mount, "corrupt inode %Lu (btree).",
                        (unsigned long long) ip->i_ino);
-               XFS_ERROR_REPORT("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
-                                ip->i_mount);
+               XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
+                                ip->i_mount, dip);
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -813,11 +804,9 @@ xfs_iread(
         */
        if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC) {
 #ifdef DEBUG
-               xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
-                               "dip->di_magic (0x%x) != "
-                               "XFS_DINODE_MAGIC (0x%x)",
-                               be16_to_cpu(dip->di_magic),
-                               XFS_DINODE_MAGIC);
+               xfs_alert(mp,
+                       "%s: dip->di_magic (0x%x) != XFS_DINODE_MAGIC (0x%x)",
+                       __func__, be16_to_cpu(dip->di_magic), XFS_DINODE_MAGIC);
 #endif /* DEBUG */
                error = XFS_ERROR(EINVAL);
                goto out_brelse;
@@ -835,9 +824,8 @@ xfs_iread(
                error = xfs_iformat(ip, dip);
                if (error)  {
 #ifdef DEBUG
-                       xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
-                                       "xfs_iformat() returned error %d",
-                                       error);
+                       xfs_alert(mp, "%s: xfs_iformat() returned error %d",
+                               __func__, error);
 #endif /* DEBUG */
                        goto out_brelse;
                }
@@ -1016,8 +1004,8 @@ xfs_ialloc(
         * This is because we're setting fields here we need
         * to prevent others from looking at until we're done.
         */
-       error = xfs_trans_iget(tp->t_mountp, tp, ino,
-                               XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);
+       error = xfs_iget(tp->t_mountp, tp, ino, XFS_IGET_CREATE,
+                        XFS_ILOCK_EXCL, &ip);
        if (error)
                return error;
        ASSERT(ip != NULL);
@@ -1166,6 +1154,7 @@ xfs_ialloc(
        /*
         * Log the new values stuffed into the inode.
         */
+       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
        xfs_trans_log_inode(tp, ip, flags);
 
        /* now that we have an i_mode we can setup inode ops and unlock */
@@ -1820,9 +1809,8 @@ xfs_iunlink_remove(
                 */
                error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
                if (error) {
-                       cmn_err(CE_WARN,
-                               "xfs_iunlink_remove: xfs_itobp()  returned an error %d on %s.  Returning error.",
-                               error, mp->m_fsname);
+                       xfs_warn(mp, "%s: xfs_itobp() returned error %d.",
+                               __func__, error);
                        return error;
                }
                next_agino = be32_to_cpu(dip->di_next_unlinked);
@@ -1867,9 +1855,9 @@ xfs_iunlink_remove(
                        error = xfs_inotobp(mp, tp, next_ino, &last_dip,
                                            &last_ibp, &last_offset, 0);
                        if (error) {
-                               cmn_err(CE_WARN,
-                       "xfs_iunlink_remove: xfs_inotobp()  returned an error %d on %s.  Returning error.",
-                                       error, mp->m_fsname);
+                               xfs_warn(mp,
+                                       "%s: xfs_inotobp() returned error %d.",
+                                       __func__, error);
                                return error;
                        }
                        next_agino = be32_to_cpu(last_dip->di_next_unlinked);
@@ -1882,9 +1870,8 @@ xfs_iunlink_remove(
                 */
                error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
                if (error) {
-                       cmn_err(CE_WARN,
-                               "xfs_iunlink_remove: xfs_itobp()  returned an error %d on %s.  Returning error.",
-                               error, mp->m_fsname);
+                       xfs_warn(mp, "%s: xfs_itobp(2) returned error %d.",
+                               __func__, error);
                        return error;
                }
                next_agino = be32_to_cpu(dip->di_next_unlinked);
@@ -2939,16 +2926,16 @@ xfs_iflush_int(
 
        if (XFS_TEST_ERROR(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC,
                               mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
-               xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                   "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p",
-                       ip->i_ino, be16_to_cpu(dip->di_magic), dip);
+               xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                       "%s: Bad inode %Lu magic number 0x%x, ptr 0x%p",
+                       __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip);
                goto corrupt_out;
        }
        if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC,
                                mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) {
-               xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                       "xfs_iflush: Bad inode %Lu, ptr 0x%p, magic number 0x%x",
-                       ip->i_ino, ip, ip->i_d.di_magic);
+               xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                       "%s: Bad inode %Lu, ptr 0x%p, magic number 0x%x",
+                       __func__, ip->i_ino, ip, ip->i_d.di_magic);
                goto corrupt_out;
        }
        if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
@@ -2956,9 +2943,9 @@ xfs_iflush_int(
                    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
                    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
                    mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) {
-                       xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                               "xfs_iflush: Bad regular inode %Lu, ptr 0x%p",
-                               ip->i_ino, ip);
+                       xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                               "%s: Bad regular inode %Lu, ptr 0x%p",
+                               __func__, ip->i_ino, ip);
                        goto corrupt_out;
                }
        } else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
@@ -2967,28 +2954,28 @@ xfs_iflush_int(
                    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
                    (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
                    mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) {
-                       xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                               "xfs_iflush: Bad directory inode %Lu, ptr 0x%p",
-                               ip->i_ino, ip);
+                       xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                               "%s: Bad directory inode %Lu, ptr 0x%p",
+                               __func__, ip->i_ino, ip);
                        goto corrupt_out;
                }
        }
        if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents >
                                ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5,
                                XFS_RANDOM_IFLUSH_5)) {
-               xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                       "xfs_iflush: detected corrupt incore inode %Lu, total extents = %d, nblocks = %Ld, ptr 0x%p",
-                       ip->i_ino,
+               xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                       "%s: detected corrupt incore inode %Lu, "
+                       "total extents = %d, nblocks = %Ld, ptr 0x%p",
+                       __func__, ip->i_ino,
                        ip->i_d.di_nextents + ip->i_d.di_anextents,
-                       ip->i_d.di_nblocks,
-                       ip);
+                       ip->i_d.di_nblocks, ip);
                goto corrupt_out;
        }
        if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize,
                                mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) {
-               xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp,
-                       "xfs_iflush: bad inode %Lu, forkoff 0x%x, ptr 0x%p",
-                       ip->i_ino, ip->i_d.di_forkoff, ip);
+               xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+                       "%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p",
+                       __func__, ip->i_ino, ip->i_d.di_forkoff, ip);
                goto corrupt_out;
        }
        /*
index 5c95fa8ec11da9c703f756b4dbe42e81a569a6ac..f753200cef8d365593e9a0c1c1b155e968f3f8f8 100644 (file)
@@ -409,28 +409,35 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
 /*
  * Flags for lockdep annotations.
  *
- * XFS_I[O]LOCK_PARENT - for operations that require locking two inodes
- * (ie directory operations that require locking a directory inode and
- * an entry inode).  The first inode gets locked with this flag so it
- * gets a lockdep subclass of 1 and the second lock will have a lockdep
- * subclass of 0.
+ * XFS_LOCK_PARENT - for directory operations that require locking a
+ * parent directory inode and a child entry inode.  The parent gets locked
+ * with this flag so it gets a lockdep subclass of 1 and the child entry
+ * lock will have a lockdep subclass of 0.
+ *
+ * XFS_LOCK_RTBITMAP/XFS_LOCK_RTSUM - the realtime device bitmap and summary
+ * inodes do not participate in the normal lock order, and thus have their
+ * own subclasses.
  *
  * XFS_LOCK_INUMORDER - for locking several inodes at the some time
  * with xfs_lock_inodes().  This flag is used as the starting subclass
  * and each subsequent lock acquired will increment the subclass by one.
- * So the first lock acquired will have a lockdep subclass of 2, the
- * second lock will have a lockdep subclass of 3, and so on. It is
+ * So the first lock acquired will have a lockdep subclass of 4, the
+ * second lock will have a lockdep subclass of 5, and so on. It is
  * the responsibility of the class builder to shift this to the correct
  * portion of the lock_mode lockdep mask.
  */
 #define XFS_LOCK_PARENT                1
-#define XFS_LOCK_INUMORDER     2
+#define XFS_LOCK_RTBITMAP      2
+#define XFS_LOCK_RTSUM         3
+#define XFS_LOCK_INUMORDER     4
 
 #define XFS_IOLOCK_SHIFT       16
 #define        XFS_IOLOCK_PARENT       (XFS_LOCK_PARENT << XFS_IOLOCK_SHIFT)
 
 #define XFS_ILOCK_SHIFT                24
 #define        XFS_ILOCK_PARENT        (XFS_LOCK_PARENT << XFS_ILOCK_SHIFT)
+#define        XFS_ILOCK_RTBITMAP      (XFS_LOCK_RTBITMAP << XFS_ILOCK_SHIFT)
+#define        XFS_ILOCK_RTSUM         (XFS_LOCK_RTSUM << XFS_ILOCK_SHIFT)
 
 #define XFS_IOLOCK_DEP_MASK    0x00ff0000
 #define XFS_ILOCK_DEP_MASK     0xff000000
index 8a0f044750c3207eff174c4137bcd77580465894..091d82b94c4de518208d8eebc37abe4a7f3d4f1d 100644 (file)
@@ -101,11 +101,11 @@ xfs_iomap_eof_align_last_fsb(
 }
 
 STATIC int
-xfs_cmn_err_fsblock_zero(
+xfs_alert_fsblock_zero(
        xfs_inode_t     *ip,
        xfs_bmbt_irec_t *imap)
 {
-       xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
+       xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO,
                        "Access to block zero in inode %llu "
                        "start_block: %llx start_off: %llx "
                        "blkcnt: %llx extent-state: %x\n",
@@ -246,7 +246,7 @@ xfs_iomap_write_direct(
        }
 
        if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) {
-               error = xfs_cmn_err_fsblock_zero(ip, imap);
+               error = xfs_alert_fsblock_zero(ip, imap);
                goto error_out;
        }
 
@@ -464,7 +464,7 @@ retry:
        }
 
        if (!(imap[0].br_startblock || XFS_IS_REALTIME_INODE(ip)))
-               return xfs_cmn_err_fsblock_zero(ip, &imap[0]);
+               return xfs_alert_fsblock_zero(ip, &imap[0]);
 
        *ret_imap = imap[0];
        return 0;
@@ -614,7 +614,7 @@ xfs_iomap_write_allocate(
                 * covers at least part of the callers request
                 */
                if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
-                       return xfs_cmn_err_fsblock_zero(ip, imap);
+                       return xfs_alert_fsblock_zero(ip, imap);
 
                if ((offset_fsb >= imap->br_startoff) &&
                    (offset_fsb < (imap->br_startoff +
@@ -724,7 +724,7 @@ xfs_iomap_write_unwritten(
                        return XFS_ERROR(error);
 
                if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip)))
-                       return xfs_cmn_err_fsblock_zero(ip, &imap);
+                       return xfs_alert_fsblock_zero(ip, &imap);
 
                if ((numblks_fsb = imap.br_blockcount) == 0) {
                        /*
index ae6fef1ff563e19ceb6b97393ed3ec8804c110b5..25efa9b8a6029ac35df73942459132abd71dc228 100644 (file)
@@ -374,11 +374,10 @@ xfs_log_mount(
        int             error;
 
        if (!(mp->m_flags & XFS_MOUNT_NORECOVERY))
-               cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname);
+               xfs_notice(mp, "Mounting Filesystem");
        else {
-               cmn_err(CE_NOTE,
-                       "Mounting filesystem \"%s\" in no-recovery mode.  Filesystem will be inconsistent.",
-                       mp->m_fsname);
+               xfs_notice(mp,
+"Mounting filesystem in no-recovery mode.  Filesystem will be inconsistent.");
                ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
        }
 
@@ -393,7 +392,7 @@ xfs_log_mount(
         */
        error = xfs_trans_ail_init(mp);
        if (error) {
-               cmn_err(CE_WARN, "XFS: AIL initialisation failed: error %d", error);
+               xfs_warn(mp, "AIL initialisation failed: error %d", error);
                goto out_free_log;
        }
        mp->m_log->l_ailp = mp->m_ail;
@@ -413,7 +412,8 @@ xfs_log_mount(
                if (readonly)
                        mp->m_flags |= XFS_MOUNT_RDONLY;
                if (error) {
-                       cmn_err(CE_WARN, "XFS: log mount/recovery failed: error %d", error);
+                       xfs_warn(mp, "log mount/recovery failed: error %d",
+                               error);
                        goto out_destroy_ail;
                }
        }
@@ -542,10 +542,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
                         */
                }
 
-               if (error) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "xfs_log_unmount: unmount record failed");
-               }
+               if (error)
+                       xfs_alert(mp, "%s: unmount record failed", __func__);
 
 
                spin_lock(&log->l_icloglock);
@@ -852,7 +850,7 @@ xlog_space_left(
                 * In this case we just want to return the size of the
                 * log as the amount of space left.
                 */
-               xfs_fs_cmn_err(CE_ALERT, log->l_mp,
+               xfs_alert(log->l_mp,
                        "xlog_space_left: head behind tail\n"
                        "  tail_cycle = %d, tail_bytes = %d\n"
                        "  GH   cycle = %d, GH   bytes = %d",
@@ -1001,7 +999,7 @@ xlog_alloc_log(xfs_mount_t *mp,
 
        log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
        if (!log) {
-               xlog_warn("XFS: Log allocation failed: No memory!");
+               xfs_warn(mp, "Log allocation failed: No memory!");
                goto out;
        }
 
@@ -1029,24 +1027,24 @@ xlog_alloc_log(xfs_mount_t      *mp,
        if (xfs_sb_version_hassector(&mp->m_sb)) {
                log2_size = mp->m_sb.sb_logsectlog;
                if (log2_size < BBSHIFT) {
-                       xlog_warn("XFS: Log sector size too small "
-                               "(0x%x < 0x%x)", log2_size, BBSHIFT);
+                       xfs_warn(mp, "Log sector size too small (0x%x < 0x%x)",
+                               log2_size, BBSHIFT);
                        goto out_free_log;
                }
 
                log2_size -= BBSHIFT;
                if (log2_size > mp->m_sectbb_log) {
-                       xlog_warn("XFS: Log sector size too large "
-                               "(0x%x > 0x%x)", log2_size, mp->m_sectbb_log);
+                       xfs_warn(mp, "Log sector size too large (0x%x > 0x%x)",
+                               log2_size, mp->m_sectbb_log);
                        goto out_free_log;
                }
 
                /* for larger sector sizes, must have v2 or external log */
                if (log2_size && log->l_logBBstart > 0 &&
                            !xfs_sb_version_haslogv2(&mp->m_sb)) {
-
-                       xlog_warn("XFS: log sector size (0x%x) invalid "
-                                 "for configuration.", log2_size);
+                       xfs_warn(mp,
+               "log sector size (0x%x) invalid for configuration.",
+                               log2_size);
                        goto out_free_log;
                }
        }
@@ -1563,38 +1561,36 @@ xlog_print_tic_res(
            "SWAPEXT"
        };
 
-       xfs_fs_cmn_err(CE_WARN, mp,
-                       "xfs_log_write: reservation summary:\n"
-                       "  trans type  = %s (%u)\n"
-                       "  unit res    = %d bytes\n"
-                       "  current res = %d bytes\n"
-                       "  total reg   = %u bytes (o/flow = %u bytes)\n"
-                       "  ophdrs      = %u (ophdr space = %u bytes)\n"
-                       "  ophdr + reg = %u bytes\n"
-                       "  num regions = %u\n",
-                       ((ticket->t_trans_type <= 0 ||
-                         ticket->t_trans_type > XFS_TRANS_TYPE_MAX) ?
-                         "bad-trans-type" : trans_type_str[ticket->t_trans_type-1]),
-                       ticket->t_trans_type,
-                       ticket->t_unit_res,
-                       ticket->t_curr_res,
-                       ticket->t_res_arr_sum, ticket->t_res_o_flow,
-                       ticket->t_res_num_ophdrs, ophdr_spc,
-                       ticket->t_res_arr_sum + 
-                       ticket->t_res_o_flow + ophdr_spc,
-                       ticket->t_res_num);
+       xfs_warn(mp,
+               "xfs_log_write: reservation summary:\n"
+               "  trans type  = %s (%u)\n"
+               "  unit res    = %d bytes\n"
+               "  current res = %d bytes\n"
+               "  total reg   = %u bytes (o/flow = %u bytes)\n"
+               "  ophdrs      = %u (ophdr space = %u bytes)\n"
+               "  ophdr + reg = %u bytes\n"
+               "  num regions = %u\n",
+               ((ticket->t_trans_type <= 0 ||
+                 ticket->t_trans_type > XFS_TRANS_TYPE_MAX) ?
+                 "bad-trans-type" : trans_type_str[ticket->t_trans_type-1]),
+               ticket->t_trans_type,
+               ticket->t_unit_res,
+               ticket->t_curr_res,
+               ticket->t_res_arr_sum, ticket->t_res_o_flow,
+               ticket->t_res_num_ophdrs, ophdr_spc,
+               ticket->t_res_arr_sum +
+               ticket->t_res_o_flow + ophdr_spc,
+               ticket->t_res_num);
 
        for (i = 0; i < ticket->t_res_num; i++) {
-               uint r_type = ticket->t_res_arr[i].r_type; 
-               cmn_err(CE_WARN,
-                           "region[%u]: %s - %u bytes\n",
-                           i, 
+               uint r_type = ticket->t_res_arr[i].r_type;
+               xfs_warn(mp, "region[%u]: %s - %u bytes\n", i,
                            ((r_type <= 0 || r_type > XLOG_REG_TYPE_MAX) ?
                            "bad-rtype" : res_type_str[r_type-1]),
                            ticket->t_res_arr[i].r_len);
        }
 
-       xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp,
+       xfs_alert_tag(mp, XFS_PTAG_LOGRES,
                "xfs_log_write: reservation ran out. Need to up reservation");
        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 }
@@ -1682,7 +1678,7 @@ xlog_write_setup_ophdr(
        case XFS_LOG:
                break;
        default:
-               xfs_fs_cmn_err(CE_WARN, log->l_mp,
+               xfs_warn(log->l_mp,
                        "Bad XFS transaction clientid 0x%x in ticket 0x%p",
                        ophdr->oh_clientid, ticket);
                return NULL;
@@ -2264,7 +2260,7 @@ xlog_state_do_callback(
                if (repeats > 5000) {
                        flushcnt += repeats;
                        repeats = 0;
-                       xfs_fs_cmn_err(CE_WARN, log->l_mp,
+                       xfs_warn(log->l_mp,
                                "%s: possible infinite loop (%d iterations)",
                                __func__, flushcnt);
                }
@@ -3052,10 +3048,8 @@ xfs_log_force(
        int     error;
 
        error = _xfs_log_force(mp, flags, NULL);
-       if (error) {
-               xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: "
-                       "error %d returned.", error);
-       }
+       if (error)
+               xfs_warn(mp, "%s: error %d returned.", __func__, error);
 }
 
 /*
@@ -3204,10 +3198,8 @@ xfs_log_force_lsn(
        int     error;
 
        error = _xfs_log_force_lsn(mp, lsn, flags, NULL);
-       if (error) {
-               xfs_fs_cmn_err(CE_WARN, mp, "xfs_log_force: "
-                       "error %d returned.", error);
-       }
+       if (error)
+               xfs_warn(mp, "%s: error %d returned.", __func__, error);
 }
 
 /*
@@ -3412,7 +3404,7 @@ xlog_verify_dest_ptr(
        }
 
        if (!good_ptr)
-               xlog_panic("xlog_verify_dest_ptr: invalid ptr");
+               xfs_emerg(log->l_mp, "%s: invalid ptr", __func__);
 }
 
 STATIC void
@@ -3448,16 +3440,16 @@ xlog_verify_tail_lsn(xlog_t         *log,
        blocks =
            log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn));
        if (blocks < BTOBB(iclog->ic_offset)+BTOBB(log->l_iclog_hsize))
-           xlog_panic("xlog_verify_tail_lsn: ran out of log space");
+               xfs_emerg(log->l_mp, "%s: ran out of log space", __func__);
     } else {
        ASSERT(CYCLE_LSN(tail_lsn)+1 == log->l_prev_cycle);
 
        if (BLOCK_LSN(tail_lsn) == log->l_prev_block)
-           xlog_panic("xlog_verify_tail_lsn: tail wrapped");
+               xfs_emerg(log->l_mp, "%s: tail wrapped", __func__);
 
        blocks = BLOCK_LSN(tail_lsn) - log->l_prev_block;
        if (blocks < BTOBB(iclog->ic_offset) + 1)
-           xlog_panic("xlog_verify_tail_lsn: ran out of log space");
+               xfs_emerg(log->l_mp, "%s: ran out of log space", __func__);
     }
 }      /* xlog_verify_tail_lsn */
 
@@ -3497,22 +3489,23 @@ xlog_verify_iclog(xlog_t         *log,
        icptr = log->l_iclog;
        for (i=0; i < log->l_iclog_bufs; i++) {
                if (icptr == NULL)
-                       xlog_panic("xlog_verify_iclog: invalid ptr");
+                       xfs_emerg(log->l_mp, "%s: invalid ptr", __func__);
                icptr = icptr->ic_next;
        }
        if (icptr != log->l_iclog)
-               xlog_panic("xlog_verify_iclog: corrupt iclog ring");
+               xfs_emerg(log->l_mp, "%s: corrupt iclog ring", __func__);
        spin_unlock(&log->l_icloglock);
 
        /* check log magic numbers */
        if (be32_to_cpu(iclog->ic_header.h_magicno) != XLOG_HEADER_MAGIC_NUM)
-               xlog_panic("xlog_verify_iclog: invalid magic num");
+               xfs_emerg(log->l_mp, "%s: invalid magic num", __func__);
 
        ptr = (xfs_caddr_t) &iclog->ic_header;
        for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&iclog->ic_header) + count;
             ptr += BBSIZE) {
                if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM)
-                       xlog_panic("xlog_verify_iclog: unexpected magic num");
+                       xfs_emerg(log->l_mp, "%s: unexpected magic num",
+                               __func__);
        }
 
        /* check fields */
@@ -3542,9 +3535,10 @@ xlog_verify_iclog(xlog_t  *log,
                        }
                }
                if (clientid != XFS_TRANSACTION && clientid != XFS_LOG)
-                       cmn_err(CE_WARN, "xlog_verify_iclog: "
-                               "invalid clientid %d op 0x%p offset 0x%lx",
-                               clientid, ophead, (unsigned long)field_offset);
+                       xfs_warn(log->l_mp,
+                               "%s: invalid clientid %d op 0x%p offset 0x%lx",
+                               __func__, clientid, ophead,
+                               (unsigned long)field_offset);
 
                /* check length */
                field_offset = (__psint_t)
index d5f8be8f4bf603cac8c3f0394759e5fefdd8d42e..15dbf1f9c2be6c962655a84f6a254cc191723cee 100644 (file)
@@ -87,10 +87,6 @@ static inline uint xlog_get_client_id(__be32 i)
        return be32_to_cpu(i) >> 24;
 }
 
-#define xlog_panic(args...)    cmn_err(CE_PANIC, ## args)
-#define xlog_exit(args...)     cmn_err(CE_PANIC, ## args)
-#define xlog_warn(args...)     cmn_err(CE_WARN, ## args)
-
 /*
  * In core log state
  */
index aa0ebb776903317a8d29916396eb547c3ce296c9..0c4a5618e7af769c051da1337f4f338457b14866 100644 (file)
@@ -92,7 +92,7 @@ xlog_get_bp(
        int             nbblks)
 {
        if (!xlog_buf_bbcount_valid(log, nbblks)) {
-               xlog_warn("XFS: Invalid block length (0x%x) given for buffer",
+               xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return NULL;
@@ -160,7 +160,7 @@ xlog_bread_noalign(
        int             error;
 
        if (!xlog_buf_bbcount_valid(log, nbblks)) {
-               xlog_warn("XFS: Invalid block length (0x%x) given for buffer",
+               xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return EFSCORRUPTED;
@@ -219,7 +219,7 @@ xlog_bwrite(
        int             error;
 
        if (!xlog_buf_bbcount_valid(log, nbblks)) {
-               xlog_warn("XFS: Invalid block length (0x%x) given for buffer",
+               xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer",
                        nbblks);
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp);
                return EFSCORRUPTED;
@@ -254,9 +254,9 @@ xlog_header_check_dump(
        xfs_mount_t             *mp,
        xlog_rec_header_t       *head)
 {
-       cmn_err(CE_DEBUG, "%s:  SB : uuid = %pU, fmt = %d\n",
+       xfs_debug(mp, "%s:  SB : uuid = %pU, fmt = %d\n",
                __func__, &mp->m_sb.sb_uuid, XLOG_FMT);
-       cmn_err(CE_DEBUG, "    log : uuid = %pU, fmt = %d\n",
+       xfs_debug(mp, "    log : uuid = %pU, fmt = %d\n",
                &head->h_fs_uuid, be32_to_cpu(head->h_fmt));
 }
 #else
@@ -279,15 +279,15 @@ xlog_header_check_recover(
         * a dirty log created in IRIX.
         */
        if (unlikely(be32_to_cpu(head->h_fmt) != XLOG_FMT)) {
-               xlog_warn(
-       "XFS: dirty log written in incompatible format - can't recover");
+               xfs_warn(mp,
+       "dirty log written in incompatible format - can't recover");
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_recover(1)",
                                 XFS_ERRLEVEL_HIGH, mp);
                return XFS_ERROR(EFSCORRUPTED);
        } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
-               xlog_warn(
-       "XFS: dirty log entry has mismatched uuid - can't recover");
+               xfs_warn(mp,
+       "dirty log entry has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_recover(2)",
                                 XFS_ERRLEVEL_HIGH, mp);
@@ -312,9 +312,9 @@ xlog_header_check_mount(
                 * h_fs_uuid is nil, we assume this log was last mounted
                 * by IRIX and continue.
                 */
-               xlog_warn("XFS: nil uuid in log - IRIX style log");
+               xfs_warn(mp, "nil uuid in log - IRIX style log");
        } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
-               xlog_warn("XFS: log has mismatched uuid - can't recover");
+               xfs_warn(mp, "log has mismatched uuid - can't recover");
                xlog_header_check_dump(mp, head);
                XFS_ERROR_REPORT("xlog_header_check_mount",
                                 XFS_ERRLEVEL_HIGH, mp);
@@ -490,8 +490,8 @@ xlog_find_verify_log_record(
        for (i = (*last_blk) - 1; i >= 0; i--) {
                if (i < start_blk) {
                        /* valid log record not found */
-                       xlog_warn(
-               "XFS: Log inconsistent (didn't find previous header)");
+                       xfs_warn(log->l_mp,
+               "Log inconsistent (didn't find previous header)");
                        ASSERT(0);
                        error = XFS_ERROR(EIO);
                        goto out;
@@ -591,12 +591,12 @@ xlog_find_head(
                         * mkfs etc write a dummy unmount record to a fresh
                         * log so we can store the uuid in there
                         */
-                       xlog_warn("XFS: totally zeroed log");
+                       xfs_warn(log->l_mp, "totally zeroed log");
                }
 
                return 0;
        } else if (error) {
-               xlog_warn("XFS: empty log check failed");
+               xfs_warn(log->l_mp, "empty log check failed");
                return error;
        }
 
@@ -819,7 +819,7 @@ validate_head:
        xlog_put_bp(bp);
 
        if (error)
-           xlog_warn("XFS: failed to find log head");
+               xfs_warn(log->l_mp, "failed to find log head");
        return error;
 }
 
@@ -912,7 +912,7 @@ xlog_find_tail(
                }
        }
        if (!found) {
-               xlog_warn("XFS: xlog_find_tail: couldn't find sync record");
+               xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
                ASSERT(0);
                return XFS_ERROR(EIO);
        }
@@ -1028,7 +1028,7 @@ done:
        xlog_put_bp(bp);
 
        if (error)
-               xlog_warn("XFS: failed to locate log tail");
+               xfs_warn(log->l_mp, "failed to locate log tail");
        return error;
 }
 
@@ -1092,7 +1092,8 @@ xlog_find_zeroed(
                 * the first block must be 1. If it's not, maybe we're
                 * not looking at a log... Bail out.
                 */
-               xlog_warn("XFS: Log inconsistent or not a log (last==0, first!=1)");
+               xfs_warn(log->l_mp,
+                       "Log inconsistent or not a log (last==0, first!=1)");
                return XFS_ERROR(EINVAL);
        }
 
@@ -1506,8 +1507,8 @@ xlog_recover_add_to_trans(
        if (list_empty(&trans->r_itemq)) {
                /* we need to catch log corruptions here */
                if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) {
-                       xlog_warn("XFS: xlog_recover_add_to_trans: "
-                                 "bad header magic number");
+                       xfs_warn(log->l_mp, "%s: bad header magic number",
+                               __func__);
                        ASSERT(0);
                        return XFS_ERROR(EIO);
                }
@@ -1534,8 +1535,8 @@ xlog_recover_add_to_trans(
        if (item->ri_total == 0) {              /* first region to be added */
                if (in_f->ilf_size == 0 ||
                    in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) {
-                       xlog_warn(
-       "XFS: bad number of regions (%d) in inode log format",
+                       xfs_warn(log->l_mp,
+               "bad number of regions (%d) in inode log format",
                                  in_f->ilf_size);
                        ASSERT(0);
                        return XFS_ERROR(EIO);
@@ -1592,8 +1593,9 @@ xlog_recover_reorder_trans(
                        list_move_tail(&item->ri_list, &trans->r_itemq);
                        break;
                default:
-                       xlog_warn(
-       "XFS: xlog_recover_reorder_trans: unrecognized type of log operation");
+                       xfs_warn(log->l_mp,
+                               "%s: unrecognized type of log operation",
+                               __func__);
                        ASSERT(0);
                        return XFS_ERROR(EIO);
                }
@@ -1803,8 +1805,9 @@ xlog_recover_do_inode_buffer(
                logged_nextp = item->ri_buf[item_index].i_addr +
                                next_unlinked_offset - reg_buf_offset;
                if (unlikely(*logged_nextp == 0)) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "bad inode buffer log record (ptr = 0x%p, bp = 0x%p).  XFS trying to replay bad (0) inode di_next_unlinked field",
+                       xfs_alert(mp,
+               "Bad inode buffer log record (ptr = 0x%p, bp = 0x%p). "
+               "Trying to replay bad (0) inode di_next_unlinked field.",
                                item, bp);
                        XFS_ERROR_REPORT("xlog_recover_do_inode_buf",
                                         XFS_ERRLEVEL_LOW, mp);
@@ -1863,17 +1866,17 @@ xlog_recover_do_reg_buffer(
                if (buf_f->blf_flags &
                   (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
                        if (item->ri_buf[i].i_addr == NULL) {
-                               cmn_err(CE_ALERT,
+                               xfs_alert(mp,
                                        "XFS: NULL dquot in %s.", __func__);
                                goto next;
                        }
                        if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) {
-                               cmn_err(CE_ALERT,
+                               xfs_alert(mp,
                                        "XFS: dquot too small (%d) in %s.",
                                        item->ri_buf[i].i_len, __func__);
                                goto next;
                        }
-                       error = xfs_qm_dqcheck(item->ri_buf[i].i_addr,
+                       error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr,
                                               -1, 0, XFS_QMOPT_DOWARN,
                                               "dquot_buf_recover");
                        if (error)
@@ -1898,6 +1901,7 @@ xlog_recover_do_reg_buffer(
  */
 int
 xfs_qm_dqcheck(
+       struct xfs_mount *mp,
        xfs_disk_dquot_t *ddq,
        xfs_dqid_t       id,
        uint             type,    /* used only when IO_dorepair is true */
@@ -1924,14 +1928,14 @@ xfs_qm_dqcheck(
         */
        if (be16_to_cpu(ddq->d_magic) != XFS_DQUOT_MAGIC) {
                if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
+                       xfs_alert(mp,
                        "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x",
                        str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC);
                errs++;
        }
        if (ddq->d_version != XFS_DQUOT_VERSION) {
                if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
+                       xfs_alert(mp,
                        "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x",
                        str, id, ddq->d_version, XFS_DQUOT_VERSION);
                errs++;
@@ -1941,7 +1945,7 @@ xfs_qm_dqcheck(
            ddq->d_flags != XFS_DQ_PROJ &&
            ddq->d_flags != XFS_DQ_GROUP) {
                if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
+                       xfs_alert(mp,
                        "%s : XFS dquot ID 0x%x, unknown flags 0x%x",
                        str, id, ddq->d_flags);
                errs++;
@@ -1949,7 +1953,7 @@ xfs_qm_dqcheck(
 
        if (id != -1 && id != be32_to_cpu(ddq->d_id)) {
                if (flags & XFS_QMOPT_DOWARN)
-                       cmn_err(CE_ALERT,
+                       xfs_alert(mp,
                        "%s : ondisk-dquot 0x%p, ID mismatch: "
                        "0x%x expected, found id 0x%x",
                        str, ddq, id, be32_to_cpu(ddq->d_id));
@@ -1962,9 +1966,8 @@ xfs_qm_dqcheck(
                                be64_to_cpu(ddq->d_blk_softlimit)) {
                        if (!ddq->d_btimer) {
                                if (flags & XFS_QMOPT_DOWARN)
-                                       cmn_err(CE_ALERT,
-                                       "%s : Dquot ID 0x%x (0x%p) "
-                                       "BLK TIMER NOT STARTED",
+                                       xfs_alert(mp,
+                       "%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED",
                                        str, (int)be32_to_cpu(ddq->d_id), ddq);
                                errs++;
                        }
@@ -1974,9 +1977,8 @@ xfs_qm_dqcheck(
                                be64_to_cpu(ddq->d_ino_softlimit)) {
                        if (!ddq->d_itimer) {
                                if (flags & XFS_QMOPT_DOWARN)
-                                       cmn_err(CE_ALERT,
-                                       "%s : Dquot ID 0x%x (0x%p) "
-                                       "INODE TIMER NOT STARTED",
+                                       xfs_alert(mp,
+                       "%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED",
                                        str, (int)be32_to_cpu(ddq->d_id), ddq);
                                errs++;
                        }
@@ -1986,9 +1988,8 @@ xfs_qm_dqcheck(
                                be64_to_cpu(ddq->d_rtb_softlimit)) {
                        if (!ddq->d_rtbtimer) {
                                if (flags & XFS_QMOPT_DOWARN)
-                                       cmn_err(CE_ALERT,
-                                       "%s : Dquot ID 0x%x (0x%p) "
-                                       "RTBLK TIMER NOT STARTED",
+                                       xfs_alert(mp,
+                       "%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED",
                                        str, (int)be32_to_cpu(ddq->d_id), ddq);
                                errs++;
                        }
@@ -1999,7 +2000,7 @@ xfs_qm_dqcheck(
                return errs;
 
        if (flags & XFS_QMOPT_DOWARN)
-               cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id);
+               xfs_notice(mp, "Re-initializing dquot ID 0x%x", id);
 
        /*
         * Typically, a repair is only requested by quotacheck.
@@ -2218,9 +2219,9 @@ xlog_recover_inode_pass2(
         */
        if (unlikely(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC)) {
                xfs_buf_relse(bp);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_inode_recover: Bad inode magic number, dino ptr = 0x%p, dino bp = 0x%p, ino = %Ld",
-                       dip, bp, in_f->ilf_ino);
+               xfs_alert(mp,
+       "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld",
+                       __func__, dip, bp, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)",
                                 XFS_ERRLEVEL_LOW, mp);
                error = EFSCORRUPTED;
@@ -2229,9 +2230,9 @@ xlog_recover_inode_pass2(
        dicp = item->ri_buf[1].i_addr;
        if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
                xfs_buf_relse(bp);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, ino %Ld",
-                       item, in_f->ilf_ino);
+               xfs_alert(mp,
+                       "%s: Bad inode log record, rec ptr 0x%p, ino %Ld",
+                       __func__, item, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)",
                                 XFS_ERRLEVEL_LOW, mp);
                error = EFSCORRUPTED;
@@ -2263,9 +2264,10 @@ xlog_recover_inode_pass2(
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
                                         XFS_ERRLEVEL_LOW, mp, dicp);
                        xfs_buf_relse(bp);
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
-                               item, dip, bp, in_f->ilf_ino);
+                       xfs_alert(mp,
+               "%s: Bad regular inode log record, rec ptr 0x%p, "
+               "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
+                               __func__, item, dip, bp, in_f->ilf_ino);
                        error = EFSCORRUPTED;
                        goto error;
                }
@@ -2276,9 +2278,10 @@ xlog_recover_inode_pass2(
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)",
                                             XFS_ERRLEVEL_LOW, mp, dicp);
                        xfs_buf_relse(bp);
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                               "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
-                               item, dip, bp, in_f->ilf_ino);
+                       xfs_alert(mp,
+               "%s: Bad dir inode log record, rec ptr 0x%p, "
+               "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
+                               __func__, item, dip, bp, in_f->ilf_ino);
                        error = EFSCORRUPTED;
                        goto error;
                }
@@ -2287,9 +2290,10 @@ xlog_recover_inode_pass2(
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
                xfs_buf_relse(bp);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld",
-                       item, dip, bp, in_f->ilf_ino,
+               xfs_alert(mp,
+       "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
+       "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld",
+                       __func__, item, dip, bp, in_f->ilf_ino,
                        dicp->di_nextents + dicp->di_anextents,
                        dicp->di_nblocks);
                error = EFSCORRUPTED;
@@ -2299,8 +2303,9 @@ xlog_recover_inode_pass2(
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
                xfs_buf_relse(bp);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x",
+               xfs_alert(mp,
+       "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
+       "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__,
                        item, dip, bp, in_f->ilf_ino, dicp->di_forkoff);
                error = EFSCORRUPTED;
                goto error;
@@ -2309,9 +2314,9 @@ xlog_recover_inode_pass2(
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
                xfs_buf_relse(bp);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p",
-                       item->ri_buf[1].i_len, item);
+               xfs_alert(mp,
+                       "%s: Bad inode log record length %d, rec ptr 0x%p",
+                       __func__, item->ri_buf[1].i_len, item);
                error = EFSCORRUPTED;
                goto error;
        }
@@ -2398,7 +2403,7 @@ xlog_recover_inode_pass2(
                        break;
 
                default:
-                       xlog_warn("XFS: xlog_recover_inode_pass2: Invalid flag");
+                       xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
                        ASSERT(0);
                        xfs_buf_relse(bp);
                        error = EIO;
@@ -2467,13 +2472,11 @@ xlog_recover_dquot_pass2(
 
        recddq = item->ri_buf[1].i_addr;
        if (recddq == NULL) {
-               cmn_err(CE_ALERT,
-                       "XFS: NULL dquot in %s.", __func__);
+               xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
                return XFS_ERROR(EIO);
        }
        if (item->ri_buf[1].i_len < sizeof(xfs_disk_dquot_t)) {
-               cmn_err(CE_ALERT,
-                       "XFS: dquot too small (%d) in %s.",
+               xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
                        item->ri_buf[1].i_len, __func__);
                return XFS_ERROR(EIO);
        }
@@ -2498,12 +2501,10 @@ xlog_recover_dquot_pass2(
         */
        dq_f = item->ri_buf[0].i_addr;
        ASSERT(dq_f);
-       if ((error = xfs_qm_dqcheck(recddq,
-                          dq_f->qlf_id,
-                          0, XFS_QMOPT_DOWARN,
-                          "xlog_recover_dquot_pass2 (log copy)"))) {
+       error = xfs_qm_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
+                          "xlog_recover_dquot_pass2 (log copy)");
+       if (error)
                return XFS_ERROR(EIO);
-       }
        ASSERT(dq_f->qlf_len == 1);
 
        error = xfs_read_buf(mp, mp->m_ddev_targp,
@@ -2523,8 +2524,9 @@ xlog_recover_dquot_pass2(
         * was among a chunk of dquots created earlier, and we did some
         * minimal initialization then.
         */
-       if (xfs_qm_dqcheck(ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
-                          "xlog_recover_dquot_pass2")) {
+       error = xfs_qm_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,
+                          "xlog_recover_dquot_pass2");
+       if (error) {
                xfs_buf_relse(bp);
                return XFS_ERROR(EIO);
        }
@@ -2676,9 +2678,8 @@ xlog_recover_commit_pass1(
                /* nothing to do in pass 1 */
                return 0;
        default:
-               xlog_warn(
-       "XFS: invalid item type (%d) xlog_recover_commit_pass1",
-                       ITEM_TYPE(item));
+               xfs_warn(log->l_mp, "%s: invalid item type (%d)",
+                       __func__, ITEM_TYPE(item));
                ASSERT(0);
                return XFS_ERROR(EIO);
        }
@@ -2707,9 +2708,8 @@ xlog_recover_commit_pass2(
                /* nothing to do in pass2 */
                return 0;
        default:
-               xlog_warn(
-       "XFS: invalid item type (%d) xlog_recover_commit_pass2",
-                       ITEM_TYPE(item));
+               xfs_warn(log->l_mp, "%s: invalid item type (%d)",
+                       __func__, ITEM_TYPE(item));
                ASSERT(0);
                return XFS_ERROR(EIO);
        }
@@ -2751,10 +2751,11 @@ xlog_recover_commit_trans(
 
 STATIC int
 xlog_recover_unmount_trans(
+       struct log              *log,
        xlog_recover_t          *trans)
 {
        /* Do nothing now */
-       xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR");
+       xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
        return 0;
 }
 
@@ -2797,8 +2798,8 @@ xlog_recover_process_data(
                dp += sizeof(xlog_op_header_t);
                if (ohead->oh_clientid != XFS_TRANSACTION &&
                    ohead->oh_clientid != XFS_LOG) {
-                       xlog_warn(
-               "XFS: xlog_recover_process_data: bad clientid");
+                       xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
+                                       __func__, ohead->oh_clientid);
                        ASSERT(0);
                        return (XFS_ERROR(EIO));
                }
@@ -2811,8 +2812,8 @@ xlog_recover_process_data(
                                        be64_to_cpu(rhead->h_lsn));
                } else {
                        if (dp + be32_to_cpu(ohead->oh_len) > lp) {
-                               xlog_warn(
-                       "XFS: xlog_recover_process_data: bad length");
+                               xfs_warn(log->l_mp, "%s: bad length 0x%x",
+                                       __func__, be32_to_cpu(ohead->oh_len));
                                WARN_ON(1);
                                return (XFS_ERROR(EIO));
                        }
@@ -2825,7 +2826,7 @@ xlog_recover_process_data(
                                                                trans, pass);
                                break;
                        case XLOG_UNMOUNT_TRANS:
-                               error = xlog_recover_unmount_trans(trans);
+                               error = xlog_recover_unmount_trans(log, trans);
                                break;
                        case XLOG_WAS_CONT_TRANS:
                                error = xlog_recover_add_to_cont_trans(log,
@@ -2833,8 +2834,8 @@ xlog_recover_process_data(
                                                be32_to_cpu(ohead->oh_len));
                                break;
                        case XLOG_START_TRANS:
-                               xlog_warn(
-                       "XFS: xlog_recover_process_data: bad transaction");
+                               xfs_warn(log->l_mp, "%s: bad transaction",
+                                       __func__);
                                ASSERT(0);
                                error = XFS_ERROR(EIO);
                                break;
@@ -2844,8 +2845,8 @@ xlog_recover_process_data(
                                                dp, be32_to_cpu(ohead->oh_len));
                                break;
                        default:
-                               xlog_warn(
-                       "XFS: xlog_recover_process_data: bad flag");
+                               xfs_warn(log->l_mp, "%s: bad flag 0x%x",
+                                       __func__, flags);
                                ASSERT(0);
                                error = XFS_ERROR(EIO);
                                break;
@@ -3030,8 +3031,7 @@ xlog_recover_clear_agi_bucket(
 out_abort:
        xfs_trans_cancel(tp, XFS_TRANS_ABORT);
 out_error:
-       xfs_fs_cmn_err(CE_WARN, mp, "xlog_recover_clear_agi_bucket: "
-                       "failed to clear agi %d. Continuing.", agno);
+       xfs_warn(mp, "%s: failed to clear agi %d. Continuing.", __func__, agno);
        return;
 }
 
@@ -3282,7 +3282,7 @@ xlog_valid_rec_header(
        if (unlikely(
            (!rhead->h_version ||
            (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) {
-               xlog_warn("XFS: %s: unrecognised log version (%d).",
+               xfs_warn(log->l_mp, "%s: unrecognised log version (%d).",
                        __func__, be32_to_cpu(rhead->h_version));
                return XFS_ERROR(EIO);
        }
@@ -3740,10 +3740,9 @@ xlog_recover(
                        return error;
                }
 
-               cmn_err(CE_NOTE,
-                       "Starting XFS recovery on filesystem: %s (logdev: %s)",
-                       log->l_mp->m_fsname, log->l_mp->m_logname ?
-                       log->l_mp->m_logname : "internal");
+               xfs_notice(log->l_mp, "Starting recovery (logdev: %s)",
+                               log->l_mp->m_logname ? log->l_mp->m_logname
+                                                    : "internal");
 
                error = xlog_do_recover(log, head_blk, tail_blk);
                log->l_flags |= XLOG_RECOVERY_NEEDED;
@@ -3776,9 +3775,7 @@ xlog_recover_finish(
                int     error;
                error = xlog_recover_process_efis(log);
                if (error) {
-                       cmn_err(CE_ALERT,
-                               "Failed to recover EFIs on filesystem: %s",
-                               log->l_mp->m_fsname);
+                       xfs_alert(log->l_mp, "Failed to recover EFIs");
                        return error;
                }
                /*
@@ -3793,15 +3790,12 @@ xlog_recover_finish(
 
                xlog_recover_check_summary(log);
 
-               cmn_err(CE_NOTE,
-                       "Ending XFS recovery on filesystem: %s (logdev: %s)",
-                       log->l_mp->m_fsname, log->l_mp->m_logname ?
-                       log->l_mp->m_logname : "internal");
+               xfs_notice(log->l_mp, "Ending recovery (logdev: %s)",
+                               log->l_mp->m_logname ? log->l_mp->m_logname
+                                                    : "internal");
                log->l_flags &= ~XLOG_RECOVERY_NEEDED;
        } else {
-               cmn_err(CE_DEBUG,
-                       "Ending clean XFS mount for filesystem: %s\n",
-                       log->l_mp->m_fsname);
+               xfs_info(log->l_mp, "Ending clean mount");
        }
        return 0;
 }
@@ -3834,10 +3828,8 @@ xlog_recover_check_summary(
        for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
                error = xfs_read_agf(mp, NULL, agno, 0, &agfbp);
                if (error) {
-                       xfs_fs_cmn_err(CE_ALERT, mp,
-                                       "xlog_recover_check_summary(agf)"
-                                       "agf read failed agno %d error %d",
-                                                       agno, error);
+                       xfs_alert(mp, "%s agf read failed agno %d error %d",
+                                               __func__, agno, error);
                } else {
                        agfp = XFS_BUF_TO_AGF(agfbp);
                        freeblks += be32_to_cpu(agfp->agf_freeblks) +
@@ -3846,7 +3838,10 @@ xlog_recover_check_summary(
                }
 
                error = xfs_read_agi(mp, NULL, agno, &agibp);
-               if (!error) {
+               if (error) {
+                       xfs_alert(mp, "%s agi read failed agno %d error %d",
+                                               __func__, agno, error);
+               } else {
                        struct xfs_agi  *agi = XFS_BUF_TO_AGI(agibp);
 
                        itotal += be32_to_cpu(agi->agi_count);
index d447aef84bc3a552fe44fdd1559bbf05d3f5f17f..bb3f9a7b24ed7b6d36ef5536ea9d0b4020d9725e 100644 (file)
@@ -133,9 +133,7 @@ xfs_uuid_mount(
                return 0;
 
        if (uuid_is_nil(uuid)) {
-               cmn_err(CE_WARN,
-                       "XFS: Filesystem %s has nil UUID - can't mount",
-                       mp->m_fsname);
+               xfs_warn(mp, "Filesystem has nil UUID - can't mount");
                return XFS_ERROR(EINVAL);
        }
 
@@ -163,8 +161,7 @@ xfs_uuid_mount(
 
  out_duplicate:
        mutex_unlock(&xfs_uuid_table_mutex);
-       cmn_err(CE_WARN, "XFS: Filesystem %s has duplicate UUID - can't mount",
-                        mp->m_fsname);
+       xfs_warn(mp, "Filesystem has duplicate UUID - can't mount");
        return XFS_ERROR(EINVAL);
 }
 
@@ -311,6 +308,8 @@ xfs_mount_validate_sb(
        xfs_sb_t        *sbp,
        int             flags)
 {
+       int             loud = !(flags & XFS_MFSI_QUIET);
+
        /*
         * If the log device and data device have the
         * same device number, the log is internal.
@@ -319,28 +318,32 @@ xfs_mount_validate_sb(
         * a volume filesystem in a non-volume manner.
         */
        if (sbp->sb_magicnum != XFS_SB_MAGIC) {
-               xfs_fs_mount_cmn_err(flags, "bad magic number");
+               if (loud)
+                       xfs_warn(mp, "bad magic number");
                return XFS_ERROR(EWRONGFS);
        }
 
        if (!xfs_sb_good_version(sbp)) {
-               xfs_fs_mount_cmn_err(flags, "bad version");
+               if (loud)
+                       xfs_warn(mp, "bad version");
                return XFS_ERROR(EWRONGFS);
        }
 
        if (unlikely(
            sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
-               xfs_fs_mount_cmn_err(flags,
-                       "filesystem is marked as having an external log; "
-                       "specify logdev on the\nmount command line.");
+               if (loud)
+                       xfs_warn(mp,
+               "filesystem is marked as having an external log; "
+               "specify logdev on the mount command line.");
                return XFS_ERROR(EINVAL);
        }
 
        if (unlikely(
            sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
-               xfs_fs_mount_cmn_err(flags,
-                       "filesystem is marked as having an internal log; "
-                       "do not specify logdev on\nthe mount command line.");
+               if (loud)
+                       xfs_warn(mp,
+               "filesystem is marked as having an internal log; "
+               "do not specify logdev on the mount command line.");
                return XFS_ERROR(EINVAL);
        }
 
@@ -369,7 +372,8 @@ xfs_mount_validate_sb(
            (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
            (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)  ||
            (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */))) {
-               xfs_fs_mount_cmn_err(flags, "SB sanity check 1 failed");
+               if (loud)
+                       xfs_warn(mp, "SB sanity check 1 failed");
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -382,7 +386,8 @@ xfs_mount_validate_sb(
             (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks ||
            sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) *
                              sbp->sb_agblocks + XFS_MIN_AG_BLOCKS)) {
-               xfs_fs_mount_cmn_err(flags, "SB sanity check 2 failed");
+               if (loud)
+                       xfs_warn(mp, "SB sanity check 2 failed");
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -390,12 +395,12 @@ xfs_mount_validate_sb(
         * Until this is fixed only page-sized or smaller data blocks work.
         */
        if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
-               xfs_fs_mount_cmn_err(flags,
-                       "file system with blocksize %d bytes",
-                       sbp->sb_blocksize);
-               xfs_fs_mount_cmn_err(flags,
-                       "only pagesize (%ld) or less will currently work.",
-                       PAGE_SIZE);
+               if (loud) {
+                       xfs_warn(mp,
+               "File system with blocksize %d bytes. "
+               "Only pagesize (%ld) or less will currently work.",
+                               sbp->sb_blocksize, PAGE_SIZE);
+               }
                return XFS_ERROR(ENOSYS);
        }
 
@@ -409,21 +414,23 @@ xfs_mount_validate_sb(
        case 2048:
                break;
        default:
-               xfs_fs_mount_cmn_err(flags,
-                       "inode size of %d bytes not supported",
-                       sbp->sb_inodesize);
+               if (loud)
+                       xfs_warn(mp, "inode size of %d bytes not supported",
+                               sbp->sb_inodesize);
                return XFS_ERROR(ENOSYS);
        }
 
        if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
            xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
-               xfs_fs_mount_cmn_err(flags,
-                       "file system too large to be mounted on this system.");
+               if (loud)
+                       xfs_warn(mp,
+               "file system too large to be mounted on this system.");
                return XFS_ERROR(EFBIG);
        }
 
        if (unlikely(sbp->sb_inprogress)) {
-               xfs_fs_mount_cmn_err(flags, "file system busy");
+               if (loud)
+                       xfs_warn(mp, "file system busy");
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -431,8 +438,9 @@ xfs_mount_validate_sb(
         * Version 1 directory format has never worked on Linux.
         */
        if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
-               xfs_fs_mount_cmn_err(flags,
-                       "file system using version 1 directory format");
+               if (loud)
+                       xfs_warn(mp,
+                               "file system using version 1 directory format");
                return XFS_ERROR(ENOSYS);
        }
 
@@ -673,6 +681,7 @@ xfs_readsb(xfs_mount_t *mp, int flags)
        unsigned int    sector_size;
        xfs_buf_t       *bp;
        int             error;
+       int             loud = !(flags & XFS_MFSI_QUIET);
 
        ASSERT(mp->m_sb_bp == NULL);
        ASSERT(mp->m_ddev_targp != NULL);
@@ -688,7 +697,8 @@ reread:
        bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
                                        XFS_SB_DADDR, sector_size, 0);
        if (!bp) {
-               xfs_fs_mount_cmn_err(flags, "SB buffer read failed");
+               if (loud)
+                       xfs_warn(mp, "SB buffer read failed");
                return EIO;
        }
 
@@ -699,7 +709,8 @@ reread:
        xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
        error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
        if (error) {
-               xfs_fs_mount_cmn_err(flags, "SB validate failed");
+               if (loud)
+                       xfs_warn(mp, "SB validate failed");
                goto release_buf;
        }
 
@@ -707,9 +718,9 @@ reread:
         * We must be able to do sector-sized and sector-aligned IO.
         */
        if (sector_size > mp->m_sb.sb_sectsize) {
-               xfs_fs_mount_cmn_err(flags,
-                       "device supports only %u byte sectors (not %u)",
-                       sector_size, mp->m_sb.sb_sectsize);
+               if (loud)
+                       xfs_warn(mp, "device supports %u byte sectors (not %u)",
+                               sector_size, mp->m_sb.sb_sectsize);
                error = ENOSYS;
                goto release_buf;
        }
@@ -853,8 +864,7 @@ xfs_update_alignment(xfs_mount_t *mp)
                if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
                    (BBTOB(mp->m_swidth) & mp->m_blockmask)) {
                        if (mp->m_flags & XFS_MOUNT_RETERR) {
-                               cmn_err(CE_WARN,
-                                       "XFS: alignment check 1 failed");
+                               xfs_warn(mp, "alignment check 1 failed");
                                return XFS_ERROR(EINVAL);
                        }
                        mp->m_dalign = mp->m_swidth = 0;
@@ -867,8 +877,9 @@ xfs_update_alignment(xfs_mount_t *mp)
                                if (mp->m_flags & XFS_MOUNT_RETERR) {
                                        return XFS_ERROR(EINVAL);
                                }
-                               xfs_fs_cmn_err(CE_WARN, mp,
-"stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)",
+                               xfs_warn(mp,
+               "stripe alignment turned off: sunit(%d)/swidth(%d) "
+               "incompatible with agsize(%d)",
                                        mp->m_dalign, mp->m_swidth,
                                        sbp->sb_agblocks);
 
@@ -878,9 +889,9 @@ xfs_update_alignment(xfs_mount_t *mp)
                                mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
                        } else {
                                if (mp->m_flags & XFS_MOUNT_RETERR) {
-                                       xfs_fs_cmn_err(CE_WARN, mp,
-"stripe alignment turned off: sunit(%d) less than bsize(%d)",
-                                               mp->m_dalign,
+                                       xfs_warn(mp,
+               "stripe alignment turned off: sunit(%d) less than bsize(%d)",
+                                               mp->m_dalign,
                                                mp->m_blockmask +1);
                                        return XFS_ERROR(EINVAL);
                                }
@@ -1026,14 +1037,14 @@ xfs_check_sizes(xfs_mount_t *mp)
 
        d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
        if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
-               cmn_err(CE_WARN, "XFS: filesystem size mismatch detected");
+               xfs_warn(mp, "filesystem size mismatch detected");
                return XFS_ERROR(EFBIG);
        }
        bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
                                        d - XFS_FSS_TO_BB(mp, 1),
                                        BBTOB(XFS_FSS_TO_BB(mp, 1)), 0);
        if (!bp) {
-               cmn_err(CE_WARN, "XFS: last sector read failed");
+               xfs_warn(mp, "last sector read failed");
                return EIO;
        }
        xfs_buf_relse(bp);
@@ -1041,14 +1052,14 @@ xfs_check_sizes(xfs_mount_t *mp)
        if (mp->m_logdev_targp != mp->m_ddev_targp) {
                d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
                if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
-                       cmn_err(CE_WARN, "XFS: log size mismatch detected");
+                       xfs_warn(mp, "log size mismatch detected");
                        return XFS_ERROR(EFBIG);
                }
                bp = xfs_buf_read_uncached(mp, mp->m_logdev_targp,
                                        d - XFS_FSB_TO_BB(mp, 1),
                                        XFS_FSB_TO_B(mp, 1), 0);
                if (!bp) {
-                       cmn_err(CE_WARN, "XFS: log device read failed");
+                       xfs_warn(mp, "log device read failed");
                        return EIO;
                }
                xfs_buf_relse(bp);
@@ -1086,7 +1097,7 @@ xfs_mount_reset_sbqflags(
                return 0;
 
 #ifdef QUOTADEBUG
-       xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
+       xfs_notice(mp, "Writing superblock quota changes");
 #endif
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
@@ -1094,8 +1105,7 @@ xfs_mount_reset_sbqflags(
                                      XFS_DEFAULT_LOG_COUNT);
        if (error) {
                xfs_trans_cancel(tp, 0);
-               xfs_fs_cmn_err(CE_ALERT, mp,
-                       "xfs_mount_reset_sbqflags: Superblock update failed!");
+               xfs_alert(mp, "%s: Superblock update failed!", __func__);
                return error;
        }
 
@@ -1161,8 +1171,7 @@ xfs_mountfs(
         * transaction subsystem is online.
         */
        if (xfs_sb_has_mismatched_features2(sbp)) {
-               cmn_err(CE_WARN,
-                       "XFS: correcting sb_features alignment problem");
+               xfs_warn(mp, "correcting sb_features alignment problem");
                sbp->sb_features2 |= sbp->sb_bad_features2;
                sbp->sb_bad_features2 = sbp->sb_features2;
                mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
@@ -1241,7 +1250,7 @@ xfs_mountfs(
         */
        error = xfs_rtmount_init(mp);
        if (error) {
-               cmn_err(CE_WARN, "XFS: RT mount failed");
+               xfs_warn(mp, "RT mount failed");
                goto out_remove_uuid;
        }
 
@@ -1272,12 +1281,12 @@ xfs_mountfs(
        INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
        error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
        if (error) {
-               cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error);
+               xfs_warn(mp, "Failed per-ag init: %d", error);
                goto out_remove_uuid;
        }
 
        if (!sbp->sb_logblocks) {
-               cmn_err(CE_WARN, "XFS: no log defined");
+               xfs_warn(mp, "no log defined");
                XFS_ERROR_REPORT("xfs_mountfs", XFS_ERRLEVEL_LOW, mp);
                error = XFS_ERROR(EFSCORRUPTED);
                goto out_free_perag;
@@ -1290,7 +1299,7 @@ xfs_mountfs(
                              XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
                              XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
        if (error) {
-               cmn_err(CE_WARN, "XFS: log mount failed");
+               xfs_warn(mp, "log mount failed");
                goto out_free_perag;
        }
 
@@ -1327,16 +1336,14 @@ xfs_mountfs(
         */
        error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip);
        if (error) {
-               cmn_err(CE_WARN, "XFS: failed to read root inode");
+               xfs_warn(mp, "failed to read root inode");
                goto out_log_dealloc;
        }
 
        ASSERT(rip != NULL);
 
        if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) {
-               cmn_err(CE_WARN, "XFS: corrupted root inode");
-               cmn_err(CE_WARN, "Device %s - root %llu is not a directory",
-                       XFS_BUFTARG_NAME(mp->m_ddev_targp),
+               xfs_warn(mp, "corrupted root inode %llu: not a directory",
                        (unsigned long long)rip->i_ino);
                xfs_iunlock(rip, XFS_ILOCK_EXCL);
                XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
@@ -1356,7 +1363,7 @@ xfs_mountfs(
                /*
                 * Free up the root inode.
                 */
-               cmn_err(CE_WARN, "XFS: failed to read RT inodes");
+               xfs_warn(mp, "failed to read RT inodes");
                goto out_rele_rip;
        }
 
@@ -1368,7 +1375,7 @@ xfs_mountfs(
        if (mp->m_update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
                error = xfs_mount_log_sb(mp, mp->m_update_flags);
                if (error) {
-                       cmn_err(CE_WARN, "XFS: failed to write sb changes");
+                       xfs_warn(mp, "failed to write sb changes");
                        goto out_rtunmount;
                }
        }
@@ -1389,10 +1396,7 @@ xfs_mountfs(
                 * quotachecked license.
                 */
                if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
-                       cmn_err(CE_NOTE,
-                               "XFS: resetting qflags for filesystem %s",
-                               mp->m_fsname);
-
+                       xfs_notice(mp, "resetting quota flags");
                        error = xfs_mount_reset_sbqflags(mp);
                        if (error)
                                return error;
@@ -1406,7 +1410,7 @@ xfs_mountfs(
         */
        error = xfs_log_mount_finish(mp);
        if (error) {
-               cmn_err(CE_WARN, "XFS: log mount finish failed");
+               xfs_warn(mp, "log mount finish failed");
                goto out_rtunmount;
        }
 
@@ -1435,8 +1439,8 @@ xfs_mountfs(
                resblks = xfs_default_resblks(mp);
                error = xfs_reserve_blocks(mp, &resblks, NULL);
                if (error)
-                       cmn_err(CE_WARN, "XFS: Unable to allocate reserve "
-                               "blocks. Continuing without a reserve pool.");
+                       xfs_warn(mp,
+       "Unable to allocate reserve blocks. Continuing without reserve pool.");
        }
 
        return 0;
@@ -1525,12 +1529,12 @@ xfs_unmountfs(
        resblks = 0;
        error = xfs_reserve_blocks(mp, &resblks, NULL);
        if (error)
-               cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. "
+               xfs_warn(mp, "Unable to free reserved block pool. "
                                "Freespace may not be correct on next mount.");
 
        error = xfs_log_sbcount(mp, 1);
        if (error)
-               cmn_err(CE_WARN, "XFS: Unable to update superblock counters. "
+               xfs_warn(mp, "Unable to update superblock counters. "
                                "Freespace may not be correct on next mount.");
        xfs_unmountfs_writesb(mp);
        xfs_unmountfs_wait(mp);                 /* wait for async bufs */
@@ -2013,10 +2017,8 @@ xfs_dev_is_read_only(
        if (xfs_readonly_buftarg(mp->m_ddev_targp) ||
            xfs_readonly_buftarg(mp->m_logdev_targp) ||
            (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) {
-               cmn_err(CE_NOTE,
-                       "XFS: %s required on read-only device.", message);
-               cmn_err(CE_NOTE,
-                       "XFS: write access unavailable, cannot proceed.");
+               xfs_notice(mp, "%s required on read-only device.", message);
+               xfs_notice(mp, "write access unavailable, cannot proceed.");
                return EROFS;
        }
        return 0;
index 9bb6eda4cd215903077612233bf3b6c0d1577327..a595f29567fedda40964ae11eb1e885859acb238 100644 (file)
@@ -382,7 +382,8 @@ static inline int xfs_qm_sync(struct xfs_mount *mp, int flags)
        xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, nb, ni, \
                                f | XFS_QMOPT_RES_REGBLKS)
 
-extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *);
+extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *,
+                               xfs_dqid_t, uint, uint, char *);
 extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
 #endif /* __KERNEL__ */
index 12a19138531048555651e28330ade938a1b2b36f..8f76fdff4f4688484fac811a23f97cf23f91d23a 100644 (file)
@@ -76,7 +76,7 @@ xfs_growfs_rt_alloc(
        xfs_mount_t     *mp,            /* file system mount point */
        xfs_extlen_t    oblocks,        /* old count of blocks */
        xfs_extlen_t    nblocks,        /* new count of blocks */
-       xfs_ino_t       ino)            /* inode number (bitmap/summary) */
+       xfs_inode_t     *ip)            /* inode (bitmap/summary) */
 {
        xfs_fileoff_t   bno;            /* block number in file */
        xfs_buf_t       *bp;            /* temporary buffer for zeroing */
@@ -86,7 +86,6 @@ xfs_growfs_rt_alloc(
        xfs_fsblock_t   firstblock;     /* first block allocated in xaction */
        xfs_bmap_free_t flist;          /* list of freed blocks */
        xfs_fsblock_t   fsbno;          /* filesystem block for bno */
-       xfs_inode_t     *ip;            /* pointer to incore inode */
        xfs_bmbt_irec_t map;            /* block map output */
        int             nmap;           /* number of block maps */
        int             resblks;        /* space reservation */
@@ -112,9 +111,9 @@ xfs_growfs_rt_alloc(
                /*
                 * Lock the inode.
                 */
-               if ((error = xfs_trans_iget(mp, tp, ino, 0,
-                                               XFS_ILOCK_EXCL, &ip)))
-                       goto error_cancel;
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
+
                xfs_bmap_init(&flist, &firstblock);
                /*
                 * Allocate blocks to the bitmap file.
@@ -155,9 +154,8 @@ xfs_growfs_rt_alloc(
                        /*
                         * Lock the bitmap inode.
                         */
-                       if ((error = xfs_trans_iget(mp, tp, ino, 0,
-                                                       XFS_ILOCK_EXCL, &ip)))
-                               goto error_cancel;
+                       xfs_ilock(ip, XFS_ILOCK_EXCL);
+                       xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
                        /*
                         * Get a buffer for the block.
                         */
@@ -1854,7 +1852,6 @@ xfs_growfs_rt(
        xfs_rtblock_t   bmbno;          /* bitmap block number */
        xfs_buf_t       *bp;            /* temporary buffer */
        int             error;          /* error return value */
-       xfs_inode_t     *ip;            /* bitmap inode, used as lock */
        xfs_mount_t     *nmp;           /* new (fake) mount structure */
        xfs_drfsbno_t   nrblocks;       /* new number of realtime blocks */
        xfs_extlen_t    nrbmblocks;     /* new number of rt bitmap blocks */
@@ -1918,11 +1915,11 @@ xfs_growfs_rt(
        /*
         * Allocate space to the bitmap and summary files, as necessary.
         */
-       if ((error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks,
-                       mp->m_sb.sb_rbmino)))
+       error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip);
+       if (error)
                return error;
-       if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks,
-                       mp->m_sb.sb_rsumino)))
+       error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
+       if (error)
                return error;
        /*
         * Allocate a new (fake) mount/sb.
@@ -1972,10 +1969,8 @@ xfs_growfs_rt(
                /*
                 * Lock out other callers by grabbing the bitmap inode lock.
                 */
-               if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
-                                               XFS_ILOCK_EXCL, &ip)))
-                       goto error_cancel;
-               ASSERT(ip == mp->m_rbmip);
+               xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin_ref(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
                /*
                 * Update the bitmap inode's size.
                 */
@@ -1986,10 +1981,8 @@ xfs_growfs_rt(
                /*
                 * Get the summary inode into the transaction.
                 */
-               if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
-                                               XFS_ILOCK_EXCL, &ip)))
-                       goto error_cancel;
-               ASSERT(ip == mp->m_rsumip);
+               xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin_ref(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
                /*
                 * Update the summary inode's size.
                 */
@@ -2075,15 +2068,15 @@ xfs_rtallocate_extent(
        xfs_extlen_t    prod,           /* extent product factor */
        xfs_rtblock_t   *rtblock)       /* out: start block allocated */
 {
+       xfs_mount_t     *mp = tp->t_mountp;
        int             error;          /* error value */
-       xfs_inode_t     *ip;            /* inode for bitmap file */
-       xfs_mount_t     *mp;            /* file system mount structure */
        xfs_rtblock_t   r;              /* result allocated block */
        xfs_fsblock_t   sb;             /* summary file block number */
        xfs_buf_t       *sumbp;         /* summary file block buffer */
 
+       ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
        ASSERT(minlen > 0 && minlen <= maxlen);
-       mp = tp->t_mountp;
+
        /*
         * If prod is set then figure out what to do to minlen and maxlen.
         */
@@ -2099,12 +2092,7 @@ xfs_rtallocate_extent(
                        return 0;
                }
        }
-       /*
-        * Lock out other callers by grabbing the bitmap inode lock.
-        */
-       if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
-                                       XFS_ILOCK_EXCL, &ip)))
-               return error;
+
        sumbp = NULL;
        /*
         * Allocate by size, or near another block, or exactly at some block.
@@ -2123,11 +2111,12 @@ xfs_rtallocate_extent(
                                len, &sumbp, &sb, prod, &r);
                break;
        default:
+               error = EIO;
                ASSERT(0);
        }
-       if (error) {
+       if (error)
                return error;
-       }
+
        /*
         * If it worked, update the superblock.
         */
@@ -2155,7 +2144,6 @@ xfs_rtfree_extent(
        xfs_extlen_t    len)            /* length of extent freed */
 {
        int             error;          /* error value */
-       xfs_inode_t     *ip;            /* bitmap file inode */
        xfs_mount_t     *mp;            /* file system mount structure */
        xfs_fsblock_t   sb;             /* summary file block number */
        xfs_buf_t       *sumbp;         /* summary file block buffer */
@@ -2164,9 +2152,9 @@ xfs_rtfree_extent(
        /*
         * Synchronize by locking the bitmap inode.
         */
-       if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
-                                       XFS_ILOCK_EXCL, &ip)))
-               return error;
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin_ref(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+
 #if defined(__KERNEL__) && defined(DEBUG)
        /*
         * Check to see that this whole range is currently allocated.
@@ -2199,10 +2187,10 @@ xfs_rtfree_extent(
         */
        if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==
            mp->m_sb.sb_rextents) {
-               if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM))
-                       ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
-               *(__uint64_t *)&ip->i_d.di_atime = 0;
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+               if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM))
+                       mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
+               *(__uint64_t *)&mp->m_rbmip->i_d.di_atime = 0;
+               xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
        }
        return 0;
 }
@@ -2222,8 +2210,8 @@ xfs_rtmount_init(
        if (sbp->sb_rblocks == 0)
                return 0;
        if (mp->m_rtdev_targp == NULL) {
-               cmn_err(CE_WARN,
-       "XFS: This filesystem has a realtime volume, use rtdev=device option");
+               xfs_warn(mp,
+       "Filesystem has a realtime volume, use rtdev=device option");
                return XFS_ERROR(ENODEV);
        }
        mp->m_rsumlevels = sbp->sb_rextslog + 1;
@@ -2237,7 +2225,7 @@ xfs_rtmount_init(
         */
        d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
        if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {
-               cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu",
+               xfs_warn(mp, "realtime mount -- %llu != %llu",
                        (unsigned long long) XFS_BB_TO_FSB(mp, d),
                        (unsigned long long) mp->m_sb.sb_rblocks);
                return XFS_ERROR(EFBIG);
@@ -2246,7 +2234,7 @@ xfs_rtmount_init(
                                        d - XFS_FSB_TO_BB(mp, 1),
                                        XFS_FSB_TO_B(mp, 1), 0);
        if (!bp) {
-               cmn_err(CE_WARN, "XFS: realtime device size check failed");
+               xfs_warn(mp, "realtime device size check failed");
                return EIO;
        }
        xfs_buf_relse(bp);
@@ -2306,20 +2294,16 @@ xfs_rtpick_extent(
        xfs_rtblock_t   *pick)          /* result rt extent */
 {
        xfs_rtblock_t   b;              /* result block */
-       int             error;          /* error return value */
-       xfs_inode_t     *ip;            /* bitmap incore inode */
        int             log2;           /* log of sequence number */
        __uint64_t      resid;          /* residual after log removed */
        __uint64_t      seq;            /* sequence number of file creation */
        __uint64_t      *seqp;          /* pointer to seqno in inode */
 
-       if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
-                                       XFS_ILOCK_EXCL, &ip)))
-               return error;
-       ASSERT(ip == mp->m_rbmip);
-       seqp = (__uint64_t *)&ip->i_d.di_atime;
-       if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {
-               ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
+       ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
+
+       seqp = (__uint64_t *)&mp->m_rbmip->i_d.di_atime;
+       if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {
+               mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
                *seqp = 0;
        }
        seq = *seqp;
@@ -2335,7 +2319,7 @@ xfs_rtpick_extent(
                        b = mp->m_sb.sb_rextents - len;
        }
        *seqp = seq + 1;
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
        *pick = b;
        return 0;
 }
index ff614c29b44142da429bb33db904afdf843469ad..09e1f4f35e971c0e1edf326cfeca9d21f67a6953 100644 (file)
@@ -154,7 +154,7 @@ xfs_rtmount_init(
        if (mp->m_sb.sb_rblocks == 0)
                return 0;
 
-       cmn_err(CE_WARN, "XFS: Not built with CONFIG_XFS_RT");
+       xfs_warn(mp, "Not built with CONFIG_XFS_RT");
        return ENOSYS;
 }
 # define xfs_rtmount_inodes(m)  (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
index 56861d5daaef54432a94a640a7b1e65812030ef7..d6d6fdfe9422b47545de1bbeb9e6713c67be160b 100644 (file)
@@ -49,9 +49,9 @@ xfs_do_force_shutdown(
        logerror = flags & SHUTDOWN_LOG_IO_ERROR;
 
        if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
-               cmn_err(CE_NOTE, "xfs_force_shutdown(%s,0x%x) called from "
-                                "line %d of file %s.  Return address = 0x%p",
-                       mp->m_fsname, flags, lnnum, fname, __return_address);
+               xfs_notice(mp,
+       "%s(0x%x) called from line %d of file %s.  Return address = 0x%p",
+                       __func__, flags, lnnum, fname, __return_address);
        }
        /*
         * No need to duplicate efforts.
@@ -69,30 +69,25 @@ xfs_do_force_shutdown(
                return;
 
        if (flags & SHUTDOWN_CORRUPT_INCORE) {
-               xfs_cmn_err(XFS_PTAG_SHUTDOWN_CORRUPT, CE_ALERT, mp,
-    "Corruption of in-memory data detected.  Shutting down filesystem: %s",
-                       mp->m_fsname);
-               if (XFS_ERRLEVEL_HIGH <= xfs_error_level) {
+               xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
+    "Corruption of in-memory data detected.  Shutting down filesystem");
+               if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
                        xfs_stack_trace();
-               }
        } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
                if (logerror) {
-                       xfs_cmn_err(XFS_PTAG_SHUTDOWN_LOGERROR, CE_ALERT, mp,
-               "Log I/O Error Detected.  Shutting down filesystem: %s",
-                               mp->m_fsname);
+                       xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
+               "Log I/O Error Detected.  Shutting down filesystem");
                } else if (flags & SHUTDOWN_DEVICE_REQ) {
-                       xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
-               "All device paths lost.  Shutting down filesystem: %s",
-                               mp->m_fsname);
+                       xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
+               "All device paths lost.  Shutting down filesystem");
                } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
-                       xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
-               "I/O Error Detected.  Shutting down filesystem: %s",
-                               mp->m_fsname);
+                       xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
+               "I/O Error Detected. Shutting down filesystem");
                }
        }
        if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
-               cmn_err(CE_ALERT, "Please umount the filesystem, "
-                                 "and rectify the problem(s)");
+               xfs_alert(mp,
+       "Please umount the filesystem and rectify the problem(s)");
        }
 }
 
@@ -106,10 +101,9 @@ xfs_ioerror_alert(
        xfs_buf_t               *bp,
        xfs_daddr_t             blkno)
 {
-       cmn_err(CE_ALERT,
- "I/O error in filesystem (\"%s\") meta-data dev %s block 0x%llx"
- "       (\"%s\") error %d buf count %zd",
-               (!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname,
+       xfs_alert(mp,
+                "I/O error occurred: meta-data dev %s block 0x%llx"
+                "       (\"%s\") error %d buf count %zd",
                XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
                (__uint64_t)blkno, func,
                XFS_BUF_GETERROR(bp), XFS_BUF_COUNT(bp));
@@ -173,17 +167,9 @@ xfs_extlen_t
 xfs_get_extsz_hint(
        struct xfs_inode        *ip)
 {
-       xfs_extlen_t            extsz;
-
-       if (unlikely(XFS_IS_REALTIME_INODE(ip))) {
-               extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
-                               ? ip->i_d.di_extsize
-                               : ip->i_mount->m_sb.sb_rextsize;
-               ASSERT(extsz);
-       } else {
-               extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
-                               ? ip->i_d.di_extsize : 0;
-       }
-
-       return extsz;
+       if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
+               return ip->i_d.di_extsize;
+       if (XFS_IS_REALTIME_INODE(ip))
+               return ip->i_mount->m_sb.sb_rextsize;
+       return 0;
 }
index c2042b736b81131a780703d8a5907c848793eebb..06a9759b6352aa497d64396d9ce3fa0900506d3f 100644 (file)
@@ -469,8 +469,6 @@ void                xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
 void           xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
 void           xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
-int            xfs_trans_iget(struct xfs_mount *, xfs_trans_t *,
-                              xfs_ino_t , uint, uint, struct xfs_inode **);
 void           xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
 void           xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint);
 void           xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *);
index c5bbbc45db91ed97429a043ba8144cc53509a993..12aff9584e299a2d026a84f1871c669f0fdb9a4c 100644 (file)
@@ -563,7 +563,7 @@ xfs_trans_ail_delete_bulk(
 
                        spin_unlock(&ailp->xa_lock);
                        if (!XFS_FORCED_SHUTDOWN(mp)) {
-                               xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
+                               xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
                "%s: attempting to delete a log item that is not in the AIL",
                                                __func__);
                                xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
index c47918c302a50593341de2add8e5072078d9804e..3bea66132334c91e83278a5c581fae7d399e1490 100644 (file)
@@ -305,7 +305,7 @@ xfs_trans_read_buf(
                        if (xfs_error_target == target) {
                                if (((xfs_req_num++) % xfs_error_mod) == 0) {
                                        xfs_buf_relse(bp);
-                                       cmn_err(CE_DEBUG, "Returning error!\n");
+                                       xfs_debug(mp, "Returning error!");
                                        return XFS_ERROR(EIO);
                                }
                        }
@@ -403,7 +403,7 @@ xfs_trans_read_buf(
                                xfs_force_shutdown(tp->t_mountp,
                                                   SHUTDOWN_META_IO_ERROR);
                                xfs_buf_relse(bp);
-                               cmn_err(CE_DEBUG, "Returning trans error!\n");
+                               xfs_debug(mp, "Returning trans error!");
                                return XFS_ERROR(EIO);
                        }
                }
@@ -427,7 +427,7 @@ shutdown_abort:
         */
 #if defined(DEBUG)
        if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
-               cmn_err(CE_NOTE, "about to pop assert, bp == 0x%p", bp);
+               xfs_notice(mp, "about to pop assert, bp == 0x%p", bp);
 #endif
        ASSERT((XFS_BUF_BFLAGS(bp) & (XBF_STALE|XBF_DELWRI)) !=
                                     (XBF_STALE|XBF_DELWRI));
index ccb34532768bd65a1c5baa14a4a0a143df1ea2cb..16084d8ea231a0434823ef3c9007333fdbd675f7 100644 (file)
@@ -43,28 +43,6 @@ xfs_trans_inode_broot_debug(
 #define        xfs_trans_inode_broot_debug(ip)
 #endif
 
-/*
- * Get an inode and join it to the transaction.
- */
-int
-xfs_trans_iget(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_ino_t       ino,
-       uint            flags,
-       uint            lock_flags,
-       xfs_inode_t     **ipp)
-{
-       int                     error;
-
-       error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp);
-       if (!error && tp) {
-               xfs_trans_ijoin(tp, *ipp);
-               (*ipp)->i_itemp->ili_lock_flags = lock_flags;
-       }
-       return error;
-}
-
 /*
  * Add a locked inode to the transaction.
  *
index d8e6f8cd6f0c89782dd0d5df7a2e7a0329688235..37d8146ee15b2022edecce33ffc896ed84c55e59 100644 (file)
@@ -1189,9 +1189,8 @@ xfs_inactive(
                 * inode might be lost for a long time or forever.
                 */
                if (!XFS_FORCED_SHUTDOWN(mp)) {
-                       cmn_err(CE_NOTE,
-               "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
-                               error, mp->m_fsname);
+                       xfs_notice(mp, "%s: xfs_ifree returned error %d",
+                               __func__, error);
                        xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
                }
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
@@ -1208,12 +1207,12 @@ xfs_inactive(
                 */
                error = xfs_bmap_finish(&tp,  &free_list, &committed);
                if (error)
-                       xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
-                               "xfs_bmap_finish() returned error %d", error);
+                       xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
+                               __func__, error);
                error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
                if (error)
-                       xfs_fs_cmn_err(CE_NOTE, mp, "xfs_inactive: "
-                               "xfs_trans_commit() returned error %d", error);
+                       xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
+                               __func__, error);
        }
 
        /*
@@ -1310,7 +1309,7 @@ xfs_create(
        error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
        if (error)
-               goto std_return;
+               return error;
 
        if (is_dir) {
                rdev = 0;
@@ -1389,12 +1388,6 @@ xfs_create(
                goto out_trans_abort;
        }
 
-       /*
-        * At this point, we've gotten a newly allocated inode.
-        * It is locked (and joined to the transaction).
-        */
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
        /*
         * Now we join the directory inode to the transaction.  We do not do it
         * earlier because xfs_dir_ialloc might commit the previous transaction
@@ -1440,22 +1433,13 @@ xfs_create(
         */
        xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp);
 
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to return the
-        * vnode to the caller, we bump the vnode ref count now.
-        */
-       IHOLD(ip);
-
        error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error)
-               goto out_abort_rele;
+               goto out_bmap_cancel;
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error) {
-               IRELE(ip);
-               goto out_dqrele;
-       }
+       if (error)
+               goto out_release_inode;
 
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
@@ -1469,27 +1453,21 @@ xfs_create(
        cancel_flags |= XFS_TRANS_ABORT;
  out_trans_cancel:
        xfs_trans_cancel(tp, cancel_flags);
- out_dqrele:
+ out_release_inode:
+       /*
+        * Wait until after the current transaction is aborted to
+        * release the inode.  This prevents recursive transactions
+        * and deadlocks from xfs_inactive.
+        */
+       if (ip)
+               IRELE(ip);
+
        xfs_qm_dqrele(udqp);
        xfs_qm_dqrele(gdqp);
 
        if (unlock_dp_on_error)
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
- std_return:
        return error;
-
- out_abort_rele:
-       /*
-        * Wait until after the current transaction is aborted to
-        * release the inode.  This prevents recursive transactions
-        * and deadlocks from xfs_inactive.
-        */
-       xfs_bmap_cancel(&free_list);
-       cancel_flags |= XFS_TRANS_ABORT;
-       xfs_trans_cancel(tp, cancel_flags);
-       IRELE(ip);
-       unlock_dp_on_error = B_FALSE;
-       goto out_dqrele;
 }
 
 #ifdef DEBUG
@@ -2114,9 +2092,8 @@ xfs_symlink(
                                  XFS_BMAPI_WRITE | XFS_BMAPI_METADATA,
                                  &first_block, resblks, mval, &nmaps,
                                  &free_list);
-               if (error) {
-                       goto error1;
-               }
+               if (error)
+                       goto error2;
 
                if (resblks)
                        resblks -= fs_blocks;
@@ -2148,7 +2125,7 @@ xfs_symlink(
        error = xfs_dir_createname(tp, dp, link_name, ip->i_ino,
                                        &first_block, &free_list, resblks);
        if (error)
-               goto error1;
+               goto error2;
        xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
@@ -2161,13 +2138,6 @@ xfs_symlink(
                xfs_trans_set_sync(tp);
        }
 
-       /*
-        * xfs_trans_commit normally decrements the vnode ref count
-        * when it unlocks the inode. Since we want to return the
-        * vnode to the caller, we bump the vnode ref count now.
-        */
-       IHOLD(ip);
-
        error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                goto error2;
index ef1cef77d32ba0687491bdbb5852d32fe40075c8..d7bd661bfae73ed39cb15f17a39c4c06b78b1d63 100644 (file)
 
 #if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES)
 /*
- * Module name is included in both debug and non-debug versions primarily for
- * error messages. The __FILE__ macro is not very useful for this, because it
- * often includes the entire pathname to the module
+ * The module name is used primarily for error and debug messages.
+ * The __FILE__ macro is not very useful for this, because it
+ * usually includes the entire pathname to the module making the
+ * debug output difficult to read.
  */
 #define ACPI_MODULE_NAME(name)          static const char ACPI_UNUSED_VAR _acpi_module_name[] = name;
 #else
+/*
+ * For the no-debug and no-error-msg cases, we must at least define
+ * a null module name.
+ */
 #define ACPI_MODULE_NAME(name)
+#define _acpi_module_name ""
 #endif
 
 /*
index ff103ba96b78cb4956cd49259ce0dfa4947b04e3..3a10ef5914eb5ab67dc981e3f6d21ee4cf0b3908 100644 (file)
@@ -250,7 +250,6 @@ struct acpi_device_wakeup {
        struct acpi_handle_list resources;
        struct acpi_device_wakeup_flags flags;
        int prepare_count;
-       int run_wake_count;
 };
 
 /* Device */
index e46ec95a8adac68abf713952066a5be8bc59c293..f6ad63d25b739fbba1d41eabed483db4abf7feb1 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20110112
+#define ACPI_CA_VERSION                 0x20110316
 
 #include "actypes.h"
 #include "actbl.h"
index 7e42bfee0e296a4dee55fc8de24e6caebfd1526d..d41c94885211c351f33c724cf523dacacd5e4b6f 100644 (file)
@@ -343,4 +343,20 @@ struct acpi_table_desc {
 #include <acpi/actbl1.h>
 #include <acpi/actbl2.h>
 
+/*
+ * Sizes of the various flavors of FADT. We need to look closely
+ * at the FADT length because the version number essentially tells
+ * us nothing because of many BIOS bugs where the version does not
+ * match the expected length. In other words, the length of the
+ * FADT is the bottom line as to what the version really is.
+ *
+ * For reference, the values below are as follows:
+ *     FADT V1  size: 0x74
+ *     FADT V2  size: 0x84
+ *     FADT V3+ size: 0xF4
+ */
+#define ACPI_FADT_V1_SIZE       (u32) (ACPI_FADT_OFFSET (flags) + 4)
+#define ACPI_FADT_V2_SIZE       (u32) (ACPI_FADT_OFFSET (reserved4[0]) + 3)
+#define ACPI_FADT_V3_SIZE       (u32) (sizeof (struct acpi_table_fadt))
+
 #endif                         /* __ACTBL_H__ */
index 0fc15dfb2e22c2bdeef92428960028d3efcc6540..58bdd0545c5afba6432c45ef8218b616e09f59ae 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Name: actbl2.h - ACPI Specification Revision 2.0 Tables
+ * Name: actbl2.h - ACPI Table Definitions (tables not in ACPI spec)
  *
  *****************************************************************************/
 
@@ -714,6 +714,68 @@ struct acpi_table_mchi {
        u8 pci_function;
 };
 
+/*******************************************************************************
+ *
+ * SLIC - Software Licensing Description Table
+ *        Version 1
+ *
+ * Conforms to "OEM Activation 2.0 for Windows Vista Operating Systems",
+ * Copyright 2006
+ *
+ ******************************************************************************/
+
+/* Basic SLIC table is only the common ACPI header */
+
+struct acpi_table_slic {
+       struct acpi_table_header header;        /* Common ACPI table header */
+};
+
+/* Common SLIC subtable header */
+
+struct acpi_slic_header {
+       u32 type;
+       u32 length;
+};
+
+/* Values for Type field above */
+
+enum acpi_slic_type {
+       ACPI_SLIC_TYPE_PUBLIC_KEY = 0,
+       ACPI_SLIC_TYPE_WINDOWS_MARKER = 1,
+       ACPI_SLIC_TYPE_RESERVED = 2     /* 2 and greater are reserved */
+};
+
+/*
+ * SLIC Sub-tables, correspond to Type in struct acpi_slic_header
+ */
+
+/* 0: Public Key Structure */
+
+struct acpi_slic_key {
+       struct acpi_slic_header header;
+       u8 key_type;
+       u8 version;
+       u16 reserved;
+       u32 algorithm;
+       char magic[4];
+       u32 bit_length;
+       u32 exponent;
+       u8 modulus[128];
+};
+
+/* 1: Windows Marker Structure */
+
+struct acpi_slic_marker {
+       struct acpi_slic_header header;
+       u32 version;
+       char oem_id[ACPI_OEM_ID_SIZE];  /* ASCII OEM identification */
+       char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];      /* ASCII OEM table identification */
+       char windows_flag[8];
+       u32 slic_version;
+       u8 reserved[16];
+       u8 signature[128];
+};
+
 /*******************************************************************************
  *
  * SPCR - Serial Port Console Redirection table
index c4dbb132d902c0d2284473d30a954926c1745ac4..e67b523a50e1a3bee89745d389b19e20466b80bd 100644 (file)
@@ -30,10 +30,11 @@ int apei_hest_parse(apei_hest_func_t func, void *data);
 
 int erst_write(const struct cper_record_header *record);
 ssize_t erst_get_record_count(void);
-int erst_get_next_record_id(u64 *record_id);
+int erst_get_record_id_begin(int *pos);
+int erst_get_record_id_next(int *pos, u64 *record_id);
+void erst_get_record_id_end(void);
 ssize_t erst_read(u64 record_id, struct cper_record_header *record,
                  size_t buflen);
-ssize_t erst_read_next(struct cper_record_header *record, size_t buflen);
 int erst_clear(u64 record_id);
 
 #endif
index a54f4421a24d8bc738815fdf9c1c5884795a94f3..280ca7a96f75072d038f1e7e4b6a0b5ace27144e 100644 (file)
@@ -38,8 +38,7 @@
 
 #include <asm-generic/bitops/atomic.h>
 #include <asm-generic/bitops/non-atomic.h>
-#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/le.h>
 #include <asm-generic/bitops/ext2-atomic.h>
-#include <asm-generic/bitops/minix.h>
 
 #endif /* __ASM_GENERIC_BITOPS_H */
index ab1c875efb74f4698003253a5e3b379f3f277aac..ecf1c9d8a7cc43e8d9adaffecac83c5b9e37ff27 100644 (file)
@@ -5,7 +5,7 @@
        ({                                              \
                int ret;                                \
                spin_lock(lock);                        \
-               ret = ext2_set_bit((nr), (unsigned long *)(addr)); \
+               ret = __test_and_set_bit_le(nr, addr);  \
                spin_unlock(lock);                      \
                ret;                                    \
        })
@@ -14,7 +14,7 @@
        ({                                              \
                int ret;                                \
                spin_lock(lock);                        \
-               ret = ext2_clear_bit((nr), (unsigned long *)(addr)); \
+               ret = __test_and_clear_bit_le(nr, addr);        \
                spin_unlock(lock);                      \
                ret;                                    \
        })
diff --git a/include/asm-generic/bitops/ext2-non-atomic.h b/include/asm-generic/bitops/ext2-non-atomic.h
deleted file mode 100644 (file)
index 63cf822..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_
-#define _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_
-
-#include <asm-generic/bitops/le.h>
-
-#define ext2_set_bit(nr,addr)  \
-       generic___test_and_set_le_bit((nr),(unsigned long *)(addr))
-#define ext2_clear_bit(nr,addr)        \
-       generic___test_and_clear_le_bit((nr),(unsigned long *)(addr))
-
-#define ext2_test_bit(nr,addr) \
-       generic_test_le_bit((nr),(unsigned long *)(addr))
-#define ext2_find_first_zero_bit(addr, size) \
-       generic_find_first_zero_le_bit((unsigned long *)(addr), (size))
-#define ext2_find_next_zero_bit(addr, size, off) \
-       generic_find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
-#define ext2_find_next_bit(addr, size, off) \
-       generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
-
-#endif /* _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_ */
index 80e3bf13b2b97ed613c4126413bfbde8766dbda4..946a21b1b5dc66dffae64c4b58f10efaa2e940fd 100644 (file)
@@ -4,54 +4,77 @@
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
-#define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
-#define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
-
 #if defined(__LITTLE_ENDIAN)
 
-#define generic_test_le_bit(nr, addr) test_bit(nr, addr)
-#define generic___set_le_bit(nr, addr) __set_bit(nr, addr)
-#define generic___clear_le_bit(nr, addr) __clear_bit(nr, addr)
+#define BITOP_LE_SWIZZLE       0
 
-#define generic_test_and_set_le_bit(nr, addr) test_and_set_bit(nr, addr)
-#define generic_test_and_clear_le_bit(nr, addr) test_and_clear_bit(nr, addr)
+static inline unsigned long find_next_zero_bit_le(const void *addr,
+               unsigned long size, unsigned long offset)
+{
+       return find_next_zero_bit(addr, size, offset);
+}
 
-#define generic___test_and_set_le_bit(nr, addr) __test_and_set_bit(nr, addr)
-#define generic___test_and_clear_le_bit(nr, addr) __test_and_clear_bit(nr, addr)
+static inline unsigned long find_next_bit_le(const void *addr,
+               unsigned long size, unsigned long offset)
+{
+       return find_next_bit(addr, size, offset);
+}
 
-#define generic_find_next_zero_le_bit(addr, size, offset) find_next_zero_bit(addr, size, offset)
-#define generic_find_next_le_bit(addr, size, offset) \
-                       find_next_bit(addr, size, offset)
+static inline unsigned long find_first_zero_bit_le(const void *addr,
+               unsigned long size)
+{
+       return find_first_zero_bit(addr, size);
+}
 
 #elif defined(__BIG_ENDIAN)
 
-#define generic_test_le_bit(nr, addr) \
-       test_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define generic___set_le_bit(nr, addr) \
-       __set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define generic___clear_le_bit(nr, addr) \
-       __clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-
-#define generic_test_and_set_le_bit(nr, addr) \
-       test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define generic_test_and_clear_le_bit(nr, addr) \
-       test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-
-#define generic___test_and_set_le_bit(nr, addr) \
-       __test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
-#define generic___test_and_clear_le_bit(nr, addr) \
-       __test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr))
+#define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
 
-extern unsigned long generic_find_next_zero_le_bit(const unsigned long *addr,
+extern unsigned long find_next_zero_bit_le(const void *addr,
                unsigned long size, unsigned long offset);
-extern unsigned long generic_find_next_le_bit(const unsigned long *addr,
+extern unsigned long find_next_bit_le(const void *addr,
                unsigned long size, unsigned long offset);
 
+#define find_first_zero_bit_le(addr, size) \
+       find_next_zero_bit_le((addr), (size), 0)
+
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 
-#define generic_find_first_zero_le_bit(addr, size) \
-        generic_find_next_zero_le_bit((addr), (size), 0)
+static inline int test_bit_le(int nr, const void *addr)
+{
+       return test_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline void __set_bit_le(int nr, void *addr)
+{
+       __set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline void __clear_bit_le(int nr, void *addr)
+{
+       __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int test_and_set_bit_le(int nr, void *addr)
+{
+       return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int test_and_clear_bit_le(int nr, void *addr)
+{
+       return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int __test_and_set_bit_le(int nr, void *addr)
+{
+       return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
+
+static inline int __test_and_clear_bit_le(int nr, void *addr)
+{
+       return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
+}
 
 #endif /* _ASM_GENERIC_BITOPS_LE_H_ */
diff --git a/include/asm-generic/bitops/minix-le.h b/include/asm-generic/bitops/minix-le.h
deleted file mode 100644 (file)
index 4a981c1..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _ASM_GENERIC_BITOPS_MINIX_LE_H_
-#define _ASM_GENERIC_BITOPS_MINIX_LE_H_
-
-#include <asm-generic/bitops/le.h>
-
-#define minix_test_and_set_bit(nr,addr)        \
-       generic___test_and_set_le_bit((nr),(unsigned long *)(addr))
-#define minix_set_bit(nr,addr)         \
-       generic___set_le_bit((nr),(unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr,addr) \
-       generic___test_and_clear_le_bit((nr),(unsigned long *)(addr))
-#define minix_test_bit(nr,addr)                \
-       generic_test_le_bit((nr),(unsigned long *)(addr))
-#define minix_find_first_zero_bit(addr,size) \
-       generic_find_first_zero_le_bit((unsigned long *)(addr),(size))
-
-#endif /* _ASM_GENERIC_BITOPS_MINIX_LE_H_ */
diff --git a/include/asm-generic/bitops/minix.h b/include/asm-generic/bitops/minix.h
deleted file mode 100644 (file)
index 91f42e8..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _ASM_GENERIC_BITOPS_MINIX_H_
-#define _ASM_GENERIC_BITOPS_MINIX_H_
-
-#define minix_test_and_set_bit(nr,addr)        \
-       __test_and_set_bit((nr),(unsigned long *)(addr))
-#define minix_set_bit(nr,addr)         \
-       __set_bit((nr),(unsigned long *)(addr))
-#define minix_test_and_clear_bit(nr,addr) \
-       __test_and_clear_bit((nr),(unsigned long *)(addr))
-#define minix_test_bit(nr,addr)                \
-       test_bit((nr),(unsigned long *)(addr))
-#define minix_find_first_zero_bit(addr,size) \
-       find_first_zero_bit((unsigned long *)(addr),(size))
-
-#endif /* _ASM_GENERIC_BITOPS_MINIX_H_ */
index c2c9ba032d4688c80cf7b3e1546da8a558068ec5..f2d2faf4d9ae9379b420d65113d4f9c366d0a9da 100644 (file)
@@ -165,10 +165,36 @@ extern void warn_slowpath_null(const char *file, const int line);
 #define WARN_ON_RATELIMIT(condition, state)                    \
                WARN_ON((condition) && __ratelimit(state))
 
+/*
+ * WARN_ON_SMP() is for cases that the warning is either
+ * meaningless for !SMP or may even cause failures.
+ * This is usually used for cases that we have
+ * WARN_ON(!spin_is_locked(&lock)) checks, as spin_is_locked()
+ * returns 0 for uniprocessor settings.
+ * It can also be used with values that are only defined
+ * on SMP:
+ *
+ * struct foo {
+ *  [...]
+ * #ifdef CONFIG_SMP
+ *     int bar;
+ * #endif
+ * };
+ *
+ * void func(struct foo *zoot)
+ * {
+ *     WARN_ON_SMP(!zoot->bar);
+ *
+ * For CONFIG_SMP, WARN_ON_SMP() should act the same as WARN_ON(),
+ * and should be a nop and return false for uniprocessor.
+ *
+ * if (WARN_ON_SMP(x)) returns true only when CONFIG_SMP is set
+ * and x is true.
+ */
 #ifdef CONFIG_SMP
 # define WARN_ON_SMP(x)                        WARN_ON(x)
 #else
-# define WARN_ON_SMP(x)                        do { } while (0)
+# define WARN_ON_SMP(x)                        ({0;})
 #endif
 
 #endif
index fba7d33ca3f2b98eafcaf579a1b6244301df8b22..7a0f69e6c618d6f52c6b6a57ad0318532259590c 100644 (file)
@@ -12,31 +12,4 @@ typedef unsigned short umode_t;
 
 #endif /* __ASSEMBLY__ */
 
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-/*
- * DMA addresses may be very different from physical addresses
- * and pointers. i386 and powerpc may have 64 bit DMA on 32 bit
- * systems, while sparc64 uses 32 bit DMA addresses for 64 bit
- * physical addresses.
- * This default defines dma_addr_t to have the same size as
- * phys_addr_t, which is the most common way.
- * Do not define the dma64_addr_t type, which never really
- * worked.
- */
-#ifndef dma_addr_t
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
-typedef u64 dma_addr_t;
-#else
-typedef u32 dma_addr_t;
-#endif /* CONFIG_PHYS_ADDR_T_64BIT */
-#endif /* dma_addr_t */
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_GENERIC_TYPES_H */
index 57af0338d2709972d7dfee827f67da05e2efdb7d..07c40d5149de41ee263a450db1141781f806f44b 100644 (file)
@@ -650,9 +650,13 @@ __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
 __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
 #define __NR_open_by_handle_at         265
 __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
+#define __NR_clock_adjtime 266
+__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+#define __NR_syncfs 267
+__SYSCALL(__NR_syncfs, sys_syncfs)
 
 #undef __NR_syscalls
-#define __NR_syscalls 266
+#define __NR_syscalls 268
 
 /*
  * All syscalls below here should go away really,
index 9ac431396176d6c5e89d44084af7b249c41b94fc..4be33b4ca2f898a10296d3e2a6a4469942c6555a 100644 (file)
@@ -463,12 +463,15 @@ struct drm_irq_busid {
 enum drm_vblank_seq_type {
        _DRM_VBLANK_ABSOLUTE = 0x0,     /**< Wait for specific vblank sequence number */
        _DRM_VBLANK_RELATIVE = 0x1,     /**< Wait for given number of vblanks */
+       /* bits 1-6 are reserved for high crtcs */
+       _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e,
        _DRM_VBLANK_EVENT = 0x4000000,   /**< Send event instead of blocking */
        _DRM_VBLANK_FLIP = 0x8000000,   /**< Scheduled buffer swap should flip */
        _DRM_VBLANK_NEXTONMISS = 0x10000000,    /**< If missed, wait for next vblank */
        _DRM_VBLANK_SECONDARY = 0x20000000,     /**< Secondary display controller */
        _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */
 };
+#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1
 
 #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
 #define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
@@ -753,6 +756,7 @@ struct drm_event_vblank {
 };
 
 #define DRM_CAP_DUMB_BUFFER 0x1
+#define DRM_CAP_VBLANK_HIGH_CRTC 0x2
 
 /* typedef area */
 #ifndef __KERNEL__
index b0ada6f37dd65a2ad7e9cf475034fa1737fe0fc5..75cf611641e6330e4006294ad18be9ad0604b827 100644 (file)
@@ -233,6 +233,7 @@ header-y += magic.h
 header-y += major.h
 header-y += map_to_7segment.h
 header-y += matroxfb.h
+header-y += media.h
 header-y += mempolicy.h
 header-y += meye.h
 header-y += mii.h
@@ -276,6 +277,7 @@ header-y += nfsacl.h
 header-y += nl80211.h
 header-y += nubus.h
 header-y += nvram.h
+header-y += omap3isp.h
 header-y += omapfb.h
 header-y += oom.h
 header-y += param.h
@@ -370,6 +372,8 @@ header-y += unistd.h
 header-y += usbdevice_fs.h
 header-y += utime.h
 header-y += utsname.h
+header-y += v4l2-mediabus.h
+header-y += v4l2-subdev.h
 header-y += veth.h
 header-y += vhost.h
 header-y += videodev2.h
index 7180013a4a3aecd5d455802fce0ee4d74f479989..4afd7102459d7fbdef49be451141e16b0591f5e7 100644 (file)
@@ -10,7 +10,6 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
        return ioremap_cache(phys, size);
 }
 
-int acpi_os_map_generic_address(struct acpi_generic_address *addr);
-void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size);
 
 #endif
index f7df1eefc1071ac71a985650343ec1ca2bfbf9ac..8414de22a779dc5561a2729d2605368a5344a487 100644 (file)
@@ -7,6 +7,28 @@
 #ifndef _AER_H_
 #define _AER_H_
 
+struct aer_header_log_regs {
+       unsigned int dw0;
+       unsigned int dw1;
+       unsigned int dw2;
+       unsigned int dw3;
+};
+
+struct aer_capability_regs {
+       u32 header;
+       u32 uncor_status;
+       u32 uncor_mask;
+       u32 uncor_severity;
+       u32 cor_status;
+       u32 cor_mask;
+       u32 cap_control;
+       struct aer_header_log_regs header_log;
+       u32 root_command;
+       u32 root_status;
+       u16 cor_err_source;
+       u16 uncor_err_source;
+};
+
 #if defined(CONFIG_PCIEAER)
 /* pci-e port driver needs this function to enable aer */
 extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
@@ -27,5 +49,7 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 }
 #endif
 
+extern void cper_print_aer(const char *prefix, int cper_severity,
+                          struct aer_capability_regs *aer);
 #endif //_AER_H_
 
index be33b3affc8ada39fdaaf78bb2deefaca8385615..24d26efd1432606813b969d2ecd3dbfcb7ee0cda 100644 (file)
@@ -53,6 +53,7 @@
 #define CNTL_LCDBPP8           (3 << 1)
 #define CNTL_LCDBPP16          (4 << 1)
 #define CNTL_LCDBPP16_565      (6 << 1)
+#define CNTL_LCDBPP16_444      (7 << 1)
 #define CNTL_LCDBPP24          (5 << 1)
 #define CNTL_LCDBW             (1 << 4)
 #define CNTL_LCDTFT            (1 << 5)
 #define CNTL_LDMAFIFOTIME      (1 << 15)
 #define CNTL_WATERMARK         (1 << 16)
 
+enum {
+       /* individual formats */
+       CLCD_CAP_RGB444         = (1 << 0),
+       CLCD_CAP_RGB5551        = (1 << 1),
+       CLCD_CAP_RGB565         = (1 << 2),
+       CLCD_CAP_RGB888         = (1 << 3),
+       CLCD_CAP_BGR444         = (1 << 4),
+       CLCD_CAP_BGR5551        = (1 << 5),
+       CLCD_CAP_BGR565         = (1 << 6),
+       CLCD_CAP_BGR888         = (1 << 7),
+
+       /* connection layouts */
+       CLCD_CAP_444            = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
+       CLCD_CAP_5551           = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
+       CLCD_CAP_565            = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
+       CLCD_CAP_888            = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
+
+       /* red/blue ordering */
+       CLCD_CAP_RGB            = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
+                                 CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
+       CLCD_CAP_BGR            = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
+                                 CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
+
+       CLCD_CAP_ALL            = CLCD_CAP_BGR | CLCD_CAP_RGB,
+};
+
 struct clcd_panel {
        struct fb_videomode     mode;
        signed short            width;  /* width in mm */
@@ -73,6 +100,7 @@ struct clcd_panel {
        u32                     tim2;
        u32                     tim3;
        u32                     cntl;
+       u32                     caps;
        unsigned int            bpp:8,
                                fixedtimings:1,
                                grayscale:1;
@@ -96,6 +124,11 @@ struct clcd_fb;
 struct clcd_board {
        const char *name;
 
+       /*
+        * Optional.  Hardware capability flags.
+        */
+       u32     caps;
+
        /*
         * Optional.  Check whether the var structure is acceptable
         * for this display.
@@ -155,34 +188,35 @@ struct clcd_fb {
 
 static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 {
+       struct fb_var_screeninfo *var = &fb->fb.var;
        u32 val, cpl;
 
        /*
         * Program the CLCD controller registers and start the CLCD
         */
-       val = ((fb->fb.var.xres / 16) - 1) << 2;
-       val |= (fb->fb.var.hsync_len - 1) << 8;
-       val |= (fb->fb.var.right_margin - 1) << 16;
-       val |= (fb->fb.var.left_margin - 1) << 24;
+       val = ((var->xres / 16) - 1) << 2;
+       val |= (var->hsync_len - 1) << 8;
+       val |= (var->right_margin - 1) << 16;
+       val |= (var->left_margin - 1) << 24;
        regs->tim0 = val;
 
-       val = fb->fb.var.yres;
+       val = var->yres;
        if (fb->panel->cntl & CNTL_LCDDUAL)
                val /= 2;
        val -= 1;
-       val |= (fb->fb.var.vsync_len - 1) << 10;
-       val |= fb->fb.var.lower_margin << 16;
-       val |= fb->fb.var.upper_margin << 24;
+       val |= (var->vsync_len - 1) << 10;
+       val |= var->lower_margin << 16;
+       val |= var->upper_margin << 24;
        regs->tim1 = val;
 
        val = fb->panel->tim2;
-       val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
-       val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
+       val |= var->sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
+       val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
 
-       cpl = fb->fb.var.xres_virtual;
+       cpl = var->xres_virtual;
        if (fb->panel->cntl & CNTL_LCDTFT)        /* TFT */
                /* / 1 */;
-       else if (!fb->fb.var.grayscale)           /* STN color */
+       else if (!var->grayscale)                 /* STN color */
                cpl = cpl * 8 / 3;
        else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
                cpl /= 8;
@@ -194,10 +228,22 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
        regs->tim3 = fb->panel->tim3;
 
        val = fb->panel->cntl;
-       if (fb->fb.var.grayscale)
+       if (var->grayscale)
                val |= CNTL_LCDBW;
 
-       switch (fb->fb.var.bits_per_pixel) {
+       if (fb->panel->caps && fb->board->caps &&
+           var->bits_per_pixel >= 16) {
+               /*
+                * if board and panel supply capabilities, we can support
+                * changing BGR/RGB depending on supplied parameters
+                */
+               if (var->red.offset == 0)
+                       val &= ~CNTL_BGR;
+               else
+                       val |= CNTL_BGR;
+       }
+
+       switch (var->bits_per_pixel) {
        case 1:
                val |= CNTL_LCDBPP1;
                break;
@@ -212,15 +258,17 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
                break;
        case 16:
                /*
-                * PL110 cannot choose between 5551 and 565 modes in
-                * its control register
+                * PL110 cannot choose between 5551 and 565 modes in its
+                * control register.  It is possible to use 565 with
+                * custom external wiring.
                 */
-               if ((fb->dev->periphid & 0x000fffff) == 0x00041110)
+               if (amba_part(fb->dev) == 0x110 ||
+                   var->green.length == 5)
                        val |= CNTL_LCDBPP16;
-               else if (fb->fb.var.green.length == 5)
-                       val |= CNTL_LCDBPP16;
-               else
+               else if (var->green.length == 6)
                        val |= CNTL_LCDBPP16_565;
+               else
+                       val |= CNTL_LCDBPP16_444;
                break;
        case 32:
                val |= CNTL_LCDBPP24;
@@ -228,7 +276,7 @@ static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
        }
 
        regs->cntl = val;
-       regs->pixclock = fb->fb.var.pixclock;
+       regs->pixclock = var->pixclock;
 }
 
 static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
index 4ce34fa937d4910cf8d7546e54de1e888fb0abb2..96f4094b706d9ddd8f8e694655d36c8648326a8a 100644 (file)
@@ -66,8 +66,6 @@ struct backing_dev_info {
        unsigned int capabilities; /* Device capabilities */
        congested_fn *congested_fn; /* Function pointer if device is md/dm */
        void *congested_data;   /* Pointer to aux data for congested func */
-       void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
-       void *unplug_io_data;
 
        char *name;
 
@@ -251,7 +249,6 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
 
 extern struct backing_dev_info default_backing_dev_info;
 extern struct backing_dev_info noop_backing_dev_info;
-void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page);
 
 int writeback_in_progress(struct backing_dev_info *bdi);
 
@@ -336,17 +333,4 @@ static inline int bdi_sched_wait(void *word)
        return 0;
 }
 
-static inline void blk_run_backing_dev(struct backing_dev_info *bdi,
-                                      struct page *page)
-{
-       if (bdi && bdi->unplug_io_fn)
-               bdi->unplug_io_fn(bdi, page);
-}
-
-static inline void blk_run_address_space(struct address_space *mapping)
-{
-       if (mapping)
-               blk_run_backing_dev(mapping->backing_dev_info, NULL);
-}
-
 #endif         /* _LINUX_BACKING_DEV_H */
index 4a3d52e545e186876f2e36d679c9812e4ce1d8a0..5ffc6dda46751a44681ee3f94808ceeb50fd0d38 100644 (file)
@@ -32,6 +32,13 @@ enum backlight_update_reason {
        BACKLIGHT_UPDATE_SYSFS,
 };
 
+enum backlight_type {
+       BACKLIGHT_RAW = 1,
+       BACKLIGHT_PLATFORM,
+       BACKLIGHT_FIRMWARE,
+       BACKLIGHT_TYPE_MAX,
+};
+
 struct backlight_device;
 struct fb_info;
 
@@ -62,6 +69,8 @@ struct backlight_properties {
        /* FB Blanking active? (values as for power) */
        /* Due to be removed, please use (state & BL_CORE_FBBLANK) */
        int fb_blank;
+       /* Backlight type */
+       enum backlight_type type;
        /* Flags used to signal drivers of state changes */
        /* Upper 4 bits are reserved for driver internal use */
        unsigned int state;
index 35dcdb3589bc9a59047a58e166efc540c22a3105..ce33e6868a2f57116ae76510f4dc5de183c2b8fd 100644 (file)
@@ -304,7 +304,6 @@ struct biovec_slab {
 };
 
 extern struct bio_set *fs_bio_set;
-extern struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly;
 
 /*
  * a small number of entries is fine, not going to be performance critical.
index 46ad5197537af19697396a4e43179e6322a255aa..be50d9e70a7d45577782c90050384252db735bd8 100644 (file)
@@ -128,7 +128,6 @@ enum rq_flag_bits {
        __REQ_NOIDLE,           /* don't anticipate more IO after this one */
 
        /* bio only flags */
-       __REQ_UNPLUG,           /* unplug the immediately after submission */
        __REQ_RAHEAD,           /* read ahead, can fail anytime */
        __REQ_THROTTLED,        /* This bio has already been subjected to
                                 * throttling rules. Don't do it again. */
@@ -148,9 +147,11 @@ enum rq_flag_bits {
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_COPY_USER,        /* contains copies of user pages */
        __REQ_FLUSH,            /* request for cache flush */
+       __REQ_FLUSH_SEQ,        /* request for flush sequence */
        __REQ_IO_STAT,          /* account I/O stat */
        __REQ_MIXED_MERGE,      /* merge of different types, fail separately */
        __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
+       __REQ_ON_PLUG,          /* on plug list */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -170,7 +171,6 @@ enum rq_flag_bits {
         REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
 #define REQ_CLONE_MASK         REQ_COMMON_MASK
 
-#define REQ_UNPLUG             (1 << __REQ_UNPLUG)
 #define REQ_RAHEAD             (1 << __REQ_RAHEAD)
 #define REQ_THROTTLED          (1 << __REQ_THROTTLED)
 
@@ -188,8 +188,10 @@ enum rq_flag_bits {
 #define REQ_ALLOCED            (1 << __REQ_ALLOCED)
 #define REQ_COPY_USER          (1 << __REQ_COPY_USER)
 #define REQ_FLUSH              (1 << __REQ_FLUSH)
+#define REQ_FLUSH_SEQ          (1 << __REQ_FLUSH_SEQ)
 #define REQ_IO_STAT            (1 << __REQ_IO_STAT)
 #define REQ_MIXED_MERGE                (1 << __REQ_MIXED_MERGE)
 #define REQ_SECURE             (1 << __REQ_SECURE)
+#define REQ_ON_PLUG            (1 << __REQ_ON_PLUG)
 
 #endif /* __LINUX_BLK_TYPES_H */
index d5063e1b55559f0ecfa1e0e757d136510c99b4bf..16a902f099ac0ee7b1f64c4322c6255a82aa0e09 100644 (file)
@@ -108,11 +108,17 @@ struct request {
 
        /*
         * Three pointers are available for the IO schedulers, if they need
-        * more they have to dynamically allocate it.
+        * more they have to dynamically allocate it.  Flush requests are
+        * never put on the IO scheduler. So let the flush fields share
+        * space with the three elevator_private pointers.
         */
-       void *elevator_private;
-       void *elevator_private2;
-       void *elevator_private3;
+       union {
+               void *elevator_private[3];
+               struct {
+                       unsigned int            seq;
+                       struct list_head        list;
+               } flush;
+       };
 
        struct gendisk *rq_disk;
        struct hd_struct *part;
@@ -190,7 +196,6 @@ typedef void (request_fn_proc) (struct request_queue *q);
 typedef int (make_request_fn) (struct request_queue *q, struct bio *bio);
 typedef int (prep_rq_fn) (struct request_queue *, struct request *);
 typedef void (unprep_rq_fn) (struct request_queue *, struct request *);
-typedef void (unplug_fn) (struct request_queue *);
 
 struct bio_vec;
 struct bvec_merge_data {
@@ -273,7 +278,6 @@ struct request_queue
        make_request_fn         *make_request_fn;
        prep_rq_fn              *prep_rq_fn;
        unprep_rq_fn            *unprep_rq_fn;
-       unplug_fn               *unplug_fn;
        merge_bvec_fn           *merge_bvec_fn;
        softirq_done_fn         *softirq_done_fn;
        rq_timed_out_fn         *rq_timed_out_fn;
@@ -287,12 +291,9 @@ struct request_queue
        struct request          *boundary_rq;
 
        /*
-        * Auto-unplugging state
+        * Delayed queue handling
         */
-       struct timer_list       unplug_timer;
-       int                     unplug_thresh;  /* After this many requests */
-       unsigned long           unplug_delay;   /* After this many jiffies */
-       struct work_struct      unplug_work;
+       struct delayed_work     delay_work;
 
        struct backing_dev_info backing_dev_info;
 
@@ -363,11 +364,12 @@ struct request_queue
         * for flush operations
         */
        unsigned int            flush_flags;
-       unsigned int            flush_seq;
-       int                     flush_err;
+       unsigned int            flush_pending_idx:1;
+       unsigned int            flush_running_idx:1;
+       unsigned long           flush_pending_since;
+       struct list_head        flush_queue[2];
+       struct list_head        flush_data_in_flight;
        struct request          flush_rq;
-       struct request          *orig_flush_rq;
-       struct list_head        pending_flushes;
 
        struct mutex            sysfs_lock;
 
@@ -387,14 +389,13 @@ struct request_queue
 #define QUEUE_FLAG_ASYNCFULL   4       /* write queue has been filled */
 #define QUEUE_FLAG_DEAD                5       /* queue being torn down */
 #define QUEUE_FLAG_REENTER     6       /* Re-entrancy avoidance */
-#define QUEUE_FLAG_PLUGGED     7       /* queue is plugged */
-#define QUEUE_FLAG_ELVSWITCH   8       /* don't use elevator, just do FIFO */
-#define QUEUE_FLAG_BIDI                9       /* queue supports bidi requests */
-#define QUEUE_FLAG_NOMERGES    10      /* disable merge attempts */
-#define QUEUE_FLAG_SAME_COMP   11      /* force complete on same CPU */
-#define QUEUE_FLAG_FAIL_IO     12      /* fake timeout */
-#define QUEUE_FLAG_STACKABLE   13      /* supports request stacking */
-#define QUEUE_FLAG_NONROT      14      /* non-rotational device (SSD) */
+#define QUEUE_FLAG_ELVSWITCH   7       /* don't use elevator, just do FIFO */
+#define QUEUE_FLAG_BIDI                8       /* queue supports bidi requests */
+#define QUEUE_FLAG_NOMERGES     9      /* disable merge attempts */
+#define QUEUE_FLAG_SAME_COMP   10      /* force complete on same CPU */
+#define QUEUE_FLAG_FAIL_IO     11      /* fake timeout */
+#define QUEUE_FLAG_STACKABLE   12      /* supports request stacking */
+#define QUEUE_FLAG_NONROT      13      /* non-rotational device (SSD) */
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 #define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
 #define QUEUE_FLAG_DISCARD     16      /* supports DISCARD */
@@ -472,7 +473,6 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
        __clear_bit(flag, &q->queue_flags);
 }
 
-#define blk_queue_plugged(q)   test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_queue_tagged(q)    test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_stopped(q)   test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
 #define blk_queue_nomerges(q)  test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
@@ -667,9 +667,7 @@ extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
 extern void blk_rq_unprep_clone(struct request *rq);
 extern int blk_insert_cloned_request(struct request_queue *q,
                                     struct request *rq);
-extern void blk_plug_device(struct request_queue *);
-extern void blk_plug_device_unlocked(struct request_queue *);
-extern int blk_remove_plug(struct request_queue *);
+extern void blk_delay_queue(struct request_queue *, unsigned long);
 extern void blk_recount_segments(struct request_queue *, struct bio *);
 extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
                          unsigned int, void __user *);
@@ -713,7 +711,6 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *,
                          struct request *, int);
 extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
                                  struct request *, int, rq_end_io_fn *);
-extern void blk_unplug(struct request_queue *q);
 
 static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
 {
@@ -850,7 +847,6 @@ extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bd
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
-extern void generic_unplug_device(struct request_queue *);
 extern long nr_blockdev_pages(void);
 
 int blk_get_queue(struct request_queue *);
@@ -858,6 +854,31 @@ struct request_queue *blk_alloc_queue(gfp_t);
 struct request_queue *blk_alloc_queue_node(gfp_t, int);
 extern void blk_put_queue(struct request_queue *);
 
+struct blk_plug {
+       unsigned long magic;
+       struct list_head list;
+       unsigned int should_sort;
+};
+
+extern void blk_start_plug(struct blk_plug *);
+extern void blk_finish_plug(struct blk_plug *);
+extern void __blk_flush_plug(struct task_struct *, struct blk_plug *);
+
+static inline void blk_flush_plug(struct task_struct *tsk)
+{
+       struct blk_plug *plug = tsk->plug;
+
+       if (unlikely(plug))
+               __blk_flush_plug(tsk, plug);
+}
+
+static inline bool blk_needs_flush_plug(struct task_struct *tsk)
+{
+       struct blk_plug *plug = tsk->plug;
+
+       return plug && !list_empty(&plug->list);
+}
+
 /*
  * tag stuff
  */
@@ -1135,7 +1156,6 @@ static inline uint64_t rq_io_start_time_ns(struct request *req)
 extern int blk_throtl_init(struct request_queue *q);
 extern void blk_throtl_exit(struct request_queue *q);
 extern int blk_throtl_bio(struct request_queue *q, struct bio **bio);
-extern void throtl_shutdown_timer_wq(struct request_queue *q);
 #else /* CONFIG_BLK_DEV_THROTTLING */
 static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
 {
@@ -1144,7 +1164,6 @@ static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
 
 static inline int blk_throtl_init(struct request_queue *q) { return 0; }
 static inline int blk_throtl_exit(struct request_queue *q) { return 0; }
-static inline void throtl_shutdown_timer_wq(struct request_queue *q) {}
 #endif /* CONFIG_BLK_DEV_THROTTLING */
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
@@ -1278,6 +1297,26 @@ static inline long nr_blockdev_pages(void)
        return 0;
 }
 
+struct blk_plug {
+};
+
+static inline void blk_start_plug(struct blk_plug *plug)
+{
+}
+
+static inline void blk_finish_plug(struct blk_plug *plug)
+{
+}
+
+static inline void blk_flush_plug(struct task_struct *task)
+{
+}
+
+static inline bool blk_needs_flush_plug(struct task_struct *tsk)
+{
+       return false;
+}
+
 #endif /* CONFIG_BLOCK */
 
 #endif
index 499dfe982a0e8a21066e815daa400ac8b57ec5b4..b8613e806aa9c0b410b119519bc7044e44889570 100644 (file)
@@ -19,10 +19,6 @@ extern unsigned long min_low_pfn;
  */
 extern unsigned long max_pfn;
 
-#ifdef CONFIG_CRASH_DUMP
-extern unsigned long saved_max_pfn;
-#endif
-
 #ifndef CONFIG_NO_BOOTMEM
 /*
  * node_bootmem_map is a map pointer - the bits represent all physical 
index 68d1fe7b877c82e2d302fb31f3702836bc6d6843..f5df23561b96d0428cfed1d26fdaa11127e46b0d 100644 (file)
@@ -219,7 +219,6 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size);
 int block_commit_write(struct page *page, unsigned from, unsigned to);
 int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
                                get_block_t get_block);
-void block_sync_page(struct page *);
 sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
 int block_truncate_page(struct address_space *, loff_t, get_block_t *);
 int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
index fb16a3699b99f682c88bea8cdbb71c0862ca368f..16ee8b49a20030cc190c36d4689e43e0c01348a8 100644 (file)
@@ -368,6 +368,15 @@ struct cpu_vfs_cap_data {
 
 #ifdef __KERNEL__
 
+struct dentry;
+struct user_namespace;
+
+struct user_namespace *current_user_ns(void);
+
+extern const kernel_cap_t __cap_empty_set;
+extern const kernel_cap_t __cap_full_set;
+extern const kernel_cap_t __cap_init_eff_set;
+
 /*
  * Internal kernel functions only
  */
@@ -530,40 +539,27 @@ static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
                           cap_intersect(permitted, __cap_nfsd_set));
 }
 
-extern const kernel_cap_t __cap_empty_set;
-extern const kernel_cap_t __cap_full_set;
-extern const kernel_cap_t __cap_init_eff_set;
-
-/**
- * has_capability - Determine if a task has a superior capability available
- * @t: The task in question
- * @cap: The capability to be tested for
- *
- * Return true if the specified task has the given superior capability
- * currently in effect, false if not.
- *
- * Note that this does not set PF_SUPERPRIV on the task.
- */
-#define has_capability(t, cap) (security_real_capable((t), (cap)) == 0)
+extern bool has_capability(struct task_struct *t, int cap);
+extern bool has_ns_capability(struct task_struct *t,
+                             struct user_namespace *ns, int cap);
+extern bool has_capability_noaudit(struct task_struct *t, int cap);
+extern bool capable(int cap);
+extern bool ns_capable(struct user_namespace *ns, int cap);
+extern bool task_ns_capable(struct task_struct *t, int cap);
 
 /**
- * has_capability_noaudit - Determine if a task has a superior capability available (unaudited)
- * @t: The task in question
- * @cap: The capability to be tested for
+ * nsown_capable - Check superior capability to one's own user_ns
+ * @cap: The capability in question
  *
- * Return true if the specified task has the given superior capability
- * currently in effect, false if not, but don't write an audit message for the
- * check.
- *
- * Note that this does not set PF_SUPERPRIV on the task.
+ * Return true if the current task has the given superior capability
+ * targeted at its own user namespace.
  */
-#define has_capability_noaudit(t, cap) \
-       (security_real_capable_noaudit((t), (cap)) == 0)
-
-extern int capable(int cap);
+static inline bool nsown_capable(int cap)
+{
+       return ns_capable(current_user_ns(), cap);
+}
 
 /* audit system wants to get cap info from files as well */
-struct dentry;
 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
 
 #endif /* __KERNEL__ */
index 09dcc0c2ffd52bd8d69d04ace79a00ca6d909f5c..b8e995fbd8670a2c7303d590432dc2a5e1f62b0d 100644 (file)
@@ -136,9 +136,18 @@ struct ceph_dir_layout {
 
 
 /* osd */
-#define CEPH_MSG_OSD_MAP          41
-#define CEPH_MSG_OSD_OP           42
-#define CEPH_MSG_OSD_OPREPLY      43
+#define CEPH_MSG_OSD_MAP                41
+#define CEPH_MSG_OSD_OP                 42
+#define CEPH_MSG_OSD_OPREPLY            43
+#define CEPH_MSG_WATCH_NOTIFY           44
+
+
+/* watch-notify operations */
+enum {
+  WATCH_NOTIFY                         = 1, /* notifying watcher */
+  WATCH_NOTIFY_COMPLETE                        = 2, /* notifier notified when done */
+};
+
 
 /* pool operations */
 enum {
@@ -213,8 +222,10 @@ struct ceph_client_mount {
        struct ceph_mon_request_header monhdr;
 } __attribute__ ((packed));
 
+#define CEPH_SUBSCRIBE_ONETIME    1  /* i want only 1 update after have */
+
 struct ceph_mon_subscribe_item {
-       __le64 have_version;    __le64 have;
+       __le64 have_version;    __le64 have;
        __u8 onetime;
 } __attribute__ ((packed));
 
index 72c72bfccb88181b8b7c480e445849bfc0c8ab28..0d2e0fffb470734d90cb1248ee9f02613764f54f 100644 (file)
@@ -71,7 +71,6 @@ struct ceph_options {
 #define CEPH_OSD_TIMEOUT_DEFAULT    60  /* seconds */
 #define CEPH_OSD_KEEPALIVE_DEFAULT  5
 #define CEPH_OSD_IDLE_TTL_DEFAULT    60
-#define CEPH_MOUNT_RSIZE_DEFAULT    (512*1024) /* readahead */
 
 #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
 #define CEPH_MSG_MAX_DATA_LEN  (16*1024*1024)
index a1af29648fb54be5c0b5ac1cfc62879314145d56..f88eacb111d4151dc5491797fe0e03faaadc26a9 100644 (file)
@@ -32,6 +32,7 @@ struct ceph_osd {
        struct rb_node o_node;
        struct ceph_connection o_con;
        struct list_head o_requests;
+       struct list_head o_linger_requests;
        struct list_head o_osd_lru;
        struct ceph_authorizer *o_authorizer;
        void *o_authorizer_buf, *o_authorizer_reply_buf;
@@ -47,6 +48,8 @@ struct ceph_osd_request {
        struct rb_node  r_node;
        struct list_head r_req_lru_item;
        struct list_head r_osd_item;
+       struct list_head r_linger_item;
+       struct list_head r_linger_osd;
        struct ceph_osd *r_osd;
        struct ceph_pg   r_pgid;
        int              r_pg_osds[CEPH_PG_MAX_SIZE];
@@ -59,6 +62,7 @@ struct ceph_osd_request {
        int               r_flags;     /* any additional flags for the osd */
        u32               r_sent;      /* >0 if r_request is sending/sent */
        int               r_got_reply;
+       int               r_linger;
 
        struct ceph_osd_client *r_osdc;
        struct kref       r_kref;
@@ -74,7 +78,6 @@ struct ceph_osd_request {
        char              r_oid[40];          /* object name */
        int               r_oid_len;
        unsigned long     r_stamp;            /* send OR check time */
-       bool              r_resend;           /* msg send failed, needs retry */
 
        struct ceph_file_layout r_file_layout;
        struct ceph_snap_context *r_snapc;    /* snap context for writes */
@@ -90,6 +93,26 @@ struct ceph_osd_request {
        struct ceph_pagelist *r_trail;        /* trailing part of the data */
 };
 
+struct ceph_osd_event {
+       u64 cookie;
+       int one_shot;
+       struct ceph_osd_client *osdc;
+       void (*cb)(u64, u64, u8, void *);
+       void *data;
+       struct rb_node node;
+       struct list_head osd_node;
+       struct kref kref;
+       struct completion completion;
+};
+
+struct ceph_osd_event_work {
+       struct work_struct work;
+       struct ceph_osd_event *event;
+        u64 ver;
+        u64 notify_id;
+        u8 opcode;
+};
+
 struct ceph_osd_client {
        struct ceph_client     *client;
 
@@ -104,7 +127,10 @@ struct ceph_osd_client {
        u64                    timeout_tid;   /* tid of timeout triggering rq */
        u64                    last_tid;      /* tid of last request */
        struct rb_root         requests;      /* pending requests */
-       struct list_head       req_lru;       /* pending requests lru */
+       struct list_head       req_lru;       /* in-flight lru */
+       struct list_head       req_unsent;    /* unsent/need-resend queue */
+       struct list_head       req_notarget;  /* map to no osd */
+       struct list_head       req_linger;    /* lingering requests */
        int                    num_requests;
        struct delayed_work    timeout_work;
        struct delayed_work    osds_timeout_work;
@@ -116,6 +142,12 @@ struct ceph_osd_client {
 
        struct ceph_msgpool     msgpool_op;
        struct ceph_msgpool     msgpool_op_reply;
+
+       spinlock_t              event_lock;
+       struct rb_root          event_tree;
+       u64                     event_count;
+
+       struct workqueue_struct *notify_wq;
 };
 
 struct ceph_osd_req_op {
@@ -150,6 +182,13 @@ struct ceph_osd_req_op {
                struct {
                        u64 snapid;
                } snap;
+               struct {
+                       u64 cookie;
+                       u64 ver;
+                       __u8 flag;
+                       u32 prot_ver;
+                       u32 timeout;
+               } watch;
        };
        u32 payload_len;
 };
@@ -198,6 +237,11 @@ extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
                                      bool use_mempool, int num_reply,
                                      int page_align);
 
+extern void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc,
+                                        struct ceph_osd_request *req);
+extern void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc,
+                                               struct ceph_osd_request *req);
+
 static inline void ceph_osdc_get_request(struct ceph_osd_request *req)
 {
        kref_get(&req->r_kref);
@@ -233,5 +277,14 @@ extern int ceph_osdc_writepages(struct ceph_osd_client *osdc,
                                struct page **pages, int nr_pages,
                                int flags, int do_sync, bool nofail);
 
+/* watch/notify events */
+extern int ceph_osdc_create_event(struct ceph_osd_client *osdc,
+                                 void (*event_cb)(u64, u64, u8, void *),
+                                 int one_shot, void *data,
+                                 struct ceph_osd_event **pevent);
+extern void ceph_osdc_cancel_event(struct ceph_osd_event *event);
+extern int ceph_osdc_wait_event(struct ceph_osd_event *event,
+                               unsigned long timeout);
+extern void ceph_osdc_put_event(struct ceph_osd_event *event);
 #endif
 
index 6d5247f2e81b273538e78df5db1dc9204674a2d3..0a99099801a4ec56ad04e0dcbe1e25e28eba2210 100644 (file)
@@ -12,9 +12,9 @@
  * osdmap encoding versions
  */
 #define CEPH_OSDMAP_INC_VERSION     5
-#define CEPH_OSDMAP_INC_VERSION_EXT 5
+#define CEPH_OSDMAP_INC_VERSION_EXT 6
 #define CEPH_OSDMAP_VERSION         5
-#define CEPH_OSDMAP_VERSION_EXT     5
+#define CEPH_OSDMAP_VERSION_EXT     6
 
 /*
  * fs id
@@ -181,9 +181,17 @@ enum {
        /* read */
        CEPH_OSD_OP_READ      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 1,
        CEPH_OSD_OP_STAT      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 2,
+       CEPH_OSD_OP_MAPEXT    = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 3,
 
        /* fancy read */
-       CEPH_OSD_OP_MASKTRUNC = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4,
+       CEPH_OSD_OP_MASKTRUNC   = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 4,
+       CEPH_OSD_OP_SPARSE_READ = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 5,
+
+       CEPH_OSD_OP_NOTIFY    = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 6,
+       CEPH_OSD_OP_NOTIFY_ACK = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 7,
+
+       /* versioning */
+       CEPH_OSD_OP_ASSERT_VER = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 8,
 
        /* write */
        CEPH_OSD_OP_WRITE     = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 1,
@@ -205,6 +213,8 @@ enum {
        CEPH_OSD_OP_CREATE  = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13,
        CEPH_OSD_OP_ROLLBACK= CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 14,
 
+       CEPH_OSD_OP_WATCH   = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 15,
+
        /** attrs **/
        /* read */
        CEPH_OSD_OP_GETXATTR  = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_ATTR | 1,
@@ -218,11 +228,14 @@ enum {
        CEPH_OSD_OP_RMXATTR   = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_ATTR | 4,
 
        /** subop **/
-       CEPH_OSD_OP_PULL           = CEPH_OSD_OP_MODE_SUB | 1,
-       CEPH_OSD_OP_PUSH           = CEPH_OSD_OP_MODE_SUB | 2,
-       CEPH_OSD_OP_BALANCEREADS   = CEPH_OSD_OP_MODE_SUB | 3,
-       CEPH_OSD_OP_UNBALANCEREADS = CEPH_OSD_OP_MODE_SUB | 4,
-       CEPH_OSD_OP_SCRUB          = CEPH_OSD_OP_MODE_SUB | 5,
+       CEPH_OSD_OP_PULL            = CEPH_OSD_OP_MODE_SUB | 1,
+       CEPH_OSD_OP_PUSH            = CEPH_OSD_OP_MODE_SUB | 2,
+       CEPH_OSD_OP_BALANCEREADS    = CEPH_OSD_OP_MODE_SUB | 3,
+       CEPH_OSD_OP_UNBALANCEREADS  = CEPH_OSD_OP_MODE_SUB | 4,
+       CEPH_OSD_OP_SCRUB           = CEPH_OSD_OP_MODE_SUB | 5,
+       CEPH_OSD_OP_SCRUB_RESERVE   = CEPH_OSD_OP_MODE_SUB | 6,
+       CEPH_OSD_OP_SCRUB_UNRESERVE = CEPH_OSD_OP_MODE_SUB | 7,
+       CEPH_OSD_OP_SCRUB_STOP      = CEPH_OSD_OP_MODE_SUB | 8,
 
        /** lock **/
        CEPH_OSD_OP_WRLOCK    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_LOCK | 1,
@@ -328,6 +341,8 @@ enum {
        CEPH_OSD_CMPXATTR_MODE_U64    = 2
 };
 
+#define RADOS_NOTIFY_VER       1
+
 /*
  * an individual object operation.  each may be accompanied by some data
  * payload
@@ -359,7 +374,12 @@ struct ceph_osd_op {
                struct {
                        __le64 snapid;
                } __attribute__ ((packed)) snap;
-       };
+               struct {
+                       __le64 cookie;
+                       __le64 ver;
+                       __u8 flag;      /* 0 = unwatch, 1 = watch */
+               } __attribute__ ((packed)) watch;
+};
        __le32 payload_len;
 } __attribute__ ((packed));
 
@@ -402,4 +422,5 @@ struct ceph_osd_reply_head {
 } __attribute__ ((packed));
 
 
+
 #endif
index dfa2ed4c0d26a7d285512211ab739ec9a721960e..cc9f7a4286490a3bae2d47db3fe74d2dabfd4aac 100644 (file)
@@ -11,9 +11,6 @@
 /* The full zone was compacted */
 #define COMPACT_COMPLETE       3
 
-#define COMPACT_MODE_DIRECT_RECLAIM    0
-#define COMPACT_MODE_KSWAPD            1
-
 #ifdef CONFIG_COMPACTION
 extern int sysctl_compact_memory;
 extern int sysctl_compaction_handler(struct ctl_table *table, int write,
@@ -28,8 +25,7 @@ extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        bool sync);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
 extern unsigned long compact_zone_order(struct zone *zone, int order,
-                                       gfp_t gfp_mask, bool sync,
-                                       int compact_mode);
+                                       gfp_t gfp_mask, bool sync);
 
 /* Do not skip compaction more than 64 times */
 #define COMPACT_MAX_DEFER_SHIFT 6
@@ -74,8 +70,7 @@ static inline unsigned long compaction_suitable(struct zone *zone, int order)
 }
 
 static inline unsigned long compact_zone_order(struct zone *zone, int order,
-                                              gfp_t gfp_mask, bool sync,
-                                              int compact_mode)
+                                              gfp_t gfp_mask, bool sync)
 {
        return COMPACT_CONTINUE;
 }
index 16508bcddaccdb12490ce70a357c54be69643000..cb4c1eb7778e4f776bf9343f93d5f9c8636ab148 100644 (file)
 #if !defined(__noclone)
 #define __noclone      /* not needed */
 #endif
+
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
+
+#define __always_inline                inline __attribute__((always_inline))
index b721129e0469f12decf2d764b421728e608e5e00..37d412436d0fcd3a467eabc43bead67ca941f385 100644 (file)
 #   error "GCOV profiling support for gcc versions below 3.4 not included"
 # endif /* __GNUC_MINOR__ */
 #endif /* CONFIG_GCOV_KERNEL */
-
-/*
- * A trick to suppress uninitialized variable warning without generating any
- * code
- */
-#define uninitialized_var(x) x = x
-
-#define __always_inline                inline __attribute__((always_inline))
index fcfa5b9a4317af2b272d06073d7af51019ebf321..64b7c003fd7a50c056d98f0a2aa412da067a753d 100644 (file)
 #define __used                 __attribute__((__used__))
 #define __must_check           __attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
-#define __always_inline                inline __attribute__((always_inline))
-
-/*
- * A trick to suppress uninitialized variable warning without generating any
- * code
- */
-#define uninitialized_var(x) x = x
 
 #if __GNUC_MINOR__ >= 3
 /* Mark functions as cold. gcc will assume any path leading to a call
@@ -53,7 +46,6 @@
 #define __noclone      __attribute__((__noclone__))
 
 #endif
-
 #endif
 
 #if __GNUC_MINOR__ > 0
index 3104aaff5dd027f55ce43b38f9ad99db4c3a667e..372a25839fd181be11b631849ffc627b37bb93ec 100644 (file)
@@ -388,5 +388,7 @@ struct cper_sec_pcie {
 #pragma pack()
 
 u64 cper_next_record_id(void);
+void cper_print_bits(const char *prefix, unsigned int bits,
+                    const char *strs[], unsigned int strs_size);
 
 #endif
index e20dd1f9b40a75ed05e52ac7e40de8f3c5e6e151..391a259b2cc90784157d57d1f5ca1c14641636e1 100644 (file)
@@ -11,7 +11,7 @@
 extern u32  crc32_le(u32 crc, unsigned char const *p, size_t len);
 extern u32  crc32_be(u32 crc, unsigned char const *p, size_t len);
 
-#define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)data, length)
+#define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)(data), length)
 
 /*
  * Helpers for hash table generation of ethernet nics:
index 4aaeab3764469961f1106d988e57e58a91e1a16e..9aeeb0ba200363909bfd52a5a59f11cee7c54f5c 100644 (file)
@@ -354,9 +354,11 @@ static inline void put_cred(const struct cred *_cred)
 #define current_fsgid()        (current_cred_xxx(fsgid))
 #define current_cap()          (current_cred_xxx(cap_effective))
 #define current_user()         (current_cred_xxx(user))
-#define current_user_ns()      (current_cred_xxx(user)->user_ns)
+#define _current_user_ns()     (current_cred_xxx(user)->user_ns)
 #define current_security()     (current_cred_xxx(security))
 
+extern struct user_namespace *current_user_ns(void);
+
 #define current_uid_gid(_uid, _gid)            \
 do {                                           \
        const struct cred *__cred;              \
index 1a87760d65322b2d0528886b3232d2707f725532..f2afed4fa9454776c79611d52755121dff749342 100644 (file)
@@ -416,7 +416,6 @@ static inline bool d_mountpoint(struct dentry *dentry)
        return dentry->d_flags & DCACHE_MOUNTED;
 }
 
-extern struct vfsmount *lookup_mnt(struct path *);
 extern struct dentry *lookup_create(struct nameidata *nd, int is_dir);
 
 extern int sysctl_vfs_cache_pressure;
index 272496d1fae41bbb7de1db89b1131ab87283972b..e2768834f39775f4baeae6e5e9316b64184a823c 100644 (file)
@@ -285,11 +285,6 @@ void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callback
  */
 int dm_table_complete(struct dm_table *t);
 
-/*
- * Unplug all devices in a table.
- */
-void dm_table_unplug_all(struct dm_table *t);
-
 /*
  * Table reference counting.
  */
index 78bbf47bbb96523076dfe1f933323361f7eeda32..3708455ee6c38f49cb8d7fd97b040f100a3379aa 100644 (file)
@@ -267,9 +267,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       19
-#define DM_VERSION_PATCHLEVEL  1
-#define DM_VERSION_EXTRA       "-ioctl (2011-01-07)"
+#define DM_VERSION_MINOR       20
+#define DM_VERSION_PATCHLEVEL  0
+#define DM_VERSION_EXTRA       "-ioctl (2011-02-02)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
@@ -328,4 +328,10 @@ enum {
  */
 #define DM_UUID_FLAG                   (1 << 14) /* In */
 
+/*
+ * If set, all buffers are wiped after use. Use when sending
+ * or requesting sensitive data such as an encryption key.
+ */
+#define DM_SECURE_DATA_FLAG            (1 << 15) /* In */
+
 #endif                         /* _LINUX_DM_IOCTL_H */
index c8aad713a0460bd1c66c0962f930602501b2f9e7..6998d9376ef902781acd1c13d06ebdbbff9f56fe 100644 (file)
 /**
  * struct dw_dma_platform_data - Controller configuration parameters
  * @nr_channels: Number of channels supported by hardware (max 8)
+ * @is_private: The device channels should be marked as private and not for
+ *     by the general purpose DMA channel allocator.
  */
 struct dw_dma_platform_data {
        unsigned int    nr_channels;
+       bool            is_private;
+#define CHAN_ALLOCATION_ASCENDING      0       /* zero to seven */
+#define CHAN_ALLOCATION_DESCENDING     1       /* seven to zero */
+       unsigned char   chan_allocation_order;
+#define CHAN_PRIORITY_ASCENDING                0       /* chan0 highest */
+#define CHAN_PRIORITY_DESCENDING       1       /* chan7 highest */
+       unsigned char   chan_priority;
 };
 
 /**
@@ -33,6 +42,30 @@ enum dw_dma_slave_width {
        DW_DMA_SLAVE_WIDTH_32BIT,
 };
 
+/* bursts size */
+enum dw_dma_msize {
+       DW_DMA_MSIZE_1,
+       DW_DMA_MSIZE_4,
+       DW_DMA_MSIZE_8,
+       DW_DMA_MSIZE_16,
+       DW_DMA_MSIZE_32,
+       DW_DMA_MSIZE_64,
+       DW_DMA_MSIZE_128,
+       DW_DMA_MSIZE_256,
+};
+
+/* flow controller */
+enum dw_dma_fc {
+       DW_DMA_FC_D_M2M,
+       DW_DMA_FC_D_M2P,
+       DW_DMA_FC_D_P2M,
+       DW_DMA_FC_D_P2P,
+       DW_DMA_FC_P_P2M,
+       DW_DMA_FC_SP_P2P,
+       DW_DMA_FC_P_M2P,
+       DW_DMA_FC_DP_P2P,
+};
+
 /**
  * struct dw_dma_slave - Controller-specific information about a slave
  *
@@ -44,6 +77,11 @@ enum dw_dma_slave_width {
  * @reg_width: peripheral register width
  * @cfg_hi: Platform-specific initializer for the CFG_HI register
  * @cfg_lo: Platform-specific initializer for the CFG_LO register
+ * @src_master: src master for transfers on allocated channel.
+ * @dst_master: dest master for transfers on allocated channel.
+ * @src_msize: src burst size.
+ * @dst_msize: dest burst size.
+ * @fc: flow controller for DMA transfer
  */
 struct dw_dma_slave {
        struct device           *dma_dev;
@@ -52,6 +90,11 @@ struct dw_dma_slave {
        enum dw_dma_slave_width reg_width;
        u32                     cfg_hi;
        u32                     cfg_lo;
+       u8                      src_master;
+       u8                      dst_master;
+       u8                      src_msize;
+       u8                      dst_msize;
+       u8                      fc;
 };
 
 /* Platform-configurable bits in CFG_HI */
@@ -62,7 +105,6 @@ struct dw_dma_slave {
 #define DWC_CFGH_DST_PER(x)    ((x) << 11)
 
 /* Platform-configurable bits in CFG_LO */
-#define DWC_CFGL_PRIO(x)       ((x) << 5)      /* priority */
 #define DWC_CFGL_LOCK_CH_XFER  (0 << 12)       /* scope of LOCK_CH */
 #define DWC_CFGL_LOCK_CH_BLOCK (1 << 12)
 #define DWC_CFGL_LOCK_CH_XACT  (2 << 12)
index 4d857973d2c94317cf11041a4a7070794fc13a99..d93efcc4457050ffa1e511a825c273f60796ed69 100644 (file)
@@ -20,7 +20,6 @@ typedef void (elevator_bio_merged_fn) (struct request_queue *,
 typedef int (elevator_dispatch_fn) (struct request_queue *, int);
 
 typedef void (elevator_add_req_fn) (struct request_queue *, struct request *);
-typedef int (elevator_queue_empty_fn) (struct request_queue *);
 typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *);
 typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *);
 typedef int (elevator_may_queue_fn) (struct request_queue *, int);
@@ -46,7 +45,6 @@ struct elevator_ops
        elevator_activate_req_fn *elevator_activate_req_fn;
        elevator_deactivate_req_fn *elevator_deactivate_req_fn;
 
-       elevator_queue_empty_fn *elevator_queue_empty_fn;
        elevator_completed_req_fn *elevator_completed_req_fn;
 
        elevator_request_list_fn *elevator_former_req_fn;
@@ -101,17 +99,17 @@ struct elevator_queue
  */
 extern void elv_dispatch_sort(struct request_queue *, struct request *);
 extern void elv_dispatch_add_tail(struct request_queue *, struct request *);
-extern void elv_add_request(struct request_queue *, struct request *, int, int);
-extern void __elv_add_request(struct request_queue *, struct request *, int, int);
+extern void elv_add_request(struct request_queue *, struct request *, int);
+extern void __elv_add_request(struct request_queue *, struct request *, int);
 extern void elv_insert(struct request_queue *, struct request *, int);
 extern int elv_merge(struct request_queue *, struct request **, struct bio *);
+extern int elv_try_merge(struct request *, struct bio *);
 extern void elv_merge_requests(struct request_queue *, struct request *,
                               struct request *);
 extern void elv_merged_request(struct request_queue *, struct request *, int);
 extern void elv_bio_merged(struct request_queue *q, struct request *,
                                struct bio *);
 extern void elv_requeue_request(struct request_queue *, struct request *);
-extern int elv_queue_empty(struct request_queue *);
 extern struct request *elv_former_request(struct request_queue *, struct request *);
 extern struct request *elv_latter_request(struct request_queue *, struct request *);
 extern int elv_register_queue(struct request_queue *q);
@@ -167,6 +165,8 @@ extern struct request *elv_rb_find(struct rb_root *, sector_t);
 #define ELEVATOR_INSERT_BACK   2
 #define ELEVATOR_INSERT_SORT   3
 #define ELEVATOR_INSERT_REQUEUE        4
+#define ELEVATOR_INSERT_FLUSH  5
+#define ELEVATOR_INSERT_SORT_MERGE     6
 
 /*
  * return values from elevator_may_queue_fn
index 448afc12c78afe6157929010a7fba01a6d63ba8e..f2edce25a76b64f91701cdbd2c680dce19b90706 100644 (file)
@@ -52,6 +52,14 @@ static inline void * __must_check ERR_CAST(const void *ptr)
        return (void *) ptr;
 }
 
+static inline int __must_check PTR_RET(const void *ptr)
+{
+       if (IS_ERR(ptr))
+               return PTR_ERR(ptr);
+       else
+               return 0;
+}
+
 #endif
 
 #endif /* _LINUX_ERR_H */
index 6043c64c207afa170c3de5a0551bd68451314263..85c1d302c12ec6833c013fc076b801da85a07abc 100644 (file)
@@ -418,13 +418,13 @@ struct ext3_inode {
 #define EXT2_MOUNT_DATA_FLAGS          EXT3_MOUNT_DATA_FLAGS
 #endif
 
-#define ext3_set_bit                   ext2_set_bit
+#define ext3_set_bit                   __test_and_set_bit_le
 #define ext3_set_bit_atomic            ext2_set_bit_atomic
-#define ext3_clear_bit                 ext2_clear_bit
+#define ext3_clear_bit                 __test_and_clear_bit_le
 #define ext3_clear_bit_atomic          ext2_clear_bit_atomic
-#define ext3_test_bit                  ext2_test_bit
-#define ext3_find_first_zero_bit       ext2_find_first_zero_bit
-#define ext3_find_next_zero_bit                ext2_find_next_zero_bit
+#define ext3_test_bit                  test_bit_le
+#define ext3_find_first_zero_bit       find_first_zero_bit_le
+#define ext3_find_next_zero_bit                find_next_zero_bit_le
 
 /*
  * Maximal mount counts between two filesystem checks
index fc023d67676f6e18be83551c8543806bc05e08b8..c64f3680d4f154b2bc2959380e0b04ecd5477d52 100644 (file)
@@ -93,7 +93,7 @@ struct fw_card {
        int current_tlabel;
        u64 tlabel_mask;
        struct list_head transaction_list;
-       unsigned long reset_jiffies;
+       u64 reset_jiffies;
 
        u32 split_timeout_hi;
        u32 split_timeout_lo;
index 7061a8587ee32a5fe92cfaa6891bd0e120a39eb1..b677bd77f2d67cbabb168fe6d38fc846b01b443e 100644 (file)
@@ -138,16 +138,10 @@ struct inodes_stat_t {
  *                     block layer could (in theory) choose to ignore this
  *                     request if it runs into resource problems.
  * WRITE               A normal async write. Device will be plugged.
- * WRITE_SYNC_PLUG     Synchronous write. Identical to WRITE, but passes down
+ * WRITE_SYNC          Synchronous write. Identical to WRITE, but passes down
  *                     the hint that someone will be waiting on this IO
- *                     shortly. The device must still be unplugged explicitly,
- *                     WRITE_SYNC_PLUG does not do this as we could be
- *                     submitting more writes before we actually wait on any
- *                     of them.
- * WRITE_SYNC          Like WRITE_SYNC_PLUG, but also unplugs the device
- *                     immediately after submission. The write equivalent
- *                     of READ_SYNC.
- * WRITE_ODIRECT_PLUG  Special case write for O_DIRECT only.
+ *                     shortly. The write equivalent of READ_SYNC.
+ * WRITE_ODIRECT       Special case write for O_DIRECT only.
  * WRITE_FLUSH         Like WRITE_SYNC but with preceding cache flush.
  * WRITE_FUA           Like WRITE_SYNC but data is guaranteed to be on
  *                     non-volatile media on completion.
@@ -163,18 +157,14 @@ struct inodes_stat_t {
 #define WRITE                  RW_MASK
 #define READA                  RWA_MASK
 
-#define READ_SYNC              (READ | REQ_SYNC | REQ_UNPLUG)
+#define READ_SYNC              (READ | REQ_SYNC)
 #define READ_META              (READ | REQ_META)
-#define WRITE_SYNC_PLUG                (WRITE | REQ_SYNC | REQ_NOIDLE)
-#define WRITE_SYNC             (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG)
-#define WRITE_ODIRECT_PLUG     (WRITE | REQ_SYNC)
+#define WRITE_SYNC             (WRITE | REQ_SYNC | REQ_NOIDLE)
+#define WRITE_ODIRECT          (WRITE | REQ_SYNC)
 #define WRITE_META             (WRITE | REQ_META)
-#define WRITE_FLUSH            (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG | \
-                                REQ_FLUSH)
-#define WRITE_FUA              (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG | \
-                                REQ_FUA)
-#define WRITE_FLUSH_FUA                (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG | \
-                                REQ_FLUSH | REQ_FUA)
+#define WRITE_FLUSH            (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH)
+#define WRITE_FUA              (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA)
+#define WRITE_FLUSH_FUA                (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA)
 
 #define SEL_IN         1
 #define SEL_OUT                2
@@ -586,7 +576,6 @@ typedef int (*read_actor_t)(read_descriptor_t *, struct page *,
 struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc);
        int (*readpage)(struct file *, struct page *);
-       void (*sync_page)(struct page *);
 
        /* Write back some dirty pages from this mapping. */
        int (*writepages)(struct address_space *, struct writeback_control *);
@@ -662,9 +651,9 @@ struct address_space {
 
 struct block_device {
        dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
+       int                     bd_openers;
        struct inode *          bd_inode;       /* will die */
        struct super_block *    bd_super;
-       int                     bd_openers;
        struct mutex            bd_mutex;       /* open/close mutex */
        struct list_head        bd_inodes;
        void *                  bd_claiming;
@@ -1457,8 +1446,13 @@ enum {
 #define put_fs_excl() atomic_dec(&current->fs_excl)
 #define has_fs_excl() atomic_read(&current->fs_excl)
 
-#define is_owner_or_cap(inode) \
-       ((current_fsuid() == (inode)->i_uid) || capable(CAP_FOWNER))
+/*
+ * until VFS tracks user namespaces for inodes, just make all files
+ * belong to init_user_ns
+ */
+extern struct user_namespace init_user_ns;
+#define inode_userns(inode) (&init_user_ns)
+extern bool inode_owner_or_capable(const struct inode *inode);
 
 /* not quite ready to be deprecated, but... */
 extern void lock_super(struct super_block *);
@@ -1642,7 +1636,7 @@ struct super_operations {
 };
 
 /*
- * Inode state bits.  Protected by inode_lock.
+ * Inode state bits.  Protected by inode->i_lock
  *
  * Three bits determine the dirty state of the inode, I_DIRTY_SYNC,
  * I_DIRTY_DATASYNC and I_DIRTY_PAGES.
index c0d5f6945c1ebffcccc452da109e353b646a4b0c..d764a426e9fdbf5b5086542e3eeb6c6a2e6d3c8a 100644 (file)
@@ -109,7 +109,7 @@ struct hd_struct {
        int make_it_fail;
 #endif
        unsigned long stamp;
-       int in_flight[2];
+       atomic_t in_flight[2];
 #ifdef CONFIG_SMP
        struct disk_stats __percpu *dkstats;
 #else
@@ -370,21 +370,21 @@ static inline void free_part_stats(struct hd_struct *part)
 
 static inline void part_inc_in_flight(struct hd_struct *part, int rw)
 {
-       part->in_flight[rw]++;
+       atomic_inc(&part->in_flight[rw]);
        if (part->partno)
-               part_to_disk(part)->part0.in_flight[rw]++;
+               atomic_inc(&part_to_disk(part)->part0.in_flight[rw]);
 }
 
 static inline void part_dec_in_flight(struct hd_struct *part, int rw)
 {
-       part->in_flight[rw]--;
+       atomic_dec(&part->in_flight[rw]);
        if (part->partno)
-               part_to_disk(part)->part0.in_flight[rw]--;
+               atomic_dec(&part_to_disk(part)->part0.in_flight[rw]);
 }
 
 static inline int part_in_flight(struct hd_struct *part)
 {
-       return part->in_flight[0] + part->in_flight[1];
+       return atomic_read(&part->in_flight[0]) + atomic_read(&part->in_flight[1]);
 }
 
 static inline struct partition_meta_info *alloc_part_info(struct gendisk *disk)
index dca31761b3110e92f5a0e28e47cef0c60d910cef..bfb8f934521e02b313cc1a497ec08850ac3493c1 100644 (file)
@@ -35,6 +35,7 @@ struct vm_area_struct;
 #define ___GFP_NOTRACK         0
 #endif
 #define ___GFP_NO_KSWAPD       0x400000u
+#define ___GFP_OTHER_NODE      0x800000u
 
 /*
  * GFP bitmasks..
@@ -83,6 +84,7 @@ struct vm_area_struct;
 #define __GFP_NOTRACK  ((__force gfp_t)___GFP_NOTRACK)  /* Don't track with kmemcheck */
 
 #define __GFP_NO_KSWAPD        ((__force gfp_t)___GFP_NO_KSWAPD)
+#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
 
 /*
  * This may seem redundant, but it's a way of annotating false positives vs.
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
deleted file mode 100644 (file)
index 4bef5c5..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/*                                                                          */
-/* i2c-id.h - identifier values for i2c drivers and adapters                */
-/*                                                                          */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-1999 Simon G. Vogl
-
-    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_I2C_ID_H
-#define LINUX_I2C_ID_H
-
-/* Please note that I2C driver IDs are optional. They are only needed if a
-   legacy chip driver needs to identify a bus or a bus driver needs to
-   identify a legacy client. If you don't need them, just don't set them. */
-
-/*
- * ---- Adapter types ----------------------------------------------------
- */
-
-/* --- Bit algorithm adapters                                          */
-#define I2C_HW_B_CX2388x       0x01001b /* connexant 2388x based tv cards */
-
-#endif /* LINUX_I2C_ID_H */
index 06a8d9c7de98765c3b73e1093c346de452c0fbd5..f1e3ff5880a9f1d6d505f2e1102aeceef10fdb47 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/types.h>
 #ifdef __KERNEL__
 #include <linux/module.h>
-#include <linux/i2c-id.h>
 #include <linux/mod_devicetable.h>
 #include <linux/device.h>      /* for struct device */
 #include <linux/sched.h>       /* for completion */
@@ -105,8 +104,8 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
 /**
  * struct i2c_driver - represent an I2C device driver
  * @class: What kind of i2c device we instantiate (for detect)
- * @attach_adapter: Callback for bus addition (for legacy drivers)
- * @detach_adapter: Callback for bus removal (for legacy drivers)
+ * @attach_adapter: Callback for bus addition (deprecated)
+ * @detach_adapter: Callback for bus removal (deprecated)
  * @probe: Callback for device binding
  * @remove: Callback for device unbinding
  * @shutdown: Callback for device shutdown
@@ -144,11 +143,11 @@ struct i2c_driver {
        unsigned int class;
 
        /* Notifies the driver that a new bus has appeared or is about to be
-        * removed. You should avoid using this if you can, it will probably
-        * be removed in a near future.
+        * removed. You should avoid using this, it will be removed in a
+        * near future.
         */
-       int (*attach_adapter)(struct i2c_adapter *);
-       int (*detach_adapter)(struct i2c_adapter *);
+       int (*attach_adapter)(struct i2c_adapter *) __deprecated;
+       int (*detach_adapter)(struct i2c_adapter *) __deprecated;
 
        /* Standard driver model interfaces */
        int (*probe)(struct i2c_client *, const struct i2c_device_id *);
@@ -354,7 +353,6 @@ struct i2c_algorithm {
  */
 struct i2c_adapter {
        struct module *owner;
-       unsigned int id __deprecated;
        unsigned int class;               /* classes to allow probing for */
        const struct i2c_algorithm *algo; /* the algorithm to access the bus */
        void *algo_data;
@@ -396,6 +394,8 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
                return NULL;
 }
 
+int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
+
 /* Adapter locking functions, exported for shared pin cases */
 void i2c_lock_adapter(struct i2c_adapter *);
 void i2c_unlock_adapter(struct i2c_adapter *);
@@ -447,7 +447,7 @@ extern void i2c_release_client(struct i2c_client *client);
 extern void i2c_clients_command(struct i2c_adapter *adap,
                                unsigned int cmd, void *arg);
 
-extern struct i2c_adapter *i2c_get_adapter(int id);
+extern struct i2c_adapter *i2c_get_adapter(int nr);
 extern void i2c_put_adapter(struct i2c_adapter *adap);
 
 
diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
new file mode 100644 (file)
index 0000000..d5aa2a0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Platform Data for ADS1015 12-bit 4-input ADC
+ * (C) Copyright 2010
+ * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.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.
+ *
+ * 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_ADS1015_H
+#define LINUX_ADS1015_H
+
+#define ADS1015_CHANNELS 8
+
+struct ads1015_channel_data {
+       bool enabled;
+       unsigned int pga;
+       unsigned int data_rate;
+};
+
+struct ads1015_platform_data {
+       struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+};
+
+#endif /* LINUX_ADS1015_H */
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
new file mode 100644 (file)
index 0000000..f027f7a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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.
+ */
+
+#ifndef __LINUX_ATMEL_MXT_TS_H
+#define __LINUX_ATMEL_MXT_TS_H
+
+#include <linux/types.h>
+
+/* Orient */
+#define MXT_NORMAL             0x0
+#define MXT_DIAGONAL           0x1
+#define MXT_HORIZONTAL_FLIP    0x2
+#define MXT_ROTATED_90_COUNTER 0x3
+#define MXT_VERTICAL_FLIP      0x4
+#define MXT_ROTATED_90         0x5
+#define MXT_ROTATED_180                0x6
+#define MXT_DIAGONAL_COUNTER   0x7
+
+/* The platform data for the Atmel maXTouch touchscreen driver */
+struct mxt_platform_data {
+       const u8 *config;
+       size_t config_length;
+
+       unsigned int x_line;
+       unsigned int y_line;
+       unsigned int x_size;
+       unsigned int y_size;
+       unsigned int blen;
+       unsigned int threshold;
+       unsigned int voltage;
+       unsigned char orient;
+       unsigned long irqflags;
+};
+
+#endif /* __LINUX_ATMEL_MXT_TS_H */
index 725ae7c313ff3914ecd077df1e33b2c2a8e8b7d2..61bb18a4fd3c9946a19d90ea293f1d966042c0a4 100644 (file)
@@ -18,6 +18,7 @@
 #define MCS_KEY_CODE(v)                ((v) & 0xffff)
 
 struct mcs_platform_data {
+       void (*poweron)(bool);
        void (*cfg_pin)(void);
 
        /* touchscreen */
diff --git a/include/linux/i2c/pxa-i2c.h b/include/linux/i2c/pxa-i2c.h
new file mode 100644 (file)
index 0000000..1a9f65e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  i2c_pxa.h
+ *
+ *  Copyright (C) 2002 Intrinsyc Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+#ifndef _I2C_PXA_H_
+#define _I2C_PXA_H_
+
+#if 0
+#define DEF_TIMEOUT             3
+#else
+/* need a longer timeout if we're dealing with the fact we may well be
+ * looking at a multi-master environment
+*/
+#define DEF_TIMEOUT             32
+#endif
+
+#define BUS_ERROR               (-EREMOTEIO)
+#define XFER_NAKED              (-ECONNREFUSED)
+#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
+
+/* ICR initialize bit values
+*
+*  15. FM       0 (100 Khz operation)
+*  14. UR       0 (No unit reset)
+*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
+*                                       matching its slave address)
+*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
+*                                       in master mode)
+*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
+*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
+*  9.  IRFIE    1 (Enable interrupts from full buffer received)
+*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
+*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
+*  6.  IUE      0 (Disable unit until we change settings)
+*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
+*  4.  MA       0 (Only send stop with the ICR stop bit)
+*  3.  TB       0 (We are not transmitting a byte initially)
+*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
+*  1.  STOP     0 (Do not send a STOP)
+*  0.  START    0 (Do not send a START)
+*
+*/
+#define I2C_ICR_INIT   (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+
+/* I2C status register init values
+ *
+ * 10. BED      1 (Clear bus error detected)
+ * 9.  SAD      1 (Clear slave address detected)
+ * 7.  IRF      1 (Clear IDBR Receive Full)
+ * 6.  ITE      1 (Clear IDBR Transmit Empty)
+ * 5.  ALD      1 (Clear Arbitration Loss Detected)
+ * 4.  SSD      1 (Clear Slave Stop Detected)
+ */
+#define I2C_ISR_INIT   0x7FF  /* status register init */
+
+struct i2c_slave_client;
+
+struct i2c_pxa_platform_data {
+       unsigned int            slave_addr;
+       struct i2c_slave_client *slave;
+       unsigned int            class;
+       unsigned int            use_pio :1;
+       unsigned int            fast_mode :1;
+};
+
+extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
+
+#ifdef CONFIG_PXA27x
+extern void pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
+#ifdef CONFIG_PXA3xx
+extern void pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info);
+#endif
+
+#endif
diff --git a/include/linux/i2c/qt602240_ts.h b/include/linux/i2c/qt602240_ts.h
deleted file mode 100644 (file)
index c5033e1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * AT42QT602240/ATMXT224 Touchscreen driver
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.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.
- */
-
-#ifndef __LINUX_QT602240_TS_H
-#define __LINUX_QT602240_TS_H
-
-/* Orient */
-#define QT602240_NORMAL                        0x0
-#define QT602240_DIAGONAL              0x1
-#define QT602240_HORIZONTAL_FLIP       0x2
-#define QT602240_ROTATED_90_COUNTER    0x3
-#define QT602240_VERTICAL_FLIP         0x4
-#define QT602240_ROTATED_90            0x5
-#define QT602240_ROTATED_180           0x6
-#define QT602240_DIAGONAL_COUNTER      0x7
-
-/* The platform data for the AT42QT602240/ATMXT224 touchscreen driver */
-struct qt602240_platform_data {
-       unsigned int x_line;
-       unsigned int y_line;
-       unsigned int x_size;
-       unsigned int y_size;
-       unsigned int blen;
-       unsigned int threshold;
-       unsigned int voltage;
-       unsigned char orient;
-};
-
-#endif /* __LINUX_QT602240_TS_H */
index 58afd9d2c438ea323cc6255c1c87057f85d8bd15..0c0d1ae79981f90e48fa71eea442a8d06026c7f1 100644 (file)
@@ -698,6 +698,7 @@ struct twl4030_platform_data {
        struct regulator_init_data              *vana;
        struct regulator_init_data              *vcxio;
        struct regulator_init_data              *vusb;
+       struct regulator_init_data              *clk32kg;
 };
 
 /*----------------------------------------------------------------------*/
@@ -777,5 +778,6 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
 
 /* INTERNAL LDOs */
 #define TWL6030_REG_VRTC       47
+#define TWL6030_REG_CLK32KG    48
 
 #endif /* End of __TWL4030_H */
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
new file mode 100644 (file)
index 0000000..6427d29
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * twl4030_madc.h - Header for TWL4030 MADC
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _TWL4030_MADC_H
+#define _TWL4030_MADC_H
+
+struct twl4030_madc_conversion_method {
+       u8 sel;
+       u8 avg;
+       u8 rbase;
+       u8 ctrl;
+};
+
+#define TWL4030_MADC_MAX_CHANNELS 16
+
+
+/*
+ * twl4030_madc_request- madc request packet for channel conversion
+ * @channels:  16 bit bitmap for individual channels
+ * @do_avgP:   sample the input channel for 4 consecutive cycles
+ * @method:    RT, SW1, SW2
+ * @type:      Polling or interrupt based method
+ */
+
+struct twl4030_madc_request {
+       unsigned long channels;
+       u16 do_avg;
+       u16 method;
+       u16 type;
+       bool active;
+       bool result_pending;
+       int rbuf[TWL4030_MADC_MAX_CHANNELS];
+       void (*func_cb)(int len, int channels, int *buf);
+};
+
+enum conversion_methods {
+       TWL4030_MADC_RT,
+       TWL4030_MADC_SW1,
+       TWL4030_MADC_SW2,
+       TWL4030_MADC_NUM_METHODS
+};
+
+enum sample_type {
+       TWL4030_MADC_WAIT,
+       TWL4030_MADC_IRQ_ONESHOT,
+       TWL4030_MADC_IRQ_REARM
+};
+
+#define TWL4030_MADC_CTRL1             0x00
+#define TWL4030_MADC_CTRL2             0x01
+
+#define TWL4030_MADC_RTSELECT_LSB      0x02
+#define TWL4030_MADC_SW1SELECT_LSB     0x06
+#define TWL4030_MADC_SW2SELECT_LSB     0x0A
+
+#define TWL4030_MADC_RTAVERAGE_LSB     0x04
+#define TWL4030_MADC_SW1AVERAGE_LSB    0x08
+#define TWL4030_MADC_SW2AVERAGE_LSB    0x0C
+
+#define TWL4030_MADC_CTRL_SW1          0x12
+#define TWL4030_MADC_CTRL_SW2          0x13
+
+#define TWL4030_MADC_RTCH0_LSB         0x17
+#define TWL4030_MADC_GPCH0_LSB         0x37
+
+#define TWL4030_MADC_MADCON    (1 << 0)        /* MADC power on */
+#define TWL4030_MADC_BUSY      (1 << 0)        /* MADC busy */
+/* MADC conversion completion */
+#define TWL4030_MADC_EOC_SW    (1 << 1)
+/* MADC SWx start conversion */
+#define TWL4030_MADC_SW_START  (1 << 5)
+#define TWL4030_MADC_ADCIN0    (1 << 0)
+#define TWL4030_MADC_ADCIN1    (1 << 1)
+#define TWL4030_MADC_ADCIN2    (1 << 2)
+#define TWL4030_MADC_ADCIN3    (1 << 3)
+#define TWL4030_MADC_ADCIN4    (1 << 4)
+#define TWL4030_MADC_ADCIN5    (1 << 5)
+#define TWL4030_MADC_ADCIN6    (1 << 6)
+#define TWL4030_MADC_ADCIN7    (1 << 7)
+#define TWL4030_MADC_ADCIN8    (1 << 8)
+#define TWL4030_MADC_ADCIN9    (1 << 9)
+#define TWL4030_MADC_ADCIN10   (1 << 10)
+#define TWL4030_MADC_ADCIN11   (1 << 11)
+#define TWL4030_MADC_ADCIN12   (1 << 12)
+#define TWL4030_MADC_ADCIN13   (1 << 13)
+#define TWL4030_MADC_ADCIN14   (1 << 14)
+#define TWL4030_MADC_ADCIN15   (1 << 15)
+
+/* Fixed channels */
+#define TWL4030_MADC_BTEMP     TWL4030_MADC_ADCIN1
+#define TWL4030_MADC_VBUS      TWL4030_MADC_ADCIN8
+#define TWL4030_MADC_VBKB      TWL4030_MADC_ADCIN9
+#define TWL4030_MADC_ICHG      TWL4030_MADC_ADCIN10
+#define TWL4030_MADC_VCHG      TWL4030_MADC_ADCIN11
+#define TWL4030_MADC_VBAT      TWL4030_MADC_ADCIN12
+
+/* Step size and prescaler ratio */
+#define TEMP_STEP_SIZE          147
+#define TEMP_PSR_R              100
+#define CURR_STEP_SIZE         147
+#define CURR_PSR_R1            44
+#define CURR_PSR_R2            88
+
+#define TWL4030_BCI_BCICTL1    0x23
+#define TWL4030_BCI_CGAIN      0x020
+#define TWL4030_BCI_MESBAT     (1 << 1)
+#define TWL4030_BCI_TYPEN      (1 << 4)
+#define TWL4030_BCI_ITHEN      (1 << 3)
+
+#define REG_BCICTL2             0x024
+#define TWL4030_BCI_ITHSENS    0x007
+
+struct twl4030_madc_user_parms {
+       int channel;
+       int average;
+       int status;
+       u16 result;
+};
+
+int twl4030_madc_conversion(struct twl4030_madc_request *conv);
+int twl4030_get_madc_conversion(int channel_no);
+#endif
index 5e3dddf8f562651f488dd4b3061fbfefabb98f7a..ce0b72464eb814bf5902e3daf423522934963b8c 100644 (file)
  * @poll: driver-supplied method that polls the device and posts
  *     input events (mandatory).
  * @poll_interval: specifies how often the poll() method should be called.
- *     Defaults to 500 msec unless overriden when registering the device.
+ *     Defaults to 500 msec unless overridden when registering the device.
  * @poll_interval_max: specifies upper bound for the poll interval.
  *     Defaults to the initial value of @poll_interval.
  * @poll_interval_min: specifies lower bound for the poll interval.
  *     Defaults to 0.
- * @input: input device structire associated with the polled device.
+ * @input: input device structure associated with the polled device.
  *     Must be properly initialized by the driver (id, name, phys, bits).
  *
  * Polled input device provides a skeleton for supporting simple input
index e428382ca28a59aac1a16f1f5926f28a3c7fb24b..056ae8a5bd9b8bb3424c431ff60bcc22c155b4da 100644 (file)
@@ -1154,8 +1154,6 @@ struct ff_effect {
  *     sparse keymaps. If not supplied default mechanism will be used.
  *     The method is being called while holding event_lock and thus must
  *     not sleep
- * @getkeycode_new: transition method
- * @setkeycode_new: transition method
  * @ff: force feedback structure associated with the device if device
  *     supports force feedback effects
  * @repeat_key: stores key code of the last key pressed; used to implement
@@ -1234,14 +1232,10 @@ struct input_dev {
        void *keycode;
 
        int (*setkeycode)(struct input_dev *dev,
-                         unsigned int scancode, unsigned int keycode);
+                         const struct input_keymap_entry *ke,
+                         unsigned int *old_keycode);
        int (*getkeycode)(struct input_dev *dev,
-                         unsigned int scancode, unsigned int *keycode);
-       int (*setkeycode_new)(struct input_dev *dev,
-                             const struct input_keymap_entry *ke,
-                             unsigned int *old_keycode);
-       int (*getkeycode_new)(struct input_dev *dev,
-                             struct input_keymap_entry *ke);
+                         struct input_keymap_entry *ke);
 
        struct ff_device *ff;
 
index 51952989ad426dd19deef978f68ea4f7b123ec5c..a6d1655f9607de872a10fecaa744e38412c8edb2 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/idr.h>
 #include <linux/rwsem.h>
 #include <linux/notifier.h>
+#include <linux/nsproxy.h>
 
 /*
  * ipc namespace events
@@ -15,6 +16,7 @@
 
 #define IPCNS_CALLBACK_PRI 0
 
+struct user_namespace;
 
 struct ipc_ids {
        int in_use;
@@ -56,6 +58,8 @@ struct ipc_namespace {
        unsigned int    mq_msg_max;      /* initialized to DFLT_MSGMAX */
        unsigned int    mq_msgsize_max;  /* initialized to DFLT_MSGSIZEMAX */
 
+       /* user_ns which owns the ipc ns */
+       struct user_namespace *user_ns;
 };
 
 extern struct ipc_namespace init_ipc_ns;
@@ -90,7 +94,7 @@ static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; }
 
 #if defined(CONFIG_IPC_NS)
 extern struct ipc_namespace *copy_ipcs(unsigned long flags,
-                                      struct ipc_namespace *ns);
+                                      struct task_struct *tsk);
 static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
 {
        if (ns)
@@ -101,12 +105,12 @@ static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
 extern void put_ipc_ns(struct ipc_namespace *ns);
 #else
 static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
-               struct ipc_namespace *ns)
+                                             struct task_struct *tsk)
 {
        if (flags & CLONE_NEWIPC)
                return ERR_PTR(-EINVAL);
 
-       return ns;
+       return tsk->nsproxy->ipc_ns;
 }
 
 static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
index 1d3577f30d45f62c55ef18f12eb6204b7f0dd1e9..5d876c9b3a3dc0343ac38605f88797df319958da 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/ptrace.h>
 #include <asm/irq_regs.h>
 
+struct seq_file;
 struct irq_desc;
 struct irq_data;
 typedef        void (*irq_flow_handler_t)(unsigned int irq,
@@ -270,6 +271,7 @@ static inline bool irqd_can_move_in_process_context(struct irq_data *d)
  * @irq_set_wake:      enable/disable power-management wake-on of an IRQ
  * @irq_bus_lock:      function to lock access to slow bus (i2c) chips
  * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
+ * @irq_print_chip:    optional to print special chip info in show_interrupts
  * @flags:             chip specific flags
  *
  * @release:           release function solely used by UML
@@ -317,6 +319,8 @@ struct irq_chip {
        void            (*irq_bus_lock)(struct irq_data *data);
        void            (*irq_bus_sync_unlock)(struct irq_data *data);
 
+       void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
+
        unsigned long   flags;
 
        /* Currently used only by UML, might disappear one day.*/
index 00218371518b0830328f6c089b3d5df0df471d4c..15e6c3905f41625dc20bcf761365b2cc8aa48620 100644 (file)
@@ -100,13 +100,6 @@ struct irq_desc {
 extern struct irq_desc irq_desc[NR_IRQS];
 #endif
 
-/* Will be removed once the last users in power and sh are gone */
-extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node);
-static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
-{
-       return desc;
-}
-
 #ifdef CONFIG_GENERIC_HARDIRQS
 
 static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc)
@@ -178,24 +171,52 @@ static inline int irq_has_action(unsigned int irq)
        return desc->action != NULL;
 }
 
-#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
-static inline int irq_balancing_disabled(unsigned int irq)
+/* caller has locked the irq_desc and both params are valid */
+static inline void __irq_set_handler_locked(unsigned int irq,
+                                           irq_flow_handler_t handler)
 {
        struct irq_desc *desc;
 
        desc = irq_to_desc(irq);
-       return desc->status & IRQ_NO_BALANCING_MASK;
+       desc->handle_irq = handler;
 }
-#endif
 
 /* caller has locked the irq_desc and both params are valid */
+static inline void
+__irq_set_chip_handler_name_locked(unsigned int irq, struct irq_chip *chip,
+                                  irq_flow_handler_t handler, const char *name)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       irq_desc_get_irq_data(desc)->chip = chip;
+       desc->handle_irq = handler;
+       desc->name = name;
+}
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
 static inline void __set_irq_handler_unlocked(int irq,
                                              irq_flow_handler_t handler)
+{
+       __irq_set_handler_locked(irq, handler);
+}
+
+static inline int irq_balancing_disabled(unsigned int irq)
 {
        struct irq_desc *desc;
 
        desc = irq_to_desc(irq);
-       desc->handle_irq = handler;
+       return desc->status & IRQ_NO_BALANCING_MASK;
+}
+#endif
+
+static inline void
+irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc)
+               lockdep_set_class(&desc->lock, class);
 }
 
 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
index 27e79c27ba0869685d128a6b31377601a4585598..a32dcaec04e147917a3e085a5e83146189782336 100644 (file)
@@ -432,13 +432,35 @@ struct jbd2_journal_handle
        int                     h_err;
 
        /* Flags [no locking] */
-       unsigned int    h_sync:         1;      /* sync-on-close */
-       unsigned int    h_jdata:        1;      /* force data journaling */
-       unsigned int    h_aborted:      1;      /* fatal error on handle */
+       unsigned int    h_sync:1;       /* sync-on-close */
+       unsigned int    h_jdata:1;      /* force data journaling */
+       unsigned int    h_aborted:1;    /* fatal error on handle */
+       unsigned int    h_cowing:1;     /* COWing block to snapshot */
+
+       /* Number of buffers requested by user:
+        * (before adding the COW credits factor) */
+       unsigned int    h_base_credits:14;
+
+       /* Number of buffers the user is allowed to dirty:
+        * (counts only buffers dirtied when !h_cowing) */
+       unsigned int    h_user_credits:14;
+
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        struct lockdep_map      h_lockdep_map;
 #endif
+
+#ifdef CONFIG_JBD2_DEBUG
+       /* COW debugging counters: */
+       unsigned int h_cow_moved; /* blocks moved to snapshot */
+       unsigned int h_cow_copied; /* blocks copied to snapshot */
+       unsigned int h_cow_ok_jh; /* blocks already COWed during current
+                                    transaction */
+       unsigned int h_cow_ok_bitmap; /* blocks not set in COW bitmap */
+       unsigned int h_cow_ok_mapped;/* blocks already mapped in snapshot */
+       unsigned int h_cow_bitmaps; /* COW bitmaps created */
+       unsigned int h_cow_excluded; /* blocks set in exclude bitmap */
+#endif
 };
 
 
index 525aac3c97dfeca86b1a6801d07aec59c9e8599d..44e95d0a721f1eb50db7e41df52a15403ddf814d 100644 (file)
@@ -40,6 +40,13 @@ struct journal_head {
         */
        unsigned b_modified;
 
+       /*
+        * This feild tracks the last transaction id in which this buffer
+        * has been cowed
+        * [jbd_lock_bh_state()]
+        */
+       unsigned b_cow_tid;
+
        /*
         * Copy of the buffer data frozen for writing to the log.
         * [jbd_lock_bh_state()]
index d8e9b3d1c23c3b698081c669e07484496d54960b..0df513b7a9f8670674a491338852d9a5570f5186 100644 (file)
@@ -36,6 +36,7 @@ const char *kallsyms_lookup(unsigned long addr,
 
 /* Look up a kernel symbol and return it in a text buffer. */
 extern int sprint_symbol(char *buffer, unsigned long address);
+extern int sprint_backtrace(char *buffer, unsigned long address);
 
 /* Look up a kernel symbol and print it to the kernel messages. */
 extern void __print_symbol(const char *fmt, unsigned long address);
@@ -79,6 +80,12 @@ static inline int sprint_symbol(char *buffer, unsigned long addr)
        return 0;
 }
 
+static inline int sprint_backtrace(char *buffer, unsigned long addr)
+{
+       *buffer = '\0';
+       return 0;
+}
+
 static inline int lookup_symbol_name(unsigned long addr, char *symname)
 {
        return -ERANGE;
index 4b0761cc7dd9d448ee22d6a9252405b83e1ef315..ec2d17bc1f1eaeccc4d7971d0643fba6d380b737 100644 (file)
@@ -159,7 +159,7 @@ static inline void con_schedule_flip(struct tty_struct *t)
        if (t->buf.tail != NULL)
                t->buf.tail->commit = t->buf.tail->used;
        spin_unlock_irqrestore(&t->buf.lock, flags);
-       schedule_delayed_work(&t->buf.work, 0);
+       schedule_work(&t->buf.work);
 }
 
 #endif
index 2fe6e84894a4bc10006511bbbb67b15d8197958d..00cec4dc0ae25a3cf6ac57bebcc239d145b8d641 100644 (file)
@@ -187,14 +187,76 @@ NORET_TYPE void do_exit(long error_code)
        ATTRIB_NORET;
 NORET_TYPE void complete_and_exit(struct completion *, long)
        ATTRIB_NORET;
+
+/* Internal, do not use. */
+int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
+int __must_check _kstrtol(const char *s, unsigned int base, long *res);
+
+int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res);
+int __must_check kstrtoll(const char *s, unsigned int base, long long *res);
+static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
+{
+       /*
+        * We want to shortcut function call, but
+        * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
+        */
+       if (sizeof(unsigned long) == sizeof(unsigned long long) &&
+           __alignof__(unsigned long) == __alignof__(unsigned long long))
+               return kstrtoull(s, base, (unsigned long long *)res);
+       else
+               return _kstrtoul(s, base, res);
+}
+
+static inline int __must_check kstrtol(const char *s, unsigned int base, long *res)
+{
+       /*
+        * We want to shortcut function call, but
+        * __builtin_types_compatible_p(long, long long) = 0.
+        */
+       if (sizeof(long) == sizeof(long long) &&
+           __alignof__(long) == __alignof__(long long))
+               return kstrtoll(s, base, (long long *)res);
+       else
+               return _kstrtol(s, base, res);
+}
+
+int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res);
+int __must_check kstrtoint(const char *s, unsigned int base, int *res);
+
+static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res)
+{
+       return kstrtoull(s, base, res);
+}
+
+static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res)
+{
+       return kstrtoll(s, base, res);
+}
+
+static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res)
+{
+       return kstrtouint(s, base, res);
+}
+
+static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res)
+{
+       return kstrtoint(s, base, res);
+}
+
+int __must_check kstrtou16(const char *s, unsigned int base, u16 *res);
+int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
+int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
+int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
+
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
 extern long long simple_strtoll(const char *,char **,unsigned int);
-extern int __must_check strict_strtoul(const char *, unsigned int, unsigned long *);
-extern int __must_check strict_strtol(const char *, unsigned int, long *);
-extern int __must_check strict_strtoull(const char *, unsigned int, unsigned long long *);
-extern int __must_check strict_strtoll(const char *, unsigned int, long long *);
+#define strict_strtoul kstrtoul
+#define strict_strtol  kstrtol
+#define strict_strtoull        kstrtoull
+#define strict_strtoll kstrtoll
+
 extern int sprintf(char * buf, const char * fmt, ...)
        __attribute__ ((format (printf, 2, 3)));
 extern int vsprintf(char *buf, const char *, va_list)
index 092e4250a4583f735140221d5f4dd7a4667d3d69..10ca03d0a250e280682479c4228536120c2cee4f 100644 (file)
@@ -297,6 +297,7 @@ extern int
 kgdb_handle_exception(int ex_vector, int signo, int err_code,
                      struct pt_regs *regs);
 extern int kgdb_nmicallback(int cpu, void *regs);
+extern void gdbstub_exit(int status);
 
 extern int                     kgdb_single_step;
 extern atomic_t                        kgdb_active;
index 7ff16f7d3ed41530a9c67cdaa2bc5bbf2c609f87..1e923e5e88e81cdc83c8455eefb776eb1b5de588 100644 (file)
@@ -4,10 +4,15 @@
 #include <linux/err.h>
 #include <linux/sched.h>
 
-struct task_struct *kthread_create(int (*threadfn)(void *data),
-                                  void *data,
-                                  const char namefmt[], ...)
-       __attribute__((format(printf, 3, 4)));
+struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
+                                          void *data,
+                                          int node,
+                                          const char namefmt[], ...)
+       __attribute__((format(printf, 4, 5)));
+
+#define kthread_create(threadfn, data, namefmt, arg...) \
+       kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
+
 
 /**
  * kthread_run - create and wake a thread.
@@ -34,6 +39,7 @@ void *kthread_data(struct task_struct *k);
 
 int kthreadd(void *unused);
 extern struct task_struct *kthreadd_task;
+extern int tsk_fork_get_node(struct task_struct *tsk);
 
 /*
  * Simple work processor based on kthread.
diff --git a/include/linux/led-lm3530.h b/include/linux/led-lm3530.h
new file mode 100644 (file)
index 0000000..bb69d20
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 ST-Ericsson SA.
+ * Copyright (C) 2009 Motorola, Inc.
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Simple driver for National Semiconductor LM35330 Backlight driver chip
+ *
+ * Author: Shreshtha Kumar SAHU <shreshthakumar.sahu@stericsson.com>
+ * based on leds-lm3530.c by Dan Murphy <D.Murphy@motorola.com>
+ */
+
+#ifndef _LINUX_LED_LM3530_H__
+#define _LINUX_LED_LM3530_H__
+
+#define LM3530_FS_CURR_5mA             (0) /* Full Scale Current */
+#define LM3530_FS_CURR_8mA             (1)
+#define LM3530_FS_CURR_12mA            (2)
+#define LM3530_FS_CURR_15mA            (3)
+#define LM3530_FS_CURR_19mA            (4)
+#define LM3530_FS_CURR_22mA            (5)
+#define LM3530_FS_CURR_26mA            (6)
+#define LM3530_FS_CURR_29mA            (7)
+
+#define LM3530_ALS_AVRG_TIME_32ms      (0) /* ALS Averaging Time */
+#define LM3530_ALS_AVRG_TIME_64ms      (1)
+#define LM3530_ALS_AVRG_TIME_128ms     (2)
+#define LM3530_ALS_AVRG_TIME_256ms     (3)
+#define LM3530_ALS_AVRG_TIME_512ms     (4)
+#define LM3530_ALS_AVRG_TIME_1024ms    (5)
+#define LM3530_ALS_AVRG_TIME_2048ms    (6)
+#define LM3530_ALS_AVRG_TIME_4096ms    (7)
+
+#define LM3530_RAMP_TIME_1ms           (0) /* Brigtness Ramp Time */
+#define LM3530_RAMP_TIME_130ms         (1) /* Max to 0 and vice versa */
+#define LM3530_RAMP_TIME_260ms         (2)
+#define LM3530_RAMP_TIME_520ms         (3)
+#define LM3530_RAMP_TIME_1s            (4)
+#define LM3530_RAMP_TIME_2s            (5)
+#define LM3530_RAMP_TIME_4s            (6)
+#define LM3530_RAMP_TIME_8s            (7)
+
+/* ALS Resistor Select */
+#define LM3530_ALS_IMPD_Z              (0x00) /* ALS Impedence */
+#define LM3530_ALS_IMPD_13_53kOhm      (0x01)
+#define LM3530_ALS_IMPD_9_01kOhm       (0x02)
+#define LM3530_ALS_IMPD_5_41kOhm       (0x03)
+#define LM3530_ALS_IMPD_2_27kOhm       (0x04)
+#define LM3530_ALS_IMPD_1_94kOhm       (0x05)
+#define LM3530_ALS_IMPD_1_81kOhm       (0x06)
+#define LM3530_ALS_IMPD_1_6kOhm                (0x07)
+#define LM3530_ALS_IMPD_1_138kOhm      (0x08)
+#define LM3530_ALS_IMPD_1_05kOhm       (0x09)
+#define LM3530_ALS_IMPD_1_011kOhm      (0x0A)
+#define LM3530_ALS_IMPD_941Ohm         (0x0B)
+#define LM3530_ALS_IMPD_759Ohm         (0x0C)
+#define LM3530_ALS_IMPD_719Ohm         (0x0D)
+#define LM3530_ALS_IMPD_700Ohm         (0x0E)
+#define LM3530_ALS_IMPD_667Ohm         (0x0F)
+
+enum lm3530_mode {
+       LM3530_BL_MODE_MANUAL = 0,      /* "man" */
+       LM3530_BL_MODE_ALS,             /* "als" */
+       LM3530_BL_MODE_PWM,             /* "pwm" */
+};
+
+/* ALS input select */
+enum lm3530_als_mode {
+       LM3530_INPUT_AVRG = 0,  /* ALS1 and ALS2 input average */
+       LM3530_INPUT_ALS1,      /* ALS1 Input */
+       LM3530_INPUT_ALS2,      /* ALS2 Input */
+       LM3530_INPUT_CEIL,      /* Max of ALS1 and ALS2 */
+};
+
+/**
+ * struct lm3530_platform_data
+ * @mode: mode of operation i.e. Manual, ALS or PWM
+ * @als_input_mode: select source of ALS input - ALS1/2 or average
+ * @max_current: full scale LED current
+ * @pwm_pol_hi: PWM input polarity - active high/active low
+ * @als_avrg_time: ALS input averaging time
+ * @brt_ramp_law: brightness mapping mode - exponential/linear
+ * @brt_ramp_fall: rate of fall of led current
+ * @brt_ramp_rise: rate of rise of led current
+ * @als1_resistor_sel: internal resistance from ALS1 input to ground
+ * @als2_resistor_sel: internal resistance from ALS2 input to ground
+ * @brt_val: brightness value (0-255)
+ */
+struct lm3530_platform_data {
+       enum lm3530_mode mode;
+       enum lm3530_als_mode als_input_mode;
+
+       u8 max_current;
+       bool pwm_pol_hi;
+       u8 als_avrg_time;
+
+       bool brt_ramp_law;
+       u8 brt_ramp_fall;
+       u8 brt_ramp_rise;
+
+       u8 als1_resistor_sel;
+       u8 als2_resistor_sel;
+
+       u8 brt_val;
+};
+
+#endif /* _LINUX_LED_LM3530_H__ */
index 0f19df9e37b0fec0394d0350abf86a3aa63cc518..61e0340a4b770c3675787130afdc8174eb902262 100644 (file)
@@ -145,6 +145,9 @@ extern void led_trigger_register_simple(const char *name,
 extern void led_trigger_unregister_simple(struct led_trigger *trigger);
 extern void led_trigger_event(struct led_trigger *trigger,
                                enum led_brightness event);
+extern void led_trigger_blink(struct led_trigger *trigger,
+                             unsigned long *delay_on,
+                             unsigned long *delay_off);
 
 #else
 
@@ -194,11 +197,11 @@ struct gpio_led {
 
 struct gpio_led_platform_data {
        int             num_leds;
-       struct gpio_led *leds;
+       const struct gpio_led *leds;
 
 #define GPIO_LED_NO_BLINK_LOW  0       /* No blink GPIO state low */
 #define GPIO_LED_NO_BLINK_HIGH 1       /* No blink GPIO state high */
-#define GPIO_LED_BLINK         2       /* Plase, blink */
+#define GPIO_LED_BLINK         2       /* Please, blink */
        int             (*gpio_blink_set)(unsigned gpio, int state,
                                        unsigned long *delay_on,
                                        unsigned long *delay_off);
index 6cfe344f9559604d4037b005860dfc279833ac99..1e5df2af8d845c6a2ff63115245c88cba4a95cdc 100644 (file)
@@ -23,6 +23,7 @@
 #define XENFS_SUPER_MAGIC      0xabba1974
 #define EXT4_SUPER_MAGIC       0xEF53
 #define BTRFS_SUPER_MAGIC      0x9123683E
+#define NILFS_SUPER_MAGIC      0x3434
 #define HPFS_SUPER_MAGIC       0xf995e849
 #define ISOFS_SUPER_MAGIC      0x9660
 #define JFFS2_SUPER_MAGIC      0x72b6
diff --git a/include/linux/media.h b/include/linux/media.h
new file mode 100644 (file)
index 0000000..0ef8833
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Multimedia device API
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MEDIA_H
+#define __LINUX_MEDIA_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#define MEDIA_API_VERSION      KERNEL_VERSION(0, 1, 0)
+
+struct media_device_info {
+       char driver[16];
+       char model[32];
+       char serial[40];
+       char bus_info[32];
+       __u32 media_version;
+       __u32 hw_revision;
+       __u32 driver_version;
+       __u32 reserved[31];
+};
+
+#define MEDIA_ENT_ID_FLAG_NEXT         (1 << 31)
+
+#define MEDIA_ENT_TYPE_SHIFT           16
+#define MEDIA_ENT_TYPE_MASK            0x00ff0000
+#define MEDIA_ENT_SUBTYPE_MASK         0x0000ffff
+
+#define MEDIA_ENT_T_DEVNODE            (1 << MEDIA_ENT_TYPE_SHIFT)
+#define MEDIA_ENT_T_DEVNODE_V4L                (MEDIA_ENT_T_DEVNODE + 1)
+#define MEDIA_ENT_T_DEVNODE_FB         (MEDIA_ENT_T_DEVNODE + 2)
+#define MEDIA_ENT_T_DEVNODE_ALSA       (MEDIA_ENT_T_DEVNODE + 3)
+#define MEDIA_ENT_T_DEVNODE_DVB                (MEDIA_ENT_T_DEVNODE + 4)
+
+#define MEDIA_ENT_T_V4L2_SUBDEV                (2 << MEDIA_ENT_TYPE_SHIFT)
+#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
+#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH  (MEDIA_ENT_T_V4L2_SUBDEV + 2)
+#define MEDIA_ENT_T_V4L2_SUBDEV_LENS   (MEDIA_ENT_T_V4L2_SUBDEV + 3)
+
+#define MEDIA_ENT_FL_DEFAULT           (1 << 0)
+
+struct media_entity_desc {
+       __u32 id;
+       char name[32];
+       __u32 type;
+       __u32 revision;
+       __u32 flags;
+       __u32 group_id;
+       __u16 pads;
+       __u16 links;
+
+       __u32 reserved[4];
+
+       union {
+               /* Node specifications */
+               struct {
+                       __u32 major;
+                       __u32 minor;
+               } v4l;
+               struct {
+                       __u32 major;
+                       __u32 minor;
+               } fb;
+               struct {
+                       __u32 card;
+                       __u32 device;
+                       __u32 subdevice;
+               } alsa;
+               int dvb;
+
+               /* Sub-device specifications */
+               /* Nothing needed yet */
+               __u8 raw[184];
+       };
+};
+
+#define MEDIA_PAD_FL_SINK              (1 << 0)
+#define MEDIA_PAD_FL_SOURCE            (1 << 1)
+
+struct media_pad_desc {
+       __u32 entity;           /* entity ID */
+       __u16 index;            /* pad index */
+       __u32 flags;            /* pad flags */
+       __u32 reserved[2];
+};
+
+#define MEDIA_LNK_FL_ENABLED           (1 << 0)
+#define MEDIA_LNK_FL_IMMUTABLE         (1 << 1)
+#define MEDIA_LNK_FL_DYNAMIC           (1 << 2)
+
+struct media_link_desc {
+       struct media_pad_desc source;
+       struct media_pad_desc sink;
+       __u32 flags;
+       __u32 reserved[2];
+};
+
+struct media_links_enum {
+       __u32 entity;
+       /* Should have enough room for pads elements */
+       struct media_pad_desc __user *pads;
+       /* Should have enough room for links elements */
+       struct media_link_desc __user *links;
+       __u32 reserved[4];
+};
+
+#define MEDIA_IOC_DEVICE_INFO          _IOWR('|', 0x00, struct media_device_info)
+#define MEDIA_IOC_ENUM_ENTITIES                _IOWR('|', 0x01, struct media_entity_desc)
+#define MEDIA_IOC_ENUM_LINKS           _IOWR('|', 0x02, struct media_links_enum)
+#define MEDIA_IOC_SETUP_LINK           _IOWR('|', 0x03, struct media_link_desc)
+
+#endif /* __LINUX_MEDIA_H */
index f512e189be5a496b2aa1b555c1fd34e056fc81e6..5a5ce7055839b607ed688ba4c19c595b4686f875 100644 (file)
@@ -62,6 +62,7 @@ extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                        gfp_t gfp_mask);
 extern void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru);
 extern void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru);
+extern void mem_cgroup_rotate_reclaimable_page(struct page *page);
 extern void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru);
 extern void mem_cgroup_del_lru(struct page *page);
 extern void mem_cgroup_move_lists(struct page *page,
@@ -96,7 +97,7 @@ extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem);
 
 extern int
 mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr);
+       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask);
 extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
        struct page *oldpage, struct page *newpage, bool migration_ok);
 
@@ -150,6 +151,10 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *mem);
 void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
 #endif
 
+#ifdef CONFIG_DEBUG_VM
+bool mem_cgroup_bad_page_check(struct page *page);
+void mem_cgroup_print_bad_page(struct page *page);
+#endif
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct mem_cgroup;
 
@@ -211,6 +216,11 @@ static inline void mem_cgroup_del_lru_list(struct page *page, int lru)
        return ;
 }
 
+static inline inline void mem_cgroup_rotate_reclaimable_page(struct page *page)
+{
+       return ;
+}
+
 static inline void mem_cgroup_rotate_lru_list(struct page *page, int lru)
 {
        return ;
@@ -249,7 +259,7 @@ static inline struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem)
 
 static inline int
 mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
-       struct mem_cgroup **ptr)
+       struct mem_cgroup **ptr, gfp_t gfp_mask)
 {
        return 0;
 }
@@ -346,5 +356,18 @@ static inline void mem_cgroup_split_huge_fixup(struct page *head,
 
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
+#if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
+static inline bool
+mem_cgroup_bad_page_check(struct page *page)
+{
+       return false;
+}
+
+static inline void
+mem_cgroup_print_bad_page(struct page *page)
+{
+}
+#endif
+
 #endif /* _LINUX_MEMCONTROL_H */
 
index 4db1fbd8969ea3ee26b8214d8f89091e43ce02c7..8fba7972ff5f782f57c4db2609e70a847f308f89 100644 (file)
@@ -131,9 +131,11 @@ enum {
        PM8607_ID_LDO8,
        PM8607_ID_LDO9,
        PM8607_ID_LDO10,
+       PM8607_ID_LDO11,
        PM8607_ID_LDO12,
        PM8607_ID_LDO13,
        PM8607_ID_LDO14,
+       PM8607_ID_LDO15,
 
        PM8607_ID_RG_MAX,
 };
@@ -310,8 +312,6 @@ struct pm860x_chip {
 
 };
 
-#define PM8607_MAX_REGULATOR   PM8607_ID_RG_MAX        /* 3 Bucks, 13 LDOs */
-
 enum {
        GI2C_PORT = 0,
        PI2C_PORT,
@@ -351,23 +351,31 @@ struct pm860x_platform_data {
        struct pm860x_led_pdata         *led;
        struct pm860x_touch_pdata       *touch;
        struct pm860x_power_pdata       *power;
+       struct regulator_init_data      *regulator;
 
        unsigned short  companion_addr; /* I2C address of companion chip */
        int             i2c_port;       /* Controlled by GI2C or PI2C */
        int             irq_mode;       /* Clear interrupt by read/write(0/1) */
        int             irq_base;       /* IRQ base number of 88pm860x */
-       struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
+       int             num_leds;
+       int             num_backlights;
+       int             num_regulators;
 };
 
-extern char pm860x_backlight_name[][MFD_NAME_SIZE];
-extern char pm860x_led_name[][MFD_NAME_SIZE];
-
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
 extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *);
 extern int pm860x_set_bits(struct i2c_client *, int, unsigned char,
                           unsigned char);
+extern int pm860x_page_reg_read(struct i2c_client *, int);
+extern int pm860x_page_reg_write(struct i2c_client *, int, unsigned char);
+extern int pm860x_page_bulk_read(struct i2c_client *, int, int,
+                                unsigned char *);
+extern int pm860x_page_bulk_write(struct i2c_client *, int, int,
+                                 unsigned char *);
+extern int pm860x_page_set_bits(struct i2c_client *, int, unsigned char,
+                               unsigned char);
 
 extern int pm860x_device_init(struct pm860x_chip *chip,
                              struct pm860x_platform_data *pdata) __devinit ;
index 37f56b7c4c15e164d7a1c74dccd333e0d6ed215f..56f8dea721529cd0a979ea8e466a75470c70b4f3 100644 (file)
  * @dev: parent device
  * @lock: read/write operations lock
  * @irq_lock: genirq bus lock
- * @revision: chip revision
  * @irq: irq line
+ * @chip_id: chip revision id
  * @write: register write
  * @read: register read
  * @rx_buf: rx buf for SPI
@@ -124,7 +124,7 @@ struct ab8500 {
        struct device   *dev;
        struct mutex    lock;
        struct mutex    irq_lock;
-       int             revision;
+
        int             irq_base;
        int             irq;
        u8              chip_id;
diff --git a/include/linux/mfd/ab8500/gpadc.h b/include/linux/mfd/ab8500/gpadc.h
new file mode 100644 (file)
index 0000000..46b9540
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Licensed under GPLv2.
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ */
+
+#ifndef        _AB8500_GPADC_H
+#define _AB8500_GPADC_H
+
+/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
+#define BAT_CTRL       0x01
+#define BTEMP_BALL     0x02
+#define MAIN_CHARGER_V 0x03
+#define ACC_DETECT1    0x04
+#define ACC_DETECT2    0x05
+#define ADC_AUX1       0x06
+#define ADC_AUX2       0x07
+#define MAIN_BAT_V     0x08
+#define VBUS_V         0x09
+#define MAIN_CHARGER_C 0x0A
+#define USB_CHARGER_C  0x0B
+#define BK_BAT_V       0x0C
+#define DIE_TEMP       0x0D
+
+struct ab8500_gpadc;
+
+struct ab8500_gpadc *ab8500_gpadc_get(char *name);
+int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input);
+
+#endif /* _AB8500_GPADC_H */
diff --git a/include/linux/mfd/ab8500/sysctrl.h b/include/linux/mfd/ab8500/sysctrl.h
new file mode 100644 (file)
index 0000000..10da029
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __AB8500_SYSCTRL_H
+#define __AB8500_SYSCTRL_H
+
+#include <linux/bitops.h>
+
+#ifdef CONFIG_AB8500_CORE
+
+int ab8500_sysctrl_read(u16 reg, u8 *value);
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
+
+#else
+
+static inline int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+       return 0;
+}
+
+static inline int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+       return 0;
+}
+
+#endif /* CONFIG_AB8500_CORE */
+
+static inline int ab8500_sysctrl_set(u16 reg, u8 bits)
+{
+       return ab8500_sysctrl_write(reg, bits, bits);
+}
+
+static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
+{
+       return ab8500_sysctrl_write(reg, bits, 0);
+}
+
+/* Registers */
+#define AB8500_TURNONSTATUS            0x100
+#define AB8500_RESETSTATUS             0x101
+#define AB8500_PONKEY1PRESSSTATUS      0x102
+#define AB8500_SYSCLKREQSTATUS         0x142
+#define AB8500_STW4500CTRL1            0x180
+#define AB8500_STW4500CTRL2            0x181
+#define AB8500_STW4500CTRL3            0x200
+#define AB8500_MAINWDOGCTRL            0x201
+#define AB8500_MAINWDOGTIMER           0x202
+#define AB8500_LOWBAT                  0x203
+#define AB8500_BATTOK                  0x204
+#define AB8500_SYSCLKTIMER             0x205
+#define AB8500_SMPSCLKCTRL             0x206
+#define AB8500_SMPSCLKSEL1             0x207
+#define AB8500_SMPSCLKSEL2             0x208
+#define AB8500_SMPSCLKSEL3             0x209
+#define AB8500_SYSULPCLKCONF           0x20A
+#define AB8500_SYSULPCLKCTRL1          0x20B
+#define AB8500_SYSCLKCTRL              0x20C
+#define AB8500_SYSCLKREQ1VALID         0x20D
+#define AB8500_SYSTEMCTRLSUP           0x20F
+#define AB8500_SYSCLKREQ1RFCLKBUF      0x210
+#define AB8500_SYSCLKREQ2RFCLKBUF      0x211
+#define AB8500_SYSCLKREQ3RFCLKBUF      0x212
+#define AB8500_SYSCLKREQ4RFCLKBUF      0x213
+#define AB8500_SYSCLKREQ5RFCLKBUF      0x214
+#define AB8500_SYSCLKREQ6RFCLKBUF      0x215
+#define AB8500_SYSCLKREQ7RFCLKBUF      0x216
+#define AB8500_SYSCLKREQ8RFCLKBUF      0x217
+#define AB8500_DITHERCLKCTRL           0x220
+#define AB8500_SWATCTRL                        0x230
+#define AB8500_HIQCLKCTRL              0x232
+#define AB8500_VSIMSYSCLKCTRL          0x233
+
+/* Bits */
+#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
+#define AB8500_TURNONSTATUS_PONKEY1DBF BIT(1)
+#define AB8500_TURNONSTATUS_PONKEY2DBF BIT(2)
+#define AB8500_TURNONSTATUS_RTCALARM BIT(3)
+#define AB8500_TURNONSTATUS_MAINCHDET BIT(4)
+#define AB8500_TURNONSTATUS_VBUSDET BIT(5)
+#define AB8500_TURNONSTATUS_USBIDDETECT BIT(6)
+
+#define AB8500_RESETSTATUS_RESETN4500NSTATUS BIT(0)
+#define AB8500_RESETSTATUS_SWRESETN4500NSTATUS BIT(2)
+
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_MASK 0x7F
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_SHIFT 0
+
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ1STATUS BIT(0)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ2STATUS BIT(1)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ3STATUS BIT(2)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ4STATUS BIT(3)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ5STATUS BIT(4)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ6STATUS BIT(5)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ7STATUS BIT(6)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ8STATUS BIT(7)
+
+#define AB8500_STW4500CTRL1_SWOFF BIT(0)
+#define AB8500_STW4500CTRL1_SWRESET4500N BIT(1)
+#define AB8500_STW4500CTRL1_THDB8500SWOFF BIT(2)
+
+#define AB8500_STW4500CTRL2_RESETNVAUX1VALID BIT(0)
+#define AB8500_STW4500CTRL2_RESETNVAUX2VALID BIT(1)
+#define AB8500_STW4500CTRL2_RESETNVAUX3VALID BIT(2)
+#define AB8500_STW4500CTRL2_RESETNVMODVALID BIT(3)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY1VALID BIT(4)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY2VALID BIT(5)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY3VALID BIT(6)
+#define AB8500_STW4500CTRL2_RESETNVSMPS1VALID BIT(7)
+
+#define AB8500_STW4500CTRL3_CLK32KOUT2DIS BIT(0)
+#define AB8500_STW4500CTRL3_RESETAUDN BIT(1)
+#define AB8500_STW4500CTRL3_RESETDENCN BIT(2)
+#define AB8500_STW4500CTRL3_THSDENA BIT(3)
+
+#define AB8500_MAINWDOGCTRL_MAINWDOGENA BIT(0)
+#define AB8500_MAINWDOGCTRL_MAINWDOGKICK BIT(1)
+#define AB8500_MAINWDOGCTRL_WDEXPTURNONVALID BIT(4)
+
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_MASK 0x7F
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_SHIFT 0
+
+#define AB8500_LOWBAT_LOWBATENA BIT(0)
+#define AB8500_LOWBAT_LOWBAT_MASK 0x7E
+#define AB8500_LOWBAT_LOWBAT_SHIFT 1
+
+#define AB8500_BATTOK_BATTOKSEL0THF_MASK 0x0F
+#define AB8500_BATTOK_BATTOKSEL0THF_SHIFT 0
+#define AB8500_BATTOK_BATTOKSEL1THF_MASK 0xF0
+#define AB8500_BATTOK_BATTOKSEL1THF_SHIFT 4
+
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_MASK 0x0F
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_SHIFT 0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_MASK 0xF0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_SHIFT 4
+
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_MASK 0x03
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_SHIFT 0
+#define AB8500_SMPSCLKCTRL_3M2CLKINTENA BIT(2)
+
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_SHIFT 3
+
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK 0x03
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_SHIFT 0
+#define AB8500_SYSULPCLKCONF_CLK27MHZSTRE BIT(2)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKDELN BIT(3)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKINV BIT(4)
+#define AB8500_SYSULPCLKCONF_ULPCLKSTRE BIT(5)
+#define AB8500_SYSULPCLKCONF_CLK27MHZBUFENA BIT(6)
+#define AB8500_SYSULPCLKCONF_CLK27MHZPDENA BIT(7)
+
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK 0x03
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT 0
+#define AB8500_SYSULPCLKCTRL1_ULPCLKREQ BIT(2)
+#define AB8500_SYSULPCLKCTRL1_4500SYSCLKREQ BIT(3)
+#define AB8500_SYSULPCLKCTRL1_AUDIOCLKENA BIT(4)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ BIT(5)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ BIT(6)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ BIT(7)
+
+#define AB8500_SYSCLKCTRL_TVOUTPLLENA BIT(0)
+#define AB8500_SYSCLKCTRL_TVOUTCLKENA BIT(1)
+#define AB8500_SYSCLKCTRL_USBCLKENA BIT(2)
+
+#define AB8500_SYSCLKREQ1VALID_SYSCLKREQ1VALID BIT(0)
+#define AB8500_SYSCLKREQ1VALID_ULPCLKREQ1VALID BIT(1)
+#define AB8500_SYSCLKREQ1VALID_USBSYSCLKREQ1VALID BIT(2)
+
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_MASK 0x03
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_SHIFT 0
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_MASK 0x0C
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_SHIFT 2
+#define AB8500_SYSTEMCTRLSUP_INTDB8500NOD BIT(4)
+
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF4 BIT(4)
+
+#define AB8500_DITHERCLKCTRL_VARMDITHERENA BIT(0)
+#define AB8500_DITHERCLKCTRL_VSMPS3DITHERENA BIT(1)
+#define AB8500_DITHERCLKCTRL_VSMPS1DITHERENA BIT(2)
+#define AB8500_DITHERCLKCTRL_VSMPS2DITHERENA BIT(3)
+#define AB8500_DITHERCLKCTRL_VMODDITHERENA BIT(4)
+#define AB8500_DITHERCLKCTRL_VAPEDITHERENA BIT(5)
+#define AB8500_DITHERCLKCTRL_DITHERDEL_MASK 0xC0
+#define AB8500_DITHERCLKCTRL_DITHERDEL_SHIFT 6
+
+#define AB8500_SWATCTRL_UPDATERF BIT(0)
+#define AB8500_SWATCTRL_SWATENABLE BIT(1)
+#define AB8500_SWATCTRL_RFOFFTIMER_MASK 0x1C
+#define AB8500_SWATCTRL_RFOFFTIMER_SHIFT 2
+#define AB8500_SWATCTRL_SWATBIT5 BIT(6)
+
+#define AB8500_HIQCLKCTRL_SYSCLKREQ1HIQENAVALID BIT(0)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ2HIQENAVALID BIT(1)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ3HIQENAVALID BIT(2)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ4HIQENAVALID BIT(3)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ5HIQENAVALID BIT(4)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ6HIQENAVALID BIT(5)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ7HIQENAVALID BIT(6)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ8HIQENAVALID BIT(7)
+
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ1VALID BIT(0)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ2VALID BIT(1)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ3VALID BIT(2)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ4VALID BIT(3)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ5VALID BIT(4)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ6VALID BIT(5)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
+
+#endif /* __AB8500_SYSCTRL_H */
index 67bd6f7ecf3228f7ca9a024ba09b5ef056521d63..7d9b6ae1c203928ea28b0971d528054ad0a23162 100644 (file)
@@ -186,7 +186,6 @@ struct abx500_init_settings {
 struct ab3550_platform_data {
        struct {unsigned int base; unsigned int count; } irq;
        void *dev_data[AB3550_NUM_DEVICES];
-       size_t dev_data_sz[AB3550_NUM_DEVICES];
        struct abx500_init_settings *init_settings;
        unsigned int init_settings_sz;
 };
index 835996e167e138560a69ffe107b3a46e49d67506..1408bf8eed5f2b811bd22aad529c951f1bcc5c1f 100644 (file)
@@ -25,22 +25,20 @@ struct mfd_cell {
        const char              *name;
        int                     id;
 
+       /* refcounting for multiple drivers to use a single cell */
+       atomic_t                *usage_count;
        int                     (*enable)(struct platform_device *dev);
        int                     (*disable)(struct platform_device *dev);
+
        int                     (*suspend)(struct platform_device *dev);
        int                     (*resume)(struct platform_device *dev);
 
-       /* driver-specific data for MFD-aware "cell" drivers */
-       void                    *driver_data;
-
-       /* platform_data can be used to either pass data to "generic"
-          driver or as a hook to mfd_cell for the "cell" drivers */
-       void                    *platform_data;
-       size_t                  data_size;
+       /* mfd_data can be used to pass data to client drivers */
+       void                    *mfd_data;
 
        /*
-        * This resources can be specified relatively to the parent device.
-        * For accessing device you should use resources from device
+        * These resources can be specified relative to the parent device.
+        * For accessing hardware you should use resources from the platform dev
         */
        int                     num_resources;
        const struct resource   *resources;
@@ -55,11 +53,47 @@ struct mfd_cell {
        bool                    pm_runtime_no_callbacks;
 };
 
+/*
+ * Convenience functions for clients using shared cells.  Refcounting
+ * happens automatically, with the cell's enable/disable callbacks
+ * being called only when a device is first being enabled or no other
+ * clients are making use of it.
+ */
+extern int mfd_cell_enable(struct platform_device *pdev);
+extern int mfd_cell_disable(struct platform_device *pdev);
+
+/*
+ * Given a platform device that's been created by mfd_add_devices(), fetch
+ * the mfd_cell that created it.
+ */
+static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
+{
+       return pdev->dev.platform_data;
+}
+
+/*
+ * Given a platform device that's been created by mfd_add_devices(), fetch
+ * the .mfd_data entry from the mfd_cell that created it.
+ */
+static inline void *mfd_get_data(struct platform_device *pdev)
+{
+       return mfd_get_cell(pdev)->mfd_data;
+}
+
 extern int mfd_add_devices(struct device *parent, int id,
-                          const struct mfd_cell *cells, int n_devs,
+                          struct mfd_cell *cells, int n_devs,
                           struct resource *mem_base,
                           int irq_base);
 
 extern void mfd_remove_devices(struct device *parent);
 
+/*
+ * For MFD drivers with clients sharing access to resources, these create
+ * multiple platform devices per cell.  Contention handling must still be
+ * handled via drivers (ie, with enable/disable hooks).
+ */
+extern int mfd_shared_platform_driver_register(struct platform_driver *drv,
+               const char *cellname);
+extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv);
+
 #endif
diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h
new file mode 100644 (file)
index 0000000..93a9477
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * max8997.h - Voltage regulator driver for the Maxim 8997
+ *
+ *  Copyright (C) 2010 Samsung Electrnoics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_MAX8997_PRIV_H
+#define __LINUX_MFD_MAX8997_PRIV_H
+
+#include <linux/i2c.h>
+
+enum max8997_pmic_reg {
+       MAX8997_REG_PMIC_ID0    = 0x00,
+       MAX8997_REG_PMIC_ID1    = 0x01,
+       MAX8997_REG_INTSRC      = 0x02,
+       MAX8997_REG_INT1        = 0x03,
+       MAX8997_REG_INT2        = 0x04,
+       MAX8997_REG_INT3        = 0x05,
+       MAX8997_REG_INT4        = 0x06,
+
+       MAX8997_REG_INT1MSK     = 0x08,
+       MAX8997_REG_INT2MSK     = 0x09,
+       MAX8997_REG_INT3MSK     = 0x0a,
+       MAX8997_REG_INT4MSK     = 0x0b,
+
+       MAX8997_REG_STATUS1     = 0x0d,
+       MAX8997_REG_STATUS2     = 0x0e,
+       MAX8997_REG_STATUS3     = 0x0f,
+       MAX8997_REG_STATUS4     = 0x10,
+
+       MAX8997_REG_MAINCON1    = 0x13,
+       MAX8997_REG_MAINCON2    = 0x14,
+       MAX8997_REG_BUCKRAMP    = 0x15,
+
+       MAX8997_REG_BUCK1CTRL   = 0x18,
+       MAX8997_REG_BUCK1DVS1   = 0x19,
+       MAX8997_REG_BUCK1DVS2   = 0x1a,
+       MAX8997_REG_BUCK1DVS3   = 0x1b,
+       MAX8997_REG_BUCK1DVS4   = 0x1c,
+       MAX8997_REG_BUCK1DVS5   = 0x1d,
+       MAX8997_REG_BUCK1DVS6   = 0x1e,
+       MAX8997_REG_BUCK1DVS7   = 0x1f,
+       MAX8997_REG_BUCK1DVS8   = 0x20,
+       MAX8997_REG_BUCK2CTRL   = 0x21,
+       MAX8997_REG_BUCK2DVS1   = 0x22,
+       MAX8997_REG_BUCK2DVS2   = 0x23,
+       MAX8997_REG_BUCK2DVS3   = 0x24,
+       MAX8997_REG_BUCK2DVS4   = 0x25,
+       MAX8997_REG_BUCK2DVS5   = 0x26,
+       MAX8997_REG_BUCK2DVS6   = 0x27,
+       MAX8997_REG_BUCK2DVS7   = 0x28,
+       MAX8997_REG_BUCK2DVS8   = 0x29,
+       MAX8997_REG_BUCK3CTRL   = 0x2a,
+       MAX8997_REG_BUCK3DVS    = 0x2b,
+       MAX8997_REG_BUCK4CTRL   = 0x2c,
+       MAX8997_REG_BUCK4DVS    = 0x2d,
+       MAX8997_REG_BUCK5CTRL   = 0x2e,
+       MAX8997_REG_BUCK5DVS1   = 0x2f,
+       MAX8997_REG_BUCK5DVS2   = 0x30,
+       MAX8997_REG_BUCK5DVS3   = 0x31,
+       MAX8997_REG_BUCK5DVS4   = 0x32,
+       MAX8997_REG_BUCK5DVS5   = 0x33,
+       MAX8997_REG_BUCK5DVS6   = 0x34,
+       MAX8997_REG_BUCK5DVS7   = 0x35,
+       MAX8997_REG_BUCK5DVS8   = 0x36,
+       MAX8997_REG_BUCK6CTRL   = 0x37,
+       MAX8997_REG_BUCK6BPSKIPCTRL     = 0x38,
+       MAX8997_REG_BUCK7CTRL   = 0x39,
+       MAX8997_REG_BUCK7DVS    = 0x3a,
+       MAX8997_REG_LDO1CTRL    = 0x3b,
+       MAX8997_REG_LDO2CTRL    = 0x3c,
+       MAX8997_REG_LDO3CTRL    = 0x3d,
+       MAX8997_REG_LDO4CTRL    = 0x3e,
+       MAX8997_REG_LDO5CTRL    = 0x3f,
+       MAX8997_REG_LDO6CTRL    = 0x40,
+       MAX8997_REG_LDO7CTRL    = 0x41,
+       MAX8997_REG_LDO8CTRL    = 0x42,
+       MAX8997_REG_LDO9CTRL    = 0x43,
+       MAX8997_REG_LDO10CTRL   = 0x44,
+       MAX8997_REG_LDO11CTRL   = 0x45,
+       MAX8997_REG_LDO12CTRL   = 0x46,
+       MAX8997_REG_LDO13CTRL   = 0x47,
+       MAX8997_REG_LDO14CTRL   = 0x48,
+       MAX8997_REG_LDO15CTRL   = 0x49,
+       MAX8997_REG_LDO16CTRL   = 0x4a,
+       MAX8997_REG_LDO17CTRL   = 0x4b,
+       MAX8997_REG_LDO18CTRL   = 0x4c,
+       MAX8997_REG_LDO21CTRL   = 0x4d,
+
+       MAX8997_REG_MBCCTRL1    = 0x50,
+       MAX8997_REG_MBCCTRL2    = 0x51,
+       MAX8997_REG_MBCCTRL3    = 0x52,
+       MAX8997_REG_MBCCTRL4    = 0x53,
+       MAX8997_REG_MBCCTRL5    = 0x54,
+       MAX8997_REG_MBCCTRL6    = 0x55,
+       MAX8997_REG_OTPCGHCVS   = 0x56,
+
+       MAX8997_REG_SAFEOUTCTRL = 0x5a,
+
+       MAX8997_REG_LBCNFG1     = 0x5e,
+       MAX8997_REG_LBCNFG2     = 0x5f,
+       MAX8997_REG_BBCCTRL     = 0x60,
+
+       MAX8997_REG_FLASH1_CUR  = 0x63, /* 0x63 ~ 0x6e for FLASH */
+       MAX8997_REG_FLASH2_CUR  = 0x64,
+       MAX8997_REG_MOVIE_CUR   = 0x65,
+       MAX8997_REG_GSMB_CUR    = 0x66,
+       MAX8997_REG_BOOST_CNTL  = 0x67,
+       MAX8997_REG_LEN_CNTL    = 0x68,
+       MAX8997_REG_FLASH_CNTL  = 0x69,
+       MAX8997_REG_WDT_CNTL    = 0x6a,
+       MAX8997_REG_MAXFLASH1   = 0x6b,
+       MAX8997_REG_MAXFLASH2   = 0x6c,
+       MAX8997_REG_FLASHSTATUS = 0x6d,
+       MAX8997_REG_FLASHSTATUSMASK     = 0x6e,
+
+       MAX8997_REG_GPIOCNTL1   = 0x70,
+       MAX8997_REG_GPIOCNTL2   = 0x71,
+       MAX8997_REG_GPIOCNTL3   = 0x72,
+       MAX8997_REG_GPIOCNTL4   = 0x73,
+       MAX8997_REG_GPIOCNTL5   = 0x74,
+       MAX8997_REG_GPIOCNTL6   = 0x75,
+       MAX8997_REG_GPIOCNTL7   = 0x76,
+       MAX8997_REG_GPIOCNTL8   = 0x77,
+       MAX8997_REG_GPIOCNTL9   = 0x78,
+       MAX8997_REG_GPIOCNTL10  = 0x79,
+       MAX8997_REG_GPIOCNTL11  = 0x7a,
+       MAX8997_REG_GPIOCNTL12  = 0x7b,
+
+       MAX8997_REG_LDO1CONFIG  = 0x80,
+       MAX8997_REG_LDO2CONFIG  = 0x81,
+       MAX8997_REG_LDO3CONFIG  = 0x82,
+       MAX8997_REG_LDO4CONFIG  = 0x83,
+       MAX8997_REG_LDO5CONFIG  = 0x84,
+       MAX8997_REG_LDO6CONFIG  = 0x85,
+       MAX8997_REG_LDO7CONFIG  = 0x86,
+       MAX8997_REG_LDO8CONFIG  = 0x87,
+       MAX8997_REG_LDO9CONFIG  = 0x88,
+       MAX8997_REG_LDO10CONFIG = 0x89,
+       MAX8997_REG_LDO11CONFIG = 0x8a,
+       MAX8997_REG_LDO12CONFIG = 0x8b,
+       MAX8997_REG_LDO13CONFIG = 0x8c,
+       MAX8997_REG_LDO14CONFIG = 0x8d,
+       MAX8997_REG_LDO15CONFIG = 0x8e,
+       MAX8997_REG_LDO16CONFIG = 0x8f,
+       MAX8997_REG_LDO17CONFIG = 0x90,
+       MAX8997_REG_LDO18CONFIG = 0x91,
+       MAX8997_REG_LDO21CONFIG = 0x92,
+
+       MAX8997_REG_DVSOKTIMER1 = 0x97,
+       MAX8997_REG_DVSOKTIMER2 = 0x98,
+       MAX8997_REG_DVSOKTIMER4 = 0x99,
+       MAX8997_REG_DVSOKTIMER5 = 0x9a,
+
+       MAX8997_REG_PMIC_END    = 0x9b,
+};
+
+enum max8997_muic_reg {
+       MAX8997_MUIC_REG_ID             = 0x0,
+       MAX8997_MUIC_REG_INT1           = 0x1,
+       MAX8997_MUIC_REG_INT2           = 0x2,
+       MAX8997_MUIC_REG_INT3           = 0x3,
+       MAX8997_MUIC_REG_STATUS1        = 0x4,
+       MAX8997_MUIC_REG_STATUS2        = 0x5,
+       MAX8997_MUIC_REG_STATUS3        = 0x6,
+       MAX8997_MUIC_REG_INTMASK1       = 0x7,
+       MAX8997_MUIC_REG_INTMASK2       = 0x8,
+       MAX8997_MUIC_REG_INTMASK3       = 0x9,
+       MAX8997_MUIC_REG_CDETCTRL       = 0xa,
+
+       MAX8997_MUIC_REG_CONTROL1       = 0xc,
+       MAX8997_MUIC_REG_CONTROL2       = 0xd,
+       MAX8997_MUIC_REG_CONTROL3       = 0xe,
+
+       MAX8997_MUIC_REG_END            = 0xf,
+};
+
+enum max8997_haptic_reg {
+       MAX8997_HAPTIC_REG_GENERAL      = 0x00,
+       MAX8997_HAPTIC_REG_CONF1        = 0x01,
+       MAX8997_HAPTIC_REG_CONF2        = 0x02,
+       MAX8997_HAPTIC_REG_DRVCONF      = 0x03,
+       MAX8997_HAPTIC_REG_CYCLECONF1   = 0x04,
+       MAX8997_HAPTIC_REG_CYCLECONF2   = 0x05,
+       MAX8997_HAPTIC_REG_SIGCONF1     = 0x06,
+       MAX8997_HAPTIC_REG_SIGCONF2     = 0x07,
+       MAX8997_HAPTIC_REG_SIGCONF3     = 0x08,
+       MAX8997_HAPTIC_REG_SIGCONF4     = 0x09,
+       MAX8997_HAPTIC_REG_SIGDC1       = 0x0a,
+       MAX8997_HAPTIC_REG_SIGDC2       = 0x0b,
+       MAX8997_HAPTIC_REG_SIGPWMDC1    = 0x0c,
+       MAX8997_HAPTIC_REG_SIGPWMDC2    = 0x0d,
+       MAX8997_HAPTIC_REG_SIGPWMDC3    = 0x0e,
+       MAX8997_HAPTIC_REG_SIGPWMDC4    = 0x0f,
+       MAX8997_HAPTIC_REG_MTR_REV      = 0x10,
+
+       MAX8997_HAPTIC_REG_END          = 0x11,
+};
+
+/* slave addr = 0x0c: using "2nd part" of rev4 datasheet */
+enum max8997_rtc_reg {
+       MAX8997_RTC_CTRLMASK            = 0x02,
+       MAX8997_RTC_CTRL                = 0x03,
+       MAX8997_RTC_UPDATE1             = 0x04,
+       MAX8997_RTC_UPDATE2             = 0x05,
+       MAX8997_RTC_WTSR_SMPL           = 0x06,
+
+       MAX8997_RTC_SEC                 = 0x10,
+       MAX8997_RTC_MIN                 = 0x11,
+       MAX8997_RTC_HOUR                = 0x12,
+       MAX8997_RTC_DAY_OF_WEEK         = 0x13,
+       MAX8997_RTC_MONTH               = 0x14,
+       MAX8997_RTC_YEAR                = 0x15,
+       MAX8997_RTC_DAY_OF_MONTH        = 0x16,
+       MAX8997_RTC_ALARM1_SEC          = 0x17,
+       MAX8997_RTC_ALARM1_MIN          = 0x18,
+       MAX8997_RTC_ALARM1_HOUR         = 0x19,
+       MAX8997_RTC_ALARM1_DAY_OF_WEEK  = 0x1a,
+       MAX8997_RTC_ALARM1_MONTH        = 0x1b,
+       MAX8997_RTC_ALARM1_YEAR         = 0x1c,
+       MAX8997_RTC_ALARM1_DAY_OF_MONTH = 0x1d,
+       MAX8997_RTC_ALARM2_SEC          = 0x1e,
+       MAX8997_RTC_ALARM2_MIN          = 0x1f,
+       MAX8997_RTC_ALARM2_HOUR         = 0x20,
+       MAX8997_RTC_ALARM2_DAY_OF_WEEK  = 0x21,
+       MAX8997_RTC_ALARM2_MONTH        = 0x22,
+       MAX8997_RTC_ALARM2_YEAR         = 0x23,
+       MAX8997_RTC_ALARM2_DAY_OF_MONTH = 0x24,
+};
+
+enum max8997_irq_source {
+       PMIC_INT1 = 0,
+       PMIC_INT2,
+       PMIC_INT3,
+       PMIC_INT4,
+
+       FUEL_GAUGE, /* Ignored (MAX17042 driver handles) */
+
+       MUIC_INT1,
+       MUIC_INT2,
+       MUIC_INT3,
+
+       GPIO_LOW, /* Not implemented */
+       GPIO_HI, /* Not implemented */
+
+       FLASH_STATUS, /* Not implemented */
+
+       MAX8997_IRQ_GROUP_NR,
+};
+
+enum max8997_irq {
+       MAX8997_PMICIRQ_PWRONR,
+       MAX8997_PMICIRQ_PWRONF,
+       MAX8997_PMICIRQ_PWRON1SEC,
+       MAX8997_PMICIRQ_JIGONR,
+       MAX8997_PMICIRQ_JIGONF,
+       MAX8997_PMICIRQ_LOWBAT2,
+       MAX8997_PMICIRQ_LOWBAT1,
+
+       MAX8997_PMICIRQ_JIGR,
+       MAX8997_PMICIRQ_JIGF,
+       MAX8997_PMICIRQ_MR,
+       MAX8997_PMICIRQ_DVS1OK,
+       MAX8997_PMICIRQ_DVS2OK,
+       MAX8997_PMICIRQ_DVS3OK,
+       MAX8997_PMICIRQ_DVS4OK,
+
+       MAX8997_PMICIRQ_CHGINS,
+       MAX8997_PMICIRQ_CHGRM,
+       MAX8997_PMICIRQ_DCINOVP,
+       MAX8997_PMICIRQ_TOPOFFR,
+       MAX8997_PMICIRQ_CHGRSTF,
+       MAX8997_PMICIRQ_MBCHGTMEXPD,
+
+       MAX8997_PMICIRQ_RTC60S,
+       MAX8997_PMICIRQ_RTCA1,
+       MAX8997_PMICIRQ_RTCA2,
+       MAX8997_PMICIRQ_SMPL_INT,
+       MAX8997_PMICIRQ_RTC1S,
+       MAX8997_PMICIRQ_WTSR,
+
+       MAX8997_MUICIRQ_ADCError,
+       MAX8997_MUICIRQ_ADCLow,
+       MAX8997_MUICIRQ_ADC,
+
+       MAX8997_MUICIRQ_VBVolt,
+       MAX8997_MUICIRQ_DBChg,
+       MAX8997_MUICIRQ_DCDTmr,
+       MAX8997_MUICIRQ_ChgDetRun,
+       MAX8997_MUICIRQ_ChgTyp,
+
+       MAX8997_MUICIRQ_OVP,
+
+       MAX8997_IRQ_NR,
+};
+
+#define MAX8997_REG_BUCK1DVS(x)        (MAX8997_REG_BUCK1DVS1 + (x) - 1)
+#define MAX8997_REG_BUCK2DVS(x)        (MAX8997_REG_BUCK2DVS1 + (x) - 1)
+#define MAX8997_REG_BUCK5DVS(x)        (MAX8997_REG_BUCK5DVS1 + (x) - 1)
+
+struct max8997_dev {
+       struct device *dev;
+       struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */
+       struct i2c_client *rtc; /* slave addr 0x0c */
+       struct i2c_client *haptic; /* slave addr 0x90 */
+       struct i2c_client *muic; /* slave addr 0x4a */
+       struct mutex iolock;
+
+       int type;
+       struct platform_device *battery; /* battery control (not fuel gauge) */
+
+       bool wakeup;
+
+       /* For hibernation */
+       u8 reg_dump[MAX8997_REG_PMIC_END + MAX8997_MUIC_REG_END +
+               MAX8997_HAPTIC_REG_END];
+};
+
+enum max8997_types {
+       TYPE_MAX8997,
+       TYPE_MAX8966,
+};
+
+extern int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
+extern int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value);
+extern int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count,
+                               u8 *buf);
+extern int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask);
+
+#endif /*  __LINUX_MFD_MAX8997_PRIV_H */
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
new file mode 100644 (file)
index 0000000..cb671b3
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * max8997.h - Driver for the Maxim 8997/8966
+ *
+ *  Copyright (C) 2009-2010 Samsung Electrnoics
+ *  MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8998.h
+ *
+ * MAX8997 has PMIC, MUIC, HAPTIC, RTC, FLASH, and Fuel Gauge devices.
+ * Except Fuel Gauge, every device shares the same I2C bus and included in
+ * this mfd driver. Although the fuel gauge is included in the chip, it is
+ * excluded from the driver because a) it has a different I2C bus from
+ * others and b) it can be enabled simply by using MAX17042 driver.
+ */
+
+#ifndef __LINUX_MFD_MAX8998_H
+#define __LINUX_MFD_MAX8998_H
+
+#include <linux/regulator/consumer.h>
+
+/* MAX8997/8966 regulator IDs */
+enum max8998_regulators {
+       MAX8997_LDO1 = 0,
+       MAX8997_LDO2,
+       MAX8997_LDO3,
+       MAX8997_LDO4,
+       MAX8997_LDO5,
+       MAX8997_LDO6,
+       MAX8997_LDO7,
+       MAX8997_LDO8,
+       MAX8997_LDO9,
+       MAX8997_LDO10,
+       MAX8997_LDO11,
+       MAX8997_LDO12,
+       MAX8997_LDO13,
+       MAX8997_LDO14,
+       MAX8997_LDO15,
+       MAX8997_LDO16,
+       MAX8997_LDO17,
+       MAX8997_LDO18,
+       MAX8997_LDO21,
+       MAX8997_BUCK1,
+       MAX8997_BUCK2,
+       MAX8997_BUCK3,
+       MAX8997_BUCK4,
+       MAX8997_BUCK5,
+       MAX8997_BUCK6,
+       MAX8997_BUCK7,
+       MAX8997_EN32KHZ_AP,
+       MAX8997_EN32KHZ_CP,
+       MAX8997_ENVICHG,
+       MAX8997_ESAFEOUT1,
+       MAX8997_ESAFEOUT2,
+       MAX8997_CHARGER_CV, /* control MBCCV of MBCCTRL3 */
+       MAX8997_CHARGER, /* charger current, MBCCTRL4 */
+       MAX8997_CHARGER_TOPOFF, /* MBCCTRL5 */
+
+       MAX8997_REG_MAX,
+};
+
+struct max8997_regulator_data {
+       int id;
+       struct regulator_init_data *initdata;
+};
+
+struct max8997_platform_data {
+       bool wakeup;
+       /* IRQ: Not implemented */
+       /* ---- PMIC ---- */
+       struct max8997_regulator_data *regulators;
+       int num_regulators;
+
+       /*
+        * SET1~3 DVS GPIOs control Buck1, 2, and 5 simultaneously. Therefore,
+        * With buckx_gpiodvs enabled, the buckx cannot be controlled
+        * independently. To control buckx (of 1, 2, and 5) independently,
+        * disable buckx_gpiodvs and control with BUCKxDVS1 register.
+        *
+        * When buckx_gpiodvs and bucky_gpiodvs are both enabled, set_voltage
+        * on buckx will change the voltage of bucky at the same time.
+        *
+        */
+       bool ignore_gpiodvs_side_effect;
+       int buck125_gpios[3]; /* GPIO of [0]SET1, [1]SET2, [2]SET3 */
+       int buck125_default_idx; /* Default value of SET1, 2, 3 */
+       unsigned int buck1_voltage[8]; /* buckx_voltage in uV */
+       bool buck1_gpiodvs;
+       unsigned int buck2_voltage[8];
+       bool buck2_gpiodvs;
+       unsigned int buck5_voltage[8];
+       bool buck5_gpiodvs;
+
+       /* MUIC: Not implemented */
+       /* HAPTIC: Not implemented */
+       /* RTC: Not implemented */
+       /* Flash: Not implemented */
+       /* Charger control: Not implemented */
+};
+
+#endif /* __LINUX_MFD_MAX8998_H */
index a1d391b40e682ca9cc7a659739e3ebed1efd670d..c064beaaccb7f482bd969c226ef2aae0de9e8612 100644 (file)
@@ -146,8 +146,7 @@ struct mc13xxx_platform_data {
 #define MC13XXX_USE_LED                (1 << 5)
        unsigned int flags;
 
-       int num_regulators;
-       struct mc13xxx_regulator_init_data *regulators;
+       struct mc13xxx_regulator_platform_data regulators;
        struct mc13xxx_leds_platform_data *leds;
 };
 
diff --git a/include/linux/mfd/tps6105x.h b/include/linux/mfd/tps6105x.h
new file mode 100644 (file)
index 0000000..386743d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef MFD_TPS6105X_H
+#define MFD_TPS6105X_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+
+/*
+ * Register definitions to all subdrivers
+ */
+#define TPS6105X_REG_0                 0x00
+#define TPS6105X_REG0_MODE_SHIFT       6
+#define TPS6105X_REG0_MODE_MASK                (0x03<<6)
+/* These defines for both reg0 and reg1 */
+#define TPS6105X_REG0_MODE_SHUTDOWN    0x00
+#define TPS6105X_REG0_MODE_TORCH       0x01
+#define TPS6105X_REG0_MODE_TORCH_FLASH 0x02
+#define TPS6105X_REG0_MODE_VOLTAGE     0x03
+#define TPS6105X_REG0_VOLTAGE_SHIFT    4
+#define TPS6105X_REG0_VOLTAGE_MASK     (3<<4)
+#define TPS6105X_REG0_VOLTAGE_450      0
+#define TPS6105X_REG0_VOLTAGE_500      1
+#define TPS6105X_REG0_VOLTAGE_525      2
+#define TPS6105X_REG0_VOLTAGE_500_2    3
+#define TPS6105X_REG0_DIMMING_SHIFT    3
+#define TPS6105X_REG0_TORCHC_SHIFT     0
+#define TPS6105X_REG0_TORCHC_MASK      (7<<0)
+#define TPS6105X_REG0_TORCHC_0         0x00
+#define TPS6105X_REG0_TORCHC_50                0x01
+#define TPS6105X_REG0_TORCHC_75                0x02
+#define TPS6105X_REG0_TORCHC_100       0x03
+#define TPS6105X_REG0_TORCHC_150       0x04
+#define TPS6105X_REG0_TORCHC_200       0x05
+#define TPS6105X_REG0_TORCHC_250_400   0x06
+#define TPS6105X_REG0_TORCHC_250_500   0x07
+#define TPS6105X_REG_1                 0x01
+#define TPS6105X_REG1_MODE_SHIFT       6
+#define TPS6105X_REG1_MODE_MASK                (0x03<<6)
+#define TPS6105X_REG1_MODE_SHUTDOWN    0x00
+#define TPS6105X_REG1_MODE_TORCH       0x01
+#define TPS6105X_REG1_MODE_TORCH_FLASH 0x02
+#define TPS6105X_REG1_MODE_VOLTAGE     0x03
+#define TPS6105X_REG_2                 0x02
+#define TPS6105X_REG_3                 0x03
+
+/**
+ * enum tps6105x_mode - desired mode for the TPS6105x
+ * @TPS6105X_MODE_SHUTDOWN: this instance is inactive, not used for anything
+ * @TPS61905X_MODE_TORCH: this instance is used as a LED, usually a while
+ *     LED, for example as backlight or flashlight. If this is set, the
+ *     TPS6105X will register to the LED framework
+ * @TPS6105X_MODE_TORCH_FLASH: this instance is used as a flashgun, usually
+ *     in a camera
+ * @TPS6105X_MODE_VOLTAGE: this instance is used as a voltage regulator and
+ *     will register to the regulator framework
+ */
+enum tps6105x_mode {
+       TPS6105X_MODE_SHUTDOWN,
+       TPS6105X_MODE_TORCH,
+       TPS6105X_MODE_TORCH_FLASH,
+       TPS6105X_MODE_VOLTAGE,
+};
+
+/**
+ * struct tps6105x_platform_data - TPS61905x platform data
+ * @mode: what mode this instance shall be operated in,
+ *     this is not selectable at runtime
+ * @regulator_data: initialization data for the voltage
+ *     regulator if used as a voltage source
+ */
+struct tps6105x_platform_data {
+       enum tps6105x_mode mode;
+       struct regulator_init_data *regulator_data;
+};
+
+/**
+ * struct tps6105x - state holder for the TPS6105x drivers
+ * @mutex: mutex to serialize I2C accesses
+ * @i2c_client: corresponding I2C client
+ * @regulator: regulator device if used in voltage mode
+ */
+struct tps6105x {
+       struct tps6105x_platform_data *pdata;
+       struct mutex            lock;
+       struct i2c_client       *client;
+       struct regulator_dev    *regulator;
+};
+
+extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value);
+extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf);
+extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
+                                u8 bitmask, u8 bitvalues);
+
+#endif
index 9787293eae5f7f7f5f42144763cf3bb26c443573..db2f3f454a1b60ed4ddcbe380935c4808d377062 100644 (file)
@@ -280,7 +280,9 @@ struct wl1273_core {
 
        struct i2c_client *client;
 
+       int (*read)(struct wl1273_core *core, u8, u16 *);
        int (*write)(struct wl1273_core *core, u8, u16);
+       int (*write_data)(struct wl1273_core *core, u8 *, u16);
        int (*set_audio)(struct wl1273_core *core, unsigned int);
        int (*set_volume)(struct wl1273_core *core, unsigned int);
 };
index fd322aca33ba89a9cec62eb7f3909f813b2267a5..afe4db49402d142036761855cd9c9b6714bfec8d 100644 (file)
@@ -80,7 +80,8 @@ struct wm831x_touch_pdata {
        int isel;              /** Current for pen down (uA) */
        int rpu;               /** Pen down sensitivity resistor divider */
        int pressure;          /** Report pressure (boolean) */
-       int data_irq;          /** Touch data ready IRQ */
+       unsigned int data_irq; /** Touch data ready IRQ */
+       unsigned int pd_irq;   /** Touch pendown detect IRQ */
 };
 
 enum wm831x_watchdog_action {
@@ -103,11 +104,17 @@ struct wm831x_watchdog_pdata {
 #define WM831X_MAX_ISINK  2
 
 struct wm831x_pdata {
+       /** Used to distinguish multiple WM831x chips */
+       int wm831x_num;
+
        /** Called before subdevices are set up */
        int (*pre_init)(struct wm831x *wm831x);
        /** Called after subdevices are set up */
        int (*post_init)(struct wm831x *wm831x);
 
+       /** Put the /IRQ line into CMOS mode */
+       bool irq_cmos;
+
        int irq_base;
        int gpio_base;
        struct wm831x_backlight_pdata *backlight;
index ef4f0b6083a39ae55450a289cc70269df6937e62..f0b69cdae41cc94f24c995d9812301d9eb711451 100644 (file)
@@ -59,7 +59,7 @@ struct wm8994 {
        int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
                        int bytes, void *dest);
        int (*write_dev)(struct wm8994 *wm8994, unsigned short reg,
-                        int bytes, void *src);
+                        int bytes, const void *src);
 
        void *control_data;
 
@@ -88,6 +88,8 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
                    unsigned short mask, unsigned short val);
 int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
                     int count, u16 *buf);
+int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg,
+                    int count, const u16 *buf);
 
 
 /* Helper to save on boilerplate */
index 581703d86fbd04f3dcbe01faad8444ba979a1639..7606d7db96c90be584687bf478e416dae1d535ec 100644 (file)
@@ -151,6 +151,7 @@ extern pgprot_t protection_map[16];
 #define FAULT_FLAG_NONLINEAR   0x02    /* Fault was via a nonlinear mapping */
 #define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
 #define FAULT_FLAG_ALLOW_RETRY 0x08    /* Retry fault if blocking */
+#define FAULT_FLAG_RETRY_NOWAIT        0x10    /* Don't drop mmap_sem and wait when retrying */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -859,7 +860,14 @@ extern void pagefault_out_of_memory(void);
 
 #define offset_in_page(p)      ((unsigned long)(p) & ~PAGE_MASK)
 
+/*
+ * Flags passed to show_mem() and __show_free_areas() to suppress output in
+ * various contexts.
+ */
+#define SHOW_MEM_FILTER_NODES  (0x0001u)       /* filter disallowed nodes */
+
 extern void show_free_areas(void);
+extern void __show_free_areas(unsigned int flags);
 
 int shmem_lock(struct file *file, int lock, struct user_struct *user);
 struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
@@ -906,6 +914,9 @@ unsigned long unmap_vmas(struct mmu_gather **tlb,
  * @pgd_entry: if set, called for each non-empty PGD (top-level) entry
  * @pud_entry: if set, called for each non-empty PUD (2nd-level) entry
  * @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry
+ *            this handler is required to be able to handle
+ *            pmd_trans_huge() pmds.  They may simply choose to
+ *            split_huge_page() instead of handling it explicitly.
  * @pte_entry: if set, called for each non-empty PTE (4th-level) entry
  * @pte_hole: if set, called for each hole at all levels
  * @hugetlb_entry: if set, called for each hugetlb entry
@@ -971,6 +982,8 @@ static inline int handle_mm_fault(struct mm_struct *mm,
 
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
+extern int access_remote_vm(struct mm_struct *mm, unsigned long addr,
+               void *buf, int len, int write);
 
 int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                     unsigned long start, int len, unsigned int foll_flags,
@@ -1347,7 +1360,7 @@ extern void setup_per_zone_wmarks(void);
 extern void calculate_zone_inactive_ratio(struct zone *zone);
 extern void mem_init(void);
 extern void __init mmap_init(void);
-extern void show_mem(void);
+extern void show_mem(unsigned int flags);
 extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
 extern int after_bootmem;
@@ -1537,6 +1550,8 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address,
 #define FOLL_GET       0x04    /* do get_page on page */
 #define FOLL_DUMP      0x08    /* give error on hole if it would be zero */
 #define FOLL_FORCE     0x10    /* get_user_pages read/write w/o permission */
+#define FOLL_NOWAIT    0x20    /* if a disk transfer is needed, start the IO
+                                * and return without waiting upon it */
 #define FOLL_MLOCK     0x40    /* mark page as mlocked */
 #define FOLL_SPLIT     0x80    /* don't return transhuge pages, split them */
 #define FOLL_HWPOISON  0x100   /* check page is hwpoisoned */
@@ -1578,13 +1593,13 @@ static inline bool kernel_page_present(struct page *page) { return true; }
 #endif /* CONFIG_HIBERNATION */
 #endif
 
-extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
+extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm);
 #ifdef __HAVE_ARCH_GATE_AREA
-int in_gate_area_no_task(unsigned long addr);
-int in_gate_area(struct task_struct *task, unsigned long addr);
+int in_gate_area_no_mm(unsigned long addr);
+int in_gate_area(struct mm_struct *mm, unsigned long addr);
 #else
-int in_gate_area_no_task(unsigned long addr);
-#define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);})
+int in_gate_area_no_mm(unsigned long addr);
+#define in_gate_area(mm, addr) ({(void)mm; in_gate_area_no_mm(addr);})
 #endif /* __HAVE_ARCH_GATE_AREA */
 
 int drop_caches_sysctl_handler(struct ctl_table *, int,
index 26bc4e2cd2750aea3695f9f38a8e365716f764ac..02aa5619709b9bab0a40d183fc3b0b017b8bd50c 100644 (file)
@@ -237,8 +237,9 @@ struct mm_struct {
        atomic_t mm_users;                      /* How many users with user space? */
        atomic_t mm_count;                      /* How many references to "struct mm_struct" (users count as 1) */
        int map_count;                          /* number of VMAs */
-       struct rw_semaphore mmap_sem;
+
        spinlock_t page_table_lock;             /* Protects page tables and some counters */
+       struct rw_semaphore mmap_sem;
 
        struct list_head mmlist;                /* List of maybe swapped mm's.  These are globally strung
                                                 * together off init_mm.mmlist, and are protected
@@ -281,6 +282,9 @@ struct mm_struct {
        unsigned int token_priority;
        unsigned int last_interval;
 
+       /* How many tasks sharing this mm are OOM_DISABLE */
+       atomic_t oom_disable_count;
+
        unsigned long flags; /* Must use atomic bitops to access the bits */
 
        struct core_state *core_state; /* coredumping support */
@@ -313,8 +317,6 @@ struct mm_struct {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        pgtable_t pmd_huge_pte; /* protected by page_table_lock */
 #endif
-       /* How many tasks sharing this mm are OOM_DISABLE */
-       atomic_t oom_disable_count;
 };
 
 /* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
diff --git a/include/linux/mmc/boot.h b/include/linux/mmc/boot.h
new file mode 100644 (file)
index 0000000..39d787c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MMC_BOOT_H
+#define MMC_BOOT_H
+
+enum { MMC_PROGRESS_ENTER, MMC_PROGRESS_INIT,
+       MMC_PROGRESS_LOAD, MMC_PROGRESS_DONE };
+
+#endif
index 8ce082781ccb403385ec57b5989be5f5f6692a55..adb4888248be9a06219f71f39dceb06c60edd15d 100644 (file)
@@ -54,6 +54,9 @@ struct mmc_ext_csd {
        unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
        unsigned int            sec_erase_mult; /* Secure erase multiplier */
        unsigned int            trim_timeout;           /* In milliseconds */
+       bool                    enhanced_area_en;       /* enable bit */
+       unsigned long long      enhanced_area_offset;   /* Units: Byte */
+       unsigned int            enhanced_area_size;     /* Units: KB */
 };
 
 struct sd_scr {
@@ -121,6 +124,7 @@ struct mmc_card {
                                                /* for byte mode */
 #define MMC_QUIRK_NONSTD_SDIO  (1<<2)          /* non-standard SDIO card attached */
                                                /* (missing CIA registers) */
+#define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)     /* clock gating the sdio bus will make card fail */
 
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
@@ -148,6 +152,8 @@ struct mmc_card {
        struct dentry           *debugfs_root;
 };
 
+void mmc_fixup_device(struct mmc_card *dev);
+
 #define mmc_card_mmc(c)                ((c)->type == MMC_TYPE_MMC)
 #define mmc_card_sd(c)         ((c)->type == MMC_TYPE_SD)
 #define mmc_card_sdio(c)       ((c)->type == MMC_TYPE_SDIO)
index 64e013f1cfb82a883a93982ec2cea3b42a0729fb..07f27af4dba5221b1139206cc2bd33858a3b38ef 100644 (file)
@@ -160,6 +160,7 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 
 extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
+extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
 /**
index 16b0261763ed5189306c6e23e24383e96522211d..c0207a770476fbaa5c25db5f1045293c7409c4c2 100644 (file)
@@ -140,6 +140,7 @@ struct dw_mci {
        u32                     bus_hz;
        u32                     current_speed;
        u32                     num_slots;
+       u32                     fifoth_val;
        struct platform_device  *pdev;
        struct dw_mci_board     *pdata;
        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
@@ -151,6 +152,8 @@ struct dw_mci {
 
        /* Workaround flags */
        u32                     quirks;
+
+       struct regulator        *vmmc;  /* Power regulator */
 };
 
 /* DMA ops for Internal/External DMAC interface */
@@ -165,14 +168,14 @@ struct dw_mci_dma_ops {
 };
 
 /* IP Quirks/flags. */
-/* No special quirks or flags to cater for */
-#define DW_MCI_QUIRK_NONE              0
 /* DTO fix for command transmission with IDMAC configured */
-#define DW_MCI_QUIRK_IDMAC_DTO         1
+#define DW_MCI_QUIRK_IDMAC_DTO                 BIT(0)
 /* delay needed between retries on some 2.11a implementations */
-#define DW_MCI_QUIRK_RETRY_DELAY       2
+#define DW_MCI_QUIRK_RETRY_DELAY               BIT(1)
 /* High Speed Capable - Supports HS cards (upto 50MHz) */
-#define DW_MCI_QUIRK_HIGHSPEED         4
+#define DW_MCI_QUIRK_HIGHSPEED                 BIT(2)
+/* Unreliable card detection */
+#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION     BIT(3)
 
 
 struct dma_pdata;
@@ -192,6 +195,8 @@ struct dw_mci_board {
        u32 quirks; /* Workaround / Quirk flags */
        unsigned int bus_hz; /* Bus speed */
 
+       unsigned int caps;      /* Capabilities */
+
        /* delay in mS before detecting cards after interrupt */
        u32 detect_delay_ms;
 
index 612301f85d144608066f1131bc330a3007a7c1e0..264ba5451e3b98449832d94693d167792cec1f7b 100644 (file)
@@ -253,6 +253,8 @@ struct _mmc_csd {
  * EXT_CSD fields
  */
 
+#define EXT_CSD_PARTITION_ATTRIBUTE    156     /* R/W */
+#define EXT_CSD_PARTITION_SUPPORT      160     /* RO */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
 #define EXT_CSD_BUS_WIDTH              183     /* R/W */
@@ -262,6 +264,7 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE              196     /* RO */
 #define EXT_CSD_SEC_CNT                        212     /* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT            217     /* RO */
+#define EXT_CSD_HC_WP_GRP_SIZE         221     /* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT     223     /* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE      224     /* RO */
 #define EXT_CSD_SEC_TRIM_MULT          229     /* RO */
index 38d3930928128b755d98ece1c2f8fe1437dfd19c..9eb9b4b96f5507ac767024f098db2a8b24490fc9 100644 (file)
@@ -104,9 +104,6 @@ static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 
 #define SH_MMCIF_BBS 512 /* boot block size */
 
-enum { MMCIF_PROGRESS_ENTER, MMCIF_PROGRESS_INIT,
-       MMCIF_PROGRESS_LOAD, MMCIF_PROGRESS_DONE };
-
 static inline void sh_mmcif_boot_cmd_send(void __iomem *base,
                                          unsigned long cmd, unsigned long arg)
 {
index 134716e5e3509f9c56e11334137a9aefb41c4a21..b528f6d4b860d394e2870a02022366a209abcec0 100644 (file)
@@ -550,6 +550,7 @@ enum {
        NFSPROC4_CLNT_SETACL,
        NFSPROC4_CLNT_FS_LOCATIONS,
        NFSPROC4_CLNT_RELEASE_LOCKOWNER,
+       NFSPROC4_CLNT_SECINFO,
 
        /* nfs41 */
        NFSPROC4_CLNT_EXCHANGE_ID,
@@ -560,6 +561,7 @@ enum {
        NFSPROC4_CLNT_RECLAIM_COMPLETE,
        NFSPROC4_CLNT_LAYOUTGET,
        NFSPROC4_CLNT_GETDEVICEINFO,
+       NFSPROC4_CLNT_LAYOUTCOMMIT,
 };
 
 /* nfs41 types */
index f88522b10a384b5864ecf57ce4d76fdd23b19319..1b93b9c60e553abadc33216bedd06c1880aeae86 100644 (file)
@@ -33,6 +33,8 @@
 #define FLUSH_STABLE           4       /* commit to stable storage */
 #define FLUSH_LOWPRI           8       /* low priority background flush */
 #define FLUSH_HIGHPRI          16      /* high priority memory reclaim flush */
+#define FLUSH_COND_STABLE      32      /* conditional stable write - only stable
+                                        * if everything fits in one RPC */
 
 #ifdef __KERNEL__
 
@@ -93,8 +95,13 @@ struct nfs_open_context {
        int error;
 
        struct list_head list;
+};
 
+struct nfs_open_dir_context {
+       struct rpc_cred *cred;
        __u64 dir_cookie;
+       __u64 dup_cookie;
+       int duped;
 };
 
 /*
@@ -191,6 +198,7 @@ struct nfs_inode {
 
        /* pNFS layout information */
        struct pnfs_layout_hdr *layout;
+       atomic_t                commits_outstanding;
 #endif /* CONFIG_NFS_V4*/
 #ifdef CONFIG_NFS_FSCACHE
        struct fscache_cookie   *fscache;
@@ -219,6 +227,8 @@ struct nfs_inode {
 #define NFS_INO_FSCACHE                (5)             /* inode can be cached by FS-Cache */
 #define NFS_INO_FSCACHE_LOCK   (6)             /* FS-Cache cookie management lock */
 #define NFS_INO_COMMIT         (7)             /* inode is committing unstable writes */
+#define NFS_INO_PNFS_COMMIT    (8)             /* use pnfs code for commit */
+#define NFS_INO_LAYOUTCOMMIT   (9)             /* layoutcommit required */
 
 static inline struct nfs_inode *NFS_I(const struct inode *inode)
 {
index 90907ada6d52dac63cbcfb7712f97e3a3a8853d3..8023e4e25133cbcebbbd97b85c33df1943d34e13 100644 (file)
@@ -33,11 +33,15 @@ enum {
        PG_CLEAN,
        PG_NEED_COMMIT,
        PG_NEED_RESCHED,
+       PG_PNFS_COMMIT,
 };
 
 struct nfs_inode;
 struct nfs_page {
-       struct list_head        wb_list;        /* Defines state of page: */
+       union {
+               struct list_head        wb_list;        /* Defines state of page: */
+               struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */
+       };
        struct page             *wb_page;       /* page to read in/write out */
        struct nfs_open_context *wb_context;    /* File state context info */
        struct nfs_lock_context *wb_lock_context;       /* lock context info */
@@ -57,6 +61,7 @@ struct nfs_pageio_descriptor {
        size_t                  pg_count;
        size_t                  pg_bsize;
        unsigned int            pg_base;
+       char                    pg_moreio;
 
        struct inode            *pg_inode;
        int                     (*pg_doio)(struct nfs_pageio_descriptor *);
index 2c2c67d2eb42293370481fc7c70f5feeebfa8aaf..78b101e487eac78113ea001974d7e50ebf6b6e8b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/nfsacl.h>
 #include <linux/nfs3.h>
+#include <linux/sunrpc/gss_api.h>
 
 /*
  * To change the maximum rsize and wsize supported by the NFS client, adjust
@@ -14,6 +15,9 @@
 #define NFS_DEF_FILE_IO_SIZE   (4096U)
 #define NFS_MIN_FILE_IO_SIZE   (1024U)
 
+/* Forward declaration for NFS v3 */
+struct nfs4_secinfo_flavors;
+
 struct nfs_fsid {
        uint64_t                major;
        uint64_t                minor;
@@ -78,6 +82,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_CHANGE          (1U << 17)
 #define NFS_ATTR_FATTR_PRECHANGE       (1U << 18)
 #define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
+#define NFS_ATTR_FATTR_MOUNTPOINT      (1U << 20)      /* Treat as mountpoint */
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
                | NFS_ATTR_FATTR_MODE \
@@ -190,8 +195,9 @@ struct nfs4_get_lease_time_res {
 #define PNFS_LAYOUT_MAXSIZE 4096
 
 struct nfs4_layoutdriver_data {
+       struct page **pages;
+       __u32 pglen;
        __u32 len;
-       void *buf;
 };
 
 struct pnfs_layout_range {
@@ -209,6 +215,7 @@ struct nfs4_layoutget_args {
        struct nfs_open_context *ctx;
        struct nfs4_sequence_args seq_args;
        nfs4_stateid stateid;
+       struct nfs4_layoutdriver_data layout;
 };
 
 struct nfs4_layoutget_res {
@@ -216,8 +223,8 @@ struct nfs4_layoutget_res {
        struct pnfs_layout_range range;
        __u32 type;
        nfs4_stateid stateid;
-       struct nfs4_layoutdriver_data layout;
        struct nfs4_sequence_res seq_res;
+       struct nfs4_layoutdriver_data *layoutp;
 };
 
 struct nfs4_layoutget {
@@ -236,6 +243,29 @@ struct nfs4_getdeviceinfo_res {
        struct nfs4_sequence_res seq_res;
 };
 
+struct nfs4_layoutcommit_args {
+       nfs4_stateid stateid;
+       __u64 lastbytewritten;
+       struct inode *inode;
+       const u32 *bitmask;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_layoutcommit_res {
+       struct nfs_fattr *fattr;
+       const struct nfs_server *server;
+       struct nfs4_sequence_res seq_res;
+};
+
+struct nfs4_layoutcommit_data {
+       struct rpc_task task;
+       struct nfs_fattr fattr;
+       struct pnfs_layout_segment *lseg;
+       struct rpc_cred *cred;
+       struct nfs4_layoutcommit_args args;
+       struct nfs4_layoutcommit_res res;
+};
+
 /*
  * Arguments to the open call.
  */
@@ -936,6 +966,38 @@ struct nfs4_fs_locations_res {
        struct nfs4_sequence_res        seq_res;
 };
 
+struct nfs4_secinfo_oid {
+       unsigned int len;
+       char data[GSS_OID_MAX_LEN];
+};
+
+struct nfs4_secinfo_gss {
+       struct nfs4_secinfo_oid sec_oid4;
+       unsigned int qop4;
+       unsigned int service;
+};
+
+struct nfs4_secinfo_flavor {
+       unsigned int            flavor;
+       struct nfs4_secinfo_gss gss;
+};
+
+struct nfs4_secinfo_flavors {
+       unsigned int num_flavors;
+       struct nfs4_secinfo_flavor flavors[0];
+};
+
+struct nfs4_secinfo_arg {
+       const struct nfs_fh             *dir_fh;
+       const struct qstr               *name;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs4_secinfo_res {
+       struct nfs4_secinfo_flavors     *flavors;
+       struct nfs4_sequence_res        seq_res;
+};
+
 #endif /* CONFIG_NFS_V4 */
 
 struct nfstime4 {
@@ -1040,6 +1102,7 @@ struct nfs_write_data {
        struct nfs_writeres     res;            /* result struct */
        struct pnfs_layout_segment *lseg;
        struct nfs_client       *ds_clp;        /* pNFS data server */
+       int                     ds_commit_index;
        const struct rpc_call_ops *mds_ops;
        int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data);
 #ifdef CONFIG_NFS_V4
@@ -1071,7 +1134,7 @@ struct nfs_rpc_ops {
                            struct nfs_fattr *);
        int     (*setattr) (struct dentry *, struct nfs_fattr *,
                            struct iattr *);
-       int     (*lookup)  (struct inode *, struct qstr *,
+       int     (*lookup)  (struct rpc_clnt *clnt, struct inode *, struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *);
        int     (*access)  (struct inode *, struct nfs_access_entry *);
        int     (*readlink)(struct inode *, struct page *, unsigned int,
@@ -1118,6 +1181,7 @@ struct nfs_rpc_ops {
                                struct iattr *iattr);
        int     (*init_client) (struct nfs_client *, const struct rpc_timeout *,
                                const char *, rpc_authflavor_t, int);
+       int     (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
 };
 
 /*
index 227e49dd5720f5743661aedfc43fa6cb1e461f94..8768c469e93e611f1636748cf5cabf8250896ec7 100644 (file)
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
-
-/*
- * Inode flags stored in nilfs_inode and on-memory nilfs inode
- *
- * We define these flags based on ext2-fs because of the
- * compatibility reason; to avoid problems in chattr(1)
- */
-#define NILFS_SECRM_FL         0x00000001 /* Secure deletion */
-#define NILFS_UNRM_FL          0x00000002 /* Undelete */
-#define NILFS_SYNC_FL          0x00000008 /* Synchronous updates */
-#define NILFS_IMMUTABLE_FL     0x00000010 /* Immutable file */
-#define NILFS_APPEND_FL                0x00000020 /* writes to file may only append */
-#define NILFS_NODUMP_FL                0x00000040 /* do not dump file */
-#define NILFS_NOATIME_FL       0x00000080 /* do not update atime */
-/* Reserved for compression usage... */
-#define NILFS_NOTAIL_FL                0x00008000 /* file tail should not be merged */
-#define NILFS_DIRSYNC_FL       0x00010000 /* dirsync behaviour */
-
-#define NILFS_FL_USER_VISIBLE  0x0003DFFF /* User visible flags */
-#define NILFS_FL_USER_MODIFIABLE       0x000380FF /* User modifiable flags */
+#include <linux/magic.h>
 
 
 #define NILFS_INODE_BMAP_SIZE  7
@@ -236,8 +217,10 @@ struct nilfs_super_block {
  * If there is a bit set in the incompatible feature set that the kernel
  * doesn't know about, it should refuse to mount the filesystem.
  */
+#define NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT    0x00000001ULL
+
 #define NILFS_FEATURE_COMPAT_SUPP      0ULL
-#define NILFS_FEATURE_COMPAT_RO_SUPP   0ULL
+#define NILFS_FEATURE_COMPAT_RO_SUPP   NILFS_FEATURE_COMPAT_RO_BLOCK_COUNT
 #define NILFS_FEATURE_INCOMPAT_SUPP    0ULL
 
 /*
@@ -260,7 +243,6 @@ struct nilfs_super_block {
 #define NILFS_USER_INO         11      /* Fisrt user's file inode number */
 
 #define NILFS_SB_OFFSET_BYTES  1024    /* byte offset of nilfs superblock */
-#define NILFS_SUPER_MAGIC      0x3434  /* NILFS filesystem  magic number */
 
 #define NILFS_SEG_MIN_BLOCKS   16      /* Minimum number of blocks in
                                           a full segment */
@@ -346,17 +328,21 @@ static inline unsigned nilfs_rec_len_from_disk(__le16 dlen)
 {
        unsigned len = le16_to_cpu(dlen);
 
+#if !defined(__KERNEL__) || (PAGE_CACHE_SIZE >= 65536)
        if (len == NILFS_MAX_REC_LEN)
                return 1 << 16;
+#endif
        return len;
 }
 
 static inline __le16 nilfs_rec_len_to_disk(unsigned len)
 {
+#if !defined(__KERNEL__) || (PAGE_CACHE_SIZE >= 65536)
        if (len == (1 << 16))
                return cpu_to_le16(NILFS_MAX_REC_LEN);
        else if (len > (1 << 16))
                BUG();
+#endif
        return cpu_to_le16(len);
 }
 
@@ -525,7 +511,7 @@ struct nilfs_checkpoint {
        __le64 cp_create;
        __le64 cp_nblk_inc;
        __le64 cp_inodes_count;
-       __le64 cp_blocks_count;         /* Reserved (might be deleted) */
+       __le64 cp_blocks_count;
 
        /* Do not change the byte offset of ifile inode.
           To keep the compatibility of the disk format,
index 17c7e21c0bd7745a383ce1dddd9269c75214ae90..fb51ae38cea7b6cdf6497670147da05b41af5aea 100644 (file)
@@ -52,9 +52,6 @@ extern struct platform_device *of_platform_device_create(struct device_node *np,
                                                   const char *bus_id,
                                                   struct device *parent);
 
-/* pseudo "matches" value to not do deep probe */
-#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
-
 extern int of_platform_bus_probe(struct device_node *root,
                                 const struct of_device_id *matches,
                                 struct device *parent);
diff --git a/include/linux/omap3isp.h b/include/linux/omap3isp.h
new file mode 100644 (file)
index 0000000..150822b
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * omap3isp.h
+ *
+ * TI OMAP3 ISP - User-space API
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP3_ISP_USER_H
+#define OMAP3_ISP_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Private IOCTLs
+ *
+ * VIDIOC_OMAP3ISP_CCDC_CFG: Set CCDC configuration
+ * VIDIOC_OMAP3ISP_PRV_CFG: Set preview engine configuration
+ * VIDIOC_OMAP3ISP_AEWB_CFG: Set AEWB module configuration
+ * VIDIOC_OMAP3ISP_HIST_CFG: Set histogram module configuration
+ * VIDIOC_OMAP3ISP_AF_CFG: Set auto-focus module configuration
+ * VIDIOC_OMAP3ISP_STAT_REQ: Read statistics (AEWB/AF/histogram) data
+ * VIDIOC_OMAP3ISP_STAT_EN: Enable/disable a statistics module
+ */
+
+#define VIDIOC_OMAP3ISP_CCDC_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct omap3isp_ccdc_update_config)
+#define VIDIOC_OMAP3ISP_PRV_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct omap3isp_prev_update_config)
+#define VIDIOC_OMAP3ISP_AEWB_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct omap3isp_h3a_aewb_config)
+#define VIDIOC_OMAP3ISP_HIST_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct omap3isp_hist_config)
+#define VIDIOC_OMAP3ISP_AF_CFG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct omap3isp_h3a_af_config)
+#define VIDIOC_OMAP3ISP_STAT_REQ \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct omap3isp_stat_data)
+#define VIDIOC_OMAP3ISP_STAT_EN \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 7, unsigned long)
+
+/*
+ * Events
+ *
+ * V4L2_EVENT_OMAP3ISP_AEWB: AEWB statistics data ready
+ * V4L2_EVENT_OMAP3ISP_AF: AF statistics data ready
+ * V4L2_EVENT_OMAP3ISP_HIST: Histogram statistics data ready
+ * V4L2_EVENT_OMAP3ISP_HS_VS: Horizontal/vertical synchronization detected
+ */
+
+#define V4L2_EVENT_OMAP3ISP_CLASS      (V4L2_EVENT_PRIVATE_START | 0x100)
+#define V4L2_EVENT_OMAP3ISP_AEWB       (V4L2_EVENT_OMAP3ISP_CLASS | 0x1)
+#define V4L2_EVENT_OMAP3ISP_AF         (V4L2_EVENT_OMAP3ISP_CLASS | 0x2)
+#define V4L2_EVENT_OMAP3ISP_HIST       (V4L2_EVENT_OMAP3ISP_CLASS | 0x3)
+#define V4L2_EVENT_OMAP3ISP_HS_VS      (V4L2_EVENT_OMAP3ISP_CLASS | 0x4)
+
+struct omap3isp_stat_event_status {
+       __u32 frame_number;
+       __u16 config_counter;
+       __u8 buf_err;
+};
+
+/* AE/AWB related structures and flags*/
+
+/* H3A Range Constants */
+#define OMAP3ISP_AEWB_MAX_SATURATION_LIM       1023
+#define OMAP3ISP_AEWB_MIN_WIN_H                        2
+#define OMAP3ISP_AEWB_MAX_WIN_H                        256
+#define OMAP3ISP_AEWB_MIN_WIN_W                        6
+#define OMAP3ISP_AEWB_MAX_WIN_W                        256
+#define OMAP3ISP_AEWB_MIN_WINVC                        1
+#define OMAP3ISP_AEWB_MIN_WINHC                        1
+#define OMAP3ISP_AEWB_MAX_WINVC                        128
+#define OMAP3ISP_AEWB_MAX_WINHC                        36
+#define OMAP3ISP_AEWB_MAX_WINSTART             4095
+#define OMAP3ISP_AEWB_MIN_SUB_INC              2
+#define OMAP3ISP_AEWB_MAX_SUB_INC              32
+#define OMAP3ISP_AEWB_MAX_BUF_SIZE             83600
+
+#define OMAP3ISP_AF_IIRSH_MIN                  0
+#define OMAP3ISP_AF_IIRSH_MAX                  4095
+#define OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN 1
+#define OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX 36
+#define OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN   1
+#define OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX   128
+#define OMAP3ISP_AF_PAXEL_INCREMENT_MIN                2
+#define OMAP3ISP_AF_PAXEL_INCREMENT_MAX                32
+#define OMAP3ISP_AF_PAXEL_HEIGHT_MIN           2
+#define OMAP3ISP_AF_PAXEL_HEIGHT_MAX           256
+#define OMAP3ISP_AF_PAXEL_WIDTH_MIN            16
+#define OMAP3ISP_AF_PAXEL_WIDTH_MAX            256
+#define OMAP3ISP_AF_PAXEL_HZSTART_MIN          1
+#define OMAP3ISP_AF_PAXEL_HZSTART_MAX          4095
+#define OMAP3ISP_AF_PAXEL_VTSTART_MIN          0
+#define OMAP3ISP_AF_PAXEL_VTSTART_MAX          4095
+#define OMAP3ISP_AF_THRESHOLD_MAX              255
+#define OMAP3ISP_AF_COEF_MAX                   4095
+#define OMAP3ISP_AF_PAXEL_SIZE                 48
+#define OMAP3ISP_AF_MAX_BUF_SIZE               221184
+
+/**
+ * struct omap3isp_h3a_aewb_config - AE AWB configuration reset values
+ * saturation_limit: Saturation limit.
+ * @win_height: Window Height. Range 2 - 256, even values only.
+ * @win_width: Window Width. Range 6 - 256, even values only.
+ * @ver_win_count: Vertical Window Count. Range 1 - 128.
+ * @hor_win_count: Horizontal Window Count. Range 1 - 36.
+ * @ver_win_start: Vertical Window Start. Range 0 - 4095.
+ * @hor_win_start: Horizontal Window Start. Range 0 - 4095.
+ * @blk_ver_win_start: Black Vertical Windows Start. Range 0 - 4095.
+ * @blk_win_height: Black Window Height. Range 2 - 256, even values only.
+ * @subsample_ver_inc: Subsample Vertical points increment Range 2 - 32, even
+ *                     values only.
+ * @subsample_hor_inc: Subsample Horizontal points increment Range 2 - 32, even
+ *                     values only.
+ * @alaw_enable: AEW ALAW EN flag.
+ */
+struct omap3isp_h3a_aewb_config {
+       /*
+        * Common fields.
+        * They should be the first ones and must be in the same order as in
+        * ispstat_generic_config struct.
+        */
+       __u32 buf_size;
+       __u16 config_counter;
+
+       /* Private fields */
+       __u16 saturation_limit;
+       __u16 win_height;
+       __u16 win_width;
+       __u16 ver_win_count;
+       __u16 hor_win_count;
+       __u16 ver_win_start;
+       __u16 hor_win_start;
+       __u16 blk_ver_win_start;
+       __u16 blk_win_height;
+       __u16 subsample_ver_inc;
+       __u16 subsample_hor_inc;
+       __u8 alaw_enable;
+};
+
+/**
+ * struct omap3isp_stat_data - Statistic data sent to or received from user
+ * @ts: Timestamp of returned framestats.
+ * @buf: Pointer to pass to user.
+ * @frame_number: Frame number of requested stats.
+ * @cur_frame: Current frame number being processed.
+ * @config_counter: Number of the configuration associated with the data.
+ */
+struct omap3isp_stat_data {
+       struct timeval ts;
+       void __user *buf;
+       __u32 buf_size;
+       __u16 frame_number;
+       __u16 cur_frame;
+       __u16 config_counter;
+};
+
+
+/* Histogram related structs */
+
+/* Flags for number of bins */
+#define OMAP3ISP_HIST_BINS_32          0
+#define OMAP3ISP_HIST_BINS_64          1
+#define OMAP3ISP_HIST_BINS_128         2
+#define OMAP3ISP_HIST_BINS_256         3
+
+/* Number of bins * 4 colors * 4-bytes word */
+#define OMAP3ISP_HIST_MEM_SIZE_BINS(n) ((1 << ((n)+5))*4*4)
+
+#define OMAP3ISP_HIST_MEM_SIZE         1024
+#define OMAP3ISP_HIST_MIN_REGIONS      1
+#define OMAP3ISP_HIST_MAX_REGIONS      4
+#define OMAP3ISP_HIST_MAX_WB_GAIN      255
+#define OMAP3ISP_HIST_MIN_WB_GAIN      0
+#define OMAP3ISP_HIST_MAX_BIT_WIDTH    14
+#define OMAP3ISP_HIST_MIN_BIT_WIDTH    8
+#define OMAP3ISP_HIST_MAX_WG           4
+#define OMAP3ISP_HIST_MAX_BUF_SIZE     4096
+
+/* Source */
+#define OMAP3ISP_HIST_SOURCE_CCDC      0
+#define OMAP3ISP_HIST_SOURCE_MEM       1
+
+/* CFA pattern */
+#define OMAP3ISP_HIST_CFA_BAYER                0
+#define OMAP3ISP_HIST_CFA_FOVEONX3     1
+
+struct omap3isp_hist_region {
+       __u16 h_start;
+       __u16 h_end;
+       __u16 v_start;
+       __u16 v_end;
+};
+
+struct omap3isp_hist_config {
+       /*
+        * Common fields.
+        * They should be the first ones and must be in the same order as in
+        * ispstat_generic_config struct.
+        */
+       __u32 buf_size;
+       __u16 config_counter;
+
+       __u8 num_acc_frames;    /* Num of image frames to be processed and
+                                  accumulated for each histogram frame */
+       __u16 hist_bins;        /* number of bins: 32, 64, 128, or 256 */
+       __u8 cfa;               /* BAYER or FOVEON X3 */
+       __u8 wg[OMAP3ISP_HIST_MAX_WG];  /* White Balance Gain */
+       __u8 num_regions;       /* number of regions to be configured */
+       struct omap3isp_hist_region region[OMAP3ISP_HIST_MAX_REGIONS];
+};
+
+/* Auto Focus related structs */
+
+#define OMAP3ISP_AF_NUM_COEF           11
+
+enum omap3isp_h3a_af_fvmode {
+       OMAP3ISP_AF_MODE_SUMMED = 0,
+       OMAP3ISP_AF_MODE_PEAK = 1
+};
+
+/* Red, Green, and blue pixel location in the AF windows */
+enum omap3isp_h3a_af_rgbpos {
+       OMAP3ISP_AF_GR_GB_BAYER = 0,    /* GR and GB as Bayer pattern */
+       OMAP3ISP_AF_RG_GB_BAYER = 1,    /* RG and GB as Bayer pattern */
+       OMAP3ISP_AF_GR_BG_BAYER = 2,    /* GR and BG as Bayer pattern */
+       OMAP3ISP_AF_RG_BG_BAYER = 3,    /* RG and BG as Bayer pattern */
+       OMAP3ISP_AF_GG_RB_CUSTOM = 4,   /* GG and RB as custom pattern */
+       OMAP3ISP_AF_RB_GG_CUSTOM = 5    /* RB and GG as custom pattern */
+};
+
+/* Contains the information regarding the Horizontal Median Filter */
+struct omap3isp_h3a_af_hmf {
+       __u8 enable;    /* Status of Horizontal Median Filter */
+       __u8 threshold; /* Threshhold Value for Horizontal Median Filter */
+};
+
+/* Contains the information regarding the IIR Filters */
+struct omap3isp_h3a_af_iir {
+       __u16 h_start;                  /* IIR horizontal start */
+       __u16 coeff_set0[OMAP3ISP_AF_NUM_COEF]; /* Filter coefficient, set 0 */
+       __u16 coeff_set1[OMAP3ISP_AF_NUM_COEF]; /* Filter coefficient, set 1 */
+};
+
+/* Contains the information regarding the Paxels Structure in AF Engine */
+struct omap3isp_h3a_af_paxel {
+       __u16 h_start;  /* Horizontal Start Position */
+       __u16 v_start;  /* Vertical Start Position */
+       __u8 width;     /* Width of the Paxel */
+       __u8 height;    /* Height of the Paxel */
+       __u8 h_cnt;     /* Horizontal Count */
+       __u8 v_cnt;     /* vertical Count */
+       __u8 line_inc;  /* Line Increment */
+};
+
+/* Contains the parameters required for hardware set up of AF Engine */
+struct omap3isp_h3a_af_config {
+       /*
+        * Common fields.
+        * They should be the first ones and must be in the same order as in
+        * ispstat_generic_config struct.
+        */
+       __u32 buf_size;
+       __u16 config_counter;
+
+       struct omap3isp_h3a_af_hmf hmf;         /* HMF configurations */
+       struct omap3isp_h3a_af_iir iir;         /* IIR filter configurations */
+       struct omap3isp_h3a_af_paxel paxel;     /* Paxel parameters */
+       enum omap3isp_h3a_af_rgbpos rgb_pos;    /* RGB Positions */
+       enum omap3isp_h3a_af_fvmode fvmode;     /* Accumulator mode */
+       __u8 alaw_enable;                       /* AF ALAW status */
+};
+
+/* ISP CCDC structs */
+
+/* Abstraction layer CCDC configurations */
+#define OMAP3ISP_CCDC_ALAW             (1 << 0)
+#define OMAP3ISP_CCDC_LPF              (1 << 1)
+#define OMAP3ISP_CCDC_BLCLAMP          (1 << 2)
+#define OMAP3ISP_CCDC_BCOMP            (1 << 3)
+#define OMAP3ISP_CCDC_FPC              (1 << 4)
+#define OMAP3ISP_CCDC_CULL             (1 << 5)
+#define OMAP3ISP_CCDC_CONFIG_LSC       (1 << 7)
+#define OMAP3ISP_CCDC_TBL_LSC          (1 << 8)
+
+#define OMAP3ISP_RGB_MAX               3
+
+/* Enumeration constants for Alaw input width */
+enum omap3isp_alaw_ipwidth {
+       OMAP3ISP_ALAW_BIT12_3 = 0x3,
+       OMAP3ISP_ALAW_BIT11_2 = 0x4,
+       OMAP3ISP_ALAW_BIT10_1 = 0x5,
+       OMAP3ISP_ALAW_BIT9_0 = 0x6
+};
+
+/**
+ * struct omap3isp_ccdc_lsc_config - LSC configuration
+ * @offset: Table Offset of the gain table.
+ * @gain_mode_n: Vertical dimension of a paxel in LSC configuration.
+ * @gain_mode_m: Horizontal dimension of a paxel in LSC configuration.
+ * @gain_format: Gain table format.
+ * @fmtsph: Start pixel horizontal from start of the HS sync pulse.
+ * @fmtlnh: Number of pixels in horizontal direction to use for the data
+ *          reformatter.
+ * @fmtslv: Start line from start of VS sync pulse for the data reformatter.
+ * @fmtlnv: Number of lines in vertical direction for the data reformatter.
+ * @initial_x: X position, in pixels, of the first active pixel in reference
+ *             to the first active paxel. Must be an even number.
+ * @initial_y: Y position, in pixels, of the first active pixel in reference
+ *             to the first active paxel. Must be an even number.
+ * @size: Size of LSC gain table. Filled when loaded from userspace.
+ */
+struct omap3isp_ccdc_lsc_config {
+       __u16 offset;
+       __u8 gain_mode_n;
+       __u8 gain_mode_m;
+       __u8 gain_format;
+       __u16 fmtsph;
+       __u16 fmtlnh;
+       __u16 fmtslv;
+       __u16 fmtlnv;
+       __u8 initial_x;
+       __u8 initial_y;
+       __u32 size;
+};
+
+/**
+ * struct omap3isp_ccdc_bclamp - Optical & Digital black clamp subtract
+ * @obgain: Optical black average gain.
+ * @obstpixel: Start Pixel w.r.t. HS pulse in Optical black sample.
+ * @oblines: Optical Black Sample lines.
+ * @oblen: Optical Black Sample Length.
+ * @dcsubval: Digital Black Clamp subtract value.
+ */
+struct omap3isp_ccdc_bclamp {
+       __u8 obgain;
+       __u8 obstpixel;
+       __u8 oblines;
+       __u8 oblen;
+       __u16 dcsubval;
+};
+
+/**
+ * struct omap3isp_ccdc_fpc - Faulty Pixels Correction
+ * @fpnum: Number of faulty pixels to be corrected in the frame.
+ * @fpcaddr: Memory address of the FPC Table
+ */
+struct omap3isp_ccdc_fpc {
+       __u16 fpnum;
+       __u32 fpcaddr;
+};
+
+/**
+ * struct omap3isp_ccdc_blcomp - Black Level Compensation parameters
+ * @b_mg: B/Mg pixels. 2's complement. -128 to +127.
+ * @gb_g: Gb/G pixels. 2's complement. -128 to +127.
+ * @gr_cy: Gr/Cy pixels. 2's complement. -128 to +127.
+ * @r_ye: R/Ye pixels. 2's complement. -128 to +127.
+ */
+struct omap3isp_ccdc_blcomp {
+       __u8 b_mg;
+       __u8 gb_g;
+       __u8 gr_cy;
+       __u8 r_ye;
+};
+
+/**
+ * omap3isp_ccdc_culling - Culling parameters
+ * @v_pattern: Vertical culling pattern.
+ * @h_odd: Horizontal Culling pattern for odd lines.
+ * @h_even: Horizontal Culling pattern for even lines.
+ */
+struct omap3isp_ccdc_culling {
+       __u8 v_pattern;
+       __u16 h_odd;
+       __u16 h_even;
+};
+
+/**
+ * omap3isp_ccdc_update_config - CCDC configuration
+ * @update: Specifies which CCDC registers should be updated.
+ * @flag: Specifies which CCDC functions should be enabled.
+ * @alawip: Enable/Disable A-Law compression.
+ * @bclamp: Black clamp control register.
+ * @blcomp: Black level compensation value for RGrGbB Pixels. 2's complement.
+ * @fpc: Number of faulty pixels corrected in the frame, address of FPC table.
+ * @cull: Cull control register.
+ * @lsc: Pointer to LSC gain table.
+ */
+struct omap3isp_ccdc_update_config {
+       __u16 update;
+       __u16 flag;
+       enum omap3isp_alaw_ipwidth alawip;
+       struct omap3isp_ccdc_bclamp __user *bclamp;
+       struct omap3isp_ccdc_blcomp __user *blcomp;
+       struct omap3isp_ccdc_fpc __user *fpc;
+       struct omap3isp_ccdc_lsc_config __user *lsc_cfg;
+       struct omap3isp_ccdc_culling __user *cull;
+       __u8 __user *lsc;
+};
+
+/* Preview configurations */
+#define OMAP3ISP_PREV_LUMAENH          (1 << 0)
+#define OMAP3ISP_PREV_INVALAW          (1 << 1)
+#define OMAP3ISP_PREV_HRZ_MED          (1 << 2)
+#define OMAP3ISP_PREV_CFA              (1 << 3)
+#define OMAP3ISP_PREV_CHROMA_SUPP      (1 << 4)
+#define OMAP3ISP_PREV_WB               (1 << 5)
+#define OMAP3ISP_PREV_BLKADJ           (1 << 6)
+#define OMAP3ISP_PREV_RGB2RGB          (1 << 7)
+#define OMAP3ISP_PREV_COLOR_CONV       (1 << 8)
+#define OMAP3ISP_PREV_YC_LIMIT         (1 << 9)
+#define OMAP3ISP_PREV_DEFECT_COR       (1 << 10)
+#define OMAP3ISP_PREV_GAMMABYPASS      (1 << 11)
+#define OMAP3ISP_PREV_DRK_FRM_CAPTURE  (1 << 12)
+#define OMAP3ISP_PREV_DRK_FRM_SUBTRACT (1 << 13)
+#define OMAP3ISP_PREV_LENS_SHADING     (1 << 14)
+#define OMAP3ISP_PREV_NF               (1 << 15)
+#define OMAP3ISP_PREV_GAMMA            (1 << 16)
+
+#define OMAP3ISP_PREV_NF_TBL_SIZE      64
+#define OMAP3ISP_PREV_CFA_TBL_SIZE     576
+#define OMAP3ISP_PREV_GAMMA_TBL_SIZE   1024
+#define OMAP3ISP_PREV_YENH_TBL_SIZE    128
+
+#define OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS  4
+
+/**
+ * struct omap3isp_prev_hmed - Horizontal Median Filter
+ * @odddist: Distance between consecutive pixels of same color in the odd line.
+ * @evendist: Distance between consecutive pixels of same color in the even
+ *            line.
+ * @thres: Horizontal median filter threshold.
+ */
+struct omap3isp_prev_hmed {
+       __u8 odddist;
+       __u8 evendist;
+       __u8 thres;
+};
+
+/*
+ * Enumeration for CFA Formats supported by preview
+ */
+enum omap3isp_cfa_fmt {
+       OMAP3ISP_CFAFMT_BAYER,
+       OMAP3ISP_CFAFMT_SONYVGA,
+       OMAP3ISP_CFAFMT_RGBFOVEON,
+       OMAP3ISP_CFAFMT_DNSPL,
+       OMAP3ISP_CFAFMT_HONEYCOMB,
+       OMAP3ISP_CFAFMT_RRGGBBFOVEON
+};
+
+/**
+ * struct omap3isp_prev_cfa - CFA Interpolation
+ * @format: CFA Format Enum value supported by preview.
+ * @gradthrs_vert: CFA Gradient Threshold - Vertical.
+ * @gradthrs_horz: CFA Gradient Threshold - Horizontal.
+ * @table: Pointer to the CFA table.
+ */
+struct omap3isp_prev_cfa {
+       enum omap3isp_cfa_fmt format;
+       __u8 gradthrs_vert;
+       __u8 gradthrs_horz;
+       __u32 table[OMAP3ISP_PREV_CFA_TBL_SIZE];
+};
+
+/**
+ * struct omap3isp_prev_csup - Chrominance Suppression
+ * @gain: Gain.
+ * @thres: Threshold.
+ * @hypf_en: Flag to enable/disable the High Pass Filter.
+ */
+struct omap3isp_prev_csup {
+       __u8 gain;
+       __u8 thres;
+       __u8 hypf_en;
+};
+
+/**
+ * struct omap3isp_prev_wbal - White Balance
+ * @dgain: Digital gain (U10Q8).
+ * @coef3: White balance gain - COEF 3 (U8Q5).
+ * @coef2: White balance gain - COEF 2 (U8Q5).
+ * @coef1: White balance gain - COEF 1 (U8Q5).
+ * @coef0: White balance gain - COEF 0 (U8Q5).
+ */
+struct omap3isp_prev_wbal {
+       __u16 dgain;
+       __u8 coef3;
+       __u8 coef2;
+       __u8 coef1;
+       __u8 coef0;
+};
+
+/**
+ * struct omap3isp_prev_blkadj - Black Level Adjustment
+ * @red: Black level offset adjustment for Red in 2's complement format
+ * @green: Black level offset adjustment for Green in 2's complement format
+ * @blue: Black level offset adjustment for Blue in 2's complement format
+ */
+struct omap3isp_prev_blkadj {
+       /*Black level offset adjustment for Red in 2's complement format */
+       __u8 red;
+       /*Black level offset adjustment for Green in 2's complement format */
+       __u8 green;
+       /* Black level offset adjustment for Blue in 2's complement format */
+       __u8 blue;
+};
+
+/**
+ * struct omap3isp_prev_rgbtorgb - RGB to RGB Blending
+ * @matrix: Blending values(S12Q8 format)
+ *              [RR] [GR] [BR]
+ *              [RG] [GG] [BG]
+ *              [RB] [GB] [BB]
+ * @offset: Blending offset value for R,G,B in 2's complement integer format.
+ */
+struct omap3isp_prev_rgbtorgb {
+       __u16 matrix[OMAP3ISP_RGB_MAX][OMAP3ISP_RGB_MAX];
+       __u16 offset[OMAP3ISP_RGB_MAX];
+};
+
+/**
+ * struct omap3isp_prev_csc - Color Space Conversion from RGB-YCbYCr
+ * @matrix: Color space conversion coefficients(S10Q8)
+ *              [CSCRY]  [CSCGY]  [CSCBY]
+ *              [CSCRCB] [CSCGCB] [CSCBCB]
+ *              [CSCRCR] [CSCGCR] [CSCBCR]
+ * @offset: CSC offset values for Y offset, CB offset and CR offset respectively
+ */
+struct omap3isp_prev_csc {
+       __u16 matrix[OMAP3ISP_RGB_MAX][OMAP3ISP_RGB_MAX];
+       __s16 offset[OMAP3ISP_RGB_MAX];
+};
+
+/**
+ * struct omap3isp_prev_yclimit - Y, C Value Limit
+ * @minC: Minimum C value
+ * @maxC: Maximum C value
+ * @minY: Minimum Y value
+ * @maxY: Maximum Y value
+ */
+struct omap3isp_prev_yclimit {
+       __u8 minC;
+       __u8 maxC;
+       __u8 minY;
+       __u8 maxY;
+};
+
+/**
+ * struct omap3isp_prev_dcor - Defect correction
+ * @couplet_mode_en: Flag to enable or disable the couplet dc Correction in NF
+ * @detect_correct: Thresholds for correction bit 0:10 detect 16:25 correct
+ */
+struct omap3isp_prev_dcor {
+       __u8 couplet_mode_en;
+       __u32 detect_correct[OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS];
+};
+
+/**
+ * struct omap3isp_prev_nf - Noise Filter
+ * @spread: Spread value to be used in Noise Filter
+ * @table: Pointer to the Noise Filter table
+ */
+struct omap3isp_prev_nf {
+       __u8 spread;
+       __u32 table[OMAP3ISP_PREV_NF_TBL_SIZE];
+};
+
+/**
+ * struct omap3isp_prev_gtables - Gamma correction tables
+ * @red: Array for red gamma table.
+ * @green: Array for green gamma table.
+ * @blue: Array for blue gamma table.
+ */
+struct omap3isp_prev_gtables {
+       __u32 red[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
+       __u32 green[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
+       __u32 blue[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
+};
+
+/**
+ * struct omap3isp_prev_luma - Luma enhancement
+ * @table: Array for luma enhancement table.
+ */
+struct omap3isp_prev_luma {
+       __u32 table[OMAP3ISP_PREV_YENH_TBL_SIZE];
+};
+
+/**
+ * struct omap3isp_prev_update_config - Preview engine configuration (user)
+ * @update: Specifies which ISP Preview registers should be updated.
+ * @flag: Specifies which ISP Preview functions should be enabled.
+ * @shading_shift: 3bit value of shift used in shading compensation.
+ * @luma: Pointer to luma enhancement structure.
+ * @hmed: Pointer to structure containing the odd and even distance.
+ *        between the pixels in the image along with the filter threshold.
+ * @cfa: Pointer to structure containing the CFA interpolation table, CFA.
+ *       format in the image, vertical and horizontal gradient threshold.
+ * @csup: Pointer to Structure for Chrominance Suppression coefficients.
+ * @wbal: Pointer to structure for White Balance.
+ * @blkadj: Pointer to structure for Black Adjustment.
+ * @rgb2rgb: Pointer to structure for RGB to RGB Blending.
+ * @csc: Pointer to structure for Color Space Conversion from RGB-YCbYCr.
+ * @yclimit: Pointer to structure for Y, C Value Limit.
+ * @dcor: Pointer to structure for defect correction.
+ * @nf: Pointer to structure for Noise Filter
+ * @gamma: Pointer to gamma structure.
+ */
+struct omap3isp_prev_update_config {
+       __u32 update;
+       __u32 flag;
+       __u32 shading_shift;
+       struct omap3isp_prev_luma __user *luma;
+       struct omap3isp_prev_hmed __user *hmed;
+       struct omap3isp_prev_cfa __user *cfa;
+       struct omap3isp_prev_csup __user *csup;
+       struct omap3isp_prev_wbal __user *wbal;
+       struct omap3isp_prev_blkadj __user *blkadj;
+       struct omap3isp_prev_rgbtorgb __user *rgb2rgb;
+       struct omap3isp_prev_csc __user *csc;
+       struct omap3isp_prev_yclimit __user *yclimit;
+       struct omap3isp_prev_dcor __user *dcor;
+       struct omap3isp_prev_nf __user *nf;
+       struct omap3isp_prev_gtables __user *gamma;
+};
+
+#endif /* OMAP3_ISP_USER_H */
index 0db8037e27256a8aa04fb81afa543a5db806482b..811183de1ef5eb27792b0b272f7e513c6b78d457 100644 (file)
@@ -196,7 +196,7 @@ static inline int __TestClearPage##uname(struct page *page) { return 0; }
 
 struct page;   /* forward declaration */
 
-TESTPAGEFLAG(Locked, locked) TESTSETFLAG(Locked, locked)
+TESTPAGEFLAG(Locked, locked)
 PAGEFLAG(Error, error) TESTCLEARFLAG(Error, error)
 PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
 PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty)
index 6d6cb7a57bb3af7129baa644d7f3de0c24a58eab..f5de21de31dda91b54b05c199616ccf2113864b9 100644 (file)
@@ -1,8 +1,26 @@
 #ifndef __LINUX_PAGE_CGROUP_H
 #define __LINUX_PAGE_CGROUP_H
 
+enum {
+       /* flags for mem_cgroup */
+       PCG_LOCK,  /* Lock for pc->mem_cgroup and following bits. */
+       PCG_CACHE, /* charged as cache */
+       PCG_USED, /* this object is in use. */
+       PCG_MIGRATION, /* under page migration */
+       /* flags for mem_cgroup and file and I/O status */
+       PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
+       PCG_FILE_MAPPED, /* page is accounted as "mapped" */
+       /* No lock in page_cgroup */
+       PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
+       __NR_PCG_FLAGS,
+};
+
+#ifndef __GENERATING_BOUNDS_H
+#include <generated/bounds.h>
+
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 #include <linux/bit_spinlock.h>
+
 /*
  * Page Cgroup can be considered as an extended mem_map.
  * A page_cgroup page is associated with every page descriptor. The
@@ -13,7 +31,6 @@
 struct page_cgroup {
        unsigned long flags;
        struct mem_cgroup *mem_cgroup;
-       struct page *page;
        struct list_head lru;           /* per cgroup LRU list */
 };
 
@@ -32,19 +49,7 @@ static inline void __init page_cgroup_init(void)
 #endif
 
 struct page_cgroup *lookup_page_cgroup(struct page *page);
-
-enum {
-       /* flags for mem_cgroup */
-       PCG_LOCK,  /* Lock for pc->mem_cgroup and following bits. */
-       PCG_CACHE, /* charged as cache */
-       PCG_USED, /* this object is in use. */
-       PCG_MIGRATION, /* under page migration */
-       /* flags for mem_cgroup and file and I/O status */
-       PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
-       PCG_FILE_MAPPED, /* page is accounted as "mapped" */
-       /* No lock in page_cgroup */
-       PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
-};
+struct page *lookup_cgroup_page(struct page_cgroup *pc);
 
 #define TESTPCGFLAG(uname, lname)                      \
 static inline int PageCgroup##uname(struct page_cgroup *pc)    \
@@ -85,16 +90,6 @@ SETPCGFLAG(Migration, MIGRATION)
 CLEARPCGFLAG(Migration, MIGRATION)
 TESTPCGFLAG(Migration, MIGRATION)
 
-static inline int page_cgroup_nid(struct page_cgroup *pc)
-{
-       return page_to_nid(pc->page);
-}
-
-static inline enum zone_type page_cgroup_zid(struct page_cgroup *pc)
-{
-       return page_zonenum(pc->page);
-}
-
 static inline void lock_page_cgroup(struct page_cgroup *pc)
 {
        /*
@@ -109,11 +104,6 @@ static inline void unlock_page_cgroup(struct page_cgroup *pc)
        bit_spin_unlock(PCG_LOCK, &pc->flags);
 }
 
-static inline int page_is_cgroup_locked(struct page_cgroup *pc)
-{
-       return bit_spin_is_locked(PCG_LOCK, &pc->flags);
-}
-
 static inline void move_lock_page_cgroup(struct page_cgroup *pc,
        unsigned long *flags)
 {
@@ -132,6 +122,39 @@ static inline void move_unlock_page_cgroup(struct page_cgroup *pc,
        local_irq_restore(*flags);
 }
 
+#ifdef CONFIG_SPARSEMEM
+#define PCG_ARRAYID_WIDTH      SECTIONS_SHIFT
+#else
+#define PCG_ARRAYID_WIDTH      NODES_SHIFT
+#endif
+
+#if (PCG_ARRAYID_WIDTH > BITS_PER_LONG - NR_PCG_FLAGS)
+#error Not enough space left in pc->flags to store page_cgroup array IDs
+#endif
+
+/* pc->flags: ARRAY-ID | FLAGS */
+
+#define PCG_ARRAYID_MASK       ((1UL << PCG_ARRAYID_WIDTH) - 1)
+
+#define PCG_ARRAYID_OFFSET     (BITS_PER_LONG - PCG_ARRAYID_WIDTH)
+/*
+ * Zero the shift count for non-existant fields, to prevent compiler
+ * warnings and ensure references are optimized away.
+ */
+#define PCG_ARRAYID_SHIFT      (PCG_ARRAYID_OFFSET * (PCG_ARRAYID_WIDTH != 0))
+
+static inline void set_page_cgroup_array_id(struct page_cgroup *pc,
+                                           unsigned long id)
+{
+       pc->flags &= ~(PCG_ARRAYID_MASK << PCG_ARRAYID_SHIFT);
+       pc->flags |= (id & PCG_ARRAYID_MASK) << PCG_ARRAYID_SHIFT;
+}
+
+static inline unsigned long page_cgroup_array_id(struct page_cgroup *pc)
+{
+       return (pc->flags >> PCG_ARRAYID_SHIFT) & PCG_ARRAYID_MASK;
+}
+
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct page_cgroup;
 
@@ -152,7 +175,7 @@ static inline void __init page_cgroup_init_flatmem(void)
 {
 }
 
-#endif
+#endif /* CONFIG_CGROUP_MEM_RES_CTLR */
 
 #include <linux/swap.h>
 
@@ -188,5 +211,8 @@ static inline void swap_cgroup_swapoff(int type)
        return;
 }
 
-#endif
-#endif
+#endif /* CONFIG_CGROUP_MEM_RES_CTLR_SWAP */
+
+#endif /* !__GENERATING_BOUNDS_H */
+
+#endif /* __LINUX_PAGE_CGROUP_H */
index 9c66e994540f6d91750e6d78b30201c0156e0de9..c119506526467d204b2c78a7d47bc0a7152129a4 100644 (file)
@@ -298,7 +298,6 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
 
 extern void __lock_page(struct page *page);
 extern int __lock_page_killable(struct page *page);
-extern void __lock_page_nosync(struct page *page);
 extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                                unsigned int flags);
 extern void unlock_page(struct page *page);
@@ -341,17 +340,6 @@ static inline int lock_page_killable(struct page *page)
        return 0;
 }
 
-/*
- * lock_page_nosync should only be used if we can't pin the page's inode.
- * Doesn't play quite so well with block device plugging.
- */
-static inline void lock_page_nosync(struct page *page)
-{
-       might_sleep();
-       if (!trylock_page(page))
-               __lock_page_nosync(page);
-}
-       
 /*
  * lock_page_or_retry - Lock the page, unless this would block and the
  * caller indicated that it can handle a retry.
@@ -455,8 +443,9 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
                                pgoff_t index, gfp_t gfp_mask);
 int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
                                pgoff_t index, gfp_t gfp_mask);
-extern void remove_from_page_cache(struct page *page);
-extern void __remove_from_page_cache(struct page *page);
+extern void delete_from_page_cache(struct page *page);
+extern void __delete_from_page_cache(struct page *page);
+int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask);
 
 /*
  * Like add_to_page_cache_locked, but used to add newly allocated pages:
index ce6810512c6629598f99a25775663dc7f8fa24c4..67cb3ae3801696f973ffc15e491513167cad99c5 100644 (file)
@@ -26,6 +26,7 @@
 extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
 extern void pci_disable_link_state(struct pci_dev *pdev, int state);
 extern void pcie_clear_aspm(void);
 extern void pcie_no_aspm(void);
@@ -39,6 +40,9 @@ static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev)
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
 {
 }
+static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
+{
+}
 static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
 }
index 16c9f2e61977e6f7e3192384435e43ad6aaecf9d..96f70d7e058dd043716ae216e3918567923f28bb 100644 (file)
@@ -1002,12 +1002,11 @@ extern bool pcie_ports_auto;
 #endif
 
 #ifndef CONFIG_PCIEASPM
-static inline int pcie_aspm_enabled(void)
-{
-       return 0;
-}
+static inline int pcie_aspm_enabled(void) { return 0; }
+static inline bool pcie_aspm_support_enabled(void) { return false; }
 #else
 extern int pcie_aspm_enabled(void);
+extern bool pcie_aspm_support_enabled(void);
 #endif
 
 #ifdef CONFIG_PCIEAER
index bda221dfaf0aa849119a3b5ce4a6000ae1eaa57e..11fd38151cc9bda3c96c9709aa5c92249f840fee 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82372FB_1  0x7601
 #define PCI_DEVICE_ID_INTEL_SCH_LPC    0x8119
 #define PCI_DEVICE_ID_INTEL_SCH_IDE    0x811a
+#define PCI_DEVICE_ID_INTEL_ITC_LPC    0x8186
 #define PCI_DEVICE_ID_INTEL_82454GX    0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX    0x84ca
index f495c01472404263fff40e0c694fa6c5375a882d..311b4dc785a19b5188cdd32260b50041d3403cc6 100644 (file)
@@ -938,9 +938,7 @@ struct perf_cpu_context {
        struct list_head                rotation_list;
        int                             jiffies_interval;
        struct pmu                      *active_pmu;
-#ifdef CONFIG_CGROUP_PERF
        struct perf_cgroup              *cgrp;
-#endif
 };
 
 struct perf_output_handle {
index 49f1c2f66e951bc7e226a5809450af8714c80473..efceda0a51b137b3c154488a5f6d90385be064ba 100644 (file)
@@ -140,6 +140,17 @@ static inline struct pid_namespace *ns_of_pid(struct pid *pid)
        return ns;
 }
 
+/*
+ * is_child_reaper returns true if the pid is the init process
+ * of the current namespace. As this one could be checked before
+ * pid_ns->child_reaper is assigned in copy_process, we check
+ * with the pid number.
+ */
+static inline bool is_child_reaper(struct pid *pid)
+{
+       return pid->numbers[pid->level].nr == 1;
+}
+
 /*
  * the helpers to get the pid's id seen from different namespaces
  *
diff --git a/include/linux/power/bq20z75.h b/include/linux/power/bq20z75.h
new file mode 100644 (file)
index 0000000..b0843b6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Gas Gauge driver for TI's BQ20Z75
+ *
+ * Copyright (c) 2010, NVIDIA 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __LINUX_POWER_BQ20Z75_H_
+#define __LINUX_POWER_BQ20Z75_H_
+
+#include <linux/power_supply.h>
+#include <linux/types.h>
+
+/**
+ * struct bq20z75_platform_data - platform data for bq20z75 devices
+ * @battery_detect:            GPIO which is used to detect battery presence
+ * @battery_detect_present:    gpio state when battery is present (0 / 1)
+ * @i2c_retry_count:           # of times to retry on i2c IO failure
+ */
+struct bq20z75_platform_data {
+       int battery_detect;
+       int battery_detect_present;
+       int i2c_retry_count;
+};
+
+#endif
diff --git a/include/linux/power/bq27x00_battery.h b/include/linux/power/bq27x00_battery.h
new file mode 100644 (file)
index 0000000..a857f71
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __LINUX_BQ27X00_BATTERY_H__
+#define __LINUX_BQ27X00_BATTERY_H__
+
+/**
+ * struct bq27000_plaform_data - Platform data for bq27000 devices
+ * @name: Name of the battery. If NULL the driver will fallback to "bq27000".
+ * @read: HDQ read callback.
+ *     This function should provide access to the HDQ bus the battery is
+ *     connected to.
+ *     The first parameter is a pointer to the battery device, the second the
+ *     register to be read. The return value should either be the content of
+ *     the passed register or an error value.
+ */
+struct bq27000_platform_data {
+       const char *name;
+       int (*read)(struct device *dev, unsigned int);
+};
+
+#endif
index 7d7325685c421a8b7da8746ea47583396bb61b8c..204c18dfdc9e839a378cfd4200342784c22be5b7 100644 (file)
@@ -173,6 +173,8 @@ struct power_supply {
        char *full_trig_name;
        struct led_trigger *online_trig;
        char *online_trig_name;
+       struct led_trigger *charging_blink_full_solid_trig;
+       char *charging_blink_full_solid_trig_name;
 #endif
 };
 
@@ -213,4 +215,49 @@ extern void power_supply_unregister(struct power_supply *psy);
 /* For APM emulation, think legacy userspace. */
 extern struct class *power_supply_class;
 
+static inline bool power_supply_is_amp_property(enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_EMPTY:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_AVG:
+       case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static inline bool power_supply_is_watt_property(enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_EMPTY:
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+       case POWER_SUPPLY_PROP_ENERGY_AVG:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+       case POWER_SUPPLY_PROP_POWER_NOW:
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 #endif /* __LINUX_POWER_SUPPLY_H__ */
index 379eaed72d4b447d7e3b5098ab48e65d7bd959f9..838c1149251a1e8edff75dd2db6ef58092542386 100644 (file)
@@ -50,7 +50,7 @@ typedef       int (write_proc_t)(struct file *file, const char __user *buffer,
 
 struct proc_dir_entry {
        unsigned int low_ino;
-       unsigned short namelen;
+       unsigned int namelen;
        const char *name;
        mode_t mode;
        nlink_t nlink;
index e031e1a486d9fc8e7d7d6539c75d39df1235d2c2..5e3e25a3c9c38d3c3c5be63d2b40cd740f62cfd7 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef __LINUX_PWM_BACKLIGHT_H
 #define __LINUX_PWM_BACKLIGHT_H
 
+#include <linux/backlight.h>
+
 struct platform_pwm_backlight_data {
        int pwm_id;
        unsigned int max_brightness;
@@ -13,6 +15,7 @@ struct platform_pwm_backlight_data {
        int (*init)(struct device *dev);
        int (*notify)(struct device *dev, int brightness);
        void (*exit)(struct device *dev);
+       int (*check_fb)(struct device *dev, struct fb_info *info);
 };
 
 #endif
index eb354f6f26b333d078adb645a0488ae279935d13..26f9e3612e0f6618e8d15285db9b354d63ffbb96 100644 (file)
@@ -277,7 +277,7 @@ static inline int dquot_alloc_space(struct inode *inode, qsize_t nr)
                /*
                 * Mark inode fully dirty. Since we are allocating blocks, inode
                 * would become fully dirty soon anyway and it reportedly
-                * reduces inode_lock contention.
+                * reduces lock contention.
                 */
                mark_inode_dirty(inode);
        }
index c21072adbfad7e84417b8cf925e2fc0b21172cea..0a3842aacba998e4c776bd980d5e2eb2eacd247d 100644 (file)
@@ -1124,15 +1124,18 @@ struct reiserfs_de_head {
 #   define aligned_address(addr)           ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
 #   define unaligned_offset(addr)          (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
 
-#   define set_bit_unaligned(nr, addr)     ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
-#   define test_bit_unaligned(nr, addr)    ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define set_bit_unaligned(nr, addr) \
+       __test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define clear_bit_unaligned(nr, addr)       \
+       __test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
+#   define test_bit_unaligned(nr, addr)        \
+       test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr))
 
 #else
 
-#   define set_bit_unaligned(nr, addr)     ext2_set_bit(nr, addr)
-#   define clear_bit_unaligned(nr, addr)   ext2_clear_bit(nr, addr)
-#   define test_bit_unaligned(nr, addr)    ext2_test_bit(nr, addr)
+#   define set_bit_unaligned(nr, addr) __test_and_set_bit_le(nr, addr)
+#   define clear_bit_unaligned(nr, addr)       __test_and_clear_bit_le(nr, addr)
+#   define test_bit_unaligned(nr, addr)        test_bit_le(nr, addr)
 
 #endif
 
@@ -2329,14 +2332,10 @@ __u32 keyed_hash(const signed char *msg, int len);
 __u32 yura_hash(const signed char *msg, int len);
 __u32 r5_hash(const signed char *msg, int len);
 
-/* the ext2 bit routines adjust for big or little endian as
-** appropriate for the arch, so in our laziness we use them rather
-** than using the bit routines they call more directly.  These
-** routines must be used when changing on disk bitmaps.  */
-#define reiserfs_test_and_set_le_bit   ext2_set_bit
-#define reiserfs_test_and_clear_le_bit ext2_clear_bit
-#define reiserfs_test_le_bit           ext2_test_bit
-#define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit
+#define reiserfs_test_and_set_le_bit   __test_and_set_bit_le
+#define reiserfs_test_and_clear_le_bit __test_and_clear_bit_le
+#define reiserfs_test_le_bit           test_bit_le
+#define reiserfs_find_next_zero_le_bit find_next_zero_bit_le
 
 /* sometimes reiserfs_truncate may require to allocate few new blocks
    to perform indirect2direct conversion. People probably used to
index a5930cb6614577517223ba642854b78ba339197b..c9d625ca659ec387c6b9456c4d03d0bb4af80fb9 100644 (file)
@@ -129,20 +129,22 @@ int __must_check res_counter_charge(struct res_counter *counter,
 void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
 void res_counter_uncharge(struct res_counter *counter, unsigned long val);
 
-static inline bool res_counter_limit_check_locked(struct res_counter *cnt)
-{
-       if (cnt->usage < cnt->limit)
-               return true;
-
-       return false;
-}
-
-static inline bool res_counter_soft_limit_check_locked(struct res_counter *cnt)
+/**
+ * res_counter_margin - calculate chargeable space of a counter
+ * @cnt: the counter
+ *
+ * Returns the difference between the hard limit and the current usage
+ * of resource counter @cnt.
+ */
+static inline unsigned long long res_counter_margin(struct res_counter *cnt)
 {
-       if (cnt->usage < cnt->soft_limit)
-               return true;
+       unsigned long long margin;
+       unsigned long flags;
 
-       return false;
+       spin_lock_irqsave(&cnt->lock, flags);
+       margin = cnt->limit - cnt->usage;
+       spin_unlock_irqrestore(&cnt->lock, flags);
+       return margin;
 }
 
 /**
@@ -167,52 +169,6 @@ res_counter_soft_limit_excess(struct res_counter *cnt)
        return excess;
 }
 
-/*
- * Helper function to detect if the cgroup is within it's limit or
- * not. It's currently called from cgroup_rss_prepare()
- */
-static inline bool res_counter_check_under_limit(struct res_counter *cnt)
-{
-       bool ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cnt->lock, flags);
-       ret = res_counter_limit_check_locked(cnt);
-       spin_unlock_irqrestore(&cnt->lock, flags);
-       return ret;
-}
-
-/**
- * res_counter_check_margin - check if the counter allows charging
- * @cnt: the resource counter to check
- * @bytes: the number of bytes to check the remaining space against
- *
- * Returns a boolean value on whether the counter can be charged
- * @bytes or whether this would exceed the limit.
- */
-static inline bool res_counter_check_margin(struct res_counter *cnt,
-                                           unsigned long bytes)
-{
-       bool ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cnt->lock, flags);
-       ret = cnt->limit - cnt->usage >= bytes;
-       spin_unlock_irqrestore(&cnt->lock, flags);
-       return ret;
-}
-
-static inline bool res_counter_check_under_soft_limit(struct res_counter *cnt)
-{
-       bool ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cnt->lock, flags);
-       ret = res_counter_soft_limit_check_locked(cnt);
-       spin_unlock_irqrestore(&cnt->lock, flags);
-       return ret;
-}
-
 static inline void res_counter_reset_max(struct res_counter *cnt)
 {
        unsigned long flags;
index ff681ebba5854c8a074a90ef68c994c0d4578e3b..4e37a7cfa726f07dd65114c37a5ae3bc798904ab 100644 (file)
@@ -24,6 +24,7 @@
 #define RIO_NO_HOPCOUNT                -1
 #define RIO_INVALID_DESTID     0xffff
 
+#define RIO_MAX_MPORTS         8
 #define RIO_MAX_MPORT_RESOURCES        16
 #define RIO_MAX_DEV_RESOURCES  16
 
@@ -241,7 +242,7 @@ struct rio_mport {
        struct rio_msg inb_msg[RIO_MAX_MBOX];
        struct rio_msg outb_msg[RIO_MAX_MBOX];
        int host_deviceid;      /* Host device ID */
-       struct rio_ops *ops;    /* maintenance transaction functions */
+       struct rio_ops *ops;    /* low-level architecture-dependent routines */
        unsigned char id;       /* port ID, unique among all ports */
        unsigned char index;    /* port index, unique among all port
                                   interfaces of the same type */
@@ -285,6 +286,13 @@ struct rio_net {
  * @cwrite: Callback to perform network write of config space.
  * @dsend: Callback to send a doorbell message.
  * @pwenable: Callback to enable/disable port-write message handling.
+ * @open_outb_mbox: Callback to initialize outbound mailbox.
+ * @close_outb_mbox: Callback to shut down outbound mailbox.
+ * @open_inb_mbox: Callback to initialize inbound mailbox.
+ * @close_inb_mbox: Callback to        shut down inbound mailbox.
+ * @add_outb_message: Callback to add a message to an outbound mailbox queue.
+ * @add_inb_buffer: Callback to        add a buffer to an inbound mailbox queue.
+ * @get_inb_message: Callback to get a message from an inbound mailbox queue.
  */
 struct rio_ops {
        int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len,
@@ -297,6 +305,16 @@ struct rio_ops {
                        u8 hopcount, u32 offset, int len, u32 data);
        int (*dsend) (struct rio_mport *mport, int index, u16 destid, u16 data);
        int (*pwenable) (struct rio_mport *mport, int enable);
+       int (*open_outb_mbox)(struct rio_mport *mport, void *dev_id,
+                             int mbox, int entries);
+       void (*close_outb_mbox)(struct rio_mport *mport, int mbox);
+       int  (*open_inb_mbox)(struct rio_mport *mport, void *dev_id,
+                            int mbox, int entries);
+       void (*close_inb_mbox)(struct rio_mport *mport, int mbox);
+       int  (*add_outb_message)(struct rio_mport *mport, struct rio_dev *rdev,
+                                int mbox, void *buffer, size_t len);
+       int (*add_inb_buffer)(struct rio_mport *mport, int mbox, void *buf);
+       void *(*get_inb_message)(struct rio_mport *mport, int mbox);
 };
 
 #define RIO_RESOURCE_MEM       0x00000100
@@ -378,12 +396,7 @@ union rio_pw_msg {
 };
 
 /* Architecture and hardware-specific functions */
-extern int rio_init_mports(void);
 extern void rio_register_mport(struct rio_mport *);
-extern int rio_hw_add_outb_message(struct rio_mport *, struct rio_dev *, int,
-                                  void *, size_t);
-extern int rio_hw_add_inb_buffer(struct rio_mport *, int, void *);
-extern void *rio_hw_get_inb_message(struct rio_mport *, int);
 extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int);
 extern void rio_close_inb_mbox(struct rio_mport *, int);
 extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int);
index e09e565c4bce1470209fcb07d429a98a3edc9bbf..229b3ca23134634999a93d32bf6eb4a9c01d5448 100644 (file)
@@ -317,7 +317,8 @@ static inline int rio_add_outb_message(struct rio_mport *mport,
                                       struct rio_dev *rdev, int mbox,
                                       void *buffer, size_t len)
 {
-       return rio_hw_add_outb_message(mport, rdev, mbox, buffer, len);
+       return mport->ops->add_outb_message(mport, rdev, mbox,
+                                                  buffer, len);
 }
 
 extern int rio_request_inb_mbox(struct rio_mport *, void *, int, int,
@@ -336,7 +337,7 @@ extern int rio_release_inb_mbox(struct rio_mport *, int);
 static inline int rio_add_inb_buffer(struct rio_mport *mport, int mbox,
                                     void *buffer)
 {
-       return rio_hw_add_inb_buffer(mport, mbox, buffer);
+       return mport->ops->add_inb_buffer(mport, mbox, buffer);
 }
 
 /**
@@ -348,7 +349,7 @@ static inline int rio_add_inb_buffer(struct rio_mport *mport, int mbox,
  */
 static inline void *rio_get_inb_message(struct rio_mport *mport, int mbox)
 {
-       return rio_hw_get_inb_message(mport, mbox);
+       return mport->ops->get_inb_message(mport, mbox);
 }
 
 /* Doorbell management */
index e9fd04ca1e518f9f6eeb0d430443a64e667722e4..830e65dc01ee1f264e715632f2f99fd95c7bd529 100644 (file)
 struct anon_vma {
        struct anon_vma *root;  /* Root of this anon_vma tree */
        spinlock_t lock;        /* Serialize access to vma list */
-#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
-
        /*
-        * The external_refcount is taken by either KSM or page migration
-        * to take a reference to an anon_vma when there is no
+        * The refcount is taken on an anon_vma when there is no
         * guarantee that the vma of page tables will exist for
         * the duration of the operation. A caller that takes
         * the reference is responsible for clearing up the
         * anon_vma if they are the last user on release
         */
-       atomic_t external_refcount;
-#endif
+       atomic_t refcount;
+
        /*
         * NOTE: the LSB of the head.next is set by
         * mm_take_all_locks() _after_ taking the above lock. So the
@@ -71,42 +68,19 @@ struct anon_vma_chain {
 };
 
 #ifdef CONFIG_MMU
-#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
-static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma)
-{
-       atomic_set(&anon_vma->external_refcount, 0);
-}
-
-static inline int anonvma_external_refcount(struct anon_vma *anon_vma)
-{
-       return atomic_read(&anon_vma->external_refcount);
-}
-
 static inline void get_anon_vma(struct anon_vma *anon_vma)
 {
-       atomic_inc(&anon_vma->external_refcount);
+       atomic_inc(&anon_vma->refcount);
 }
 
-void drop_anon_vma(struct anon_vma *);
-#else
-static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma)
-{
-}
+void __put_anon_vma(struct anon_vma *anon_vma);
 
-static inline int anonvma_external_refcount(struct anon_vma *anon_vma)
-{
-       return 0;
-}
-
-static inline void get_anon_vma(struct anon_vma *anon_vma)
+static inline void put_anon_vma(struct anon_vma *anon_vma)
 {
+       if (atomic_dec_and_test(&anon_vma->refcount))
+               __put_anon_vma(anon_vma);
 }
 
-static inline void drop_anon_vma(struct anon_vma *anon_vma)
-{
-}
-#endif /* CONFIG_KSM */
-
 static inline struct anon_vma *page_anon_vma(struct page *page)
 {
        if (((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) !=
@@ -148,7 +122,6 @@ void unlink_anon_vmas(struct vm_area_struct *);
 int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *);
 int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *);
 void __anon_vma_link(struct vm_area_struct *);
-void anon_vma_free(struct anon_vma *);
 
 static inline void anon_vma_merge(struct vm_area_struct *vma,
                                  struct vm_area_struct *next)
@@ -157,6 +130,8 @@ static inline void anon_vma_merge(struct vm_area_struct *vma,
        unlink_anon_vmas(next);
 }
 
+struct anon_vma *page_get_anon_vma(struct page *page);
+
 /*
  * rmap interfaces called when adding or removing pte of page
  */
index c15936fe998b9672e634967fe03734e8da53aef2..83bd2e2982fc776f9d2fcffacdae88b6c76c40ca 100644 (file)
@@ -99,6 +99,7 @@ struct robust_list_head;
 struct bio_list;
 struct fs_struct;
 struct perf_event_context;
+struct blk_plug;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -516,7 +517,7 @@ struct thread_group_cputimer {
 struct autogroup;
 
 /*
- * NOTE! "signal_struct" does not have it's own
+ * NOTE! "signal_struct" does not have its own
  * locking, because a shared signal_struct always
  * implies a shared sighand_struct, so locking
  * sighand_struct is always a proper superset of
@@ -1428,6 +1429,11 @@ struct task_struct {
 /* stacked block device info */
        struct bio_list *bio_list;
 
+#ifdef CONFIG_BLOCK
+/* stack plugging */
+       struct blk_plug *plug;
+#endif
+
 /* VM state */
        struct reclaim_state *reclaim_state;
 
@@ -1471,6 +1477,7 @@ struct task_struct {
 #ifdef CONFIG_NUMA
        struct mempolicy *mempolicy;    /* Protected by alloc_lock */
        short il_next;
+       short pref_node_fork;
 #endif
        atomic_t fs_excl;       /* holding fs exclusive resources */
        struct rcu_head rcu;
@@ -1523,8 +1530,8 @@ struct task_struct {
        struct memcg_batch_info {
                int do_batch;   /* incremented when batch uncharge started */
                struct mem_cgroup *memcg; /* target memcg of uncharge */
-               unsigned long bytes;            /* uncharged usage */
-               unsigned long memsw_bytes; /* uncharged mem+swap usage */
+               unsigned long nr_pages; /* uncharged usage */
+               unsigned long memsw_nr_pages; /* uncharged mem+swap usage */
        } memcg_batch;
 #endif
 };
index 56cac520d014f222928cd1205a9622bdfa49cc2d..ca02f1716736906c0bc98227a6b11be7975af2ff 100644 (file)
 
 struct ctl_table;
 struct audit_krule;
+struct user_namespace;
 
 /*
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
 extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
-                      int cap, int audit);
+                      struct user_namespace *ns, int cap, int audit);
 extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
 extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -1262,6 +1263,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     credentials.
  *     @tsk contains the task_struct for the process.
  *     @cred contains the credentials to use.
+ *      @ns contains the user namespace we want the capability in
  *     @cap contains the capability <include/linux/capability.h>.
  *     @audit: Whether to write an audit message or not
  *     Return 0 if the capability is granted for @tsk.
@@ -1384,7 +1386,7 @@ struct security_operations {
                       const kernel_cap_t *inheritable,
                       const kernel_cap_t *permitted);
        int (*capable) (struct task_struct *tsk, const struct cred *cred,
-                       int cap, int audit);
+                       struct user_namespace *ns, int cap, int audit);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
        int (*quota_on) (struct dentry *dentry);
        int (*syslog) (int type);
@@ -1665,9 +1667,12 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(const struct cred *cred, int cap);
-int security_real_capable(struct task_struct *tsk, int cap);
-int security_real_capable_noaudit(struct task_struct *tsk, int cap);
+int security_capable(struct user_namespace *ns, const struct cred *cred,
+                       int cap);
+int security_real_capable(struct task_struct *tsk, struct user_namespace *ns,
+                       int cap);
+int security_real_capable_noaudit(struct task_struct *tsk,
+                       struct user_namespace *ns, int cap);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
 int security_syslog(int type);
@@ -1860,28 +1865,29 @@ static inline int security_capset(struct cred *new,
        return cap_capset(new, old, effective, inheritable, permitted);
 }
 
-static inline int security_capable(const struct cred *cred, int cap)
+static inline int security_capable(struct user_namespace *ns,
+                                  const struct cred *cred, int cap)
 {
-       return cap_capable(current, cred, cap, SECURITY_CAP_AUDIT);
+       return cap_capable(current, cred, ns, cap, SECURITY_CAP_AUDIT);
 }
 
-static inline int security_real_capable(struct task_struct *tsk, int cap)
+static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap)
 {
        int ret;
 
        rcu_read_lock();
-       ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
+       ret = cap_capable(tsk, __task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT);
        rcu_read_unlock();
        return ret;
 }
 
 static inline
-int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+int security_real_capable_noaudit(struct task_struct *tsk, struct user_namespace *ns, int cap)
 {
        int ret;
 
        rcu_read_lock();
-       ret = cap_capable(tsk, __task_cred(tsk), cap,
+       ret = cap_capable(tsk, __task_cred(tsk), ns, cap,
                               SECURITY_CAP_NOAUDIT);
        rcu_read_unlock();
        return ret;
diff --git a/include/linux/sigma.h b/include/linux/sigma.h
new file mode 100644 (file)
index 0000000..e2accb3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Load firmware files from Analog Devices SigmaStudio
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __SIGMA_FIRMWARE_H__
+#define __SIGMA_FIRMWARE_H__
+
+#include <linux/firmware.h>
+#include <linux/types.h>
+
+struct i2c_client;
+
+#define SIGMA_MAGIC "ADISIGM"
+
+struct sigma_firmware {
+       const struct firmware *fw;
+       size_t pos;
+};
+
+struct sigma_firmware_header {
+       unsigned char magic[7];
+       u8 version;
+       u32 crc;
+};
+
+enum {
+       SIGMA_ACTION_WRITEXBYTES = 0,
+       SIGMA_ACTION_WRITESINGLE,
+       SIGMA_ACTION_WRITESAFELOAD,
+       SIGMA_ACTION_DELAY,
+       SIGMA_ACTION_PLLWAIT,
+       SIGMA_ACTION_NOOP,
+       SIGMA_ACTION_END,
+};
+
+struct sigma_action {
+       u8 instr;
+       u8 len_hi;
+       u16 len;
+       u16 addr;
+       unsigned char payload[];
+};
+
+static inline u32 sigma_action_len(struct sigma_action *sa)
+{
+       return (sa->len_hi << 16) | sa->len;
+}
+
+static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len)
+{
+       return sizeof(*sa) + payload_len + (payload_len % 2);
+}
+
+extern int process_sigma_firmware(struct i2c_client *client, const char *name);
+
+#endif
index fa9086647eb7aef52284006c575e716703bb17de..ad4dd1c8d30aadcdee4dec8d95524d77df7a74a3 100644 (file)
@@ -105,7 +105,6 @@ void kmem_cache_destroy(struct kmem_cache *);
 int kmem_cache_shrink(struct kmem_cache *);
 void kmem_cache_free(struct kmem_cache *, void *);
 unsigned int kmem_cache_size(struct kmem_cache *);
-const char *kmem_cache_name(struct kmem_cache *);
 
 /*
  * Please use this macro to create slab caches. Simply specify the
index 8b6e8ae5d5cabcd6f267405a1007d56de0070b64..45ca123e800219777001f75113324f6cfd60486f 100644 (file)
@@ -32,10 +32,14 @@ enum stat_item {
        DEACTIVATE_TO_TAIL,     /* Cpu slab was moved to the tail of partials */
        DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
        ORDER_FALLBACK,         /* Number of times fallback was necessary */
+       CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
        NR_SLUB_STAT_ITEMS };
 
 struct kmem_cache_cpu {
-       void **freelist;        /* Pointer to first free per cpu object */
+       void **freelist;        /* Pointer to next available object */
+#ifdef CONFIG_CMPXCHG_LOCAL
+       unsigned long tid;      /* Globally unique transaction id */
+#endif
        struct page *page;      /* The slab from which we are allocating */
        int node;               /* The node of the page (or -1 for debug) */
 #ifdef CONFIG_SLUB_STATS
@@ -70,6 +74,7 @@ struct kmem_cache {
        struct kmem_cache_cpu __percpu *cpu_slab;
        /* Used for retriving partial slabs etc */
        unsigned long flags;
+       unsigned long min_partial;
        int size;               /* The size of an object including meta data */
        int objsize;            /* The size of an object without meta data */
        int offset;             /* Free pointer offset. */
@@ -83,7 +88,7 @@ struct kmem_cache {
        void (*ctor)(void *);
        int inuse;              /* Offset to metadata */
        int align;              /* Alignment */
-       unsigned long min_partial;
+       int reserved;           /* Reserved bytes at the end of slabs */
        const char *name;       /* Name (only for display!) */
        struct list_head list;  /* List of slab caches */
 #ifdef CONFIG_SYSFS
index 214f93209b8c0fb847971b41f0b5ea242b241e8a..02fde50a79a57bc6ea1cb0369a30b1efa56b989b 100644 (file)
@@ -172,3 +172,11 @@ struct sm501_platdata {
        struct sm501_platdata_gpio_i2c  *gpio_i2c;
        unsigned int                     gpio_i2c_nr;
 };
+
+#if defined(CONFIG_PPC32)
+#define smc501_readl(addr)             ioread32be((addr))
+#define smc501_writel(val, addr)       iowrite32be((val), (addr))
+#else
+#define smc501_readl(addr)             readl(addr)
+#define smc501_writel(val, addr)       writel(val, addr)
+#endif
index 6dc95cac6b3dabc390ac271cca9a0e4fb16436ac..74243c86ba39fd475c3188083f95d0f367133498 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/cpumask.h>
+#include <linux/init.h>
 
 extern void cpu_idle(void);
 
@@ -114,6 +115,8 @@ int on_each_cpu(smp_call_func_t func, void *info, int wait);
 void smp_prepare_boot_cpu(void);
 
 extern unsigned int setup_max_cpus;
+extern void __init setup_nr_cpu_ids(void);
+extern void __init smp_init(void);
 
 #else /* !SMP */
 
diff --git a/include/linux/spi/tsc2005.h b/include/linux/spi/tsc2005.h
new file mode 100644 (file)
index 0000000..d9b0c84
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * This file is part of TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Aaro Koskinen <aaro.koskinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _LINUX_SPI_TSC2005_H
+#define _LINUX_SPI_TSC2005_H
+
+#include <linux/types.h>
+
+struct tsc2005_platform_data {
+       int             ts_pressure_max;
+       int             ts_pressure_fudge;
+       int             ts_x_max;
+       int             ts_x_fudge;
+       int             ts_y_max;
+       int             ts_y_fudge;
+       int             ts_x_plate_ohm;
+       unsigned int    esd_timeout_ms;
+       void            (*set_reset)(bool enable);
+};
+
+#endif
index 5d8048beb0517b056ce119dd6e92b08998becbd6..332da61cf8b71fc73d802b2609210f46641a9ea1 100644 (file)
@@ -126,6 +126,9 @@ struct gss_api_mech *gss_mech_get_by_name(const char *);
 /* Similar, but get by pseudoflavor. */
 struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
 
+/* Fill in an array with a list of supported pseudoflavors */
+int gss_mech_list_pseudoflavors(u32 *);
+
 /* Just increments the mechanism's reference count and returns its input: */
 struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
 
index c59a51a2b0e792c39b5de96fecf228b3bfaca244..bfa68e837d6a31a5b5653538ea4ea40da471050f 100644 (file)
@@ -67,25 +67,25 @@ struct svga_pll {
 
 /* Write a value to the attribute register */
 
-static inline void svga_wattr(u8 index, u8 data)
+static inline void svga_wattr(void __iomem *regbase, u8 index, u8 data)
 {
-       inb(0x3DA);
-       outb(index, 0x3C0);
-       outb(data, 0x3C0);
+       vga_r(regbase, VGA_IS1_RC);
+       vga_w(regbase, VGA_ATT_IW, index);
+       vga_w(regbase, VGA_ATT_W, data);
 }
 
 /* Write a value to a sequence register with a mask */
 
-static inline void svga_wseq_mask(u8 index, u8 data, u8 mask)
+static inline void svga_wseq_mask(void __iomem *regbase, u8 index, u8 data, u8 mask)
 {
-       vga_wseq(NULL, index, (data & mask) | (vga_rseq(NULL, index) & ~mask));
+       vga_wseq(regbase, index, (data & mask) | (vga_rseq(regbase, index) & ~mask));
 }
 
 /* Write a value to a CRT register with a mask */
 
-static inline void svga_wcrt_mask(u8 index, u8 data, u8 mask)
+static inline void svga_wcrt_mask(void __iomem *regbase, u8 index, u8 data, u8 mask)
 {
-       vga_wcrt(NULL, index, (data & mask) | (vga_rcrt(NULL, index) & ~mask));
+       vga_wcrt(regbase, index, (data & mask) | (vga_rcrt(regbase, index) & ~mask));
 }
 
 static inline int svga_primary_device(struct pci_dev *dev)
@@ -96,27 +96,27 @@ static inline int svga_primary_device(struct pci_dev *dev)
 }
 
 
-void svga_wcrt_multi(const struct vga_regset *regset, u32 value);
-void svga_wseq_multi(const struct vga_regset *regset, u32 value);
+void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value);
+void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value);
 
-void svga_set_default_gfx_regs(void);
-void svga_set_default_atc_regs(void);
-void svga_set_default_seq_regs(void);
-void svga_set_default_crt_regs(void);
-void svga_set_textmode_vga_regs(void);
+void svga_set_default_gfx_regs(void __iomem *regbase);
+void svga_set_default_atc_regs(void __iomem *regbase);
+void svga_set_default_seq_regs(void __iomem *regbase);
+void svga_set_default_crt_regs(void __iomem *regbase);
+void svga_set_textmode_vga_regs(void __iomem *regbase);
 
 void svga_settile(struct fb_info *info, struct fb_tilemap *map);
 void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area);
 void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect);
 void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit);
-void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor);
+void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor);
 int svga_get_tilemax(struct fb_info *info);
 void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
                   struct fb_var_screeninfo *var);
 
 int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node);
 int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node);
-void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node);
+void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node);
 
 int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix);
 
index 4d559325d919fb5fa194d6a7e61711ae52e01192..a5c6da5d8df8dd5ad28b6b9525bfa787caa3e74d 100644 (file)
@@ -155,6 +155,15 @@ enum {
 #define SWAP_CLUSTER_MAX 32
 #define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX
 
+/*
+ * Ratio between the present memory in the zone and the "gap" that
+ * we're allowing kswapd to shrink in addition to the per-zone high
+ * wmark, even for zones that already have the high wmark satisfied,
+ * in order to provide better per-zone lru behavior. We are ok to
+ * spend not more than 1% of the memory for this zone balancing "gap".
+ */
+#define KSWAPD_ZONE_BALANCE_GAP_RATIO 100
+
 #define SWAP_MAP_MAX   0x3e    /* Max duplication count, in first swap_map */
 #define SWAP_MAP_BAD   0x3f    /* Note pageblock is bad, in first swap_map */
 #define SWAP_HAS_CACHE 0x40    /* Flag page is cached, in first swap_map */
@@ -215,6 +224,7 @@ extern void mark_page_accessed(struct page *);
 extern void lru_add_drain(void);
 extern int lru_add_drain_all(void);
 extern void rotate_reclaimable_page(struct page *page);
+extern void deactivate_page(struct page *page);
 extern void swap_setup(void);
 
 extern void add_page_to_unevictable_list(struct page *page);
@@ -299,8 +309,6 @@ extern void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
                                        struct page **pagep, swp_entry_t *ent);
 #endif
 
-extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
-
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
 extern int swap_readpage(struct page *);
index 1f5c18e6f4f17bedfbd38e64da3cc112d1cb90bb..83ecc1749ef6153581d295706d6c4768c11931e0 100644 (file)
@@ -825,6 +825,7 @@ asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags
 asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
                                  u64 mask, int fd,
                                  const char  __user *pathname);
+asmlinkage long sys_syncfs(int fd);
 
 int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]);
 
index 4e53d4641b388c965903af977d33b53f5fb1e20b..9f469c700550e79dc7fc3949e34c94096c2078ff 100644 (file)
@@ -82,7 +82,7 @@ struct tty_buffer {
 
 
 struct tty_bufhead {
-       struct delayed_work work;
+       struct work_struct work;
        spinlock_t lock;
        struct tty_buffer *head;        /* Queue head */
        struct tty_buffer *tail;        /* Active buffer */
index c2a9eb44f2fa974cc7ac15a35ae9c184c1e6773f..176da8c1fbb180e20a925ba79e80420bdf66b7a9 100644 (file)
@@ -150,6 +150,12 @@ typedef unsigned long blkcnt_t;
 #define pgoff_t unsigned long
 #endif
 
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+typedef u64 dma_addr_t;
+#else
+typedef u32 dma_addr_t;
+#endif /* dma_addr_t */
+
 #endif /* __KERNEL__ */
 
 /*
index 69f39974c041b964c4a32bb0dead5942f191dae2..4e5b0213fdc16adc61dbb4d46ee5e98030c9a1cc 100644 (file)
@@ -37,9 +37,13 @@ struct new_utsname {
 #include <linux/nsproxy.h>
 #include <linux/err.h>
 
+struct user_namespace;
+extern struct user_namespace init_user_ns;
+
 struct uts_namespace {
        struct kref kref;
        struct new_utsname name;
+       struct user_namespace *user_ns;
 };
 extern struct uts_namespace init_uts_ns;
 
@@ -50,7 +54,7 @@ static inline void get_uts_ns(struct uts_namespace *ns)
 }
 
 extern struct uts_namespace *copy_utsname(unsigned long flags,
-                                       struct uts_namespace *ns);
+                                         struct task_struct *tsk);
 extern void free_uts_ns(struct kref *kref);
 
 static inline void put_uts_ns(struct uts_namespace *ns)
@@ -67,12 +71,12 @@ static inline void put_uts_ns(struct uts_namespace *ns)
 }
 
 static inline struct uts_namespace *copy_utsname(unsigned long flags,
-                                       struct uts_namespace *ns)
+                                                struct task_struct *tsk)
 {
        if (flags & CLONE_NEWUTS)
                return ERR_PTR(-EINVAL);
 
-       return ns;
+       return tsk->nsproxy->uts_ns;
 }
 #endif
 
diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
new file mode 100644 (file)
index 0000000..7054a7a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Media Bus API header
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_V4L2_MEDIABUS_H
+#define __LINUX_V4L2_MEDIABUS_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+/*
+ * These pixel codes uniquely identify data formats on the media bus. Mostly
+ * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
+ * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
+ * data format is fixed. Additionally, "2X8" means that one pixel is transferred
+ * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
+ * transferred over the bus: "LE" means that the least significant bits are
+ * transferred first, "BE" means that the most significant bits are transferred
+ * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+ * incomplete high byte, are filled with padding bits.
+ *
+ * The pixel codes are grouped by type, bus_width, bits per component, samples
+ * per pixel and order of subsamples. Numerical values are sorted using generic
+ * numerical sort order (8 thus comes before 10).
+ *
+ * As their value can't change when a new pixel code is inserted in the
+ * enumeration, the pixel codes are explicitly given a numerical value. The next
+ * free values for each category are listed below, update them when inserting
+ * new pixel codes.
+ */
+enum v4l2_mbus_pixelcode {
+       V4L2_MBUS_FMT_FIXED = 0x0001,
+
+       /* RGB - next is 0x1009 */
+       V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
+       V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
+       V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
+       V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004,
+       V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005,
+       V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
+       V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
+       V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+
+       /* YUV (including grey) - next is 0x2013 */
+       V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
+       V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
+       V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
+       V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004,
+       V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005,
+       V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006,
+       V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007,
+       V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008,
+       V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009,
+       V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
+       V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
+       V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
+       V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f,
+       V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
+       V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
+       V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
+       V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
+       V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
+
+       /* Bayer - next is 0x3013 */
+       V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+       V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+       V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
+       V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c,
+       V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
+       V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 = 0x300d,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
+       V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
+       V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
+       V4L2_MBUS_FMT_SGBRG10_1X10 = 0x300e,
+       V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
+       V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f,
+       V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
+       V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010,
+       V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011,
+       V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012,
+};
+
+/**
+ * struct v4l2_mbus_framefmt - frame format on the media bus
+ * @width:     frame width
+ * @height:    frame height
+ * @code:      data format code (from enum v4l2_mbus_pixelcode)
+ * @field:     used interlacing type (from enum v4l2_field)
+ * @colorspace:        colorspace of the data (from enum v4l2_colorspace)
+ */
+struct v4l2_mbus_framefmt {
+       __u32                   width;
+       __u32                   height;
+       __u32                   code;
+       __u32                   field;
+       __u32                   colorspace;
+       __u32                   reserved[7];
+};
+
+#endif
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
new file mode 100644 (file)
index 0000000..ed29cbb
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * V4L2 subdev userspace API
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_V4L2_SUBDEV_H
+#define __LINUX_V4L2_SUBDEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/v4l2-mediabus.h>
+
+/**
+ * enum v4l2_subdev_format_whence - Media bus format type
+ * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
+ * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
+ */
+enum v4l2_subdev_format_whence {
+       V4L2_SUBDEV_FORMAT_TRY = 0,
+       V4L2_SUBDEV_FORMAT_ACTIVE = 1,
+};
+
+/**
+ * struct v4l2_subdev_format - Pad-level media bus format
+ * @which: format type (from enum v4l2_subdev_format_whence)
+ * @pad: pad number, as reported by the media API
+ * @format: media bus format (format code and frame size)
+ */
+struct v4l2_subdev_format {
+       __u32 which;
+       __u32 pad;
+       struct v4l2_mbus_framefmt format;
+       __u32 reserved[8];
+};
+
+/**
+ * struct v4l2_subdev_crop - Pad-level crop settings
+ * @which: format type (from enum v4l2_subdev_format_whence)
+ * @pad: pad number, as reported by the media API
+ * @rect: pad crop rectangle boundaries
+ */
+struct v4l2_subdev_crop {
+       __u32 which;
+       __u32 pad;
+       struct v4l2_rect rect;
+       __u32 reserved[8];
+};
+
+/**
+ * struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: format index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ */
+struct v4l2_subdev_mbus_code_enum {
+       __u32 pad;
+       __u32 index;
+       __u32 code;
+       __u32 reserved[9];
+};
+
+/**
+ * struct v4l2_subdev_frame_size_enum - Media bus format enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: format index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ */
+struct v4l2_subdev_frame_size_enum {
+       __u32 index;
+       __u32 pad;
+       __u32 code;
+       __u32 min_width;
+       __u32 max_width;
+       __u32 min_height;
+       __u32 max_height;
+       __u32 reserved[9];
+};
+
+/**
+ * struct v4l2_subdev_frame_interval - Pad-level frame rate
+ * @pad: pad number, as reported by the media API
+ * @interval: frame interval in seconds
+ */
+struct v4l2_subdev_frame_interval {
+       __u32 pad;
+       struct v4l2_fract interval;
+       __u32 reserved[9];
+};
+
+/**
+ * struct v4l2_subdev_frame_interval_enum - Frame interval enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: frame interval index during enumeration
+ * @code: format code (from enum v4l2_mbus_pixelcode)
+ * @width: frame width in pixels
+ * @height: frame height in pixels
+ * @interval: frame interval in seconds
+ */
+struct v4l2_subdev_frame_interval_enum {
+       __u32 index;
+       __u32 pad;
+       __u32 code;
+       __u32 width;
+       __u32 height;
+       struct v4l2_fract interval;
+       __u32 reserved[9];
+};
+
+#define VIDIOC_SUBDEV_G_FMT    _IOWR('V',  4, struct v4l2_subdev_format)
+#define VIDIOC_SUBDEV_S_FMT    _IOWR('V',  5, struct v4l2_subdev_format)
+#define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
+                       _IOWR('V', 21, struct v4l2_subdev_frame_interval)
+#define VIDIOC_SUBDEV_S_FRAME_INTERVAL \
+                       _IOWR('V', 22, struct v4l2_subdev_frame_interval)
+#define VIDIOC_SUBDEV_ENUM_MBUS_CODE \
+                       _IOWR('V',  2, struct v4l2_subdev_mbus_code_enum)
+#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+                       _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
+#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+                       _IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
+#define VIDIOC_SUBDEV_G_CROP   _IOWR('V', 59, struct v4l2_subdev_crop)
+#define VIDIOC_SUBDEV_S_CROP   _IOWR('V', 60, struct v4l2_subdev_crop)
+
+#endif
index 5f6f47044abfecffcb4cc8112e4b25996825f49b..aa6c393b7ae991cd2f02242627fca08d0f0b713b 100644 (file)
@@ -70,6 +70,7 @@
  * Moved from videodev.h
  */
 #define VIDEO_MAX_FRAME               32
+#define VIDEO_MAX_PLANES               8
 
 #ifndef __KERNEL__
 
@@ -157,9 +158,23 @@ enum v4l2_buf_type {
        /* Experimental */
        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
 #endif
+       V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
+       V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
        V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
+#define V4L2_TYPE_IS_MULTIPLANAR(type)                 \
+       ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE   \
+        || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+
+#define V4L2_TYPE_IS_OUTPUT(type)                              \
+       ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT                   \
+        || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE         \
+        || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY               \
+        || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY        \
+        || (type) == V4L2_BUF_TYPE_VBI_OUTPUT                  \
+        || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+
 enum v4l2_tuner_type {
        V4L2_TUNER_RADIO             = 1,
        V4L2_TUNER_ANALOG_TV         = 2,
@@ -245,6 +260,11 @@ struct v4l2_capability {
 #define V4L2_CAP_HW_FREQ_SEEK          0x00000400  /* Can do hardware frequency seek  */
 #define V4L2_CAP_RDS_OUTPUT            0x00000800  /* Is an RDS encoder */
 
+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE  0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE   0x00002000
+
 #define V4L2_CAP_TUNER                 0x00010000  /* has a tuner */
 #define V4L2_CAP_AUDIO                 0x00020000  /* has audio support */
 #define V4L2_CAP_RADIO                 0x00040000  /* is a radio device */
@@ -319,6 +339,13 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
 #define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
 
+/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV12MT  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
+
+/* three non contiguous planes - Y, Cb, Cr */
+#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
+
 /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
@@ -328,6 +355,10 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
 #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
 #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12  RGRG.. GBGB.. */
        /* 10bit raw bayer DPCM compressed to 8 bits */
 #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
        /*
@@ -365,6 +396,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
 #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
 #define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
+#define V4L2_PIX_FMT_JPGL      v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
@@ -517,6 +549,62 @@ struct v4l2_requestbuffers {
        __u32                   reserved[2];
 };
 
+/**
+ * struct v4l2_plane - plane info for multi-planar buffers
+ * @bytesused:         number of bytes occupied by data in the plane (payload)
+ * @length:            size of this plane (NOT the payload) in bytes
+ * @mem_offset:                when memory in the associated struct v4l2_buffer is
+ *                     V4L2_MEMORY_MMAP, equals the offset from the start of
+ *                     the device memory for this plane (or is a "cookie" that
+ *                     should be passed to mmap() called on the video node)
+ * @userptr:           when memory is V4L2_MEMORY_USERPTR, a userspace pointer
+ *                     pointing to this plane
+ * @data_offset:       offset in the plane to the start of data; usually 0,
+ *                     unless there is a header in front of the data
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ */
+struct v4l2_plane {
+       __u32                   bytesused;
+       __u32                   length;
+       union {
+               __u32           mem_offset;
+               unsigned long   userptr;
+       } m;
+       __u32                   data_offset;
+       __u32                   reserved[11];
+};
+
+/**
+ * struct v4l2_buffer - video buffer info
+ * @index:     id number of the buffer
+ * @type:      buffer type (type == *_MPLANE for multiplanar buffers)
+ * @bytesused: number of bytes occupied by data in the buffer (payload);
+ *             unused (set to 0) for multiplanar buffers
+ * @flags:     buffer informational flags
+ * @field:     field order of the image in the buffer
+ * @timestamp: frame timestamp
+ * @timecode:  frame timecode
+ * @sequence:  sequence count of this frame
+ * @memory:    the method, in which the actual video data is passed
+ * @offset:    for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ *             offset from the start of the device memory for this plane,
+ *             (or a "cookie" that should be passed to mmap() as offset)
+ * @userptr:   for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
+ *             a userspace pointer pointing to this buffer
+ * @planes:    for multiplanar buffers; userspace pointer to the array of plane
+ *             info structs for this buffer
+ * @length:    size in bytes of the buffer (NOT its payload) for single-plane
+ *             buffers (when type != *_MPLANE); number of elements in the
+ *             planes array for multi-plane buffers
+ * @input:     input number from which the video data has has been captured
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
 struct v4l2_buffer {
        __u32                   index;
        enum v4l2_buf_type      type;
@@ -532,6 +620,7 @@ struct v4l2_buffer {
        union {
                __u32           offset;
                unsigned long   userptr;
+               struct v4l2_plane *planes;
        } m;
        __u32                   length;
        __u32                   input;
@@ -1622,12 +1711,56 @@ struct v4l2_mpeg_vbi_fmt_ivtv {
  *     A G G R E G A T E   S T R U C T U R E S
  */
 
-/*     Stream data format
+/**
+ * struct v4l2_plane_pix_format - additional, per-plane format definition
+ * @sizeimage:         maximum size in bytes required for data, for which
+ *                     this plane will be used
+ * @bytesperline:      distance in bytes between the leftmost pixels in two
+ *                     adjacent lines
+ */
+struct v4l2_plane_pix_format {
+       __u32           sizeimage;
+       __u16           bytesperline;
+       __u16           reserved[7];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_pix_format_mplane - multiplanar format definition
+ * @width:             image width in pixels
+ * @height:            image height in pixels
+ * @pixelformat:       little endian four character code (fourcc)
+ * @field:             field order (for interlaced video)
+ * @colorspace:                supplemental to pixelformat
+ * @plane_fmt:         per-plane information
+ * @num_planes:                number of planes for this format
+ */
+struct v4l2_pix_format_mplane {
+       __u32                           width;
+       __u32                           height;
+       __u32                           pixelformat;
+       enum v4l2_field                 field;
+       enum v4l2_colorspace            colorspace;
+
+       struct v4l2_plane_pix_format    plane_fmt[VIDEO_MAX_PLANES];
+       __u8                            num_planes;
+       __u8                            reserved[11];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_format - stream data format
+ * @type:      type of the data stream
+ * @pix:       definition of an image format
+ * @pix_mp:    definition of a multiplanar image format
+ * @win:       definition of an overlaid image
+ * @vbi:       raw VBI capture or output parameters
+ * @sliced:    sliced VBI capture or output parameters
+ * @raw_data:  placeholder for future extensions and custom formats
  */
 struct v4l2_format {
        enum v4l2_buf_type type;
        union {
                struct v4l2_pix_format          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+               struct v4l2_pix_format_mplane   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
                struct v4l2_window              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                struct v4l2_vbi_format          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
                struct v4l2_sliced_vbi_format   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
@@ -1635,7 +1768,6 @@ struct v4l2_format {
        } fmt;
 };
 
-
 /*     Stream type-dependent parameters
  */
 struct v4l2_streamparm {
@@ -1808,16 +1940,6 @@ struct v4l2_dbg_chip_ident {
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
-#ifdef __OLD_VIDIOC_
-/* for compatibility, will go away some day */
-#define VIDIOC_OVERLAY_OLD             _IOWR('V', 14, int)
-#define VIDIOC_S_PARM_OLD               _IOW('V', 22, struct v4l2_streamparm)
-#define VIDIOC_S_CTRL_OLD               _IOW('V', 28, struct v4l2_control)
-#define VIDIOC_G_AUDIO_OLD             _IOWR('V', 33, struct v4l2_audio)
-#define VIDIOC_G_AUDOUT_OLD            _IOWR('V', 49, struct v4l2_audioout)
-#define VIDIOC_CROPCAP_OLD              _IOR('V', 58, struct v4l2_cropcap)
-#endif
-
 #define BASE_VIDIOC_PRIVATE    192             /* 192-255 are private */
 
 #endif /* __LINUX_VIDEODEV2_H */
index 833e676d6d92c1e46336eca0b2206e3aa4273795..461c0119664ff88d2bf8797f2541ccae74ce0698 100644 (file)
@@ -220,12 +220,12 @@ static inline unsigned long node_page_state(int node,
                zone_page_state(&zones[ZONE_MOVABLE], item);
 }
 
-extern void zone_statistics(struct zone *, struct zone *);
+extern void zone_statistics(struct zone *, struct zone *, gfp_t gfp);
 
 #else
 
 #define node_page_state(node, item) global_page_state(item)
-#define zone_statistics(_zl,_z) do { } while (0)
+#define zone_statistics(_zl, _z, gfp) do { } while (0)
 
 #endif /* CONFIG_NUMA */
 
index 0ead399e08b5cfc549d1debf26f8e7915c7c9904..17e7ccc322a50452736b0b43ad33d250ee1a00e3 100644 (file)
@@ -9,7 +9,7 @@
 
 struct backing_dev_info;
 
-extern spinlock_t inode_lock;
+extern spinlock_t inode_wb_list_lock;
 
 /*
  * fs/fs-writeback.c
index 40c49cb3eb518355f14d05ec8d043e00f1bb45c3..9c5a6b4de0a30d716b2ec72470813be3a2dd82a8 100644 (file)
@@ -179,11 +179,16 @@ typedef z_stream *z_streamp;
 
                         /* basic functions */
 
-extern int zlib_deflate_workspacesize (void);
+extern int zlib_deflate_workspacesize (int windowBits, int memLevel);
 /*
    Returns the number of bytes that needs to be allocated for a per-
-   stream workspace.  A pointer to this number of bytes should be
-   returned in stream->workspace before calling zlib_deflateInit().
+   stream workspace with the specified parameters.  A pointer to this
+   number of bytes should be returned in stream->workspace before
+   you call zlib_deflateInit() or zlib_deflateInit2().  If you call
+   zlib_deflateInit(), specify windowBits = MAX_WBITS and memLevel =
+   MAX_MEM_LEVEL here.  If you call zlib_deflateInit2(), the windowBits
+   and memLevel parameters passed to zlib_deflateInit2() must not
+   exceed those passed here.
 */
 
 /* 
diff --git a/include/media/media-device.h b/include/media/media-device.h
new file mode 100644 (file)
index 0000000..6a27d91
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Media device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _MEDIA_DEVICE_H
+#define _MEDIA_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+#include <media/media-devnode.h>
+#include <media/media-entity.h>
+
+/**
+ * struct media_device - Media device
+ * @dev:       Parent device
+ * @devnode:   Media device node
+ * @model:     Device model name
+ * @serial:    Device serial number (optional)
+ * @bus_info:  Unique and stable device location identifier
+ * @hw_revision: Hardware device revision
+ * @driver_version: Device driver version
+ * @entity_id: ID of the next entity to be registered
+ * @entities:  List of registered entities
+ * @lock:      Entities list lock
+ * @graph_mutex: Entities graph operation lock
+ *
+ * This structure represents an abstract high-level media device. It allows easy
+ * access to entities and provides basic media device-level support. The
+ * structure can be allocated directly or embedded in a larger structure.
+ *
+ * The parent @dev is a physical device. It must be set before registering the
+ * media device.
+ *
+ * @model is a descriptive model name exported through sysfs. It doesn't have to
+ * be unique.
+ */
+struct media_device {
+       /* dev->driver_data points to this struct. */
+       struct device *dev;
+       struct media_devnode devnode;
+
+       char model[32];
+       char serial[40];
+       char bus_info[32];
+       u32 hw_revision;
+       u32 driver_version;
+
+       u32 entity_id;
+       struct list_head entities;
+
+       /* Protects the entities list */
+       spinlock_t lock;
+       /* Serializes graph operations. */
+       struct mutex graph_mutex;
+
+       int (*link_notify)(struct media_pad *source,
+                          struct media_pad *sink, u32 flags);
+};
+
+/* media_devnode to media_device */
+#define to_media_device(node) container_of(node, struct media_device, devnode)
+
+int __must_check media_device_register(struct media_device *mdev);
+void media_device_unregister(struct media_device *mdev);
+
+int __must_check media_device_register_entity(struct media_device *mdev,
+                                             struct media_entity *entity);
+void media_device_unregister_entity(struct media_entity *entity);
+
+/* Iterate over all entities. */
+#define media_device_for_each_entity(entity, mdev)                     \
+       list_for_each_entry(entity, &(mdev)->entities, list)
+
+#endif
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
new file mode 100644 (file)
index 0000000..f6caafc
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Media device node
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * 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
+ *
+ * --
+ *
+ * Common functions for media-related drivers to register and unregister media
+ * device nodes.
+ */
+
+#ifndef _MEDIA_DEVNODE_H
+#define _MEDIA_DEVNODE_H
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+/*
+ * Flag to mark the media_devnode struct as registered. Drivers must not touch
+ * this flag directly, it will be set and cleared by media_devnode_register and
+ * media_devnode_unregister.
+ */
+#define MEDIA_FLAG_REGISTERED  0
+
+struct media_file_operations {
+       struct module *owner;
+       ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+       ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+       unsigned int (*poll) (struct file *, struct poll_table_struct *);
+       long (*ioctl) (struct file *, unsigned int, unsigned long);
+       int (*open) (struct file *);
+       int (*release) (struct file *);
+};
+
+/**
+ * struct media_devnode - Media device node
+ * @parent:    parent device
+ * @minor:     device node minor number
+ * @flags:     flags, combination of the MEDIA_FLAG_* constants
+ *
+ * This structure represents a media-related device node.
+ *
+ * The @parent is a physical device. It must be set by core or device drivers
+ * before registering the node.
+ */
+struct media_devnode {
+       /* device ops */
+       const struct media_file_operations *fops;
+
+       /* sysfs */
+       struct device dev;              /* media device */
+       struct cdev cdev;               /* character device */
+       struct device *parent;          /* device parent */
+
+       /* device info */
+       int minor;
+       unsigned long flags;            /* Use bitops to access flags */
+
+       /* callbacks */
+       void (*release)(struct media_devnode *mdev);
+};
+
+/* dev to media_devnode */
+#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+
+int __must_check media_devnode_register(struct media_devnode *mdev);
+void media_devnode_unregister(struct media_devnode *mdev);
+
+static inline struct media_devnode *media_devnode_data(struct file *filp)
+{
+       return filp->private_data;
+}
+
+static inline int media_devnode_is_registered(struct media_devnode *mdev)
+{
+       return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
+}
+
+#endif /* _MEDIA_DEVNODE_H */
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
new file mode 100644 (file)
index 0000000..cd8bca6
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Media entity
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _MEDIA_ENTITY_H
+#define _MEDIA_ENTITY_H
+
+#include <linux/list.h>
+#include <linux/media.h>
+
+struct media_pipeline {
+};
+
+struct media_link {
+       struct media_pad *source;       /* Source pad */
+       struct media_pad *sink;         /* Sink pad  */
+       struct media_link *reverse;     /* Link in the reverse direction */
+       unsigned long flags;            /* Link flags (MEDIA_LNK_FL_*) */
+};
+
+struct media_pad {
+       struct media_entity *entity;    /* Entity this pad belongs to */
+       u16 index;                      /* Pad index in the entity pads array */
+       unsigned long flags;            /* Pad flags (MEDIA_PAD_FL_*) */
+};
+
+struct media_entity_operations {
+       int (*link_setup)(struct media_entity *entity,
+                         const struct media_pad *local,
+                         const struct media_pad *remote, u32 flags);
+};
+
+struct media_entity {
+       struct list_head list;
+       struct media_device *parent;    /* Media device this entity belongs to*/
+       u32 id;                         /* Entity ID, unique in the parent media
+                                        * device context */
+       const char *name;               /* Entity name */
+       u32 type;                       /* Entity type (MEDIA_ENT_T_*) */
+       u32 revision;                   /* Entity revision, driver specific */
+       unsigned long flags;            /* Entity flags (MEDIA_ENT_FL_*) */
+       u32 group_id;                   /* Entity group ID */
+
+       u16 num_pads;                   /* Number of sink and source pads */
+       u16 num_links;                  /* Number of existing links, both
+                                        * enabled and disabled */
+       u16 num_backlinks;              /* Number of backlinks */
+       u16 max_links;                  /* Maximum number of links */
+
+       struct media_pad *pads;         /* Pads array (num_pads elements) */
+       struct media_link *links;       /* Links array (max_links elements)*/
+
+       const struct media_entity_operations *ops;      /* Entity operations */
+
+       /* Reference counts must never be negative, but are signed integers on
+        * purpose: a simple WARN_ON(<0) check can be used to detect reference
+        * count bugs that would make them negative.
+        */
+       int stream_count;               /* Stream count for the entity. */
+       int use_count;                  /* Use count for the entity. */
+
+       struct media_pipeline *pipe;    /* Pipeline this entity belongs to. */
+
+       union {
+               /* Node specifications */
+               struct {
+                       u32 major;
+                       u32 minor;
+               } v4l;
+               struct {
+                       u32 major;
+                       u32 minor;
+               } fb;
+               struct {
+                       u32 card;
+                       u32 device;
+                       u32 subdevice;
+               } alsa;
+               int dvb;
+
+               /* Sub-device specifications */
+               /* Nothing needed yet */
+       };
+};
+
+static inline u32 media_entity_type(struct media_entity *entity)
+{
+       return entity->type & MEDIA_ENT_TYPE_MASK;
+}
+
+static inline u32 media_entity_subtype(struct media_entity *entity)
+{
+       return entity->type & MEDIA_ENT_SUBTYPE_MASK;
+}
+
+#define MEDIA_ENTITY_ENUM_MAX_DEPTH    16
+
+struct media_entity_graph {
+       struct {
+               struct media_entity *entity;
+               int link;
+       } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+       int top;
+};
+
+int media_entity_init(struct media_entity *entity, u16 num_pads,
+               struct media_pad *pads, u16 extra_links);
+void media_entity_cleanup(struct media_entity *entity);
+
+int media_entity_create_link(struct media_entity *source, u16 source_pad,
+               struct media_entity *sink, u16 sink_pad, u32 flags);
+int __media_entity_setup_link(struct media_link *link, u32 flags);
+int media_entity_setup_link(struct media_link *link, u32 flags);
+struct media_link *media_entity_find_link(struct media_pad *source,
+               struct media_pad *sink);
+struct media_pad *media_entity_remote_source(struct media_pad *pad);
+
+struct media_entity *media_entity_get(struct media_entity *entity);
+void media_entity_put(struct media_entity *entity);
+
+void media_entity_graph_walk_start(struct media_entity_graph *graph,
+               struct media_entity *entity);
+struct media_entity *
+media_entity_graph_walk_next(struct media_entity_graph *graph);
+void media_entity_pipeline_start(struct media_entity *entity,
+               struct media_pipeline *pipe);
+void media_entity_pipeline_stop(struct media_entity *entity);
+
+#define media_entity_call(entity, operation, args...)                  \
+       (((entity)->ops && (entity)->ops->operation) ?                  \
+        (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
+
+#endif
diff --git a/include/media/noon010pc30.h b/include/media/noon010pc30.h
new file mode 100644 (file)
index 0000000..58eafee
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Driver header for NOON010PC30L camera sensor chip.
+ *
+ * Copyright (c) 2010 Samsung Electronics, Co. Ltd
+ * Contact: Sylwester Nawrocki <s.nawrocki@samsung.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.
+ */
+
+#ifndef NOON010PC30_H
+#define NOON010PC30_H
+
+/**
+ * @clk_rate: the clock frequency in Hz
+ * @gpio_nreset: GPIO driving nRESET pin
+ * @gpio_nstby: GPIO driving nSTBY pin
+ */
+
+struct noon010pc30_platform_data {
+       unsigned long clk_rate;
+       int gpio_nreset;
+       int gpio_nstby;
+};
+
+#endif /* NOON010PC30_H */
index ee9e2f747c76a5f12f8ff21f718417478e9bd92b..9184751f19c0acf803ea69a10da560e0a0307545 100644 (file)
@@ -94,7 +94,7 @@ void rc_map_init(void);
 #define RC_MAP_GADMEI_RM008Z             "rc-gadmei-rm008z"
 #define RC_MAP_GENIUS_TVGO_A11MCE        "rc-genius-tvgo-a11mce"
 #define RC_MAP_GOTVIEW7135               "rc-gotview7135"
-#define RC_MAP_HAUPPAUGE_NEW             "rc-hauppauge-new"
+#define RC_MAP_HAUPPAUGE_NEW             "rc-hauppauge"
 #define RC_MAP_IMON_MCE                  "rc-imon-mce"
 #define RC_MAP_IMON_PAD                  "rc-imon-pad"
 #define RC_MAP_IODATA_BCTV7E             "rc-iodata-bctv7e"
@@ -125,14 +125,16 @@ void rc_map_init(void);
 #define RC_MAP_PROTEUS_2309              "rc-proteus-2309"
 #define RC_MAP_PURPLETV                  "rc-purpletv"
 #define RC_MAP_PV951                     "rc-pv951"
-#define RC_MAP_RC5_HAUPPAUGE_NEW         "rc-rc5-hauppauge-new"
+#define RC_MAP_HAUPPAUGE                 "rc-hauppauge"
 #define RC_MAP_RC5_TV                    "rc-rc5-tv"
 #define RC_MAP_RC6_MCE                   "rc-rc6-mce"
 #define RC_MAP_REAL_AUDIO_220_32_KEYS    "rc-real-audio-220-32-keys"
 #define RC_MAP_STREAMZAP                 "rc-streamzap"
 #define RC_MAP_TBS_NEC                   "rc-tbs-nec"
+#define RC_MAP_TECHNISAT_USB2            "rc-technisat-usb2"
 #define RC_MAP_TERRATEC_CINERGY_XS       "rc-terratec-cinergy-xs"
 #define RC_MAP_TERRATEC_SLIM             "rc-terratec-slim"
+#define RC_MAP_TERRATEC_SLIM_2           "rc-terratec-slim-2"
 #define RC_MAP_TEVII_NEC                 "rc-tevii-nec"
 #define RC_MAP_TOTAL_MEDIA_IN_HAND       "rc-total-media-in-hand"
 #define RC_MAP_TREKSTOR                  "rc-trekstor"
diff --git a/include/media/s3c_fimc.h b/include/media/s3c_fimc.h
deleted file mode 100644 (file)
index ca1b673..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Samsung S5P SoC camera interface driver header
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd
- * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef S3C_FIMC_H_
-#define S3C_FIMC_H_
-
-enum cam_bus_type {
-       FIMC_ITU_601 = 1,
-       FIMC_ITU_656,
-       FIMC_MIPI_CSI2,
-       FIMC_LCD_WB, /* FIFO link from LCD mixer */
-};
-
-#define FIMC_CLK_INV_PCLK      (1 << 0)
-#define FIMC_CLK_INV_VSYNC     (1 << 1)
-#define FIMC_CLK_INV_HREF      (1 << 2)
-#define FIMC_CLK_INV_HSYNC     (1 << 3)
-
-struct i2c_board_info;
-
-/**
- * struct s3c_fimc_isp_info - image sensor information required for host
- *                           interace configuration.
- *
- * @board_info: pointer to I2C subdevice's board info
- * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
- * @i2c_bus_num: i2c control bus id the sensor is attached to
- * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
- * @bus_width: camera data bus width in bits
- * @flags: flags defining bus signals polarity inversion (High by default)
- */
-struct s3c_fimc_isp_info {
-       struct i2c_board_info *board_info;
-       enum cam_bus_type bus_type;
-       u16 i2c_bus_num;
-       u16 mux_id;
-       u16 bus_width;
-       u16 flags;
-};
-
-
-#define FIMC_MAX_CAMIF_CLIENTS 2
-
-/**
- * struct s3c_platform_fimc - camera host interface platform data
- *
- * @isp_info: properties of camera sensor required for host interface setup
- */
-struct s3c_platform_fimc {
-       struct s3c_fimc_isp_info *isp_info[FIMC_MAX_CAMIF_CLIENTS];
-};
-#endif /* S3C_FIMC_H_ */
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
new file mode 100644 (file)
index 0000000..9fdff8a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Samsung S5P SoC camera interface driver header
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef S5P_FIMC_H_
+#define S5P_FIMC_H_
+
+enum cam_bus_type {
+       FIMC_ITU_601 = 1,
+       FIMC_ITU_656,
+       FIMC_MIPI_CSI2,
+       FIMC_LCD_WB, /* FIFO link from LCD mixer */
+};
+
+#define FIMC_CLK_INV_PCLK      (1 << 0)
+#define FIMC_CLK_INV_VSYNC     (1 << 1)
+#define FIMC_CLK_INV_HREF      (1 << 2)
+#define FIMC_CLK_INV_HSYNC     (1 << 3)
+
+struct i2c_board_info;
+
+/**
+ * struct s5p_fimc_isp_info - image sensor information required for host
+ *                           interace configuration.
+ *
+ * @board_info: pointer to I2C subdevice's board info
+ * @clk_frequency: frequency of the clock the host interface provides to sensor
+ * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
+ * @csi_data_align: MIPI-CSI interface data alignment in bits
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ * @flags: flags defining bus signals polarity inversion (High by default)
+ */
+struct s5p_fimc_isp_info {
+       struct i2c_board_info *board_info;
+       unsigned long clk_frequency;
+       enum cam_bus_type bus_type;
+       u16 csi_data_align;
+       u16 i2c_bus_num;
+       u16 mux_id;
+       u16 flags;
+};
+
+/**
+ * struct s5p_platform_fimc - camera host interface platform data
+ *
+ * @isp_info: properties of camera sensor required for host interface setup
+ * @num_clients: the number of attached image sensors
+ */
+struct s5p_platform_fimc {
+       struct s5p_fimc_isp_info *isp_info;
+       int num_clients;
+};
+#endif /* S5P_FIMC_H_ */
index 9386db829fb7d01190d2d86cf3cf319440e337c5..f80b5372baf37ee3d6324b5e5809d85594a748fc 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pm.h>
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
 #include <media/v4l2-device.h>
 
 extern struct bus_type soc_camera_bus_type;
@@ -29,6 +30,8 @@ struct soc_camera_device {
        struct device *pdev;            /* Platform device */
        s32 user_width;
        s32 user_height;
+       u32 bytesperline;               /* for padding, zero if unused */
+       u32 sizeimage;
        enum v4l2_colorspace colorspace;
        unsigned char iface;            /* Host number */
        unsigned char devnum;           /* Device number per host */
@@ -44,7 +47,10 @@ struct soc_camera_device {
        int use_count;
        struct mutex video_lock;        /* Protects device data */
        struct file *streamer;          /* stream owner */
-       struct videobuf_queue vb_vidq;
+       union {
+               struct videobuf_queue vb_vidq;
+               struct vb2_queue vb2_vidq;
+       };
 };
 
 struct soc_camera_host {
@@ -78,6 +84,8 @@ struct soc_camera_host_ops {
        int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        void (*init_videobuf)(struct videobuf_queue *,
                              struct soc_camera_device *);
+       int (*init_videobuf2)(struct vb2_queue *,
+                             struct soc_camera_device *);
        int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *);
        int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
        int (*set_bus_param)(struct soc_camera_device *, __u32);
@@ -85,6 +93,7 @@ struct soc_camera_host_ops {
        int (*set_ctrl)(struct soc_camera_device *, struct v4l2_control *);
        int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
        int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
+       int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
        unsigned int (*poll)(struct file *, poll_table *);
        const struct v4l2_queryctrl *controls;
        int num_controls;
@@ -299,4 +308,17 @@ static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *cli
        return icd->vdev;
 }
 
+static inline struct soc_camera_device *soc_camera_from_vb2q(struct vb2_queue *vq)
+{
+       return container_of(vq, struct soc_camera_device, vb2_vidq);
+}
+
+static inline struct soc_camera_device *soc_camera_from_vbq(struct videobuf_queue *vq)
+{
+       return container_of(vq, struct soc_camera_device, vb_vidq);
+}
+
+void soc_camera_lock(struct vb2_queue *vq);
+void soc_camera_unlock(struct vb2_queue *vq);
+
 #endif
index 037cd7be001e75f5751f6db848d39fa9142c7b2f..b338108ec305cd1864baefe3a4f36a8d23156249 100644 (file)
@@ -12,8 +12,7 @@
 #define SOC_MEDIABUS_H
 
 #include <linux/videodev2.h>
-
-#include <media/v4l2-mediabus.h>
+#include <linux/v4l2-mediabus.h>
 
 /**
  * enum soc_mbus_packing - data packing types on the media-bus
@@ -61,5 +60,6 @@ struct soc_mbus_pixelfmt {
 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
        enum v4l2_mbus_pixelcode code);
 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf);
 
 #endif
index 51811eac46f1175ad18b86b3f9e2a4fff8b0e83c..963e33471835d6360620d4714eaec7d8b54bf0ed 100644 (file)
@@ -21,6 +21,7 @@
 
 #ifndef _TUNER_H
 #define _TUNER_H
+#ifdef __KERNEL__
 
 #include <linux/videodev2.h>
 
 #define TUNER_NXP_TDA18271             83
 #define TUNER_SONY_BTF_PXN01Z          84
 #define TUNER_PHILIPS_FQ1236_MK5       85      /* NTSC, TDA9885, no FM radio */
+#define TUNER_TENA_TNF_5337            86
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
 #define TDA9887_GAIN_NORMAL            (1<<20)
 #define TDA9887_RIF_41_3               (1<<21)  /* radio IF1 41.3 vs 33.3 */
 
-#ifdef __KERNEL__
-
 enum tuner_mode {
-       T_UNINITIALIZED = 0,
        T_RADIO         = 1 << V4L2_TUNER_RADIO,
        T_ANALOG_TV     = 1 << V4L2_TUNER_ANALOG_TV,
-       T_DIGITAL_TV    = 1 << V4L2_TUNER_DIGITAL_TV,
-       T_STANDBY       = 1 << 31
+       /* Don't need to map V4L2_TUNER_DIGITAL_TV, as tuner-core won't use it */
 };
 
 /* Older boards only had a single tuner device. Nowadays multiple tuner
@@ -193,11 +191,3 @@ struct tuner_setup {
 #endif /* __KERNEL__ */
 
 #endif /* _TUNER_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 44fe44ec9ea7963bead81f104958ecb8d00cf6e3..b3edb67a83114e10af4409a46388187c84a5c53e 100644 (file)
@@ -75,6 +75,7 @@ enum {
        V4L2_IDENT_OV9640 = 257,
        V4L2_IDENT_OV6650 = 258,
        V4L2_IDENT_OV2640 = 259,
+       V4L2_IDENT_OV9740 = 260,
 
        /* module saa7146: reserved range 300-309 */
        V4L2_IDENT_SAA7146 = 300,
@@ -209,6 +210,9 @@ enum {
        /* module sn9c20x: just ident 10000 */
        V4L2_IDENT_SN9C20X = 10000,
 
+       /* Siliconfile sensors: reserved range 10100 - 10199 */
+       V4L2_IDENT_NOON010PC30  = 10100,
+
        /* module cx231xx and cx25840 */
        V4L2_IDENT_CX2310X_AV = 23099, /* Integrated A/V decoder; not in '100 */
        V4L2_IDENT_CX23100    = 23100,
index a659319e858257d0bfe2c736f8a97fb2b4fcdcb8..a298ec49ddc489ba70d47003fba8a39f32335ff4 100644 (file)
 
 /* ------------------------------------------------------------------------- */
 
-/* Priority helper functions */
-
-struct v4l2_prio_state {
-       atomic_t prios[4];
-};
-void v4l2_prio_init(struct v4l2_prio_state *global);
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
-                    enum v4l2_priority new);
-void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local);
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local);
-
-/* ------------------------------------------------------------------------- */
-
 /* Control helper functions */
 
 int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
index 15802a067a127da4592ce731049a336f9edc46d6..8266d5ade2ffd39532cc4e3347e549524334c273 100644 (file)
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 
+#include <media/media-entity.h>
+
 #define VIDEO_MAJOR    81
 
 #define VFL_TYPE_GRABBER       0
 #define VFL_TYPE_VBI           1
 #define VFL_TYPE_RADIO         2
-#define VFL_TYPE_MAX           3
+#define VFL_TYPE_SUBDEV                3
+#define VFL_TYPE_MAX           4
 
 struct v4l2_ioctl_callbacks;
 struct video_device;
@@ -32,7 +35,25 @@ struct v4l2_ctrl_handler;
    Drivers can clear this flag if they want to block all future
    device access. It is cleared by video_unregister_device. */
 #define V4L2_FL_REGISTERED     (0)
+/* file->private_data points to struct v4l2_fh */
 #define V4L2_FL_USES_V4L2_FH   (1)
+/* Use the prio field of v4l2_fh for core priority checking */
+#define V4L2_FL_USE_FH_PRIO    (2)
+
+/* Priority helper functions */
+
+struct v4l2_prio_state {
+       atomic_t prios[4];
+};
+
+void v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+                    enum v4l2_priority new);
+void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local);
+
 
 struct v4l2_file_operations {
        struct module *owner;
@@ -54,6 +75,9 @@ struct v4l2_file_operations {
 
 struct video_device
 {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity entity;
+#endif
        /* device ops */
        const struct v4l2_file_operations *fops;
 
@@ -68,6 +92,9 @@ struct video_device
        /* Control handler associated with this device node. May be NULL. */
        struct v4l2_ctrl_handler *ctrl_handler;
 
+       /* Priority state. If NULL, then v4l2_dev->prio will be used. */
+       struct v4l2_prio_state *prio;
+
        /* device info */
        char name[32];
        int vfl_type;
@@ -99,18 +126,31 @@ struct video_device
        struct mutex *lock;
 };
 
+#define media_entity_to_video_device(entity) \
+       container_of(entity, struct video_device, entity)
 /* dev to video-device */
 #define to_video_device(cd) container_of(cd, struct video_device, dev)
 
+int __must_check __video_register_device(struct video_device *vdev, int type,
+               int nr, int warn_if_nr_in_use, struct module *owner);
+
 /* Register video devices. Note that if video_register_device fails,
    the release() callback of the video_device structure is *not* called, so
    the caller is responsible for freeing any data. Usually that means that
    you call video_device_release() on failure. */
-int __must_check video_register_device(struct video_device *vdev, int type, int nr);
+static inline int __must_check video_register_device(struct video_device *vdev,
+               int type, int nr)
+{
+       return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
+}
 
 /* Same as video_register_device, but no warning is issued if the desired
    device node number was already in use. */
-int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr);
+static inline int __must_check video_register_device_no_warn(
+               struct video_device *vdev, int type, int nr)
+{
+       return __video_register_device(vdev, type, nr, 0, vdev->fops->owner);
+}
 
 /* Unregister video devices. Will do nothing if vdev == NULL or
    video_is_registered() returns false. */
index b16f307d471a2df59fd622cba1b338e42503ec16..bd102cf509ac28ee9a0c5e70fcc9c4916ea50910 100644 (file)
@@ -21,7 +21,9 @@
 #ifndef _V4L2_DEVICE_H
 #define _V4L2_DEVICE_H
 
+#include <media/media-device.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-dev.h>
 
 /* Each instance of a V4L2 device should create the v4l2_device struct,
    either stand-alone or embedded in a larger struct.
@@ -39,6 +41,9 @@ struct v4l2_device {
           Note: dev might be NULL if there is no parent device
           as is the case with e.g. ISA devices. */
        struct device *dev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_device *mdev;
+#endif
        /* used to keep track of the registered subdevs */
        struct list_head subdevs;
        /* lock this struct; can be used by the driver as well if this
@@ -51,10 +56,23 @@ struct v4l2_device {
                        unsigned int notification, void *arg);
        /* The control handler. May be NULL. */
        struct v4l2_ctrl_handler *ctrl_handler;
+       /* Device's priority state */
+       struct v4l2_prio_state prio;
        /* BKL replacement mutex. Temporary solution only. */
        struct mutex ioctl_lock;
+       /* Keep track of the references to this struct. */
+       struct kref ref;
+       /* Release function that is called when the ref count goes to 0. */
+       void (*release)(struct v4l2_device *v4l2_dev);
 };
 
+static inline void v4l2_device_get(struct v4l2_device *v4l2_dev)
+{
+       kref_get(&v4l2_dev->ref);
+}
+
+int v4l2_device_put(struct v4l2_device *v4l2_dev);
+
 /* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev.
    dev may be NULL in rare cases (ISA devices). In that case you
    must fill in the v4l2_dev->name field before calling this function. */
@@ -96,6 +114,12 @@ int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
    wasn't registered. In that case it will do nothing. */
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
 
+/* Register device nodes for all subdev of the v4l2 device that are marked with
+ * the V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+ */
+int __must_check
+v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev);
+
 /* Iterate over all subdevs. */
 #define v4l2_device_for_each_subdev(sd, v4l2_dev)                      \
        list_for_each_entry(sd, &(v4l2_dev)->subdevs, list)
index 1d72dde320bf1e21501688ca14bb7833241fbdc7..0206aa55be24cd2b47e685f44918a9fa721ee96f 100644 (file)
@@ -35,6 +35,7 @@ struct v4l2_fh {
        struct list_head        list;
        struct video_device     *vdev;
        struct v4l2_events      *events; /* events, pending and subscribed */
+       enum v4l2_priority      prio;
 };
 
 /*
@@ -49,9 +50,17 @@ int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
  * handle must be initialised first.
  */
 void v4l2_fh_add(struct v4l2_fh *fh);
+/*
+ * Can be used as the open() op of v4l2_file_operations.
+ * It allocates a v4l2_fh and inits and adds it to the video_device associated
+ * with the file pointer.
+ */
+int v4l2_fh_open(struct file *filp);
 /*
  * Remove file handle from the list of file handles. Must be called in
  * v4l2_file_operations->release() handler if the driver uses v4l2_fh.
+ * On error filp->private_data will be NULL, otherwise it will point to
+ * the v4l2_fh struct.
  */
 void v4l2_fh_del(struct v4l2_fh *fh);
 /*
@@ -61,5 +70,25 @@ void v4l2_fh_del(struct v4l2_fh *fh);
  * driver uses v4l2_fh.
  */
 void v4l2_fh_exit(struct v4l2_fh *fh);
+/*
+ * Can be used as the release() op of v4l2_file_operations.
+ * It deletes and exits the v4l2_fh associated with the file pointer and
+ * frees it. It will do nothing if filp->private_data (the pointer to the
+ * v4l2_fh struct) is NULL. This function always returns 0.
+ */
+int v4l2_fh_release(struct file *filp);
+/*
+ * Returns 1 if this filehandle is the only filehandle opened for the
+ * associated video_device. If fh is NULL, then it returns 0.
+ */
+int v4l2_fh_is_singular(struct v4l2_fh *fh);
+/*
+ * Helper function with struct file as argument. If filp->private_data is
+ * NULL, then it will return 0.
+ */
+static inline int v4l2_fh_is_singular_file(struct file *filp)
+{
+       return v4l2_fh_is_singular(filp->private_data);
+}
 
 #endif /* V4L2_EVENT_H */
index 67df37542c68d5d9607719d6517d243c9e317505..dd9f1e7b8ff72321a99a965d34ec5ac682395a8c 100644 (file)
@@ -37,6 +37,10 @@ struct v4l2_ioctl_ops {
                                            struct v4l2_fmtdesc *f);
        int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh,
                                            struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh,
+                                             struct v4l2_fmtdesc *f);
+       int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh,
+                                             struct v4l2_fmtdesc *f);
        int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
                                            struct v4l2_fmtdesc *f);
 
@@ -57,6 +61,10 @@ struct v4l2_ioctl_ops {
                                        struct v4l2_format *f);
        int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh,
                                        struct v4l2_format *f);
+       int (*vidioc_g_fmt_vid_cap_mplane)(struct file *file, void *fh,
+                                          struct v4l2_format *f);
+       int (*vidioc_g_fmt_vid_out_mplane)(struct file *file, void *fh,
+                                          struct v4l2_format *f);
        int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
                                        struct v4l2_format *f);
 
@@ -77,6 +85,10 @@ struct v4l2_ioctl_ops {
                                        struct v4l2_format *f);
        int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh,
                                        struct v4l2_format *f);
+       int (*vidioc_s_fmt_vid_cap_mplane)(struct file *file, void *fh,
+                                          struct v4l2_format *f);
+       int (*vidioc_s_fmt_vid_out_mplane)(struct file *file, void *fh,
+                                          struct v4l2_format *f);
        int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
                                        struct v4l2_format *f);
 
@@ -97,6 +109,10 @@ struct v4l2_ioctl_ops {
                                          struct v4l2_format *f);
        int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh,
                                          struct v4l2_format *f);
+       int (*vidioc_try_fmt_vid_cap_mplane)(struct file *file, void *fh,
+                                            struct v4l2_format *f);
+       int (*vidioc_try_fmt_vid_out_mplane)(struct file *file, void *fh,
+                                            struct v4l2_format *f);
        int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
                                          struct v4l2_format *f);
 
@@ -254,7 +270,7 @@ struct v4l2_ioctl_ops {
 
        /* For other private ioctls */
        long (*vidioc_default)         (struct file *file, void *fh,
-                                       int cmd, void *arg);
+                                       bool valid_prio, int cmd, void *arg);
 };
 
 
index 8e6559838ae32f844ec9f33626787d9b86b19316..971c7fa29614092cc35fd4cf736ece5c54df5d3e 100644 (file)
 #ifndef V4L2_MEDIABUS_H
 #define V4L2_MEDIABUS_H
 
-/*
- * These pixel codes uniquely identify data formats on the media bus. Mostly
- * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
- * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
- * data format is fixed. Additionally, "2X8" means that one pixel is transferred
- * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
- * transferred over the bus: "LE" means that the least significant bits are
- * transferred first, "BE" means that the most significant bits are transferred
- * first, and "PADHI" and "PADLO" define which bits - low or high, in the
- * incomplete high byte, are filled with padding bits.
- */
-enum v4l2_mbus_pixelcode {
-       V4L2_MBUS_FMT_FIXED = 1,
-       V4L2_MBUS_FMT_YUYV8_2X8,
-       V4L2_MBUS_FMT_YVYU8_2X8,
-       V4L2_MBUS_FMT_UYVY8_2X8,
-       V4L2_MBUS_FMT_VYUY8_2X8,
-       V4L2_MBUS_FMT_YVYU10_2X10,
-       V4L2_MBUS_FMT_YUYV10_2X10,
-       V4L2_MBUS_FMT_YVYU10_1X20,
-       V4L2_MBUS_FMT_YUYV10_1X20,
-       V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
-       V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
-       V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
-       V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
-       V4L2_MBUS_FMT_RGB565_2X8_LE,
-       V4L2_MBUS_FMT_RGB565_2X8_BE,
-       V4L2_MBUS_FMT_BGR565_2X8_LE,
-       V4L2_MBUS_FMT_BGR565_2X8_BE,
-       V4L2_MBUS_FMT_SBGGR8_1X8,
-       V4L2_MBUS_FMT_SBGGR10_1X10,
-       V4L2_MBUS_FMT_GREY8_1X8,
-       V4L2_MBUS_FMT_Y10_1X10,
-       V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
-       V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
-       V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
-       V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
-       V4L2_MBUS_FMT_SGRBG8_1X8,
-       V4L2_MBUS_FMT_SBGGR12_1X12,
-       V4L2_MBUS_FMT_YUYV8_1_5X8,
-       V4L2_MBUS_FMT_YVYU8_1_5X8,
-       V4L2_MBUS_FMT_UYVY8_1_5X8,
-       V4L2_MBUS_FMT_VYUY8_1_5X8,
-};
-
-/**
- * struct v4l2_mbus_framefmt - frame format on the media bus
- * @width:     frame width
- * @height:    frame height
- * @code:      data format code
- * @field:     used interlacing type
- * @colorspace:        colorspace of the data
- */
-struct v4l2_mbus_framefmt {
-       __u32                           width;
-       __u32                           height;
-       enum v4l2_mbus_pixelcode        code;
-       enum v4l2_field                 field;
-       enum v4l2_colorspace            colorspace;
-};
+#include <linux/v4l2-mediabus.h>
 
 static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
                                const struct v4l2_mbus_framefmt *mbus_fmt)
index 8d149f1c58d037253a487eb9d4c2b6103c198297..16ac4733e80d9bad5822a104f1faa6f1388abf24 100644 (file)
@@ -5,7 +5,7 @@
  * and destination.
  *
  * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- * Pawel Osciak, <p.osciak@samsung.com>
+ * Pawel Osciak, <pawel@osciak.com>
  * Marek Szyprowski, <m.szyprowski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,7 @@
 #ifndef _MEDIA_V4L2_MEM2MEM_H
 #define _MEDIA_V4L2_MEM2MEM_H
 
-#include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
 
 /**
  * struct v4l2_m2m_ops - mem-to-mem device driver callbacks
@@ -45,17 +45,20 @@ struct v4l2_m2m_ops {
        void (*device_run)(void *priv);
        int (*job_ready)(void *priv);
        void (*job_abort)(void *priv);
+       void (*lock)(void *priv);
+       void (*unlock)(void *priv);
 };
 
 struct v4l2_m2m_dev;
 
 struct v4l2_m2m_queue_ctx {
 /* private: internal use only */
-       struct videobuf_queue   q;
+       struct vb2_queue        q;
 
        /* Queue for buffers ready to be processed as soon as this
         * instance receives access to the device */
        struct list_head        rdy_queue;
+       spinlock_t              rdy_spinlock;
        u8                      num_rdy;
 };
 
@@ -72,19 +75,31 @@ struct v4l2_m2m_ctx {
        /* For device job queue */
        struct list_head                queue;
        unsigned long                   job_flags;
+       wait_queue_head_t               finished;
 
        /* Instance private data */
        void                            *priv;
 };
 
+struct v4l2_m2m_buffer {
+       struct vb2_buffer       vb;
+       struct list_head        list;
+};
+
 void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev);
 
-struct videobuf_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
+struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
                                       enum v4l2_buf_type type);
 
 void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
                         struct v4l2_m2m_ctx *m2m_ctx);
 
+static inline void
+v4l2_m2m_buf_done(struct vb2_buffer *buf, enum vb2_buffer_state state)
+{
+       vb2_buffer_done(buf, state);
+}
+
 int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                     struct v4l2_requestbuffers *reqbufs);
 
@@ -110,13 +125,13 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops);
 void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev);
 
-struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(void *priv, struct v4l2_m2m_dev *m2m_dev,
-                       void (*vq_init)(void *priv, struct videobuf_queue *,
-                                       enum v4l2_buf_type));
+struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
+               void *drv_priv,
+               int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq));
+
 void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx);
 
-void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct videobuf_queue *vq,
-                       struct videobuf_buffer *vb);
+void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb);
 
 /**
  * v4l2_m2m_num_src_bufs_ready() - return the number of source buffers ready for
@@ -138,7 +153,7 @@ unsigned int v4l2_m2m_num_dst_bufs_ready(struct v4l2_m2m_ctx *m2m_ctx)
        return m2m_ctx->out_q_ctx.num_rdy;
 }
 
-void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type);
+void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx);
 
 /**
  * v4l2_m2m_next_src_buf() - return next source buffer from the list of ready
@@ -146,7 +161,7 @@ void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type);
  */
 static inline void *v4l2_m2m_next_src_buf(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_next_buf(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       return v4l2_m2m_next_buf(&m2m_ctx->out_q_ctx);
 }
 
 /**
@@ -155,29 +170,28 @@ static inline void *v4l2_m2m_next_src_buf(struct v4l2_m2m_ctx *m2m_ctx)
  */
 static inline void *v4l2_m2m_next_dst_buf(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_next_buf(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       return v4l2_m2m_next_buf(&m2m_ctx->cap_q_ctx);
 }
 
 /**
- * v4l2_m2m_get_src_vq() - return videobuf_queue for source buffers
+ * v4l2_m2m_get_src_vq() - return vb2_queue for source buffers
  */
 static inline
-struct videobuf_queue *v4l2_m2m_get_src_vq(struct v4l2_m2m_ctx *m2m_ctx)
+struct vb2_queue *v4l2_m2m_get_src_vq(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       return &m2m_ctx->out_q_ctx.q;
 }
 
 /**
- * v4l2_m2m_get_dst_vq() - return videobuf_queue for destination buffers
+ * v4l2_m2m_get_dst_vq() - return vb2_queue for destination buffers
  */
 static inline
-struct videobuf_queue *v4l2_m2m_get_dst_vq(struct v4l2_m2m_ctx *m2m_ctx)
+struct vb2_queue *v4l2_m2m_get_dst_vq(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       return &m2m_ctx->cap_q_ctx.q;
 }
 
-void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx,
-                         enum v4l2_buf_type type);
+void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx);
 
 /**
  * v4l2_m2m_src_buf_remove() - take off a source buffer from the list of ready
@@ -185,7 +199,7 @@ void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx,
  */
 static inline void *v4l2_m2m_src_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_buf_remove(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       return v4l2_m2m_buf_remove(&m2m_ctx->out_q_ctx);
 }
 
 /**
@@ -194,7 +208,7 @@ static inline void *v4l2_m2m_src_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
  */
 static inline void *v4l2_m2m_dst_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       return v4l2_m2m_buf_remove(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       return v4l2_m2m_buf_remove(&m2m_ctx->cap_q_ctx);
 }
 
 #endif /* _MEDIA_V4L2_MEM2MEM_H */
index daf1e57d9b266e9be3daf59e2c0e141351fa78d8..1562c4ff3a650de87a1dc20581b2a389fd458808 100644 (file)
 #ifndef _V4L2_SUBDEV_H
 #define _V4L2_SUBDEV_H
 
+#include <linux/v4l2-subdev.h>
+#include <media/media-entity.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
 #include <media/v4l2-mediabus.h>
 
 /* generic v4l2_device notify callback notification values */
 
 struct v4l2_device;
 struct v4l2_ctrl_handler;
+struct v4l2_event_subscription;
+struct v4l2_fh;
 struct v4l2_subdev;
+struct v4l2_subdev_fh;
 struct tuner_setup;
 
 /* decode_vbi_line */
@@ -160,6 +167,10 @@ struct v4l2_subdev_core_ops {
        int (*s_power)(struct v4l2_subdev *sd, int on);
        int (*interrupt_service_routine)(struct v4l2_subdev *sd,
                                                u32 status, bool *handled);
+       int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                              struct v4l2_event_subscription *sub);
+       int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                                struct v4l2_event_subscription *sub);
 };
 
 /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
@@ -257,6 +268,10 @@ struct v4l2_subdev_video_ops {
        int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
        int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
        int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
+       int (*g_frame_interval)(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_frame_interval *interval);
+       int (*s_frame_interval)(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_frame_interval *interval);
        int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
        int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
        int (*enum_dv_presets) (struct v4l2_subdev *sd,
@@ -271,6 +286,8 @@ struct v4l2_subdev_video_ops {
                        struct v4l2_dv_timings *timings);
        int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
                             enum v4l2_mbus_pixelcode *code);
+       int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
+                            struct v4l2_frmsizeenum *fsize);
        int (*g_mbus_fmt)(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *fmt);
        int (*try_mbus_fmt)(struct v4l2_subdev *sd,
@@ -324,9 +341,13 @@ struct v4l2_subdev_vbi_ops {
  *                   This is needed for some sensors, which always corrupt
  *                   several top lines of the output image, or which send their
  *                   metadata in them.
+ * @g_skip_frames: number of frames to skip at stream start. This is needed for
+ *                buggy sensors that generate faulty frames when they are
+ *                turned on.
  */
 struct v4l2_subdev_sensor_ops {
        int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines);
+       int (*g_skip_frames)(struct v4l2_subdev *sd, u32 *frames);
 };
 
 /*
@@ -401,6 +422,25 @@ struct v4l2_subdev_ir_ops {
                                struct v4l2_subdev_ir_parameters *params);
 };
 
+struct v4l2_subdev_pad_ops {
+       int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_mbus_code_enum *code);
+       int (*enum_frame_size)(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_frame_size_enum *fse);
+       int (*enum_frame_interval)(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_interval_enum *fie);
+       int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *format);
+       int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_format *format);
+       int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_crop *crop);
+       int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                      struct v4l2_subdev_crop *crop);
+};
+
 struct v4l2_subdev_ops {
        const struct v4l2_subdev_core_ops       *core;
        const struct v4l2_subdev_tuner_ops      *tuner;
@@ -409,6 +449,7 @@ struct v4l2_subdev_ops {
        const struct v4l2_subdev_vbi_ops        *vbi;
        const struct v4l2_subdev_ir_ops         *ir;
        const struct v4l2_subdev_sensor_ops     *sensor;
+       const struct v4l2_subdev_pad_ops        *pad;
 };
 
 /*
@@ -420,23 +461,36 @@ struct v4l2_subdev_ops {
  *
  * unregistered: called when this subdev is unregistered. When called the
  *     v4l2_dev field is still set to the correct v4l2_device.
+ *
+ * open: called when the subdev device node is opened by an application.
+ *
+ * close: called when the subdev device node is closed.
  */
 struct v4l2_subdev_internal_ops {
        int (*registered)(struct v4l2_subdev *sd);
        void (*unregistered)(struct v4l2_subdev *sd);
+       int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
+       int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
 };
 
 #define V4L2_SUBDEV_NAME_SIZE 32
 
 /* Set this flag if this subdev is a i2c device. */
-#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+#define V4L2_SUBDEV_FL_IS_I2C                  (1U << 0)
 /* Set this flag if this subdev is a spi device. */
-#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
+#define V4L2_SUBDEV_FL_IS_SPI                  (1U << 1)
+/* Set this flag if this subdev needs a device node. */
+#define V4L2_SUBDEV_FL_HAS_DEVNODE             (1U << 2)
+/* Set this flag if this subdev generates events. */
+#define V4L2_SUBDEV_FL_HAS_EVENTS              (1U << 3)
 
 /* Each instance of a subdev driver should create this struct, either
    stand-alone or embedded in a larger struct.
  */
 struct v4l2_subdev {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+       struct media_entity entity;
+#endif
        struct list_head list;
        struct module *owner;
        u32 flags;
@@ -453,8 +507,47 @@ struct v4l2_subdev {
        /* pointer to private data */
        void *dev_priv;
        void *host_priv;
+       /* subdev device node */
+       struct video_device devnode;
+       /* number of events to be allocated on open */
+       unsigned int nevents;
+};
+
+#define media_entity_to_v4l2_subdev(ent) \
+       container_of(ent, struct v4l2_subdev, entity)
+#define vdev_to_v4l2_subdev(vdev) \
+       container_of(vdev, struct v4l2_subdev, devnode)
+
+/*
+ * Used for storing subdev information per file handle
+ */
+struct v4l2_subdev_fh {
+       struct v4l2_fh vfh;
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+       struct v4l2_mbus_framefmt *try_fmt;
+       struct v4l2_rect *try_crop;
+#endif
 };
 
+#define to_v4l2_subdev_fh(fh)  \
+       container_of(fh, struct v4l2_subdev_fh, vfh)
+
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static inline struct v4l2_mbus_framefmt *
+v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+       return &fh->try_fmt[pad];
+}
+
+static inline struct v4l2_rect *
+v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+       return &fh->try_crop[pad];
+}
+#endif
+
+extern const struct v4l2_file_operations v4l2_subdev_fops;
+
 static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
 {
        sd->dev_priv = p;
@@ -475,20 +568,8 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
        return sd->host_priv;
 }
 
-static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
-                                       const struct v4l2_subdev_ops *ops)
-{
-       INIT_LIST_HEAD(&sd->list);
-       /* ops->core MUST be set */
-       BUG_ON(!ops || !ops->core);
-       sd->ops = ops;
-       sd->v4l2_dev = NULL;
-       sd->flags = 0;
-       sd->name[0] = '\0';
-       sd->grp_id = 0;
-       sd->dev_priv = NULL;
-       sd->host_priv = NULL;
-}
+void v4l2_subdev_init(struct v4l2_subdev *sd,
+                     const struct v4l2_subdev_ops *ops);
 
 /* Call an ops of a v4l2_subdev, doing the right checks against
    NULL pointers.
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
new file mode 100644 (file)
index 0000000..f87472a
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * videobuf2-core.h - V4L2 driver helper framework
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+#ifndef _MEDIA_VIDEOBUF2_CORE_H
+#define _MEDIA_VIDEOBUF2_CORE_H
+
+#include <linux/mm_types.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/videodev2.h>
+
+struct vb2_alloc_ctx;
+struct vb2_fileio_data;
+
+/**
+ * struct vb2_mem_ops - memory handling/memory allocator operations
+ * @alloc:     allocate video memory and, optionally, allocator private data,
+ *             return NULL on failure or a pointer to allocator private,
+ *             per-buffer data on success; the returned private structure
+ *             will then be passed as buf_priv argument to other ops in this
+ *             structure
+ * @put:       inform the allocator that the buffer will no longer be used;
+ *             usually will result in the allocator freeing the buffer (if
+ *             no other users of this buffer are present); the buf_priv
+ *             argument is the allocator private per-buffer structure
+ *             previously returned from the alloc callback
+ * @get_userptr: acquire userspace memory for a hardware operation; used for
+ *              USERPTR memory types; vaddr is the address passed to the
+ *              videobuf layer when queuing a video buffer of USERPTR type;
+ *              should return an allocator private per-buffer structure
+ *              associated with the buffer on success, NULL on failure;
+ *              the returned private structure will then be passed as buf_priv
+ *              argument to other ops in this structure
+ * @put_userptr: inform the allocator that a USERPTR buffer will no longer
+ *              be used
+ * @vaddr:     return a kernel virtual address to a given memory buffer
+ *             associated with the passed private structure or NULL if no
+ *             such mapping exists
+ * @cookie:    return allocator specific cookie for a given memory buffer
+ *             associated with the passed private structure or NULL if not
+ *             available
+ * @num_users: return the current number of users of a memory buffer;
+ *             return 1 if the videobuf layer (or actually the driver using
+ *             it) is the only user
+ * @mmap:      setup a userspace mapping for a given memory buffer under
+ *             the provided virtual memory region
+ *
+ * Required ops for USERPTR types: get_userptr, put_userptr.
+ * Required ops for MMAP types: alloc, put, num_users, mmap.
+ * Required ops for read/write access types: alloc, put, num_users, vaddr
+ */
+struct vb2_mem_ops {
+       void            *(*alloc)(void *alloc_ctx, unsigned long size);
+       void            (*put)(void *buf_priv);
+
+       void            *(*get_userptr)(void *alloc_ctx, unsigned long vaddr,
+                                       unsigned long size, int write);
+       void            (*put_userptr)(void *buf_priv);
+
+       void            *(*vaddr)(void *buf_priv);
+       void            *(*cookie)(void *buf_priv);
+
+       unsigned int    (*num_users)(void *buf_priv);
+
+       int             (*mmap)(void *buf_priv, struct vm_area_struct *vma);
+};
+
+struct vb2_plane {
+       void                    *mem_priv;
+       int                     mapped:1;
+};
+
+/**
+ * enum vb2_io_modes - queue access methods
+ * @VB2_MMAP:          driver supports MMAP with streaming API
+ * @VB2_USERPTR:       driver supports USERPTR with streaming API
+ * @VB2_READ:          driver supports read() style access
+ * @VB2_WRITE:         driver supports write() style access
+ */
+enum vb2_io_modes {
+       VB2_MMAP        = (1 << 0),
+       VB2_USERPTR     = (1 << 1),
+       VB2_READ        = (1 << 2),
+       VB2_WRITE       = (1 << 3),
+};
+
+/**
+ * enum vb2_fileio_flags - flags for selecting a mode of the file io emulator,
+ * by default the 'streaming' style is used by the file io emulator
+ * @VB2_FILEIO_READ_ONCE:      report EOF after reading the first buffer
+ * @VB2_FILEIO_WRITE_IMMEDIATELY:      queue buffer after each write() call
+ */
+enum vb2_fileio_flags {
+       VB2_FILEIO_READ_ONCE            = (1 << 0),
+       VB2_FILEIO_WRITE_IMMEDIATELY    = (1 << 1),
+};
+
+/**
+ * enum vb2_buffer_state - current video buffer state
+ * @VB2_BUF_STATE_DEQUEUED:    buffer under userspace control
+ * @VB2_BUF_STATE_QUEUED:      buffer queued in videobuf, but not in driver
+ * @VB2_BUF_STATE_ACTIVE:      buffer queued in driver and possibly used
+ *                             in a hardware operation
+ * @VB2_BUF_STATE_DONE:                buffer returned from driver to videobuf, but
+ *                             not yet dequeued to userspace
+ * @VB2_BUF_STATE_ERROR:       same as above, but the operation on the buffer
+ *                             has ended with an error, which will be reported
+ *                             to the userspace when it is dequeued
+ */
+enum vb2_buffer_state {
+       VB2_BUF_STATE_DEQUEUED,
+       VB2_BUF_STATE_QUEUED,
+       VB2_BUF_STATE_ACTIVE,
+       VB2_BUF_STATE_DONE,
+       VB2_BUF_STATE_ERROR,
+};
+
+struct vb2_queue;
+
+/**
+ * struct vb2_buffer - represents a video buffer
+ * @v4l2_buf:          struct v4l2_buffer associated with this buffer; can
+ *                     be read by the driver and relevant entries can be
+ *                     changed by the driver in case of CAPTURE types
+ *                     (such as timestamp)
+ * @v4l2_planes:       struct v4l2_planes associated with this buffer; can
+ *                     be read by the driver and relevant entries can be
+ *                     changed by the driver in case of CAPTURE types
+ *                     (such as bytesused); NOTE that even for single-planar
+ *                     types, the v4l2_planes[0] struct should be used
+ *                     instead of v4l2_buf for filling bytesused - drivers
+ *                     should use the vb2_set_plane_payload() function for that
+ * @vb2_queue:         the queue to which this driver belongs
+ * @num_planes:                number of planes in the buffer
+ *                     on an internal driver queue
+ * @state:             current buffer state; do not change
+ * @queued_entry:      entry on the queued buffers list, which holds all
+ *                     buffers queued from userspace
+ * @done_entry:                entry on the list that stores all buffers ready to
+ *                     be dequeued to userspace
+ * @planes:            private per-plane information; do not change
+ * @num_planes_mapped: number of mapped planes; do not change
+ */
+struct vb2_buffer {
+       struct v4l2_buffer      v4l2_buf;
+       struct v4l2_plane       v4l2_planes[VIDEO_MAX_PLANES];
+
+       struct vb2_queue        *vb2_queue;
+
+       unsigned int            num_planes;
+
+/* Private: internal use only */
+       enum vb2_buffer_state   state;
+
+       struct list_head        queued_entry;
+       struct list_head        done_entry;
+
+       struct vb2_plane        planes[VIDEO_MAX_PLANES];
+       unsigned int            num_planes_mapped;
+};
+
+/**
+ * struct vb2_ops - driver-specific callbacks
+ *
+ * @queue_setup:       called from a VIDIOC_REQBUFS handler, before
+ *                     memory allocation; driver should return the required
+ *                     number of buffers in num_buffers, the required number
+ *                     of planes per buffer in num_planes; the size of each
+ *                     plane should be set in the sizes[] array and optional
+ *                     per-plane allocator specific context in alloc_ctxs[]
+ *                     array
+ * @wait_prepare:      release any locks taken while calling vb2 functions;
+ *                     it is called before an ioctl needs to wait for a new
+ *                     buffer to arrive; required to avoid a deadlock in
+ *                     blocking access type
+ * @wait_finish:       reacquire all locks released in the previous callback;
+ *                     required to continue operation after sleeping while
+ *                     waiting for a new buffer to arrive
+ * @buf_init:          called once after allocating a buffer (in MMAP case)
+ *                     or after acquiring a new USERPTR buffer; drivers may
+ *                     perform additional buffer-related initialization;
+ *                     initialization failure (return != 0) will prevent
+ *                     queue setup from completing successfully; optional
+ * @buf_prepare:       called every time the buffer is queued from userspace;
+ *                     drivers may perform any initialization required before
+ *                     each hardware operation in this callback;
+ *                     if an error is returned, the buffer will not be queued
+ *                     in driver; optional
+ * @buf_finish:                called before every dequeue of the buffer back to
+ *                     userspace; drivers may perform any operations required
+ *                     before userspace accesses the buffer; optional
+ * @buf_cleanup:       called once before the buffer is freed; drivers may
+ *                     perform any additional cleanup; optional
+ * @start_streaming:   called once before entering 'streaming' state; enables
+ *                     driver to receive buffers over buf_queue() callback
+ * @stop_streaming:    called when 'streaming' state must be disabled; driver
+ *                     should stop any DMA transactions or wait until they
+ *                     finish and give back all buffers it got from buf_queue()
+ *                     callback; may use vb2_wait_for_all_buffers() function
+ * @buf_queue:         passes buffer vb to the driver; driver may start
+ *                     hardware operation on this buffer; driver should give
+ *                     the buffer back by calling vb2_buffer_done() function
+ */
+struct vb2_ops {
+       int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers,
+                          unsigned int *num_planes, unsigned long sizes[],
+                          void *alloc_ctxs[]);
+
+       void (*wait_prepare)(struct vb2_queue *q);
+       void (*wait_finish)(struct vb2_queue *q);
+
+       int (*buf_init)(struct vb2_buffer *vb);
+       int (*buf_prepare)(struct vb2_buffer *vb);
+       int (*buf_finish)(struct vb2_buffer *vb);
+       void (*buf_cleanup)(struct vb2_buffer *vb);
+
+       int (*start_streaming)(struct vb2_queue *q);
+       int (*stop_streaming)(struct vb2_queue *q);
+
+       void (*buf_queue)(struct vb2_buffer *vb);
+};
+
+/**
+ * struct vb2_queue - a videobuf queue
+ *
+ * @type:      queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h
+ * @io_modes:  supported io methods (see vb2_io_modes enum)
+ * @io_flags:  additional io flags (see vb2_fileio_flags enum)
+ * @ops:       driver-specific callbacks
+ * @mem_ops:   memory allocator specific callbacks
+ * @drv_priv:  driver private data
+ * @buf_struct_size: size of the driver-specific buffer structure;
+ *             "0" indicates the driver doesn't want to use a custom buffer
+ *             structure type, so sizeof(struct vb2_buffer) will is used
+ *
+ * @memory:    current memory type used
+ * @bufs:      videobuf buffer structures
+ * @num_buffers: number of allocated/used buffers
+ * @queued_list: list of buffers currently queued from userspace
+ * @queued_count: number of buffers owned by the driver
+ * @done_list: list of buffers ready to be dequeued to userspace
+ * @done_lock: lock to protect done_list list
+ * @done_wq:   waitqueue for processes waiting for buffers ready to be dequeued
+ * @alloc_ctx: memory type/allocator-specific contexts for each plane
+ * @streaming: current streaming state
+ * @fileio:    file io emulator internal data, used only if emulator is active
+ */
+struct vb2_queue {
+       enum v4l2_buf_type              type;
+       unsigned int                    io_modes;
+       unsigned int                    io_flags;
+
+       const struct vb2_ops            *ops;
+       const struct vb2_mem_ops        *mem_ops;
+       void                            *drv_priv;
+       unsigned int                    buf_struct_size;
+
+/* private: internal use only */
+       enum v4l2_memory                memory;
+       struct vb2_buffer               *bufs[VIDEO_MAX_FRAME];
+       unsigned int                    num_buffers;
+
+       struct list_head                queued_list;
+
+       atomic_t                        queued_count;
+       struct list_head                done_list;
+       spinlock_t                      done_lock;
+       wait_queue_head_t               done_wq;
+
+       void                            *alloc_ctx[VIDEO_MAX_PLANES];
+
+       unsigned int                    streaming:1;
+
+       struct vb2_fileio_data          *fileio;
+};
+
+void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no);
+void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no);
+
+void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
+int vb2_wait_for_all_buffers(struct vb2_queue *q);
+
+int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req);
+
+int vb2_queue_init(struct vb2_queue *q);
+
+void vb2_queue_release(struct vb2_queue *q);
+
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
+
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type);
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
+
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblock);
+size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count,
+               loff_t *ppos, int nonblock);
+
+/**
+ * vb2_is_streaming() - return streaming status of the queue
+ * @q:         videobuf queue
+ */
+static inline bool vb2_is_streaming(struct vb2_queue *q)
+{
+       return q->streaming;
+}
+
+/**
+ * vb2_is_busy() - return busy status of the queue
+ * @q:         videobuf queue
+ *
+ * This function checks if queue has any buffers allocated.
+ */
+static inline bool vb2_is_busy(struct vb2_queue *q)
+{
+       return (q->num_buffers > 0);
+}
+
+/**
+ * vb2_get_drv_priv() - return driver private data associated with the queue
+ * @q:         videobuf queue
+ */
+static inline void *vb2_get_drv_priv(struct vb2_queue *q)
+{
+       return q->drv_priv;
+}
+
+/**
+ * vb2_set_plane_payload() - set bytesused for the plane plane_no
+ * @vb:                buffer for which plane payload should be set
+ * @plane_no:  plane number for which payload should be set
+ * @size:      payload in bytes
+ */
+static inline void vb2_set_plane_payload(struct vb2_buffer *vb,
+                                unsigned int plane_no, unsigned long size)
+{
+       if (plane_no < vb->num_planes)
+               vb->v4l2_planes[plane_no].bytesused = size;
+}
+
+/**
+ * vb2_get_plane_payload() - get bytesused for the plane plane_no
+ * @vb:                buffer for which plane payload should be set
+ * @plane_no:  plane number for which payload should be set
+ * @size:      payload in bytes
+ */
+static inline unsigned long vb2_get_plane_payload(struct vb2_buffer *vb,
+                                unsigned int plane_no)
+{
+       if (plane_no < vb->num_planes)
+               return vb->v4l2_planes[plane_no].bytesused;
+       return 0;
+}
+
+/**
+ * vb2_plane_size() - return plane size in bytes
+ * @vb:                buffer for which plane size should be returned
+ * @plane_no:  plane number for which size should be returned
+ */
+static inline unsigned long
+vb2_plane_size(struct vb2_buffer *vb, unsigned int plane_no)
+{
+       if (plane_no < vb->num_planes)
+               return vb->v4l2_planes[plane_no].length;
+       return 0;
+}
+
+#endif /* _MEDIA_VIDEOBUF2_CORE_H */
diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h
new file mode 100644 (file)
index 0000000..7e6c68b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * videobuf2-dma-coherent.h - DMA coherent memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_DMA_COHERENT_H
+#define _MEDIA_VIDEOBUF2_DMA_COHERENT_H
+
+#include <media/videobuf2-core.h>
+#include <linux/dma-mapping.h>
+
+static inline dma_addr_t
+vb2_dma_contig_plane_paddr(struct vb2_buffer *vb, unsigned int plane_no)
+{
+       dma_addr_t *paddr = vb2_plane_cookie(vb, plane_no);
+
+       return *paddr;
+}
+
+void *vb2_dma_contig_init_ctx(struct device *dev);
+void vb2_dma_contig_cleanup_ctx(void *alloc_ctx);
+
+extern const struct vb2_mem_ops vb2_dma_contig_memops;
+
+#endif
diff --git a/include/media/videobuf2-dma-sg.h b/include/media/videobuf2-dma-sg.h
new file mode 100644 (file)
index 0000000..0038526
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * videobuf2-dma-sg.h - DMA scatter/gather memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_DMA_SG_H
+#define _MEDIA_VIDEOBUF2_DMA_SG_H
+
+#include <media/videobuf2-core.h>
+
+struct vb2_dma_sg_desc {
+       unsigned long           size;
+       unsigned int            num_pages;
+       struct scatterlist      *sglist;
+};
+
+static inline struct vb2_dma_sg_desc *vb2_dma_sg_plane_desc(
+               struct vb2_buffer *vb, unsigned int plane_no)
+{
+       return (struct vb2_dma_sg_desc *)vb2_plane_cookie(vb, plane_no);
+}
+
+extern const struct vb2_mem_ops vb2_dma_sg_memops;
+
+#endif
diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h
new file mode 100644 (file)
index 0000000..84e1f6c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * videobuf2-memops.h - generic memory handling routines for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.com>
+ *        Marek Szyprowski <m.szyprowski@samsung.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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_MEMOPS_H
+#define _MEDIA_VIDEOBUF2_MEMOPS_H
+
+#include <media/videobuf2-core.h>
+
+/**
+ * vb2_vmarea_handler - common vma refcount tracking handler
+ * @refcount:  pointer to refcount entry in the buffer
+ * @put:       callback to function that decreases buffer refcount
+ * @arg:       argument for @put callback
+ */
+struct vb2_vmarea_handler {
+       atomic_t                *refcount;
+       void                    (*put)(void *arg);
+       void                    *arg;
+};
+
+extern const struct vm_operations_struct vb2_common_vm_ops;
+
+int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
+                          struct vm_area_struct **res_vma, dma_addr_t *res_pa);
+
+int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+                               unsigned long size,
+                               const struct vm_operations_struct *vm_ops,
+                               void *priv);
+
+struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
+void vb2_put_vma(struct vm_area_struct *vma);
+
+
+#endif
diff --git a/include/media/videobuf2-vmalloc.h b/include/media/videobuf2-vmalloc.h
new file mode 100644 (file)
index 0000000..93a76b4
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * videobuf2-vmalloc.h - vmalloc memory allocator for videobuf2
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * Author: Pawel Osciak <pawel@osciak.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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_VMALLOC_H
+#define _MEDIA_VIDEOBUF2_VMALLOC_H
+
+#include <media/videobuf2-core.h>
+
+extern const struct vb2_mem_ops vb2_vmalloc_memops;
+
+#endif
index 60739c5a23ae3e30e943b55dc45cd53289720db4..d0e801a9935cd09a4205691e1c710a0504d26bd9 100644 (file)
 #define WM8775_AIN3 4
 #define WM8775_AIN4 8
 
+
+struct wm8775_platform_data {
+       /*
+        * FIXME: Instead, we should parametrize the params
+        * that need different settings between ivtv, pvrusb2, and Nova-S
+        */
+       bool is_nova_s;
+};
+
 #endif
diff --git a/include/staging/altera.h b/include/staging/altera.h
new file mode 100644 (file)
index 0000000..94c0c61
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * altera.h
+ *
+ * altera FPGA driver
+ *
+ * Copyright (C) Altera Corporation 1998-2001
+ * Copyright (C) 2010 NetUP Inc.
+ * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ALTERA_H_
+#define _ALTERA_H_
+
+struct altera_config {
+       void *dev;
+       u8 *action;
+       int (*jtag_io) (void *dev, int tms, int tdi, int tdo);
+};
+
+#if defined(CONFIG_ALTERA_STAPL) || \
+               (defined(CONFIG_ALTERA_STAPL_MODULE) && defined(MODULE))
+
+extern int altera_init(struct altera_config *config, const struct firmware *fw);
+#else
+
+static inline int altera_init(struct altera_config *config,
+                                               const struct firmware *fw)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return 0;
+}
+#endif /* CONFIG_ALTERA_STAPL */
+
+#endif /* _ALTERA_H_ */
index e5e345fb2a5c37db45de06bcdf02f3796aec64c4..e09592d2f916adfdf041272e3b7a672379f7eea1 100644 (file)
@@ -21,8 +21,7 @@ TRACE_EVENT(ext4_free_inode,
        TP_ARGS(inode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        umode_t, mode                   )
                __field(        uid_t,  uid                     )
@@ -31,8 +30,7 @@ TRACE_EVENT(ext4_free_inode,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->mode   = inode->i_mode;
                __entry->uid    = inode->i_uid;
@@ -41,9 +39,9 @@ TRACE_EVENT(ext4_free_inode,
        ),
 
        TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->mode,
-                 __entry->uid, __entry->gid,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->mode, __entry->uid, __entry->gid,
                  (unsigned long long) __entry->blocks)
 );
 
@@ -53,21 +51,19 @@ TRACE_EVENT(ext4_request_inode,
        TP_ARGS(dir, mode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  dir                     )
                __field(        umode_t, mode                   )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(dir->i_sb->s_dev);
-               __entry->dev_minor = MINOR(dir->i_sb->s_dev);
+               __entry->dev    = dir->i_sb->s_dev;
                __entry->dir    = dir->i_ino;
                __entry->mode   = mode;
        ),
 
        TP_printk("dev %d,%d dir %lu mode 0%o",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
@@ -77,23 +73,21 @@ TRACE_EVENT(ext4_allocate_inode,
        TP_ARGS(inode, dir, mode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        ino_t,  dir                     )
                __field(        umode_t, mode                   )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->dir    = dir->i_ino;
                __entry->mode   = mode;
        ),
 
        TP_printk("dev %d,%d ino %lu dir %lu mode 0%o",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  (unsigned long) __entry->dir, __entry->mode)
 );
@@ -104,21 +98,19 @@ TRACE_EVENT(ext4_evict_inode,
        TP_ARGS(inode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        int,    nlink                   )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->nlink  = inode->i_nlink;
        ),
 
        TP_printk("dev %d,%d ino %lu nlink %d",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->nlink)
 );
 
@@ -128,21 +120,19 @@ TRACE_EVENT(ext4_drop_inode,
        TP_ARGS(inode, drop),
 
        TP_STRUCT__entry(
-               __field(        int,    dev_major               )
-               __field(        int,    dev_minor               )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        int,    drop                    )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->drop   = drop;
        ),
 
        TP_printk("dev %d,%d ino %lu drop %d",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->drop)
 );
 
@@ -152,21 +142,19 @@ TRACE_EVENT(ext4_mark_inode_dirty,
        TP_ARGS(inode, IP),
 
        TP_STRUCT__entry(
-               __field(        int,    dev_major               )
-               __field(        int,    dev_minor               )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(unsigned long,  ip                      )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->ip     = IP;
        ),
 
        TP_printk("dev %d,%d ino %lu caller %pF",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, (void *)__entry->ip)
 );
 
@@ -176,21 +164,19 @@ TRACE_EVENT(ext4_begin_ordered_truncate,
        TP_ARGS(inode, new_size),
 
        TP_STRUCT__entry(
-               __field(        int,    dev_major               )
-               __field(        int,    dev_minor               )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        loff_t, new_size                )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->dev            = inode->i_sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->new_size       = new_size;
        ),
 
        TP_printk("dev %d,%d ino %lu new_size %lld",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  (long long) __entry->new_size)
 );
@@ -203,8 +189,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
        TP_ARGS(inode, pos, len, flags),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        loff_t, pos                     )
                __field(        unsigned int, len               )
@@ -212,8 +197,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->pos    = pos;
                __entry->len    = len;
@@ -221,7 +205,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin,
        ),
 
        TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->pos, __entry->len, __entry->flags)
 );
@@ -249,8 +233,7 @@ DECLARE_EVENT_CLASS(ext4__write_end,
        TP_ARGS(inode, pos, len, copied),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        loff_t, pos                     )
                __field(        unsigned int, len               )
@@ -258,8 +241,7 @@ DECLARE_EVENT_CLASS(ext4__write_end,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->pos    = pos;
                __entry->len    = len;
@@ -267,9 +249,9 @@ DECLARE_EVENT_CLASS(ext4__write_end,
        ),
 
        TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->pos,
-                 __entry->len, __entry->copied)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->pos, __entry->len, __entry->copied)
 );
 
 DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end,
@@ -310,22 +292,20 @@ TRACE_EVENT(ext4_writepage,
        TP_ARGS(inode, page),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        pgoff_t, index                  )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->index  = page->index;
        ),
 
        TP_printk("dev %d,%d ino %lu page_index %lu",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->index)
 );
 
@@ -335,43 +315,39 @@ TRACE_EVENT(ext4_da_writepages,
        TP_ARGS(inode, wbc),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        long,   nr_to_write             )
                __field(        long,   pages_skipped           )
                __field(        loff_t, range_start             )
                __field(        loff_t, range_end               )
+               __field(        int,    sync_mode               )
                __field(        char,   for_kupdate             )
-               __field(        char,   for_reclaim             )
                __field(        char,   range_cyclic            )
                __field(       pgoff_t, writeback_index         )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->dev            = inode->i_sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->nr_to_write    = wbc->nr_to_write;
                __entry->pages_skipped  = wbc->pages_skipped;
                __entry->range_start    = wbc->range_start;
                __entry->range_end      = wbc->range_end;
+               __entry->sync_mode      = wbc->sync_mode;
                __entry->for_kupdate    = wbc->for_kupdate;
-               __entry->for_reclaim    = wbc->for_reclaim;
                __entry->range_cyclic   = wbc->range_cyclic;
                __entry->writeback_index = inode->i_mapping->writeback_index;
        ),
 
        TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld "
-                 "range_start %llu range_end %llu "
-                 "for_kupdate %d for_reclaim %d "
-                 "range_cyclic %d writeback_index %lu",
-                 __entry->dev_major, __entry->dev_minor,
+                 "range_start %llu range_end %llu sync_mode %d"
+                 "for_kupdate %d range_cyclic %d writeback_index %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->nr_to_write,
                  __entry->pages_skipped, __entry->range_start,
-                 __entry->range_end,
-                 __entry->for_kupdate, __entry->for_reclaim,
-                 __entry->range_cyclic,
+                 __entry->range_end, __entry->sync_mode,
+                 __entry->for_kupdate, __entry->range_cyclic,
                  (unsigned long) __entry->writeback_index)
 );
 
@@ -381,8 +357,7 @@ TRACE_EVENT(ext4_da_write_pages,
        TP_ARGS(inode, mpd),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u64,  b_blocknr               )
                __field(        __u32,  b_size                  )
@@ -390,11 +365,11 @@ TRACE_EVENT(ext4_da_write_pages,
                __field(        unsigned long,  first_page      )
                __field(        int,    io_done                 )
                __field(        int,    pages_written           )
+               __field(        int,    sync_mode               )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->dev            = inode->i_sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->b_blocknr      = mpd->b_blocknr;
                __entry->b_size         = mpd->b_size;
@@ -402,14 +377,18 @@ TRACE_EVENT(ext4_da_write_pages,
                __entry->first_page     = mpd->first_page;
                __entry->io_done        = mpd->io_done;
                __entry->pages_written  = mpd->pages_written;
+               __entry->sync_mode      = mpd->wbc->sync_mode;
        ),
 
-       TP_printk("dev %d,%d ino %lu b_blocknr %llu b_size %u b_state 0x%04x first_page %lu io_done %d pages_written %d",
-                 __entry->dev_major, __entry->dev_minor,
+       TP_printk("dev %d,%d ino %lu b_blocknr %llu b_size %u b_state 0x%04x "
+                 "first_page %lu io_done %d pages_written %d sync_mode %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->b_blocknr, __entry->b_size,
                  __entry->b_state, __entry->first_page,
-                 __entry->io_done, __entry->pages_written)
+                 __entry->io_done, __entry->pages_written,
+                 __entry->sync_mode
+                  )
 );
 
 TRACE_EVENT(ext4_da_writepages_result,
@@ -419,35 +398,100 @@ TRACE_EVENT(ext4_da_writepages_result,
        TP_ARGS(inode, wbc, ret, pages_written),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        int,    ret                     )
                __field(        int,    pages_written           )
                __field(        long,   pages_skipped           )
+               __field(        int,    sync_mode               )
                __field(        char,   more_io                 )       
                __field(       pgoff_t, writeback_index         )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->dev            = inode->i_sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->ret            = ret;
                __entry->pages_written  = pages_written;
                __entry->pages_skipped  = wbc->pages_skipped;
+               __entry->sync_mode      = wbc->sync_mode;
                __entry->more_io        = wbc->more_io;
                __entry->writeback_index = inode->i_mapping->writeback_index;
        ),
 
-       TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld more_io %d writeback_index %lu",
-                 __entry->dev_major, __entry->dev_minor,
+       TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld "
+                 " more_io %d sync_mode %d writeback_index %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino, __entry->ret,
                  __entry->pages_written, __entry->pages_skipped,
-                 __entry->more_io,
+                 __entry->more_io, __entry->sync_mode,
                  (unsigned long) __entry->writeback_index)
 );
 
+DECLARE_EVENT_CLASS(ext4__page_op,
+       TP_PROTO(struct page *page),
+
+       TP_ARGS(page),
+
+       TP_STRUCT__entry(
+               __field(        pgoff_t, index                  )
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+
+       ),
+
+       TP_fast_assign(
+               __entry->index  = page->index;
+               __entry->ino    = page->mapping->host->i_ino;
+               __entry->dev    = page->mapping->host->i_sb->s_dev;
+       ),
+
+       TP_printk("dev %d,%d ino %lu page_index %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->index)
+);
+
+DEFINE_EVENT(ext4__page_op, ext4_readpage,
+
+       TP_PROTO(struct page *page),
+
+       TP_ARGS(page)
+);
+
+DEFINE_EVENT(ext4__page_op, ext4_releasepage,
+
+       TP_PROTO(struct page *page),
+
+       TP_ARGS(page)
+);
+
+TRACE_EVENT(ext4_invalidatepage,
+       TP_PROTO(struct page *page, unsigned long offset),
+
+       TP_ARGS(page, offset),
+
+       TP_STRUCT__entry(
+               __field(        pgoff_t, index                  )
+               __field(        unsigned long, offset           )
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+
+       ),
+
+       TP_fast_assign(
+               __entry->index  = page->index;
+               __entry->offset = offset;
+               __entry->ino    = page->mapping->host->i_ino;
+               __entry->dev    = page->mapping->host->i_sb->s_dev;
+       ),
+
+       TP_printk("dev %d,%d ino %lu page_index %lu offset %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->index, __entry->offset)
+);
+
 TRACE_EVENT(ext4_discard_blocks,
        TP_PROTO(struct super_block *sb, unsigned long long blk,
                        unsigned long long count),
@@ -455,22 +499,20 @@ TRACE_EVENT(ext4_discard_blocks,
        TP_ARGS(sb, blk, count),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        __u64,  blk                     )
                __field(        __u64,  count                   )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(sb->s_dev);
-               __entry->dev_minor = MINOR(sb->s_dev);
+               __entry->dev    = sb->s_dev;
                __entry->blk    = blk;
                __entry->count  = count;
        ),
 
        TP_printk("dev %d,%d blk %llu count %llu",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->blk, __entry->count)
 );
 
@@ -481,8 +523,7 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa,
        TP_ARGS(ac, pa),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u64,  pa_pstart               )
                __field(        __u32,  pa_len                  )
@@ -491,8 +532,7 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(ac->ac_sb->s_dev);
-               __entry->dev_minor      = MINOR(ac->ac_sb->s_dev);
+               __entry->dev            = ac->ac_sb->s_dev;
                __entry->ino            = ac->ac_inode->i_ino;
                __entry->pa_pstart      = pa->pa_pstart;
                __entry->pa_len         = pa->pa_len;
@@ -500,9 +540,9 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa,
        ),
 
        TP_printk("dev %d,%d ino %lu pstart %llu len %u lstart %llu",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->pa_pstart,
-                 __entry->pa_len, __entry->pa_lstart)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart)
 );
 
 DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa,
@@ -530,8 +570,7 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
        TP_ARGS(sb, inode, pa, block, count),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u64,  block                   )
                __field(        __u32,  count                   )
@@ -539,16 +578,16 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(sb->s_dev);
-               __entry->dev_minor      = MINOR(sb->s_dev);
+               __entry->dev            = sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->block          = block;
                __entry->count          = count;
        ),
 
        TP_printk("dev %d,%d ino %lu block %llu count %u",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->block, __entry->count)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->block, __entry->count)
 );
 
 TRACE_EVENT(ext4_mb_release_group_pa,
@@ -558,22 +597,20 @@ TRACE_EVENT(ext4_mb_release_group_pa,
        TP_ARGS(sb, pa),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        __u64,  pa_pstart               )
                __field(        __u32,  pa_len                  )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(sb->s_dev);
-               __entry->dev_minor      = MINOR(sb->s_dev);
+               __entry->dev            = sb->s_dev;
                __entry->pa_pstart      = pa->pa_pstart;
                __entry->pa_len         = pa->pa_len;
        ),
 
        TP_printk("dev %d,%d pstart %llu len %u",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->pa_pstart, __entry->pa_len)
 );
 
@@ -583,20 +620,18 @@ TRACE_EVENT(ext4_discard_preallocations,
        TP_ARGS(inode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
        ),
 
        TP_printk("dev %d,%d ino %lu",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino)
 );
 
@@ -606,20 +641,19 @@ TRACE_EVENT(ext4_mb_discard_preallocations,
        TP_ARGS(sb, needed),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        int,    needed                  )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(sb->s_dev);
-               __entry->dev_minor = MINOR(sb->s_dev);
+               __entry->dev    = sb->s_dev;
                __entry->needed = needed;
        ),
 
        TP_printk("dev %d,%d needed %d",
-                 __entry->dev_major, __entry->dev_minor, __entry->needed)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->needed)
 );
 
 TRACE_EVENT(ext4_request_blocks,
@@ -628,8 +662,7 @@ TRACE_EVENT(ext4_request_blocks,
        TP_ARGS(ar),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        unsigned int, flags             )
                __field(        unsigned int, len               )
@@ -642,8 +675,7 @@ TRACE_EVENT(ext4_request_blocks,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev);
+               __entry->dev    = ar->inode->i_sb->s_dev;
                __entry->ino    = ar->inode->i_ino;
                __entry->flags  = ar->flags;
                __entry->len    = ar->len;
@@ -655,8 +687,9 @@ TRACE_EVENT(ext4_request_blocks,
                __entry->pright = ar->pright;
        ),
 
-       TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
-                 __entry->dev_major, __entry->dev_minor,
+       TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu "
+                 "lleft %llu lright %llu pleft %llu pright %llu ",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->flags, __entry->len,
                  (unsigned long long) __entry->logical,
@@ -673,8 +706,7 @@ TRACE_EVENT(ext4_allocate_blocks,
        TP_ARGS(ar, block),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u64,  block                   )
                __field(        unsigned int, flags             )
@@ -688,8 +720,7 @@ TRACE_EVENT(ext4_allocate_blocks,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev);
+               __entry->dev    = ar->inode->i_sb->s_dev;
                __entry->ino    = ar->inode->i_ino;
                __entry->block  = block;
                __entry->flags  = ar->flags;
@@ -702,10 +733,11 @@ TRACE_EVENT(ext4_allocate_blocks,
                __entry->pright = ar->pright;
        ),
 
-       TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->flags,
-                 __entry->len, __entry->block,
+       TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu "
+                 "goal %llu lleft %llu lright %llu pleft %llu pright %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->flags, __entry->len, __entry->block,
                  (unsigned long long) __entry->logical,
                  (unsigned long long) __entry->goal,
                  (unsigned long long) __entry->lleft,
@@ -721,8 +753,7 @@ TRACE_EVENT(ext4_free_blocks,
        TP_ARGS(inode, block, count, flags),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(      umode_t, mode                     )
                __field(        __u64,  block                   )
@@ -731,8 +762,7 @@ TRACE_EVENT(ext4_free_blocks,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->dev            = inode->i_sb->s_dev;
                __entry->ino            = inode->i_ino;
                __entry->mode           = inode->i_mode;
                __entry->block          = block;
@@ -741,20 +771,19 @@ TRACE_EVENT(ext4_free_blocks,
        ),
 
        TP_printk("dev %d,%d ino %lu mode 0%o block %llu count %lu flags %d",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->mode, __entry->block, __entry->count,
                  __entry->flags)
 );
 
-TRACE_EVENT(ext4_sync_file,
+TRACE_EVENT(ext4_sync_file_enter,
        TP_PROTO(struct file *file, int datasync),
 
        TP_ARGS(file, datasync),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        ino_t,  parent                  )
                __field(        int,    datasync                )
@@ -763,39 +792,60 @@ TRACE_EVENT(ext4_sync_file,
        TP_fast_assign(
                struct dentry *dentry = file->f_path.dentry;
 
-               __entry->dev_major      = MAJOR(dentry->d_inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(dentry->d_inode->i_sb->s_dev);
+               __entry->dev            = dentry->d_inode->i_sb->s_dev;
                __entry->ino            = dentry->d_inode->i_ino;
                __entry->datasync       = datasync;
                __entry->parent         = dentry->d_parent->d_inode->i_ino;
        ),
 
        TP_printk("dev %d,%d ino %ld parent %ld datasync %d ",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  (unsigned long) __entry->parent, __entry->datasync)
 );
 
+TRACE_EVENT(ext4_sync_file_exit,
+       TP_PROTO(struct inode *inode, int ret),
+
+       TP_ARGS(inode, ret),
+
+       TP_STRUCT__entry(
+               __field(        int,    ret                     )
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+       ),
+
+       TP_fast_assign(
+               __entry->ret            = ret;
+               __entry->ino            = inode->i_ino;
+               __entry->dev            = inode->i_sb->s_dev;
+       ),
+
+       TP_printk("dev %d,%d ino %ld ret %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->ret)
+);
+
 TRACE_EVENT(ext4_sync_fs,
        TP_PROTO(struct super_block *sb, int wait),
 
        TP_ARGS(sb, wait),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        int,    wait                    )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(sb->s_dev);
-               __entry->dev_minor = MINOR(sb->s_dev);
+               __entry->dev    = sb->s_dev;
                __entry->wait   = wait;
        ),
 
-       TP_printk("dev %d,%d wait %d", __entry->dev_major,
-                 __entry->dev_minor, __entry->wait)
+       TP_printk("dev %d,%d wait %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->wait)
 );
 
 TRACE_EVENT(ext4_alloc_da_blocks,
@@ -804,23 +854,21 @@ TRACE_EVENT(ext4_alloc_da_blocks,
        TP_ARGS(inode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field( unsigned int,  data_blocks     )
                __field( unsigned int,  meta_blocks     )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->data_blocks = EXT4_I(inode)->i_reserved_data_blocks;
                __entry->meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks;
        ),
 
        TP_printk("dev %d,%d ino %lu data_blocks %u meta_blocks %u",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->data_blocks, __entry->meta_blocks)
 );
@@ -831,8 +879,7 @@ TRACE_EVENT(ext4_mballoc_alloc,
        TP_ARGS(ac),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u16,  found                   )
                __field(        __u16,  groups                  )
@@ -855,8 +902,7 @@ TRACE_EVENT(ext4_mballoc_alloc,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(ac->ac_inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(ac->ac_inode->i_sb->s_dev);
+               __entry->dev            = ac->ac_inode->i_sb->s_dev;
                __entry->ino            = ac->ac_inode->i_ino;
                __entry->found          = ac->ac_found;
                __entry->flags          = ac->ac_flags;
@@ -881,7 +927,7 @@ TRACE_EVENT(ext4_mballoc_alloc,
        TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u "
                  "result %u/%d/%u@%u blks %u grps %u cr %u flags 0x%04x "
                  "tail %u broken %u",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->orig_group, __entry->orig_start,
                  __entry->orig_len, __entry->orig_logical,
@@ -900,8 +946,7 @@ TRACE_EVENT(ext4_mballoc_prealloc,
        TP_ARGS(ac),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        __u32,  orig_logical            )
                __field(          int,  orig_start              )
@@ -914,8 +959,7 @@ TRACE_EVENT(ext4_mballoc_prealloc,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(ac->ac_inode->i_sb->s_dev);
-               __entry->dev_minor      = MINOR(ac->ac_inode->i_sb->s_dev);
+               __entry->dev            = ac->ac_inode->i_sb->s_dev;
                __entry->ino            = ac->ac_inode->i_ino;
                __entry->orig_logical   = ac->ac_o_ex.fe_logical;
                __entry->orig_start     = ac->ac_o_ex.fe_start;
@@ -928,7 +972,7 @@ TRACE_EVENT(ext4_mballoc_prealloc,
        ),
 
        TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->orig_group, __entry->orig_start,
                  __entry->orig_len, __entry->orig_logical,
@@ -946,8 +990,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc,
        TP_ARGS(sb, inode, group, start, len),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(          int,  result_start            )
                __field(        __u32,  result_group            )
@@ -955,8 +998,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(sb->s_dev);
-               __entry->dev_minor      = MINOR(sb->s_dev);
+               __entry->dev            = sb->s_dev;
                __entry->ino            = inode ? inode->i_ino : 0;
                __entry->result_start   = start;
                __entry->result_group   = group;
@@ -964,7 +1006,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc,
        ),
 
        TP_printk("dev %d,%d inode %lu extent %u/%d/%u ",
-                 __entry->dev_major, __entry->dev_minor,
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->result_group, __entry->result_start,
                  __entry->result_len)
@@ -998,8 +1040,7 @@ TRACE_EVENT(ext4_forget,
        TP_ARGS(inode, is_metadata, block),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        umode_t, mode                   )
                __field(        int,    is_metadata             )
@@ -1007,8 +1048,7 @@ TRACE_EVENT(ext4_forget,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->mode   = inode->i_mode;
                __entry->is_metadata = is_metadata;
@@ -1016,9 +1056,9 @@ TRACE_EVENT(ext4_forget,
        ),
 
        TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %llu",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->mode,
-                 __entry->is_metadata, __entry->block)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->mode, __entry->is_metadata, __entry->block)
 );
 
 TRACE_EVENT(ext4_da_update_reserve_space,
@@ -1027,8 +1067,7 @@ TRACE_EVENT(ext4_da_update_reserve_space,
        TP_ARGS(inode, used_blocks),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        umode_t, mode                   )
                __field(        __u64,  i_blocks                )
@@ -1039,8 +1078,7 @@ TRACE_EVENT(ext4_da_update_reserve_space,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->mode   = inode->i_mode;
                __entry->i_blocks = inode->i_blocks;
@@ -1050,10 +1088,12 @@ TRACE_EVENT(ext4_da_update_reserve_space,
                __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks;
        ),
 
-       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino, __entry->mode,
-                 (unsigned long long) __entry->i_blocks,
+       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d "
+                 "reserved_data_blocks %d reserved_meta_blocks %d "
+                 "allocated_meta_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->mode,  (unsigned long long) __entry->i_blocks,
                  __entry->used_blocks, __entry->reserved_data_blocks,
                  __entry->reserved_meta_blocks, __entry->allocated_meta_blocks)
 );
@@ -1064,8 +1104,7 @@ TRACE_EVENT(ext4_da_reserve_space,
        TP_ARGS(inode, md_needed),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        umode_t, mode                   )
                __field(        __u64,  i_blocks                )
@@ -1075,8 +1114,7 @@ TRACE_EVENT(ext4_da_reserve_space,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->mode   = inode->i_mode;
                __entry->i_blocks = inode->i_blocks;
@@ -1085,8 +1123,9 @@ TRACE_EVENT(ext4_da_reserve_space,
                __entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks;
        ),
 
-       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu md_needed %d reserved_data_blocks %d reserved_meta_blocks %d",
-                 __entry->dev_major, __entry->dev_minor,
+       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu md_needed %d "
+                 "reserved_data_blocks %d reserved_meta_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->mode, (unsigned long long) __entry->i_blocks,
                  __entry->md_needed, __entry->reserved_data_blocks,
@@ -1099,8 +1138,7 @@ TRACE_EVENT(ext4_da_release_space,
        TP_ARGS(inode, freed_blocks),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
                __field(        umode_t, mode                   )
                __field(        __u64,  i_blocks                )
@@ -1111,8 +1149,7 @@ TRACE_EVENT(ext4_da_release_space,
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
                __entry->mode   = inode->i_mode;
                __entry->i_blocks = inode->i_blocks;
@@ -1122,8 +1159,10 @@ TRACE_EVENT(ext4_da_release_space,
                __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks;
        ),
 
-       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d",
-                 __entry->dev_major, __entry->dev_minor,
+       TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d "
+                 "reserved_data_blocks %d reserved_meta_blocks %d "
+                 "allocated_meta_blocks %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  (unsigned long) __entry->ino,
                  __entry->mode, (unsigned long long) __entry->i_blocks,
                  __entry->freed_blocks, __entry->reserved_data_blocks,
@@ -1136,20 +1175,19 @@ DECLARE_EVENT_CLASS(ext4__bitmap_load,
        TP_ARGS(sb, group),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        __u32,  group                   )
 
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(sb->s_dev);
-               __entry->dev_minor = MINOR(sb->s_dev);
+               __entry->dev    = sb->s_dev;
                __entry->group  = group;
        ),
 
        TP_printk("dev %d,%d group %u",
-                 __entry->dev_major, __entry->dev_minor, __entry->group)
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->group)
 );
 
 DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load,
@@ -1166,6 +1204,349 @@ DEFINE_EVENT(ext4__bitmap_load, ext4_mb_buddy_bitmap_load,
        TP_ARGS(sb, group)
 );
 
+DEFINE_EVENT(ext4__bitmap_load, ext4_read_block_bitmap_load,
+
+       TP_PROTO(struct super_block *sb, unsigned long group),
+
+       TP_ARGS(sb, group)
+);
+
+DEFINE_EVENT(ext4__bitmap_load, ext4_load_inode_bitmap,
+
+       TP_PROTO(struct super_block *sb, unsigned long group),
+
+       TP_ARGS(sb, group)
+);
+
+TRACE_EVENT(ext4_direct_IO_enter,
+       TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw),
+
+       TP_ARGS(inode, offset, len, rw),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+               __field(        loff_t, pos                     )
+               __field(        unsigned long,  len             )
+               __field(        int,    rw                      )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->pos    = offset;
+               __entry->len    = len;
+               __entry->rw     = rw;
+       ),
+
+       TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned long long) __entry->pos, __entry->len, __entry->rw)
+);
+
+TRACE_EVENT(ext4_direct_IO_exit,
+       TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw, int ret),
+
+       TP_ARGS(inode, offset, len, rw, ret),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+               __field(        loff_t, pos                     )
+               __field(        unsigned long,  len             )
+               __field(        int,    rw                      )
+               __field(        int,    ret                     )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->pos    = offset;
+               __entry->len    = len;
+               __entry->rw     = rw;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d ret %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned long long) __entry->pos, __entry->len,
+                 __entry->rw, __entry->ret)
+);
+
+TRACE_EVENT(ext4_fallocate_enter,
+       TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode),
+
+       TP_ARGS(inode, offset, len, mode),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+               __field(        loff_t, pos                     )
+               __field(        loff_t, len                     )
+               __field(        int,    mode                    )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->pos    = offset;
+               __entry->len    = len;
+               __entry->mode   = mode;
+       ),
+
+       TP_printk("dev %d,%d ino %ld pos %llu len %llu mode %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned long long) __entry->pos,
+                 (unsigned long long) __entry->len, __entry->mode)
+);
+
+TRACE_EVENT(ext4_fallocate_exit,
+       TP_PROTO(struct inode *inode, loff_t offset, unsigned int max_blocks, int ret),
+
+       TP_ARGS(inode, offset, max_blocks, ret),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+               __field(        loff_t, pos                     )
+               __field(        unsigned,       blocks          )
+               __field(        int,    ret                     )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->pos    = offset;
+               __entry->blocks = max_blocks;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev %d,%d ino %ld pos %llu blocks %d ret %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned long long) __entry->pos, __entry->blocks,
+                 __entry->ret)
+);
+
+TRACE_EVENT(ext4_unlink_enter,
+       TP_PROTO(struct inode *parent, struct dentry *dentry),
+
+       TP_ARGS(parent, dentry),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  parent                  )
+               __field(        ino_t,  ino                     )
+               __field(        loff_t, size                    )
+               __field(        dev_t,  dev                     )
+       ),
+
+       TP_fast_assign(
+               __entry->parent         = parent->i_ino;
+               __entry->ino            = dentry->d_inode->i_ino;
+               __entry->size           = dentry->d_inode->i_size;
+               __entry->dev            = dentry->d_inode->i_sb->s_dev;
+       ),
+
+       TP_printk("dev %d,%d ino %ld size %lld parent %ld",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino, __entry->size,
+                 (unsigned long) __entry->parent)
+);
+
+TRACE_EVENT(ext4_unlink_exit,
+       TP_PROTO(struct dentry *dentry, int ret),
+
+       TP_ARGS(dentry, ret),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino                     )
+               __field(        dev_t,  dev                     )
+               __field(        int,    ret                     )
+       ),
+
+       TP_fast_assign(
+               __entry->ino            = dentry->d_inode->i_ino;
+               __entry->dev            = dentry->d_inode->i_sb->s_dev;
+               __entry->ret            = ret;
+       ),
+
+       TP_printk("dev %d,%d ino %ld ret %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 __entry->ret)
+);
+
+DECLARE_EVENT_CLASS(ext4__truncate,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,          ino             )
+               __field(        dev_t,          dev             )
+               __field(        blkcnt_t,       blocks          )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->blocks = inode->i_blocks;
+       ),
+
+       TP_printk("dev %d,%d ino %lu blocks %lu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino, (unsigned long) __entry->blocks)
+);
+
+DEFINE_EVENT(ext4__truncate, ext4_truncate_enter,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+DEFINE_EVENT(ext4__truncate, ext4_truncate_exit,
+
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode)
+);
+
+DECLARE_EVENT_CLASS(ext4__map_blocks_enter,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                unsigned len, unsigned flags),
+
+       TP_ARGS(inode, lblk, len, flags),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,          ino             )
+               __field(        dev_t,          dev             )
+               __field(        ext4_lblk_t,    lblk            )
+               __field(        unsigned,       len             )
+               __field(        unsigned,       flags           )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->lblk   = lblk;
+               __entry->len    = len;
+               __entry->flags  = flags;
+       ),
+
+       TP_printk("dev %d,%d ino %lu lblk %u len %u flags %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned) __entry->lblk, __entry->len, __entry->flags)
+);
+
+DEFINE_EVENT(ext4__map_blocks_enter, ext4_ext_map_blocks_enter,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                unsigned len, unsigned flags),
+
+       TP_ARGS(inode, lblk, len, flags)
+);
+
+DEFINE_EVENT(ext4__map_blocks_enter, ext4_ind_map_blocks_enter,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                unsigned len, unsigned flags),
+
+       TP_ARGS(inode, lblk, len, flags)
+);
+
+DECLARE_EVENT_CLASS(ext4__map_blocks_exit,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                ext4_fsblk_t pblk, unsigned len, int ret),
+
+       TP_ARGS(inode, lblk, pblk, len, ret),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,          ino             )
+               __field(        dev_t,          dev             )
+               __field(        ext4_lblk_t,    lblk            )
+               __field(        ext4_fsblk_t,   pblk            )
+               __field(        unsigned,       len             )
+               __field(        int,            ret             )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->lblk   = lblk;
+               __entry->pblk   = pblk;
+               __entry->len    = len;
+               __entry->ret    = ret;
+       ),
+
+       TP_printk("dev %d,%d ino %lu lblk %u pblk %llu len %u ret %d",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned) __entry->lblk, (unsigned long long) __entry->pblk,
+                 __entry->len, __entry->ret)
+);
+
+DEFINE_EVENT(ext4__map_blocks_exit, ext4_ext_map_blocks_exit,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                ext4_fsblk_t pblk, unsigned len, int ret),
+
+       TP_ARGS(inode, lblk, pblk, len, ret)
+);
+
+DEFINE_EVENT(ext4__map_blocks_exit, ext4_ind_map_blocks_exit,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk,
+                ext4_fsblk_t pblk, unsigned len, int ret),
+
+       TP_ARGS(inode, lblk, pblk, len, ret)
+);
+
+TRACE_EVENT(ext4_ext_load_extent,
+       TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk),
+
+       TP_ARGS(inode, lblk, pblk),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,          ino             )
+               __field(        dev_t,          dev             )
+               __field(        ext4_lblk_t,    lblk            )
+               __field(        ext4_fsblk_t,   pblk            )
+       ),
+
+       TP_fast_assign(
+               __entry->ino    = inode->i_ino;
+               __entry->dev    = inode->i_sb->s_dev;
+               __entry->lblk   = lblk;
+               __entry->pblk   = pblk;
+       ),
+
+       TP_printk("dev %d,%d ino %lu lblk %u pblk %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino,
+                 (unsigned) __entry->lblk, (unsigned long long) __entry->pblk)
+);
+
+TRACE_EVENT(ext4_load_inode,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        ino_t,  ino             )
+               __field(        dev_t,  dev             )
+       ),
+
+       TP_fast_assign(
+               __entry->ino            = inode->i_ino;
+               __entry->dev            = inode->i_sb->s_dev;
+       ),
+
+       TP_printk("dev %d,%d ino %ld",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 (unsigned long) __entry->ino)
+);
+
 #endif /* _TRACE_EXT4_H */
 
 /* This part must be outside protection */
index 7447ea9305b54eeece947d812a1c87cd3a58ba1c..bf16545cc97756d263305f17712f522b979bbf32 100644 (file)
@@ -17,19 +17,17 @@ TRACE_EVENT(jbd2_checkpoint,
        TP_ARGS(journal, result),
 
        TP_STRUCT__entry(
-               __field(        int,    dev_major               )
-               __field(        int,    dev_minor               )
+               __field(        dev_t,  dev                     )
                __field(        int,    result                  )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(journal->j_fs_dev->bd_dev);
-               __entry->dev_minor      = MINOR(journal->j_fs_dev->bd_dev);
+               __entry->dev            = journal->j_fs_dev->bd_dev;
                __entry->result         = result;
        ),
 
-       TP_printk("dev %d,%d result %d",
-                 __entry->dev_major, __entry->dev_minor, __entry->result)
+       TP_printk("dev %s result %d",
+                 jbd2_dev_to_name(__entry->dev), __entry->result)
 );
 
 DECLARE_EVENT_CLASS(jbd2_commit,
@@ -39,22 +37,20 @@ DECLARE_EVENT_CLASS(jbd2_commit,
        TP_ARGS(journal, commit_transaction),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        char,   sync_commit               )
                __field(        int,    transaction               )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(journal->j_fs_dev->bd_dev);
-               __entry->dev_minor      = MINOR(journal->j_fs_dev->bd_dev);
+               __entry->dev            = journal->j_fs_dev->bd_dev;
                __entry->sync_commit = commit_transaction->t_synchronous_commit;
                __entry->transaction    = commit_transaction->t_tid;
        ),
 
-       TP_printk("dev %d,%d transaction %d sync %d",
-                 __entry->dev_major, __entry->dev_minor,
-                 __entry->transaction, __entry->sync_commit)
+       TP_printk("dev %s transaction %d sync %d",
+                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
+                 __entry->sync_commit)
 );
 
 DEFINE_EVENT(jbd2_commit, jbd2_start_commit,
@@ -91,24 +87,22 @@ TRACE_EVENT(jbd2_end_commit,
        TP_ARGS(journal, commit_transaction),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        char,   sync_commit               )
                __field(        int,    transaction               )
                __field(        int,    head                      )
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(journal->j_fs_dev->bd_dev);
-               __entry->dev_minor      = MINOR(journal->j_fs_dev->bd_dev);
+               __entry->dev            = journal->j_fs_dev->bd_dev;
                __entry->sync_commit = commit_transaction->t_synchronous_commit;
                __entry->transaction    = commit_transaction->t_tid;
                __entry->head           = journal->j_tail_sequence;
        ),
 
-       TP_printk("dev %d,%d transaction %d sync %d head %d",
-                 __entry->dev_major, __entry->dev_minor,
-                 __entry->transaction, __entry->sync_commit, __entry->head)
+       TP_printk("dev %s transaction %d sync %d head %d",
+                 jbd2_dev_to_name(__entry->dev), __entry->transaction,
+                 __entry->sync_commit, __entry->head)
 );
 
 TRACE_EVENT(jbd2_submit_inode_data,
@@ -117,20 +111,17 @@ TRACE_EVENT(jbd2_submit_inode_data,
        TP_ARGS(inode),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        ino_t,  ino                     )
        ),
 
        TP_fast_assign(
-               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
-               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->dev    = inode->i_sb->s_dev;
                __entry->ino    = inode->i_ino;
        ),
 
-       TP_printk("dev %d,%d ino %lu",
-                 __entry->dev_major, __entry->dev_minor,
-                 (unsigned long) __entry->ino)
+       TP_printk("dev %s ino %lu",
+                 jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino)
 );
 
 TRACE_EVENT(jbd2_run_stats,
@@ -140,8 +131,7 @@ TRACE_EVENT(jbd2_run_stats,
        TP_ARGS(dev, tid, stats),
 
        TP_STRUCT__entry(
-               __field(                  int,  dev_major       )
-               __field(                  int,  dev_minor       )
+               __field(                dev_t,  dev             )
                __field(        unsigned long,  tid             )
                __field(        unsigned long,  wait            )
                __field(        unsigned long,  running         )
@@ -154,8 +144,7 @@ TRACE_EVENT(jbd2_run_stats,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(dev);
-               __entry->dev_minor      = MINOR(dev);
+               __entry->dev            = dev;
                __entry->tid            = tid;
                __entry->wait           = stats->rs_wait;
                __entry->running        = stats->rs_running;
@@ -167,9 +156,9 @@ TRACE_EVENT(jbd2_run_stats,
                __entry->blocks_logged  = stats->rs_blocks_logged;
        ),
 
-       TP_printk("dev %d,%d tid %lu wait %u running %u locked %u flushing %u "
+       TP_printk("dev %s tid %lu wait %u running %u locked %u flushing %u "
                  "logging %u handle_count %u blocks %u blocks_logged %u",
-                 __entry->dev_major, __entry->dev_minor, __entry->tid,
+                 jbd2_dev_to_name(__entry->dev), __entry->tid,
                  jiffies_to_msecs(__entry->wait),
                  jiffies_to_msecs(__entry->running),
                  jiffies_to_msecs(__entry->locked),
@@ -186,8 +175,7 @@ TRACE_EVENT(jbd2_checkpoint_stats,
        TP_ARGS(dev, tid, stats),
 
        TP_STRUCT__entry(
-               __field(                  int,  dev_major       )
-               __field(                  int,  dev_minor       )
+               __field(                dev_t,  dev             )
                __field(        unsigned long,  tid             )
                __field(        unsigned long,  chp_time        )
                __field(                __u32,  forced_to_close )
@@ -196,8 +184,7 @@ TRACE_EVENT(jbd2_checkpoint_stats,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(dev);
-               __entry->dev_minor      = MINOR(dev);
+               __entry->dev            = dev;
                __entry->tid            = tid;
                __entry->chp_time       = stats->cs_chp_time;
                __entry->forced_to_close= stats->cs_forced_to_close;
@@ -205,9 +192,9 @@ TRACE_EVENT(jbd2_checkpoint_stats,
                __entry->dropped        = stats->cs_dropped;
        ),
 
-       TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u "
+       TP_printk("dev %s tid %lu chp_time %u forced_to_close %u "
                  "written %u dropped %u",
-                 __entry->dev_major, __entry->dev_minor, __entry->tid,
+                 jbd2_dev_to_name(__entry->dev), __entry->tid,
                  jiffies_to_msecs(__entry->chp_time),
                  __entry->forced_to_close, __entry->written, __entry->dropped)
 );
@@ -220,8 +207,7 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
        TP_ARGS(journal, first_tid, block_nr, freed),
 
        TP_STRUCT__entry(
-               __field(        int,   dev_major                )
-               __field(        int,   dev_minor                )
+               __field(        dev_t,  dev                     )
                __field(        tid_t,  tail_sequence           )
                __field(        tid_t,  first_tid               )
                __field(unsigned long,  block_nr                )
@@ -229,18 +215,16 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
        ),
 
        TP_fast_assign(
-               __entry->dev_major      = MAJOR(journal->j_fs_dev->bd_dev);
-               __entry->dev_minor      = MINOR(journal->j_fs_dev->bd_dev);
+               __entry->dev            = journal->j_fs_dev->bd_dev;
                __entry->tail_sequence  = journal->j_tail_sequence;
                __entry->first_tid      = first_tid;
                __entry->block_nr       = block_nr;
                __entry->freed          = freed;
        ),
 
-       TP_printk("dev %d,%d from %u to %u offset %lu freed %lu",
-                 __entry->dev_major, __entry->dev_minor,
-                 __entry->tail_sequence, __entry->first_tid,
-                 __entry->block_nr, __entry->freed)
+       TP_printk("dev %s from %u to %u offset %lu freed %lu",
+                 jbd2_dev_to_name(__entry->dev), __entry->tail_sequence,
+                 __entry->first_tid, __entry->block_nr, __entry->freed)
 );
 
 #endif /* _TRACE_JBD2_H */
index 0c864db1a4662a5e1c89f902830e5cf4a7f91efc..28447f1594fa3fcf5a3a337cf34b4671528a424f 100644 (file)
@@ -52,6 +52,7 @@ struct atmel_lcdfb_info {
        u8                      bl_power;
 #endif
        bool                    lcdcon_is_backlight;
+       bool                    lcdcon_pol_negative;
        u8                      saved_lcdcon;
 
        u8                      default_bpp;
index 24fe022c55f976004c7acfb1c22ed6b7f0ce0954..76ac9194cbc437911e2394f8e94f4530eff716c8 100644 (file)
@@ -110,8 +110,8 @@ static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
 
 /*
  * This is the number of bits of precision for the loops_per_jiffy.  Each
- * bit takes on average 1.5/HZ seconds.  This (like the original) is a little
- * better than 1%
+ * time we refine our estimate after the first takes 1.5/HZ seconds, so try
+ * to start with a good estimate.
  * For the boot cpu we can skip the delay calibration and assign it a value
  * calculated based on the timer frequency.
  * For the rest of the CPUs we cannot assume that the timer frequency is same as
@@ -119,10 +119,72 @@ static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
  */
 #define LPS_PREC 8
 
+static unsigned long __cpuinit calibrate_delay_converge(void)
+{
+       /* First stage - slowly accelerate to find initial bounds */
+       unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;
+       int trials = 0, band = 0, trial_in_band = 0;
+
+       lpj = (1<<12);
+
+       /* wait for "start of" clock tick */
+       ticks = jiffies;
+       while (ticks == jiffies)
+               ; /* nothing */
+       /* Go .. */
+       ticks = jiffies;
+       do {
+               if (++trial_in_band == (1<<band)) {
+                       ++band;
+                       trial_in_band = 0;
+               }
+               __delay(lpj * band);
+               trials += band;
+       } while (ticks == jiffies);
+       /*
+        * We overshot, so retreat to a clear underestimate. Then estimate
+        * the largest likely undershoot. This defines our chop bounds.
+        */
+       trials -= band;
+       loopadd_base = lpj * band;
+       lpj_base = lpj * trials;
+
+recalibrate:
+       lpj = lpj_base;
+       loopadd = loopadd_base;
+
+       /*
+        * Do a binary approximation to get lpj set to
+        * equal one clock (up to LPS_PREC bits)
+        */
+       chop_limit = lpj >> LPS_PREC;
+       while (loopadd > chop_limit) {
+               lpj += loopadd;
+               ticks = jiffies;
+               while (ticks == jiffies)
+                       ; /* nothing */
+               ticks = jiffies;
+               __delay(lpj);
+               if (jiffies != ticks)   /* longer than 1 tick */
+                       lpj -= loopadd;
+               loopadd >>= 1;
+       }
+       /*
+        * If we incremented every single time possible, presume we've
+        * massively underestimated initially, and retry with a higher
+        * start, and larger range. (Only seen on x86_64, due to SMIs)
+        */
+       if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
+               lpj_base = lpj;
+               loopadd_base <<= 2;
+               goto recalibrate;
+       }
+
+       return lpj;
+}
+
 void __cpuinit calibrate_delay(void)
 {
-       unsigned long ticks, loopbit;
-       int lps_precision = LPS_PREC;
        static bool printed;
 
        if (preset_lpj) {
@@ -139,39 +201,9 @@ void __cpuinit calibrate_delay(void)
                        pr_info("Calibrating delay using timer "
                                "specific routine.. ");
        } else {
-               loops_per_jiffy = (1<<12);
-
                if (!printed)
                        pr_info("Calibrating delay loop... ");
-               while ((loops_per_jiffy <<= 1) != 0) {
-                       /* wait for "start of" clock tick */
-                       ticks = jiffies;
-                       while (ticks == jiffies)
-                               /* nothing */;
-                       /* Go .. */
-                       ticks = jiffies;
-                       __delay(loops_per_jiffy);
-                       ticks = jiffies - ticks;
-                       if (ticks)
-                               break;
-               }
-
-               /*
-                * Do a binary approximation to get loops_per_jiffy set to
-                * equal one clock (up to lps_precision bits)
-                */
-               loops_per_jiffy >>= 1;
-               loopbit = loops_per_jiffy;
-               while (lps_precision-- && (loopbit >>= 1)) {
-                       loops_per_jiffy |= loopbit;
-                       ticks = jiffies;
-                       while (ticks == jiffies)
-                               /* nothing */;
-                       ticks = jiffies;
-                       __delay(loops_per_jiffy);
-                       if (jiffies != ticks)   /* longer than 1 tick */
-                               loops_per_jiffy &= ~loopbit;
-               }
+               loops_per_jiffy = calibrate_delay_converge();
        }
        if (!printed)
                pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
index 2b54bef33b55c65f8fda4ebf3129db3453c8f53d..3e011215779563e3c739fcbc70021d601c506bc9 100644 (file)
@@ -293,7 +293,8 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 
        sys_chdir((const char __user __force *)"/root");
        ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
-       printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
+       printk(KERN_INFO
+              "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
               current->fs->pwd.mnt->mnt_sb->s_type->name,
               current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?
               " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
index 6e1ee6987c78dbca4cb3f01aaa031e4b3a42708f..fe9acb0ae4808bd663187d802960d788f73276c1 100644 (file)
@@ -64,7 +64,7 @@ identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor)
 
        buf = kmalloc(size, GFP_KERNEL);
        if (!buf)
-               return -1;
+               return -ENOMEM;
 
        minixsb = (struct minix_super_block *) buf;
        ext2sb = (struct ext2_super_block *) buf;
index 33c37c379e96458521a0111a968849139edcf586..4a9479ef4540df99586d5e0b3854c2b3c46d91c4 100644 (file)
@@ -129,63 +129,6 @@ static char *static_command_line;
 static char *execute_command;
 static char *ramdisk_execute_command;
 
-#ifdef CONFIG_SMP
-/* Setup configured maximum number of CPUs to activate */
-unsigned int setup_max_cpus = NR_CPUS;
-EXPORT_SYMBOL(setup_max_cpus);
-
-
-/*
- * Setup routine for controlling SMP activation
- *
- * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
- * activation entirely (the MPS table probe still happens, though).
- *
- * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
- * greater than 0, limits the maximum number of CPUs activated in
- * SMP mode to <NUM>.
- */
-
-void __weak arch_disable_smp_support(void) { }
-
-static int __init nosmp(char *str)
-{
-       setup_max_cpus = 0;
-       arch_disable_smp_support();
-
-       return 0;
-}
-
-early_param("nosmp", nosmp);
-
-/* this is hard limit */
-static int __init nrcpus(char *str)
-{
-       int nr_cpus;
-
-       get_option(&str, &nr_cpus);
-       if (nr_cpus > 0 && nr_cpus < nr_cpu_ids)
-               nr_cpu_ids = nr_cpus;
-
-       return 0;
-}
-
-early_param("nr_cpus", nrcpus);
-
-static int __init maxcpus(char *str)
-{
-       get_option(&str, &setup_max_cpus);
-       if (setup_max_cpus == 0)
-               arch_disable_smp_support();
-
-       return 0;
-}
-
-early_param("maxcpus", maxcpus);
-#else
-static const unsigned int setup_max_cpus = NR_CPUS;
-#endif
-
 /*
  * If set, this is an indication to the drivers that reset the underlying
  * device before going ahead with the initialization otherwise driver might
@@ -362,7 +305,7 @@ static int __init rdinit_setup(char *str)
 __setup("rdinit=", rdinit_setup);
 
 #ifndef CONFIG_SMP
-
+static const unsigned int setup_max_cpus = NR_CPUS;
 #ifdef CONFIG_X86_LOCAL_APIC
 static void __init smp_init(void)
 {
@@ -374,37 +317,6 @@ static void __init smp_init(void)
 
 static inline void setup_nr_cpu_ids(void) { }
 static inline void smp_prepare_cpus(unsigned int maxcpus) { }
-
-#else
-
-/* Setup number of possible processor ids */
-int nr_cpu_ids __read_mostly = NR_CPUS;
-EXPORT_SYMBOL(nr_cpu_ids);
-
-/* An arch may set nr_cpu_ids earlier if needed, so this would be redundant */
-static void __init setup_nr_cpu_ids(void)
-{
-       nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
-}
-
-/* Called by boot processor to activate the rest. */
-static void __init smp_init(void)
-{
-       unsigned int cpu;
-
-       /* FIXME: This should be done in userspace --RR */
-       for_each_present_cpu(cpu) {
-               if (num_online_cpus() >= setup_max_cpus)
-                       break;
-               if (!cpu_online(cpu))
-                       cpu_up(cpu);
-       }
-
-       /* Any cleanup work */
-       printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus());
-       smp_cpus_done(setup_max_cpus);
-}
-
 #endif
 
 /*
@@ -875,15 +787,6 @@ static int __init kernel_init(void * unused)
         * init can run on any cpu.
         */
        set_cpus_allowed_ptr(current, cpu_all_mask);
-       /*
-        * Tell the world that we're going to be the grim
-        * reaper of innocent orphaned children.
-        *
-        * We don't want people to have to make incorrect
-        * assumptions about where in the task array this
-        * can be found.
-        */
-       init_pid_ns.child_reaper = current;
 
        cad_pid = task_pid(current);
 
index adff586401a50c2e6de2ee145ae6a047fd03c6ba..86fe0ccb997abdd2e97a920288fd2d3fbfd9736e 100644 (file)
@@ -33,6 +33,7 @@ struct uts_namespace init_uts_ns = {
                .machine        = UTS_MACHINE,
                .domainname     = UTS_DOMAINNAME,
        },
+       .user_ns = &init_user_ns,
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
 
index 747b65507a91c3d7a03022f17797e742a6ee53e0..0e732e92e22fa56a3f1c89af08ecf04a06a65cc8 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -421,7 +421,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
                        return -EFAULT;
        }
 
-       ipcp = ipcctl_pre_down(&msg_ids(ns), msqid, cmd,
+       ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
                               &msqid64.msg_perm, msqid64.msg_qbytes);
        if (IS_ERR(ipcp))
                return PTR_ERR(ipcp);
@@ -539,7 +539,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
                        success_return = 0;
                }
                err = -EACCES;
-               if (ipcperms(&msq->q_perm, S_IRUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IRUGO))
                        goto out_unlock;
 
                err = security_msg_queue_msgctl(msq, cmd);
@@ -664,7 +664,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                struct msg_sender s;
 
                err = -EACCES;
-               if (ipcperms(&msq->q_perm, S_IWUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IWUGO))
                        goto out_unlock_free;
 
                err = security_msg_queue_msgsnd(msq, msg, msgflg);
@@ -774,7 +774,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                struct list_head *tmp;
 
                msg = ERR_PTR(-EACCES);
-               if (ipcperms(&msq->q_perm, S_IRUGO))
+               if (ipcperms(ns, &msq->q_perm, S_IRUGO))
                        goto out_unlock;
 
                msg = ERR_PTR(-EAGAIN);
index f095ee26883333fcc69d7c32e907a8f1949e2f3f..8b5ce5d3f3ef3e4f468d5afc4175cd22518fc029 100644 (file)
@@ -32,6 +32,7 @@ struct ipc_namespace init_ipc_ns = {
        .mq_msg_max      = DFLT_MSGMAX,
        .mq_msgsize_max  = DFLT_MSGSIZEMAX,
 #endif
+       .user_ns = &init_user_ns,
 };
 
 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
index a1094ff0befa2775c5e9023c44c1520ff813ad04..8054c8e5faf1da309ef7b44d9ecebd4000883277 100644 (file)
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
+#include <linux/user_namespace.h>
 
 #include "util.h"
 
-static struct ipc_namespace *create_ipc_ns(void)
+static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
+                                          struct ipc_namespace *old_ns)
 {
        struct ipc_namespace *ns;
        int err;
@@ -43,14 +45,19 @@ static struct ipc_namespace *create_ipc_ns(void)
        ipcns_notify(IPCNS_CREATED);
        register_ipcns_notifier(ns);
 
+       ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+
        return ns;
 }
 
-struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
+struct ipc_namespace *copy_ipcs(unsigned long flags,
+                               struct task_struct *tsk)
 {
+       struct ipc_namespace *ns = tsk->nsproxy->ipc_ns;
+
        if (!(flags & CLONE_NEWIPC))
                return get_ipc_ns(ns);
-       return create_ipc_ns();
+       return create_ipc_ns(tsk, ns);
 }
 
 /*
@@ -97,7 +104,6 @@ static void free_ipc_ns(struct ipc_namespace *ns)
        sem_exit_ns(ns);
        msg_exit_ns(ns);
        shm_exit_ns(ns);
-       kfree(ns);
        atomic_dec(&nr_ipc_ns);
 
        /*
@@ -105,6 +111,8 @@ static void free_ipc_ns(struct ipc_namespace *ns)
         * order to have a correct value when recomputing msgmni.
         */
        ipcns_notify(IPCNS_REMOVED);
+       put_user_ns(ns->user_ns);
+       kfree(ns);
 }
 
 /*
index 0e0d49bbb867f239be5690968227c53e7c0226c0..ae040a0727c2101b0acf03c915669449aff37b90 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -817,7 +817,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                }
 
                err = -EACCES;
-               if (ipcperms (&sma->sem_perm, S_IRUGO))
+               if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
                        goto out_unlock;
 
                err = security_sem_semctl(sma, cmd);
@@ -862,7 +862,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
        nsems = sma->sem_nsems;
 
        err = -EACCES;
-       if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
+       if (ipcperms(ns, &sma->sem_perm,
+                       (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
                goto out_unlock;
 
        err = security_sem_semctl(sma, cmd);
@@ -1047,7 +1048,8 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
                        return -EFAULT;
        }
 
-       ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0);
+       ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
+                              &semid64.sem_perm, 0);
        if (IS_ERR(ipcp))
                return PTR_ERR(ipcp);
 
@@ -1386,7 +1388,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
                goto out_unlock_free;
 
        error = -EACCES;
-       if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
+       if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
                goto out_unlock_free;
 
        error = security_sem_semop(sma, sops, nsops, alter);
index 7d3bb22a93022e4911028bffd6710f1426e7b0e8..8644452f5c4cd687b9112b7fb19a7ebe34ef929c 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -623,7 +623,8 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
                        return -EFAULT;
        }
 
-       ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
+       ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
+                              &shmid64.shm_perm, 0);
        if (IS_ERR(ipcp))
                return PTR_ERR(ipcp);
 
@@ -737,7 +738,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                        result = 0;
                }
                err = -EACCES;
-               if (ipcperms (&shp->shm_perm, S_IRUGO))
+               if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
                        goto out_unlock;
                err = security_shm_shmctl(shp, cmd);
                if (err)
@@ -773,7 +774,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
 
                audit_ipc_obj(&(shp->shm_perm));
 
-               if (!capable(CAP_IPC_LOCK)) {
+               if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
                        uid_t euid = current_euid();
                        err = -EPERM;
                        if (euid != shp->shm_perm.uid &&
@@ -888,7 +889,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
        }
 
        err = -EACCES;
-       if (ipcperms(&shp->shm_perm, acc_mode))
+       if (ipcperms(ns, &shp->shm_perm, acc_mode))
                goto out_unlock;
 
        err = security_shm_shmat(shp, shmaddr, shmflg);
index 69a0cc13d9669847cce05fd67fc2203ffdeacb9e..8fd1b891ec0c71c7a7ad8052f46da47709d2f029 100644 (file)
@@ -329,12 +329,14 @@ retry:
  *
  *     It is called with ipc_ids.rw_mutex and ipcp->lock held.
  */
-static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
-                       struct ipc_params *params)
+static int ipc_check_perms(struct ipc_namespace *ns,
+                          struct kern_ipc_perm *ipcp,
+                          struct ipc_ops *ops,
+                          struct ipc_params *params)
 {
        int err;
 
-       if (ipcperms(ipcp, params->flg))
+       if (ipcperms(ns, ipcp, params->flg))
                err = -EACCES;
        else {
                err = ops->associate(ipcp, params->flg);
@@ -396,7 +398,7 @@ retry:
                                 * ipc_check_perms returns the IPC id on
                                 * success
                                 */
-                               err = ipc_check_perms(ipcp, ops, params);
+                               err = ipc_check_perms(ns, ipcp, ops, params);
                }
                ipc_unlock(ipcp);
        }
@@ -610,10 +612,12 @@ void ipc_rcu_putref(void *ptr)
  *
  *     Check user, group, other permissions for access
  *     to ipc resources. return 0 if allowed
+ *
+ *     @flag will most probably be 0 or S_...UGO from <linux/stat.h>
  */
  
-int ipcperms (struct kern_ipc_perm *ipcp, short flag)
-{      /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
+int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
+{
        uid_t euid = current_euid();
        int requested_mode, granted_mode;
 
@@ -627,7 +631,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag)
                granted_mode >>= 3;
        /* is there some bit set in requested_mode but not in granted_mode? */
        if ((requested_mode & ~granted_mode & 0007) && 
-           !capable(CAP_IPC_OWNER))
+           !ns_capable(ns->user_ns, CAP_IPC_OWNER))
                return -1;
 
        return security_ipc_permission(ipcp, flag);
@@ -765,6 +769,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 
 /**
  * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
+ * @ids:  the ipc namespace
  * @ids:  the table of ids where to look for the ipc
  * @id:   the id of the ipc to retrieve
  * @cmd:  the cmd to check
@@ -779,7 +784,8 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
  *  - returns the ipc with both ipc and rw_mutex locks held in case of success
  *    or an err-code without any lock held otherwise.
  */
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
+struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
+                                     struct ipc_ids *ids, int id, int cmd,
                                      struct ipc64_perm *perm, int extra_perm)
 {
        struct kern_ipc_perm *ipcp;
@@ -799,8 +805,8 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
                                         perm->gid, perm->mode);
 
        euid = current_euid();
-       if (euid == ipcp->cuid ||
-           euid == ipcp->uid  || capable(CAP_SYS_ADMIN))
+       if (euid == ipcp->cuid || euid == ipcp->uid  ||
+           ns_capable(ns->user_ns, CAP_SYS_ADMIN))
                return ipcp;
 
        err = -EPERM;
index 764b51a37a6ad352ad6d1f12a1016749a3bbc1a7..6f5c20bedaab21ff1dd0e05ad90ae0ecadeb82aa 100644 (file)
@@ -103,7 +103,7 @@ int ipc_get_maxid(struct ipc_ids *);
 void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
 
 /* must be called with ipcp locked */
-int ipcperms(struct kern_ipc_perm *ipcp, short flg);
+int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
 
 /* for rare, potentially huge allocations.
  * both function can sleep
@@ -126,7 +126,8 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
 void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
 void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
 void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
+struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
+                                     struct ipc_ids *ids, int id, int cmd,
                                      struct ipc64_perm *perm, int extra_perm);
 
 #ifndef __ARCH_WANT_IPC_PARSE_VERSION
index 353d3fe8ba339554655a0b61808a9d385dc55144..85cbfb31e73e97b2e2548cba6837a98c39cbaf2b 100644 (file)
@@ -107,6 +107,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index 98a51f26c13691b9f6f5955cdc83840f8932c2be..0c9b862292b26dc0494f771f96532fd8995c2b3b 100644 (file)
@@ -9,11 +9,13 @@
 #include <linux/page-flags.h>
 #include <linux/mmzone.h>
 #include <linux/kbuild.h>
+#include <linux/page_cgroup.h>
 
 void foo(void)
 {
        /* The enum constants to put into include/generated/bounds.h */
        DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS);
        DEFINE(MAX_NR_ZONES, __MAX_NR_ZONES);
+       DEFINE(NR_PCG_FLAGS, __NR_PCG_FLAGS);
        /* End of constants */
 }
index 9e9385f132c81759ca2fbe6891d45d25775ff07d..bf0c734d0c123f6b5733629f2f1bff4614197a3f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 
 /*
@@ -289,6 +290,60 @@ error:
        return ret;
 }
 
+/**
+ * has_capability - Does a task have a capability in init_user_ns
+ * @t: The task in question
+ * @cap: The capability to be tested for
+ *
+ * Return true if the specified task has the given superior capability
+ * currently in effect to the initial user namespace, false if not.
+ *
+ * Note that this does not set PF_SUPERPRIV on the task.
+ */
+bool has_capability(struct task_struct *t, int cap)
+{
+       int ret = security_real_capable(t, &init_user_ns, cap);
+
+       return (ret == 0);
+}
+
+/**
+ * has_capability - Does a task have a capability in a specific user ns
+ * @t: The task in question
+ * @ns: target user namespace
+ * @cap: The capability to be tested for
+ *
+ * Return true if the specified task has the given superior capability
+ * currently in effect to the specified user namespace, false if not.
+ *
+ * Note that this does not set PF_SUPERPRIV on the task.
+ */
+bool has_ns_capability(struct task_struct *t,
+                      struct user_namespace *ns, int cap)
+{
+       int ret = security_real_capable(t, ns, cap);
+
+       return (ret == 0);
+}
+
+/**
+ * has_capability_noaudit - Does a task have a capability (unaudited)
+ * @t: The task in question
+ * @cap: The capability to be tested for
+ *
+ * Return true if the specified task has the given superior capability
+ * currently in effect to init_user_ns, false if not.  Don't write an
+ * audit message for the check.
+ *
+ * Note that this does not set PF_SUPERPRIV on the task.
+ */
+bool has_capability_noaudit(struct task_struct *t, int cap)
+{
+       int ret = security_real_capable_noaudit(t, &init_user_ns, cap);
+
+       return (ret == 0);
+}
+
 /**
  * capable - Determine if the current task has a superior capability in effect
  * @cap: The capability to be tested for
@@ -299,17 +354,48 @@ error:
  * This sets PF_SUPERPRIV on the task if the capability is available on the
  * assumption that it's about to be used.
  */
-int capable(int cap)
+bool capable(int cap)
+{
+       return ns_capable(&init_user_ns, cap);
+}
+EXPORT_SYMBOL(capable);
+
+/**
+ * ns_capable - Determine if the current task has a superior capability in effect
+ * @ns:  The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable(struct user_namespace *ns, int cap)
 {
        if (unlikely(!cap_valid(cap))) {
                printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
                BUG();
        }
 
-       if (security_capable(current_cred(), cap) == 0) {
+       if (security_capable(ns, current_cred(), cap) == 0) {
                current->flags |= PF_SUPERPRIV;
-               return 1;
+               return true;
        }
-       return 0;
+       return false;
 }
-EXPORT_SYMBOL(capable);
+EXPORT_SYMBOL(ns_capable);
+
+/**
+ * task_ns_capable - Determine whether current task has a superior
+ * capability targeted at a specific task's user namespace.
+ * @t: The task whose user namespace is targeted.
+ * @cap: The capability in question.
+ *
+ *  Return true if it does, false otherwise.
+ */
+bool task_ns_capable(struct task_struct *t, int cap)
+{
+       return ns_capable(task_cred_xxx(t, user)->user_ns, cap);
+}
+EXPORT_SYMBOL(task_ns_capable);
index 95362d15128cb7b40ad2bddc35add5adb76c00cb..e31b220a743deda483fe4ec300254affd76f87e0 100644 (file)
@@ -1813,10 +1813,8 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
 
        /* Update the css_set linked lists if we're using them */
        write_lock(&css_set_lock);
-       if (!list_empty(&tsk->cg_list)) {
-               list_del(&tsk->cg_list);
-               list_add(&tsk->cg_list, &newcg->tasks);
-       }
+       if (!list_empty(&tsk->cg_list))
+               list_move(&tsk->cg_list, &newcg->tasks);
        write_unlock(&css_set_lock);
 
        for_each_subsys(root, ss) {
@@ -3655,12 +3653,12 @@ again:
        spin_lock(&release_list_lock);
        set_bit(CGRP_REMOVED, &cgrp->flags);
        if (!list_empty(&cgrp->release_list))
-               list_del(&cgrp->release_list);
+               list_del_init(&cgrp->release_list);
        spin_unlock(&release_list_lock);
 
        cgroup_lock_hierarchy(cgrp->root);
        /* delete this cgroup from parent->children */
-       list_del(&cgrp->sibling);
+       list_del_init(&cgrp->sibling);
        cgroup_unlock_hierarchy(cgrp->root);
 
        d = dget(cgrp->dentry);
@@ -3879,7 +3877,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
        subsys[ss->subsys_id] = NULL;
 
        /* remove subsystem from rootnode's list of subsystems */
-       list_del(&ss->sibling);
+       list_del_init(&ss->sibling);
 
        /*
         * disentangle the css from all css_sets attached to the dummytop. as
@@ -4241,7 +4239,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
        if (!list_empty(&tsk->cg_list)) {
                write_lock(&css_set_lock);
                if (!list_empty(&tsk->cg_list))
-                       list_del(&tsk->cg_list);
+                       list_del_init(&tsk->cg_list);
                write_unlock(&css_set_lock);
        }
 
index 156cc555614089345553a6e7710580c4f069be0e..c95fc4df0faad535e70165971388c09a40580b73 100644 (file)
@@ -160,7 +160,6 @@ static void cpu_notify_nofail(unsigned long val, void *v)
 {
        BUG_ON(cpu_notify(val, v));
 }
-
 EXPORT_SYMBOL(register_cpu_notifier);
 
 void __ref unregister_cpu_notifier(struct notifier_block *nb)
@@ -205,7 +204,6 @@ static int __ref take_cpu_down(void *_param)
                return err;
 
        cpu_notify(CPU_DYING | param->mod, param->hcpu);
-
        return 0;
 }
 
@@ -227,6 +225,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
                return -EINVAL;
 
        cpu_hotplug_begin();
+
        err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
        if (err) {
                nr_calls--;
@@ -304,7 +303,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
        if (ret) {
                nr_calls--;
-               printk("%s: attempt to bring up CPU %u failed\n",
+               printk(KERN_WARNING "%s: attempt to bring up CPU %u failed\n",
                                __func__, cpu);
                goto out_notify;
        }
@@ -450,14 +449,14 @@ void __ref enable_nonboot_cpus(void)
        if (cpumask_empty(frozen_cpus))
                goto out;
 
-       printk("Enabling non-boot CPUs ...\n");
+       printk(KERN_INFO "Enabling non-boot CPUs ...\n");
 
        arch_enable_nonboot_cpus_begin();
 
        for_each_cpu(cpu, frozen_cpus) {
                error = _cpu_up(cpu, 1);
                if (!error) {
-                       printk("CPU%d is up\n", cpu);
+                       printk(KERN_INFO "CPU%d is up\n", cpu);
                        continue;
                }
                printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
@@ -509,7 +508,7 @@ void __cpuinit notify_cpu_starting(unsigned int cpu)
  */
 
 /* cpu_bit_bitmap[0] is empty - so we can back into it */
-#define MASK_DECLARE_1(x)      [x+1][0] = 1UL << (x)
+#define MASK_DECLARE_1(x)      [x+1][0] = (1UL << (x))
 #define MASK_DECLARE_2(x)      MASK_DECLARE_1(x), MASK_DECLARE_1(x+1)
 #define MASK_DECLARE_4(x)      MASK_DECLARE_2(x), MASK_DECLARE_2(x+2)
 #define MASK_DECLARE_8(x)      MASK_DECLARE_4(x), MASK_DECLARE_4(x+4)
index e92e981890321a7cc73beb11a8b32edf19d6a17c..33eee16addb83bb6aaf411b03a09e3872671c42f 100644 (file)
@@ -1015,17 +1015,12 @@ static void cpuset_change_nodemask(struct task_struct *p,
        struct cpuset *cs;
        int migrate;
        const nodemask_t *oldmem = scan->data;
-       NODEMASK_ALLOC(nodemask_t, newmems, GFP_KERNEL);
-
-       if (!newmems)
-               return;
+       static nodemask_t newmems;      /* protected by cgroup_mutex */
 
        cs = cgroup_cs(scan->cg);
-       guarantee_online_mems(cs, newmems);
-
-       cpuset_change_task_nodemask(p, newmems);
+       guarantee_online_mems(cs, &newmems);
 
-       NODEMASK_FREE(newmems);
+       cpuset_change_task_nodemask(p, &newmems);
 
        mm = get_task_mm(p);
        if (!mm)
@@ -1438,44 +1433,35 @@ static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,
        struct mm_struct *mm;
        struct cpuset *cs = cgroup_cs(cont);
        struct cpuset *oldcs = cgroup_cs(oldcont);
-       NODEMASK_ALLOC(nodemask_t, from, GFP_KERNEL);
-       NODEMASK_ALLOC(nodemask_t, to, GFP_KERNEL);
-
-       if (from == NULL || to == NULL)
-               goto alloc_fail;
+       static nodemask_t to;           /* protected by cgroup_mutex */
 
        if (cs == &top_cpuset) {
                cpumask_copy(cpus_attach, cpu_possible_mask);
        } else {
                guarantee_online_cpus(cs, cpus_attach);
        }
-       guarantee_online_mems(cs, to);
+       guarantee_online_mems(cs, &to);
 
        /* do per-task migration stuff possibly for each in the threadgroup */
-       cpuset_attach_task(tsk, to, cs);
+       cpuset_attach_task(tsk, &to, cs);
        if (threadgroup) {
                struct task_struct *c;
                rcu_read_lock();
                list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       cpuset_attach_task(c, to, cs);
+                       cpuset_attach_task(c, &to, cs);
                }
                rcu_read_unlock();
        }
 
        /* change mm; only needs to be done once even if threadgroup */
-       *from = oldcs->mems_allowed;
-       *to = cs->mems_allowed;
+       to = cs->mems_allowed;
        mm = get_task_mm(tsk);
        if (mm) {
-               mpol_rebind_mm(mm, to);
+               mpol_rebind_mm(mm, &to);
                if (is_memory_migrate(cs))
-                       cpuset_migrate_mm(mm, from, to);
+                       cpuset_migrate_mm(mm, &oldcs->mems_allowed, &to);
                mmput(mm);
        }
-
-alloc_fail:
-       NODEMASK_FREE(from);
-       NODEMASK_FREE(to);
 }
 
 /* The various types of files and directories in a cpuset file system */
@@ -1610,34 +1596,26 @@ out:
  * across a page fault.
  */
 
-static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs)
+static size_t cpuset_sprintf_cpulist(char *page, struct cpuset *cs)
 {
-       int ret;
+       size_t count;
 
        mutex_lock(&callback_mutex);
-       ret = cpulist_scnprintf(page, PAGE_SIZE, cs->cpus_allowed);
+       count = cpulist_scnprintf(page, PAGE_SIZE, cs->cpus_allowed);
        mutex_unlock(&callback_mutex);
 
-       return ret;
+       return count;
 }
 
-static int cpuset_sprintf_memlist(char *page, struct cpuset *cs)
+static size_t cpuset_sprintf_memlist(char *page, struct cpuset *cs)
 {
-       NODEMASK_ALLOC(nodemask_t, mask, GFP_KERNEL);
-       int retval;
-
-       if (mask == NULL)
-               return -ENOMEM;
+       size_t count;
 
        mutex_lock(&callback_mutex);
-       *mask = cs->mems_allowed;
+       count = nodelist_scnprintf(page, PAGE_SIZE, cs->mems_allowed);
        mutex_unlock(&callback_mutex);
 
-       retval = nodelist_scnprintf(page, PAGE_SIZE, *mask);
-
-       NODEMASK_FREE(mask);
-
-       return retval;
+       return count;
 }
 
 static ssize_t cpuset_common_file_read(struct cgroup *cont,
@@ -1862,8 +1840,10 @@ static void cpuset_post_clone(struct cgroup_subsys *ss,
        cs = cgroup_cs(cgroup);
        parent_cs = cgroup_cs(parent);
 
+       mutex_lock(&callback_mutex);
        cs->mems_allowed = parent_cs->mems_allowed;
        cpumask_copy(cs->cpus_allowed, parent_cs->cpus_allowed);
+       mutex_unlock(&callback_mutex);
        return;
 }
 
@@ -2066,10 +2046,7 @@ static void scan_for_empty_cpusets(struct cpuset *root)
        struct cpuset *cp;      /* scans cpusets being updated */
        struct cpuset *child;   /* scans child cpusets of cp */
        struct cgroup *cont;
-       NODEMASK_ALLOC(nodemask_t, oldmems, GFP_KERNEL);
-
-       if (oldmems == NULL)
-               return;
+       static nodemask_t oldmems;      /* protected by cgroup_mutex */
 
        list_add_tail((struct list_head *)&root->stack_list, &queue);
 
@@ -2086,7 +2063,7 @@ static void scan_for_empty_cpusets(struct cpuset *root)
                    nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY]))
                        continue;
 
-               *oldmems = cp->mems_allowed;
+               oldmems = cp->mems_allowed;
 
                /* Remove offline cpus and mems from this cpuset. */
                mutex_lock(&callback_mutex);
@@ -2102,10 +2079,9 @@ static void scan_for_empty_cpusets(struct cpuset *root)
                        remove_tasks_in_empty_cpuset(cp);
                else {
                        update_tasks_cpumask(cp, NULL);
-                       update_tasks_nodemask(cp, oldmems, NULL);
+                       update_tasks_nodemask(cp, &oldmems, NULL);
                }
        }
-       NODEMASK_FREE(oldmems);
 }
 
 /*
@@ -2147,19 +2123,16 @@ void cpuset_update_active_cpus(void)
 static int cpuset_track_online_nodes(struct notifier_block *self,
                                unsigned long action, void *arg)
 {
-       NODEMASK_ALLOC(nodemask_t, oldmems, GFP_KERNEL);
-
-       if (oldmems == NULL)
-               return NOTIFY_DONE;
+       static nodemask_t oldmems;      /* protected by cgroup_mutex */
 
        cgroup_lock();
        switch (action) {
        case MEM_ONLINE:
-               *oldmems = top_cpuset.mems_allowed;
+               oldmems = top_cpuset.mems_allowed;
                mutex_lock(&callback_mutex);
                top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
                mutex_unlock(&callback_mutex);
-               update_tasks_nodemask(&top_cpuset, oldmems, NULL);
+               update_tasks_nodemask(&top_cpuset, &oldmems, NULL);
                break;
        case MEM_OFFLINE:
                /*
@@ -2173,7 +2146,6 @@ static int cpuset_track_online_nodes(struct notifier_block *self,
        }
        cgroup_unlock();
 
-       NODEMASK_FREE(oldmems);
        return NOTIFY_OK;
 }
 #endif
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..5f85690
--- /dev/null
@@ -0,0 +1,34 @@
+#include <linux/kernel.h>
+#include <linux/crash_dump.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
+
+/*
+ * stores the physical address of elf header of crash image
+ *
+ * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by
+ * is_kdump_kernel() to determine if we are booting after a panic. Hence put
+ * it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
+ */
+unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+
+/*
+ * elfcorehdr= specifies the location of elf core header stored by the crashed
+ * kernel. This option will be passed by kexec loader to the capture kernel.
+ */
+static int __init setup_elfcorehdr(char *arg)
+{
+       char *end;
+       if (!arg)
+               return -EINVAL;
+       elfcorehdr_addr = memparse(arg, &end);
+       return end > arg ? 0 : -EINVAL;
+}
+early_param("elfcorehdr", setup_elfcorehdr);
index 2343c132c5a7f45556bf156388705ac921fa84e0..5557b55048df1a35fff09933a274c9a5e32b7084 100644 (file)
@@ -741,6 +741,12 @@ int set_create_files_as(struct cred *new, struct inode *inode)
 }
 EXPORT_SYMBOL(set_create_files_as);
 
+struct user_namespace *current_user_ns(void)
+{
+       return _current_user_ns();
+}
+EXPORT_SYMBOL(current_user_ns);
+
 #ifdef CONFIG_DEBUG_CREDENTIALS
 
 bool creds_are_invalid(const struct cred *cred)
index 481a7bd2dfe752267ba3273a1bb8e4a972c17fa5..a11db956dd62c4c5a5fa22699ccd3662a88f00bc 100644 (file)
@@ -1093,3 +1093,33 @@ int gdbstub_state(struct kgdb_state *ks, char *cmd)
        put_packet(remcom_out_buffer);
        return 0;
 }
+
+/**
+ * gdbstub_exit - Send an exit message to GDB
+ * @status: The exit code to report.
+ */
+void gdbstub_exit(int status)
+{
+       unsigned char checksum, ch, buffer[3];
+       int loop;
+
+       buffer[0] = 'W';
+       buffer[1] = hex_asc_hi(status);
+       buffer[2] = hex_asc_lo(status);
+
+       dbg_io_ops->write_char('$');
+       checksum = 0;
+
+       for (loop = 0; loop < 3; loop++) {
+               ch = buffer[loop];
+               checksum += ch;
+               dbg_io_ops->write_char(ch);
+       }
+
+       dbg_io_ops->write_char('#');
+       dbg_io_ops->write_char(hex_asc_hi(checksum));
+       dbg_io_ops->write_char(hex_asc_lo(checksum));
+
+       /* make sure the output is flushed, lest the bootloader clobber it */
+       dbg_io_ops->flush();
+}
index f9a45ebcc7b17c30ac1d39338b75600b6287b10f..6a488ad2dce5bf9a1b6ba24376e1449e603687e4 100644 (file)
@@ -908,6 +908,7 @@ NORET_TYPE void do_exit(long code)
        profile_task_exit(tsk);
 
        WARN_ON(atomic_read(&tsk->fs_excl));
+       WARN_ON(blk_needs_flush_plug(tsk));
 
        if (unlikely(in_interrupt()))
                panic("Aiee, killing interrupt handler!");
index 05b92c457010700a7578bb4fb418e612a8332fa3..e7548dee636b1f29f344d4c2a9749a963135f477 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/tracehook.h>
 #include <linux/futex.h>
 #include <linux/compat.h>
+#include <linux/kthread.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/rcupdate.h>
 #include <linux/ptrace.h>
@@ -109,20 +110,25 @@ int nr_processes(void)
 }
 
 #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
-# define alloc_task_struct()   kmem_cache_alloc(task_struct_cachep, GFP_KERNEL)
-# define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk))
+# define alloc_task_struct_node(node)          \
+               kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node)
+# define free_task_struct(tsk)                 \
+               kmem_cache_free(task_struct_cachep, (tsk))
 static struct kmem_cache *task_struct_cachep;
 #endif
 
 #ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR
-static inline struct thread_info *alloc_thread_info(struct task_struct *tsk)
+static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
+                                                 int node)
 {
 #ifdef CONFIG_DEBUG_STACK_USAGE
        gfp_t mask = GFP_KERNEL | __GFP_ZERO;
 #else
        gfp_t mask = GFP_KERNEL;
 #endif
-       return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
+       struct page *page = alloc_pages_node(node, mask, THREAD_SIZE_ORDER);
+
+       return page ? page_address(page) : NULL;
 }
 
 static inline void free_thread_info(struct thread_info *ti)
@@ -249,16 +255,16 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        struct task_struct *tsk;
        struct thread_info *ti;
        unsigned long *stackend;
-
+       int node = tsk_fork_get_node(orig);
        int err;
 
        prepare_to_copy(orig);
 
-       tsk = alloc_task_struct();
+       tsk = alloc_task_struct_node(node);
        if (!tsk)
                return NULL;
 
-       ti = alloc_thread_info(tsk);
+       ti = alloc_thread_info_node(tsk, node);
        if (!ti) {
                free_task_struct(tsk);
                return NULL;
@@ -1181,12 +1187,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                pid = alloc_pid(p->nsproxy->pid_ns);
                if (!pid)
                        goto bad_fork_cleanup_io;
-
-               if (clone_flags & CLONE_NEWPID) {
-                       retval = pid_ns_prepare_proc(p->nsproxy->pid_ns);
-                       if (retval < 0)
-                               goto bad_fork_free_pid;
-               }
        }
 
        p->pid = pid_nr(pid);
@@ -1205,6 +1205,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
         * Clear TID on mm_release()?
         */
        p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL;
+#ifdef CONFIG_BLOCK
+       p->plug = NULL;
+#endif
 #ifdef CONFIG_FUTEX
        p->robust_list = NULL;
 #ifdef CONFIG_COMPAT
@@ -1290,7 +1293,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                tracehook_finish_clone(p, clone_flags, trace);
 
                if (thread_group_leader(p)) {
-                       if (clone_flags & CLONE_NEWPID)
+                       if (is_child_reaper(pid))
                                p->nsproxy->pid_ns->child_reaper = p;
 
                        p->signal->leader_pid = pid;
@@ -1513,38 +1516,24 @@ void __init proc_caches_init(void)
 }
 
 /*
- * Check constraints on flags passed to the unshare system call and
- * force unsharing of additional process context as appropriate.
+ * Check constraints on flags passed to the unshare system call.
  */
-static void check_unshare_flags(unsigned long *flags_ptr)
+static int check_unshare_flags(unsigned long unshare_flags)
 {
+       if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
+                               CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
+                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
+               return -EINVAL;
        /*
-        * If unsharing a thread from a thread group, must also
-        * unshare vm.
-        */
-       if (*flags_ptr & CLONE_THREAD)
-               *flags_ptr |= CLONE_VM;
-
-       /*
-        * If unsharing vm, must also unshare signal handlers.
-        */
-       if (*flags_ptr & CLONE_VM)
-               *flags_ptr |= CLONE_SIGHAND;
-
-       /*
-        * If unsharing namespace, must also unshare filesystem information.
+        * Not implemented, but pretend it works if there is nothing to
+        * unshare. Note that unsharing CLONE_THREAD or CLONE_SIGHAND
+        * needs to unshare vm.
         */
-       if (*flags_ptr & CLONE_NEWNS)
-               *flags_ptr |= CLONE_FS;
-}
-
-/*
- * Unsharing of tasks created with CLONE_THREAD is not supported yet
- */
-static int unshare_thread(unsigned long unshare_flags)
-{
-       if (unshare_flags & CLONE_THREAD)
-               return -EINVAL;
+       if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) {
+               /* FIXME: get_task_mm() increments ->mm_users */
+               if (atomic_read(&current->mm->mm_users) > 1)
+                       return -EINVAL;
+       }
 
        return 0;
 }
@@ -1570,34 +1559,6 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
        return 0;
 }
 
-/*
- * Unsharing of sighand is not supported yet
- */
-static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
-{
-       struct sighand_struct *sigh = current->sighand;
-
-       if ((unshare_flags & CLONE_SIGHAND) && atomic_read(&sigh->count) > 1)
-               return -EINVAL;
-       else
-               return 0;
-}
-
-/*
- * Unshare vm if it is being shared
- */
-static int unshare_vm(unsigned long unshare_flags, struct mm_struct **new_mmp)
-{
-       struct mm_struct *mm = current->mm;
-
-       if ((unshare_flags & CLONE_VM) &&
-           (mm && atomic_read(&mm->mm_users) > 1)) {
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 /*
  * Unshare file descriptor table if it is being shared
  */
@@ -1626,23 +1587,21 @@ static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp
  */
 SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
 {
-       int err = 0;
        struct fs_struct *fs, *new_fs = NULL;
-       struct sighand_struct *new_sigh = NULL;
-       struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
        struct files_struct *fd, *new_fd = NULL;
        struct nsproxy *new_nsproxy = NULL;
        int do_sysvsem = 0;
+       int err;
 
-       check_unshare_flags(&unshare_flags);
-
-       /* Return -EINVAL for all unsupported flags */
-       err = -EINVAL;
-       if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
-                               CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
-                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
+       err = check_unshare_flags(unshare_flags);
+       if (err)
                goto bad_unshare_out;
 
+       /*
+        * If unsharing namespace, must also unshare filesystem information.
+        */
+       if (unshare_flags & CLONE_NEWNS)
+               unshare_flags |= CLONE_FS;
        /*
         * CLONE_NEWIPC must also detach from the undolist: after switching
         * to a new ipc namespace, the semaphore arrays from the old
@@ -1650,21 +1609,15 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
         */
        if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM))
                do_sysvsem = 1;
-       if ((err = unshare_thread(unshare_flags)))
-               goto bad_unshare_out;
        if ((err = unshare_fs(unshare_flags, &new_fs)))
-               goto bad_unshare_cleanup_thread;
-       if ((err = unshare_sighand(unshare_flags, &new_sigh)))
-               goto bad_unshare_cleanup_fs;
-       if ((err = unshare_vm(unshare_flags, &new_mm)))
-               goto bad_unshare_cleanup_sigh;
+               goto bad_unshare_out;
        if ((err = unshare_fd(unshare_flags, &new_fd)))
-               goto bad_unshare_cleanup_vm;
+               goto bad_unshare_cleanup_fs;
        if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
                        new_fs)))
                goto bad_unshare_cleanup_fd;
 
-       if (new_fs ||  new_mm || new_fd || do_sysvsem || new_nsproxy) {
+       if (new_fs || new_fd || do_sysvsem || new_nsproxy) {
                if (do_sysvsem) {
                        /*
                         * CLONE_SYSVSEM is equivalent to sys_exit().
@@ -1690,19 +1643,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
                        spin_unlock(&fs->lock);
                }
 
-               if (new_mm) {
-                       mm = current->mm;
-                       active_mm = current->active_mm;
-                       current->mm = new_mm;
-                       current->active_mm = new_mm;
-                       if (current->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) {
-                               atomic_dec(&mm->oom_disable_count);
-                               atomic_inc(&new_mm->oom_disable_count);
-                       }
-                       activate_mm(active_mm, new_mm);
-                       new_mm = mm;
-               }
-
                if (new_fd) {
                        fd = current->files;
                        current->files = new_fd;
@@ -1719,20 +1659,10 @@ bad_unshare_cleanup_fd:
        if (new_fd)
                put_files_struct(new_fd);
 
-bad_unshare_cleanup_vm:
-       if (new_mm)
-               mmput(new_mm);
-
-bad_unshare_cleanup_sigh:
-       if (new_sigh)
-               if (atomic_dec_and_test(&new_sigh->count))
-                       kmem_cache_free(sighand_cachep, new_sigh);
-
 bad_unshare_cleanup_fs:
        if (new_fs)
                free_fs_struct(new_fs);
 
-bad_unshare_cleanup_thread:
 bad_unshare_out:
        return err;
 }
index bda41571538263394eb468e486abc00e6e46ae96..dfb924ffe65ba758627864ac45c55bb9bda290bc 100644 (file)
@@ -782,8 +782,8 @@ static void __unqueue_futex(struct futex_q *q)
 {
        struct futex_hash_bucket *hb;
 
-       if (WARN_ON(!q->lock_ptr || !spin_is_locked(q->lock_ptr)
-                       || plist_node_empty(&q->list)))
+       if (WARN_ON_SMP(!q->lock_ptr || !spin_is_locked(q->lock_ptr))
+           || WARN_ON(plist_node_empty(&q->list)))
                return;
 
        hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
@@ -2418,10 +2418,19 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
                        goto err_unlock;
                ret = -EPERM;
                pcred = __task_cred(p);
+               /* If victim is in different user_ns, then uids are not
+                  comparable, so we must have CAP_SYS_PTRACE */
+               if (cred->user->user_ns != pcred->user->user_ns) {
+                       if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
+                               goto err_unlock;
+                       goto ok;
+               }
+               /* If victim is in same user_ns, then uids are comparable */
                if (cred->euid != pcred->euid &&
                    cred->euid != pcred->uid &&
-                   !capable(CAP_SYS_PTRACE))
+                   !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
                        goto err_unlock;
+ok:
                head = p->robust_list;
                rcu_read_unlock();
        }
index a7934ac75e5bf4b2b7f5b819d24e8f6f08a1ff1a..5f9e689dc8f0f7d52824108c56712e45e2e81560 100644 (file)
@@ -153,10 +153,19 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
                        goto err_unlock;
                ret = -EPERM;
                pcred = __task_cred(p);
+               /* If victim is in different user_ns, then uids are not
+                  comparable, so we must have CAP_SYS_PTRACE */
+               if (cred->user->user_ns != pcred->user->user_ns) {
+                       if (!ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
+                               goto err_unlock;
+                       goto ok;
+               }
+               /* If victim is in same user_ns, then uids are comparable */
                if (cred->euid != pcred->euid &&
                    cred->euid != pcred->uid &&
-                   !capable(CAP_SYS_PTRACE))
+                   !ns_capable(pcred->user->user_ns, CAP_SYS_PTRACE))
                        goto err_unlock;
+ok:
                head = p->compat_robust_list;
                rcu_read_unlock();
        }
index 3f761001d517e2e3ae3b92f24cd85bcd6cd32262..e97ca59e2520dce3a3c0d7b2460d444e1b7591c0 100644 (file)
@@ -1,3 +1,3 @@
-EXTRA_CFLAGS := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"'
+ccflags-y := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"'
 
 obj-$(CONFIG_GCOV_KERNEL) := base.o fs.o gcc_3_4.o
index 253dc0f35cf4c30786d1ff3565427d1374762a04..1cc476d52dd3b6e477ebd2d70a0d97b61219f189 100644 (file)
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!capable(CAP_SETGID))
+       if (!nsown_capable(CAP_SETGID))
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
index 09bef82d74cb9f25517d781a5cc1070c72b482c1..00f2c037267aa622780fd9f12dd555096116586e 100644 (file)
@@ -31,6 +31,10 @@ config GENERIC_IRQ_PROBE
 config GENERIC_IRQ_SHOW
        bool
 
+# Print level/edge extra information
+config GENERIC_IRQ_SHOW_LEVEL
+       bool
+
 # Support for delayed migration from interrupt context
 config GENERIC_PENDING_IRQ
        bool
index dbccc799407f08c3bd9fba76b8af4178868085ca..6fb014f172f7397a7edeec525d53a9b649dfcf25 100644 (file)
@@ -198,15 +198,6 @@ err:
        return -ENOMEM;
 }
 
-struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
-{
-       int res = irq_alloc_descs(irq, irq, 1, node);
-
-       if (res == -EEXIST || res == irq)
-               return irq_to_desc(irq);
-       return NULL;
-}
-
 static int irq_expand_nr_irqs(unsigned int nr)
 {
        if (nr > IRQ_BITMAP_BITS)
@@ -283,11 +274,6 @@ struct irq_desc *irq_to_desc(unsigned int irq)
        return (irq < NR_IRQS) ? irq_desc + irq : NULL;
 }
 
-struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
-{
-       return irq_to_desc(irq);
-}
-
 static void free_desc(unsigned int irq)
 {
        dynamic_irq_cleanup(irq);
index 760248de109d8e9d9ec163bbd251684c9b00a054..626d092eed9a0d8b191f561b558c1478c7e45df6 100644 (file)
@@ -404,7 +404,20 @@ int show_interrupts(struct seq_file *p, void *v)
        seq_printf(p, "%*d: ", prec, i);
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-       seq_printf(p, " %8s", desc->irq_data.chip->name);
+
+       if (desc->irq_data.chip) {
+               if (desc->irq_data.chip->irq_print_chip)
+                       desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
+               else if (desc->irq_data.chip->name)
+                       seq_printf(p, " %8s", desc->irq_data.chip->name);
+               else
+                       seq_printf(p, " %8s", "-");
+       } else {
+               seq_printf(p, " %8s", "None");
+       }
+#ifdef CONFIG_GENIRC_IRQ_SHOW_LEVEL
+       seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
+#endif
        if (desc->name)
                seq_printf(p, "-%-8s", desc->name);
 
index 6f6d091b57573bf37fc98fdcb2df91c08787543d..079f1d39a8b84a9105852864cbc8ceaf8875d5ac 100644 (file)
@@ -64,14 +64,14 @@ static inline int is_kernel_text(unsigned long addr)
        if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) ||
            arch_is_kernel_text(addr))
                return 1;
-       return in_gate_area_no_task(addr);
+       return in_gate_area_no_mm(addr);
 }
 
 static inline int is_kernel(unsigned long addr)
 {
        if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)
                return 1;
-       return in_gate_area_no_task(addr);
+       return in_gate_area_no_mm(addr);
 }
 
 static int is_ksym_addr(unsigned long addr)
@@ -342,13 +342,15 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
 }
 
 /* Look up a kernel symbol and return it in a text buffer. */
-int sprint_symbol(char *buffer, unsigned long address)
+static int __sprint_symbol(char *buffer, unsigned long address,
+                          int symbol_offset)
 {
        char *modname;
        const char *name;
        unsigned long offset, size;
        int len;
 
+       address += symbol_offset;
        name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
        if (!name)
                return sprintf(buffer, "0x%lx", address);
@@ -357,17 +359,53 @@ int sprint_symbol(char *buffer, unsigned long address)
                strcpy(buffer, name);
        len = strlen(buffer);
        buffer += len;
+       offset -= symbol_offset;
 
        if (modname)
-               len += sprintf(buffer, "+%#lx/%#lx [%s]",
-                                               offset, size, modname);
+               len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname);
        else
                len += sprintf(buffer, "+%#lx/%#lx", offset, size);
 
        return len;
 }
+
+/**
+ * sprint_symbol - Look up a kernel symbol and return it in a text buffer
+ * @buffer: buffer to be stored
+ * @address: address to lookup
+ *
+ * This function looks up a kernel symbol with @address and stores its name,
+ * offset, size and module name to @buffer if possible. If no symbol was found,
+ * just saves its @address as is.
+ *
+ * This function returns the number of bytes stored in @buffer.
+ */
+int sprint_symbol(char *buffer, unsigned long address)
+{
+       return __sprint_symbol(buffer, address, 0);
+}
+
 EXPORT_SYMBOL_GPL(sprint_symbol);
 
+/**
+ * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
+ * @buffer: buffer to be stored
+ * @address: address to lookup
+ *
+ * This function is for stack backtrace and does the same thing as
+ * sprint_symbol() but with modified/decreased @address. If there is a
+ * tail-call to the function marked "noreturn", gcc optimized out code after
+ * the call so that the stack-saved return address could point outside of the
+ * caller. This function ensures that kallsyms will find the original caller
+ * by decreasing @address.
+ *
+ * This function returns the number of bytes stored in @buffer.
+ */
+int sprint_backtrace(char *buffer, unsigned long address)
+{
+       return __sprint_symbol(buffer, address, -1);
+}
+
 /* Look up a kernel symbol and print it to the kernel messages. */
 void __print_symbol(const char *fmt, unsigned long address)
 {
@@ -477,13 +515,11 @@ static int s_show(struct seq_file *m, void *p)
                 */
                type = iter->exported ? toupper(iter->type) :
                                        tolower(iter->type);
-               seq_printf(m, "%0*lx %c %s\t[%s]\n",
-                          (int)(2 * sizeof(void *)),
-                          iter->value, type, iter->name, iter->module_name);
+               seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value,
+                          type, iter->name, iter->module_name);
        } else
-               seq_printf(m, "%0*lx %c %s\n",
-                          (int)(2 * sizeof(void *)),
-                          iter->value, iter->type, iter->name);
+               seq_printf(m, "%pK %c %s\n", (void *)iter->value,
+                          iter->type, iter->name);
        return 0;
 }
 
index c55afba990a384ae0c17abd6f826878ad300a7cf..684ab3f7dd72faec6e5036be77f1acd6c648327b 100644 (file)
@@ -27,6 +27,7 @@ struct kthread_create_info
        /* Information passed to kthread() from kthreadd. */
        int (*threadfn)(void *data);
        void *data;
+       int node;
 
        /* Result passed back to kthread_create() from kthreadd. */
        struct task_struct *result;
@@ -98,10 +99,23 @@ static int kthread(void *_create)
        do_exit(ret);
 }
 
+/* called from do_fork() to get node information for about to be created task */
+int tsk_fork_get_node(struct task_struct *tsk)
+{
+#ifdef CONFIG_NUMA
+       if (tsk == kthreadd_task)
+               return tsk->pref_node_fork;
+#endif
+       return numa_node_id();
+}
+
 static void create_kthread(struct kthread_create_info *create)
 {
        int pid;
 
+#ifdef CONFIG_NUMA
+       current->pref_node_fork = create->node;
+#endif
        /* We want our own signal handler (we take no signals by default). */
        pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
        if (pid < 0) {
@@ -111,15 +125,18 @@ static void create_kthread(struct kthread_create_info *create)
 }
 
 /**
- * kthread_create - create a kthread.
+ * kthread_create_on_node - create a kthread.
  * @threadfn: the function to run until signal_pending(current).
  * @data: data ptr for @threadfn.
+ * @node: memory node number.
  * @namefmt: printf-style name for the thread.
  *
  * Description: This helper function creates and names a kernel
  * thread.  The thread will be stopped: use wake_up_process() to start
  * it.  See also kthread_run().
  *
+ * If thread is going to be bound on a particular cpu, give its node
+ * in @node, to get NUMA affinity for kthread stack, or else give -1.
  * When woken, the thread will run @threadfn() with @data as its
  * argument. @threadfn() can either call do_exit() directly if it is a
  * standalone thread for which noone will call kthread_stop(), or
@@ -129,15 +146,17 @@ static void create_kthread(struct kthread_create_info *create)
  *
  * Returns a task_struct or ERR_PTR(-ENOMEM).
  */
-struct task_struct *kthread_create(int (*threadfn)(void *data),
-                                  void *data,
-                                  const char namefmt[],
-                                  ...)
+struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
+                                          void *data,
+                                          int node,
+                                          const char namefmt[],
+                                          ...)
 {
        struct kthread_create_info create;
 
        create.threadfn = threadfn;
        create.data = data;
+       create.node = node;
        init_completion(&create.done);
 
        spin_lock(&kthread_create_lock);
@@ -164,7 +183,7 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
        }
        return create.result;
 }
-EXPORT_SYMBOL(kthread_create);
+EXPORT_SYMBOL(kthread_create_on_node);
 
 /**
  * kthread_bind - bind a just-created kthread to a cpu.
index 1969d2fc4b36328cf48798620506ddcd0ec330d0..71edd2f60c026fb3f923a56302f8e445e0910fb4 100644 (file)
@@ -225,7 +225,7 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
                      nr_irq_read_safe = 0, nr_irq_read_unsafe = 0,
                      nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0,
                      nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
-                     sum_forward_deps = 0, factor = 0;
+                     sum_forward_deps = 0;
 
        list_for_each_entry(class, &all_lock_classes, lock_entry) {
 
@@ -283,13 +283,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
                        nr_hardirq_unsafe * nr_hardirq_safe +
                        nr_list_entries);
 
-       /*
-        * Estimated factor between direct and indirect
-        * dependencies:
-        */
-       if (nr_list_entries)
-               factor = sum_forward_deps / nr_list_entries;
-
 #ifdef CONFIG_PROVE_LOCKING
        seq_printf(m, " dependency chains:             %11lu [max: %lu]\n",
                        nr_lock_chains, MAX_LOCKDEP_CHAINS);
index efa290ea94bf75d843a876a0a729bbd851088429..1f9f7bc56ca190185270689ff801ca62354b001a 100644 (file)
@@ -1168,7 +1168,7 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
 {
        struct module_sect_attr *sattr =
                container_of(mattr, struct module_sect_attr, mattr);
-       return sprintf(buf, "0x%lx\n", sattr->address);
+       return sprintf(buf, "0x%pK\n", (void *)sattr->address);
 }
 
 static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
@@ -3224,7 +3224,7 @@ static int m_show(struct seq_file *m, void *p)
                   mod->state == MODULE_STATE_COMING ? "Loading":
                   "Live");
        /* Used by oprofile and other similar tools. */
-       seq_printf(m, " 0x%p", mod->module_core);
+       seq_printf(m, " 0x%pK", mod->module_core);
 
        /* Taints info */
        if (mod->taints)
index f74e6c00e26d1f50fb1c404b2a6e5505354882bf..a05d191ffdd903bd2efc5e10d783021ef1b29a98 100644 (file)
@@ -69,13 +69,13 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
                goto out_ns;
        }
 
-       new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
+       new_nsp->uts_ns = copy_utsname(flags, tsk);
        if (IS_ERR(new_nsp->uts_ns)) {
                err = PTR_ERR(new_nsp->uts_ns);
                goto out_uts;
        }
 
-       new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
+       new_nsp->ipc_ns = copy_ipcs(flags, tsk);
        if (IS_ERR(new_nsp->ipc_ns)) {
                err = PTR_ERR(new_nsp->ipc_ns);
                goto out_ipc;
index 991bb87a170408ae2db0fdc29047432ae4204377..69231670eb952357809488fa58cffef5596e9c63 100644 (file)
@@ -433,3 +433,13 @@ EXPORT_SYMBOL(__stack_chk_fail);
 
 core_param(panic, panic_timeout, int, 0644);
 core_param(pause_on_oops, pause_on_oops, int, 0644);
+
+static int __init oops_setup(char *s)
+{
+       if (!s)
+               return -EINVAL;
+       if (!strcmp(s, "panic"))
+               panic_on_oops = 1;
+       return 0;
+}
+early_param("oops", oops_setup);
index 3472bb1a070c4c2972e2c790da9fb9dd86e36488..c75925c4d1e29a3296bed32a6f0eeb7e6c189c29 100644 (file)
@@ -145,7 +145,8 @@ static struct srcu_struct pmus_srcu;
  */
 int sysctl_perf_event_paranoid __read_mostly = 1;
 
-int sysctl_perf_event_mlock __read_mostly = 512; /* 'free' kb per user */
+/* Minimum for 128 pages + 1 for the user control page */
+int sysctl_perf_event_mlock __read_mostly = 516; /* 'free' kb per user */
 
 /*
  * max perf event sample rate
@@ -941,6 +942,7 @@ static void perf_group_attach(struct perf_event *event)
 static void
 list_del_event(struct perf_event *event, struct perf_event_context *ctx)
 {
+       struct perf_cpu_context *cpuctx;
        /*
         * We can have double detach due to exit/hot-unplug + close.
         */
@@ -949,8 +951,17 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
 
        event->attach_state &= ~PERF_ATTACH_CONTEXT;
 
-       if (is_cgroup_event(event))
+       if (is_cgroup_event(event)) {
                ctx->nr_cgroups--;
+               cpuctx = __get_cpu_context(ctx);
+               /*
+                * if there are no more cgroup events
+                * then cler cgrp to avoid stale pointer
+                * in update_cgrp_time_from_cpuctx()
+                */
+               if (!ctx->nr_cgroups)
+                       cpuctx->cgrp = NULL;
+       }
 
        ctx->nr_events--;
        if (event->attr.inherit_stat)
index a5aff94e1f0b49d30eb77ff056dd6712d5687e5e..e9c9adc84ca6e50f5f457e081bb45c36b35bf4d1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/err.h>
 #include <linux/acct.h>
 #include <linux/slab.h>
+#include <linux/proc_fs.h>
 
 #define BITS_PER_PAGE          (PAGE_SIZE*8)
 
@@ -72,7 +73,7 @@ static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_p
 {
        struct pid_namespace *ns;
        unsigned int level = parent_pid_ns->level + 1;
-       int i;
+       int i, err = -ENOMEM;
 
        ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL);
        if (ns == NULL)
@@ -96,14 +97,20 @@ static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_p
        for (i = 1; i < PIDMAP_ENTRIES; i++)
                atomic_set(&ns->pidmap[i].nr_free, BITS_PER_PAGE);
 
+       err = pid_ns_prepare_proc(ns);
+       if (err)
+               goto out_put_parent_pid_ns;
+
        return ns;
 
+out_put_parent_pid_ns:
+       put_pid_ns(parent_pid_ns);
 out_free_map:
        kfree(ns->pidmap[0].page);
 out_free:
        kmem_cache_free(pid_ns_cachep, ns);
 out:
-       return ERR_PTR(-ENOMEM);
+       return ERR_PTR(err);
 }
 
 static void destroy_pid_namespace(struct pid_namespace *ns)
index c350e18b53e3f4d5f7683680634de3f2bf1bf3a3..c5ebc6a9064390583ed4f9cb6c11cf857fd0c318 100644 (file)
@@ -1,4 +1,5 @@
-ccflags-$(CONFIG_PM_DEBUG)     :=      -DDEBUG
+
+ccflags-$(CONFIG_PM_DEBUG)     := -DDEBUG
 
 obj-$(CONFIG_PM)               += main.o
 obj-$(CONFIG_PM_SLEEP)         += console.o
index 83bbc7c02df95fd3560bdac7340cc3804d167d38..d09dd10c5a5efc2c206a85bd31a431268e37cc7f 100644 (file)
@@ -28,7 +28,7 @@
 static int submit(int rw, struct block_device *bdev, sector_t sector,
                struct page *page, struct bio **bio_chain)
 {
-       const int bio_rw = rw | REQ_SYNC | REQ_UNPLUG;
+       const int bio_rw = rw | REQ_SYNC;
        struct bio *bio;
 
        bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
index 33284adb21895b7bee8fa74b160f86d7f1458d52..da8ca817eae3b817d037f3f2d4b9666e52569b35 100644 (file)
@@ -53,7 +53,7 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
 #define __LOG_BUF_LEN  (1 << CONFIG_LOG_BUF_SHIFT)
 
 /* printk's without a loglevel use this.. */
-#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
+#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
 /* We show everything that is MORE important than this.. */
 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
@@ -112,6 +112,11 @@ static unsigned log_start; /* Index into log_buf: next char to be read by syslog
 static unsigned con_start;     /* Index into log_buf: next char to be sent to consoles */
 static unsigned log_end;       /* Index into log_buf: most-recently-written-char + 1 */
 
+/*
+ * If exclusive_console is non-NULL then only this console is to be printed to.
+ */
+static struct console *exclusive_console;
+
 /*
  *     Array of consoles built from command line options (console=)
  */
@@ -476,6 +481,8 @@ static void __call_console_drivers(unsigned start, unsigned end)
        struct console *con;
 
        for_each_console(con) {
+               if (exclusive_console && con != exclusive_console)
+                       continue;
                if ((con->flags & CON_ENABLED) && con->write &&
                                (cpu_online(smp_processor_id()) ||
                                (con->flags & CON_ANYTIME)))
@@ -1230,6 +1237,11 @@ void console_unlock(void)
                local_irq_restore(flags);
        }
        console_locked = 0;
+
+       /* Release the exclusive_console once it is used */
+       if (unlikely(exclusive_console))
+               exclusive_console = NULL;
+
        up(&console_sem);
        spin_unlock_irqrestore(&logbuf_lock, flags);
        if (wake_klogd)
@@ -1316,6 +1328,18 @@ void console_start(struct console *console)
 }
 EXPORT_SYMBOL(console_start);
 
+static int __read_mostly keep_bootcon;
+
+static int __init keep_bootcon_setup(char *str)
+{
+       keep_bootcon = 1;
+       printk(KERN_INFO "debug: skip boot console de-registration.\n");
+
+       return 0;
+}
+
+early_param("keep_bootcon", keep_bootcon_setup);
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to
@@ -1452,6 +1476,12 @@ void register_console(struct console *newcon)
                spin_lock_irqsave(&logbuf_lock, flags);
                con_start = log_start;
                spin_unlock_irqrestore(&logbuf_lock, flags);
+               /*
+                * We're about to replay the log buffer.  Only do this to the
+                * just-registered console to avoid excessive message spam to
+                * the already-registered consoles.
+                */
+               exclusive_console = newcon;
        }
        console_unlock();
        console_sysfs_notify();
@@ -1463,7 +1493,9 @@ void register_console(struct console *newcon)
         * users know there might be something in the kernel's log buffer that
         * went to the bootconsole (that they do not see on the real console)
         */
-       if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
+       if (bcon &&
+           ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
+           !keep_bootcon) {
                /* we need to iterate through twice, to make sure we print
                 * everything out, before we unregister the console(s)
                 */
index e2302e40b360006d671b4fe5cad9baf5de7419e3..0fc1eed28d2783e0b2779fe50d1ff86fbf4ca858 100644 (file)
@@ -134,21 +134,24 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
                return 0;
        rcu_read_lock();
        tcred = __task_cred(task);
-       if ((cred->uid != tcred->euid ||
-            cred->uid != tcred->suid ||
-            cred->uid != tcred->uid  ||
-            cred->gid != tcred->egid ||
-            cred->gid != tcred->sgid ||
-            cred->gid != tcred->gid) &&
-           !capable(CAP_SYS_PTRACE)) {
-               rcu_read_unlock();
-               return -EPERM;
-       }
+       if (cred->user->user_ns == tcred->user->user_ns &&
+           (cred->uid == tcred->euid &&
+            cred->uid == tcred->suid &&
+            cred->uid == tcred->uid  &&
+            cred->gid == tcred->egid &&
+            cred->gid == tcred->sgid &&
+            cred->gid == tcred->gid))
+               goto ok;
+       if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE))
+               goto ok;
+       rcu_read_unlock();
+       return -EPERM;
+ok:
        rcu_read_unlock();
        smp_rmb();
        if (task->mm)
                dumpable = get_dumpable(task->mm);
-       if (!dumpable && !capable(CAP_SYS_PTRACE))
+       if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE))
                return -EPERM;
 
        return security_ptrace_access_check(task, mode);
@@ -198,7 +201,7 @@ static int ptrace_attach(struct task_struct *task)
                goto unlock_tasklist;
 
        task->ptrace = PT_PTRACED;
-       if (capable(CAP_SYS_PTRACE))
+       if (task_ns_capable(task, CAP_SYS_PTRACE))
                task->ptrace |= PT_PTRACE_CAP;
 
        __ptrace_link(task, current);
index c7eaa37a768b785cf69cd2eb64ab3fb75c052124..34683efa2cceee37f0a76db7531b8f5fc265a325 100644 (file)
@@ -126,10 +126,24 @@ ssize_t res_counter_read(struct res_counter *counter, int member,
                        pos, buf, s - buf);
 }
 
+#if BITS_PER_LONG == 32
+u64 res_counter_read_u64(struct res_counter *counter, int member)
+{
+       unsigned long flags;
+       u64 ret;
+
+       spin_lock_irqsave(&counter->lock, flags);
+       ret = *res_counter_member(counter, member);
+       spin_unlock_irqrestore(&counter->lock, flags);
+
+       return ret;
+}
+#else
 u64 res_counter_read_u64(struct res_counter *counter, int member)
 {
        return *res_counter_member(counter, member);
 }
+#endif
 
 int res_counter_memparse_write_strategy(const char *buf,
                                        unsigned long long *res)
index a172494a9a636e3797a23194bb5a75834d0dd59b..f592ce6f861624857597199920bc5a12900136a7 100644 (file)
@@ -4115,6 +4115,16 @@ need_resched:
                switch_count = &prev->nvcsw;
        }
 
+       /*
+        * If we are going to sleep and we have plugged IO queued, make
+        * sure to submit it to avoid deadlocks.
+        */
+       if (prev->state != TASK_RUNNING && blk_needs_flush_plug(prev)) {
+               raw_spin_unlock(&rq->lock);
+               blk_flush_plug(prev);
+               raw_spin_lock(&rq->lock);
+       }
+
        pre_schedule(rq, prev);
 
        if (unlikely(!rq->nr_running))
@@ -4892,8 +4902,11 @@ static bool check_same_owner(struct task_struct *p)
 
        rcu_read_lock();
        pcred = __task_cred(p);
-       match = (cred->euid == pcred->euid ||
-                cred->euid == pcred->uid);
+       if (cred->user->user_ns == pcred->user->user_ns)
+               match = (cred->euid == pcred->euid ||
+                        cred->euid == pcred->uid);
+       else
+               match = false;
        rcu_read_unlock();
        return match;
 }
@@ -5221,7 +5234,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
                goto out_free_cpus_allowed;
        }
        retval = -EPERM;
-       if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
+       if (!check_same_owner(p) && !task_ns_capable(p, CAP_SYS_NICE))
                goto out_unlock;
 
        retval = security_task_setscheduler(p);
@@ -5460,6 +5473,8 @@ EXPORT_SYMBOL(yield);
  * yield_to - yield the current processor to another thread in
  * your thread group, or accelerate that thread toward the
  * processor it's on.
+ * @p: target task
+ * @preempt: whether task preemption is allowed or not
  *
  * It's the caller's job to ensure that the target task struct
  * can't go away on us before we can do any checks.
@@ -5525,6 +5540,7 @@ void __sched io_schedule(void)
 
        delayacct_blkio_start();
        atomic_inc(&rq->nr_iowait);
+       blk_flush_plug(current);
        current->in_iowait = 1;
        schedule();
        current->in_iowait = 0;
@@ -5540,6 +5556,7 @@ long __sched io_schedule_timeout(long timeout)
 
        delayacct_blkio_start();
        atomic_inc(&rq->nr_iowait);
+       blk_flush_plug(current);
        current->in_iowait = 1;
        ret = schedule_timeout(timeout);
        current->in_iowait = 0;
@@ -8434,7 +8451,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
 {
        struct cfs_rq *cfs_rq;
        struct sched_entity *se;
-       struct rq *rq;
        int i;
 
        tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL);
@@ -8447,8 +8463,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
        tg->shares = NICE_0_LOAD;
 
        for_each_possible_cpu(i) {
-               rq = cpu_rq(i);
-
                cfs_rq = kzalloc_node(sizeof(struct cfs_rq),
                                      GFP_KERNEL, cpu_to_node(i));
                if (!cfs_rq)
index c82f26c1b7c358b6c06fc35eddc079c6aacf31bb..a776a6396427c4ea4347b2a3e814d2d61cf69bf8 100644 (file)
@@ -94,6 +94,4 @@ static const struct sched_class idle_sched_class = {
 
        .prio_changed           = prio_changed_idle,
        .switched_to            = switched_to_idle,
-
-       /* no .task_new for idle tasks */
 };
index 84ec9bcf82d92758021f6b398bceee83bb0d0d0c..1ba2bd40fdacf3f89e0b71f0f8c1020c0151a05c 100644 (file)
@@ -102,6 +102,4 @@ static const struct sched_class stop_sched_class = {
 
        .prio_changed           = prio_changed_stop,
        .switched_to            = switched_to_stop,
-
-       /* no .task_new for stop tasks */
 };
index 4e3cff10fdceda165e8e9f22c0e9b861dba918d8..324eff5468ad6c1a07ee0d43d6d4dffc301de9ac 100644 (file)
@@ -635,6 +635,27 @@ static inline bool si_fromuser(const struct siginfo *info)
                (!is_si_special(info) && SI_FROMUSER(info));
 }
 
+/*
+ * called with RCU read lock from check_kill_permission()
+ */
+static int kill_ok_by_cred(struct task_struct *t)
+{
+       const struct cred *cred = current_cred();
+       const struct cred *tcred = __task_cred(t);
+
+       if (cred->user->user_ns == tcred->user->user_ns &&
+           (cred->euid == tcred->suid ||
+            cred->euid == tcred->uid ||
+            cred->uid  == tcred->suid ||
+            cred->uid  == tcred->uid))
+               return 1;
+
+       if (ns_capable(tcred->user->user_ns, CAP_KILL))
+               return 1;
+
+       return 0;
+}
+
 /*
  * Bad permissions for sending the signal
  * - the caller must hold the RCU read lock
@@ -642,7 +663,6 @@ static inline bool si_fromuser(const struct siginfo *info)
 static int check_kill_permission(int sig, struct siginfo *info,
                                 struct task_struct *t)
 {
-       const struct cred *cred, *tcred;
        struct pid *sid;
        int error;
 
@@ -656,14 +676,8 @@ static int check_kill_permission(int sig, struct siginfo *info,
        if (error)
                return error;
 
-       cred = current_cred();
-       tcred = __task_cred(t);
        if (!same_thread_group(current, t) &&
-           (cred->euid ^ tcred->suid) &&
-           (cred->euid ^ tcred->uid) &&
-           (cred->uid  ^ tcred->suid) &&
-           (cred->uid  ^ tcred->uid) &&
-           !capable(CAP_KILL)) {
+           !kill_ok_by_cred(t)) {
                switch (sig) {
                case SIGCONT:
                        sid = task_session(t);
@@ -2421,9 +2435,13 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
                return -EFAULT;
 
        /* Not even root can pretend to send signals from the kernel.
-          Nor can they impersonate a kill(), which adds source info.  */
-       if (info.si_code >= 0)
+        * Nor can they impersonate a kill()/tgkill(), which adds source info.
+        */
+       if (info.si_code != SI_QUEUE) {
+               /* We used to allow any < 0 si_code */
+               WARN_ON_ONCE(info.si_code < 0);
                return -EPERM;
+       }
        info.si_signo = sig;
 
        /* POSIX.1b doesn't mention process groups.  */
@@ -2437,9 +2455,13 @@ long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
                return -EINVAL;
 
        /* Not even root can pretend to send signals from the kernel.
-          Nor can they impersonate a kill(), which adds source info.  */
-       if (info->si_code >= 0)
+        * Nor can they impersonate a kill()/tgkill(), which adds source info.
+        */
+       if (info->si_code != SI_QUEUE) {
+               /* We used to allow any < 0 si_code */
+               WARN_ON_ONCE(info->si_code < 0);
                return -EPERM;
+       }
        info->si_signo = sig;
 
        return do_send_specific(tgid, pid, sig, info);
index 7cbd0f293df4484682e18ae637cc5cbcd2ba87ba..73a1951935581f48915d77e8409a3049b78de8df 100644 (file)
@@ -604,6 +604,87 @@ void ipi_call_unlock_irq(void)
 }
 #endif /* USE_GENERIC_SMP_HELPERS */
 
+/* Setup configured maximum number of CPUs to activate */
+unsigned int setup_max_cpus = NR_CPUS;
+EXPORT_SYMBOL(setup_max_cpus);
+
+
+/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ * activation entirely (the MPS table probe still happens, though).
+ *
+ * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ * greater than 0, limits the maximum number of CPUs activated in
+ * SMP mode to <NUM>.
+ */
+
+void __weak arch_disable_smp_support(void) { }
+
+static int __init nosmp(char *str)
+{
+       setup_max_cpus = 0;
+       arch_disable_smp_support();
+
+       return 0;
+}
+
+early_param("nosmp", nosmp);
+
+/* this is hard limit */
+static int __init nrcpus(char *str)
+{
+       int nr_cpus;
+
+       get_option(&str, &nr_cpus);
+       if (nr_cpus > 0 && nr_cpus < nr_cpu_ids)
+               nr_cpu_ids = nr_cpus;
+
+       return 0;
+}
+
+early_param("nr_cpus", nrcpus);
+
+static int __init maxcpus(char *str)
+{
+       get_option(&str, &setup_max_cpus);
+       if (setup_max_cpus == 0)
+               arch_disable_smp_support();
+
+       return 0;
+}
+
+early_param("maxcpus", maxcpus);
+
+/* Setup number of possible processor ids */
+int nr_cpu_ids __read_mostly = NR_CPUS;
+EXPORT_SYMBOL(nr_cpu_ids);
+
+/* An arch may set nr_cpu_ids earlier if needed, so this would be redundant */
+void __init setup_nr_cpu_ids(void)
+{
+       nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
+}
+
+/* Called by boot processor to activate the rest. */
+void __init smp_init(void)
+{
+       unsigned int cpu;
+
+       /* FIXME: This should be done in userspace --RR */
+       for_each_present_cpu(cpu) {
+               if (num_online_cpus() >= setup_max_cpus)
+                       break;
+               if (!cpu_online(cpu))
+                       cpu_up(cpu);
+       }
+
+       /* Any cleanup work */
+       printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus());
+       smp_cpus_done(setup_max_cpus);
+}
+
 /*
  * Call a function on all processors.  May be used during early boot while
  * early_boot_irqs_disabled is set.  Use local_irq_save/restore() instead
index 56e5dec837f05bd28f90221e2f0b666af23378c9..735d8709517228195b8a95f737bf555e7de712c3 100644 (file)
@@ -845,7 +845,10 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               p = kthread_create(run_ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
+               p = kthread_create_on_node(run_ksoftirqd,
+                                          hcpu,
+                                          cpu_to_node(hotcpu),
+                                          "ksoftirqd/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk("ksoftirqd for %i failed\n", hotcpu);
                        return notifier_from_errno(PTR_ERR(p));
index 2df820b03beb17499afccd6c3acc59e08bfd0194..e3516b29076cc38763a99c3584a02b8544f7b5d4 100644 (file)
@@ -301,8 +301,10 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
        case CPU_UP_PREPARE:
                BUG_ON(stopper->thread || stopper->enabled ||
                       !list_empty(&stopper->works));
-               p = kthread_create(cpu_stopper_thread, stopper, "migration/%d",
-                                  cpu);
+               p = kthread_create_on_node(cpu_stopper_thread,
+                                          stopper,
+                                          cpu_to_node(cpu),
+                                          "migration/%d", cpu);
                if (IS_ERR(p))
                        return notifier_from_errno(PTR_ERR(p));
                get_task_struct(p);
index 1ad48b3b9068ff7454d753c7e36e844ab507afd8..af468edf096a4dc11763dd202dd6e44ee01f07ef 100644 (file)
@@ -119,17 +119,34 @@ EXPORT_SYMBOL(cad_pid);
 
 void (*pm_power_off_prepare)(void);
 
+/*
+ * Returns true if current's euid is same as p's uid or euid,
+ * or has CAP_SYS_NICE to p's user_ns.
+ *
+ * Called with rcu_read_lock, creds are safe
+ */
+static bool set_one_prio_perm(struct task_struct *p)
+{
+       const struct cred *cred = current_cred(), *pcred = __task_cred(p);
+
+       if (pcred->user->user_ns == cred->user->user_ns &&
+           (pcred->uid  == cred->euid ||
+            pcred->euid == cred->euid))
+               return true;
+       if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
+               return true;
+       return false;
+}
+
 /*
  * set the priority of a task
  * - the caller must hold the RCU read lock
  */
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
-       const struct cred *cred = current_cred(), *pcred = __task_cred(p);
        int no_nice;
 
-       if (pcred->uid  != cred->euid &&
-           pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
+       if (!set_one_prio_perm(p)) {
                error = -EPERM;
                goto out;
        }
@@ -506,7 +523,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
        if (rgid != (gid_t) -1) {
                if (old->gid == rgid ||
                    old->egid == rgid ||
-                   capable(CAP_SETGID))
+                   nsown_capable(CAP_SETGID))
                        new->gid = rgid;
                else
                        goto error;
@@ -515,7 +532,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
                if (old->gid == egid ||
                    old->egid == egid ||
                    old->sgid == egid ||
-                   capable(CAP_SETGID))
+                   nsown_capable(CAP_SETGID))
                        new->egid = egid;
                else
                        goto error;
@@ -550,7 +567,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
        old = current_cred();
 
        retval = -EPERM;
-       if (capable(CAP_SETGID))
+       if (nsown_capable(CAP_SETGID))
                new->gid = new->egid = new->sgid = new->fsgid = gid;
        else if (gid == old->gid || gid == old->sgid)
                new->egid = new->fsgid = gid;
@@ -617,7 +634,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                new->uid = ruid;
                if (old->uid != ruid &&
                    old->euid != ruid &&
-                   !capable(CAP_SETUID))
+                   !nsown_capable(CAP_SETUID))
                        goto error;
        }
 
@@ -626,7 +643,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                if (old->uid != euid &&
                    old->euid != euid &&
                    old->suid != euid &&
-                   !capable(CAP_SETUID))
+                   !nsown_capable(CAP_SETUID))
                        goto error;
        }
 
@@ -674,7 +691,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
        old = current_cred();
 
        retval = -EPERM;
-       if (capable(CAP_SETUID)) {
+       if (nsown_capable(CAP_SETUID)) {
                new->suid = new->uid = uid;
                if (uid != old->uid) {
                        retval = set_user(new);
@@ -716,7 +733,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
        old = current_cred();
 
        retval = -EPERM;
-       if (!capable(CAP_SETUID)) {
+       if (!nsown_capable(CAP_SETUID)) {
                if (ruid != (uid_t) -1 && ruid != old->uid &&
                    ruid != old->euid  && ruid != old->suid)
                        goto error;
@@ -780,7 +797,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
        old = current_cred();
 
        retval = -EPERM;
-       if (!capable(CAP_SETGID)) {
+       if (!nsown_capable(CAP_SETGID)) {
                if (rgid != (gid_t) -1 && rgid != old->gid &&
                    rgid != old->egid  && rgid != old->sgid)
                        goto error;
@@ -840,7 +857,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
 
        if (uid == old->uid  || uid == old->euid  ||
            uid == old->suid || uid == old->fsuid ||
-           capable(CAP_SETUID)) {
+           nsown_capable(CAP_SETUID)) {
                if (uid != old_fsuid) {
                        new->fsuid = uid;
                        if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
@@ -873,7 +890,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
 
        if (gid == old->gid  || gid == old->egid  ||
            gid == old->sgid || gid == old->fsgid ||
-           capable(CAP_SETGID)) {
+           nsown_capable(CAP_SETGID)) {
                if (gid != old_fsgid) {
                        new->fsgid = gid;
                        goto change_okay;
@@ -1181,8 +1198,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
        int errno;
        char tmp[__NEW_UTS_LEN];
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
                return -EPERM;
+
        if (len < 0 || len > __NEW_UTS_LEN)
                return -EINVAL;
        down_write(&uts_sem);
@@ -1230,7 +1248,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
        int errno;
        char tmp[__NEW_UTS_LEN];
 
-       if (!capable(CAP_SYS_ADMIN))
+       if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
                return -EPERM;
        if (len < 0 || len > __NEW_UTS_LEN)
                return -EINVAL;
@@ -1345,6 +1363,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource,
        rlim = tsk->signal->rlim + resource;
        task_lock(tsk->group_leader);
        if (new_rlim) {
+               /* Keep the capable check against init_user_ns until
+                  cgroups can contain all limits */
                if (new_rlim->rlim_max > rlim->rlim_max &&
                                !capable(CAP_SYS_RESOURCE))
                        retval = -EPERM;
@@ -1388,19 +1408,22 @@ static int check_prlimit_permission(struct task_struct *task)
 {
        const struct cred *cred = current_cred(), *tcred;
 
-       tcred = __task_cred(task);
-       if (current != task &&
-           (cred->uid != tcred->euid ||
-            cred->uid != tcred->suid ||
-            cred->uid != tcred->uid  ||
-            cred->gid != tcred->egid ||
-            cred->gid != tcred->sgid ||
-            cred->gid != tcred->gid) &&
-            !capable(CAP_SYS_RESOURCE)) {
-               return -EPERM;
-       }
+       if (current == task)
+               return 0;
 
-       return 0;
+       tcred = __task_cred(task);
+       if (cred->user->user_ns == tcred->user->user_ns &&
+           (cred->uid == tcred->euid &&
+            cred->uid == tcred->suid &&
+            cred->uid == tcred->uid  &&
+            cred->gid == tcred->egid &&
+            cred->gid == tcred->sgid &&
+            cred->gid == tcred->gid))
+               return 0;
+       if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
+               return 0;
+
+       return -EPERM;
 }
 
 SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource,
index 40245d697602be1965ab763bf7dc7798a03b960b..c0bb32414b174d575f836c9eb779f2e30cb793dd 100644 (file)
@@ -117,6 +117,7 @@ static int neg_one = -1;
 static int zero;
 static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
+static int __maybe_unused three = 3;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
 #ifdef CONFIG_PRINTK
@@ -169,6 +170,11 @@ static int proc_taint(struct ctl_table *table, int write,
                               void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
+#ifdef CONFIG_PRINTK
+static int proc_dmesg_restrict(struct ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp, loff_t *ppos);
+#endif
+
 #ifdef CONFIG_MAGIC_SYSRQ
 /* Note: sysrq code uses it's own private copy */
 static int __sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
@@ -706,7 +712,7 @@ static struct ctl_table kern_table[] = {
                .data           = &kptr_restrict,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
+               .proc_handler   = proc_dmesg_restrict,
                .extra1         = &zero,
                .extra2         = &two,
        },
@@ -971,14 +977,18 @@ static struct ctl_table vm_table[] = {
                .data           = &sysctl_overcommit_memory,
                .maxlen         = sizeof(sysctl_overcommit_memory),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &two,
        },
        {
                .procname       = "panic_on_oom",
                .data           = &sysctl_panic_on_oom,
                .maxlen         = sizeof(sysctl_panic_on_oom),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &two,
        },
        {
                .procname       = "oom_kill_allocating_task",
@@ -1006,7 +1016,8 @@ static struct ctl_table vm_table[] = {
                .data           = &page_cluster,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
        },
        {
                .procname       = "dirty_background_ratio",
@@ -1054,7 +1065,8 @@ static struct ctl_table vm_table[] = {
                .data           = &dirty_expire_interval,
                .maxlen         = sizeof(dirty_expire_interval),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
        },
        {
                .procname       = "nr_pdflush_threads",
@@ -1130,6 +1142,8 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = drop_caches_sysctl_handler,
+               .extra1         = &one,
+               .extra2         = &three,
        },
 #ifdef CONFIG_COMPACTION
        {
@@ -2385,6 +2399,17 @@ static int proc_taint(struct ctl_table *table, int write,
        return err;
 }
 
+#ifdef CONFIG_PRINTK
+static int proc_dmesg_restrict(struct ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       if (write && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+}
+#endif
+
 struct do_proc_dointvec_minmax_conv_param {
        int *min;
        int *max;
index 10b90d8a03c48678258c6aaf3de353af7b06ed36..4e4932a7b3608ac6e32175ee87481c1ac47a3572 100644 (file)
@@ -111,11 +111,9 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
                const char *fail = NULL;
 
                if (table->parent) {
-                       if (table->procname && !table->parent->procname)
+                       if (!table->parent->procname)
                                set_fail(&fail, table, "Parent without procname");
                }
-               if (!table->procname)
-                       set_fail(&fail, table, "No procname");
                if (table->child) {
                        if (table->data)
                                set_fail(&fail, table, "Directory with data?");
@@ -144,12 +142,8 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
                                        set_fail(&fail, table, "No maxlen");
                        }
 #ifdef CONFIG_PROC_SYSCTL
-                       if (table->procname && !table->proc_handler)
+                       if (!table->proc_handler)
                                set_fail(&fail, table, "No proc_handler");
-#endif
-#if 0
-                       if (!table->procname && table->proc_handler)
-                               set_fail(&fail, table, "proc_handler without procname");
 #endif
                        sysctl_check_leaf(namespaces, table, &fail);
                }
index 3971c6b9d58db668c029365a1120506dda3179d8..9ffea360a778a3ebf2890fdff5c1b79ddc5542c6 100644 (file)
@@ -685,7 +685,7 @@ static int __init taskstats_init(void)
                goto err_cgroup_ops;
 
        family_registered = 1;
-       printk("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
+       pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
        return 0;
 err_cgroup_ops:
        genl_unregister_ops(&family, &taskstats_ops);
index cbafed7d4f386c77816abb4ffe9d7141af29f446..7aa40f8e182d569bcba8c0a3f33bb0f73b6f4950 100644 (file)
@@ -703,28 +703,21 @@ void blk_trace_shutdown(struct request_queue *q)
  *
  **/
 static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
-                                   u32 what)
+                            u32 what)
 {
        struct blk_trace *bt = q->blk_trace;
-       int rw = rq->cmd_flags & 0x03;
 
        if (likely(!bt))
                return;
 
-       if (rq->cmd_flags & REQ_DISCARD)
-               rw |= REQ_DISCARD;
-
-       if (rq->cmd_flags & REQ_SECURE)
-               rw |= REQ_SECURE;
-
        if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
                what |= BLK_TC_ACT(BLK_TC_PC);
-               __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw,
+               __blk_add_trace(bt, 0, blk_rq_bytes(rq), rq->cmd_flags,
                                what, rq->errors, rq->cmd_len, rq->cmd);
        } else  {
                what |= BLK_TC_ACT(BLK_TC_FS);
-               __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rw,
-                               what, rq->errors, 0, NULL);
+               __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
+                               rq->cmd_flags, what, rq->errors, 0, NULL);
        }
 }
 
index 888b611897d3737fddb0c890084cacfbe2a359b3..c075f4ea6b94f1c9772915b064082341d843e9d5 100644 (file)
@@ -1467,7 +1467,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                return t_hash_next(m, pos);
 
        (*pos)++;
-       iter->pos = *pos;
+       iter->pos = iter->func_pos = *pos;
 
        if (iter->flags & FTRACE_ITER_PRINTALL)
                return t_hash_start(m, pos);
@@ -1502,7 +1502,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
        if (!rec)
                return t_hash_start(m, pos);
 
-       iter->func_pos = *pos;
        iter->func = rec;
 
        return iter;
index 419209893d87b528488203ea258a39021fd70ad3..51c6e89e8619a56e28949d26f7f7053b5d32b5af 100644 (file)
@@ -189,7 +189,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!capable(CAP_SETGID))
+       if (!nsown_capable(CAP_SETGID))
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
index 5c598ca781df4bf6f907043ed1d43f98b3b7ef58..9e03e9c1df8d47fb7242125a6ac3b848d71ca801 100644 (file)
 #include <linux/module.h>
 #include <linux/user_namespace.h>
 
+/*
+ * userns count is 1 for root user, 1 for init_uts_ns,
+ * and 1 for... ?
+ */
 struct user_namespace init_user_ns = {
        .kref = {
-               .refcount       = ATOMIC_INIT(2),
+               .refcount       = ATOMIC_INIT(3),
        },
        .creator = &root_user,
 };
@@ -47,7 +51,7 @@ static struct kmem_cache *uid_cachep;
  */
 static DEFINE_SPINLOCK(uidhash_lock);
 
-/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */
+/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->user_ns */
 struct user_struct root_user = {
        .__count        = ATOMIC_INIT(2),
        .processes      = ATOMIC_INIT(1),
index 8a82b4b8ea52cb3690e25bf039eaf32ff5c8c079..44646179eabae8e8fd848174869f7d1782c90be8 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/utsname.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/user_namespace.h>
 
 static struct uts_namespace *create_uts_ns(void)
 {
@@ -30,7 +31,8 @@ static struct uts_namespace *create_uts_ns(void)
  * @old_ns: namespace to clone
  * Return NULL on error (failure to kmalloc), new ns otherwise
  */
-static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
+static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
+                                         struct uts_namespace *old_ns)
 {
        struct uts_namespace *ns;
 
@@ -40,6 +42,7 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
 
        down_read(&uts_sem);
        memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
+       ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
        up_read(&uts_sem);
        return ns;
 }
@@ -50,8 +53,10 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
  * utsname of this process won't be seen by parent, and vice
  * versa.
  */
-struct uts_namespace *copy_utsname(unsigned long flags, struct uts_namespace *old_ns)
+struct uts_namespace *copy_utsname(unsigned long flags,
+                                  struct task_struct *tsk)
 {
+       struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
        struct uts_namespace *new_ns;
 
        BUG_ON(!old_ns);
@@ -60,7 +65,7 @@ struct uts_namespace *copy_utsname(unsigned long flags, struct uts_namespace *ol
        if (!(flags & CLONE_NEWUTS))
                return old_ns;
 
-       new_ns = clone_uts_ns(old_ns);
+       new_ns = clone_uts_ns(tsk, old_ns);
 
        put_uts_ns(old_ns);
        return new_ns;
@@ -71,5 +76,6 @@ void free_uts_ns(struct kref *kref)
        struct uts_namespace *ns;
 
        ns = container_of(kref, struct uts_namespace, kref);
+       put_user_ns(ns->user_ns);
        kfree(ns);
 }
index 18bb15776c57162b60675adf69e7afd765b34fb0..140dce750450edc8db5285817c26fd354ec0c56a 100644 (file)
@@ -48,12 +48,15 @@ static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
  * Should we panic when a soft-lockup or hard-lockup occurs:
  */
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
-static int hardlockup_panic;
+static int hardlockup_panic =
+                       CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
 
 static int __init hardlockup_panic_setup(char *str)
 {
        if (!strncmp(str, "panic", 5))
                hardlockup_panic = 1;
+       else if (!strncmp(str, "nopanic", 7))
+               hardlockup_panic = 0;
        else if (!strncmp(str, "0", 1))
                watchdog_enabled = 0;
        return 1;
@@ -415,19 +418,22 @@ static int watchdog_prepare_cpu(int cpu)
 static int watchdog_enable(int cpu)
 {
        struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
-       int err;
+       int err = 0;
 
        /* enable the perf event */
        err = watchdog_nmi_enable(cpu);
-       if (err)
-               return err;
+
+       /* Regardless of err above, fall through and start softlockup */
 
        /* create the watchdog thread */
        if (!p) {
                p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
                if (IS_ERR(p)) {
                        printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
-                       return PTR_ERR(p);
+                       if (!err)
+                               /* if hardlockup hasn't already set this */
+                               err = PTR_ERR(p);
+                       goto out;
                }
                kthread_bind(p, cpu);
                per_cpu(watchdog_touch_ts, cpu) = 0;
@@ -435,7 +441,8 @@ static int watchdog_enable(int cpu)
                wake_up_process(p);
        }
 
-       return 0;
+out:
+       return err;
 }
 
 static void watchdog_disable(int cpu)
@@ -547,7 +554,13 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
 #endif /* CONFIG_HOTPLUG_CPU */
        }
-       return notifier_from_errno(err);
+
+       /*
+        * hardlockup and softlockup are not important enough
+        * to block cpu bring up.  Just always succeed and
+        * rely on printk output to flag problems.
+        */
+       return NOTIFY_OK;
 }
 
 static struct notifier_block __cpuinitdata cpu_nfb = {
index 5ca7ce9ce754d5bc66ccea708dea458885d0f86a..04ef830690eceea974d90add3de55b57bc4048f6 100644 (file)
@@ -1366,8 +1366,10 @@ static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
        worker->id = id;
 
        if (!on_unbound_cpu)
-               worker->task = kthread_create(worker_thread, worker,
-                                             "kworker/%u:%d", gcwq->cpu, id);
+               worker->task = kthread_create_on_node(worker_thread,
+                                                     worker,
+                                                     cpu_to_node(gcwq->cpu),
+                                                     "kworker/%u:%d", gcwq->cpu, id);
        else
                worker->task = kthread_create(worker_thread, worker,
                                              "kworker/u:%d", id);
index 3a55a43c43ebb2dce87b15bf0a8bf2579cea1c84..23fa7a359db74008cbbb7d17599edcd480d76a97 100644 (file)
@@ -22,6 +22,9 @@ config GENERIC_FIND_FIRST_BIT
 config GENERIC_FIND_NEXT_BIT
        bool
 
+config GENERIC_FIND_BIT_LE
+       bool
+
 config GENERIC_FIND_LAST_BIT
        bool
        default y
index 6f440d82b58db05e63d3a2ff9e32918e74974ebc..df9234c5f9d1c003a4b93e71df13248edba836a9 100644 (file)
@@ -9,6 +9,17 @@ config PRINTK_TIME
          operations.  This is useful for identifying long delays
          in kernel startup.
 
+config DEFAULT_MESSAGE_LOGLEVEL
+       int "Default message log level (1-7)"
+       range 1 7
+       default "4"
+       help
+         Default log level for printk statements with no specified priority.
+
+         This was hard-coded to KERN_WARNING since at least 2.6.10 but folks
+         that are auditing their logs closely may want to set it to a lower
+         priority.
+
 config ENABLE_WARN_DEPRECATED
        bool "Enable __deprecated logic"
        default y
@@ -102,11 +113,6 @@ config HEADERS_CHECK
 
 config DEBUG_SECTION_MISMATCH
        bool "Enable full Section mismatch analysis"
-       depends on UNDEFINED || (BLACKFIN)
-       default y
-       # This option is on purpose disabled for now.
-       # It will be enabled when we are down to a reasonable number
-       # of section mismatch warnings (< 10 for an allyesconfig build)
        help
          The section mismatch analysis checks if there are illegal
          references from one section to another section.
@@ -176,6 +182,23 @@ config HARDLOCKUP_DETECTOR
        def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \
                 !ARCH_HAS_NMI_WATCHDOG
 
+config BOOTPARAM_HARDLOCKUP_PANIC
+       bool "Panic (Reboot) On Hard Lockups"
+       depends on LOCKUP_DETECTOR
+       help
+         Say Y here to enable the kernel to panic on "hard lockups",
+         which are bugs that cause the kernel to loop in kernel
+         mode with interrupts disabled for more than 60 seconds.
+
+         Say N if unsure.
+
+config BOOTPARAM_HARDLOCKUP_PANIC_VALUE
+       int
+       depends on LOCKUP_DETECTOR
+       range 0 1
+       default 0 if !BOOTPARAM_HARDLOCKUP_PANIC
+       default 1 if BOOTPARAM_HARDLOCKUP_PANIC
+
 config BOOTPARAM_SOFTLOCKUP_PANIC
        bool "Panic (Reboot) On Soft Lockups"
        depends on LOCKUP_DETECTOR
@@ -1227,3 +1250,6 @@ source "samples/Kconfig"
 source "lib/Kconfig.kgdb"
 
 source "lib/Kconfig.kmemcheck"
+
+config TEST_KSTRTOX
+       tristate "Test kstrto*() family of functions at runtime"
index ef7ed71a6ffde56e3739ecb78372d8b55a92e951..d7872b5c4c1c375d92b5dd7468636a132932ca8f 100644 (file)
@@ -22,6 +22,8 @@ lib-y += kobject.o kref.o klist.o
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
         string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o
+obj-y += kstrtox.o
+obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
@@ -38,6 +40,7 @@ lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
 lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
+lib-$(CONFIG_GENERIC_FIND_BIT_LE) += find_next_bit.o
 obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o
 
 CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
index 24c59ded47a05d5617e2fe2501077f990de1ec4b..b0a8767282bf674fe980f17b5d192103e5ffc4f5 100644 (file)
@@ -160,6 +160,7 @@ EXPORT_SYMBOL(find_first_zero_bit);
 #endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
 
 #ifdef __BIG_ENDIAN
+#ifdef CONFIG_GENERIC_FIND_BIT_LE
 
 /* include/linux/byteorder does not support "unsigned long" type */
 static inline unsigned long ext2_swabp(const unsigned long * x)
@@ -185,15 +186,16 @@ static inline unsigned long ext2_swab(const unsigned long y)
 #endif
 }
 
-unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
+unsigned long find_next_zero_bit_le(const void *addr, unsigned
                long size, unsigned long offset)
 {
-       const unsigned long *p = addr + BITOP_WORD(offset);
+       const unsigned long *p = addr;
        unsigned long result = offset & ~(BITS_PER_LONG - 1);
        unsigned long tmp;
 
        if (offset >= size)
                return size;
+       p += BITOP_WORD(offset);
        size -= result;
        offset &= (BITS_PER_LONG - 1UL);
        if (offset) {
@@ -226,18 +228,18 @@ found_middle:
 found_middle_swap:
        return result + ffz(ext2_swab(tmp));
 }
+EXPORT_SYMBOL(find_next_zero_bit_le);
 
-EXPORT_SYMBOL(generic_find_next_zero_le_bit);
-
-unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
+unsigned long find_next_bit_le(const void *addr, unsigned
                long size, unsigned long offset)
 {
-       const unsigned long *p = addr + BITOP_WORD(offset);
+       const unsigned long *p = addr;
        unsigned long result = offset & ~(BITS_PER_LONG - 1);
        unsigned long tmp;
 
        if (offset >= size)
                return size;
+       p += BITOP_WORD(offset);
        size -= result;
        offset &= (BITS_PER_LONG - 1UL);
        if (offset) {
@@ -271,5 +273,7 @@ found_middle:
 found_middle_swap:
        return result + __ffs(ext2_swab(tmp));
 }
-EXPORT_SYMBOL(generic_find_next_le_bit);
+EXPORT_SYMBOL(find_next_bit_le);
+
+#endif /* CONFIG_GENERIC_FIND_BIT_LE */
 #endif /* __BIG_ENDIAN */
diff --git a/lib/kstrtox.c b/lib/kstrtox.c
new file mode 100644 (file)
index 0000000..05672e8
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Convert integer string representation to an integer.
+ * If an integer doesn't fit into specified type, -E is returned.
+ *
+ * Integer starts with optional sign.
+ * kstrtou*() functions do not accept sign "-".
+ *
+ * Radix 0 means autodetection: leading "0x" implies radix 16,
+ * leading "0" implies radix 8, otherwise radix is 10.
+ * Autodetection hints work after optional sign, but not before.
+ *
+ * If -E is returned, result is not touched.
+ */
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+static inline char _tolower(const char c)
+{
+       return c | 0x20;
+}
+
+static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+       unsigned long long acc;
+       int ok;
+
+       if (base == 0) {
+               if (s[0] == '0') {
+                       if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
+                               base = 16;
+                       else
+                               base = 8;
+               } else
+                       base = 10;
+       }
+       if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
+               s += 2;
+
+       acc = 0;
+       ok = 0;
+       while (*s) {
+               unsigned int val;
+
+               if ('0' <= *s && *s <= '9')
+                       val = *s - '0';
+               else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f')
+                       val = _tolower(*s) - 'a' + 10;
+               else if (*s == '\n') {
+                       if (*(s + 1) == '\0')
+                               break;
+                       else
+                               return -EINVAL;
+               } else
+                       return -EINVAL;
+
+               if (val >= base)
+                       return -EINVAL;
+               if (acc > div_u64(ULLONG_MAX - val, base))
+                       return -ERANGE;
+               acc = acc * base + val;
+               ok = 1;
+
+               s++;
+       }
+       if (!ok)
+               return -EINVAL;
+       *res = acc;
+       return 0;
+}
+
+int kstrtoull(const char *s, unsigned int base, unsigned long long *res)
+{
+       if (s[0] == '+')
+               s++;
+       return _kstrtoull(s, base, res);
+}
+EXPORT_SYMBOL(kstrtoull);
+
+int kstrtoll(const char *s, unsigned int base, long long *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       if (s[0] == '-') {
+               rv = _kstrtoull(s + 1, base, &tmp);
+               if (rv < 0)
+                       return rv;
+               if ((long long)(-tmp) >= 0)
+                       return -ERANGE;
+               *res = -tmp;
+       } else {
+               rv = kstrtoull(s, base, &tmp);
+               if (rv < 0)
+                       return rv;
+               if ((long long)tmp < 0)
+                       return -ERANGE;
+               *res = tmp;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(kstrtoll);
+
+/* Internal, do not use. */
+int _kstrtoul(const char *s, unsigned int base, unsigned long *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(unsigned long)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(_kstrtoul);
+
+/* Internal, do not use. */
+int _kstrtol(const char *s, unsigned int base, long *res)
+{
+       long long tmp;
+       int rv;
+
+       rv = kstrtoll(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (long long)(long)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(_kstrtol);
+
+int kstrtouint(const char *s, unsigned int base, unsigned int *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(unsigned int)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtouint);
+
+int kstrtoint(const char *s, unsigned int base, int *res)
+{
+       long long tmp;
+       int rv;
+
+       rv = kstrtoll(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (long long)(int)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtoint);
+
+int kstrtou16(const char *s, unsigned int base, u16 *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(u16)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtou16);
+
+int kstrtos16(const char *s, unsigned int base, s16 *res)
+{
+       long long tmp;
+       int rv;
+
+       rv = kstrtoll(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (long long)(s16)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtos16);
+
+int kstrtou8(const char *s, unsigned int base, u8 *res)
+{
+       unsigned long long tmp;
+       int rv;
+
+       rv = kstrtoull(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (unsigned long long)(u8)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtou8);
+
+int kstrtos8(const char *s, unsigned int base, s8 *res)
+{
+       long long tmp;
+       int rv;
+
+       rv = kstrtoll(s, base, &tmp);
+       if (rv < 0)
+               return rv;
+       if (tmp != (long long)(s8)tmp)
+               return -ERANGE;
+       *res = tmp;
+       return 0;
+}
+EXPORT_SYMBOL(kstrtos8);
index fdc77c82f922a2078778c422454d9da83253f08f..90cbe4bb5960fc480eaf45273638159ac48d2aa7 100644 (file)
@@ -9,14 +9,14 @@
 #include <linux/nmi.h>
 #include <linux/quicklist.h>
 
-void show_mem(void)
+void show_mem(unsigned int filter)
 {
        pg_data_t *pgdat;
        unsigned long total = 0, reserved = 0, shared = 0,
                nonshared = 0, highmem = 0;
 
        printk("Mem-Info:\n");
-       show_free_areas();
+       __show_free_areas(filter);
 
        for_each_online_pgdat(pgdat) {
                unsigned long i, flags;
diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c
new file mode 100644 (file)
index 0000000..325c2f9
--- /dev/null
@@ -0,0 +1,739 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define for_each_test(i, test) \
+       for (i = 0; i < sizeof(test) / sizeof(test[0]); i++)
+
+struct test_fail {
+       const char *str;
+       unsigned int base;
+};
+
+#define DEFINE_TEST_FAIL(test) \
+       const struct test_fail test[] __initdata
+
+#define DECLARE_TEST_OK(type, test_type)       \
+       test_type {                             \
+               const char *str;                \
+               unsigned int base;              \
+               type expected_res;              \
+       }
+
+#define DEFINE_TEST_OK(type, test)     \
+       const type test[] __initdata
+
+#define TEST_FAIL(fn, type, fmt, test)                                 \
+{                                                                      \
+       unsigned int i;                                                 \
+                                                                       \
+       for_each_test(i, test) {                                        \
+               const struct test_fail *t = &test[i];                   \
+               type tmp;                                               \
+               int rv;                                                 \
+                                                                       \
+               tmp = 0;                                                \
+               rv = fn(t->str, t->base, &tmp);                         \
+               if (rv >= 0) {                                          \
+                       WARN(1, "str '%s', base %u, expected -E, got %d/" fmt "\n",     \
+                               t->str, t->base, rv, tmp);              \
+                       continue;                                       \
+               }                                                       \
+       }                                                               \
+}
+
+#define TEST_OK(fn, type, fmt, test)                                   \
+{                                                                      \
+       unsigned int i;                                                 \
+                                                                       \
+       for_each_test(i, test) {                                        \
+               const typeof(test[0]) *t = &test[i];                    \
+               type res;                                               \
+               int rv;                                                 \
+                                                                       \
+               rv = fn(t->str, t->base, &res);                         \
+               if (rv != 0) {                                          \
+                       WARN(1, "str '%s', base %u, expected 0/" fmt ", got %d\n",      \
+                               t->str, t->base, t->expected_res, rv);  \
+                       continue;                                       \
+               }                                                       \
+               if (res != t->expected_res) {                           \
+                       WARN(1, "str '%s', base %u, expected " fmt ", got " fmt "\n",   \
+                               t->str, t->base, t->expected_res, res); \
+                       continue;                                       \
+               }                                                       \
+       }                                                               \
+}
+
+static void __init test_kstrtoull_ok(void)
+{
+       DECLARE_TEST_OK(unsigned long long, struct test_ull);
+       static DEFINE_TEST_OK(struct test_ull, test_ull_ok) = {
+               {"0",   10,     0ULL},
+               {"1",   10,     1ULL},
+               {"127", 10,     127ULL},
+               {"128", 10,     128ULL},
+               {"129", 10,     129ULL},
+               {"255", 10,     255ULL},
+               {"256", 10,     256ULL},
+               {"257", 10,     257ULL},
+               {"32767",       10,     32767ULL},
+               {"32768",       10,     32768ULL},
+               {"32769",       10,     32769ULL},
+               {"65535",       10,     65535ULL},
+               {"65536",       10,     65536ULL},
+               {"65537",       10,     65537ULL},
+               {"2147483647",  10,     2147483647ULL},
+               {"2147483648",  10,     2147483648ULL},
+               {"2147483649",  10,     2147483649ULL},
+               {"4294967295",  10,     4294967295ULL},
+               {"4294967296",  10,     4294967296ULL},
+               {"4294967297",  10,     4294967297ULL},
+               {"9223372036854775807", 10,     9223372036854775807ULL},
+               {"9223372036854775808", 10,     9223372036854775808ULL},
+               {"9223372036854775809", 10,     9223372036854775809ULL},
+               {"18446744073709551614",        10,     18446744073709551614ULL},
+               {"18446744073709551615",        10,     18446744073709551615ULL},
+
+               {"00",          8,      00ULL},
+               {"01",          8,      01ULL},
+               {"0177",        8,      0177ULL},
+               {"0200",        8,      0200ULL},
+               {"0201",        8,      0201ULL},
+               {"0377",        8,      0377ULL},
+               {"0400",        8,      0400ULL},
+               {"0401",        8,      0401ULL},
+               {"077777",      8,      077777ULL},
+               {"0100000",     8,      0100000ULL},
+               {"0100001",     8,      0100001ULL},
+               {"0177777",     8,      0177777ULL},
+               {"0200000",     8,      0200000ULL},
+               {"0200001",     8,      0200001ULL},
+               {"017777777777",        8,      017777777777ULL},
+               {"020000000000",        8,      020000000000ULL},
+               {"020000000001",        8,      020000000001ULL},
+               {"037777777777",        8,      037777777777ULL},
+               {"040000000000",        8,      040000000000ULL},
+               {"040000000001",        8,      040000000001ULL},
+               {"0777777777777777777777",      8,      0777777777777777777777ULL},
+               {"01000000000000000000000",     8,      01000000000000000000000ULL},
+               {"01000000000000000000001",     8,      01000000000000000000001ULL},
+               {"01777777777777777777776",     8,      01777777777777777777776ULL},
+               {"01777777777777777777777",     8,      01777777777777777777777ULL},
+
+               {"0x0",         16,     0x0ULL},
+               {"0x1",         16,     0x1ULL},
+               {"0x7f",        16,     0x7fULL},
+               {"0x80",        16,     0x80ULL},
+               {"0x81",        16,     0x81ULL},
+               {"0xff",        16,     0xffULL},
+               {"0x100",       16,     0x100ULL},
+               {"0x101",       16,     0x101ULL},
+               {"0x7fff",      16,     0x7fffULL},
+               {"0x8000",      16,     0x8000ULL},
+               {"0x8001",      16,     0x8001ULL},
+               {"0xffff",      16,     0xffffULL},
+               {"0x10000",     16,     0x10000ULL},
+               {"0x10001",     16,     0x10001ULL},
+               {"0x7fffffff",  16,     0x7fffffffULL},
+               {"0x80000000",  16,     0x80000000ULL},
+               {"0x80000001",  16,     0x80000001ULL},
+               {"0xffffffff",  16,     0xffffffffULL},
+               {"0x100000000", 16,     0x100000000ULL},
+               {"0x100000001", 16,     0x100000001ULL},
+               {"0x7fffffffffffffff",  16,     0x7fffffffffffffffULL},
+               {"0x8000000000000000",  16,     0x8000000000000000ULL},
+               {"0x8000000000000001",  16,     0x8000000000000001ULL},
+               {"0xfffffffffffffffe",  16,     0xfffffffffffffffeULL},
+               {"0xffffffffffffffff",  16,     0xffffffffffffffffULL},
+
+               {"0\n", 0,      0ULL},
+       };
+       TEST_OK(kstrtoull, unsigned long long, "%llu", test_ull_ok);
+}
+
+static void __init test_kstrtoull_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_ull_fail) = {
+               {"",    0},
+               {"",    8},
+               {"",    10},
+               {"",    16},
+               {"\n",  0},
+               {"\n",  8},
+               {"\n",  10},
+               {"\n",  16},
+               {"\n0", 0},
+               {"\n0", 8},
+               {"\n0", 10},
+               {"\n0", 16},
+               {"+",   0},
+               {"+",   8},
+               {"+",   10},
+               {"+",   16},
+               {"-",   0},
+               {"-",   8},
+               {"-",   10},
+               {"-",   16},
+               {"0x",  0},
+               {"0x",  16},
+               {"0X",  0},
+               {"0X",  16},
+               {"0 ",  0},
+               {"1+",  0},
+               {"1-",  0},
+               {" 2",  0},
+               /* base autodetection */
+               {"0x0z",        0},
+               {"0z",          0},
+               {"a",           0},
+               /* digit >= base */
+               {"2",   2},
+               {"8",   8},
+               {"a",   10},
+               {"A",   10},
+               {"g",   16},
+               {"G",   16},
+               /* overflow */
+               {"10000000000000000000000000000000000000000000000000000000000000000",   2},
+               {"2000000000000000000000",      8},
+               {"18446744073709551616",        10},
+               {"10000000000000000",   16},
+               /* negative */
+               {"-0", 0},
+               {"-0", 8},
+               {"-0", 10},
+               {"-0", 16},
+               {"-1", 0},
+               {"-1", 8},
+               {"-1", 10},
+               {"-1", 16},
+               /* sign is first character if any */
+               {"-+1", 0},
+               {"-+1", 8},
+               {"-+1", 10},
+               {"-+1", 16},
+               /* nothing after \n */
+               {"0\n0", 0},
+               {"0\n0", 8},
+               {"0\n0", 10},
+               {"0\n0", 16},
+               {"0\n+", 0},
+               {"0\n+", 8},
+               {"0\n+", 10},
+               {"0\n+", 16},
+               {"0\n-", 0},
+               {"0\n-", 8},
+               {"0\n-", 10},
+               {"0\n-", 16},
+               {"0\n ", 0},
+               {"0\n ", 8},
+               {"0\n ", 10},
+               {"0\n ", 16},
+       };
+       TEST_FAIL(kstrtoull, unsigned long long, "%llu", test_ull_fail);
+}
+
+static void __init test_kstrtoll_ok(void)
+{
+       DECLARE_TEST_OK(long long, struct test_ll);
+       static DEFINE_TEST_OK(struct test_ll, test_ll_ok) = {
+               {"0",   10,     0LL},
+               {"1",   10,     1LL},
+               {"127", 10,     127LL},
+               {"128", 10,     128LL},
+               {"129", 10,     129LL},
+               {"255", 10,     255LL},
+               {"256", 10,     256LL},
+               {"257", 10,     257LL},
+               {"32767",       10,     32767LL},
+               {"32768",       10,     32768LL},
+               {"32769",       10,     32769LL},
+               {"65535",       10,     65535LL},
+               {"65536",       10,     65536LL},
+               {"65537",       10,     65537LL},
+               {"2147483647",  10,     2147483647LL},
+               {"2147483648",  10,     2147483648LL},
+               {"2147483649",  10,     2147483649LL},
+               {"4294967295",  10,     4294967295LL},
+               {"4294967296",  10,     4294967296LL},
+               {"4294967297",  10,     4294967297LL},
+               {"9223372036854775807", 10,     9223372036854775807LL},
+
+               {"-1",  10,     -1LL},
+               {"-2",  10,     -2LL},
+               {"-9223372036854775808",        10,     LLONG_MIN},
+       };
+       TEST_OK(kstrtoll, long long, "%lld", test_ll_ok);
+}
+
+static void __init test_kstrtoll_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_ll_fail) = {
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"-9223372036854775809",        10},
+               {"-18446744073709551614",       10},
+               {"-18446744073709551615",       10},
+               /* negative zero isn't an integer in Linux */
+               {"-0",  0},
+               {"-0",  8},
+               {"-0",  10},
+               {"-0",  16},
+               /* sign is first character if any */
+               {"-+1", 0},
+               {"-+1", 8},
+               {"-+1", 10},
+               {"-+1", 16},
+       };
+       TEST_FAIL(kstrtoll, long long, "%lld", test_ll_fail);
+}
+
+static void __init test_kstrtou64_ok(void)
+{
+       DECLARE_TEST_OK(u64, struct test_u64);
+       static DEFINE_TEST_OK(struct test_u64, test_u64_ok) = {
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+               {"32768",       10,     32768},
+               {"32769",       10,     32769},
+               {"65534",       10,     65534},
+               {"65535",       10,     65535},
+               {"65536",       10,     65536},
+               {"65537",       10,     65537},
+               {"2147483646",  10,     2147483646},
+               {"2147483647",  10,     2147483647},
+               {"2147483648",  10,     2147483648},
+               {"2147483649",  10,     2147483649},
+               {"4294967294",  10,     4294967294},
+               {"4294967295",  10,     4294967295},
+               {"4294967296",  10,     4294967296},
+               {"4294967297",  10,     4294967297},
+               {"9223372036854775806", 10,     9223372036854775806ULL},
+               {"9223372036854775807", 10,     9223372036854775807ULL},
+               {"9223372036854775808", 10,     9223372036854775808ULL},
+               {"9223372036854775809", 10,     9223372036854775809ULL},
+               {"18446744073709551614",        10,     18446744073709551614ULL},
+               {"18446744073709551615",        10,     18446744073709551615ULL},
+       };
+       TEST_OK(kstrtou64, u64, "%llu", test_u64_ok);
+}
+
+static void __init test_kstrtou64_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_u64_fail) = {
+               {"-2",  10},
+               {"-1",  10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtou64, u64, "%llu", test_u64_fail);
+}
+
+static void __init test_kstrtos64_ok(void)
+{
+       DECLARE_TEST_OK(s64, struct test_s64);
+       static DEFINE_TEST_OK(struct test_s64, test_s64_ok) = {
+               {"-128",        10,     -128},
+               {"-127",        10,     -127},
+               {"-1",  10,     -1},
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+               {"32768",       10,     32768},
+               {"32769",       10,     32769},
+               {"65534",       10,     65534},
+               {"65535",       10,     65535},
+               {"65536",       10,     65536},
+               {"65537",       10,     65537},
+               {"2147483646",  10,     2147483646},
+               {"2147483647",  10,     2147483647},
+               {"2147483648",  10,     2147483648},
+               {"2147483649",  10,     2147483649},
+               {"4294967294",  10,     4294967294},
+               {"4294967295",  10,     4294967295},
+               {"4294967296",  10,     4294967296},
+               {"4294967297",  10,     4294967297},
+               {"9223372036854775806", 10,     9223372036854775806LL},
+               {"9223372036854775807", 10,     9223372036854775807LL},
+       };
+       TEST_OK(kstrtos64, s64, "%lld", test_s64_ok);
+}
+
+static void __init test_kstrtos64_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_s64_fail) = {
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtos64, s64, "%lld", test_s64_fail);
+}
+
+static void __init test_kstrtou32_ok(void)
+{
+       DECLARE_TEST_OK(u32, struct test_u32);
+       static DEFINE_TEST_OK(struct test_u32, test_u32_ok) = {
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+               {"32768",       10,     32768},
+               {"32769",       10,     32769},
+               {"65534",       10,     65534},
+               {"65535",       10,     65535},
+               {"65536",       10,     65536},
+               {"65537",       10,     65537},
+               {"2147483646",  10,     2147483646},
+               {"2147483647",  10,     2147483647},
+               {"2147483648",  10,     2147483648},
+               {"2147483649",  10,     2147483649},
+               {"4294967294",  10,     4294967294},
+               {"4294967295",  10,     4294967295},
+       };
+       TEST_OK(kstrtou32, u32, "%u", test_u32_ok);
+}
+
+static void __init test_kstrtou32_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_u32_fail) = {
+               {"-2",  10},
+               {"-1",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtou32, u32, "%u", test_u32_fail);
+}
+
+static void __init test_kstrtos32_ok(void)
+{
+       DECLARE_TEST_OK(s32, struct test_s32);
+       static DEFINE_TEST_OK(struct test_s32, test_s32_ok) = {
+               {"-128",        10,     -128},
+               {"-127",        10,     -127},
+               {"-1",  10,     -1},
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+               {"32768",       10,     32768},
+               {"32769",       10,     32769},
+               {"65534",       10,     65534},
+               {"65535",       10,     65535},
+               {"65536",       10,     65536},
+               {"65537",       10,     65537},
+               {"2147483646",  10,     2147483646},
+               {"2147483647",  10,     2147483647},
+       };
+       TEST_OK(kstrtos32, s32, "%d", test_s32_ok);
+}
+
+static void __init test_kstrtos32_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_s32_fail) = {
+               {"2147483648",  10},
+               {"2147483649",  10},
+               {"4294967294",  10},
+               {"4294967295",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtos32, s32, "%d", test_s32_fail);
+}
+
+static void __init test_kstrtou16_ok(void)
+{
+       DECLARE_TEST_OK(u16, struct test_u16);
+       static DEFINE_TEST_OK(struct test_u16, test_u16_ok) = {
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+               {"32768",       10,     32768},
+               {"32769",       10,     32769},
+               {"65534",       10,     65534},
+               {"65535",       10,     65535},
+       };
+       TEST_OK(kstrtou16, u16, "%hu", test_u16_ok);
+}
+
+static void __init test_kstrtou16_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_u16_fail) = {
+               {"-2",  10},
+               {"-1",  10},
+               {"65536",       10},
+               {"65537",       10},
+               {"2147483646",  10},
+               {"2147483647",  10},
+               {"2147483648",  10},
+               {"2147483649",  10},
+               {"4294967294",  10},
+               {"4294967295",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtou16, u16, "%hu", test_u16_fail);
+}
+
+static void __init test_kstrtos16_ok(void)
+{
+       DECLARE_TEST_OK(s16, struct test_s16);
+       static DEFINE_TEST_OK(struct test_s16, test_s16_ok) = {
+               {"-130",        10,     -130},
+               {"-129",        10,     -129},
+               {"-128",        10,     -128},
+               {"-127",        10,     -127},
+               {"-1",  10,     -1},
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+               {"256", 10,     256},
+               {"257", 10,     257},
+               {"32766",       10,     32766},
+               {"32767",       10,     32767},
+       };
+       TEST_OK(kstrtos16, s16, "%hd", test_s16_ok);
+}
+
+static void __init test_kstrtos16_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_s16_fail) = {
+               {"32768",       10},
+               {"32769",       10},
+               {"65534",       10},
+               {"65535",       10},
+               {"65536",       10},
+               {"65537",       10},
+               {"2147483646",  10},
+               {"2147483647",  10},
+               {"2147483648",  10},
+               {"2147483649",  10},
+               {"4294967294",  10},
+               {"4294967295",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtos16, s16, "%hd", test_s16_fail);
+}
+
+static void __init test_kstrtou8_ok(void)
+{
+       DECLARE_TEST_OK(u8, struct test_u8);
+       static DEFINE_TEST_OK(struct test_u8, test_u8_ok) = {
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+               {"128", 10,     128},
+               {"129", 10,     129},
+               {"254", 10,     254},
+               {"255", 10,     255},
+       };
+       TEST_OK(kstrtou8, u8, "%hhu", test_u8_ok);
+}
+
+static void __init test_kstrtou8_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_u8_fail) = {
+               {"-2",  10},
+               {"-1",  10},
+               {"256", 10},
+               {"257", 10},
+               {"32766",       10},
+               {"32767",       10},
+               {"32768",       10},
+               {"32769",       10},
+               {"65534",       10},
+               {"65535",       10},
+               {"65536",       10},
+               {"65537",       10},
+               {"2147483646",  10},
+               {"2147483647",  10},
+               {"2147483648",  10},
+               {"2147483649",  10},
+               {"4294967294",  10},
+               {"4294967295",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtou8, u8, "%hhu", test_u8_fail);
+}
+
+static void __init test_kstrtos8_ok(void)
+{
+       DECLARE_TEST_OK(s8, struct test_s8);
+       static DEFINE_TEST_OK(struct test_s8, test_s8_ok) = {
+               {"-128",        10,     -128},
+               {"-127",        10,     -127},
+               {"-1",  10,     -1},
+               {"0",   10,     0},
+               {"1",   10,     1},
+               {"126", 10,     126},
+               {"127", 10,     127},
+       };
+       TEST_OK(kstrtos8, s8, "%hhd", test_s8_ok);
+}
+
+static void __init test_kstrtos8_fail(void)
+{
+       static DEFINE_TEST_FAIL(test_s8_fail) = {
+               {"-130",        10},
+               {"-129",        10},
+               {"128", 10},
+               {"129", 10},
+               {"254", 10},
+               {"255", 10},
+               {"256", 10},
+               {"257", 10},
+               {"32766",       10},
+               {"32767",       10},
+               {"32768",       10},
+               {"32769",       10},
+               {"65534",       10},
+               {"65535",       10},
+               {"65536",       10},
+               {"65537",       10},
+               {"2147483646",  10},
+               {"2147483647",  10},
+               {"2147483648",  10},
+               {"2147483649",  10},
+               {"4294967294",  10},
+               {"4294967295",  10},
+               {"4294967296",  10},
+               {"4294967297",  10},
+               {"9223372036854775806", 10},
+               {"9223372036854775807", 10},
+               {"9223372036854775808", 10},
+               {"9223372036854775809", 10},
+               {"18446744073709551614",        10},
+               {"18446744073709551615",        10},
+               {"18446744073709551616",        10},
+               {"18446744073709551617",        10},
+       };
+       TEST_FAIL(kstrtos8, s8, "%hhd", test_s8_fail);
+}
+
+static int __init test_kstrtox_init(void)
+{
+       test_kstrtoull_ok();
+       test_kstrtoull_fail();
+       test_kstrtoll_ok();
+       test_kstrtoll_fail();
+
+       test_kstrtou64_ok();
+       test_kstrtou64_fail();
+       test_kstrtos64_ok();
+       test_kstrtos64_fail();
+
+       test_kstrtou32_ok();
+       test_kstrtou32_fail();
+       test_kstrtos32_ok();
+       test_kstrtos32_fail();
+
+       test_kstrtou16_ok();
+       test_kstrtou16_fail();
+       test_kstrtos16_ok();
+       test_kstrtos16_fail();
+
+       test_kstrtou8_ok();
+       test_kstrtou8_fail();
+       test_kstrtos8_ok();
+       test_kstrtos8_fail();
+       return -EINVAL;
+}
+module_init(test_kstrtox_init);
+MODULE_LICENSE("Dual BSD/GPL");
index d3023df8477f67285c43129574148264237a8d60..bc0ac6b333dc95464da43485d40a5966ef60eeb6 100644 (file)
@@ -120,147 +120,6 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base)
 }
 EXPORT_SYMBOL(simple_strtoll);
 
-/**
- * strict_strtoul - convert a string to an unsigned long strictly
- * @cp: The string to be converted
- * @base: The number base to use
- * @res: The converted result value
- *
- * strict_strtoul converts a string to an unsigned long only if the
- * string is really an unsigned long string, any string containing
- * any invalid char at the tail will be rejected and -EINVAL is returned,
- * only a newline char at the tail is acceptible because people generally
- * change a module parameter in the following way:
- *
- *     echo 1024 > /sys/module/e1000/parameters/copybreak
- *
- * echo will append a newline to the tail.
- *
- * It returns 0 if conversion is successful and *res is set to the converted
- * value, otherwise it returns -EINVAL and *res is set to 0.
- *
- * simple_strtoul just ignores the successive invalid characters and
- * return the converted value of prefix part of the string.
- */
-int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
-{
-       char *tail;
-       unsigned long val;
-
-       *res = 0;
-       if (!*cp)
-               return -EINVAL;
-
-       val = simple_strtoul(cp, &tail, base);
-       if (tail == cp)
-               return -EINVAL;
-
-       if ((tail[0] == '\0') || (tail[0] == '\n' && tail[1] == '\0')) {
-               *res = val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL(strict_strtoul);
-
-/**
- * strict_strtol - convert a string to a long strictly
- * @cp: The string to be converted
- * @base: The number base to use
- * @res: The converted result value
- *
- * strict_strtol is similiar to strict_strtoul, but it allows the first
- * character of a string is '-'.
- *
- * It returns 0 if conversion is successful and *res is set to the converted
- * value, otherwise it returns -EINVAL and *res is set to 0.
- */
-int strict_strtol(const char *cp, unsigned int base, long *res)
-{
-       int ret;
-       if (*cp == '-') {
-               ret = strict_strtoul(cp + 1, base, (unsigned long *)res);
-               if (!ret)
-                       *res = -(*res);
-       } else {
-               ret = strict_strtoul(cp, base, (unsigned long *)res);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(strict_strtol);
-
-/**
- * strict_strtoull - convert a string to an unsigned long long strictly
- * @cp: The string to be converted
- * @base: The number base to use
- * @res: The converted result value
- *
- * strict_strtoull converts a string to an unsigned long long only if the
- * string is really an unsigned long long string, any string containing
- * any invalid char at the tail will be rejected and -EINVAL is returned,
- * only a newline char at the tail is acceptible because people generally
- * change a module parameter in the following way:
- *
- *     echo 1024 > /sys/module/e1000/parameters/copybreak
- *
- * echo will append a newline to the tail of the string.
- *
- * It returns 0 if conversion is successful and *res is set to the converted
- * value, otherwise it returns -EINVAL and *res is set to 0.
- *
- * simple_strtoull just ignores the successive invalid characters and
- * return the converted value of prefix part of the string.
- */
-int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res)
-{
-       char *tail;
-       unsigned long long val;
-
-       *res = 0;
-       if (!*cp)
-               return -EINVAL;
-
-       val = simple_strtoull(cp, &tail, base);
-       if (tail == cp)
-               return -EINVAL;
-       if ((tail[0] == '\0') || (tail[0] == '\n' && tail[1] == '\0')) {
-               *res = val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-EXPORT_SYMBOL(strict_strtoull);
-
-/**
- * strict_strtoll - convert a string to a long long strictly
- * @cp: The string to be converted
- * @base: The number base to use
- * @res: The converted result value
- *
- * strict_strtoll is similiar to strict_strtoull, but it allows the first
- * character of a string is '-'.
- *
- * It returns 0 if conversion is successful and *res is set to the converted
- * value, otherwise it returns -EINVAL and *res is set to 0.
- */
-int strict_strtoll(const char *cp, unsigned int base, long long *res)
-{
-       int ret;
-       if (*cp == '-') {
-               ret = strict_strtoull(cp + 1, base, (unsigned long long *)res);
-               if (!ret)
-                       *res = -(*res);
-       } else {
-               ret = strict_strtoull(cp, base, (unsigned long long *)res);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(strict_strtoll);
-
 static noinline_for_stack
 int skip_atoi(const char **s)
 {
@@ -574,7 +433,9 @@ char *symbol_string(char *buf, char *end, void *ptr,
        unsigned long value = (unsigned long) ptr;
 #ifdef CONFIG_KALLSYMS
        char sym[KSYM_SYMBOL_LEN];
-       if (ext != 'f' && ext != 's')
+       if (ext == 'B')
+               sprint_backtrace(sym, value);
+       else if (ext != 'f' && ext != 's')
                sprint_symbol(sym, value);
        else
                kallsyms_lookup(value, NULL, NULL, NULL, sym);
@@ -949,6 +810,7 @@ int kptr_restrict = 1;
  * - 'f' For simple symbolic function names without offset
  * - 'S' For symbolic direct pointers with offset
  * - 's' For symbolic direct pointers without offset
+ * - 'B' For backtraced symbolic direct pointers with offset
  * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
  * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
  * - 'M' For a 6-byte MAC address, it prints the address in the
@@ -991,7 +853,7 @@ static noinline_for_stack
 char *pointer(const char *fmt, char *buf, char *end, void *ptr,
              struct printf_spec spec)
 {
-       if (!ptr) {
+       if (!ptr && *fmt != 'K') {
                /*
                 * Print (null) with the same width as a pointer so it makes
                 * tabular output look nice.
@@ -1008,6 +870,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                /* Fallthrough */
        case 'S':
        case 's':
+       case 'B':
                return symbol_string(buf, end, ptr, spec, *fmt);
        case 'R':
        case 'r':
@@ -1047,16 +910,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                        if (spec.field_width == -1)
                                spec.field_width = 2 * sizeof(void *);
                        return string(buf, end, "pK-error", spec);
-               } else if ((kptr_restrict == 0) ||
-                        (kptr_restrict == 1 &&
-                         has_capability_noaudit(current, CAP_SYSLOG)))
-                       break;
-
-               if (spec.field_width == -1) {
-                       spec.field_width = 2 * sizeof(void *);
-                       spec.flags |= ZEROPAD;
                }
-               return number(buf, end, 0, spec);
+               if (!((kptr_restrict == 0) ||
+                     (kptr_restrict == 1 &&
+                      has_capability_noaudit(current, CAP_SYSLOG))))
+                       ptr = NULL;
+               break;
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
@@ -1279,6 +1138,7 @@ qualifier:
  * %ps output the name of a text symbol without offset
  * %pF output the name of a function pointer with its offset
  * %pf output the name of a function pointer without its offset
+ * %pB output the name of a backtrace symbol with its offset
  * %pR output the address range in a struct resource with decoded flags
  * %pr output the address range in a struct resource with raw flags
  * %pM output a 6-byte MAC address with colons
index 46a31e5f49c3ef44ad5e7d2ecd557476b7f466f1..d63381e8e3331064463283420d872842e27c8a9a 100644 (file)
@@ -176,6 +176,7 @@ int zlib_deflateInit2(
     deflate_state *s;
     int noheader = 0;
     deflate_workspace *mem;
+    char *next;
 
     ush *overlay;
     /* We overlay pending_buf and d_buf+l_buf. This works since the average
@@ -199,6 +200,21 @@ int zlib_deflateInit2(
        strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
         return Z_STREAM_ERROR;
     }
+
+    /*
+     * Direct the workspace's pointers to the chunks that were allocated
+     * along with the deflate_workspace struct.
+     */
+    next = (char *) mem;
+    next += sizeof(*mem);
+    mem->window_memory = (Byte *) next;
+    next += zlib_deflate_window_memsize(windowBits);
+    mem->prev_memory = (Pos *) next;
+    next += zlib_deflate_prev_memsize(windowBits);
+    mem->head_memory = (Pos *) next;
+    next += zlib_deflate_head_memsize(memLevel);
+    mem->overlay_memory = next;
+
     s = (deflate_state *) &(mem->deflate_memory);
     strm->state = (struct internal_state *)s;
     s->strm = strm;
@@ -1247,7 +1263,18 @@ static block_state deflate_slow(
     return flush == Z_FINISH ? finish_done : block_done;
 }
 
-int zlib_deflate_workspacesize(void)
+int zlib_deflate_workspacesize(int windowBits, int memLevel)
 {
-    return sizeof(deflate_workspace);
+    if (windowBits < 0) /* undocumented feature: suppress zlib header */
+        windowBits = -windowBits;
+
+    /* Since the return value is typically passed to vmalloc() unchecked... */
+    BUG_ON(memLevel < 1 || memLevel > MAX_MEM_LEVEL || windowBits < 9 ||
+                                                       windowBits > 15);
+
+    return sizeof(deflate_workspace)
+        + zlib_deflate_window_memsize(windowBits)
+        + zlib_deflate_prev_memsize(windowBits)
+        + zlib_deflate_head_memsize(memLevel)
+        + zlib_deflate_overlay_memsize(memLevel);
 }
index 6b15a909ca3f0cfc163b4cdcd8a1613884643784..b640b6402e99e3a74db809012a4138c4cef48457 100644 (file)
@@ -241,12 +241,21 @@ typedef struct deflate_state {
 typedef struct deflate_workspace {
     /* State memory for the deflator */
     deflate_state deflate_memory;
-    Byte window_memory[2 * (1 << MAX_WBITS)];
-    Pos prev_memory[1 << MAX_WBITS];
-    Pos head_memory[1 << (MAX_MEM_LEVEL + 7)];
-    char overlay_memory[(1 << (MAX_MEM_LEVEL + 6)) * (sizeof(ush)+2)];
+    Byte *window_memory;
+    Pos *prev_memory;
+    Pos *head_memory;
+    char *overlay_memory;
 } deflate_workspace;
 
+#define zlib_deflate_window_memsize(windowBits) \
+       (2 * (1 << (windowBits)) * sizeof(Byte))
+#define zlib_deflate_prev_memsize(windowBits) \
+       ((1 << (windowBits)) * sizeof(Pos))
+#define zlib_deflate_head_memsize(memLevel) \
+       ((1 << ((memLevel)+7)) * sizeof(Pos))
+#define zlib_deflate_overlay_memsize(memLevel) \
+       ((1 << ((memLevel)+6)) * (sizeof(ush)+2))
+
 /* Output a byte on the stream.
  * IN assertion: there is enough room in pending_buf.
  */
index af7cfb43d2f0526019b86fa35a75202aae222d1c..8b1a477162dc07242e7a461951bca291cff3dde7 100644 (file)
@@ -1,27 +1,24 @@
 config DEBUG_PAGEALLOC
        bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL && ARCH_SUPPORTS_DEBUG_PAGEALLOC
-       depends on !HIBERNATION || !PPC && !SPARC
+       depends on DEBUG_KERNEL
+       depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC
        depends on !KMEMCHECK
+       select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC
        ---help---
          Unmap pages from the kernel linear mapping after free_pages().
          This results in a large slowdown, but helps to find certain types
          of memory corruption.
 
+         For architectures which don't enable ARCH_SUPPORTS_DEBUG_PAGEALLOC,
+         fill the pages with poison patterns after free_pages() and verify
+         the patterns before alloc_pages().  Additionally,
+         this option cannot be enabled in combination with hibernation as
+         that would result in incorrect warnings of memory corruption after
+         a resume because free pages are not saved to the suspend image.
+
 config WANT_PAGE_DEBUG_FLAGS
        bool
 
 config PAGE_POISONING
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL && !ARCH_SUPPORTS_DEBUG_PAGEALLOC
-       depends on !HIBERNATION
-       select DEBUG_PAGEALLOC
+       bool
        select WANT_PAGE_DEBUG_FLAGS
-       ---help---
-          Fill the pages with poison patterns after free_pages() and verify
-          the patterns before alloc_pages(). This results in a large slowdown,
-          but helps to find certain types of memory corruption.
-
-          This option cannot be enabled in combination with hibernation as
-          that would result in incorrect warnings of memory corruption after
-          a resume because free pages are not saved to the suspend image.
index 027100d30227fead0a4010d1feb0e2791a98fcaa..0d9a036ada66358f1d5bb37baf4f269f6e3fef18 100644 (file)
 
 static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
 
-void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
-{
-}
-EXPORT_SYMBOL(default_unplug_io_fn);
-
 struct backing_dev_info default_backing_dev_info = {
        .name           = "default",
        .ra_pages       = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE,
        .state          = 0,
        .capabilities   = BDI_CAP_MAP_COPY,
-       .unplug_io_fn   = default_unplug_io_fn,
 };
 EXPORT_SYMBOL_GPL(default_backing_dev_info);
 
@@ -73,14 +67,14 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
        struct inode *inode;
 
        nr_wb = nr_dirty = nr_io = nr_more_io = 0;
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
                nr_dirty++;
        list_for_each_entry(inode, &wb->b_io, i_wb_list)
                nr_io++;
        list_for_each_entry(inode, &wb->b_more_io, i_wb_list)
                nr_more_io++;
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
 
        global_dirty_limits(&background_thresh, &dirty_thresh);
        bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
@@ -604,7 +598,7 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
        spin_lock(&sb_lock);
        list_for_each_entry(sb, &super_blocks, s_list) {
                if (sb->s_bdi == bdi)
-                       sb->s_bdi = NULL;
+                       sb->s_bdi = &default_backing_dev_info;
        }
        spin_unlock(&sb_lock);
 }
@@ -682,11 +676,11 @@ void bdi_destroy(struct backing_dev_info *bdi)
        if (bdi_has_dirty_io(bdi)) {
                struct bdi_writeback *dst = &default_backing_dev_info.wb;
 
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                list_splice(&bdi->wb.b_dirty, &dst->b_dirty);
                list_splice(&bdi->wb.b_io, &dst->b_io);
                list_splice(&bdi->wb.b_more_io, &dst->b_more_io);
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_wb_list_lock);
        }
 
        bdi_unregister(bdi);
index 07aeb89e396ea140dbd7a28640aacb8fa2707b9a..01d5a4b3dd0c1dd857f05f474ce096a9a2938001 100644 (file)
@@ -34,14 +34,6 @@ unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
 
-#ifdef CONFIG_CRASH_DUMP
-/*
- * If we have booted due to a crash, max_pfn will be a very low value. We need
- * to know the amount of memory that the previous kernel used.
- */
-unsigned long saved_max_pfn;
-#endif
-
 bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
 
 static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
index 8be430b812def9f32058ffb8c7e259ff1375d98e..021a2960ef9e18d061c972590f7651a35e7652ce 100644 (file)
@@ -42,8 +42,6 @@ struct compact_control {
        unsigned int order;             /* order a direct compactor needs */
        int migratetype;                /* MOVABLE, RECLAIMABLE etc */
        struct zone *zone;
-
-       int compact_mode;
 };
 
 static unsigned long release_freepages(struct list_head *freelist)
@@ -155,7 +153,6 @@ static void isolate_freepages(struct zone *zone,
         * pages on cc->migratepages. We stop searching if the migrate
         * and free page scanners meet or enough free pages are isolated.
         */
-       spin_lock_irqsave(&zone->lock, flags);
        for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;
                                        pfn -= pageblock_nr_pages) {
                unsigned long isolated;
@@ -178,9 +175,19 @@ static void isolate_freepages(struct zone *zone,
                if (!suitable_migration_target(page))
                        continue;
 
-               /* Found a block suitable for isolating free pages from */
-               isolated = isolate_freepages_block(zone, pfn, freelist);
-               nr_freepages += isolated;
+               /*
+                * Found a block suitable for isolating free pages from. Now
+                * we disabled interrupts, double check things are ok and
+                * isolate the pages. This is to minimise the time IRQs
+                * are disabled
+                */
+               isolated = 0;
+               spin_lock_irqsave(&zone->lock, flags);
+               if (suitable_migration_target(page)) {
+                       isolated = isolate_freepages_block(zone, pfn, freelist);
+                       nr_freepages += isolated;
+               }
+               spin_unlock_irqrestore(&zone->lock, flags);
 
                /*
                 * Record the highest PFN we isolated pages from. When next
@@ -190,7 +197,6 @@ static void isolate_freepages(struct zone *zone,
                if (isolated)
                        high_pfn = max(high_pfn, pfn);
        }
-       spin_unlock_irqrestore(&zone->lock, flags);
 
        /* split_free_page does not map the pages */
        list_for_each_entry(page, freelist, lru) {
@@ -271,9 +277,27 @@ static unsigned long isolate_migratepages(struct zone *zone,
        }
 
        /* Time to isolate some pages for migration */
+       cond_resched();
        spin_lock_irq(&zone->lru_lock);
        for (; low_pfn < end_pfn; low_pfn++) {
                struct page *page;
+               bool locked = true;
+
+               /* give a chance to irqs before checking need_resched() */
+               if (!((low_pfn+1) % SWAP_CLUSTER_MAX)) {
+                       spin_unlock_irq(&zone->lru_lock);
+                       locked = false;
+               }
+               if (need_resched() || spin_is_contended(&zone->lru_lock)) {
+                       if (locked)
+                               spin_unlock_irq(&zone->lru_lock);
+                       cond_resched();
+                       spin_lock_irq(&zone->lru_lock);
+                       if (fatal_signal_pending(current))
+                               break;
+               } else if (!locked)
+                       spin_lock_irq(&zone->lru_lock);
+
                if (!pfn_valid_within(low_pfn))
                        continue;
                nr_scanned++;
@@ -397,10 +421,7 @@ static int compact_finished(struct zone *zone,
                return COMPACT_COMPLETE;
 
        /* Compaction run is not finished if the watermark is not met */
-       if (cc->compact_mode != COMPACT_MODE_KSWAPD)
-               watermark = low_wmark_pages(zone);
-       else
-               watermark = high_wmark_pages(zone);
+       watermark = low_wmark_pages(zone);
        watermark += (1 << cc->order);
 
        if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
@@ -413,15 +434,6 @@ static int compact_finished(struct zone *zone,
        if (cc->order == -1)
                return COMPACT_CONTINUE;
 
-       /*
-        * Generating only one page of the right order is not enough
-        * for kswapd, we must continue until we're above the high
-        * watermark as a pool for high order GFP_ATOMIC allocations
-        * too.
-        */
-       if (cc->compact_mode == COMPACT_MODE_KSWAPD)
-               return COMPACT_CONTINUE;
-
        /* Direct compactor: Is a suitable page free? */
        for (order = cc->order; order < MAX_ORDER; order++) {
                /* Job done if page is free of the right migratetype */
@@ -508,12 +520,13 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 
        while ((ret = compact_finished(zone, cc)) == COMPACT_CONTINUE) {
                unsigned long nr_migrate, nr_remaining;
+               int err;
 
                if (!isolate_migratepages(zone, cc))
                        continue;
 
                nr_migrate = cc->nr_migratepages;
-               migrate_pages(&cc->migratepages, compaction_alloc,
+               err = migrate_pages(&cc->migratepages, compaction_alloc,
                                (unsigned long)cc, false,
                                cc->sync);
                update_nr_listpages(cc);
@@ -527,7 +540,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                                                nr_remaining);
 
                /* Release LRU pages not migrated */
-               if (!list_empty(&cc->migratepages)) {
+               if (err) {
                        putback_lru_pages(&cc->migratepages);
                        cc->nr_migratepages = 0;
                }
@@ -543,8 +556,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
 
 unsigned long compact_zone_order(struct zone *zone,
                                 int order, gfp_t gfp_mask,
-                                bool sync,
-                                int compact_mode)
+                                bool sync)
 {
        struct compact_control cc = {
                .nr_freepages = 0,
@@ -553,7 +565,6 @@ unsigned long compact_zone_order(struct zone *zone,
                .migratetype = allocflags_to_migratetype(gfp_mask),
                .zone = zone,
                .sync = sync,
-               .compact_mode = compact_mode,
        };
        INIT_LIST_HEAD(&cc.freepages);
        INIT_LIST_HEAD(&cc.migratepages);
@@ -599,8 +610,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                                                                nodemask) {
                int status;
 
-               status = compact_zone_order(zone, order, gfp_mask, sync,
-                                           COMPACT_MODE_DIRECT_RECLAIM);
+               status = compact_zone_order(zone, order, gfp_mask, sync);
                rc = max(status, rc);
 
                /* If a normal allocation would succeed, stop compacting */
@@ -631,7 +641,6 @@ static int compact_node(int nid)
                        .nr_freepages = 0,
                        .nr_migratepages = 0,
                        .order = -1,
-                       .compact_mode = COMPACT_MODE_DIRECT_RECLAIM,
                };
 
                zone = &pgdat->node_zones[zoneid];
index 83a45d35468b961340fb19a958eee77d0e2e2297..c641edf553a9373dd3f2c3a20c584fa3dcb2c957 100644 (file)
@@ -80,8 +80,8 @@
  *  ->i_mutex
  *    ->i_alloc_sem             (various)
  *
- *  ->inode_lock
- *    ->sb_lock                        (fs/fs-writeback.c)
+ *  inode_wb_list_lock
+ *    sb_lock                  (fs/fs-writeback.c)
  *    ->mapping->tree_lock     (__sync_single_inode)
  *
  *  ->i_mmap_lock
  *    ->zone.lru_lock          (check_pte_range->isolate_lru_page)
  *    ->private_lock           (page_remove_rmap->set_page_dirty)
  *    ->tree_lock              (page_remove_rmap->set_page_dirty)
- *    ->inode_lock             (page_remove_rmap->set_page_dirty)
- *    ->inode_lock             (zap_pte_range->set_page_dirty)
+ *    inode_wb_list_lock       (page_remove_rmap->set_page_dirty)
+ *    ->inode->i_lock          (page_remove_rmap->set_page_dirty)
+ *    inode_wb_list_lock       (zap_pte_range->set_page_dirty)
+ *    ->inode->i_lock          (zap_pte_range->set_page_dirty)
  *    ->private_lock           (zap_pte_range->__set_page_dirty_buffers)
  *
  *  (code doesn't rely on that order, so you could switch it around)
  */
 
 /*
- * Remove a page from the page cache and free it. Caller has to make
+ * Delete a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
  * is safe.  The caller must hold the mapping's tree_lock.
  */
-void __remove_from_page_cache(struct page *page)
+void __delete_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
 
@@ -137,7 +139,15 @@ void __remove_from_page_cache(struct page *page)
        }
 }
 
-void remove_from_page_cache(struct page *page)
+/**
+ * delete_from_page_cache - delete page from page cache
+ * @page: the page which the kernel is trying to remove from page cache
+ *
+ * This must be called only on pages that have been verified to be in the page
+ * cache and locked.  It will never put the page into the free list, the caller
+ * has a reference on the page.
+ */
+void delete_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
        void (*freepage)(struct page *);
@@ -146,54 +156,25 @@ void remove_from_page_cache(struct page *page)
 
        freepage = mapping->a_ops->freepage;
        spin_lock_irq(&mapping->tree_lock);
-       __remove_from_page_cache(page);
+       __delete_from_page_cache(page);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
 
        if (freepage)
                freepage(page);
+       page_cache_release(page);
 }
-EXPORT_SYMBOL(remove_from_page_cache);
+EXPORT_SYMBOL(delete_from_page_cache);
 
-static int sync_page(void *word)
+static int sleep_on_page(void *word)
 {
-       struct address_space *mapping;
-       struct page *page;
-
-       page = container_of((unsigned long *)word, struct page, flags);
-
-       /*
-        * page_mapping() is being called without PG_locked held.
-        * Some knowledge of the state and use of the page is used to
-        * reduce the requirements down to a memory barrier.
-        * The danger here is of a stale page_mapping() return value
-        * indicating a struct address_space different from the one it's
-        * associated with when it is associated with one.
-        * After smp_mb(), it's either the correct page_mapping() for
-        * the page, or an old page_mapping() and the page's own
-        * page_mapping() has gone NULL.
-        * The ->sync_page() address_space operation must tolerate
-        * page_mapping() going NULL. By an amazing coincidence,
-        * this comes about because none of the users of the page
-        * in the ->sync_page() methods make essential use of the
-        * page_mapping(), merely passing the page down to the backing
-        * device's unplug functions when it's non-NULL, which in turn
-        * ignore it for all cases but swap, where only page_private(page) is
-        * of interest. When page_mapping() does go NULL, the entire
-        * call stack gracefully ignores the page and returns.
-        * -- wli
-        */
-       smp_mb();
-       mapping = page_mapping(page);
-       if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
-               mapping->a_ops->sync_page(page);
        io_schedule();
        return 0;
 }
 
-static int sync_page_killable(void *word)
+static int sleep_on_page_killable(void *word)
 {
-       sync_page(word);
+       sleep_on_page(word);
        return fatal_signal_pending(current) ? -EINTR : 0;
 }
 
@@ -386,6 +367,76 @@ int filemap_write_and_wait_range(struct address_space *mapping,
 }
 EXPORT_SYMBOL(filemap_write_and_wait_range);
 
+/**
+ * replace_page_cache_page - replace a pagecache page with a new one
+ * @old:       page to be replaced
+ * @new:       page to replace with
+ * @gfp_mask:  allocation mode
+ *
+ * This function replaces a page in the pagecache with a new one.  On
+ * success it acquires the pagecache reference for the new page and
+ * drops it for the old page.  Both the old and new pages must be
+ * locked.  This function does not add the new page to the LRU, the
+ * caller must do that.
+ *
+ * The remove + add is atomic.  The only way this function can fail is
+ * memory allocation failure.
+ */
+int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
+{
+       int error;
+       struct mem_cgroup *memcg = NULL;
+
+       VM_BUG_ON(!PageLocked(old));
+       VM_BUG_ON(!PageLocked(new));
+       VM_BUG_ON(new->mapping);
+
+       /*
+        * This is not page migration, but prepare_migration and
+        * end_migration does enough work for charge replacement.
+        *
+        * In the longer term we probably want a specialized function
+        * for moving the charge from old to new in a more efficient
+        * manner.
+        */
+       error = mem_cgroup_prepare_migration(old, new, &memcg, gfp_mask);
+       if (error)
+               return error;
+
+       error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+       if (!error) {
+               struct address_space *mapping = old->mapping;
+               void (*freepage)(struct page *);
+
+               pgoff_t offset = old->index;
+               freepage = mapping->a_ops->freepage;
+
+               page_cache_get(new);
+               new->mapping = mapping;
+               new->index = offset;
+
+               spin_lock_irq(&mapping->tree_lock);
+               __delete_from_page_cache(old);
+               error = radix_tree_insert(&mapping->page_tree, offset, new);
+               BUG_ON(error);
+               mapping->nrpages++;
+               __inc_zone_page_state(new, NR_FILE_PAGES);
+               if (PageSwapBacked(new))
+                       __inc_zone_page_state(new, NR_SHMEM);
+               spin_unlock_irq(&mapping->tree_lock);
+               radix_tree_preload_end();
+               if (freepage)
+                       freepage(old);
+               page_cache_release(old);
+               mem_cgroup_end_migration(memcg, old, new, true);
+       } else {
+               mem_cgroup_end_migration(memcg, old, new, false);
+       }
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(replace_page_cache_page);
+
 /**
  * add_to_page_cache_locked - add a locked page to the pagecache
  * @page:      page to add
@@ -479,12 +530,6 @@ struct page *__page_cache_alloc(gfp_t gfp)
 EXPORT_SYMBOL(__page_cache_alloc);
 #endif
 
-static int __sleep_on_page_lock(void *word)
-{
-       io_schedule();
-       return 0;
-}
-
 /*
  * In order to wait for pages to become available there must be
  * waitqueues associated with pages. By using a hash table of
@@ -512,7 +557,7 @@ void wait_on_page_bit(struct page *page, int bit_nr)
        DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
 
        if (test_bit(bit_nr, &page->flags))
-               __wait_on_bit(page_waitqueue(page), &wait, sync_page,
+               __wait_on_bit(page_waitqueue(page), &wait, sleep_on_page,
                                                        TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(wait_on_page_bit);
@@ -576,17 +621,12 @@ EXPORT_SYMBOL(end_page_writeback);
 /**
  * __lock_page - get a lock on the page, assuming we need to sleep to get it
  * @page: the page to lock
- *
- * Ugly. Running sync_page() in state TASK_UNINTERRUPTIBLE is scary.  If some
- * random driver's requestfn sets TASK_RUNNING, we could busywait.  However
- * chances are that on the second loop, the block layer's plug list is empty,
- * so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
  */
 void __lock_page(struct page *page)
 {
        DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
-       __wait_on_bit_lock(page_waitqueue(page), &wait, sync_page,
+       __wait_on_bit_lock(page_waitqueue(page), &wait, sleep_on_page,
                                                        TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL(__lock_page);
@@ -596,24 +636,10 @@ int __lock_page_killable(struct page *page)
        DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
        return __wait_on_bit_lock(page_waitqueue(page), &wait,
-                                       sync_page_killable, TASK_KILLABLE);
+                                       sleep_on_page_killable, TASK_KILLABLE);
 }
 EXPORT_SYMBOL_GPL(__lock_page_killable);
 
-/**
- * __lock_page_nosync - get a lock on the page, without calling sync_page()
- * @page: the page to lock
- *
- * Variant of lock_page that does not require the caller to hold a reference
- * on the page's mapping.
- */
-void __lock_page_nosync(struct page *page)
-{
-       DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
-       __wait_on_bit_lock(page_waitqueue(page), &wait, __sleep_on_page_lock,
-                                                       TASK_UNINTERRUPTIBLE);
-}
-
 int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                         unsigned int flags)
 {
@@ -621,8 +647,10 @@ int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                __lock_page(page);
                return 1;
        } else {
-               up_read(&mm->mmap_sem);
-               wait_on_page_locked(page);
+               if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) {
+                       up_read(&mm->mmap_sem);
+                       wait_on_page_locked(page);
+               }
                return 0;
        }
 }
@@ -782,9 +810,13 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
+
+               /*
+                * This can only trigger when the entry at index 0 moves out
+                * of or back to the root: none yet gotten, safe to restart.
+                */
                if (radix_tree_deref_retry(page)) {
-                       if (ret)
-                               start = pages[ret-1]->index;
+                       WARN_ON(start | i);
                        goto restart;
                }
 
@@ -800,6 +832,13 @@ repeat:
                pages[ret] = page;
                ret++;
        }
+
+       /*
+        * If all entries were removed before we could secure them,
+        * try again, because callers stop trying once 0 is returned.
+        */
+       if (unlikely(!ret && nr_found))
+               goto restart;
        rcu_read_unlock();
        return ret;
 }
@@ -834,6 +873,11 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
+
+               /*
+                * This can only trigger when the entry at index 0 moves out
+                * of or back to the root: none yet gotten, safe to restart.
+                */
                if (radix_tree_deref_retry(page))
                        goto restart;
 
@@ -894,6 +938,11 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
+
+               /*
+                * This can only trigger when the entry at index 0 moves out
+                * of or back to the root: none yet gotten, safe to restart.
+                */
                if (radix_tree_deref_retry(page))
                        goto restart;
 
@@ -909,6 +958,13 @@ repeat:
                pages[ret] = page;
                ret++;
        }
+
+       /*
+        * If all entries were removed before we could secure them,
+        * try again, because callers stop trying once 0 is returned.
+        */
+       if (unlikely(!ret && nr_found))
+               goto restart;
        rcu_read_unlock();
 
        if (ret)
@@ -1298,12 +1354,15 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
        unsigned long seg = 0;
        size_t count;
        loff_t *ppos = &iocb->ki_pos;
+       struct blk_plug plug;
 
        count = 0;
        retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
        if (retval)
                return retval;
 
+       blk_start_plug(&plug);
+
        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
        if (filp->f_flags & O_DIRECT) {
                loff_t size;
@@ -1376,6 +1435,7 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                        break;
        }
 out:
+       blk_finish_plug(&plug);
        return retval;
 }
 EXPORT_SYMBOL(generic_file_aio_read);
@@ -2487,11 +2547,13 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       struct blk_plug plug;
        ssize_t ret;
 
        BUG_ON(iocb->ki_pos != pos);
 
        mutex_lock(&inode->i_mutex);
+       blk_start_plug(&plug);
        ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
        mutex_unlock(&inode->i_mutex);
 
@@ -2502,6 +2564,7 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                if (err < 0 && ret > 0)
                        ret = err;
        }
+       blk_finish_plug(&plug);
        return ret;
 }
 EXPORT_SYMBOL(generic_file_aio_write);
index 113e35c4750209b7cf6f61f54a041f37219ebc4d..0a619e0e2e0bd26da68b26948f065e1be72a8aa0 100644 (file)
@@ -643,23 +643,24 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
        return ret;
 }
 
-static inline gfp_t alloc_hugepage_gfpmask(int defrag)
+static inline gfp_t alloc_hugepage_gfpmask(int defrag, gfp_t extra_gfp)
 {
-       return GFP_TRANSHUGE & ~(defrag ? 0 : __GFP_WAIT);
+       return (GFP_TRANSHUGE & ~(defrag ? 0 : __GFP_WAIT)) | extra_gfp;
 }
 
 static inline struct page *alloc_hugepage_vma(int defrag,
                                              struct vm_area_struct *vma,
-                                             unsigned long haddr, int nd)
+                                             unsigned long haddr, int nd,
+                                             gfp_t extra_gfp)
 {
-       return alloc_pages_vma(alloc_hugepage_gfpmask(defrag),
+       return alloc_pages_vma(alloc_hugepage_gfpmask(defrag, extra_gfp),
                               HPAGE_PMD_ORDER, vma, haddr, nd);
 }
 
 #ifndef CONFIG_NUMA
 static inline struct page *alloc_hugepage(int defrag)
 {
-       return alloc_pages(alloc_hugepage_gfpmask(defrag),
+       return alloc_pages(alloc_hugepage_gfpmask(defrag, 0),
                           HPAGE_PMD_ORDER);
 }
 #endif
@@ -678,7 +679,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                if (unlikely(khugepaged_enter(vma)))
                        return VM_FAULT_OOM;
                page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                         vma, haddr, numa_node_id());
+                                         vma, haddr, numa_node_id(), 0);
                if (unlikely(!page))
                        goto out;
                if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
@@ -799,7 +800,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
        }
 
        for (i = 0; i < HPAGE_PMD_NR; i++) {
-               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE,
+               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE |
+                                              __GFP_OTHER_NODE,
                                               vma, address, page_to_nid(page));
                if (unlikely(!pages[i] ||
                             mem_cgroup_newpage_charge(pages[i], mm,
@@ -902,7 +904,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (transparent_hugepage_enabled(vma) &&
            !transparent_hugepage_debug_cow())
                new_page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                             vma, haddr, numa_node_id());
+                                             vma, haddr, numa_node_id(), 0);
        else
                new_page = NULL;
 
@@ -1779,7 +1781,7 @@ static void collapse_huge_page(struct mm_struct *mm,
         * scalability.
         */
        new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address,
-                                     node);
+                                     node, __GFP_OTHER_NODE);
        if (unlikely(!new_page)) {
                up_read(&mm->mmap_sem);
                *hpage = ERR_PTR(-ENOMEM);
index bb0b7c128015f5cbb9f23d78b88c4b5e6eec2e7b..06de5aa4d64415af31fc5137ded307b634ae2c7b 100644 (file)
@@ -1872,8 +1872,7 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
        unsigned long tmp;
        int ret;
 
-       if (!write)
-               tmp = h->max_huge_pages;
+       tmp = h->max_huge_pages;
 
        if (write && h->order >= MAX_ORDER)
                return -EINVAL;
@@ -1938,8 +1937,7 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
        unsigned long tmp;
        int ret;
 
-       if (!write)
-               tmp = h->nr_overcommit_huge_pages;
+       tmp = h->nr_overcommit_huge_pages;
 
        if (write && h->order >= MAX_ORDER)
                return -EINVAL;
index c2b2a94f9d6773d1be1aece2387d6a6a52b1ae33..1bbe785aa559cb2f1c8bb87c329b4b9239b4d01d 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -301,20 +301,6 @@ static inline int in_stable_tree(struct rmap_item *rmap_item)
        return rmap_item->address & STABLE_FLAG;
 }
 
-static void hold_anon_vma(struct rmap_item *rmap_item,
-                         struct anon_vma *anon_vma)
-{
-       rmap_item->anon_vma = anon_vma;
-       get_anon_vma(anon_vma);
-}
-
-static void ksm_drop_anon_vma(struct rmap_item *rmap_item)
-{
-       struct anon_vma *anon_vma = rmap_item->anon_vma;
-
-       drop_anon_vma(anon_vma);
-}
-
 /*
  * ksmd, and unmerge_and_remove_all_rmap_items(), must not touch an mm's
  * page tables after it has passed through ksm_exit() - which, if necessary,
@@ -397,7 +383,7 @@ static void break_cow(struct rmap_item *rmap_item)
         * It is not an accident that whenever we want to break COW
         * to undo, we also need to drop a reference to the anon_vma.
         */
-       ksm_drop_anon_vma(rmap_item);
+       put_anon_vma(rmap_item->anon_vma);
 
        down_read(&mm->mmap_sem);
        if (ksm_test_exit(mm))
@@ -466,7 +452,7 @@ static void remove_node_from_stable_tree(struct stable_node *stable_node)
                        ksm_pages_sharing--;
                else
                        ksm_pages_shared--;
-               ksm_drop_anon_vma(rmap_item);
+               put_anon_vma(rmap_item->anon_vma);
                rmap_item->address &= PAGE_MASK;
                cond_resched();
        }
@@ -554,7 +540,7 @@ static void remove_rmap_item_from_tree(struct rmap_item *rmap_item)
                else
                        ksm_pages_shared--;
 
-               ksm_drop_anon_vma(rmap_item);
+               put_anon_vma(rmap_item->anon_vma);
                rmap_item->address &= PAGE_MASK;
 
        } else if (rmap_item->address & UNSTABLE_FLAG) {
@@ -949,7 +935,8 @@ static int try_to_merge_with_ksm_page(struct rmap_item *rmap_item,
                goto out;
 
        /* Must get reference to anon_vma while still holding mmap_sem */
-       hold_anon_vma(rmap_item, vma->anon_vma);
+       rmap_item->anon_vma = vma->anon_vma;
+       get_anon_vma(vma->anon_vma);
 out:
        up_read(&mm->mmap_sem);
        return err;
index 4618fda975a0e1c149b6735d64b6a779cc8c301d..a0562d1a6ad426e1b21d43882b1f5f187330edfa 100644 (file)
@@ -58,28 +58,6 @@ static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, p
        return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
 }
 
-static long __init_memblock memblock_addrs_adjacent(phys_addr_t base1, phys_addr_t size1,
-                              phys_addr_t base2, phys_addr_t size2)
-{
-       if (base2 == base1 + size1)
-               return 1;
-       else if (base1 == base2 + size2)
-               return -1;
-
-       return 0;
-}
-
-static long __init_memblock memblock_regions_adjacent(struct memblock_type *type,
-                                unsigned long r1, unsigned long r2)
-{
-       phys_addr_t base1 = type->regions[r1].base;
-       phys_addr_t size1 = type->regions[r1].size;
-       phys_addr_t base2 = type->regions[r2].base;
-       phys_addr_t size2 = type->regions[r2].size;
-
-       return memblock_addrs_adjacent(base1, size1, base2, size2);
-}
-
 long __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
 {
        unsigned long i;
@@ -206,14 +184,13 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
                type->regions[i].size = type->regions[i + 1].size;
        }
        type->cnt--;
-}
 
-/* Assumption: base addr of region 1 < base addr of region 2 */
-static void __init_memblock memblock_coalesce_regions(struct memblock_type *type,
-               unsigned long r1, unsigned long r2)
-{
-       type->regions[r1].size += type->regions[r2].size;
-       memblock_remove_region(type, r2);
+       /* Special case for empty arrays */
+       if (type->cnt == 0) {
+               type->cnt = 1;
+               type->regions[0].base = 0;
+               type->regions[0].size = 0;
+       }
 }
 
 /* Defined below but needed now */
@@ -276,7 +253,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type)
                return 0;
 
        /* Add the new reserved region now. Should not fail ! */
-       BUG_ON(memblock_add_region(&memblock.reserved, addr, new_size) < 0);
+       BUG_ON(memblock_add_region(&memblock.reserved, addr, new_size));
 
        /* If the array wasn't our static init one, then free it. We only do
         * that before SLAB is available as later on, we don't know whether
@@ -296,58 +273,99 @@ extern int __init_memblock __weak memblock_memory_can_coalesce(phys_addr_t addr1
        return 1;
 }
 
-static long __init_memblock memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
+static long __init_memblock memblock_add_region(struct memblock_type *type,
+                                               phys_addr_t base, phys_addr_t size)
 {
-       unsigned long coalesced = 0;
-       long adjacent, i;
-
-       if ((type->cnt == 1) && (type->regions[0].size == 0)) {
-               type->regions[0].base = base;
-               type->regions[0].size = size;
-               return 0;
-       }
+       phys_addr_t end = base + size;
+       int i, slot = -1;
 
-       /* First try and coalesce this MEMBLOCK with another. */
+       /* First try and coalesce this MEMBLOCK with others */
        for (i = 0; i < type->cnt; i++) {
-               phys_addr_t rgnbase = type->regions[i].base;
-               phys_addr_t rgnsize = type->regions[i].size;
+               struct memblock_region *rgn = &type->regions[i];
+               phys_addr_t rend = rgn->base + rgn->size;
+
+               /* Exit if there's no possible hits */
+               if (rgn->base > end || rgn->size == 0)
+                       break;
 
-               if ((rgnbase == base) && (rgnsize == size))
-                       /* Already have this region, so we're done */
+               /* Check if we are fully enclosed within an existing
+                * block
+                */
+               if (rgn->base <= base && rend >= end)
                        return 0;
 
-               adjacent = memblock_addrs_adjacent(base, size, rgnbase, rgnsize);
-               /* Check if arch allows coalescing */
-               if (adjacent != 0 && type == &memblock.memory &&
-                   !memblock_memory_can_coalesce(base, size, rgnbase, rgnsize))
-                       break;
-               if (adjacent > 0) {
-                       type->regions[i].base -= size;
-                       type->regions[i].size += size;
-                       coalesced++;
-                       break;
-               } else if (adjacent < 0) {
-                       type->regions[i].size += size;
-                       coalesced++;
-                       break;
+               /* Check if we overlap or are adjacent with the bottom
+                * of a block.
+                */
+               if (base < rgn->base && end >= rgn->base) {
+                       /* If we can't coalesce, create a new block */
+                       if (!memblock_memory_can_coalesce(base, size,
+                                                         rgn->base,
+                                                         rgn->size)) {
+                               /* Overlap & can't coalesce are mutually
+                                * exclusive, if you do that, be prepared
+                                * for trouble
+                                */
+                               WARN_ON(end != rgn->base);
+                               goto new_block;
+                       }
+                       /* We extend the bottom of the block down to our
+                        * base
+                        */
+                       rgn->base = base;
+                       rgn->size = rend - base;
+
+                       /* Return if we have nothing else to allocate
+                        * (fully coalesced)
+                        */
+                       if (rend >= end)
+                               return 0;
+
+                       /* We continue processing from the end of the
+                        * coalesced block.
+                        */
+                       base = rend;
+                       size = end - base;
+               }
+
+               /* Now check if we overlap or are adjacent with the
+                * top of a block
+                */
+               if (base <= rend && end >= rend) {
+                       /* If we can't coalesce, create a new block */
+                       if (!memblock_memory_can_coalesce(rgn->base,
+                                                         rgn->size,
+                                                         base, size)) {
+                               /* Overlap & can't coalesce are mutually
+                                * exclusive, if you do that, be prepared
+                                * for trouble
+                                */
+                               WARN_ON(rend != base);
+                               goto new_block;
+                       }
+                       /* We adjust our base down to enclose the
+                        * original block and destroy it. It will be
+                        * part of our new allocation. Since we've
+                        * freed an entry, we know we won't fail
+                        * to allocate one later, so we won't risk
+                        * losing the original block allocation.
+                        */
+                       size += (base - rgn->base);
+                       base = rgn->base;
+                       memblock_remove_region(type, i--);
                }
        }
 
-       /* If we plugged a hole, we may want to also coalesce with the
-        * next region
+       /* If the array is empty, special case, replace the fake
+        * filler region and return
         */
-       if ((i < type->cnt - 1) && memblock_regions_adjacent(type, i, i+1) &&
-           ((type != &memblock.memory || memblock_memory_can_coalesce(type->regions[i].base,
-                                                            type->regions[i].size,
-                                                            type->regions[i+1].base,
-                                                            type->regions[i+1].size)))) {
-               memblock_coalesce_regions(type, i, i+1);
-               coalesced++;
+       if ((type->cnt == 1) && (type->regions[0].size == 0)) {
+               type->regions[0].base = base;
+               type->regions[0].size = size;
+               return 0;
        }
 
-       if (coalesced)
-               return coalesced;
-
+ new_block:
        /* If we are out of space, we fail. It's too late to resize the array
         * but then this shouldn't have happened in the first place.
         */
@@ -362,13 +380,14 @@ static long __init_memblock memblock_add_region(struct memblock_type *type, phys
                } else {
                        type->regions[i+1].base = base;
                        type->regions[i+1].size = size;
+                       slot = i + 1;
                        break;
                }
        }
-
        if (base < type->regions[0].base) {
                type->regions[0].base = base;
                type->regions[0].size = size;
+               slot = 0;
        }
        type->cnt++;
 
@@ -376,7 +395,8 @@ static long __init_memblock memblock_add_region(struct memblock_type *type, phys
         * our allocation and return an error
         */
        if (type->cnt == type->max && memblock_double_array(type)) {
-               type->cnt--;
+               BUG_ON(slot < 0);
+               memblock_remove_region(type, slot);
                return -1;
        }
 
@@ -389,52 +409,55 @@ long __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
 
 }
 
-static long __init_memblock __memblock_remove(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
+static long __init_memblock __memblock_remove(struct memblock_type *type,
+                                             phys_addr_t base, phys_addr_t size)
 {
-       phys_addr_t rgnbegin, rgnend;
        phys_addr_t end = base + size;
        int i;
 
-       rgnbegin = rgnend = 0; /* supress gcc warnings */
-
-       /* Find the region where (base, size) belongs to */
-       for (i=0; i < type->cnt; i++) {
-               rgnbegin = type->regions[i].base;
-               rgnend = rgnbegin + type->regions[i].size;
+       /* Walk through the array for collisions */
+       for (i = 0; i < type->cnt; i++) {
+               struct memblock_region *rgn = &type->regions[i];
+               phys_addr_t rend = rgn->base + rgn->size;
 
-               if ((rgnbegin <= base) && (end <= rgnend))
+               /* Nothing more to do, exit */
+               if (rgn->base > end || rgn->size == 0)
                        break;
-       }
 
-       /* Didn't find the region */
-       if (i == type->cnt)
-               return -1;
+               /* If we fully enclose the block, drop it */
+               if (base <= rgn->base && end >= rend) {
+                       memblock_remove_region(type, i--);
+                       continue;
+               }
 
-       /* Check to see if we are removing entire region */
-       if ((rgnbegin == base) && (rgnend == end)) {
-               memblock_remove_region(type, i);
-               return 0;
-       }
+               /* If we are fully enclosed within a block
+                * then we need to split it and we are done
+                */
+               if (base > rgn->base && end < rend) {
+                       rgn->size = base - rgn->base;
+                       if (!memblock_add_region(type, end, rend - end))
+                               return 0;
+                       /* Failure to split is bad, we at least
+                        * restore the block before erroring
+                        */
+                       rgn->size = rend - rgn->base;
+                       WARN_ON(1);
+                       return -1;
+               }
 
-       /* Check to see if region is matching at the front */
-       if (rgnbegin == base) {
-               type->regions[i].base = end;
-               type->regions[i].size -= size;
-               return 0;
-       }
+               /* Check if we need to trim the bottom of a block */
+               if (rgn->base < end && rend > end) {
+                       rgn->size -= end - rgn->base;
+                       rgn->base = end;
+                       break;
+               }
 
-       /* Check to see if the region is matching at the end */
-       if (rgnend == end) {
-               type->regions[i].size -= size;
-               return 0;
-       }
+               /* And check if we need to trim the top of a block */
+               if (base < rend)
+                       rgn->size -= rend - base;
 
-       /*
-        * We need to split the entry -  adjust the current one to the
-        * beginging of the hole and add the region after hole.
-        */
-       type->regions[i].size = base - type->regions[i].base;
-       return memblock_add_region(type, end, rgnend - end);
+       }
+       return 0;
 }
 
 long __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
@@ -467,7 +490,7 @@ phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, ph
 
        found = memblock_find_base(size, align, 0, max_addr);
        if (found != MEMBLOCK_ERROR &&
-           memblock_add_region(&memblock.reserved, found, size) >= 0)
+           !memblock_add_region(&memblock.reserved, found, size))
                return found;
 
        return 0;
@@ -548,7 +571,7 @@ static phys_addr_t __init memblock_alloc_nid_region(struct memblock_region *mp,
                if (this_nid == nid) {
                        phys_addr_t ret = memblock_find_region(start, this_end, size, align);
                        if (ret != MEMBLOCK_ERROR &&
-                           memblock_add_region(&memblock.reserved, ret, size) >= 0)
+                           !memblock_add_region(&memblock.reserved, ret, size))
                                return ret;
                }
                start = this_end;
index da53a252b259f0f36f553e9646187db18d49d76a..1f0b460fe58c5308caae219343e415ec75f59f0d 100644 (file)
@@ -73,15 +73,6 @@ static int really_do_swap_account __initdata = 0;
 #define do_swap_account                (0)
 #endif
 
-/*
- * Per memcg event counter is incremented at every pagein/pageout. This counter
- * is used for trigger some periodic events. This is straightforward and better
- * than using jiffies etc. to handle periodic memcg event.
- *
- * These values will be used as !((event) & ((1 <<(thresh)) - 1))
- */
-#define THRESHOLDS_EVENTS_THRESH (7) /* once in 128 */
-#define SOFTLIMIT_EVENTS_THRESH (10) /* once in 1024 */
 
 /*
  * Statistics for memory cgroup.
@@ -93,19 +84,36 @@ enum mem_cgroup_stat_index {
        MEM_CGROUP_STAT_CACHE,     /* # of pages charged as cache */
        MEM_CGROUP_STAT_RSS,       /* # of pages charged as anon rss */
        MEM_CGROUP_STAT_FILE_MAPPED,  /* # of pages charged as file rss */
-       MEM_CGROUP_STAT_PGPGIN_COUNT,   /* # of pages paged in */
-       MEM_CGROUP_STAT_PGPGOUT_COUNT,  /* # of pages paged out */
        MEM_CGROUP_STAT_SWAPOUT, /* # of pages, swapped out */
        MEM_CGROUP_STAT_DATA, /* end of data requires synchronization */
-       /* incremented at every  pagein/pageout */
-       MEM_CGROUP_EVENTS = MEM_CGROUP_STAT_DATA,
        MEM_CGROUP_ON_MOVE,     /* someone is moving account between groups */
-
        MEM_CGROUP_STAT_NSTATS,
 };
 
+enum mem_cgroup_events_index {
+       MEM_CGROUP_EVENTS_PGPGIN,       /* # of pages paged in */
+       MEM_CGROUP_EVENTS_PGPGOUT,      /* # of pages paged out */
+       MEM_CGROUP_EVENTS_COUNT,        /* # of pages paged in/out */
+       MEM_CGROUP_EVENTS_NSTATS,
+};
+/*
+ * Per memcg event counter is incremented at every pagein/pageout. With THP,
+ * it will be incremated by the number of pages. This counter is used for
+ * for trigger some periodic events. This is straightforward and better
+ * than using jiffies etc. to handle periodic memcg event.
+ */
+enum mem_cgroup_events_target {
+       MEM_CGROUP_TARGET_THRESH,
+       MEM_CGROUP_TARGET_SOFTLIMIT,
+       MEM_CGROUP_NTARGETS,
+};
+#define THRESHOLDS_EVENTS_TARGET (128)
+#define SOFTLIMIT_EVENTS_TARGET (1024)
+
 struct mem_cgroup_stat_cpu {
-       s64 count[MEM_CGROUP_STAT_NSTATS];
+       long count[MEM_CGROUP_STAT_NSTATS];
+       unsigned long events[MEM_CGROUP_EVENTS_NSTATS];
+       unsigned long targets[MEM_CGROUP_NTARGETS];
 };
 
 /*
@@ -218,12 +226,6 @@ struct mem_cgroup {
         * per zone LRU lists.
         */
        struct mem_cgroup_lru_info info;
-
-       /*
-         protect against reclaim related member.
-       */
-       spinlock_t reclaim_param_lock;
-
        /*
         * While reclaiming in a hierarchy, we cache the last child we
         * reclaimed from.
@@ -327,13 +329,6 @@ enum charge_type {
        NR_CHARGE_TYPE,
 };
 
-/* only for here (for easy reading.) */
-#define PCGF_CACHE     (1UL << PCG_CACHE)
-#define PCGF_USED      (1UL << PCG_USED)
-#define PCGF_LOCK      (1UL << PCG_LOCK)
-/* Not used, but added here for completeness */
-#define PCGF_ACCT      (1UL << PCG_ACCT)
-
 /* for encoding cft->private value on file */
 #define _MEM                   (0)
 #define _MEMSWAP               (1)
@@ -371,14 +366,10 @@ struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem)
 }
 
 static struct mem_cgroup_per_zone *
-page_cgroup_zoneinfo(struct page_cgroup *pc)
+page_cgroup_zoneinfo(struct mem_cgroup *mem, struct page *page)
 {
-       struct mem_cgroup *mem = pc->mem_cgroup;
-       int nid = page_cgroup_nid(pc);
-       int zid = page_cgroup_zid(pc);
-
-       if (!mem)
-               return NULL;
+       int nid = page_to_nid(page);
+       int zid = page_zonenum(page);
 
        return mem_cgroup_zoneinfo(mem, nid, zid);
 }
@@ -504,11 +495,6 @@ static void mem_cgroup_remove_from_trees(struct mem_cgroup *mem)
        }
 }
 
-static inline unsigned long mem_cgroup_get_excess(struct mem_cgroup *mem)
-{
-       return res_counter_soft_limit_excess(&mem->res) >> PAGE_SHIFT;
-}
-
 static struct mem_cgroup_per_zone *
 __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
 {
@@ -565,11 +551,11 @@ mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
  * common workload, threashold and synchonization as vmstat[] should be
  * implemented.
  */
-static s64 mem_cgroup_read_stat(struct mem_cgroup *mem,
-               enum mem_cgroup_stat_index idx)
+static long mem_cgroup_read_stat(struct mem_cgroup *mem,
+                                enum mem_cgroup_stat_index idx)
 {
+       long val = 0;
        int cpu;
-       s64 val = 0;
 
        get_online_cpus();
        for_each_online_cpu(cpu)
@@ -583,9 +569,9 @@ static s64 mem_cgroup_read_stat(struct mem_cgroup *mem,
        return val;
 }
 
-static s64 mem_cgroup_local_usage(struct mem_cgroup *mem)
+static long mem_cgroup_local_usage(struct mem_cgroup *mem)
 {
-       s64 ret;
+       long ret;
 
        ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS);
        ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE);
@@ -599,6 +585,22 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
        this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
 }
 
+static unsigned long mem_cgroup_read_events(struct mem_cgroup *mem,
+                                           enum mem_cgroup_events_index idx)
+{
+       unsigned long val = 0;
+       int cpu;
+
+       for_each_online_cpu(cpu)
+               val += per_cpu(mem->stat->events[idx], cpu);
+#ifdef CONFIG_HOTPLUG_CPU
+       spin_lock(&mem->pcp_counter_lock);
+       val += mem->nocpu_base.events[idx];
+       spin_unlock(&mem->pcp_counter_lock);
+#endif
+       return val;
+}
+
 static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
                                         bool file, int nr_pages)
 {
@@ -611,13 +613,13 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
 
        /* pagein of a big page is an event. So, ignore page size */
        if (nr_pages > 0)
-               __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
+               __this_cpu_inc(mem->stat->events[MEM_CGROUP_EVENTS_PGPGIN]);
        else {
-               __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
+               __this_cpu_inc(mem->stat->events[MEM_CGROUP_EVENTS_PGPGOUT]);
                nr_pages = -nr_pages; /* for event */
        }
 
-       __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
+       __this_cpu_add(mem->stat->events[MEM_CGROUP_EVENTS_COUNT], nr_pages);
 
        preempt_enable();
 }
@@ -637,13 +639,34 @@ static unsigned long mem_cgroup_get_local_zonestat(struct mem_cgroup *mem,
        return total;
 }
 
-static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift)
+static bool __memcg_event_check(struct mem_cgroup *mem, int target)
 {
-       s64 val;
+       unsigned long val, next;
+
+       val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]);
+       next = this_cpu_read(mem->stat->targets[target]);
+       /* from time_after() in jiffies.h */
+       return ((long)next - (long)val < 0);
+}
+
+static void __mem_cgroup_target_update(struct mem_cgroup *mem, int target)
+{
+       unsigned long val, next;
 
-       val = this_cpu_read(mem->stat->count[MEM_CGROUP_EVENTS]);
+       val = this_cpu_read(mem->stat->events[MEM_CGROUP_EVENTS_COUNT]);
 
-       return !(val & ((1 << event_mask_shift) - 1));
+       switch (target) {
+       case MEM_CGROUP_TARGET_THRESH:
+               next = val + THRESHOLDS_EVENTS_TARGET;
+               break;
+       case MEM_CGROUP_TARGET_SOFTLIMIT:
+               next = val + SOFTLIMIT_EVENTS_TARGET;
+               break;
+       default:
+               return;
+       }
+
+       this_cpu_write(mem->stat->targets[target], next);
 }
 
 /*
@@ -653,10 +676,15 @@ static bool __memcg_event_check(struct mem_cgroup *mem, int event_mask_shift)
 static void memcg_check_events(struct mem_cgroup *mem, struct page *page)
 {
        /* threshold event is triggered in finer grain than soft limit */
-       if (unlikely(__memcg_event_check(mem, THRESHOLDS_EVENTS_THRESH))) {
+       if (unlikely(__memcg_event_check(mem, MEM_CGROUP_TARGET_THRESH))) {
                mem_cgroup_threshold(mem);
-               if (unlikely(__memcg_event_check(mem, SOFTLIMIT_EVENTS_THRESH)))
+               __mem_cgroup_target_update(mem, MEM_CGROUP_TARGET_THRESH);
+               if (unlikely(__memcg_event_check(mem,
+                       MEM_CGROUP_TARGET_SOFTLIMIT))){
                        mem_cgroup_update_tree(mem, page);
+                       __mem_cgroup_target_update(mem,
+                               MEM_CGROUP_TARGET_SOFTLIMIT);
+               }
        }
 }
 
@@ -815,7 +843,7 @@ void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru)
         * We don't check PCG_USED bit. It's cleared when the "page" is finally
         * removed from global LRU.
         */
-       mz = page_cgroup_zoneinfo(pc);
+       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
        /* huge page split is done under lru_lock. so, we have no races. */
        MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
        if (mem_cgroup_is_root(pc->mem_cgroup))
@@ -829,6 +857,32 @@ void mem_cgroup_del_lru(struct page *page)
        mem_cgroup_del_lru_list(page, page_lru(page));
 }
 
+/*
+ * Writeback is about to end against a page which has been marked for immediate
+ * reclaim.  If it still appears to be reclaimable, move it to the tail of the
+ * inactive list.
+ */
+void mem_cgroup_rotate_reclaimable_page(struct page *page)
+{
+       struct mem_cgroup_per_zone *mz;
+       struct page_cgroup *pc;
+       enum lru_list lru = page_lru(page);
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pc = lookup_page_cgroup(page);
+       /* unused or root page is not rotated. */
+       if (!PageCgroupUsed(pc))
+               return;
+       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+       smp_rmb();
+       if (mem_cgroup_is_root(pc->mem_cgroup))
+               return;
+       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
+       list_move_tail(&pc->lru, &mz->lists[lru]);
+}
+
 void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
 {
        struct mem_cgroup_per_zone *mz;
@@ -845,7 +899,7 @@ void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
        smp_rmb();
        if (mem_cgroup_is_root(pc->mem_cgroup))
                return;
-       mz = page_cgroup_zoneinfo(pc);
+       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
        list_move(&pc->lru, &mz->lists[lru]);
 }
 
@@ -862,7 +916,7 @@ void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
                return;
        /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
        smp_rmb();
-       mz = page_cgroup_zoneinfo(pc);
+       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
        /* huge page split is done under lru_lock. so, we have no races. */
        MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
        SetPageCgroupAcctLRU(pc);
@@ -872,18 +926,28 @@ void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
 }
 
 /*
- * At handling SwapCache, pc->mem_cgroup may be changed while it's linked to
- * lru because the page may.be reused after it's fully uncharged (because of
- * SwapCache behavior).To handle that, unlink page_cgroup from LRU when charge
- * it again. This function is only used to charge SwapCache. It's done under
- * lock_page and expected that zone->lru_lock is never held.
+ * At handling SwapCache and other FUSE stuff, pc->mem_cgroup may be changed
+ * while it's linked to lru because the page may be reused after it's fully
+ * uncharged. To handle that, unlink page_cgroup from LRU when charge it again.
+ * It's done under lock_page and expected that zone->lru_lock isnever held.
  */
-static void mem_cgroup_lru_del_before_commit_swapcache(struct page *page)
+static void mem_cgroup_lru_del_before_commit(struct page *page)
 {
        unsigned long flags;
        struct zone *zone = page_zone(page);
        struct page_cgroup *pc = lookup_page_cgroup(page);
 
+       /*
+        * Doing this check without taking ->lru_lock seems wrong but this
+        * is safe. Because if page_cgroup's USED bit is unset, the page
+        * will not be added to any memcg's LRU. If page_cgroup's USED bit is
+        * set, the commit after this will fail, anyway.
+        * This all charge/uncharge is done under some mutual execustion.
+        * So, we don't need to taking care of changes in USED bit.
+        */
+       if (likely(!PageLRU(page)))
+               return;
+
        spin_lock_irqsave(&zone->lru_lock, flags);
        /*
         * Forget old LRU when this page_cgroup is *not* used. This Used bit
@@ -894,12 +958,15 @@ static void mem_cgroup_lru_del_before_commit_swapcache(struct page *page)
        spin_unlock_irqrestore(&zone->lru_lock, flags);
 }
 
-static void mem_cgroup_lru_add_after_commit_swapcache(struct page *page)
+static void mem_cgroup_lru_add_after_commit(struct page *page)
 {
        unsigned long flags;
        struct zone *zone = page_zone(page);
        struct page_cgroup *pc = lookup_page_cgroup(page);
 
+       /* taking care of that the page is added to LRU while we commit it */
+       if (likely(!PageLRU(page)))
+               return;
        spin_lock_irqsave(&zone->lru_lock, flags);
        /* link when the page is linked to LRU but page_cgroup isn't */
        if (PageLRU(page) && !PageCgroupAcctLRU(pc))
@@ -1032,10 +1099,7 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
                return NULL;
        /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
        smp_rmb();
-       mz = page_cgroup_zoneinfo(pc);
-       if (!mz)
-               return NULL;
-
+       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
        return &mz->reclaim_stat;
 }
 
@@ -1067,9 +1131,11 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
                if (scan >= nr_to_scan)
                        break;
 
-               page = pc->page;
                if (unlikely(!PageCgroupUsed(pc)))
                        continue;
+
+               page = lookup_cgroup_page(pc);
+
                if (unlikely(!PageLRU(page)))
                        continue;
 
@@ -1101,49 +1167,32 @@ unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
 #define mem_cgroup_from_res_counter(counter, member)   \
        container_of(counter, struct mem_cgroup, member)
 
-static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
-{
-       if (do_swap_account) {
-               if (res_counter_check_under_limit(&mem->res) &&
-                       res_counter_check_under_limit(&mem->memsw))
-                       return true;
-       } else
-               if (res_counter_check_under_limit(&mem->res))
-                       return true;
-       return false;
-}
-
 /**
- * mem_cgroup_check_margin - check if the memory cgroup allows charging
- * @mem: memory cgroup to check
- * @bytes: the number of bytes the caller intends to charge
+ * mem_cgroup_margin - calculate chargeable space of a memory cgroup
+ * @mem: the memory cgroup
  *
- * Returns a boolean value on whether @mem can be charged @bytes or
- * whether this would exceed the limit.
+ * Returns the maximum amount of memory @mem can be charged with, in
+ * pages.
  */
-static bool mem_cgroup_check_margin(struct mem_cgroup *mem, unsigned long bytes)
+static unsigned long mem_cgroup_margin(struct mem_cgroup *mem)
 {
-       if (!res_counter_check_margin(&mem->res, bytes))
-               return false;
-       if (do_swap_account && !res_counter_check_margin(&mem->memsw, bytes))
-               return false;
-       return true;
+       unsigned long long margin;
+
+       margin = res_counter_margin(&mem->res);
+       if (do_swap_account)
+               margin = min(margin, res_counter_margin(&mem->memsw));
+       return margin >> PAGE_SHIFT;
 }
 
 static unsigned int get_swappiness(struct mem_cgroup *memcg)
 {
        struct cgroup *cgrp = memcg->css.cgroup;
-       unsigned int swappiness;
 
        /* root ? */
        if (cgrp->parent == NULL)
                return vm_swappiness;
 
-       spin_lock(&memcg->reclaim_param_lock);
-       swappiness = memcg->swappiness;
-       spin_unlock(&memcg->reclaim_param_lock);
-
-       return swappiness;
+       return memcg->swappiness;
 }
 
 static void mem_cgroup_start_move(struct mem_cgroup *mem)
@@ -1359,13 +1408,11 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem)
 
                rcu_read_unlock();
                /* Updates scanning parameter */
-               spin_lock(&root_mem->reclaim_param_lock);
                if (!css) {
                        /* this means start scan from ID:1 */
                        root_mem->last_scanned_child = 0;
                } else
                        root_mem->last_scanned_child = found;
-               spin_unlock(&root_mem->reclaim_param_lock);
        }
 
        return ret;
@@ -1394,7 +1441,9 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
        bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP;
        bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
        bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
-       unsigned long excess = mem_cgroup_get_excess(root_mem);
+       unsigned long excess;
+
+       excess = res_counter_soft_limit_excess(&root_mem->res) >> PAGE_SHIFT;
 
        /* If memsw_is_minimum==1, swap-out is of-no-use. */
        if (root_mem->memsw_is_minimum)
@@ -1451,9 +1500,9 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
                        return ret;
                total += ret;
                if (check_soft) {
-                       if (res_counter_check_under_soft_limit(&root_mem->res))
+                       if (!res_counter_soft_limit_excess(&root_mem->res))
                                return total;
-               } else if (mem_cgroup_check_under_limit(root_mem))
+               } else if (mem_cgroup_margin(root_mem))
                        return 1 + total;
        }
        return total;
@@ -1661,17 +1710,17 @@ EXPORT_SYMBOL(mem_cgroup_update_page_stat);
  * size of first charge trial. "32" comes from vmscan.c's magic value.
  * TODO: maybe necessary to use big numbers in big irons.
  */
-#define CHARGE_SIZE    (32 * PAGE_SIZE)
+#define CHARGE_BATCH   32U
 struct memcg_stock_pcp {
        struct mem_cgroup *cached; /* this never be root cgroup */
-       int charge;
+       unsigned int nr_pages;
        struct work_struct work;
 };
 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
 static atomic_t memcg_drain_count;
 
 /*
- * Try to consume stocked charge on this cpu. If success, PAGE_SIZE is consumed
+ * Try to consume stocked charge on this cpu. If success, one page is consumed
  * from local stock and true is returned. If the stock is 0 or charges from a
  * cgroup which is not current target, returns false. This stock will be
  * refilled.
@@ -1682,8 +1731,8 @@ static bool consume_stock(struct mem_cgroup *mem)
        bool ret = true;
 
        stock = &get_cpu_var(memcg_stock);
-       if (mem == stock->cached && stock->charge)
-               stock->charge -= PAGE_SIZE;
+       if (mem == stock->cached && stock->nr_pages)
+               stock->nr_pages--;
        else /* need to call res_counter_charge */
                ret = false;
        put_cpu_var(memcg_stock);
@@ -1697,13 +1746,15 @@ static void drain_stock(struct memcg_stock_pcp *stock)
 {
        struct mem_cgroup *old = stock->cached;
 
-       if (stock->charge) {
-               res_counter_uncharge(&old->res, stock->charge);
+       if (stock->nr_pages) {
+               unsigned long bytes = stock->nr_pages * PAGE_SIZE;
+
+               res_counter_uncharge(&old->res, bytes);
                if (do_swap_account)
-                       res_counter_uncharge(&old->memsw, stock->charge);
+                       res_counter_uncharge(&old->memsw, bytes);
+               stock->nr_pages = 0;
        }
        stock->cached = NULL;
-       stock->charge = 0;
 }
 
 /*
@@ -1720,7 +1771,7 @@ static void drain_local_stock(struct work_struct *dummy)
  * Cache charges(val) which is from res_counter, to local per_cpu area.
  * This will be consumed by consume_stock() function, later.
  */
-static void refill_stock(struct mem_cgroup *mem, int val)
+static void refill_stock(struct mem_cgroup *mem, unsigned int nr_pages)
 {
        struct memcg_stock_pcp *stock = &get_cpu_var(memcg_stock);
 
@@ -1728,7 +1779,7 @@ static void refill_stock(struct mem_cgroup *mem, int val)
                drain_stock(stock);
                stock->cached = mem;
        }
-       stock->charge += val;
+       stock->nr_pages += nr_pages;
        put_cpu_var(memcg_stock);
 }
 
@@ -1780,11 +1831,17 @@ static void mem_cgroup_drain_pcp_counter(struct mem_cgroup *mem, int cpu)
 
        spin_lock(&mem->pcp_counter_lock);
        for (i = 0; i < MEM_CGROUP_STAT_DATA; i++) {
-               s64 x = per_cpu(mem->stat->count[i], cpu);
+               long x = per_cpu(mem->stat->count[i], cpu);
 
                per_cpu(mem->stat->count[i], cpu) = 0;
                mem->nocpu_base.count[i] += x;
        }
+       for (i = 0; i < MEM_CGROUP_EVENTS_NSTATS; i++) {
+               unsigned long x = per_cpu(mem->stat->events[i], cpu);
+
+               per_cpu(mem->stat->events[i], cpu) = 0;
+               mem->nocpu_base.events[i] += x;
+       }
        /* need to clear ON_MOVE value, works as a kind of lock. */
        per_cpu(mem->stat->count[MEM_CGROUP_ON_MOVE], cpu) = 0;
        spin_unlock(&mem->pcp_counter_lock);
@@ -1834,9 +1891,10 @@ enum {
        CHARGE_OOM_DIE,         /* the current is killed because of OOM */
 };
 
-static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
-                               int csize, bool oom_check)
+static int mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
+                               unsigned int nr_pages, bool oom_check)
 {
+       unsigned long csize = nr_pages * PAGE_SIZE;
        struct mem_cgroup *mem_over_limit;
        struct res_counter *fail_res;
        unsigned long flags = 0;
@@ -1857,14 +1915,13 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
        } else
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, res);
        /*
-        * csize can be either a huge page (HPAGE_SIZE), a batch of
-        * regular pages (CHARGE_SIZE), or a single regular page
-        * (PAGE_SIZE).
+        * nr_pages can be either a huge page (HPAGE_PMD_NR), a batch
+        * of regular pages (CHARGE_BATCH), or a single regular page (1).
         *
         * Never reclaim on behalf of optional batching, retry with a
         * single page instead.
         */
-       if (csize == CHARGE_SIZE)
+       if (nr_pages == CHARGE_BATCH)
                return CHARGE_RETRY;
 
        if (!(gfp_mask & __GFP_WAIT))
@@ -1872,7 +1929,7 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
 
        ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
                                              gfp_mask, flags);
-       if (mem_cgroup_check_margin(mem_over_limit, csize))
+       if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
                return CHARGE_RETRY;
        /*
         * Even though the limit is exceeded at this point, reclaim
@@ -1883,7 +1940,7 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
         * unlikely to succeed so close to the limit, and we fall back
         * to regular pages anyway in case of failure.
         */
-       if (csize == PAGE_SIZE && ret)
+       if (nr_pages == 1 && ret)
                return CHARGE_RETRY;
 
        /*
@@ -1909,13 +1966,14 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
  */
 static int __mem_cgroup_try_charge(struct mm_struct *mm,
                                   gfp_t gfp_mask,
-                                  struct mem_cgroup **memcg, bool oom,
-                                  int page_size)
+                                  unsigned int nr_pages,
+                                  struct mem_cgroup **memcg,
+                                  bool oom)
 {
+       unsigned int batch = max(CHARGE_BATCH, nr_pages);
        int nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES;
        struct mem_cgroup *mem = NULL;
        int ret;
-       int csize = max(CHARGE_SIZE, (unsigned long) page_size);
 
        /*
         * Unlike gloval-vm's OOM-kill, we're not in memory shortage
@@ -1940,7 +1998,7 @@ again:
                VM_BUG_ON(css_is_removed(&mem->css));
                if (mem_cgroup_is_root(mem))
                        goto done;
-               if (page_size == PAGE_SIZE && consume_stock(mem))
+               if (nr_pages == 1 && consume_stock(mem))
                        goto done;
                css_get(&mem->css);
        } else {
@@ -1963,7 +2021,7 @@ again:
                        rcu_read_unlock();
                        goto done;
                }
-               if (page_size == PAGE_SIZE && consume_stock(mem)) {
+               if (nr_pages == 1 && consume_stock(mem)) {
                        /*
                         * It seems dagerous to access memcg without css_get().
                         * But considering how consume_stok works, it's not
@@ -1998,13 +2056,12 @@ again:
                        nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES;
                }
 
-               ret = __mem_cgroup_do_charge(mem, gfp_mask, csize, oom_check);
-
+               ret = mem_cgroup_do_charge(mem, gfp_mask, batch, oom_check);
                switch (ret) {
                case CHARGE_OK:
                        break;
                case CHARGE_RETRY: /* not in OOM situation but retry */
-                       csize = page_size;
+                       batch = nr_pages;
                        css_put(&mem->css);
                        mem = NULL;
                        goto again;
@@ -2025,8 +2082,8 @@ again:
                }
        } while (ret != CHARGE_OK);
 
-       if (csize > page_size)
-               refill_stock(mem, csize - page_size);
+       if (batch > nr_pages)
+               refill_stock(mem, batch - nr_pages);
        css_put(&mem->css);
 done:
        *memcg = mem;
@@ -2045,21 +2102,17 @@ bypass:
  * gotten by try_charge().
  */
 static void __mem_cgroup_cancel_charge(struct mem_cgroup *mem,
-                                                       unsigned long count)
+                                      unsigned int nr_pages)
 {
        if (!mem_cgroup_is_root(mem)) {
-               res_counter_uncharge(&mem->res, PAGE_SIZE * count);
+               unsigned long bytes = nr_pages * PAGE_SIZE;
+
+               res_counter_uncharge(&mem->res, bytes);
                if (do_swap_account)
-                       res_counter_uncharge(&mem->memsw, PAGE_SIZE * count);
+                       res_counter_uncharge(&mem->memsw, bytes);
        }
 }
 
-static void mem_cgroup_cancel_charge(struct mem_cgroup *mem,
-                                    int page_size)
-{
-       __mem_cgroup_cancel_charge(mem, page_size >> PAGE_SHIFT);
-}
-
 /*
  * A helper function to get mem_cgroup from ID. must be called under
  * rcu_read_lock(). The caller must check css_is_removed() or some if
@@ -2108,20 +2161,15 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
 }
 
 static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
+                                      struct page *page,
+                                      unsigned int nr_pages,
                                       struct page_cgroup *pc,
-                                      enum charge_type ctype,
-                                      int page_size)
+                                      enum charge_type ctype)
 {
-       int nr_pages = page_size >> PAGE_SHIFT;
-
-       /* try_charge() can return NULL to *memcg, taking care of it. */
-       if (!mem)
-               return;
-
        lock_page_cgroup(pc);
        if (unlikely(PageCgroupUsed(pc))) {
                unlock_page_cgroup(pc);
-               mem_cgroup_cancel_charge(mem, page_size);
+               __mem_cgroup_cancel_charge(mem, nr_pages);
                return;
        }
        /*
@@ -2158,7 +2206,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
         * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
         * if they exceeds softlimit.
         */
-       memcg_check_events(mem, pc->page);
+       memcg_check_events(mem, page);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -2195,7 +2243,7 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
                 * We hold lru_lock, then, reduce counter directly.
                 */
                lru = page_lru(head);
-               mz = page_cgroup_zoneinfo(head_pc);
+               mz = page_cgroup_zoneinfo(head_pc->mem_cgroup, head);
                MEM_CGROUP_ZSTAT(mz, lru) -= 1;
        }
        tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
@@ -2204,7 +2252,9 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
 #endif
 
 /**
- * __mem_cgroup_move_account - move account of the page
+ * mem_cgroup_move_account - move account of the page
+ * @page: the page
+ * @nr_pages: number of regular pages (>1 for huge pages)
  * @pc:        page_cgroup of the page.
  * @from: mem_cgroup which the page is moved from.
  * @to:        mem_cgroup which the page is moved to. @from != @to.
@@ -2212,25 +2262,42 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
  *
  * The caller must confirm following.
  * - page is not on LRU (isolate_page() is useful.)
- * - the pc is locked, used, and ->mem_cgroup points to @from.
+ * - compound_lock is held when nr_pages > 1
  *
  * This function doesn't do "charge" nor css_get to new cgroup. It should be
  * done by a caller(__mem_cgroup_try_charge would be usefull). If @uncharge is
  * true, this function does "uncharge" from old cgroup, but it doesn't if
  * @uncharge is false, so a caller should do "uncharge".
  */
-
-static void __mem_cgroup_move_account(struct page_cgroup *pc,
-       struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge,
-       int charge_size)
+static int mem_cgroup_move_account(struct page *page,
+                                  unsigned int nr_pages,
+                                  struct page_cgroup *pc,
+                                  struct mem_cgroup *from,
+                                  struct mem_cgroup *to,
+                                  bool uncharge)
 {
-       int nr_pages = charge_size >> PAGE_SHIFT;
+       unsigned long flags;
+       int ret;
 
        VM_BUG_ON(from == to);
-       VM_BUG_ON(PageLRU(pc->page));
-       VM_BUG_ON(!page_is_cgroup_locked(pc));
-       VM_BUG_ON(!PageCgroupUsed(pc));
-       VM_BUG_ON(pc->mem_cgroup != from);
+       VM_BUG_ON(PageLRU(page));
+       /*
+        * The page is isolated from LRU. So, collapse function
+        * will not handle this page. But page splitting can happen.
+        * Do this check under compound_page_lock(). The caller should
+        * hold it.
+        */
+       ret = -EBUSY;
+       if (nr_pages > 1 && !PageTransHuge(page))
+               goto out;
+
+       lock_page_cgroup(pc);
+
+       ret = -EINVAL;
+       if (!PageCgroupUsed(pc) || pc->mem_cgroup != from)
+               goto unlock;
+
+       move_lock_page_cgroup(pc, &flags);
 
        if (PageCgroupFileMapped(pc)) {
                /* Update mapped_file data for mem_cgroup */
@@ -2242,7 +2309,7 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
        mem_cgroup_charge_statistics(from, PageCgroupCache(pc), -nr_pages);
        if (uncharge)
                /* This is not "cancel", but cancel_charge does all we need. */
-               mem_cgroup_cancel_charge(from, charge_size);
+               __mem_cgroup_cancel_charge(from, nr_pages);
 
        /* caller should have done css_get */
        pc->mem_cgroup = to;
@@ -2254,40 +2321,16 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
         * garanteed that "to" is never removed. So, we don't check rmdir
         * status here.
         */
-}
-
-/*
- * check whether the @pc is valid for moving account and call
- * __mem_cgroup_move_account()
- */
-static int mem_cgroup_move_account(struct page_cgroup *pc,
-               struct mem_cgroup *from, struct mem_cgroup *to,
-               bool uncharge, int charge_size)
-{
-       int ret = -EINVAL;
-       unsigned long flags;
-       /*
-        * The page is isolated from LRU. So, collapse function
-        * will not handle this page. But page splitting can happen.
-        * Do this check under compound_page_lock(). The caller should
-        * hold it.
-        */
-       if ((charge_size > PAGE_SIZE) && !PageTransHuge(pc->page))
-               return -EBUSY;
-
-       lock_page_cgroup(pc);
-       if (PageCgroupUsed(pc) && pc->mem_cgroup == from) {
-               move_lock_page_cgroup(pc, &flags);
-               __mem_cgroup_move_account(pc, from, to, uncharge, charge_size);
-               move_unlock_page_cgroup(pc, &flags);
-               ret = 0;
-       }
+       move_unlock_page_cgroup(pc, &flags);
+       ret = 0;
+unlock:
        unlock_page_cgroup(pc);
        /*
         * check events
         */
-       memcg_check_events(to, pc->page);
-       memcg_check_events(from, pc->page);
+       memcg_check_events(to, page);
+       memcg_check_events(from, page);
+out:
        return ret;
 }
 
@@ -2295,16 +2338,16 @@ static int mem_cgroup_move_account(struct page_cgroup *pc,
  * move charges to its parent.
  */
 
-static int mem_cgroup_move_parent(struct page_cgroup *pc,
+static int mem_cgroup_move_parent(struct page *page,
+                                 struct page_cgroup *pc,
                                  struct mem_cgroup *child,
                                  gfp_t gfp_mask)
 {
-       struct page *page = pc->page;
        struct cgroup *cg = child->css.cgroup;
        struct cgroup *pcg = cg->parent;
        struct mem_cgroup *parent;
-       int page_size = PAGE_SIZE;
-       unsigned long flags;
+       unsigned int nr_pages;
+       unsigned long uninitialized_var(flags);
        int ret;
 
        /* Is ROOT ? */
@@ -2317,23 +2360,21 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
        if (isolate_lru_page(page))
                goto put;
 
-       if (PageTransHuge(page))
-               page_size = HPAGE_SIZE;
+       nr_pages = hpage_nr_pages(page);
 
        parent = mem_cgroup_from_cont(pcg);
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask,
-                               &parent, false, page_size);
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask, nr_pages, &parent, false);
        if (ret || !parent)
                goto put_back;
 
-       if (page_size > PAGE_SIZE)
+       if (nr_pages > 1)
                flags = compound_lock_irqsave(page);
 
-       ret = mem_cgroup_move_account(pc, child, parent, true, page_size);
+       ret = mem_cgroup_move_account(page, nr_pages, pc, child, parent, true);
        if (ret)
-               mem_cgroup_cancel_charge(parent, page_size);
+               __mem_cgroup_cancel_charge(parent, nr_pages);
 
-       if (page_size > PAGE_SIZE)
+       if (nr_pages > 1)
                compound_unlock_irqrestore(page, flags);
 put_back:
        putback_lru_page(page);
@@ -2353,13 +2394,13 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask, enum charge_type ctype)
 {
        struct mem_cgroup *mem = NULL;
-       int page_size = PAGE_SIZE;
+       unsigned int nr_pages = 1;
        struct page_cgroup *pc;
        bool oom = true;
        int ret;
 
        if (PageTransHuge(page)) {
-               page_size <<= compound_order(page);
+               nr_pages <<= compound_order(page);
                VM_BUG_ON(!PageTransHuge(page));
                /*
                 * Never OOM-kill a process for a huge page.  The
@@ -2369,16 +2410,13 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
        }
 
        pc = lookup_page_cgroup(page);
-       /* can happen at boot */
-       if (unlikely(!pc))
-               return 0;
-       prefetchw(pc);
+       BUG_ON(!pc); /* XXX: remove this and move pc lookup into commit */
 
-       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, oom, page_size);
+       ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &mem, oom);
        if (ret || !mem)
                return ret;
 
-       __mem_cgroup_commit_charge(mem, pc, ctype, page_size);
+       __mem_cgroup_commit_charge(mem, page, nr_pages, pc, ctype);
        return 0;
 }
 
@@ -2406,9 +2444,26 @@ static void
 __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
                                        enum charge_type ctype);
 
+static void
+__mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *mem,
+                                       enum charge_type ctype)
+{
+       struct page_cgroup *pc = lookup_page_cgroup(page);
+       /*
+        * In some case, SwapCache, FUSE(splice_buf->radixtree), the page
+        * is already on LRU. It means the page may on some other page_cgroup's
+        * LRU. Take care of it.
+        */
+       mem_cgroup_lru_del_before_commit(page);
+       __mem_cgroup_commit_charge(mem, page, 1, pc, ctype);
+       mem_cgroup_lru_add_after_commit(page);
+       return;
+}
+
 int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
+       struct mem_cgroup *mem = NULL;
        int ret;
 
        if (mem_cgroup_disabled())
@@ -2443,14 +2498,22 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
        if (unlikely(!mm))
                mm = &init_mm;
 
-       if (page_is_file_cache(page))
-               return mem_cgroup_charge_common(page, mm, gfp_mask,
-                               MEM_CGROUP_CHARGE_TYPE_CACHE);
+       if (page_is_file_cache(page)) {
+               ret = __mem_cgroup_try_charge(mm, gfp_mask, 1, &mem, true);
+               if (ret || !mem)
+                       return ret;
 
+               /*
+                * FUSE reuses pages without going through the final
+                * put that would remove them from the LRU list, make
+                * sure that they get relinked properly.
+                */
+               __mem_cgroup_commit_charge_lrucare(page, mem,
+                                       MEM_CGROUP_CHARGE_TYPE_CACHE);
+               return ret;
+       }
        /* shmem */
        if (PageSwapCache(page)) {
-               struct mem_cgroup *mem = NULL;
-
                ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &mem);
                if (!ret)
                        __mem_cgroup_commit_charge_swapin(page, mem,
@@ -2475,6 +2538,8 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
        struct mem_cgroup *mem;
        int ret;
 
+       *ptr = NULL;
+
        if (mem_cgroup_disabled())
                return 0;
 
@@ -2492,30 +2557,26 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
        if (!mem)
                goto charge_cur_mm;
        *ptr = mem;
-       ret = __mem_cgroup_try_charge(NULL, mask, ptr, true, PAGE_SIZE);
+       ret = __mem_cgroup_try_charge(NULL, mask, 1, ptr, true);
        css_put(&mem->css);
        return ret;
 charge_cur_mm:
        if (unlikely(!mm))
                mm = &init_mm;
-       return __mem_cgroup_try_charge(mm, mask, ptr, true, PAGE_SIZE);
+       return __mem_cgroup_try_charge(mm, mask, 1, ptr, true);
 }
 
 static void
 __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
                                        enum charge_type ctype)
 {
-       struct page_cgroup *pc;
-
        if (mem_cgroup_disabled())
                return;
        if (!ptr)
                return;
        cgroup_exclude_rmdir(&ptr->css);
-       pc = lookup_page_cgroup(page);
-       mem_cgroup_lru_del_before_commit_swapcache(page);
-       __mem_cgroup_commit_charge(ptr, pc, ctype, PAGE_SIZE);
-       mem_cgroup_lru_add_after_commit_swapcache(page);
+
+       __mem_cgroup_commit_charge_lrucare(page, ptr, ctype);
        /*
         * Now swap is on-memory. This means this page may be
         * counted both as mem and swap....double count.
@@ -2563,15 +2624,16 @@ void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *mem)
                return;
        if (!mem)
                return;
-       mem_cgroup_cancel_charge(mem, PAGE_SIZE);
+       __mem_cgroup_cancel_charge(mem, 1);
 }
 
-static void
-__do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype,
-             int page_size)
+static void mem_cgroup_do_uncharge(struct mem_cgroup *mem,
+                                  unsigned int nr_pages,
+                                  const enum charge_type ctype)
 {
        struct memcg_batch_info *batch = NULL;
        bool uncharge_memsw = true;
+
        /* If swapout, usage of swap doesn't decrease */
        if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT)
                uncharge_memsw = false;
@@ -2595,7 +2657,7 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype,
        if (!batch->do_batch || test_thread_flag(TIF_MEMDIE))
                goto direct_uncharge;
 
-       if (page_size != PAGE_SIZE)
+       if (nr_pages > 1)
                goto direct_uncharge;
 
        /*
@@ -2606,14 +2668,14 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype,
        if (batch->memcg != mem)
                goto direct_uncharge;
        /* remember freed charge and uncharge it later */
-       batch->bytes += PAGE_SIZE;
+       batch->nr_pages++;
        if (uncharge_memsw)
-               batch->memsw_bytes += PAGE_SIZE;
+               batch->memsw_nr_pages++;
        return;
 direct_uncharge:
-       res_counter_uncharge(&mem->res, page_size);
+       res_counter_uncharge(&mem->res, nr_pages * PAGE_SIZE);
        if (uncharge_memsw)
-               res_counter_uncharge(&mem->memsw, page_size);
+               res_counter_uncharge(&mem->memsw, nr_pages * PAGE_SIZE);
        if (unlikely(batch->memcg != mem))
                memcg_oom_recover(mem);
        return;
@@ -2625,10 +2687,9 @@ direct_uncharge:
 static struct mem_cgroup *
 __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
 {
-       int count;
-       struct page_cgroup *pc;
        struct mem_cgroup *mem = NULL;
-       int page_size = PAGE_SIZE;
+       unsigned int nr_pages = 1;
+       struct page_cgroup *pc;
 
        if (mem_cgroup_disabled())
                return NULL;
@@ -2637,11 +2698,9 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
                return NULL;
 
        if (PageTransHuge(page)) {
-               page_size <<= compound_order(page);
+               nr_pages <<= compound_order(page);
                VM_BUG_ON(!PageTransHuge(page));
        }
-
-       count = page_size >> PAGE_SHIFT;
        /*
         * Check if our page_cgroup is valid
         */
@@ -2674,7 +2733,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
                break;
        }
 
-       mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -count);
+       mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -nr_pages);
 
        ClearPageCgroupUsed(pc);
        /*
@@ -2695,7 +2754,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
                mem_cgroup_get(mem);
        }
        if (!mem_cgroup_is_root(mem))
-               __do_uncharge(mem, ctype, page_size);
+               mem_cgroup_do_uncharge(mem, nr_pages, ctype);
 
        return mem;
 
@@ -2735,8 +2794,8 @@ void mem_cgroup_uncharge_start(void)
        /* We can do nest. */
        if (current->memcg_batch.do_batch == 1) {
                current->memcg_batch.memcg = NULL;
-               current->memcg_batch.bytes = 0;
-               current->memcg_batch.memsw_bytes = 0;
+               current->memcg_batch.nr_pages = 0;
+               current->memcg_batch.memsw_nr_pages = 0;
        }
 }
 
@@ -2757,10 +2816,12 @@ void mem_cgroup_uncharge_end(void)
         * This "batch->memcg" is valid without any css_get/put etc...
         * bacause we hide charges behind us.
         */
-       if (batch->bytes)
-               res_counter_uncharge(&batch->memcg->res, batch->bytes);
-       if (batch->memsw_bytes)
-               res_counter_uncharge(&batch->memcg->memsw, batch->memsw_bytes);
+       if (batch->nr_pages)
+               res_counter_uncharge(&batch->memcg->res,
+                                    batch->nr_pages * PAGE_SIZE);
+       if (batch->memsw_nr_pages)
+               res_counter_uncharge(&batch->memcg->memsw,
+                                    batch->memsw_nr_pages * PAGE_SIZE);
        memcg_oom_recover(batch->memcg);
        /* forget this pointer (for sanity check) */
        batch->memcg = NULL;
@@ -2883,13 +2944,15 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
  * page belongs to.
  */
 int mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr)
+       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask)
 {
-       struct page_cgroup *pc;
        struct mem_cgroup *mem = NULL;
+       struct page_cgroup *pc;
        enum charge_type ctype;
        int ret = 0;
 
+       *ptr = NULL;
+
        VM_BUG_ON(PageTransHuge(page));
        if (mem_cgroup_disabled())
                return 0;
@@ -2940,7 +3003,7 @@ int mem_cgroup_prepare_migration(struct page *page,
                return 0;
 
        *ptr = mem;
-       ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false, PAGE_SIZE);
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, ptr, false);
        css_put(&mem->css);/* drop extra refcnt */
        if (ret || *ptr == NULL) {
                if (PageAnon(page)) {
@@ -2967,7 +3030,7 @@ int mem_cgroup_prepare_migration(struct page *page,
                ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
        else
                ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
-       __mem_cgroup_commit_charge(mem, pc, ctype, PAGE_SIZE);
+       __mem_cgroup_commit_charge(mem, page, 1, pc, ctype);
        return ret;
 }
 
@@ -3032,7 +3095,7 @@ int mem_cgroup_shmem_charge_fallback(struct page *page,
                            struct mm_struct *mm,
                            gfp_t gfp_mask)
 {
-       struct mem_cgroup *mem = NULL;
+       struct mem_cgroup *mem;
        int ret;
 
        if (mem_cgroup_disabled())
@@ -3045,6 +3108,52 @@ int mem_cgroup_shmem_charge_fallback(struct page *page,
        return ret;
 }
 
+#ifdef CONFIG_DEBUG_VM
+static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
+{
+       struct page_cgroup *pc;
+
+       pc = lookup_page_cgroup(page);
+       if (likely(pc) && PageCgroupUsed(pc))
+               return pc;
+       return NULL;
+}
+
+bool mem_cgroup_bad_page_check(struct page *page)
+{
+       if (mem_cgroup_disabled())
+               return false;
+
+       return lookup_page_cgroup_used(page) != NULL;
+}
+
+void mem_cgroup_print_bad_page(struct page *page)
+{
+       struct page_cgroup *pc;
+
+       pc = lookup_page_cgroup_used(page);
+       if (pc) {
+               int ret = -1;
+               char *path;
+
+               printk(KERN_ALERT "pc:%p pc->flags:%lx pc->mem_cgroup:%p",
+                      pc, pc->flags, pc->mem_cgroup);
+
+               path = kmalloc(PATH_MAX, GFP_KERNEL);
+               if (path) {
+                       rcu_read_lock();
+                       ret = cgroup_path(pc->mem_cgroup->css.cgroup,
+                                                       path, PATH_MAX);
+                       rcu_read_unlock();
+               }
+
+               printk(KERN_CONT "(%s)\n",
+                               (ret < 0) ? "cannot get the path" : path);
+               kfree(path);
+       }
+}
+#endif
+
 static DEFINE_MUTEX(set_limit_mutex);
 
 static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
@@ -3288,6 +3397,8 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *mem,
        loop += 256;
        busy = NULL;
        while (loop--) {
+               struct page *page;
+
                ret = 0;
                spin_lock_irqsave(&zone->lru_lock, flags);
                if (list_empty(list)) {
@@ -3303,7 +3414,9 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *mem,
                }
                spin_unlock_irqrestore(&zone->lru_lock, flags);
 
-               ret = mem_cgroup_move_parent(pc, mem, GFP_KERNEL);
+               page = lookup_cgroup_page(pc);
+
+               ret = mem_cgroup_move_parent(page, pc, mem, GFP_KERNEL);
                if (ret == -ENOMEM)
                        break;
 
@@ -3451,13 +3564,13 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
 }
 
 
-static u64 mem_cgroup_get_recursive_idx_stat(struct mem_cgroup *mem,
-                               enum mem_cgroup_stat_index idx)
+static unsigned long mem_cgroup_recursive_stat(struct mem_cgroup *mem,
+                                              enum mem_cgroup_stat_index idx)
 {
        struct mem_cgroup *iter;
-       s64 val = 0;
+       long val = 0;
 
-       /* each per cpu's value can be minus.Then, use s64 */
+       /* Per-cpu values can be negative, use a signed accumulator */
        for_each_mem_cgroup_tree(iter, mem)
                val += mem_cgroup_read_stat(iter, idx);
 
@@ -3477,12 +3590,11 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *mem, bool swap)
                        return res_counter_read_u64(&mem->memsw, RES_USAGE);
        }
 
-       val = mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_CACHE);
-       val += mem_cgroup_get_recursive_idx_stat(mem, MEM_CGROUP_STAT_RSS);
+       val = mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_CACHE);
+       val += mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_RSS);
 
        if (swap)
-               val += mem_cgroup_get_recursive_idx_stat(mem,
-                               MEM_CGROUP_STAT_SWAPOUT);
+               val += mem_cgroup_recursive_stat(mem, MEM_CGROUP_STAT_SWAPOUT);
 
        return val << PAGE_SHIFT;
 }
@@ -3702,9 +3814,9 @@ mem_cgroup_get_local_stat(struct mem_cgroup *mem, struct mcs_total_stat *s)
        s->stat[MCS_RSS] += val * PAGE_SIZE;
        val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_FILE_MAPPED);
        s->stat[MCS_FILE_MAPPED] += val * PAGE_SIZE;
-       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGIN_COUNT);
+       val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGPGIN);
        s->stat[MCS_PGPGIN] += val;
-       val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_PGPGOUT_COUNT);
+       val = mem_cgroup_read_events(mem, MEM_CGROUP_EVENTS_PGPGOUT);
        s->stat[MCS_PGPGOUT] += val;
        if (do_swap_account) {
                val = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_SWAPOUT);
@@ -3828,9 +3940,7 @@ static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft,
                return -EINVAL;
        }
 
-       spin_lock(&memcg->reclaim_param_lock);
        memcg->swappiness = val;
-       spin_unlock(&memcg->reclaim_param_lock);
 
        cgroup_unlock();
 
@@ -4486,7 +4596,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&mem->memsw, NULL);
        }
        mem->last_scanned_child = 0;
-       spin_lock_init(&mem->reclaim_param_lock);
        INIT_LIST_HEAD(&mem->oom_notify);
 
        if (parent)
@@ -4574,8 +4683,7 @@ one_by_one:
                        batch_count = PRECHARGE_COUNT_AT_ONCE;
                        cond_resched();
                }
-               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false,
-                                             PAGE_SIZE);
+               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, 1, &mem, false);
                if (ret || !mem)
                        /* mem_cgroup_clear_mc() will do uncharge later */
                        return -ENOMEM;
@@ -4737,7 +4845,8 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
        pte_t *pte;
        spinlock_t *ptl;
 
-       VM_BUG_ON(pmd_trans_huge(*pmd));
+       split_huge_page_pmd(walk->mm, pmd);
+
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        for (; addr != end; pte++, addr += PAGE_SIZE)
                if (is_target_pte_for_mc(vma, addr, *pte, NULL))
@@ -4899,8 +5008,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
        pte_t *pte;
        spinlock_t *ptl;
 
+       split_huge_page_pmd(walk->mm, pmd);
 retry:
-       VM_BUG_ON(pmd_trans_huge(*pmd));
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        for (; addr != end; addr += PAGE_SIZE) {
                pte_t ptent = *(pte++);
@@ -4920,8 +5029,8 @@ retry:
                        if (isolate_lru_page(page))
                                goto put;
                        pc = lookup_page_cgroup(page);
-                       if (!mem_cgroup_move_account(pc,
-                                       mc.from, mc.to, false, PAGE_SIZE)) {
+                       if (!mem_cgroup_move_account(page, 1, pc,
+                                                    mc.from, mc.to, false)) {
                                mc.precharge--;
                                /* we uncharge from mc.from later. */
                                mc.moved_charge++;
index 99ccb44726232204b1a1fee9ddfabc4e2d5b2653..37feb9fec228ae6a8f34ba42d0845ca33ed5da32 100644 (file)
@@ -945,7 +945,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
                collect_procs(ppage, &tokill);
 
        if (hpage != ppage)
-               lock_page_nosync(ppage);
+               lock_page(ppage);
 
        ret = try_to_unmap(ppage, ttu);
        if (ret != SWAP_SUCCESS)
@@ -1038,7 +1038,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
                         * Check "just unpoisoned", "filter hit", and
                         * "race with other subpage."
                         */
-                       lock_page_nosync(hpage);
+                       lock_page(hpage);
                        if (!PageHWPoison(hpage)
                            || (hwpoison_filter(p) && TestClearPageHWPoison(p))
                            || (p != hpage && TestSetPageHWPoison(hpage))) {
@@ -1088,7 +1088,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * It's very difficult to mess with pages currently under IO
         * and in many cases impossible, so we just avoid it here.
         */
-       lock_page_nosync(hpage);
+       lock_page(hpage);
 
        /*
         * unpoison always clear PG_hwpoison inside page lock
@@ -1130,7 +1130,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
 
        /*
         * Now take care of user space mappings.
-        * Abort on fail: __remove_from_page_cache() assumes unmapped page.
+        * Abort on fail: __delete_from_page_cache() assumes unmapped page.
         */
        if (hwpoison_user_mappings(p, pfn, trapno) != SWAP_SUCCESS) {
                printk(KERN_ERR "MCE %#lx: cannot unmap page, give up\n", pfn);
@@ -1231,7 +1231,7 @@ int unpoison_memory(unsigned long pfn)
                return 0;
        }
 
-       lock_page_nosync(page);
+       lock_page(page);
        /*
         * This test is racy because PG_hwpoison is set outside of page lock.
         * That's acceptable because that won't trigger kernel panic. Instead,
index e48945ab362b87904d3a541e27902dc0d492cecb..51a5c23704afa29663863d308d682f0eb56c3a73 100644 (file)
@@ -1486,9 +1486,9 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                struct vm_area_struct *vma;
 
                vma = find_extend_vma(mm, start);
-               if (!vma && in_gate_area(tsk, start)) {
+               if (!vma && in_gate_area(mm, start)) {
                        unsigned long pg = start & PAGE_MASK;
-                       struct vm_area_struct *gate_vma = get_gate_vma(tsk);
+                       struct vm_area_struct *gate_vma = get_gate_vma(mm);
                        pgd_t *pgd;
                        pud_t *pud;
                        pmd_t *pmd;
@@ -1569,6 +1569,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                        fault_flags |= FAULT_FLAG_WRITE;
                                if (nonblocking)
                                        fault_flags |= FAULT_FLAG_ALLOW_RETRY;
+                               if (foll_flags & FOLL_NOWAIT)
+                                       fault_flags |= (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT);
 
                                ret = handle_mm_fault(mm, vma, start,
                                                        fault_flags);
@@ -1589,13 +1591,17 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                                return i ? i : -EFAULT;
                                        BUG();
                                }
-                               if (ret & VM_FAULT_MAJOR)
-                                       tsk->maj_flt++;
-                               else
-                                       tsk->min_flt++;
+
+                               if (tsk) {
+                                       if (ret & VM_FAULT_MAJOR)
+                                               tsk->maj_flt++;
+                                       else
+                                               tsk->min_flt++;
+                               }
 
                                if (ret & VM_FAULT_RETRY) {
-                                       *nonblocking = 0;
+                                       if (nonblocking)
+                                               *nonblocking = 0;
                                        return i;
                                }
 
@@ -1638,7 +1644,8 @@ EXPORT_SYMBOL(__get_user_pages);
 
 /**
  * get_user_pages() - pin user pages in memory
- * @tsk:       task_struct of target task
+ * @tsk:       the task_struct to use for page fault accounting, or
+ *             NULL if faults are not to be recorded.
  * @mm:                mm_struct of target mm
  * @start:     starting user address
  * @nr_pages:  number of pages from start to pin
@@ -2764,7 +2771,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        swp_entry_t entry;
        pte_t pte;
        int locked;
-       struct mem_cgroup *ptr = NULL;
+       struct mem_cgroup *ptr;
        int exclusive = 0;
        int ret = 0;
 
@@ -3496,7 +3503,7 @@ static int __init gate_vma_init(void)
 __initcall(gate_vma_init);
 #endif
 
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
 {
 #ifdef AT_SYSINFO_EHDR
        return &gate_vma;
@@ -3505,7 +3512,7 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
 #endif
 }
 
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
 #ifdef AT_SYSINFO_EHDR
        if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END))
@@ -3646,20 +3653,15 @@ int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
 #endif
 
 /*
- * Access another process' address space.
- * Source/target buffer must be kernel space,
- * Do not walk the page table directly, use get_user_pages
+ * Access another process' address space as given in mm.  If non-NULL, use the
+ * given task for page fault accounting.
  */
-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
+               unsigned long addr, void *buf, int len, int write)
 {
-       struct mm_struct *mm;
        struct vm_area_struct *vma;
        void *old_buf = buf;
 
-       mm = get_task_mm(tsk);
-       if (!mm)
-               return 0;
-
        down_read(&mm->mmap_sem);
        /* ignore errors, just check how much was successfully transferred */
        while (len) {
@@ -3708,11 +3710,47 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
                addr += bytes;
        }
        up_read(&mm->mmap_sem);
-       mmput(mm);
 
        return buf - old_buf;
 }
 
+/**
+ * @access_remote_vm - access another process' address space
+ * @mm:                the mm_struct of the target address space
+ * @addr:      start address to access
+ * @buf:       source or destination buffer
+ * @len:       number of bytes to transfer
+ * @write:     whether the access is a write
+ *
+ * The caller must hold a reference on @mm.
+ */
+int access_remote_vm(struct mm_struct *mm, unsigned long addr,
+               void *buf, int len, int write)
+{
+       return __access_remote_vm(NULL, mm, addr, buf, len, write);
+}
+
+/*
+ * Access another process' address space.
+ * Source/target buffer must be kernel space,
+ * Do not walk the page table directly, use get_user_pages
+ */
+int access_process_vm(struct task_struct *tsk, unsigned long addr,
+               void *buf, int len, int write)
+{
+       struct mm_struct *mm;
+       int ret;
+
+       mm = get_task_mm(tsk);
+       if (!mm)
+               return 0;
+
+       ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
+       mmput(mm);
+
+       return ret;
+}
+
 /*
  * Print the name of a VMA.
  */
index 78062ab641ff55f2a727afbf1fcf10aed843620c..959a8b8c7350c28ffa6cacced61b4c24977479da 100644 (file)
@@ -1979,8 +1979,7 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
        case MPOL_INTERLEAVE:
                return nodes_equal(a->v.nodes, b->v.nodes);
        case MPOL_PREFERRED:
-               return a->v.preferred_node == b->v.preferred_node &&
-                       a->flags == b->flags;
+               return a->v.preferred_node == b->v.preferred_node;
        default:
                BUG();
                return 0;
index 352de555626c4434471a53e29bee7a02516adfe3..b0406d739ea7a07b282e3e65a387a31770b40d11 100644 (file)
@@ -564,7 +564,7 @@ static int fallback_migrate_page(struct address_space *mapping,
  *  == 0 - success
  */
 static int move_to_new_page(struct page *newpage, struct page *page,
-                                               int remap_swapcache)
+                                       int remap_swapcache, bool sync)
 {
        struct address_space *mapping;
        int rc;
@@ -586,18 +586,28 @@ static int move_to_new_page(struct page *newpage, struct page *page,
        mapping = page_mapping(page);
        if (!mapping)
                rc = migrate_page(mapping, newpage, page);
-       else if (mapping->a_ops->migratepage)
+       else {
                /*
-                * Most pages have a mapping and most filesystems
-                * should provide a migration function. Anonymous
-                * pages are part of swap space which also has its
-                * own migration function. This is the most common
-                * path for page migration.
+                * Do not writeback pages if !sync and migratepage is
+                * not pointing to migrate_page() which is nonblocking
+                * (swapcache/tmpfs uses migratepage = migrate_page).
                 */
-               rc = mapping->a_ops->migratepage(mapping,
-                                               newpage, page);
-       else
-               rc = fallback_migrate_page(mapping, newpage, page);
+               if (PageDirty(page) && !sync &&
+                   mapping->a_ops->migratepage != migrate_page)
+                       rc = -EBUSY;
+               else if (mapping->a_ops->migratepage)
+                       /*
+                        * Most pages have a mapping and most filesystems
+                        * should provide a migration function. Anonymous
+                        * pages are part of swap space which also has its
+                        * own migration function. This is the most common
+                        * path for page migration.
+                        */
+                       rc = mapping->a_ops->migratepage(mapping,
+                                                       newpage, page);
+               else
+                       rc = fallback_migrate_page(mapping, newpage, page);
+       }
 
        if (rc) {
                newpage->mapping = NULL;
@@ -623,7 +633,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        struct page *newpage = get_new_page(page, private, &result);
        int remap_swapcache = 1;
        int charge = 0;
-       struct mem_cgroup *mem = NULL;
+       struct mem_cgroup *mem;
        struct anon_vma *anon_vma = NULL;
 
        if (!newpage)
@@ -641,7 +651,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        rc = -EAGAIN;
 
        if (!trylock_page(page)) {
-               if (!force)
+               if (!force || !sync)
                        goto move_newpage;
 
                /*
@@ -678,7 +688,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        }
 
        /* charge against new page */
-       charge = mem_cgroup_prepare_migration(page, newpage, &mem);
+       charge = mem_cgroup_prepare_migration(page, newpage, &mem, GFP_KERNEL);
        if (charge == -ENOMEM) {
                rc = -ENOMEM;
                goto unlock;
@@ -686,7 +696,15 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        BUG_ON(charge);
 
        if (PageWriteback(page)) {
-               if (!force || !sync)
+               /*
+                * For !sync, there is no point retrying as the retry loop
+                * is expected to be too short for PageWriteback to be cleared
+                */
+               if (!sync) {
+                       rc = -EBUSY;
+                       goto uncharge;
+               }
+               if (!force)
                        goto uncharge;
                wait_on_page_writeback(page);
        }
@@ -757,14 +775,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
 
 skip_unmap:
        if (!page_mapped(page))
-               rc = move_to_new_page(newpage, page, remap_swapcache);
+               rc = move_to_new_page(newpage, page, remap_swapcache, sync);
 
        if (rc && remap_swapcache)
                remove_migration_ptes(page, page);
 
        /* Drop an anon_vma reference if we took one */
        if (anon_vma)
-               drop_anon_vma(anon_vma);
+               put_anon_vma(anon_vma);
 
 uncharge:
        if (!charge)
@@ -850,13 +868,13 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
        if (!page_mapped(hpage))
-               rc = move_to_new_page(new_hpage, hpage, 1);
+               rc = move_to_new_page(new_hpage, hpage, 1, sync);
 
        if (rc)
                remove_migration_ptes(hpage, hpage);
 
        if (anon_vma)
-               drop_anon_vma(anon_vma);
+               put_anon_vma(anon_vma);
 out:
        unlock_page(hpage);
 
index c3924c7f00bead9d027b222e478a6a97462ac4c3..2689a08c79affabda1e46b65271c60e3ba653ab7 100644 (file)
@@ -237,7 +237,7 @@ long mlock_vma_pages_range(struct vm_area_struct *vma,
 
        if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) ||
                        is_vm_hugetlb_page(vma) ||
-                       vma == get_gate_vma(current))) {
+                       vma == get_gate_vma(current->mm))) {
 
                __mlock_vma_pages_range(vma, start, end, NULL);
 
@@ -332,7 +332,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
        int lock = newflags & VM_LOCKED;
 
        if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
-           is_vm_hugetlb_page(vma) || vma == get_gate_vma(current))
+           is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
                goto out;       /* don't set VM_LOCKED,  don't count */
 
        pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
index e2bdb07079cee8d67b7e1eb771fec6d509045145..e99f6cd1da1fccbb1756782c2218a75623b61b2f 100644 (file)
@@ -32,14 +32,6 @@ unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
 
-#ifdef CONFIG_CRASH_DUMP
-/*
- * If we have booted due to a crash, max_pfn will be a very low value. We need
- * to know the amount of memory that the previous kernel used.
- */
-unsigned long saved_max_pfn;
-#endif
-
 static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
                                        u64 goal, u64 limit)
 {
index f59e1424d3db650fc23617f60d060d6b68ce271b..cb86e7d5e7f5591c8508fba1f98a150e1e968e50 100644 (file)
@@ -1842,10 +1842,6 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
 }
 EXPORT_SYMBOL(remap_vmalloc_range);
 
-void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
-{
-}
-
 unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr,
        unsigned long len, unsigned long pgoff, unsigned long flags)
 {
@@ -1963,7 +1959,7 @@ error:
        return -ENOMEM;
 }
 
-int in_gate_area_no_task(unsigned long addr)
+int in_gate_area_no_mm(unsigned long addr)
 {
        return 0;
 }
index 7dcca55ede7ca1493df615af994f6ba23c1bb129..6a819d1b2c7dd70015b9fadff8f28d70f3b6f422 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/memcontrol.h>
 #include <linux/mempolicy.h>
 #include <linux/security.h>
+#include <linux/ptrace.h>
 
 int sysctl_panic_on_oom;
 int sysctl_oom_kill_allocating_task;
@@ -292,13 +293,15 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                unsigned long totalpages, struct mem_cgroup *mem,
                const nodemask_t *nodemask)
 {
-       struct task_struct *p;
+       struct task_struct *g, *p;
        struct task_struct *chosen = NULL;
        *ppoints = 0;
 
-       for_each_process(p) {
+       do_each_thread(g, p) {
                unsigned int points;
 
+               if (!p->mm)
+                       continue;
                if (oom_unkillable_task(p, mem, nodemask))
                        continue;
 
@@ -314,22 +317,29 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                if (test_tsk_thread_flag(p, TIF_MEMDIE))
                        return ERR_PTR(-1UL);
 
-               /*
-                * This is in the process of releasing memory so wait for it
-                * to finish before killing some other task by mistake.
-                *
-                * However, if p is the current task, we allow the 'kill' to
-                * go ahead if it is exiting: this will simply set TIF_MEMDIE,
-                * which will allow it to gain access to memory reserves in
-                * the process of exiting and releasing its resources.
-                * Otherwise we could get an easy OOM deadlock.
-                */
-               if (thread_group_empty(p) && (p->flags & PF_EXITING) && p->mm) {
-                       if (p != current)
-                               return ERR_PTR(-1UL);
-
-                       chosen = p;
-                       *ppoints = 1000;
+               if (p->flags & PF_EXITING) {
+                       /*
+                        * If p is the current task and is in the process of
+                        * releasing memory, we allow the "kill" to set
+                        * TIF_MEMDIE, which will allow it to gain access to
+                        * memory reserves.  Otherwise, it may stall forever.
+                        *
+                        * The loop isn't broken here, however, in case other
+                        * threads are found to have already been oom killed.
+                        */
+                       if (p == current) {
+                               chosen = p;
+                               *ppoints = 1000;
+                       } else {
+                               /*
+                                * If this task is not being ptraced on exit,
+                                * then wait for it to finish before killing
+                                * some other task unnecessarily.
+                                */
+                               if (!(task_ptrace(p->group_leader) &
+                                                       PT_TRACE_EXIT))
+                                       return ERR_PTR(-1UL);
+                       }
                }
 
                points = oom_badness(p, mem, nodemask, totalpages);
@@ -337,7 +347,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                        chosen = p;
                        *ppoints = points;
                }
-       }
+       } while_each_thread(g, p);
 
        return chosen;
 }
@@ -396,7 +406,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
        task_unlock(current);
        dump_stack();
        mem_cgroup_print_oom_info(mem, p);
-       show_mem();
+       show_mem(SHOW_MEM_FILTER_NODES);
        if (sysctl_oom_dump_tasks)
                dump_tasks(mem, nodemask);
 }
@@ -491,6 +501,8 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                list_for_each_entry(child, &t->children, sibling) {
                        unsigned int child_points;
 
+                       if (child->mm == p->mm)
+                               continue;
                        /*
                         * oom_badness() returns 0 if the thread is unkillable
                         */
@@ -537,6 +549,17 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        unsigned int points = 0;
        struct task_struct *p;
 
+       /*
+        * If current has a pending SIGKILL, then automatically select it.  The
+        * goal is to allow it to allocate so that it may quickly exit and free
+        * its memory.
+        */
+       if (fatal_signal_pending(current)) {
+               set_thread_flag(TIF_MEMDIE);
+               boost_dying_task_prio(current, NULL);
+               return;
+       }
+
        check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0, NULL);
        limit = mem_cgroup_get_limit(mem) >> PAGE_SHIFT;
        read_lock(&tasklist_lock);
index 2cb01f6ec5d019e7e431d9f18cdba6f3bde573e4..31f698862420021cc9b1e39e608077d1d468730a 100644 (file)
@@ -927,7 +927,7 @@ retry:
                                break;
                        }
 
-                       done_index = page->index + 1;
+                       done_index = page->index;
 
                        lock_page(page);
 
@@ -977,6 +977,7 @@ continue_unlock:
                                         * not be suitable for data integrity
                                         * writeout).
                                         */
+                                       done_index = page->index + 1;
                                        done = 1;
                                        break;
                                }
@@ -1039,11 +1040,17 @@ static int __writepage(struct page *page, struct writeback_control *wbc,
 int generic_writepages(struct address_space *mapping,
                       struct writeback_control *wbc)
 {
+       struct blk_plug plug;
+       int ret;
+
        /* deal with chardevs and other special file */
        if (!mapping->a_ops->writepage)
                return 0;
 
-       return write_cache_pages(mapping, wbc, __writepage, mapping);
+       blk_start_plug(&plug);
+       ret = write_cache_pages(mapping, wbc, __writepage, mapping);
+       blk_finish_plug(&plug);
+       return ret;
 }
 
 EXPORT_SYMBOL(generic_writepages);
@@ -1211,6 +1218,17 @@ int set_page_dirty(struct page *page)
 
        if (likely(mapping)) {
                int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
+               /*
+                * readahead/lru_deactivate_page could remain
+                * PG_readahead/PG_reclaim due to race with end_page_writeback
+                * About readahead, if the page is written, the flags would be
+                * reset. So no problem.
+                * About lru_deactivate_page, if the page is redirty, the flag
+                * will be reset. So no problem. but if the page is used by readahead
+                * it will confuse readahead and make it restart the size rampup
+                * process. But it's a trivial problem.
+                */
+               ClearPageReclaim(page);
 #ifdef CONFIG_BLOCK
                if (!spd)
                        spd = __set_page_dirty_buffers;
@@ -1239,7 +1257,7 @@ int set_page_dirty_lock(struct page *page)
 {
        int ret;
 
-       lock_page_nosync(page);
+       lock_page(page);
        ret = set_page_dirty(page);
        unlock_page(page);
        return ret;
@@ -1266,7 +1284,6 @@ int clear_page_dirty_for_io(struct page *page)
 
        BUG_ON(!PageLocked(page));
 
-       ClearPageReclaim(page);
        if (mapping && mapping_cap_account_dirty(mapping)) {
                /*
                 * Yes, Virginia, this is indeed insane.
index 7945247b1e534541ffa9cc145353191064ad6b2f..d6e7ba7373be7caea9f12eb73bf994df5ddc7467 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/compaction.h>
 #include <trace/events/kmem.h>
 #include <linux/ftrace_event.h>
+#include <linux/memcontrol.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -565,7 +566,8 @@ static inline int free_pages_check(struct page *page)
        if (unlikely(page_mapcount(page) |
                (page->mapping != NULL)  |
                (atomic_read(&page->_count) != 0) |
-               (page->flags & PAGE_FLAGS_CHECK_AT_FREE))) {
+               (page->flags & PAGE_FLAGS_CHECK_AT_FREE) |
+               (mem_cgroup_bad_page_check(page)))) {
                bad_page(page);
                return 1;
        }
@@ -614,6 +616,10 @@ static void free_pcppages_bulk(struct zone *zone, int count,
                        list = &pcp->lists[migratetype];
                } while (list_empty(list));
 
+               /* This is the only non-empty list. Free them all. */
+               if (batch_free == MIGRATE_PCPTYPES)
+                       batch_free = to_free;
+
                do {
                        page = list_entry(list->prev, struct page, lru);
                        /* must delete as __free_one_page list manipulates */
@@ -750,7 +756,8 @@ static inline int check_new_page(struct page *page)
        if (unlikely(page_mapcount(page) |
                (page->mapping != NULL)  |
                (atomic_read(&page->_count) != 0)  |
-               (page->flags & PAGE_FLAGS_CHECK_AT_PREP))) {
+               (page->flags & PAGE_FLAGS_CHECK_AT_PREP) |
+               (mem_cgroup_bad_page_check(page)))) {
                bad_page(page);
                return 1;
        }
@@ -863,9 +870,8 @@ static int move_freepages(struct zone *zone,
                }
 
                order = page_order(page);
-               list_del(&page->lru);
-               list_add(&page->lru,
-                       &zone->free_area[order].free_list[migratetype]);
+               list_move(&page->lru,
+                         &zone->free_area[order].free_list[migratetype]);
                page += 1 << order;
                pages_moved += 1 << order;
        }
@@ -1333,7 +1339,7 @@ again:
        }
 
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
-       zone_statistics(preferred_zone, zone);
+       zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
 
        VM_BUG_ON(bad_range(zone, page));
@@ -1714,6 +1720,20 @@ try_next_zone:
        return page;
 }
 
+/*
+ * Large machines with many possible nodes should not always dump per-node
+ * meminfo in irq context.
+ */
+static inline bool should_suppress_show_mem(void)
+{
+       bool ret = false;
+
+#if NODES_SHIFT > 8
+       ret = in_interrupt();
+#endif
+       return ret;
+}
+
 static inline int
 should_alloc_retry(gfp_t gfp_mask, unsigned int order,
                                unsigned long pages_reclaimed)
@@ -2085,7 +2105,7 @@ rebalance:
                                        sync_migration);
        if (page)
                goto got_pg;
-       sync_migration = true;
+       sync_migration = !(gfp_mask & __GFP_NO_KSWAPD);
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
@@ -2157,11 +2177,25 @@ rebalance:
 
 nopage:
        if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) {
-               printk(KERN_WARNING "%s: page allocation failure."
-                       " order:%d, mode:0x%x\n",
+               unsigned int filter = SHOW_MEM_FILTER_NODES;
+
+               /*
+                * This documents exceptions given to allocations in certain
+                * contexts that are allowed to allocate outside current's set
+                * of allowed nodes.
+                */
+               if (!(gfp_mask & __GFP_NOMEMALLOC))
+                       if (test_thread_flag(TIF_MEMDIE) ||
+                           (current->flags & (PF_MEMALLOC | PF_EXITING)))
+                               filter &= ~SHOW_MEM_FILTER_NODES;
+               if (in_interrupt() || !wait)
+                       filter &= ~SHOW_MEM_FILTER_NODES;
+
+               pr_warning("%s: page allocation failure. order:%d, mode:0x%x\n",
                        current->comm, order, gfp_mask);
                dump_stack();
-               show_mem();
+               if (!should_suppress_show_mem())
+                       show_mem(filter);
        }
        return page;
 got_pg:
@@ -2411,19 +2445,42 @@ void si_meminfo_node(struct sysinfo *val, int nid)
 }
 #endif
 
+/*
+ * Determine whether the zone's node should be displayed or not, depending on
+ * whether SHOW_MEM_FILTER_NODES was passed to __show_free_areas().
+ */
+static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
+{
+       bool ret = false;
+
+       if (!(flags & SHOW_MEM_FILTER_NODES))
+               goto out;
+
+       get_mems_allowed();
+       ret = !node_isset(zone->zone_pgdat->node_id,
+                               cpuset_current_mems_allowed);
+       put_mems_allowed();
+out:
+       return ret;
+}
+
 #define K(x) ((x) << (PAGE_SHIFT-10))
 
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
  * memory on each free list with the exception of the first item on the list.
+ * Suppresses nodes that are not allowed by current's cpuset if
+ * SHOW_MEM_FILTER_NODES is passed.
  */
-void show_free_areas(void)
+void __show_free_areas(unsigned int filter)
 {
        int cpu;
        struct zone *zone;
 
        for_each_populated_zone(zone) {
+               if (skip_free_areas_zone(filter, zone))
+                       continue;
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
 
@@ -2465,6 +2522,8 @@ void show_free_areas(void)
        for_each_populated_zone(zone) {
                int i;
 
+               if (skip_free_areas_zone(filter, zone))
+                       continue;
                show_node(zone);
                printk("%s"
                        " free:%lukB"
@@ -2532,6 +2591,8 @@ void show_free_areas(void)
        for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
+               if (skip_free_areas_zone(filter, zone))
+                       continue;
                show_node(zone);
                printk("%s: ", zone->name);
 
@@ -2551,6 +2612,11 @@ void show_free_areas(void)
        show_swap_cache_info();
 }
 
+void show_free_areas(void)
+{
+       __show_free_areas(0);
+}
+
 static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
 {
        zoneref->zone = zone;
@@ -5621,4 +5687,5 @@ void dump_page(struct page *page)
                page, atomic_read(&page->_count), page_mapcount(page),
                page->mapping, page->index);
        dump_page_flags(page->flags);
+       mem_cgroup_print_bad_page(page);
 }
index 5bffada7cde17a383e5ba510c2cca4be23463042..a12cc3fa98594b931c16012dd53a52dbd49fdb6f 100644 (file)
 #include <linux/swapops.h>
 #include <linux/kmemleak.h>
 
-static void __meminit
-__init_page_cgroup(struct page_cgroup *pc, unsigned long pfn)
+static void __meminit init_page_cgroup(struct page_cgroup *pc, unsigned long id)
 {
        pc->flags = 0;
+       set_page_cgroup_array_id(pc, id);
        pc->mem_cgroup = NULL;
-       pc->page = pfn_to_page(pfn);
        INIT_LIST_HEAD(&pc->lru);
 }
 static unsigned long total_usage;
@@ -43,6 +42,19 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
        return base + offset;
 }
 
+struct page *lookup_cgroup_page(struct page_cgroup *pc)
+{
+       unsigned long pfn;
+       struct page *page;
+       pg_data_t *pgdat;
+
+       pgdat = NODE_DATA(page_cgroup_array_id(pc));
+       pfn = pc - pgdat->node_page_cgroup + pgdat->node_start_pfn;
+       page = pfn_to_page(pfn);
+       VM_BUG_ON(pc != lookup_page_cgroup(page));
+       return page;
+}
+
 static int __init alloc_node_page_cgroup(int nid)
 {
        struct page_cgroup *base, *pc;
@@ -63,7 +75,7 @@ static int __init alloc_node_page_cgroup(int nid)
                return -ENOMEM;
        for (index = 0; index < nr_pages; index++) {
                pc = base + index;
-               __init_page_cgroup(pc, start_pfn + index);
+               init_page_cgroup(pc, nid);
        }
        NODE_DATA(nid)->node_page_cgroup = base;
        total_usage += table_size;
@@ -105,46 +117,75 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
        return section->page_cgroup + pfn;
 }
 
-/* __alloc_bootmem...() is protected by !slab_available() */
+struct page *lookup_cgroup_page(struct page_cgroup *pc)
+{
+       struct mem_section *section;
+       struct page *page;
+       unsigned long nr;
+
+       nr = page_cgroup_array_id(pc);
+       section = __nr_to_section(nr);
+       page = pfn_to_page(pc - section->page_cgroup);
+       VM_BUG_ON(pc != lookup_page_cgroup(page));
+       return page;
+}
+
+static void *__init_refok alloc_page_cgroup(size_t size, int nid)
+{
+       void *addr = NULL;
+
+       addr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN);
+       if (addr)
+               return addr;
+
+       if (node_state(nid, N_HIGH_MEMORY))
+               addr = vmalloc_node(size, nid);
+       else
+               addr = vmalloc(size);
+
+       return addr;
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+static void free_page_cgroup(void *addr)
+{
+       if (is_vmalloc_addr(addr)) {
+               vfree(addr);
+       } else {
+               struct page *page = virt_to_page(addr);
+               size_t table_size =
+                       sizeof(struct page_cgroup) * PAGES_PER_SECTION;
+
+               BUG_ON(PageReserved(page));
+               free_pages_exact(addr, table_size);
+       }
+}
+#endif
+
 static int __init_refok init_section_page_cgroup(unsigned long pfn)
 {
-       struct mem_section *section = __pfn_to_section(pfn);
        struct page_cgroup *base, *pc;
+       struct mem_section *section;
        unsigned long table_size;
+       unsigned long nr;
        int nid, index;
 
-       if (!section->page_cgroup) {
-               nid = page_to_nid(pfn_to_page(pfn));
-               table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-               VM_BUG_ON(!slab_is_available());
-               if (node_state(nid, N_HIGH_MEMORY)) {
-                       base = kmalloc_node(table_size,
-                               GFP_KERNEL | __GFP_NOWARN, nid);
-                       if (!base)
-                               base = vmalloc_node(table_size, nid);
-               } else {
-                       base = kmalloc(table_size, GFP_KERNEL | __GFP_NOWARN);
-                       if (!base)
-                               base = vmalloc(table_size);
-               }
-               /*
-                * The value stored in section->page_cgroup is (base - pfn)
-                * and it does not point to the memory block allocated above,
-                * causing kmemleak false positives.
-                */
-               kmemleak_not_leak(base);
-       } else {
-               /*
-                * We don't have to allocate page_cgroup again, but
-                * address of memmap may be changed. So, we have to initialize
-                * again.
-                */
-               base = section->page_cgroup + pfn;
-               table_size = 0;
-               /* check address of memmap is changed or not. */
-               if (base->page == pfn_to_page(pfn))
-                       return 0;
-       }
+       nr = pfn_to_section_nr(pfn);
+       section = __nr_to_section(nr);
+
+       if (section->page_cgroup)
+               return 0;
+
+       nid = page_to_nid(pfn_to_page(pfn));
+       table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
+       base = alloc_page_cgroup(table_size, nid);
+
+       /*
+        * The value stored in section->page_cgroup is (base - pfn)
+        * and it does not point to the memory block allocated above,
+        * causing kmemleak false positives.
+        */
+       kmemleak_not_leak(base);
 
        if (!base) {
                printk(KERN_ERR "page cgroup allocation failure\n");
@@ -153,7 +194,7 @@ static int __init_refok init_section_page_cgroup(unsigned long pfn)
 
        for (index = 0; index < PAGES_PER_SECTION; index++) {
                pc = base + index;
-               __init_page_cgroup(pc, pfn + index);
+               init_page_cgroup(pc, nr);
        }
 
        section->page_cgroup = base - pfn;
@@ -170,16 +211,8 @@ void __free_page_cgroup(unsigned long pfn)
        if (!ms || !ms->page_cgroup)
                return;
        base = ms->page_cgroup + pfn;
-       if (is_vmalloc_addr(base)) {
-               vfree(base);
-               ms->page_cgroup = NULL;
-       } else {
-               struct page *page = virt_to_page(base);
-               if (!PageReserved(page)) { /* Is bootmem ? */
-                       kfree(base);
-                       ms->page_cgroup = NULL;
-               }
-       }
+       free_page_cgroup(base);
+       ms->page_cgroup = NULL;
 }
 
 int __meminit online_page_cgroup(unsigned long start_pfn,
@@ -243,12 +276,7 @@ static int __meminit page_cgroup_callback(struct notifier_block *self,
                break;
        }
 
-       if (ret)
-               ret = notifier_from_errno(ret);
-       else
-               ret = NOTIFY_OK;
-
-       return ret;
+       return notifier_from_errno(ret);
 }
 
 #endif
index 2dee975bf469003dd02e2f318399c16a428e4937..dc76b4d0611ecb59fd85d89a78896c792443a62f 100644 (file)
@@ -106,7 +106,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
                goto out;
        }
        if (wbc->sync_mode == WB_SYNC_ALL)
-               rw |= REQ_SYNC | REQ_UNPLUG;
+               rw |= REQ_SYNC;
        count_vm_event(PSWPOUT);
        set_page_writeback(page);
        unlock_page(page);
index 7cfa6ae023038ef4d1f05c6224c85faad173d533..c3450d5336111830ad0b572efc08000006de13bd 100644 (file)
@@ -33,19 +33,35 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
 
        pmd = pmd_offset(pud, addr);
        do {
+again:
                next = pmd_addr_end(addr, end);
-               split_huge_page_pmd(walk->mm, pmd);
-               if (pmd_none_or_clear_bad(pmd)) {
+               if (pmd_none(*pmd)) {
                        if (walk->pte_hole)
                                err = walk->pte_hole(addr, next, walk);
                        if (err)
                                break;
                        continue;
                }
+               /*
+                * This implies that each ->pmd_entry() handler
+                * needs to know about pmd_trans_huge() pmds
+                */
                if (walk->pmd_entry)
                        err = walk->pmd_entry(pmd, addr, next, walk);
-               if (!err && walk->pte_entry)
-                       err = walk_pte_range(pmd, addr, next, walk);
+               if (err)
+                       break;
+
+               /*
+                * Check this here so we only break down trans_huge
+                * pages when we _need_ to
+                */
+               if (!walk->pte_entry)
+                       continue;
+
+               split_huge_page_pmd(walk->mm, pmd);
+               if (pmd_none_or_clear_bad(pmd))
+                       goto again;
+               err = walk_pte_range(pmd, addr, next, walk);
                if (err)
                        break;
        } while (pmd++, addr = next, addr != end);
index 77506a291a2d4caa90c64839896df7b9176bbaa1..2c0cc489e2880cb319a92b905a5ee7b292039b7f 100644 (file)
@@ -109,9 +109,12 @@ EXPORT_SYMBOL(read_cache_pages);
 static int read_pages(struct address_space *mapping, struct file *filp,
                struct list_head *pages, unsigned nr_pages)
 {
+       struct blk_plug plug;
        unsigned page_idx;
        int ret;
 
+       blk_start_plug(&plug);
+
        if (mapping->a_ops->readpages) {
                ret = mapping->a_ops->readpages(filp, mapping, pages, nr_pages);
                /* Clean up the remaining pages */
@@ -129,7 +132,10 @@ static int read_pages(struct address_space *mapping, struct file *filp,
                page_cache_release(page);
        }
        ret = 0;
+
 out:
+       blk_finish_plug(&plug);
+
        return ret;
 }
 
@@ -554,17 +560,5 @@ page_cache_async_readahead(struct address_space *mapping,
 
        /* do read-ahead */
        ondemand_readahead(mapping, ra, filp, true, offset, req_size);
-
-#ifdef CONFIG_BLOCK
-       /*
-        * Normally the current page is !uptodate and lock_page() will be
-        * immediately called to implicitly unplug the device. However this
-        * is not always true for RAID conifgurations, where data arrives
-        * not strictly in their submission order. In this case we need to
-        * explicitly kick off the IO.
-        */
-       if (PageUptodate(page))
-               blk_run_backing_dev(mapping->backing_dev_info, NULL);
-#endif
 }
 EXPORT_SYMBOL_GPL(page_cache_async_readahead);
index 941bf82e896128b618284ae17a25d963c13838fc..8da044a1db0f4db1524f2450cd733e41eb8690ca 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
  *             swap_lock (in swap_duplicate, swap_info_get)
  *               mmlist_lock (in mmput, drain_mmlist and others)
  *               mapping->private_lock (in __set_page_dirty_buffers)
- *               inode_lock (in set_page_dirty's __mark_inode_dirty)
+ *               inode->i_lock (in set_page_dirty's __mark_inode_dirty)
+ *               inode_wb_list_lock (in set_page_dirty's __mark_inode_dirty)
  *                 sb_lock (within inode_lock in fs/fs-writeback.c)
  *                 mapping->tree_lock (widely used, in set_page_dirty,
  *                           in arch-dependent flush_dcache_mmap_lock,
- *                           within inode_lock in __sync_single_inode)
+ *                           within inode_wb_list_lock in __sync_single_inode)
  *
  * (code doesn't rely on that order so it could be switched around)
  * ->tasklist_lock
@@ -67,11 +68,24 @@ static struct kmem_cache *anon_vma_chain_cachep;
 
 static inline struct anon_vma *anon_vma_alloc(void)
 {
-       return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
+       struct anon_vma *anon_vma;
+
+       anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
+       if (anon_vma) {
+               atomic_set(&anon_vma->refcount, 1);
+               /*
+                * Initialise the anon_vma root to point to itself. If called
+                * from fork, the root will be reset to the parents anon_vma.
+                */
+               anon_vma->root = anon_vma;
+       }
+
+       return anon_vma;
 }
 
-void anon_vma_free(struct anon_vma *anon_vma)
+static inline void anon_vma_free(struct anon_vma *anon_vma)
 {
+       VM_BUG_ON(atomic_read(&anon_vma->refcount));
        kmem_cache_free(anon_vma_cachep, anon_vma);
 }
 
@@ -133,11 +147,6 @@ int anon_vma_prepare(struct vm_area_struct *vma)
                        if (unlikely(!anon_vma))
                                goto out_enomem_free_avc;
                        allocated = anon_vma;
-                       /*
-                        * This VMA had no anon_vma yet.  This anon_vma is
-                        * the root of any anon_vma tree that might form.
-                        */
-                       anon_vma->root = anon_vma;
                }
 
                anon_vma_lock(anon_vma);
@@ -156,7 +165,7 @@ int anon_vma_prepare(struct vm_area_struct *vma)
                anon_vma_unlock(anon_vma);
 
                if (unlikely(allocated))
-                       anon_vma_free(allocated);
+                       put_anon_vma(allocated);
                if (unlikely(avc))
                        anon_vma_chain_free(avc);
        }
@@ -241,9 +250,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
         */
        anon_vma->root = pvma->anon_vma->root;
        /*
-        * With KSM refcounts, an anon_vma can stay around longer than the
-        * process it belongs to.  The root anon_vma needs to be pinned
-        * until this anon_vma is freed, because the lock lives in the root.
+        * With refcounts, an anon_vma can stay around longer than the
+        * process it belongs to. The root anon_vma needs to be pinned until
+        * this anon_vma is freed, because the lock lives in the root.
         */
        get_anon_vma(anon_vma->root);
        /* Mark this anon_vma as the one where our new (COWed) pages go. */
@@ -253,7 +262,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        return 0;
 
  out_error_free_anon_vma:
-       anon_vma_free(anon_vma);
+       put_anon_vma(anon_vma);
  out_error:
        unlink_anon_vmas(vma);
        return -ENOMEM;
@@ -272,15 +281,11 @@ static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain)
        list_del(&anon_vma_chain->same_anon_vma);
 
        /* We must garbage collect the anon_vma if it's empty */
-       empty = list_empty(&anon_vma->head) && !anonvma_external_refcount(anon_vma);
+       empty = list_empty(&anon_vma->head);
        anon_vma_unlock(anon_vma);
 
-       if (empty) {
-               /* We no longer need the root anon_vma */
-               if (anon_vma->root != anon_vma)
-                       drop_anon_vma(anon_vma->root);
-               anon_vma_free(anon_vma);
-       }
+       if (empty)
+               put_anon_vma(anon_vma);
 }
 
 void unlink_anon_vmas(struct vm_area_struct *vma)
@@ -303,7 +308,7 @@ static void anon_vma_ctor(void *data)
        struct anon_vma *anon_vma = data;
 
        spin_lock_init(&anon_vma->lock);
-       anonvma_external_refcount_init(anon_vma);
+       atomic_set(&anon_vma->refcount, 0);
        INIT_LIST_HEAD(&anon_vma->head);
 }
 
@@ -1486,41 +1491,15 @@ int try_to_munlock(struct page *page)
                return try_to_unmap_file(page, TTU_MUNLOCK);
 }
 
-#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
-/*
- * Drop an anon_vma refcount, freeing the anon_vma and anon_vma->root
- * if necessary.  Be careful to do all the tests under the lock.  Once
- * we know we are the last user, nobody else can get a reference and we
- * can do the freeing without the lock.
- */
-void drop_anon_vma(struct anon_vma *anon_vma)
+void __put_anon_vma(struct anon_vma *anon_vma)
 {
-       BUG_ON(atomic_read(&anon_vma->external_refcount) <= 0);
-       if (atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->root->lock)) {
-               struct anon_vma *root = anon_vma->root;
-               int empty = list_empty(&anon_vma->head);
-               int last_root_user = 0;
-               int root_empty = 0;
+       struct anon_vma *root = anon_vma->root;
 
-               /*
-                * The refcount on a non-root anon_vma got dropped.  Drop
-                * the refcount on the root and check if we need to free it.
-                */
-               if (empty && anon_vma != root) {
-                       BUG_ON(atomic_read(&root->external_refcount) <= 0);
-                       last_root_user = atomic_dec_and_test(&root->external_refcount);
-                       root_empty = list_empty(&root->head);
-               }
-               anon_vma_unlock(anon_vma);
+       if (root != anon_vma && atomic_dec_and_test(&root->refcount))
+               anon_vma_free(root);
 
-               if (empty) {
-                       anon_vma_free(anon_vma);
-                       if (root_empty && last_root_user)
-                               anon_vma_free(root);
-               }
-       }
+       anon_vma_free(anon_vma);
 }
-#endif
 
 #ifdef CONFIG_MIGRATION
 /*
index 048a95a5244d4eb5522c7aa17fa94ca625f660f5..58da7c150ba6d7b4132f423663ff920345038d7c 100644 (file)
@@ -224,7 +224,6 @@ static const struct vm_operations_struct shmem_vm_ops;
 static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
        .ra_pages       = 0,    /* No readahead */
        .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
-       .unplug_io_fn   = default_unplug_io_fn,
 };
 
 static LIST_HEAD(shmem_swaplist);
@@ -1081,7 +1080,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        shmem_recalc_inode(inode);
 
        if (swap.val && add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
-               remove_from_page_cache(page);
+               delete_from_page_cache(page);
                shmem_swp_set(info, entry, swap.val);
                shmem_swp_unmap(entry);
                if (list_empty(&info->swaplist))
@@ -1091,7 +1090,6 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                spin_unlock(&info->lock);
                swap_shmem_alloc(swap);
                BUG_ON(page_mapped(page));
-               page_cache_release(page);       /* pagecache ref */
                swap_writepage(page, wbc);
                if (inode) {
                        mutex_lock(&shmem_swaplist_mutex);
@@ -2794,5 +2792,6 @@ int shmem_zero_setup(struct vm_area_struct *vma)
                fput(vma->vm_file);
        vma->vm_file = file;
        vma->vm_ops = &shmem_vm_ops;
+       vma->vm_flags |= VM_CAN_NONLINEAR;
        return 0;
 }
index 37961d1f584fed737f52a9981673bc7be9011efe..568803f121a8769b73b5d76c7b49ea82b3f8e10f 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -190,22 +190,6 @@ typedef unsigned int kmem_bufctl_t;
 #define        BUFCTL_ACTIVE   (((kmem_bufctl_t)(~0U))-2)
 #define        SLAB_LIMIT      (((kmem_bufctl_t)(~0U))-3)
 
-/*
- * struct slab
- *
- * Manages the objs in a slab. Placed either at the beginning of mem allocated
- * for a slab, or allocated from an general cache.
- * Slabs are chained into three list: fully used, partial, fully free slabs.
- */
-struct slab {
-       struct list_head list;
-       unsigned long colouroff;
-       void *s_mem;            /* including colour offset */
-       unsigned int inuse;     /* num of objs active in slab */
-       kmem_bufctl_t free;
-       unsigned short nodeid;
-};
-
 /*
  * struct slab_rcu
  *
@@ -219,8 +203,6 @@ struct slab {
  *
  * rcu_read_lock before reading the address, then rcu_read_unlock after
  * taking the spinlock within the structure expected at that address.
- *
- * We assume struct slab_rcu can overlay struct slab when destroying.
  */
 struct slab_rcu {
        struct rcu_head head;
@@ -228,6 +210,27 @@ struct slab_rcu {
        void *addr;
 };
 
+/*
+ * struct slab
+ *
+ * Manages the objs in a slab. Placed either at the beginning of mem allocated
+ * for a slab, or allocated from an general cache.
+ * Slabs are chained into three list: fully used, partial, fully free slabs.
+ */
+struct slab {
+       union {
+               struct {
+                       struct list_head list;
+                       unsigned long colouroff;
+                       void *s_mem;            /* including colour offset */
+                       unsigned int inuse;     /* num of objs active in slab */
+                       kmem_bufctl_t free;
+                       unsigned short nodeid;
+               };
+               struct slab_rcu __slab_cover_slab_rcu;
+       };
+};
+
 /*
  * struct array_cache
  *
@@ -1387,7 +1390,7 @@ static int __meminit slab_memory_callback(struct notifier_block *self,
                break;
        }
 out:
-       return ret ? notifier_from_errno(ret) : NOTIFY_OK;
+       return notifier_from_errno(ret);
 }
 #endif /* CONFIG_NUMA && CONFIG_MEMORY_HOTPLUG */
 
@@ -2147,8 +2150,6 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
  *
  * @name must be valid until the cache is destroyed. This implies that
  * the module calling this has to destroy the cache before getting unloaded.
- * Note that kmem_cache_name() is not guaranteed to return the same pointer,
- * therefore applications must manage it themselves.
  *
  * The flags are
  *
@@ -2288,8 +2289,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        if (ralign < align) {
                ralign = align;
        }
-       /* disable debug if not aligning with REDZONE_ALIGN */
-       if (ralign & (__alignof__(unsigned long long) - 1))
+       /* disable debug if necessary */
+       if (ralign > __alignof__(unsigned long long))
                flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
        /*
         * 4) Store it.
@@ -2315,8 +2316,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
         */
        if (flags & SLAB_RED_ZONE) {
                /* add space for red zone words */
-               cachep->obj_offset += align;
-               size += align + sizeof(unsigned long long);
+               cachep->obj_offset += sizeof(unsigned long long);
+               size += 2 * sizeof(unsigned long long);
        }
        if (flags & SLAB_STORE_USER) {
                /* user store requires one word storage behind the end of
@@ -3840,12 +3841,6 @@ unsigned int kmem_cache_size(struct kmem_cache *cachep)
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
-const char *kmem_cache_name(struct kmem_cache *cachep)
-{
-       return cachep->name;
-}
-EXPORT_SYMBOL_GPL(kmem_cache_name);
-
 /*
  * This initializes kmem_list3 or resizes various caches for all nodes.
  */
index 3588eaaef7267284ed6fb2a0d6475717ed622db5..46e0aee33a235068bcaf6144dc299ed0ff248991 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -666,12 +666,6 @@ unsigned int kmem_cache_size(struct kmem_cache *c)
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
-const char *kmem_cache_name(struct kmem_cache *c)
-{
-       return c->name;
-}
-EXPORT_SYMBOL(kmem_cache_name);
-
 int kmem_cache_shrink(struct kmem_cache *d)
 {
        return 0;
index e15aa7f193c9734518f3c3508210c70f294e4ad3..f881874843a5ff67a3d1cef595c35bf72a3c3565 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -217,7 +217,7 @@ static inline void sysfs_slab_remove(struct kmem_cache *s)
 
 #endif
 
-static inline void stat(struct kmem_cache *s, enum stat_item si)
+static inline void stat(const struct kmem_cache *s, enum stat_item si)
 {
 #ifdef CONFIG_SLUB_STATS
        __this_cpu_inc(s->cpu_slab->stat[si]);
@@ -281,11 +281,40 @@ static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
        return (p - addr) / s->size;
 }
 
+static inline size_t slab_ksize(const struct kmem_cache *s)
+{
+#ifdef CONFIG_SLUB_DEBUG
+       /*
+        * Debugging requires use of the padding between object
+        * and whatever may come after it.
+        */
+       if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
+               return s->objsize;
+
+#endif
+       /*
+        * If we have the need to store the freelist pointer
+        * back there or track user information then we can
+        * only use the space before that information.
+        */
+       if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
+               return s->inuse;
+       /*
+        * Else we can use all the padding etc for the allocation
+        */
+       return s->size;
+}
+
+static inline int order_objects(int order, unsigned long size, int reserved)
+{
+       return ((PAGE_SIZE << order) - reserved) / size;
+}
+
 static inline struct kmem_cache_order_objects oo_make(int order,
-                                               unsigned long size)
+               unsigned long size, int reserved)
 {
        struct kmem_cache_order_objects x = {
-               (order << OO_SHIFT) + (PAGE_SIZE << order) / size
+               (order << OO_SHIFT) + order_objects(order, size, reserved)
        };
 
        return x;
@@ -617,7 +646,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
                return 1;
 
        start = page_address(page);
-       length = (PAGE_SIZE << compound_order(page));
+       length = (PAGE_SIZE << compound_order(page)) - s->reserved;
        end = start + length;
        remainder = length % s->size;
        if (!remainder)
@@ -698,7 +727,7 @@ static int check_slab(struct kmem_cache *s, struct page *page)
                return 0;
        }
 
-       maxobj = (PAGE_SIZE << compound_order(page)) / s->size;
+       maxobj = order_objects(compound_order(page), s->size, s->reserved);
        if (page->objects > maxobj) {
                slab_err(s, page, "objects %u > max %u",
                        s->name, page->objects, maxobj);
@@ -748,7 +777,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
                nr++;
        }
 
-       max_objects = (PAGE_SIZE << compound_order(page)) / s->size;
+       max_objects = order_objects(compound_order(page), s->size, s->reserved);
        if (max_objects > MAX_OBJS_PER_PAGE)
                max_objects = MAX_OBJS_PER_PAGE;
 
@@ -800,21 +829,31 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
 static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
 {
        flags &= gfp_allowed_mask;
-       kmemcheck_slab_alloc(s, flags, object, s->objsize);
+       kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
        kmemleak_alloc_recursive(object, s->objsize, 1, s->flags, flags);
 }
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x)
 {
        kmemleak_free_recursive(x, s->flags);
-}
 
-static inline void slab_free_hook_irq(struct kmem_cache *s, void *object)
-{
-       kmemcheck_slab_free(s, object, s->objsize);
-       debug_check_no_locks_freed(object, s->objsize);
+       /*
+        * Trouble is that we may no longer disable interupts in the fast path
+        * So in order to make the debug calls that expect irqs to be
+        * disabled we need to disable interrupts temporarily.
+        */
+#if defined(CONFIG_KMEMCHECK) || defined(CONFIG_LOCKDEP)
+       {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               kmemcheck_slab_free(s, x, s->objsize);
+               debug_check_no_locks_freed(x, s->objsize);
+               local_irq_restore(flags);
+       }
+#endif
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
-               debug_check_no_obj_freed(object, s->objsize);
+               debug_check_no_obj_freed(x, s->objsize);
 }
 
 /*
@@ -1101,9 +1140,6 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
 
 static inline void slab_free_hook(struct kmem_cache *s, void *x) {}
 
-static inline void slab_free_hook_irq(struct kmem_cache *s,
-               void *object) {}
-
 #endif /* CONFIG_SLUB_DEBUG */
 
 /*
@@ -1249,21 +1285,38 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
        __free_pages(page, order);
 }
 
+#define need_reserve_slab_rcu                                          \
+       (sizeof(((struct page *)NULL)->lru) < sizeof(struct rcu_head))
+
 static void rcu_free_slab(struct rcu_head *h)
 {
        struct page *page;
 
-       page = container_of((struct list_head *)h, struct page, lru);
+       if (need_reserve_slab_rcu)
+               page = virt_to_head_page(h);
+       else
+               page = container_of((struct list_head *)h, struct page, lru);
+
        __free_slab(page->slab, page);
 }
 
 static void free_slab(struct kmem_cache *s, struct page *page)
 {
        if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
-               /*
-                * RCU free overloads the RCU head over the LRU
-                */
-               struct rcu_head *head = (void *)&page->lru;
+               struct rcu_head *head;
+
+               if (need_reserve_slab_rcu) {
+                       int order = compound_order(page);
+                       int offset = (PAGE_SIZE << order) - s->reserved;
+
+                       VM_BUG_ON(s->reserved != sizeof(*head));
+                       head = page_address(page) + offset;
+               } else {
+                       /*
+                        * RCU free overloads the RCU head over the LRU
+                        */
+                       head = (void *)&page->lru;
+               }
 
                call_rcu(head, rcu_free_slab);
        } else
@@ -1487,6 +1540,78 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
        }
 }
 
+#ifdef CONFIG_CMPXCHG_LOCAL
+#ifdef CONFIG_PREEMPT
+/*
+ * Calculate the next globally unique transaction for disambiguiation
+ * during cmpxchg. The transactions start with the cpu number and are then
+ * incremented by CONFIG_NR_CPUS.
+ */
+#define TID_STEP  roundup_pow_of_two(CONFIG_NR_CPUS)
+#else
+/*
+ * No preemption supported therefore also no need to check for
+ * different cpus.
+ */
+#define TID_STEP 1
+#endif
+
+static inline unsigned long next_tid(unsigned long tid)
+{
+       return tid + TID_STEP;
+}
+
+static inline unsigned int tid_to_cpu(unsigned long tid)
+{
+       return tid % TID_STEP;
+}
+
+static inline unsigned long tid_to_event(unsigned long tid)
+{
+       return tid / TID_STEP;
+}
+
+static inline unsigned int init_tid(int cpu)
+{
+       return cpu;
+}
+
+static inline void note_cmpxchg_failure(const char *n,
+               const struct kmem_cache *s, unsigned long tid)
+{
+#ifdef SLUB_DEBUG_CMPXCHG
+       unsigned long actual_tid = __this_cpu_read(s->cpu_slab->tid);
+
+       printk(KERN_INFO "%s %s: cmpxchg redo ", n, s->name);
+
+#ifdef CONFIG_PREEMPT
+       if (tid_to_cpu(tid) != tid_to_cpu(actual_tid))
+               printk("due to cpu change %d -> %d\n",
+                       tid_to_cpu(tid), tid_to_cpu(actual_tid));
+       else
+#endif
+       if (tid_to_event(tid) != tid_to_event(actual_tid))
+               printk("due to cpu running other code. Event %ld->%ld\n",
+                       tid_to_event(tid), tid_to_event(actual_tid));
+       else
+               printk("for unknown reason: actual=%lx was=%lx target=%lx\n",
+                       actual_tid, tid, next_tid(tid));
+#endif
+       stat(s, CMPXCHG_DOUBLE_CPU_FAIL);
+}
+
+#endif
+
+void init_kmem_cache_cpus(struct kmem_cache *s)
+{
+#ifdef CONFIG_CMPXCHG_LOCAL
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
+#endif
+
+}
 /*
  * Remove the cpu slab
  */
@@ -1518,6 +1643,9 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
                page->inuse--;
        }
        c->page = NULL;
+#ifdef CONFIG_CMPXCHG_LOCAL
+       c->tid = next_tid(c->tid);
+#endif
        unfreeze_slab(s, page, tail);
 }
 
@@ -1652,6 +1780,19 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 {
        void **object;
        struct page *new;
+#ifdef CONFIG_CMPXCHG_LOCAL
+       unsigned long flags;
+
+       local_irq_save(flags);
+#ifdef CONFIG_PREEMPT
+       /*
+        * We may have been preempted and rescheduled on a different
+        * cpu before disabling interrupts. Need to reload cpu area
+        * pointer.
+        */
+       c = this_cpu_ptr(s->cpu_slab);
+#endif
+#endif
 
        /* We handle __GFP_ZERO in the caller */
        gfpflags &= ~__GFP_ZERO;
@@ -1678,6 +1819,10 @@ load_freelist:
        c->node = page_to_nid(c->page);
 unlock_out:
        slab_unlock(c->page);
+#ifdef CONFIG_CMPXCHG_LOCAL
+       c->tid = next_tid(c->tid);
+       local_irq_restore(flags);
+#endif
        stat(s, ALLOC_SLOWPATH);
        return object;
 
@@ -1713,6 +1858,9 @@ new_slab:
        }
        if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
                slab_out_of_memory(s, gfpflags, node);
+#ifdef CONFIG_CMPXCHG_LOCAL
+       local_irq_restore(flags);
+#endif
        return NULL;
 debug:
        if (!alloc_debug_processing(s, c->page, object, addr))
@@ -1739,23 +1887,76 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
 {
        void **object;
        struct kmem_cache_cpu *c;
+#ifdef CONFIG_CMPXCHG_LOCAL
+       unsigned long tid;
+#else
        unsigned long flags;
+#endif
 
        if (slab_pre_alloc_hook(s, gfpflags))
                return NULL;
 
+#ifndef CONFIG_CMPXCHG_LOCAL
        local_irq_save(flags);
+#else
+redo:
+#endif
+
+       /*
+        * Must read kmem_cache cpu data via this cpu ptr. Preemption is
+        * enabled. We may switch back and forth between cpus while
+        * reading from one cpu area. That does not matter as long
+        * as we end up on the original cpu again when doing the cmpxchg.
+        */
        c = __this_cpu_ptr(s->cpu_slab);
+
+#ifdef CONFIG_CMPXCHG_LOCAL
+       /*
+        * The transaction ids are globally unique per cpu and per operation on
+        * a per cpu queue. Thus they can be guarantee that the cmpxchg_double
+        * occurs on the right processor and that there was no operation on the
+        * linked list in between.
+        */
+       tid = c->tid;
+       barrier();
+#endif
+
        object = c->freelist;
        if (unlikely(!object || !node_match(c, node)))
 
                object = __slab_alloc(s, gfpflags, node, addr, c);
 
        else {
+#ifdef CONFIG_CMPXCHG_LOCAL
+               /*
+                * The cmpxchg will only match if there was no additonal
+                * operation and if we are on the right processor.
+                *
+                * The cmpxchg does the following atomically (without lock semantics!)
+                * 1. Relocate first pointer to the current per cpu area.
+                * 2. Verify that tid and freelist have not been changed
+                * 3. If they were not changed replace tid and freelist
+                *
+                * Since this is without lock semantics the protection is only against
+                * code executing on this cpu *not* from access by other cpus.
+                */
+               if (unlikely(!this_cpu_cmpxchg_double(
+                               s->cpu_slab->freelist, s->cpu_slab->tid,
+                               object, tid,
+                               get_freepointer(s, object), next_tid(tid)))) {
+
+                       note_cmpxchg_failure("slab_alloc", s, tid);
+                       goto redo;
+               }
+#else
                c->freelist = get_freepointer(s, object);
+#endif
                stat(s, ALLOC_FASTPATH);
        }
+
+#ifndef CONFIG_CMPXCHG_LOCAL
        local_irq_restore(flags);
+#endif
 
        if (unlikely(gfpflags & __GFP_ZERO) && object)
                memset(object, 0, s->objsize);
@@ -1833,9 +2034,13 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 {
        void *prior;
        void **object = (void *)x;
+#ifdef CONFIG_CMPXCHG_LOCAL
+       unsigned long flags;
 
-       stat(s, FREE_SLOWPATH);
+       local_irq_save(flags);
+#endif
        slab_lock(page);
+       stat(s, FREE_SLOWPATH);
 
        if (kmem_cache_debug(s))
                goto debug;
@@ -1865,6 +2070,9 @@ checks_ok:
 
 out_unlock:
        slab_unlock(page);
+#ifdef CONFIG_CMPXCHG_LOCAL
+       local_irq_restore(flags);
+#endif
        return;
 
 slab_empty:
@@ -1876,6 +2084,9 @@ slab_empty:
                stat(s, FREE_REMOVE_PARTIAL);
        }
        slab_unlock(page);
+#ifdef CONFIG_CMPXCHG_LOCAL
+       local_irq_restore(flags);
+#endif
        stat(s, FREE_SLAB);
        discard_slab(s, page);
        return;
@@ -1902,23 +2113,56 @@ static __always_inline void slab_free(struct kmem_cache *s,
 {
        void **object = (void *)x;
        struct kmem_cache_cpu *c;
+#ifdef CONFIG_CMPXCHG_LOCAL
+       unsigned long tid;
+#else
        unsigned long flags;
+#endif
 
        slab_free_hook(s, x);
 
+#ifndef CONFIG_CMPXCHG_LOCAL
        local_irq_save(flags);
+
+#else
+redo:
+#endif
+
+       /*
+        * Determine the currently cpus per cpu slab.
+        * The cpu may change afterward. However that does not matter since
+        * data is retrieved via this pointer. If we are on the same cpu
+        * during the cmpxchg then the free will succedd.
+        */
        c = __this_cpu_ptr(s->cpu_slab);
 
-       slab_free_hook_irq(s, x);
+#ifdef CONFIG_CMPXCHG_LOCAL
+       tid = c->tid;
+       barrier();
+#endif
 
        if (likely(page == c->page && c->node != NUMA_NO_NODE)) {
                set_freepointer(s, object, c->freelist);
+
+#ifdef CONFIG_CMPXCHG_LOCAL
+               if (unlikely(!this_cpu_cmpxchg_double(
+                               s->cpu_slab->freelist, s->cpu_slab->tid,
+                               c->freelist, tid,
+                               object, next_tid(tid)))) {
+
+                       note_cmpxchg_failure("slab_free", s, tid);
+                       goto redo;
+               }
+#else
                c->freelist = object;
+#endif
                stat(s, FREE_FASTPATH);
        } else
                __slab_free(s, page, x, addr);
 
+#ifndef CONFIG_CMPXCHG_LOCAL
        local_irq_restore(flags);
+#endif
 }
 
 void kmem_cache_free(struct kmem_cache *s, void *x)
@@ -1988,13 +2232,13 @@ static int slub_nomerge;
  * the smallest order which will fit the object.
  */
 static inline int slab_order(int size, int min_objects,
-                               int max_order, int fract_leftover)
+                               int max_order, int fract_leftover, int reserved)
 {
        int order;
        int rem;
        int min_order = slub_min_order;
 
-       if ((PAGE_SIZE << min_order) / size > MAX_OBJS_PER_PAGE)
+       if (order_objects(min_order, size, reserved) > MAX_OBJS_PER_PAGE)
                return get_order(size * MAX_OBJS_PER_PAGE) - 1;
 
        for (order = max(min_order,
@@ -2003,10 +2247,10 @@ static inline int slab_order(int size, int min_objects,
 
                unsigned long slab_size = PAGE_SIZE << order;
 
-               if (slab_size < min_objects * size)
+               if (slab_size < min_objects * size + reserved)
                        continue;
 
-               rem = slab_size % size;
+               rem = (slab_size - reserved) % size;
 
                if (rem <= slab_size / fract_leftover)
                        break;
@@ -2016,7 +2260,7 @@ static inline int slab_order(int size, int min_objects,
        return order;
 }
 
-static inline int calculate_order(int size)
+static inline int calculate_order(int size, int reserved)
 {
        int order;
        int min_objects;
@@ -2034,14 +2278,14 @@ static inline int calculate_order(int size)
        min_objects = slub_min_objects;
        if (!min_objects)
                min_objects = 4 * (fls(nr_cpu_ids) + 1);
-       max_objects = (PAGE_SIZE << slub_max_order)/size;
+       max_objects = order_objects(slub_max_order, size, reserved);
        min_objects = min(min_objects, max_objects);
 
        while (min_objects > 1) {
                fraction = 16;
                while (fraction >= 4) {
                        order = slab_order(size, min_objects,
-                                               slub_max_order, fraction);
+                                       slub_max_order, fraction, reserved);
                        if (order <= slub_max_order)
                                return order;
                        fraction /= 2;
@@ -2053,14 +2297,14 @@ static inline int calculate_order(int size)
         * We were unable to place multiple objects in a slab. Now
         * lets see if we can place a single object there.
         */
-       order = slab_order(size, 1, slub_max_order, 1);
+       order = slab_order(size, 1, slub_max_order, 1, reserved);
        if (order <= slub_max_order)
                return order;
 
        /*
         * Doh this slab cannot be placed using slub_max_order.
         */
-       order = slab_order(size, 1, MAX_ORDER, 1);
+       order = slab_order(size, 1, MAX_ORDER, 1, reserved);
        if (order < MAX_ORDER)
                return order;
        return -ENOSYS;
@@ -2110,9 +2354,23 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
        BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
                        SLUB_PAGE_SHIFT * sizeof(struct kmem_cache_cpu));
 
+#ifdef CONFIG_CMPXCHG_LOCAL
+       /*
+        * Must align to double word boundary for the double cmpxchg instructions
+        * to work.
+        */
+       s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu), 2 * sizeof(void *));
+#else
+       /* Regular alignment is sufficient */
        s->cpu_slab = alloc_percpu(struct kmem_cache_cpu);
+#endif
+
+       if (!s->cpu_slab)
+               return 0;
 
-       return s->cpu_slab != NULL;
+       init_kmem_cache_cpus(s);
+
+       return 1;
 }
 
 static struct kmem_cache *kmem_cache_node;
@@ -2311,7 +2569,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
        if (forced_order >= 0)
                order = forced_order;
        else
-               order = calculate_order(size);
+               order = calculate_order(size, s->reserved);
 
        if (order < 0)
                return 0;
@@ -2329,8 +2587,8 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
        /*
         * Determine the number of objects per slab
         */
-       s->oo = oo_make(order, size);
-       s->min = oo_make(get_order(size), size);
+       s->oo = oo_make(order, size, s->reserved);
+       s->min = oo_make(get_order(size), size, s->reserved);
        if (oo_objects(s->oo) > oo_objects(s->max))
                s->max = s->oo;
 
@@ -2349,6 +2607,10 @@ static int kmem_cache_open(struct kmem_cache *s,
        s->objsize = size;
        s->align = align;
        s->flags = kmem_cache_flags(size, flags, name, ctor);
+       s->reserved = 0;
+
+       if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
+               s->reserved = sizeof(struct rcu_head);
 
        if (!calculate_sizes(s, -1))
                goto error;
@@ -2399,12 +2661,6 @@ unsigned int kmem_cache_size(struct kmem_cache *s)
 }
 EXPORT_SYMBOL(kmem_cache_size);
 
-const char *kmem_cache_name(struct kmem_cache *s)
-{
-       return s->name;
-}
-EXPORT_SYMBOL(kmem_cache_name);
-
 static void list_slab_objects(struct kmem_cache *s, struct page *page,
                                                        const char *text)
 {
@@ -2696,7 +2952,6 @@ EXPORT_SYMBOL(__kmalloc_node);
 size_t ksize(const void *object)
 {
        struct page *page;
-       struct kmem_cache *s;
 
        if (unlikely(object == ZERO_SIZE_PTR))
                return 0;
@@ -2707,28 +2962,8 @@ size_t ksize(const void *object)
                WARN_ON(!PageCompound(page));
                return PAGE_SIZE << compound_order(page);
        }
-       s = page->slab;
-
-#ifdef CONFIG_SLUB_DEBUG
-       /*
-        * Debugging requires use of the padding between object
-        * and whatever may come after it.
-        */
-       if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
-               return s->objsize;
 
-#endif
-       /*
-        * If we have the need to store the freelist pointer
-        * back there or track user information then we can
-        * only use the space before that information.
-        */
-       if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
-               return s->inuse;
-       /*
-        * Else we can use all the padding etc for the allocation
-        */
-       return s->size;
+       return slab_ksize(page->slab);
 }
 EXPORT_SYMBOL(ksize);
 
@@ -4017,6 +4252,12 @@ static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
 }
 SLAB_ATTR_RO(destroy_by_rcu);
 
+static ssize_t reserved_show(struct kmem_cache *s, char *buf)
+{
+       return sprintf(buf, "%d\n", s->reserved);
+}
+SLAB_ATTR_RO(reserved);
+
 #ifdef CONFIG_SLUB_DEBUG
 static ssize_t slabs_show(struct kmem_cache *s, char *buf)
 {
@@ -4303,6 +4544,7 @@ static struct attribute *slab_attrs[] = {
        &reclaim_account_attr.attr,
        &destroy_by_rcu_attr.attr,
        &shrink_attr.attr,
+       &reserved_attr.attr,
 #ifdef CONFIG_SLUB_DEBUG
        &total_objects_attr.attr,
        &slabs_attr.attr,
index c02f93611a849e6c79bdbae2e13ee6e4cff6eb37..a448db377cb046d0871506f156b430dceed818fe 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -39,6 +39,7 @@ int page_cluster;
 
 static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS], lru_add_pvecs);
 static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
+static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);
 
 /*
  * This path almost never happens for VM activity - pages are normally
@@ -178,15 +179,13 @@ void put_pages_list(struct list_head *pages)
 }
 EXPORT_SYMBOL(put_pages_list);
 
-/*
- * pagevec_move_tail() must be called with IRQ disabled.
- * Otherwise this may cause nasty races.
- */
-static void pagevec_move_tail(struct pagevec *pvec)
+static void pagevec_lru_move_fn(struct pagevec *pvec,
+                               void (*move_fn)(struct page *page, void *arg),
+                               void *arg)
 {
        int i;
-       int pgmoved = 0;
        struct zone *zone = NULL;
+       unsigned long flags = 0;
 
        for (i = 0; i < pagevec_count(pvec); i++) {
                struct page *page = pvec->pages[i];
@@ -194,29 +193,50 @@ static void pagevec_move_tail(struct pagevec *pvec)
 
                if (pagezone != zone) {
                        if (zone)
-                               spin_unlock(&zone->lru_lock);
+                               spin_unlock_irqrestore(&zone->lru_lock, flags);
                        zone = pagezone;
-                       spin_lock(&zone->lru_lock);
-               }
-               if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
-                       int lru = page_lru_base_type(page);
-                       list_move_tail(&page->lru, &zone->lru[lru].list);
-                       pgmoved++;
+                       spin_lock_irqsave(&zone->lru_lock, flags);
                }
+
+               (*move_fn)(page, arg);
        }
        if (zone)
-               spin_unlock(&zone->lru_lock);
-       __count_vm_events(PGROTATED, pgmoved);
+               spin_unlock_irqrestore(&zone->lru_lock, flags);
        release_pages(pvec->pages, pvec->nr, pvec->cold);
        pagevec_reinit(pvec);
 }
 
+static void pagevec_move_tail_fn(struct page *page, void *arg)
+{
+       int *pgmoved = arg;
+       struct zone *zone = page_zone(page);
+
+       if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
+               enum lru_list lru = page_lru_base_type(page);
+               list_move_tail(&page->lru, &zone->lru[lru].list);
+               mem_cgroup_rotate_reclaimable_page(page);
+               (*pgmoved)++;
+       }
+}
+
+/*
+ * pagevec_move_tail() must be called with IRQ disabled.
+ * Otherwise this may cause nasty races.
+ */
+static void pagevec_move_tail(struct pagevec *pvec)
+{
+       int pgmoved = 0;
+
+       pagevec_lru_move_fn(pvec, pagevec_move_tail_fn, &pgmoved);
+       __count_vm_events(PGROTATED, pgmoved);
+}
+
 /*
  * Writeback is about to end against a page which has been marked for immediate
  * reclaim.  If it still appears to be reclaimable, move it to the tail of the
  * inactive list.
  */
-void  rotate_reclaimable_page(struct page *page)
+void rotate_reclaimable_page(struct page *page)
 {
        if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) &&
            !PageUnevictable(page) && PageLRU(page)) {
@@ -346,6 +366,71 @@ void add_page_to_unevictable_list(struct page *page)
        spin_unlock_irq(&zone->lru_lock);
 }
 
+/*
+ * If the page can not be invalidated, it is moved to the
+ * inactive list to speed up its reclaim.  It is moved to the
+ * head of the list, rather than the tail, to give the flusher
+ * threads some time to write it out, as this is much more
+ * effective than the single-page writeout from reclaim.
+ *
+ * If the page isn't page_mapped and dirty/writeback, the page
+ * could reclaim asap using PG_reclaim.
+ *
+ * 1. active, mapped page -> none
+ * 2. active, dirty/writeback page -> inactive, head, PG_reclaim
+ * 3. inactive, mapped page -> none
+ * 4. inactive, dirty/writeback page -> inactive, head, PG_reclaim
+ * 5. inactive, clean -> inactive, tail
+ * 6. Others -> none
+ *
+ * In 4, why it moves inactive's head, the VM expects the page would
+ * be write it out by flusher threads as this is much more effective
+ * than the single-page writeout from reclaim.
+ */
+static void lru_deactivate_fn(struct page *page, void *arg)
+{
+       int lru, file;
+       bool active;
+       struct zone *zone = page_zone(page);
+
+       if (!PageLRU(page))
+               return;
+
+       /* Some processes are using the page */
+       if (page_mapped(page))
+               return;
+
+       active = PageActive(page);
+
+       file = page_is_file_cache(page);
+       lru = page_lru_base_type(page);
+       del_page_from_lru_list(zone, page, lru + active);
+       ClearPageActive(page);
+       ClearPageReferenced(page);
+       add_page_to_lru_list(zone, page, lru);
+
+       if (PageWriteback(page) || PageDirty(page)) {
+               /*
+                * PG_reclaim could be raced with end_page_writeback
+                * It can make readahead confusing.  But race window
+                * is _really_ small and  it's non-critical problem.
+                */
+               SetPageReclaim(page);
+       } else {
+               /*
+                * The page's writeback ends up during pagevec
+                * We moves tha page into tail of inactive.
+                */
+               list_move_tail(&page->lru, &zone->lru[lru].list);
+               mem_cgroup_rotate_reclaimable_page(page);
+               __count_vm_event(PGROTATED);
+       }
+
+       if (active)
+               __count_vm_event(PGDEACTIVATE);
+       update_page_reclaim_stat(zone, page, file, 0);
+}
+
 /*
  * Drain pages out of the cpu's pagevecs.
  * Either "cpu" is the current CPU, and preemption has already been
@@ -372,6 +457,29 @@ static void drain_cpu_pagevecs(int cpu)
                pagevec_move_tail(pvec);
                local_irq_restore(flags);
        }
+
+       pvec = &per_cpu(lru_deactivate_pvecs, cpu);
+       if (pagevec_count(pvec))
+               pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+}
+
+/**
+ * deactivate_page - forcefully deactivate a page
+ * @page: page to deactivate
+ *
+ * This function hints the VM that @page is a good reclaim candidate,
+ * for example if its invalidation fails due to the page being dirty
+ * or under writeback.
+ */
+void deactivate_page(struct page *page)
+{
+       if (likely(get_page_unless_zero(page))) {
+               struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs);
+
+               if (!pagevec_add(pvec, page))
+                       pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+               put_cpu_var(lru_deactivate_pvecs);
+       }
 }
 
 void lru_add_drain(void)
@@ -516,44 +624,33 @@ void lru_add_page_tail(struct zone* zone,
        }
 }
 
+static void ____pagevec_lru_add_fn(struct page *page, void *arg)
+{
+       enum lru_list lru = (enum lru_list)arg;
+       struct zone *zone = page_zone(page);
+       int file = is_file_lru(lru);
+       int active = is_active_lru(lru);
+
+       VM_BUG_ON(PageActive(page));
+       VM_BUG_ON(PageUnevictable(page));
+       VM_BUG_ON(PageLRU(page));
+
+       SetPageLRU(page);
+       if (active)
+               SetPageActive(page);
+       update_page_reclaim_stat(zone, page, file, active);
+       add_page_to_lru_list(zone, page, lru);
+}
+
 /*
  * Add the passed pages to the LRU, then drop the caller's refcount
  * on them.  Reinitialises the caller's pagevec.
  */
 void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
 {
-       int i;
-       struct zone *zone = NULL;
-
        VM_BUG_ON(is_unevictable_lru(lru));
 
-       for (i = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-               struct zone *pagezone = page_zone(page);
-               int file;
-               int active;
-
-               if (pagezone != zone) {
-                       if (zone)
-                               spin_unlock_irq(&zone->lru_lock);
-                       zone = pagezone;
-                       spin_lock_irq(&zone->lru_lock);
-               }
-               VM_BUG_ON(PageActive(page));
-               VM_BUG_ON(PageUnevictable(page));
-               VM_BUG_ON(PageLRU(page));
-               SetPageLRU(page);
-               active = is_active_lru(lru);
-               file = is_file_lru(lru);
-               if (active)
-                       SetPageActive(page);
-               update_page_reclaim_stat(zone, page, file, active);
-               add_page_to_lru_list(zone, page, lru);
-       }
-       if (zone)
-               spin_unlock_irq(&zone->lru_lock);
-       release_pages(pvec->pages, pvec->nr, pvec->cold);
-       pagevec_reinit(pvec);
+       pagevec_lru_move_fn(pvec, ____pagevec_lru_add_fn, (void *)lru);
 }
 
 EXPORT_SYMBOL(____pagevec_lru_add);
index 5c8cfabbc9bc3abdbf7f342656ea8c58b727aae8..46680461785bef647c3618bc7d493d1909aea80f 100644 (file)
 
 /*
  * swapper_space is a fiction, retained to simplify the path through
- * vmscan's shrink_page_list, to make sync_page look nicer, and to allow
- * future use of radix_tree tags in the swap cache.
+ * vmscan's shrink_page_list.
  */
 static const struct address_space_operations swap_aops = {
        .writepage      = swap_writepage,
-       .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
        .migratepage    = migrate_page,
 };
@@ -37,7 +35,6 @@ static const struct address_space_operations swap_aops = {
 static struct backing_dev_info swap_backing_dev_info = {
        .name           = "swap",
        .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
-       .unplug_io_fn   = swap_unplug_io_fn,
 };
 
 struct address_space swapper_space = {
index 0341c5700e346fa62401e9815720ed85af3a20c9..8c6b3ce38f09aa0e4f824ce3f70e6e9254a87724 100644 (file)
@@ -94,39 +94,6 @@ __try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset)
        return ret;
 }
 
-/*
- * We need this because the bdev->unplug_fn can sleep and we cannot
- * hold swap_lock while calling the unplug_fn. And swap_lock
- * cannot be turned into a mutex.
- */
-static DECLARE_RWSEM(swap_unplug_sem);
-
-void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
-{
-       swp_entry_t entry;
-
-       down_read(&swap_unplug_sem);
-       entry.val = page_private(page);
-       if (PageSwapCache(page)) {
-               struct block_device *bdev = swap_info[swp_type(entry)]->bdev;
-               struct backing_dev_info *bdi;
-
-               /*
-                * If the page is removed from swapcache from under us (with a
-                * racy try_to_unuse/swapoff) we need an additional reference
-                * count to avoid reading garbage from page_private(page) above.
-                * If the WARN_ON triggers during a swapoff it maybe the race
-                * condition and it's harmless. However if it triggers without
-                * swapoff it signals a problem.
-                */
-               WARN_ON(page_count(page) <= 1);
-
-               bdi = bdev->bd_inode->i_mapping->backing_dev_info;
-               blk_run_backing_dev(bdi, page);
-       }
-       up_read(&swap_unplug_sem);
-}
-
 /*
  * swapon tell device that all the old swap contents can be discarded,
  * to allow the swap device to optimize its wear-levelling.
@@ -212,8 +179,8 @@ static int wait_for_discard(void *word)
 #define SWAPFILE_CLUSTER       256
 #define LATENCY_LIMIT          256
 
-static inline unsigned long scan_swap_map(struct swap_info_struct *si,
-                                         unsigned char usage)
+static unsigned long scan_swap_map(struct swap_info_struct *si,
+                                  unsigned char usage)
 {
        unsigned long offset;
        unsigned long scan_base;
@@ -880,7 +847,7 @@ unsigned int count_swap_pages(int type, int free)
 static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
-       struct mem_cgroup *ptr = NULL;
+       struct mem_cgroup *ptr;
        spinlock_t *ptl;
        pte_t *pte;
        int ret = 1;
@@ -1550,6 +1517,36 @@ bad_bmap:
        goto out;
 }
 
+static void enable_swap_info(struct swap_info_struct *p, int prio,
+                               unsigned char *swap_map)
+{
+       int i, prev;
+
+       spin_lock(&swap_lock);
+       if (prio >= 0)
+               p->prio = prio;
+       else
+               p->prio = --least_priority;
+       p->swap_map = swap_map;
+       p->flags |= SWP_WRITEOK;
+       nr_swap_pages += p->pages;
+       total_swap_pages += p->pages;
+
+       /* insert swap space into swap_list: */
+       prev = -1;
+       for (i = swap_list.head; i >= 0; i = swap_info[i]->next) {
+               if (p->prio >= swap_info[i]->prio)
+                       break;
+               prev = i;
+       }
+       p->next = i;
+       if (prev < 0)
+               swap_list.head = swap_list.next = p->type;
+       else
+               swap_info[prev]->next = p->type;
+       spin_unlock(&swap_lock);
+}
+
 SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 {
        struct swap_info_struct *p = NULL;
@@ -1621,32 +1618,17 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        current->flags &= ~PF_OOM_ORIGIN;
 
        if (err) {
+               /*
+                * reading p->prio and p->swap_map outside the lock is
+                * safe here because only sys_swapon and sys_swapoff
+                * change them, and there can be no other sys_swapon or
+                * sys_swapoff for this swap_info_struct at this point.
+                */
                /* re-insert swap space back into swap_list */
-               spin_lock(&swap_lock);
-               if (p->prio < 0)
-                       p->prio = --least_priority;
-               prev = -1;
-               for (i = swap_list.head; i >= 0; i = swap_info[i]->next) {
-                       if (p->prio >= swap_info[i]->prio)
-                               break;
-                       prev = i;
-               }
-               p->next = i;
-               if (prev < 0)
-                       swap_list.head = swap_list.next = type;
-               else
-                       swap_info[prev]->next = type;
-               nr_swap_pages += p->pages;
-               total_swap_pages += p->pages;
-               p->flags |= SWP_WRITEOK;
-               spin_unlock(&swap_lock);
+               enable_swap_info(p, p->prio, p->swap_map);
                goto out_dput;
        }
 
-       /* wait for any unplug function to finish */
-       down_write(&swap_unplug_sem);
-       up_write(&swap_unplug_sem);
-
        destroy_swap_extents(p);
        if (p->flags & SWP_CONTINUED)
                free_swap_count_continuations(p);
@@ -1844,49 +1826,24 @@ static int __init max_swapfiles_check(void)
 late_initcall(max_swapfiles_check);
 #endif
 
-/*
- * Written 01/25/92 by Simmule Turner, heavily changed by Linus.
- *
- * The swapon system call
- */
-SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
+static struct swap_info_struct *alloc_swap_info(void)
 {
        struct swap_info_struct *p;
-       char *name = NULL;
-       struct block_device *bdev = NULL;
-       struct file *swap_file = NULL;
-       struct address_space *mapping;
        unsigned int type;
-       int i, prev;
-       int error;
-       union swap_header *swap_header;
-       unsigned int nr_good_pages;
-       int nr_extents = 0;
-       sector_t span;
-       unsigned long maxpages;
-       unsigned long swapfilepages;
-       unsigned char *swap_map = NULL;
-       struct page *page = NULL;
-       struct inode *inode = NULL;
-       int did_down = 0;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
 
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        spin_lock(&swap_lock);
        for (type = 0; type < nr_swapfiles; type++) {
                if (!(swap_info[type]->flags & SWP_USED))
                        break;
        }
-       error = -EPERM;
        if (type >= MAX_SWAPFILES) {
                spin_unlock(&swap_lock);
                kfree(p);
-               goto out;
+               return ERR_PTR(-EPERM);
        }
        if (type >= nr_swapfiles) {
                p->type = type;
@@ -1911,81 +1868,49 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        p->next = -1;
        spin_unlock(&swap_lock);
 
-       name = getname(specialfile);
-       error = PTR_ERR(name);
-       if (IS_ERR(name)) {
-               name = NULL;
-               goto bad_swap_2;
-       }
-       swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0);
-       error = PTR_ERR(swap_file);
-       if (IS_ERR(swap_file)) {
-               swap_file = NULL;
-               goto bad_swap_2;
-       }
-
-       p->swap_file = swap_file;
-       mapping = swap_file->f_mapping;
-       inode = mapping->host;
-
-       error = -EBUSY;
-       for (i = 0; i < nr_swapfiles; i++) {
-               struct swap_info_struct *q = swap_info[i];
+       return p;
+}
 
-               if (i == type || !q->swap_file)
-                       continue;
-               if (mapping == q->swap_file->f_mapping)
-                       goto bad_swap;
-       }
+static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
+{
+       int error;
 
-       error = -EINVAL;
        if (S_ISBLK(inode->i_mode)) {
-               bdev = bdgrab(I_BDEV(inode));
-               error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL,
+               p->bdev = bdgrab(I_BDEV(inode));
+               error = blkdev_get(p->bdev,
+                                  FMODE_READ | FMODE_WRITE | FMODE_EXCL,
                                   sys_swapon);
                if (error < 0) {
-                       bdev = NULL;
-                       error = -EINVAL;
-                       goto bad_swap;
+                       p->bdev = NULL;
+                       return -EINVAL;
                }
-               p->old_block_size = block_size(bdev);
-               error = set_blocksize(bdev, PAGE_SIZE);
+               p->old_block_size = block_size(p->bdev);
+               error = set_blocksize(p->bdev, PAGE_SIZE);
                if (error < 0)
-                       goto bad_swap;
-               p->bdev = bdev;
+                       return error;
                p->flags |= SWP_BLKDEV;
        } else if (S_ISREG(inode->i_mode)) {
                p->bdev = inode->i_sb->s_bdev;
                mutex_lock(&inode->i_mutex);
-               did_down = 1;
-               if (IS_SWAPFILE(inode)) {
-                       error = -EBUSY;
-                       goto bad_swap;
-               }
-       } else {
-               goto bad_swap;
-       }
+               if (IS_SWAPFILE(inode))
+                       return -EBUSY;
+       } else
+               return -EINVAL;
 
-       swapfilepages = i_size_read(inode) >> PAGE_SHIFT;
+       return 0;
+}
 
-       /*
-        * Read the swap header.
-        */
-       if (!mapping->a_ops->readpage) {
-               error = -EINVAL;
-               goto bad_swap;
-       }
-       page = read_mapping_page(mapping, 0, swap_file);
-       if (IS_ERR(page)) {
-               error = PTR_ERR(page);
-               goto bad_swap;
-       }
-       swap_header = kmap(page);
+static unsigned long read_swap_header(struct swap_info_struct *p,
+                                       union swap_header *swap_header,
+                                       struct inode *inode)
+{
+       int i;
+       unsigned long maxpages;
+       unsigned long swapfilepages;
 
        if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) {
                printk(KERN_ERR "Unable to find swap-space signature\n");
-               error = -EINVAL;
-               goto bad_swap;
+               return 0;
        }
 
        /* swap partition endianess hack... */
@@ -2001,8 +1926,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                printk(KERN_WARNING
                       "Unable to handle swap header version %d\n",
                       swap_header->info.version);
-               error = -EINVAL;
-               goto bad_swap;
+               return 0;
        }
 
        p->lowest_bit  = 1;
@@ -2033,61 +1957,155 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        }
        p->highest_bit = maxpages - 1;
 
-       error = -EINVAL;
        if (!maxpages)
-               goto bad_swap;
+               return 0;
+       swapfilepages = i_size_read(inode) >> PAGE_SHIFT;
        if (swapfilepages && maxpages > swapfilepages) {
                printk(KERN_WARNING
                       "Swap area shorter than signature indicates\n");
-               goto bad_swap;
+               return 0;
        }
        if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))
-               goto bad_swap;
+               return 0;
        if (swap_header->info.nr_badpages > MAX_SWAP_BADPAGES)
-               goto bad_swap;
+               return 0;
 
-       /* OK, set up the swap map and apply the bad block list */
-       swap_map = vmalloc(maxpages);
-       if (!swap_map) {
-               error = -ENOMEM;
-               goto bad_swap;
-       }
+       return maxpages;
+}
+
+static int setup_swap_map_and_extents(struct swap_info_struct *p,
+                                       union swap_header *swap_header,
+                                       unsigned char *swap_map,
+                                       unsigned long maxpages,
+                                       sector_t *span)
+{
+       int i;
+       unsigned int nr_good_pages;
+       int nr_extents;
 
-       memset(swap_map, 0, maxpages);
        nr_good_pages = maxpages - 1;   /* omit header page */
 
        for (i = 0; i < swap_header->info.nr_badpages; i++) {
                unsigned int page_nr = swap_header->info.badpages[i];
-               if (page_nr == 0 || page_nr > swap_header->info.last_page) {
-                       error = -EINVAL;
-                       goto bad_swap;
-               }
+               if (page_nr == 0 || page_nr > swap_header->info.last_page)
+                       return -EINVAL;
                if (page_nr < maxpages) {
                        swap_map[page_nr] = SWAP_MAP_BAD;
                        nr_good_pages--;
                }
        }
 
-       error = swap_cgroup_swapon(type, maxpages);
-       if (error)
-               goto bad_swap;
-
        if (nr_good_pages) {
                swap_map[0] = SWAP_MAP_BAD;
                p->max = maxpages;
                p->pages = nr_good_pages;
-               nr_extents = setup_swap_extents(p, &span);
-               if (nr_extents < 0) {
-                       error = nr_extents;
-                       goto bad_swap;
-               }
+               nr_extents = setup_swap_extents(p, span);
+               if (nr_extents < 0)
+                       return nr_extents;
                nr_good_pages = p->pages;
        }
        if (!nr_good_pages) {
                printk(KERN_WARNING "Empty swap-file\n");
+               return -EINVAL;
+       }
+
+       return nr_extents;
+}
+
+SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
+{
+       struct swap_info_struct *p;
+       char *name;
+       struct file *swap_file = NULL;
+       struct address_space *mapping;
+       int i;
+       int prio;
+       int error;
+       union swap_header *swap_header;
+       int nr_extents;
+       sector_t span;
+       unsigned long maxpages;
+       unsigned char *swap_map = NULL;
+       struct page *page = NULL;
+       struct inode *inode = NULL;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       p = alloc_swap_info();
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       name = getname(specialfile);
+       if (IS_ERR(name)) {
+               error = PTR_ERR(name);
+               name = NULL;
+               goto bad_swap;
+       }
+       swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0);
+       if (IS_ERR(swap_file)) {
+               error = PTR_ERR(swap_file);
+               swap_file = NULL;
+               goto bad_swap;
+       }
+
+       p->swap_file = swap_file;
+       mapping = swap_file->f_mapping;
+
+       for (i = 0; i < nr_swapfiles; i++) {
+               struct swap_info_struct *q = swap_info[i];
+
+               if (q == p || !q->swap_file)
+                       continue;
+               if (mapping == q->swap_file->f_mapping) {
+                       error = -EBUSY;
+                       goto bad_swap;
+               }
+       }
+
+       inode = mapping->host;
+       /* If S_ISREG(inode->i_mode) will do mutex_lock(&inode->i_mutex); */
+       error = claim_swapfile(p, inode);
+       if (unlikely(error))
+               goto bad_swap;
+
+       /*
+        * Read the swap header.
+        */
+       if (!mapping->a_ops->readpage) {
                error = -EINVAL;
                goto bad_swap;
        }
+       page = read_mapping_page(mapping, 0, swap_file);
+       if (IS_ERR(page)) {
+               error = PTR_ERR(page);
+               goto bad_swap;
+       }
+       swap_header = kmap(page);
+
+       maxpages = read_swap_header(p, swap_header, inode);
+       if (unlikely(!maxpages)) {
+               error = -EINVAL;
+               goto bad_swap;
+       }
+
+       /* OK, set up the swap map and apply the bad block list */
+       swap_map = vzalloc(maxpages);
+       if (!swap_map) {
+               error = -ENOMEM;
+               goto bad_swap;
+       }
+
+       error = swap_cgroup_swapon(p->type, maxpages);
+       if (error)
+               goto bad_swap;
+
+       nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map,
+               maxpages, &span);
+       if (unlikely(nr_extents < 0)) {
+               error = nr_extents;
+               goto bad_swap;
+       }
 
        if (p->bdev) {
                if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
@@ -2099,58 +2117,46 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        }
 
        mutex_lock(&swapon_mutex);
-       spin_lock(&swap_lock);
+       prio = -1;
        if (swap_flags & SWAP_FLAG_PREFER)
-               p->prio =
+               prio =
                  (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT;
-       else
-               p->prio = --least_priority;
-       p->swap_map = swap_map;
-       p->flags |= SWP_WRITEOK;
-       nr_swap_pages += nr_good_pages;
-       total_swap_pages += nr_good_pages;
+       enable_swap_info(p, prio, swap_map);
 
        printk(KERN_INFO "Adding %uk swap on %s.  "
                        "Priority:%d extents:%d across:%lluk %s%s\n",
-               nr_good_pages<<(PAGE_SHIFT-10), name, p->prio,
+               p->pages<<(PAGE_SHIFT-10), name, p->prio,
                nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
                (p->flags & SWP_SOLIDSTATE) ? "SS" : "",
                (p->flags & SWP_DISCARDABLE) ? "D" : "");
 
-       /* insert swap space into swap_list: */
-       prev = -1;
-       for (i = swap_list.head; i >= 0; i = swap_info[i]->next) {
-               if (p->prio >= swap_info[i]->prio)
-                       break;
-               prev = i;
-       }
-       p->next = i;
-       if (prev < 0)
-               swap_list.head = swap_list.next = type;
-       else
-               swap_info[prev]->next = type;
-       spin_unlock(&swap_lock);
        mutex_unlock(&swapon_mutex);
        atomic_inc(&proc_poll_event);
        wake_up_interruptible(&proc_poll_wait);
 
+       if (S_ISREG(inode->i_mode))
+               inode->i_flags |= S_SWAPFILE;
        error = 0;
        goto out;
 bad_swap:
-       if (bdev) {
-               set_blocksize(bdev, p->old_block_size);
-               blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+       if (inode && S_ISBLK(inode->i_mode) && p->bdev) {
+               set_blocksize(p->bdev, p->old_block_size);
+               blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
        }
        destroy_swap_extents(p);
-       swap_cgroup_swapoff(type);
-bad_swap_2:
+       swap_cgroup_swapoff(p->type);
        spin_lock(&swap_lock);
        p->swap_file = NULL;
        p->flags = 0;
        spin_unlock(&swap_lock);
        vfree(swap_map);
-       if (swap_file)
+       if (swap_file) {
+               if (inode && S_ISREG(inode->i_mode)) {
+                       mutex_unlock(&inode->i_mutex);
+                       inode = NULL;
+               }
                filp_close(swap_file, NULL);
+       }
 out:
        if (page && !IS_ERR(page)) {
                kunmap(page);
@@ -2158,11 +2164,8 @@ out:
        }
        if (name)
                putname(name);
-       if (did_down) {
-               if (!error)
-                       inode->i_flags |= S_SWAPFILE;
+       if (inode && S_ISREG(inode->i_mode))
                mutex_unlock(&inode->i_mutex);
-       }
        return error;
 }
 
index d64296be00d39e5c66199e94269f3b8f5ba0bf64..a9566752913596152022f5d22983cb4f2cb4d2cf 100644 (file)
@@ -106,9 +106,8 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
        cancel_dirty_page(page, PAGE_CACHE_SIZE);
 
        clear_page_mlock(page);
-       remove_from_page_cache(page);
        ClearPageMappedToDisk(page);
-       page_cache_release(page);       /* pagecache ref */
+       delete_from_page_cache(page);
        return 0;
 }
 
@@ -322,11 +321,12 @@ EXPORT_SYMBOL(truncate_inode_pages);
  * pagetables.
  */
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
-                                      pgoff_t start, pgoff_t end)
+               pgoff_t start, pgoff_t end)
 {
        struct pagevec pvec;
        pgoff_t next = start;
-       unsigned long ret = 0;
+       unsigned long ret;
+       unsigned long count = 0;
        int i;
 
        pagevec_init(&pvec, 0);
@@ -353,9 +353,15 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                        if (lock_failed)
                                continue;
 
-                       ret += invalidate_inode_page(page);
-
+                       ret = invalidate_inode_page(page);
                        unlock_page(page);
+                       /*
+                        * Invalidation is a hint that the page is no longer
+                        * of interest and try to speed up its reclaim.
+                        */
+                       if (!ret)
+                               deactivate_page(page);
+                       count += ret;
                        if (next > end)
                                break;
                }
@@ -363,7 +369,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                mem_cgroup_uncharge_end();
                cond_resched();
        }
-       return ret;
+       return count;
 }
 EXPORT_SYMBOL(invalidate_mapping_pages);
 
@@ -389,7 +395,7 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
 
        clear_page_mlock(page);
        BUG_ON(page_has_private(page));
-       __remove_from_page_cache(page);
+       __delete_from_page_cache(page);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
 
index f9b166732e70f44f703a8a510cb4d0c850bd30a0..5d6030235d7a8e4462498e6d9154ca97029069ed 100644 (file)
@@ -261,8 +261,15 @@ struct vmap_area {
 };
 
 static DEFINE_SPINLOCK(vmap_area_lock);
-static struct rb_root vmap_area_root = RB_ROOT;
 static LIST_HEAD(vmap_area_list);
+static struct rb_root vmap_area_root = RB_ROOT;
+
+/* The vmap cache globals are protected by vmap_area_lock */
+static struct rb_node *free_vmap_cache;
+static unsigned long cached_hole_size;
+static unsigned long cached_vstart;
+static unsigned long cached_align;
+
 static unsigned long vmap_area_pcpu_hole;
 
 static struct vmap_area *__find_vmap_area(unsigned long addr)
@@ -331,9 +338,11 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
        struct rb_node *n;
        unsigned long addr;
        int purged = 0;
+       struct vmap_area *first;
 
        BUG_ON(!size);
        BUG_ON(size & ~PAGE_MASK);
+       BUG_ON(!is_power_of_2(align));
 
        va = kmalloc_node(sizeof(struct vmap_area),
                        gfp_mask & GFP_RECLAIM_MASK, node);
@@ -341,79 +350,106 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
                return ERR_PTR(-ENOMEM);
 
 retry:
-       addr = ALIGN(vstart, align);
-
        spin_lock(&vmap_area_lock);
-       if (addr + size - 1 < addr)
-               goto overflow;
+       /*
+        * Invalidate cache if we have more permissive parameters.
+        * cached_hole_size notes the largest hole noticed _below_
+        * the vmap_area cached in free_vmap_cache: if size fits
+        * into that hole, we want to scan from vstart to reuse
+        * the hole instead of allocating above free_vmap_cache.
+        * Note that __free_vmap_area may update free_vmap_cache
+        * without updating cached_hole_size or cached_align.
+        */
+       if (!free_vmap_cache ||
+                       size < cached_hole_size ||
+                       vstart < cached_vstart ||
+                       align < cached_align) {
+nocache:
+               cached_hole_size = 0;
+               free_vmap_cache = NULL;
+       }
+       /* record if we encounter less permissive parameters */
+       cached_vstart = vstart;
+       cached_align = align;
+
+       /* find starting point for our search */
+       if (free_vmap_cache) {
+               first = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
+               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               if (addr < vstart)
+                       goto nocache;
+               if (addr + size - 1 < addr)
+                       goto overflow;
+
+       } else {
+               addr = ALIGN(vstart, align);
+               if (addr + size - 1 < addr)
+                       goto overflow;
 
-       /* XXX: could have a last_hole cache */
-       n = vmap_area_root.rb_node;
-       if (n) {
-               struct vmap_area *first = NULL;
+               n = vmap_area_root.rb_node;
+               first = NULL;
 
-               do {
+               while (n) {
                        struct vmap_area *tmp;
                        tmp = rb_entry(n, struct vmap_area, rb_node);
                        if (tmp->va_end >= addr) {
-                               if (!first && tmp->va_start < addr + size)
-                                       first = tmp;
-                               n = n->rb_left;
-                       } else {
                                first = tmp;
+                               if (tmp->va_start <= addr)
+                                       break;
+                               n = n->rb_left;
+                       } else
                                n = n->rb_right;
-                       }
-               } while (n);
+               }
 
                if (!first)
                        goto found;
-
-               if (first->va_end < addr) {
-                       n = rb_next(&first->rb_node);
-                       if (n)
-                               first = rb_entry(n, struct vmap_area, rb_node);
-                       else
-                               goto found;
-               }
-
-               while (addr + size > first->va_start && addr + size <= vend) {
-                       addr = ALIGN(first->va_end + PAGE_SIZE, align);
-                       if (addr + size - 1 < addr)
-                               goto overflow;
-
-                       n = rb_next(&first->rb_node);
-                       if (n)
-                               first = rb_entry(n, struct vmap_area, rb_node);
-                       else
-                               goto found;
-               }
        }
-found:
-       if (addr + size > vend) {
-overflow:
-               spin_unlock(&vmap_area_lock);
-               if (!purged) {
-                       purge_vmap_area_lazy();
-                       purged = 1;
-                       goto retry;
-               }
-               if (printk_ratelimit())
-                       printk(KERN_WARNING
-                               "vmap allocation for size %lu failed: "
-                               "use vmalloc=<size> to increase size.\n", size);
-               kfree(va);
-               return ERR_PTR(-EBUSY);
+
+       /* from the starting point, walk areas until a suitable hole is found */
+       while (addr + size >= first->va_start && addr + size <= vend) {
+               if (addr + cached_hole_size < first->va_start)
+                       cached_hole_size = first->va_start - addr;
+               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               if (addr + size - 1 < addr)
+                       goto overflow;
+
+               n = rb_next(&first->rb_node);
+               if (n)
+                       first = rb_entry(n, struct vmap_area, rb_node);
+               else
+                       goto found;
        }
 
-       BUG_ON(addr & (align-1));
+found:
+       if (addr + size > vend)
+               goto overflow;
 
        va->va_start = addr;
        va->va_end = addr + size;
        va->flags = 0;
        __insert_vmap_area(va);
+       free_vmap_cache = &va->rb_node;
        spin_unlock(&vmap_area_lock);
 
+       BUG_ON(va->va_start & (align-1));
+       BUG_ON(va->va_start < vstart);
+       BUG_ON(va->va_end > vend);
+
        return va;
+
+overflow:
+       spin_unlock(&vmap_area_lock);
+       if (!purged) {
+               purge_vmap_area_lazy();
+               purged = 1;
+               goto retry;
+       }
+       if (printk_ratelimit())
+               printk(KERN_WARNING
+                       "vmap allocation for size %lu failed: "
+                       "use vmalloc=<size> to increase size.\n", size);
+       kfree(va);
+       return ERR_PTR(-EBUSY);
 }
 
 static void rcu_free_va(struct rcu_head *head)
@@ -426,6 +462,22 @@ static void rcu_free_va(struct rcu_head *head)
 static void __free_vmap_area(struct vmap_area *va)
 {
        BUG_ON(RB_EMPTY_NODE(&va->rb_node));
+
+       if (free_vmap_cache) {
+               if (va->va_end < cached_vstart) {
+                       free_vmap_cache = NULL;
+               } else {
+                       struct vmap_area *cache;
+                       cache = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
+                       if (va->va_start <= cache->va_start) {
+                               free_vmap_cache = rb_prev(&va->rb_node);
+                               /*
+                                * We don't try to update cached_hole_size or
+                                * cached_align, but it won't go very wrong.
+                                */
+                       }
+               }
+       }
        rb_erase(&va->rb_node, &vmap_area_root);
        RB_CLEAR_NODE(&va->rb_node);
        list_del_rcu(&va->list);
@@ -1951,8 +2003,6 @@ finished:
  *     should know vmalloc() area is valid and can use memcpy().
  *     This is for routines which have to access vmalloc area without
  *     any informaion, as /dev/kmem.
- *
- *     The caller should guarantee KM_USER1 is not used.
  */
 
 long vwrite(char *buf, char *addr, unsigned long count)
index 6771ea70bfe7e399d96237a58d3860357aad4c46..f73b8657c2d03053f9b0340a55132ee2d3ebd2f0 100644 (file)
@@ -358,7 +358,7 @@ static int may_write_to_queue(struct backing_dev_info *bdi,
 static void handle_write_error(struct address_space *mapping,
                                struct page *page, int error)
 {
-       lock_page_nosync(page);
+       lock_page(page);
        if (page_mapping(page) == mapping)
                mapping_set_error(mapping, error);
        unlock_page(page);
@@ -514,7 +514,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
 
                freepage = mapping->a_ops->freepage;
 
-               __remove_from_page_cache(page);
+               __delete_from_page_cache(page);
                spin_unlock_irq(&mapping->tree_lock);
                mem_cgroup_uncharge_cache_page(page);
 
@@ -2397,9 +2397,9 @@ loop_again:
                 * cause too much scanning of the lower zones.
                 */
                for (i = 0; i <= end_zone; i++) {
-                       int compaction;
                        struct zone *zone = pgdat->node_zones + i;
                        int nr_slab;
+                       unsigned long balance_gap;
 
                        if (!populated_zone(zone))
                                continue;
@@ -2416,11 +2416,20 @@ loop_again:
                        mem_cgroup_soft_limit_reclaim(zone, order, sc.gfp_mask);
 
                        /*
-                        * We put equal pressure on every zone, unless one
-                        * zone has way too many pages free already.
+                        * We put equal pressure on every zone, unless
+                        * one zone has way too many pages free
+                        * already. The "too many pages" is defined
+                        * as the high wmark plus a "gap" where the
+                        * gap is either the low watermark or 1%
+                        * of the zone, whichever is smaller.
                         */
+                       balance_gap = min(low_wmark_pages(zone),
+                               (zone->present_pages +
+                                       KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
+                               KSWAPD_ZONE_BALANCE_GAP_RATIO);
                        if (!zone_watermark_ok_safe(zone, order,
-                                       8*high_wmark_pages(zone), end_zone, 0))
+                                       high_wmark_pages(zone) + balance_gap,
+                                       end_zone, 0))
                                shrink_zone(priority, zone, &sc);
                        reclaim_state->reclaimed_slab = 0;
                        nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
@@ -2428,24 +2437,9 @@ loop_again:
                        sc.nr_reclaimed += reclaim_state->reclaimed_slab;
                        total_scanned += sc.nr_scanned;
 
-                       compaction = 0;
-                       if (order &&
-                           zone_watermark_ok(zone, 0,
-                                              high_wmark_pages(zone),
-                                             end_zone, 0) &&
-                           !zone_watermark_ok(zone, order,
-                                              high_wmark_pages(zone),
-                                              end_zone, 0)) {
-                               compact_zone_order(zone,
-                                                  order,
-                                                  sc.gfp_mask, false,
-                                                  COMPACT_MODE_KSWAPD);
-                               compaction = 1;
-                       }
-
                        if (zone->all_unreclaimable)
                                continue;
-                       if (!compaction && nr_slab == 0 &&
+                       if (nr_slab == 0 &&
                            !zone_reclaimable(zone))
                                zone->all_unreclaimable = 1;
                        /*
index 0c3b5048773e6d486f43343a859ebf785161036e..772b39b87d955078b4f0d7a1b7114751e0ef9a74 100644 (file)
@@ -500,8 +500,12 @@ void refresh_cpu_vm_stats(int cpu)
  * z       = the zone from which the allocation occurred.
  *
  * Must be called with interrupts disabled.
+ *
+ * When __GFP_OTHER_NODE is set assume the node of the preferred
+ * zone is the local node. This is useful for daemons who allocate
+ * memory on behalf of other processes.
  */
-void zone_statistics(struct zone *preferred_zone, struct zone *z)
+void zone_statistics(struct zone *preferred_zone, struct zone *z, gfp_t flags)
 {
        if (z->zone_pgdat == preferred_zone->zone_pgdat) {
                __inc_zone_state(z, NUMA_HIT);
@@ -509,7 +513,8 @@ void zone_statistics(struct zone *preferred_zone, struct zone *z)
                __inc_zone_state(z, NUMA_MISS);
                __inc_zone_state(preferred_zone, NUMA_FOREIGN);
        }
-       if (z->node == numa_node_id())
+       if (z->node == ((flags & __GFP_OTHER_NODE) ?
+                       preferred_zone->node : numa_node_id()))
                __inc_zone_state(z, NUMA_LOCAL);
        else
                __inc_zone_state(z, NUMA_OTHER);
index 347ec0cd2718696b1c84136ca1c21aa27fa94d21..2ccbf04d37dfd22a7a65a36cd3c63887d58b823d 100644 (file)
@@ -223,7 +223,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
 
        req = &c->reqs[row][col];
        if (!req->tc) {
-               req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
+               req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS);
                if (!req->wq) {
                        printk(KERN_ERR "Couldn't grow tag array\n");
                        return ERR_PTR(-ENOMEM);
@@ -233,17 +233,17 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
                                P9_TRANS_PREF_PAYLOAD_SEP) {
                        int alloc_msize = min(c->msize, 4096);
                        req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
-                                       GFP_KERNEL);
+                                         GFP_NOFS);
                        req->tc->capacity = alloc_msize;
                        req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
-                                       GFP_KERNEL);
+                                         GFP_NOFS);
                        req->rc->capacity = alloc_msize;
                } else {
                        req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
-                                       GFP_KERNEL);
+                                         GFP_NOFS);
                        req->tc->capacity = c->msize;
                        req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
-                                       GFP_KERNEL);
+                                         GFP_NOFS);
                        req->rc->capacity = c->msize;
                }
                if ((!req->tc) || (!req->rc)) {
index 2ce515b859b3340dac437cacd16160dd299f59a0..8a4084fa8b5a907df17db9b023c215d1bb7da772 100644 (file)
@@ -205,7 +205,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                if (errcode)
                                        break;
 
-                               *sptr = kmalloc(len + 1, GFP_KERNEL);
+                               *sptr = kmalloc(len + 1, GFP_NOFS);
                                if (*sptr == NULL) {
                                        errcode = -EFAULT;
                                        break;
@@ -273,7 +273,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                if (!errcode) {
                                        *wnames =
                                            kmalloc(sizeof(char *) * *nwname,
-                                                   GFP_KERNEL);
+                                                   GFP_NOFS);
                                        if (!*wnames)
                                                errcode = -ENOMEM;
                                }
@@ -317,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                        *wqids =
                                            kmalloc(*nwqid *
                                                    sizeof(struct p9_qid),
-                                                   GFP_KERNEL);
+                                                   GFP_NOFS);
                                        if (*wqids == NULL)
                                                errcode = -ENOMEM;
                                }
index d62b9aa58df80ca868240c3db899f20299831f74..9172ab78fcb0e90f48f81ea48810bc7eb8a160c7 100644 (file)
@@ -41,9 +41,9 @@ EXPORT_SYMBOL(p9_release_req_pages);
 int
 p9_nr_pages(struct p9_req_t *req)
 {
-       int start_page, end_page;
-       start_page =  (unsigned long long)req->tc->pubuf >> PAGE_SHIFT;
-       end_page = ((unsigned long long)req->tc->pubuf + req->tc->pbuf_size +
+       unsigned long start_page, end_page;
+       start_page =  (unsigned long)req->tc->pubuf >> PAGE_SHIFT;
+       end_page = ((unsigned long)req->tc->pubuf + req->tc->pbuf_size +
                        PAGE_SIZE - 1) >> PAGE_SHIFT;
        return end_page - start_page;
 }
@@ -69,8 +69,8 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
        *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1);
 
        if (*pdata_off)
-               first_page_bytes = min((PAGE_SIZE - *pdata_off),
-                               req->tc->pbuf_size);
+               first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off),
+                                      req->tc->pbuf_size);
 
        rpinfo = req->tc->private;
        pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf,
index a30471e517402c565086518d393004cf092c5d31..aa5672b15eae2cc2c8ae638ad662277070e58079 100644 (file)
@@ -350,7 +350,7 @@ static void p9_read_work(struct work_struct *work)
 
                if (m->req->rc == NULL) {
                        m->req->rc = kmalloc(sizeof(struct p9_fcall) +
-                                               m->client->msize, GFP_KERNEL);
+                                               m->client->msize, GFP_NOFS);
                        if (!m->req->rc) {
                                m->req = NULL;
                                err = -ENOMEM;
index 29a54ccd213d5709839fbdd5e27a11c4ac5b1188..150e0c4bbf40287f263e3eba1c03245bce22cb38 100644 (file)
@@ -424,7 +424,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
        struct p9_rdma_context *rpl_context = NULL;
 
        /* Allocate an fcall for the reply */
-       rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL);
+       rpl_context = kmalloc(sizeof *rpl_context, GFP_NOFS);
        if (!rpl_context) {
                err = -ENOMEM;
                goto err_close;
@@ -437,7 +437,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
         */
        if (!req->rc) {
                req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize,
-                                                               GFP_KERNEL);
+                                 GFP_NOFS);
                if (req->rc) {
                        req->rc->sdata = (char *) req->rc +
                                                sizeof(struct p9_fcall);
@@ -468,7 +468,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
        req->rc = NULL;
 
        /* Post the request */
-       c = kmalloc(sizeof *c, GFP_KERNEL);
+       c = kmalloc(sizeof *c, GFP_NOFS);
        if (!c) {
                err = -ENOMEM;
                goto err_free1;
index 9b550ed9c7110bb8b339d91c7e2f1eb4cd5878e8..e8f046b071821636daf99ae9ef79e88f28ef7a09 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include <linux/scatterlist.h>
+#include <linux/swap.h>
 #include <linux/virtio.h>
 #include <linux/virtio_9p.h>
 #include "trans_common.h"
@@ -51,6 +52,8 @@
 
 /* a single mutex to manage channel initialization and attachment */
 static DEFINE_MUTEX(virtio_9p_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
+static atomic_t vp_pinned = ATOMIC_INIT(0);
 
 /**
  * struct virtio_chan - per-instance transport information
@@ -78,7 +81,10 @@ struct virtio_chan {
        struct virtqueue *vq;
        int ring_bufs_avail;
        wait_queue_head_t *vc_wq;
-
+       /* This is global limit. Since we don't have a global structure,
+        * will be placing it in each channel.
+        */
+       int p9_max_pages;
        /* Scatterlist: can be too big for stack. */
        struct scatterlist sg[VIRTQUEUE_NUM];
 
@@ -141,34 +147,36 @@ static void req_done(struct virtqueue *vq)
 
        P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
 
-       do {
+       while (1) {
                spin_lock_irqsave(&chan->lock, flags);
                rc = virtqueue_get_buf(chan->vq, &len);
 
-               if (rc != NULL) {
-                       if (!chan->ring_bufs_avail) {
-                               chan->ring_bufs_avail = 1;
-                               wake_up(chan->vc_wq);
-                       }
-                       spin_unlock_irqrestore(&chan->lock, flags);
-                       P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
-                       P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
-                                       rc->tag);
-                       req = p9_tag_lookup(chan->client, rc->tag);
-                       req->status = REQ_STATUS_RCVD;
-                       if (req->tc->private) {
-                               struct trans_rpage_info *rp = req->tc->private;
-                               /*Release pages */
-                               p9_release_req_pages(rp);
-                               if (rp->rp_alloc)
-                                       kfree(rp);
-                               req->tc->private = NULL;
-                       }
-                       p9_client_cb(chan->client, req);
-               } else {
+               if (rc == NULL) {
                        spin_unlock_irqrestore(&chan->lock, flags);
+                       break;
+               }
+
+               chan->ring_bufs_avail = 1;
+               spin_unlock_irqrestore(&chan->lock, flags);
+               /* Wakeup if anyone waiting for VirtIO ring space. */
+               wake_up(chan->vc_wq);
+               P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
+               P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
+               req = p9_tag_lookup(chan->client, rc->tag);
+               if (req->tc->private) {
+                       struct trans_rpage_info *rp = req->tc->private;
+                       int p = rp->rp_nr_pages;
+                       /*Release pages */
+                       p9_release_req_pages(rp);
+                       atomic_sub(p, &vp_pinned);
+                       wake_up(&vp_wq);
+                       if (rp->rp_alloc)
+                               kfree(rp);
+                       req->tc->private = NULL;
                }
-       } while (rc != NULL);
+               req->status = REQ_STATUS_RCVD;
+               p9_client_cb(chan->client, req);
+       }
 }
 
 /**
@@ -263,7 +271,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
 
        P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
 
-req_retry:
        req->status = REQ_STATUS_SENT;
 
        if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) {
@@ -271,6 +278,14 @@ req_retry:
                int rpinfo_size = sizeof(struct trans_rpage_info) +
                        sizeof(struct page *) * nr_pages;
 
+               if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
+                       err = wait_event_interruptible(vp_wq,
+                               atomic_read(&vp_pinned) < chan->p9_max_pages);
+                       if (err  == -ERESTARTSYS)
+                               return err;
+                       P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n");
+               }
+
                if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
                        /* We can use sdata */
                        req->tc->private = req->tc->sdata + req->tc->size;
@@ -293,9 +308,12 @@ req_retry:
                        if (rpinfo->rp_alloc)
                                kfree(rpinfo);
                        return err;
+               } else {
+                       atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
                }
        }
 
+req_retry_pinned:
        spin_lock_irqsave(&chan->lock, flags);
 
        /* Handle out VirtIO ring buffers */
@@ -356,7 +374,7 @@ req_retry:
                                return err;
 
                        P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
-                       goto req_retry;
+                       goto req_retry_pinned;
                } else {
                        spin_unlock_irqrestore(&chan->lock, flags);
                        P9_DPRINTK(P9_DEBUG_TRANS,
@@ -453,6 +471,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        }
        init_waitqueue_head(chan->vc_wq);
        chan->ring_bufs_avail = 1;
+       /* Ceiling limit to avoid denial of service attacks */
+       chan->p9_max_pages = nr_free_buffer_pages()/4;
 
        mutex_lock(&virtio_9p_lock);
        list_add_tail(&chan->chan_list, &virtio_chan_list);
index e048701a72d230821f6e23eeddd89f5a14fc2f9b..b84619b5ba221e4576b2e8ad99256bb4f91f47cb 100644 (file)
@@ -92,7 +92,7 @@ int p9_idpool_get(struct p9_idpool *p)
        unsigned long flags;
 
 retry:
-       if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
+       if (idr_pre_get(&p->pool, GFP_NOFS) == 0)
                return 0;
 
        spin_lock_irqsave(&p->lock, flags);
index eb2a666b0be7011e9b27618c62060416543cb706..1fc1ee11dfa28088f00becf58d7c22fd2420cb36 100644 (file)
@@ -78,8 +78,10 @@ int ceph_unarmor(char *dst, const char *src, const char *end)
        while (src < end) {
                int a, b, c, d;
 
-               if (src < end && src[0] == '\n')
+               if (src[0] == '\n') {
                        src++;
+                       continue;
+               }
                if (src + 4 > end)
                        return -EINVAL;
                a = decode_bits(src[0]);
index f3e4a13fea0c8a5337ce5383951fb389ea24144a..95f96ab94bba12b57052705d385be749d6183c53 100644 (file)
@@ -62,6 +62,7 @@ const char *ceph_msg_type_name(int type)
        case CEPH_MSG_OSD_MAP: return "osd_map";
        case CEPH_MSG_OSD_OP: return "osd_op";
        case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
+       case CEPH_MSG_WATCH_NOTIFY: return "watch_notify";
        default: return "unknown";
        }
 }
index 3e20a122ffa2f2bf40a91596fe12bb93e6874b64..02212ed50852eaa41b5d0c75c7f121b77f074ce3 100644 (file)
 #define OSD_OPREPLY_FRONT_LEN  512
 
 static const struct ceph_connection_operations osd_con_ops;
-static int __kick_requests(struct ceph_osd_client *osdc,
-                         struct ceph_osd *kickosd);
 
-static void kick_requests(struct ceph_osd_client *osdc, struct ceph_osd *osd);
+static void send_queued(struct ceph_osd_client *osdc);
+static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd);
+static void __register_request(struct ceph_osd_client *osdc,
+                              struct ceph_osd_request *req);
+static void __unregister_linger_request(struct ceph_osd_client *osdc,
+                                       struct ceph_osd_request *req);
+static int __send_request(struct ceph_osd_client *osdc,
+                         struct ceph_osd_request *req);
 
 static int op_needs_trail(int op)
 {
@@ -34,6 +39,7 @@ static int op_needs_trail(int op)
        case CEPH_OSD_OP_SETXATTR:
        case CEPH_OSD_OP_CMPXATTR:
        case CEPH_OSD_OP_CALL:
+       case CEPH_OSD_OP_NOTIFY:
                return 1;
        default:
                return 0;
@@ -209,6 +215,8 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        init_completion(&req->r_completion);
        init_completion(&req->r_safe_completion);
        INIT_LIST_HEAD(&req->r_unsafe_item);
+       INIT_LIST_HEAD(&req->r_linger_item);
+       INIT_LIST_HEAD(&req->r_linger_osd);
        req->r_flags = flags;
 
        WARN_ON((flags & (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) == 0);
@@ -315,6 +323,24 @@ static void osd_req_encode_op(struct ceph_osd_request *req,
                break;
        case CEPH_OSD_OP_STARTSYNC:
                break;
+       case CEPH_OSD_OP_NOTIFY:
+               {
+                       __le32 prot_ver = cpu_to_le32(src->watch.prot_ver);
+                       __le32 timeout = cpu_to_le32(src->watch.timeout);
+
+                       BUG_ON(!req->r_trail);
+
+                       ceph_pagelist_append(req->r_trail,
+                                               &prot_ver, sizeof(prot_ver));
+                       ceph_pagelist_append(req->r_trail,
+                                               &timeout, sizeof(timeout));
+               }
+       case CEPH_OSD_OP_NOTIFY_ACK:
+       case CEPH_OSD_OP_WATCH:
+               dst->watch.cookie = cpu_to_le64(src->watch.cookie);
+               dst->watch.ver = cpu_to_le64(src->watch.ver);
+               dst->watch.flag = src->watch.flag;
+               break;
        default:
                pr_err("unrecognized osd opcode %d\n", dst->op);
                WARN_ON(1);
@@ -529,6 +555,45 @@ __lookup_request_ge(struct ceph_osd_client *osdc,
        return NULL;
 }
 
+/*
+ * Resubmit requests pending on the given osd.
+ */
+static void __kick_osd_requests(struct ceph_osd_client *osdc,
+                               struct ceph_osd *osd)
+{
+       struct ceph_osd_request *req, *nreq;
+       int err;
+
+       dout("__kick_osd_requests osd%d\n", osd->o_osd);
+       err = __reset_osd(osdc, osd);
+       if (err == -EAGAIN)
+               return;
+
+       list_for_each_entry(req, &osd->o_requests, r_osd_item) {
+               list_move(&req->r_req_lru_item, &osdc->req_unsent);
+               dout("requeued %p tid %llu osd%d\n", req, req->r_tid,
+                    osd->o_osd);
+               if (!req->r_linger)
+                       req->r_flags |= CEPH_OSD_FLAG_RETRY;
+       }
+
+       list_for_each_entry_safe(req, nreq, &osd->o_linger_requests,
+                                r_linger_osd) {
+               __unregister_linger_request(osdc, req);
+               __register_request(osdc, req);
+               list_move(&req->r_req_lru_item, &osdc->req_unsent);
+               dout("requeued lingering %p tid %llu osd%d\n", req, req->r_tid,
+                    osd->o_osd);
+       }
+}
+
+static void kick_osd_requests(struct ceph_osd_client *osdc,
+                             struct ceph_osd *kickosd)
+{
+       mutex_lock(&osdc->request_mutex);
+       __kick_osd_requests(osdc, kickosd);
+       mutex_unlock(&osdc->request_mutex);
+}
 
 /*
  * If the osd connection drops, we need to resubmit all requests.
@@ -543,7 +608,8 @@ static void osd_reset(struct ceph_connection *con)
        dout("osd_reset osd%d\n", osd->o_osd);
        osdc = osd->o_osdc;
        down_read(&osdc->map_sem);
-       kick_requests(osdc, osd);
+       kick_osd_requests(osdc, osd);
+       send_queued(osdc);
        up_read(&osdc->map_sem);
 }
 
@@ -561,6 +627,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc)
        atomic_set(&osd->o_ref, 1);
        osd->o_osdc = osdc;
        INIT_LIST_HEAD(&osd->o_requests);
+       INIT_LIST_HEAD(&osd->o_linger_requests);
        INIT_LIST_HEAD(&osd->o_osd_lru);
        osd->o_incarnation = 1;
 
@@ -650,7 +717,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
        int ret = 0;
 
        dout("__reset_osd %p osd%d\n", osd, osd->o_osd);
-       if (list_empty(&osd->o_requests)) {
+       if (list_empty(&osd->o_requests) &&
+           list_empty(&osd->o_linger_requests)) {
                __remove_osd(osdc, osd);
        } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd],
                          &osd->o_con.peer_addr,
@@ -723,10 +791,9 @@ static void __cancel_osd_timeout(struct ceph_osd_client *osdc)
  * Register request, assign tid.  If this is the first request, set up
  * the timeout event.
  */
-static void register_request(struct ceph_osd_client *osdc,
-                            struct ceph_osd_request *req)
+static void __register_request(struct ceph_osd_client *osdc,
+                              struct ceph_osd_request *req)
 {
-       mutex_lock(&osdc->request_mutex);
        req->r_tid = ++osdc->last_tid;
        req->r_request->hdr.tid = cpu_to_le64(req->r_tid);
        INIT_LIST_HEAD(&req->r_req_lru_item);
@@ -740,6 +807,13 @@ static void register_request(struct ceph_osd_client *osdc,
                dout(" first request, scheduling timeout\n");
                __schedule_osd_timeout(osdc);
        }
+}
+
+static void register_request(struct ceph_osd_client *osdc,
+                            struct ceph_osd_request *req)
+{
+       mutex_lock(&osdc->request_mutex);
+       __register_request(osdc, req);
        mutex_unlock(&osdc->request_mutex);
 }
 
@@ -758,9 +832,14 @@ static void __unregister_request(struct ceph_osd_client *osdc,
                ceph_con_revoke(&req->r_osd->o_con, req->r_request);
 
                list_del_init(&req->r_osd_item);
-               if (list_empty(&req->r_osd->o_requests))
+               if (list_empty(&req->r_osd->o_requests) &&
+                   list_empty(&req->r_osd->o_linger_requests)) {
+                       dout("moving osd to %p lru\n", req->r_osd);
                        __move_osd_to_lru(osdc, req->r_osd);
-               req->r_osd = NULL;
+               }
+               if (list_empty(&req->r_osd_item) &&
+                   list_empty(&req->r_linger_item))
+                       req->r_osd = NULL;
        }
 
        ceph_osdc_put_request(req);
@@ -781,20 +860,72 @@ static void __cancel_request(struct ceph_osd_request *req)
                ceph_con_revoke(&req->r_osd->o_con, req->r_request);
                req->r_sent = 0;
        }
-       list_del_init(&req->r_req_lru_item);
 }
 
+static void __register_linger_request(struct ceph_osd_client *osdc,
+                                   struct ceph_osd_request *req)
+{
+       dout("__register_linger_request %p\n", req);
+       list_add_tail(&req->r_linger_item, &osdc->req_linger);
+       list_add_tail(&req->r_linger_osd, &req->r_osd->o_linger_requests);
+}
+
+static void __unregister_linger_request(struct ceph_osd_client *osdc,
+                                       struct ceph_osd_request *req)
+{
+       dout("__unregister_linger_request %p\n", req);
+       if (req->r_osd) {
+               list_del_init(&req->r_linger_item);
+               list_del_init(&req->r_linger_osd);
+
+               if (list_empty(&req->r_osd->o_requests) &&
+                   list_empty(&req->r_osd->o_linger_requests)) {
+                       dout("moving osd to %p lru\n", req->r_osd);
+                       __move_osd_to_lru(osdc, req->r_osd);
+               }
+               req->r_osd = NULL;
+       }
+}
+
+void ceph_osdc_unregister_linger_request(struct ceph_osd_client *osdc,
+                                        struct ceph_osd_request *req)
+{
+       mutex_lock(&osdc->request_mutex);
+       if (req->r_linger) {
+               __unregister_linger_request(osdc, req);
+               ceph_osdc_put_request(req);
+       }
+       mutex_unlock(&osdc->request_mutex);
+}
+EXPORT_SYMBOL(ceph_osdc_unregister_linger_request);
+
+void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc,
+                                 struct ceph_osd_request *req)
+{
+       if (!req->r_linger) {
+               dout("set_request_linger %p\n", req);
+               req->r_linger = 1;
+               /*
+                * caller is now responsible for calling
+                * unregister_linger_request
+                */
+               ceph_osdc_get_request(req);
+       }
+}
+EXPORT_SYMBOL(ceph_osdc_set_request_linger);
+
 /*
  * Pick an osd (the first 'up' osd in the pg), allocate the osd struct
  * (as needed), and set the request r_osd appropriately.  If there is
- * no up osd, set r_osd to NULL.
+ * no up osd, set r_osd to NULL.  Move the request to the appropiate list
+ * (unsent, homeless) or leave on in-flight lru.
  *
  * Return 0 if unchanged, 1 if changed, or negative on error.
  *
  * Caller should hold map_sem for read and request_mutex.
  */
-static int __map_osds(struct ceph_osd_client *osdc,
-                     struct ceph_osd_request *req)
+static int __map_request(struct ceph_osd_client *osdc,
+                        struct ceph_osd_request *req)
 {
        struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
        struct ceph_pg pgid;
@@ -802,11 +933,13 @@ static int __map_osds(struct ceph_osd_client *osdc,
        int o = -1, num = 0;
        int err;
 
-       dout("map_osds %p tid %lld\n", req, req->r_tid);
+       dout("map_request %p tid %lld\n", req, req->r_tid);
        err = ceph_calc_object_layout(&reqhead->layout, req->r_oid,
                                      &req->r_file_layout, osdc->osdmap);
-       if (err)
+       if (err) {
+               list_move(&req->r_req_lru_item, &osdc->req_notarget);
                return err;
+       }
        pgid = reqhead->layout.ol_pgid;
        req->r_pgid = pgid;
 
@@ -823,7 +956,7 @@ static int __map_osds(struct ceph_osd_client *osdc,
            (req->r_osd == NULL && o == -1))
                return 0;  /* no change */
 
-       dout("map_osds tid %llu pgid %d.%x osd%d (was osd%d)\n",
+       dout("map_request tid %llu pgid %d.%x osd%d (was osd%d)\n",
             req->r_tid, le32_to_cpu(pgid.pool), le16_to_cpu(pgid.ps), o,
             req->r_osd ? req->r_osd->o_osd : -1);
 
@@ -841,10 +974,12 @@ static int __map_osds(struct ceph_osd_client *osdc,
        if (!req->r_osd && o >= 0) {
                err = -ENOMEM;
                req->r_osd = create_osd(osdc);
-               if (!req->r_osd)
+               if (!req->r_osd) {
+                       list_move(&req->r_req_lru_item, &osdc->req_notarget);
                        goto out;
+               }
 
-               dout("map_osds osd %p is osd%d\n", req->r_osd, o);
+               dout("map_request osd %p is osd%d\n", req->r_osd, o);
                req->r_osd->o_osd = o;
                req->r_osd->o_con.peer_name.num = cpu_to_le64(o);
                __insert_osd(osdc, req->r_osd);
@@ -855,6 +990,9 @@ static int __map_osds(struct ceph_osd_client *osdc,
        if (req->r_osd) {
                __remove_osd_from_lru(req->r_osd);
                list_add(&req->r_osd_item, &req->r_osd->o_requests);
+               list_move(&req->r_req_lru_item, &osdc->req_unsent);
+       } else {
+               list_move(&req->r_req_lru_item, &osdc->req_notarget);
        }
        err = 1;   /* osd or pg changed */
 
@@ -869,16 +1007,6 @@ static int __send_request(struct ceph_osd_client *osdc,
                          struct ceph_osd_request *req)
 {
        struct ceph_osd_request_head *reqhead;
-       int err;
-
-       err = __map_osds(osdc, req);
-       if (err < 0)
-               return err;
-       if (req->r_osd == NULL) {
-               dout("send_request %p no up osds in pg\n", req);
-               ceph_monc_request_next_osdmap(&osdc->client->monc);
-               return 0;
-       }
 
        dout("send_request %p tid %llu to osd%d flags %d\n",
             req, req->r_tid, req->r_osd->o_osd, req->r_flags);
@@ -897,6 +1025,21 @@ static int __send_request(struct ceph_osd_client *osdc,
        return 0;
 }
 
+/*
+ * Send any requests in the queue (req_unsent).
+ */
+static void send_queued(struct ceph_osd_client *osdc)
+{
+       struct ceph_osd_request *req, *tmp;
+
+       dout("send_queued\n");
+       mutex_lock(&osdc->request_mutex);
+       list_for_each_entry_safe(req, tmp, &osdc->req_unsent, r_req_lru_item) {
+               __send_request(osdc, req);
+       }
+       mutex_unlock(&osdc->request_mutex);
+}
+
 /*
  * Timeout callback, called every N seconds when 1 or more osd
  * requests has been active for more than N seconds.  When this
@@ -916,30 +1059,13 @@ static void handle_timeout(struct work_struct *work)
        unsigned long keepalive =
                osdc->client->options->osd_keepalive_timeout * HZ;
        unsigned long last_stamp = 0;
-       struct rb_node *p;
        struct list_head slow_osds;
-
        dout("timeout\n");
        down_read(&osdc->map_sem);
 
        ceph_monc_request_next_osdmap(&osdc->client->monc);
 
        mutex_lock(&osdc->request_mutex);
-       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
-               req = rb_entry(p, struct ceph_osd_request, r_node);
-
-               if (req->r_resend) {
-                       int err;
-
-                       dout("osdc resending prev failed %lld\n", req->r_tid);
-                       err = __send_request(osdc, req);
-                       if (err)
-                               dout("osdc failed again on %lld\n", req->r_tid);
-                       else
-                               req->r_resend = false;
-                       continue;
-               }
-       }
 
        /*
         * reset osds that appear to be _really_ unresponsive.  this
@@ -963,7 +1089,7 @@ static void handle_timeout(struct work_struct *work)
                BUG_ON(!osd);
                pr_warning(" tid %llu timed out on osd%d, will reset osd\n",
                           req->r_tid, osd->o_osd);
-               __kick_requests(osdc, osd);
+               __kick_osd_requests(osdc, osd);
        }
 
        /*
@@ -991,7 +1117,7 @@ static void handle_timeout(struct work_struct *work)
 
        __schedule_osd_timeout(osdc);
        mutex_unlock(&osdc->request_mutex);
-
+       send_queued(osdc);
        up_read(&osdc->map_sem);
 }
 
@@ -1035,7 +1161,6 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
            numops * sizeof(struct ceph_osd_op))
                goto bad;
        dout("handle_reply %p tid %llu result %d\n", msg, tid, (int)result);
-
        /* lookup */
        mutex_lock(&osdc->request_mutex);
        req = __lookup_request(osdc, tid);
@@ -1079,6 +1204,9 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
 
        dout("handle_reply tid %llu flags %d\n", tid, flags);
 
+       if (req->r_linger && (flags & CEPH_OSD_FLAG_ONDISK))
+               __register_linger_request(osdc, req);
+
        /* either this is a read, or we got the safe response */
        if (result < 0 ||
            (flags & CEPH_OSD_FLAG_ONDISK) ||
@@ -1099,6 +1227,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
        }
 
 done:
+       dout("req=%p req->r_linger=%d\n", req, req->r_linger);
        ceph_osdc_put_request(req);
        return;
 
@@ -1109,108 +1238,83 @@ bad:
        ceph_msg_dump(msg);
 }
 
-
-static int __kick_requests(struct ceph_osd_client *osdc,
-                         struct ceph_osd *kickosd)
+static void reset_changed_osds(struct ceph_osd_client *osdc)
 {
-       struct ceph_osd_request *req;
        struct rb_node *p, *n;
-       int needmap = 0;
-       int err;
 
-       dout("kick_requests osd%d\n", kickosd ? kickosd->o_osd : -1);
-       if (kickosd) {
-               err = __reset_osd(osdc, kickosd);
-               if (err == -EAGAIN)
-                       return 1;
-       } else {
-               for (p = rb_first(&osdc->osds); p; p = n) {
-                       struct ceph_osd *osd =
-                               rb_entry(p, struct ceph_osd, o_node);
-
-                       n = rb_next(p);
-                       if (!ceph_osd_is_up(osdc->osdmap, osd->o_osd) ||
-                           memcmp(&osd->o_con.peer_addr,
-                                  ceph_osd_addr(osdc->osdmap,
-                                                osd->o_osd),
-                                  sizeof(struct ceph_entity_addr)) != 0)
-                               __reset_osd(osdc, osd);
-               }
+       for (p = rb_first(&osdc->osds); p; p = n) {
+               struct ceph_osd *osd = rb_entry(p, struct ceph_osd, o_node);
+
+               n = rb_next(p);
+               if (!ceph_osd_is_up(osdc->osdmap, osd->o_osd) ||
+                   memcmp(&osd->o_con.peer_addr,
+                          ceph_osd_addr(osdc->osdmap,
+                                        osd->o_osd),
+                          sizeof(struct ceph_entity_addr)) != 0)
+                       __reset_osd(osdc, osd);
        }
+}
+
+/*
+ * Requeue requests whose mapping to an OSD has changed.  If requests map to
+ * no osd, request a new map.
+ *
+ * Caller should hold map_sem for read and request_mutex.
+ */
+static void kick_requests(struct ceph_osd_client *osdc)
+{
+       struct ceph_osd_request *req, *nreq;
+       struct rb_node *p;
+       int needmap = 0;
+       int err;
 
+       dout("kick_requests\n");
+       mutex_lock(&osdc->request_mutex);
        for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
                req = rb_entry(p, struct ceph_osd_request, r_node);
-
-               if (req->r_resend) {
-                       dout(" r_resend set on tid %llu\n", req->r_tid);
-                       __cancel_request(req);
-                       goto kick;
-               }
-               if (req->r_osd && kickosd == req->r_osd) {
-                       __cancel_request(req);
-                       goto kick;
+               err = __map_request(osdc, req);
+               if (err < 0)
+                       continue;  /* error */
+               if (req->r_osd == NULL) {
+                       dout("%p tid %llu maps to no osd\n", req, req->r_tid);
+                       needmap++;  /* request a newer map */
+               } else if (err > 0) {
+                       dout("%p tid %llu requeued on osd%d\n", req, req->r_tid,
+                            req->r_osd ? req->r_osd->o_osd : -1);
+                       if (!req->r_linger)
+                               req->r_flags |= CEPH_OSD_FLAG_RETRY;
                }
+       }
+
+       list_for_each_entry_safe(req, nreq, &osdc->req_linger,
+                                r_linger_item) {
+               dout("linger req=%p req->r_osd=%p\n", req, req->r_osd);
 
-               err = __map_osds(osdc, req);
+               err = __map_request(osdc, req);
                if (err == 0)
-                       continue;  /* no change */
-               if (err < 0) {
-                       /*
-                        * FIXME: really, we should set the request
-                        * error and fail if this isn't a 'nofail'
-                        * request, but that's a fair bit more
-                        * complicated to do.  So retry!
-                        */
-                       dout(" setting r_resend on %llu\n", req->r_tid);
-                       req->r_resend = true;
-                       continue;
-               }
+                       continue;  /* no change and no osd was specified */
+               if (err < 0)
+                       continue;  /* hrm! */
                if (req->r_osd == NULL) {
                        dout("tid %llu maps to no valid osd\n", req->r_tid);
                        needmap++;  /* request a newer map */
                        continue;
                }
 
-kick:
-               dout("kicking %p tid %llu osd%d\n", req, req->r_tid,
+               dout("kicking lingering %p tid %llu osd%d\n", req, req->r_tid,
                     req->r_osd ? req->r_osd->o_osd : -1);
-               req->r_flags |= CEPH_OSD_FLAG_RETRY;
-               err = __send_request(osdc, req);
-               if (err) {
-                       dout(" setting r_resend on %llu\n", req->r_tid);
-                       req->r_resend = true;
-               }
+               __unregister_linger_request(osdc, req);
+               __register_request(osdc, req);
        }
-
-       return needmap;
-}
-
-/*
- * Resubmit osd requests whose osd or osd address has changed.  Request
- * a new osd map if osds are down, or we are otherwise unable to determine
- * how to direct a request.
- *
- * Close connections to down osds.
- *
- * If @who is specified, resubmit requests for that specific osd.
- *
- * Caller should hold map_sem for read and request_mutex.
- */
-static void kick_requests(struct ceph_osd_client *osdc,
-                         struct ceph_osd *kickosd)
-{
-       int needmap;
-
-       mutex_lock(&osdc->request_mutex);
-       needmap = __kick_requests(osdc, kickosd);
        mutex_unlock(&osdc->request_mutex);
 
        if (needmap) {
                dout("%d requests for down osds, need new map\n", needmap);
                ceph_monc_request_next_osdmap(&osdc->client->monc);
        }
-
 }
+
+
 /*
  * Process updated osd map.
  *
@@ -1263,6 +1367,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                                ceph_osdmap_destroy(osdc->osdmap);
                                osdc->osdmap = newmap;
                        }
+                       kick_requests(osdc);
+                       reset_changed_osds(osdc);
                } else {
                        dout("ignoring incremental map %u len %d\n",
                             epoch, maplen);
@@ -1300,6 +1406,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                        osdc->osdmap = newmap;
                        if (oldmap)
                                ceph_osdmap_destroy(oldmap);
+                       kick_requests(osdc);
                }
                p += maplen;
                nr_maps--;
@@ -1308,8 +1415,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 done:
        downgrade_write(&osdc->map_sem);
        ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
-       if (newmap)
-               kick_requests(osdc, NULL);
+       send_queued(osdc);
        up_read(&osdc->map_sem);
        wake_up_all(&osdc->client->auth_wq);
        return;
@@ -1321,6 +1427,223 @@ bad:
        return;
 }
 
+/*
+ * watch/notify callback event infrastructure
+ *
+ * These callbacks are used both for watch and notify operations.
+ */
+static void __release_event(struct kref *kref)
+{
+       struct ceph_osd_event *event =
+               container_of(kref, struct ceph_osd_event, kref);
+
+       dout("__release_event %p\n", event);
+       kfree(event);
+}
+
+static void get_event(struct ceph_osd_event *event)
+{
+       kref_get(&event->kref);
+}
+
+void ceph_osdc_put_event(struct ceph_osd_event *event)
+{
+       kref_put(&event->kref, __release_event);
+}
+EXPORT_SYMBOL(ceph_osdc_put_event);
+
+static void __insert_event(struct ceph_osd_client *osdc,
+                            struct ceph_osd_event *new)
+{
+       struct rb_node **p = &osdc->event_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_osd_event *event = NULL;
+
+       while (*p) {
+               parent = *p;
+               event = rb_entry(parent, struct ceph_osd_event, node);
+               if (new->cookie < event->cookie)
+                       p = &(*p)->rb_left;
+               else if (new->cookie > event->cookie)
+                       p = &(*p)->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&new->node, parent, p);
+       rb_insert_color(&new->node, &osdc->event_tree);
+}
+
+static struct ceph_osd_event *__find_event(struct ceph_osd_client *osdc,
+                                               u64 cookie)
+{
+       struct rb_node **p = &osdc->event_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct ceph_osd_event *event = NULL;
+
+       while (*p) {
+               parent = *p;
+               event = rb_entry(parent, struct ceph_osd_event, node);
+               if (cookie < event->cookie)
+                       p = &(*p)->rb_left;
+               else if (cookie > event->cookie)
+                       p = &(*p)->rb_right;
+               else
+                       return event;
+       }
+       return NULL;
+}
+
+static void __remove_event(struct ceph_osd_event *event)
+{
+       struct ceph_osd_client *osdc = event->osdc;
+
+       if (!RB_EMPTY_NODE(&event->node)) {
+               dout("__remove_event removed %p\n", event);
+               rb_erase(&event->node, &osdc->event_tree);
+               ceph_osdc_put_event(event);
+       } else {
+               dout("__remove_event didn't remove %p\n", event);
+       }
+}
+
+int ceph_osdc_create_event(struct ceph_osd_client *osdc,
+                          void (*event_cb)(u64, u64, u8, void *),
+                          int one_shot, void *data,
+                          struct ceph_osd_event **pevent)
+{
+       struct ceph_osd_event *event;
+
+       event = kmalloc(sizeof(*event), GFP_NOIO);
+       if (!event)
+               return -ENOMEM;
+
+       dout("create_event %p\n", event);
+       event->cb = event_cb;
+       event->one_shot = one_shot;
+       event->data = data;
+       event->osdc = osdc;
+       INIT_LIST_HEAD(&event->osd_node);
+       kref_init(&event->kref);   /* one ref for us */
+       kref_get(&event->kref);    /* one ref for the caller */
+       init_completion(&event->completion);
+
+       spin_lock(&osdc->event_lock);
+       event->cookie = ++osdc->event_count;
+       __insert_event(osdc, event);
+       spin_unlock(&osdc->event_lock);
+
+       *pevent = event;
+       return 0;
+}
+EXPORT_SYMBOL(ceph_osdc_create_event);
+
+void ceph_osdc_cancel_event(struct ceph_osd_event *event)
+{
+       struct ceph_osd_client *osdc = event->osdc;
+
+       dout("cancel_event %p\n", event);
+       spin_lock(&osdc->event_lock);
+       __remove_event(event);
+       spin_unlock(&osdc->event_lock);
+       ceph_osdc_put_event(event); /* caller's */
+}
+EXPORT_SYMBOL(ceph_osdc_cancel_event);
+
+
+static void do_event_work(struct work_struct *work)
+{
+       struct ceph_osd_event_work *event_work =
+               container_of(work, struct ceph_osd_event_work, work);
+       struct ceph_osd_event *event = event_work->event;
+       u64 ver = event_work->ver;
+       u64 notify_id = event_work->notify_id;
+       u8 opcode = event_work->opcode;
+
+       dout("do_event_work completing %p\n", event);
+       event->cb(ver, notify_id, opcode, event->data);
+       complete(&event->completion);
+       dout("do_event_work completed %p\n", event);
+       ceph_osdc_put_event(event);
+       kfree(event_work);
+}
+
+
+/*
+ * Process osd watch notifications
+ */
+void handle_watch_notify(struct ceph_osd_client *osdc, struct ceph_msg *msg)
+{
+       void *p, *end;
+       u8 proto_ver;
+       u64 cookie, ver, notify_id;
+       u8 opcode;
+       struct ceph_osd_event *event;
+       struct ceph_osd_event_work *event_work;
+
+       p = msg->front.iov_base;
+       end = p + msg->front.iov_len;
+
+       ceph_decode_8_safe(&p, end, proto_ver, bad);
+       ceph_decode_8_safe(&p, end, opcode, bad);
+       ceph_decode_64_safe(&p, end, cookie, bad);
+       ceph_decode_64_safe(&p, end, ver, bad);
+       ceph_decode_64_safe(&p, end, notify_id, bad);
+
+       spin_lock(&osdc->event_lock);
+       event = __find_event(osdc, cookie);
+       if (event) {
+               get_event(event);
+               if (event->one_shot)
+                       __remove_event(event);
+       }
+       spin_unlock(&osdc->event_lock);
+       dout("handle_watch_notify cookie %lld ver %lld event %p\n",
+            cookie, ver, event);
+       if (event) {
+               event_work = kmalloc(sizeof(*event_work), GFP_NOIO);
+               INIT_WORK(&event_work->work, do_event_work);
+               if (!event_work) {
+                       dout("ERROR: could not allocate event_work\n");
+                       goto done_err;
+               }
+               event_work->event = event;
+               event_work->ver = ver;
+               event_work->notify_id = notify_id;
+               event_work->opcode = opcode;
+               if (!queue_work(osdc->notify_wq, &event_work->work)) {
+                       dout("WARNING: failed to queue notify event work\n");
+                       goto done_err;
+               }
+       }
+
+       return;
+
+done_err:
+       complete(&event->completion);
+       ceph_osdc_put_event(event);
+       return;
+
+bad:
+       pr_err("osdc handle_watch_notify corrupt msg\n");
+       return;
+}
+
+int ceph_osdc_wait_event(struct ceph_osd_event *event, unsigned long timeout)
+{
+       int err;
+
+       dout("wait_event %p\n", event);
+       err = wait_for_completion_interruptible_timeout(&event->completion,
+                                                       timeout * HZ);
+       ceph_osdc_put_event(event);
+       if (err > 0)
+               err = 0;
+       dout("wait_event %p returns %d\n", event, err);
+       return err;
+}
+EXPORT_SYMBOL(ceph_osdc_wait_event);
+
 /*
  * Register request, send initial attempt.
  */
@@ -1347,15 +1670,22 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
         * the request still han't been touched yet.
         */
        if (req->r_sent == 0) {
-               rc = __send_request(osdc, req);
-               if (rc) {
-                       if (nofail) {
-                               dout("osdc_start_request failed send, "
-                                    " marking %lld\n", req->r_tid);
-                               req->r_resend = true;
-                               rc = 0;
-                       } else {
-                               __unregister_request(osdc, req);
+               rc = __map_request(osdc, req);
+               if (rc < 0)
+                       return rc;
+               if (req->r_osd == NULL) {
+                       dout("send_request %p no up osds in pg\n", req);
+                       ceph_monc_request_next_osdmap(&osdc->client->monc);
+               } else {
+                       rc = __send_request(osdc, req);
+                       if (rc) {
+                               if (nofail) {
+                                       dout("osdc_start_request failed send, "
+                                            " will retry %lld\n", req->r_tid);
+                                       rc = 0;
+                               } else {
+                                       __unregister_request(osdc, req);
+                               }
                        }
                }
        }
@@ -1441,9 +1771,15 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        INIT_LIST_HEAD(&osdc->osd_lru);
        osdc->requests = RB_ROOT;
        INIT_LIST_HEAD(&osdc->req_lru);
+       INIT_LIST_HEAD(&osdc->req_unsent);
+       INIT_LIST_HEAD(&osdc->req_notarget);
+       INIT_LIST_HEAD(&osdc->req_linger);
        osdc->num_requests = 0;
        INIT_DELAYED_WORK(&osdc->timeout_work, handle_timeout);
        INIT_DELAYED_WORK(&osdc->osds_timeout_work, handle_osds_timeout);
+       spin_lock_init(&osdc->event_lock);
+       osdc->event_tree = RB_ROOT;
+       osdc->event_count = 0;
 
        schedule_delayed_work(&osdc->osds_timeout_work,
           round_jiffies_relative(osdc->client->options->osd_idle_ttl * HZ));
@@ -1463,6 +1799,13 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
                                "osd_op_reply");
        if (err < 0)
                goto out_msgpool;
+
+       osdc->notify_wq = create_singlethread_workqueue("ceph-watch-notify");
+       if (IS_ERR(osdc->notify_wq)) {
+               err = PTR_ERR(osdc->notify_wq);
+               osdc->notify_wq = NULL;
+               goto out_msgpool;
+       }
        return 0;
 
 out_msgpool:
@@ -1476,6 +1819,8 @@ EXPORT_SYMBOL(ceph_osdc_init);
 
 void ceph_osdc_stop(struct ceph_osd_client *osdc)
 {
+       flush_workqueue(osdc->notify_wq);
+       destroy_workqueue(osdc->notify_wq);
        cancel_delayed_work_sync(&osdc->timeout_work);
        cancel_delayed_work_sync(&osdc->osds_timeout_work);
        if (osdc->osdmap) {
@@ -1483,6 +1828,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
                osdc->osdmap = NULL;
        }
        remove_old_osds(osdc, 1);
+       WARN_ON(!RB_EMPTY_ROOT(&osdc->osds));
        mempool_destroy(osdc->req_mempool);
        ceph_msgpool_destroy(&osdc->msgpool_op);
        ceph_msgpool_destroy(&osdc->msgpool_op_reply);
@@ -1591,6 +1937,9 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
        case CEPH_MSG_OSD_OPREPLY:
                handle_reply(osdc, msg, con);
                break;
+       case CEPH_MSG_WATCH_NOTIFY:
+               handle_watch_notify(osdc, msg);
+               break;
 
        default:
                pr_err("received unknown message type %d %s\n", type,
@@ -1684,6 +2033,7 @@ static struct ceph_msg *alloc_msg(struct ceph_connection *con,
 
        switch (type) {
        case CEPH_MSG_OSD_MAP:
+       case CEPH_MSG_WATCH_NOTIFY:
                return ceph_msg_new(type, front, GFP_NOFS);
        case CEPH_MSG_OSD_OPREPLY:
                return get_reply(con, hdr, skip);
index 0c55eaa70e39568a7ee2e280675cd8c01cf547b6..aeeece72b72fa25d29dfd3162a2f9c3a8ef6fcbd 100644 (file)
@@ -3761,7 +3761,10 @@ static int __init pktgen_create_thread(int cpu)
        list_add_tail(&t->th_list, &pktgen_threads);
        init_completion(&t->start_done);
 
-       p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
+       p = kthread_create_on_node(pktgen_thread_worker,
+                                  t,
+                                  cpu_to_node(cpu),
+                                  "kpktgend_%d", cpu);
        if (IS_ERR(p)) {
                pr_err("kernel_thread() failed for cpu %d\n", t->cpu);
                list_del(&t->th_list);
index 75ea686f27d5aeedfd220dfbfa514295d6cc8ecc..6daaa49d133f1eb389e11da9d931f71814d3ec68 100644 (file)
@@ -33,8 +33,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/rbtree.h>
-
-#include <asm-generic/bitops/le.h>
+#include <linux/bitops.h>
 
 #include "rds.h"
 
@@ -285,7 +284,7 @@ void rds_cong_set_bit(struct rds_cong_map *map, __be16 port)
        i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
        off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
 
-       generic___set_le_bit(off, (void *)map->m_page_addrs[i]);
+       __set_bit_le(off, (void *)map->m_page_addrs[i]);
 }
 
 void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
@@ -299,7 +298,7 @@ void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
        i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
        off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
 
-       generic___clear_le_bit(off, (void *)map->m_page_addrs[i]);
+       __clear_bit_le(off, (void *)map->m_page_addrs[i]);
 }
 
 static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
@@ -310,7 +309,7 @@ static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
        i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
        off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
 
-       return generic_test_le_bit(off, (void *)map->m_page_addrs[i]);
+       return test_bit_le(off, (void *)map->m_page_addrs[i]);
 }
 
 void rds_cong_add_socket(struct rds_sock *rs)
index 8b4061049d764a86320974f6e6eda39c7033affb..e3c36a2744128a47b94537e00a78e5055a5a7fe5 100644 (file)
@@ -160,6 +160,28 @@ gss_mech_get_by_name(const char *name)
 
 EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
 
+struct gss_api_mech *
+gss_mech_get_by_OID(struct xdr_netobj *obj)
+{
+       struct gss_api_mech     *pos, *gm = NULL;
+
+       spin_lock(&registered_mechs_lock);
+       list_for_each_entry(pos, &registered_mechs, gm_list) {
+               if (obj->len == pos->gm_oid.len) {
+                       if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) {
+                               if (try_module_get(pos->gm_owner))
+                                       gm = pos;
+                               break;
+                       }
+               }
+       }
+       spin_unlock(&registered_mechs_lock);
+       return gm;
+
+}
+
+EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
+
 static inline int
 mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
 {
@@ -193,6 +215,22 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
 
 EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
 
+int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr)
+{
+       struct gss_api_mech *pos = NULL;
+       int i = 0;
+
+       spin_lock(&registered_mechs_lock);
+       list_for_each_entry(pos, &registered_mechs, gm_list) {
+               array_ptr[i] = pos->gm_pfs->pseudoflavor;
+               i++;
+       }
+       spin_unlock(&registered_mechs_lock);
+       return i;
+}
+
+EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors);
+
 u32
 gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
 {
index 30916b06c12bd7f5ade9f9cea0641e51ac52e528..c8e10216c1134dc88db21c870174f8654cbedffc 100644 (file)
@@ -38,6 +38,14 @@ struct unix_domain {
 
 extern struct auth_ops svcauth_unix;
 
+static void svcauth_unix_domain_release(struct auth_domain *dom)
+{
+       struct unix_domain *ud = container_of(dom, struct unix_domain, h);
+
+       kfree(dom->name);
+       kfree(ud);
+}
+
 struct auth_domain *unix_domain_find(char *name)
 {
        struct auth_domain *rv;
@@ -47,7 +55,7 @@ struct auth_domain *unix_domain_find(char *name)
        while(1) {
                if (rv) {
                        if (new && rv != &new->h)
-                               auth_domain_put(&new->h);
+                               svcauth_unix_domain_release(&new->h);
 
                        if (rv->flavour != &svcauth_unix) {
                                auth_domain_put(rv);
@@ -74,14 +82,6 @@ struct auth_domain *unix_domain_find(char *name)
 }
 EXPORT_SYMBOL_GPL(unix_domain_find);
 
-static void svcauth_unix_domain_release(struct auth_domain *dom)
-{
-       struct unix_domain *ud = container_of(dom, struct unix_domain, h);
-
-       kfree(dom->name);
-       kfree(ud);
-}
-
 
 /**************************************************
  * cache for IP address to unix_domain
index be96d429b475f72c31f5d16a0b9e28d677d969b9..1e336a06d3e6375af0221b5a65f9db7236c2c4a0 100644 (file)
@@ -710,6 +710,8 @@ static void xs_reset_transport(struct sock_xprt *transport)
        if (sk == NULL)
                return;
 
+       transport->srcport = 0;
+
        write_lock_bh(&sk->sk_callback_lock);
        transport->inet = NULL;
        transport->sock = NULL;
index 2e088109fbd5238f3e4f6d293848606d0ac95a58..fcea26168bca718afb07cf4a2a71081b309e906e 100644 (file)
@@ -18,6 +18,11 @@ always               := $(hostprogs-y) $(hostprogs-m)
 # The following hostprogs-y programs are only build on demand
 hostprogs-y += unifdef
 
+# This target is used internally to avoid "is up to date" messages
+PHONY += build_unifdef
+build_unifdef: scripts/unifdef FORCE
+       @:
+
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
 subdir-$(CONFIG_SECURITY_SELINUX) += selinux
index 4eb99ab34053769f5b2b644594427b2bdc108c82..d5f925abe4d29710ab0b314bf28d29752b35dc8d 100644 (file)
@@ -49,6 +49,40 @@ ifeq ($(KBUILD_NOPEDANTIC),)
                 $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use EXTRA_CFLAGS)
         endif
 endif
+
+#
+# make W=1 settings
+#
+# $(call cc-option... ) handles gcc -W.. options which
+# are not supported by all versions of the compiler
+ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
+KBUILD_EXTRA_WARNINGS := -Wextra
+KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
+KBUILD_EXTRA_WARNINGS += -Waggregate-return
+KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
+KBUILD_EXTRA_WARNINGS += -Wcast-qual
+KBUILD_EXTRA_WARNINGS += -Wcast-align
+KBUILD_EXTRA_WARNINGS += -Wconversion
+KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
+KBUILD_EXTRA_WARNINGS += -Wlogical-op
+KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
+KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
+KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
+KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
+KBUILD_EXTRA_WARNINGS += -Wnested-externs
+KBUILD_EXTRA_WARNINGS += -Wold-style-definition
+KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
+KBUILD_EXTRA_WARNINGS += -Wpacked
+KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
+KBUILD_EXTRA_WARNINGS += -Wpadded
+KBUILD_EXTRA_WARNINGS += -Wpointer-arith
+KBUILD_EXTRA_WARNINGS += -Wredundant-decls
+KBUILD_EXTRA_WARNINGS += -Wshadow
+KBUILD_EXTRA_WARNINGS += -Wswitch-default
+KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
+KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
+endif
+
 include scripts/Makefile.lib
 
 ifdef host-progs
@@ -403,7 +437,6 @@ ifneq ($(cmd_files),)
   include $(cmd_files)
 endif
 
-
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable se we can use it in if_changed and friends.
 
index 6501a50e17f0e157dab2dab3d64d8807fc3669da..6129020c41a94570ff49f5e42b5963a23105ba8e 100755 (executable)
@@ -17,7 +17,9 @@ def getsizes(file):
     sym = {}
     for l in os.popen("nm --size-sort " + file).readlines():
         size, type, name = l[:-1].split()
-        if type in "tTdDbB":
+        if type in "tTdDbBrR":
+            # strip generated symbols
+            if name[:6] == "__mod_": continue
             # function names begin with '.' on 64-bit powerpc
             if "." in name[1:]: name = "static." + name.split(".")[0]
             sym[name] = sym.get(name, 0) + int(size, 16)
index 58848e3e392c7c45004340d8704229da18e990eb..8f9e394298cda6cb17edd29b5239d0a134732650 100755 (executable)
@@ -2804,9 +2804,9 @@ sub process {
                        WARN("consider using a completion\n" . $herecurr);
 
                }
-# recommend strict_strto* over simple_strto*
+# recommend kstrto* over simple_strto*
                if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
-                       WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+                       WARN("consider using kstrto* in preference to simple_$1\n" . $herecurr);
                }
 # check for __initcall(), use device_initcall() explicitly please
                if ($line =~ /^.\s*__initcall\s*\(/) {
@@ -2902,6 +2902,11 @@ sub process {
                    $line =~ /DEVICE_ATTR.*S_IWUGO/ ) {
                        WARN("Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
                }
+
+               # Check for memset with swapped arguments
+               if ($line =~ /memset.*\,(\ |)(0x|)0(\ |0|)\);/) {
+                       ERROR("memset size is 3rd argument, not the second.\n" . $herecurr);
+               }
        }
 
        # If we have no input at all, then there is nothing to report on
@@ -2944,6 +2949,7 @@ sub process {
                if ($rpt_cleaners) {
                        print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
                        print "      scripts/cleanfile\n\n";
+                       $rpt_cleaners = 0;
                }
        }
 
index 1512c0a755acea37da3d190c88ae47c04023f883..e1862429ccda55ea41f760acd299ea6747319f0c 100755 (executable)
@@ -56,10 +56,11 @@ trap "rm -f $tmp1 $tmp2" 0
 dump_config "$img"
 
 # That didn't work, so retry after decompression.
-try_decompress '\037\213\010' xy  gunzip
-try_decompress 'BZh'          xy  bunzip2
-try_decompress '\135\0\0\0'   xxx unlzma
-try_decompress '\211\114\132' xy  'lzop -d'
+try_decompress '\037\213\010' xy    gunzip
+try_decompress '\3757zXZ\000' abcde unxz
+try_decompress 'BZh'          xy    bunzip2
+try_decompress '\135\0\0\0'   xxx   unlzma
+try_decompress '\211\114\132' xy    'lzop -d'
 
 # Bail out:
 echo "$me: Cannot find kernel config." >&2
index e420fe440019fd7c1ea8c0a80319f68bd6f4983b..13d03cf05d95115571839e2c791fc87fa1c9612a 100644 (file)
@@ -28,9 +28,9 @@ $(obj)/keywords.c: $(obj)/keywords.gperf FORCE
 # flex
 
 quiet_cmd_lex.c = FLEX    $@
-      cmd_lex.c = flex -o$@ -d $< $(obj)/parse.h
+      cmd_lex.c = flex -o$@ -d $<
 
-$(obj)/lex.c: $(obj)/lex.l $(obj)/parse.h $(obj)/keywords.c FORCE
+$(obj)/lex.c: $(obj)/lex.l $(obj)/keywords.c FORCE
        $(call if_changed,lex.c)
        cp $@ $@_shipped
 
index f99115ebe9254a4ef630eabe127bc7cf25e2195c..f9e75531ea0390836bfdc0fa5c8ad5b42ca12924 100644 (file)
@@ -53,12 +53,22 @@ static int nsyms;
 static struct symbol *expansion_trail;
 static struct symbol *visited_symbols;
 
-static const char *const symbol_type_name[] = {
-       "normal", "typedef", "enum", "struct", "union"
+static const struct {
+       int n;
+       const char *name;
+} symbol_types[] = {
+       [SYM_NORMAL]     = { 0, NULL},
+       [SYM_TYPEDEF]    = {'t', "typedef"},
+       [SYM_ENUM]       = {'e', "enum"},
+       [SYM_STRUCT]     = {'s', "struct"},
+       [SYM_UNION]      = {'u', "union"},
+       [SYM_ENUM_CONST] = {'E', "enum constant"},
 };
 
 static int equal_list(struct string_list *a, struct string_list *b);
 static void print_list(FILE * f, struct string_list *list);
+static struct string_list *concat_list(struct string_list *start, ...);
+static struct string_list *mk_node(const char *string);
 static void print_location(void);
 static void print_type_name(enum symbol_type type, const char *name);
 
@@ -140,14 +150,20 @@ static unsigned long crc32(const char *s)
 
 static enum symbol_type map_to_ns(enum symbol_type t)
 {
-       if (t == SYM_TYPEDEF)
-               t = SYM_NORMAL;
-       else if (t == SYM_UNION)
-               t = SYM_STRUCT;
+       switch (t) {
+       case SYM_ENUM_CONST:
+       case SYM_NORMAL:
+       case SYM_TYPEDEF:
+               return SYM_NORMAL;
+       case SYM_ENUM:
+       case SYM_STRUCT:
+       case SYM_UNION:
+               return SYM_STRUCT;
+       }
        return t;
 }
 
-struct symbol *find_symbol(const char *name, enum symbol_type ns)
+struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
 {
        unsigned long h = crc32(name) % HASH_BUCKETS;
        struct symbol *sym;
@@ -158,6 +174,8 @@ struct symbol *find_symbol(const char *name, enum symbol_type ns)
                    sym->is_declared)
                        break;
 
+       if (exact && sym && sym->type != ns)
+               return NULL;
        return sym;
 }
 
@@ -180,10 +198,47 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
                            struct string_list *defn, int is_extern,
                            int is_reference)
 {
-       unsigned long h = crc32(name) % HASH_BUCKETS;
+       unsigned long h;
        struct symbol *sym;
        enum symbol_status status = STATUS_UNCHANGED;
+       /* The parser adds symbols in the order their declaration completes,
+        * so it is safe to store the value of the previous enum constant in
+        * a static variable.
+        */
+       static int enum_counter;
+       static struct string_list *last_enum_expr;
+
+       if (type == SYM_ENUM_CONST) {
+               if (defn) {
+                       free_list(last_enum_expr, NULL);
+                       last_enum_expr = copy_list_range(defn, NULL);
+                       enum_counter = 1;
+               } else {
+                       struct string_list *expr;
+                       char buf[20];
+
+                       snprintf(buf, sizeof(buf), "%d", enum_counter++);
+                       if (last_enum_expr) {
+                               expr = copy_list_range(last_enum_expr, NULL);
+                               defn = concat_list(mk_node("("),
+                                                  expr,
+                                                  mk_node(")"),
+                                                  mk_node("+"),
+                                                  mk_node(buf), NULL);
+                       } else {
+                               defn = mk_node(buf);
+                       }
+               }
+       } else if (type == SYM_ENUM) {
+               free_list(last_enum_expr, NULL);
+               last_enum_expr = NULL;
+               enum_counter = 0;
+               if (!name)
+                       /* Anonymous enum definition, nothing more to do */
+                       return NULL;
+       }
 
+       h = crc32(name) % HASH_BUCKETS;
        for (sym = symtab[h]; sym; sym = sym->hash_next) {
                if (map_to_ns(sym->type) == map_to_ns(type) &&
                    strcmp(name, sym->name) == 0) {
@@ -247,8 +302,12 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type,
        sym->is_override = 0;
 
        if (flag_debug) {
-               fprintf(debugfile, "Defn for %s %s == <",
-                       symbol_type_name[type], name);
+               if (symbol_types[type].name)
+                       fprintf(debugfile, "Defn for %s %s == <",
+                               symbol_types[type].name, name);
+               else
+                       fprintf(debugfile, "Defn for type%d %s == <",
+                               type, name);
                if (is_extern)
                        fputs("extern ", debugfile);
                print_list(debugfile, defn);
@@ -288,6 +347,35 @@ void free_list(struct string_list *s, struct string_list *e)
        }
 }
 
+static struct string_list *mk_node(const char *string)
+{
+       struct string_list *newnode;
+
+       newnode = xmalloc(sizeof(*newnode));
+       newnode->string = xstrdup(string);
+       newnode->tag = SYM_NORMAL;
+       newnode->next = NULL;
+
+       return newnode;
+}
+
+static struct string_list *concat_list(struct string_list *start, ...)
+{
+       va_list ap;
+       struct string_list *n, *n2;
+
+       if (!start)
+               return NULL;
+       for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
+               for (n2 = n; n2->next; n2 = n2->next)
+                       ;
+               n2->next = start;
+               start = n;
+       }
+       va_end(ap);
+       return start;
+}
+
 struct string_list *copy_node(struct string_list *node)
 {
        struct string_list *newnode;
@@ -299,6 +387,22 @@ struct string_list *copy_node(struct string_list *node)
        return newnode;
 }
 
+struct string_list *copy_list_range(struct string_list *start,
+                                   struct string_list *end)
+{
+       struct string_list *res, *n;
+
+       if (start == end)
+               return NULL;
+       n = res = copy_node(start);
+       for (start = start->next; start != end; start = start->next) {
+               n->next = copy_node(start);
+               n = n->next;
+       }
+       n->next = NULL;
+       return res;
+}
+
 static int equal_list(struct string_list *a, struct string_list *b)
 {
        while (a && b) {
@@ -346,8 +450,8 @@ static struct string_list *read_node(FILE *f)
        if (node.string[1] == '#') {
                int n;
 
-               for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
-                       if (node.string[0] == symbol_type_name[n][0]) {
+               for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
+                       if (node.string[0] == symbol_types[n].n) {
                                node.tag = n;
                                node.string += 2;
                                return copy_node(&node);
@@ -397,8 +501,8 @@ static void read_reference(FILE *f)
 
 static void print_node(FILE * f, struct string_list *list)
 {
-       if (list->tag != SYM_NORMAL) {
-               putc(symbol_type_name[list->tag][0], f);
+       if (symbol_types[list->tag].n) {
+               putc(symbol_types[list->tag].n, f);
                putc('#', f);
        }
        fputs(list->string, f);
@@ -468,8 +572,9 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
                        crc = partial_crc32_one(' ', crc);
                        break;
 
+               case SYM_ENUM_CONST:
                case SYM_TYPEDEF:
-                       subsym = find_symbol(cur->string, cur->tag);
+                       subsym = find_symbol(cur->string, cur->tag, 0);
                        /* FIXME: Bad reference files can segfault here. */
                        if (subsym->expansion_trail) {
                                if (flag_dump_defs)
@@ -486,55 +591,30 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
                case SYM_STRUCT:
                case SYM_UNION:
                case SYM_ENUM:
-                       subsym = find_symbol(cur->string, cur->tag);
+                       subsym = find_symbol(cur->string, cur->tag, 0);
                        if (!subsym) {
-                               struct string_list *n, *t = NULL;
+                               struct string_list *n;
 
                                error_with_pos("expand undefined %s %s",
-                                              symbol_type_name[cur->tag],
+                                              symbol_types[cur->tag].name,
                                               cur->string);
-
-                               n = xmalloc(sizeof(*n));
-                               n->string = xstrdup(symbol_type_name[cur->tag]);
-                               n->tag = SYM_NORMAL;
-                               n->next = t;
-                               t = n;
-
-                               n = xmalloc(sizeof(*n));
-                               n->string = xstrdup(cur->string);
-                               n->tag = SYM_NORMAL;
-                               n->next = t;
-                               t = n;
-
-                               n = xmalloc(sizeof(*n));
-                               n->string = xstrdup("{");
-                               n->tag = SYM_NORMAL;
-                               n->next = t;
-                               t = n;
-
-                               n = xmalloc(sizeof(*n));
-                               n->string = xstrdup("UNKNOWN");
-                               n->tag = SYM_NORMAL;
-                               n->next = t;
-                               t = n;
-
-                               n = xmalloc(sizeof(*n));
-                               n->string = xstrdup("}");
-                               n->tag = SYM_NORMAL;
-                               n->next = t;
-                               t = n;
-
+                               n = concat_list(mk_node
+                                               (symbol_types[cur->tag].name),
+                                               mk_node(cur->string),
+                                               mk_node("{"),
+                                               mk_node("UNKNOWN"),
+                                               mk_node("}"), NULL);
                                subsym =
                                    add_symbol(cur->string, cur->tag, n, 0);
                        }
                        if (subsym->expansion_trail) {
                                if (flag_dump_defs) {
                                        fprintf(debugfile, "%s %s ",
-                                               symbol_type_name[cur->tag],
+                                               symbol_types[cur->tag].name,
                                                cur->string);
                                }
 
-                               crc = partial_crc32(symbol_type_name[cur->tag],
+                               crc = partial_crc32(symbol_types[cur->tag].name,
                                                    crc);
                                crc = partial_crc32_one(' ', crc);
                                crc = partial_crc32(cur->string, crc);
@@ -565,7 +645,7 @@ void export_symbol(const char *name)
 {
        struct symbol *sym;
 
-       sym = find_symbol(name, SYM_NORMAL);
+       sym = find_symbol(name, SYM_NORMAL, 0);
        if (!sym)
                error_with_pos("export undefined symbol %s", name);
        else {
@@ -624,8 +704,8 @@ static void print_location(void)
 
 static void print_type_name(enum symbol_type type, const char *name)
 {
-       if (type != SYM_NORMAL)
-               fprintf(stderr, "%s %s", symbol_type_name[type], name);
+       if (symbol_types[type].name)
+               fprintf(stderr, "%s %s", symbol_types[type].name, name);
        else
                fprintf(stderr, "%s", name);
 }
@@ -771,8 +851,8 @@ int main(int argc, char **argv)
 
                        if (sym->is_override)
                                fputs("override ", dumpfile);
-                       if (sym->type != SYM_NORMAL) {
-                               putc(symbol_type_name[sym->type][0], dumpfile);
+                       if (symbol_types[sym->type].n) {
+                               putc(symbol_types[sym->type].n, dumpfile);
                                putc('#', dumpfile);
                        }
                        fputs(sym->name, dumpfile);
index 25c4d40cefc134f2609593ed60546daba55e1aab..7ec52ae3846aa3c2b70837fd652d7e20bbf9dcb0 100644 (file)
@@ -26,7 +26,8 @@
 #include <stdio.h>
 
 enum symbol_type {
-       SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
+       SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION,
+       SYM_ENUM_CONST
 };
 
 enum symbol_status {
@@ -58,7 +59,7 @@ typedef struct string_list **yystype;
 extern int cur_line;
 extern char *cur_filename;
 
-struct symbol *find_symbol(const char *name, enum symbol_type ns);
+struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact);
 struct symbol *add_symbol(const char *name, enum symbol_type type,
                          struct string_list *defn, int is_extern);
 void export_symbol(const char *);
@@ -66,6 +67,8 @@ void export_symbol(const char *);
 void free_node(struct string_list *list);
 void free_list(struct string_list *s, struct string_list *e);
 struct string_list *copy_node(struct string_list *);
+struct string_list *copy_list_range(struct string_list *start,
+                                   struct string_list *end);
 
 int yylex(void);
 int yyparse(void);
index 2ac23bcca5b537fad4c8b06401404b20adb03e9e..af4939041e4b6f082a446fab07b5d79addf30ef0 100644 (file)
@@ -79,6 +79,7 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
 
 /* Limits of integral types. */
 #ifndef INT8_MIN
@@ -109,8 +110,6 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
-#endif /* ! C99 */
-
 #endif /* ! FLEXINT_H */
 
 /* %endif */
@@ -456,16 +455,16 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[76] =
+static yyconst flex_int16_t yy_accept[73] =
     {   0,
-        0,    0,    0,    0,   14,   12,    4,    3,   12,    7,
-       12,   12,    7,   12,   12,   12,   12,   12,    9,    9,
-       12,   12,   12,    4,    0,    5,    0,    7,    0,    6,
-        0,    0,    0,    0,    0,    0,    2,    8,   10,   10,
-        9,    0,    0,    9,    9,    0,    9,    0,    0,   11,
-        0,    0,    0,   10,    0,   10,    9,    9,    0,    0,
-        0,    0,    0,    0,    0,   10,   10,    0,    0,    0,
-        0,    0,    0,    1,    0
+        0,    0,   14,   12,    4,    3,   12,    7,   12,   12,
+       12,   12,   12,    9,    9,   12,   12,    7,   12,   12,
+        4,    0,    5,    0,    7,    8,    0,    6,    0,    0,
+       10,   10,    9,    0,    0,    9,    9,    0,    9,    0,
+        0,    0,    0,    2,    0,    0,   11,    0,   10,    0,
+       10,    9,    9,    0,    0,    0,   10,   10,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        1,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -507,108 +506,104 @@ static yyconst flex_int32_t yy_meta[29] =
         8,    7,    3,    3,    3,    1,    3,    1
     } ;
 
-static yyconst flex_int16_t yy_base[88] =
+static yyconst flex_int16_t yy_base[85] =
     {   0,
-        0,  147,   21,  140,  145,  284,   39,  284,   26,    0,
-       32,  126,   40,   44,  115,   35,   36,   46,   50,   53,
-       39,   61,   54,   79,   65,  284,    0,    0,   66,  284,
-        0,  119,   79,   75,  123,  104,  284,  284,  107,    0,
-       79,   73,   76,   76,   66,    0,    0,   85,   86,  284,
-      133,   83,   91,  284,   99,  147,  284,  114,  122,   70,
-      107,  141,  172,  151,  135,  181,  284,  137,  114,  157,
-      149,   48,   45,  284,  284,  208,  214,  222,  230,  238,
-      246,  250,  255,  256,  261,  267,  275
+        0,  145,  150,  266,   27,  266,   25,    0,  131,   23,
+       23,   16,   23,   39,   31,   25,   39,   60,   22,   65,
+       57,   43,  266,    0,    0,  266,   61,  266,    0,  128,
+       74,    0,  113,   59,   62,  113,   52,    0,    0,   72,
+       66,  110,  100,  266,   73,   74,  266,   70,  266,   90,
+      103,  266,   84,  129,  108,  113,  143,  266,  107,   66,
+      118,  137,  168,  120,   80,   91,  145,  143,   83,   41,
+      266,  266,  190,  196,  204,  212,  220,  228,  232,  237,
+      238,  243,  249,  257
     } ;
 
-static yyconst flex_int16_t yy_def[88] =
+static yyconst flex_int16_t yy_def[85] =
     {   0,
-       75,    1,    1,    3,   75,   75,   75,   75,   76,   77,
-       78,   75,   77,   79,   75,   75,   75,   75,   75,   19,
-       75,   75,   75,   75,   76,   75,   80,   77,   78,   75,
-       81,   75,   76,   78,   79,   79,   75,   75,   75,   39,
-       19,   82,   83,   75,   75,   84,   20,   76,   78,   75,
-       79,   51,   85,   75,   75,   75,   75,   84,   79,   51,
-       79,   79,   79,   51,   75,   75,   75,   86,   79,   63,
-       86,   87,   87,   75,    0,   75,   75,   75,   75,   75,
-       75,   75,   75,   75,   75,   75,   75
+       72,    1,   72,   72,   72,   72,   73,   74,   72,   72,
+       75,   72,   72,   72,   14,   72,   72,   74,   72,   76,
+       72,   73,   72,   77,   74,   72,   75,   72,   78,   72,
+       72,   31,   14,   79,   80,   72,   72,   81,   15,   73,
+       75,   76,   76,   72,   73,   75,   72,   82,   72,   72,
+       72,   72,   81,   76,   54,   72,   72,   72,   76,   54,
+       76,   76,   76,   54,   83,   76,   63,   83,   84,   84,
+       72,    0,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   72,   72,   72
     } ;
 
-static yyconst flex_int16_t yy_nxt[313] =
+static yyconst flex_int16_t yy_nxt[295] =
     {   0,
-        6,    7,    8,    7,    9,    6,   10,    6,    6,   11,
-        6,    6,   12,    6,    6,    6,    6,    6,    6,   10,
-       10,   10,   13,   10,   10,    6,   10,    6,   15,   16,
-       26,   15,   17,   18,   19,   20,   20,   21,   15,   22,
-       24,   30,   24,   38,   33,   36,   37,   74,   23,   34,
-       74,   27,   38,   38,   38,   38,   38,   31,   32,   39,
-       39,   39,   40,   41,   41,   42,   47,   47,   47,   26,
-       43,   38,   44,   45,   46,   30,   44,   75,   38,   38,
-       24,   38,   24,   26,   30,   40,   55,   55,   57,   26,
-       27,   31,   57,   43,   35,   30,   64,   64,   64,   57,
-
-       31,   65,   65,   75,   27,   36,   37,   35,   59,   37,
-       27,   31,   56,   56,   56,   59,   37,   51,   52,   52,
-       39,   39,   39,   59,   37,   37,   68,   53,   54,   54,
-       69,   50,   38,   54,   59,   37,   44,   45,   32,   37,
-       44,   35,   59,   37,   75,   14,   60,   60,   66,   66,
-       66,   37,   14,   72,   75,   61,   62,   63,   59,   61,
-       56,   56,   56,   69,   64,   64,   64,   69,   67,   67,
-       75,   75,   75,   67,   37,   35,   75,   75,   75,   61,
-       62,   75,   75,   61,   75,   70,   70,   70,   75,   75,
-       75,   70,   70,   70,   66,   66,   66,   75,   75,   75,
-
-       75,   75,   54,   54,   75,   75,   75,   54,   25,   25,
-       25,   25,   25,   25,   25,   25,   28,   75,   75,   28,
-       28,   28,   29,   29,   29,   29,   29,   29,   29,   29,
-       35,   35,   35,   35,   35,   35,   35,   35,   48,   75,
-       48,   48,   48,   48,   48,   48,   49,   75,   49,   49,
-       49,   49,   49,   49,   42,   42,   75,   42,   56,   75,
-       56,   58,   58,   58,   66,   75,   66,   71,   71,   71,
-       71,   71,   71,   71,   71,   73,   73,   73,   73,   73,
-       73,   73,   73,    5,   75,   75,   75,   75,   75,   75,
-       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
-
-       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
-       75,   75
+        4,    5,    6,    5,    7,    4,    8,    9,   10,   11,
+        9,   12,   13,   14,   15,   15,   16,    9,   17,    8,
+        8,    8,   18,    8,    8,    4,    8,   19,   21,   23,
+       21,   26,   28,   26,   26,   30,   31,   31,   31,   26,
+       26,   26,   26,   71,   39,   39,   39,   23,   29,   26,
+       24,   32,   33,   33,   34,   72,   26,   26,   21,   35,
+       21,   36,   37,   38,   40,   36,   43,   44,   24,   41,
+       28,   32,   50,   50,   52,   28,   23,   23,   52,   35,
+       56,   56,   44,   28,   42,   71,   29,   31,   31,   31,
+       42,   29,   59,   44,   48,   49,   49,   24,   24,   29,
+
+       49,   43,   44,   51,   51,   51,   36,   37,   59,   44,
+       36,   65,   44,   54,   55,   55,   51,   51,   51,   59,
+       44,   64,   64,   64,   58,   58,   57,   57,   57,   58,
+       59,   44,   42,   64,   64,   64,   52,   72,   59,   44,
+       47,   66,   60,   60,   42,   44,   59,   69,   26,   72,
+       20,   61,   62,   63,   72,   61,   57,   57,   57,   66,
+       72,   72,   72,   66,   49,   49,   72,   61,   62,   49,
+       44,   61,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   67,   67,   67,   72,   72,   72,   67,   67,   67,
+       22,   22,   22,   22,   22,   22,   22,   22,   25,   72,
+
+       72,   25,   25,   25,   27,   27,   27,   27,   27,   27,
+       27,   27,   42,   42,   42,   42,   42,   42,   42,   42,
+       45,   72,   45,   45,   45,   45,   45,   45,   46,   72,
+       46,   46,   46,   46,   46,   46,   34,   34,   72,   34,
+       51,   72,   51,   53,   53,   53,   57,   72,   57,   68,
+       68,   68,   68,   68,   68,   68,   68,   70,   70,   70,
+       70,   70,   70,   70,   70,    3,   72,   72,   72,   72,
+       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   72,   72,   72
+
     } ;
 
-static yyconst flex_int16_t yy_chk[313] =
+static yyconst flex_int16_t yy_chk[295] =
     {   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,    3,    3,
-        9,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        7,   11,    7,   16,   13,   14,   14,   73,    3,   13,
-       72,    9,   16,   17,   17,   21,   21,   11,   18,   18,
-       18,   18,   19,   19,   19,   19,   20,   20,   20,   25,
-       19,   23,   19,   19,   19,   29,   19,   20,   22,   22,
-       24,   23,   24,   33,   34,   42,   43,   43,   45,   48,
-       25,   29,   45,   42,   60,   49,   52,   52,   52,   44,
-
-       34,   53,   53,   41,   33,   36,   36,   52,   61,   61,
-       48,   49,   55,   55,   55,   69,   69,   36,   36,   36,
-       39,   39,   39,   59,   59,   35,   59,   39,   39,   39,
-       61,   32,   15,   39,   51,   51,   58,   58,   12,   68,
-       58,   68,   62,   62,    5,    4,   51,   51,   65,   65,
-       65,   71,    2,   71,    0,   51,   51,   51,   70,   51,
-       56,   56,   56,   62,   64,   64,   64,   62,   56,   56,
-        0,    0,    0,   56,   63,   64,    0,    0,    0,   70,
-       70,    0,    0,   70,    0,   63,   63,   63,    0,    0,
-        0,   63,   63,   63,   66,   66,   66,    0,    0,    0,
-
-        0,    0,   66,   66,    0,    0,    0,   66,   76,   76,
-       76,   76,   76,   76,   76,   76,   77,    0,    0,   77,
-       77,   77,   78,   78,   78,   78,   78,   78,   78,   78,
-       79,   79,   79,   79,   79,   79,   79,   79,   80,    0,
-       80,   80,   80,   80,   80,   80,   81,    0,   81,   81,
-       81,   81,   81,   81,   82,   82,    0,   82,   83,    0,
-       83,   84,   84,   84,   85,    0,   85,   86,   86,   86,
-       86,   86,   86,   86,   86,   87,   87,   87,   87,   87,
-       87,   87,   87,   75,   75,   75,   75,   75,   75,   75,
-       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
-
-       75,   75,   75,   75,   75,   75,   75,   75,   75,   75,
-       75,   75
+        1,    1,    1,    1,    1,    1,    1,    1,    5,    7,
+        5,   10,   11,   12,   12,   13,   13,   13,   13,   19,
+       10,   16,   16,   70,   15,   15,   15,   22,   11,   19,
+        7,   14,   14,   14,   14,   15,   17,   17,   21,   14,
+       21,   14,   14,   14,   18,   14,   20,   20,   22,   18,
+       27,   34,   35,   35,   37,   41,   40,   45,   37,   34,
+       48,   48,   65,   46,   65,   69,   27,   31,   31,   31,
+       60,   41,   66,   66,   31,   31,   31,   40,   45,   46,
+
+       31,   43,   43,   50,   50,   50,   53,   53,   59,   59,
+       53,   59,   42,   43,   43,   43,   51,   51,   51,   61,
+       61,   55,   55,   55,   51,   51,   56,   56,   56,   51,
+       54,   54,   55,   64,   64,   64,   36,   33,   62,   62,
+       30,   61,   54,   54,   64,   68,   67,   68,    9,    3,
+        2,   54,   54,   54,    0,   54,   57,   57,   57,   62,
+        0,    0,    0,   62,   57,   57,    0,   67,   67,   57,
+       63,   67,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   63,   63,   63,    0,    0,    0,   63,   63,   63,
+       73,   73,   73,   73,   73,   73,   73,   73,   74,    0,
+
+        0,   74,   74,   74,   75,   75,   75,   75,   75,   75,
+       75,   75,   76,   76,   76,   76,   76,   76,   76,   76,
+       77,    0,   77,   77,   77,   77,   77,   77,   78,    0,
+       78,   78,   78,   78,   78,   78,   79,   79,    0,   79,
+       80,    0,   80,   81,   81,   81,   82,    0,   82,   83,
+       83,   83,   83,   83,   83,   83,   83,   84,   84,   84,
+       84,   84,   84,   84,   84,   72,   72,   72,   72,   72,
+       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   72,   72,   72,   72,   72,   72,   72,   72,   72,
+       72,   72,   72,   72
+
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -619,8 +614,8 @@ int yy_flex_debug = 1;
 
 static yyconst flex_int16_t yy_rule_linenum[13] =
     {   0,
-       71,   72,   73,   76,   79,   80,   81,   87,   88,   89,
-       91,   94
+       67,   68,   69,   72,   75,   76,   77,   83,   84,   85,
+       87,   90
     } ;
 
 /* The intent behind this definition is that it'll catch
@@ -667,15 +662,11 @@ char *yytext;
    and then we categorize those basic tokens in the second stage.  */
 #define YY_DECL                static int yylex1(void)
 
-/* Version 2 checksumming does proper tokenization; version 1 wasn't
-   quite so pedantic.  */
-
 /* We don't do multiple input files.  */
 #define YY_NO_INPUT 1
-#line 676 "scripts/genksyms/lex.c"
+#line 668 "scripts/genksyms/lex.c"
 
 #define INITIAL 0
-#define V2_TOKENS 1
 
 #ifndef YY_NO_UNISTD_H
 /* Special case for "unistd.h", since it is non-ANSI. We include it way
@@ -808,7 +799,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; \
@@ -918,12 +909,12 @@ YY_DECL
        register int yy_act;
     
 /* %% [7.0] user's declarations go here */
-#line 67 "scripts/genksyms/lex.l"
+#line 63 "scripts/genksyms/lex.l"
 
 
 
  /* Keep track of our location in the original source files.  */
-#line 927 "scripts/genksyms/lex.c"
+#line 918 "scripts/genksyms/lex.c"
 
        if ( !(yy_init) )
                {
@@ -987,13 +978,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 >= 76 )
+                               if ( yy_current_state >= 73 )
                                        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] != 284 );
+               while ( yy_base[yy_current_state] != 266 );
 
 yy_find_action:
 /* %% [10.0] code to find the action number goes here */
@@ -1041,42 +1032,42 @@ do_action:      /* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 71 "scripts/genksyms/lex.l"
+#line 67 "scripts/genksyms/lex.l"
 return FILENAME;
        YY_BREAK
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 72 "scripts/genksyms/lex.l"
+#line 68 "scripts/genksyms/lex.l"
 cur_line++;
        YY_BREAK
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 73 "scripts/genksyms/lex.l"
+#line 69 "scripts/genksyms/lex.l"
 cur_line++;
        YY_BREAK
 /* Ignore all other whitespace.  */
 case 4:
 YY_RULE_SETUP
-#line 76 "scripts/genksyms/lex.l"
+#line 72 "scripts/genksyms/lex.l"
 ;
        YY_BREAK
 case 5:
 /* rule 5 can match eol */
 YY_RULE_SETUP
-#line 79 "scripts/genksyms/lex.l"
+#line 75 "scripts/genksyms/lex.l"
 return STRING;
        YY_BREAK
 case 6:
 /* rule 6 can match eol */
 YY_RULE_SETUP
-#line 80 "scripts/genksyms/lex.l"
+#line 76 "scripts/genksyms/lex.l"
 return CHAR;
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 81 "scripts/genksyms/lex.l"
+#line 77 "scripts/genksyms/lex.l"
 return IDENT;
        YY_BREAK
 /* The Pedant requires that the other C multi-character tokens be
@@ -1085,38 +1076,37 @@ return IDENT;
     around them properly.  */
 case 8:
 YY_RULE_SETUP
-#line 87 "scripts/genksyms/lex.l"
+#line 83 "scripts/genksyms/lex.l"
 return OTHER;
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 88 "scripts/genksyms/lex.l"
+#line 84 "scripts/genksyms/lex.l"
 return INT;
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 89 "scripts/genksyms/lex.l"
+#line 85 "scripts/genksyms/lex.l"
 return REAL;
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 91 "scripts/genksyms/lex.l"
+#line 87 "scripts/genksyms/lex.l"
 return DOTS;
        YY_BREAK
 /* All other tokens are single characters.  */
 case 12:
 YY_RULE_SETUP
-#line 94 "scripts/genksyms/lex.l"
+#line 90 "scripts/genksyms/lex.l"
 return yytext[0];
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 97 "scripts/genksyms/lex.l"
+#line 93 "scripts/genksyms/lex.l"
 ECHO;
        YY_BREAK
-#line 1118 "scripts/genksyms/lex.c"
+#line 1109 "scripts/genksyms/lex.c"
 case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(V2_TOKENS):
        yyterminate();
 
        case YY_END_OF_BUFFER:
@@ -1429,7 +1419,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 >= 76 )
+                       if ( yy_current_state >= 73 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1462,11 +1452,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 >= 76 )
+               if ( yy_current_state >= 73 )
                        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 == 75);
+       yy_is_jam = (yy_current_state == 72);
 
        return yy_is_jam ? 0 : yy_current_state;
 }
@@ -2252,7 +2242,7 @@ void yyfree (void * ptr )
 
 /* %ok-for-header */
 
-#line 97 "scripts/genksyms/lex.l"
+#line 93 "scripts/genksyms/lex.l"
 
 
 
@@ -2263,12 +2253,23 @@ void yyfree (void * ptr )
 
 /* Macros to append to our phrase collection list.  */
 
+/*
+ * We mark any token, that that equals to a known enumerator, as
+ * SYM_ENUM_CONST. The parser will change this for struct and union tags later,
+ * the only problem is struct and union members:
+ *    enum e { a, b }; struct s { int a, b; }
+ * but in this case, the only effect will be, that the ABI checksums become
+ * more volatile, which is acceptable. Also, such collisions are quite rare,
+ * so far it was only observed in include/linux/telephony.h.
+ */
 #define _APP(T,L)      do {                                               \
                          cur_node = next_node;                            \
                          next_node = xmalloc(sizeof(*next_node));         \
                          next_node->next = cur_node;                      \
                          cur_node->string = memcpy(xmalloc(L+1), T, L+1); \
-                         cur_node->tag = SYM_NORMAL;                      \
+                         cur_node->tag =                                  \
+                           find_symbol(cur_node->string, SYM_ENUM_CONST, 1)?\
+                           SYM_ENUM_CONST : SYM_NORMAL ;                  \
                        } while (0)
 
 #define APP            _APP(yytext, yyleng)
@@ -2294,7 +2295,6 @@ yylex(void)
 
   if (lexstate == ST_NOTSTARTED)
     {
-      BEGIN(V2_TOKENS);
       next_node = xmalloc(sizeof(*next_node));
       next_node->next = NULL;
       lexstate = ST_NORMAL;
@@ -2347,8 +2347,8 @@ repeat:
 
                  case STRUCT_KEYW:
                  case UNION_KEYW:
-                   dont_want_brace_phrase = 3;
                  case ENUM_KEYW:
+                   dont_want_brace_phrase = 3;
                    suppress_type_lookup = 2;
                    goto fini;
 
@@ -2358,8 +2358,7 @@ repeat:
              }
            if (!suppress_type_lookup)
              {
-               struct symbol *sym = find_symbol(yytext, SYM_TYPEDEF);
-               if (sym && sym->type == SYM_TYPEDEF)
+               if (find_symbol(yytext, SYM_TYPEDEF, 1))
                  token = TYPE;
              }
          }
@@ -2478,7 +2477,20 @@ repeat:
          ++count;
          APP;
          goto repeat;
-       case ')': case ']': case '}':
+       case '}':
+         /* is this the last line of an enum declaration? */
+         if (count == 0)
+           {
+             /* Put back the token we just read so's we can find it again
+                after registering the expression.  */
+             unput(token);
+
+             lexstate = ST_NORMAL;
+             token = EXPRESSION_PHRASE;
+             break;
+           }
+         /* FALLTHRU */
+       case ')': case ']':
          --count;
          APP;
          goto repeat;
@@ -2567,143 +2579,4 @@ fini:
 
   return token;
 }
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, 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, 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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     ASM_KEYW = 258,
-     ATTRIBUTE_KEYW = 259,
-     AUTO_KEYW = 260,
-     BOOL_KEYW = 261,
-     CHAR_KEYW = 262,
-     CONST_KEYW = 263,
-     DOUBLE_KEYW = 264,
-     ENUM_KEYW = 265,
-     EXTERN_KEYW = 266,
-     EXTENSION_KEYW = 267,
-     FLOAT_KEYW = 268,
-     INLINE_KEYW = 269,
-     INT_KEYW = 270,
-     LONG_KEYW = 271,
-     REGISTER_KEYW = 272,
-     RESTRICT_KEYW = 273,
-     SHORT_KEYW = 274,
-     SIGNED_KEYW = 275,
-     STATIC_KEYW = 276,
-     STRUCT_KEYW = 277,
-     TYPEDEF_KEYW = 278,
-     UNION_KEYW = 279,
-     UNSIGNED_KEYW = 280,
-     VOID_KEYW = 281,
-     VOLATILE_KEYW = 282,
-     TYPEOF_KEYW = 283,
-     EXPORT_SYMBOL_KEYW = 284,
-     ASM_PHRASE = 285,
-     ATTRIBUTE_PHRASE = 286,
-     BRACE_PHRASE = 287,
-     BRACKET_PHRASE = 288,
-     EXPRESSION_PHRASE = 289,
-     CHAR = 290,
-     DOTS = 291,
-     IDENT = 292,
-     INT = 293,
-     REAL = 294,
-     STRING = 295,
-     TYPE = 296,
-     OTHER = 297,
-     FILENAME = 298
-   };
-#endif
-/* Tokens.  */
-#define ASM_KEYW 258
-#define ATTRIBUTE_KEYW 259
-#define AUTO_KEYW 260
-#define BOOL_KEYW 261
-#define CHAR_KEYW 262
-#define CONST_KEYW 263
-#define DOUBLE_KEYW 264
-#define ENUM_KEYW 265
-#define EXTERN_KEYW 266
-#define EXTENSION_KEYW 267
-#define FLOAT_KEYW 268
-#define INLINE_KEYW 269
-#define INT_KEYW 270
-#define LONG_KEYW 271
-#define REGISTER_KEYW 272
-#define RESTRICT_KEYW 273
-#define SHORT_KEYW 274
-#define SIGNED_KEYW 275
-#define STATIC_KEYW 276
-#define STRUCT_KEYW 277
-#define TYPEDEF_KEYW 278
-#define UNION_KEYW 279
-#define UNSIGNED_KEYW 280
-#define VOID_KEYW 281
-#define VOLATILE_KEYW 282
-#define TYPEOF_KEYW 283
-#define EXPORT_SYMBOL_KEYW 284
-#define ASM_PHRASE 285
-#define ATTRIBUTE_PHRASE 286
-#define BRACE_PHRASE 287
-#define BRACKET_PHRASE 288
-#define EXPRESSION_PHRASE 289
-#define CHAR 290
-#define DOTS 291
-#define IDENT 292
-#define INT 293
-#define REAL 294
-#define STRING 295
-#define TYPE 296
-#define OTHER 297
-#define FILENAME 298
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
 
index fe50ff9dacd089d56760c79244c3d4cfacb4c32d..e4ddd493fec3eac20061b1d3701a47c0c36c6ab7 100644 (file)
@@ -55,10 +55,6 @@ CHAR                 L?\'([^\\\']*\\.)*[^\\\']*\'
 
 MC_TOKEN               ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
 
-/* Version 2 checksumming does proper tokenization; version 1 wasn't
-   quite so pedantic.  */
-%s V2_TOKENS
-
 /* We don't do multiple input files.  */
 %option noyywrap
 
@@ -84,9 +80,9 @@ MC_TOKEN              ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
     recognized as tokens.  We don't actually use them since we don't
     parse expressions, but we do want whitespace to be arranged
     around them properly.  */
-<V2_TOKENS>{MC_TOKEN}                  return OTHER;
-<V2_TOKENS>{INT}                       return INT;
-<V2_TOKENS>{REAL}                      return REAL;
+{MC_TOKEN}                             return OTHER;
+{INT}                                  return INT;
+{REAL}                                 return REAL;
 
 "..."                                  return DOTS;
 
@@ -103,12 +99,23 @@ MC_TOKEN           ([~%^&*+=|<>/-]=)|(&&)|("||")|(->)|(<<)|(>>)
 
 /* Macros to append to our phrase collection list.  */
 
+/*
+ * We mark any token, that that equals to a known enumerator, as
+ * SYM_ENUM_CONST. The parser will change this for struct and union tags later,
+ * the only problem is struct and union members:
+ *    enum e { a, b }; struct s { int a, b; }
+ * but in this case, the only effect will be, that the ABI checksums become
+ * more volatile, which is acceptable. Also, such collisions are quite rare,
+ * so far it was only observed in include/linux/telephony.h.
+ */
 #define _APP(T,L)      do {                                               \
                          cur_node = next_node;                            \
                          next_node = xmalloc(sizeof(*next_node));         \
                          next_node->next = cur_node;                      \
                          cur_node->string = memcpy(xmalloc(L+1), T, L+1); \
-                         cur_node->tag = SYM_NORMAL;                      \
+                         cur_node->tag =                                  \
+                           find_symbol(cur_node->string, SYM_ENUM_CONST, 1)?\
+                           SYM_ENUM_CONST : SYM_NORMAL ;                  \
                        } while (0)
 
 #define APP            _APP(yytext, yyleng)
@@ -134,7 +141,6 @@ yylex(void)
 
   if (lexstate == ST_NOTSTARTED)
     {
-      BEGIN(V2_TOKENS);
       next_node = xmalloc(sizeof(*next_node));
       next_node->next = NULL;
       lexstate = ST_NORMAL;
@@ -187,8 +193,8 @@ repeat:
 
                  case STRUCT_KEYW:
                  case UNION_KEYW:
-                   dont_want_brace_phrase = 3;
                  case ENUM_KEYW:
+                   dont_want_brace_phrase = 3;
                    suppress_type_lookup = 2;
                    goto fini;
 
@@ -198,8 +204,7 @@ repeat:
              }
            if (!suppress_type_lookup)
              {
-               struct symbol *sym = find_symbol(yytext, SYM_TYPEDEF);
-               if (sym && sym->type == SYM_TYPEDEF)
+               if (find_symbol(yytext, SYM_TYPEDEF, 1))
                  token = TYPE;
              }
          }
@@ -318,7 +323,20 @@ repeat:
          ++count;
          APP;
          goto repeat;
-       case ')': case ']': case '}':
+       case '}':
+         /* is this the last line of an enum declaration? */
+         if (count == 0)
+           {
+             /* Put back the token we just read so's we can find it again
+                after registering the expression.  */
+             unput(token);
+
+             lexstate = ST_NORMAL;
+             token = EXPRESSION_PHRASE;
+             break;
+           }
+         /* FALLTHRU */
+       case ')': case ']':
          --count;
          APP;
          goto repeat;
index 809b949e495b58267a180c31688ffd926e0adb49..1a0b8607fb0e5ff7412626598443bbe6807404a7 100644 (file)
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   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.
-
+   the Free Software Foundation, either version 3 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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -29,7 +28,7 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
@@ -47,7 +46,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.3"
+#define YYBISON_VERSION "2.4.1"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
 /* Pure parsers.  */
 #define YYPURE 0
 
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
 /* Using locations.  */
 #define YYLSP_NEEDED 0
 
 
 
+/* Copy the first part of user declarations.  */
+
+/* Line 189 of yacc.c  */
+#line 24 "scripts/genksyms/parse.y"
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "genksyms.h"
+
+static int is_typedef;
+static int is_extern;
+static char *current_name;
+static struct string_list *decl_spec;
+
+static void yyerror(const char *);
+
+static inline void
+remove_node(struct string_list **p)
+{
+  struct string_list *node = *p;
+  *p = node->next;
+  free_node(node);
+}
+
+static inline void
+remove_list(struct string_list **pb, struct string_list **pe)
+{
+  struct string_list *b = *pb, *e = *pe;
+  *pb = e;
+  free_list(b, e);
+}
+
+
+
+/* Line 189 of yacc.c  */
+#line 106 "scripts/genksyms/parse.c"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
      FILENAME = 298
    };
 #endif
-/* Tokens.  */
-#define ASM_KEYW 258
-#define ATTRIBUTE_KEYW 259
-#define AUTO_KEYW 260
-#define BOOL_KEYW 261
-#define CHAR_KEYW 262
-#define CONST_KEYW 263
-#define DOUBLE_KEYW 264
-#define ENUM_KEYW 265
-#define EXTERN_KEYW 266
-#define EXTENSION_KEYW 267
-#define FLOAT_KEYW 268
-#define INLINE_KEYW 269
-#define INT_KEYW 270
-#define LONG_KEYW 271
-#define REGISTER_KEYW 272
-#define RESTRICT_KEYW 273
-#define SHORT_KEYW 274
-#define SIGNED_KEYW 275
-#define STATIC_KEYW 276
-#define STRUCT_KEYW 277
-#define TYPEDEF_KEYW 278
-#define UNION_KEYW 279
-#define UNSIGNED_KEYW 280
-#define VOID_KEYW 281
-#define VOLATILE_KEYW 282
-#define TYPEOF_KEYW 283
-#define EXPORT_SYMBOL_KEYW 284
-#define ASM_PHRASE 285
-#define ATTRIBUTE_PHRASE 286
-#define BRACE_PHRASE 287
-#define BRACKET_PHRASE 288
-#define EXPRESSION_PHRASE 289
-#define CHAR 290
-#define DOTS 291
-#define IDENT 292
-#define INT 293
-#define REAL 294
-#define STRING 295
-#define TYPE 296
-#define OTHER 297
-#define FILENAME 298
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 24 "scripts/genksyms/parse.y"
-
-
-#include <assert.h>
-#include <stdlib.h>
-#include "genksyms.h"
-
-static int is_typedef;
-static int is_extern;
-static char *current_name;
-static struct string_list *decl_spec;
-
-static void yyerror(const char *);
-
-static inline void
-remove_node(struct string_list **p)
-{
-  struct string_list *node = *p;
-  *p = node->next;
-  free_node(node);
-}
-
-static inline void
-remove_list(struct string_list **pb, struct string_list **pe)
-{
-  struct string_list *b = *pb, *e = *pe;
-  *pb = e;
-  free_list(b, e);
-}
-
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
 
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 
-
 /* Copy the second part of user declarations.  */
 
 
-/* Line 216 of yacc.c.  */
-#line 223 "scripts/genksyms/parse.c"
+/* Line 264 of yacc.c  */
+#line 191 "scripts/genksyms/parse.c"
 
 #ifdef short
 # undef short
@@ -294,14 +262,14 @@ typedef short int yytype_int16;
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static int
-YYID (int i)
+YYID (int yyi)
 #else
 static int
-YYID (i)
-    int i;
+YYID (yyi)
+    int yyi;
 #endif
 {
-  return i;
+  return yyi;
 }
 #endif
 
@@ -382,9 +350,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
 
 /* The size of the maximum gap between one aligned stack and the next.  */
 # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -418,12 +386,12 @@ union yyalloc
    elements in the stack, and YYPTR gives the new location of the
    stack.  Advance YYPTR to a properly aligned location for the next
    stack.  */
-# define YYSTACK_RELOCATE(Stack)                                       \
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
     do                                                                 \
       {                                                                        \
        YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
-       Stack = &yyptr->Stack;                                          \
+       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+       Stack = &yyptr->Stack_alloc;                                    \
        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
        yyptr += yynewbytes / sizeof (*yyptr);                          \
       }                                                                        \
@@ -434,16 +402,16 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  4
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   523
+#define YYLAST   532
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  53
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  46
+#define YYNNTS  49
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  126
+#define YYNRULES  132
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  178
+#define YYNSTATES  188
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -504,7 +472,8 @@ static const yytype_uint16 yyprhs[] =
      239,   242,   245,   247,   248,   250,   252,   257,   262,   265,
      269,   273,   277,   278,   280,   283,   287,   291,   292,   294,
      296,   299,   303,   306,   307,   309,   311,   315,   318,   321,
-     323,   326,   327,   330,   333,   334,   336
+     323,   326,   327,   330,   334,   339,   341,   345,   347,   351,
+     354,   355,   357
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
@@ -512,16 +481,16 @@ static const yytype_int8 yyrhs[] =
 {
       54,     0,    -1,    55,    -1,    54,    55,    -1,    -1,    56,
       57,    -1,    -1,    12,    23,    58,    60,    -1,    -1,    23,
-      59,    60,    -1,    60,    -1,    84,    -1,    96,    -1,    98,
+      59,    60,    -1,    60,    -1,    84,    -1,    99,    -1,   101,
       -1,     1,    44,    -1,     1,    45,    -1,    64,    61,    44,
       -1,    -1,    62,    -1,    63,    -1,    62,    46,    63,    -1,
-      74,    97,    95,    85,    -1,    -1,    65,    -1,    66,    -1,
+      74,   100,    95,    85,    -1,    -1,    65,    -1,    66,    -1,
       65,    66,    -1,    67,    -1,    68,    -1,     5,    -1,    17,
       -1,    21,    -1,    11,    -1,    14,    -1,    69,    -1,    73,
       -1,    28,    47,    65,    48,    49,    -1,    28,    47,    65,
       49,    -1,    22,    37,    -1,    24,    37,    -1,    10,    37,
       -1,    22,    37,    87,    -1,    24,    37,    87,    -1,    10,
-      37,    32,    -1,    10,    32,    -1,    22,    87,    -1,    24,
+      37,    96,    -1,    10,    96,    -1,    22,    87,    -1,    24,
       87,    -1,     7,    -1,    19,    -1,    15,    -1,    16,    -1,
       20,    -1,    25,    -1,    13,    -1,     9,    -1,    26,    -1,
        6,    -1,    41,    -1,    48,    71,    -1,    -1,    72,    -1,
@@ -543,26 +512,29 @@ static const yytype_int8 yyrhs[] =
       91,    44,    -1,     1,    44,    -1,    -1,    92,    -1,    93,
       -1,    92,    46,    93,    -1,    76,    95,    -1,    37,    94,
       -1,    94,    -1,    52,    34,    -1,    -1,    95,    31,    -1,
-      30,    44,    -1,    -1,    30,    -1,    29,    47,    37,    49,
-      44,    -1
+      51,    97,    45,    -1,    51,    97,    46,    45,    -1,    98,
+      -1,    97,    46,    98,    -1,    37,    -1,    37,    50,    34,
+      -1,    30,    44,    -1,    -1,    30,    -1,    29,    47,    37,
+      49,    44,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   103,   103,   104,   108,   108,   114,   114,   116,   116,
-     118,   119,   120,   121,   122,   123,   127,   141,   142,   146,
-     154,   167,   173,   174,   178,   179,   183,   189,   193,   194,
-     195,   196,   197,   201,   202,   203,   204,   208,   210,   212,
-     216,   223,   230,   239,   240,   241,   245,   246,   247,   248,
-     249,   250,   251,   252,   253,   254,   255,   259,   264,   265,
-     269,   270,   274,   274,   274,   275,   283,   284,   288,   297,
-     299,   301,   303,   305,   312,   313,   317,   318,   319,   321,
-     323,   325,   327,   332,   333,   334,   338,   339,   343,   344,
-     349,   354,   356,   360,   361,   369,   373,   375,   377,   379,
-     381,   386,   395,   396,   401,   406,   407,   411,   412,   416,
-     417,   421,   423,   428,   429,   433,   434,   438,   439,   440,
-     444,   448,   449,   453,   457,   458,   462
+       0,   104,   104,   105,   109,   109,   115,   115,   117,   117,
+     119,   120,   121,   122,   123,   124,   128,   142,   143,   147,
+     155,   168,   174,   175,   179,   180,   184,   190,   194,   195,
+     196,   197,   198,   202,   203,   204,   205,   209,   211,   213,
+     217,   224,   231,   241,   244,   245,   249,   250,   251,   252,
+     253,   254,   255,   256,   257,   258,   259,   263,   268,   269,
+     273,   274,   278,   278,   278,   279,   287,   288,   292,   301,
+     303,   305,   307,   309,   316,   317,   321,   322,   323,   325,
+     327,   329,   331,   336,   337,   338,   342,   343,   347,   348,
+     353,   358,   360,   364,   365,   373,   377,   379,   381,   383,
+     385,   390,   399,   400,   405,   410,   411,   415,   416,   420,
+     421,   425,   427,   432,   433,   437,   438,   442,   443,   444,
+     448,   452,   453,   457,   458,   462,   463,   466,   471,   479,
+     483,   484,   488
 };
 #endif
 
@@ -581,8 +553,8 @@ static const char *const yytname[] =
   "ATTRIBUTE_PHRASE", "BRACE_PHRASE", "BRACKET_PHRASE",
   "EXPRESSION_PHRASE", "CHAR", "DOTS", "IDENT", "INT", "REAL", "STRING",
   "TYPE", "OTHER", "FILENAME", "';'", "'}'", "','", "'('", "'*'", "')'",
-  "'='", "'{'", "':'", "$accept", "declaration_seq", "declaration", "@1",
-  "declaration1", "@2", "@3", "simple_declaration",
+  "'='", "'{'", "':'", "$accept", "declaration_seq", "declaration", "$@1",
+  "declaration1", "$@2", "$@3", "simple_declaration",
   "init_declarator_list_opt", "init_declarator_list", "init_declarator",
   "decl_specifier_seq_opt", "decl_specifier_seq", "decl_specifier",
   "storage_class_specifier", "type_specifier", "simple_type_specifier",
@@ -596,7 +568,8 @@ static const char *const yytname[] =
   "member_specification", "member_declaration",
   "member_declarator_list_opt", "member_declarator_list",
   "member_declarator", "member_bitfield_declarator", "attribute_opt",
-  "asm_definition", "asm_phrase_opt", "export_definition", 0
+  "enum_body", "enumerator_list", "enumerator", "asm_definition",
+  "asm_phrase_opt", "export_definition", 0
 };
 #endif
 
@@ -629,7 +602,8 @@ static const yytype_uint8 yyr1[] =
       81,    82,    82,    83,    83,    83,    83,    83,    83,    83,
       83,    84,    85,    85,    86,    87,    87,    88,    88,    89,
       89,    90,    90,    91,    91,    92,    92,    93,    93,    93,
-      94,    95,    95,    96,    97,    97,    98
+      94,    95,    95,    96,    96,    97,    97,    98,    98,    99,
+     100,   100,   101
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -647,7 +621,8 @@ static const yytype_uint8 yyr2[] =
        2,     2,     1,     0,     1,     1,     4,     4,     2,     3,
        3,     3,     0,     1,     2,     3,     3,     0,     1,     1,
        2,     3,     2,     0,     1,     1,     3,     2,     2,     1,
-       2,     0,     2,     2,     0,     1,     5
+       2,     0,     2,     3,     4,     1,     3,     1,     3,     2,
+       0,     1,     5
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -659,17 +634,18 @@ static const yytype_uint8 yydefact[] =
       62,    53,     0,    31,     0,    52,    32,    48,    49,    29,
       65,    47,    50,    30,     0,     8,     0,    51,    54,    63,
        0,     0,     0,    64,    56,     5,    10,    17,    23,    24,
-      26,    27,    33,    34,    11,    12,    13,    14,    15,    43,
-      39,     6,    37,     0,    44,    22,    38,    45,     0,     0,
-     123,    68,     0,    58,     0,    18,    19,     0,   124,    67,
-      25,    42,    22,    40,     0,   113,     0,     0,   109,     9,
-      17,    41,     0,     0,     0,     0,    57,    59,    60,    16,
-       0,    66,   125,   101,   121,    71,     0,     7,   112,   106,
-      76,    77,     0,     0,     0,   121,    75,     0,   114,   115,
-     119,   105,     0,   110,   124,     0,    36,     0,    73,    72,
-      61,    20,   102,     0,    93,     0,    84,    87,    88,   118,
+      26,    27,    33,    34,    11,    12,    13,    14,    15,    39,
+       0,    43,     6,    37,     0,    44,    22,    38,    45,     0,
+       0,   129,    68,     0,    58,     0,    18,    19,     0,   130,
+      67,    25,    42,   127,     0,   125,    22,    40,     0,   113,
+       0,     0,   109,     9,    17,    41,     0,     0,     0,     0,
+      57,    59,    60,    16,     0,    66,   131,   101,   121,    71,
+       0,     0,   123,     0,     7,   112,   106,    76,    77,     0,
+       0,     0,   121,    75,     0,   114,   115,   119,   105,     0,
+     110,   130,     0,    36,     0,    73,    72,    61,    20,   102,
+       0,    93,     0,    84,    87,    88,   128,   124,   126,   118,
        0,    76,     0,   120,    74,   117,    80,     0,   111,     0,
-      35,   126,   122,     0,    21,   103,    70,    94,    56,     0,
+      35,   132,   122,     0,    21,   103,    70,    94,    56,     0,
       93,    90,    92,    69,    83,     0,    82,    81,     0,     0,
      116,   104,     0,    95,     0,    91,    98,     0,    85,    89,
       79,    78,   100,    99,     0,     0,    97,    96
@@ -678,46 +654,47 @@ static const yytype_uint8 yydefact[] =
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,     2,     3,    35,    72,    55,    36,    64,    65,
-      66,    75,    38,    39,    40,    41,    42,    67,    86,    87,
-      43,   114,    69,   105,   106,   125,   126,   127,   128,   151,
-     152,    44,   144,   145,    54,    76,    77,    78,   107,   108,
-     109,   110,   122,    45,    94,    46
+      -1,     1,     2,     3,    35,    76,    56,    36,    65,    66,
+      67,    79,    38,    39,    40,    41,    42,    68,    90,    91,
+      43,   121,    70,   112,   113,   132,   133,   134,   135,   161,
+     162,    44,   154,   155,    55,    80,    81,    82,   114,   115,
+     116,   117,   129,    51,    74,    75,    45,    98,    46
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -134
+#define YYPACT_NINF -135
 static const yytype_int16 yypact[] =
 {
-    -134,    16,  -134,   312,  -134,  -134,    20,  -134,  -134,  -134,
-    -134,  -134,   -18,  -134,    -3,  -134,  -134,  -134,  -134,  -134,
-    -134,  -134,  -134,  -134,   -26,  -134,   -25,  -134,  -134,  -134,
-      -7,     5,    27,  -134,  -134,  -134,  -134,    46,   482,  -134,
-    -134,  -134,  -134,  -134,  -134,  -134,  -134,  -134,  -134,  -134,
-      -8,  -134,    30,    97,  -134,   482,    30,  -134,   482,     7,
-    -134,  -134,    12,    10,    42,    55,  -134,    46,   -15,    15,
-    -134,  -134,   482,  -134,    25,    26,    47,   145,  -134,  -134,
-      46,  -134,   356,    39,    71,    77,  -134,    10,  -134,  -134,
-      46,  -134,  -134,  -134,  -134,  -134,   193,  -134,  -134,  -134,
-      75,  -134,     6,    95,    43,  -134,    28,    86,    85,  -134,
-    -134,  -134,    88,  -134,   103,    87,  -134,    91,  -134,  -134,
-    -134,  -134,   -23,    90,   401,    94,   101,   102,  -134,  -134,
-      98,  -134,   108,  -134,  -134,   109,  -134,   230,  -134,    26,
-    -134,  -134,  -134,   134,  -134,  -134,  -134,  -134,  -134,     9,
-      48,  -134,    35,  -134,  -134,   445,  -134,  -134,   125,   126,
-    -134,  -134,   128,  -134,   129,  -134,  -134,   267,  -134,  -134,
-    -134,  -134,  -134,  -134,   130,   131,  -134,  -134
+    -135,    20,  -135,   321,  -135,  -135,    30,  -135,  -135,  -135,
+    -135,  -135,   -28,  -135,     2,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,    -6,  -135,     9,  -135,  -135,  -135,
+      -5,    15,   -17,  -135,  -135,  -135,  -135,    18,   491,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,   -22,
+      31,  -135,  -135,    19,   106,  -135,   491,    19,  -135,   491,
+      50,  -135,  -135,    11,    -3,    51,    57,  -135,    18,   -14,
+      14,  -135,  -135,    48,    46,  -135,   491,  -135,    33,    32,
+      59,   154,  -135,  -135,    18,  -135,   365,    56,    60,    61,
+    -135,    -3,  -135,  -135,    18,  -135,  -135,  -135,  -135,  -135,
+     202,    74,  -135,   -23,  -135,  -135,  -135,    77,  -135,    16,
+     101,    49,  -135,    34,    92,    93,  -135,  -135,  -135,    94,
+    -135,   110,    95,  -135,    97,  -135,  -135,  -135,  -135,   -20,
+      96,   410,    99,   113,   100,  -135,  -135,  -135,  -135,  -135,
+     103,  -135,   107,  -135,  -135,   111,  -135,   239,  -135,    32,
+    -135,  -135,  -135,   123,  -135,  -135,  -135,  -135,  -135,     3,
+      52,  -135,    38,  -135,  -135,   454,  -135,  -135,   117,   128,
+    -135,  -135,   134,  -135,   135,  -135,  -135,   276,  -135,  -135,
+    -135,  -135,  -135,  -135,   137,   138,  -135,  -135
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -134,  -134,   180,  -134,  -134,  -134,  -134,   -33,  -134,  -134,
-      93,     0,   -58,   -37,  -134,  -134,  -134,   -73,  -134,  -134,
-     -54,   -32,  -134,   -81,  -134,  -133,  -134,  -134,    29,   -50,
-    -134,  -134,  -134,  -134,   -20,  -134,  -134,   110,  -134,  -134,
-      49,    96,    80,  -134,  -134,  -134
+    -135,  -135,   187,  -135,  -135,  -135,  -135,   -50,  -135,  -135,
+      98,     0,   -59,   -37,  -135,  -135,  -135,   -77,  -135,  -135,
+     -54,   -30,  -135,   -90,  -135,  -134,  -135,  -135,    24,   -58,
+    -135,  -135,  -135,  -135,   -18,  -135,  -135,   109,  -135,  -135,
+      44,    87,    84,   148,  -135,   102,  -135,  -135,  -135
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -727,116 +704,118 @@ static const yytype_int16 yypgoto[] =
 #define YYTABLE_NINF -109
 static const yytype_int16 yytable[] =
 {
-      82,    70,   104,    37,   159,    68,    57,   130,   142,    88,
-     162,    52,    56,    84,    49,    92,     4,    93,    10,    50,
-      51,   132,    79,   134,    71,    53,    53,   143,    20,   104,
-      85,   104,    73,   120,   175,    91,    81,    29,   124,    97,
-      58,    33,   -93,   131,    83,    70,   147,   101,    95,    61,
-     163,   150,    59,   102,    63,    80,   149,    63,   -93,    62,
-      63,   136,    96,   100,    47,    48,   104,   101,   166,    98,
-      99,    60,    80,   102,    63,   137,   150,   150,   103,   124,
-     131,    53,   167,    61,   101,   147,    89,    70,   117,   163,
-     102,    63,   111,    62,    63,   149,    63,   124,    74,   164,
-     165,    90,     7,     8,     9,    10,    11,    12,    13,   124,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-     118,    26,    27,    28,    29,    30,   119,   103,    33,   133,
-     138,   139,    98,    92,   -22,   141,   140,   154,    34,   146,
-     142,   -22,  -107,   153,   -22,   -22,   112,   156,   155,   -22,
-       7,     8,     9,    10,    11,    12,    13,   157,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,   161,    26,
-      27,    28,    29,    30,   170,   171,    33,   172,   173,   176,
-     177,     5,   -22,   121,   169,   135,    34,   113,   160,   -22,
-    -108,     0,   -22,   -22,   123,     0,   129,   -22,     7,     8,
-       9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
-      19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
-      29,    30,     0,     0,    33,     0,     0,     0,     0,   -86,
-       0,   158,     0,     0,    34,     7,     8,     9,    10,    11,
-      12,    13,   -86,    15,    16,    17,    18,    19,    20,    21,
-      22,    23,    24,     0,    26,    27,    28,    29,    30,     0,
-       0,    33,     0,     0,     0,     0,   -86,     0,   174,     0,
-       0,    34,     7,     8,     9,    10,    11,    12,    13,   -86,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-       0,    26,    27,    28,    29,    30,     0,     0,    33,     0,
-       0,     0,     0,   -86,     0,     0,     0,     0,    34,     0,
-       0,     0,     0,     6,     0,     0,   -86,     7,     8,     9,
-      10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,     0,     0,     0,     0,     0,   -22,
-       0,     0,     0,    34,     0,     0,   -22,     0,     0,   -22,
-     -22,     7,     8,     9,    10,    11,    12,    13,     0,    15,
+      86,    71,   111,    37,   172,    10,    83,    69,    58,    49,
+      92,   152,    88,   169,    73,    20,    96,   140,    97,   142,
+       4,   144,   137,    50,    29,    52,   104,    61,    33,    50,
+     153,    53,   111,    89,   111,    77,   -93,   127,    95,    85,
+     157,   131,    59,   185,   173,    54,    57,    99,    62,    71,
+     159,    64,   -93,   141,   160,    62,    84,   108,    63,    64,
+      54,   100,    60,   109,    64,    63,    64,   146,    73,   107,
+      54,   176,   111,   108,    47,    48,    84,   105,   106,   109,
+      64,   147,   160,   160,   110,   177,   141,    87,   131,   157,
+     108,   102,   103,   173,    71,    93,   109,    64,   101,   159,
+      64,   174,   175,    94,   118,   124,   131,    78,   136,   125,
+     126,     7,     8,     9,    10,    11,    12,    13,   131,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,   110,
+      26,    27,    28,    29,    30,   143,   148,    33,   105,   149,
+      96,   151,   152,   -22,   150,   156,   165,    34,   163,   164,
+     -22,  -107,   166,   -22,   -22,   119,   167,   171,   -22,     7,
+       8,     9,    10,    11,    12,    13,   180,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,   181,    26,    27,
+      28,    29,    30,   182,   183,    33,   186,   187,     5,   179,
+     120,   -22,   128,   170,   139,    34,   145,    72,   -22,  -108,
+       0,   -22,   -22,   130,     0,   138,   -22,     7,     8,     9,
+      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
+      30,     0,     0,    33,     0,     0,     0,     0,   -86,     0,
+     168,     0,     0,    34,     7,     8,     9,    10,    11,    12,
+      13,   -86,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
+      33,     0,     0,     0,     0,   -86,     0,   184,     0,     0,
+      34,     7,     8,     9,    10,    11,    12,    13,   -86,    15,
       16,    17,    18,    19,    20,    21,    22,    23,    24,     0,
       26,    27,    28,    29,    30,     0,     0,    33,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,    34,     0,     0,
-       0,     0,     0,     0,   115,   116,     7,     8,     9,    10,
-      11,    12,    13,     0,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,     0,    26,    27,    28,    29,    30,
-       0,     0,    33,     0,     0,     0,     0,     0,   147,     0,
-       0,     0,   148,     0,     0,     0,     0,     0,   149,    63,
+       0,     0,   -86,     0,     0,     0,     0,    34,     0,     0,
+       0,     0,     6,     0,     0,   -86,     7,     8,     9,    10,
+      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,     0,     0,     0,     0,     0,   -22,     0,
+       0,     0,    34,     0,     0,   -22,     0,     0,   -22,   -22,
        7,     8,     9,    10,    11,    12,    13,     0,    15,    16,
       17,    18,    19,    20,    21,    22,    23,    24,     0,    26,
       27,    28,    29,    30,     0,     0,    33,     0,     0,     0,
-       0,   168,     0,     0,     0,     0,    34,     7,     8,     9,
-      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
-      30,     0,     0,    33,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    34
+       0,     0,     0,     0,     0,     0,    34,     0,     0,     0,
+       0,     0,     0,   122,   123,     7,     8,     9,    10,    11,
+      12,    13,     0,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,     0,    26,    27,    28,    29,    30,     0,
+       0,    33,     0,     0,     0,     0,     0,   157,     0,     0,
+       0,   158,     0,     0,     0,     0,     0,   159,    64,     7,
+       8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
+      28,    29,    30,     0,     0,    33,     0,     0,     0,     0,
+     178,     0,     0,     0,     0,    34,     7,     8,     9,    10,
+      11,    12,    13,     0,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,     0,    26,    27,    28,    29,    30,
+       0,     0,    33,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    34
 };
 
 static const yytype_int16 yycheck[] =
 {
-      58,    38,    75,     3,   137,    37,    26,     1,    31,    63,
-       1,    37,    37,     1,    32,    30,     0,    32,     8,    37,
-      23,   102,    55,   104,    32,    51,    51,    50,    18,   102,
-      62,   104,    52,    87,   167,    67,    56,    27,    96,    72,
-      47,    31,    33,    37,    37,    82,    37,    41,    33,    37,
-      41,   124,    47,    47,    48,    55,    47,    48,    49,    47,
-      48,    33,    47,    37,    44,    45,   139,    41,    33,    44,
-      45,    44,    72,    47,    48,    47,   149,   150,    52,   137,
-      37,    51,    47,    37,    41,    37,    44,   124,    49,    41,
-      47,    48,    45,    47,    48,    47,    48,   155,     1,   149,
-     150,    46,     5,     6,     7,     8,     9,    10,    11,   167,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      49,    24,    25,    26,    27,    28,    49,    52,    31,    34,
-      44,    46,    44,    30,    37,    44,    49,    36,    41,    49,
-      31,    44,    45,    49,    47,    48,     1,    49,    46,    52,
-       5,     6,     7,     8,     9,    10,    11,    49,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    34,    24,
-      25,    26,    27,    28,    49,    49,    31,    49,    49,    49,
-      49,     1,    37,    90,   155,   105,    41,    77,   139,    44,
-      45,    -1,    47,    48,     1,    -1,   100,    52,     5,     6,
-       7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
-      27,    28,    -1,    -1,    31,    -1,    -1,    -1,    -1,    36,
-      -1,     1,    -1,    -1,    41,     5,     6,     7,     8,     9,
-      10,    11,    49,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,    -1,    24,    25,    26,    27,    28,    -1,
-      -1,    31,    -1,    -1,    -1,    -1,    36,    -1,     1,    -1,
-      -1,    41,     5,     6,     7,     8,     9,    10,    11,    49,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      -1,    24,    25,    26,    27,    28,    -1,    -1,    31,    -1,
-      -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    41,    -1,
-      -1,    -1,    -1,     1,    -1,    -1,    49,     5,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    -1,    -1,    -1,    -1,    -1,    37,
-      -1,    -1,    -1,    41,    -1,    -1,    44,    -1,    -1,    47,
-      48,     5,     6,     7,     8,     9,    10,    11,    -1,    13,
+      59,    38,    79,     3,     1,     8,    56,    37,    26,    37,
+      64,    31,     1,   147,    37,    18,    30,     1,    32,   109,
+       0,   111,    45,    51,    27,    23,    76,    44,    31,    51,
+      50,    37,   109,    63,   111,    53,    33,    91,    68,    57,
+      37,   100,    47,   177,    41,    51,    37,    33,    37,    86,
+      47,    48,    49,    37,   131,    37,    56,    41,    47,    48,
+      51,    47,    47,    47,    48,    47,    48,    33,    37,    37,
+      51,    33,   149,    41,    44,    45,    76,    44,    45,    47,
+      48,    47,   159,   160,    52,    47,    37,    37,   147,    37,
+      41,    45,    46,    41,   131,    44,    47,    48,    50,    47,
+      48,   159,   160,    46,    45,    49,   165,     1,    34,    49,
+      49,     5,     6,     7,     8,     9,    10,    11,   177,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    52,
+      24,    25,    26,    27,    28,    34,    44,    31,    44,    46,
+      30,    44,    31,    37,    49,    49,    46,    41,    49,    36,
+      44,    45,    49,    47,    48,     1,    49,    34,    52,     5,
+       6,     7,     8,     9,    10,    11,    49,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    49,    24,    25,
+      26,    27,    28,    49,    49,    31,    49,    49,     1,   165,
+      81,    37,    94,   149,   107,    41,   112,    49,    44,    45,
+      -1,    47,    48,     1,    -1,   103,    52,     5,     6,     7,
+       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
+      28,    -1,    -1,    31,    -1,    -1,    -1,    -1,    36,    -1,
+       1,    -1,    -1,    41,     5,     6,     7,     8,     9,    10,
+      11,    49,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
+      31,    -1,    -1,    -1,    -1,    36,    -1,     1,    -1,    -1,
+      41,     5,     6,     7,     8,     9,    10,    11,    49,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,    -1,
       24,    25,    26,    27,    28,    -1,    -1,    31,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    41,    -1,    -1,
-      -1,    -1,    -1,    -1,    48,    49,     5,     6,     7,     8,
-       9,    10,    11,    -1,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,    -1,    24,    25,    26,    27,    28,
-      -1,    -1,    31,    -1,    -1,    -1,    -1,    -1,    37,    -1,
-      -1,    -1,    41,    -1,    -1,    -1,    -1,    -1,    47,    48,
+      -1,    -1,    36,    -1,    -1,    -1,    -1,    41,    -1,    -1,
+      -1,    -1,     1,    -1,    -1,    49,     5,     6,     7,     8,
+       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    -1,    -1,    -1,    -1,    -1,    37,    -1,
+      -1,    -1,    41,    -1,    -1,    44,    -1,    -1,    47,    48,
        5,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    -1,    24,
       25,    26,    27,    28,    -1,    -1,    31,    -1,    -1,    -1,
-      -1,    36,    -1,    -1,    -1,    -1,    41,     5,     6,     7,
-       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
-      28,    -1,    -1,    31,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    41
+      -1,    -1,    -1,    -1,    -1,    -1,    41,    -1,    -1,    -1,
+      -1,    -1,    -1,    48,    49,     5,     6,     7,     8,     9,
+      10,    11,    -1,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    -1,    24,    25,    26,    27,    28,    -1,
+      -1,    31,    -1,    -1,    -1,    -1,    -1,    37,    -1,    -1,
+      -1,    41,    -1,    -1,    -1,    -1,    -1,    47,    48,     5,
+       6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
+      26,    27,    28,    -1,    -1,    31,    -1,    -1,    -1,    -1,
+      36,    -1,    -1,    -1,    -1,    41,     5,     6,     7,     8,
+       9,    10,    11,    -1,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    -1,    24,    25,    26,    27,    28,
+      -1,    -1,    31,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    41
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -847,15 +826,16 @@ static const yytype_uint8 yystos[] =
        8,     9,    10,    11,    12,    13,    14,    15,    16,    17,
       18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
       28,    29,    30,    31,    41,    57,    60,    64,    65,    66,
-      67,    68,    69,    73,    84,    96,    98,    44,    45,    32,
-      37,    23,    37,    51,    87,    59,    37,    87,    47,    47,
-      44,    37,    47,    48,    61,    62,    63,    70,    74,    75,
-      66,    32,    58,    87,     1,    64,    88,    89,    90,    60,
-      64,    87,    65,    37,     1,    74,    71,    72,    73,    44,
-      46,    74,    30,    32,    97,    33,    47,    60,    44,    45,
-      37,    41,    47,    52,    70,    76,    77,    91,    92,    93,
-      94,    45,     1,    90,    74,    48,    49,    49,    49,    49,
-      73,    63,    95,     1,    65,    78,    79,    80,    81,    94,
+      67,    68,    69,    73,    84,    99,   101,    44,    45,    37,
+      51,    96,    23,    37,    51,    87,    59,    37,    87,    47,
+      47,    44,    37,    47,    48,    61,    62,    63,    70,    74,
+      75,    66,    96,    37,    97,    98,    58,    87,     1,    64,
+      88,    89,    90,    60,    64,    87,    65,    37,     1,    74,
+      71,    72,    73,    44,    46,    74,    30,    32,   100,    33,
+      47,    50,    45,    46,    60,    44,    45,    37,    41,    47,
+      52,    70,    76,    77,    91,    92,    93,    94,    45,     1,
+      90,    74,    48,    49,    49,    49,    49,    73,    63,    95,
+       1,    65,    78,    79,    80,    81,    34,    45,    98,    94,
        1,    37,    76,    34,    76,    95,    33,    47,    44,    46,
       49,    44,    31,    50,    85,    86,    49,    37,    41,    47,
       70,    82,    83,    49,    36,    46,    49,    49,     1,    78,
@@ -1045,17 +1025,20 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
 #else
 static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
   YYFPRINTF (stderr, "\n");
 }
 
@@ -1089,11 +1072,11 @@ yy_reduce_print (yyvsp, yyrule)
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
-      fprintf (stderr, "   $%d = ", yyi + 1);
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
       yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
                       &(yyvsp[(yyi + 1) - (yynrhs)])
                                       );
-      fprintf (stderr, "\n");
+      YYFPRINTF (stderr, "\n");
     }
 }
 
@@ -1373,10 +1356,8 @@ yydestruct (yymsg, yytype, yyvaluep)
        break;
     }
 }
-\f
 
 /* Prevent warnings from -Wmissing-prototypes.  */
-
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
 int yyparse (void *YYPARSE_PARAM);
@@ -1392,11 +1373,10 @@ int yyparse ();
 #endif /* ! YYPARSE_PARAM */
 
 
-
-/* The look-ahead symbol.  */
+/* The lookahead symbol.  */
 int yychar;
 
-/* The semantic value of the look-ahead symbol.  */
+/* The semantic value of the lookahead symbol.  */
 YYSTYPE yylval;
 
 /* Number of syntax errors so far.  */
@@ -1404,9 +1384,9 @@ int yynerrs;
 
 
 
-/*----------.
-| yyparse.  |
-`----------*/
+/*-------------------------.
+| yyparse or yypush_parse.  |
+`-------------------------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1430,66 +1410,68 @@ yyparse ()
 #endif
 #endif
 {
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
 
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
 
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
+    int yystate;
+    /* Number of tokens to shift before error messages enabled.  */
+    int yyerrstatus;
 
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
+    /* The stacks and their tools:
+       `yyss': related to states.
+       `yyvs': related to semantic values.
 
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
+       Refer to the stacks thru separate pointers, to allow yyoverflow
+       to reallocate them elsewhere.  */
 
+    /* The state stack.  */
+    yytype_int16 yyssa[YYINITDEPTH];
+    yytype_int16 *yyss;
+    yytype_int16 *yyssp;
 
+    /* The semantic value stack.  */
+    YYSTYPE yyvsa[YYINITDEPTH];
+    YYSTYPE *yyvs;
+    YYSTYPE *yyvsp;
 
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
+    YYSIZE_T yystacksize;
 
+  int yyn;
+  int yyresult;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
 
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
 
   /* The number of symbols on the RHS of the reduced rule.
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
   YYDPRINTF ((stderr, "Starting parse\n"));
 
   yystate = 0;
   yyerrstatus = 0;
   yynerrs = 0;
-  yychar = YYEMPTY;            /* Cause a token to be read.  */
+  yychar = YYEMPTY; /* Cause a token to be read.  */
 
   /* Initialize stack pointers.
      Waste one element of value and location stack
      so that they stay on the same level as the state stack.
      The wasted elements are never initialized.  */
-
   yyssp = yyss;
   yyvsp = yyvs;
 
@@ -1519,7 +1501,6 @@ yyparse ()
        YYSTYPE *yyvs1 = yyvs;
        yytype_int16 *yyss1 = yyss;
 
-
        /* Each stack pointer address is followed by the size of the
           data in use in that stack, in bytes.  This used to be a
           conditional around just the two extra args, but that might
@@ -1527,7 +1508,6 @@ yyparse ()
        yyoverflow (YY_("memory exhausted"),
                    &yyss1, yysize * sizeof (*yyssp),
                    &yyvs1, yysize * sizeof (*yyvsp),
-
                    &yystacksize);
 
        yyss = yyss1;
@@ -1550,9 +1530,8 @@ yyparse ()
          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
        if (! yyptr)
          goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss);
-       YYSTACK_RELOCATE (yyvs);
-
+       YYSTACK_RELOCATE (yyss_alloc, yyss);
+       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
 #  undef YYSTACK_RELOCATE
        if (yyss1 != yyssa)
          YYSTACK_FREE (yyss1);
@@ -1563,7 +1542,6 @@ yyparse ()
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
 
-
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
                  (unsigned long int) yystacksize));
 
@@ -1573,6 +1551,9 @@ yyparse ()
 
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
 
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
   goto yybackup;
 
 /*-----------.
@@ -1581,16 +1562,16 @@ yyparse ()
 yybackup:
 
   /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
+     lookahead token if we need one and don't already have one.  */
 
-  /* First try to decide what to do without reference to look-ahead token.  */
+  /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
   if (yyn == YYPACT_NINF)
     goto yydefault;
 
-  /* Not known => get a look-ahead token if don't already have one.  */
+  /* Not known => get a lookahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
@@ -1622,20 +1603,16 @@ yybackup:
       goto yyreduce;
     }
 
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
   /* Count tokens shifted since error; after three, turn off error
      status.  */
   if (yyerrstatus)
     yyerrstatus--;
 
-  /* Shift the look-ahead token.  */
+  /* Shift the lookahead token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
 
   yystate = yyn;
   *++yyvsp = yylval;
@@ -1675,47 +1652,65 @@ yyreduce:
   switch (yyn)
     {
         case 4:
-#line 108 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 109 "scripts/genksyms/parse.y"
     { is_typedef = 0; is_extern = 0; current_name = NULL; decl_spec = NULL; ;}
     break;
 
   case 5:
-#line 110 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 111 "scripts/genksyms/parse.y"
     { free_list(*(yyvsp[(2) - (2)]), NULL); *(yyvsp[(2) - (2)]) = NULL; ;}
     break;
 
   case 6:
-#line 114 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 115 "scripts/genksyms/parse.y"
     { is_typedef = 1; ;}
     break;
 
   case 7:
-#line 115 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 116 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 8:
-#line 116 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 117 "scripts/genksyms/parse.y"
     { is_typedef = 1; ;}
     break;
 
   case 9:
-#line 117 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 118 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 14:
-#line 122 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 123 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 15:
-#line 123 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 124 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 16:
-#line 128 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 129 "scripts/genksyms/parse.y"
     { if (current_name) {
                    struct string_list *decl = (*(yyvsp[(3) - (3)]))->next;
                    (*(yyvsp[(3) - (3)]))->next = NULL;
@@ -1729,12 +1724,16 @@ yyreduce:
     break;
 
   case 17:
-#line 141 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 142 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 19:
-#line 147 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 148 "scripts/genksyms/parse.y"
     { struct string_list *decl = *(yyvsp[(1) - (1)]);
                  *(yyvsp[(1) - (1)]) = NULL;
                  add_symbol(current_name,
@@ -1745,7 +1744,9 @@ yyreduce:
     break;
 
   case 20:
-#line 155 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 156 "scripts/genksyms/parse.y"
     { struct string_list *decl = *(yyvsp[(3) - (3)]);
                  *(yyvsp[(3) - (3)]) = NULL;
                  free_list(*(yyvsp[(2) - (3)]), NULL);
@@ -1758,27 +1759,37 @@ yyreduce:
     break;
 
   case 21:
-#line 168 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 169 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]) ? (yyvsp[(4) - (4)]) : (yyvsp[(3) - (4)]) ? (yyvsp[(3) - (4)]) : (yyvsp[(2) - (4)]) ? (yyvsp[(2) - (4)]) : (yyvsp[(1) - (4)]); ;}
     break;
 
   case 22:
-#line 173 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 174 "scripts/genksyms/parse.y"
     { decl_spec = NULL; ;}
     break;
 
   case 24:
-#line 178 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 179 "scripts/genksyms/parse.y"
     { decl_spec = *(yyvsp[(1) - (1)]); ;}
     break;
 
   case 25:
-#line 179 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 180 "scripts/genksyms/parse.y"
     { decl_spec = *(yyvsp[(2) - (2)]); ;}
     break;
 
   case 26:
-#line 184 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 185 "scripts/genksyms/parse.y"
     { /* Version 2 checksumming ignores storage class, as that
                     is really irrelevant to the linkage.  */
                  remove_node((yyvsp[(1) - (1)]));
@@ -1787,32 +1798,44 @@ yyreduce:
     break;
 
   case 31:
-#line 196 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 197 "scripts/genksyms/parse.y"
     { is_extern = 1; (yyval) = (yyvsp[(1) - (1)]); ;}
     break;
 
   case 32:
-#line 197 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 198 "scripts/genksyms/parse.y"
     { is_extern = 0; (yyval) = (yyvsp[(1) - (1)]); ;}
     break;
 
   case 37:
-#line 209 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 210 "scripts/genksyms/parse.y"
     { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_STRUCT; (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 38:
-#line 211 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 212 "scripts/genksyms/parse.y"
     { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_UNION; (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 39:
-#line 213 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 214 "scripts/genksyms/parse.y"
     { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_ENUM; (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 40:
-#line 217 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 218 "scripts/genksyms/parse.y"
     { struct string_list *s = *(yyvsp[(3) - (3)]), *i = *(yyvsp[(2) - (3)]), *r;
                  r = copy_node(i); r->tag = SYM_STRUCT;
                  r->next = (*(yyvsp[(1) - (3)]))->next; *(yyvsp[(3) - (3)]) = r; (*(yyvsp[(1) - (3)]))->next = NULL;
@@ -1822,7 +1845,9 @@ yyreduce:
     break;
 
   case 41:
-#line 224 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 225 "scripts/genksyms/parse.y"
     { struct string_list *s = *(yyvsp[(3) - (3)]), *i = *(yyvsp[(2) - (3)]), *r;
                  r = copy_node(i); r->tag = SYM_UNION;
                  r->next = (*(yyvsp[(1) - (3)]))->next; *(yyvsp[(3) - (3)]) = r; (*(yyvsp[(1) - (3)]))->next = NULL;
@@ -1832,7 +1857,9 @@ yyreduce:
     break;
 
   case 42:
-#line 231 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 232 "scripts/genksyms/parse.y"
     { struct string_list *s = *(yyvsp[(3) - (3)]), *i = *(yyvsp[(2) - (3)]), *r;
                  r = copy_node(i); r->tag = SYM_ENUM;
                  r->next = (*(yyvsp[(1) - (3)]))->next; *(yyvsp[(3) - (3)]) = r; (*(yyvsp[(1) - (3)]))->next = NULL;
@@ -1842,42 +1869,58 @@ yyreduce:
     break;
 
   case 43:
-#line 239 "scripts/genksyms/parse.y"
-    { (yyval) = (yyvsp[(2) - (2)]); ;}
+
+/* Line 1455 of yacc.c  */
+#line 242 "scripts/genksyms/parse.y"
+    { add_symbol(NULL, SYM_ENUM, NULL, 0); (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 44:
-#line 240 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 244 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 45:
-#line 241 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 245 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 56:
-#line 255 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 259 "scripts/genksyms/parse.y"
     { (*(yyvsp[(1) - (1)]))->tag = SYM_TYPEDEF; (yyval) = (yyvsp[(1) - (1)]); ;}
     break;
 
   case 57:
-#line 260 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 264 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); ;}
     break;
 
   case 58:
-#line 264 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 268 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 61:
-#line 270 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 274 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 65:
-#line 276 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 280 "scripts/genksyms/parse.y"
     { /* restrict has no effect in prototypes so ignore it */
                  remove_node((yyvsp[(1) - (1)]));
                  (yyval) = (yyvsp[(1) - (1)]);
@@ -1885,12 +1928,16 @@ yyreduce:
     break;
 
   case 66:
-#line 283 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 287 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 68:
-#line 289 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 293 "scripts/genksyms/parse.y"
     { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
                    YYERROR;
@@ -1902,97 +1949,135 @@ yyreduce:
     break;
 
   case 69:
-#line 298 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 302 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 70:
-#line 300 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 304 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 71:
-#line 302 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 306 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 72:
-#line 304 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 308 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 73:
-#line 306 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 310 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 74:
-#line 312 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 316 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 78:
-#line 320 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 324 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 79:
-#line 322 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 326 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 80:
-#line 324 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 328 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 81:
-#line 326 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 330 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 82:
-#line 328 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 332 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 83:
-#line 332 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 336 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 85:
-#line 334 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 338 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 86:
-#line 338 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 342 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 89:
-#line 345 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 349 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 90:
-#line 350 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 354 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); ;}
     break;
 
   case 91:
-#line 355 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 359 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); ;}
     break;
 
   case 93:
-#line 360 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 364 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 94:
-#line 362 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 366 "scripts/genksyms/parse.y"
     { /* For version 2 checksums, we don't want to remember
                     private parameter names.  */
                  remove_node((yyvsp[(1) - (1)]));
@@ -2001,39 +2086,53 @@ yyreduce:
     break;
 
   case 95:
-#line 370 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 374 "scripts/genksyms/parse.y"
     { remove_node((yyvsp[(1) - (1)]));
                  (yyval) = (yyvsp[(1) - (1)]);
                ;}
     break;
 
   case 96:
-#line 374 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 378 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 97:
-#line 376 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 380 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(4) - (4)]); ;}
     break;
 
   case 98:
-#line 378 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 382 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 99:
-#line 380 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 384 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 100:
-#line 382 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 386 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 101:
-#line 387 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 391 "scripts/genksyms/parse.y"
     { struct string_list *decl = *(yyvsp[(2) - (3)]);
                  *(yyvsp[(2) - (3)]) = NULL;
                  add_symbol(current_name, SYM_NORMAL, decl, is_extern);
@@ -2042,93 +2141,163 @@ yyreduce:
     break;
 
   case 102:
-#line 395 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 399 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 104:
-#line 402 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 406 "scripts/genksyms/parse.y"
     { remove_list((yyvsp[(2) - (2)]), &(*(yyvsp[(1) - (2)]))->next); (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 105:
-#line 406 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 410 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 106:
-#line 407 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 411 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 107:
-#line 411 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 415 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 110:
-#line 417 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 421 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 111:
-#line 422 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 426 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 112:
-#line 424 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 428 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 113:
-#line 428 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 432 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 116:
-#line 434 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 438 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 117:
-#line 438 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 442 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); ;}
     break;
 
   case 118:
-#line 439 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 443 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 120:
-#line 444 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 448 "scripts/genksyms/parse.y"
     { (yyval) = (yyvsp[(2) - (2)]); ;}
     break;
 
   case 121:
-#line 448 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 452 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
   case 123:
-#line 453 "scripts/genksyms/parse.y"
-    { (yyval) = (yyvsp[(2) - (2)]); ;}
+
+/* Line 1455 of yacc.c  */
+#line 457 "scripts/genksyms/parse.y"
+    { (yyval) = (yyvsp[(3) - (3)]); ;}
     break;
 
   case 124:
-#line 457 "scripts/genksyms/parse.y"
+
+/* Line 1455 of yacc.c  */
+#line 458 "scripts/genksyms/parse.y"
+    { (yyval) = (yyvsp[(4) - (4)]); ;}
+    break;
+
+  case 127:
+
+/* Line 1455 of yacc.c  */
+#line 467 "scripts/genksyms/parse.y"
+    {
+                       const char *name = strdup((*(yyvsp[(1) - (1)]))->string);
+                       add_symbol(name, SYM_ENUM_CONST, NULL, 0);
+               ;}
+    break;
+
+  case 128:
+
+/* Line 1455 of yacc.c  */
+#line 472 "scripts/genksyms/parse.y"
+    {
+                       const char *name = strdup((*(yyvsp[(1) - (3)]))->string);
+                       struct string_list *expr = copy_list_range(*(yyvsp[(3) - (3)]), *(yyvsp[(2) - (3)]));
+                       add_symbol(name, SYM_ENUM_CONST, expr, 0);
+               ;}
+    break;
+
+  case 129:
+
+/* Line 1455 of yacc.c  */
+#line 479 "scripts/genksyms/parse.y"
+    { (yyval) = (yyvsp[(2) - (2)]); ;}
+    break;
+
+  case 130:
+
+/* Line 1455 of yacc.c  */
+#line 483 "scripts/genksyms/parse.y"
     { (yyval) = NULL; ;}
     break;
 
-  case 126:
-#line 463 "scripts/genksyms/parse.y"
+  case 132:
+
+/* Line 1455 of yacc.c  */
+#line 489 "scripts/genksyms/parse.y"
     { export_symbol((*(yyvsp[(3) - (5)]))->string); (yyval) = (yyvsp[(5) - (5)]); ;}
     break;
 
 
-/* Line 1267 of yacc.c.  */
-#line 2132 "scripts/genksyms/parse.c"
+
+/* Line 1455 of yacc.c  */
+#line 2301 "scripts/genksyms/parse.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -2139,7 +2308,6 @@ yyreduce:
 
   *++yyvsp = yyval;
 
-
   /* Now `shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
      number reduced by.  */
@@ -2204,7 +2372,7 @@ yyerrlab:
 
   if (yyerrstatus == 3)
     {
-      /* If just tried and failed to reuse look-ahead token after an
+      /* If just tried and failed to reuse lookahead token after an
         error, discard it.  */
 
       if (yychar <= YYEOF)
@@ -2221,7 +2389,7 @@ yyerrlab:
        }
     }
 
-  /* Else will try to reuse look-ahead token after shifting the error
+  /* Else will try to reuse lookahead token after shifting the error
      token.  */
   goto yyerrlab1;
 
@@ -2278,9 +2446,6 @@ yyerrlab1:
       YY_STACK_PRINT (yyss, yyssp);
     }
 
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
   *++yyvsp = yylval;
 
 
@@ -2305,7 +2470,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
-#ifndef yyoverflow
+#if !defined(yyoverflow) || YYERROR_VERBOSE
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
@@ -2316,7 +2481,7 @@ yyexhaustedlab:
 #endif
 
 yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
+  if (yychar != YYEMPTY)
      yydestruct ("Cleanup: discarding lookahead",
                 yytoken, &yylval);
   /* Do not reclaim the symbols of the rule which action triggered
@@ -2342,7 +2507,9 @@ yyreturn:
 }
 
 
-#line 467 "scripts/genksyms/parse.y"
+
+/* Line 1675 of yacc.c  */
+#line 493 "scripts/genksyms/parse.y"
 
 
 static void
index c4eeec652b79958eee113475f7f6b214f23f935f..517523669251b9638ff0e933c7cb9ff9fe97fb00 100644 (file)
@@ -1,24 +1,23 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
 
-/* Skeleton interface for Bison's Yacc-like parsers in C
+/* A Bison parser, made by GNU Bison 2.4.1.  */
 
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Skeleton interface for Bison's Yacc-like parsers in C
+   
+      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
+   
+   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.
-
+   the Free Software Foundation, either version 3 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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-
+   
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+
 /* Tokens.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
      FILENAME = 298
    };
 #endif
-/* Tokens.  */
-#define ASM_KEYW 258
-#define ATTRIBUTE_KEYW 259
-#define AUTO_KEYW 260
-#define BOOL_KEYW 261
-#define CHAR_KEYW 262
-#define CONST_KEYW 263
-#define DOUBLE_KEYW 264
-#define ENUM_KEYW 265
-#define EXTERN_KEYW 266
-#define EXTENSION_KEYW 267
-#define FLOAT_KEYW 268
-#define INLINE_KEYW 269
-#define INT_KEYW 270
-#define LONG_KEYW 271
-#define REGISTER_KEYW 272
-#define RESTRICT_KEYW 273
-#define SHORT_KEYW 274
-#define SIGNED_KEYW 275
-#define STATIC_KEYW 276
-#define STRUCT_KEYW 277
-#define TYPEDEF_KEYW 278
-#define UNION_KEYW 279
-#define UNSIGNED_KEYW 280
-#define VOID_KEYW 281
-#define VOLATILE_KEYW 282
-#define TYPEOF_KEYW 283
-#define EXPORT_SYMBOL_KEYW 284
-#define ASM_PHRASE 285
-#define ATTRIBUTE_PHRASE 286
-#define BRACE_PHRASE 287
-#define BRACKET_PHRASE 288
-#define EXPRESSION_PHRASE 289
-#define CHAR 290
-#define DOTS 291
-#define IDENT 292
-#define INT 293
-#define REAL 294
-#define STRING 295
-#define TYPE 296
-#define OTHER 297
-#define FILENAME 298
-
 
 
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 extern YYSTYPE yylval;
 
+
index 09a265cd71939cba93839a53ba3b5ebf23574254..ba5c242866c11b4c0803822bd45b940ad16b8474 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#include <string.h>
 #include "genksyms.h"
 
 static int is_typedef;
@@ -227,16 +228,19 @@ type_specifier:
                  add_symbol(i->string, SYM_UNION, s, is_extern);
                  $$ = $3;
                }
-       | ENUM_KEYW IDENT BRACE_PHRASE
+       | ENUM_KEYW IDENT enum_body
                { struct string_list *s = *$3, *i = *$2, *r;
                  r = copy_node(i); r->tag = SYM_ENUM;
                  r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
                  add_symbol(i->string, SYM_ENUM, s, is_extern);
                  $$ = $3;
                }
-
-       /* Anonymous s/u/e definitions.  Nothing needs doing.  */
-       | ENUM_KEYW BRACE_PHRASE                        { $$ = $2; }
+       /*
+        * Anonymous enum definition. Tell add_symbol() to restart its counter.
+        */
+       | ENUM_KEYW enum_body
+               { add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
+       /* Anonymous s/u definitions.  Nothing needs doing.  */
        | STRUCT_KEYW class_body                        { $$ = $2; }
        | UNION_KEYW class_body                         { $$ = $2; }
        ;
@@ -449,6 +453,28 @@ attribute_opt:
        | attribute_opt ATTRIBUTE_PHRASE
        ;
 
+enum_body:
+       '{' enumerator_list '}'                         { $$ = $3; }
+       | '{' enumerator_list ',' '}'                   { $$ = $4; }
+        ;
+
+enumerator_list:
+       enumerator
+       | enumerator_list ',' enumerator
+
+enumerator:
+       IDENT
+               {
+                       const char *name = strdup((*$1)->string);
+                       add_symbol(name, SYM_ENUM_CONST, NULL, 0);
+               }
+       | IDENT '=' EXPRESSION_PHRASE
+               {
+                       const char *name = strdup((*$1)->string);
+                       struct string_list *expr = copy_list_range(*$3, *$2);
+                       add_symbol(name, SYM_ENUM_CONST, expr, 0);
+               }
+
 asm_definition:
        ASM_PHRASE ';'                                  { $$ = $2; }
        ;
index 139e0fff8e3131159d8d16046d2cf9bc72503aaa..d29a8d75cb22ebb37f747f1b0b46d5df24974e58 100755 (executable)
@@ -420,6 +420,14 @@ foreach my $file (@ARGV) {
 
        open(my $patch, "< $file")
            or die "$P: Can't open $file: $!\n";
+
+       # We can check arbitrary information before the patch
+       # like the commit message, mail headers, etc...
+       # This allows us to match arbitrary keywords against any part
+       # of a git format-patch generated file (subject tags, etc...)
+
+       my $patch_prefix = "";                  #Parsing the intro
+
        while (<$patch>) {
            my $patch_line = $_;
            if (m/^\+\+\+\s+(\S+)/) {
@@ -428,13 +436,14 @@ foreach my $file (@ARGV) {
                $filename =~ s@\n@@;
                $lastfile = $filename;
                push(@files, $filename);
+               $patch_prefix = "^[+-].*";      #Now parsing the actual patch
            } elsif (m/^\@\@ -(\d+),(\d+)/) {
                if ($email_git_blame) {
                    push(@range, "$lastfile:$1:$2");
                }
            } elsif ($keywords) {
                foreach my $line (keys %keyword_hash) {
-                   if ($patch_line =~ m/^[+-].*$keyword_hash{$line}/x) {
+                   if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
                        push(@keyword_tvi, $line);
                    }
                }
index e8fba959fffb4681f397857288c5aab4d159f895..cd104afcc5f27d8dca823ae33edeece2868e28d5 100644 (file)
@@ -1248,6 +1248,19 @@ static int is_function(Elf_Sym *sym)
                return -1;
 }
 
+static void print_section_list(const char * const list[20])
+{
+       const char *const *s = list;
+
+       while (*s) {
+               fprintf(stderr, "%s", *s);
+               s++;
+               if (*s)
+                       fprintf(stderr, ", ");
+       }
+       fprintf(stderr, "\n");
+}
+
 /*
  * Print a warning about a section mismatch.
  * Try to find symbols near it so user can find it.
@@ -1304,7 +1317,6 @@ static void report_sec_mismatch(const char *modname,
                break;
        case DATA_TO_ANY_INIT: {
                prl_to = sec2annotation(tosec);
-               const char *const *s = mismatch->symbol_white_list;
                fprintf(stderr,
                "The variable %s references\n"
                "the %s %s%s%s\n"
@@ -1312,9 +1324,7 @@ static void report_sec_mismatch(const char *modname,
                "variable with __init* or __refdata (see linux/init.h) "
                "or name the variable:\n",
                fromsym, to, prl_to, tosym, to_p);
-               while (*s)
-                       fprintf(stderr, "%s, ", *s++);
-               fprintf(stderr, "\n");
+               print_section_list(mismatch->symbol_white_list);
                free(prl_to);
                break;
        }
@@ -1329,7 +1339,6 @@ static void report_sec_mismatch(const char *modname,
                break;
        case DATA_TO_ANY_EXIT: {
                prl_to = sec2annotation(tosec);
-               const char *const *s = mismatch->symbol_white_list;
                fprintf(stderr,
                "The variable %s references\n"
                "the %s %s%s%s\n"
@@ -1337,9 +1346,7 @@ static void report_sec_mismatch(const char *modname,
                "variable with __exit* (see linux/init.h) or "
                "name the variable:\n",
                fromsym, to, prl_to, tosym, to_p);
-               while (*s)
-                       fprintf(stderr, "%s, ", *s++);
-               fprintf(stderr, "\n");
+               print_section_list(mismatch->symbol_white_list);
                free(prl_to);
                break;
        }
index d0b931b994fccebc025c1c281c8cfd1573b7f64b..a834b935f5363d80ab56b15a1acf3cb477f21e42 100644 (file)
@@ -127,7 +127,8 @@ rm -r $(perf-tar);                                                  \
 $(if $(findstring tar-src,$@),,                                     \
 $(if $(findstring bz2,$@),bzip2,                                    \
 $(if $(findstring gz,$@),gzip,                                      \
-$(error unknown target $@)))                                       \
+$(if $(findstring xz,$@),xz,                                        \
+$(error unknown target $@))))                                       \
        -f -9 $(perf-tar).tar)
 
 perf-%pkg: FORCE
@@ -142,7 +143,9 @@ help: FORCE
        @echo '  tar-pkg             - Build the kernel as an uncompressed tarball'
        @echo '  targz-pkg           - Build the kernel as a gzip compressed tarball'
        @echo '  tarbz2-pkg          - Build the kernel as a bzip2 compressed tarball'
+       @echo '  tarxz-pkg           - Build the kernel as a xz compressed tarball'
        @echo '  perf-tar-src-pkg    - Build $(perf-tar).tar source tarball'
        @echo '  perf-targz-src-pkg  - Build $(perf-tar).tar.gz source tarball'
        @echo '  perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball'
+       @echo '  perf-tarxz-src-pkg  - Build $(perf-tar).tar.xz source tarball'
 
index 51b2aa0acb82db959b67ca1170439c436ae0ab3b..83c9c04102f2bc9fd06d783d31df60eb5e793c5d 100644 (file)
@@ -35,6 +35,10 @@ case "${1}" in
                compress="bzip2 -c9"
                file_ext=".bz2"
                ;;
+       tarxz-pkg)
+               compress="xz -c9"
+               file_ext=".xz"
+               ;;
        *)
                echo "Unknown tarball target \"${1}\" requested, please add it to ${0}." >&2
                exit 1
index ef8729f48586d193d3926d5bd6c4d0b9c34bcb96..4d403844e137a59f53f032bc4972a35e86b2327f 100755 (executable)
@@ -86,12 +86,16 @@ scm_version()
 
        # Check for mercurial and a mercurial repo.
        if test -d .hg && hgid=`hg id 2>/dev/null`; then
-               tag=`printf '%s' "$hgid" | cut -s -d' ' -f2`
-
-               # Do we have an untagged version?
-               if [ -z "$tag" -o "$tag" = tip ]; then
-                       id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
+               # Do we have an tagged version?  If so, latesttagdistance == 1
+               if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then
+                       id=`hg log -r . --template '{latesttag}'`
                        printf '%s%s' -hg "$id"
+               else
+                       tag=`printf '%s' "$hgid" | cut -d' ' -f2`
+                       if [ -z "$tag" -o "$tag" = tip ]; then
+                               id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
+                               printf '%s%s' -hg "$id"
+                       fi
                fi
 
                # Are there uncommitted changes?
index 92fdc4546141125a14410af0b8d4b1ce8464e2fe..bd6185d529cff980e8516429abdc9f3ca2646391 100755 (executable)
@@ -114,6 +114,11 @@ docscope()
        cscope -b -f cscope.out
 }
 
+dogtags()
+{
+       all_sources | gtags -f -
+}
+
 exuberant()
 {
        all_sources | xargs $1 -a                               \
@@ -187,6 +192,10 @@ case "$1" in
                docscope
                ;;
 
+       "gtags")
+               dogtags
+               ;;
+
        "tags")
                rm -f tags
                xtags ctags
index 44d39785e50da4a67bdde65a86e55b6a795e55b3..7493c0ee51cc93e7cc7a7a7a3920a917ab560659 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>
+ * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 /*
+ * unifdef - remove ifdef'ed lines
+ *
  * This code was derived from software contributed to Berkeley by Dave Yost.
  * It was rewritten to support ANSI C by Tony Finch. The original version
  * of unifdef carried the 4-clause BSD copyright licence. None of its code
  * remains in this version (though some of the names remain) so it now
  * carries a more liberal licence.
  *
- * The latest version is available from http://dotat.at/prog/unifdef
- */
-
-static const char * const copyright[] = {
-    "@(#) Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>\n",
-    "$dotat: unifdef/unifdef.c,v 1.190 2009/11/27 17:21:26 fanf2 Exp $",
-};
-
-/*
- * unifdef - remove ifdef'ed lines
- *
  *  Wishlist:
  *      provide an option which will append the name of the
  *        appropriate symbol after #else's and #endif's
@@ -48,12 +39,16 @@ static const char * const copyright[] = {
  *        #else's and #endif's to see that they match their
  *        corresponding #ifdef or #ifndef
  *
- *   The first two items above require better buffer handling, which would
- *     also make it possible to handle all "dodgy" directives correctly.
+ *   These require better buffer handling, which would also make
+ *   it possible to handle all "dodgy" directives correctly.
  */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include <ctype.h>
 #include <err.h>
+#include <errno.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -61,6 +56,12 @@ static const char * const copyright[] = {
 #include <string.h>
 #include <unistd.h>
 
+const char copyright[] =
+    "@(#) $Version: unifdef-2.5 $\n"
+    "@(#) $Author: Tony Finch (dot@dotat.at) $\n"
+    "@(#) $URL: http://dotat.at/prog/unifdef $\n"
+;
+
 /* types of input lines: */
 typedef enum {
        LT_TRUEI,               /* a true #if with ignore flag */
@@ -152,6 +153,11 @@ static char const * const linestate_name[] = {
  */
 #define        EDITSLOP        10
 
+/*
+ * For temporary filenames
+ */
+#define TEMPLATE        "unifdef.XXXXXX"
+
 /*
  * Globals.
  */
@@ -165,6 +171,7 @@ static bool             strictlogic;                /* -K: keep ambiguous #ifs */
 static bool             killconsts;            /* -k: eval constant #ifs */
 static bool             lnnum;                 /* -n: add #line directives */
 static bool             symlist;               /* -s: output symbol list */
+static bool             symdepth;              /* -S: output symbol depth */
 static bool             text;                  /* -t: this is a text file */
 
 static const char      *symname[MAXSYMS];      /* symbol name */
@@ -175,10 +182,18 @@ static int              nsyms;                    /* number of symbols */
 static FILE            *input;                 /* input file pointer */
 static const char      *filename;              /* input file name */
 static int              linenum;               /* current line number */
+static FILE            *output;                        /* output file pointer */
+static const char      *ofilename;             /* output file name */
+static bool             overwriting;           /* output overwrites input */
+static char             tempname[FILENAME_MAX];        /* used when overwriting */
 
 static char             tline[MAXLINE+EDITSLOP];/* input buffer plus space */
 static char            *keyword;               /* used for editing #elif's */
 
+static const char      *newline;               /* input file format */
+static const char       newline_unix[] = "\n";
+static const char       newline_crlf[] = "\r\n";
+
 static Comment_state    incomment;             /* comment parser state */
 static Line_state       linestate;             /* #if line parser state */
 static Ifstate          ifstate[MAXDEPTH];     /* #if processor state */
@@ -189,10 +204,13 @@ static int              delcount;         /* count of deleted lines */
 static unsigned         blankcount;            /* count of blank lines */
 static unsigned         blankmax;              /* maximum recent blankcount */
 static bool             constexpr;             /* constant #if expression */
+static bool             zerosyms = true;       /* to format symdepth output */
+static bool             firstsym;              /* ditto */
 
 static int              exitstat;              /* program exit status */
 
 static void             addsym(bool, bool, char *);
+static void             closeout(void);
 static void             debug(const char *, ...);
 static void             done(void);
 static void             error(const char *);
@@ -212,6 +230,7 @@ static void             state(Ifstate);
 static int              strlcmp(const char *, const char *, size_t);
 static void             unnest(void);
 static void             usage(void);
+static void             version(void);
 
 #define endsym(c) (!isalnum((unsigned char)c) && c != '_')
 
@@ -223,7 +242,7 @@ main(int argc, char *argv[])
 {
        int opt;
 
-       while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1)
+       while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1)
                switch (opt) {
                case 'i': /* treat stuff controlled by these symbols as text */
                        /*
@@ -245,16 +264,15 @@ main(int argc, char *argv[])
                case 'U': /* undef a symbol */
                        addsym(false, false, optarg);
                        break;
-               case 'I':
-                       /* no-op for compatibility with cpp */
-                       break;
-               case 'B': /* compress blank lines around removed section */
-                       compblank = true;
+               case 'I': /* no-op for compatibility with cpp */
                        break;
                case 'b': /* blank deleted lines instead of omitting them */
                case 'l': /* backwards compatibility */
                        lnblank = true;
                        break;
+               case 'B': /* compress blank lines around removed section */
+                       compblank = true;
+                       break;
                case 'c': /* treat -D as -U and vice versa */
                        complement = true;
                        break;
@@ -273,12 +291,20 @@ main(int argc, char *argv[])
                case 'n': /* add #line directive after deleted lines */
                        lnnum = true;
                        break;
+               case 'o': /* output to a file */
+                       ofilename = optarg;
+                       break;
                case 's': /* only output list of symbols that control #ifs */
                        symlist = true;
                        break;
+               case 'S': /* list symbols with their nesting depth */
+                       symlist = symdepth = true;
+                       break;
                case 't': /* don't parse C comments */
                        text = true;
                        break;
+               case 'V': /* print version */
+                       version();
                default:
                        usage();
                }
@@ -290,21 +316,68 @@ main(int argc, char *argv[])
                errx(2, "can only do one file");
        } else if (argc == 1 && strcmp(*argv, "-") != 0) {
                filename = *argv;
-               input = fopen(filename, "r");
+               input = fopen(filename, "rb");
                if (input == NULL)
                        err(2, "can't open %s", filename);
        } else {
                filename = "[stdin]";
                input = stdin;
        }
+       if (ofilename == NULL) {
+               ofilename = "[stdout]";
+               output = stdout;
+       } else {
+               struct stat ist, ost;
+               if (stat(ofilename, &ost) == 0 &&
+                   fstat(fileno(input), &ist) == 0)
+                       overwriting = (ist.st_dev == ost.st_dev
+                                   && ist.st_ino == ost.st_ino);
+               if (overwriting) {
+                       const char *dirsep;
+                       int ofd;
+
+                       dirsep = strrchr(ofilename, '/');
+                       if (dirsep != NULL)
+                               snprintf(tempname, sizeof(tempname),
+                                   "%.*s/" TEMPLATE,
+                                   (int)(dirsep - ofilename), ofilename);
+                       else
+                               snprintf(tempname, sizeof(tempname),
+                                   TEMPLATE);
+                       ofd = mkstemp(tempname);
+                       if (ofd != -1)
+                               output = fdopen(ofd, "wb+");
+                       if (output == NULL)
+                               err(2, "can't create temporary file");
+                       fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+               } else {
+                       output = fopen(ofilename, "wb");
+                       if (output == NULL)
+                               err(2, "can't open %s", ofilename);
+               }
+       }
        process();
        abort(); /* bug */
 }
 
+static void
+version(void)
+{
+       const char *c = copyright;
+       for (;;) {
+               while (*++c != '$')
+                       if (*c == '\0')
+                               exit(0);
+               while (*++c != '$')
+                       putc(*c, stderr);
+               putc('\n', stderr);
+       }
+}
+
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: unifdef [-BbcdeKknst] [-Ipath]"
+       fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]"
            " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
        exit(2);
 }
@@ -322,7 +395,8 @@ usage(void)
  * When we have processed a group that starts off with a known-false
  * #if/#elif sequence (which has therefore been deleted) followed by a
  * #elif that we don't understand and therefore must keep, we edit the
- * latter into a #if to keep the nesting correct.
+ * latter into a #if to keep the nesting correct. We use strncpy() to
+ * overwrite the 4 byte token "elif" with "if  " without a '\0' byte.
  *
  * When we find a true #elif in a group, the following block will
  * always be kept and the rest of the sequence after the next #elif or
@@ -375,11 +449,11 @@ static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
 static void Idrop (void) { Fdrop();  ignoreon(); }
 static void Itrue (void) { Ftrue();  ignoreon(); }
 static void Ifalse(void) { Ffalse(); ignoreon(); }
-/* edit this line */
+/* modify this line */
 static void Mpass (void) { strncpy(keyword, "if  ", 4); Pelif(); }
-static void Mtrue (void) { keywordedit("else\n");  state(IS_TRUE_MIDDLE); }
-static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
-static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
+static void Mtrue (void) { keywordedit("else");  state(IS_TRUE_MIDDLE); }
+static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
+static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
 
 static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
 /* IS_OUTSIDE */
@@ -431,13 +505,6 @@ static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
  * State machine utility functions
  */
 static void
-done(void)
-{
-       if (incomment)
-               error("EOF in comment");
-       exit(exitstat);
-}
-static void
 ignoreoff(void)
 {
        if (depth == 0)
@@ -452,14 +519,8 @@ ignoreon(void)
 static void
 keywordedit(const char *replacement)
 {
-       size_t size = tline + sizeof(tline) - keyword;
-       char *dst = keyword;
-       const char *src = replacement;
-       if (size != 0) {
-               while ((--size != 0) && (*src != '\0'))
-                       *dst++ = *src++;
-               *dst = '\0';
-       }
+       snprintf(keyword, tline + sizeof(tline) - keyword,
+           "%s%s", replacement, newline);
        print();
 }
 static void
@@ -494,24 +555,26 @@ flushline(bool keep)
        if (symlist)
                return;
        if (keep ^ complement) {
-               bool blankline = tline[strspn(tline, " \t\n")] == '\0';
+               bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
                if (blankline && compblank && blankcount != blankmax) {
                        delcount += 1;
                        blankcount += 1;
                } else {
                        if (lnnum && delcount > 0)
-                               printf("#line %d\n", linenum);
-                       fputs(tline, stdout);
+                               printf("#line %d%s", linenum, newline);
+                       fputs(tline, output);
                        delcount = 0;
                        blankmax = blankcount = blankline ? blankcount + 1 : 0;
                }
        } else {
                if (lnblank)
-                       putc('\n', stdout);
+                       fputs(newline, output);
                exitstat = 1;
                delcount += 1;
                blankcount = 0;
        }
+       if (debugging)
+               fflush(output);
 }
 
 /*
@@ -520,21 +583,54 @@ flushline(bool keep)
 static void
 process(void)
 {
-       Linetype lineval;
-
        /* When compressing blank lines, act as if the file
           is preceded by a large number of blank lines. */
        blankmax = blankcount = 1000;
        for (;;) {
-               linenum++;
-               lineval = parseline();
+               Linetype lineval = parseline();
                trans_table[ifstate[depth]][lineval]();
-               debug("process %s -> %s depth %d",
-                   linetype_name[lineval],
+               debug("process line %d %s -> %s depth %d",
+                   linenum, linetype_name[lineval],
                    ifstate_name[ifstate[depth]], depth);
        }
 }
 
+/*
+ * Flush the output and handle errors.
+ */
+static void
+closeout(void)
+{
+       if (symdepth && !zerosyms)
+               printf("\n");
+       if (fclose(output) == EOF) {
+               warn("couldn't write to %s", ofilename);
+               if (overwriting) {
+                       unlink(tempname);
+                       errx(2, "%s unchanged", filename);
+               } else {
+                       exit(2);
+               }
+       }
+}
+
+/*
+ * Clean up and exit.
+ */
+static void
+done(void)
+{
+       if (incomment)
+               error("EOF in comment");
+       closeout();
+       if (overwriting && rename(tempname, ofilename) == -1) {
+               warn("couldn't rename temporary file");
+               unlink(tempname);
+               errx(2, "%s unchanged", ofilename);
+       }
+       exit(exitstat);
+}
+
 /*
  * Parse a line and determine its type. We keep the preprocessor line
  * parser state between calls in the global variable linestate, with
@@ -549,14 +645,22 @@ parseline(void)
        Linetype retval;
        Comment_state wascomment;
 
+       linenum++;
        if (fgets(tline, MAXLINE, input) == NULL)
                return (LT_EOF);
+       if (newline == NULL) {
+               if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
+                       newline = newline_crlf;
+               else
+                       newline = newline_unix;
+       }
        retval = LT_PLAIN;
        wascomment = incomment;
        cp = skipcomment(tline);
        if (linestate == LS_START) {
                if (*cp == '#') {
                        linestate = LS_HASH;
+                       firstsym = true;
                        cp = skipcomment(cp + 1);
                } else if (*cp != '\0')
                        linestate = LS_DIRTY;
@@ -566,7 +670,8 @@ parseline(void)
                cp = skipsym(cp);
                kwlen = cp - keyword;
                /* no way can we deal with a continuation inside a keyword */
-               if (strncmp(cp, "\\\n", 2) == 0)
+               if (strncmp(cp, "\\\r\n", 3) == 0 ||
+                   strncmp(cp, "\\\n", 2) == 0)
                        Eioccc();
                if (strlcmp("ifdef", keyword, kwlen) == 0 ||
                    strlcmp("ifndef", keyword, kwlen) == 0) {
@@ -617,9 +722,8 @@ parseline(void)
                        size_t len = cp - tline;
                        if (fgets(tline + len, MAXLINE - len, input) == NULL) {
                                /* append the missing newline */
-                               tline[len+0] = '\n';
-                               tline[len+1] = '\0';
-                               cp++;
+                               strcpy(tline + len, newline);
+                               cp += strlen(newline);
                                linestate = LS_START;
                        } else {
                                linestate = LS_DIRTY;
@@ -630,7 +734,7 @@ parseline(void)
                while (*cp != '\0')
                        cp = skipcomment(cp + 1);
        }
-       debug("parser %s comment %s line",
+       debug("parser line %d state %s comment %s line", linenum,
            comment_name[incomment], linestate_name[linestate]);
        return (retval);
 }
@@ -875,11 +979,16 @@ skipcomment(const char *cp)
        }
        while (*cp != '\0')
                /* don't reset to LS_START after a line continuation */
-               if (strncmp(cp, "\\\n", 2) == 0)
+               if (strncmp(cp, "\\\r\n", 3) == 0)
+                       cp += 3;
+               else if (strncmp(cp, "\\\n", 2) == 0)
                        cp += 2;
                else switch (incomment) {
                case NO_COMMENT:
-                       if (strncmp(cp, "/\\\n", 3) == 0) {
+                       if (strncmp(cp, "/\\\r\n", 4) == 0) {
+                               incomment = STARTING_COMMENT;
+                               cp += 4;
+                       } else if (strncmp(cp, "/\\\n", 3) == 0) {
                                incomment = STARTING_COMMENT;
                                cp += 3;
                        } else if (strncmp(cp, "/*", 2) == 0) {
@@ -899,7 +1008,7 @@ skipcomment(const char *cp)
                        } else if (strncmp(cp, "\n", 1) == 0) {
                                linestate = LS_START;
                                cp += 1;
-                       } else if (strchr(" \t", *cp) != NULL) {
+                       } else if (strchr(" \r\t", *cp) != NULL) {
                                cp += 1;
                        } else
                                return (cp);
@@ -931,7 +1040,10 @@ skipcomment(const char *cp)
                                cp += 1;
                        continue;
                case C_COMMENT:
-                       if (strncmp(cp, "*\\\n", 3) == 0) {
+                       if (strncmp(cp, "*\\\r\n", 4) == 0) {
+                               incomment = FINISHING_COMMENT;
+                               cp += 4;
+                       } else if (strncmp(cp, "*\\\n", 3) == 0) {
                                incomment = FINISHING_COMMENT;
                                cp += 3;
                        } else if (strncmp(cp, "*/", 2) == 0) {
@@ -1015,7 +1127,13 @@ findsym(const char *str)
        if (cp == str)
                return (-1);
        if (symlist) {
-               printf("%.*s\n", (int)(cp-str), str);
+               if (symdepth && firstsym)
+                       printf("%s%3d", zerosyms ? "" : "\n", depth);
+               firstsym = zerosyms = false;
+               printf("%s%.*s%s",
+                   symdepth ? " " : "",
+                   (int)(cp-str), str,
+                   symdepth ? "" : "\n");
                /* we don't care about the value of the symbol */
                return (0);
        }
@@ -1052,7 +1170,7 @@ addsym(bool ignorethis, bool definethis, char *sym)
                        value[symind] = val+1;
                        *val = '\0';
                } else if (*val == '\0')
-                       value[symind] = "";
+                       value[symind] = "1";
                else
                        usage();
        } else {
@@ -1060,6 +1178,8 @@ addsym(bool ignorethis, bool definethis, char *sym)
                        usage();
                value[symind] = NULL;
        }
+       debug("addsym %s=%s", symname[symind],
+           value[symind] ? value[symind] : "undef");
 }
 
 /*
@@ -1100,5 +1220,6 @@ error(const char *msg)
        else
                warnx("%s: %d: %s (#if line %d depth %d)",
                    filename, linenum, msg, stifline[depth], depth);
+       closeout();
        errx(2, "output may be truncated");
 }
index d21a427a35ae1a8fd30a6b4222e6db0f5508cd3c..ae3a698415e63603d9b159814b45c58b0f83eee0 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ctype.h>
 #include <linux/sysctl.h>
 #include <linux/audit.h>
+#include <linux/user_namespace.h>
 #include <net/sock.h>
 
 #include "include/apparmor.h"
@@ -136,11 +137,11 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
 }
 
 static int apparmor_capable(struct task_struct *task, const struct cred *cred,
-                           int cap, int audit)
+                           struct user_namespace *ns, int cap, int audit)
 {
        struct aa_profile *profile;
        /* cap_capable returns 0 on success, else -EPERM */
-       int error = cap_capable(task, cred, cap, audit);
+       int error = cap_capable(task, cred, ns, cap, audit);
        if (!error) {
                profile = aa_cred_profile(cred);
                if (!unconfined(profile))
index 49c57fd60aea226d53070c1f9fd71ee208df9da5..f20e984ccfb459c141222f51791f4b5a3fcab6a9 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/prctl.h>
 #include <linux/securebits.h>
+#include <linux/user_namespace.h>
 
 /*
  * If a non-root user executes a setuid-root binary in
@@ -67,6 +68,7 @@ EXPORT_SYMBOL(cap_netlink_recv);
  * cap_capable - Determine whether a task has a particular effective capability
  * @tsk: The task to query
  * @cred: The credentials to use
+ * @ns:  The user namespace in which we need the capability
  * @cap: The capability to check for
  * @audit: Whether to write an audit message or not
  *
@@ -78,10 +80,30 @@ EXPORT_SYMBOL(cap_netlink_recv);
  * cap_has_capability() returns 0 when a task has a capability, but the
  * kernel's capable() and has_capability() returns 1 for this case.
  */
-int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
-               int audit)
+int cap_capable(struct task_struct *tsk, const struct cred *cred,
+               struct user_namespace *targ_ns, int cap, int audit)
 {
-       return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
+       for (;;) {
+               /* The creator of the user namespace has all caps. */
+               if (targ_ns != &init_user_ns && targ_ns->creator == cred->user)
+                       return 0;
+
+               /* Do we have the necessary capabilities? */
+               if (targ_ns == cred->user->user_ns)
+                       return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
+
+               /* Have we tried all of the parent namespaces? */
+               if (targ_ns == &init_user_ns)
+                       return -EPERM;
+
+               /*
+                *If you have a capability in a parent user ns, then you have
+                * it over all children user namespaces as well.
+                */
+               targ_ns = targ_ns->creator->user_ns;
+       }
+
+       /* We never get here */
 }
 
 /**
@@ -105,18 +127,30 @@ int cap_settime(const struct timespec *ts, const struct timezone *tz)
  * @child: The process to be accessed
  * @mode: The mode of attachment.
  *
+ * If we are in the same or an ancestor user_ns and have all the target
+ * task's capabilities, then ptrace access is allowed.
+ * If we have the ptrace capability to the target user_ns, then ptrace
+ * access is allowed.
+ * Else denied.
+ *
  * Determine whether a process may access another, returning 0 if permission
  * granted, -ve if denied.
  */
 int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
        int ret = 0;
+       const struct cred *cred, *child_cred;
 
        rcu_read_lock();
-       if (!cap_issubset(__task_cred(child)->cap_permitted,
-                         current_cred()->cap_permitted) &&
-           !capable(CAP_SYS_PTRACE))
-               ret = -EPERM;
+       cred = current_cred();
+       child_cred = __task_cred(child);
+       if (cred->user->user_ns == child_cred->user->user_ns &&
+           cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
+               goto out;
+       if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
+               goto out;
+       ret = -EPERM;
+out:
        rcu_read_unlock();
        return ret;
 }
@@ -125,18 +159,30 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
  * cap_ptrace_traceme - Determine whether another process may trace the current
  * @parent: The task proposed to be the tracer
  *
+ * If parent is in the same or an ancestor user_ns and has all current's
+ * capabilities, then ptrace access is allowed.
+ * If parent has the ptrace capability to current's user_ns, then ptrace
+ * access is allowed.
+ * Else denied.
+ *
  * Determine whether the nominated task is permitted to trace the current
  * process, returning 0 if permission is granted, -ve if denied.
  */
 int cap_ptrace_traceme(struct task_struct *parent)
 {
        int ret = 0;
+       const struct cred *cred, *child_cred;
 
        rcu_read_lock();
-       if (!cap_issubset(current_cred()->cap_permitted,
-                         __task_cred(parent)->cap_permitted) &&
-           !has_capability(parent, CAP_SYS_PTRACE))
-               ret = -EPERM;
+       cred = __task_cred(parent);
+       child_cred = current_cred();
+       if (cred->user->user_ns == child_cred->user->user_ns &&
+           cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
+               goto out;
+       if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
+               goto out;
+       ret = -EPERM;
+out:
        rcu_read_unlock();
        return ret;
 }
@@ -176,7 +222,8 @@ static inline int cap_inh_is_capped(void)
        /* they are so limited unless the current task has the CAP_SETPCAP
         * capability
         */
-       if (cap_capable(current, current_cred(), CAP_SETPCAP,
+       if (cap_capable(current, current_cred(),
+                       current_cred()->user->user_ns, CAP_SETPCAP,
                        SECURITY_CAP_AUDIT) == 0)
                return 0;
        return 1;
@@ -828,7 +875,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                     & (new->securebits ^ arg2))                        /*[1]*/
                    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))   /*[2]*/
                    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))   /*[3]*/
-                   || (cap_capable(current, current_cred(), CAP_SETPCAP,
+                   || (cap_capable(current, current_cred(),
+                                   current_cred()->user->user_ns, CAP_SETPCAP,
                                    SECURITY_CAP_AUDIT) != 0)           /*[4]*/
                        /*
                         * [1] no changing of bits that are locked
@@ -893,7 +941,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
-       if (cap_capable(current, current_cred(), CAP_SYS_ADMIN,
+       if (cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_ADMIN,
                        SECURITY_CAP_NOAUDIT) == 0)
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
@@ -920,7 +968,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
        int ret = 0;
 
        if (addr < dac_mmap_min_addr) {
-               ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
+               ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO,
                                  SECURITY_CAP_AUDIT);
                /* set PF_SUPERPRIV if it turns out we allow the low mmap */
                if (ret == 0)
index 9187665a3fdd8fcd13bd6d19a630b5fc8f4c9ab7..101142369db45c0846ca3dbe064b90a2ea83fbf9 100644 (file)
@@ -154,29 +154,33 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(const struct cred *cred, int cap)
+int security_capable(struct user_namespace *ns, const struct cred *cred,
+                    int cap)
 {
-       return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT);
+       return security_ops->capable(current, cred, ns, cap,
+                                    SECURITY_CAP_AUDIT);
 }
 
-int security_real_capable(struct task_struct *tsk, int cap)
+int security_real_capable(struct task_struct *tsk, struct user_namespace *ns,
+                         int cap)
 {
        const struct cred *cred;
        int ret;
 
        cred = get_task_cred(tsk);
-       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
+       ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_AUDIT);
        put_cred(cred);
        return ret;
 }
 
-int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+int security_real_capable_noaudit(struct task_struct *tsk,
+                                 struct user_namespace *ns, int cap)
 {
        const struct cred *cred;
        int ret;
 
        cred = get_task_cred(tsk);
-       ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
+       ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_NOAUDIT);
        put_cred(cred);
        return ret;
 }
index 6475e1f0223eb45e937301927ef6495fae5c525b..f9c3764e48590e5737a0afddb63043b25675f23b 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/mutex.h>
 #include <linux/posix-timers.h>
 #include <linux/syslog.h>
+#include <linux/user_namespace.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -1846,11 +1847,11 @@ static int selinux_capset(struct cred *new, const struct cred *old,
  */
 
 static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
-                          int cap, int audit)
+                          struct user_namespace *ns, int cap, int audit)
 {
        int rc;
 
-       rc = cap_capable(tsk, cred, cap, audit);
+       rc = cap_capable(tsk, cred, ns, cap, audit);
        if (rc)
                return rc;
 
@@ -1931,7 +1932,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int rc, cap_sys_admin = 0;
 
-       rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
+       rc = selinux_capable(current, current_cred(),
+                            &init_user_ns, CAP_SYS_ADMIN,
                             SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
@@ -2723,7 +2725,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!(sbsec->flags & SE_SBLABELSUPP))
                return -EOPNOTSUPP;
 
-       if (!is_owner_or_cap(inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        COMMON_AUDIT_DATA_INIT(&ad, FS);
@@ -2834,7 +2836,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
+       error = selinux_capable(current, current_cred(),
+                               &init_user_ns, CAP_MAC_ADMIN,
                                SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
@@ -2968,7 +2971,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        case KDSKBENT:
        case KDSKBSENT:
                error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG,
-                                           SECURITY_CAP_AUDIT);
+                                       SECURITY_CAP_AUDIT);
                break;
 
        /* default case assumes that the command will go
index f1a03f223495f70043914326c4a563798f10ef34..5d582de91c1904bcf3bee9446232b7ab8fca57ac 100644 (file)
@@ -1265,6 +1265,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                case 0x10ec0660:
                case 0x10ec0662:
                case 0x10ec0663:
+               case 0x10ec0665:
                case 0x10ec0862:
                case 0x10ec0889:
                        set_eapd(codec, 0x14, 1);
@@ -4240,6 +4241,7 @@ static void alc_power_eapd(struct hda_codec *codec)
        case 0x10ec0660:
        case 0x10ec0662:
        case 0x10ec0663:
+       case 0x10ec0665:
        case 0x10ec0862:
        case 0x10ec0889:
                set_eapd(codec, 0x14, 0);
@@ -16006,9 +16008,12 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
                                return err;
                } else {
                        const char *name = pfx;
-                       if (!name)
+                       int index = i;
+                       if (!name) {
                                name = chname[i];
-                       err = __alc861_create_out_sw(codec, name, nid, i, 3);
+                               index = 0;
+                       }
+                       err = __alc861_create_out_sw(codec, name, nid, index, 3);
                        if (err < 0)
                                return err;
                }
@@ -17159,16 +17164,19 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                return err;
                } else {
                        const char *name = pfx;
-                       if (!name)
+                       int index = i;
+                       if (!name) {
                                name = chname[i];
+                               index = 0;
+                       }
                        err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                               name, i,
+                                               name, index,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                              name, i,
+                                              name, index,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -19217,12 +19225,15 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
                                return err;
                } else {
                        const char *name = pfx;
-                       if (!name)
+                       int index = i;
+                       if (!name) {
                                name = chname[i];
-                       err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
+                               index = 0;
+                       }
+                       err = __alc662_add_vol_ctl(spec, name, nid, index, 3);
                        if (err < 0)
                                return err;
-                       err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
+                       err = __alc662_add_sw_ctl(spec, name, mix, index, 3);
                        if (err < 0)
                                return err;
                }
index 63b0054200a878e3d879f259f3ad5134ba7e7682..1371b57c11e823209336a3a2f86b6274e550a0b9 100644 (file)
@@ -159,6 +159,7 @@ struct via_spec {
 #endif
 };
 
+static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
 static struct via_spec * via_new_spec(struct hda_codec *codec)
 {
        struct via_spec *spec;
@@ -169,6 +170,10 @@ static struct via_spec * via_new_spec(struct hda_codec *codec)
 
        codec->spec = spec;
        spec->codec = codec;
+       spec->codec_type = get_codec_type(codec);
+       /* VT1708BCE & VT1708S are almost same */
+       if (spec->codec_type == VT1708BCE)
+               spec->codec_type = VT1708S;
        return spec;
 }
 
@@ -1101,6 +1106,7 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       int ret;
 
        if (!spec->mux_nids[adc_idx])
                return -EINVAL;
@@ -1109,12 +1115,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
                               AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0)
                snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0,
                                    AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-       /* update jack power state */
-       set_jack_power_state(codec);
 
-       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+       ret = snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                     spec->mux_nids[adc_idx],
                                     &spec->cur_mux[adc_idx]);
+       /* update jack power state */
+       set_jack_power_state(codec);
+
+       return ret;
 }
 
 static int via_independent_hp_info(struct snd_kcontrol *kcontrol,
@@ -1188,8 +1196,16 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
        /* Get Independent Mode index of headphone pin widget */
        spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel
                ? 1 : 0;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel);
+       if (spec->codec_type == VT1718S)
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CONNECT_SEL, pinsel ? 2 : 0);
+       else
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_CONNECT_SEL, pinsel);
 
+       if (spec->codec_type == VT1812)
+               snd_hda_codec_write(codec, 0x35, 0,
+                                   AC_VERB_SET_CONNECT_SEL, pinsel);
        if (spec->multiout.hp_nid && spec->multiout.hp_nid
            != spec->multiout.dac_nids[HDA_FRONT])
                snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid,
@@ -1208,6 +1224,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol,
                activate_ctl(codec, "Headphone Playback Switch",
                             spec->hp_independent_mode);
        }
+       /* update jack power state */
+       set_jack_power_state(codec);
        return 0;
 }
 
@@ -1248,9 +1266,12 @@ static int via_hp_build(struct hda_codec *codec)
                break;
        }
 
-       nums = snd_hda_get_connections(codec, nid, conn, HDA_MAX_CONNECTIONS);
-       if (nums <= 1)
-               return 0;
+       if (spec->codec_type != VT1708) {
+               nums = snd_hda_get_connections(codec, nid,
+                                              conn, HDA_MAX_CONNECTIONS);
+               if (nums <= 1)
+                       return 0;
+       }
 
        knew = via_clone_control(spec, &via_hp_mixer[0]);
        if (knew == NULL)
@@ -1310,6 +1331,11 @@ static void mute_aa_path(struct hda_codec *codec, int mute)
                start_idx = 2;
                end_idx = 4;
                break;
+       case VT1718S:
+               nid_mixer = 0x21;
+               start_idx = 1;
+               end_idx = 3;
+               break;
        default:
                return;
        }
@@ -2185,10 +2211,6 @@ static int via_init(struct hda_codec *codec)
        for (i = 0; i < spec->num_iverbs; i++)
                snd_hda_sequence_write(codec, spec->init_verbs[i]);
 
-       spec->codec_type = get_codec_type(codec);
-       if (spec->codec_type == VT1708BCE)
-               spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost
-                                              same */
        /* Lydia Add for EAPD enable */
        if (!spec->dig_in_nid) { /* No Digital In connection */
                if (spec->dig_in_pin) {
@@ -2438,7 +2460,14 @@ static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
                else
                        type_idx = 0;
                label = hda_get_autocfg_input_label(codec, cfg, i);
-               err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
+               if (spec->codec_type == VT1708S ||
+                   spec->codec_type == VT1702 ||
+                   spec->codec_type == VT1716S)
+                       err = via_new_analog_input(spec, label, type_idx,
+                                                  idx+1, cap_nid);
+               else
+                       err = via_new_analog_input(spec, label, type_idx,
+                                                  idx, cap_nid);
                if (err < 0)
                        return err;
                snd_hda_add_imux_item(imux, label, idx, NULL);
@@ -4147,6 +4176,11 @@ static int patch_vt1708S(struct hda_codec *codec)
                spec->stream_name_analog = "VT1708BCE Analog";
                spec->stream_name_digital = "VT1708BCE Digital";
        }
+       /* correct names for VT1818S */
+       if (codec->vendor_id == 0x11060440) {
+               spec->stream_name_analog = "VT1818S Analog";
+               spec->stream_name_digital = "VT1818S Digital";
+       }
        return 0;
 }
 
index d63c1754e05f82d75e5f2a8763bf4cf1540c763a..6943e24a74a16b0adb4dd6f2ef7c0ef3a23293ee 100644 (file)
@@ -51,7 +51,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TWL6040 if TWL4030_CORE
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
-       select SND_SOC_WL1273 if RADIO_WL1273
+       select SND_SOC_WL1273 if MFD_WL1273_CORE
        select SND_SOC_WM2000 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
        select SND_SOC_WM8400 if MFD_WM8400
index 347a567b01e16e6a8a3eb370c6d8cba5ac1af914..b8066ef10bb0ae65dcf3b49582fe89329e17f09c 100644 (file)
@@ -153,7 +153,8 @@ static int cq93vc_resume(struct snd_soc_codec *codec)
 
 static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-       struct davinci_vc *davinci_vc = snd_soc_codec_get_drvdata(codec);
+       struct davinci_vc *davinci_vc =
+                       mfd_get_data(to_platform_device(codec->dev));
 
        davinci_vc->cq93vc.codec = codec;
        codec->control_data = davinci_vc;
index 1f7217f703ee60381deea291658e93f23949e01c..ff29380c9ed30ee5eb2eda225e505b1415de0269 100644 (file)
@@ -772,6 +772,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+#ifdef CONFIG_REGULATOR
 static int ldo_regulator_is_enabled(struct regulator_dev *dev)
 {
        struct ldo_regulator *ldo = rdev_get_drvdata(dev);
@@ -901,6 +902,19 @@ static int ldo_regulator_remove(struct snd_soc_codec *codec)
 
        return 0;
 }
+#else
+static int ldo_regulator_register(struct snd_soc_codec *codec,
+                               struct regulator_init_data *init_data,
+                               int voltage)
+{
+       return -EINVAL;
+}
+
+static int ldo_regulator_remove(struct snd_soc_codec *codec)
+{
+       return 0;
+}
+#endif
 
 /*
  * set dac bias
index e4d464b937d6d34559b00df234086dbac542ba1b..8512800f63260c8fab14431b123fdcd972f09945 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/core.h>
 #include <linux/i2c/twl.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -732,7 +733,8 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
+       struct twl4030_codec_audio_data *pdata =
+                       mfd_get_data(to_platform_device(codec->dev));
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -2297,7 +2299,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
+       struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev);
 
        if (!pdata) {
                dev_err(&pdev->dev, "platform_data is missing\n");
index e76847a9438b00f2b75aaa597ac365af656b543a..48ffd406a71d18e2170a7b8ca69214a9de4ee8a6 100644 (file)
@@ -486,7 +486,8 @@ static struct snd_soc_dai_driver uda134x_dai = {
 static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
        struct uda134x_priv *uda134x;
-       struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
+       struct uda134x_platform_data *pd = codec->card->dev->platform_data;
+
        int ret;
 
        printk(KERN_INFO "UDA134X SoC Audio Codec\n");
index 861b28f543d2d46d60ff00903603319550e80573..c8a874d0d4cae5d9a0a66974ff3ac5b4887d492a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author:      Matti Aaltonen, <matti.j.aaltonen@nokia.com>
  *
- * Copyright:   (C) 2010 Nokia Corporation
+ * Copyright:   (C) 2010, 2011 Nokia Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -179,7 +179,12 @@ static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+/*
+ * TODO: Implement the audio routing in the driver. Now this control
+ * only indicates the setting that has been done elsewhere (in the user
+ * space).
+ */
+static const char * const wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
 
 static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
@@ -239,7 +244,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
-static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
+static const char * const wl1273_audio_strings[] = { "Digital", "Analog" };
 
 static const struct soc_enum wl1273_audio_enum =
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
@@ -436,7 +441,8 @@ EXPORT_SYMBOL_GPL(wl1273_get_format);
 
 static int wl1273_probe(struct snd_soc_codec *codec)
 {
-       struct wl1273_core **core = codec->dev->platform_data;
+       struct wl1273_core **core =
+                       mfd_get_data(to_platform_device(codec->dev));
        struct wl1273_priv *wl1273;
        int r;
 
index 3c3bc079167e9936bb5722cdb1683dff14f11969..736b785e375606435ab0e181f8d48634966242ff 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/wm8400-audio.h>
 #include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -1377,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work)
 
 static int wm8400_codec_probe(struct snd_soc_codec *codec)
 {
-       struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
+       struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev));
        struct wm8400_priv *priv;
        int ret;
        u16 reg;
index 9d2afccc3a2d645dceb1e263ef7158f4c7667934..13e05a302a92edf15aa1f464298f7ae81a2e7579 100644 (file)
@@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
-       struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
+       struct davinci_vc *davinci_vc = mfd_get_data(pdev);
        struct davinci_vcif_dev *davinci_vcif_dev;
        int ret;
 
index 3cb70075107811e76b65a23828e1c140b2c6a485..dc9d551f6788db05a420a0598494e947be4bcc51 100644 (file)
@@ -219,7 +219,7 @@ static struct snd_soc_ops s3c24xx_uda134x_ops = {
 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .name = "UDA134X",
        .stream_name = "UDA134X",
-       .codec_name = "uda134x-hifi",
+       .codec_name = "uda134x-codec",
        .codec_dai_name = "uda134x-hifi",
        .cpu_dai_name = "s3c24xx-iis",
        .ops = &s3c24xx_uda134x_ops,
@@ -314,6 +314,7 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 
        platform_set_drvdata(s3c24xx_uda134x_snd_device,
                             &snd_soc_s3c24xx_uda134x);
+       platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x));
        ret = platform_device_add(s3c24xx_uda134x_snd_device);
        if (ret) {
                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
index 17efacdb248a9d15e3af2e8f46bb1c8489effe61..4dda58926bc52c282d29b769b40d6f546a3230fe 100644 (file)
@@ -259,8 +259,6 @@ static ssize_t codec_reg_write_file(struct file *file,
        while (*start == ' ')
                start++;
        reg = simple_strtoul(start, &start, 16);
-       if ((reg >= codec->driver->reg_cache_size) || (reg % step))
-               return -EINVAL;
        while (*start == ' ')
                start++;
        if (strict_strtoul(start, 16, &value))
index 340a0bc5303e9264622a50e3d9d6dcf40d984310..7e96249536b4e092ac52115efa547bacc8f86cc7 100644 (file)
@@ -19,7 +19,7 @@ static int do_mod_firmware_load(const char *fn, char **fp)
                printk(KERN_INFO "Unable to load '%s'.\n", fn);
                return 0;
        }
-       l = filp->f_path.dentry->d_inode->i_size;
+       l = i_size_read(filp->f_path.dentry->d_inode);
        if (l <= 0 || l > 131072)
        {
                printk(KERN_INFO "Invalid firmware '%s'\n", fn);
index 40722f8711adc82001001d4fa3f69b8c35b34253..a90662af2d6bbd7b2df46d17cb1da01ee849d29c 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/usb.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
@@ -283,6 +284,15 @@ static int snd_usb_audio_dev_free(struct snd_device *device)
        return snd_usb_audio_free(chip);
 }
 
+static void remove_trailing_spaces(char *str)
+{
+       char *p;
+
+       if (!*str)
+               return;
+       for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--)
+               *p = 0;
+}
 
 /*
  * create a chip instance and set its names.
@@ -351,7 +361,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        snd_component_add(card, component);
 
        /* retrieve the device string as shortname */
-       if (quirk && quirk->product_name) {
+       if (quirk && quirk->product_name && *quirk->product_name) {
                strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname));
        } else {
                if (!dev->descriptor.iProduct ||
@@ -363,9 +373,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                                USB_ID_PRODUCT(chip->usb_id));
                }
        }
+       remove_trailing_spaces(card->shortname);
 
        /* retrieve the vendor and device strings as longname */
-       if (quirk && quirk->vendor_name) {
+       if (quirk && quirk->vendor_name && *quirk->vendor_name) {
                len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname));
        } else {
                if (dev->descriptor.iManufacturer)
@@ -375,8 +386,11 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                        len = 0;
                /* we don't really care if there isn't any vendor string */
        }
-       if (len > 0)
-               strlcat(card->longname, " ", sizeof(card->longname));
+       if (len > 0) {
+               remove_trailing_spaces(card->longname);
+               if (*card->longname)
+                       strlcat(card->longname, " ", sizeof(card->longname));
+       }
 
        strlcat(card->longname, card->shortname, sizeof(card->longname));
 
index 695de4b5ae633efbadfe13af7c85774ab9fc337f..e18eb7ed30ae3b00af785c6bef248b4714bf34f4 100644 (file)
@@ -42,9 +42,9 @@ static const char *sym_hist_filter;
 
 static int perf_evlist__add_sample(struct perf_evlist *evlist,
                                   struct perf_sample *sample,
+                                  struct perf_evsel *evsel,
                                   struct addr_location *al)
 {
-       struct perf_evsel *evsel;
        struct hist_entry *he;
        int ret;
 
@@ -59,18 +59,6 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
                return 0;
        }
 
-       evsel = perf_evlist__id2evsel(evlist, sample->id);
-       if (evsel == NULL) {
-               /*
-                * FIXME: Propagate this back, but at least we're in a builtin,
-                * where exit() is allowed. ;-)
-                */
-               ui__warning("Invalid %s file, contains samples with id not in "
-                           "its header!\n", input_name);
-               exit_browser(0);
-               exit(1);
-       }
-
        he = __hists__add_entry(&evsel->hists, al, NULL, 1);
        if (he == NULL)
                return -ENOMEM;
@@ -92,6 +80,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
 
 static int process_sample_event(union perf_event *event,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel,
                                struct perf_session *session)
 {
        struct addr_location al;
@@ -103,7 +92,8 @@ static int process_sample_event(union perf_event *event,
                return -1;
        }
 
-       if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) {
+       if (!al.filtered &&
+           perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
                pr_warning("problem incrementing symbol count, "
                           "skipping event\n");
                return -1;
index 6b7d91160ecb3f844e0f6342f311e1785609d5c8..e8219990f8b86b9131f0ba8c81a18af5bf8b7dc9 100644 (file)
@@ -32,6 +32,7 @@ static int hists__add_entry(struct hists *self,
 
 static int diff__process_sample_event(union perf_event *event,
                                      struct perf_sample *sample,
+                                     struct perf_evsel *evsel __used,
                                      struct perf_session *session)
 {
        struct addr_location al;
index e29f04ed33963c0839b8d1c7e9d2fe1e310f4ea6..8dfc12bb119b91c2af2e6b07f956e9f45d342788 100644 (file)
@@ -43,6 +43,14 @@ static int perf_event__repipe(union perf_event *event,
        return perf_event__repipe_synth(event, session);
 }
 
+static int perf_event__repipe_sample(union perf_event *event,
+                             struct perf_sample *sample __used,
+                             struct perf_evsel *evsel __used,
+                             struct perf_session *session)
+{
+       return perf_event__repipe_synth(event, session);
+}
+
 static int perf_event__repipe_mmap(union perf_event *event,
                                   struct perf_sample *sample,
                                   struct perf_session *session)
@@ -124,6 +132,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
 
 static int perf_event__inject_buildid(union perf_event *event,
                                      struct perf_sample *sample,
+                                     struct perf_evsel *evsel __used,
                                      struct perf_session *session)
 {
        struct addr_location al;
@@ -164,7 +173,7 @@ repipe:
 }
 
 struct perf_event_ops inject_ops = {
-       .sample         = perf_event__repipe,
+       .sample         = perf_event__repipe_sample,
        .mmap           = perf_event__repipe,
        .comm           = perf_event__repipe,
        .fork           = perf_event__repipe,
index 7f618f4e7b795c593c059a3198f4f89f6621bb80..225e963df105964166d5e5c8c252f76635bf7e37 100644 (file)
@@ -305,6 +305,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
 
 static int process_sample_event(union perf_event *event,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel __used,
                                struct perf_session *session)
 {
        struct thread *thread = perf_session__findnew(session, event->ip.pid);
index 7a2a79d2cf2cc837a9e0894273b53cc31f3c589b..9ac05aafd9b2563e9625945e5dfa93dc98dfabad 100644 (file)
@@ -845,7 +845,9 @@ static void dump_info(void)
                die("Unknown type of information\n");
 }
 
-static int process_sample_event(union perf_event *event, struct perf_sample *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_evsel *evsel __used,
                                struct perf_session *s)
 {
        struct thread *thread = perf_session__findnew(s, sample->tid);
index b1b82009ab9b8f8ce5065e644b2985915155d3ae..498c6f70a74784ecd249ccd0c9cc495651f1047d 100644 (file)
@@ -50,12 +50,12 @@ static symbol_filter_t      annotate_init;
 
 static int perf_session__add_hist_entry(struct perf_session *session,
                                        struct addr_location *al,
-                                       struct perf_sample *sample)
+                                       struct perf_sample *sample,
+                                       struct perf_evsel *evsel)
 {
        struct symbol *parent = NULL;
        int err = 0;
        struct hist_entry *he;
-       struct perf_evsel *evsel;
 
        if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
                err = perf_session__resolve_callchain(session, al->thread,
@@ -64,18 +64,6 @@ static int perf_session__add_hist_entry(struct perf_session *session,
                        return err;
        }
 
-       evsel = perf_evlist__id2evsel(session->evlist, sample->id);
-       if (evsel == NULL) {
-               /*
-                * FIXME: Propagate this back, but at least we're in a builtin,
-                * where exit() is allowed. ;-)
-                */
-               ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in "
-                           "its header!\n", input_name, sample->id);
-               exit_browser(0);
-               exit(1);
-       }
-
        he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
        if (he == NULL)
                return -ENOMEM;
@@ -113,6 +101,7 @@ out:
 
 static int process_sample_event(union perf_event *event,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel,
                                struct perf_session *session)
 {
        struct addr_location al;
@@ -127,7 +116,7 @@ static int process_sample_event(union perf_event *event,
        if (al.filtered || (hide_unresolved && al.sym == NULL))
                return 0;
 
-       if (perf_session__add_hist_entry(session, &al, sample)) {
+       if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
                pr_debug("problem incrementing symbol period, skipping event\n");
                return -1;
        }
index a32f411faeac15f10fbd54e2cac2e547bcc0972f..dcfe8873c9a1b1b0813373aa2ae9365c639a16e7 100644 (file)
@@ -1603,6 +1603,7 @@ static void process_raw_event(union perf_event *raw_event __used,
 
 static int process_sample_event(union perf_event *event,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel __used,
                                struct perf_session *session)
 {
        struct thread *thread;
index 9f5fc54921413af3b783ffef688f6c1177afa941..ac574ea23917e13e8f02c4db33f74a13ee14d825 100644 (file)
@@ -162,19 +162,11 @@ static void print_sample_start(struct perf_sample *sample,
 
 static void process_event(union perf_event *event __unused,
                          struct perf_sample *sample,
+                         struct perf_evsel *evsel,
                          struct perf_session *session,
                          struct thread *thread)
 {
-       struct perf_event_attr *attr;
-       struct perf_evsel *evsel;
-
-       evsel = perf_evlist__id2evsel(session->evlist, sample->id);
-       if (evsel == NULL) {
-               pr_err("Invalid data. Contains samples with id not in "
-                      "its header!\n");
-               return;
-       }
-       attr = &evsel->attr;
+       struct perf_event_attr *attr = &evsel->attr;
 
        if (output_fields[attr->type] == 0)
                return;
@@ -244,6 +236,7 @@ static char const           *input_name = "perf.data";
 
 static int process_sample_event(union perf_event *event,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel,
                                struct perf_session *session)
 {
        struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -264,7 +257,7 @@ static int process_sample_event(union perf_event *event,
                last_timestamp = sample->time;
                return 0;
        }
-       scripting_ops->process_event(event, sample, session, thread);
+       scripting_ops->process_event(event, sample, evsel, session, thread);
 
        session->hists.stats.total_period += sample->period;
        return 0;
index 67c0459dc325276dbf690889f07f580632f46ab5..aa26f4d66d1020eb075942dc42fdc874d7dfaddc 100644 (file)
@@ -488,6 +488,7 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
 
 static int process_sample_event(union perf_event *event __used,
                                struct perf_sample *sample,
+                               struct perf_evsel *evsel __used,
                                struct perf_session *session)
 {
        struct trace_entry *te;
@@ -506,6 +507,16 @@ static int process_sample_event(union perf_event *event __used,
                struct power_entry_old *peo;
                peo = (void *)te;
 #endif
+               /*
+                * FIXME: use evsel, its already mapped from id to perf_evsel,
+                * remove perf_header__find_event infrastructure bits.
+                * Mapping all these "power:cpu_idle" strings to the tracepoint
+                * ID and then just comparing against evsel->attr.config.
+                *
+                * e.g.:
+                *
+                * if (evsel->attr.config == power_cpu_idle_id)
+                */
                event_str = perf_header__find_event(te->type);
 
                if (!event_str)
index 70f1075cc5b03493a13ddf943f126b96d4035554..676b4fb0070f09be3d09fcb253f776754f7f711c 100644 (file)
@@ -515,7 +515,9 @@ static void handle_keypress(struct perf_session *session, int c)
                        break;
                case 'E':
                        if (top.evlist->nr_entries > 1) {
-                               int counter;
+                               /* Select 0 as the default event: */
+                               int counter = 0;
+
                                fprintf(stderr, "\nAvailable events:");
 
                                list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
index 31f934af9861e69437c09b286735451a12bf78fd..a91cd99f26ea2d420d03f38c9cf89b53cf50db8d 100644 (file)
@@ -16,6 +16,7 @@
 
 static int build_id__mark_dso_hit(union perf_event *event,
                                  struct perf_sample *sample __used,
+                                 struct perf_evsel *evsel __used,
                                  struct perf_session *session)
 {
        struct addr_location al;
index e5230c0ef95b91e5aeaff97c6efd59ad271d06d0..93862a8027ea05c675616ff7004879309584b311 100644 (file)
@@ -695,13 +695,50 @@ out:
        return err;
 }
 
+static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
+                                                int input, u64 offset, u64 size)
+{
+       struct perf_session *session = container_of(header, struct perf_session, header);
+       struct {
+               struct perf_event_header   header;
+               u8                         build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
+               char                       filename[0];
+       } old_bev;
+       struct build_id_event bev;
+       char filename[PATH_MAX];
+       u64 limit = offset + size;
+
+       while (offset < limit) {
+               ssize_t len;
+
+               if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
+                       return -1;
+
+               if (header->needs_swap)
+                       perf_event_header__bswap(&old_bev.header);
+
+               len = old_bev.header.size - sizeof(old_bev);
+               if (read(input, filename, len) != len)
+                       return -1;
+
+               bev.header = old_bev.header;
+               bev.pid    = 0;
+               memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
+               __event_process_build_id(&bev, filename, session);
+
+               offset += bev.header.size;
+       }
+
+       return 0;
+}
+
 static int perf_header__read_build_ids(struct perf_header *header,
                                       int input, u64 offset, u64 size)
 {
        struct perf_session *session = container_of(header, struct perf_session, header);
        struct build_id_event bev;
        char filename[PATH_MAX];
-       u64 limit = offset + size;
+       u64 limit = offset + size, orig_offset = offset;
        int err = -1;
 
        while (offset < limit) {
@@ -716,6 +753,24 @@ static int perf_header__read_build_ids(struct perf_header *header,
                len = bev.header.size - sizeof(bev);
                if (read(input, filename, len) != len)
                        goto out;
+               /*
+                * The a1645ce1 changeset:
+                *
+                * "perf: 'perf kvm' tool for monitoring guest performance from host"
+                *
+                * Added a field to struct build_id_event that broke the file
+                * format.
+                *
+                * Since the kernel build-id is the first entry, process the
+                * table using the old format if the well known
+                * '[kernel.kallsyms]' string for the kernel build-id has the
+                * first 4 characters chopped off (where the pid_t sits).
+                */
+               if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
+                       if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
+                               return -1;
+                       return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
+               }
 
                __event_process_build_id(&bev, filename, session);
 
index cb6858a2f9a35df35f6dff6943360f2e76499c5d..3beb97c4d82204c28b357c077c60116495f56da6 100644 (file)
@@ -29,6 +29,7 @@ struct events_stats {
        u32 nr_events[PERF_RECORD_HEADER_MAX];
        u32 nr_unknown_events;
        u32 nr_invalid_chains;
+       u32 nr_unknown_id;
 };
 
 enum hist_column {
index 621427212e86f09a8736acc3af89545567b4a319..74350ffb57fee5ec34ff550b0d4ec8ca5e611d3f 100644 (file)
@@ -247,6 +247,7 @@ static inline struct event *find_cache_event(int type)
 
 static void perl_process_event(union perf_event *pevent __unused,
                               struct perf_sample *sample,
+                              struct perf_evsel *evsel,
                               struct perf_session *session __unused,
                               struct thread *thread)
 {
index 1b85d6055159370457f8003d4734ed09dd4f6f90..6ccf70e8d8f2a8c78a1d18d72cde1647a43e418c 100644 (file)
@@ -206,6 +206,7 @@ static inline struct event *find_cache_event(int type)
 
 static void python_process_event(union perf_event *pevent __unused,
                                 struct perf_sample *sample,
+                                struct perf_evsel *evsel __unused,
                                 struct perf_session *session __unused,
                                 struct thread *thread)
 {
index c68cf40764f9b006a83ec45ee0e3a8e2520b24af..caa224522fea9b0ff04984595a09e2eccd31e438 100644 (file)
@@ -280,6 +280,15 @@ static int process_event_synth_stub(union perf_event *event __used,
        return 0;
 }
 
+static int process_event_sample_stub(union perf_event *event __used,
+                                    struct perf_sample *sample __used,
+                                    struct perf_evsel *evsel __used,
+                                    struct perf_session *session __used)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
 static int process_event_stub(union perf_event *event __used,
                              struct perf_sample *sample __used,
                              struct perf_session *session __used)
@@ -303,7 +312,7 @@ static int process_finished_round(union perf_event *event,
 static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
 {
        if (handler->sample == NULL)
-               handler->sample = process_event_stub;
+               handler->sample = process_event_sample_stub;
        if (handler->mmap == NULL)
                handler->mmap = process_event_stub;
        if (handler->comm == NULL)
@@ -698,12 +707,19 @@ static int perf_session_deliver_event(struct perf_session *session,
                                      struct perf_event_ops *ops,
                                      u64 file_offset)
 {
+       struct perf_evsel *evsel;
+
        dump_event(session, event, file_offset, sample);
 
        switch (event->header.type) {
        case PERF_RECORD_SAMPLE:
                dump_sample(session, event, sample);
-               return ops->sample(event, sample, session);
+               evsel = perf_evlist__id2evsel(session->evlist, sample->id);
+               if (evsel == NULL) {
+                       ++session->hists.stats.nr_unknown_id;
+                       return -1;
+               }
+               return ops->sample(event, sample, evsel, session);
        case PERF_RECORD_MMAP:
                return ops->mmap(event, sample, session);
        case PERF_RECORD_COMM:
@@ -845,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
                            session->hists.stats.nr_unknown_events);
        }
 
+       if (session->hists.stats.nr_unknown_id != 0) {
+               ui__warning("%u samples with id not present in the header\n",
+                           session->hists.stats.nr_unknown_id);
+       }
+
        if (session->hists.stats.nr_invalid_chains != 0) {
                ui__warning("Found invalid callchains!\n\n"
                            "%u out of %u events were discarded for this reason.\n\n"
index 0b3c9afecaa9e22e5eac904a92c34742e0898532..1ac481fc1100dd1676bcdeaa392b73b15663117d 100644 (file)
@@ -55,8 +55,11 @@ struct perf_session {
        char                    filename[0];
 };
 
+struct perf_evsel;
 struct perf_event_ops;
 
+typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
+                           struct perf_evsel *evsel, struct perf_session *session);
 typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
                        struct perf_session *session);
 typedef int (*event_synth_op)(union perf_event *self,
@@ -65,8 +68,8 @@ typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
                         struct perf_event_ops *ops);
 
 struct perf_event_ops {
-       event_op        sample,
-                       mmap,
+       event_sample    sample;
+       event_op        mmap,
                        comm,
                        fork,
                        exit,
index 651dbfe7f4f32b744f828e0ae3ea6ada59b35dec..17df793c89243a44324c5c0deafa45807d0b7f6b 100644 (file)
@@ -1486,7 +1486,9 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
         * On the first pass, only load images if they have a full symtab.
         * Failing that, do a second pass where we accept .dynsym also
         */
-       for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1;
+       want_symtab = 1;
+restart:
+       for (self->symtab_type = SYMTAB__BUILD_ID_CACHE;
             self->symtab_type != SYMTAB__NOT_FOUND;
             self->symtab_type++) {
                switch (self->symtab_type) {
@@ -1536,17 +1538,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
                        snprintf(name, size, "%s%s", symbol_conf.symfs,
                                 self->long_name);
                        break;
-
-               default:
-                       /*
-                        * If we wanted a full symtab but no image had one,
-                        * relax our requirements and repeat the search.
-                        */
-                       if (want_symtab) {
-                               want_symtab = 0;
-                               self->symtab_type = SYMTAB__BUILD_ID_CACHE;
-                       } else
-                               continue;
+               default:;
                }
 
                /* Name is now the name of the next image to try */
@@ -1573,6 +1565,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
                }
        }
 
+       /*
+        * If we wanted a full symtab but no image had one,
+        * relax our requirements and repeat the search.
+        */
+       if (ret <= 0 && want_symtab) {
+               want_symtab = 0;
+               goto restart;
+       }
+
        free(name);
        if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
                return 0;
index 66f4b78737ab355fc2c75510b37e04d9f57642bf..c9dcbec7d800857e766fe35a26a29dba09e2469a 100644 (file)
@@ -38,6 +38,7 @@ static int stop_script_unsupported(void)
 
 static void process_event_unsupported(union perf_event *event __unused,
                                      struct perf_sample *sample __unused,
+                                     struct perf_evsel *evsel __unused,
                                      struct perf_session *session __unused,
                                      struct thread *thread __unused)
 {
index b04da5722437d5c7976aef1366ec5472e6422122..f674dda3363b42c407b5fc225ec55ecc3c9ad06b 100644 (file)
@@ -280,6 +280,7 @@ struct scripting_ops {
        int (*stop_script) (void);
        void (*process_event) (union perf_event *event,
                               struct perf_sample *sample,
+                              struct perf_evsel *evsel,
                               struct perf_session *session,
                               struct thread *thread);
        int (*generate_script) (const char *outfile);
index ba7c63af6f3b2bc8a53a91de50ff9ad669468fb8..8ce792ea08e9f782d3e661dbbb99798839a08ed4 100755 (executable)
@@ -37,6 +37,8 @@ $default{"POWEROFF_ON_SUCCESS"}       = 0;
 $default{"BUILD_OPTIONS"}      = "";
 $default{"BISECT_SLEEP_TIME"}  = 60;   # sleep time between bisects
 $default{"CLEAR_LOG"}          = 0;
+$default{"BISECT_MANUAL"}      = 0;
+$default{"BISECT_SKIP"}                = 1;
 $default{"SUCCESS_LINE"}       = "login:";
 $default{"BOOTED_TIMEOUT"}     = 1;
 $default{"DIE_ON_FAILURE"}     = 1;
@@ -45,6 +47,7 @@ $default{"SCP_TO_TARGET"}     = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
 $default{"REBOOT"}             = "ssh \$SSH_USER\@\$MACHINE reboot";
 $default{"STOP_AFTER_SUCCESS"} = 10;
 $default{"STOP_AFTER_FAILURE"} = 60;
+$default{"STOP_TEST_AFTER"}    = 600;
 $default{"LOCALVERSION"}       = "-test";
 
 my $ktest_config;
@@ -81,6 +84,8 @@ my $addconfig;
 my $in_bisect = 0;
 my $bisect_bad = "";
 my $reverse_bisect;
+my $bisect_manual;
+my $bisect_skip;
 my $in_patchcheck = 0;
 my $run_test;
 my $redirect;
@@ -98,6 +103,7 @@ my $console;
 my $success_line;
 my $stop_after_success;
 my $stop_after_failure;
+my $stop_test_after;
 my $build_target;
 my $target_image;
 my $localversion;
@@ -462,6 +468,10 @@ sub dodie {
        `$power_off`;
     }
 
+    if (defined($opt{"LOG_FILE"})) {
+       print " See $opt{LOG_FILE} for more info.\n";
+    }
+
     die @_, "\n";
 }
 
@@ -760,8 +770,10 @@ sub monitor {
 
     my $success_start;
     my $failure_start;
+    my $monitor_start = time;
+    my $done = 0;
 
-    for (;;) {
+    while (!$done) {
 
        if ($booted) {
            $line = wait_for_input($monitor_fp, $booted_timeout);
@@ -796,7 +808,7 @@ sub monitor {
        }
 
        if ($full_line =~ /call trace:/i) {
-           if (!$skip_call_trace) {
+           if (!$bug && !$skip_call_trace) {
                $bug = 1;
                $failure_start = time;
            }
@@ -816,12 +828,19 @@ sub monitor {
        }
 
        if ($full_line =~ /Kernel panic -/) {
+           $failure_start = time;
            $bug = 1;
        }
 
        if ($line =~ /\n/) {
            $full_line = "";
        }
+
+       if ($stop_test_after > 0 && !$booted && !$bug) {
+           if (time - $monitor_start > $stop_test_after) {
+               $done = 1;
+           }
+       }
     }
 
     close(DMESG);
@@ -925,6 +944,18 @@ sub check_buildlog {
     return 1;
 }
 
+sub make_oldconfig {
+    my ($defconfig) = @_;
+
+    if (!run_command "$defconfig $make oldnoconfig") {
+       # Perhaps oldnoconfig doesn't exist in this version of the kernel
+       # try a yes '' | oldconfig
+       doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
+       run_command "yes '' | $defconfig $make oldconfig" or
+           dodie "failed make config oldconfig";
+    }
+}
+
 sub build {
     my ($type) = @_;
     my $defconfig = "";
@@ -970,8 +1001,12 @@ sub build {
        $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
     }
 
-    run_command "$defconfig $make $type" or
-       dodie "failed make config";
+    if ($type eq "oldnoconfig") {
+       make_oldconfig $defconfig;
+    } else {
+       run_command "$defconfig $make $type" or
+           dodie "failed make config";
+    }
 
     $redirect = "$buildlog";
     if (!run_command "$make $build_options") {
@@ -1025,6 +1060,21 @@ sub get_version {
     doprint "$version\n";
 }
 
+sub answer_bisect {
+    for (;;) {
+       doprint "Pass or fail? [p/f]";
+       my $ans = <STDIN>;
+       chomp $ans;
+       if ($ans eq "p" || $ans eq "P") {
+           return 1;
+       } elsif ($ans eq "f" || $ans eq "F") {
+           return 0;
+       } else {
+           print "Please answer 'P' or 'F'\n";
+       }
+    }
+}
+
 sub child_run_test {
     my $failed = 0;
 
@@ -1070,6 +1120,7 @@ sub do_run_test {
 
            # we are not guaranteed to get a full line
            $full_line .= $line;
+           doprint $line;
 
            if ($full_line =~ /call trace:/i) {
                $bug = 1;
@@ -1086,6 +1137,19 @@ sub do_run_test {
     } while (!$child_done && !$bug);
 
     if ($bug) {
+       my $failure_start = time;
+       my $now;
+       do {
+           $line = wait_for_input($monitor_fp, 1);
+           if (defined($line)) {
+               doprint $line;
+           }
+           $now = time;
+           if ($now - $failure_start >= $stop_after_failure) {
+               last;
+           }
+       } while (defined($line));
+
        doprint "Detected kernel crash!\n";
        # kill the child with extreme prejudice
        kill 9, $child_pid;
@@ -1131,7 +1195,15 @@ sub run_git_bisect {
     return 1;
 }
 
-# returns 1 on success, 0 on failure
+sub bisect_reboot {
+    doprint "Reboot and sleep $bisect_sleep_time seconds\n";
+    reboot;
+    start_monitor;
+    wait_for_monitor $bisect_sleep_time;
+    end_monitor;
+}
+
+# returns 1 on success, 0 on failure, -1 on skip
 sub run_bisect_test {
     my ($type, $buildtype) = @_;
 
@@ -1145,6 +1217,10 @@ sub run_bisect_test {
     build $buildtype or $failed = 1;
 
     if ($type ne "build") {
+       if ($failed && $bisect_skip) {
+           $in_bisect = 0;
+           return -1;
+       }
        dodie "Failed on build" if $failed;
 
        # Now boot the box
@@ -1156,6 +1232,12 @@ sub run_bisect_test {
        monitor or $failed = 1;
 
        if ($type ne "boot") {
+           if ($failed && $bisect_skip) {
+               end_monitor;
+               bisect_reboot;
+               $in_bisect = 0;
+               return -1;
+           }
            dodie "Failed on boot" if $failed;
 
            do_run_test or $failed = 1;
@@ -1168,11 +1250,7 @@ sub run_bisect_test {
 
        # reboot the box to a good kernel
        if ($type ne "build") {
-           doprint "Reboot and sleep $bisect_sleep_time seconds\n";
-           reboot;
-           start_monitor;
-           wait_for_monitor $bisect_sleep_time;
-           end_monitor;
+           bisect_reboot;
        }
     } else {
        $result = 1;
@@ -1193,16 +1271,22 @@ sub run_bisect {
 
     my $ret = run_bisect_test $type, $buildtype;
 
+    if ($bisect_manual) {
+       $ret = answer_bisect;
+    }
 
     # Are we looking for where it worked, not failed?
     if ($reverse_bisect) {
        $ret = !$ret;
     }
 
-    if ($ret) {
+    if ($ret > 0) {
        return "good";
-    } else {
+    } elsif ($ret == 0) {
        return  "bad";
+    } elsif ($bisect_skip) {
+       doprint "HIT A BAD COMMIT ... SKIPPING\n";
+       return "skip";
     }
 }
 
@@ -1220,6 +1304,13 @@ sub bisect {
     my $type = $opt{"BISECT_TYPE[$i]"};
     my $start = $opt{"BISECT_START[$i]"};
     my $replay = $opt{"BISECT_REPLAY[$i]"};
+    my $start_files = $opt{"BISECT_FILES[$i]"};
+
+    if (defined($start_files)) {
+       $start_files = " -- " . $start_files;
+    } else {
+       $start_files = "";
+    }
 
     # convert to true sha1's
     $good = get_sha1($good);
@@ -1273,7 +1364,7 @@ sub bisect {
            die "Failed to checkout $head";
     }
 
-    run_command "git bisect start" or
+    run_command "git bisect start$start_files" or
        dodie "could not start bisect";
 
     run_command "git bisect good $good" or
@@ -1390,9 +1481,7 @@ sub create_config {
     close(OUT);
 
 #    exit;
-    run_command "$make oldnoconfig" or
-       dodie "failed make config oldconfig";
-
+    make_oldconfig "";
 }
 
 sub compare_configs {
@@ -1505,7 +1594,9 @@ sub run_config_bisect {
        }
 
        $ret = run_config_bisect_test $type;
-
+       if ($bisect_manual) {
+           $ret = answer_bisect;
+       }
        if ($ret) {
            process_passed %current_config;
            return 0;
@@ -1536,7 +1627,13 @@ sub run_config_bisect {
        $half = int($#start_list / 2);
     } while ($half > 0);
 
-    # we found a single config, try it again
+    # we found a single config, try it again unless we are running manually
+
+    if ($bisect_manual) {
+       process_failed $start_list[0];
+       return 1;
+    }
+
     my @tophalf = @start_list[0 .. 0];
 
     $ret = run_config_bisect_test $type;
@@ -1594,8 +1691,7 @@ sub config_bisect {
     close(IN);
 
     # Now run oldconfig with the minconfig (and addconfigs)
-    run_command "$defconfig $make oldnoconfig" or
-       dodie "failed make config oldconfig";
+    make_oldconfig $defconfig;
 
     # check to see what we lost (or gained)
     open (IN, $output_config)
@@ -1907,6 +2003,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
     $sleep_time = set_test_option("SLEEP_TIME", $i);
     $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
+    $bisect_manual = set_test_option("BISECT_MANUAL", $i);
+    $bisect_skip = set_test_option("BISECT_SKIP", $i);
     $store_failures = set_test_option("STORE_FAILURES", $i);
     $timeout = set_test_option("TIMEOUT", $i);
     $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
@@ -1914,6 +2012,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
     $success_line = set_test_option("SUCCESS_LINE", $i);
     $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
     $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
+    $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
     $build_target = set_test_option("BUILD_TARGET", $i);
     $ssh_exec = set_test_option("SSH_EXEC", $i);
     $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
index 3408c594b2deceaf5d58cd526a154362c427b6f2..4c5d6bd74a0207b50d8a74ff204270afdb60601a 100644 (file)
 # (default 60)
 #STOP_AFTER_FAILURE = 60
 
+# In case the console constantly fills the screen, having
+# a specified time to stop the test if it never succeeds nor fails
+# is recommended.
+# Note: this is ignored if a success or failure is detected.
+# (in seconds)
+# (default 600, -1 is to never stop)
+#STOP_TEST_AFTER = 600
+
 # Stop testing if a build fails. If set, the script will end if
 # a failure is detected, otherwise it will save off the .config,
 # dmesg and bootlog in a directory called
 #   git bisect good, git bisect bad, and running the git bisect replay
 #   if the BISECT_REPLAY is set.
 #
+# BISECT_SKIP = 1 (optional, default 0)
+#
+#   If BISECT_TYPE is set to test but the build fails, ktest will
+#   simply fail the test and end their. You could use BISECT_REPLAY
+#   and BISECT_START to resume after you found a new starting point,
+#   or you could set BISECT_SKIP to 1. If BISECT_SKIP is set to 1,
+#   when something other than the BISECT_TYPE fails, ktest.pl will
+#   run "git bisect skip" and try again.
+#
+# BISECT_FILES = <path> (optional, default undefined)
+#
+#   To just run the git bisect on a specific path, set BISECT_FILES.
+#   For example:
+#
+#     BISECT_FILES = arch/x86 kernel/time
+#
+#   Will run the bisect with "git bisect start -- arch/x86 kernel/time"
+#
 # BISECT_REVERSE = 1 (optional, default 0)
 #
 #   In those strange instances where it was broken forever
 #   With BISECT_REVERSE = 1, The test will consider failures as
 #   good, and success as bad.
 #
+# BISECT_MANUAL = 1 (optional, default 0)
+#
+#   In case there's a problem with automating the bisect for
+#   whatever reason. (Can't reboot, want to inspect each iteration)
+#   Doing a BISECT_MANUAL will have the test wait for you to
+#   tell it if the test passed or failed after each iteration.
+#   This is basicall the same as running git bisect yourself
+#   but ktest will rebuild and install the kernel for you.
+#
 # BISECT_CHECK = 1 (optional, default 0)
 #
 #   Just to be sure the good is good and bad is bad, setting
 #
 #   CONFIG_BISECT is the config that failed to boot
 #
+#   If BISECT_MANUAL is set, it will pause between iterations.
+#   This is useful to use just ktest.pl just for the config bisect.
+#   If you set it to build, it will run the bisect and you can
+#   control what happens in between iterations. It will ask you if
+#   the test succeeded or not and continue the config bisect.
+#
 # Example:
 #   TEST_START
 #   TEST_TYPE = config_bisect
 #   CONFIG_BISECT_TYPE = build
 #   CONFIG_BISECT = /home/test/Ā¢onfig-bad
 #   MIN_CONFIG = /home/test/config-min
+#   BISECT_MANUAL = 1
 #
index 1fa0d292119a4681ad8c691d3dcfbd94e7cb37a4..7bee6dc8cdb2b5cc65dcc68b0ecf67aa4774d446 100644 (file)
@@ -52,7 +52,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm-generic/bitops/le.h>
 
 #include "coalesced_mmio.h"
 #include "async_pf.h"
@@ -1439,7 +1438,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot,
        if (memslot && memslot->dirty_bitmap) {
                unsigned long rel_gfn = gfn - memslot->base_gfn;
 
-               generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
+               __set_bit_le(rel_gfn, memslot->dirty_bitmap);
        }
 }